blob: 869abdfbbb9abe5112db41186bd7f77a734445f7 [file]
// Copyright 2022 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 _useLocalFlutterFlag = 'use-local-flutter';
const _updatePerfettoFlag = 'update-perfetto';
const _buildAppFlag = 'build-app';
const _machineFlag = 'machine';
const _allowEmbeddingFlag = 'allow-embedding';
/// This command builds DevTools in release mode by running the
/// `devtools_tool build-release` command and then serves DevTools with a
/// locally running DevTools server.
///
/// If the [_buildAppFlag] is negated (e.g. --no-build-app), then the DevTools
/// web app will not be rebuilt before serving.
///
/// If [_useLocalFlutterFlag] is present, the Flutter SDK will not be updated to
/// the latest Flutter candidate. Use this flag to save the cost of updating the
/// Flutter SDK when you already have the proper SDK checked out.
///
/// If [_updatePerfettoFlag] is present, the precompiled bits for Perfetto will
/// be updated from the `devtools_tool update-perfetto` command as part of the
/// DevTools build process (e.g. running `devtools_tool build-release`).
class ServeCommand extends Command {
ServeCommand() {
argParser
..addFlag(
_useLocalFlutterFlag,
negatable: false,
defaultsTo: false,
help:
'Whether to use the Flutter SDK on PATH instead of the Flutter SDK '
'contained in the "tool/flutter-sdk" directory.',
)
..addFlag(
_updatePerfettoFlag,
negatable: false,
defaultsTo: false,
help: 'Whether to update the Perfetto assets before building DevTools.',
)
..addFlag(
_buildAppFlag,
negatable: true,
defaultsTo: true,
help:
'Whether to build the DevTools app in release mode before starting '
'the DevTools server.',
)
// Flags defined in the server in DDS.
..addFlag(
_machineFlag,
negatable: false,
help: 'Sets output format to JSON for consumption in tools.',
)
..addFlag(
_allowEmbeddingFlag,
help: 'Allow embedding DevTools inside an iframe.',
);
}
@override
String get name => 'serve';
@override
String get description =>
'Builds DevTools in release mode and serves the web app with a locally '
'running DevTools server.';
@override
Future run() async {
final repo = DevToolsRepo.getInstance();
final processManager = ProcessManager();
final useLocalFlutter = argResults![_useLocalFlutterFlag];
final updatePerfetto = argResults![_updatePerfettoFlag];
final buildApp = argResults![_buildAppFlag];
final remainingArguments = List.of(argResults!.arguments)
..remove(_useLocalFlutterFlag)
..remove(_updatePerfettoFlag)
..remove(_buildAppFlag)
..remove('--no-$_buildAppFlag');
final localDartSdkLocation = Platform.environment['LOCAL_DART_SDK'];
if (localDartSdkLocation == null) {
throw Exception('LOCAL_DART_SDK environment variable not set. Please add '
'the following to your \'.bash_profile\' or \'.bashrc\' file:\n'
'export LOCAL_DART_SDK=<absolute/path/to/my/dart-sdk/sdk>');
}
// Validate the path looks correct in case it was set without the /sdk or
// similar.
final pkgDir = Directory(path.join(localDartSdkLocation, 'pkg'));
if (!pkgDir.existsSync()) {
throw Exception(
'No pkg directory found in LOCAL_DART_SDK at "${pkgDir.path}"\n'
'Is LOCAL_DART_SDK set correctly to the dart-sdk${path.separator}sdk '
'directory?',
);
}
final devToolsBuildLocation =
path.join(repo.devtoolsAppDirectoryPath, 'build', 'web');
if (buildApp) {
final process = await processManager.runProcess(
CliCommand.tool(
'build-release'
' ${useLocalFlutter ? '--$_useLocalFlutterFlag' : ''}'
' ${updatePerfetto ? '--$_updatePerfettoFlag' : ''}',
),
);
if (process.exitCode == 1) {
throw Exception(
'Something went wrong while running `devtools_tool build-release`',
);
}
logStatus('completed building DevTools: $devToolsBuildLocation');
}
logStatus('running pub get for DDS in the local dart sdk');
await processManager.runProcess(
CliCommand.from('dart', ['pub', 'get']),
workingDirectory: path.join(localDartSdkLocation, 'pkg', 'dds'),
);
logStatus('serving DevTools with a local devtools server...');
final serveLocalScriptPath = path.join(
'pkg',
'dds',
'tool',
'devtools_server',
'serve_local.dart',
);
// This call will not exit until explicitly terminated by the user.
await processManager.runProcess(
CliCommand.from(
'dart',
[
serveLocalScriptPath,
'--devtools-build=$devToolsBuildLocation',
// Pass any args that were provided to our script along. This allows IDEs
// to pass `--machine` (etc.) so that this script can behave the same as
// the "dart devtools" command for testing local DevTools/server changes.
...remainingArguments,
],
),
workingDirectory: localDartSdkLocation,
);
}
}