Skip to content

Commit d73f33a

Browse files
authored
refactor: added ScriptConfigurationEntry (#69)
1 parent f8a79b0 commit d73f33a

File tree

6 files changed

+203
-36
lines changed

6 files changed

+203
-36
lines changed

lib/installer.dart

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,5 @@
22
/// {@canonicalFor system_shell.SystemShell}
33
library installer;
44

5-
export 'src/installer/completion_installation.dart';
6-
export 'src/installer/exceptions.dart';
7-
export 'src/installer/shell_completion_configuration.dart';
5+
export 'src/installer/installer.dart';
86
export 'src/system_shell.dart';

lib/src/installer/completion_installation.dart

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -207,18 +207,15 @@ class CompletionInstallation {
207207
logger.info('No file found at $configPath, creating one now');
208208
configFile.createSync();
209209
}
210-
final commandScriptName = '$rootCommand.${configuration.shell.name}';
211-
212-
final containsLine =
213-
configFile.readAsStringSync().contains(commandScriptName);
214210

215-
if (containsLine) {
211+
if (ScriptConfigurationEntry(rootCommand).existsIn(configFile)) {
216212
logger.warn(
217213
'A config entry for $rootCommand was already found on $configPath.',
218214
);
219215
return;
220216
}
221217

218+
final commandScriptName = '$rootCommand.${configuration.shell.name}';
222219
_sourceScriptOnFile(
223220
configFile: configFile,
224221
scriptName: rootCommand,
@@ -240,28 +237,18 @@ class CompletionInstallation {
240237
'to $_shellRCFilePath',
241238
);
242239

243-
final completionConfigDirPath = completionConfigDir.path;
244-
245-
final completionConfigPath = path.join(
246-
completionConfigDirPath,
247-
configuration.completionConfigForShellFileName,
248-
);
249-
250240
final shellRCFile = File(_shellRCFilePath);
251-
252241
if (!shellRCFile.existsSync()) {
253242
throw CompletionInstallationException(
254243
rootCommand: rootCommand,
255244
message: 'No configuration file found at ${shellRCFile.path}',
256245
);
257246
}
258247

259-
final containsLine =
260-
shellRCFile.readAsStringSync().contains(completionConfigPath);
261-
262-
if (containsLine) {
263-
logger.warn('A completion config entry was already found on'
264-
' $_shellRCFilePath.');
248+
if (const ScriptConfigurationEntry('Completion').existsIn(shellRCFile)) {
249+
logger.warn(
250+
'''A completion config entry was already found on $_shellRCFilePath.''',
251+
);
265252
return;
266253
}
267254

@@ -307,15 +294,12 @@ class CompletionInstallation {
307294

308295
description ??= 'Completion config for "$scriptName"';
309296

310-
configFile.writeAsStringSync(
311-
mode: FileMode.append,
312-
'''
313-
\n## [$scriptName]
297+
final content = '''
314298
## $description
315-
${configuration!.sourceLineTemplate(scriptPath)}
316-
## [/$scriptName]
317-
318-
''',
299+
${configuration!.sourceLineTemplate(scriptPath)}''';
300+
ScriptConfigurationEntry(scriptName).appendTo(
301+
configFile,
302+
content: content,
319303
);
320304

321305
logger.info('Added config to $configFilePath');

lib/src/installer/installer.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export 'completion_installation.dart';
2+
export 'exceptions.dart';
3+
export 'script_configuration_entry.dart';
4+
export 'shell_completion_configuration.dart';
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import 'dart:io';
2+
3+
/// {@template script_entry}
4+
/// A script entry is a section of a file that starts with [_startComment] and
5+
/// ends with [_endComment].
6+
/// {@endtemplate}
7+
class ScriptConfigurationEntry {
8+
/// {@macro script_entry}
9+
const ScriptConfigurationEntry(this.name)
10+
: _startComment = '## [$name]',
11+
_endComment = '## [/$name]';
12+
13+
/// The name of the entry.
14+
final String name;
15+
16+
/// The start comment of the entry.
17+
final String _startComment;
18+
19+
/// The end comment of the entry.
20+
final String _endComment;
21+
22+
/// Whether there is an entry with [name] in [file].
23+
///
24+
/// If the [file] does not exist, this will return false.
25+
bool existsIn(File file) {
26+
if (!file.existsSync()) return false;
27+
final content = file.readAsStringSync();
28+
return content.contains(_startComment) && content.contains(_endComment);
29+
}
30+
31+
/// Adds an entry with [name] to the end of the [file].
32+
///
33+
/// If the [file] does not exist, it will be created.
34+
///
35+
/// If [content] is not null, it will be added within the entry.
36+
void appendTo(File file, {String? content}) {
37+
if (!file.existsSync()) {
38+
file.createSync(recursive: true);
39+
}
40+
41+
final entry = StringBuffer()
42+
..writeln()
43+
..writeln(_startComment)
44+
..writeln(content)
45+
..writeln(_endComment)
46+
..writeln();
47+
48+
file.writeAsStringSync(
49+
entry.toString(),
50+
mode: FileMode.append,
51+
);
52+
}
53+
}

test/src/installer/completion_installation_test.dart

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ void main() {
225225

226226
// ignore: leading_newlines_in_multiline_strings
227227
expect(configFile.readAsStringSync(), '''
228-
\n## [very_good]
228+
\n## [very_good]
229229
## Completion config for "very_good"
230230
[[ -f ${configDir.path}/very_good.zsh ]] && . ${configDir.path}/very_good.zsh || true
231231
## [/very_good]
@@ -286,7 +286,7 @@ void main() {
286286

287287
// ignore: leading_newlines_in_multiline_strings
288288
expect(rcFile.readAsStringSync(), '''
289-
\n## [Completion]
289+
\n## [Completion]
290290
## Completion scripts setup. Remove the following line to uninstall
291291
[[ -f ${configDir.path}/zsh-config.zsh ]] && . ${configDir.path}/zsh-config.zsh || true
292292
## [/Completion]
@@ -394,7 +394,7 @@ void main() {
394394

395395
// ignore: leading_newlines_in_multiline_strings
396396
expect(rcFile.readAsStringSync(), '''
397-
\n## [Completion]
397+
\n## [Completion]
398398
## Completion scripts setup. Remove the following line to uninstall
399399
[[ -f ${configDir.path}/zsh-config.zsh ]] && . ${configDir.path}/zsh-config.zsh || true
400400
## [/Completion]
@@ -408,12 +408,12 @@ void main() {
408408

409409
// ignore: leading_newlines_in_multiline_strings
410410
expect(globalConfig.readAsStringSync(), '''
411-
\n## [very_good]
411+
\n## [very_good]
412412
## Completion config for "very_good"
413413
[[ -f ${configDir.path}/very_good.zsh ]] && . ${configDir.path}/very_good.zsh || true
414414
## [/very_good]
415415
416-
\n## [not_good]
416+
\n## [not_good]
417417
## Completion config for "not_good"
418418
[[ -f ${configDir.path}/not_good.zsh ]] && . ${configDir.path}/not_good.zsh || true
419419
## [/not_good]
@@ -447,7 +447,7 @@ void main() {
447447

448448
// ignore: leading_newlines_in_multiline_strings
449449
expect(bashProfile.readAsStringSync(), '''
450-
\n## [Completion]
450+
\n## [Completion]
451451
## Completion scripts setup. Remove the following line to uninstall
452452
[ -f ${configDir.path}/bash-config.bash ] && . ${configDir.path}/bash-config.bash || true
453453
## [/Completion]
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// ignore_for_file: prefer_const_constructors
2+
3+
import 'dart:io';
4+
5+
import 'package:cli_completion/src/installer/script_configuration_entry.dart';
6+
import 'package:path/path.dart' as path;
7+
import 'package:test/test.dart';
8+
9+
void main() {
10+
group('$ScriptConfigurationEntry', () {
11+
test('can be instatiated', () {
12+
expect(() => ScriptConfigurationEntry('name'), returnsNormally);
13+
});
14+
15+
test('has a name', () {
16+
expect(ScriptConfigurationEntry('name').name, 'name');
17+
});
18+
19+
group('appendsTo', () {
20+
test('returns normally when file exist', () {
21+
final tempDirectory = Directory.systemTemp.createTempSync();
22+
addTearDown(() => tempDirectory.deleteSync(recursive: true));
23+
24+
final filePath = path.join(tempDirectory.path, 'file');
25+
final file = File(filePath)..createSync();
26+
27+
final entry = ScriptConfigurationEntry('name');
28+
29+
expect(
30+
() => entry.appendTo(file),
31+
returnsNormally,
32+
);
33+
});
34+
35+
test('returns normally when file does not exist', () {
36+
final tempDirectory = Directory.systemTemp.createTempSync();
37+
addTearDown(() => tempDirectory.deleteSync(recursive: true));
38+
39+
final filePath = path.join(tempDirectory.path, 'file');
40+
final file = File(filePath);
41+
42+
final entry = ScriptConfigurationEntry('name');
43+
44+
expect(
45+
() => entry.appendTo(file),
46+
returnsNormally,
47+
);
48+
});
49+
50+
test('correctly appends content', () {
51+
final tempDirectory = Directory.systemTemp.createTempSync();
52+
addTearDown(() => tempDirectory.deleteSync(recursive: true));
53+
54+
final filePath = path.join(tempDirectory.path, 'file');
55+
final file = File(filePath)..createSync();
56+
const initialContent = 'hello world\n';
57+
file.writeAsStringSync(initialContent);
58+
59+
final entry = ScriptConfigurationEntry('name');
60+
const entryContent = 'hello world';
61+
62+
entry.appendTo(file, content: entryContent);
63+
64+
final fileContent = file.readAsStringSync();
65+
const expectedContent = '''
66+
$initialContent
67+
## [name]
68+
$entryContent
69+
## [/name]
70+
71+
''';
72+
expect(fileContent, equals(expectedContent));
73+
});
74+
});
75+
76+
group('existsIn', () {
77+
group('returns false', () {
78+
test('when when file does not exist', () {
79+
final tempDirectory = Directory.systemTemp.createTempSync();
80+
addTearDown(() => tempDirectory.deleteSync(recursive: true));
81+
82+
final filePath = path.join(tempDirectory.path, 'file');
83+
final file = File(filePath);
84+
85+
final entry = ScriptConfigurationEntry('name');
86+
87+
expect(entry.existsIn(file), isFalse);
88+
});
89+
90+
test('when file exists without entry', () {
91+
final tempDirectory = Directory.systemTemp.createTempSync();
92+
addTearDown(() => tempDirectory.deleteSync(recursive: true));
93+
94+
final filePath = path.join(tempDirectory.path, 'file');
95+
final file = File(filePath)..createSync();
96+
97+
final entry = ScriptConfigurationEntry('name');
98+
99+
expect(entry.existsIn(file), isFalse);
100+
});
101+
102+
test('when file exists with another entry', () {
103+
final tempDirectory = Directory.systemTemp.createTempSync();
104+
addTearDown(() => tempDirectory.deleteSync(recursive: true));
105+
106+
final filePath = path.join(tempDirectory.path, 'file');
107+
final file = File(filePath)..createSync();
108+
ScriptConfigurationEntry('other').appendTo(file);
109+
110+
final entry = ScriptConfigurationEntry('name');
111+
expect(entry.existsIn(file), isFalse);
112+
});
113+
});
114+
115+
test('returns true when file exists with an entry', () {
116+
final tempDirectory = Directory.systemTemp.createTempSync();
117+
addTearDown(() => tempDirectory.deleteSync(recursive: true));
118+
119+
final filePath = path.join(tempDirectory.path, 'file');
120+
final file = File(filePath)..createSync();
121+
122+
final entry = ScriptConfigurationEntry('name')..appendTo(file);
123+
124+
expect(entry.existsIn(file), isTrue);
125+
});
126+
});
127+
});
128+
}

0 commit comments

Comments
 (0)