Unverified Commit 13a6d40f authored by Kevin Moore's avatar Kevin Moore Committed by GitHub

flutter_tools: ensure the context value passed to pub is consistent (#13366)

Adds a class `PubContext` with a fixed set of allowed values
Make it clear these values should not be changed casually

Fixed one inconsistency already: update_packages vs update_pkgs
Provide more information for verify calls
Eliminate `ctx_` prefix.
parent cbcdd03e
...@@ -162,7 +162,7 @@ class CreateCommand extends FlutterCommand { ...@@ -162,7 +162,7 @@ class CreateCommand extends FlutterCommand {
generatedCount += _renderTemplate('package', dirPath, templateContext); generatedCount += _renderTemplate('package', dirPath, templateContext);
if (argResults['pub']) if (argResults['pub'])
await pubGet(context: 'create_pkg', directory: dirPath); await pubGet(context: PubContext.createPackage, directory: dirPath);
final String relativePath = fs.path.relative(dirPath); final String relativePath = fs.path.relative(dirPath);
printStatus('Wrote $generatedCount files.'); printStatus('Wrote $generatedCount files.');
...@@ -180,7 +180,7 @@ class CreateCommand extends FlutterCommand { ...@@ -180,7 +180,7 @@ class CreateCommand extends FlutterCommand {
generatedCount += _renderTemplate('plugin', dirPath, templateContext); generatedCount += _renderTemplate('plugin', dirPath, templateContext);
if (argResults['pub']) if (argResults['pub'])
await pubGet(context: 'create_plugin', directory: dirPath); await pubGet(context: PubContext.createPlugin, directory: dirPath);
if (android_sdk.androidSdk != null) if (android_sdk.androidSdk != null)
gradle.updateLocalProperties(projectPath: dirPath); gradle.updateLocalProperties(projectPath: dirPath);
...@@ -218,7 +218,7 @@ class CreateCommand extends FlutterCommand { ...@@ -218,7 +218,7 @@ class CreateCommand extends FlutterCommand {
); );
if (argResults['pub']) { if (argResults['pub']) {
await pubGet(context: 'create', directory: appPath); await pubGet(context: PubContext.create, directory: appPath);
injectPlugins(directory: appPath); injectPlugins(directory: appPath);
} }
......
...@@ -69,7 +69,7 @@ class PackagesGetCommand extends FlutterCommand { ...@@ -69,7 +69,7 @@ class PackagesGetCommand extends FlutterCommand {
); );
} }
await pubGet(context: 'get', await pubGet(context: PubContext.pubGet,
directory: target, directory: target,
upgrade: upgrade, upgrade: upgrade,
offline: argResults['offline'], offline: argResults['offline'],
...@@ -102,7 +102,7 @@ class PackagesTestCommand extends FlutterCommand { ...@@ -102,7 +102,7 @@ class PackagesTestCommand extends FlutterCommand {
} }
@override @override
Future<Null> runCommand() => pub(<String>['run', 'test']..addAll(argResults.rest), context: 'run_test', retry: false); Future<Null> runCommand() => pub(<String>['run', 'test']..addAll(argResults.rest), context: PubContext.runTest, retry: false);
} }
class PackagesPassthroughCommand extends FlutterCommand { class PackagesPassthroughCommand extends FlutterCommand {
......
...@@ -146,7 +146,7 @@ class UpdatePackagesCommand extends FlutterCommand { ...@@ -146,7 +146,7 @@ class UpdatePackagesCommand extends FlutterCommand {
fakePackage.createSync(); fakePackage.createSync();
fakePackage.writeAsStringSync(_generateFakePubspec(dependencies.values)); fakePackage.writeAsStringSync(_generateFakePubspec(dependencies.values));
// First we run "pub upgrade" on this generated package: // First we run "pub upgrade" on this generated package:
await pubGet(context: 'update_packages', directory: temporaryDirectory.path, upgrade: true, checkLastModified: false); await pubGet(context: PubContext.updatePackages, directory: temporaryDirectory.path, upgrade: true, checkLastModified: false);
// Then we run "pub deps --style=compact" on the result. We pipe all the // Then we run "pub deps --style=compact" on the result. We pipe all the
// output to tree.fill(), which parses it so that it can create a graph // output to tree.fill(), which parses it so that it can create a graph
// of all the dependencies so that we can figure out the transitive // of all the dependencies so that we can figure out the transitive
...@@ -154,7 +154,7 @@ class UpdatePackagesCommand extends FlutterCommand { ...@@ -154,7 +154,7 @@ class UpdatePackagesCommand extends FlutterCommand {
// each package. // each package.
await pub( await pub(
<String>['deps', '--style=compact'], <String>['deps', '--style=compact'],
context: 'update_pkgs', context: PubContext.updatePackages,
directory: temporaryDirectory.path, directory: temporaryDirectory.path,
filter: tree.fill, filter: tree.fill,
retry: false, // errors here are usually fatal since we're not hitting the network retry: false, // errors here are usually fatal since we're not hitting the network
...@@ -211,7 +211,7 @@ class UpdatePackagesCommand extends FlutterCommand { ...@@ -211,7 +211,7 @@ class UpdatePackagesCommand extends FlutterCommand {
int count = 0; int count = 0;
for (Directory dir in packages) { for (Directory dir in packages) {
await pubGet(context: 'update_packages', directory: dir.path, checkLastModified: false); await pubGet(context: PubContext.updatePackages, directory: dir.path, checkLastModified: false);
count += 1; count += 1;
} }
......
...@@ -68,7 +68,7 @@ class UpgradeCommand extends FlutterCommand { ...@@ -68,7 +68,7 @@ class UpgradeCommand extends FlutterCommand {
final String projRoot = findProjectRoot(); final String projRoot = findProjectRoot();
if (projRoot != null) { if (projRoot != null) {
printStatus(''); printStatus('');
await pubGet(context: 'upgrade', directory: projRoot, upgrade: true, checkLastModified: false); await pubGet(context: PubContext.pubUpgrade, directory: projRoot, upgrade: true, checkLastModified: false);
} }
// Run a doctor check in case system requirements have changed. // Run a doctor check in case system requirements have changed.
......
...@@ -16,6 +16,43 @@ import '../cache.dart'; ...@@ -16,6 +16,43 @@ import '../cache.dart';
import '../globals.dart'; import '../globals.dart';
import 'sdk.dart'; import 'sdk.dart';
/// Represents Flutter-specific data that is added to the `PUB_ENVIRONMENT`
/// environment variable and allows understanding the type of requests made to
/// the package site on Flutter's behalf.
// DO NOT update without contacting kevmoo.
// We have server-side tooling that assumes the values are consistent.
class PubContext {
static final RegExp _validContext = new RegExp('[a-z][a-z_]*[a-z]');
static final PubContext create = new PubContext._(<String>['create']);
static final PubContext createPackage = new PubContext._(<String>['create_pkg']);
static final PubContext createPlugin = new PubContext._(<String>['create_plugin']);
static final PubContext interactive = new PubContext._(<String>['interactive']);
static final PubContext pubGet = new PubContext._(<String>['get']);
static final PubContext pubUpgrade = new PubContext._(<String>['upgrade']);
static final PubContext runTest = new PubContext._(<String>['run_test']);
static final PubContext flutterTests = new PubContext._(<String>['flutter_tests']);
static final PubContext updatePackages = new PubContext._(<String>['update_packages']);
final List<String> _values;
PubContext._(this._values) {
for (String item in _values) {
if (!_validContext.hasMatch(item)) {
throw new ArgumentError.value(
_values, 'value', 'Must match RegExp ${_validContext.pattern}');
}
}
}
static PubContext getVerifyContext(String commandName) =>
new PubContext._(<String>['verify', commandName.replaceAll('-', '_')]);
@override
String toString() => 'PubContext: ${_values.join(':')}';
}
bool _shouldRunPubGet({ File pubSpecYaml, File dotPackages }) { bool _shouldRunPubGet({ File pubSpecYaml, File dotPackages }) {
if (!dotPackages.existsSync()) if (!dotPackages.existsSync())
return true; return true;
...@@ -30,9 +67,9 @@ bool _shouldRunPubGet({ File pubSpecYaml, File dotPackages }) { ...@@ -30,9 +67,9 @@ bool _shouldRunPubGet({ File pubSpecYaml, File dotPackages }) {
} }
/// [context] provides extra information to package server requests to /// [context] provides extra information to package server requests to
/// understand usage. It must match the regular expression `[a-z][a-z_]*[a-z]`. /// understand usage.
Future<Null> pubGet({ Future<Null> pubGet({
@required String context, @required PubContext context,
String directory, String directory,
bool skipIfAbsent: false, bool skipIfAbsent: false,
bool upgrade: false, bool upgrade: false,
...@@ -90,9 +127,9 @@ typedef String MessageFilter(String message); ...@@ -90,9 +127,9 @@ typedef String MessageFilter(String message);
/// `arguments` list) unless `showTraceForErrors` is false. /// `arguments` list) unless `showTraceForErrors` is false.
/// ///
/// [context] provides extra information to package server requests to /// [context] provides extra information to package server requests to
/// understand usage. It must match the regular expression `[a-z][a-z_]*[a-z]`. /// understand usage.
Future<Null> pub(List<String> arguments, { Future<Null> pub(List<String> arguments, {
@required String context, @required PubContext context,
String directory, String directory,
MessageFilter filter, MessageFilter filter,
String failureMessage: 'pub failed', String failureMessage: 'pub failed',
...@@ -133,7 +170,7 @@ Future<Null> pubInteractively(List<String> arguments, { ...@@ -133,7 +170,7 @@ Future<Null> pubInteractively(List<String> arguments, {
final int code = await runInteractively( final int code = await runInteractively(
_pubCommand(arguments), _pubCommand(arguments),
workingDirectory: directory, workingDirectory: directory,
environment: _createPubEnvironment('interactive'), environment: _createPubEnvironment(PubContext.interactive),
); );
if (code != 0) if (code != 0)
throwToolExit('pub finished with exit code $code', exitCode: code); throwToolExit('pub finished with exit code $code', exitCode: code);
...@@ -147,8 +184,8 @@ List<String> _pubCommand(List<String> arguments) { ...@@ -147,8 +184,8 @@ List<String> _pubCommand(List<String> arguments) {
/// The full environment used when running pub. /// The full environment used when running pub.
/// ///
/// [context] provides extra information to package server requests to /// [context] provides extra information to package server requests to
/// understand usage. It must match the regular expression `[a-z][a-z_]*[a-z]`. /// understand usage.
Map<String, String> _createPubEnvironment(String context) { Map<String, String> _createPubEnvironment(PubContext context) {
final Map<String, String> environment = <String, String>{ final Map<String, String> environment = <String, String>{
'FLUTTER_ROOT': Cache.flutterRoot, 'FLUTTER_ROOT': Cache.flutterRoot,
_pubEnvironmentKey: _getPubEnvironmentValue(context), _pubEnvironmentKey: _getPubEnvironmentValue(context),
...@@ -168,15 +205,15 @@ const String _pubEnvironmentKey = 'PUB_ENVIRONMENT'; ...@@ -168,15 +205,15 @@ const String _pubEnvironmentKey = 'PUB_ENVIRONMENT';
/// The console environment key used by the pub tool to find the cache directory. /// The console environment key used by the pub tool to find the cache directory.
const String _pubCacheEnvironmentKey = 'PUB_CACHE'; const String _pubCacheEnvironmentKey = 'PUB_CACHE';
final RegExp _validContext = new RegExp('[a-z][a-z_]*[a-z]');
/// Returns the environment value that should be used when running pub. /// Returns the environment value that should be used when running pub.
/// ///
/// Includes any existing environment variable, if one exists. /// Includes any existing environment variable, if one exists.
/// ///
/// [context] provides extra information to package server requests to /// [context] provides extra information to package server requests to
/// understand usage. It must match the regular expression `[a-z][a-z_]*[a-z]`. /// understand usage.
String _getPubEnvironmentValue(String pubContext) { String _getPubEnvironmentValue(PubContext pubContext) {
// DO NOT update this function without contacting kevmoo.
// We have server-side tooling that assumes the values are consistent.
final List<String> values = <String>[]; final List<String> values = <String>[];
final String existing = platform.environment[_pubEnvironmentKey]; final String existing = platform.environment[_pubEnvironmentKey];
...@@ -190,11 +227,7 @@ String _getPubEnvironmentValue(String pubContext) { ...@@ -190,11 +227,7 @@ String _getPubEnvironmentValue(String pubContext) {
} }
values.add('flutter_cli'); values.add('flutter_cli');
values.addAll(pubContext._values);
if (!_validContext.hasMatch(pubContext)) {
throw new ArgumentError.value(pubContext, 'pubContext', 'Must match RegExp ${_validContext.pattern}');
}
values.add('ctx_$pubContext');
return values.join(':'); return values.join(':');
} }
......
...@@ -242,7 +242,7 @@ abstract class FlutterCommand extends Command<Null> { ...@@ -242,7 +242,7 @@ abstract class FlutterCommand extends Command<Null> {
await cache.updateAll(); await cache.updateAll();
if (shouldRunPub) if (shouldRunPub)
await pubGet(context: 'verify'); await pubGet(context: PubContext.getVerifyContext(name));
setupApplicationPackages(); setupApplicationPackages();
......
...@@ -32,7 +32,7 @@ void main() { ...@@ -32,7 +32,7 @@ void main() {
testUsingContext('AnalysisServer success', () async { testUsingContext('AnalysisServer success', () async {
_createSampleProject(tempDir); _createSampleProject(tempDir);
await pubGet(context: 'flutter_tests', directory: tempDir.path); await pubGet(context: PubContext.flutterTests, directory: tempDir.path);
server = new AnalysisServer(dartSdkPath, <String>[tempDir.path]); server = new AnalysisServer(dartSdkPath, <String>[tempDir.path]);
...@@ -52,7 +52,7 @@ void main() { ...@@ -52,7 +52,7 @@ void main() {
testUsingContext('AnalysisServer errors', () async { testUsingContext('AnalysisServer errors', () async {
_createSampleProject(tempDir, brokenCode: true); _createSampleProject(tempDir, brokenCode: true);
await pubGet(context: 'flutter_tests', directory: tempDir.path); await pubGet(context: PubContext.flutterTests, directory: tempDir.path);
server = new AnalysisServer(dartSdkPath, <String>[tempDir.path]); server = new AnalysisServer(dartSdkPath, <String>[tempDir.path]);
......
...@@ -26,7 +26,7 @@ void main() { ...@@ -26,7 +26,7 @@ void main() {
new FakeAsync().run((FakeAsync time) { new FakeAsync().run((FakeAsync time) {
expect(processMock.lastPubEnvironmment, isNull); expect(processMock.lastPubEnvironmment, isNull);
pubGet(context: 'flutter_tests', checkLastModified: false).then((Null value) { pubGet(context: PubContext.flutterTests, checkLastModified: false).then((Null value) {
error = 'test completed unexpectedly'; error = 'test completed unexpectedly';
}, onError: (dynamic thrownError) { }, onError: (dynamic thrownError) {
error = 'test failed unexpectedly: $thrownError'; error = 'test failed unexpectedly: $thrownError';
...@@ -37,7 +37,7 @@ void main() { ...@@ -37,7 +37,7 @@ void main() {
'Running "flutter packages get" in /...\n' 'Running "flutter packages get" in /...\n'
'pub get failed (69) -- attempting retry 1 in 1 second...\n' 'pub get failed (69) -- attempting retry 1 in 1 second...\n'
); );
expect(processMock.lastPubEnvironmment, contains('flutter_cli:ctx_flutter_tests')); expect(processMock.lastPubEnvironmment, contains('flutter_cli:flutter_tests'));
expect(processMock.lastPubCache, isNull); expect(processMock.lastPubCache, isNull);
time.elapse(const Duration(milliseconds: 500)); time.elapse(const Duration(milliseconds: 500));
expect(testLogger.statusText, expect(testLogger.statusText,
...@@ -96,7 +96,7 @@ void main() { ...@@ -96,7 +96,7 @@ void main() {
MockDirectory.findCache = true; MockDirectory.findCache = true;
expect(processMock.lastPubEnvironmment, isNull); expect(processMock.lastPubEnvironmment, isNull);
expect(processMock.lastPubCache, isNull); expect(processMock.lastPubCache, isNull);
pubGet(context: 'flutter_tests', checkLastModified: false).then((Null value) { pubGet(context: PubContext.flutterTests, checkLastModified: false).then((Null value) {
error = 'test completed unexpectedly'; error = 'test completed unexpectedly';
}, onError: (dynamic thrownError) { }, onError: (dynamic thrownError) {
error = 'test failed unexpectedly: $thrownError'; error = 'test failed unexpectedly: $thrownError';
...@@ -122,7 +122,7 @@ void main() { ...@@ -122,7 +122,7 @@ void main() {
MockDirectory.findCache = false; MockDirectory.findCache = false;
expect(processMock.lastPubEnvironmment, isNull); expect(processMock.lastPubEnvironmment, isNull);
expect(processMock.lastPubCache, isNull); expect(processMock.lastPubCache, isNull);
pubGet(context: 'flutter_tests', checkLastModified: false).then((Null value) { pubGet(context: PubContext.flutterTests, checkLastModified: false).then((Null value) {
error = 'test completed unexpectedly'; error = 'test completed unexpectedly';
}, onError: (dynamic thrownError) { }, onError: (dynamic thrownError) {
error = 'test failed unexpectedly: $thrownError'; error = 'test failed unexpectedly: $thrownError';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment