Vagrantの補完機能を弄る on windows

vagrantのプラグイン"sahara"を導入して

* `vagrant sandbox on`
* `vagrant sandbox commit`
* `vagrant sandbox status`

のようなコマンドをよく打つので、打ち込みやすいように補完機能を拡張しました。

vagrant 1.9.5だとコメント欄に示したように、snapshotのサブコマンドが古い形式で表示されるので、[brbsixのvagrant-bash-completion](https://github.com/brbsix/vagrant-bash-completion/)　のファイルを書き換えるようにしました。


# 環境

* OS: Windows10 64 bit
* shell: msys2
* vagrant: version 1.9.5


# vagrantのインストール
chocolateyなどを使ってvagrantをインストールします。
Virtualboxがうまく動かなかったので、最新版ではなく1.9.5版を使っています。


## vagrantとvirtualboxの組み合わせ
蛇足ながら…

windows版のvirtualマシンは不安定なので、vagrantとvirtualboxのバージョンの組み合わせは必ずしも最新版をそろえるべきではないみたいです。
2017年8月現在、以下のバージョンの組み合わせは私の環境で問題なく動きます。


```
cinst vagrant --version 1.9.5
cisnt virtualbox --version  5.1.22
```

デスクトップ環境ではcinstコマンドでmsiのダウンロードまでしか進みませんでした。tempディレクトリにダウンロードしたインストーラー使って普通にインストールしました。


# bashにbrbsixのvagrant-bash-completionを読み込ませる

## brbsixを`git clone`
[brbsixのvagrant-bash-completion](https://github.com/brbsix/vagrant-bash-completion/)をcloneしてきます。

```sh
$ cd /etc/profile.d
$ git clone git@github.com:brbsix/vagrant-bash-completion.git
```

cloneした補完コマンドファイルを確認します。以下のパスに入っていると思います。

`/etc/profile.d/vagrant-bash-completion/vagrant-bash-completion/etc/bash_completion.d/vagrant`

sandboxコマンドを追加するので、とりあえずリネームします。

```sh
$ mv /etc/profile.d/vagrant-bash-completion/vagrant-bash-completion/etc/bash_completion.d/vagrant /etc/profile.d/vagrant-bash-completion/vagrant-bash-completion/etc/bash_completion.d/vagrant_sandbox
```


## .bash_profile実行時に読込
.bash_profileに以下の行を追加します。


```sh:.bash_profileに追加
# Set vagrant completion file
if [ -f "/etc/profile.d/vagrant-bash-completion/vagrant-bash-completion/etc/bash_completion.d/vagrant_sandbox" ] ; then
  source "/etc/profile.d/vagrant-bash-completion/vagrant-bash-completion/etc/bash_completion.d/vagrant_sandbox"
fi
```



# vagrant.exeをvagrantにリネーム
インストーラーにより、環境変数に`C:\HashiCorp\Vagrant\bin\`が追加されました。
そのため、`vag` <kbd>tab</kbd>と打つと`C:\HashiCorp\Vagrant\bin\`に入っているファイルである`vagrant.exe`を見つけて`vagrant.exe`と補完されてしまいます。

`vagrant_completion.sh`はvagrantの文字にしか反応しないので、`vagrant.exe`と打たれると補完機能が働きません。
対策としてvagrant.exeの入っているパスにvagrantというファイルを作成しました。
vagrant.exeをコピーしてvagrantにリネームするだけです。


# vagrantプラグインの補完機能を追加
cloneし、リネームしたvagrant_sandboxファイルを書き換えます。(絶対パスはここ→`/etc/profile.d/vagrant-bash-completion/vagrant-bash-completion/etc/bash_completion.d/vagrant_sandbox`)


## `sandbox`を補完
`vagrant` <kbd>tab</kbd> <kbd>tab</kbd>で`sandbox`が補完候補に見えるようにします。

* `__VAGRANT_COMMAND`変数に`sandbox`の文字を追加

## `sandbox`サブコマンドを補完

* `__VAGRANT_SANDBOX_COMMANDS=(commit off on rollback status)`を追加
* case文の分岐に`sandbox)`を追加する。

diff結果を以下に示します。

```diff:vagrantとvagrant_sandbox
--- vagrant 2017-08-17 12:02:13.030107700 +0900
+++ vagrant_sandbox 2017-08-17 12:25:03.473979000 +0900
@@ -36,7 +36,7 @@
 __VAGRANT_COMMANDS=(box cap connect destroy docker-logs docker-run
     global-status halt help init list-commands login package plugin
     port powershell provider provision push rdp reload resume rsync
-    rsync-auto share snapshot ssh ssh-config status suspend up version)
+    rsync-auto sandbox share snapshot ssh ssh-config status suspend up version)
 
 __VAGRANT_BOX_COMMANDS=(add list outdated prune remove repackage update)
 
@@ -44,6 +44,8 @@
 
 __VAGRANT_SNAPSHOT_COMMANDS=(back delete go list take)
 
+__VAGRANT_SANDBOX_COMMANDS=(commit off on rollback status)
+
 __vagrant_complete(){
     local command_options=''
 
@@ -584,6 +586,22 @@
 
                 return 0
                 ;;
+
+            sandbox)
+                if (( __VAGRANT_STATIC_COMPLETION == 1 )); then
+                    readarray -t COMPREPLY < <(compgen -W "${__VAGRANT_SANDBOX_COMMANDS[*]}" -- "$cur")
+                    return 0
+                fi
+
+                # get sandbox commands only if they are not already cached
+                [[ -z $__vagrant_sandbox_commands ]] && {
+                    __vagrant_sandbox_commands=$(__vagrant_get_subcommands sandbox) || return 1
+                }
+
+                readarray -t COMPREPLY < <(compgen -W "$__vagrant_sandbox_commands" -- "$cur")
+
+                return 0
+                ;;
 
             share)
                 [[ $prev =~ ^(--domain|--http|--https|--name|--ssh-port)$ ]] && return 0
```


最後にシェルを再起動するか、`.bash_profile`を再読み込みして、補完機能を有効化します。

```sh
$ source .bash_profile  # .bash_profile再読み込み
```



# コード

gistに[vagrant_sandbox](https://gist.github.com/u1and0/9bc66d623e7098cc5ad077edb8ef5671#file-vagrant_sandbox)を載せます。

```sh 
# ~/.bash_profileの書き換え
$ git clone git@github.com:brbsix/vagrant-bash-completion.git  # gitのクローン
$ mv /etc/profile.d/vagrant-bash-completion/vagrant-bash-completion/etc/bash_completion.d/vagrant /etc/profile.d/vagrant-bash-completion/vagrant-bash-completion/etc/bash_completion.d/vagrant_sandbox  # リネーム
# gistからvagrant_sandboxをコピペ
# vagrant.exeをvagrantにリネーム
$ source ~/.bash_profile  # .bash_profileの再読み込み
```

一時期Ubuntu上でvagrantを試したときは特に設定しなくてもsandboxを補完してくれたような気がしました。やっぱりLinuxのcui操作は簡単でいいねー