[Dart] コマンド(CLI)ツールを作る

[Dart] コマンド(CLI)ツールを作る

2023-06-05 hit count image

Dartでコマンド(CLI)ツールを作る方法について説明します。

概要

Flutterでアプリを開発する際に、コマンド(CLI - Command Line Interface)で何かをする機能が必要になる時があります。例えば、pubspec.yamlファイルのversionをアップデートする時、直接修正することもできますが、次のようにコマンドでアップデートすることもできます。

dart run bull:pub_version --version 2.5.7

今回のブログポストではDartを使ってコマンド(CLI)ツールを作る方法について説明します。

パッケージプロジェクト生成

Dartを使ってコマンドツールを作ってpub.devにデプロイするためDartパッケージプロジェクトを生成する必要があります。pub.devにデプロイする必要がない場合、既存のプロジェクトでコマンドツールを作ることもできるので、この部分は飛ばしても構いません。

そしたら次のコマンドを実行してDartパッケージを生成します。

# dart create --template=package [PACKAGE_NAME]
dart create --template=package cli_example

プロジェクトが生成されると次のようなフォルダやファイルが生成されることが確認できます。

cli_example
├── CHANGELOG.md
├── README.md
├── analysis_options.yaml
├── example
│   └── cli_example_example.dart
├── lib
│   ├── cli_example.dart
│   └── src
│       └── cli_example_base.dart
├── pubspec.lock
├── pubspec.yaml
└── test
    └── cli_example_test.dart

argsパッケージインストール

argsパッケージはDartでコマンド(CLI)を作るのを助けるパッケージです。

argsパッケージを使うために次のコマンドを実行してargsパッケージをインストールします。

dart pub add args

Flutterプロジェクトなら次のコマンドを実行してargsパッケージをインストールします。

flutter pub add args

コマンド実装

Dartでコマンド(CLI)を作るためにはargsパッケージのCommandクラスを使う必要があります。lib/src/cli_example_base.dartファイルを開いて次のように修正します。

import 'package:args/command_runner.dart';

class Echo extends Command {
  @override
  final name = 'echo';

  @override
  final description = 'Echo option';

  Echo() {
    argParser.addOption('message', help: 'A message to echo');
  }

  @override
  void run() {
    String? message = argResults?['message'];

    // ignore: avoid_print
    print('Message: $message');
  }
}

Commandクラスを継承すると3つのメンバーをオーバーライド(Override)しなければなりません。nameはコマンドの名前で、descriptionはコマンドの説明文です。そしてrun()関数はコマンドを実装する部分です。

Commandクラスでは基本的にargParseargResults変数を使うことができます。コンストラクタ(Echo())でargParseraddOptionを使ってコマンドで必要なオプション名(message)と説明文(help)を追加しました。

そしてコマンドの実装部分であるrun()関数の中でargResults?['message']を使ってコマンドオプションに設定された値を取得し、printを使ってその内容を出力するようにしました。

実際コマンドを実装する時にはargParserに色んなオプションを追加することになり、run()関数でオプションによって色んな機能を実装することになります。

コマンド追加

libフォルド中に実装された内容は、パッケージをインストールしてDartファイルの中でパッkー次の内容を酔うんで使うことができます。つまり、わたいだちが作ってEchoはコマンドで使うことは不可能で、*.dartファイル中で使うことが可能です。

私たちが作ったEchoコマンドを*.dartファイルではなくコマンドで使うようにするためには、binフォルダを作ってEchoコマンドを実行するファイルを作る必要があります。

そしたら、binフォルダを作ってbin/cli_example.dartファイルを作って次のように修正します。

import 'package:args/command_runner.dart';
import 'package:cli_example/cli_example.dart';

void main(List<String> arguments) {
  CommandRunner(
    "cli_example",
    "Dart CLI example",
  )
    ..addCommand(Echo())
    ..run(arguments);
}

ユーザがコマンドを実行するとmain関数が実行されargumentsにユーザが入力したオプションと値が設定されます。

このファイルではargsパッケージを使って私たちが作ったEchoコマンドを登録(addCommand)して、ユーザが入力した値(arguments)と一緒に実行(run)するように構成されています。

このように作ったファイルは次のようなコマンドで実行することができます。

dart run cli_example echo --message="test"

そしたら、次のような結果が確認できます。

Message: test

私たちはargsCommandクラスを使ったので、次のようなコマンドを使うことができます。

dart run cli_example -h

そしたら次のように私たちが作成したdescriptionと`help`メッセージがうまく表示されることが確認できます。

Dart CLI example

Usage: cli_example <command> [arguments]

Global options:
-h, --help    Print this usage information.

Available commands:
  echo   Echo option

Run "cli_example help <command>" for more information about a command.

もちろん、次のようにEchoコマンドについてhelpメッセージも出力することができます。

dart run cli_example echo -h

そしたら、次のような結果が確認できます。

Echo option

Usage: cli_example echo [arguments]
-h, --help       Print this usage information.
    --message    A message to echo

例題作成

私たちが作ったコマンドパッケージをpub.devにデプロイするためには、Echoコマンドを使う例題を作る必要があります。example/cli_example_example.dartファイルを開いて次のように修正します。

import 'package:args/command_runner.dart';
import 'package:cli_example/cli_example.dart';

void main() async {
  final cmd = CommandRunner(
    "cli_example",
    "Dart CLI example",
  )..addCommand(Echo());

  await cmd.run(['echo', '--message', 'test message']);
}

私たちは現在コマンドツールを作っているので実際例題を作成する必要はありません。このファイルは逆にユーザに混乱を与える可能性があるので削除することをお勧めします。

テストコード作成

コマンドを実行した時、うまく動作したか確認するテストコードを作成することができます。テストコードを作成するためにはtest/cli_example_test.dartファイルを作って次のように修正します。

import 'package:args/command_runner.dart';
import 'package:cli_example/cli_example.dart';
import 'package:run_with_print/run_with_print.dart';
import 'package:test/test.dart';

void main() {
  final runner = CommandRunner('test', 'test')..addCommand(Echo());

  test('Echo test message', () async {
    await runWithPrint((logs) async {
      await runner.run(['echo', '--message', 'test message']);
      expect(logs, ['Message: test message']);
    });
  });
}

私たちが作ったEchoコマンドはprintを使って結果を出力します。これを確認するため次のコマンドを実行してrun_with_printパッケージをインストールします。

dart pub add --dev run_with_print

インストールが完了されたら、run_with_printrunWithPrint関数を使ってprintで出力される内容チェックします。run_with_print パッケージについては次のリンクを参考してください。

次は下記のコマンドを実行してテストコードを実行してみます。

dart test test/cli_example_test.dart

そしたら、次のようにテストがうまく実行されたことが確認できます。

00:00 +1: All tests passed!

コマンドテスト

次はこのように作ったコマンドがうまく動作することを確認して見ましょう。まずコマンドを実装したコードをGitHubに上げます。そして次のコマンドを実行してコマンドを有効化します。

dart pub global activate --source git https://github.com/dev-yakuza/cli_example

このようにGitHubに上げたコードは次のように実行することができます。

dart pub global run cli_example echo --message="test messsage"

そしたら次のようにコマンドがうまく実行されたことが確認できます。

Message: test messsage

ビルド

このように作ったコマンドは独立的な実行ファイル(Standalone executable)にすることができます。次のコマンドを実行してコマンドを独立的な実行ファイルにします。

dart compile exe bin/cli_example.dart

そしたらbinフォルダにcli_example.exeファイルが生成されることが確認できます。このように生成された実行ファイルは次のように実行することができます。

./bin/cli_example.exe echo --message="test message"

コマンドの拡張子はexeですが、このコマンドファイルはWindowsだけでなく、macOSLinuxもサポートします。

pub.devへデプロイ

このように作ったコマンドパッケージをpub.devにデプロイして使うことができます。pub.devへパッケージをデプロイする方法については次のリンクを参考してください。

公式ドキュメント参考

次はDartでコマンドを作る時、参考になる公式ドキュメントです。

完了

これでDartを使ってコマンド(CLI)ツールを作る方法について見てみました。Flutterでアプリを開発する時、Dartでプロジェクトを開発する時、特定なコマンドを作る必要がある時があります。その時、このブログポストを参考にしてコマンド(CLI)ツールを作ってみてください。

私のブログが役に立ちましたか?下にコメントを残してください。それは私にとって大きな大きな力になります!

アプリ広報

今見てるブログを作成たDekuが開発したアプリを使ってみてください。
Dekuが開発したアプリはFlutterで開発されています。

興味がある方はアプリをダウンロードしてアプリを使ってくれると本当に助かります。

Posts