kyrat で接続したサーバで dein.vim を使いたいお話

# はじめに
vim を使い始めて 2 ヶ月が経ちました. はじめはなかなか慣れず苦戦することが多かったですが, 最近は [実践 Vim][1] を読みながら編集スピードを上げられるよう日々精進しております. 

さて, 実は最近日々のサーバ管理業務の中でちょっとした問題に行き当たりました. 自分は立場上,

- `hoge@server01.net`
- `admin@server01.net`
- `hoge@server02.net`
- `admin@server02.net`

といったように, 複数のサーバの複数のアカウントに SSH 接続する場面が多々あります. これらのサーバで自分の手元の .vimrc を使いたい場合, まずはじめに思いつく手段として, 予め自分の Github のリポジトリに上げておいた .vimrc をそれぞれのサーバに落としてくる方法が考えられます. しかしこれだと 新しいサーバに繋ぐたびにセッティングが必要ですし, バージョン管理も面倒です. 第一, 複数人で共有する管理者用アカウントなどに自分の .vimrc を残しておくのは他の人の迷惑にもなります.

どうになかならないものかと色々調べていたところ, 解決策の 1 つとして kyrat というものを見つけました.

[fsquillace/kyrat][2]

これは, SSH 接続した際に手元の .vimrc 類をサーバ側に転送してくれる SSH ラッパーです. ssh コマンドの替わりに kyrat コマンドを打つだけなので違和感無く移行できます. 実際に使ってみてかなり便利だと感じました.

しかし, kyrat では転送できるファイルに限りがあるため, dein.vim などでプラグイン管理をしている場合, dein.toml や dein_lazy.toml といった設定ファイルをサーバに転送することはできません. そこで本記事では, kyrat で接続したサーバで dein.vim を使うために, kyrat で dein.vim の設定ファイルを転送できるようにする方法を示します. ちなみに検証に使用した計算機としては, ローカル, サーバ共に OS が Ubuntu18.04 のものを使用しています.

# 設定手順
kyrat の導入方法については割愛します.

## 1. ~/.config/kyrat/ のディレクトリ構造の変更
kyrat を導入した段階では, このディレクトリには bashrc.d, inputrc.d, vimrc.d, tmux.conf.d の 4 つしかありません. dein.tmol, dein_lazy.toml 用にそれぞれ, settings_dein.d, settings_dein_lazy.d を追加します. 

```
$ cd ~/.config/kyrat/
$ mkdir settings_dein.d settings_dein_lazy.d
```

そうしたら, 6 つのディレクトリにそれぞれ対応するファイルを入れます. 自分は, `~/Dotfiles/` でバージョン管理するため, ここにはシンボリックリンクだけ入れておきます.

## 2. ~/.local/share/kyrat/lib/core.sh の編集
下記の core.sh の  _get_remote_command() 関数に, 転送するディレクトリを追加する処理を 4 行ほど記述します. 

```sh:core.sh
# 省略

function _get_remote_command(){
    local rc_script="$(_concatenate_files "$KYRAT_HOME"/bashrc "$KYRAT_HOME"/bashrc.d/* | $GZIP | $BASE64)"
    local inputrc_script="$(_concatenate_files "$KYRAT_HOME"/inputrc "$KYRAT_HOME"/inputrc.d/* | $GZIP | $BASE64)"
    local vimrc_script="$(_concatenate_files "$KYRAT_HOME"/vimrc "$KYRAT_HOME"/vimrc.d/* | $GZIP | $BASE64)"
    local tmux_conf="$(_concatenate_files "$KYRAT_HOME"/tmux.conf "$KYRAT_HOME"/tmux.conf.d/* | $GZIP | $BASE64)"

    local settings_dein="$(_concatenate_files "$KYRAT_HOME"/settings_dein "$KYRAT_HOME"/settings_dein.d/* | $GZIP | $BASE64)"
    local settings_dein_lazy="$(_concatenate_files "$KYRAT_HOME"/settings_dein_lazy "$KYRAT_HOME"/settings_dein_lazy.d/* | $GZIP | $BASE64)"

    local commands_opt=""
    [[ -z "${COMMANDS[@]}" ]] || commands_opt="-c \"${COMMANDS[@]}\""
    $CAT <<EOF
[[ -e /etc/motd ]] && $CAT /etc/motd || { [[ -e /etc/update-motd.d ]] && command -v run-parts &> /dev/null && run-parts /etc/update-motd.d/; }
[[ -d "$GNUBIN" ]] && PATH="$GNUBIN:\$PATH";
for tmp_dir in ${BASE_DIRS[@]}; do [[ -w "\$tmp_dir" ]] && { base_dir="\$tmp_dir"; break; } done;
[[ -z "\$base_dir" ]] && { echo >&2 "Could not find writable temp directory on the remote host. Aborting."; exit $NO_WRITABLE_DIRECTORY; };
command -v $BASE64 >/dev/null 2>&1 || { echo >&2 "kyrat requires $BASE64 command on the remote host. Aborting."; exit $NOT_EXISTING_COMMAND; };
command -v $GUNZIP >/dev/null 2>&1 || { echo >&2 "kyrat requires $GUNZIP command on the remote host. Aborting."; exit $NOT_EXISTING_COMMAND; };
kyrat_home="\$(mktemp -d kyrat-XXXXX -p "\$base_dir")";
trap "rm -rf "\$kyrat_home"; exit" EXIT HUP INT QUIT PIPE TERM KILL;
[[ -e \${HOME}/.bashrc ]] && echo "source \${HOME}/.bashrc" > "\${kyrat_home}/bashrc";
echo "${rc_script}" | $BASE64 -di | $GUNZIP >> "\${kyrat_home}/bashrc";
echo "${inputrc_script}" | $BASE64 -di | $GUNZIP > "\${kyrat_home}/inputrc";
echo "${vimrc_script}" | $BASE64 -di | $GUNZIP > "\${kyrat_home}/vimrc";
echo "${tmux_conf}" | $BASE64 -di | $GUNZIP > "\${kyrat_home}/tmux.conf";

echo "${settings_dein}" | $BASE64 -di | $GUNZIP > "\${kyrat_home}/dein.toml";
echo "${settings_dein_lazy}" | $BASE64 -di | $GUNZIP > "\${kyrat_home}/dein_lazy.toml";

VIMINIT="let \\\$MYVIMRC=\\"\${kyrat_home}/vimrc\\" | source \\\$MYVIMRC" INPUTRC="\${kyrat_home}/inputrc" TMUX_CONF="\${kyrat_home}/tmux.conf" $BASH --rcfile "\${kyrat_home}/bashrc" -i ${commands_opt};
EOF
}
```

この部分で対象のディレクトリ下にあるファイルをコンキャットして, 

```sh 
local settings_dein="$(_concatenate_files "$KYRAT_HOME"/settings_dein "$KYRAT_HOME"/settings_dein.d/* | $GZIP | $BASE64)"
local settings_dein_lazy="$(_concatenate_files "$KYRAT_HOME"/settings_dein_lazy "$KYRAT_HOME"/settings_dein_lazy.d/* | $GZIP | $BASE64)"
```

この部分で固めたファイルをサーバに転送しています.

```sh 
echo "${settings_dein}" | $BASE64 -di | $GUNZIP > "\${kyrat_home}/dein.toml";
echo "${settings_dein_lazy}" | $BASE64 -di | $GUNZIP > "\${kyrat_home}/dein_lazy.toml";
```


## 3. ~/.Dotfiles/vimrc の編集
あとは, vimrc を以下のように記述します. 基本的には dein.vim のチュートリアルにあるものと同じです. dein.vim のインストールディレクトリを作成する処理だけ追加しています. あとは, dein.toml のパスの指定がややこしいので, その辺だけ変更しています.

```vimscript:vimrc
let s:username = 'hoge'  

if &compatible
  set nocompatible
endif

let s:dein_dir = '/tmp/' . s:username . '/dein'

" dein.vim のインストールディレクトリが無ければ作成
if !isdirectory(s:dein_dir)
  execute '!mkdir -p ' s:dein_dir
endif

let s:dein_repo_dir = s:dein_dir . '/repos/github.com/Shougo/dein.vim'

if &runtimepath !~# '/dein.vim'
  if !isdirectory(s:dein_repo_dir)
    execute '!git clone https://github.com/Shougo/dein.vim' s:dein_repo_dir
  endif
  execute 'set runtimepath^=' . fnamemodify(s:dein_repo_dir, ':p')
endif

" dein.toml, dein_lazy.toml は vimrc と同じディレクトリに存在するものを読み込む.
let s:toml_dir = fnamemodify(resolve(expand('<sfile>:p')), ':h')

if dein#load_state(s:dein_dir)
  call dein#begin(s:dein_dir)

  call dein#load_toml(s:toml_dir . "/dein.toml", {'lazy': 0})
  call dein#load_toml(s:toml_dir . "/dein_lazy.toml", {'lazy': 1})

  call dein#end()
  call dein#save_state()
endif

filetype plugin indent on
syntax enable

if dein#check_install()
  call dein#install()
endif

" molokai を使うので
syntax on
set t_Co=256
colorscheme molokai

" 以降に自分の好きな設定を書く
set number
```

これで, kyrat 接続したサーバで dein.vim が使えるようになりました. 

# ディレクトリ構造

## ローカル側
### ~/Dotfiles/
.vimrc などをバージョン管理するためのディレクトリ. link.sh はただ単にシンボリックリンク張るためだけのものです. 自分の .vimrc の内容的に dein.toml, dein_lazy.toml が同ディレクトリに存在する必要があるため, ローカルで vim を起動する際には, このディレクトリ内にある vimrc を読み込むように設定してあります.

```
~/Dotfiles/
 ┣━ .git
 ┣━ README.md
 ┣━ link.sh
 ┣━ vimrc
 ┣━ tmuxconf
 ┣━ dein.toml
 ┗━ dein_lazy.tmol
```

### ~/.config/kyrat/
kyrat コマンドを使用した際にサーバに転送する .vimrc などを格納しておくディレクトリ. 自分は, .bashrc, .inputrc に関しては特にこだわりが無いので [Quickstart][2] のものを使用し, その他のファイルに関しては `~/Dotfiles/` でバージョン管理している各種ファイルからシンボリックリンクを張っています. ちなみに, 各ディレクトリ下に複数のファイルを置いた場合は, コンキャットされて 1 つのファイルとして転送されます.

```
~/.config/kyrat/
 ┣━ baserc.d/
 ┃   ┗ bashrc
 ┣━ inputrc.d/
 ┃   ┗ inputrc
 ┣━ vimrc.d/
 ┃   ┗ sym_vimrc          -> /home/username/Dotfiles/vimrc
 ┣━ tmux.conf.d/
 ┃   ┗ sym_tmuxconf       -> /home/username/Dotfiles/tmuxconf
 ┣━ settings_dein.d/
 ┃   ┗ sym_dein           -> /home/username/Dotfiles/dein.toml
 ┗━ settings_dein_lazy.d/
     ┗ sym_dein_lazy      -> /home/username/Dotfiles/dein_lazy.toml
```

### /tmp/username/
ローカル側の dein.vim のインストールディレクトリ. 初めての vim 実行で自動生成.

```
/tmp/username/
 ┗━ dein/
```

## サーバ側
### /tmp/kyrat-XXXXX/
kyrat コマンドを使用した際にローカルから転送されてきた .vimrc などが格納されるディレクトリ. kyrat でサーバに接続する毎に作られる. 接続が切れると自動消去.

```
/tmp/kyrat-XXXXX/
 ┣━ bashrc
 ┣━ inputrc
 ┣━ vimrc
 ┣━ tmuxconf
 ┣━ dein.toml
 ┗━ dein_lazy.tmol
```

### /tmp/username/
サーバ側の dein.vim のインストールディレクトリ. 初めての vim 実行で自動生成.

```
/tmp/username/
 ┗━ dein/
```

# おわりに
ローカルとサーバで同一の .vimrc を使用するため, 参照方法などが少しややこしくなってしまいましたが, 割と少ない変更で望みの仕様に変更できたので概ね満足です. ただ, 初めて vim を起動する際には結構時間がかかります. 

それと, あるアカウント `hoge` で vim を使用して `/tmp/username/` に dein.vim がインストールされた状態で, 2 つ目のアカウント `admin` で vim を使用しようとしたときに, 

```
/tmp/username/dein/cache_vim を作成できません
```

と表示されてしまします. どうやらキャッシュ周りがうまくいっていないようです. ただプラグインに関しては正常に反映されているようなので, 現状ではそのままにしてあります. vimmer の諸先輩方, 解決策があればご教授いただけると幸いです.

P.S. いつか思考のスピードで編集できるようになりたい...

# 参考記事
- [sshした先に.bashrcや.vimrcを持って行きたい人のためのsshrc][1]

[1]:https://tatsu-zine.com/books/practical-vim
[2]:https://github.com/fsquillace/kyrat
[3]:https://qiita.com/ikuwow/items/ba4ca57fd67c06fd1b19