vaguely

和歌山に戻りました。ふらふらと色々なものに手を出す毎日。

【.NET Core】dotnet newの話 その1

はじめに

このブログは .NET, .NET Core, monoのランタイム・フレームワーク・ライブラリ Advent Calendar 2018 二日目の記事です。

普段気軽に実行している dotnet new コマンドですが、どんなことが行われているのかが気になったので調べてみました。

環境

  • Windows 10 ver.1803 build 17134.407
  • .NET Core 2.1.403

コマンドを実行してログを見てみる

何はともあれコマンドを実行してみます。

dotnet new console -n ConsoleSample

実行の結果作成されたファイルは下記のとおりです。

生成されたファイル

  • ConsoleSample.csproj
  • Program.cs
  • obj
    • ConsoleSample.csproj.nuget.cache
    • ConsoleSample.csproj.nuget.g.props
    • ConsoleSample.csproj.nuget.g.targets
    • project.assets.json

プロジェクトファイル( ConsoleSample.csproj )とメインクラス( Program.cs )、残りは NuGet に関連するファイルのようです。

出力されたログの内容を見てみます。

テンプレート "Console Application" が正常に作成されました。

作成後のアクションを処理しています...
'dotnet restore' を ConsoleSample\ConsoleSample.csproj で実行しています...
  C:\Users\XXX\OneDrive\Documents\workspace\ConsoleSample\ConsoleSample.csproj のパッケージを復元しています...
  MSBuild ファイル C:\Users\XXX\OneDrive\Documents\workspace\ConsoleSample\obj\ConsoleSample.csproj.nuget.g.props を生成しています。
  MSBuild ファイル C:\Users\XXX\OneDrive\Documents\workspace\ConsoleSample\obj\ConsoleSample.csproj.nuget.g.targets を生成しています。
  C:\Users\XXX\OneDrive\Documents\workspace\ConsoleSample\ConsoleSample.csproj の復元が 627.22 ms で完了しました。

正常に復元されました。

ログからわかるのは下記でしょうか。

  • dotnet new の実行完了後に自動で dotnet restore が呼ばれている
  • 下記のファイルは dotnet new で生成され、それを元に dotnet restore が行われているらしい
    • ConsoleSample.csproj
    • Program.cs
    • obj/project.assets.json
  • dotnet restore では MSBuild ファイルが生成されている

dotnet new コマンドを探す

new に限らず、 dotnet コマンド( dotnet.exe )の実態は CLI(Command Line Interface) であるようです。

https://github.com/dotnet/cli

(余談ですが、 .NETCLI というと、 Common Language Infrastructure などと混じってややこしいですね)

ということで、ここから何が行われているかを辿ってみたいと思います。

Program.cs

CLI のメインクラスは dotnet/Progarm.cs です。

ここで何をしているかというと。。。

  1. "DOTNET_CLI_CAPTURE_TIMING" という値が環境変数に設定されているかを確認します。
    例えば 1 が設定されていれば Thread1 のパフォーマンストレースが出力されるようになります。
  2. ターミナルのデフォルトの文字コードを取得して、その文字コードでログ出力するよう設定
  3. "info" や "help" などの引数が渡されているかを確認し、あれば該当の内容を出力
  4. Telemetryの設定
  5. dotnet/BuiltinCommandsCatalog.cs で、入力されたコマンドが組み込みで用意されているかを確認
  6. dotnet/BuiltInCommandMetadata.cs として、commands/dotnet-new/NewCommandShim.cs を渡す
  7. dotnet/Parser.cs の Instance.ParseFrom で、渡された引数が問題なくパースできるかを確認
  8. コマンドの実行

となるようです。

これ以降も同様ですが、多分だいぶ端折っているところがあると思いますので、詳しくはコードをたどってみてください。

なお 5.で組み込みコマンドではなかった場合、 CommandFactory/CommandFactoryUsingResolver.cs でコマンドが生成されるようですが、今回は追いかけていません。

Telemetry について

Program.cs を含め、随所に登場するのが Telemetry 関連のコードです。

dotnet new などのコマンドを実行したときの OS や .NET などのバージョン情報などを匿名で収集している、ということのようです。

このデータは Microsoft .NET Team だけでなく、私たちも利用することができるようです。

今回はやりませんが、このデータを使って何かできないかを考えてみるのも面白そうです。

なおこれを止めるには、環境変数 "DOTNET_CLI_TELEMETRY_OPTOUT" を値 1 または true で登録すると良いようです。

処理としては dotnet/Telemetry/Telemetry.cs でクライアントの登録やトラッキングするイベントの登録などを行い、 Microsoft.DotNet.Cli.Utils/TelemetryEventEntry.cs の EntryPosted で通知しているようです。

NewCommandShim.cs

ようやく dotnet new コマンドの中身に触れられるぞ!と思うも、実際にはほぼ Microsoft.TemplateEngine.Cli/New3Command.cs を呼んでいるだけです。

  1. SessionID を取得する
  2. Telemetry のログ設定
  3. Microsoft.TemplateEngine.Cli/New3Command.cs に情報を渡して実行 (New3Command.Run)

Microsoft.TemplateEngine.Cli/New3Command.cs のソースコードは下記で見ることができます。

https://github.com/dotnet/templating

New3Command.Run

3.の引数では、言語 (C#) やフレームワークのバージョン、テンプレートからプロジェクトを生成する Microsoft.TemplateEngine.Orchestrator.RunnableProjects/RunnableProjectGenerator.cs の Assembly 情報などを Host として渡しています。

他にも、 templating からコールバックで呼ばれ、(ファイルが存在する場合は) Microsoft.TemplateEngine.Edge.dll がある C:\Program Files\dotnet\sdk\2.1.403 の Templates にある .nupkg ファイルの一覧を取得し、 インストールする FirstRun などを渡しています。

インストールは Microsoft.TemplateEngine.Cli/Installer.cs で実行しており、この部分は次回追いかけてみたいと思います。

なお C:\Program Files\dotnet\sdk\2.1.403\Templates にある .nupkg ファイルは下記のとおりです。

一番関係がありそうなファイルは nunit3.dotnetnew.template 辺りでしょうか。

Visual studio Code の NuGet NuPkg Viewer で見ると、下記のような内容でした。

Metadata:
  id: NUnit3.DotNetNew.Template
  version: 1.5.1
  title: NUnit 3 template for dotnet-new
  authors: akharlov
  owners: akharlov
  requireLicenseAcceptance: 'false'
  licenseUrl: 'https://github.com/nunit/dotnet-new-nunit/blob/master/LICENSE'
  projectUrl: 'https://github.com/nunit/dotnet-new-nunit'
  iconUrl: 'https://avatars2.githubusercontent.com/u/2678858'
  description: Project and item templates containing basic NUnit 3 Test Project.
  releaseNotes: "- update nunit dependency to v3.10.1\r\n- update NUnit3TestAdapter dependency to v3.10.0\r\n- update Microsoft.NET.Test.Sdk dependency to v15.7.2\r\n- add new `--framework` supported parameters:\r\n    + .NET Framework versions (net472)\r\n- add test fixture item templates"
  copyright: Copyright © Aleksei Kharlov aka halex2005
  language: en-US
  tags: NUnit dotnet core
  packageTypes: '[object Object]'

Contents:
  - File:    _rels/.rels
  - File:    [Content_Types].xml
  - File:    Content/dotnet-new-nunit-csharp-test-item/.template.config/template.json
  - File:    Content/dotnet-new-nunit-csharp-test-item/UnitTest1.cs
  - File:    Content/dotnet-new-nunit-csharp/.template.config/dotnetcli.host.json
  - File:    Content/dotnet-new-nunit-csharp/.template.config/template.json
  - File:    Content/dotnet-new-nunit-csharp/Company.TestProject1.csproj
  - File:    Content/dotnet-new-nunit-csharp/UnitTest1.cs
  - File:    Content/dotnet-new-nunit-fsharp-test-item/.template.config/template.json
  - File:    Content/dotnet-new-nunit-fsharp-test-item/UnitTest1.fs
  - File:    Content/dotnet-new-nunit-fsharp/.template.config/dotnetcli.host.json
  - File:    Content/dotnet-new-nunit-fsharp/.template.config/template.json
  - File:    Content/dotnet-new-nunit-fsharp/Company.TestProject1.fsproj
  - File:    Content/dotnet-new-nunit-fsharp/Program.fs
  - File:    Content/dotnet-new-nunit-fsharp/UnitTest1.fs
  - File:    Content/dotnet-new-nunit-visualbasic-test-item/.template.config/template.json
  - File:    Content/dotnet-new-nunit-visualbasic-test-item/UnitTest1.vb
  - File:    Content/dotnet-new-nunit-visualbasic/.template.config/dotnetcli.host.json
  - File:    Content/dotnet-new-nunit-visualbasic/.template.config/template.json
  - File:    Content/dotnet-new-nunit-visualbasic/Company.TestProject1.vbproj
  - File:    Content/dotnet-new-nunit-visualbasic/UnitTest1.vb
  - File:    NUnit3.DotNetNew.Template.nuspec
  - File:    package/services/metadata/core-properties/cccaa6ca700c4f9193a9511aac24f9d9.psmdcp

これがどう関係してくるのか、といったところは次回追いかけてみたいと思います。

終わりに

普段何気なく使っているツールも、処理を一つ一つ追ってみると面白いですね。

ただどこかにメモっていかないとすぐこんがらがってしまうので、この記事を書いてみることにしました。

次回は dotnet/templating を追いかけてみたいと思います。

参照