From c6b28c9ec48295df039638f3f0f033e9c6dd343c Mon Sep 17 00:00:00 2001 From: Chen Asraf Date: Mon, 22 Jul 2024 01:28:02 +0300 Subject: [PATCH] feat: similar cmd suggestions --- CHANGELOG.md | 4 +++ bin/script_runner.dart | 10 ++++-- lib/base.dart | 52 ++++++++++++++++++++++++++++++ lib/{src => }/config.dart | 10 +++--- lib/{src => }/runnable_script.dart | 8 +++-- lib/script_runner.dart | 6 ++-- lib/src/base.dart | 28 ---------------- lib/{src => }/utils.dart | 7 ++++ pubspec.yaml | 8 +++-- 9 files changed, 88 insertions(+), 45 deletions(-) create mode 100644 lib/base.dart rename lib/{src => }/config.dart (96%) rename lib/{src => }/runnable_script.dart (96%) delete mode 100644 lib/src/base.dart rename lib/{src => }/utils.dart (96%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49a0e0e..a714151 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.7.5 + +- Feat: Command suggestions by prefix + ## 0.7.4 - Fix: Script ENV not being passed properly diff --git a/bin/script_runner.dart b/bin/script_runner.dart index 74bed3d..f05f257 100755 --- a/bin/script_runner.dart +++ b/bin/script_runner.dart @@ -1,7 +1,7 @@ import 'dart:io' as io; -import 'package:script_runner/src/base.dart'; -import 'package:script_runner/src/utils.dart'; +import 'package:script_runner/base.dart'; +import 'package:script_runner/utils.dart'; /// Main entrypoint for CMD script runner. Future main(List args) async { @@ -15,7 +15,11 @@ Future main(List args) async { final code = await runScript(scriptCmd, scriptArgs); io.exit(code); } catch (e, stack) { - printColor('$e\n$stack', [TerminalColor.red]); + if (e is ScriptStateError) { + printColor(e.toString(), [TerminalColor.red]); + } else { + printColor('$e\n$stack', [TerminalColor.red]); + } if (e is io.ProcessException) { io.exit(e.errorCode); } diff --git a/lib/base.dart b/lib/base.dart new file mode 100644 index 0000000..7a2a71d --- /dev/null +++ b/lib/base.dart @@ -0,0 +1,52 @@ +import 'config.dart'; +import 'utils.dart'; + +/// Runs a script with the given name, and any extra arguments. +/// Returns the exit code. +Future runScript(String entryName, List args) async { + final config = await ScriptRunnerConfig.get(); + + if (config.scripts.isEmpty) { + throw ScriptStateError('No scripts found'); + } + + if (['-h', '--help'].contains(entryName)) { + config.printUsage(); + return 0; + } + + if (['-ls', '--list'].contains(entryName)) { + final search = args.isNotEmpty ? args.first : ''; + config.printScripts(search); + return 0; + } + + final entry = config.scriptsMap[entryName]; + + if (entry == null) { + final suggestions = config.scriptsMap.keys + .where((key) => key.toLowerCase().startsWith(entryName.toLowerCase())) + .toList(); + + if (suggestions.isNotEmpty) { + if (suggestions.length == 1) { + throw ScriptStateError( + 'No script named "$entryName" found. Did you mean "${suggestions.single}"?', + ); + } else { + throw ScriptStateError( + 'No script named "$entryName" found.\n' + 'Did you mean one of: "${suggestions.join('", "')}"?', + ); + } + } else { + throw ScriptStateError( + 'No script named "$entryName" found.\n' + 'Available scripts: ${config.scriptsMap.keys.join('", "')}', + ); + } + } + + return entry.run(args); +} + diff --git a/lib/src/config.dart b/lib/config.dart similarity index 96% rename from lib/src/config.dart rename to lib/config.dart index 0132798..3702a3e 100644 --- a/lib/src/config.dart +++ b/lib/config.dart @@ -75,7 +75,7 @@ class ScriptRunnerConfig { final sourceMap = await _tryFindConfig(fs, startDir); if (sourceMap.isEmpty) { - throw StateError('Must provide scripts in either pubspec.yaml or script_runner.yaml'); + throw ScriptStateError('Must provide scripts in either pubspec.yaml or script_runner.yaml'); } final source = sourceMap.values.first; @@ -235,7 +235,7 @@ class ScriptRunnerShellConfig { }); /// Parses a shell configuration from a [YamlMap], [Map] or [String]. - /// Other types will throw a [StateError]. + /// Other types will throw a [ScriptStateError]. factory ScriptRunnerShellConfig.parse(dynamic obj) { try { if (obj is String) { @@ -252,9 +252,9 @@ class ScriptRunnerShellConfig { if (obj == null) { return ScriptRunnerShellConfig(); } - throw StateError('Invalid shell config: $obj'); + throw ScriptStateError('Invalid shell config: $obj'); } catch (e) { - throw StateError('Error while parsing config: $obj'); + throw ScriptStateError('Error while parsing config: $obj'); } } @@ -295,7 +295,7 @@ class ScriptRunnerShellConfig { } else if (Platform.isLinux) { return OS.linux; } - throw StateError('Unsupported OS: ${Platform.operatingSystem}'); + throw ScriptStateError('Unsupported OS: ${Platform.operatingSystem}'); // return OS.unknown; } diff --git a/lib/src/runnable_script.dart b/lib/runnable_script.dart similarity index 96% rename from lib/src/runnable_script.dart rename to lib/runnable_script.dart index 58dfc77..18056b1 100644 --- a/lib/src/runnable_script.dart +++ b/lib/runnable_script.dart @@ -3,9 +3,11 @@ import 'dart:io' as io; import 'package:file/file.dart'; import 'package:file/local.dart'; import 'package:file/memory.dart'; -import 'package:script_runner/src/config.dart'; + +import 'config.dart'; // ignore: no_leading_underscores_for_library_prefixes -import 'package:script_runner/src/utils.dart' as _utils; +import 'utils.dart' as _utils; +import 'utils.dart'; /// A runnable script with pre-defined name, cmd and args. May be run using the `run` command and optionally /// supplying extra arguments to pass. @@ -98,7 +100,7 @@ class RunnableScript { env: map['env'] as Map? ?? {}, ); } catch (e) { - throw StateError('Failed to parse script, arguments: $map, $fileSystem. Error: $e'); + throw ScriptStateError('Failed to parse script, arguments: $map, $fileSystem. Error: $e'); } } diff --git a/lib/script_runner.dart b/lib/script_runner.dart index 9f1409a..98aab82 100644 --- a/lib/script_runner.dart +++ b/lib/script_runner.dart @@ -1,6 +1,6 @@ /// This is the primary library used for loading and running scripts. library script_runner; -export 'src/base.dart' show runScript; -export 'src/config.dart' show ScriptRunnerConfig, ScriptRunnerShellConfig; -export 'src/runnable_script.dart' show RunnableScript; +export 'base.dart' show runScript; +export 'config.dart' show ScriptRunnerConfig, ScriptRunnerShellConfig; +export 'runnable_script.dart' show RunnableScript; diff --git a/lib/src/base.dart b/lib/src/base.dart deleted file mode 100644 index cf24c4c..0000000 --- a/lib/src/base.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:script_runner/src/config.dart'; - -/// Runs a script with the given name, and any extra arguments. -/// Returns the exit code. -Future runScript(String entryName, List args) async { - final config = await ScriptRunnerConfig.get(); - if (config.scripts.isEmpty) { - throw StateError('No scripts found'); - } - if (['-h', '--help'].contains(entryName)) { - config.printUsage(); - return 0; - } - if (['-ls', '--list'].contains(entryName)) { - final search = args.isNotEmpty ? args.first : ''; - config.printScripts(search); - return 0; - } - final entry = config.scriptsMap[entryName]; - if (entry == null) { - throw StateError( - 'No script named "$entryName" found.\n' - 'Available scripts: ${config.scriptsMap.keys.join(', ')}', - ); - } - - return entry.run(args); -} diff --git a/lib/src/utils.dart b/lib/utils.dart similarity index 96% rename from lib/src/utils.dart rename to lib/utils.dart index 4d92cb7..93f60c4 100644 --- a/lib/src/utils.dart +++ b/lib/utils.dart @@ -134,3 +134,10 @@ class TerminalColor { static const TerminalColor bold = TerminalColor._(1); static const TerminalColor underline = TerminalColor._(4); } + +class ScriptStateError extends StateError { + ScriptStateError(super.message); + + @override + String toString() => message; +} diff --git a/pubspec.yaml b/pubspec.yaml index 6d2f8f8..1b71100 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: script_runner description: Run all your project-related scripts in a portable, simple config. -version: 0.7.4 +version: 0.7.5 homepage: https://casraf.dev/projects/dart-script-runner repository: https://github.com/chenasraf/dart_script_runner license: MIT @@ -45,10 +45,12 @@ script_runner: - 'Hello World' description: test script foobar display_cmd: false + - name: clean + cmd: rm -rf .dart_tool/pub/bin/script_runner/script_runner.dart-*.snapshot - name: activate-local - cmd: dart pub global activate --source path ./ + cmd: scr clean && dart pub global deactivate script_runner; dart pub global activate --source path ./ - name: activate-global - cmd: dart pub global activate script_runner + cmd: scr clean && dart pub global deactivate script_runner; dart pub global activate script_runner - name: combined cmd: echo 'test' && echo1 && echo2 - short: echo 'this is a short script'