diff --git a/.gitignore b/.gitignore index 65808c3..3b21e8b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,9 @@ *.iml # Local files -.local/ \ No newline at end of file +.local/ + +# Workaround for analyser issue, allow project at root +/pubspec.lock +/pubspec.yaml +/.dart_tool/ diff --git a/packages/process_run/CHANGELOG.md b/packages/process_run/CHANGELOG.md index d6d08af..703f57f 100644 --- a/packages/process_run/CHANGELOG.md +++ b/packages/process_run/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.2.0-0 + +* Export ShellBinCommand +* requires dart 3.5 + ## 1.1.0 * Remove deprecated methods diff --git a/packages/process_run/lib/process_run.dart b/packages/process_run/lib/process_run.dart index 8f3759d..c2a38f9 100644 --- a/packages/process_run/lib/process_run.dart +++ b/packages/process_run/lib/process_run.dart @@ -4,7 +4,7 @@ library; export 'package:process_run/src/shell_utils_common.dart' - show argumentsToString, argumentToString; + show argumentsToString, argumentToString, stringToArguments; export 'shell.dart'; export 'which.dart' show which, whichSync; diff --git a/packages/process_run/lib/src/bin/shell/env.dart b/packages/process_run/lib/src/bin/shell/env.dart index cddc36a..e2927ea 100644 --- a/packages/process_run/lib/src/bin/shell/env.dart +++ b/packages/process_run/lib/src/bin/shell/env.dart @@ -11,6 +11,7 @@ import 'package:process_run/src/user_config.dart'; import 'env_alias.dart'; import 'env_delete.dart'; import 'env_file_content.dart'; +import 'env_info.dart'; import 'env_path.dart'; import 'env_var.dart'; import 'import.dart'; @@ -27,7 +28,13 @@ class ShellEnvCommandBase extends ShellBinCommand { /// Local env bool get local { - final user = results[flagUser] as bool; + if (!results.wasParsed(flagUser)) { + var parent = this.parent; + if (parent is ShellEnvCommandBase) { + return parent.local; + } + } + final user = results.flag(flagUser); final local = !user; return local; } @@ -113,6 +120,8 @@ class ShellEnvCommand extends ShellEnvCommandBase { addCommand(ShellEnvAliasCommand()); addCommand(ShellEnvPathCommand()); + addCommand(ShellEnvInfoCommand()); + parser.addFlag(flagInfo, abbr: 'i', help: 'display info', negatable: false); } diff --git a/packages/process_run/lib/src/bin/shell/env_alias_delete.dart b/packages/process_run/lib/src/bin/shell/env_alias_delete.dart index eff2a17..f71c1bf 100644 --- a/packages/process_run/lib/src/bin/shell/env_alias_delete.dart +++ b/packages/process_run/lib/src/bin/shell/env_alias_delete.dart @@ -27,7 +27,7 @@ class ShellEnvAliasDeleteCommand extends ShellEnvCommandBase { stderr.writeln('At least 1 arguments expected'); exit(1); } else { - if (verbose!) { + if (verbose) { stdout.writeln('file $label: $envFilePath'); stdout.writeln('before: ${jsonEncode(ShellEnvironment().aliases)}'); } @@ -38,7 +38,7 @@ class ShellEnvAliasDeleteCommand extends ShellEnvCommandBase { modified = fileContent.deleteAlias(name) || modified; } if (modified) { - if (verbose!) { + if (verbose) { stdout.writeln('writing file'); } await fileContent.write(); @@ -46,7 +46,7 @@ class ShellEnvAliasDeleteCommand extends ShellEnvCommandBase { // Force reload shellEnvironment = null; - if (verbose!) { + if (verbose) { stdout.writeln('After: ${jsonEncode(ShellEnvironment().vars)}'); } return true; diff --git a/packages/process_run/lib/src/bin/shell/env_alias_set.dart b/packages/process_run/lib/src/bin/shell/env_alias_set.dart index 26e5fef..9ace091 100644 --- a/packages/process_run/lib/src/bin/shell/env_alias_set.dart +++ b/packages/process_run/lib/src/bin/shell/env_alias_set.dart @@ -27,7 +27,7 @@ class ShellEnvAliasSetCommand extends ShellEnvCommandBase { stderr.writeln('At least 2 arguments expected'); exit(1); } else { - if (verbose!) { + if (verbose) { stdout.writeln('file $label: $envFilePath'); stdout.writeln('before: ${jsonEncode(ShellEnvironment().aliases)}'); } @@ -39,7 +39,7 @@ class ShellEnvAliasSetCommand extends ShellEnvCommandBase { } // Force reload shellEnvironment = null; - if (verbose!) { + if (verbose) { stdout.writeln('After: ${jsonEncode(ShellEnvironment().aliases)}'); } return true; diff --git a/packages/process_run/lib/src/bin/shell/env_delete.dart b/packages/process_run/lib/src/bin/shell/env_delete.dart index 16b9af4..cf3a1f3 100644 --- a/packages/process_run/lib/src/bin/shell/env_delete.dart +++ b/packages/process_run/lib/src/bin/shell/env_delete.dart @@ -17,10 +17,10 @@ class ShellEnvDeleteCommand extends ShellEnvCommandBase { @override FutureOr onRun() async { var path = envFilePath; - if (verbose!) { + if (verbose) { stdout.writeln('envFilePath: $path'); } - var force = getFlag(flagForce)!; + var force = getFlag(flagForce); if (force || await promptConfirm('Confirm that you want to delete file ($label)')) { diff --git a/packages/process_run/lib/src/bin/shell/env_edit.dart b/packages/process_run/lib/src/bin/shell/env_edit.dart index a4c3a5b..32c04dd 100644 --- a/packages/process_run/lib/src/bin/shell/env_edit.dart +++ b/packages/process_run/lib/src/bin/shell/env_edit.dart @@ -12,7 +12,7 @@ class ShellEnvEditCommand extends ShellEnvCommandBase { @override FutureOr onRun() async { - if (verbose!) { + if (verbose) { stdout.writeln('envFilePath: $envFilePath'); } await envFileReadOrCreate(write: true); diff --git a/packages/process_run/lib/src/bin/shell/env_info.dart b/packages/process_run/lib/src/bin/shell/env_info.dart new file mode 100644 index 0000000..2856e2d --- /dev/null +++ b/packages/process_run/lib/src/bin/shell/env_info.dart @@ -0,0 +1,42 @@ +import 'package:path/path.dart'; +import 'package:process_run/src/user_config.dart'; + +import 'import.dart'; + +/// pub run process_run:shell run +class ShellEnvInfoCommand extends ShellBinCommand { + /// pub run process_run:shell run + ShellEnvInfoCommand() + : super(name: 'info', description: 'Display environment info'); + + @override + void printUsage() { + stdout.writeln('Run a command'); + stdout.writeln(); + stdout.writeln('Usage: $script env info'); + stdout.writeln(' Environment information'); + + super.printUsage(); + } + + @override + FutureOr onRun() async { + void displayInfo(String title, String path) { + var config = loadFromPath(path); + stdout.writeln('# $title'); + stdout.writeln('file: ${relative(path, from: Directory.current.path)}'); + stdout.writeln('vars: ${config.vars}'); + stdout.writeln('paths: ${config.paths}'); + } + + displayInfo('user_env', getUserEnvFilePath()!); + displayInfo('local_env', getLocalEnvFilePath()); + + return true; + } +} + +/// Direct shell env Alias dump run helper for testing. +Future main(List arguments) async { + await ShellEnvInfoCommand().parseAndRun(arguments); +} diff --git a/packages/process_run/lib/src/bin/shell/env_path.dart b/packages/process_run/lib/src/bin/shell/env_path.dart index 3771637..932213b 100644 --- a/packages/process_run/lib/src/bin/shell/env_path.dart +++ b/packages/process_run/lib/src/bin/shell/env_path.dart @@ -1,12 +1,13 @@ import 'package:process_run/src/bin/shell/env_path_dump.dart'; import 'package:process_run/src/bin/shell/env_path_prepend.dart'; +import 'env.dart'; import 'env_path_delete.dart'; import 'env_path_get.dart'; import 'import.dart'; /// Path operations -class ShellEnvPathCommand extends ShellBinCommand { +class ShellEnvPathCommand extends ShellEnvCommandBase { /// Path operations ShellEnvPathCommand() : super(name: 'path', description: 'Path operations') { addCommand(ShellEnvPathDumpCommand()); diff --git a/packages/process_run/lib/src/bin/shell/env_path_delete.dart b/packages/process_run/lib/src/bin/shell/env_path_delete.dart index 010c62a..5b73d49 100644 --- a/packages/process_run/lib/src/bin/shell/env_path_delete.dart +++ b/packages/process_run/lib/src/bin/shell/env_path_delete.dart @@ -27,7 +27,7 @@ class ShellEnvPathDeleteCommand extends ShellEnvCommandBase { stderr.writeln('At least 1 path argument expected'); exit(1); } else { - if (verbose!) { + if (verbose) { stdout.writeln('File $label: $envFilePath'); stdout.writeln('before: ${jsonEncode(ShellEnvironment().paths)}'); } @@ -37,7 +37,7 @@ class ShellEnvPathDeleteCommand extends ShellEnvCommandBase { } // Force reload shellEnvironment = null; - if (verbose!) { + if (verbose) { stdout.writeln('After: ${jsonEncode(ShellEnvironment().paths)}'); } return true; diff --git a/packages/process_run/lib/src/bin/shell/env_path_get.dart b/packages/process_run/lib/src/bin/shell/env_path_get.dart index 15d628a..07ce82b 100644 --- a/packages/process_run/lib/src/bin/shell/env_path_get.dart +++ b/packages/process_run/lib/src/bin/shell/env_path_get.dart @@ -31,7 +31,7 @@ class ShellEnvPathGetCommand extends ShellEnvCommandBase { stderr.writeln('At least 1 path argument expected'); exit(1); } else { - if (verbose!) { + if (verbose) { stdout.writeln('File $label: $envFilePath'); } dumpStringList(ShellEnvironment() diff --git a/packages/process_run/lib/src/bin/shell/env_path_prepend.dart b/packages/process_run/lib/src/bin/shell/env_path_prepend.dart index 1f08a91..d7b051f 100644 --- a/packages/process_run/lib/src/bin/shell/env_path_prepend.dart +++ b/packages/process_run/lib/src/bin/shell/env_path_prepend.dart @@ -27,7 +27,7 @@ class ShellEnvPathPrependCommand extends ShellEnvCommandBase { stderr.writeln('At least 1 path argument expected'); exit(1); } else { - if (verbose!) { + if (verbose) { stdout.writeln('before: ${jsonEncode(ShellEnvironment().paths)}'); } var fileContent = await envFileReadOrCreate(); @@ -36,7 +36,7 @@ class ShellEnvPathPrependCommand extends ShellEnvCommandBase { } // Force reload shellEnvironment = null; - if (verbose!) { + if (verbose) { stdout.writeln('After: ${jsonEncode(ShellEnvironment().paths)}'); } return true; diff --git a/packages/process_run/lib/src/bin/shell/env_var_delete.dart b/packages/process_run/lib/src/bin/shell/env_var_delete.dart index 599dee2..5bc4043 100644 --- a/packages/process_run/lib/src/bin/shell/env_var_delete.dart +++ b/packages/process_run/lib/src/bin/shell/env_var_delete.dart @@ -6,8 +6,8 @@ import 'package:process_run/src/io/io.dart'; /// Delete an environment variable from a user/local config file class ShellEnvVarDeleteCommand extends ShellEnvCommandBase { - late final _helper = ShellEnvVarDeleteIoHelper( - shell: Shell(), local: local, verbose: verbose ?? false); + late final _helper = + ShellEnvVarDeleteIoHelper(shell: Shell(), local: local, verbose: verbose); /// Delete an environment variable from a user/local config file ShellEnvVarDeleteCommand() diff --git a/packages/process_run/lib/src/bin/shell/env_var_set.dart b/packages/process_run/lib/src/bin/shell/env_var_set.dart index 0347fb4..19c78be 100644 --- a/packages/process_run/lib/src/bin/shell/env_var_set.dart +++ b/packages/process_run/lib/src/bin/shell/env_var_set.dart @@ -6,8 +6,8 @@ import 'package:process_run/src/io/io.dart'; /// Set an environment variable in a user/local config file class ShellEnvVarSetCommand extends ShellEnvCommandBase { - late final _helper = ShellEnvVarSetIoHelper( - shell: Shell(), local: local, verbose: verbose ?? false); + late final _helper = + ShellEnvVarSetIoHelper(shell: Shell(), local: local, verbose: verbose); /// Set an environment variable in a user/local config file ShellEnvVarSetCommand() diff --git a/packages/process_run/lib/src/bin/shell/run.dart b/packages/process_run/lib/src/bin/shell/run.dart index 2001a80..4537cbe 100644 --- a/packages/process_run/lib/src/bin/shell/run.dart +++ b/packages/process_run/lib/src/bin/shell/run.dart @@ -63,7 +63,7 @@ class ShellRunCommand extends ShellBinCommand { if (command == null) { exit(1); } - if (verbose!) { + if (verbose) { stdout.writeln('command: $command'); } await run(command); diff --git a/packages/process_run/lib/src/bin/shell/shell_bin_command.dart b/packages/process_run/lib/src/bin/shell/shell_bin_command.dart index 97979ba..30621df 100644 --- a/packages/process_run/lib/src/bin/shell/shell_bin_command.dart +++ b/packages/process_run/lib/src/bin/shell/shell_bin_command.dart @@ -25,7 +25,7 @@ class ShellBinCommand { bool? _verbose; /// Set before run - bool? get verbose => _verbose ??= parent?.verbose; + bool get verbose => _verbose ??= parent?.verbose ?? false; String? _description; @@ -76,12 +76,12 @@ class ShellBinCommand { /// Parse the arguments ArgResults parse(List arguments) { - // Add missing common commands - parser.addFlag(flagVersion, - help: 'Print the command version', negatable: false); - parser.addFlag(flagVerbose, - abbr: 'v', help: 'Verbose mode', negatable: false); - return results = parser.parse(arguments); + results = parser.parse(arguments); + if (parent == null) { + // Handle verbose + _verbose = getFlag(flagVerbose); + } + return results; } /// Parse and run the command @@ -100,12 +100,19 @@ class ShellBinCommand { ArgParser? parser, ShellBinCommand? parent, String? description}) { - _onRun = onRun; + //_onRun = onRun; _parser = parser; _description = description; _version = version; // read or create parser = this.parser; + // Add missing common commands + if (parent == null) { + parser.addFlag(flagVersion, + help: 'Print the command version', negatable: false); + parser.addFlag(flagVerbose, + abbr: 'v', help: 'Verbose mode', negatable: false); + } parser.addFlag(flagHelp, abbr: 'h', help: 'Usage help', negatable: false); } @@ -128,7 +135,7 @@ class ShellBinCommand { } /// Get a flag - bool? getFlag(String name) => results[name] as bool?; + bool getFlag(String name) => results.flag(name); /// Run @nonVirtual @@ -138,7 +145,7 @@ class ShellBinCommand { // Handle verbose _verbose = getFlag(flagVerbose); - final hasVersion = getFlag(flagVersion)!; + final hasVersion = getFlag(flagVersion); if (hasVersion) { stdout.writeln(version); return true; diff --git a/packages/process_run/lib/utils/shell_bin_command.dart b/packages/process_run/lib/utils/shell_bin_command.dart new file mode 100644 index 0000000..ecdc330 --- /dev/null +++ b/packages/process_run/lib/utils/shell_bin_command.dart @@ -0,0 +1 @@ +export 'package:process_run/src/mixin/shell_bin.dart'; diff --git a/packages/process_run/pubspec.yaml b/packages/process_run/pubspec.yaml index f4d5519..a7749df 100644 --- a/packages/process_run/pubspec.yaml +++ b/packages/process_run/pubspec.yaml @@ -1,5 +1,5 @@ name: process_run -version: 1.1.0 +version: 1.2.0-0 description: Process run helpers for Linux/Win/Mac and which like feature for finding executables. homepage: https://github.com/tekartik/process_run.dart/blob/master/packages/process_run diff --git a/packages/process_run/test/bin/compiled_bin_shell_test.dart b/packages/process_run/test/bin/compiled_bin_shell_test.dart new file mode 100644 index 0000000..aaccfb6 --- /dev/null +++ b/packages/process_run/test/bin/compiled_bin_shell_test.dart @@ -0,0 +1,54 @@ +@TestOn('vm') +library process_run.test.bin.shell_bin_test; + +import 'package:process_run/shell.dart'; +import 'package:process_run/src/bin/shell/import.dart'; +import 'package:pub_semver/pub_semver.dart'; +import 'package:test/test.dart'; + +import '../src/compile_shell.dart'; + +void main() { + late Shell shell; + group('compiled_bin_shell', () { + setUpAll(() async { + var dsExePath = await compileShellBin(force: false); + shell = Shell( + environment: ShellEnvironment()..aliases['ds'] = dsExePath, + verbose: false); + }); + test('version', () async { + var output = (await shell.run('ds --version')).outText.trim(); + await shell.run('ds env edit -h'); + expect(Version.parse(output), shellBinVersion); + }); + group('env', () { + group('path', () { + test('user prepend', () async { + var dummyPath = 'dummyUserPathPrepend'; + await shell.run('ds env --user path delete $dummyPath'); + var lines = (await shell.run('ds env --user path dump')).outLines; + expect(lines, isNot(contains(dummyPath))); + await shell.run('ds env --user path prepend $dummyPath'); + lines = (await shell.run('ds env --user path dump')).outLines; + expect(lines, contains(dummyPath)); + await shell.run('ds env --user path delete $dummyPath'); + lines = (await shell.run('ds env --user path dump')).outLines; + expect(lines, isNot(contains(dummyPath))); + }); + test('local prepend', () async { + var dummyPath = 'dummyLocalPathPrepend'; + await shell.run('ds env --user path delete $dummyPath'); + var lines = (await shell.run('ds env --user path dump')).outLines; + expect(lines, isNot(contains(dummyPath))); + await shell.run('ds env --user path prepend $dummyPath'); + lines = (await shell.run('ds env --user path dump')).outLines; + expect(lines, contains(dummyPath)); + await shell.run('ds env --user path delete $dummyPath'); + lines = (await shell.run('ds env --user path dump')).outLines; + expect(lines, isNot(contains(dummyPath))); + }); + }); + }); + }); +} diff --git a/packages/process_run/test/shell_bin_command_test.dart b/packages/process_run/test/shell_bin_command_test.dart new file mode 100644 index 0000000..0f9535e --- /dev/null +++ b/packages/process_run/test/shell_bin_command_test.dart @@ -0,0 +1,16 @@ +@TestOn('vm') +library; + +import 'package:process_run/utils/shell_bin_command.dart'; +import 'package:test/test.dart'; + +void main() { + test('basic', () { + var cmd = ShellBinCommand(name: 'test'); + expect(cmd.name, 'test'); + cmd.parse(['--verbose']); + expect(cmd.verbose, isTrue); + cmd.parse([]); + expect(cmd.verbose, isFalse); + }); +} diff --git a/packages/process_run/test/src/compile_shell.dart b/packages/process_run/test/src/compile_shell.dart new file mode 100644 index 0000000..5bf8ef3 --- /dev/null +++ b/packages/process_run/test/src/compile_shell.dart @@ -0,0 +1,20 @@ +import 'dart:io'; + +import 'package:path/path.dart'; +import 'package:process_run/shell.dart'; + +/// Return the executable path. +Future compileShellBin({bool force = false}) async { + var folder = + Platform.isWindows ? 'windows' : (Platform.isMacOS ? 'macos' : 'linux'); + var exeExtension = Platform.isWindows ? '.exe' : ''; + var dsExePath = join('build', folder, 'ds$exeExtension'); + var dsExeDir = dirname(dsExePath); + var shell = Shell(verbose: false); + if (!File(dsExePath).existsSync() || force) { + Directory(dsExeDir).createSync(recursive: true); + await shell.run( + 'dart compile exe ${shellArgument(join('bin', 'shell.dart'))} -o ${shellArgument(dsExePath)}'); + } + return dsExePath; +}