// Copyright 2016 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:async'; import 'dart:convert'; import 'dart:io'; import 'package:args/args.dart'; import 'package:path/path.dart' as path; import 'package:flutter_devicelab/framework/manifest.dart'; import 'package:flutter_devicelab/framework/runner.dart'; import 'package:flutter_devicelab/framework/utils.dart'; List<String> _taskNames = <String>[]; /// Runs tasks. /// /// The tasks are chosen depending on the command-line options /// (see [_argParser]). Future<Null> main(List<String> rawArgs) async { ArgResults args; try { args = _argParser.parse(rawArgs); } on FormatException catch(error) { stderr.writeln('${error.message}\n'); stderr.writeln('Usage:\n'); stderr.writeln(_argParser.usage); exitCode = 1; return null; } if (!args.wasParsed('task')) { if (args.wasParsed('stage')) { final String stageName = args['stage']; final List<ManifestTask> tasks = loadTaskManifest().tasks; for (ManifestTask task in tasks) { if (task.stage == stageName) _taskNames.add(task.name); } } else if (args.wasParsed('all')) { final List<ManifestTask> tasks = loadTaskManifest().tasks; for (ManifestTask task in tasks) { _taskNames.add(task.name); } } } if (_taskNames.isEmpty) { stderr.writeln('Failed to find tasks to run based on supplied options.'); exitCode = 1; return null; } final bool silent = args['silent']; for (String taskName in _taskNames) { section('Running task "$taskName"'); final Map<String, dynamic> result = await runTask(taskName, silent: silent); if (!result['success']) exitCode = 1; print('Task result:'); print(const JsonEncoder.withIndent(' ').convert(result)); section('Finished task "$taskName"'); } } /// Command-line options for the `run.dart` command. final ArgParser _argParser = new ArgParser() ..addOption( 'task', abbr: 't', allowMultiple: true, splitCommas: true, help: 'Either:\n' ' - the name of a task defined in manifest.yaml. Example: complex_layout__start_up.\n' ' - the path to a Dart file corresponding to a task, which resides in bin/tasks. Example: bin/tasks/complex_layout__start_up.dart.\n' '\n' 'This option may be repeated to specify multiple tasks.', callback: (List<String> value) { for (String nameOrPath in value) { final List<String> fragments = path.split(nameOrPath); final bool isDartFile = fragments.last.endsWith('.dart'); if (fragments.length == 1 && !isDartFile) { // Not a path _taskNames.add(nameOrPath); } else if (!isDartFile || fragments.length != 3 || !_listsEqual(<String>['bin', 'tasks'], fragments.take(2).toList())) { // Unsupported executable location throw new FormatException('Invalid value for option -t (--task): $nameOrPath'); } else { _taskNames.add(path.withoutExtension(fragments.last)); } } }, ) ..addOption( 'stage', abbr: 's', help: 'Name of the stage. Runs all tasks for that stage. ' 'The tasks and their stages are read from manifest.yaml.', ) ..addFlag( 'all', abbr: 'a', help: 'Runs all tasks defined in manifest.yaml.', ) ..addOption( 'test', hide: true, allowMultiple: true, splitCommas: true, callback: (List<String> value) { if (value.isNotEmpty) { throw const FormatException( 'Invalid option --test. Did you mean --task (-t)?', ); } }, ) ..addFlag( 'silent', negatable: true, defaultsTo: false, ); bool _listsEqual(List<dynamic> a, List<dynamic> b) { if (a.length != b.length) return false; for (int i = 0; i < a.length; i++) { if (a[i] != b[i]) return false; } return true; }