この記事は、PowerShell Advent Calendar 2019の一日目です。
Windowsのパッケージマネージャーの裏はPowerShellが多く使われています。
そんなWindowsにおけるパッケージマネージャーと言えば、Package Management Chocolateyが有名なのではないでしょうか?
私もChocolateyをパッケージマネージャーに用いて開発環境の構築をしてきましたが、課題が多かったためScoopに切り替えました。
Chocolateyで何が問題だったのか、なぜscoopを選んだのか、この一年scoopをどのように環境構築に利用しているのかを紹介します。
TL;DR
Chocolateyからscoopに切り替えることで開発環境の自動化、ほとんどのアプリケーションをユーザー権限でのインストールに抑え込むことが可能になりました。
scoopに切り替えて得られたものをざくっと紹介します。
- UACの不要なインストール
- 簡単なアップグレード
- 常に最新環境への追随
- 確実なアンインストール
- アプリケーションのパス均一化
- ローカル開発環境構築の自動化
将来的にmsixが広く使われるようになったら、Scoopより利用しやい仕組みになるとうれしいです。
Chocolatey の利用
Scoopに切り替えるまでChocolateyを使っていました。長年利用して感じていた課題を見てみます。
どのように Chocolatey を利用していたのか
2014年にDSCを自動化しようとしていることから、Chocolateyとは5年の付き合いです。2018年までは個人、会社の開発環境構築にChocolateyを使っていました。
Weekend Scripter: PowerShell and Chocolatey http://t.co/EhJugCrAdc
— guitarrapc_tech (@guitarrapc_tech) August 24, 2014
Chocolateyは、Windows環境でのパッケージリポジトリの提供とCLIインタフェースchoco
を通して、Windowsにおいてコマンドラインからアプリケーションをインストールする体験を提供します。
最近聞かなくなりましたが、Package Managementのバックエンドとすることで「リポジトリの1つとみなして利用」したり、「独自リポジトリにChocolateyフォーマットのnugetパッケージを置いてチームのプライベートリポジトリとする」こともできます。
前職においては、Unityのリリースを検知、自動的にNuGetパッケージを生成、社内NuGetサーバーに配置、Package Managementを使ってChocolateyパッケージをインストール可能な状態にしていました。こうすることで、Unityのインストールパスをチームで共通化し、Unityインストールの最大の敵であるダウンロードの遅さ、パッケージの分かりにくさに対応していました。
今なら Unity Hub があるので不要です。(当時は Unity Hubがなかった)
Chocolatey で困ること
Chocolateyで開発環境を構築したものの困ることがあります。アンインストールとUACです。
アンインストール
Chocolateyは、MSIやexe形式のインストールをchocolateyinstall.ps1
で扱い、アンインストールをchocolateyuninstall.ps1
で扱います。しかしその実体は地道にインストーラをたたいており、実行の待ち受けやパスで失敗したり、インストールで行っていたWindows Serviceやレジストリは消し忘れていたりします。また、そもそも多くのパッケージでアンインストールスクリプトが提供されていません。
Chocolateyでも最大規模のインストールパッケージである、Git.installのアンインストール処理でもこんな感じです。
Chocolateyを構築時だけに使うという割り切りならいいのですが、開発環境はどんどん変わっていきます。当然アンインストールをする機会も少なくないでしょう。アンインストールが不安定だったり、未提供だとインストールとは非対称に以前のWindowsでのアプリケーション管理をすることになります。
使ってきた経験から言えるのは、残念ながらChocolateyでインストールしたものであってもWindowsのApps & Feature
でアンインストール必要なものがほとんどです。
私はChocolateyで今後もやっていくという判断ができませんでした。アンインストールはスパッと終わらせたいです。
UAC
UACはWindowsでコマンドラインを使っていて感じるだるいと感じる筆頭です。Chocolateyでも残念ながらUACを求めてくるパッケージは多く存在します。 自動化するためのコマンドラインでchocolateyを使ってアプリケーションインストールの実行、席を立って戻ってみるとUACで止まっていた。という経験をお持ちの方もいるのではないでしょうか?
そもそも
choco install
などをするときに管理者に昇格したcmdやPowerShellを使うように言われます。
UACにはサンドボックスとしての安全さの提供という側面はあるものの、コマンドラインで作業していていきなりUACが表示されマウスクリックを求められるのはストレスです。特にこれはLinux/macOSでコマンドラインによる操作に慣れていると顕著に感じます。*1
Chocolatey が抱える問題点
Chocolateyが抱えている体験上の問題は2つに起因しています。
- アンインストールの不完全な提供
- UACポップアップ
アンインストールに関しては、Chocolatey自体がMSIやexeといった各型式の実行ファイルを開発者が提供するスクリプトでなんとかする方式である以上避けられないです。Chocolatey自身もValidation ProgramやChocolatey Install/uninstall/WebFileなど各種サポート関数を提供していますが、たとえこれを使っても、Windowsにおいて回避するのは難しい側面があるのは否めません。
UACも、MSIを使う以上シカタナイでしょう。%ProgramFiles%
は特権ユーザーでないとアクセスできないので。しかし可能であればアプリケーションインストールごときでUAC昇格はしたくないですし、環境によっては厄介に感じます。
Chocolateyつかれました。
Scoop への切り替え
ScoopはChocolateyとはコンセプトを別にするコマンドラインインストーラーです。
Looking for familiar Unix tools? Tired of Powershell’s Verb-Noun verbosity? Scoop helps you get the programs you need, with a minimal amount of point-and-clicking.
Homebrew的に、常に最新のアプリやUNIX Toolを、UACの縛りなく、さくっと利用できるとうれしい。そういう使い方を想定されています、まさに私にはぴったりでした。
Scoop installs programs to your home directory by default. So you don’t need admin permissions to install programs, and you won’t see UAC popups every time you need to add or remove a program.
Scoopのインストール
PowerShellからワンライナーでインストールできます。
Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh') # or shorter iwr -useb get.scoop.sh | iex
使い方はscoop help
でわかります。
$ scoop help Usage: scoop <command> [<args>] Some useful commands are: alias Manage scoop aliases bucket Manage Scoop buckets cache Show or clear the download cache checkup Check for potential problems cleanup Cleanup apps by removing old versions config Get or set configuration values create Create a custom app manifest depends List dependencies for an app export Exports (an importable) list of installed apps help Show help for a command hold Hold an app to disable updates home Opens the app homepage info Display information about an app install Install apps list List installed apps prefix Returns the path to the specified app reset Reset an app to resolve conflicts search Search available apps status Show status and check for new app versions unhold Unhold an app to enable updates uninstall Uninstall an app update Update apps, or Scoop itself virustotal Look for app's hash on virustotal.com which Locate a shim/executable (similar to 'which' on Linux) Type 'scoop help <command>' to get help for a specific command.
Scoop でアプリを利用する
sudoやGitなど、Windowsにデフォルトで入ってほしいけど入っていないCLIツールは、まさにScoopが向いています。
scoop install git
まとめてインストールできます。
scoop install 7zip sudo git jq time unzip openssl
インストールしたアプリは、jq
などアプリ名でそのまま利用できます。
$ jq --version jq-1.6
インストールされているアプリケーションも一覧表示できます。
scoop list
アンインストールも簡単です。 プロセスがロックされていない限りは確実にアンインストールできるので安心できます。*2
scoop uninstall git
Scoop のアプリを検索する
利用可能なアプリは、scoop search
で探すことができます。
GitHubにまとまっているので、そこを見て探してもいいでしょう。
Scoop のアプリをよりたくさんインストールする
Scoopは、アプリのダウンロード元にGitHubを利用しておりこれをBucketと呼んでいます。 インストール直後はMain Bucketのみがインストールされています。
scoop bucket list
Bucketはscoop bucket add
で追加できます。
Bucketを追加することで多くのアプリケーションをscoopでインストールできるようになります。
例えば、公式で提供されているExtra
Bucketは、 Main
Bucketにはないけどよく利用されるアプリケーションが含まれています。
scoop bucket add extras
extras Bucketの追加でgitkraken
などもscoopでインストール可能になります。
scoop install gitkraken
インストールするときに、Bucketを気にしなくていいのでかなり楽です。
scoop にしたことで混乱したこと
scoopの特性を把握せずにいたとき混乱したこともあります。
- 複数のパスに実行ファイルが存在することによる意図しない動作
- グローバルパスに存在が期待されるソフトウェアの継続的な更新の困難さ
例えば、.NET Core SDKはVisual Studioでも入ったりし、あらゆるツールが利用しているためscoopでインストールすることは向きません。
「何をscoopで入れて、何を入れない」という選択を自分で行う必要があるので、そういう意味では誰にでもオススメできるわけではありません。 自分で選んだ結果を自分で受け入れ、対応していける人向けです。
Scoop で過去のバージョンのアプリをインストールする
Scoopは .envのような制御はないので素直に使うなら、常に最新を使うのが楽です。(scoop install / scoop updateしていくだけ)
もし過去バージョンを利用する場合、scoop reset
で可能です。
scoop reset <app>@<version>
もし過去バージョンがたまっているversions Bucketにアプリがあるならこれを使うのも手でしょう。
scoop bucket add versions
私は過去バージョンをScoopで利用することはしません。するぐらいならScoopやめる。
Scoop を継続的に使っていくための工夫
scoopでパッケージがインストールできるといっても、アプリをインストールするコマンドをずっと書き連ね、そのコマンドをスクリプトにしたりするのはつらいものがあります。
scoop install xxx scoop install yyy scoop install xxx
やりたいのは、アプリのインストールでscoopがいい感じにしてくれればなんでもいいのです。 ということで、こんなYAMLを書くことでAnsibles likeにScoopのアプリをインストール/アンインストールできる仕組みがほしいです。
- name: "Install linux tools" scoop_install: state: present bucket: main name: - cmake - gcc - gow - jq - sudo - time - unzip - openssl - apache - name: "Install windows tools" scoop_install: state: present bucket: main name: - 7zip - aws - bat - chromedriver - git - git-lfs - ngrok - pwsh - terraform - gibo - helm - mysql-workbench
YAMLでの定義を実現するためのPowrShellモジュールScoopPlaybook
を作ったので次回紹介します。
TIPS: Scoop のアプリ実体
余り意識する必要がないのですが、興味のある人向けです。
scoopでインストールされたアプリは、基本的に~\scoop\shims\アプリ名.EXE
のパスに存在します。shimsでわかる通り、これらは~/scoop/apps/アプリ名/current
を参照しており、アプリケーションのインストールと利用が分離されています。
appsのアプリディレクトリを見ると、バージョンフォルダとcurrentが存在し、currentは常に最新バージョンのシンボリックリンクになっています。
まとめ
Chocolateyはインストールの1回に限れば便利です。が、今後もモデル的にアンインストールやUACが改善するにはmsixが来ない限り難しいでしょう。 Scoopを使うと、UNIX Toolやそれ以外のツールの多くもいい感じでインストール、アンインストールできます。
私もScoopの独自Bucketでフォントとかいくつかパッケージを公開しているので、独自のアプリケーションをScoopで配布することもいずれ記事にします。