Closed9

Swift Package Manager の実装を追ってみる (`swift package` 編)

Yutaka TajikaYutaka Tajika

まずは簡単そうなところからで swift package と打った時のコードを追ってみることにする。
上記コマンドを打った時の挙動としては、コマンドのヘルプが表示される。それがどのような実装になっているかを追ってみる。

エントリーポイントを見つけるため、ひとまず Sources/ を探す。

↓っぽい

https://github.com/apple/swift-package-manager/blob/swift-5.8-DEVELOPMENT-SNAPSHOT-2023-03-17-a/Sources/swift-package/main.swift

Commands というモジュールを import しているので、そこに SwiftPackageTools 型が定義されていそう。

Yutaka TajikaYutaka Tajika

/Sources/Commands/ ディレクトリを探す。
Sources/Commands/PackageTools/SwiftPackageTool.swiftSwiftPackageTool 型が定義されている。

https://github.com/apple/swift-package-manager/blob/swift-5.8-DEVELOPMENT-SNAPSHOT-2023-03-17-a/Sources/Commands/PackageTools/SwiftPackageTool.swift

コマンドのパースは Swift Argument Parser を使っている。
https://github.com/apple/swift-argument-parser

これは Swift Package Manager 側の dependencies を見ても分かる。
https://github.com/apple/swift-package-manager/blob/swift-5.8-DEVELOPMENT-SNAPSHOT-2023-03-17-a/Package.swift#L677

Yutaka TajikaYutaka Tajika

再掲 Sources/Commands/PackageTools/SwiftPackageTool.swift

https://github.com/apple/swift-package-manager/blob/swift-5.8-DEVELOPMENT-SNAPSHOT-2023-03-17-a/Sources/Commands/PackageTools/SwiftPackageTool.swift

SwiftPackageTool.main()main は Swift Argument Parser の ParsableCommand protocol で定義されているものと思われるので、ここでは定義されていない。

swift package と打った時の挙動としては、 swift package hogehoge という感じでサブコマンドを指定していないので、Swift Argument Parser でパースされると CommandConfigurationdefaultSubCommand で指定したサブコマンドが使用される。

ここでは DefaultCommand が指定されている。

https://github.com/apple/swift-package-manager/blob/swift-5.8-DEVELOPMENT-SNAPSHOT-2023-03-17-a/Sources/Commands/PackageTools/SwiftPackageTool.swift#L69

Yutaka TajikaYutaka Tajika

DefaultCommand の定義を調べてみると、同じファイルの中に定義されていることが分かる。

https://github.com/apple/swift-package-manager/blob/swift-5.8-DEVELOPMENT-SNAPSHOT-2023-03-17-a/Sources/Commands/PackageTools/SwiftPackageTool.swift#L82-L138

Swift Argument Parser でパースするコマンドなので、 ParsableCommand に準拠しているかと思いきや SwiftCommand なるものに準拠しているようなので、先にこちらが何かを調べる。

Swift Argument Parser で定義されている型ではないので、 Swift Package Manager の方で定義しているはず。

Yutaka TajikaYutaka Tajika

/Sources/CoreCommands モジュールの中に定義されている様子。

https://github.com/apple/swift-package-manager/blob/swift-5.8-DEVELOPMENT-SNAPSHOT-2023-03-17-a/Sources/CoreCommands/SwiftTool.swift#L68-L76

ParsableCommand に準拠した protocol のようで、利用する Swift の設定やワークスペースの設定など、各コマンドで共通になるように用意されているように見える。
Swift Argument Parser では run() が走るが、 run(_ swift: SwiftTool) を新たに定義し、SwiftCommand.run() の中で SwiftTool を生成し、 SwiftCommand に準拠した各サブコマンドで実装される run(_ swift: SwiftTool) を呼び出すようにしている。

https://github.com/apple/swift-package-manager/blob/swift-5.8-DEVELOPMENT-SNAPSHOT-2023-03-17-a/Sources/CoreCommands/SwiftTool.swift#L78-L98

Yutaka TajikaYutaka Tajika

初っ端に remaining を取り出している。
https://github.com/apple/swift-package-manager/blob/swift-5.8-DEVELOPMENT-SNAPSHOT-2023-03-17-a/Sources/Commands/PackageTools/SwiftPackageTool.swift#L98

remainingswift package foo bar と打った時に foobar が配列で格納されるように Swift Argument Parser によってパースされる。
https://github.com/apple/swift-package-manager/blob/swift-5.8-DEVELOPMENT-SNAPSHOT-2023-03-17-a/Sources/Commands/PackageTools/SwiftPackageTool.swift#L93-L94

そして、これがなかった時、つまり swift package だけの時に SwiftPackageTool.helpMessage() を出力して終了していそう。
https://github.com/apple/swift-package-manager/blob/swift-5.8-DEVELOPMENT-SNAPSHOT-2023-03-17-a/Sources/Commands/PackageTools/SwiftPackageTool.swift#L98-L101

これでヘルプが出力される挙動と一致しそうだが、 SwiftPackageTool.helpMessage() も一応見ておく。

Yutaka TajikaYutaka Tajika

と思ったが、これはどうやら Swift Argument Parser 側で定義されているものの様子。
SwiftPackageTool が準拠している ParsableArgument protocol で実装されているものっぽい。

https://github.com/apple/swift-argument-parser/blob/c5050aa63ed5bb23209e7120b7ff6618ee06e0ee/Sources/ArgumentParser/Parsable Types/ParsableArguments.swift#L141-L147

ということで、 swift package と打った時の挙動を追うのは一旦ここまで。

このスクラップは2023/03/25にクローズされました