tech.guitarrapc.cóm

Technical updates

Windows開発環境をscoopで継続的に構築する

以前 Windows の開発環境を scoop で構築しているということを書きました。

tech.guitarrapc.com

その際に、scoopを継続的に使っていくためのツール ScoopPlaybook を書いたことに触れました。 今回はその ScoopPlaybook の紹介です。

目次

TL;DR

  • ScoopPlaybook という PowerShellモジュールを作った(2年近く使っている)
  • scoop で何をインストールするかをYAML定義して使える
  • Scoop-Playbook コマンドでYAML通りに実行される
  • 使い心地は、Ansible Playbook のYAML定義とコマンドにインスパイアされている

scoop 使っていて、YAMLでインストールするツールを定義したい方は使ってみてください。

目指す姿

私は普段からOS環境を壊すことをアリと考えています。 ただし壊すからには再構築にコストをなるべくかけたくないため、対象のマシン上で再構築がコマンド一つでできるようにしています。 macOS は Homebrew や defaultsをAnsible Playbookで構築し、Ubuntu は Ansible Playbook で構築しています。

Ansible Playbook を使うことで、ほどよく緩くいい感じの目指す姿が可能になります。

  • 利用する開発ツールをYAMLに定義して
  • 何度実行しても同じ結果に収束させる

例えば Homebrew でインストールする場合は次のように定義できます。

# roles/homebrew/tasks/main.yaml
- name: 'homebrew packages installation'
  homebrew:
    name: '{{ item.name }}'
    state: "{{ item.state|default('present') }}"
  with_items: "{{ homebrew_packages }}"

# roles/homebrew/vars/main.yaml
homebrew_packages:
  - name: autoconf
  - name: awscli
  - name: aws-iam-authenticator
  - name: azure-cli
  # and so on....

一度定義してしまえばツールを定義に追加したり、アンインストール ( state: "absent" ) を指定するだけとメンテナンスが非常に簡単です。

site.yml を置いたルートパスでいつも同じコマンドを実行するだけで、YAML定義通りに環境が構築されます、便利。

$ ansible-playbook -i hosts site.yml

sudo が必要な操作 (become) なら、実行時に入れるだけです。

ansible-playbook -i hosts site.yml --ask-become-pass

WSL との相性もよく、気軽に環境を壊してサクッと作り直すことがコストでなくなります。

自分の環境にどんなツールをいれているかを説明することがふとしたときにあるのですが、定義によって、いつでも確認したり継続的に変更をかけたり、場合によっては他人に共有できるのは個人的に好みです。

WindowsでAnsiblePlaybook のようなアプリケーションインストール基盤を作る

環境の再構築はWindowsでもたびたび行います。(OSいれなおしでなくてもリセットはやりますよね)

scoopを使っていくことに決めたときに、コマンドの羅列地獄になるのは嫌だと思いました。 しかしAnsible をWindows localhost に実行はサポートされていないので、Ansible Playbook のような定義とインストールを提供することにしました。(WSLからAnsible実行するというのはナシ派) その晩にザクっと書いたのが ScoopPlaybook という PowerShell Module です。

github.com

あんまり使い方とか書いていないので、どういう利用をするのか紹介します。

scoop の通常のインストール

例えば、scoop でgow、jq、time、unzipをインストールする場合、コマンドラインで次のように実行するでしょう。

scoop install gow jq time unzip

あるいは、次のようにコマンドを分けているかもしれません。

scoop install gow
scoop install jq
scoop install time
scoop install unzip

アンインストールもコマンドラインで制御できます。

scoop uninstall gow

入っているツールは scoop list で見えますが、ほかの環境や再構築、追加インストールをするときはいちいち考えるの嫌になります。

ScoopPlaybook で定義からインストールする

ScoopPlaybook はAnsible Playbook でやっていたのと同じ目指す姿を提供します。

  • 利用する開発ツールをYAMLに定義して
  • 何度実行しても同じ結果に収束させる

利用方法は Ansible Playbookに合わせています。

  • ルートパス/site.ymlに 利用する role のYAML定義し、
  • ルートパス/roles/バケット/tasks/main.yml にツールをYAML定義したら、
  • ルートパスで、Scoop-Playbook コマンドを実行すると、Scoopバケットやツールが定義通りにインストール/アンインストールされる。

YAMLで定義して、コマンド一つで定義を実行。ただそれだけです。 実際にどうやるのかイメージしにくいので利用例を見てみましょう。

利用例

先ほどのmainバケットのツールをScoopPlaybookでYAML定義してインストールしてみましょう。 ScoopPlaybook モジュールとYAM解析モジュールをインストールします。PowerShell 5.1 以降で動作します。

PS> Install-Module ScoopPlaybook -Scope CurrentUser
PS> Install-Module "PowerShell-Yaml" -Scope CurrentUser

適当にルートパスを切ります。

md ./begin
cd ./begin

まずは、インストールしたいアプリの定義YAMLを ルートパス/roles/main/tasks/main.yml に定義します。

PS> mkdir roles/main/tasks
PS> New-Item roles/main/tasks/main.yml
PS> vim roles/main/tasks/main.yml
- name: "Install main tools"
  scoop_install:
    state: present
    bucket: main
    name:
      - gow
      - jq
      - time
      - unzip

インストールするロールを指定したYAML定義 site.yml をルートパスにおきます。

PS> New-Item site.yml
PS> vim site.yml

今回のロールは main なのでこれを一つ指定します。

name: Windows Setup
roles:
  - main

早速定義をドライランしてみましょう、次のコマンドを site.yml のパスで実行します。

PS> Scoop-Playbook -Mode check

scoop のバケットを更新して (scoop update) 、ツールがインストールされるか実行計画を確認できます。

PRE [scoop : status] ***************************************************************
  [o] skip: [run with 'check' mode]
  [o] skip: [prerequisiting availability]
  [o] skip: [updating buckets]
  [o] check: [scoop-update: Updating Scoop...]
  [o] check: [scoop-update: Updating 'main' bucket...]
  [o] check: [scoop-update: Scoop was updated successfully!]
  [o] skip: [status checking]
  [o] skip: [scoop-status: Scoop is up to date.]
  [o] check: [scoop-status: Updates are available for:]
.... 省略
PLAY [Windows Setup] ***************************************************************

TASK [main : Install main tools] ***************************************************
  [!] check: [scoop_install: gow] => Installed: No
  [!] check: [scoop_install: jq] => Installed: No
  [!] check: [scoop_install: time] => Installed: No
  [!] check: [scoop_install: unzip] => Installed: No

問題なければインストールします。Mode パラメーターを省略するか、-Mode run を明示的に付けると実行します。

PS> Scoop-Playbook
PRE [scoop : status] ***************************************************************
.... 省略
PLAY [Windows Setup] ***************************************************************

TASK [main : Install main tools] ***************************************************
  [!] changed: [scoop_install: gow] => Installed: No
  Installing 'gow' (0.8.0) [64bit]
Loading Gow-0.8.0.exe from cache
Checking hash of Gow-0.8.0.exe ... ok.
Extracting dl.7z ... done.
Running pre-install script...
Linking ~\scoop\apps\gow\current => ~\scoop\apps\gow\0.8.0
.... 省略
'gow' (0.8.0) was installed successfully!
  [!] changed: [scoop_install: jq] => Installed: No
  Installing 'jq' (1.6) [64bit]
.... 省略
'jq' (1.6) was installed successfully!
  [!] changed: [scoop_install: time] => Installed: No
  Installing 'time' (0.2018.07.25) [64bit]
.... 省略
  [!] changed: [scoop_install: time] => Installed: No
  Installing 'time' (0.2018.07.25) [64bit]
.... 省略
'time' (0.2018.07.25) was installed successfully!
Notes
-----
Please use 'timecmd' instead of 'time' in cmd.exe.
  [!] changed: [scoop_install: unzip] => Installed: No
  Installing 'unzip' (6.00) [64bit]
.... 省略
'unzip' (6.00) was installed successfully!

再度実行しても同じ結果に収束します。 もし更新があれば更新してくれます。

PS> Scoop-Playbook
Scoop-Playbook
PRE [scoop : status] ***************************************************************
.... 省略
PLAY [Windows Setup] ***************************************************************

TASK [main : Install main tools] ***************************************************
  [o] skip: [scoop_install: gow] =>   gow  0.8.0
  [o] skip: [scoop_install: jq] =>   jq  1.6
  [o] skip: [scoop_install: time] =>   time  0.2018.07.25
  [o] skip: [scoop_install: unzip] =>   unzip  6.00

何かの理由でscoop コマンドで直接インストールすることもあるでしょう、そんな時は定義に一行足せばいいだけです。 もし scoop コマンドで誤ってアンインストールしても、Scoop-Playbook を実行すれば元通りです。

Scoop で管理したいツールを定義通りに実行する。それができます。

普段の利用例

私は ScoopPlaybook を使ってYAML定義をして GitHub においています。 参考に私が普段使っているリポジトリを置いておきます。ルートパスはこのリポジトリの ./envs/windows/ パスです。

local-provisioner/envs/windows at master · guitarrapc/local-provisioner · GitHub

そのため、環境構築するときは次のコマンドを実行しています。

git clone https://github.com/guitarrapc/local-provisioner.git
cd local-provisioner/envs/windows
. ./prerequisites.ps1
sudo Scoop-Playbook

ツールの追加や削除をしたいときは、定義のYAML を修正して git commit/push するだけです。 バッチファイルやスクリプトではないので、どのように動作するかは考えず、ツールをYAMLに並べるだけなのはメンテの面で作ってよかったと思っています。 実際これなしで scoop とかいやです。

できること

ScoopPlaybookは次の操作が可能です。これしかできないです。

  • scoop_bucket_install: バケットの追加、削除
  • scoop_install: ツールのインストール、アンインストール

バケットの追加、削除

scoop は任意のGitHubリポジトリなどをバケットにすることができます。scoop bucket add xxxx ScoopPlaybook も scoop_bucket_install でバケットの追加、削除をサポートしています。

例えば extras バケットを追加する場合、次のように書けます。

- name: "Install extras bucket"
  scoop_bucket_install:
    state: present
    bucket: extras

extras バケットは特別扱いされていますが、自分の GitHub URL を指定したい場合は次のようになります。

- name: "Install guitarrapc bucket"
  scoop_bucket_install:
    state: present
    bucket: guitarrapc
    source: https://github.com/guitarrapc/scoop-bucket.git

もしも追加したバケットを消したいならstate に absent を指定します。 (source は省略できます)

- name: "Uninstall guitarrapc bucket"
  scoop_bucket_install:
    state: absent
    bucket: guitarrapc

それぞれのキーは、scoop bucket コマンドに合わせてあります。

  • state: present か absent を指定。
  • bucket: 対象のバケット名を指定
  • source: GitHub などのバケットURLを指定

ツールのインストール、アンインストール

scoop はバケットからツールのインストール、アンインストールができます。scoop install xxxx ScoopPlaybook も scoop_install でツールのインストール、アンインストールをサポートしています。

- name: "Install main tools"
  scoop_install:
    state: present
    bucket: main
    name:
      - gow

先ほど追加した gow をアンインストールするなら次のように書けます。

- name: "Uninstall main tools"
  scoop_install:
    state: absent
    bucket: main
    name:
      - gow

それぞれのキーは、scoop install コマンドに合わせてあります。

  • state: present か absent を指定。
  • bucket: 対象のバケット名を指定
  • name: ツールを配列で指定

すでにインストールされているツールに更新がある場合は、Scoop-Playbook 実行時に更新してくれます。便利。

管理者権限で実行したい

scoop はユーザー権限が基本でーとか言いますが、ツールによってはFiddler のように管理者権限がないとインストールできないものもあります。 そんなときは sudo コマンドです。

sudo コマンドをインストールしておいて(scoop install sudo 相当)

- name: "Install main tools"
  scoop_install:
    state: present
    bucket: main
    name:
      - sudo

Scoop-Playbook を sudo つきで実行すればok です。

sudo Scoop-Playbook

まとめ

一人で使ってて満足していたんですが、WinGet が出てきて未来はどうなるかと楽しみにしています。 ただ、WinGet はこのままいくとこういう YAML 定義に関しては手を出さず、誰かが何か作るのでしょう。

アンインストールやUAC考慮がない、今のWinGet 触る気はありませんが、WinGetを触る将来が来たらこういうツール書くかもしれません。 ただ、その時はたぶん PowerShell では書かない気がするかもしれない。