SDD(Sleep-Driven Development)

睡眠の重要性!!睡眠の重要性!!

Xamarin SutdioでNuGetパッケージを簡単に作る

NuGetパッケージは依存関係を自動(?)で解消してくれたりリポジトリを検索してインストールしたりで利用する分には簡単(??)なのですが、いざ作成しようとすると.nuspecを編集したりコマンド叩かなきゃいけなかったりで結構めんどくさいです。

なので簡単にNuGetパッケージを作成するXamarin Studio Addinを作成しました。

なお簡単っていっても個人運用向けで、ちゃんと公開する場合はしっかり.nuspecを編集しないといけないので結局面倒くさいです。

使い方

一番簡単な使い方。

1
からdllをダウンロードして

/Applications/Xamarin Studio.app/Contents/Resources/lib/monodevelop/AddIns

とかに入れる。

2 Xamarin Studio起動してプロジェクト開く。

3 ソリューションダブルクリックしてDescriptionに適当な文字を入れる。(ビルドしてなかったらビルドする)

f:id:crocus7724:20161018193706p:plain

4 MainMenu→Edit→Make Nuspecで.nuspecファイル作成

f:id:crocus7724:20161018193908p:plain

5 MainMenu→Edit→Make PackageでNuGetパッケージ作成

f:id:crocus7724:20161018193948p:plain

もっと詳しく

一応、上記のやり方でパッケージは作れるのですが大抵残念仕様です。なのでしっかり.nuspecを編集します。

ソリューションに追加された.nuspecファイルを見てみましょう。

<?xml version="1.0" encoding="utf-8"?>
<package>
  <metadata>
    <id>$id$</id>
    <version>$version$</version>
    <authors>$author$</authors>
    <licenseUrl>http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE</licenseUrl>
    <projectUrl>http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE</projectUrl>
    <iconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>$description$</description>
    <releaseNotes>Summary of changes made in this release of the package.</releaseNotes>
    <copyright>$copyright$</copyright>
    <tags>Tag1 Tag2</tags>
    <dependencies>
      <dependency id="Xamarin.Forms" version="2.3.1.114" />
      <dependency id="Xamarin.Android.Support.Animated.Vector.Drawable" version="23.3.0" />
      <dependency id="Xamarin.Android.Support.Design" version="23.3.0" />
      <dependency id="Xamarin.Android.Support.v4" version="23.3.0" />
      <dependency id="Xamarin.Android.Support.v7.AppCompat" version="23.3.0" />
      <dependency id="Xamarin.Android.Support.v7.CardView" version="23.3.0" />
      <dependency id="Xamarin.Android.Support.v7.MediaRouter" version="23.3.0" />
      <dependency id="Xamarin.Android.Support.v7.RecyclerView" version="23.3.0" />
      <dependency id="Xamarin.Android.Support.Vector.Drawable" version="23.3.0" />
    </dependencies>
  </metadata>
  <files>
    <file src="../Sample/bin/$Configuration$/Sample.dll" target="lib/" />
    <file src="../Sample.iOS/bin/$Configuration$/Sample.iOS.dll" target="lib/" />
    <file src="../Sample.Android/bin/$Configuration$/Sample.Android.dll" target="lib/" />
  </files>
</package>

Xamarin Studioで開くとシンタックスハイライトが全く効かないのでつらいですが見てみると$id$とか$$で囲われたのがあると思います。 これはMake Packageを実行すると対応した値に変換されます。

以下がその対応表になります。

From To Description
$id$ solution.Name ソリューションの名前
$title$ solution.Name ソリューションの名前
$version$ solution.Version ソリューションの名前
$author$ solution.AuthorInformation.Name ソリューションの製作者情報の名前
$description$ solution.Description ソリューションの詳細
$copyright$ solution.AuthorInformation.Copyright ソリューションの製作者情報のコピーライト
$Configuration$ IdeApp.Workspace.ActiveConfigurationId 現在のコンフィグ(DebugとかReleaseとか)

ただし、$hoge$はdependenciesでは使えません。そこで使うことを想定してないので書くととても残念な事になります。

また、dependencyがいっぱいありますがこれは各プロジェクトのpackages.configの中身をそのまま持ってきた感じになります。

こんな感じ↓

private static IEnumerable<XElement> GetDependencies()
            => ProjectService.CurrentSolution.GetAllProjects()
                .Where(x => File.Exists(x.BaseDirectory.Combine("packages.config")))
                .SelectMany(x => XElement.Load(x.BaseDirectory.Combine("packages.config")).Elements("package"))
                .Select(x => new XElement("dependency",
                    new XAttribute("id", x.Attribute("id").Value),
                    new XAttribute("version", x.Attribute("version").Value)))
                .Distinct(x => x.Attribute("id")?.Value);

また、filesも同じくプロジェクトをごそっと持ってきた感じになります。 こんな感じ↓

private static IEnumerable<XElement> GetFiles()
            => ProjectService.CurrentSolution.GetAllProjects()
                .Select(x => new XElement("file",
                    new XAttribute("src",
                        Path.Combine("..",
                            x.GetOutputFileName(IdeApp.Workspace.ActiveConfiguration)
                                .ToRelative(ProjectService.CurrentSolution.BaseDirectory)).Replace(
                            IdeApp.Workspace.ActiveConfigurationId, "$Configuration$")),
                    new XAttribute("target", "lib/")));

テストプロジェクトがあった場合はfilesに含まれてしまったり、全部lib/なので全プラットフォーム対象になってしまったりなのでfileは要編集です。

そしてそれぞれよしなに編集した.nuspecファイルがこちらになります。

<?xml version="1.0" encoding="utf-8"?>
<package>
  <metadata>
    <id>$id$</id>
    <version>$version$</version>
    <authors>$author$</authors>
    <licenseUrl>https://opensource.org/licenses/MIT</licenseUrl>
    <projectUrl>https://github.com/crocus7724</projectUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>$description$</description>
    <releaseNotes>First Release.</releaseNotes>
    <copyright>$copyright$</copyright>
    <tags>Xamarin, Xamarin.Forms</tags>
    <dependencies>
      <dependency id="Xamarin.Forms" version="2.3.1.114" />
    </dependencies>
  </metadata>
  <files>
    <file src="../Sample/bin/$Configuration$/Sample.dll" target="lib/portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10" />
    <file src="../Sample.iOS/bin/$Configuration$/Sample.iOS.dll" target="lib/Xamarin.iOS10" />
    <file src="../Sample.Android/bin/$Configuration$/Sample.Android.dll" target="lib/MonoAndroid10" />
  </files>
</package>

.nuspecファイルを編集した場合は⌘+Sで保存してください。残念ながらオートセーブは未実装です。

また、一応申し訳程度の設定があります。

f:id:crocus7724:20161020020910p:plain

適当英語で申し訳ないのですが、

  • 出力先ディレクトリ(Defaultだと.slnと同じ階層とか)
  • Releaseビルドを使うか($Configuration$が常時ReleaseになりますDebugって直接書いてたら意味ないオプション)
  • Make Package前にビルドするか
  • 作ったパッケージをnuget pushするか

を設定できます。

ただ、Auto Publishをする場合は事前にTerminalでnuget setapikey <key> -source <url>をする必要があります。 今回はローカルのサーバーにDockerでNuGet ServerをApiKey=nugetPublish URL=http://192.168.1.11:5001で立ててそれを使ってみました。

この場合のAPIキーの設定はこんな感じ。

nuget setapikey nuget -source http://192.168.1.11:5001

それではMake Packageをしてみましょう。

f:id:crocus7724:20161020025746p:plain

上記のようにエラーっぽいメッセージがなければ成功です。 あとはNuGetのSourcesにURLを足して

f:id:crocus7724:20161020024151p:plain

NuGetパッケージマネージャーを見てみると

f:id:crocus7724:20161020025924p:plain

追加するとちゃんとクラスも表示されているので大成功です!(もっと特徴的な名前にすればよかった)

f:id:crocus7724:20161020023311p:plain

最後に

実はこれソースコードを見ればわかるのですが裏で結構がちゃがちゃやってます(だいたいnugetのせい)。

なので結構バギーです。もしよろしければ使ってみて動かなかった場合は@crocus7724までお知らせください。