Ejemplo n.º 1
0
def hg():
    ext = []

    if yesno('mercurial_keyring', 'Install mercurial keyring?'):
        # TODO: this things needs python-devel and openssl-devel - should we
        # provide a suggestion to install those on non-OSX OS's?
        pipinstall('mercurial_keyring', trypips=['pip2', 'pip3', 'pip'])
        ext.append('mercurial_keyring')

    if yesno('hg_strip_ext', 'Enable hg strip extension?'):
        ext.append('strip')

    # include our hg config from ~/.hgrc
    lineinfile('~/.hgrc', '%%include %s/hg/hgrc' % HERE, where=WHERE_TOP)

    # because we can't put the absolute path to our dotfiles hg/ignore file in
    # our hg/hgrc file, we have to put the config entry into the main ~/.hgrc
    # using a blockinfile()
    lines = [
        '[ui]',
        'ignore.dotfiles = {}/hg/ignore'.format(HERE),
    ]
    if ext:
        lines.append('[extensions]')
    for name in ext:
        lines.append('%s = ' % name)
    blockinfile('~/.hgrc', lines, WHERE_END)
Ejemplo n.º 2
0
def search_tools():
    if yesno('install_ack', 'Install ack?', False):
        installpkg('ack', apt='ack-grep')

    if want_silver_searcher():
        installpkg('ag', yum='the_silver_searcher', apt='silversearcher-ag')

    if yesno('install_ripgrep', 'Install ripgrep?', True):
        yum = False
        if haveexecutable('yum') and install_fedora_copr():
            yum = 'ripgrep'
        installpkg('ripgrep', yum=yum)
Ejemplo n.º 3
0
def getpippaths():
    if IS_OSX:
        return {}

    # do we need to out a pip config such that py2/py3 binaries don't clobber each other?
    question = 'Force pip to install into separate py2/py3 bin dirs?'
    if not yesno('force_pip_bin_paths', question, None):
        return {}

    scripts = {}

    for version in (2, 3):
        # TODO: we probably should drop into vim somewhere and make sure g:my_pyX_paths is
        # defined in prefs.vim or else our stuff is gonna be broken
        # TODO: we also want these in our $PATH ... or not?
        pip = "pip%d" % version
        var = "g:my_py%d_paths" % version

        if not haveexecutable(pip):
            continue

        stdout = execute([pip, '--version'],
                         stdout=True)[1].decode('utf-8').rstrip()
        assert re.search(r' \(python \d+\.\d+\)$', stdout)
        version = stdout.rsplit(' ', 1)[1][:-1]
        path = '%s/.local/python-%s-bin' % (HOME, version)

        scripts[pip] = path
        lineinfile('~/.vimrc',
                   "let %s = ['%s']" % (var, path),
                   where=WHERE_END)

    return scripts
Ejemplo n.º 4
0
def nudge():
    if yesno('install_nudge', 'Install nudge?', want_full):
        nudge = InstallFromSource('https://github.com/toomuchphp/nudge.git',
                                  '~/src/nudge.git')
        nudge.select_branch('master')
        nudge.symlink('bin/nudge', '~/bin/nudge')
        run(nudge)
Ejemplo n.º 5
0
def brew_install():
    if haveexecutable('brew'):
        return

    if yesno('install_homebrew', 'Install Homebrew?', default=True):
        install_cmd = '/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"'
        execute(['bash', '-c', install_cmd], stdout="TTY")
Ejemplo n.º 6
0
def legacypl():
    if yesno('install_legacypl', 'Create clone of legacy-pl?', want_full):
        mkdir('~/playground-6')
        legacy = InstallFromSource('ssh://[email protected]/phodge/legacy-pl.git',
                                   '~/playground-6/legacy-pl.git')
        legacy.select_branch('develop')
        run(legacy)
Ejemplo n.º 7
0
def tmux_install():
    if yesno('own_tmux', 'Compile tmux from source?', None):
        need_installpkg(
            apt=('libevent-dev', 'ncurses-dev'),
            brew=('automake', 'libevent'),
        )
        tmux = InstallFromSource('https://github.com/tmux/tmux.git',
                                 '~/src/tmux.git')
        tmux.select_tag('2.7')
        tmux.compile_cmd([
            # distclean will always fail if there's nothing to clean
            ['bash', '-c', 'make distclean || :'],
            ['sh', 'autogen.sh'],
            ['./configure'],
            ['make'],
        ])
        tmux.symlink('tmux', '~/bin/tmux')
        tmux.symlink('tmux.1', '~/man/man1/tmux.1')
        run(tmux)
    else:
        try:
            # install tmux using brew or apt-get ...
            installpkg('tmux')
        except Exception:
            print("-" * 50)
            print(
                "Compiling `tmux` failed - do you need to install automake or gcc?"
            )  # noqa
            print("-" * 50)
            raise
Ejemplo n.º 8
0
def install_php_cs_fixer():
    if not yesno('want_php_cs_fixer', 'Install php-cs-fixer?'):
        return

    init_composer()

    execute(
        ['composer', 'global', 'require', 'friendsofphp/php-cs-fixer'],
    )
Ejemplo n.º 9
0
def install_nvim_via_apt():
    if not wantnvim():
        return False

    if not allow_installing_stuff:
        return False

    if not IS_UBUNTU:
        return False

    return yesno('install_nvim_package', 'Install nvim from apt?')
Ejemplo n.º 10
0
def pypirc():
    rc = HOME + '/.pypirc'
    if not yesno('write_pypirc', 'Write a .pypirc file?', want_full):
        return
    if not os.path.exists(rc):
        with open(rc, 'w') as f:
            f.write('[distutils]\n')
            f.write('index-servers=pypi\n')
            f.write('\n')
            f.write('[pypi]\n')
            f.write('repository = https://upload.pypi.org/legacy/\n')
            f.write('# TODO: put your real username here\n')
            f.write('username = USERNAME\n')
            f.write('# TODO: put your real password here\n')
            f.write('password = PASSWORD\n')
    with open(rc) as f:
        if 'TODO' in f.read() and yesno(
                None, "Edit %s now?" % rc, True, noprompt=False):
            execute(['vim', rc], stdout="TTY")
    execute(['chmod', '600', rc])
Ejemplo n.º 11
0
def homely_dev():
    if not yesno("create_homely_venv",
                 "Create ~/playground-homely virtualenv?", False):
        return

    venv = environ['HOME'] + '/playground-homely'

    # create container dir
    mkdir(venv)
    checkout = join(venv, 'homely.git')

    # create the virtualenv if it doesn't already exist
    if not exists(join(venv, 'bin')):
        execute(['virtualenv', '--python=python3', venv], stdout="TTY")

    # check out homely.git repo if it isn't there yet
    if not exists(checkout):
        execute(['git', 'clone', '[email protected]:phodge/homely.git', checkout],
                stdout="TTY")

    # need to install editable version of homely.git in both virtualenvs
    venv_pip = venv + '/bin/pip'

    execute([venv_pip, 'install', '--editable', checkout])
    mypips(venv_pip)

    # install all dev requirements
    execute(
        [venv_pip, 'install', '-r',
         join(checkout, 'requirements_dev.txt')])

    if wantjerjerrod():
        # register the playground with jerjerrod
        jerjerrod_addline('WORKSPACE', venv, ignore=["py2venv"])

    # we may want to install pandoc to make the slides, but
    if yesno('homley_want_pandoc',
             'Install pandoc to create slides?',
             recommended=True):
        from homely.install import installpkg
        installpkg('pandoc')
Ejemplo n.º 12
0
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)
Ejemplo n.º 13
0
 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)
Ejemplo n.º 14
0
def git_install():
    if not yesno('upgrade_git',
                 'Install latest git from ppa:git-core/ppa?',
                 default=want_full):
        return

    for cmd in [
        ['sudo', 'apt-add-repository', '-y', 'ppa:git-core/ppa'],
        ['sudo', 'apt-get', 'update'],
        ['sudo', 'apt-get', 'install', 'git'],
    ]:
        execute(cmd, stdout="TTY")
Ejemplo n.º 15
0
def install_php_language_server():
    if not yesno('want_php_langserver', 'Install PHP Language Server?'):
        return

    init_composer()

    execute(
        ['composer', 'global', 'require', 'felixfbecker/language-server'],
    )
    execute(
        ['composer', 'run-script', 'parse-stubs'],
        cwd=HOME + '/.config/composer/vendor/felixfbecker/language-server',
    )
Ejemplo n.º 16
0
def ubuntu_app_switcher_current_workspace():
    if not yesno(
            'ubuntu_set_app_switcher_current_workspace',
            'Ubuntu: Set alt-tab to only use current workspace?',
    ):
        return

    execute([
        'gsettings',
        'set',
        'org.gnome.shell.app-switcher',
        'current-workspace-only',
        'true',
    ])
Ejemplo n.º 17
0
def ubuntu_key_repeat_rate():
    if not yesno('ubuntu_set_repeat_rate',
                 'Ubuntu: Set keyboard repeat rate?'):
        return

    new_values = [
        ('repeat-interval', 'uint32 15'),
        ('delay', 'uint32 210'),
    ]
    for key, value in new_values:
        execute([
            'gsettings', 'set', 'org.gnome.desktop.peripherals.keyboard', key,
            value
        ])
Ejemplo n.º 18
0
def neovim_python_devel():
    playground = 'playground-neovim-python'
    venv = HOME + '/' + playground

    msg = 'Put a dev version of neovim-python in %s?' % playground
    if not yesno('install_neovim_python', msg, False):
        return

    # my fork of the neovim project
    origin = 'ssh://[email protected]/phodge/python-client.git'
    # the main neovim repo - for pulling
    neovim = 'https://github.com/neovim/python-client.git'
    # where to put the local clone
    checkout = venv + '/python-client.git'

    # create the symlink for the neovim project
    mkdir(venv)

    if not os.path.exists(checkout):
        # NOTE: using execute() directly means the checkout directory isn't tracked by homely ...
        # this is exactly what I want
        execute(['git', 'clone', origin, checkout])
        execute(['git', 'remote', 'add', 'neovim', neovim], cwd=checkout)
        execute(['git', 'fetch', 'neovim', '--prune'], cwd=checkout)

    if not os.path.exists(os.path.join(venv, 'bin')):
        execute(['virtualenv', '--python=python3', venv], stdout="TTY")

    if not os.path.exists(os.path.join(venv, 'bin')):
        execute(['virtualenv', '--python=python3', venv], stdout="TTY")

    # create a python2 virtualenv as well
    py2venv = os.path.join(venv, 'py2venv')
    if not os.path.exists(os.path.join(py2venv, 'bin')):
        execute(['virtualenv', '--python=python2.7', py2venv], stdout="TTY")

    # create a symlink to the git repo
    symlink(checkout, os.path.join(py2venv, 'python-client.git'))

    for path in [venv, py2venv]:
        pip = os.path.join(path, 'bin', 'pip')
        execute([pip, 'install', '--editable', 'python-client.git'], cwd=path)
        mypips(pip)
        # we will definitely need tests
        execute([pip, 'install', 'nose'])

    if wantjerjerrod():
        # register the playground with jerjerrod
        jerjerrod_addline('WORKSPACE', venv, ignore=["py2venv"])
Ejemplo n.º 19
0
def install_fedora_copr():
    if not allow_installing_stuff:
        return False

    if not haveexecutable('yum'):
        return False

    copr_url = 'https://copr.fedorainfracloud.org/coprs/carlwgeorge/ripgrep/repo/epel-7/carlwgeorge-ripgrep-epel-7.repo'
    if not yesno('allow_fedora_copr', 'Add fedora COPR repo on this host?',
                 None):
        return False

    # enable the repo
    installpkg('yum-utils')
    execute(['sudo', 'yum-config-manager', '--add-repo=' + copr_url],
            stdout="TTY")
    return True
Ejemplo n.º 20
0
def fzf_install():
    if not yesno('install_fzf', 'Install fzf?', want_full):
        return

    if haveexecutable('brew') and allow_installing_stuff:
        installpkg('fzf')
        brewpath = execute(['brew', '--prefix'],
                           stdout=True)[1].decode('utf-8').strip()
        if brewpath == '/opt/homebrew':
            # brew puts the fzf files into versioned folders, so all we can do
            # is glob and sort (which isn't perfect because it would need to be
            # a semver-compatible sort) and pick the first one
            fzf_path = execute(
                [
                    'bash', '-c',
                    f'echo {brewpath}/Cellar/fzf/* | sort -r | head -n 1'
                ],
                stdout=True,
            )[1].decode('utf-8').strip()
        else:
            # this is how it was on my old mac
            fzf_path = brewpath + '/opt/fzf'
    else:
        # do it the long way
        import os.path
        fzf_repo = os.path.expanduser('~/src/fzf.git')
        fzf_install = InstallFromSource('https://github.com/junegunn/fzf.git',
                                        fzf_repo)
        fzf_install.select_tag('0.17.3')
        fzf_install.compile_cmd([
            ['./install', '--bin'],
        ])
        fzf_install.symlink('bin/fzf', '~/bin/fzf')
        run(fzf_install)
        execute(['./install', '--bin'], cwd=fzf_repo, stdout='TTY')
        fzf_path = fzf_repo

    lineinfile('~/.bashrc', 'source {}/shell/completion.bash'.format(fzf_path))
    lineinfile('~/.bashrc',
               'source {}/shell/key-bindings.bash'.format(fzf_path))
    if wantzsh():
        lineinfile('~/.zshrc',
                   'source {}/shell/completion.zsh'.format(fzf_path))
        lineinfile('~/.zshrc',
                   'source {}/shell/key-bindings.zsh'.format(fzf_path))
Ejemplo n.º 21
0
def install_pyenv():
    if not yesno('want_pyenv', 'Git clone pyenv to ~/.pyenv?', default=None):
        return

    gitclone = InstallFromSource('https://github.com/pyenv/pyenv.git',
                                 '~/.pyenv')
    gitclone.select_branch('master')
    run(gitclone)

    gitclone2 = InstallFromSource('https://github.com/pyenv/pyenv-virtualenv',
                                  '~/.pyenv/plugins/pyenv-virtualenv')
    gitclone2.select_branch('master')
    run(gitclone2)

    # NOTE: on ubuntu you'll need to install libffi-dev
    if IS_UBUNTU:
        installpkg('libffi-dev', apt='libffi-dev')
        installpkg('pkgconf', apt='pkgconf')
Ejemplo n.º 22
0
def iterm2_prefs():
    if yesno('use_iterm2_prefs', 'Use custom iterm2 prefs?', default=True):
        execute([
            'defaults',
            'write',
            'com.googlecode.iterm2.plist',
            'PrefsCustomFolder',
            '-string',
            HERE + '/iterm2',
        ])
        execute([
            'defaults',
            'write',
            'com.googlecode.iterm2.plist',
            'LoadPrefsFromCustomFolder',
            '-bool',
            'true',
        ])
Ejemplo n.º 23
0
def tools():
    if yesno('install_with', 'Install `with` utility?', want_full):
        withutil = InstallFromSource('https://github.com/mchav/with',
                                     '~/src/with.git')
        withutil.symlink('with', '~/bin/with')
        withutil.select_branch('master')
        run(withutil)

    if yesno('install_universal_ctags', 'Install Universal Ctags?', want_full):
        need_installpkg(apt=('autoconf', 'g++'))
        mkdir('~/bin')
        if haveexecutable('brew'):
            # install with homebrew
            execute(['brew', 'tap', 'universal-ctags/universal-ctags'])
            execute(['brew', 'install', '--HEAD', 'universal-ctags'])
        else:
            uc = InstallFromSource('https://github.com/universal-ctags/ctags',
                                   '~/src/universal-ctags.git')
            uc.select_branch('master')
            uc.compile_cmd([
                ['./autogen.sh'],
                ['./configure'],
                ['make'],
            ])
            uc.symlink('ctags', '~/bin/ctags')
            run(uc)
    elif allow_installing_stuff and yesno('install_ctags', 'Install `ctags`?',
                                          want_full):
        installpkg('ctags')
    if allow_installing_stuff and yesno('install_patch', 'Install patch?',
                                        want_full):
        installpkg('patch')

    if allow_installing_stuff and yesno('install_tidy',
                                        'Install tidy cli tool?', want_full):
        installpkg('tidy')

    # on OSX we want to install gnu utils (brew install coreutils findutils)
    # and put /usr/local/opt/coreutils/libexec/gnubin in PATH
    if IS_OSX and haveexecutable('brew') and allow_installing_stuff:
        if yesno('brew_install_coreutils',
                 'Install gnu utils?',
                 default=want_full):
            brew_list = set(
                execute(['brew', 'list'],
                        stdout=True)[1].decode('utf-8').splitlines())
            install = [
                pkg for pkg in ('coreutils', 'findutils')
                if pkg not in brew_list
            ]
            if len(install):
                execute(['brew', 'install'] + install)
Ejemplo n.º 24
0
def shellrc():
    # this is to prevent a problem where the U+26A1 lightning character would
    # take up 2 characters of display width in Alacritty>zsh on my MSFT M1 mac,
    # screwing up the LHS prompt when it was visible.
    lightning_ok = yesno(
        'alacritty_unicode_lightning_width_issues',
        'OK to use "⚡" in zsh prompt?',
        recommended=True,
    )
    symbol = '⚡' if lightning_ok else 'e'
    lineinfile(
            '~/.shellrc',
            f'ZSH_THEME_GIT_CHANGED_SYMBOL="{symbol}"',
            where=WHERE_TOP,
    )

    lineinfile('~/.shellrc',
               'source {}/init.sh'.format(HERE),
               where=WHERE_END)
Ejemplo n.º 25
0
def ubuntu_swap_caps_escape():
    if not yesno('ubuntu_swap_caps_escape',
                 'Ubuntu: Swap caps/escape using dconf-editor?'):
        return

    cmd = ['dconf', 'read', '/org/gnome/desktop/input-sources/xkb-options']
    current = execute(cmd, stdout=True)[1].strip()
    if b"'caps:swapescape'" in current:
        # already done
        return

    if current == b'' or current == b'[]':
        new_value = "['caps:swapescape']"
    else:
        raise Exception(
            "TODO: don't know how to modify xkb-options value")  # noqa

    execute([
        'dconf', 'write', '/org/gnome/desktop/input-sources/xkb-options',
        new_value
    ])
Ejemplo n.º 26
0
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
        execute(
            ['sudo', 'bash', '-c', 'echo {} >> /etc/shells'.format(bash_exec)],
            stdout="TTY")

    if os.getenv('SHELL') != bash_exec:
        USER = os.getenv('USER')
        execute(['sudo', 'chpass', '-s', bash_exec, USER], stdout="TTY")
Ejemplo n.º 27
0
def ubuntu_install_devilspie2():
    """
    Install devilspie2 under Ubuntu.

    devilspie2 can "pin" apps like Rhythmbox or Spotify, causing them to move across all
    desktops/workspaces. This means I don't accidentally flip to another desktop/workspace when I
    go to play some music or respond to a chat message.
    """
    question = 'Install devilspie2 to manage window sticky bits?'
    if not yesno('want_devilspie2', question, default=True):
        return

    installpkg('devilspie2', apt='devilspie2', brew=None)

    symlink('devilspie2', '~/.config/devilspie2')

    with writefile('~/.config/autostart/devilspie2.desktop') as f:
        f.write("[Desktop Entry]\n")
        f.write("Type=Application\n")
        f.write("Name=devilspie2\n")
        f.write("Exec=/usr/bin/devilspie2\n")
        f.write("Comment=devilspie2 - react to gnome window events\n")
        f.write("X-GNOME-Autostart-enabled=true\n")
Ejemplo n.º 28
0
def tmux_config():
    tmux_plugins = yesno('install_tmux_plugins',
                         'Install TPM and use tmux plugins?', want_full)

    if tmux_plugins:
        mkdir('~/.tmux')
        mkdir('~/.tmux/plugins')
        tpm = InstallFromSource('https://github.com/tmux-plugins/tpm',
                                '~/.tmux/plugins/tpm')
        tpm.select_branch('master')
        run(tpm)

    # what to put in tmux config?
    wildcards = {"DOTFILES": HERE, "HOME": HOME}
    lines = ['source ~/.tmux/keybindings.conf']
    # add our dotfiles python folder to PYTHONPATH before restarting the powerline daemon
    #lines.append("set-environment PYTHONPATH '%(DOTFILES)s/python'")
    if tmux_plugins:
        lines.append('source "%(DOTFILES)s/tmux/plugins.conf"')
        # FIXME: the only way to determine if TPM installed correctly is to
        # press `[PREFIX]`, `I` to do a plugin install
    lines.append('source "%(DOTFILES)s/tmux/tmux.conf"')
    if wantpowerline():
        wildcards["POWERLINE"] = powerline_path()
        lines.extend([
            # always replace the daemon on startup, so that re-sourcing the
            # tmux conf always loads updated python modules
            'source "%(POWERLINE)s/bindings/tmux/powerline.conf"',
            'run-shell "powerline-daemon --replace -q"',
        ])
    lines = [l % wildcards for l in lines]  # noqa: E741
    blockinfile('~/.tmux.conf',
                lines,
                '# start of automated tmux config',
                '# end of automated tmux config',
                where=WHERE_TOP)
Ejemplo n.º 29
0
def get_vim_options() -> dict[str, bool]:
    ret = {}

    # vim
    ret['g:peter_give_me_a_debugger'] = yesno(
        'vim_install_debugger_plugin',
        'Vim: install a debugger plugin?',
    )

    ret['g:peter_use_builtin_php_syntax'] = (
        not HOMELY.want_php_anything) or yesno(
            'vim_use_builtin_php_syntax',
            'Vim: use builtin php syntax?',
        )

    ret['g:jerjerrod_cache_clearing'] = HOMELY.wantjerjerrod() and yesno(
        'jerjerrod_clear_cache_in_vim',
        'Jerjerrod: automatic cache clearing in Vim using BufWritePost?',
        recommended=True,
    )

    # neovim
    ret['g:peter_want_nvimdev_plugin'] = want_nvim_devel() and yesno(
        'neovim_want_nvimdev_plugin',
        'Neovim: install nvimdev.nvim plugin for neovim development?',
    )

    use_treesitter = HOMELY.wantnvim() and yesno(
        'neovim_use_treesitter',
        'Neovim: use treesitter for syntax highlighting?',
    )
    ret['g:peter_want_treesitter'] = use_treesitter
    ret['g:peter_want_treesitter_python'] = use_treesitter and yesno(
        'neovim_use_treesitter_for_python',
        'Neovim: use treesitter for PYTHON syntax highlighting?',
    )

    # other technologies
    ret['g:peter_want_terraform_plugins'] = HOMELY.want_terraform_anything
    ret['g:peter_want_rust_plugins'] = HOMELY.want_rust_anything
    ret['g:peter_want_php_plugins'] = HOMELY.want_php_anything

    return ret
Ejemplo n.º 30
0
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)