Skip to content

Commit 155f836

Browse files
authored
Fix crash creating a merged output dir with a file called lib. (#4137)
1 parent 1d0b322 commit 155f836

File tree

4 files changed

+41
-41
lines changed

4 files changed

+41
-41
lines changed

build_runner/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
- Bug fix: delete transitive generated outputs as well as direct generated
1414
outputs. So, a generated file now gets deleted if its input was a generated
1515
file that is no longer output.
16+
- Bug fix: fix crash creating a merged output dir with a file called `lib`.
1617

1718
## 2.6.1
1819

build_runner_core/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
- Bug fix: delete transitive generated outputs as well as direct generated
77
outputs. So, a generated file now gets deleted if its input was a generated
88
file that is no longer output.
9+
- Bug fix: fix crash creating a merged output dir with a file called `lib`.
910

1011
## 9.2.1
1112

build_runner_core/lib/src/environment/create_merged_dir.dart

Lines changed: 37 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,12 @@ Future<bool> _createMergedOutputDir(
120120
return false;
121121
}
122122

123-
var outputAssets = <AssetId>[];
123+
var outputPaths = <String>[];
124124
if (!outputDirExists) {
125125
await outputDir.create(recursive: true);
126126
}
127127

128-
outputAssets.addAll(
128+
outputPaths.addAll(
129129
await Future.wait([
130130
for (var id in builtAssets)
131131
_writeAsset(
@@ -154,24 +154,23 @@ Future<bool> _createMergedOutputDir(
154154
}
155155
}
156156

157-
var paths = outputAssets.map((id) => id.path).toList()..sort();
158-
var content = paths.join(_manifestSeparator);
159-
await _writeAsString(
160-
outputDir,
161-
AssetId(packageGraph.root.name, _manifestName),
162-
content,
163-
);
157+
outputPaths.sort();
158+
var content = outputPaths
159+
// Normalize path separators for the manifest.
160+
.map((path) => path.replaceAll(r'\', '/'))
161+
.join(_manifestSeparator);
162+
await _writeAsString(outputDir, _manifestName, content);
164163

165164
return true;
166165
} on FileSystemException catch (e) {
167166
if (e.osError?.errorCode != 1314) rethrow;
168-
var devModeLink =
167+
final devModeLink =
169168
'https://docs.microsoft.com/en-us/windows/uwp/get-started/'
170169
'enable-your-device-for-development';
171170
buildLog.error(
172-
'Unable to create symlink ${e.path}. Note that to create '
173-
'symlinks on windows you need to either run in a console with admin '
174-
'privileges or enable developer mode (see $devModeLink).',
171+
'Failed to create merged output directory with symlinks. '
172+
'To allow creation of symlinks run in a console with admin privileges '
173+
'or enable developer mode following $devModeLink.',
175174
);
176175
return false;
177176
}
@@ -186,12 +185,14 @@ Future<bool> _createMergedOutputDir(
186185
/// package uri are equivalent.
187186
///
188187
/// All other fields are left as is.
189-
Future<AssetId> _writeModifiedPackageConfig(
188+
///
189+
/// Returns the relative path that was written to.
190+
Future<String> _writeModifiedPackageConfig(
190191
String rootPackage,
191192
PackageGraph packageGraph,
192193
Directory outputDir,
193194
) async {
194-
var packageConfig = <String, Object?>{
195+
final packageConfig = <String, Object?>{
195196
'configVersion': 2,
196197
'packages': [
197198
for (var package in packageGraph.allPackages.values)
@@ -208,9 +209,9 @@ Future<AssetId> _writeModifiedPackageConfig(
208209
},
209210
],
210211
};
211-
var packageConfigId = AssetId(rootPackage, '.dart_tool/package_config.json');
212-
await _writeAsString(outputDir, packageConfigId, jsonEncode(packageConfig));
213-
return packageConfigId;
212+
final packageConfigPath = '.dart_tool/package_config.json';
213+
await _writeAsString(outputDir, packageConfigPath, jsonEncode(packageConfig));
214+
return packageConfigPath;
214215
}
215216

216217
Set<String> _findRootDirs(Iterable<AssetId> allAssets, String outputPath) {
@@ -225,7 +226,10 @@ Set<String> _findRootDirs(Iterable<AssetId> allAssets, String outputPath) {
225226
return rootDirs;
226227
}
227228

228-
Future<AssetId> _writeAsset(
229+
/// Writes [id] to [outputDir].
230+
///
231+
/// Returns the relative path under [outputDir] that it was written to.
232+
Future<String> _writeAsset(
229233
AssetId id,
230234
Directory outputDir,
231235
String root,
@@ -250,19 +254,18 @@ Future<AssetId> _writeAsset(
250254
}
251255
}
252256

253-
var outputId = AssetId(packageGraph.root.name, assetPath);
254257
try {
255258
if (symlinkOnly) {
256259
// We assert at the top of `createMergedOutputDirectories` that the
257260
// reader filesystem is `IoFilesystem`, so symlinks make sense.
258-
await Link(_filePathFor(outputDir, outputId)).create(
261+
await Link(_filePathFor(outputDir, assetPath)).create(
259262
reader.assetPathProvider.pathFor(
260263
reader.generatedAssetHider.maybeHide(id, packageGraph.root.name),
261264
),
262265
recursive: true,
263266
);
264267
} else {
265-
await _writeAsBytes(outputDir, outputId, await reader.readAsBytes(id));
268+
await _writeAsBytes(outputDir, assetPath, await reader.readAsBytes(id));
266269
}
267270
} on AssetNotFoundException catch (e) {
268271
if (!p.basename(id.path).startsWith('.')) {
@@ -275,32 +278,25 @@ Future<AssetId> _writeAsset(
275278
rethrow;
276279
}
277280
}
278-
return outputId;
281+
return assetPath;
279282
});
280283
}
281284

282-
Future<void> _writeAsBytes(Directory outputDir, AssetId id, List<int> bytes) =>
283-
_fileFor(outputDir, id).then((file) => file.writeAsBytes(bytes));
285+
Future<void> _writeAsBytes(Directory outputDir, String path, List<int> bytes) =>
286+
_fileFor(outputDir, path).then((file) => file.writeAsBytes(bytes));
284287

285-
Future<void> _writeAsString(Directory outputDir, AssetId id, String contents) =>
286-
_fileFor(outputDir, id).then((file) => file.writeAsString(contents));
288+
Future<void> _writeAsString(
289+
Directory outputDir,
290+
String path,
291+
String contents,
292+
) => _fileFor(outputDir, path).then((file) => file.writeAsString(contents));
287293

288-
Future<File> _fileFor(Directory outputDir, AssetId id) {
289-
return File(_filePathFor(outputDir, id)).create(recursive: true);
294+
Future<File> _fileFor(Directory outputDir, String path) {
295+
return File(_filePathFor(outputDir, path)).create(recursive: true);
290296
}
291297

292-
String _filePathFor(Directory outputDir, AssetId id) {
293-
String relativePath;
294-
if (id.path.startsWith('lib')) {
295-
relativePath = p.join(
296-
'packages',
297-
id.package,
298-
p.joinAll(p.url.split(id.path).skip(1)),
299-
);
300-
} else {
301-
relativePath = id.path;
302-
}
303-
return p.join(outputDir.path, relativePath);
298+
String _filePathFor(Directory outputDir, String path) {
299+
return p.join(outputDir.path, path);
304300
}
305301

306302
/// Checks for a manifest file in [outputDir] and deletes all referenced files.

build_runner_core/test/environment/create_merged_dir_test.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ void main() {
3636
final sources = {
3737
makeAssetId('a|lib/a.txt'): 'a',
3838
makeAssetId('a|web/b.txt'): 'b',
39+
// Regression test for https://github.com/dart-lang/build/issues/4135.
40+
makeAssetId('a|web/lib.txt'): 'lib',
3941
makeAssetId('b|lib/c.txt'): 'c',
4042
makeAssetId('b|test/outside.txt'): 'not in lib',
4143
makeAssetId('a|foo/d.txt'): 'd',

0 commit comments

Comments
 (0)