Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(559)

Unified Diff: mojo/public/dart/third_party/analyzer/lib/source/pub_package_map_provider.dart

Issue 1346773002: Stop running pub get at gclient sync time and fix build bugs (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: mojo/public/dart/third_party/analyzer/lib/source/pub_package_map_provider.dart
diff --git a/mojo/public/dart/third_party/analyzer/lib/source/pub_package_map_provider.dart b/mojo/public/dart/third_party/analyzer/lib/source/pub_package_map_provider.dart
new file mode 100644
index 0000000000000000000000000000000000000000..3e9936d1f8abf3c4e6523b03ce637935a811dfaf
--- /dev/null
+++ b/mojo/public/dart/third_party/analyzer/lib/source/pub_package_map_provider.dart
@@ -0,0 +1,171 @@
+// Copyright (c) 2014, 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.
+
+library source.pub_package_map_provider;
+
+import 'dart:collection';
+import 'dart:convert';
+import 'dart:core' hide Resource;
+import 'dart:io' as io;
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/source/package_map_provider.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/sdk_io.dart';
+
+/**
+ * The function used to run pub list.
+ */
+typedef io.ProcessResult RunPubList(Folder folder);
+
+/**
+ * Implementation of PackageMapProvider that operates by executing pub.
+ */
+class PubPackageMapProvider implements PackageMapProvider {
+ static const String PUB_LIST_COMMAND = 'list-package-dirs';
+
+ /**
+ * The name of the 'pubspec.lock' file, which we assume is the dependency
+ * in the event that [PUB_LIST_COMMAND] fails.
+ */
+ static const String PUBSPEC_LOCK_NAME = 'pubspec.lock';
+
+ /**
+ * [ResourceProvider] that is used to create the [Folder]s that populate the
+ * package map.
+ */
+ final ResourceProvider resourceProvider;
+
+ /**
+ * Sdk that we use to find the pub executable.
+ */
+ final DirectoryBasedDartSdk sdk;
+
+ /**
+ * The function used to run pub list.
+ */
+ RunPubList _runPubList;
+
+ /**
+ * Construct a new instance.
+ * A [RunPubList] implementation may be injected for testing
+ */
+ PubPackageMapProvider(this.resourceProvider, this.sdk, [this._runPubList]) {
+ if (_runPubList == null) {
+ _runPubList = _runPubListDefault;
+ }
+ }
+
+ @override
+ PackageMapInfo computePackageMap(Folder folder) {
+ // TODO(paulberry) make this asynchronous so that we can (a) do other
+ // analysis while it's in progress, and (b) time out if it takes too long
+ // to respond.
+ io.ProcessResult result;
+ try {
+ result = _runPubList(folder);
+ } on io.ProcessException catch (exception, stackTrace) {
+ AnalysisEngine.instance.logger.logInformation(
+ "Error running pub $PUB_LIST_COMMAND\n$exception\n$stackTrace");
+ }
+ if (result == null || result.exitCode != 0) {
+ String exitCode =
+ result != null ? 'exit code ${result.exitCode}' : 'null';
+ AnalysisEngine.instance.logger
+ .logInformation("pub $PUB_LIST_COMMAND failed: $exitCode");
+ return computePackageMapError(folder);
+ }
+ try {
+ PackageMapInfo packageMap =
+ parsePackageMap(JSON.decode(result.stdout), folder);
+ return packageMap;
+ } catch (exception, stackTrace) {
+ AnalysisEngine.instance.logger.logError(
+ "Malformed output from pub $PUB_LIST_COMMAND\n$exception\n$stackTrace");
+ }
+
+ return computePackageMapError(folder);
+ }
+
+ /**
+ * Create a PackageMapInfo object representing an error condition.
+ */
+ PackageMapInfo computePackageMapError(Folder folder) {
+ // Even if an error occurs, we still need to know the dependencies, so that
+ // we'll know when to try running "pub list-package-dirs" again.
+ // Unfortunately, "pub list-package-dirs" doesn't tell us dependencies when
+ // an error occurs, so just assume there is one dependency, "pubspec.lock".
+ List<String> dependencies = <String>[
+ resourceProvider.pathContext.join(folder.path, PUBSPEC_LOCK_NAME)
+ ];
+ return new PackageMapInfo(null, dependencies.toSet());
+ }
+
+ /**
+ * Decode the JSON output from pub into a package map. Paths in the
+ * output are considered relative to [folder].
+ */
+ PackageMapInfo parsePackageMap(Map obj, Folder folder) {
+ // The output of pub looks like this:
+ // {
+ // "packages": {
+ // "foo": "path/to/foo",
+ // "bar": ["path/to/bar1", "path/to/bar2"],
+ // "myapp": "path/to/myapp", // self link is included
+ // },
+ // "input_files": [
+ // "path/to/myapp/pubspec.lock"
+ // ]
+ // }
+ Map<String, List<Folder>> packageMap = new HashMap<String, List<Folder>>();
+ Map packages = obj['packages'];
+ processPaths(String packageName, List paths) {
+ List<Folder> folders = <Folder>[];
+ for (var path in paths) {
+ if (path is String) {
+ Resource resource = folder.getChildAssumingFolder(path);
+ if (resource is Folder) {
+ folders.add(resource);
+ }
+ }
+ }
+ if (folders.isNotEmpty) {
+ packageMap[packageName] = folders;
+ }
+ }
+ packages.forEach((key, value) {
+ if (value is String) {
+ processPaths(key, [value]);
+ } else if (value is List) {
+ processPaths(key, value);
+ }
+ });
+ Set<String> dependencies = new Set<String>();
+ List inputFiles = obj['input_files'];
+ if (inputFiles != null) {
+ for (var path in inputFiles) {
+ if (path is String) {
+ dependencies.add(folder.canonicalizePath(path));
+ }
+ }
+ }
+ return new PackageMapInfo(packageMap, dependencies);
+ }
+
+ /**
+ * Run pub list to determine the packages and input files.
+ */
+ io.ProcessResult _runPubListDefault(Folder folder) {
+ String executablePath = sdk.pubExecutable.getAbsolutePath();
+ List<String> arguments = [PUB_LIST_COMMAND];
+ String workingDirectory = folder.path;
+ int subprocessId = AnalysisEngine.instance.instrumentationService
+ .logSubprocessStart(executablePath, arguments, workingDirectory);
+ io.ProcessResult result = io.Process.runSync(executablePath, arguments,
+ workingDirectory: workingDirectory);
+ AnalysisEngine.instance.instrumentationService.logSubprocessResult(
+ subprocessId, result.exitCode, result.stdout, result.stderr);
+ return result;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698