From 655ff348fa27a503cf43342397fbc1d7e310945d Mon Sep 17 00:00:00 2001 From: Sigurd Meldgaard Date: Thu, 14 Mar 2024 15:25:05 +0000 Subject: [PATCH 1/2] Refactor preparing for workspaces --- lib/src/command/add.dart | 24 +-- lib/src/command/dependency_services.dart | 62 ++++--- lib/src/command/deps.dart | 44 ++--- lib/src/command/lish.dart | 10 +- lib/src/command/outdated.dart | 41 +++-- lib/src/command/remove.dart | 11 +- lib/src/command/run.dart | 2 +- lib/src/command/unpack.dart | 4 +- lib/src/command/upgrade.dart | 51 +++--- lib/src/command/uploader.dart | 2 +- lib/src/entrypoint.dart | 161 +++++++++++------- lib/src/executable.dart | 8 +- lib/src/global_packages.dart | 17 +- lib/src/log.dart | 25 ++- lib/src/package.dart | 7 + lib/src/package_graph.dart | 6 +- lib/src/pubspec_utils.dart | 8 +- lib/src/solver/solve_suggestions.dart | 25 +-- lib/src/validator.dart | 12 +- lib/src/validator/analyze.dart | 4 +- lib/src/validator/changelog.dart | 2 +- lib/src/validator/dependency.dart | 11 +- lib/src/validator/dependency_override.dart | 11 +- lib/src/validator/deprecated_fields.dart | 8 +- lib/src/validator/devtools_extension.dart | 6 +- lib/src/validator/directory.dart | 4 +- lib/src/validator/executable.dart | 6 +- lib/src/validator/flutter_constraint.dart | 2 +- lib/src/validator/flutter_plugin_format.dart | 2 +- lib/src/validator/gitignore.dart | 10 +- lib/src/validator/leak_detection.dart | 4 +- lib/src/validator/name.dart | 8 +- lib/src/validator/pubspec_field.dart | 8 +- lib/src/validator/pubspec_typo.dart | 2 +- .../validator/relative_version_numbering.dart | 17 +- lib/src/validator/sdk_constraint.dart | 4 +- lib/src/validator/size.dart | 6 +- lib/src/validator/strict_dependencies.dart | 7 +- test/package_list_files_test.dart | 47 ++--- test/test_pub.dart | 2 +- ...--verbose and on unexpected exceptions.txt | 4 - 41 files changed, 392 insertions(+), 303 deletions(-) diff --git a/lib/src/command/add.dart b/lib/src/command/add.dart index 16cfa97b9..9d74d3e17 100644 --- a/lib/src/command/add.dart +++ b/lib/src/command/add.dart @@ -192,7 +192,9 @@ Specify multiple sdk packages with descriptors.'''); /// Compute a pubspec that will depend on all the given packages, but the /// actual constraint will only be determined after a resolution decides the /// best version. - var resolutionPubspec = entrypoint.root.pubspec; + // TODO(https://github.com/dart-lang/pub/issues/4127): This should + // operate on entrypoint.workPackage. + var resolutionPubspec = entrypoint.workspaceRoot.pubspec; for (final update in updates) { /// Perform version resolution in-memory. resolutionPubspec = await _addPackageToPubspec(resolutionPubspec, update); @@ -211,8 +213,8 @@ Specify multiple sdk packages with descriptors.'''); cache, Package( resolutionPubspec, - entrypoint.rootDir, - entrypoint.root.workspaceChildren, + entrypoint.workspaceRoot.dir, + entrypoint.workspaceRoot.workspaceChildren, ), ); } on GitException { @@ -250,12 +252,12 @@ Specify multiple sdk packages with descriptors.'''); /// ensure that the modification timestamp on `pubspec.lock` and /// `.dart_tool/package_config.json` is newer than `pubspec.yaml`, /// ensuring that [entrypoint.assertUptoDate] will pass. - writeTextFile(entrypoint.pubspecPath, newPubspecText); + writeTextFile(entrypoint.workspaceRoot.pubspecPath, newPubspecText); } String? overridesFileContents; final overridesPath = - p.join(entrypoint.rootDir, Pubspec.pubspecOverridesFilename); + p.join(entrypoint.workspaceRoot.dir, Pubspec.pubspecOverridesFilename); try { overridesFileContents = readTextFile(overridesPath); } on IOException { @@ -270,10 +272,11 @@ Specify multiple sdk packages with descriptors.'''); Pubspec.parse( newPubspecText, cache.sources, - location: Uri.parse(entrypoint.pubspecPath), + location: Uri.parse(entrypoint.workspaceRoot.pubspecPath), overridesFileContents: overridesFileContents, overridesLocation: Uri.file(overridesPath), - containingDescription: RootDescription(entrypoint.rootDir), + containingDescription: + RootDescription(entrypoint.workspaceRoot.dir), ), ) .acquireDependencies( @@ -680,8 +683,9 @@ Specify multiple sdk packages with descriptors.'''); List resultPackages, List<_ParseResult> updates, ) { - final yamlEditor = YamlEditor(readTextFile(entrypoint.pubspecPath)); - log.io('Reading ${entrypoint.pubspecPath}.'); + final yamlEditor = + YamlEditor(readTextFile(entrypoint.workspaceRoot.pubspecPath)); + log.io('Reading ${entrypoint.workspaceRoot.pubspecPath}.'); log.fine('Contents:\n$yamlEditor'); for (final update in updates) { @@ -701,7 +705,7 @@ Specify multiple sdk packages with descriptors.'''); : VersionConstraint.any), ), cache, - entrypoint, + entrypoint.workPackage, ); if (yamlEditor.parseAt( diff --git a/lib/src/command/dependency_services.dart b/lib/src/command/dependency_services.dart index 5d6646868..b1f17ac96 100644 --- a/lib/src/command/dependency_services.dart +++ b/lib/src/command/dependency_services.dart @@ -65,15 +65,16 @@ class DependencyServicesReportCommand extends PubCommand { throw FormatException('"target" should be a String.'); } - final compatiblePubspec = stripDependencyOverrides(entrypoint.root.pubspec); + final compatiblePubspec = + stripDependencyOverrides(entrypoint.workspaceRoot.pubspec); final breakingPubspec = stripVersionBounds(compatiblePubspec); final compatiblePackagesResult = await _tryResolve( Package( compatiblePubspec, - entrypoint.rootDir, - entrypoint.root.workspaceChildren, + entrypoint.workspaceRoot.dir, + entrypoint.workspaceRoot.workspaceChildren, ), cache, additionalConstraints: additionalConstraints, @@ -82,8 +83,8 @@ class DependencyServicesReportCommand extends PubCommand { final breakingPackagesResult = await _tryResolve( Package( breakingPubspec, - entrypoint.rootDir, - entrypoint.root.workspaceChildren, + entrypoint.workspaceRoot.dir, + entrypoint.workspaceRoot.workspaceChildren, ), cache, additionalConstraints: additionalConstraints, @@ -123,8 +124,8 @@ class DependencyServicesReportCommand extends PubCommand { final singleBreakingPackagesResult = await _tryResolve( Package( singleBreakingPubspec, - entrypoint.rootDir, - entrypoint.root.workspaceChildren, + entrypoint.workspaceRoot.dir, + entrypoint.workspaceRoot.workspaceChildren, ), cache, ); @@ -144,8 +145,8 @@ class DependencyServicesReportCommand extends PubCommand { final smallestUpgradeResult = await _tryResolve( Package( atLeastCurrentPubspec, - entrypoint.rootDir, - entrypoint.root.workspaceChildren, + entrypoint.workspaceRoot.dir, + entrypoint.workspaceRoot.workspaceChildren, ), cache, solveType: SolveType.downgrade, @@ -230,15 +231,15 @@ class DependencyServicesListCommand extends PubCommand { @override Future runProtected() async { - final pubspec = entrypoint.root.pubspec; + final pubspec = entrypoint.workspaceRoot.pubspec; final currentPackages = fileExists(entrypoint.lockFilePath) ? entrypoint.lockFile.packages.values.toList() : (await _tryResolve( Package( pubspec, - entrypoint.rootDir, - entrypoint.root.workspaceChildren, + entrypoint.workspaceRoot.dir, + entrypoint.workspaceRoot.workspaceChildren, ), cache, ) ?? @@ -308,7 +309,7 @@ class DependencyServicesApplyCommand extends PubCommand { @override Future runProtected() async { - YamlEditor(readTextFile(entrypoint.pubspecPath)); + YamlEditor(readTextFile(entrypoint.workspaceRoot.pubspecPath)); final toApply = <_PackageVersion>[]; final input = json.decode(await utf8.decodeStream(stdin)); for (final change in input['dependencyChanges'] as Iterable) { @@ -323,8 +324,9 @@ class DependencyServicesApplyCommand extends PubCommand { ); } - final pubspec = entrypoint.root.pubspec; - final pubspecEditor = YamlEditor(readTextFile(entrypoint.pubspecPath)); + final pubspec = entrypoint.workspaceRoot.pubspec; + final pubspecEditor = + YamlEditor(readTextFile(entrypoint.workspaceRoot.pubspecPath)); final lockFile = fileExists(entrypoint.lockFilePath) ? readTextFile(entrypoint.lockFilePath) : null; @@ -450,16 +452,17 @@ class DependencyServicesApplyCommand extends PubCommand { Pubspec.parse( updatedPubspec, cache.sources, - location: toUri(entrypoint.pubspecPath), - containingDescription: RootDescription(entrypoint.rootDir), + location: toUri(entrypoint.workspaceRoot.pubspecPath), + containingDescription: + RootDescription(entrypoint.workspaceRoot.dir), ), - entrypoint.rootDir, - entrypoint.root.workspaceChildren, + entrypoint.workspaceRoot.dir, + entrypoint.workspaceRoot.workspaceChildren, ), lockFile: updatedLockfile, ); if (pubspecEditor.edits.isNotEmpty) { - writeTextFile(entrypoint.pubspecPath, updatedPubspec); + writeTextFile(entrypoint.workspaceRoot.pubspecPath, updatedPubspec); } // Only if we originally had a lock-file we write the resulting lockfile back. if (updatedLockfile != null) { @@ -717,14 +720,14 @@ Future> _computeCurrentPackages( if (fileExists(entrypoint.lockFilePath)) { currentPackages = Map.from(entrypoint.lockFile.packages); } else { - final resolution = await _tryResolve(entrypoint.root, cache) ?? + final resolution = await _tryResolve(entrypoint.workspaceRoot, cache) ?? (throw DataException('Failed to resolve pubspec')); currentPackages = Map.fromIterable( resolution, key: (e) => (e as PackageId).name, ); } - currentPackages.remove(entrypoint.root.name); + currentPackages.remove(entrypoint.workspaceRoot.name); return currentPackages; } @@ -762,7 +765,11 @@ Future> _computeUpgradeSet( ? SolveType.downgrade : SolveType.get, cache, - Package(pubspec, entrypoint.rootDir, entrypoint.root.workspaceChildren), + Package( + pubspec, + entrypoint.workspaceRoot.dir, + entrypoint.workspaceRoot.workspaceChildren, + ), lockFile: lockFile, additionalConstraints: additionalConstraints, ); @@ -785,7 +792,7 @@ Future> _computeUpgradeSet( 'name': p.name, 'version': p.versionOrHash(), 'kind': _kindString(pubspec, p.name), - 'source': _source(p, containingDir: entrypoint.root.dir), + 'source': _source(p, containingDir: entrypoint.workspaceRoot.dir), 'constraintBumped': originalConstraint == null ? null : upgradeType == _UpgradeType.compatible @@ -807,7 +814,10 @@ Future> _computeUpgradeSet( 'previousConstraint': originalConstraint?.toString(), 'previousSource': currentPackage == null ? null - : _source(currentPackage, containingDir: entrypoint.root.dir), + : _source( + currentPackage, + containingDir: entrypoint.workspaceRoot.dir, + ), }; }), // Find packages that were removed by the resolution @@ -825,7 +835,7 @@ Future> _computeUpgradeSet( 'previousConstraint': null, 'previous': _source( currentPackages[oldPackageName]!, - containingDir: entrypoint.root.dir, + containingDir: entrypoint.workspaceRoot.dir, ), }, ]; diff --git a/lib/src/command/deps.dart b/lib/src/command/deps.dart index 50f28d7a0..404fa619a 100644 --- a/lib/src/command/deps.dart +++ b/lib/src/command/deps.dart @@ -89,7 +89,7 @@ class DepsCommand extends PubCommand { usageException('Cannot combine --json and --style.'); } final visited = []; - final toVisit = [entrypoint.root.name]; + final toVisit = [entrypoint.workspaceRoot.name]; final packagesJson = []; final graph = await entrypoint.packageGraph; while (toVisit.isNotEmpty) { @@ -98,13 +98,14 @@ class DepsCommand extends PubCommand { visited.add(current); final currentPackage = (await entrypoint.packageGraph).packages[current]!; - final next = (current == entrypoint.root.name - ? entrypoint.root.immediateDependencies + final next = (current == entrypoint.workspaceRoot.name + ? entrypoint.workspaceRoot.immediateDependencies : currentPackage.dependencies) .keys .toList(); - final dependencyType = entrypoint.root.pubspec.dependencyType(current); - final kind = currentPackage == entrypoint.root + final dependencyType = + entrypoint.workspaceRoot.pubspec.dependencyType(current); + final kind = currentPackage == entrypoint.workspaceRoot ? 'root' : (dependencyType == DependencyType.direct ? 'direct' @@ -124,12 +125,12 @@ class DepsCommand extends PubCommand { } var executables = [ for (final package in [ - entrypoint.root, - ...entrypoint.root.immediateDependencies.keys + entrypoint.workspaceRoot, + ...entrypoint.workspaceRoot.immediateDependencies.keys .map((name) => graph.packages[name]), ]) ...package!.executableNames.map( - (name) => package == entrypoint.root + (name) => package == entrypoint.workspaceRoot ? ':$name' : (package.name == name ? name : '${package.name}:$name'), ), @@ -138,7 +139,7 @@ class DepsCommand extends PubCommand { buffer.writeln( JsonEncoder.withIndent(' ').convert( { - 'root': entrypoint.root.name, + 'root': entrypoint.workspaceRoot.name, 'packages': packagesJson, 'sdks': [ for (var sdk in sdks.values) @@ -158,7 +159,7 @@ class DepsCommand extends PubCommand { buffer.writeln("${log.bold('${sdk.name} SDK')} ${sdk.version}"); } - buffer.writeln(_labelPackage(entrypoint.root)); + buffer.writeln(_labelPackage(entrypoint.workspaceRoot)); switch (argResults['style']) { case 'compact': @@ -186,7 +187,7 @@ class DepsCommand extends PubCommand { Future _outputCompact( StringBuffer buffer, ) async { - var root = entrypoint.root; + var root = entrypoint.workspaceRoot; await _outputCompactPackages( 'dependencies', root.dependencies.keys, @@ -239,7 +240,7 @@ class DepsCommand extends PubCommand { /// For each dependency listed, *that* package's immediate dependencies are /// shown. Future _outputList(StringBuffer buffer) async { - var root = entrypoint.root; + var root = entrypoint.workspaceRoot; await _outputListSection('dependencies', root.dependencies.keys, buffer); if (_includeDev) { await _outputListSection( @@ -300,14 +301,15 @@ class DepsCommand extends PubCommand { // being added to the tree, and the parent map that will receive that // package. var toWalk = Queue<(Package, Map)>(); - var visited = {entrypoint.root.name}; + var visited = {entrypoint.workspaceRoot.name}; // Start with the root dependencies. var packageTree = {}; var immediateDependencies = - entrypoint.root.immediateDependencies.keys.toSet(); + entrypoint.workspaceRoot.immediateDependencies.keys.toSet(); if (!_includeDev) { - immediateDependencies.removeAll(entrypoint.root.devDependencies.keys); + immediateDependencies + .removeAll(entrypoint.workspaceRoot.devDependencies.keys); } for (var name in immediateDependencies) { toWalk.add((await _getPackage(name), packageTree)); @@ -343,7 +345,7 @@ class DepsCommand extends PubCommand { /// Gets the names of the non-immediate dependencies of the root package. Future> _getTransitiveDependencies() async { var transitive = await _getAllDependencies(); - var root = entrypoint.root; + var root = entrypoint.workspaceRoot; transitive.remove(root.name); transitive.removeAll(root.dependencies.keys); if (_includeDev) { @@ -359,8 +361,8 @@ class DepsCommand extends PubCommand { return graph.packages.keys.toSet(); } - var nonDevDependencies = entrypoint.root.dependencies.keys.toList() - ..addAll(entrypoint.root.dependencyOverrides.keys); + var nonDevDependencies = entrypoint.workspaceRoot.dependencies.keys.toList() + ..addAll(entrypoint.workspaceRoot.dependencyOverrides.keys); return nonDevDependencies .expand(graph.transitiveDependencies) .map((package) => package.name) @@ -384,10 +386,10 @@ class DepsCommand extends PubCommand { Future _outputExecutables(StringBuffer buffer) async { final graph = await entrypoint.packageGraph; var packages = [ - entrypoint.root, + entrypoint.workspaceRoot, ...(_includeDev - ? entrypoint.root.immediateDependencies - : entrypoint.root.dependencies) + ? entrypoint.workspaceRoot.immediateDependencies + : entrypoint.workspaceRoot.dependencies) .keys .map((name) => graph.packages[name]!), ]; diff --git a/lib/src/command/lish.dart b/lib/src/command/lish.dart index f716b1b1d..dec54f1d2 100644 --- a/lib/src/command/lish.dart +++ b/lib/src/command/lish.dart @@ -295,19 +295,19 @@ the \$PUB_HOSTED_URL environment variable.''', await entrypoint.acquireDependencies(SolveType.get); } - var files = entrypoint.root.listFiles(); - log.fine('Archiving and publishing ${entrypoint.root.name}.'); + var files = entrypoint.workPackage.listFiles(); + log.fine('Archiving and publishing ${entrypoint.workPackage.name}.'); // Show the package contents so the user can verify they look OK. - var package = entrypoint.root; + var package = entrypoint.workPackage; final host = computeHost(package.pubspec); log.message( 'Publishing ${package.name} ${package.version} to $host:\n' - '${tree.fromFiles(files, baseDir: entrypoint.rootDir, showFileSizes: true)}', + '${tree.fromFiles(files, baseDir: entrypoint.workPackage.dir, showFileSizes: true)}', ); final packageBytes = - await createTarGz(files, baseDir: entrypoint.rootDir).toBytes(); + await createTarGz(files, baseDir: entrypoint.workPackage.dir).toBytes(); log.message( '\nTotal compressed archive size: ${_readableFileSize(packageBytes.length)}.\n', diff --git a/lib/src/command/outdated.dart b/lib/src/command/outdated.dart index 192f1bd64..212e96708 100644 --- a/lib/src/command/outdated.dart +++ b/lib/src/command/outdated.dart @@ -128,8 +128,8 @@ Consider using the Dart 2.19 sdk to migrate to null safety.'''); } final rootPubspec = includeDependencyOverrides - ? entrypoint.root.pubspec - : stripDependencyOverrides(entrypoint.root.pubspec); + ? entrypoint.workspaceRoot.pubspec + : stripDependencyOverrides(entrypoint.workspaceRoot.pubspec); final upgradablePubspec = includeDevDependencies ? rootPubspec @@ -148,8 +148,8 @@ Consider using the Dart 2.19 sdk to migrate to null safety.'''); final upgradablePackagesResult = await _tryResolve( Package( upgradablePubspec, - entrypoint.rootDir, - entrypoint.root.workspaceChildren, + entrypoint.workspaceRoot.dir, + entrypoint.workspaceRoot.workspaceChildren, ), cache, lockFile: entrypoint.lockFile, @@ -160,8 +160,8 @@ Consider using the Dart 2.19 sdk to migrate to null safety.'''); final resolvablePackagesResult = await _tryResolve( Package( resolvablePubspec, - entrypoint.rootDir, - entrypoint.root.workspaceChildren, + entrypoint.workspaceRoot.dir, + entrypoint.workspaceRoot.workspaceChildren, ), cache, lockFile: entrypoint.lockFile, @@ -179,9 +179,18 @@ Consider using the Dart 2.19 sdk to migrate to null safety.'''); /// closure of the non-dev dependencies from the root in at least one of /// the current, upgradable and resolvable resolutions. final nonDevDependencies = { - ...await _nonDevDependencyClosure(entrypoint.root, currentPackages), - ...await _nonDevDependencyClosure(entrypoint.root, upgradablePackages), - ...await _nonDevDependencyClosure(entrypoint.root, resolvablePackages), + ...await _nonDevDependencyClosure( + entrypoint.workspaceRoot, + currentPackages, + ), + ...await _nonDevDependencyClosure( + entrypoint.workspaceRoot, + upgradablePackages, + ), + ...await _nonDevDependencyClosure( + entrypoint.workspaceRoot, + resolvablePackages, + ), }; Future<_PackageDetails> analyzeDependency(PackageRef packageRef) async { @@ -197,7 +206,8 @@ Consider using the Dart 2.19 sdk to migrate to null safety.'''); var latestIsOverridden = false; PackageId? latest; // If not overridden in current resolution we can use this - if (!entrypoint.root.pubspec.dependencyOverrides.containsKey(name)) { + if (!entrypoint.workspaceRoot.pubspec.dependencyOverrides + .containsKey(name)) { latest ??= await cache.getLatest( current?.toRef(), version: current?.version, @@ -263,7 +273,7 @@ Consider using the Dart 2.19 sdk to migrate to null safety.'''); final currentVersionDetails = await _describeVersion( current, - entrypoint.root.pubspec.dependencyOverrides.containsKey(name), + entrypoint.workspaceRoot.pubspec.dependencyOverrides.containsKey(name), ); final upgradableVersionDetails = await _describeVersion( @@ -288,7 +298,8 @@ Consider using the Dart 2.19 sdk to migrate to null safety.'''); // Filter out advisories added to `ignored_advisores` in the root pubspec. packageAdvisories = packageAdvisories .where( - (adv) => entrypoint.root.pubspec.ignoredAdvisories.intersection({ + (adv) => entrypoint.workspaceRoot.pubspec.ignoredAdvisories + .intersection({ ...adv.aliases, adv.id, }).isEmpty, @@ -322,7 +333,7 @@ Consider using the Dart 2.19 sdk to migrate to null safety.'''); final rows = <_PackageDetails>[]; final visited = { - entrypoint.root.name, + entrypoint.workspaceRoot.name, }; // Add all dependencies from the lockfile. for (final id in [ @@ -961,9 +972,9 @@ _DependencyKind _kind( Entrypoint entrypoint, Set nonDevTransitive, ) { - if (entrypoint.root.dependencies.containsKey(name)) { + if (entrypoint.workspaceRoot.dependencies.containsKey(name)) { return _DependencyKind.direct; - } else if (entrypoint.root.devDependencies.containsKey(name)) { + } else if (entrypoint.workspaceRoot.devDependencies.containsKey(name)) { return _DependencyKind.dev; } else { if (nonDevTransitive.contains(name)) { diff --git a/lib/src/command/remove.dart b/lib/src/command/remove.dart index 5490098cd..152c1df6b 100644 --- a/lib/src/command/remove.dart +++ b/lib/src/command/remove.dart @@ -88,7 +88,9 @@ To remove a dependency override of a package prefix the package name with /// Update the pubspec. _writeRemovalToPubspec(targets); } - final rootPubspec = entrypoint.root.pubspec; + // TODO(https://github.com/dart-lang/pub/issues/4127): This should + // operate on entrypoint.workPackage. + final rootPubspec = entrypoint.workspaceRoot.pubspec; final newPubspec = _removePackagesFromPubspec(rootPubspec, targets); await entrypoint.withPubspec(newPubspec).acquireDependencies( @@ -138,7 +140,8 @@ To remove a dependency override of a package prefix the package name with void _writeRemovalToPubspec(Iterable<_PackageRemoval> packages) { ArgumentError.checkNotNull(packages, 'packages'); - final yamlEditor = YamlEditor(readTextFile(entrypoint.pubspecPath)); + final yamlEditor = + YamlEditor(readTextFile(entrypoint.workspaceRoot.pubspecPath)); for (final package in packages) { final dependencyKeys = package.removeFromOverride @@ -165,13 +168,13 @@ To remove a dependency override of a package prefix the package name with } if (!found) { log.warning( - 'Package "$name" was not found in ${entrypoint.pubspecPath}!', + 'Package "$name" was not found in ${entrypoint.workspaceRoot.pubspecPath}!', ); } } /// Windows line endings are already handled by [yamlEditor] - writeTextFile(entrypoint.pubspecPath, yamlEditor.toString()); + writeTextFile(entrypoint.workspaceRoot.pubspecPath, yamlEditor.toString()); } } diff --git a/lib/src/command/run.dart b/lib/src/command/run.dart index 9fe1a0392..c949551dd 100644 --- a/lib/src/command/run.dart +++ b/lib/src/command/run.dart @@ -69,7 +69,7 @@ class RunCommand extends PubCommand { dataError('The --(no-)sound-null-safety flag is no longer supported.'); } - var package = entrypoint.root.name; + var package = entrypoint.workspaceRoot.name; var executable = argResults.rest[0]; var args = argResults.rest.skip(1).toList(); diff --git a/lib/src/command/unpack.dart b/lib/src/command/unpack.dart index ef7df9934..803d34c79 100644 --- a/lib/src/command/unpack.dart +++ b/lib/src/command/unpack.dart @@ -144,7 +144,9 @@ in a directory `foo-`. } finally { log.message('To explore type: cd $destinationDir'); if (e.example != null) { - log.message('To explore the example type: cd ${e.example!.rootDir}'); + log.message( + 'To explore the example type: cd ${e.example!.workspaceRoot.dir}', + ); } } } diff --git a/lib/src/command/upgrade.dart b/lib/src/command/upgrade.dart index 5fb176a84..91b0e2685 100644 --- a/lib/src/command/upgrade.dart +++ b/lib/src/command/upgrade.dart @@ -133,7 +133,7 @@ Consider using the Dart 2.19 sdk to migrate to null safety.'''); if (_upgradeMajorVersions) { if (argResults.flag('example') && entrypoint.example != null) { log.warning( - 'Running `upgrade --major-versions` only in `${entrypoint.rootDir}`. Run `$topLevelProgram pub upgrade --major-versions --directory example/` separately.', + 'Running `upgrade --major-versions` only in `${entrypoint.workspaceRoot.dir}`. Run `$topLevelProgram pub upgrade --major-versions --directory example/` separately.', ); } await _runUpgradeMajorVersions(); @@ -141,14 +141,14 @@ Consider using the Dart 2.19 sdk to migrate to null safety.'''); await _runUpgrade(entrypoint); if (_tighten) { final changes = tighten( - entrypoint.root.pubspec, + entrypoint.workspaceRoot.pubspec, entrypoint.lockFile.packages.values.toList(), ); if (!_dryRun) { final newPubspecText = _updatePubspec(changes); if (changes.isNotEmpty) { - writeTextFile(entrypoint.pubspecPath, newPubspecText); + writeTextFile(entrypoint.workspaceRoot.pubspecPath, newPubspecText); } } _outputChangeSummary(changes); @@ -192,7 +192,7 @@ Consider using the Dart 2.19 sdk to migrate to null safety.'''); final result = {...existingChanges}; if (argResults.flag('example') && entrypoint.example != null) { log.warning( - 'Running `upgrade --tighten` only in `${entrypoint.rootDir}`. Run `$topLevelProgram pub upgrade --tighten --directory example/` separately.', + 'Running `upgrade --tighten` only in `${entrypoint.workspaceRoot.dir}`. Run `$topLevelProgram pub upgrade --tighten --directory example/` separately.', ); } final toTighten = _packagesToUpgrade.isEmpty @@ -237,8 +237,8 @@ Consider using the Dart 2.19 sdk to migrate to null safety.'''); assert(_upgradeMajorVersions); final directDeps = [ - ...entrypoint.root.pubspec.dependencies.keys, - ...entrypoint.root.pubspec.devDependencies.keys, + ...entrypoint.workspaceRoot.pubspec.dependencies.keys, + ...entrypoint.workspaceRoot.pubspec.devDependencies.keys, ]; final toUpgrade = _packagesToUpgrade.isEmpty ? directDeps : _packagesToUpgrade; @@ -263,10 +263,12 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not: } Future _runUpgradeMajorVersions() async { + // TODO(https://github.com/dart-lang/pub/issues/4127): This should operate + // on all pubspecs in the workspace. final toUpgrade = _directDependenciesToUpgrade(); final resolvablePubspec = stripVersionBounds( - entrypoint.root.pubspec, + entrypoint.workspaceRoot.pubspec, stripOnly: toUpgrade, ); @@ -281,8 +283,8 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not: cache, Package( resolvablePubspec, - entrypoint.rootDir, - entrypoint.root.workspaceChildren, + entrypoint.workspaceRoot.dir, + entrypoint.workspaceRoot.workspaceChildren, ), ); }, @@ -296,8 +298,8 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not: // Mapping from original to changed value. var changes = {}; final declaredHostedDependencies = [ - ...entrypoint.root.pubspec.dependencies.values, - ...entrypoint.root.pubspec.devDependencies.values, + ...entrypoint.workspaceRoot.pubspec.dependencies.values, + ...entrypoint.workspaceRoot.pubspec.devDependencies.values, ].where((dep) => dep.source is HostedSource); for (final dep in declaredHostedDependencies) { final resolvedPackage = resolvedPackages[dep.name]!; @@ -308,7 +310,7 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not: } // Skip [dep] if it has a dependency_override. - if (entrypoint.root.dependencyOverrides.containsKey(dep.name)) { + if (entrypoint.workspaceRoot.dependencyOverrides.containsKey(dep.name)) { continue; } @@ -335,12 +337,12 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not: cache, Package( _updatedPubspec(newPubspecText, entrypoint), - entrypoint.rootDir, - entrypoint.root.workspaceChildren, + entrypoint.workspaceRoot.dir, + entrypoint.workspaceRoot.workspaceChildren, ), ); changes = tighten( - entrypoint.root.pubspec, + entrypoint.workspaceRoot.pubspec, solveResult.packages, existingChanges: changes, ); @@ -357,7 +359,7 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not: if (!_dryRun) { if (changes.isNotEmpty) { - writeTextFile(entrypoint.pubspecPath, newPubspecText); + writeTextFile(entrypoint.workspaceRoot.pubspecPath, newPubspecText); } } @@ -373,8 +375,8 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not: // If any of the packages to upgrade are dependency overrides, then we // show a warning. - final toUpgradeOverrides = - toUpgrade.where(entrypoint.root.dependencyOverrides.containsKey); + final toUpgradeOverrides = toUpgrade + .where(entrypoint.workspaceRoot.dependencyOverrides.containsKey); if (toUpgradeOverrides.isNotEmpty) { log.warning( 'Warning: dependency_overrides prevents upgrades for: ' @@ -388,7 +390,7 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not: Pubspec _updatedPubspec(String contents, Entrypoint entrypoint) { String? overridesFileContents; final overridesPath = - p.join(entrypoint.rootDir, Pubspec.pubspecOverridesFilename); + p.join(entrypoint.workspaceRoot.dir, Pubspec.pubspecOverridesFilename); try { overridesFileContents = readTextFile(overridesPath); } on IOException { @@ -397,10 +399,10 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not: return Pubspec.parse( contents, cache.sources, - location: Uri.parse(entrypoint.pubspecPath), + location: Uri.parse(entrypoint.workspaceRoot.pubspecPath), overridesFileContents: overridesFileContents, overridesLocation: Uri.file(overridesPath), - containingDescription: RootDescription(entrypoint.rootDir), + containingDescription: RootDescription(entrypoint.workspaceRoot.dir), ); } @@ -409,15 +411,16 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not: Map changes, ) { ArgumentError.checkNotNull(changes, 'changes'); - final yamlEditor = YamlEditor(readTextFile(entrypoint.pubspecPath)); - final deps = entrypoint.root.pubspec.dependencies.keys; + final yamlEditor = + YamlEditor(readTextFile(entrypoint.workspaceRoot.pubspecPath)); + final deps = entrypoint.workspaceRoot.pubspec.dependencies.keys; for (final change in changes.values) { final section = deps.contains(change.name) ? 'dependencies' : 'dev_dependencies'; yamlEditor.update( [section, change.name], - pubspecDescription(change, cache, entrypoint), + pubspecDescription(change, cache, entrypoint.workspaceRoot), ); } return yamlEditor.toString(); diff --git a/lib/src/command/uploader.dart b/lib/src/command/uploader.dart index c3ff77272..8a1602af7 100644 --- a/lib/src/command/uploader.dart +++ b/lib/src/command/uploader.dart @@ -49,7 +49,7 @@ class UploaderCommand extends PubCommand { Future runProtected() async { var packageName = ''; try { - packageName = entrypoint.root.name; + packageName = entrypoint.workspaceRoot.name; } on Exception catch (_) { // Probably run without a pubspec. // Just print error below without a specific package name. diff --git a/lib/src/entrypoint.dart b/lib/src/entrypoint.dart index 37e83686f..e20ef20a8 100644 --- a/lib/src/entrypoint.dart +++ b/lib/src/entrypoint.dart @@ -37,51 +37,75 @@ import 'source/unknown.dart'; import 'system_cache.dart'; import 'utils.dart'; -/// The context surrounding the root package pub is operating on. +/// The context surrounding the workspace pub is operating on. /// /// Pub operates over a directed graph of dependencies that starts at a root /// "entrypoint" package. This is typically the package where the current -/// working directory is located. An entrypoint knows the [root] package it is -/// associated with and is responsible for managing the "packages" directory -/// for it. +/// working directory is located. /// -/// That directory contains symlinks to all packages used by an app. These links -/// point either to the [SystemCache] or to some other location on the local -/// filesystem. +/// An entrypoint knows the [workspaceRoot] package it is associated with and is +/// responsible for managing the package config (.dart_tool/package_config.json) +/// and lock file (pubspec.lock) for it. /// /// While entrypoints are typically applications, a pure library package may end -/// up being used as an entrypoint. Also, a single package may be used as an -/// entrypoint in one context but not in another. For example, a package that -/// contains a reusable library may not be the entrypoint when used by an app, -/// but may be the entrypoint when you're running its tests. +/// up being used as an entrypoint while under development. Also, a single +/// package may be used as an entrypoint in one context but not in another. For +/// example, a package that contains a reusable library may not be the +/// entrypoint when used by an app, but may be the entrypoint when you're +/// running its tests. class Entrypoint { - /// The directory where the package is stored. + /// The directory where this entrypoint is created. /// - /// For cached global packages this is `PUB_CACHE/global_packages/foo - /// - /// For path-activated global packages this is the actual package dir. - /// - /// The lock file and package configurations are to be found relative to here. - final String rootDir; + /// [workspaceRoot] will be the package in the nearest parent directory that + /// has `resolution: null` + // TODO(https://github.com/dart-lang/pub/issues/4127): make this actually + // true. + final String workingDir; - Package? _root; + Package? _workspaceRoot; /// The root package this entrypoint is associated with. /// /// For a global package, this is the activated package. - Package get root => _root ??= Package.load( + Package get workspaceRoot => _workspaceRoot ??= Package.load( null, - rootDir, + workingDir, cache.sources, withPubspecOverrides: true, ); + bool get canFindWorkspaceRoot { + try { + workspaceRoot; + return true; + } on FileException { + return false; + } + } + + /// The "focus" package that the current command should act upon. + /// + /// It will be the package in the nearest parent directory to `workingDir`. + /// Example: if a workspace looks like this: + // TODO(https://github.com/dart-lang/pub/issues/4127): make this actually + // true. + /// + /// foo/ pubspec.yaml # contains `workspace: [- 'bar'] bar/ pubspec.yaml # + /// contains `resolution: workspace`. + /// + /// Running `pub add` in `foo/bar` will have bar as workPackage, and add + /// dependencies to `foo/bar/pubspec.yaml`. + /// + /// Running `pub add` in `foo` will have foo as workPackage, and add + /// dependencies to `foo/pubspec.yaml`. + Package get workPackage => workspaceRoot; + /// The system-wide cache which caches packages that need to be fetched over /// the network. final SystemCache cache; /// Whether this entrypoint exists within the package cache. - bool get isCached => p.isWithin(cache.rootDir, rootDir); + bool get isCached => p.isWithin(cache.rootDir, workingDir); /// Whether this is an entrypoint for a globally-activated package. /// @@ -165,7 +189,7 @@ class Entrypoint { // TODO(sigurdm): consider having [ensureUptoDate] and [acquireDependencies] // return the package-graph, such it by construction will always made from an // up-to-date package-config. - await ensureUpToDate(rootDir, cache: cache); + await ensureUpToDate(workspaceRoot.dir, cache: cache); var packages = { for (var packageEntry in packageConfig.nonInjectedPackages) packageEntry.name: Package.load( @@ -174,7 +198,7 @@ class Entrypoint { cache.sources, ), }; - packages[root.name] = root; + packages[workspaceRoot.name] = workspaceRoot; return PackageGraph(this, packages); } @@ -184,32 +208,28 @@ class Entrypoint { /// The path to the entrypoint's ".dart_tool/package_config.json" file /// relative to the current working directory . late String packageConfigPath = p.relative( - p.normalize(p.join(rootDir, '.dart_tool', 'package_config.json')), + p.normalize(p.join(workspaceRoot.dir, '.dart_tool', 'package_config.json')), ); - /// The path to the entrypoint package's pubspec. - String get pubspecPath => p.normalize(p.join(rootDir, 'pubspec.yaml')); - - /// The path to the entrypoint package's pubspec overrides file. - String get pubspecOverridesPath => - p.normalize(p.join(rootDir, 'pubspec_overrides.yaml')); - - /// The path to the entrypoint package's lockfile. - String get lockFilePath => p.normalize(p.join(rootDir, 'pubspec.lock')); + /// The path to the entrypoint workspace's lockfile. + String get lockFilePath => + p.normalize(p.join(workspaceRoot.dir, 'pubspec.lock')); /// The path to the directory containing dependency executable snapshots. String get _snapshotPath => p.join( - isCachedGlobal ? rootDir : p.join(rootDir, '.dart_tool/pub'), + isCachedGlobal + ? workspaceRoot.dir + : p.join(workspaceRoot.dir, '.dart_tool/pub'), 'bin', ); Entrypoint._( - this.rootDir, + this.workingDir, this._lockFile, this._example, this._packageGraph, this.cache, - this._root, + this._workspaceRoot, this.isCachedGlobal, ); @@ -218,15 +238,19 @@ class Entrypoint { /// If [checkInCache] is `true` (the default) an error will be thrown if /// [rootDir] is located inside [cache.rootDir]. Entrypoint( - this.rootDir, + this.workingDir, this.cache, { ({Pubspec pubspec, List workspacePackages})? preloaded, bool checkInCache = true, - }) : _root = preloaded == null + }) : _workspaceRoot = preloaded == null ? null - : Package(preloaded.pubspec, rootDir, preloaded.workspacePackages), + : Package( + preloaded.pubspec, + workingDir, + preloaded.workspacePackages, + ), isCachedGlobal = false { - if (checkInCache && p.isWithin(cache.rootDir, rootDir)) { + if (checkInCache && p.isWithin(cache.rootDir, workingDir)) { fail('Cannot operate on packages inside the cache.'); } } @@ -235,15 +259,15 @@ class Entrypoint { /// resolution. Entrypoint withPubspec(Pubspec pubspec) { return Entrypoint._( - rootDir, + workingDir, _lockFile, _example, _packageGraph, cache, Package( pubspec, - rootDir, - root.workspaceChildren, + workingDir, + workspaceRoot.workspaceChildren, ), isCachedGlobal, ); @@ -252,11 +276,11 @@ class Entrypoint { /// Creates an entrypoint given package and lockfile objects. /// If a SolveResult is already created it can be passed as an optimization. Entrypoint.global( - Package this._root, + Package this._workspaceRoot, this._lockFile, this.cache, { SolveResult? solveResult, - }) : rootDir = _root.dir, + }) : workingDir = _workspaceRoot.dir, isCachedGlobal = true { if (solveResult != null) { _packageGraph = @@ -269,10 +293,10 @@ class Entrypoint { /// This will be null if the example folder doesn't have a `pubspec.yaml`. Entrypoint? get example { if (_example != null) return _example; - if (!fileExists(root.path('example', 'pubspec.yaml'))) { + if (!fileExists(workspaceRoot.path('example', 'pubspec.yaml'))) { return null; } - return _example = Entrypoint(root.path('example'), cache); + return _example = Entrypoint(workspaceRoot.path('example'), cache); } Entrypoint? _example; @@ -284,8 +308,8 @@ class Entrypoint { packageConfigPath, await _packageConfigFile( cache, - entrypointSdkConstraint: - root.pubspec.sdkConstraints[sdk.identifier]?.effectiveConstraint, + entrypointSdkConstraint: workspaceRoot + .pubspec.sdkConstraints[sdk.identifier]?.effectiveConstraint, ), ); } @@ -293,13 +317,13 @@ class Entrypoint { /// Returns the contents of the `.dart_tool/package_config` file generated /// from this entrypoint based on [lockFile]. /// - /// If [isCachedGlobal] no entry will be created for [root]. + /// If [isCachedGlobal] no entry will be created for [workspaceRoot]. Future _packageConfigFile( SystemCache cache, { VersionConstraint? entrypointSdkConstraint, }) async { final entries = []; - late final relativeFromPath = p.join(rootDir, '.dart_tool'); + late final relativeFromPath = p.join(workspaceRoot.dir, '.dart_tool'); for (final name in ordered(lockFile.packages.keys)) { final id = lockFile.packages[name]!; final rootPath = cache.getDirectory(id, relativeFrom: relativeFromPath); @@ -317,12 +341,15 @@ class Entrypoint { if (!isCachedGlobal) { /// Run through the entire workspace transitive closure and add an entry /// for each package. - for (final package in root.transitiveWorkspace) { + for (final package in workspaceRoot.transitiveWorkspace) { entries.add( PackageConfigEntry( name: package.name, rootUri: p.toUri( - p.relative(package.dir, from: p.join(rootDir, '.dart_tool')), + p.relative( + package.dir, + from: p.join(workspaceRoot.dir, '.dart_tool'), + ), ), packageUri: p.toUri('lib/'), languageVersion: package.pubspec.languageVersion, @@ -350,7 +377,7 @@ class Entrypoint { return '${JsonEncoder.withIndent(' ').convert(packageConfig.toJson())}\n'; } - /// Gets all dependencies of the [root] package. + /// Gets all dependencies of the [workspaceRoot] package. /// /// Performs version resolution according to [SolveType]. /// @@ -381,9 +408,9 @@ class Entrypoint { bool summaryOnly = false, bool enforceLockfile = false, }) async { - root; // This will throw early if pubspec.yaml could not be found. + workspaceRoot; // This will throw early if pubspec.yaml could not be found. summaryOnly = summaryOnly || _summaryOnlyEnvironment; - final suffix = rootDir == '.' ? '' : ' in $rootDir'; + final suffix = workspaceRoot.dir == '.' ? '' : ' in ${workspaceRoot.dir}'; if (enforceLockfile && !fileExists(lockFilePath)) { throw ApplicationException(''' @@ -397,11 +424,13 @@ Try running `$topLevelProgram pub get` to create `$lockFilePath`.'''); try { result = await log.progress('Resolving dependencies$suffix', () async { - _checkSdkConstraint(root.pubspec); + // TODO(https://github.com/dart-lang/pub/issues/4127): Check this for + // all workspace pubspecs. + _checkSdkConstraint(workspaceRoot.pubspecPath, workspaceRoot.pubspec); return resolveVersions( type, cache, - root, + workspaceRoot, lockFile: lockFile, unlock: unlock ?? [], ); @@ -425,8 +454,8 @@ Try running `$topLevelProgram pub get` to create `$lockFilePath`.'''); final report = SolveReport( type, - rootDir, - root.pubspec, + workspaceRoot.dir, + workspaceRoot.pubspec, lockFile, newLockFile, result.availableVersions, @@ -439,7 +468,7 @@ Try running `$topLevelProgram pub get` to create `$lockFilePath`.'''); await report.show(summary: true); if (enforceLockfile && !_lockfilesMatch(lockFile, newLockFile)) { dataError(''' -Unable to satisfy `$pubspecPath` using `$lockFilePath`$suffix. +Unable to satisfy `${workspaceRoot.pubspecPath}` using `$lockFilePath`$suffix. To update `$lockFilePath` run `$topLevelProgram pub get`$suffix without `--enforce-lockfile`.'''); @@ -481,7 +510,7 @@ To update `$lockFilePath` run `$topLevelProgram pub get`$suffix without /// the package itself if they are immutable. Future> get _builtExecutables async { final graph = await packageGraph; - final r = root.immediateDependencies.keys.expand((packageName) { + final r = workspaceRoot.immediateDependencies.keys.expand((packageName) { final package = graph.packages[packageName]!; return package.executablePaths .map((path) => Executable(packageName, path)); @@ -568,8 +597,8 @@ To update `$lockFilePath` run `$topLevelProgram pub get`$suffix without /// [path] must be relative. String pathOfSnapshot(Executable executable) { return isCachedGlobal - ? executable.pathOfGlobalSnapshot(rootDir) - : executable.pathOfSnapshot(rootDir); + ? executable.pathOfGlobalSnapshot(workspaceRoot.dir) + : executable.pathOfSnapshot(workspaceRoot.dir); } /// Deletes cached snapshots that are from a different sdk. @@ -1002,7 +1031,7 @@ To update `$lockFilePath` run `$topLevelProgram pub get`$suffix without /// We require an SDK constraint lower-bound as of Dart 2.12.0 /// /// We don't allow unknown sdks. - void _checkSdkConstraint(Pubspec pubspec) { + void _checkSdkConstraint(String pubspecPath, Pubspec pubspec) { final dartSdkConstraint = pubspec.dartSdkConstraint.effectiveConstraint; // Suggest an sdk constraint giving the same language version as the // current sdk. diff --git a/lib/src/executable.dart b/lib/src/executable.dart index 8ffc20c39..dc2b901d8 100644 --- a/lib/src/executable.dart +++ b/lib/src/executable.dart @@ -56,8 +56,8 @@ Future runExecutable( // Make sure the package is an immediate dependency of the entrypoint or the // entrypoint itself. - if (entrypoint.root.name != executable.package && - !entrypoint.root.immediateDependencies.containsKey(package)) { + if (entrypoint.workspaceRoot.name != executable.package && + !entrypoint.workspaceRoot.immediateDependencies.containsKey(package)) { if ((await entrypoint.packageGraph).packages.containsKey(package)) { dataError('Package "$package" is not an immediate dependency.\n' 'Cannot run executables in transitive dependencies.'); @@ -84,7 +84,7 @@ Future runExecutable( if (!fileExists(executablePath)) { var message = 'Could not find ${log.bold(p.normalize(executable.relativePath))}'; - if (entrypoint.isCachedGlobal || package != entrypoint.root.name) { + if (entrypoint.isCachedGlobal || package != entrypoint.workspaceRoot.name) { message += ' in package ${log.bold(package)}'; } log.error('$message.'); @@ -95,7 +95,7 @@ Future runExecutable( // Since we don't access the package graph, this doesn't happen // automatically. await Entrypoint.ensureUpToDate( - entrypoint.rootDir, + entrypoint.workspaceRoot.dir, cache: entrypoint.cache, ); diff --git a/lib/src/global_packages.dart b/lib/src/global_packages.dart index fe8288644..990869a44 100644 --- a/lib/src/global_packages.dart +++ b/lib/src/global_packages.dart @@ -182,14 +182,14 @@ class GlobalPackages { // Get the package's dependencies. await entrypoint.acquireDependencies(SolveType.get); - var name = entrypoint.root.name; + var name = entrypoint.workspaceRoot.name; _describeActive(name, cache); // Write a lockfile that points to the local package. - var fullPath = canonicalize(entrypoint.rootDir); + var fullPath = canonicalize(entrypoint.workspaceRoot.dir); var id = cache.path.idFor( name, - entrypoint.root.version, + entrypoint.workspaceRoot.version, fullPath, p.current, ); @@ -205,7 +205,7 @@ class GlobalPackages { _updateBinStubs( entrypoint, - entrypoint.root, + entrypoint.workspaceRoot, executables, overwriteBinStubs: overwriteBinStubs, ); @@ -565,7 +565,7 @@ try: ); } else { await activatePath( - entrypoint.rootDir, + entrypoint.workspaceRoot.dir, packageExecutables, overwriteBinStubs: true, ); @@ -618,17 +618,18 @@ try: log.fine('Could not parse binstub $file:\n$contents'); continue; } - if (binStubPackage == entrypoint.root.name && + if (binStubPackage == entrypoint.workspaceRoot.name && binStubScript == p.basenameWithoutExtension(executable.relativePath)) { log.fine('Replacing old binstub $file'); deleteEntry(file); _createBinStub( - entrypoint.root, + entrypoint.workspaceRoot, p.basenameWithoutExtension(file), binStubScript, overwrite: true, - snapshot: executable.pathOfGlobalSnapshot(entrypoint.rootDir), + snapshot: + executable.pathOfGlobalSnapshot(entrypoint.workspaceRoot.dir), ); } } diff --git a/lib/src/log.dart b/lib/src/log.dart index e8aca47be..a7fdd2bd8 100644 --- a/lib/src/log.dart +++ b/lib/src/log.dart @@ -376,20 +376,31 @@ Platform: ${Platform.operatingSystem} '''); if (entrypoint != null) { - buffer.writeln('---- ${p.absolute(entrypoint.pubspecPath)} ----'); - if (fileExists(entrypoint.pubspecPath)) { - buffer.writeln(limitLength(readTextFile(entrypoint.pubspecPath), 5000)); + // TODO(https://github.com/dart-lang/pub/issues/4127): We probably want to + // log all pubspecs in workspace? + + if (entrypoint.canFindWorkspaceRoot) { + buffer.writeln( + '---- ${p.absolute(entrypoint.workspaceRoot.pubspecPath)} ----', + ); + buffer.writeln( + limitLength( + readTextFile(entrypoint.workspaceRoot.pubspecPath), + 5000, + ), + ); + buffer.writeln('---- End pubspec.yaml ----'); } else { buffer.writeln(''); } - buffer.writeln('---- End pubspec.yaml ----'); - buffer.writeln('---- ${p.absolute(entrypoint.lockFilePath)} ----'); - if (fileExists(entrypoint.lockFilePath)) { + if (entrypoint.canFindWorkspaceRoot && + fileExists(entrypoint.lockFilePath)) { + buffer.writeln('---- ${p.absolute(entrypoint.lockFilePath)} ----'); buffer.writeln(limitLength(readTextFile(entrypoint.lockFilePath), 5000)); + buffer.writeln('---- End pubspec.lock ----'); } else { buffer.writeln(''); } - buffer.writeln('---- End pubspec.lock ----'); } buffer.writeln('---- Log transcript ----'); diff --git a/lib/src/package.dart b/lib/src/package.dart index 954b0381e..fa9939442 100644 --- a/lib/src/package.dart +++ b/lib/src/package.dart @@ -45,6 +45,13 @@ class Package { /// The parsed pubspec associated with this package. final Pubspec pubspec; + /// The path to the entrypoint package's pubspec. + String get pubspecPath => p.normalize(p.join(dir, 'pubspec.yaml')); + + /// The path to the entrypoint package's pubspec overrides file. + String get pubspecOverridesPath => + p.normalize(p.join(dir, 'pubspec_overrides.yaml')); + /// The (non-transitive) workspace packages. final List workspaceChildren; diff --git a/lib/src/package_graph.dart b/lib/src/package_graph.dart index 0aa61b125..158b11a8b 100644 --- a/lib/src/package_graph.dart +++ b/lib/src/package_graph.dart @@ -38,7 +38,7 @@ class PackageGraph { final packages = { for (final id in result.packages) id.name: id.isRoot - ? entrypoint.root + ? entrypoint.workspaceRoot : Package( result.pubspecs[id.name]!, entrypoint.cache.getDirectory(id), @@ -55,7 +55,9 @@ class PackageGraph { /// dev and override. For any other package, it ignores dev and override /// dependencies. Set transitiveDependencies(String package) { - if (package == entrypoint.root.name) return packages.values.toSet(); + if (package == entrypoint.workspaceRoot.name) { + return packages.values.toSet(); + } if (_transitiveDependencies == null) { var closure = transitiveClosure( diff --git a/lib/src/pubspec_utils.dart b/lib/src/pubspec_utils.dart index a8a3d69b3..74b2ce8e2 100644 --- a/lib/src/pubspec_utils.dart +++ b/lib/src/pubspec_utils.dart @@ -5,7 +5,7 @@ import 'package:collection/collection.dart'; import 'package:pub_semver/pub_semver.dart'; -import 'entrypoint.dart'; +import 'package.dart'; import 'package_name.dart'; import 'pubspec.dart'; import 'source/hosted.dart'; @@ -166,7 +166,7 @@ VersionConstraint stripUpperBound(VersionConstraint constraint) { Object pubspecDescription( PackageRange range, SystemCache cache, - Entrypoint relativeEntrypoint, + Package receivingPackage, ) { final description = range.description; @@ -177,8 +177,8 @@ Object pubspecDescription( } else { return { range.source.name: description.serializeForPubspec( - containingDir: relativeEntrypoint.rootDir, - languageVersion: relativeEntrypoint.root.pubspec.languageVersion, + containingDir: receivingPackage.dir, + languageVersion: receivingPackage.pubspec.languageVersion, ), if (!constraint.isAny) 'version': constraint.toString(), }; diff --git a/lib/src/solver/solve_suggestions.dart b/lib/src/solver/solve_suggestions.dart index fbff1c9ad..9b14f7a2a 100644 --- a/lib/src/solver/solve_suggestions.dart +++ b/lib/src/solver/solve_suggestions.dart @@ -93,7 +93,8 @@ class _ResolutionSuggestion { String packageAddDescription(Entrypoint entrypoint, PackageId id) { final name = id.name; - final isDev = entrypoint.root.pubspec.devDependencies.containsKey(name); + final isDev = + entrypoint.workspaceRoot.pubspec.devDependencies.containsKey(name); final resolvedDescription = id.description; final String descriptor; final d = resolvedDescription.description.serializeForPubspec( @@ -102,7 +103,7 @@ String packageAddDescription(Entrypoint entrypoint, PackageId id) { // This currently should have no implications as we don't create suggestions // for path-packages. , - languageVersion: entrypoint.root.pubspec.languageVersion, + languageVersion: entrypoint.workspaceRoot.pubspec.languageVersion, ); if (d == null) { descriptor = VersionConstraint.compatibleWith(id.version).toString(); @@ -148,7 +149,7 @@ class _ResolutionContext { await inferBestFlutterRelease({cause.sdk.identifier: constraint}); if (bestRelease == null) return null; final result = await _tryResolve( - entrypoint.root, + entrypoint.workspaceRoot, sdkOverrides: { 'dart': bestRelease.dartVersion, 'flutter': bestRelease.flutterVersion, @@ -170,8 +171,10 @@ class _ResolutionContext { /// Attempt another resolution with a relaxed constraint on [name]. If that /// resolves, suggest upgrading to that version. Future<_ResolutionSuggestion?> suggestSinglePackageUpdate(String name) async { - final originalRange = entrypoint.root.dependencies[name] ?? - entrypoint.root.devDependencies[name]; + // TODO(https://github.com/dart-lang/pub/issues/4127): This should + // operate on all packages in workspace. + final originalRange = entrypoint.workspaceRoot.dependencies[name] ?? + entrypoint.workspaceRoot.devDependencies[name]; if (originalRange == null || originalRange.description is! HostedDescription) { // We can only relax constraints on hosted dependencies. @@ -179,7 +182,7 @@ class _ResolutionContext { } final originalConstraint = originalRange.constraint; final relaxedPubspec = stripVersionBounds( - entrypoint.root.pubspec, + entrypoint.workspaceRoot.pubspec, stripOnly: [name], stripLowerBound: true, ); @@ -187,8 +190,8 @@ class _ResolutionContext { final result = await _tryResolve( Package( relaxedPubspec, - entrypoint.rootDir, - entrypoint.root.workspaceChildren, + entrypoint.workspaceRoot.dir, + entrypoint.workspaceRoot.workspaceChildren, ), ); if (result == null) { @@ -224,15 +227,15 @@ class _ResolutionContext { Future<_ResolutionSuggestion?> suggestUnlockingAll({ required bool stripLowerBound, }) async { - final originalPubspec = entrypoint.root.pubspec; + final originalPubspec = entrypoint.workspaceRoot.pubspec; final relaxedPubspec = stripVersionBounds(originalPubspec, stripLowerBound: stripLowerBound); final result = await _tryResolve( Package( relaxedPubspec, - entrypoint.rootDir, - entrypoint.root.workspaceChildren, + entrypoint.workspaceRoot.dir, + entrypoint.workspaceRoot.workspaceChildren, ), ); if (result == null) { diff --git a/lib/src/validator.dart b/lib/src/validator.dart index 6c46f6539..38b4024c7 100644 --- a/lib/src/validator.dart +++ b/lib/src/validator.dart @@ -10,7 +10,9 @@ import 'package:pub_semver/pub_semver.dart'; import 'entrypoint.dart'; import 'log.dart' as log; +import 'package.dart'; import 'sdk.dart'; +import 'system_cache.dart'; import 'validator/analyze.dart'; import 'validator/changelog.dart'; import 'validator/compiled_dartdoc.dart'; @@ -60,7 +62,8 @@ abstract class Validator { final hints = []; late ValidationContext context; - Entrypoint get entrypoint => context.entrypoint; + Package get package => context.entrypoint.workPackage; + SystemCache get cache => context.entrypoint.cache; int get packageSize => context.packageSize; Uri get serverUrl => context.serverUrl; List get files => context.files; @@ -75,7 +78,7 @@ abstract class Validator { void validateSdkConstraint(Version firstSdkVersion, String message) { // If the SDK constraint disallowed all versions before [firstSdkVersion], // no error is necessary. - if (entrypoint.root.pubspec.dartSdkConstraint.originalConstraint + if (package.pubspec.dartSdkConstraint.originalConstraint .intersect(VersionRange(max: firstSdkVersion)) .isEmpty) { return; @@ -97,8 +100,7 @@ abstract class Validator { : firstSdkVersion.nextBreaking, ); - var newSdkConstraint = entrypoint - .root.pubspec.dartSdkConstraint.originalConstraint + var newSdkConstraint = package.pubspec.dartSdkConstraint.originalConstraint .intersect(allowedSdks); if (newSdkConstraint.isEmpty) newSdkConstraint = allowedSdks; @@ -217,7 +219,7 @@ abstract class Validator { /// entrypoint). // TODO(sigurdm): Consider moving this to a more central location. List filesBeneath(String dir, {required bool recursive}) { - final base = p.canonicalize(p.join(entrypoint.rootDir, dir)); + final base = p.canonicalize(p.join(package.dir, dir)); return files .where( recursive diff --git a/lib/src/validator/analyze.dart b/lib/src/validator/analyze.dart index ae332d9b0..839db2833 100644 --- a/lib/src/validator/analyze.dart +++ b/lib/src/validator/analyze.dart @@ -25,11 +25,11 @@ class AnalyzeValidator extends Validator { @override Future validate() async { final entries = _entriesToAnalyze - .map((dir) => p.join(entrypoint.rootDir, dir)) + .map((dir) => p.join(package.dir, dir)) .where(entryExists); final result = await runProcess( Platform.resolvedExecutable, - ['analyze', ...entries, p.join(entrypoint.rootDir, 'pubspec.yaml')], + ['analyze', ...entries, p.join(package.dir, 'pubspec.yaml')], ); if (result.exitCode != 0) { final limitedOutput = limitLength(result.stdout.join('\n'), 1000); diff --git a/lib/src/validator/changelog.dart b/lib/src/validator/changelog.dart index aa47b703d..65d7fdc1f 100644 --- a/lib/src/validator/changelog.dart +++ b/lib/src/validator/changelog.dart @@ -46,7 +46,7 @@ class ChangelogValidator extends Validator { return; } - final version = entrypoint.root.pubspec.version.toString(); + final version = package.pubspec.version.toString(); if (!contents.contains(version)) { warnings.add("$changelog doesn't mention current version ($version).\n" diff --git a/lib/src/validator/dependency.dart b/lib/src/validator/dependency.dart index ebfa101e5..f6134e279 100644 --- a/lib/src/validator/dependency.dart +++ b/lib/src/validator/dependency.dart @@ -37,8 +37,7 @@ class DependencyValidator extends Validator { Future warnAboutSource(PackageRange dep) async { List versions; try { - var ids = await entrypoint.cache - .getVersions(entrypoint.cache.hosted.refFor(dep.name)); + var ids = await cache.getVersions(cache.hosted.refFor(dep.name)); versions = ids.map((id) => id.version).toList(); } on ApplicationException catch (_) { versions = []; @@ -88,7 +87,7 @@ class DependencyValidator extends Validator { void warnAboutNoConstraint(PackageRange dep) { var message = 'Your dependency on "${dep.name}" should have a version ' 'constraint.'; - var locked = entrypoint.lockFile.packages[dep.name]; + var locked = context.entrypoint.lockFile.packages[dep.name]; if (locked != null) { message = '$message For example:\n' '\n' @@ -118,7 +117,7 @@ class DependencyValidator extends Validator { void warnAboutNoConstraintLowerBound(PackageRange dep) { var message = 'Your dependency on "${dep.name}" should have a lower bound.'; - var locked = entrypoint.lockFile.packages[dep.name]; + var locked = context.entrypoint.lockFile.packages[dep.name]; if (locked != null) { String constraint; if (locked.version == (dep.constraint as VersionRange).max) { @@ -160,7 +159,7 @@ class DependencyValidator extends Validator { } void warnAboutPrerelease(String dependencyName, VersionRange constraint) { - final packageVersion = entrypoint.root.version; + final packageVersion = package.version; if (constraint.min != null && constraint.min!.isPreRelease && !packageVersion.isPreRelease) { @@ -203,6 +202,6 @@ class DependencyValidator extends Validator { } } - await validateDependencies(entrypoint.root.pubspec.dependencies.values); + await validateDependencies(package.pubspec.dependencies.values); } } diff --git a/lib/src/validator/dependency_override.dart b/lib/src/validator/dependency_override.dart index 2fda8d506..1b875ab2c 100644 --- a/lib/src/validator/dependency_override.dart +++ b/lib/src/validator/dependency_override.dart @@ -13,13 +13,12 @@ import '../validator.dart'; class DependencyOverrideValidator extends Validator { @override Future validate() { - var overridden = MapKeySet(entrypoint.root.dependencyOverrides); - var dev = MapKeySet(entrypoint.root.devDependencies); + var overridden = MapKeySet(package.dependencyOverrides); + var dev = MapKeySet(package.devDependencies); if (overridden.difference(dev).isNotEmpty) { - final overridesFile = - entrypoint.root.pubspec.dependencyOverridesFromOverridesFile - ? entrypoint.pubspecOverridesPath - : entrypoint.pubspecPath; + final overridesFile = package.pubspec.dependencyOverridesFromOverridesFile + ? package.pubspecOverridesPath + : package.pubspecPath; hints.add(''' Non-dev dependencies are overridden in $overridesFile. diff --git a/lib/src/validator/deprecated_fields.dart b/lib/src/validator/deprecated_fields.dart index 942c8f5b4..788996c09 100644 --- a/lib/src/validator/deprecated_fields.dart +++ b/lib/src/validator/deprecated_fields.dart @@ -11,19 +11,19 @@ import '../validator.dart'; class DeprecatedFieldsValidator extends Validator { @override Future validate() async { - if (entrypoint.root.pubspec.fields.containsKey('transformers')) { + if (package.pubspec.fields.containsKey('transformers')) { warnings.add('Your pubspec.yaml includes a "transformers" section which' ' is no longer used and may be removed.'); } - if (entrypoint.root.pubspec.fields.containsKey('web')) { + if (package.pubspec.fields.containsKey('web')) { warnings.add('Your pubspec.yaml includes a "web" section which' ' is no longer used and may be removed.'); } - if (entrypoint.root.pubspec.fields.containsKey('author')) { + if (package.pubspec.fields.containsKey('author')) { warnings.add('Your pubspec.yaml includes an "author" section which' ' is no longer used and may be removed.'); } - if (entrypoint.root.pubspec.fields.containsKey('authors')) { + if (package.pubspec.fields.containsKey('authors')) { warnings.add('Your pubspec.yaml includes an "authors" section which' ' is no longer used and may be removed.'); } diff --git a/lib/src/validator/devtools_extension.dart b/lib/src/validator/devtools_extension.dart index 20012f3f2..9776c9ac3 100644 --- a/lib/src/validator/devtools_extension.dart +++ b/lib/src/validator/devtools_extension.dart @@ -15,12 +15,12 @@ class DevtoolsExtensionValidator extends Validator { @override Future validate() async { - if (dirExists(p.join(entrypoint.rootDir, 'extension', 'devtools'))) { + if (dirExists(p.join(package.dir, 'extension', 'devtools'))) { if (!files.any( (f) => p.equals( f, p.join( - entrypoint.rootDir, + package.dir, 'extension', 'devtools', 'config.yaml', @@ -29,7 +29,7 @@ class DevtoolsExtensionValidator extends Validator { ) || !files.any( (f) => p.isWithin( - p.join(entrypoint.rootDir, 'extension', 'devtools', 'build'), + p.join(package.dir, 'extension', 'devtools', 'build'), f, ), )) { diff --git a/lib/src/validator/directory.dart b/lib/src/validator/directory.dart index c0d6a124e..1870b0ebc 100644 --- a/lib/src/validator/directory.dart +++ b/lib/src/validator/directory.dart @@ -27,8 +27,8 @@ class DirectoryValidator extends Validator { for (final file in files) { // Find the topmost directory name of [file]. final dir = path.join( - entrypoint.rootDir, - path.split(path.relative(file, from: entrypoint.rootDir)).first, + package.dir, + path.split(path.relative(file, from: package.dir)).first, ); if (!visited.add(dir)) continue; if (!dirExists(dir)) continue; diff --git a/lib/src/validator/executable.dart b/lib/src/validator/executable.dart index b7679eb5d..6e786571e 100644 --- a/lib/src/validator/executable.dart +++ b/lib/src/validator/executable.dart @@ -13,10 +13,10 @@ import '../validator.dart'; class ExecutableValidator extends Validator { @override Future validate() async { - final binFiles = - filesBeneath('bin', recursive: false).map(entrypoint.root.relative); + final binFiles = filesBeneath('bin', recursive: false) + .map(package.relative); - entrypoint.root.pubspec.executables.forEach((executable, script) { + package.pubspec.executables.forEach((executable, script) { var scriptPath = p.join('bin', '$script.dart'); if (binFiles.contains(scriptPath)) return; diff --git a/lib/src/validator/flutter_constraint.dart b/lib/src/validator/flutter_constraint.dart index 1b1e2248c..cacb7c0f5 100644 --- a/lib/src/validator/flutter_constraint.dart +++ b/lib/src/validator/flutter_constraint.dart @@ -15,7 +15,7 @@ class FlutterConstraintValidator extends Validator { @override Future validate() async { - final environment = entrypoint.root.pubspec.fields['environment']; + final environment = package.pubspec.fields['environment']; if (environment is Map) { final flutterConstraint = environment['flutter']; if (flutterConstraint is String) { diff --git a/lib/src/validator/flutter_plugin_format.dart b/lib/src/validator/flutter_plugin_format.dart index 79f286cba..3b5c1d894 100644 --- a/lib/src/validator/flutter_plugin_format.dart +++ b/lib/src/validator/flutter_plugin_format.dart @@ -20,7 +20,7 @@ const _pluginDocsUrl = class FlutterPluginFormatValidator extends Validator { @override Future validate() async { - final pubspec = entrypoint.root.pubspec; + final pubspec = package.pubspec; // Ignore all packages that do not have the `flutter.plugin` property. if (pubspec.fields['flutter'] is! Map || diff --git a/lib/src/validator/gitignore.dart b/lib/src/validator/gitignore.dart index f45e233c8..6afb25d0a 100644 --- a/lib/src/validator/gitignore.dart +++ b/lib/src/validator/gitignore.dart @@ -21,7 +21,7 @@ import '../validator.dart'; class GitignoreValidator extends Validator { @override Future validate() async { - if (entrypoint.root.inGitRepo) { + if (package.inGitRepo) { late final List checkedIntoGit; try { checkedIntoGit = git.runSync( @@ -33,7 +33,7 @@ class GitignoreValidator extends Validator { '--exclude-standard', '--recurse-submodules', ], - workingDir: entrypoint.rootDir, + workingDir: package.dir, stdoutEncoding: Utf8Codec(), ); } on git.GitException catch (e) { @@ -43,9 +43,9 @@ class GitignoreValidator extends Validator { // --recurse-submodules we just continue silently. return; } - final root = git.repoRoot(entrypoint.rootDir) ?? entrypoint.rootDir; + final root = git.repoRoot(package.dir) ?? package.dir; var beneath = p.posix.joinAll( - p.split(p.normalize(p.relative(entrypoint.rootDir, from: root))), + p.split(p.normalize(p.relative(package.dir, from: root))), ); if (beneath == './') { beneath = ''; @@ -77,7 +77,7 @@ class GitignoreValidator extends Validator { }, isDir: (dir) => dirExists(resolve(dir)), ).map((file) { - final relative = p.relative(resolve(file), from: entrypoint.rootDir); + final relative = p.relative(resolve(file), from: package.dir); return Platform.isWindows ? p.posix.joinAll(p.split(relative)) : relative; diff --git a/lib/src/validator/leak_detection.dart b/lib/src/validator/leak_detection.dart index d5c28035b..945ffb749 100644 --- a/lib/src/validator/leak_detection.dart +++ b/lib/src/validator/leak_detection.dart @@ -29,14 +29,14 @@ final class LeakDetectionValidator extends Validator { Future validate() async { // Load `false_secrets` from `pubspec.yaml`. final falseSecrets = Ignore( - entrypoint.root.pubspec.falseSecrets, + package.pubspec.falseSecrets, ignoreCase: Platform.isWindows || Platform.isMacOS, ); final pool = Pool(20); // don't read more than 20 files concurrently! final leaks = await Future.wait( files.map((f) async { - final relPath = entrypoint.root.relative(f); + final relPath = package.relative(f); // Skip files matching patterns in `false_secrets` final nixPath = p.posix.joinAll(p.split(relPath)); diff --git a/lib/src/validator/name.dart b/lib/src/validator/name.dart index 9574c5b2c..24b1ace03 100644 --- a/lib/src/validator/name.dart +++ b/lib/src/validator/name.dart @@ -15,15 +15,15 @@ class NameValidator extends Validator { @override Future validate() { return Future.sync(() { - _checkName(entrypoint.root.name); + _checkName(package.name); var libraries = _libraries(files); if (libraries.length == 1) { var libName = path.basenameWithoutExtension(libraries[0]); - if (libName == entrypoint.root.name) return; + if (libName == package.name) return; warnings.add('The name of "${libraries[0]}", "$libName", should match ' - 'the name of the package, "${entrypoint.root.name}".\n' + 'the name of the package, "${package.name}".\n' 'This helps users know what library to import.'); } }); @@ -32,7 +32,7 @@ class NameValidator extends Validator { /// Returns a list of all libraries in the current package as paths relative /// to the package's root directory. List _libraries(List files) { - var libDir = entrypoint.root.path('lib'); + var libDir = package.path('lib'); return filesBeneath('lib', recursive: true) .map((file) => path.relative(file, from: path.dirname(libDir))) .where( diff --git a/lib/src/validator/pubspec_field.dart b/lib/src/validator/pubspec_field.dart index 91d8da3f3..385fbd5ec 100644 --- a/lib/src/validator/pubspec_field.dart +++ b/lib/src/validator/pubspec_field.dart @@ -29,18 +29,18 @@ class PubspecFieldValidator extends Validator { // Pubspec errors are detected lazily, so we make sure there aren't any // here. - for (var error in entrypoint.root.pubspec.allErrors) { + for (var error in package.pubspec.allErrors) { errors.add('In your pubspec.yaml, ${error.message}'); } return Future.value(); } - bool _hasField(String field) => entrypoint.root.pubspec.fields[field] != null; + bool _hasField(String field) => package.pubspec.fields[field] != null; /// Adds an error if [field] doesn't exist or isn't a string. void _validateFieldIsString(String field) { - var value = entrypoint.root.pubspec.fields[field]; + var value = package.pubspec.fields[field]; if (value == null) { errors.add('Your pubspec.yaml is missing a "$field" field.'); } else if (value is! String) { @@ -51,7 +51,7 @@ class PubspecFieldValidator extends Validator { /// Adds an error if the URL for [field] is invalid. void _validateFieldUrl(String field) { - var url = entrypoint.root.pubspec.fields[field]; + var url = package.pubspec.fields[field]; if (url == null) return; if (url is! String) { diff --git a/lib/src/validator/pubspec_typo.dart b/lib/src/validator/pubspec_typo.dart index 4510b3c4e..4ca08fa34 100644 --- a/lib/src/validator/pubspec_typo.dart +++ b/lib/src/validator/pubspec_typo.dart @@ -9,7 +9,7 @@ import '../validator.dart'; class PubspecTypoValidator extends Validator { @override Future validate() async { - final fields = entrypoint.root.pubspec.fields; + final fields = package.pubspec.fields; /// Limit the number of typo warnings so as not to drown out the other /// warnings diff --git a/lib/src/validator/relative_version_numbering.dart b/lib/src/validator/relative_version_numbering.dart index fc2b4320f..c557343aa 100644 --- a/lib/src/validator/relative_version_numbering.dart +++ b/lib/src/validator/relative_version_numbering.dart @@ -25,18 +25,21 @@ class RelativeVersionNumberingValidator extends Validator { @override Future validate() async { - final hostedSource = entrypoint.cache.hosted; + final hostedSource = cache.hosted; List existingVersions; try { - existingVersions = await entrypoint.cache.getVersions( - hostedSource.refFor(entrypoint.root.name, url: serverUrl.toString()), + existingVersions = await cache.getVersions( + hostedSource.refFor( + package.name, + url: serverUrl.toString(), + ), ); } on PackageNotFoundException { existingVersions = []; } existingVersions.sort((a, b) => a.version.compareTo(b.version)); - final currentVersion = entrypoint.root.pubspec.version; + final currentVersion = package.pubspec.version; final latestVersion = existingVersions.isEmpty ? null : existingVersions.last.version; @@ -47,7 +50,7 @@ Your version $currentVersion is earlier than that.'''); } final previousRelease = existingVersions - .lastWhereOrNull((id) => id.version < entrypoint.root.version); + .lastWhereOrNull((id) => id.version < package.version); if (previousRelease == null) return; @@ -85,10 +88,10 @@ Consider one of: hints.add(hint + suggestion); } - final previousPubspec = await entrypoint.cache.describe(previousRelease); + final previousPubspec = await cache.describe(previousRelease); final currentOptedIn = - entrypoint.root.pubspec.languageVersion.supportsNullSafety; + package.pubspec.languageVersion.supportsNullSafety; final previousOptedIn = previousPubspec.languageVersion.supportsNullSafety; if (currentOptedIn && !previousOptedIn) { diff --git a/lib/src/validator/sdk_constraint.dart b/lib/src/validator/sdk_constraint.dart index c95cd911b..c44f9b8b9 100644 --- a/lib/src/validator/sdk_constraint.dart +++ b/lib/src/validator/sdk_constraint.dart @@ -18,7 +18,7 @@ import '../validator.dart'; class SdkConstraintValidator extends Validator { @override Future validate() async { - final dartConstraint = entrypoint.root.pubspec.dartSdkConstraint; + final dartConstraint = package.pubspec.dartSdkConstraint; final originalConstraint = dartConstraint.originalConstraint; final effectiveConstraint = dartConstraint.effectiveConstraint; if (originalConstraint is VersionRange) { @@ -32,7 +32,7 @@ class SdkConstraintValidator extends Validator { } final constraintMin = originalConstraint.min; - final packageVersion = entrypoint.root.version; + final packageVersion = package.version; if (constraintMin != null && constraintMin.isPreRelease && diff --git a/lib/src/validator/size.dart b/lib/src/validator/size.dart index a8a7eae6c..fac5e1637 100644 --- a/lib/src/validator/size.dart +++ b/lib/src/validator/size.dart @@ -17,17 +17,17 @@ class SizeValidator extends Validator { if (packageSize <= _maxSize) return; var sizeInMb = (packageSize / (1 << 20)).toStringAsPrecision(4); // Current implementation of Package.listFiles skips hidden files - var ignoreExists = fileExists(entrypoint.root.path('.gitignore')); + var ignoreExists = fileExists(package.path('.gitignore')); var hint = StringBuffer(''' Your package is $sizeInMb MB. Consider the impact large downloads can have on the package consumer.'''); - if (ignoreExists && !entrypoint.root.inGitRepo) { + if (ignoreExists && !package.inGitRepo) { hint.write('\nYour .gitignore has no effect since your project ' 'does not appear to be in version control.'); - } else if (!ignoreExists && entrypoint.root.inGitRepo) { + } else if (!ignoreExists && package.inGitRepo) { hint.write('\nConsider adding a .gitignore to avoid including ' 'temporary files.'); } diff --git a/lib/src/validator/strict_dependencies.dart b/lib/src/validator/strict_dependencies.dart index bd1674e99..ea0e36f9f 100644 --- a/lib/src/validator/strict_dependencies.dart +++ b/lib/src/validator/strict_dependencies.dart @@ -23,7 +23,7 @@ class StrictDependenciesValidator extends Validator { /// Files that do not parse and directives that don't import or export /// `package:` URLs are ignored. Iterable<_Usage> _findPackages(Iterable files) sync* { - final packagePath = p.normalize(p.absolute(entrypoint.rootDir)); + final packagePath = p.normalize(p.absolute(package.dir)); final analysisContextManager = AnalysisContextManager(packagePath); for (var file in files) { @@ -63,9 +63,8 @@ class StrictDependenciesValidator extends Validator { @override Future validate() async { - var dependencies = entrypoint.root.dependencies.keys.toSet() - ..add(entrypoint.root.name); - var devDependencies = MapKeySet(entrypoint.root.devDependencies); + var dependencies = package.dependencies.keys.toSet()..add(package.name); + var devDependencies = MapKeySet(package.devDependencies); _validateLibBin(dependencies, devDependencies); _validateBenchmarkTestTool(dependencies, devDependencies); } diff --git a/test/package_list_files_test.dart b/test/package_list_files_test.dart index 7285b2114..ab2d9494a 100644 --- a/test/package_list_files_test.dart +++ b/test/package_list_files_test.dart @@ -33,7 +33,7 @@ void main() { createEntrypoint(); expect( - entrypoint!.root.listFiles(), + entrypoint!.workspaceRoot.listFiles(), unorderedEquals([ p.join(root, 'pubspec.yaml'), p.join(root, 'file1.txt'), @@ -75,7 +75,7 @@ void main() { createEntrypoint(); expect( - () => entrypoint!.root.listFiles(), + () => entrypoint!.workspaceRoot.listFiles(), throwsA( isA().having( (e) => e.message, @@ -106,7 +106,7 @@ void main() { SystemCache(rootDir: p.join(d.sandbox, cachePath)), ); - expect(entrypoint.root.listFiles(), { + expect(entrypoint.workspaceRoot.listFiles(), { p.join(root, 'pubspec.yaml'), p.join(root, 'file1.txt'), p.join(root, 'file2.txt'), @@ -129,7 +129,7 @@ void main() { createEntrypoint(); expect( - () => entrypoint!.root.listFiles(), + () => entrypoint!.workspaceRoot.listFiles(), throwsA( isA().having( (e) => e.message, @@ -158,7 +158,7 @@ void main() { createEntrypoint(); expect( - () => entrypoint!.root.listFiles(), + () => entrypoint!.workspaceRoot.listFiles(), throwsA( isA().having( (e) => e.message, @@ -177,7 +177,7 @@ void main() { d.file('.foo', ''), ]).create(); createEntrypoint(); - expect(entrypoint!.root.listFiles(), { + expect(entrypoint!.workspaceRoot.listFiles(), { p.join(root, '.foo'), p.join(root, 'pubspec.yaml'), }); @@ -201,7 +201,7 @@ void main() { ]), ]).create(); - expect(entrypoint!.root.listFiles(), { + expect(entrypoint!.workspaceRoot.listFiles(), { p.join(root, 'pubspec.yaml'), p.join(root, 'file1.txt'), p.join(root, 'file2.txt'), @@ -221,7 +221,7 @@ void main() { ]), ]).create(); - expect(entrypoint!.root.listFiles(), { + expect(entrypoint!.workspaceRoot.listFiles(), { p.join(root, 'pubspec.yaml'), p.join(root, 'file2.text'), p.join(root, 'subdir', 'subfile2.text'), @@ -254,7 +254,7 @@ void main() { createEntrypoint(p.join(appPath, 'rep', 'sub')); - expect(entrypoint!.root.listFiles(), { + expect(entrypoint!.workspaceRoot.listFiles(), { p.join(root, 'pubspec.yaml'), p.join(root, 'file2.text'), p.join(root, 'file4.gak'), @@ -284,7 +284,7 @@ void main() { }); test('respects its .gitignore with useGitIgnore', () { - expect(entrypoint!.root.listFiles(), { + expect(entrypoint!.workspaceRoot.listFiles(), { p.join(root, 'pubspec.yaml'), p.join(root, 'submodule', 'file2.text'), }); @@ -297,7 +297,10 @@ void main() { d.dir('subdir', [d.file('pubspec.lock')]), ]).create(); - expect(entrypoint!.root.listFiles(), {p.join(root, 'pubspec.yaml')}); + expect( + entrypoint!.workspaceRoot.listFiles(), + {p.join(root, 'pubspec.yaml')}, + ); }); test('allows pubspec.lock directories', () async { @@ -307,7 +310,7 @@ void main() { ]), ]).create(); - expect(entrypoint!.root.listFiles(), { + expect(entrypoint!.workspaceRoot.listFiles(), { p.join(root, 'pubspec.yaml'), p.join(root, 'pubspec.lock', 'file.txt'), }); @@ -328,7 +331,7 @@ void main() { ]), ]).create(); - expect(entrypoint!.root.listFiles(beneath: 'subdir'), { + expect(entrypoint!.workspaceRoot.listFiles(beneath: 'subdir'), { p.join(root, 'subdir', 'subfile1.txt'), p.join(root, 'subdir', 'subfile2.txt'), p.join(root, 'subdir', 'subsubdir', 'subsubfile1.txt'), @@ -347,7 +350,7 @@ void main() { d.dir('lib', [d.file('not_ignored.dart', 'content')]), ]).create(); createEntrypoint(); - expect(entrypoint!.root.listFiles(), { + expect(entrypoint!.workspaceRoot.listFiles(), { p.join(root, 'LICENSE'), p.join(root, 'CHANGELOG.md'), p.join(root, 'README.md'), @@ -399,7 +402,7 @@ void main() { ]).create(); createEntrypoint(); - expect(entrypoint!.root.listFiles(), { + expect(entrypoint!.workspaceRoot.listFiles(), { p.join(root, 'pubspec.yaml'), p.join(root, 'not_ignored_by_gitignore.txt'), p.join(root, 'ignored_by_gitignore.txt'), @@ -431,7 +434,7 @@ void main() { await repo.create(); createEntrypoint(p.join(appPath, 'packages', 'nested')); - expect(entrypoint!.root.listFiles(), { + expect(entrypoint!.workspaceRoot.listFiles(), { p.join(root, 'pubspec.yaml'), }); }); @@ -449,7 +452,7 @@ void main() { await repo.create(); createEntrypoint(p.join(appPath, 'packages', 'nested')); - expect(entrypoint!.root.listFiles(), { + expect(entrypoint!.workspaceRoot.listFiles(), { p.join(root, 'pubspec.yaml'), p.join(root, 'bin'), }); @@ -470,7 +473,7 @@ void main() { await repo.create(); createEntrypoint(p.join(appPath, 'packages', 'nested')); - expect(entrypoint!.root.listFiles(), { + expect(entrypoint!.workspaceRoot.listFiles(), { p.join(root, 'pubspec.yaml'), }); }); @@ -493,7 +496,7 @@ void main() { await repo.create(); createEntrypoint(p.join(appPath, 'packages', 'nested')); - expect(entrypoint!.root.listFiles(), { + expect(entrypoint!.workspaceRoot.listFiles(), { p.join(root, 'pubspec.yaml'), p.join(root, 'bin', 'nested_again', 'run.dart'), }); @@ -518,7 +521,7 @@ void main() { await repo.create(); createEntrypoint(p.join(appPath, 'packages', 'nested')); - expect(entrypoint!.root.listFiles(), { + expect(entrypoint!.workspaceRoot.listFiles(), { p.join(root, 'pubspec.yaml'), p.join(root, 'bin', 'run.dart'), }); @@ -545,7 +548,7 @@ void main() { await repo.create(); createEntrypoint(p.join(appPath, 'packages', 'nested')); - expect(entrypoint!.root.listFiles(), { + expect(entrypoint!.workspaceRoot.listFiles(), { p.join(root, 'pubspec.yaml'), p.join(root, 'bin', 'nested_again', 'run.dart'), }); @@ -569,7 +572,7 @@ void main() { await repo.create(); createEntrypoint(p.join(appPath, 'packages', 'nested')); - expect(entrypoint!.root.listFiles(), { + expect(entrypoint!.workspaceRoot.listFiles(), { p.join(root, 'pubspec.yaml'), p.join(root, 'bin', 'run.dart'), p.join(root, 'bin', 'nested_again', 'run.dart'), diff --git a/test/test_pub.dart b/test/test_pub.dart index 7aa3cf6c4..41649e9d2 100644 --- a/test/test_pub.dart +++ b/test/test_pub.dart @@ -911,7 +911,7 @@ Future validatePackage(ValidatorCreator fn, int? size) async { _globalServer == null ? Uri.parse('https://pub.dev') : Uri.parse(globalServer.url), - entrypoint.root.listFiles(), + entrypoint.workspaceRoot.listFiles(), ); await validator.validate(); return validator; diff --git a/test/testdata/goldens/embedding/embedding_test/logfile is written with --verbose and on unexpected exceptions.txt b/test/testdata/goldens/embedding/embedding_test/logfile is written with --verbose and on unexpected exceptions.txt index c489d00c6..26b959810 100644 --- a/test/testdata/goldens/embedding/embedding_test/logfile is written with --verbose and on unexpected exceptions.txt +++ b/test/testdata/goldens/embedding/embedding_test/logfile is written with --verbose and on unexpected exceptions.txt @@ -331,12 +331,8 @@ PUB_CACHE: "$SANDBOX/cache" Command: dart pub fail Platform: $OS ----- $SANDBOX/empty/pubspec.yaml ---- ----- End pubspec.yaml ---- ----- $SANDBOX/empty/pubspec.lock ---- ----- End pubspec.lock ---- ---- Log transcript ---- FINE: Pub 3.1.2+3 ERR : Bad state: Pub has crashed From e8a599dbd8ef77d29e6c7e6d2b56f34d6a6c785f Mon Sep 17 00:00:00 2001 From: Sigurd Meldgaard Date: Thu, 14 Mar 2024 15:33:29 +0000 Subject: [PATCH 2/2] Dartfmt --- lib/src/validator/executable.dart | 4 ++-- lib/src/validator/relative_version_numbering.dart | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/src/validator/executable.dart b/lib/src/validator/executable.dart index 6e786571e..ff178c860 100644 --- a/lib/src/validator/executable.dart +++ b/lib/src/validator/executable.dart @@ -13,8 +13,8 @@ import '../validator.dart'; class ExecutableValidator extends Validator { @override Future validate() async { - final binFiles = filesBeneath('bin', recursive: false) - .map(package.relative); + final binFiles = + filesBeneath('bin', recursive: false).map(package.relative); package.pubspec.executables.forEach((executable, script) { var scriptPath = p.join('bin', '$script.dart'); diff --git a/lib/src/validator/relative_version_numbering.dart b/lib/src/validator/relative_version_numbering.dart index c557343aa..91a6d91f7 100644 --- a/lib/src/validator/relative_version_numbering.dart +++ b/lib/src/validator/relative_version_numbering.dart @@ -49,8 +49,8 @@ The latest published version is $latestVersion. Your version $currentVersion is earlier than that.'''); } - final previousRelease = existingVersions - .lastWhereOrNull((id) => id.version < package.version); + final previousRelease = + existingVersions.lastWhereOrNull((id) => id.version < package.version); if (previousRelease == null) return; @@ -90,8 +90,7 @@ Consider one of: final previousPubspec = await cache.describe(previousRelease); - final currentOptedIn = - package.pubspec.languageVersion.supportsNullSafety; + final currentOptedIn = package.pubspec.languageVersion.supportsNullSafety; final previousOptedIn = previousPubspec.languageVersion.supportsNullSafety; if (currentOptedIn && !previousOptedIn) {