Open14

artifactbundleindex について

swifttyswiftty

まず結論から
2022/11/21 現在 Xcode14.1.0 では artifactbundleindex は利用できない

swifttyswiftty

artifactbundle

mac や linux など複数環境の実行可能ファイルを artifactbundle ディレクトリにまとめたもの

<name>.artifactbundle
 ├ info.json
 ├ <artifact>
 │  ├ <variant>
 │  │  ├ <executable>
 │  │  └ <other files>
 │  └ <variant>
 │     ├ <executable>
 │     └ <other files>
 ├ <artifact>
 │  └ <variant>
 │     ├ <executable>
 │     └ <other files>
 │ <artifact>
 ┆  └┄

基本的には artifactbundleindex を気にせずこちらを利用すれば、情報量的にも問題ないはず

swifttyswiftty

artifactbundleindex

artifactbundle との違いは上記の形式だと mac で利用する場合でも全ての variant を含めたデータをダウンロードする必要がある
それを避けるために variant 毎に分割した artifactbundle を用意して、そのパスを artifactbundleindex に記載する
index ファイルは軽量な JSON なので、その後自身の variant 向けの artifactbundle のみをダウンロードすることによって通常の artifactbundle の場合より通信量を削減できる

swifttyswiftty

罠2

Xcode14.1 だと未サポート

.binaryTarget(name:url:checksum:) に切り替えてみると以下のエラーが返る

unsupported extension for binary target 'xxx'; valid extensions are: 'zip'

valid extensions are: 'zip' の部分は supportedRemoteBinaryDependencyExtensions のデータが入るので artifactbundleindex が入っていないのはおかしい

swifttyswiftty

罠3

.binaryTarget(name:url:checksum:) のチェックサムについては以下の説明がある

The checksum for each .zip file in the index is computed in the same manner as for other binary .zip files, i.e. using swift package compute-checksum. The checksum in the binary target that references the .artifactbundleindex is the checksum of the .artifactbundleindex file itself. In this way, SwiftPM can validate the integrity of any of the .zip archives referenced by the index file.

artifactbundle と同じように swift package compute-checksum を使おうとすると zip ファイルしか対応していない

error: unexpected file type; supported extensions are: zip

代わりに以下を用いてチェックサムを求める

$ shasum -a 256 path/to/target.artifactbundleindex

罠2と罠3から混乱して artifactbundleindex.zip にしたりしてみたが、それは間違っていた

swifttyswiftty

Xcode に入っている swift package の代わりに
https://github.com/apple/swift-package-manager
を利用する

Package.swift から Xcode を立ち上げ、 swift-build をビルドする

生成された swift-build をテストしたいディレクトリにコピーし、直接実行する

$ ./swift-build
swifttyswiftty

罠4

プロポーザルのドキュメントでは、フォーマットが以下の説明になっているが一部間違っている

{
    "schemaVersion": "1.0",
    "bundles": [
        {
            "fileName": "<name of .zip file containing bundle>",
            "checksum": "<checksum of .zip file>",
            "supportedTriples": [ "<triple1>", ... ]
        },
        ...
    ]
}

bundles ではなく archives が正しい

swifttyswiftty

コメントありがとうございます!

artifactsが正しいですかね?

当時の検証環境は artifactbundleindex 周りがしっかりサポートされてない雰囲気でしたので、それから変わったのかもしれませんね。

ただ先程それっぽい定義を探してみたら archives を見ているような?感じで、改めて検証できたらなと思います!
(そこが使われているかは不明ですが…)
https://github.com/apple/swift-package-manager/blob/38c5c0537d6a894d4946a49996e1be6fd93358e8/Sources/Workspace/Workspace%2BBinaryArtifacts.swift#L595-L617

swifttyswiftty

罠5

triple の指定が本来なら arm64-apple-macosx のようだが、 swift-package-manager@main を利用している関係のせいか arm64-apple-macosx12.0 とバージョンまで含めなければならなかった

swifttyswiftty

以上を直して、ビルド時にプラグインが実行されるように調整

Package.swift
    ...
    targets: [
        .binaryTarget(name: "example",
                      url: "https://github.com/swiftty/artifactbundle-example/releases/download/0.0.6/example.artifactbundleindex",
                      checksum: "12a309e590d14d94ef3cf61837eaf97b26170b41386184ca13426edbd4db1c1d"),

        .plugin(name: "Example", capability: .buildTool(), dependencies: ["example"]),
    ],
    ...

ただしまだエラーが発生している…

./swift-build
Downloading binary artifact https://github.com/swiftty/artifactbundle-example/releases/download/0.0.6/example.artifactbundle.zip
Downloaded https://github.com/swiftty/artifactbundle-example/releases/download/0.0.6/example.artifactbundle.zip (0.49s)
error: plugin process ended by an uncaught signal: 5 <command: /usr/bin/sandbox-exec -p '(version 1)
(deny default)
(import "system.sb")
(allow file-read*)
(allow process*)
(allow file-write*
    (subpath "/private/tmp")
    (subpath "/private/var/folders/p0/00x0k5494wd6hfylzdkkl4tc0000gn/T")
)
(deny file-write*
    (subpath "/Users/xxx")
)
(allow file-write*
    (subpath "/Users/xxx/.build/plugins/outputs")
    (subpath "/Users/xxx/.build/plugins/cache")
)
' /Users/xxx/.build/plugins/cache/Example>, <output:
'Swift/ErrorType.swift:200: Fatal error: Error raised at top level: Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "xcodeTargets", intValue: nil), Swift.DecodingError.Context(codingPath: [CreateBuildToolCommandsCodingKeys(stringValue: "context", intValue: nil)], debugDescription: "No value associated with key CodingKeys(stringValue: \"xcodeTargets\", intValue: nil) (\"xcodeTargets\").", underlyingError: nil))
'>

ひとまず artifactbundle 一式の取得までは成功している様子なので、新しい Xcode が出たら改めて調査を再開する

swifttyswiftty

しばらく放置していたが、 Xcode15.2 現在では artifactbundleindex が機能するようになっていた

        .binaryTarget(
            name: "example",
            url: "https://github.com/swiftty/artifactbundle-example/releases/download/0.0.8/example.artifactbundleindex",
            checksum: "75747898724a3b40239aed5a8ffdc1d69050432b9d66f51210b7b4754fb56bf0"
        ),

        .plugin(name: "Example", capability: .buildTool(), dependencies: ["example"]),

ただし、こちらのバージョンの件はまだ発生していた
https://zenn.dev/link/comments/43a01775af3547

挙動に関して apple/swift-package-manager に起票している
https://github.com/apple/swift-package-manager/issues/7362