ProjectScaffoldを使ってみた

最近公開したF#の式木の実行器であるFSharp.Quotations.Compilerですが、 これを作るためにProjectScaffoldを使ってみたのでその知見の共有です。

ProjectScaffoldとは

ProjectScaffoldは、F#のプロジェクトを作る際の「足場」を用意してくれるツールです。 このツールを使ってプロジェクトを作ると、

  • Paketを使った外部ライブラリの管理
  • FAKEを使ったビルドやデプロイ
  • FSharp.Formattingを使ったドキュメントの作成

と言ったことが簡単に行えるようになります。 また、F#でデファクトスタンダードなディレクトリ構成や設定になるので色々と考えなくていい*1ので楽ができます。

ProjectScaffoldについては、yukitosさんがF# Project Scaffoldを使ってプロジェクトを作成するという素晴らしい記事を書いてくれているので、 まずはそれを参考にするのがいいでしょう。

ProjectScaffoldで気を付けなければいけないこと

で、ここからが本題で、実際に使ってみて分かったことなどです。

READMEとリリースノートが固定化されている

プロジェクトが作られた直後のREADMEとリリースノートは、ProjectScaffoldのものそのままになっています。 プロジェクトを作る際に起動するコマンドの中で、少なくともREADMEのひな形を作るのに十分な情報を渡しているにもかかわらず、 作ってくれません。

そのまま公開すると残念なことになるので注意しましょう。

ライセンスが固定化されている

これは結構な罠で、選択肢もなしにUnlicenseというライセンスファイルが付いてきます。 注意しましょう。

ちなみに、FQCではCC0を選んだため、別にUnlicenseのままでもそんなに変わらない気もしますが、 それでもライセンスはある程度選択式にしてほしいところです。

.NET Frameworkのバージョンが固定化されている

これも選択肢はなく、.NET Framework 4.0、Target FSharp Core Version 4.3というちょっと古いバージョンで固定されています。

場合によっては上げたり下げたりを手動でやる必要があり、ちょっと面倒です。

Paketの扱い

ProjectScaffoldを使うと、Paketというパッケージ管理ツールを使うことになります。 これはNuGetのラッパー+αなツールなんですが、 (Paketを使わずに)NuGetを使うとビルドが壊れます。 しかも、壊れたのが分かるのはFAKE側でビルドしたときで、 Visual Studio上でビルドしている限り分かりません(し、git cleanなどをしないとFAKE側で成功するのでタチが悪いです)。

ProjectScaffoldを使う場合、NuGetを直接使うのはやめましょう。 VS上から行える「NuGet参照の追加」も、便利ですがやめましょう。 外部のライブラリを使う際は、面倒でもコマンドプロンプトを立ち上げ、 paket.exeコマンドをたたいて追加するようにします。

ちなみにこのpaket.exeですが、どうやらpaket.bootstrapper.exeが最新版を拾ってくるようになっているようです。 なので、もし.paketフォルダ内になければ、build.cmdを叩きましょう。 そうすれば落ちてきます。 ネットワークにつながっていない場合は・・・つながるところでやりましょう。

FsUnitとの相性が悪い

ProjectScaffoldはデフォルトでNUnit2.6.4を使うのですが、 これが何やらFsUnit1.3.0.1と相性が悪いようです。 FsUnitを使いたい場合は一旦NUnitNUnit.Runnersを削除し、 バージョンを指定したうえでもう一度導入してからFsUnitを導入しましょう。

.paket\paket.exe remove nuget NUnit
.paket\paket.exe remove nuget NUnit.Runners
.paket\paket.exe add nuget NUnit version 2.6.3 -i
.paket\paket.exe add nuget NUnit.Runners version 2.6.3 -i
.paket\paket.exe add nuget FsUnit -i

ここで、-iオプションを使っているので、プロジェクト毎にインストールするかどうか聞かれます。 Enterキーを押さなくてもnかyを押すだけで進むので注意してください*2

FAKEの扱い

ProjectScaffoldを使うと、FAKEというビルドツールを使うことになります。 デフォルトで用意されているターゲットに不満を感じたのですが、 詳細は忘れました。 たしか、ターゲット間の依存の設定が不十分で、あるターゲットを単独で実行したら失敗した、 とかそんな感じだったと思います。

また、Paketと同じくVisual Studioとの連携は全くありませんので、 こちら側で色々なことをやり過ぎるのはお勧めしません。 MSBuildでできることはMSBuildでやった方がいいと思います。

ドキュメントのリリース

デフォルトで用意されているReleaseDocsターゲットを使えば、ドキュメントをGitHub Pagesとして公開してくれます。 この時に、tempディレクトリにgh-pagesというディレクトリを作り、 そこにgh-pagesブランチをチェックアウトする、という方法なので、 プロジェクトのルートディレクトリを汚さないという利点があります。 しかし、これを知らないと「あれ?公開処理っぽいの走ったのにリポジトリに変更がない?」と疑問に思うかもしれないので、 別ディレクトリで処理が行われる、というのは知っておくといいでしょう。 ルートディレクトリでも、git remote updateするなりすればちゃんと落ちてきます。

追記: 別ディレクトリにcloneしてくるので、globalのGitの設定が取られてきます。 ので、リポジトリ別の設定が完全に無視されてしまいます。 これによって、会社のアカウントでドキュメントがコミットされてしまうなどの事故が起こり得ます。

まとめ?

色々言いましたが、便利は便利なので、 GitHubでF#の何かを作って公開したい、と考えている人は積極的に使っていくといいでしょう。 GitHub以外のサポートは弱いので、GitHubは嫌だ、という人は改造するなりPR投げるなりするといいでしょう。 Git以外のバージョン管理のサポートはないので、Gitは嫌だ、という人は以下略。

*1:例えば、上述のツールを使った際の.gitignoreを用意してくれたりします

*2:projectオプションを使うこともできます