def shell_path(): pathregex = re.compile(r'\bpython[/\-]?\d\.\d+\b', re.IGNORECASE) lines = [] def _findpybin(pycmd): code = 'import sys, simplejson; print(simplejson.dumps(sys.path))' raw = execute([pycmd, '-c', code], stdout=True)[1].decode('utf-8') paths = simplejson.loads(raw) for path in paths: if not path.startswith(os.environ['HOME']): continue if not pathregex.search(path): continue suffix = '/lib/python/site-packages' if not path.endswith(suffix): continue binpath = path[0:-len(suffix)] + '/bin' if not os.path.exists(binpath): continue yield 'PATH_HIGH="{}:$PATH_HIGH"'.format(binpath) if want_python2_anything and haveexecutable('python2'): lines += list(_findpybin('python2')) if haveexecutable('python3') and haveexecutable('pip3'): lines += list(_findpybin('python3')) # if we are installing pip modules into separate bin paths, add them to our $PATH now pippaths = getpippaths() try: lines.append('PATH_HIGH="%s:$PATH_HIGH"' % pippaths['pip3']) except KeyError: pass try: if want_python2_anything: lines.append('PATH_HIGH="%s:$PATH_HIGH"' % pippaths['pip2']) except KeyError: pass lines.append('PATH_HIGH="$HOME/bin:$PATH_HIGH"') blockinfile('~/.shellrc', lines, '# start of PATH modifications', '# end of PATH modifications')
def main(): # TODO to auto rename to an "x.old" and warn? files.symlink("bashrc", ".bashrc") files.symlink("bash_profile", ".bash_profile") files.symlink("profile", ".profile") # TODO maybe add lines instead? files.symlink("editorconfig", ".editorconfig") if system.haveexecutable("task"): files.symlink("taskrc", ".taskrc") if system.haveexecutable("asdf"): files.symlink("tool-versions", ".tool-versions") files.symlink("asdfrc", ".asdfrc") files.symlink("default-golang-pkgs", ".default-golang-pkgs") # git common config: # TODO error if git not present # TODO into separate function gitpath = os.path.join(HERE, "common.gitconfig") system.execute(["git", "config", "--global", "include.path", gitpath]) # NOTE this might overwrite if there's another include.path already present # TODO revert/cleanup somehow? # TODO check that path specification using ~/ works # TODO does pipinstall use system pip or HOMELY's one? files.symlink("vimrc", ".vimrc") # install vim-plug files.mkdir(".vim") files.mkdir(".vim/autoload") files.mkdir(".vim/swaps") files.mkdir(".vim/backups") files.mkdir(".vim/doc") files.download( "https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim", "~/.vim/autoload/plug.vim", ) # link custom ftplugin files files.symlink("vim-ftplugin", ".vim/ftplugin") if system.haveexecutable("pipenv"): # TODO warn that they need to reload for this to take effect files.lineinfile(".bashrc.local", 'eval "$(pipenv --completion)"') if system.haveexecutable("i3"): # ~/.local/bin is towards the front of PATH thanks to .profile files.symlink("i3exit.sh", "~/.local/bin/i3exit") files.symlink("locker.sh", "~/.local/bin/locker") files.symlink("i3.conf", "~/.i3/config") if system.haveexecutable("kitty"): files.mkdir("$XDG_CONFIG_HOME/kitty") files.symlink("kitty.conf", "$XDG_CONFIG_HOME/kitty/kitty.conf") if system.haveexecutable("pre-commit"): # Install pre-commit in all new/cloned repos # See also https://pre-commit.com/#pre-commit-init-templatedir template_path = "{}/.git-template".format(os.environ["HOME"]) system.execute(["git", "config", "--global", "init.templateDir", template_path]) system.execute(["pre-commit", "init-templatedir", template_path]) return 0
def init_composer(): global INIT_DONE if not haveexecutable('composer'): raise Exception("TODO: composer is not installed") # noqa composer_config = { 'minimum-stability': 'dev', 'prefer-stable': True, } mkdir('~/.config') mkdir('~/.config/composer') with writefile('~/.config/composer/composer.json') as f: json.dump(composer_config, f) INIT_DONE = True
def nvim_install(): if install_nvim_via_apt(): installpkg('neovim') installpkg('python-neovim') return if (allow_installing_stuff and haveexecutable('brew') and yesno('install_nvim_package', 'Install nvim from apt/brew?')): installpkg('neovim') return the_hard_way = yesno('compile_nvim', 'Compile/install nvim from source?', recommended=allow_installing_stuff) if not the_hard_way: raise Exception('No way to install neovim') need_installpkg( apt=( 'libtool', 'libtool-bin', 'autoconf', 'automake', 'cmake', 'g++', 'pkg-config', 'unzip', 'gettext', ), yum=('cmake', 'gcc-c++', 'unzip'), brew=('cmake', 'libtool', 'gettext'), ) n = InstallFromSource('https://github.com/neovim/neovim.git', '~/src/neovim.git') n.select_tag(NVIM_TAG) n.compile_cmd([ ['make', 'distclean'], ['make'], ['sudo', 'make', 'install'], ]) run(n)
def vim_config(): # install vim-plug into ~/.vim mkdir('~/.vim') mkdir('~/.nvim') mkdir('~/.config') mkdir('~/.config/nvim') symlink('~/.vimrc', '~/.config/nvim/init.vim') mkdir('~/.vim/autoload') download( 'https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim', '~/.vim/autoload/plug.vim') def mkdir_r(path): assert len(path) if os.path.islink(path): raise Exception( "Cannot mkdir_r(%r): path already exists but is a symlink" % path) # if the thing already exists but isn't a dir, then we can't create it if os.path.exists(path) and not os.path.isdir(path): raise Exception( "Cannot mkdir_r(%r): path already exists but is not a dir" % path) # create the parent then our target path parent = os.path.dirname(path) if len(parent) > 5: mkdir_r(parent) mkdir(path) def _static(url, dest): dest = HOME + '/.vimstatic/' + dest mkdir_r(os.path.dirname(dest)) download(url, dest) vprefs = HOME + '/.vim/prefs.vim' nprefs = HOME + '/.nvim/prefs.vim' # chuck in a reference to our shiny new vimrc.vim (this will end up below the rtp magic block) lineinfile('~/.vimrc', 'source %s/vimrc.vim' % HERE, where=WHERE_TOP) # do we want a debugger plugin in vim? for varname, varval in get_vim_options().items(): lineinfile( '~/.vim/prefs.vim', f'let {varname} = {"1" if varval else "0"} " set by phodge\'s dotfiles' .format(varname, '1' if varval else '0'), where=WHERE_END, ) # put our magic &rtp block at the top of our vimrc blockinfile('~/.vimrc', [ ' " reset rtp', ' set runtimepath&', ' " let other scripts know they\'re allowed to modify &rtp', ' let g:allow_rtp_modify = 1', ' " grab local preferences', ' if filereadable(%r)' % vprefs, ' source %s' % vprefs, ' endif', ' if has(\'nvim\') && filereadable(%r)' % nprefs, ' source %s' % nprefs, ' endif', ], '" {{{ START OF dotfiles runtimepath magic', '" }}} END OF dotfiles runtimepath magic', where=WHERE_TOP) # if the .vimrc.preferences file doesn't exist, create it now if not os.path.exists(vprefs): with open(vprefs, 'w') as f: f.write('let g:vim_peter = 1\n') # make sure we've made a choice about clipboard option in vprefs file @whenmissing(vprefs, 'clipboard') def addclipboard(): if allowinteractive(): if yesno(None, 'Use system clipboard in vim? (clipboard=unnamed)', None): rem = "Use system clipboard" val = 'unnamed' else: rem = "Don't try and use system clipboard" val = '' with open(vprefs, 'a') as f: f.write('" %s\n' % rem) f.write("set clipboard=%s\n" % val) # put a default value about whether we want the hacky mappings for when the # terminal type isn't set correctly @whenmissing(vprefs, 'g:hackymappings') def sethackymappings(): with open(vprefs, 'a') as f: f.write('" Use hacky mappings for F-keys and keypad?\n') f.write('let g:hackymappings = 0\n') # in most cases we don't want insight_php_tests @whenmissing(vprefs, 'g:insight_php_tests') def setinsightphptests(): with open(vprefs, 'a') as f: f.write('" Do we want to use insight to check PHP code?\n') f.write('let g:insight_php_tests = []\n') # lock down &runtimepath lineinfile('~/.vimrc', 'let g:allow_rtp_modify = 0', where=WHERE_END) # if we have jerjerrod installed, add an ALWAYSFLAG entry for git repos in ~/src/plugedit if False and wantjerjerrod(): mkdir('~/.config') mkdir('~/.config/jerjerrod') lineinfile('~/.config/jerjerrod/jerjerrod.conf', 'PROJECT ~/src/plugedit/*.git ALWAYSFLAG') # icinga syntax/filetype if yesno('want_vim_icinga_stuff', 'Install vim icinga2 syntax/ftplugin?', default=False): files = ['syntax/icinga2.vim', 'ftdetect/icinga2.vim'] for name in files: url = 'https://raw.githubusercontent.com/Icinga/icinga2/master/tools/syntax/vim/{}' _static(url.format(name), name) # <est> utility hasphp = haveexecutable('php') if yesno('install_est_utility', 'Install <vim-est>?', hasphp): est = InstallFromSource('https://github.com/phodge/vim-est.git', '~/src/vim-est.git') est.select_branch('master') est.symlink('bin/est', '~/bin/est') run(est)
def powerline_theme(): right = [ { "function": "todonext.powerline.firstitem" }, ] if haveexecutable('jerjerrod') and wantjerjerrod(): wsnames = "jerjerrod.powerline.wsnames" right += [ { "function": "jerjerrod.powerline.wsscancount" }, { "function": wsnames, "args": { "category": "JERJERROD:CHANGED" } }, { "function": wsnames, "args": { "category": "JERJERROD:UNTRACKED" } }, { "function": wsnames, "args": { "category": "JERJERROD:UNPUSHED" } }, { "function": wsnames, "args": { "category": "JERJERROD:UNKNOWN" } }, ] right.append({ "function": "homely.powerline.shortstatus", "args": { "autoupdate": True, "reattach_to_user_namespace": haveexecutable('reattach-to-user-namespace'), "colors": { "paused": "HOMELY:PAUSED", "running": "HOMELY:RUNNING", "failed": "HOMELY:FAILED", "noconn": "HOMELY:NOCONN", "dirty": "HOMELY:DIRTY", "never": "HOMELY:NEVER", "ok": "HOMELY:OK", } }, }) right.append({ "function": "powerline.segments.common.time.date", "name": "time", "args": { "format": "%H:%M", "istime": True, }, }) right.append({"function": "powerline.segments.common.net.hostname"}) config = {"segments": {"right": right}} if want_unicode_fix(): config["segment_data"] = {"time": {"before": ""}} import simplejson dumped = simplejson.dumps(config) mkdir('~/.config') mkdir('~/.config/powerline') mkdir('~/.config/powerline/themes') mkdir('~/.config/powerline/themes/tmux') with writefile('~/.config/powerline/themes/tmux/default.json') as f: f.write(dumped)
from HOMELY import (allow_installing_stuff, getpippaths, section_macos, want_python2_anything, wantjerjerrod, wantzsh) bash_profile = os.environ['HOME'] + '/.bash_profile' bashrc = os.environ['HOME'] + '/.bashrc' zshrc = os.environ['HOME'] + '/.zshrc' HERE = os.path.dirname(__file__) def install_completions(rcfile): lineinfile(rcfile, 'want_click_completion homely') if wantjerjerrod(): lineinfile(rcfile, 'want_click_completion jerjerrod') @section_macos(enabled=allow_installing_stuff and haveexecutable('brew')) def bash_install(): if not yesno('upgrade_bash', 'Upgrade bash?', default=False): return # install newer version of bash using homebrew or some other mechanism execute(['brew', 'install', 'bash']) bash_exec = '/usr/local/bin/bash' # how to add /usr/local/bin/bash to /etc/shells? for line in open('/etc/shells').readlines(): if line.strip() == bash_exec: break else: # TODO: this line needs testing
def tmux_keys(): import re lines = [] # needs to be installed for the current version of python mypipinstall('pyyaml', ['pip%d' % sys.version_info.major]) import yaml with open(HERE + '/keybindings/keys.yaml') as f: document = yaml.safe_load(f) regex = re.compile(r"^(C-)?(O-)?(M-)?(S-)?([ -~]|CR|BS|SPACE|ESC)$") if 'tmux' in document: static = {} dynamic = {} if haveexecutable("reattach-to-user-namespace"): static[ 'tmux_copy_cmd'] = 'copy-pipe-and-cancel "reattach-to-user-namespace pbcopy"' elif haveexecutable("pbcopy"): static['tmux_copy_cmd'] = 'copy-pipe-and-cancel "pbcopy"' elif True: # XXX: I've been having issues with Ubuntu terminal lately where it # can't decipher the terminal codes coming from tmux's # copy-selection command static['tmux_copy_cmd'] = 'copy-pipe-and-cancel "xsel -b -i"' else: static['tmux_copy_cmd'] = 'copy-selection' sections = [ ('direct', 'bind-key -n {key} {binding}'), ('prefixed', 'bind-key {key} {binding}'), ('copy-mode-vi', 'bind-key -T copy-mode-vi {key} send-keys -X {binding}'), ] for sectionname, template in sections: for keycombo, binding in document["tmux"].get(sectionname, {}).items(): if hasattr(binding, 'keys'): # is it a dict? if 'static' in binding: binding = static[binding['static']] elif 'dynamic' in binding: binding = dynamic[binding['dynamic']]() else: raise Exception("Invalid binding %r" % binding) m = regex.match(keycombo) if not m: warn("Invalid keycombo for tmux: direct: %r" % keycombo) continue ctrl, opt, meta, shift, key = m.groups() if key == "CR": key = "Enter" elif key == "ESC": key = "Escape" elif key == "SPACE": key = "Space" else: assert not key.islower( ), "Lowercase keycombo %r is not allowed" % keycombo key = key.lower() modifiers = '' if ctrl: modifiers += 'C-' assert not opt, "O- prefix not allowed for tmux keybinding %r" % keycombo if meta: modifiers += 'M-' if shift: assert key.islower(), "Invalid keycombo %r" % keycombo key = key.upper() lines.append( template.format(key=modifiers + key, binding=binding)) # we also want to make our special PANE mode pm = TmuxCustomMode( 'panemode', "PANEMODE: Move between panes using h, j, k, l. Resize panes using H, J, K, L" ) pm.prefixkeybind('p') pm.prefixkeybind('C-p') pm.bindkey('h', 'select-pane -L') pm.bindkey('j', 'select-pane -D') pm.bindkey('k', 'select-pane -U') pm.bindkey('l', 'select-pane -R') pm.bindkey('H', 'resize-pane -L 2') pm.bindkey('J', 'resize-pane -D 2') pm.bindkey('K', 'resize-pane -U 2') pm.bindkey('L', 'resize-pane -R 2') lines.extend(pm.getlines()) with writefile('~/.tmux/keybindings.conf') as f: for line in lines: f.write(line) f.write("\n")
from pathlib import Path from homely.files import symlink from homely.system import haveexecutable, execute from homely.install import installpkg if haveexecutable('apt'): if not haveexecutable('git'): installpkg('git') if not haveexecutable('curl'): installpkg('curl') if not haveexecutable('wget'): installpkg('wget') if not haveexecutable('zsh'): installpkg('zsh') if not haveexecutable('vim'): installpkg('vim') if not haveexecutable('tmux'): installpkg('tmux') omz_dir = Path('~/.oh-my-zsh') if not omz_dir.is_dir(): execute(['sh', '-c', "'$(wget https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh -O -)'") vundle_dir = Path('~/.vim/bundle/Vundle.vim') if not vundle_dir.is_dir(): execute(['git','clone','https://github.com/VundleVim/Vundle.vim.git', '~/.vim/bundle/Vundle.vim']) execute(['vim','+PluginInstall'])