ChocolateyのApproved Packageを作成する手順

この記事はPowerShell Advent Calendar 2014の12/20の記事です。

Windowsのデファクトとパッケージマネージャーとして知るぞ知る人に活用されてきたChocolateyですが、Windows 10から公式のパッケージマネージャであるOneGetが用意されることになり、サポートリポジトリとしてChocolateyのリポジトリが最初にサポートされることになりました。

この方針によるものか不明ですが、いままでcpush時の自動チェックさえ通れば、自由に作成することができたChocolateyのパッケージにmoderatorによるapproveというものが導入され、moderatorによりapproveされないパッケージは下記のようなメッセージが表示され、信頼性の低いパッケージという位置づけになってしまいました。

This package was submitted prior to moderation and has not been approved. While it is likely safe for you, there is more risk involved.

私も2つパッケージを作っているので、なんとか正式のみなさんに安心して使って貰えるようパッケージにしたいということでJDK 8JRE 8は今のところ自分が作っているものしかないため、2つ修正して申請してみました。JDK 8はスルーされてしまっていますが、JRE 8はシェアの関係か何度かのrejectの結果、無事approveされましたので、今後ChocolateyおよびOneGetのパッケージを作成される方に参考になればと思い、approveに必要な観点を解説させて頂きます。

1. *.nuspec

*.ps1ファイルの前に、パッケージの定義で指摘を受けることがあります。

1.1. <title>と<version>

JRE 7とJRE 8のように同一製品で複数のバージョンがある場合も含めて、<title>にはバージョンを入れないように指摘を受けました。また、バージョンには個々の製品で規則がありますので、同一製品の別バージョンのパッケージがある場合、それに習いましょう。JRE 8の場合、他のJREパッケージのメンテナーからの提案もあり下記のように修正しました。

<title>Java SE Runtime Environment</title>
<version>8.0.25.03</version>

最後の.03のところはJRE自体に沿っていませんが、これはパッケージ自体に問題があった場合に同一バージョンをpushできないので苦肉の策としてつけたものです。特にここまでは文句は言われないようです。

1.2. <iconUrl>

アイコンはそれらしいのを適当に指定するのではなく、同一製品の別バージョンのパッケージと合わせる必要があります。また、フォーマットはPNGではなくSVG等ベクターフォーマットが望ましいとのことです。こちらも指摘を受けて修正しました。

2. *.ps1

2.1. ファイルの分割

インストール用のchocolateyInstall.ps1があればどのように分割しても特に問題はないようです。

2.2. Chocolatey提供APIの使用

Chocolateyが提供しているAPI(コマンドレット、関数)の機能の範疇では自分でゴリゴリ書かずにChocolateyのAPIを使用するようにという指摘がきます。

ChocolateyのAPIはChocolatey Utility Functions aka Helpers Referenceで解説されています。

例えば、JRE 8では、以下のようにクッキーとServerCertificateValidationCallbackの制御をする必要があった元々のJDK 8の制限を引き継いで”Net.WebClient”を使用していました。

function download-from-oracle($url, $output_filename) {
    if (-not (has_file($output_fileName))) {
        Write-Host "Downloading JDK from $url"
        [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
        $client = New-Object Net.WebClient
        $dummy = $client.Headers.Add('Cookie', 'gpw_e24=http://www.oracle.com; oraclelicense=accept-securebackup-cookie')
        $dummy = $client.DownloadFile($url, $output_filename)
    }
}

しかし、後述しますが、JRE 8では認証が不要なサイトでダウンロードできるようになったため、ChocolateyのAPIを使用するように指摘が来ました。下記のようにChocolateyのAPIを使うように書き換えました。

function download-from-oracle($url, $output_filename) {
    if (-not (has_file($output_fileName))) {
        Write-Host "Downloading jre from $url"
        Get-ChocolateyWebFile 'jre8' $output_fileName $url $url
    }
}

上記の”Get-ChocolateyWebFile”を使うことによって、以下の効果があります。

・ユーザーにダウンロードの進捗をプログレスパーで表示できます。これはChocolateyの標準インタフェースです。
・同一パッケージで32ビット版と64ビット版がある場合、4番目のURLの引数に64ビット版を指定すると環境に応じて自動的にダウンロードするファイルを選択してくれます。

ただし、JRE 8では64ビット環境でも32ビットJREを入れたい、64ビット環境に64ビット、32ビット両方のJREを入れたいという要望がユーザーより複数挙がったために、Chocolateyによるダウンロードの自動選択の機能は使用していません。

同じようにプラットフォームをアドホックに判断していた関数についても標準のAPIを使うよう指摘を受けました。

function use64bit() {
    $is64bitOS = (Get-WmiObject -Class Win32_ComputerSystem).SystemType -match ‘(x64)’
    return $is64bitOS
}

APIの中身を見るとそんなに凄いことしている訳ではないのですが、Chocolateyで提供している機能は徹底して使用して下さいが方針なのでまずはAPIを熟読して自分で作り込む機能を切り分けましょう。

function use64bit($Forcei586 = $false) {
    if ($Forcei586) {
        return $false
    }
    if (Test-Path (Join-Path $script_path "i586.txt")) {
        return $false
    }
    $is64bitOS = Get-ProcessorBits 64
    return $is64bitOS
}

2.3. 個人情報利用の最小化

“Get-ChocolateyWebFile”の使用の指摘には以下も含まれていました。

  • Cookie等個人情報に繋がるものは可能な限り使わなくてすむようにして下さい。

パッケージマネージャーは自動インストールに使われるものなので、特に裏で勝手にCookie等が設定されていたら不信感が募りますよね。故に本当に認証が必要で回避できない場合のみCookie等は使用するようにという方針のようです。

2.4. Chocolatey Update (cup)への対応

これは指摘を受ける前に改善したのですが、新規インストールだけでなく、Chocolatey Update (cup)によるアップデートとアップーデート後のアンインストール(前バージョンに戻す)でも正常に動作するように作っておく必要があります。

JRE 8の場合、パッケージとして別バージョンでもJRE 8のバイナリは一緒の場合があり、その場合新バージョンのバイナリをアンイストールした後、前バージョンのバイナリをアンイストールするとバイナリがなくてこけてしまう問題がありましたので、これまた苦肉の策として、こけた場合の例外を握りつぶしてアンインストールとしては正常に終了するようにしました。

try {
    Uninstall-JRE
} catch {
    # ingore exception
} finally {
    Write-ChocolateySuccess 'jre8'
}

バイナリを扱っている以上仕方ないところもありますが、ここら辺はもうちょっと洗練が必要かなと思います。

2.5. アンインストールのサポート

現在はインストールのみでアンイストールをサポートしていないパッケージが著名なものでも結構あるのですが、今後One-Getの標準リポジトリとして採用されるということを考えると、アンイストールのサポートは必須でしょう。既にJRE 8パッケージではサポートしていますが、Chocolatey APIが揃っているインストールに比べて、アンインストールのAPIは殆ど提供されておらず、以下の説明のように自分で作成するしかありません。

https://github.com/chocolatey/chocolatey/wiki/CommandsUninstall

Known Limitations

  • There are no functions defined in the chocolatey powershell module that would help with uninstall
  • There is no automatic removal of MSIs
  • Uninstall only removes the most current version of a package in the machine repository (instead of giving
  • you options to remove a certain one or all of them)
  • Requires a chocolateyUninstall.ps1 in the package itself, of which many of the currently available packages do not have.

JRE 8パッケージではインストール時にインストールしたバイナリの情報をファイルとして保存しており、その情報からアンイストールするバイナリを決定して、msiexec経由でアンインストールしています。前述したようにアンイストールをサポートしているパッケージは少なく参考にできるコードが少ないのでアンイストールの実装は試行錯誤になります。

function Uninstall-JRE {
    if (Test-Path (Join-Path $script_path "both.txt")) {
        $jre = "/qn /x {26A24AE4-039D-4CA4-87B4-2F864" + $uninstall_id + "F0}"
        Start-ChocolateyProcessAsAdmin $jre 'msiexec'
        $jre = "/qn /x {26A24AE4-039D-4CA4-87B4-2F832" + $uninstall_id + "F0}"
        Start-ChocolateyProcessAsAdmin $jre 'msiexec'
    } else {
        $use64bit = use64bit
        if ($use64bit) {
            $jre = "/qn /x {26A24AE4-039D-4CA4-87B4-2F864" + $uninstall_id + "F0}"
        } else {
            $jre = "/qn /x {26A24AE4-039D-4CA4-87B4-2F832" + $uninstall_id + "F0}"
        }
        Start-ChocolateyProcessAsAdmin $jre 'msiexec'
    }
}
try {
    Uninstall-JRE
} catch {
    # ingore exception
} finally {
    Write-ChocolateySuccess 'jre8'
}

3. 審査基準

JDK 8などダウンロード数が少ないものは再pushしても、審査のプロセスが進みませんでした。審査されるのはある程度のシェアがあるものという前提があるのかもしれません。

4. まとめ

Approvedまでの指摘と審査のプロセスのやりとりはソースコードの隅々までじっくりレビューかつ指摘してくれるというディープなもので、なかなかApprovedにならないなーと辛かったりしましたが、無料でここまでコードを指摘してくれるというのは貴重な機会であります。

Windows 10の発売後はOne-Get側で標準のリポジトリが提供され、APIや審査方法も変わってくるかもしれませんが、しばらくはChocolateyがデファクトのパッケージマネージャーのままなので、Approved Packageを作る際に本記事が参考になれば幸いです。

お次は@kazuakixさんです。

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中