From 617d79de70ef6d9e7fe5fd338e02e491aa734ba5 Mon Sep 17 00:00:00 2001 From: tom Date: Mon, 13 Oct 2025 11:03:03 +1000 Subject: [PATCH 1/4] Updated completion install so that it supports multiple ShellRC file options and will use the first one it finds. --- .../installer/completion_installation.dart | 19 +++++- .../shell_completion_configuration.dart | 13 ++-- .../completion_installation_test.dart | 67 +++++++++++++++++++ .../shell_completion_configuration_test.dart | 12 ++-- 4 files changed, 100 insertions(+), 11 deletions(-) diff --git a/lib/src/installer/completion_installation.dart b/lib/src/installer/completion_installation.dart index b0e0943..d46b98a 100644 --- a/lib/src/installer/completion_installation.dart +++ b/lib/src/installer/completion_installation.dart @@ -274,8 +274,23 @@ class CompletionInstallation { ); } - String get _shellRCFilePath => - _resolveHome(configuration!.shellRCFile, environment); + + String? __shellRCFilePath; + String get _shellRCFilePath { + String? firstPath; + if(__shellRCFilePath == null){ + for(final fileName in configuration!.shellRCFiles){ + final filePath = _resolveHome(fileName, environment); + firstPath ??= filePath; + if(File(filePath).existsSync()){ + __shellRCFilePath = filePath; + return __shellRCFilePath!; + } + } + __shellRCFilePath = firstPath; + } + return __shellRCFilePath!; + } /// Write a source to the completion global script in the shell configuration /// file, which its location is described by the [configuration]. diff --git a/lib/src/installer/shell_completion_configuration.dart b/lib/src/installer/shell_completion_configuration.dart index ee19dca..99f3886 100644 --- a/lib/src/installer/shell_completion_configuration.dart +++ b/lib/src/installer/shell_completion_configuration.dart @@ -22,7 +22,7 @@ class ShellCompletionConfiguration { /// {@macro shell_completion_configuration} const ShellCompletionConfiguration._({ required this.shell, - required this.shellRCFile, + required this.shellRCFiles, required this.sourceLineTemplate, required this.scriptTemplate, }); @@ -42,9 +42,12 @@ class ShellCompletionConfiguration { /// {@macro system_shell} final SystemShell shell; - /// The location of a config file that is run upon shell start. + /// A preferential ordered list of locations of a config file that is run upon + /// shell start. The list is to allow multiple options eg both .bash_profile + /// and .bashrc. The first option will be tried first and and if the file + /// doesn't exist the next one will be tried. /// Eg: .bash_profile or .zshrc - final String shellRCFile; + final List shellRCFiles; /// Generates a line to sources of a script file. final SourceStringTemplate sourceLineTemplate; @@ -61,7 +64,7 @@ class ShellCompletionConfiguration { @visibleForTesting final zshConfiguration = ShellCompletionConfiguration._( shell: SystemShell.zsh, - shellRCFile: '~/.zshrc', + shellRCFiles: const ['~/.zshrc'], sourceLineTemplate: (String scriptPath) { return '[[ -f $scriptPath ]] && . $scriptPath || true'; }, @@ -94,7 +97,7 @@ fi @visibleForTesting final bashConfiguration = ShellCompletionConfiguration._( shell: SystemShell.bash, - shellRCFile: '~/.bash_profile', + shellRCFiles: const ['~/.bashrc','~/.bash_profile'], sourceLineTemplate: (String scriptPath) { return '[ -f $scriptPath ] && . $scriptPath || true'; }, diff --git a/test/src/installer/completion_installation_test.dart b/test/src/installer/completion_installation_test.dart index aefea0b..03fd1f6 100644 --- a/test/src/installer/completion_installation_test.dart +++ b/test/src/installer/completion_installation_test.dart @@ -727,6 +727,73 @@ void main() { ); }, ); + + test( + 'installing completion for .bashrc', + () { + + final bashInstallation = CompletionInstallation( + logger: logger, + isWindows: false, + environment: { + 'HOME': tempDir.path, + }, + configuration: bashConfiguration, + ); + + final configDir = bashInstallation.completionConfigDir; + + final bashProfile = File(path.join(tempDir.path, '.bash_profile')) + ..createSync(); + + bashInstallation + .install('very_good'); + + // Different format needed for matching cli output + expect(bashProfile.readAsStringSync(), ''' +\n## [Completion] +## Completion scripts setup. Remove the following line to uninstall +[ -f ${configDir.path}/bash-config.bash ] && . ${configDir.path}/bash-config.bash || true +## [/Completion] + +'''); + + }, + ); + + test( + 'installing completion for .bash_profile', + () { + + final bashInstallation = CompletionInstallation( + logger: logger, + isWindows: false, + environment: { + 'HOME': tempDir.path, + }, + configuration: bashConfiguration, + ); + + final configDir = bashInstallation.completionConfigDir; + + final bashRc = File(path.join(tempDir.path, '.bashrc')) + ..createSync(); + + bashInstallation + .install('very_good'); + + // Different format needed for matching cli output + expect(bashRc.readAsStringSync(), ''' +\n## [Completion] +## Completion scripts setup. Remove the following line to uninstall +[ -f ${configDir.path}/bash-config.bash ] && . ${configDir.path}/bash-config.bash || true +## [/Completion] + +'''); + + }, + ); + }); group('uninstall', () { diff --git a/test/src/installer/shell_completion_configuration_test.dart b/test/src/installer/shell_completion_configuration_test.dart index 1e885aa..5726471 100644 --- a/test/src/installer/shell_completion_configuration_test.dart +++ b/test/src/installer/shell_completion_configuration_test.dart @@ -16,8 +16,8 @@ void main() { expect(zshConfiguration.shell, SystemShell.zsh); }); - test('shellRCFile', () { - expect(zshConfiguration.shellRCFile, '~/.zshrc'); + test('shellRCFiles', () { + expect(zshConfiguration.shellRCFiles.first, '~/.zshrc'); }); test('sourceStringTemplate', () { @@ -68,8 +68,12 @@ fi expect(bashConfiguration.shell, SystemShell.bash); }); - test('shellRCFile', () { - expect(bashConfiguration.shellRCFile, '~/.bash_profile'); + test('shellRCFiles first', () { + expect(bashConfiguration.shellRCFiles.first, '~/.bashrc'); + }); + + test('shellRCFiles last', () { + expect(bashConfiguration.shellRCFiles.last, '~/.bash_profile'); }); test('sourceStringTemplate', () { From 577d271c5fd89d4474eb56c650a17aaf30af3334 Mon Sep 17 00:00:00 2001 From: tom Date: Mon, 13 Oct 2025 12:47:56 +1000 Subject: [PATCH 2/4] Added tests and updated missing files message. --- .../installer/completion_installation.dart | 11 ++++++- .../completion_installation_test.dart | 32 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/lib/src/installer/completion_installation.dart b/lib/src/installer/completion_installation.dart index d46b98a..e41d92a 100644 --- a/lib/src/installer/completion_installation.dart +++ b/lib/src/installer/completion_installation.dart @@ -275,6 +275,7 @@ class CompletionInstallation { } + final _missingFiles = []; String? __shellRCFilePath; String get _shellRCFilePath { String? firstPath; @@ -286,6 +287,7 @@ class CompletionInstallation { __shellRCFilePath = filePath; return __shellRCFilePath!; } + _missingFiles.add(filePath); } __shellRCFilePath = firstPath; } @@ -305,9 +307,16 @@ class CompletionInstallation { final shellRCFile = File(_shellRCFilePath); if (!shellRCFile.existsSync()) { + var message = ''; + if(_missingFiles.length > 1){ + message = 'No configuration files where found at ' + '\n ${_missingFiles.join('\n ')}'; + }else{ + message = 'No configuration file found at ${shellRCFile.path}'; + } throw CompletionInstallationException( rootCommand: rootCommand, - message: 'No configuration file found at ${shellRCFile.path}', + message: message, ); } diff --git a/test/src/installer/completion_installation_test.dart b/test/src/installer/completion_installation_test.dart index 03fd1f6..28807ea 100644 --- a/test/src/installer/completion_installation_test.dart +++ b/test/src/installer/completion_installation_test.dart @@ -794,6 +794,38 @@ void main() { }, ); + test( + 'missing .bashrc and .bash_profile', + () { + + final bashInstallation = CompletionInstallation( + logger: logger, + isWindows: false, + environment: { + 'HOME': tempDir.path, + }, + configuration: bashConfiguration, + ); + + final configDir = bashInstallation.completionConfigDir; + + const exceptionsMessage = ''; + + expect( + () => bashInstallation.install('very_good'), + throwsA( + isA().having( + (e) => e.message, + 'message', + 'No configuration files where found at ' + '\n ${path.join(tempDir.path, '.bashrc')}' + '\n ${path.join(tempDir.path, '.bash_profile')}', + ), + ), + ); + + }, + ); }); group('uninstall', () { From 801fcf366bad237fdf77ca2cd669f9a57cbdb723 Mon Sep 17 00:00:00 2001 From: tom Date: Mon, 13 Oct 2025 12:48:56 +1000 Subject: [PATCH 3/4] Removed analysis issues --- test/src/installer/completion_installation_test.dart | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/src/installer/completion_installation_test.dart b/test/src/installer/completion_installation_test.dart index 28807ea..56801fa 100644 --- a/test/src/installer/completion_installation_test.dart +++ b/test/src/installer/completion_installation_test.dart @@ -807,10 +807,6 @@ void main() { configuration: bashConfiguration, ); - final configDir = bashInstallation.completionConfigDir; - - const exceptionsMessage = ''; - expect( () => bashInstallation.install('very_good'), throwsA( From 8126a41e68b7905961ef2406a182d272054256d4 Mon Sep 17 00:00:00 2001 From: tom Date: Wed, 15 Oct 2025 08:32:44 +1000 Subject: [PATCH 4/4] Ran dart format across the project. --- .../installer/completion_installation.dart | 16 ++++++------ .../shell_completion_configuration.dart | 2 +- .../completion_installation_test.dart | 25 ++++++------------- 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/lib/src/installer/completion_installation.dart b/lib/src/installer/completion_installation.dart index e41d92a..9403d7a 100644 --- a/lib/src/installer/completion_installation.dart +++ b/lib/src/installer/completion_installation.dart @@ -274,16 +274,15 @@ class CompletionInstallation { ); } - final _missingFiles = []; String? __shellRCFilePath; String get _shellRCFilePath { String? firstPath; - if(__shellRCFilePath == null){ - for(final fileName in configuration!.shellRCFiles){ + if (__shellRCFilePath == null) { + for (final fileName in configuration!.shellRCFiles) { final filePath = _resolveHome(fileName, environment); firstPath ??= filePath; - if(File(filePath).existsSync()){ + if (File(filePath).existsSync()) { __shellRCFilePath = filePath; return __shellRCFilePath!; } @@ -308,10 +307,11 @@ class CompletionInstallation { final shellRCFile = File(_shellRCFilePath); if (!shellRCFile.existsSync()) { var message = ''; - if(_missingFiles.length > 1){ - message = 'No configuration files where found at ' - '\n ${_missingFiles.join('\n ')}'; - }else{ + if (_missingFiles.length > 1) { + message = + 'No configuration files where found at ' + '\n ${_missingFiles.join('\n ')}'; + } else { message = 'No configuration file found at ${shellRCFile.path}'; } throw CompletionInstallationException( diff --git a/lib/src/installer/shell_completion_configuration.dart b/lib/src/installer/shell_completion_configuration.dart index 99f3886..f4ef92b 100644 --- a/lib/src/installer/shell_completion_configuration.dart +++ b/lib/src/installer/shell_completion_configuration.dart @@ -97,7 +97,7 @@ fi @visibleForTesting final bashConfiguration = ShellCompletionConfiguration._( shell: SystemShell.bash, - shellRCFiles: const ['~/.bashrc','~/.bash_profile'], + shellRCFiles: const ['~/.bashrc', '~/.bash_profile'], sourceLineTemplate: (String scriptPath) { return '[ -f $scriptPath ] && . $scriptPath || true'; }, diff --git a/test/src/installer/completion_installation_test.dart b/test/src/installer/completion_installation_test.dart index 56801fa..bcd302d 100644 --- a/test/src/installer/completion_installation_test.dart +++ b/test/src/installer/completion_installation_test.dart @@ -730,8 +730,7 @@ void main() { test( 'installing completion for .bashrc', - () { - + () { final bashInstallation = CompletionInstallation( logger: logger, isWindows: false, @@ -746,8 +745,7 @@ void main() { final bashProfile = File(path.join(tempDir.path, '.bash_profile')) ..createSync(); - bashInstallation - .install('very_good'); + bashInstallation.install('very_good'); // Different format needed for matching cli output expect(bashProfile.readAsStringSync(), ''' @@ -757,14 +755,12 @@ void main() { ## [/Completion] '''); - }, ); test( 'installing completion for .bash_profile', - () { - + () { final bashInstallation = CompletionInstallation( logger: logger, isWindows: false, @@ -776,11 +772,9 @@ void main() { final configDir = bashInstallation.completionConfigDir; - final bashRc = File(path.join(tempDir.path, '.bashrc')) - ..createSync(); + final bashRc = File(path.join(tempDir.path, '.bashrc'))..createSync(); - bashInstallation - .install('very_good'); + bashInstallation.install('very_good'); // Different format needed for matching cli output expect(bashRc.readAsStringSync(), ''' @@ -790,14 +784,12 @@ void main() { ## [/Completion] '''); - }, ); test( 'missing .bashrc and .bash_profile', - () { - + () { final bashInstallation = CompletionInstallation( logger: logger, isWindows: false, @@ -808,10 +800,10 @@ void main() { ); expect( - () => bashInstallation.install('very_good'), + () => bashInstallation.install('very_good'), throwsA( isA().having( - (e) => e.message, + (e) => e.message, 'message', 'No configuration files where found at ' '\n ${path.join(tempDir.path, '.bashrc')}' @@ -819,7 +811,6 @@ void main() { ), ), ); - }, ); });