mirror of
https://github.com/chenasraf/dart_script_runner.git
synced 2026-05-17 17:48:03 +00:00
chore: improve error logging
This commit is contained in:
@@ -6,7 +6,9 @@ import 'package:script_runner/utils.dart';
|
||||
/// Main entrypoint for CMD script runner.
|
||||
Future<void> main(List<String> args) async {
|
||||
if (args.isEmpty) {
|
||||
printColor('No script command provided. Use -h to see available commands.', [TerminalColor.red]);
|
||||
printColor(
|
||||
'No script command provided. Use -h or -ls to see available commands.',
|
||||
[TerminalColor.red]);
|
||||
return;
|
||||
}
|
||||
final scriptCmd = args.first;
|
||||
@@ -15,13 +17,15 @@ Future<void> main(List<String> args) async {
|
||||
final code = await runScript(scriptCmd, scriptArgs);
|
||||
io.exit(code);
|
||||
} catch (e, stack) {
|
||||
if (e is ScriptStateError) {
|
||||
if (e is ScriptError) {
|
||||
printColor(e.toString(), [TerminalColor.red]);
|
||||
} else {
|
||||
printColor('$e\n$stack', [TerminalColor.red]);
|
||||
}
|
||||
if (e is io.ProcessException) {
|
||||
} else if (e is io.ProcessException) {
|
||||
printColor(
|
||||
'Error in script "$scriptCmd": ${e.message}', [TerminalColor.red]);
|
||||
io.exit(e.errorCode);
|
||||
} else {
|
||||
printColor('Error executing script: $e\n$stack', [TerminalColor.red]);
|
||||
io.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ Future<int> runScript(String entryName, List<String> args) async {
|
||||
final config = await ScriptRunnerConfig.get();
|
||||
|
||||
if (config.scripts.isEmpty) {
|
||||
throw ScriptStateError('No scripts found');
|
||||
throw ScriptNotFoundError('No scripts found');
|
||||
}
|
||||
|
||||
if (['-h', '--help'].contains(entryName)) {
|
||||
@@ -24,27 +24,32 @@ Future<int> runScript(String entryName, List<String> args) async {
|
||||
final entry = config.scriptsMap[entryName];
|
||||
|
||||
if (entry == null) {
|
||||
final suggestions =
|
||||
config.scriptsMap.keys.where((key) => key.toLowerCase().startsWith(entryName.toLowerCase())).toList();
|
||||
final suggestions = config.scriptsMap.keys
|
||||
.where((key) => key.toLowerCase().startsWith(entryName.toLowerCase()))
|
||||
.toList();
|
||||
|
||||
if (suggestions.isNotEmpty) {
|
||||
if (suggestions.length == 1) {
|
||||
throw ScriptStateError(
|
||||
throw ScriptNotFoundError(
|
||||
'No script named "$entryName" found. Did you mean "${suggestions.single}"?',
|
||||
);
|
||||
} else {
|
||||
throw ScriptStateError(
|
||||
throw ScriptNotFoundError(
|
||||
'No script named "$entryName" found.\n'
|
||||
'Did you mean one of: "${suggestions.join('", "')}"?',
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw ScriptStateError(
|
||||
throw ScriptNotFoundError(
|
||||
'No script named "$entryName" found.\n'
|
||||
'Available scripts: ${config.scriptsMap.keys.join('", "')}',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return entry.run(args);
|
||||
try {
|
||||
return entry.run(args);
|
||||
} catch (e, stack) {
|
||||
throw ScriptError('Error running script "$entryName": $e\n$stack');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,8 @@ class ScriptRunnerConfig {
|
||||
final sourceMap = await _tryFindConfig(fs, startDir);
|
||||
|
||||
if (sourceMap.isEmpty) {
|
||||
throw ScriptStateError('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;
|
||||
@@ -100,7 +101,9 @@ class ScriptRunnerConfig {
|
||||
List<dynamic>? scriptsRaw, {
|
||||
FileSystem? fileSystem,
|
||||
}) {
|
||||
final scripts = (scriptsRaw ?? []).map((script) => RunnableScript.fromMap(script, fileSystem: fileSystem)).toList();
|
||||
final scripts = (scriptsRaw ?? [])
|
||||
.map((script) => RunnableScript.fromMap(script, fileSystem: fileSystem))
|
||||
.toList();
|
||||
return scripts.map((s) => s..preloadScripts = scripts).toList();
|
||||
}
|
||||
|
||||
@@ -138,7 +141,8 @@ class ScriptRunnerConfig {
|
||||
(configSource?.isNotEmpty == true
|
||||
? [
|
||||
colorize(' on ', titleStyle),
|
||||
colorize(configSource!, [...titleStyle, TerminalColor.underline]),
|
||||
colorize(
|
||||
configSource!, [...titleStyle, TerminalColor.underline]),
|
||||
colorize(':', titleStyle)
|
||||
].join('')
|
||||
: ':'),
|
||||
@@ -165,10 +169,15 @@ class ScriptRunnerConfig {
|
||||
|
||||
final filtered = search.isEmpty
|
||||
? scripts
|
||||
: scripts.where((scr) => [scr.name, scr.description].any((s) => s != null && s.contains(search))).toList();
|
||||
: scripts
|
||||
.where((scr) => [scr.name, scr.description]
|
||||
.any((s) => s != null && s.contains(search)))
|
||||
.toList();
|
||||
|
||||
final mapped =
|
||||
filtered.map((scr) => TableRow(scr.name, scr.description ?? '\$ ${[scr.cmd, ...scr.args].join(' ')}')).toList();
|
||||
final mapped = filtered
|
||||
.map((scr) => TableRow(scr.name,
|
||||
scr.description ?? '\$ ${[scr.cmd, ...scr.args].join(' ')}'))
|
||||
.toList();
|
||||
|
||||
final padLen = _getPadLen(mapped.map((r) => r.name).toList(), maxLen);
|
||||
|
||||
@@ -180,7 +189,8 @@ class ScriptRunnerConfig {
|
||||
/// If [search] is provided, it filters the scripts to only those that contain the search string.
|
||||
void printBuiltins([String search = '']) {
|
||||
final builtins = [
|
||||
TableRow('-ls, --list [search]', 'List available scripts. Add search term to filter.'),
|
||||
TableRow('-ls, --list [search]',
|
||||
'List available scripts. Add search term to filter.'),
|
||||
TableRow('-h, --help', 'Print this help message'),
|
||||
];
|
||||
|
||||
@@ -197,7 +207,8 @@ class ScriptRunnerConfig {
|
||||
stripColors: true,
|
||||
wrapLine: (line) => colorize(line, [TerminalColor.gray]),
|
||||
);
|
||||
printColor(' ${scr.name.padRight(padLen, ' ')} ${lines.first}', [TerminalColor.yellow]);
|
||||
printColor(' ${scr.name.padRight(padLen, ' ')} ${lines.first}',
|
||||
[TerminalColor.yellow]);
|
||||
for (final line in lines.sublist(1)) {
|
||||
print(' ${''.padRight(padLen, ' ')} $line');
|
||||
}
|
||||
@@ -205,7 +216,8 @@ class ScriptRunnerConfig {
|
||||
}
|
||||
}
|
||||
|
||||
static Future<Map<String, Map>> _tryFindConfig(FileSystem fs, String startDir) async {
|
||||
static Future<Map<String, Map>> _tryFindConfig(
|
||||
FileSystem fs, String startDir) async {
|
||||
final explorer = Unaconfig('script_runner', fs: fs);
|
||||
final config = await explorer.search();
|
||||
if (config != null) {
|
||||
|
||||
@@ -100,7 +100,8 @@ class RunnableScript {
|
||||
env: map['env'] as Map<String, String>? ?? {},
|
||||
);
|
||||
} catch (e) {
|
||||
throw ScriptStateError('Failed to parse script, arguments: $map, $fileSystem. Error: $e');
|
||||
throw ScriptStateError(
|
||||
'Failed to parse script, arguments: $map, $fileSystem. Error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +163,8 @@ class RunnableScript {
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
String _getScriptPath() => _fileSystem.path.join(_fileSystem.systemTempDirectory.path, 'script_runner_$name.sh');
|
||||
String _getScriptPath() => _fileSystem.path
|
||||
.join(_fileSystem.systemTempDirectory.path, 'script_runner_$name.sh');
|
||||
|
||||
String _getScriptContents(
|
||||
ScriptRunnerConfig config, {
|
||||
@@ -182,8 +184,11 @@ class RunnableScript {
|
||||
].join('\n');
|
||||
case OS.linux:
|
||||
case OS.macos:
|
||||
return [...preloadScripts.map((e) => "[[ ! \$(which ${e.name}) ]] && alias ${e.name}='scr ${e.name}'"), script]
|
||||
.join('\n');
|
||||
return [
|
||||
...preloadScripts.map((e) =>
|
||||
"[[ ! \$(which ${e.name}) ]] && alias ${e.name}='scr ${e.name}'"),
|
||||
script
|
||||
].join('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,9 +135,20 @@ class TerminalColor {
|
||||
static const TerminalColor underline = TerminalColor._(4);
|
||||
}
|
||||
|
||||
class ScriptStateError extends StateError {
|
||||
ScriptStateError(super.message);
|
||||
/// An error that occurs that is related to a script.
|
||||
class ScriptError extends StateError {
|
||||
ScriptError(super.message);
|
||||
|
||||
@override
|
||||
String toString() => message;
|
||||
}
|
||||
|
||||
/// An error that occurs during script execution.
|
||||
class ScriptStateError extends ScriptError {
|
||||
ScriptStateError(super.message);
|
||||
}
|
||||
|
||||
/// An error that occurs when a script is not found.
|
||||
class ScriptNotFoundError extends ScriptError {
|
||||
ScriptNotFoundError(super.message);
|
||||
}
|
||||
|
||||
17
pubspec.yaml
17
pubspec.yaml
@@ -20,11 +20,12 @@ dev_dependencies:
|
||||
btool: any
|
||||
|
||||
script_runner:
|
||||
# line_length: 100
|
||||
scripts:
|
||||
# ================================================================================
|
||||
# Real
|
||||
# ================================================================================
|
||||
- auto-fix: dart fix --apply
|
||||
- publish: dart format .; dart pub publish; format
|
||||
- publish: dart format .; dart pub publish
|
||||
- publish:dry: dart pub publish --dry-run
|
||||
- doc: dart doc
|
||||
- name: version
|
||||
@@ -33,15 +34,13 @@ script_runner:
|
||||
- name: 'version:set'
|
||||
cmd: dart run btool set packageVersion
|
||||
display_cmd: false
|
||||
- format: dart format --line-length 120 .
|
||||
- name: clean
|
||||
cmd: rm -rf .dart_tool/pub/bin/script_runner/script_runner.dart-*.snapshot
|
||||
- name: activate-local
|
||||
cmd: scr clean && dart pub global deactivate script_runner; dart pub global activate --source path ./
|
||||
- name: activate-global
|
||||
cmd: scr clean && dart pub global deactivate script_runner; dart pub global activate script_runner
|
||||
- clean: rm -rf .dart_tool/pub/bin/script_runner/script_runner.dart-*.snapshot
|
||||
- activate-local: scr clean && dart pub global deactivate script_runner; dart pub global activate --source path ./
|
||||
- activate-global: scr clean && dart pub global deactivate script_runner; dart pub global activate script_runner
|
||||
|
||||
# ================================================================================
|
||||
# Examples
|
||||
# ================================================================================
|
||||
- name: echo1
|
||||
cmd: echo "Hello World" $SHELL
|
||||
description: Interdum a scelerisque arcu felis taciti ligula pellentesque curabitur, suspendisse adipiscing quisque sed luctus elementum in imperdiet id, praesent enim sem justo sapien diam nec. Quisque erat risus sagittis penatibus per, vehicula sociosqu cubilia convallis, sollicitudin scelerisque cras aptent. Natoque ornare dictumst netus litora mollis suspendisse cubilia proin morbi primis consequat eu massa, cursus non urna ridiculus dolor duis tempus ut nam velit lacus viverra. A interdum senectus eu mus leo aptent facilisi augue tristique ante purus condimentum pulvinar porta viverra morbi, et tellus gravida porttitor non euismod suscipit neque egestas praesent arcu luctus pharetra fusce. Luctus mauris a venenatis tempus cras ante efficitur massa ultricies mollis lacus, volutpat nisi lacinia himenaeos facilisi in aliquet sodales purus integer vitae quisque, libero torquent enim mattis placerat tortor mi dignissim viverra sem.
|
||||
|
||||
@@ -184,7 +184,8 @@ Future<void> _writeCustomConf(FileSystem fs, [String? contents]) async {
|
||||
final homeDir = fs.directory(Platform.environment['HOME']!);
|
||||
homeDir.create(recursive: true);
|
||||
fs.currentDirectory = homeDir;
|
||||
final pubFile = fs.file(path.join(fs.currentDirectory.path, 'script_runner.yaml'));
|
||||
final pubFile =
|
||||
fs.file(path.join(fs.currentDirectory.path, 'script_runner.yaml'));
|
||||
pubFile.create(recursive: true);
|
||||
print('writing custom conf to ${pubFile.path}');
|
||||
await pubFile.writeAsString(
|
||||
|
||||
Reference in New Issue
Block a user