Skip to content

Commit

Permalink
Convert the update_perfetto.sh script to a dart script
Browse files Browse the repository at this point in the history
  • Loading branch information
kenzieschmoll committed Nov 1, 2023
1 parent 9cfe8ea commit b9138eb
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 2 deletions.
4 changes: 2 additions & 2 deletions tool/build_e2e.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ const argUpdatePerfetto = '--update-perfetto';
/// Flutter SDK when you already have the proper SDK checked out.
///
/// If [argUpdatePerfetto] is present, the precompiled bits for Perfetto will
/// be updated from the [update_perfetto.sh] script as part of the DevTools
/// build process (e.g. [build_release.sh]).
/// be updated from the `devtools_tool update-perfetto` command as part of the
/// DevTools build process (e.g. running `devtools_tool build-release`).
void main(List<String> args) async {
final shouldUpdatePerfetto = args.contains(argUpdatePerfetto);
final noUpdateFlutter = args.contains(argNoUpdateFlutter);
Expand Down
204 changes: 204 additions & 0 deletions tool/lib/commands/update_perfetto.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
// Copyright 2023 The Chromium Authors. 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:args/command_runner.dart';
import 'package:devtools_tool/model.dart';
import 'package:io/io.dart';
import 'package:path/path.dart' as path;

import '../utils.dart';

const _buildFlag = 'build';

class UpdatePerfettoCommand extends Command {
UpdatePerfettoCommand() {
argParser.addOption(
_buildFlag,
abbr: 'b',
help: 'The build location of the Perfetto assets. When this is not '
'specified, the Perfetto assets will be fetched from the latest '
'source code at "android.googlesource.com".',
valueHelp: '/Users/me/path/to/perfetto/out/ui/ui/dist',
);
}

@override
String get name => 'update-perfetto';

@override
String get description =>
'Updates the Perfetto assets that are included in the DevTools app bundle.';

@override
Future run() async {
final processManager = ProcessManager();

final perfettoUiCompiledLib = pathFromRepoRoot(
path.join('third_party', 'packages', 'perfetto_ui_compiled', 'lib'),
);
final perfettoDevToolsPath =
path.join(perfettoUiCompiledLib, 'dist', 'devtools');

logStatus(
'moving DevTools-Perfetto integration files to a temp directory.',
);
final tempPerfettoDevTools =
Directory(path.join(Directory.systemTemp.path, 'perfetto_devtools'))
..createSync();
await copyPath(perfettoDevToolsPath, tempPerfettoDevTools.path);

logStatus('deleting existing Perfetto build');
final existingBuild = Directory(path.join(perfettoUiCompiledLib, 'dist'));
existingBuild.deleteSync(recursive: true);

logStatus('updating Perfetto build');
final buildLocation = argResults![_buildFlag];
if (buildLocation != null) {
logStatus('using Perfetto build from $buildLocation');
await processManager.runProcess(CliCommand('cp -R $buildLocation ./'));
} else {
logStatus('cloning Perfetto from HEAD and building from source');
final tempPerfettoClone =
Directory(path.join(Directory.systemTemp.path, 'perfetto_clone'))
..createSync();
await processManager.runProcess(
CliCommand.git(
'clone https://android.googlesource.com/platform/external/perfetto',
),
workingDirectory: tempPerfettoClone.path,
);

logStatus('installing build deps and building the Perfetto UI');
await processManager.runAll(
commands: [
CliCommand('${path.join('tools', 'install-build-deps')} --ui'),
CliCommand(path.join('ui', 'build')),
],
workingDirectory: path.join(tempPerfettoClone.path, 'perfetto'),
);
await copyPath(
path.join(
tempPerfettoClone.path,
'perfetto',
'out',
'ui',
'ui',
'dist',
),
perfettoUiCompiledLib,
);

logStatus('deleting perfetto clone');
tempPerfettoClone.deleteSync(recursive: true);
}

logStatus('deleting unnecessary js source map files from build');
final deleteMatchers = [
'.js.map',
'traceconv.wasm',
'traceconv_bundle.js',
'catapult_trace_viewer.*',
'rec_*.png',
];
final libDirectory = Directory(perfettoUiCompiledLib);
final libFiles = libDirectory.listSync();
for (final file in libFiles) {
if (deleteMatchers
.any((matcher) => RegExp(r'' + matcher).hasMatch(matcher))) {
logStatus('deleting ${file.path}');
file.deleteSync();
}
}

logStatus(
'moving DevTools-Perfetto integration files back from the temp directory',
);
Directory(path.join(perfettoUiCompiledLib, 'dist', 'devtools'))
.createSync();
await copyPath(tempPerfettoDevTools.path, perfettoDevToolsPath);

logStatus(
'updating index.html headers to include DevTools-Perfetto integration files',
);
await processManager.runAll(
commands: [
CliCommand(
// ignore: unnecessary_string_escapes
'gsed -i "s/<\/head>/ <link id=\"devtools-style\" rel=\"stylesheet\" href=\"devtools\/devtools_dark.css\">\n<\/head>/g" ${path.join('dist', 'index.html')}',
),
CliCommand(
// ignore: unnecessary_string_escapes
'gsed -i "s/<\/head>/ <script src=\"devtools\/devtools_theme_handler.js\"><\/script>\n<\/head>/g" ${path.join('dist', 'index.html')}',
),
],
workingDirectory: perfettoUiCompiledLib,
);

logStatus('deleting temporary directory');
tempPerfettoDevTools.deleteSync(recursive: true);

logStatus('updating perfetto assets in the devtools_app pubspec.yaml file');
_updatePerfettoAssetsInPubspec();
}

void _updatePerfettoAssetsInPubspec() {
final mainDevToolsDirectory = DevToolsRepo.getInstance().repoPath;
final perfettoDistDir = Directory.fromUri(
Uri.parse(
'$mainDevToolsDirectory/third_party/packages/perfetto_ui_compiled/lib/dist',
),
);

// Find the new perfetto version number.
String newVersionNumber = '';
final versionRegExp = RegExp(r'v\d+[.]\d+-[0-9a-fA-F]+');
final entities = perfettoDistDir.listSync();
for (FileSystemEntity entity in entities) {
final path = entity.path;
final match = versionRegExp.firstMatch(path);
if (match != null) {
newVersionNumber = path.split('/').last;
logStatus('new Perfetto version: $newVersionNumber');
break;
}
}

if (newVersionNumber.isEmpty) {
throw Exception(
'Error updating Perfetto assets: could not find Perfetto version number '
'from entities: ${entities.map((e) => e.path).toList()}',
);
}

final pubspec = File.fromUri(
Uri.parse('$mainDevToolsDirectory/packages/devtools_app/pubspec.yaml'),
);

// TODO(kenz): Ensure the pubspec.yaml contains an entry for each file in
// [perfettoDistDir].

final perfettoAssetRegExp = RegExp(
r'(?<prefix>^.*packages\/perfetto_ui_compiled\/dist\/)(?<version>v\d+[.]\d+-[0-9a-fA-F]+)(?<suffix>\/.*$)',
);
final lines = pubspec.readAsLinesSync();
for (int i = 0; i < lines.length; i++) {
final line = lines[i];
final match = perfettoAssetRegExp.firstMatch(line);
if (match != null) {
final prefix = match.namedGroup('prefix')!;
final suffix = match.namedGroup('suffix')!;
lines[i] = '$prefix$newVersionNumber$suffix';
}
}

logStatus(
'updating devtools_app/pubspec.yaml for new Perfetto version'
'$newVersionNumber',
);
final pubspecLinesAsString = '${lines.join('\n')}\n';
pubspec.writeAsStringSync(pubspecLinesAsString);
}
}
2 changes: 2 additions & 0 deletions tool/lib/devtools_command_runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:devtools_tool/commands/fix_goldens.dart';
import 'package:devtools_tool/commands/generate_code.dart';
import 'package:devtools_tool/commands/sync.dart';
import 'package:devtools_tool/commands/update_flutter_sdk.dart';
import 'package:devtools_tool/commands/update_perfetto.dart';

import 'commands/analyze.dart';
import 'commands/list.dart';
Expand All @@ -32,5 +33,6 @@ class DevToolsCommandRunner extends CommandRunner {
addCommand(UpdateDartSdkDepsCommand());
addCommand(UpdateDevToolsVersionCommand());
addCommand(UpdateFlutterSdkCommand());
addCommand(UpdatePerfettoCommand());
}
}
4 changes: 4 additions & 0 deletions tool/update_perfetto.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
#!/bin/bash

# TODO(kenz): delete this script once we can confirm it is not used in the
# Dart SDK or in infra tooling.

# This script requires the use of `gsed`. If you do not have this installed, please run
# `brew install gnu-sed` from your Mac. This script will take several minutes to complete,
# and for that reason it should be ran once per quarter instead of once per montly release.
Expand Down
3 changes: 3 additions & 0 deletions tool/update_perfetto_assets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// TODO(kenz): delete this script once we can confirm it is not used in the
// Dart SDK or in infra tooling.

import 'dart:io';

void main(List<String> args) {
Expand Down

0 comments on commit b9138eb

Please sign in to comment.