概要
swift package plugin
コマンドの help を見ると、ファイルの書き込みを許可するオプションとして --allow-writing-to-package-directory
と --allow-writing-to-directory
があることがわかります。
❯ swift package plugin --help
# ...
--allow-writing-to-package-directory
Allow the plugin to write to the package directory
--allow-writing-to-directory <allow-writing-to-directory>
Allow the plugin to write to an additional directory
これらのオプションの具体的な動作について、 help を見るだけではよくわからなかったので調査しました。
注意点として、これらのオプションについてはプロポーザルに詳しい記載を見つけることができず、また Swift Package の実装を読んだわけではなく試したことをベースにこの記事を書いているので、もしかしたら勘違いが含まれているかもしれません。また、検証は以下の環境で行なっており、今後動作が変わる可能性があります。
- Xcode 14.3 Beta 2
- Swift 5.8
なにか指摘点を見つけられた方は、コメント等で教えていただけると助かります。
Swift Package プラグインについての基礎的な知識は以下の記事にまとめたので、よければ参照ください。
TL;DR
-
--allow-writing-to-package-directory
オプションをつけることで、プラグインが permission を指定しているかどうかに関わらず Package 内に書き込みができるようになる -
--allow-writing-to-directory <directory>
オプションをつけることで、Package 外にも書き込みができるようになる
サンプルプラグイン
--allow-writing-to-package-directory
/ --allow-writing-to-directory
オプションの効果を検証するために、何か適当なファイル書き込みを行うプラグインが必要なので、指定されたパスに空のディレクトリを作るだけの plugin を作りました。
maiyama18/ZatsuPlugins/CreateDirectoryPlugin
このサンプルプラグインを別の適当な Swift Package から使ってみます。 swift package init
で Package を作成し、 Package.swift
にプラグインを依存として追加します。
let package = Package(
name: "SomeSwiftPackage",
dependencies: [
.package(url: "https://github.com/maiyama18/ZatsuPlugins", branch: "main")
],
// ...
)
この状態で swift package plugin --list
コマンドを打つと、 CreateDirectoryPlugin
が使えるようになっていることがわかります。
❯ swift package plugin --list
‘create-directory’ (plugin ‘CreateDirectoryPlugin’ in package ‘ZatsuPlugins’)
--allow-writing-to-package-directory
オプション
それでは、実際にプラグインを使ってみます。まずはなにもオプションを指定せずに package 直下に tmp
ディレクトリを作ろうとしてみましょう。
❯ swift package plugin create-directory --path tmp
error: Failed to create directory: Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “tmp”." UserInfo={NSFilePath=tmp, NSUnderlyingError=0x600001ddc090 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
権限不足のために失敗してしまいました。 Swift Package コマンドプラグインは Package 内に書き込むために明示的な許可が必要になるためです。続いて、 --allow-writing-to-package-directory
オプションを指定して実行してみます。
❯ swift package plugin --allow-writing-to-package-directory create-directory --path tmp
Directory created at tmp
今度はディレクトリの作成に成功しました。これはオプションを指定したので当然のようにも思えますが、自分には少し驚きでした。というのも、プラグイン側の Package.swift
に package 内書き込みのための permission を記述する仕組みがありますが、現時点では以下のようにこの permission を指定していないためです。
プラグイン側で package 内に書き込むための permission を指定するには、 capability
の permissions
に .writeToPackageDirectory
を追加します。
.plugin(
name: "CreateDirectoryPlugin",
capability: .command(
intent: .custom(
verb: "create-directory",
description: "Create a directory"
),
+ permissions: [.writeToPackageDirectory(reason: "To create a directory")]
)
)
プラグイン定義側でこの permission を付けることで、利用側で --allow-writing-to-package-directory
なしでプラグインを実行した時の振る舞いが変わります。
❯ swift package plugin create-directory --path tmp
Plugin ‘CreateDirectoryPlugin’ wants permission to write to the package directory.
Stated reason: “To create a directory”.
Allow this plugin to write to the package directory? (yes/no) yes
Directory created at tmp
package 内に書き込むための理由を表示してくれ、 yes/no でインタラクティブにプラグインの実行判断ができるようになっていることがわかります。
当然ですが、 --allow-writing-to-package-directory
オプションをつけた場合はファイル書き込みが成功するのでプラグイン側で permission を付ける前と変わりません。
つまり、プラグイン側で付与する .writeToPackageDirectory
の permission は、あくまでプラグイン実行側で --allow-writing-to-package-directory
をつけない場合にのみ効果があり、 --allow-writing-to-package-directory
をつける場合はプラグイン側で permission を付与しているかどうかに関わらず package 内への書き込みを許すことになります。
ただ、 --allow-writing-to-package-directory
というオプション名から想像がつくかもしれませんが、書き込みができるのは package 内だけで、 package 外に書き込もうとすると権限エラーになります。
❯ swift package plugin --allow-writing-to-package-directory create-directory --path ../tmp
error: Failed to create directory: Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “tmp” in the folder “maiyama18”." UserInfo={NSFilePath=../tmp, NSUnderlyingError=0x600001674300 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
--allow-writing-to-directory
オプション
続いて、--allow-writing-to-directory
オプションについても見ていきます。 --allow-writing-to-package-directory
は package 内のどこでも書き込めるようにするオプションでしたが、 --allow-writing-to-directory
は指定したディレクトリ内にのみ書き込めるようにするオプションです。
Package 内に dir1 / dir2 というディレクトリを作成し、 --allow-writing-to-directory dir2
というオプションを指定すると、 dir1 への書き込みは失敗し、 dir2 への書き込みのみ成功するようになります。
❯ mkdir dir1 && mkdir dir2
❯ swift package plugin --allow-writing-to-directory dir2 create-directory --path dir1/tmp
error: Failed to create directory: Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “tmp” in the folder “dir1”." UserInfo={NSFilePath=dir1/tmp, NSUnderlyingError=0x6000003c0390 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
❯ swift package plugin --allow-writing-to-directory dir2 create-directory --path dir2/tmp
Directory created at dir2/tmp
さらに、 --allow-writing-to-directory
は package 外に書き込むことも可能です。親ディレクトリに書き込む例が以下です。
❯ swift package plugin --allow-writing-to-directory .. create-directory --path ../tmp
Directory created at ../tmp
なんとなく Swift Package プラグインは Package 内部にしか書き込めないと思っていましたが、とくにそういう制限はないようです。 Package 外に書き込めることでうれしい例としてぱっと思いつくものとしては、以下のようにアプリを Xcode project と Swift Package を組み合わせて作っている際に、 Swift Package に入れたコードフォーマットのプラグインを Xcode project にも適用できるというものがあります。もちろん、これは Swift Package プラグインの仕様上は理論的に可能というだけで、実際にそれができるかはコードフォーマットのプラグインの実装に依存します。
.
├── MyApp
│ ├── MyApp
│ └── MyApp.xcodeproj
└── Packages
└── MyAppPackage
いずれにしても、 Swift Package コマンドプラグインが --allow-writing-to-directory
オプションをつけることでPackage 外にも書き込み可能になることはプラグインの作成者としても、利用者としても認識しておきたいです。