LoginSignup
1
1

More than 1 year has passed since last update.

Swift Package コマンドプラグインの --allow-writing-to-(package-)directory オプションの動作

Posted at

概要

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 を指定するには、 capabilitypermissions.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 外にも書き込み可能になることはプラグインの作成者としても、利用者としても認識しておきたいです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1