Skip to content

Commit 30df8ed

Browse files
committed
refactor: go back to lockfiles
1 parent 3465341 commit 30df8ed

12 files changed

+864
-168
lines changed

bricks/dart_frog_prod_server/hooks/lib/dart_frog_prod_server_hooks.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ export 'src/dart_pub_get.dart';
55
export 'src/disable_workspace_resolution.dart';
66
export 'src/exit_overrides.dart';
77
export 'src/get_internal_path_dependencies.dart';
8-
export 'src/get_pubspec.dart';
8+
export 'src/get_pubspec_lock.dart';
99
export 'src/uses_workspace_resolution.dart';

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

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ 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';
76

87
/// Signature of [io.copyPath].
98
typedef CopyPath = Future<void> Function(String from, String to);
@@ -14,27 +13,34 @@ Future<List<String>> createExternalPackagesFolder({
1413
CopyPath copyPath = io.copyPath,
1514
}) async {
1615
final pathResolver = path.context;
17-
final pubspec = await getPubspec(
16+
final pubspecLock = await getPubspecLock(
1817
projectDirectory.path,
1918
pathContext: path.context,
2019
);
2120

22-
final externalPathDependencies = pubspec.dependencies.values
21+
final externalPathDependencies = pubspecLock.packages
2322
.map(
2423
(dependency) {
25-
if (dependency is! PathDependency) return null;
26-
if (pathResolver.isWithin('', dependency.path)) return null;
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;
2731

2832
return _ExternalPathDependency(
29-
name: path.basenameWithoutExtension(dependency.path),
30-
path: path.join(projectDirectory.path, dependency.path),
33+
name: dependency.name,
34+
path: path.join(projectDirectory.path, pathDescription.path),
3135
);
3236
},
3337
)
3438
.whereType<_ExternalPathDependency>()
3539
.toList();
3640

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

3945
final packagesDirectory = Directory(
4046
pathResolver.join(
@@ -62,20 +68,17 @@ Future<List<String>> createExternalPackagesFolder({
6268
buildDirectory.path,
6369
'pubspec_overrides.yaml',
6470
),
65-
).writeAsString(
66-
'''
71+
).writeAsString('''
6772
dependency_overrides:
6873
${copiedExternalPathDependencies.map(
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-
);
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+
''');
7982

8083
return copiedExternalPathDependencies
8184
.map((dependency) => dependency.path)

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

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,22 @@ 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';
65

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

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

16-
return internalPathDependencies.map((dependency) => dependency.path).toList();
20+
return internalPathDependencies
21+
.map((dependency) => dependency.pathDescription!.path)
22+
.toList();
1723
}

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

Lines changed: 0 additions & 20 deletions
This file was deleted.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import 'dart:io';
2+
3+
import 'package:dart_frog_prod_server_hooks/src/pubspec_lock/pubspec_lock.dart';
4+
import 'package:path/path.dart' as path;
5+
6+
Future<PubspecLock> getPubspecLock(
7+
String workingDirectory, {
8+
path.Context? pathContext,
9+
}) async {
10+
final pathResolver = pathContext ?? path.context;
11+
final pubspecLockFile = File(
12+
workingDirectory.isEmpty
13+
? 'pubspec.lock'
14+
: pathResolver.join(workingDirectory, 'pubspec.lock'),
15+
);
16+
17+
final content = await pubspecLockFile.readAsString();
18+
return PubspecLock.fromString(content);
19+
}
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
import 'dart:collection';
2+
3+
import 'package:equatable/equatable.dart';
4+
import 'package:yaml/yaml.dart';
5+
6+
/// {@template pubspec_lock_parse_exception}
7+
/// Thrown when a [PubspecLock] fails to parse.
8+
/// {@endtemplate}
9+
class PubspecLockParseException implements Exception {
10+
/// {@macro pubspec_lock_parse_exception}
11+
const PubspecLockParseException();
12+
}
13+
14+
/// A representation of a pubspec.lock file.
15+
class PubspecLock {
16+
const PubspecLock._({
17+
required this.packages,
18+
});
19+
20+
/// Parses a [PubspecLock] from a string.
21+
///
22+
/// If no packages are found, an empty [PubspecLock] is returned. Those
23+
/// packages entries that cannot be parsed are ignored.
24+
///
25+
/// It throws a [PubspecLockParseException] if the string cannot be parsed
26+
/// as a [YamlMap].
27+
factory PubspecLock.fromString(String content) {
28+
late final YamlMap yaml;
29+
try {
30+
yaml = loadYaml(content) as YamlMap;
31+
// ignoring for backward compatibility
32+
// ignore: avoid_catches_without_on_clauses
33+
} catch (_) {
34+
throw const PubspecLockParseException();
35+
}
36+
37+
if (!yaml.containsKey('packages')) {
38+
return PubspecLock.empty;
39+
}
40+
41+
final packages = yaml['packages'] as YamlMap;
42+
43+
final parsedPackages = <PubspecLockPackage>[];
44+
for (final entry in packages.entries) {
45+
try {
46+
final package = PubspecLockPackage.fromYamlMap(
47+
name: entry.key as String,
48+
data: entry.value as YamlMap,
49+
);
50+
parsedPackages.add(package);
51+
// ignoring for backward compatibility
52+
// ignore: avoid_catches_without_on_clauses
53+
} catch (_) {
54+
// Ignore those packages that for some reason cannot be parsed.
55+
}
56+
}
57+
58+
return PubspecLock._(
59+
packages: UnmodifiableListView(parsedPackages),
60+
);
61+
}
62+
63+
/// An empty [PubspecLock].
64+
static PubspecLock empty = PubspecLock._(
65+
packages: UnmodifiableListView([]),
66+
);
67+
68+
/// All the dependencies in the pubspec.lock file.
69+
final UnmodifiableListView<PubspecLockPackage> packages;
70+
}
71+
72+
/// {@template pubspec_lock_dependency}
73+
/// A representation of a dependency in a pubspec.lock file.
74+
/// {@endtemplate}
75+
class PubspecLockPackage extends Equatable {
76+
/// {@macro pubspec_lock_dependency}
77+
const PubspecLockPackage({
78+
required this.name,
79+
required this.type,
80+
this.pathDescription,
81+
});
82+
83+
/// Parses a [PubspecLockPackage] from a [YamlMap].
84+
factory PubspecLockPackage.fromYamlMap({
85+
required String name,
86+
required YamlMap data,
87+
}) {
88+
final dependency = data['dependency'] as String;
89+
final dependencyType = PubspecLockPackageDependencyType.parse(dependency);
90+
91+
final description = data['description'] as YamlMap?;
92+
final pathDescription = description != null
93+
? PubspecPackagePathDescription.tryParse(description)
94+
: null;
95+
96+
return PubspecLockPackage(
97+
name: name,
98+
type: dependencyType,
99+
pathDescription: pathDescription,
100+
);
101+
}
102+
103+
/// The name of the dependency.
104+
final String name;
105+
106+
/// {@macro pubspec_lock_dependency_type}
107+
final PubspecLockPackageDependencyType type;
108+
109+
/// {@macro pubspec_package_path_description}
110+
final PubspecPackagePathDescription? pathDescription;
111+
112+
@override
113+
List<Object?> get props => [name, type, pathDescription];
114+
}
115+
116+
/// {@template pubspec_lock_dependency_type}
117+
/// The type of a [PubspecLockPackage].
118+
/// {@endtemplate}
119+
enum PubspecLockPackageDependencyType {
120+
/// Another package that your package needs to work.
121+
///
122+
/// See also:
123+
///
124+
/// * [Dart's dependency documentation](https://dart.dev/tools/pub/dependencies)
125+
directMain._('direct main'),
126+
127+
/// Another package that your package needs during development.
128+
///
129+
/// See also:
130+
///
131+
/// * [Dart's developer dependency documentation](https://dart.dev/tools/pub/dependencies#dev-dependencies)
132+
directDev._('direct dev'),
133+
134+
/// A dependency that your package indirectly uses because one of its
135+
/// dependencies requires it.
136+
///
137+
/// See also:
138+
///
139+
/// * [Dart's transitive dependency documentation](https://dart.dev/tools/pub/glossary#transitive-)
140+
transitive._('transitive'),
141+
142+
/// A dependency that your package overrides that is not already a
143+
/// `direct main` or `direct dev` dependency.
144+
///
145+
/// See also:
146+
///
147+
/// * [Dart's dependency override documentation](https://dart.dev/tools/pub/dependencies#dependency-overrides)
148+
directOverridden._('direct overridden');
149+
150+
const PubspecLockPackageDependencyType._(this.value);
151+
152+
/// Parses a [PubspecLockPackageDependencyType] from a string.
153+
///
154+
/// Throws an [ArgumentError] if the string is not a valid dependency type.
155+
factory PubspecLockPackageDependencyType.parse(String value) {
156+
if (_valueMap.containsKey(value)) {
157+
return _valueMap[value]!;
158+
}
159+
160+
throw ArgumentError.value(
161+
value,
162+
'value',
163+
'Invalid PubspecLockPackageDependencyType value.',
164+
);
165+
}
166+
167+
static Map<String, PubspecLockPackageDependencyType> _valueMap = {
168+
for (final type in PubspecLockPackageDependencyType.values)
169+
type.value: type,
170+
};
171+
172+
/// The string representation of the [PubspecLockPackageDependencyType]
173+
/// as it appears in a pubspec.lock file.
174+
final String value;
175+
}
176+
177+
/// {@template pubspec_package_path_description}
178+
/// The description of a path dependency in a pubspec.lock file.
179+
///
180+
/// For example, in:
181+
/// ```yaml
182+
/// my_package:
183+
/// dependency: "direct main"
184+
/// description:
185+
/// path: "packages/my_package"
186+
/// relative: true
187+
/// source: path
188+
/// version: "1.0.0+1"
189+
/// ```
190+
///
191+
/// The description is:
192+
/// ```yaml
193+
/// path: "packages/my_package"
194+
/// relative: true
195+
/// ```
196+
///
197+
/// See also:
198+
///
199+
/// * [PubspecPackagePathDescription.tryParse], which attempts to parses a
200+
/// [YamlMap] into a [PubspecPackagePathDescription].
201+
/// {@endtemplate}
202+
class PubspecPackagePathDescription extends Equatable {
203+
const PubspecPackagePathDescription({
204+
required this.path,
205+
required this.relative,
206+
});
207+
208+
/// Attempts to parse a [YamlMap] into a [PubspecPackagePathDescription].
209+
///
210+
/// Returns `null` if the [YamlMap] does not contain the required data
211+
/// to create a [PubspecPackagePathDescription].
212+
static PubspecPackagePathDescription? tryParse(YamlMap data) {
213+
if ((!data.containsKey('path') || data['path'] is! String) ||
214+
(!data.containsKey('relative') || data['relative'] is! bool)) {
215+
return null;
216+
}
217+
218+
final path = data['path'] as String;
219+
final relative = data['relative'] as bool;
220+
221+
return PubspecPackagePathDescription(
222+
path: path,
223+
relative: relative,
224+
);
225+
}
226+
227+
final String path;
228+
final bool relative;
229+
230+
@override
231+
List<Object?> get props => [path, relative];
232+
}

0 commit comments

Comments
 (0)