| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // TODO(https://fxbug.dev/84961): Fix null safety and remove this language version. |
| // @dart=2.9 |
| |
| import 'dart:async'; |
| import 'dart:convert'; |
| import 'dart:io'; |
| import 'package:path/path.dart' as p; |
| |
| import 'package:status/status.dart'; |
| |
| /// The path, relative to a Fuchsia checkout, where we expect to find the fx |
| /// executable. |
| const fxLocation = '.jiri_root/bin/fx'; |
| |
| class GNStatusParser { |
| final RegExp argsImportExtractor = RegExp('([^/]*)/([^/]*)\.gni'); |
| |
| Map gnTitles = { |
| 'boards': 'Board', |
| 'products': 'Product', |
| 'universe_package_labels': [ |
| 'Universe packages', |
| '--with argument of `fx set`' |
| ], |
| 'base_package_labels': [ |
| 'Base packages', |
| '--with-base argument of `fx set`' |
| ], |
| 'cache_package_labels': [ |
| 'Cache packages', |
| '--with-cache argument of `fx set`' |
| ], |
| 'host_labels': ['Host labels', '--with-host argument of `fx set`'], |
| }; |
| |
| List<Item> parseGn({ProcessResult processResult}) { |
| if (processResult.exitCode != 0) { |
| // Ideally, in the line below, we would `throw Exception(...)` and catch it |
| // likewise up top, thought that is proving hard to format correctly in the test |
| // ignore: only_throw_errors |
| throw 'Unexpected error running fx gn: exit code ${processResult.exitCode}\n---- stderr output:\n${processResult.stderr}\n------'; |
| } else { |
| String json = processResult.stdout; |
| |
| List<Map<String, dynamic>> argsTree = |
| jsonDecode(json)['child'].cast<Map<String, dynamic>>().toList(); |
| |
| return collectFromTreeParser(BasicGnParser(argsTree)); |
| } |
| } |
| |
| List<Item> collectFromTreeParser(BasicGnParser parser) { |
| List<Item> results = []; |
| _addImportItems(parser, results); |
| _addDirectItems(parser, results); |
| _addCalculatedItems(parser, results); |
| return results; |
| } |
| |
| void _addDirectItems(BasicGnParser parser, List<Item> appendTo) { |
| for (String key in parser.assignedVariables.keys) { |
| dynamic value = parser.assignedVariables[key]; |
| var title = gnTitles[key]; |
| if (title != null && (value is! List || value.isNotEmpty)) { |
| // ignore: avoid_init_to_null |
| var notes = null; |
| if (title is List<String>) { |
| title = gnTitles[key][0]; |
| notes = gnTitles[key][1]; |
| } |
| appendTo.add(Item(CategoryType.buildInfo, key, title, value, notes)); |
| } |
| } |
| } |
| |
| void _addImportItems(BasicGnParser parser, List<Item> appendTo) { |
| for (String importClause in parser.imports) { |
| Match m = argsImportExtractor.firstMatch(importClause); |
| if (m != null) { |
| var key = m.group(1); |
| var title = gnTitles[key] ?? key; |
| appendTo.add( |
| Item(CategoryType.buildInfo, key, title, m.group(2), importClause), |
| ); |
| } |
| } |
| } |
| |
| void _addCalculatedItems(BasicGnParser parser, List<Item> appendTo) { |
| // goma |
| bool isGomaEnabled = parser.assignedVariables['use_goma'] == 'true'; |
| String gomaDir = parser.assignedVariables['goma_dir']; |
| appendTo.add(Item(CategoryType.buildInfo, 'goma', 'Goma', |
| isGomaEnabled ? 'enabled' : 'disabled', gomaDir)); |
| |
| // release |
| bool isRelease = parser.assignedVariables['is_debug'] == 'false'; |
| appendTo.add(Item(CategoryType.buildInfo, 'release', 'Is release?', |
| isRelease ? 'true' : 'false', '--release argument of `fx set`')); |
| } |
| } |
| |
| class GNStatusChecker { |
| Future<ProcessResult> checkGn() async { |
| EnvReader envReader = EnvReader.shared; |
| |
| /// Absolute path to the root of the Fuchsia checkout. Read from the |
| /// environment variable. |
| String fuchsiaDir = envReader.getEnv('FUCHSIA_DIR'); |
| |
| /// Path to the fx executable |
| String pathToFx = p.join(fuchsiaDir, fxLocation); |
| |
| /// Absolute path to the build directory. Read from the environment variable. |
| String buildDir = envReader.getEnv('FUCHSIA_BUILD_DIR'); |
| |
| /// Path to the args.gn |
| String pathToArgs = '$buildDir/args.gn'; |
| |
| return Process.run( |
| pathToFx, ['gn', 'format', '--dump-tree=json', pathToArgs]); |
| } |
| } |
| |
| class ArgsGnCollector implements Collector { |
| @override |
| Future<List<Item>> collect({ |
| GNStatusChecker statusChecker, |
| GNStatusParser statusParser, |
| }) async { |
| statusChecker ??= GNStatusChecker(); |
| statusParser ??= GNStatusParser(); |
| |
| ProcessResult pr = await statusChecker.checkGn(); |
| return statusParser.parseGn(processResult: pr); |
| } |
| } |