Rubyでライセンスページを自動生成するスクリプトを書いた話

お仕事で担当しているiOSアプリでの話。

背景

アプリで使っているライブラリのライセンス情報をSettings.bundleではなくローカルにある「ライセンスページ.html (ファイル名は仮名)」 をWebView上でわざわざ表示させているのですが、そのページ管理を今まで温かみのある手作業で管理しつづけていたので、ライブラリを追加・更新するたびにいちいちこのhtmlファイルに手入れないといけない運用が怠すぎた。

下手すると古いライセンス情報を表示しつづけてしまうリスクもあったので、かなりヤバい運用方法であることを知っていながらも、タスクが忙しい、書くモチベーションがない等、言い訳しながら放置。。。😨

でもここ最近タスクが落ち着いてきてそれなりに余裕も出てきたので、今回重い腰を上げて書くことにしました。

Rubyを選んだ理由

実行環境のセットアップが不要で簡単に書けそうなスクリプト言語がないか考えていた時に 最初はシェルで書こうか悩んだのですが、RubyならMacデフォルトで環境入ってるしCocoaPodsもRubyで出来てるから親和性高そうだしこれでいいんじゃね?ってなったのでRubyにしました。

考えた生成方法

RDocを使ってAcknowledgements.markdownをhtmlに変換してライセンスページ.htmlを生成

Acknowledgements.markdownを元にRDocを使ってhtmlに変換すれば楽に書けそうだなと思い使ってみたものの

  • html変換すると勝手にヘッダー部にリンク(ページトップ、ヘッダー移動)が付与されてしまう。
  • RDoc::Optionsを使えば変換ルールを変更できるっぽい?(ここがイマイチわかってない)が実装方法がわからない
  • Ruby未経験すぎて、ドキュメント見てもチンプンカンプン。
  • RDocの情報が少ない

ということがあり、Ruby初心者にはかなりハードだったためRDocを諦めました。 また自分の手で変換処理を書こうにも、markdown構文解析処理を実装するハードルが高すぎたため、この方法を断念して次の方法を考えることにしました。

Acknowledgements.plistからjsonに変換後、必要な要素を取り出してライセンスページ.htmlを生成

Macにデフォルトでplutilというコマンドが用意されている。 これはplistファイルをCUI上で操作するためのコマンドで、フィールドの編集やplistファイルから別の拡張子ファイルに変換することもできます。

OSXの固有コマンド - MacWiki

このコマンドでjsonファイルにも変換できるので、変換されたjsonファイルをスクリプト側で呼び出してパース すればいい感じにできそうだったので、このコマンドを使って実現することにしました

ライセンスページ.htmlのテンプレートを用意

body以外の要素は使い回せるので、テンプレート.htmlを用意し、その中身をスクリプト側でライセンス情報を書き込むようにします。

自動生成スクリプトを用意

jsonファイルから必要な要素を取得してhtml要素を付けたあとにテンプレートに書き込みます。 (Ruby初心者なのでガバガバコードになってるかもしれません。)

generate_licence_page.rb

require "json"
require "fileutils"

....

# JSONファイル読み込み
json_data = File.open(JSON_RESOURCE_PATH + "Acknowledgements.json") do |i|
    JSON.load(i)
end

json = json_data["PreferenceSpecifiers"]
markup_context = ""

# Acknowledgementsヘッダーフッターを削除 (必要であれば削除しなくてよい)
json.shift()
json.pop()

# JSONデータから「FooterText」「Title」を抽出してHTMLタグを付与 (付与するタグはお好みで)
for license in json do
    title = license["Title"]
    footerText = license["FooterText"]
    headerTitle = "<h2>" + title + "</h2>"
    context = "<pre>" + footerText + "</pre>"
    markup_context = markup_context + "\n" + headerTitle + "\n" + context
end

# テンプレートをコピー
FileUtils.cp(TEMPLATE_PATH, TEMPLATE_COPY_PATH)

# コピーしたテンプレートにライセンス情報を書き込む
File.open(TEMPLATE_COPY_PATH, mode = "a") { |f|
    f.write(markup_context)
    f.write("\n</body></html>")
}

# 書き込んだファイルをライセンスページ.htmlにする
File.rename(TEMPLATE_COPY_PATH, LICENSE_PAGE_PATH)

plutilと自動生成スクリプトをpod installにフックさせる

Podfileに以下を記述。plistファイル変換先のjsonファイル名は任意でOK。

post_install do |pi|
        system('plutil -convert json Pods/Target\ Support\ Files/Pods-Project/Pods-Project-acknowledgements.plist -r -o {出力先のパス}/Acknowledgements.json')
        system('ruby {スクリプトが置いてあるファイルパス}/generate_licence_page.rb')
end

これで準備完了。あとはpod installして確認。

無事ライセンスページが自動生成されるようになり、ライブラリを追加・削除しても差分が反映されたので、これで温かみのある手作業から無事開放となりました。😇

まとめ

  • RDocで躓きはしたが、Rubyが思った以上に書きやすかった。
  • plutilが優秀だった。
  • (当たり前の話だが)コードで解決できる手作業はコードで解決すべき。なるはやで。

MacOS CatalinaでBig SurのISOイメージ作成したときに詰まった

起きたこと

ベータ版のmacOS Big SurをVMware上で動かしたかったので、このページを参考にしながら作業。

【Tips】macOS Big SurをVMware Fusionにインストールする方法 - ベータ版編 - ソフトアンテナブログ

createinstallmedia 実行したらパーティションの初期化?でエラーが発生。

 ❯ sudo /Applications/Install\ macOS\ Big\ Sur\ Beta.app/Contents/Resources/createinstallmedia --volume /Volumes/bigsur                                                                                                                                              [12:06:40]
Ready to start.
To continue we need to erase the volume at /Volumes/bigsur.
If you wish to continue type (Y) then press return: y
Erasing disk: 0%... 10%...
Error erasing disk error number (22, 0)
An error occurred erasing the disk.

調査

エラーの原因がよくわからんのでググってみたら海外のスレッドで、同じようなエラーが発生している人を発見

VirtualBox: How to create a macOS High Sierra VM to run on a Mac host system « TOBI WAS HERE!

Thanks for this! I was stuck with the problem with the first boot.

Wish I would’ve found this post earlier 🙂

I also had problems converting the .cdr.dmg to an .iso file, always kept having errors. I went around the problem by copying the file to an external drive and doing the convert from there – worked like a charm.

I also had to erase the created virtual disk in the first part of the process through the GUI since I was getting the same error as above

Erasing Disk: 0%… 10%…
Error erasing disk error number (22, 0)
A error occurred erasing the disk.

Once I erased the created partition via Disk utility GUI -> I was able to proceed.

どこかしらの手順で余計に作ってしまった仮想ディスクをアンマウントしたらエラーが解決したらしい。

やったこと

ディスクユーティリティを起動してみると、SharedSupportという仮想ディスクがマウントされていたので、これをアンマウントして再実行

 ❯ sudo /Applications/Install\ macOS\ Big\ Sur\ Beta.app/Contents/Resources/createinstallmedia --volume /Volumes/bigsur                                                                                                                                              [12:16:52]
Password:
Ready to start.
To continue we need to erase the volume at /Volumes/bigsur.
If you wish to continue type (Y) then press return: y
Erasing disk: 0%... 10%... 20%... 30%... 100%
Copying to disk: 0%... 10%... 20%... 30%... 40%... 50%... 60%... 70%... 80%... 90%... 100%
Making disk bootable...
Copying boot files...
Install media now available at "/Volumes/Install macOS Big Sur Beta"

なんとか無事に通った。

得た知見

  • ISOイメージを作るときに初期化エラーに失敗したら、ディスクユーティリティで余計なディスクマウントがされていないか確認して不要なディスクであれば消去すること。

【iOS】NavigationBarのタイトル部分のテキストスタイルを変更する

ちゃんと[NSAttributesString: Any]?型パラメータが用意されてるので、そこに必要な設定を入れたDictionaryをセットすると動くぞ!

self.navigationController?.navigationBar.titleTextAttributes = [
    .foregroundColor: UIColor.white,
    .backgroundColor: UIColor.black
]
        

結果

f:id:skouta310:20181210011706p:plain
navigationbar_title_attributed

タイトルもUILabelだからそりゃあるさ。

【iOS】UITableViewCellのセル選択ハイライトの色を変更する

UITableViewCellにはselectedBackgroundViewというプロバティが用意されてるので、そこにViewをセットするだけ!

 // ハイライトカラー設定
 let highlightedView = UIView(frame: self.frame)
 highlightedView.backgroundColor = .white
 selectedBackgroundView = UIView(frame: self.frame)

ね、簡単でしょ?

参考: selectedBackgroundView - UITableViewCell | Apple Developer Documentation

【Git】ローカルのファイルだけgitignoreしたい時の設定

Gitの管理対象外にしたいけどプロジェクト共通で設定しないといけない訳でもないファイル達(IntelliJの.ideaみたいなやつ)がある時は .git/info/excludeにgit管理させないディレクトリを書くと自動的にignoreしてくれる

$ vi .git/info/exclude

例:

 # git ls-files --others --exclude-from=.git/info/exclude
 # Lines that start with '#' are comments.
 # For a project mostly in C, the following would be a good set of
 # exclude patterns (uncomment them if you want to use them):
 # *.[oa]
 # *~

 .idea/ 

技術書典 4に行ってきました。

本日(4/22)、技術書典 4に行ってまいりました! (投稿時間過ぎちゃったけど)

本日の戦利品はこちら。

f:id:skouta310:20180422232717j:plain

色んな技術ジャンルの同人サークルが出展していて、電子工作の本だったりサーバのノウハウとかプログラミングの話をまとめられたものなど、ユニークな同人誌が沢山並んでました。

イベントはかなり大盛況で、動員数は6000人を超えたとか。すごい。

中には企業ブースもあってここでしか買えない書籍も売られていたり、あのオライリーがグッズ販売していたりここでしか買えないものも売られていました。

写真: 開場待ちしてた時の様子

f:id:skouta310:20180422231807j:plain

自分はあらかじめ行きたいサークルは決めていたものの、目を引くものが有りすぎて立ち止まって見てたりしてたので 気づいたら1〜2件ぐらい完売してしまっていて買えなかったのが残念だった点ですが、また5の時は足早に買いに行こうと思います。

今日買った本達はあとでゆっくり読んでいこうと思います。 でもこれ全部読み切れるかな・・・。いや読み切ってみせる。(読み切れないフラグ)

前の謎エラーが解決した件

前の記事の件。

musttodie.hatenablog.com

結局問題だった箇所が組み込んだ先のIB設定で、ModuleのところにFramework名をそのまま入れたら解決した。 コードにIBOutletでつないでも問題なく動いたので一件落着。

IBはFrameworkをちゃんと設定してあげないと参照できないのかな?

とりあえず自分で作ったUIのFrameworkは必ずModuleに設定すべし。