Skip to content

Commit b706a2d

Browse files
committed
wip: use paths instead of names with backwards compatibility
1 parent cc786aa commit b706a2d

File tree

2 files changed

+171
-100
lines changed

2 files changed

+171
-100
lines changed

lib/src/commands/create/commands/create_subcommand.dart

Lines changed: 34 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -117,27 +117,44 @@ abstract class CreateSubCommand extends Command<int> {
117117

118118
/// Gets the output [Directory].
119119
Directory get outputDirectory {
120-
final directory = argResults['output-directory'] as String? ?? '.';
121-
return Directory(directory);
122-
}
120+
final directory = argResults['output-directory'] as String?;
121+
122+
if (directory != null) {
123+
return Directory(directory);
124+
}
123125

124-
/// The project name that the user provided.
125-
///
126-
/// Since the project name could be user provided as either:
127-
/// 1. A valid package name
128-
/// 2. '.', the current working directory (the project assumes the cwd's name)
129-
/// this needs to exist to provide a fallback value for [outputDirectory] and
130-
/// [projectName].
131-
String get _projectName {
132126
final args = argResults.rest;
133-
_validateProjectName(args);
134-
return args.first;
127+
128+
return Directory(args.first);
135129
}
136130

137131
/// Gets the project name.
138-
String get projectName => _projectName == '.'
139-
? path.basename(Directory.current.path)
140-
: _projectName;
132+
String get projectName {
133+
final args = argResults.rest;
134+
135+
if (args.isEmpty) {
136+
usageException('No option specified for the project name.');
137+
}
138+
139+
if (args.length > 1) {
140+
usageException('Multiple project names specified.');
141+
}
142+
143+
final name = args.first == '.'
144+
? path.basename(Directory.current.path)
145+
: path.basename(args.first);
146+
147+
final isValidPackageName = _isValidPackageName(name);
148+
149+
if (!isValidPackageName) {
150+
usageException(
151+
'"$name" is not a valid package name.\n\n'
152+
'See https://dart.dev/tools/pub/pubspec#name for more information.',
153+
);
154+
}
155+
156+
return name;
157+
}
141158

142159
/// Gets the description for the project.
143160
String get projectDescription => argResults['description'] as String? ?? '';
@@ -158,28 +175,6 @@ abstract class CreateSubCommand extends Command<int> {
158175
return match != null && match.end == name.length;
159176
}
160177

161-
void _validateProjectName(List<String> args) {
162-
logger.detail('Validating project name; args: $args');
163-
164-
if (args.isEmpty) {
165-
usageException('No option specified for the project name.');
166-
}
167-
168-
if (args.length > 1) {
169-
usageException('Multiple project names specified.');
170-
}
171-
172-
final name = args.first;
173-
174-
final isValidProjectName = _isValidPackageName(name);
175-
if (!isValidProjectName) {
176-
usageException(
177-
'"$name" is not a valid package name.\n\n'
178-
'See https://dart.dev/tools/pub/pubspec#name for more information.',
179-
);
180-
}
181-
}
182-
183178
Future<MasonGenerator> _getGeneratorForTemplate() async {
184179
try {
185180
final brick = Brick.version(
@@ -223,12 +218,7 @@ abstract class CreateSubCommand extends Command<int> {
223218

224219
await template.onGenerateComplete(
225220
logger,
226-
Directory(
227-
[
228-
target.dir.path,
229-
if (_projectName != '.') projectName,
230-
].join(Platform.pathSeparator),
231-
),
221+
outputDirectory,
232222
);
233223

234224
return ExitCode.success.code;

test/src/commands/create/create_subcommand_test.dart

Lines changed: 137 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -237,60 +237,131 @@ Run "runner help" to see global options.''';
237237
});
238238

239239
group('parsing of options', () {
240-
test('parses description, output dir and project name', () async {
241-
final result = await runner.run([
242-
'create_subcommand',
243-
'test_project',
244-
'--description',
245-
'test_desc',
246-
'--output-directory',
247-
'test_dir',
248-
]);
240+
group('for project name', () {
241+
test('uses current directory basename as name if . provided',
242+
() async {
243+
final expectedProjectName = path.basename(Directory.current.path);
249244

250-
expect(result, equals(ExitCode.success.code));
251-
verify(() => logger.progress('Bootstrapping')).called(1);
245+
final result = await runner.run([
246+
'create_subcommand',
247+
'.',
248+
]);
252249

253-
verify(
254-
() => hooks.preGen(
255-
vars: <String, dynamic>{
256-
'project_name': 'test_project',
257-
'description': 'test_desc',
258-
},
259-
onVarsChanged: any(named: 'onVarsChanged'),
260-
),
261-
);
262-
verify(
263-
() => generator.generate(
264-
any(
265-
that: isA<DirectoryGeneratorTarget>().having(
266-
(g) => g.dir.path,
267-
'dir',
268-
'test_dir',
269-
),
250+
expect(result, equals(ExitCode.success.code));
251+
verify(() => logger.progress('Bootstrapping')).called(1);
252+
253+
verify(
254+
() => hooks.preGen(
255+
vars: <String, dynamic>{
256+
'project_name': expectedProjectName,
257+
'description':
258+
'A Very Good Project created by Very Good CLI.',
259+
},
260+
onVarsChanged: any(named: 'onVarsChanged'),
270261
),
271-
vars: <String, dynamic>{
272-
'project_name': 'test_project',
273-
'description': 'test_desc',
274-
},
275-
logger: logger,
276-
),
277-
).called(1);
278-
expect(
279-
progressLogs,
280-
equals(['Generated ${generatedFiles.length} file(s)']),
281-
);
282-
verify(
283-
() => template.onGenerateComplete(
284-
logger,
285-
any(
286-
that: isA<Directory>().having(
287-
(d) => d.path,
288-
'path',
289-
path.join('test_dir', 'test_project'),
290-
),
262+
);
263+
});
264+
265+
test('uses name if just a name is provided', () async {
266+
final result = await runner.run([
267+
'create_subcommand',
268+
'name',
269+
]);
270+
271+
expect(result, equals(ExitCode.success.code));
272+
verify(() => logger.progress('Bootstrapping')).called(1);
273+
274+
verify(
275+
() => hooks.preGen(
276+
vars: <String, dynamic>{
277+
'project_name': 'name',
278+
'description':
279+
'A Very Good Project created by Very Good CLI.',
280+
},
281+
onVarsChanged: any(named: 'onVarsChanged'),
291282
),
292-
),
293-
).called(1);
283+
);
284+
});
285+
286+
test('uses last path segment if absolute path is provided', () async {
287+
final result = await runner.run([
288+
'create_subcommand',
289+
'/path/to/name',
290+
]);
291+
292+
expect(result, equals(ExitCode.success.code));
293+
verify(() => logger.progress('Bootstrapping')).called(1);
294+
295+
verify(
296+
() => hooks.preGen(
297+
vars: <String, dynamic>{
298+
'project_name': 'name',
299+
'description':
300+
'A Very Good Project created by Very Good CLI.',
301+
},
302+
onVarsChanged: any(named: 'onVarsChanged'),
303+
),
304+
);
305+
});
306+
307+
test('uses last path segment if a relative path is provided',
308+
() async {
309+
final result = await runner.run([
310+
'create_subcommand',
311+
'./name',
312+
]);
313+
314+
expect(result, equals(ExitCode.success.code));
315+
verify(() => logger.progress('Bootstrapping')).called(1);
316+
317+
verify(
318+
() => hooks.preGen(
319+
vars: <String, dynamic>{
320+
'project_name': 'name',
321+
'description':
322+
'A Very Good Project created by Very Good CLI.',
323+
},
324+
onVarsChanged: any(named: 'onVarsChanged'),
325+
),
326+
);
327+
});
328+
});
329+
330+
group('for output directory', () {
331+
test(
332+
'uses directory provided in --output-directory instead of the '
333+
'one parsed from project',
334+
() async {
335+
final result = await runner.run([
336+
'create_subcommand',
337+
'path/to/test_project',
338+
'--output-directory',
339+
'path/to/test_dir',
340+
'--description',
341+
'test_desc',
342+
]);
343+
344+
expect(result, equals(ExitCode.success.code));
345+
verify(() => logger.progress('Bootstrapping')).called(1);
346+
347+
verify(
348+
() => generator.generate(
349+
any(
350+
that: isA<DirectoryGeneratorTarget>().having(
351+
(g) => g.dir.path,
352+
'dir',
353+
'path/to/test_dir',
354+
),
355+
),
356+
vars: <String, dynamic>{
357+
'project_name': 'test_project',
358+
'description': 'test_desc',
359+
},
360+
logger: logger,
361+
),
362+
).called(1);
363+
},
364+
);
294365
});
295366

296367
test('allows projects to be cwd (.)', () async {
@@ -317,7 +388,9 @@ Run "runner help" to see global options.''';
317388
() => generator.generate(
318389
any(
319390
that: isA<DirectoryGeneratorTarget>().having(
320-
(g) => g.dir.path,
391+
(g) {
392+
return g.dir.path;
393+
},
321394
'dir',
322395
'.',
323396
),
@@ -338,7 +411,11 @@ Run "runner help" to see global options.''';
338411
logger,
339412
any(
340413
that: isA<Directory>().having(
341-
(d) => d.path,
414+
(d) {
415+
print(Directory.current);
416+
print(d.absolute.path);
417+
return d.path;
418+
},
342419
'path',
343420
'.',
344421
),
@@ -373,9 +450,11 @@ Run "runner help" to see global options.''';
373450
() => generator.generate(
374451
any(
375452
that: isA<DirectoryGeneratorTarget>().having(
376-
(g) => g.dir.path,
453+
(g) {
454+
return g.dir.path;
455+
},
377456
'dir',
378-
'.',
457+
'test_project',
379458
),
380459
),
381460
vars: <String, dynamic>{
@@ -391,9 +470,11 @@ Run "runner help" to see global options.''';
391470
logger,
392471
any(
393472
that: isA<Directory>().having(
394-
(d) => d.path,
473+
(d) {
474+
return d.path;
475+
},
395476
'path',
396-
'./test_project',
477+
'test_project',
397478
),
398479
),
399480
),

0 commit comments

Comments
 (0)