tech.guitarrapc.cóm

Technical updates

Windows開発環境の構築をChocolateyからscoopに切り替える

この記事は、PowerShell Advent Calendar 2019の一日目です。

qiita.com

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を使っていました。

Chocolateyは、Windows環境でのパッケージリポジトリの提供とCLIインタフェースchocoを通して、Windowsにおいてコマンドラインからアプリケーションをインストールする体験を提供します。

chocolatey.org

最近聞かなくなりましたが、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.org

gist.github.com

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.

https://scoop.sh/scoop.sh

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にまとまっているので、そこを見て探してもいいでしょう。

github.com

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>

github.com

もし過去バージョンがたまっているversions Bucketにアプリがあるならこれを使うのも手でしょう。

scoop bucket add versions

github.com

私は過去バージョンを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を作ったので次回紹介します。

github.com

TIPS: Scoop のアプリ実体

余り意識する必要がないのですが、興味のある人向けです。

scoopでインストールされたアプリは、基本的に~\scoop\shims\アプリ名.EXEのパスに存在します。shimsでわかる通り、これらは~/scoop/apps/アプリ名/currentを参照しており、アプリケーションのインストールと利用が分離されています。

scoopのshimsフォルダー

appsのアプリディレクトリを見ると、バージョンフォルダとcurrentが存在し、currentは常に最新バージョンのシンボリックリンクになっています。

shims が参照しているappsのディレクトリ

まとめ

Chocolateyはインストールの1回に限れば便利です。が、今後もモデル的にアンインストールやUACが改善するにはmsixが来ない限り難しいでしょう。 Scoopを使うと、UNIX Toolやそれ以外のツールの多くもいい感じでインストール、アンインストールできます。

私もScoopの独自Bucketでフォントとかいくつかパッケージを公開しているので、独自のアプリケーションをScoopで配布することもいずれ記事にします。

*1:私はGUI操作時よりコマンドライン操作時の方がUACをストレスに感じます

*2:Windowsなのでプロセスが実行中はファイルがロックされます