Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

出力パスのディレクトリ保証の実装を変更する #126

Merged
merged 1 commit into from
Sep 18, 2024

Conversation

omochi
Copy link
Owner

@omochi omochi commented Sep 18, 2024

現状と課題

現在 outputDirectory/ を付け足しています。
この変更は #117 で実装されていました。

コメントによるとディレクトリであることを保証したいようですが、
これは Foundation.URL の取り扱いとしては変です。

例えば以下のように末尾スラッシュをつけると、さらにそこにファイルを結合した時に、
パス文字列にダブルスラッシュが出現してしまいます。

let dir = URL(fileURLWithPath: "dir").appending(component: "/")
let file = dir.appendingPathComponent("main.swift")
print(file.path) 
// => /Users/omochi/temp/dir//main.swift

実際、C2TSの動作ログで、ダブルスラッシュが含まれるパスが表示されてしまいます。

そもそも URL 型は、「そのパスがディレクトリかどうか」というフラグを内部で保持しています。
これは、 init時に isDirectory 引数で指定することができます。
引数を省略した場合は、ファイルシステムに問い合わせてディレクトリの実在性に基づいて設定されます。

この属性は、相対パスを解決する時などに動作に影響があります。
例えばウェブブラウザが home/index.html を表示しているときに、
login.html と書かれたリンクを踏んだ時、解決されるURLに影響します。
index.html がファイルであれば、現在居るのは home ディレクトリなので、
home/login.html が宛先になります。
もし index.html がディレクトリであれば、
現在いるのは home/index.html ディレクトリなので(拡張子から考えて不自然ですが)
home/index.html/login.html が宛先になります。

print(
    URL(
        fileURLWithPath: "login.html",
        relativeTo: URL(fileURLWithPath: "home/index.html", isDirectory: false)
    ).path
)
// => /Users/omochi/temp/home/login.html

print(
    URL(
        fileURLWithPath: "login.html",
        relativeTo: URL(fileURLWithPath: "home/index.html", isDirectory: true)
    ).path
)
// => /Users/omochi/temp/home/index.html/login.html

この relativeTo に指定したURLは baseURL プロパティとして保持されていて、
initで指定しなかった場合は暗黙にカレントディレクトリになっています。

path を使うと結合結果が得られますが、 relativePath を使うと自身のパス部分だけが得られます。

C2TSではこの relativePath を活用しているので、
relativeTo, baseURL, isDirectory も合わせて正しく使いたいです。

また URL はディレクトリを表す末尾スラッシュはパス表現としては含めず、
パスの結合操作などの際に必要に応じてスラッシュを挿入します。

ただしfileスキームのURL形式で表示する場合は、ディレクトリならば末尾スラッシュをつけます。

let file = URL(fileURLWithPath: "file", isDirectory: false)
print(file.path) // => /Users/omochi/temp/file
print(file.absoluteString) // => file:///Users/omochi/temp/file

let dir = URL(fileURLWithPath: "dir", isDirectory: true)
print(dir.path) // => /Users/omochi/temp/dir
print(dir.absoluteString) // => file:///Users/omochi/temp/dir/

自分で末尾スラッシュのパスをつけてしまうと、
pathComponents などの返す結果もちょっと変になります。
URL形式だとそれだけでダブルスラッシュになってしまいます。

let dir = URL(fileURLWithPath: "dir").appendingPathComponent("/")
print(dir.pathComponents)
// => ["/", "Users", "omochi", "temp", "dir", "/"]
print(dir.absoluteURL)
// => file:///Users/omochi/temp/dir//

これは相対パスの解決処理などに影響する可能性もあります。

修正

initで受けた outputDirectory を操作して、 isDirectorytrueURL を作り直し、それを保持するようにします。

他の案

initで受けた outputDirectoryhasDirectoryPath をみて false だったら例外を投げることを検討しました。
互換性の問題が出そうなのと、この仕様を知らないと難しいので微妙かなと思いました。

Copy link
Collaborator

@sidepelican sidepelican left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

なるほど。確かにここはディレクトリパスを保証したかっただけかつ/がpathComponentsとして扱われると気づいてなくて、/をつけることでディレクトリ扱いにしたつもりになってそうですね。
isDirectoryフラグがそのように機能していることは気づいてませんでした。勉強になります

@sidepelican sidepelican merged commit ad43c6c into main Sep 18, 2024
1 check passed
@sidepelican sidepelican deleted the fine-dir-assume branch September 18, 2024 05:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants