chore: improve error logging

This commit is contained in:
2024-07-22 01:40:47 +03:00
parent c192e6c843
commit 74e1674fdf
7 changed files with 75 additions and 38 deletions

View File

@@ -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);
}
}
}

View File

@@ -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');
}
}

View File

@@ -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) {

View File

@@ -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');
}
}
}

View File

@@ -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);
}

View File

@@ -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.

View File

@@ -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(