Skip to content

Commit

Permalink
feat: similar cmd suggestions
Browse files Browse the repository at this point in the history
  • Loading branch information
chenasraf committed Jul 21, 2024
1 parent 62a3c40 commit c6b28c9
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 45 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.7.5

- Feat: Command suggestions by prefix

## 0.7.4

- Fix: Script ENV not being passed properly
Expand Down
10 changes: 7 additions & 3 deletions bin/script_runner.dart
Original file line number Diff line number Diff line change
@@ -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<void> main(List<String> args) async {
Expand All @@ -15,7 +15,11 @@ Future<void> main(List<String> 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);
}
Expand Down
52 changes: 52 additions & 0 deletions lib/base.dart
Original file line number Diff line number Diff line change
@@ -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<int> runScript(String entryName, List<String> 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);
}

10 changes: 5 additions & 5 deletions lib/src/config.dart → lib/config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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');
}
}

Expand Down Expand Up @@ -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;
}

Expand Down
8 changes: 5 additions & 3 deletions lib/src/runnable_script.dart → lib/runnable_script.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -98,7 +100,7 @@ class RunnableScript {
env: map['env'] as Map<String, String>? ?? {},
);
} catch (e) {
throw StateError('Failed to parse script, arguments: $map, $fileSystem. Error: $e');
throw ScriptStateError('Failed to parse script, arguments: $map, $fileSystem. Error: $e');
}
}

Expand Down
6 changes: 3 additions & 3 deletions lib/script_runner.dart
Original file line number Diff line number Diff line change
@@ -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;
28 changes: 0 additions & 28 deletions lib/src/base.dart

This file was deleted.

7 changes: 7 additions & 0 deletions lib/src/utils.dart → lib/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
8 changes: 5 additions & 3 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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'
Expand Down

0 comments on commit c6b28c9

Please sign in to comment.