From 0de3baf3806c83f20ceefc6fd9f48995a0f6e885 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Fri, 21 May 2021 18:35:08 -0700 Subject: [PATCH] wip - add-overrides command --- mono_repo.yaml | 4 + mono_repo/CHANGELOG.md | 1 + mono_repo/lib/src/commands/add_overrides.dart | 113 ++++++++++++++++++ mono_repo/lib/src/mono_config.dart | 9 ++ mono_repo/lib/src/runner.dart | 2 + mono_repo/pubspec.yaml | 1 + 6 files changed, 130 insertions(+) create mode 100644 mono_repo/lib/src/commands/add_overrides.dart diff --git a/mono_repo.yaml b/mono_repo.yaml index 6bda1639..90b1e7fb 100644 --- a/mono_repo.yaml +++ b/mono_repo.yaml @@ -19,3 +19,7 @@ github: "${CHAT_WEBHOOK_URL}" env: CHAT_WEBHOOK_URL: ${{ secrets.CHAT_WEBHOOK_URL }} + +dependency_overrides: + shelf_static: + git: https://github.com/dart-lang/shelf_static/ diff --git a/mono_repo/CHANGELOG.md b/mono_repo/CHANGELOG.md index 87fed2e1..5b1af091 100644 --- a/mono_repo/CHANGELOG.md +++ b/mono_repo/CHANGELOG.md @@ -1,6 +1,7 @@ ## 4.2.0-dev - Change calls from `pub` to `dart pub` within generated scripts. +- WIP on `add-overrides` ## 4.1.0 diff --git a/mono_repo/lib/src/commands/add_overrides.dart b/mono_repo/lib/src/commands/add_overrides.dart new file mode 100644 index 00000000..780c29ff --- /dev/null +++ b/mono_repo/lib/src/commands/add_overrides.dart @@ -0,0 +1,113 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:io'; + +import 'package:path/path.dart' as p; +import 'package:pubspec_parse/pubspec_parse.dart'; +import 'package:yaml/yaml.dart'; +import 'package:yaml_edit/yaml_edit.dart'; + +import '../../mono_repo.dart'; +import '../root_config.dart'; +import 'mono_repo_command.dart'; + +class AddOverridesCommand extends MonoRepoCommand { + @override + String get name => 'add-overrides'; + + @override + String get description => + 'Generates the CI configuration for child packages.'; + + @override + void run() => addOverrides(rootConfig()); +} + +void addOverrides(RootConfig config) { + final dependencyOverrides = config.monoConfig.dependencyOverrides; + if (dependencyOverrides.isEmpty) { + throw UserException('No dependency_overrides defined!'); + } + + final updateQueue = {}; + + for (var package in config) { + print(package.relativePath); + final pubspecPath = p.join(package.relativePath, 'pubspec.yaml'); + final lockPath = p.join(package.relativePath, 'pubspec.lock'); + final lockFile = File(lockPath); + + final lockYaml = + loadYaml(lockFile.readAsStringSync(), sourceUrl: Uri.parse(lockPath)) + as YamlMap; + final packages = lockYaml['packages'] as YamlMap; + + final toOverride = packages.keys + .cast() + .where((element) => dependencyOverrides.keys.contains(element)) + .toSet(); + + if (toOverride.isEmpty) { + print('Nothing to update in "$pubspecPath".'); + continue; + } + + final pubspecFile = File(pubspecPath); + final pubspecYaml = YamlEditor(pubspecFile.readAsStringSync()); + + final pubspecOverrides = pubspecYaml + .parseAt(['dependency_overrides'], orElse: () => wrapAsYamlNode(null)); + + if (pubspecOverrides is YamlScalar && pubspecOverrides.value == null) { + // no overrides! + pubspecYaml.update(['dependency_overrides'], {}); + } else if (pubspecOverrides is! YamlMap) { + throw UserException( + '"${pubspecFile.path}" has a `dependency_overrides` value, but it is ' + 'not a Map. Not sure what to do!', + ); + } + + // We're ready to start adding dependency overrides! + for (var newOverride in toOverride) { + final newDep = dependencyOverrides[newOverride]!; + + Map newValue; + + if (newDep is PathDependency) { + final path = p.isAbsolute(newDep.path) + ? newDep.path + : p.relative(p.absolute(newDep.path), from: package.relativePath); + newValue = {'path': path}; + } else if (newDep is GitDependency) { + newValue = { + 'git': { + 'url': newDep.url.toString(), + if (newDep.path != null) 'path': newDep.path!, + if (newDep.ref != null) 'ref': newDep.ref!, + } + }; + } else { + // TODO: support "normal" dependencies + throw UserException('Not sure how to write `$newDep`.'); + } + + // TODO: if there is already a value at the target and it doesn't equal + // the value we're adding – throw! + + pubspecYaml.update( + ['dependency_overrides', newOverride], + newValue, + ); + } + + updateQueue[pubspecPath] = pubspecYaml.toString(); + } + + assert(updateQueue.isNotEmpty); + for (var entry in updateQueue.entries) { + File(entry.key).writeAsStringSync(entry.value); + } +} diff --git a/mono_repo/lib/src/mono_config.dart b/mono_repo/lib/src/mono_config.dart index 83299123..82cf221c 100644 --- a/mono_repo/lib/src/mono_config.dart +++ b/mono_repo/lib/src/mono_config.dart @@ -4,6 +4,8 @@ import 'package:json_annotation/json_annotation.dart'; import 'package:path/path.dart' as p; +// ignore: implementation_imports +import 'package:pubspec_parse/src/dependency.dart'; import 'github_config.dart'; import 'yaml.dart'; @@ -16,6 +18,7 @@ const _monoConfigFileName = 'mono_repo.yaml'; const _reservedTravisKeys = {'cache', 'jobs', 'language'}; const _allowedMonoConfigKeys = { + 'dependency_overrides', 'github', 'merge_stages', 'pretty_ansi', @@ -41,6 +44,7 @@ class MonoConfig { final String? selfValidateStage; final Map travis; final GitHubConfig github; + final Map dependencyOverrides; MonoConfig._({ required Set? ci, @@ -52,6 +56,7 @@ class MonoConfig { required this.selfValidateStage, required this.travis, required this.github, + required this.dependencyOverrides, }) : ci = ci ?? const {CI.travis}; factory MonoConfig({ @@ -62,6 +67,7 @@ class MonoConfig { required String? selfValidateStage, required Map travis, required Map github, + required Map dependencyOverrides, }) { final overlappingKeys = travis.keys.where(_reservedTravisKeys.contains).toList(); @@ -87,6 +93,7 @@ class MonoConfig { selfValidateStage: selfValidateStage, travis: travis.map((k, v) => MapEntry(k as String, v))..remove('stages'), github: GitHubConfig.fromJson(github), + dependencyOverrides: parseDeps(dependencyOverrides), ); } @@ -184,6 +191,7 @@ class MonoConfig { selfValidateStage: _selfValidateFromValue(selfValidate), travis: travis, github: github, + dependencyOverrides: json['dependency_overrides'] as Map? ?? {}, ); } else { throw CheckedFromJsonException( @@ -208,6 +216,7 @@ class MonoConfig { selfValidateStage: null, travis: {}, github: {}, + dependencyOverrides: {}, ); } diff --git a/mono_repo/lib/src/runner.dart b/mono_repo/lib/src/runner.dart index 105bcf78..3db8106a 100644 --- a/mono_repo/lib/src/runner.dart +++ b/mono_repo/lib/src/runner.dart @@ -7,6 +7,7 @@ import 'dart:async'; import 'package:args/args.dart'; import 'package:args/command_runner.dart'; +import 'commands/add_overrides.dart'; import 'commands/check.dart'; import 'commands/generate.dart'; import 'commands/mono_repo_command.dart'; @@ -22,6 +23,7 @@ final commands = List>.unmodifiable( PresubmitCommand(), PubCommand(), TravisCommand(), + AddOverridesCommand(), ], ); diff --git a/mono_repo/pubspec.yaml b/mono_repo/pubspec.yaml index bd32db90..a9ee86e9 100644 --- a/mono_repo/pubspec.yaml +++ b/mono_repo/pubspec.yaml @@ -20,6 +20,7 @@ dependencies: pub_semver: ^2.0.0 pubspec_parse: ^1.0.0 yaml: ^3.0.0 + yaml_edit: ^2.0.0 dev_dependencies: build_runner: ^2.0.1