Skip to content

Commit 67dd01e

Browse files
[flutter_tools] tool exit from flutter create when provided just a drive letter (#106451)
1 parent 79d08aa commit 67dd01e

File tree

3 files changed

+59
-0
lines changed

3 files changed

+59
-0
lines changed

packages/flutter_tools/lib/src/commands/create_base.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,27 @@ abstract class CreateBase extends FlutterCommand {
132132
);
133133
}
134134

135+
/// Pattern for a Windows file system drive (e.g. "D:").
136+
///
137+
/// `dart:io` does not recognize strings matching this pattern as absolute
138+
/// paths, as they have no top level back-slash; however, users often specify
139+
/// this
140+
@visibleForTesting
141+
static final RegExp kWindowsDrivePattern = RegExp(r'^[a-zA-Z]:$');
142+
135143
/// The output directory of the command.
136144
@protected
145+
@visibleForTesting
137146
Directory get projectDir {
147+
final String argProjectDir = argResults!.rest.first;
148+
if (globals.platform.isWindows && kWindowsDrivePattern.hasMatch(argProjectDir)) {
149+
throwToolExit(
150+
'You attempted to create a flutter project at the path "$argProjectDir", which is the name of a drive. This '
151+
'is usually a mistake--you probably want to specify a containing directory, like "$argProjectDir\\app_name". '
152+
'If you really want it at the drive root, re-run the command with the root directory after the drive, like '
153+
'"$argProjectDir\\".',
154+
);
155+
}
138156
return globals.fs.directory(argResults!.rest.first);
139157
}
140158

packages/flutter_tools/test/commands.shard/permeable/create_test.dart

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import 'dart:async';
88
import 'dart:convert';
9+
import 'dart:io' as io;
910

1011
import 'package:args/command_runner.dart';
1112
import 'package:file_testing/file_testing.dart';
@@ -113,6 +114,37 @@ void main() {
113114
expect(Uuid.isValidUUID(fromString: identifier), isTrue);
114115
});
115116

117+
testUsingContext('tool exits on Windows if given a drive letter without a path', () async {
118+
// Must use LocalFileSystem as it is dependent on dart:io handling of
119+
// Windows paths, which the MemoryFileSystem does not implement
120+
final Directory workingDir = globals.fs.directory(r'X:\path\to\working\dir');
121+
// Must use [io.IOOverrides] as directory.absolute depends on Directory.current
122+
// from dart:io.
123+
await io.IOOverrides.runZoned<Future<void>>(
124+
() async {
125+
// Verify IOOverrides is working
126+
expect(io.Directory.current, workingDir);
127+
final CreateCommand command = CreateCommand();
128+
final CommandRunner<void> runner = createTestCommandRunner(command);
129+
const String driveName = 'X:';
130+
await expectToolExitLater(
131+
runner.run(<String>[
132+
'create',
133+
'--project-name',
134+
'test_app',
135+
'--offline',
136+
driveName,
137+
]),
138+
contains('You attempted to create a flutter project at the path "$driveName"'),
139+
);
140+
},
141+
getCurrentDirectory: () => workingDir,
142+
);
143+
}, overrides: <Type, Generator>{
144+
Logger: () => BufferLogger.test(),
145+
}, skip: !io.Platform.isWindows // [intended] relies on Windows file system
146+
);
147+
116148
// Verify that we create a default project ('app') that is
117149
// well-formed.
118150
testUsingContext('can create a default project', () async {

packages/flutter_tools/test/general.shard/create_config_test.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,13 @@ void main() {
1919

2020
expect(isValidPackageName('Foo_bar'), false);
2121
});
22+
23+
test('kWindowsDrivePattern', () {
24+
expect(CreateBase.kWindowsDrivePattern.hasMatch(r'D:\'), isFalse);
25+
expect(CreateBase.kWindowsDrivePattern.hasMatch(r'z:\'), isFalse);
26+
expect(CreateBase.kWindowsDrivePattern.hasMatch(r'\d:'), isFalse);
27+
expect(CreateBase.kWindowsDrivePattern.hasMatch(r'ef:'), isFalse);
28+
expect(CreateBase.kWindowsDrivePattern.hasMatch(r'D:'), isTrue);
29+
expect(CreateBase.kWindowsDrivePattern.hasMatch(r'c:'), isTrue);
30+
});
2231
}

0 commit comments

Comments
 (0)