[Flutter] dartToolを活用していいFlutterライフを送ろう

## 経緯
Qiitaの投稿イベント始まりましたね！

以下の記事をみて、Windows環境でもやってみよーと思って
`make`コマンドを打ってみると`make`なんてコマンドは無いよとなりました。

macOSでは標準で`make`が使えるのですがWindowsだとインストールが必要みたいです。
`chocolatey`で[簡単にinstallできる](https://qiita.com/Sego-don/items/ca5d96935f464f3ad46c)とはいえ、みんなFlutterやるにあたってdart環境をつくると思うのでdartでできるようにしてみました。

https://qiita.com/isekiryu/items/67d081671fe8c9fba0b9

## 完成したソース
`/lib` 直下にtool.dartを置けば完成です。

:::note warn
fvm 以下はfvmが使える環境を想定しています
fvmを使っていない場合にはfvmは省略可能です。
:::
以下のようにコマンドを打つと<commnand>内の処理が実行されます
```shell
fvm dart tool.dart <command>
```
```tool.dart
import 'dart:io';

void main(List<String> args) async {
  final command = args.isEmpty ? 'help' : args.first;

  const colors = {
    'BLACK': '\x1B[30m',
    'RED': '\x1B[31m',
    'GREEN': '\x1B[32m',
    'YELLOW': '\x1B[33m',
    'LIGHTPURPLE': '\x1B[34m',
    'PURPLE': '\x1B[35m',
    'BLUE': '\x1B[36m',
    'WHITE': '\x1B[37m',
    'RESET': '\x1B[0m',
  };

  Future<void> runCommand(String description, List<String> command) async {
    stdout.writeln('${colors['YELLOW']}$description${colors['RESET']}');
    final process = await Process.start(command.first, command.sublist(1),
        runInShell: true);
    await stdout.addStream(process.stdout);
    await stderr.addStream(process.stderr);
    final exitCode = await process.exitCode;
    if (exitCode != 0) {
      exit(exitCode);
    }
  }

  switch (command) {
    case 'colors':
      for (var color in colors.entries) {
        if (color.key != 'RESET') {
          print('${color.value}${color.key}${colors['RESET']}');
        }
      }
      break;

    case 'setup':
      await runCommand('Setup project', [
        'fvm',
        'flutter',
        'pub',
        'get',
      ]);
      await runCommand('Build runner', [
        'fvm',
        'flutter',
        'packages',
        'pub',
        'run',
        'build_runner',
        'build',
        '--delete-conflicting-outputs',
      ]);
      break;

    case 'clean':
      await runCommand('Clean', [
        'fvm',
        'flutter',
        'clean',
      ]);
      File('pubspec.lock').deleteSync();
      break;

    case 'gen':
      await runCommand('Generate', [
        'fvm',
        'flutter',
        'packages',
        'pub',
        'run',
        'build_runner',
        'build',
        '--delete-conflicting-outputs',
      ]);
      break;

    case 'analyze':
      await runCommand('Analyze source', [
        'fvm',
        'flutter',
        'analyze',
      ]);
      break;

    case 'test':
      await runCommand('Unit Test', [
        'fvm',
        'flutter',
        'test',
      ]);
      break;

    case 'delete-generate-file':
      await runCommand('Delete generated files', [
        'find',
        '.',
        '-maxdepth',
        '20',
        '-type',
        'f',
        '-name',
        '*.freezed.dart',
        '-o',
        '-name',
        '*.g.dart',
        '-delete',
      ]);
      break;

    case 'run_dev':
      await runCommand('Run app with dev flavor', [
        'fvm',
        'flutter',
        'run',
        '-t',
        'lib/main_develop.dart',
        '--flavor',
        'develop',
      ]);
      break;

    case 'run_prod':
      await runCommand('Run app with production flavor', [
        'fvm',
        'flutter',
        'run',
        '-t',
        'lib/main_production.dart',
        '--flavor',
        'production',
      ]);
      break;

    case 'help':
    default:
      print('''
Usage: dart run tool.dart <command>

Available commands:
  colors               Show color samples
  setup                Setup project (pub get + build_runner)
  clean                Clean Flutter project and remove pubspec.lock
  gen                  Run build_runner
  analyze              Analyze Dart source
  test                 Run unit tests
  delete-generate-file Delete generated *.g.dart and *.freezed.dart
  run_dev              Run app with dev flavor
  run_prod             Run app with production flavor
''');
  }
}

```