try! Swift Tokyo 2024に参加してDocCにコントリビュートしました
try! Swift Tokyo 2024
2024年3月22日〜24日、新型コロナウィルスの影響で中止となったtry! Swift Tokyo 2020から4年を経て、try! Swift Tokyoが5年ぶりに帰ってきました。ここのところ業務でSwiftをほとんど触っていないこともあって、リハビリとキャッチアップと東京旅行を兼ねて参加してきました。毎回、参加するたびに英語力のなさを痛感するのですが、それは脇に置いといて、たくさんのワクワクを体験することができました。
それぞれのセッションも素晴らしかったし、スポンサーブースも賑わっていたし、久しぶりの人たちと会うことができたし、くじ運もやたらよかったし。そして、最終日のワークショップ!
Open Source Swift Workshop
最終日(3月24日)の午後は、Open Source Swift Workshopに参加しました。Swift関連のOSSについて、課題を探して、解決して、Pull Request(PR)を出すことを目標にするという、ゴールが遠そうなワークショップです。ぼくは前回2019年にもこのワークショップに参加したのですが、当然、時間内には終わらず、でもイベントの終了後も作業を続けた結果、最終的にはPRを出してマージしてもらえたという、よい思い出があります。
前回の成果のPRたち
https://github.com/apple/swift-corelibs-foundation/pull/2046
https://github.com/apple/swift-corelibs-foundation/pull/2313
そこで今回も参加を決めていたのですが、前日になってちょっと探しても自分にできそうなことが見つからず、最悪、Swiftコンパイラのビルドができたら自分を褒めようと前日の夜からビルドに取り組んでいました(最終的にビルドはできました)。その時、Discordでビルドに関する情報を交換していた関係で、当日ワークショップの始まる前にshizさんと話していました。ぼくが「できそうなことが見つからないんですよー」と言ったら、「だったらDocCで修正方針まで検討が済んでいるイシューがあるので挑戦してみてください」と提案してもらえたので、そのイシューに挑戦することにしました。
ところが、色々と手こずりました。DocCのビルドに失敗したり(ターゲットがmacOSじゃなくてiPhoneになっていたという凡ミス😇)、そもそもDocCに普通のMarkdownを喰わせる方法がわからなくて調べたり、自分がビルドしたDocCではうまくプレビューまでできなかったり(CONTRIBUTING.mdにやり方が書かれていたのを見落としていたことに後になって気づきました🫠)途中、何度かメンターとしてまわっていたshizさんに助けてもらいました。
結果、Xcodeに付属のDocCで確かに現象が再現するという再現環境を作っただけでワークショップの時間が終わりました。つまり、shizさんがイシューを立てる前の段階に追いついただけ…。
PRを出すまで
try! Swiftから帰ってきてからも、続きの作業を行いました。
このイシューは「## テスト」のような日本語文字列の見出しがあるときに、そのアンカーを指す「<doc:SomeMarkdown#テスト>」というリンクを生成してもうまくジャンプしないというものです。
最終的に生成されるHTMLにて、リンクの方は
<a href="SomeMarkdown#%25E3%2583%2586%25E3%2582%25B9%25E3%2583%2588">
とフラグメント部分がパーセントエンコードされているのに、見出しの方のアンカーは
<h2 id="テスト">
とエンコードされていないのが原因です。
そこで、アンカーの方にもエンコードを行うようにしたいね、というのが、shizさんがイシューを立てる前に以下のforumで議論されていた内容です。
DocCは直接HTMLを生成するのではなく、ドキュメントの内容を含むJSONファイルを出力します。Vue.jsを使って作られたレンダラーがそのJSONファイルを読んでHTML DOMツリーを生成します。再現するときに出力されたJSONファイルを確認すると、その時点でリンク先URLの方はエンコードされているのに、見出しのアンカーの方はエンコードがされていないとわかりました。このJSONの出力を直せばいいことになります。
出力されるJSONのキー名などでソースコードをgrepして、その値を出力してそうなところに当たりをつけてブレークポイントを貼ります。デバッガで止まったらスタックトレースを遡ってブレークポイントを貼りながら値が作られるところを探します。そうやってアンカーが作られているところを見つけ、そこでエンコードを行うようにしました。
これでジャンプするようになるだろうと思ったのですが、やはりジャンプしません。JSONファイルをよくよく見比べてみたところ、「テスト」をパーセントエンコードするようにした結果は
%E3%83%86%E3%82%B9%E3%83%88
です。ところが、リンク先のフラグメントは
%25E3%2583%2586%25E3%2582%25B9%25E3%2583%2588
となっています。…なんてこった!実はリンク先の方にもパーセントエンコードが二重に行われているというバグがあったのです🙌
同じようにgrepとブレークポイントを駆使して、リンク先のURLを生成しているところを見つけ出します。そっちはすでにURLになっているフラグメントをさらにURLにしていることがわかりました。こちらも修正すると、期待通りリンクがジャンプするようになりました🎉
PRには修正箇所のテストケースを含めるようにCONTRIBUTING.mdに書かれていたので、テストケースも作ります。といっても、どこにどんなテストを書けばいいかわからないので、とりあえず修正した場所のクラス名と同じような名前のテストケースを見つけ、その周辺にすでにあったテストケースを参考にしながら(パクりながら)それっぽいテストケースを作りました。修正前のコードではテストケースが失敗し、修正後のコードでテストケースが通るようになることを確認したのち、ついにPRを出しました。
これが3月26日の夜。try! Swiftの2日後です。なお、このPRに残る力をすべて注いでしまったぼくは、PRを出した時点で発熱していて翌日寝込むことになりました💦(コロナ・インフルを心配しましたが、どちらも陰性でした)
PRを出してから
shizさんが「次どうすればいい?誰にレビューしてもらったらいい?」(意訳)とforumで聞いてくれたのですが、特に反応は無く、しばらくは動きがありませんでした。ですが、4月の終わり近くになってronnqvistさんがレビューを開始してくれました。とてもしっかりと見てくれて、「見出しとリンクを持つ小さいドキュメントを作って、そのレンダーされるリンクと見出しがそれぞれエンコードされていることを確認するテストケースを書いた方がいい。でもそういったテストケースは初めて書く人にはハードだから、その中心となるコードを示すよ」という感じで、実際に値を確認する部分以外のほとんどのコードを提示してくれました。
また、ぼくが修正した点についても、「very minor:」とした上で、もう少し短く書く方法などを示してくれました。その後も、何回か指摘をしてもらえて、最終的には、ぼくが修正したところもほとんどronnqvistさんが示してくれたコードに変わったような気がしますね😅
ところが、それらを修正したあとronnqvistさんがCIにテストを走らせると、なぜかテストがmacOSでもLinuxでもコケます。ぼくのローカルでは通ってるのに!(あるある)
ぼくのローカルはApple SiliconのSonomaですが、CIで使われているmacOSはIntel CPUのVenturaっぽいのでその違いでしょうか。
[Pipeline] sh
+ swift --version
swift-driver version: 1.87.3 Apple Swift version 5.9.2 (swiftlang-5.9.2.2.51 clang-1500.1.0.2.2)
Target: x86_64-apple-macosx13.0
macOSを他に用意することはできないので、LinuxのDockerイメージでも確認したところ、そちらでもテストがコケることがわかりました。とりあえず手元に再現環境を作ることに成功!
コケているところ付近にprintを入れて、テストが通るローカルmacOSとLinuxイメージで何が違うのかを確認したのち、違いがある値が作られてそうなところにまたprintを入れて…いうのを繰り返して、ようやくURL(string:)の挙動が違っているせいだと分かりました。ただ、今回直したところではなく、ronnqvistさんの提案してくれたテスト方法ではぼくの修正点までそもそも到達していないことがわかりました。
そっちにも修正を入れてみたのですが、ronnqvistさん曰く「どうやら君は別の無関係のバグを見つけたらしいね」とのこと。この修正はPRに含めなくていいということで(そもそも修正方法も正しくないっぽい)、ronnqvistさんが示してくれた回避コードをテストケースに入れて、修正の方はリバートしました。そして、CIでのテストがついに通りました!
そういうわけで、5月10日の夜(日本時間)になって、PRがマージされたのでした😭
これでぼくのtry! Swift Tokyo 2024がようやく終わった…!
おわりに
来年もtry! Swift Tokyoに参加するぞー!
この記事が気に入ったらサポートをしてみませんか?