• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'dart:async';
6import 'dart:convert';
7import 'dart:io';
8
9import 'package:args/args.dart';
10import 'package:path/path.dart' as path;
11
12import 'package:flutter_devicelab/framework/manifest.dart';
13import 'package:flutter_devicelab/framework/runner.dart';
14import 'package:flutter_devicelab/framework/utils.dart';
15
16List<String> _taskNames = <String>[];
17
18/// Runs tasks.
19///
20/// The tasks are chosen depending on the command-line options
21/// (see [_argParser]).
22Future<void> main(List<String> rawArgs) async {
23  ArgResults args;
24  try {
25    args = _argParser.parse(rawArgs);
26  } on FormatException catch (error) {
27    stderr.writeln('${error.message}\n');
28    stderr.writeln('Usage:\n');
29    stderr.writeln(_argParser.usage);
30    exitCode = 1;
31    return;
32  }
33
34  if (!args.wasParsed('task')) {
35    if (args.wasParsed('stage')) {
36      final String stageName = args['stage'];
37      final List<ManifestTask> tasks = loadTaskManifest().tasks;
38      for (ManifestTask task in tasks) {
39        if (task.stage == stageName)
40          _taskNames.add(task.name);
41      }
42    } else if (args.wasParsed('all')) {
43      final List<ManifestTask> tasks = loadTaskManifest().tasks;
44      for (ManifestTask task in tasks) {
45        _taskNames.add(task.name);
46      }
47    }
48  }
49
50  if (_taskNames.isEmpty) {
51    stderr.writeln('Failed to find tasks to run based on supplied options.');
52    exitCode = 1;
53    return;
54  }
55
56  final bool silent = args['silent'];
57  final String localEngine = args['local-engine'];
58  final String localEngineSrcPath = args['local-engine-src-path'];
59
60  for (String taskName in _taskNames) {
61    section('Running task "$taskName"');
62    final Map<String, dynamic> result = await runTask(
63      taskName,
64      silent: silent,
65      localEngine: localEngine,
66      localEngineSrcPath: localEngineSrcPath,
67    );
68
69    if (!result['success'])
70      exitCode = 1;
71
72    print('Task result:');
73    print(const JsonEncoder.withIndent('  ').convert(result));
74    section('Finished task "$taskName"');
75  }
76}
77
78/// Command-line options for the `run.dart` command.
79final ArgParser _argParser = ArgParser()
80  ..addMultiOption(
81    'task',
82    abbr: 't',
83    splitCommas: true,
84    help: 'Either:\n'
85        ' - the name of a task defined in manifest.yaml. Example: complex_layout__start_up.\n'
86        ' - the path to a Dart file corresponding to a task, which resides in bin/tasks. Example: bin/tasks/complex_layout__start_up.dart.\n'
87        '\n'
88        'This option may be repeated to specify multiple tasks.',
89    callback: (List<String> value) {
90      for (String nameOrPath in value) {
91        final List<String> fragments = path.split(nameOrPath);
92        final bool isDartFile = fragments.last.endsWith('.dart');
93
94        if (fragments.length == 1 && !isDartFile) {
95          // Not a path
96          _taskNames.add(nameOrPath);
97        } else if (!isDartFile || fragments.length != 3 || !_listsEqual(<String>['bin', 'tasks'], fragments.take(2).toList())) {
98          // Unsupported executable location
99          throw FormatException('Invalid value for option -t (--task): $nameOrPath');
100        } else {
101          _taskNames.add(path.withoutExtension(fragments.last));
102        }
103      }
104    },
105  )
106  ..addOption(
107    'stage',
108    abbr: 's',
109    help: 'Name of the stage. Runs all tasks for that stage. '
110          'The tasks and their stages are read from manifest.yaml.',
111  )
112  ..addFlag(
113    'all',
114    abbr: 'a',
115    help: 'Runs all tasks defined in manifest.yaml.',
116  )
117  ..addMultiOption(
118    'test',
119    hide: true,
120    splitCommas: true,
121    callback: (List<String> value) {
122      if (value.isNotEmpty) {
123        throw const FormatException(
124          'Invalid option --test. Did you mean --task (-t)?',
125        );
126      }
127    },
128  )
129  ..addFlag(
130    'silent',
131    negatable: true,
132    defaultsTo: false,
133  )
134  ..addOption(
135    'local-engine',
136    help: 'Name of a build output within the engine out directory, if you are '
137          'building Flutter locally. Use this to select a specific version of '
138          'the engine if you have built multiple engine targets. This path is '
139          'relative to --local-engine-src-path/out.',
140  )
141  ..addOption(
142    'local-engine-src-path',
143    help: 'Path to your engine src directory, if you are building Flutter '
144          'locally. Defaults to \$FLUTTER_ENGINE if set, or tries to guess at '
145          'the location based on the value of the --flutter-root option.',
146  );
147
148bool _listsEqual(List<dynamic> a, List<dynamic> b) {
149  if (a.length != b.length)
150    return false;
151
152  for (int i = 0; i < a.length; i++) {
153    if (a[i] != b[i])
154      return false;
155  }
156
157  return true;
158}
159