Skip to content

Commit

Permalink
[flutter_tools] tool exit from flutter create when provided just a dr…
Browse files Browse the repository at this point in the history
…ive letter (#106451)
  • Loading branch information
christopherfujino authored Jun 24, 2022
1 parent 79d08aa commit 67dd01e
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 0 deletions.
18 changes: 18 additions & 0 deletions packages/flutter_tools/lib/src/commands/create_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,27 @@ abstract class CreateBase extends FlutterCommand {
);
}

/// Pattern for a Windows file system drive (e.g. "D:").
///
/// `dart:io` does not recognize strings matching this pattern as absolute
/// paths, as they have no top level back-slash; however, users often specify
/// this
@visibleForTesting
static final RegExp kWindowsDrivePattern = RegExp(r'^[a-zA-Z]:$');

/// The output directory of the command.
@protected
@visibleForTesting
Directory get projectDir {
final String argProjectDir = argResults!.rest.first;
if (globals.platform.isWindows && kWindowsDrivePattern.hasMatch(argProjectDir)) {
throwToolExit(
'You attempted to create a flutter project at the path "$argProjectDir", which is the name of a drive. This '
'is usually a mistake--you probably want to specify a containing directory, like "$argProjectDir\\app_name". '
'If you really want it at the drive root, re-run the command with the root directory after the drive, like '
'"$argProjectDir\\".',
);
}
return globals.fs.directory(argResults!.rest.first);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import 'dart:async';
import 'dart:convert';
import 'dart:io' as io;

import 'package:args/command_runner.dart';
import 'package:file_testing/file_testing.dart';
Expand Down Expand Up @@ -113,6 +114,37 @@ void main() {
expect(Uuid.isValidUUID(fromString: identifier), isTrue);
});

testUsingContext('tool exits on Windows if given a drive letter without a path', () async {
// Must use LocalFileSystem as it is dependent on dart:io handling of
// Windows paths, which the MemoryFileSystem does not implement
final Directory workingDir = globals.fs.directory(r'X:\path\to\working\dir');
// Must use [io.IOOverrides] as directory.absolute depends on Directory.current
// from dart:io.
await io.IOOverrides.runZoned<Future<void>>(
() async {
// Verify IOOverrides is working
expect(io.Directory.current, workingDir);
final CreateCommand command = CreateCommand();
final CommandRunner<void> runner = createTestCommandRunner(command);
const String driveName = 'X:';
await expectToolExitLater(
runner.run(<String>[
'create',
'--project-name',
'test_app',
'--offline',
driveName,
]),
contains('You attempted to create a flutter project at the path "$driveName"'),
);
},
getCurrentDirectory: () => workingDir,
);
}, overrides: <Type, Generator>{
Logger: () => BufferLogger.test(),
}, skip: !io.Platform.isWindows // [intended] relies on Windows file system
);

// Verify that we create a default project ('app') that is
// well-formed.
testUsingContext('can create a default project', () async {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,13 @@ void main() {

expect(isValidPackageName('Foo_bar'), false);
});

test('kWindowsDrivePattern', () {
expect(CreateBase.kWindowsDrivePattern.hasMatch(r'D:\'), isFalse);
expect(CreateBase.kWindowsDrivePattern.hasMatch(r'z:\'), isFalse);
expect(CreateBase.kWindowsDrivePattern.hasMatch(r'\d:'), isFalse);
expect(CreateBase.kWindowsDrivePattern.hasMatch(r'ef:'), isFalse);
expect(CreateBase.kWindowsDrivePattern.hasMatch(r'D:'), isTrue);
expect(CreateBase.kWindowsDrivePattern.hasMatch(r'c:'), isTrue);
});
}

0 comments on commit 67dd01e

Please sign in to comment.