Fabricで最新のVimをバラまく

Vim Advent Calendar 2013の8日目の記事です。
昨日は@mattn_jpさんのVim script は人々の生活を豊かにしなければならないッ!でした。


以下のような開発環境で作業をするとき、ちょっとした編集なら特に困ることもないのですが、
バリバリとコードを書くとなるとさすがに素のVimは不便で困っていました。

f:id:daisuzu:20131207235804p:plain

最初はvimrcだけ転送したりとか、特定のプラグインだけを転送して使っていましたが、
色々と面倒になってしまったので、もうVim環境をまるごと転送してしまうことにしました。

Vim環境を作るのに用意したのは開発環境と同じOSの仮想マシンです。

f:id:daisuzu:20131207235822p:plain

この仮想マシン

をしたら.tar.gzとかで固めてまるっと開発環境にばらまきます。

ただ、毎回手作業をするとなるとそのうちやらなくなってしまうので
Fabricさんにやってもらいましょう。

# -*- coding: utf-8 -*-
""" fabfile for vim. """

from fabric.api import (
    run,
    get,
    put,
    cd,
    hosts,
)

# Vimのソースコードをhg cloneした場所
VIM_SRC = '~/src/vim'

# Vimのインストール先
VIM_PATH = '$HOME/work/daisuzu/local'

# vimrcをgit cloneした場所
VIMRC_PATH = '~/work/daisuzu/.vim/dotvim'

# 最初に読み込むvimrc
MYVIMRC = '~/work/daisuzu/vimrc'

# 作成したしたVim環境の格納場所
VIM_ARCHIVE = './work/daisuzu'

# Vimをビルドする際に設定する環境変数
env_export = [
    {'vi_cv_path_python3':
        '$HOME/.pyenv/versions/3.3.2/bin/python3'},
]
env_str = ' && '.join(
    [
        'export {key}={value}'.format(
            key=x.keys()[0],
            value=x.values()[0])
        for x in env_export
    ]
)

# Vimの./configureのオプション
config = [
    {'with-features':
        'huge'},
    {'enable-multibyte':
        ''},
    {'enable-gui':
        'gtk2'},
    {'enable-rubyinterp':
        'dynamic'},
    {'enable-pythoninterp':
        'dynamic'},
    {'with-python-config-dir':
        '$HOME/.pyenv/versions/2.7.5/lib/python2.7/config'},
    {'enable-python3interp':
        'dynamic'},
    {'with-python3-config-dir':
        '$HOME/.pyenv/versions/3.3.2/lib/python3.3/config-3.3m'},
    {'enable-perlinterp':
        'dynamic'},
    {'enable-luainterp':
        'dynamic'},
    {'with-luajit':
        ''},
    {'with-lua-prefix':
        '$HOME/.luaenv/versions/luajit-2.0.1-p1'},
    {'enable-gpm':
        ''},
    {'enable-xim':
        ''},
    {'enable-cscope':
        ''},
    {'enable-fontset':
        ''},
    {'with-compiledby':
        '"daisuzu <daisuzu@gmail.com>"'},
    {'prefix':
        '$HOME/work/daisuzu/local'},
]
config_str = ' '.join(
    [
        '--{key}{value}'.format(
            key=x.keys()[0],
            value='=' + x.values()[0] if x.values()[0] else '')
        for x in config
    ]
)


@hosts(['centos6'])
def build():
    """ build vim. """

    with cd(VIM_SRC):
        result = run('hg incoming', warn_only=True)
        if not result.return_code:
            # 新しいパッチが来ていたらVimをビルドする
            run('hg pull')
            run('hg update')
            run('make distclean')
            run(
                '{env} && {cmd} {arg}'.format(
                    env=env_str,
                    cmd='./configure',
                    arg=config_str
                )
            )
            run('make')
            run('sudo /usr/local/bin/paco -D make install')

    # vimrcを更新する
    with cd(VIMRC_PATH):
        run('git pull --rebase')

    # プラグインを更新する
    run(
        '{vim} {opt} {so_cmd} {update_cmd} --cmd qall'.format(
            vim=VIM_PATH + '/bin/vim',
            opt='-N -u NONE -i NONE -V1 -e -s',
            so_cmd='--cmd "source ' + MYVIMRC + '"',
            update_cmd='--cmd NeoBundleUpdate'
        ),
        warn_only=True
    )

    # Vim環境とif_xxxに必要な環境を圧縮する
    run('tar zcvf dotvim.tar.gz --exclude .git ' + VIM_ARCHIVE)
    run('tar zcvf dotenv.tar.gz --exclude .git .luaenv .pyenv .plenv .rbenv')

    # ローカルマシンに一旦コピー
    get('dotenv.tar.gz', '/home/daisuzu/tmp/dotfiles/dotenv.tar.gz')
    get('dotvim.tar.gz', '/home/daisuzu/tmp/dotfiles/dotvim.tar.gz')


@hosts(['relay-host00'])
def dist():
    """ dist vim. """

    # Vimをバラまくホストたち
    target_hosts = [
        'target-host01',
        'target-host02',
    ]

    # まずは踏み台ホストにファイルをコピー
    put('/home/daisuzu/tmp/dotfiles/dotenv.tar.gz', 'dotfiles/dotenv.tar.gz')
    put('/home/daisuzu/tmp/dotfiles/dotvim.tar.gz', 'dotfiles/dotvim.tar.gz')

    # 対象のホストに一式をコピーしてから展開する
    for h in target_hosts:
        run(
            '{scp} {file} {host}:{dst}'.format(
                scp='myscp',
                file='dotfiles/dotenv.tar.gz',
                host=h,
                dst='work/daisuzu/dotfiles'
            )
        )

        run(
            '{scp} {file} {host}:{dst}'.format(
                scp='myscp',
                file='dotfiles/dotvim.tar.gz',
                host=h,
                dst='work/daisuzu/dotfiles'
            )
        )

        run(
            '{ssh} {host} "{cmd}"'.format(
                ssh='myssh',
                host=h,
                cmd='tar zxvf work/daisuzu/dotfiles/dotenv.tar.gz'
            )
        )

        run(
            '{ssh} {host} "{cmd}"'.format(
                ssh='myssh',
                host=h,
                cmd='tar zxvf work/daisuzu/dotfiles/dotvim.tar.gz'
            )
        )

FabricにしたのはChefとかAnsibleだと踏み台ホストで動かすことができなかったからです。

このfabfileでは以下の環境で動作することを想定しています。

[~/]
+ .luaenv/      ==> luajit-2.0.1-p1がインストール済
+ .plenv/       ==> 5.18.0がインストール済
+ .pyenv/       ==> 2.7.5と3.3.2がインストール済
+ .rbenv/       ==> 1.9.3-p448がインストール済
- src/
 |+ vim/        ==> hg clone https://code.google.com/p/vim/
- work/
 |- daisuzu/
  |- .vim
   |+ Bundle/   ==> neobundle#rcするディレクトリ
   |- dotvim/   ==> git clone git://github.com/daisuzu/dotvim
    |  .vimrc
  |- local/     ==> ビルドしたVimはここにインストールされる
   |- bin/
    |  vim
   |+ share/
  |  vimrc      ==> このvimrcから~/work/daisuzu/.vim/dotvim/.vimrcを読み込む

開発環境は同じユーザに複数人がログインして使うことがあるため、
標準のVimには一切影響を与えないようにしています。

そのため、新たにインストールしたVim

$ ~/work/daisuzu/local/bin/vim -u ~/work/daisuzu/vimrc

として実行するかaliasに設定してあげる必要があります。


あとは気が向いたタイミングでこのfabfile.pyを叩くなりcronで回すなりすれば
Vim環境をアップデートすることができます。

ね、簡単でしょう?


なんでわざわざこんなことをするかって!?
そんなのよく使うプラグインがより速く、より強くとif_luaを...
な なにをする そのまさかー!
He has turned to the dark side.


明日は@Linda_ppさんです。