Skip to content

Commit 3e13bb0

Browse files
committed
fix: use workspace lockfile in production build
1 parent b4b43a8 commit 3e13bb0

File tree

11 files changed

+282
-643
lines changed

11 files changed

+282
-643
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
export 'src/copy_workspace_pubspec_lock.dart';
12
export 'src/create_bundle.dart';
23
export 'src/create_external_packages_folder.dart';
34
export 'src/dart_pub_get.dart';
45
export 'src/disable_workspace_resolution.dart';
56
export 'src/exit_overrides.dart';
67
export 'src/get_internal_path_dependencies.dart';
7-
export 'src/get_pubspec_lock.dart';
8+
export 'src/get_pubspec.dart';
89
export 'src/uses_workspace_resolution.dart';
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import 'dart:io';
2+
import 'package:mason/mason.dart';
3+
import 'package:path/path.dart' as path;
4+
import 'package:pubspec_parse/pubspec_parse.dart';
5+
6+
/// Opts out of dart workspaces until we can generate per package lockfiles.
7+
void copyWorkspacePubspecLock(
8+
HookContext context, {
9+
required String buildDirectory,
10+
required String workingDirectory,
11+
required void Function(int exitCode) exit,
12+
}) {
13+
final workspaceRoot = _getWorkspaceRoot();
14+
if (workspaceRoot == null) {
15+
context.logger.err(
16+
'Unable to determine workspace root for $workingDirectory',
17+
);
18+
return exit(1);
19+
}
20+
final pubspecLockFile = File(path.join(workspaceRoot.path, 'pubspec.lock'));
21+
if (!pubspecLockFile.existsSync()) return;
22+
23+
try {
24+
pubspecLockFile.copySync(path.join(buildDirectory, 'pubspec.lock'));
25+
} on Exception catch (error) {
26+
context.logger.err('$error');
27+
return exit(1);
28+
}
29+
}
30+
31+
/// Returns the root directory of the nearest Flutter project.
32+
Directory? _getWorkspaceRoot() {
33+
final file = _findNearestAncestor(
34+
where: (path) => _getWorkspaceRootPubspecYaml(cwd: Directory(path)),
35+
);
36+
if (file == null || !file.existsSync()) return null;
37+
return Directory(path.dirname(file.path));
38+
}
39+
40+
/// The workspace root `pubspec.yaml` file for this project.
41+
File? _getWorkspaceRootPubspecYaml({required Directory cwd}) {
42+
try {
43+
final pubspecYamlFile = File(path.join(cwd.path, 'pubspec.yaml'));
44+
if (!pubspecYamlFile.existsSync()) return null;
45+
final pubspec = Pubspec.parse(pubspecYamlFile.readAsStringSync());
46+
if (pubspec.workspace?.isEmpty ?? true) return null;
47+
return pubspecYamlFile;
48+
} on Exception {
49+
return null;
50+
}
51+
}
52+
53+
/// Finds nearest ancestor file
54+
/// relative to the [cwd] that satisfies [where].
55+
File? _findNearestAncestor({
56+
required File? Function(String path) where,
57+
Directory? cwd,
58+
}) {
59+
Directory? prev;
60+
var dir = cwd ?? Directory.current;
61+
while (prev?.path != dir.path) {
62+
final file = where(dir.path);
63+
if (file?.existsSync() ?? false) return file;
64+
prev = dir;
65+
dir = dir.parent;
66+
}
67+
return null;
68+
}

bricks/dart_frog_prod_server/hooks/lib/src/create_external_packages_folder.dart

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'dart:io';
33
import 'package:dart_frog_prod_server_hooks/dart_frog_prod_server_hooks.dart';
44
import 'package:io/io.dart' as io;
55
import 'package:path/path.dart' as path;
6+
import 'package:pubspec_parse/pubspec_parse.dart';
67

78
/// Signature of [io.copyPath].
89
typedef CopyPath = Future<void> Function(String from, String to);
@@ -13,34 +14,27 @@ Future<List<String>> createExternalPackagesFolder({
1314
CopyPath copyPath = io.copyPath,
1415
}) async {
1516
final pathResolver = path.context;
16-
final pubspecLock = await getPubspecLock(
17+
final pubspec = await getPubspec(
1718
projectDirectory.path,
1819
pathContext: path.context,
1920
);
2021

21-
final externalPathDependencies = pubspecLock.packages
22+
final externalPathDependencies = pubspec.dependencies.values
2223
.map(
2324
(dependency) {
24-
final pathDescription = dependency.pathDescription;
25-
if (pathDescription == null) {
26-
return null;
27-
}
28-
29-
final isExternal = !pathResolver.isWithin('', pathDescription.path);
30-
if (!isExternal) return null;
25+
if (dependency is! PathDependency) return null;
26+
if (pathResolver.isWithin('', dependency.path)) return null;
3127

3228
return _ExternalPathDependency(
33-
name: dependency.name,
34-
path: path.join(projectDirectory.path, pathDescription.path),
29+
name: path.basenameWithoutExtension(dependency.path),
30+
path: path.join(projectDirectory.path, dependency.path),
3531
);
3632
},
3733
)
3834
.whereType<_ExternalPathDependency>()
3935
.toList();
4036

41-
if (externalPathDependencies.isEmpty) {
42-
return [];
43-
}
37+
if (externalPathDependencies.isEmpty) return [];
4438

4539
final packagesDirectory = Directory(
4640
pathResolver.join(
@@ -68,17 +62,20 @@ Future<List<String>> createExternalPackagesFolder({
6862
buildDirectory.path,
6963
'pubspec_overrides.yaml',
7064
),
71-
).writeAsString('''
65+
).writeAsString(
66+
'''
7267
dependency_overrides:
7368
${copiedExternalPathDependencies.map(
74-
(dependency) {
75-
final name = dependency.name;
76-
final path =
77-
pathResolver.relative(dependency.path, from: buildDirectory.path);
78-
return ' $name:\n path: $path';
79-
},
80-
).join('\n')}
81-
''');
69+
(dependency) {
70+
final name = dependency.name;
71+
final path =
72+
pathResolver.relative(dependency.path, from: buildDirectory.path);
73+
return ' $name:\n path: $path';
74+
},
75+
).join('\n')}
76+
''',
77+
mode: FileMode.append,
78+
);
8279

8380
return copiedExternalPathDependencies
8481
.map((dependency) => dependency.path)

bricks/dart_frog_prod_server/hooks/lib/src/disable_workspace_resolution.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ import 'package:path/path.dart' as path;
66
/// https://github.com/dart-lang/pub/issues/4594
77
void disableWorkspaceResolution(
88
HookContext context, {
9-
required String workingDirectory,
9+
required String buildDirectory,
1010
required void Function(int exitCode) exit,
1111
}) {
1212
try {
1313
File(
14-
path.join(workingDirectory, 'pubspec_overrides.yaml'),
15-
).writeAsStringSync('resolution: null', mode: FileMode.append);
14+
path.join(buildDirectory, 'pubspec_overrides.yaml'),
15+
).writeAsStringSync('resolution: null\n', mode: FileMode.append);
1616
} on Exception catch (e) {
1717
context.logger.err('$e');
1818
exit(1);

bricks/dart_frog_prod_server/hooks/lib/src/get_internal_path_dependencies.dart

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,17 @@ import 'dart:io' as io;
22

33
import 'package:dart_frog_prod_server_hooks/dart_frog_prod_server_hooks.dart';
44
import 'package:path/path.dart' as path;
5+
import 'package:pubspec_parse/pubspec_parse.dart';
56

67
Future<List<String>> getInternalPathDependencies(io.Directory directory) async {
7-
final pubspecLock = await getPubspecLock(directory.path);
8+
final pubspec = await getPubspec(directory.path);
89

9-
final internalPathDependencies = pubspecLock.packages.where(
10+
final internalPathDependencies = pubspec.dependencies.values.where(
1011
(dependency) {
11-
final pathDescription = dependency.pathDescription;
12-
if (pathDescription == null) {
13-
return false;
14-
}
15-
16-
return path.isWithin('', pathDescription.path);
12+
if (dependency is! PathDependency) return false;
13+
return path.isWithin('', dependency.path);
1714
},
18-
);
15+
).cast<PathDependency>();
1916

20-
return internalPathDependencies
21-
.map((dependency) => dependency.pathDescription!.path)
22-
.toList();
17+
return internalPathDependencies.map((dependency) => dependency.path).toList();
2318
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import 'dart:io';
2+
3+
import 'package:path/path.dart' as path;
4+
import 'package:pubspec_parse/pubspec_parse.dart';
5+
6+
Future<Pubspec> getPubspec(
7+
String workingDirectory, {
8+
path.Context? pathContext,
9+
}) async {
10+
const pubspecYaml = 'pubspec.yaml';
11+
final pathResolver = pathContext ?? path.context;
12+
final pubspecFile = File(
13+
workingDirectory.isEmpty
14+
? pubspecYaml
15+
: pathResolver.join(workingDirectory, pubspecYaml),
16+
);
17+
18+
final content = await pubspecFile.readAsString();
19+
return Pubspec.parse(content);
20+
}

bricks/dart_frog_prod_server/hooks/lib/src/get_pubspec_lock.dart

Lines changed: 0 additions & 19 deletions
This file was deleted.

0 commit comments

Comments
 (0)