前回の記事でラッパーコマンドの場合、ConsoleAppFramework v5へ移行する悩みを書きました。その後ConsoleAppFramework 5.4.0がリリースされ、ラッパーコマンドへの引数を渡しがサポートされました。これによってConsoleAppFramework v5でもラッパーコマンドをかけるようになったので、さくっとみてみます。
引数エスケープのサポート
5.4.0で、前回の記事でいうところの--
を使って引数を分ける方法がサポートされました。以下の例でいうと、メソッドのパラメーターである引数1・引数2と、メソッドのパラメーター外を--
で区別できます。
$ バッチA --引数1 値 --引数2 値 -- コマンドAの引数
例えば次のようなメソッド定義を用意します。エスケープされた引数を受け取るには、ConsoleAppContext
のEscapedArguments
を利用します。
using ConsoleAppFramework; var app = ConsoleApp.Create(); app.Add("", (string msg, ConsoleAppContext context) => Console.WriteLine($""" Arguments: {string.Join(" ", context.Arguments)} CommandArguments: {string.Join(" ", context.CommandArguments)} EscapedArguments: {string.Join(" ", context.EscapedArguments)} """ )); app.Run(args);
実行してみましょう。
// Output: // Arguments: --msg foo -- --hello bar --hoge moge // CommandArguments: --msg foo // EscapedArguments: --hello bar --hoge moge args = ["--msg", "foo", "--", "--hello", "bar", "--hoge", "moge"]; // Output: // Arguments: --msg foo // CommandArguments: --msg foo // EscapedArguments: args = ["--msg", "foo"]; // Output: // Arguments: --msg foo // CommandArguments: --msg foo // EscapedArguments: args = ["--msg", "foo", "--"];
ラッパーコマンドに引数を渡す
エスケープされた引数がわかっているなら、ラッパーコマンドにわたすのも簡単です。System.Diagnostics.Processでラッパーコマンドを実行するなら、Argumentsプロパティに渡せばOKです。1
using ConsoleAppFramework; using System.Diagnostics; args = ["--msg", "foo", "--", "run", "--help"]; var app = ConsoleApp.Create(); app.Add("", async (string msg, ConsoleAppContext context, CancellationToken ct = default) => { Console.WriteLine($"Starting dotnet run. {msg}"); var psi = new ProcessStartInfo() { FileName = "dotnet", Arguments = string.Join(" ", context.EscapedArguments), CreateNoWindow = true, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, }; using var process = new Process() { StartInfo = psi, }; process.OutputDataReceived += static (_, args) => Console.WriteLine(args.Data); process.ErrorDataReceived += static (_, args) => Console.WriteLine(args.Data); process.Exited += static (_, _) => Console.WriteLine("Exited"); process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); await process.WaitForExitAsync(ct); }); app.Run(args);
dotnet run --help
が実行されていることが出力からわかります。いい感じに何とかなることがわかりますね。
Starting dotnet run. foo Description: .NET Run Command Usage: dotnet run [<applicationArguments>...] [options] Arguments: <applicationArguments> Arguments passed to the application that is being run. [] Options: -c, --configuration <CONFIGURATION> The configuration to run for. The default for most projects is 'Debug'. -f, --framework <FRAMEWORK> The target framework to run for. The target framework must also be specified in the project file. -r, --runtime <RUNTIME_IDENTIFIER> The target runtime to run for. --project <project> The path to the project file to run (defaults to the current directory if there is only one project). -lp, --launch-profile <launch-profile> The name of the launch profile (if any) to use when launching the application. --no-launch-profile Do not attempt to use launchSettings.json to configure the application. --no-build Do not build the project before running. Implies --no-restore. --interactive Allows the command to stop and wait for user input or action (for example to complete authentication). --no-restore Do not restore the project before building. --sc, --self-contained Publish the .NET runtime with your application so the runtime doesn't need to be installed on the target machine. The default is 'false.' However, when targeting .NET 7 or lower, the default is 'true' if a runtime identifier is specified. --no-self-contained Publish your application as a framework dependent application. A compatible .NET runtime must be installed on the target machine to run your application. -v, --verbosity <LEVEL> Set the MSBuild verbosity level. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic]. -a, --arch <ARCH> The target architecture. --os <OS> The target operating system. --disable-build-servers Force the command to ignore any persistent build servers. --artifacts-path <ARTIFACTS_DIR> The artifacts path. All output from the project, including build, publish, and pack output, will go in subfolders under the specified path. -?, -h, --help Show command line help. Exited
5.4.0の破壊的変更
TargetFrameworkは変わってないものの、LangVersionが13まで上がっています。このため、TargetFrameworkをnet8.0
にしている場合は<LangVersion>13</LangVersion>
を追加しましょう。2
破壊的変更になるので注意です。
まとめ
ConsoleAppFramework v5にアップグレードできたのでうれしいですねぇ。エスケープされた引数を識別できるようにAPIが用意されているのも使い勝手がよく、v4よりも扱いやすくなりました。
- プロセスの実行は罠が多くこのコードも例外処理が甘いです。事情を加味するとプロセス実行にはCysharp/ProcessXを使っておくと楽です。↩
- net9.0ならLangVerisonの指定は不要です。↩