Scoopを使ったWindows環境構築のススメ - Super!!

ネット上にあるWindowsの環境構築やソフト紹介の記事を見て、まず「クリック」という単語を見ないことはないと思います。
あまつさえエクスプローラー間でのドラッグアンドドロップに設定フォームへの入力をするだなんて……AnsibleやDockerがすでに浸透しきった昨今、果たしてこれ以上に異常かつ原始的なことが他にあるのだろうか?

……と、そんな反語表現をWindowsの環境設定のたびに考えているアナタのための記事になります。

なお内容があまりにも長くなりそうなので、以下の3記事に分割してお伝えする予定です。
総じて、**マウスなしでの全環境構築の完遂**を究極目標に、[Scoop](https://github.com/lukesampson/scoop)を主体として自動化できるものは自動化し楽をすることに主眼を置いた内容になります。

守章:　Scoopの基礎、簡単なManifestの作成　←　今回はこれ
破章:　[バージョン管理と自動アップデート](https://qiita.com/rkbk60/items/c55223c26a42776f7101)
離章:　Scoopを用いた環境構築する際の勘所

今回は主役であるScoopを自由に使いこなすための基礎知識を解説します。
もはやScoopの解説記事といっても過言ではありません。

---
*追記: 2020/3/17*
予想以上にこの記事をストックしてくださる方が多いため、少し古くなっていた情報を更新しました。

## Scoopとは

まずは[Scoop](https://github.com/lukesampson/scoop)が何なのかについて述べておきましょう。
ScoopはCLI(黒背景に文字だけの画面)で操作できるアプリ自動導入＆管理ツールです。

たとえば、Gitの導入について。
通常、WindowsでGitを導入する際はブラウザを開き、GitHubのGit For Windowsのリリースページにアクセスして、目的のexeファイルをダウンロードして、インストーラーの指示に従ってチェックボックスをポチポチして……とけっこうな手間がかかります。

しかし、Scoopが導入してあれば、

```text:プロンプト
> scoop install git
```

たったこれだけでダウンロードとインストールにPATHの設定、Git-Bashのリンク作成までも自動でやってくれます!! しかもノークリック!! とっても便利!!　[^1]
もちろんGitだけではなく、FireFoxにPHPやVim、変わり者としてはDTMソフトのReaperなんてのもあったりもします。ほとんどのエンジニアであれば素のScoopを使うだけで満足できるくらい網羅されています。
早い話、Windows版**Homebrew**と言っても過言ではないでしょう。

ちなみにこの手の話題では先発であるChocolateyも候補に出てきますが、私はほとんどの場合Scoopの利用を薦めています。

まず、Chocolateyが管理者権限を常に必要とするのに対し、Scoopは**ほとんどの場合、管理者権限を一切必要としません。**
つまりChocolateyではなくScoopを使うことで、会社支給のPCやネットカフェにあるWindowsでも環境構築ができます。素晴らしいですね!!

またChocolateyとは違い、**導入に必要なスクリプトを簡単に作成、任意の公開Gitリポジトリで管理＆利用できる**というのも美味しいポイントです。
前述の通りほとんどの人が必要としているアプリ情報はどちらにも潤沢に揃っていますが、その内部で動くスクリプトにバグがあったりちょっと挙動変更したい部分があった場合、Chocolateyはメンテナーの方に依頼して変更を待たないといけないので時間がかかる上にその修正がされる保証もありません。対してScoopは既存の情報を参考に5〜20行程度のファイルをサクっと自作してGitHubとかに公開することで対処ができます。

## Scoopを使ってみる

早速Scoopを試してみましょう。前述のGit導入コマンドを実行するための環境を整えます。
(いちおうPowerShellのバージョンが3.0以上という制約はありますが、Windows8以降~~もしくはアップデートをしているWindows7~~であれば問題はありません。)

まずはPowerShellを起動しましょう。Windowsキーで`powershell`と入力してEnter押すだけです。
そして以下の2コマンドをコピペで入力します。

```powershell:PowerShellプロンプト
PS: Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force
PS: iwr -useb get.scoop.sh | iex
```

上のコマンド`Set-ExecutionPolicy`はScoopやそのインストールスクリプトなどを実行できるようにするためのものです。
下のコマンド`iwr -useb ...`が実際のScoopインストールコマンドです。

### インストールとアンインストール

上記のインストール処理が終わったら先ほど例示したGitを導入します。Scoopの利用にGitは不可欠同然なので、まだ入れていない方は実際に入れてみましょう。

```text:プロンプト(ここからはPowerShellじゃなくてもOK)
> scoop install git
```

導入したGitを削除したい場合は以下のコマンドを実行。

```text:プロンプト
> scoop uninstall git
```

### extras Bucketの追加
このままでも開発環境を整えるには十分なのですが、それでも導入できる数は限られています。
そこでBucketと呼ばれるものを導入して利用可能なアプリを増やしてみましょう。
ここではFireFoxを例に出します。

FireFoxのパッケージ情報は*extras*というBucketに格納されています。
いちおう現時点ではインストールができないことを確認するため、パッケージ検索をしてみましょう。`scoop search`コマンドを使います。

```text:プロンプト
scoop search firefox
```

見つからないことを確認したら、extras Bucketを追加してみましょう。Bucket関連の操作は`scoop bucket`コマンドを用います。

```text:プロンプト
> scoop bucket add extras
```

これでextras Bucketが追加され、インストールできるアプリがぐんと増えました。`scoop search firefox`を実行すれば*extras* Bucketにfirefoxがあることも確認できます。

なおインストールをはじめとして各種コマンドは対象Bucketが異なっても基本的に変わりません。

```text:プロンプト
> scoop install firefox
> scoop uninstall firefox
```

### その他Bucketの追加

Scoopに追加できるBucketはextrasだけではありません。
他にどんなBucketがあるのか気になる人は以下から情報収集してみるといいでしょう。

- `scoop bucket known`  
  scoop公式が提供しているBucketを表示するコマンド。  
  それぞれが何を提供しているかは[公式リポジトリのREADME](https://github.com/lukesampson/scoop/blob/master/README.md)から各Bucketリポジトリへのリンクがあるのでそちらを参照。
- [scoop-directory](https://github.com/rasa/scoop-directory)  
  第三者がGitHubにて作成したBucketの集計。[awesome-scoop](https://github.com/tapannallan/awesome-scoop)の後継？  
  最終更新日やスターなどでソートされている他、各Bucketからインストールできるアプリも確認可能。

ちなみに後者にあるような他の人のBucket(Gitリポジトリ)を利用する場合はコマンドにおまけを足します。
例えば最近更新を再開した日本人向けBucketを利用するならこんな感じ。`ALIAS`の部分は各々好きな名前に変えてください。

```text:プロンプト
> scoop bucket add ALIAS https://github.com/dooteeen/scoop-for-jp
```

またScoopをGUIで操作できるアプリもあり、この機能を用いてインストール可能。
低スペックPCでは動作がもっさりするものの直感的に操作できます。おすすめ。

```text:プロンプト
> scoop bucket add viewer https://github.com/prezesp/scoop-viewer-bucket
> scoop install scoop-viewer

# 起動は以下どちらかのコマンドで
> scoop gui
> scoopviewer
```

### アプリのアップデート
インストールしたアプリがバージョンアップしていた場合、更新するにはどうすればよいでしょう? Scoopなら簡単にできます。

```text:プロンプト
> scoop update
> scoop update *
```

それぞれ上の文でscoop自体のアップデートを、下の文でインストールしたアプリすべてをアップデートを行います。とても簡単ですね。
~~個人的には`scoop update; scoop update *`とセミコロンでつなげて一気に実行することをお薦めします。~~

Scoopには独自のエイリアスを作成する`alias`コマンドが用意されているのでこちらを利用しましょう。

```text:プロンプト
> scoop alias add up "scoop update; scoop update *"

> scoop up
```
この例のうち上のコマンドだけ実行すればOKです。
以降は`scoop up`を実行するだけで自身と全パッケージのアップデートを行ってくれます。

-----

以上で基本の利用法はおしまいです。他にもいくつかコマンドもありますが、通常の用法ではこれ以上のコマンドを覚える必要はないと思います。
気になる人は`scoop help`コマンドの出力や、公式[Wiki](https://github.com/lukesampson/scoop/wiki)、他のScoop解説記事をご覧ください。

ここからは「自分の思うがままに」環境構築をするための解説になります。



## 独自のパッケージを作ってみる

先ほどScoopの優秀な点として、簡単なファイルを公開Gitリポジトリに置くことで利用できる、というものを挙げました。
ここからは実際に簡単なパッケージの定義ファイル(以降 Manifest 表記)を作ってみて、その驚くべき実力を体感してみましょう。
今回は[Ctrl2cap](https://technet.microsoft.com/ja-jp/sysinternals/bb897578.aspx)(CapsLockキーをCtrlキーに置き換えるアプリ)を題材にします。

なおここで語る内容は公式Wikiのうち[Creating an App Manifest](https://github.com/lukesampson/scoop/wiki/Creating-an-app-manifest)と[App Manifests](https://github.com/lukesampson/scoop/wiki/App-Manifests)の一部を和訳し例を加えただけのものなので、英語が読める方はそちらもご覧ください。

### 事前準備 1 -- Bucketの作成

前述の*extras* Bucketもそうですが、Bucketの実態はGitリポジトリです。
後々公開することも考えて、予め適当なディレクトリに適当なリポジトリを作っておきましょう。

以降紹介するファイルはすべてこのリポジトリの直下にあるものとします。

### 事前準備 2 -- Manifestのデバッグ方法

ScoopはローカルにあるManifestファイルを用いてインストールする機能を持っています。
これを利用してManifestの開発をするとよいでしょう。

導入は`scoop install .\target-manifest.json`でOKです。
再実行するときはいったん`scoop uninstall .\target-manifest`を実行する必要があるので以下のようなコマンドエイリアスを作成しておくといいでしょう。

```text:再導入用コマンド
> scoop alias reinstall "scoop uninstall $*; scoop install $*"

# 使用例
> scoop reinstall .\sample.json
```

### (ほぼ)最小構成

それではManifestを作ってみましょう。
`scoop install ctrl2cap`でとりあえず使えるようになる構成のManifestはこちらになります。

```ctrl2cap.json
{
    "version": "2.0",
    "url": "http://download.sysinternals.com/files/Ctrl2Cap.zip",

    "##": "ctrl2cap.exeへパスを通す",
    "bin": "ctrl2cap.exe"
}
```

シンプル! シンプルです!! これにはPowerShell嫌いの方もにっこりしてくれることでしょう。
Scoopのパッケージ情報であるManifestは必要な情報だけをJSONに書き記すだけでOKなのです。

ちなみに各属性の内容はこちら。

**version (必須)**
インストールするアプリのバージョン。

**url (必須)**
ダウンロードするファイルのURL。

**##**
コメント用。処理には一切関与しません。

**bin**
ユーザーPATHで参照できるようにしたいファイル。文字列もしくはその配列で指定します。
1次元または2次元の文字列配列なら複数のファイルを対象にしたり、別名を付けてパスを通すことができます。
また上記例のようにurl属性で指定したファイルがzipなどの圧縮ファイルなら、それを展開した中身を選べます。

### スタートメニューに表示させる

とりあえずManifestはできましたが、上記のものでは単に圧縮ファイルの中にあったctrl2cap.exeにパスが通っただけです。
Ctrl2capでキーの上書きをするには管理者権限で実行する必要があるため、わざわざプロンプトを開き直してコマンドを叩くのは面倒です。ここでは誰でも確実に管理者として実行できるように、スタートメニューを経由させましょう。

```ctrl2cap.json
{
    "version": "2.0",
    "url": "http://download.sysinternals.com/files/Ctrl2Cap.zip",

    "##": "ctrl2cap.exeへパスを通し、スタートメニューにも表示させる",
    "bin": "ctrl2cap.exe",
    "shortcuts": [
        [
            "ctrl2cap.exe",
            "ctrl2cap"
        ]
    ],
    "notes": [
        "NOTE: まだキーの置換は完了していません!!",
        "スタートメニューからctrl2capで検索、管理者権限で実行してください。"
    ]
}
```

新しく**shortcuts**属性を追加しました。これをつけることでスタートメニューにショートカットを追加することができます。
値は文字列の2次元配列で、最初の要素に実体ファイル名、次の要素にショートカットの名前を指定します。[^2]

またどうやって起動・実行するのか知らせるために、**notes**属性も付け加えてみました。ここに指定した文字列配列はすべての処理が終了したときに表示されるため、ユーザーに伝えたいことがあればここに書いておくとよいでしょう。

### 自動で有効化させる

でもやっぱり、スタートメニューを経由するのは面倒です。せっかく自動化した意味がありません。
そこで*main* Bucket(最初からあるBucket)に存在する`sudo`コマンドを用いて管理者権限による実行も自動でやらせましょう。

```ctrl2cap.json
{
    "version": "2.0",
    "url": "http://download.sysinternals.com/files/Ctrl2Cap.zip",

     "##": "自動でcapsをctrlに置き換える(要 管理者権限)",
    
    "pre_install": {
        "script": "scoop install sudo"
    },
    "installer": {
        "script": [
            "sudo $dir\\ctrl2cap.exe /install",
            "if ($? == $false) {",
            "    Write-Host '===================================' -Foreground Red",
            "    Write-Host 'ctrl2capの実行に失敗しました。' -Foreground Red",
            "    Write-Host 'スタートメニューから再度起動してください。' -Foreground Red",
            "    Write-Host '===================================' -Foreground Red",
            "}"
        ]
    },
    
    "bin": "ctrl2cap.exe",
    "shortcuts": [
        [
            "ctrl2cap.exe",
            "ctrl2cap"
        ]
    ]
}
```

**pre_install**属性、**installer**属性を加えてみました。それぞれインストール前に実行するスクリプト、インストーラーとして実行するスクリプトです。正しく言えば、中身のscript属性に文字列もしくはその配列を指定することで単行もしくは複数行のPowerShellスクリプトを実行できます。
またinstallerのスクリプト中で`$dir`という未定義の変数が使われていますが、これはScoop側で定義されている解凍された圧縮ファイルのディレクトリパスになります。このようなscript属性中で利用できる変数は他に、version属性と同じ値をもつ`$version`などがあります。

さてこれでsudoコマンドを確保しつつ、自動でキー置換ができるようになったはずです(未検証)
ただ、`scoop`を実行している最中に同じコマンドを発行しています……なんか嫌ですね。さらにこれでは依存関係があることがScoopに伝わらないという実用上の問題点もあります。
そこでpre_install属性の`scoop install sudo`に該当する処理を以下のように書き換えてみます。

```ctrl2cap.json
{
    "version": "2.0",
    "url": "http://download.sysinternals.com/files/Ctrl2Cap.zip",

    "##": "自動でcapsをctrlに置き換える(要 管理者権限)",
    
    "depends": [
        "sudo"
    ],
    "installer": {
        "script": [
            "sudo $dir\\ctrl2cap.exe /install",
            "if ($? == $false) {",
            "    Write-Host '===================================' -Foreground Red",
            "    Write-Host 'ctrl2capの実行に失敗しました。' -Foreground Red",
            "    Write-Host 'スタートメニューから再度起動してください。' -Foreground Red",
            "    Write-Host '===================================' -Foreground Red",
            "}"
        ]
    },
    
    "bin": "ctrl2cap.exe",
    "shortcuts": [
        [
            "ctrl2cap.exe",
            "ctrl2cap"
        ]
    ]
}
```

依存関係を示すための**depends**属性に`sudo`を指定しました。これで確実に実行できるようになっただけでなく、`scoop search`などのコマンドで依存関係が分かるようになりました。

### hashも明記しておこう

さて、これでほぼ完全に動作する(はずの)Manifestができましたが、ひとつ問題があります。
このままではインストールの際、「hashが設定されてないゾ」というWarningが発生して怒られてしまうのです。
ダウンロードがきちんと行われたことを保証するためにも、**hash**属性にhash値[^3]を明記しておきましょう。

```ctrl2cap.json
{
    "version": "2.0",
    "url": "http://download.sysinternals.com/files/Ctrl2Cap.zip",
    "hash": "2d8c06374da140beda79ac1940ab2b06a56a9af182dba70a6338313d768a2ac2",

    "##": "(depends ~ shortcutsは省略しています。)"
}
```

なおhash値の確認方法はここでは紹介しないため、各自調べてみてください。
いちおう、上記Warningが出たときにチェックサムを表示してくれる機能があるということだけ伝えておきます。

### その他情報を書いておく

上記hash属性の追加でManifestとしては問題なく動くようになりました(きっと)
あとは公開するにあたってこれらの情報も書き加えておきましょう。

**description**
パッケージの概要を示す属性。簡潔に。

**homepage**
ホームページを示す属性。

**license**
アプリのライセンス。
`"license": "MIT"`のようにライセンス名を直接書いてもいいし、url属性をもったオブジェクトを当ててリポジトリのライセンスファイルURLを参照させるのもOK。

### 公開してBucketとして利用する

ここまでできたらManifestは完璧です。満を持してお好きなホスティングサービスにgit-pushしちゃいましょう。
これで`scoop bucket add AwesomeBucket https://somewhere.com/your/bucket-repository.git`すれば1コマンドでCtrl2capを自動導入できるようになります!!



## あとがき

ここまで、Scoopを使うメリット/基本的な使い方/バージョン更新を伴わないパッケージ(Manifest)の作り方を見ていただきました。お疲れ様です。
とくに後半の、簡単なJSON(と必要に応じてPowerShell)を書くだけで独自の自動構築が可能になる部分だけでも、かなりの時間的・労力的コストが削減できそうことがお分かりいただけたのではないでしょうか。

[次回](https://qiita.com/rkbk60/items/c55223c26a42776f7101)は[KaoriYa版Vim](https://github.com/koron/vim-kaoriya)などを題材にバージョンの自動更新について書こうと思います。またScoopの解説記事です。

解りにくい点や間違い等ありましたら遠慮なくコメントしていただけると嬉しいです。



[^1]: Unixを常用する人には当たり前な話ですね。
[^2]: 3番目および4番目にも役割が指定されています。詳しくはWiki参照。
[^3]: デフォルトはsha256。sha1やMD5も利用可能の他、hashの書かれたURLを参照することもできます。