Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9525

【メモ】C#でCLIコマンドを作成するためのライブラリ「EntryPoint」の使い方

$
0
0

C#でバッチ処理作る機会があり、ベースになるフレームワークがないかと探していたらEntryPointというライブラリを見つけました。
CLIコマンドを保守する上でとても便利なライブラリだと感じました。ですが、日本語の記事が見つからなかったので実装例をメモしておきます。

Nick-Lucas/EntryPoint
https://github.com/Nick-Lucas/EntryPoint

環境

$ dotnet --version
3.1.200

手元にwindowsがなくmacを使用しました。基本的にwindowsでも同じだと思います。
(前はwindwsでビルドしました。)

プロジェクト作成

$ dotnet new console -n QiitaEntryPoint -o QiitaEntryPoint
cd QiitaEntryPoint
dotnet add package EntryPoint

QiitaEntryPointというプロジェクトを作成し、EntryPointをnugetでインストールします。

ディレクトリ構成

$ tree
.├── CommandLine
│   ├── CliCommands.cs
│   ├── Primary
│   │   ├── PrimaryCliCommand.cs
│   │   └── PrimaryCliCommandArgs.cs
│   └── Secondary
│       └── SecondaryCliCommand.cs
├── Program.cs
└── QiitaEntryPoint.csproj

最終的には上記のようになります。
サンプルコードを参考にしつつ、コマンドの処理が膨らんでもファイルを作りやすいようにコマンドごとにディレクトリを切りました。

実装

今回はPrimaryコマンドとSecondaryコマンドを用意しました。

Primaryコマンド

Primaryコマンドの処理内容となります。
コマンドライン引数と対応したクラス「PrimaryCliCommandArgs」を引数に取ります。

PrimaryCliCommand.cs
usingSystem;namespaceQiitaEntryPoint.CommandLine.Primary{publicclassPrimaryCliCommand{publicvoidHandle(PrimaryCliCommandArgsargs){if(args.AddDay){Console.WriteLine($"Hello. {args.Message} by {DateTime.Today.ToShortDateString()}");}else{Console.WriteLine(args.Message);}}}}

こちらはPrimaryコマンドのコマンドライン引数と対応したクラスです。
「BaseCliArguments」を継承します。

PrimaryCliCommandArgs.cs
usingEntryPoint;namespaceQiitaEntryPoint.CommandLine.Primary{publicclassPrimaryCliCommandArgs:BaseCliArguments{publicPrimaryCliCommandArgs():base("Primary Command"){}[Required][OptionParameter(ShortName:'m',LongName:"message")][Help("Output message")]publicstringMessage{get;set;}[Option(ShortName:'d',LongName:"day")][Help("add execute day")]publicboolAddDay{get;set;}}}

下記のコマンドでMessageに対して"I am Engineer"がAddDayに対して"true"が入ってくるイメージです。

$ dotnet run primary ---m"I am Engineer"-d

[Required]を使用することでその引数は必須になります。

$ dotnet run primary

Arguments Error: 
The option -m/--message was not included, but is a required option

また、LongNameで引数名を指定して、ShortNameで引数の省略形を設定できます。
他にもいろいろ機能があるので以下のサンプルコードを参考にすると良いです。直感的に理解できると思います。

https://github.com/Nick-Lucas/EntryPoint/blob/master/test/Example/CommandLine/PrimaryCliArguments.cs

ヘルプを表示するとこんな感じです。

$ dotnet run primary ----help
Primary Command v1 Documentation

   Usage:
   QiitaEntryPoint [-o | --option][-p VALUE | --parameter VALUE ][ operands ]


Arguments:

   -d--day 
   add execute day

   -h--help 
   Displays Help information about arguments when set-m--message[String] 
   REQUIRED
   Output message

Secondaryコマンド

Secondaryコマンドは引数を受け取らないシンプルなコマンドとします。

SecondaryCliCommand.cs
usingSystem;namespaceQiitaEntryPoint.CommandLine.Secondary{publicclassSecondaryCliCommand{publicvoidHandle(){Console.WriteLine("Called secondaryCliCommand");}}}

処理の振り分け

このクラスは各コマンドのファサードになっており、各コマンドの処理へと振り分けを行います。
「BaseCliCommands」を継承します。

CliCommands.cs
usingEntryPoint;usingQiitaEntryPoint.CommandLine.Primary;usingQiitaEntryPoint.CommandLine.Secondary;namespaceQiitaEntryPoint.CommandLine{publicclassCliCommands:BaseCliCommands{[DefaultCommand][Command("primary")][Help("The Main command")]publicvoidPrimary(string[]args){varoptions=Cli.Parse<PrimaryCliCommandArgs>(args);varcommand=newPrimaryCliCommand();command.Handle(options);}[Command("secondary")][Help("The Secondary command")]publicvoidSecondary(string[]args){varcommand=newSecondaryCliCommand();command.Handle();}}}

ここも直感的ですが、CommandAttributeを設定することで、コマンドと処理の紐付けが行われます。
[DefaultCommand]を設定すると、コマンド名を省略したときのデフォルト操作を指定することができます。

Cli.Parse<PrimaryCliCommandArgs>(args);を実行することで、型引数にコマンドライン引数をパースしたインスタンスを取得できます。

ヘルプを表示するとこんな感じです。

$ dotnet run ----help
Commands for QiitaEntryPoint

Usage:
QiitaEntryPoint [COMMAND] [COMMAND ARGUMENTS]

For Command Help:
QiitaEntryPoint [COMMAND] --help

   PRIMARY [DEFAULT]
   The Main command

   SECONDARY
   The Secondary command

Main関数

最後にエントリーポイントを実装します。

Program.cs
usingEntryPoint;usingQiitaEntryPoint.CommandLine;namespaceQiitaEntryPoint{classProgram{staticvoidMain(string[]args){Cli.Execute<CliCommands>(args);}}}

実行

3つのパターンで実行してみます。

$ dotnet run ---m"I am Engineer"-d
Hello. I am Engineer by 2020/11/02

$ dotnet run primary ---m"I am Engineer"
I am Engineer

$ dotnet run secondary
Called secondaryCliCommand

最後に

バッチ処理の実装方法はいろいろあると思いますが、こちらのライブラリを使用することで初見にも優しいソースコードになると思います。(CommandAttributeから追えば良いので)
また、CLIコマンド特有のヘルプ処理などをAttributeで切り出すことにより、本質的な実装に集中できるとともにクリーンなコードを書くことができると感じました。

今回使用したソースコードです。
https://github.com/ishiyama0530/qiita-EntryPoint


Viewing all articles
Browse latest Browse all 9525

Trending Articles