blob: 8708bb64e1408f3cfe5c1ef70991e0163d88a235 [file] [log] [blame]
// Copyright (c) 2022, 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';
/// This script creates monorepo's DEPS file, which is based on
/// flutter/engine/DEPS. Changes to Dart dependencies from
/// dart-lang/sdk/DEPS are merged into engine/DEPS, and the
/// paths of dependencies are changed, to put the engine checkout
/// at the path engine/src/flutter in the gclient solution.
///
/// The script does not use any package dependencies, so it can
/// be run without running 'dart pub get' first.
void main(List<String> args) async {
final root = Platform.script.resolve('../..');
if (root != Directory.current.uri) {
print('create_monorepo_deps must be run from the root of '
'a monorepo gclient checkout.');
exit(1);
}
// Arguments are like --flutter=[40-character commit hash]
final hashArgument = RegExp(r'--(\w*)=(\w{40})');
final matchedArguments = [
for (final arg in args) hashArgument.matchAsPrefix(arg)
];
final hashes = {
for (final match in matchedArguments)
if (match != null) match[1]!: match[2]!
};
final engineDeps = File.fromUri(root.resolve('engine/src/flutter/DEPS'));
final monorepoDeps = File.fromUri(root.resolve('monorepo/DEPS'));
await engineDeps.copy(monorepoDeps.path);
final result = await Process.run('python3', [
root
.resolve('engine/src/tools/dart/create_updated_flutter_deps.py')
.toFilePath(),
'-f',
monorepoDeps.path
]);
if (result.exitCode != 0) {
print('create_updated_flutter_deps.py -f ${monorepoDeps.path} failed');
print(' exit code: ${result.exitCode}');
print(result.stdout);
print(result.stderr);
exit(1);
}
final deps = await monorepoDeps.readAsLines();
commentDartRevision(deps);
removeDartDependency(deps);
stopSdkDownload(deps);
addPinnedRepositories(deps, hashes);
moveDepsToEngine(deps);
await monorepoDeps.writeAsString(deps.join('\n') + '\n', flush: true);
}
/// Add comment to the 'dart_revision' variable
/// that it is unused in the monorepo DEPS.
/// The download prebuild SDK steps still use it, but they are disabled.
void commentDartRevision(List<String> deps) {
final firstCommentStart = ' # When updating the Dart revision,';
final dartRevisionLineStart = " 'dart_revision':";
var index = deps.indexWhere((line) => line.startsWith(firstCommentStart));
if (index != -1) {
deps.insert(
index, ' # The dart_revision variable is not used in monorepo.');
}
index = deps.indexWhere((line) => line.startsWith(dartRevisionLineStart));
if (index != -1) {
deps[index] = "$dartRevisionLineStart 'unused',";
}
}
void removeDartDependency(List<String> deps) {
final index = deps.indexOf(" 'src/third_party/dart':");
if (index == -1 || !deps[index + 1].startsWith(" Var('dart_git')")) {
print('Could not remove the Dart dependency');
exit(1);
}
deps.removeRange(index, index + 2);
}
void stopSdkDownload(List<String> deps) {
final downloadLine = " 'download_dart_sdk': True,";
final noDownloadLine = " 'download_dart_sdk': False,";
final index = deps.indexOf(downloadLine);
if (index == -1) {
print("Could not modify 'download_dart_sdk'");
exit(1);
}
deps[index] = noDownloadLine;
}
/// Adds pinned dependencies for flutter/flutter, flutter/engine, and Dart SDK.
void addPinnedRepositories(List<String> deps, Map<String, String> hashes) {
final depsIndex = deps.indexOf('deps = {');
if (depsIndex == -1 ||
depsIndex + 2 > deps.length ||
!deps[depsIndex + 1]
.startsWith(" 'src': 'https://github.com/flutter/buildroot.git'") ||
hashes['dart'] == null ||
hashes['engine'] == null ||
hashes['flutter'] == null) {
print('Could not add dart and flutter dependencies to DEPS');
exit(1);
}
deps.insertAll(depsIndex + 2, [
'',
" 'src/flutter': Var('flutter_git') + '/mirrors/engine' + "
"'@' + '${hashes['engine']!}',",
'',
" 'src/third_party/dart': Var('dart_git') + '/sdk' + '@' + "
"'${hashes['dart']!}',",
'',
" 'flutter': Var('flutter_git') + '/mirrors/flutter' + '@' + "
"'${hashes['flutter']}',",
]);
}
/// Move the dependencies that engine DEPS checks out into src/
/// to the equivalent path in engine/src/.
void moveDepsToEngine(List<String> deps) {
final depsIndex = deps.indexOf('deps = {');
var recursedepsIndex = deps.indexOf('recursedeps = [');
final hooksIndex = deps.indexOf('hooks = [');
if (depsIndex == -1) {
print("Could not relocate dependencies. Could not find deps section");
exit(1);
}
if (recursedepsIndex == -1) {
// No recursedeps section.
recursedepsIndex = hooksIndex;
}
if (hooksIndex == -1) {
print("Could not relocate dependencies. Could not find hooks section");
exit(1);
}
final preDepsSrcLine = RegExp("^gclient_gn_args_file = 'src/third_part");
for (var i = 0; i < depsIndex; i++) {
if (preDepsSrcLine.hasMatch(deps[i])) {
deps[i] = deps[i].replaceFirst('src', 'engine/src');
}
}
var count = 0;
final srcDependencySrcLine = RegExp(r"^\s+'src(/[\w-]+)*':");
for (var i = depsIndex; i < recursedepsIndex; i++) {
if (srcDependencySrcLine.hasMatch(deps[i])) {
deps[i] = deps[i].replaceFirst('src', 'engine/src');
count++;
}
}
print('Moved $count dependencies to engine/src');
final recursedepsSrcLine = RegExp("^ 'src/");
for (var i = recursedepsIndex; i < hooksIndex; i++) {
if (recursedepsSrcLine.hasMatch(deps[i])) {
deps[i] = deps[i].replaceFirst(" 'src/", " 'engine/src/");
}
}
final hooksSrcLine = RegExp(" 'src/");
for (var i = hooksIndex; i < deps.length; i++) {
if (hooksSrcLine.hasMatch(deps[i])) {
deps[i] = deps[i].replaceAll(" 'src/", " 'engine/src/");
}
}
}