| // Copyright (c) 2018, 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. |
| import 'dart:io'; |
| |
| // TODO(rnystrom): Differences from test.dart's version: |
| // - Remove special handling for "ff" as firefox. |
| // - "windows" -> "win". |
| // - "macos" -> "mac". |
| // - toString() on enum classes is just name. |
| // - builderTag defaults to empty string, not null. |
| // Need to migrate test.dart to not expect the above before it can use this. |
| |
| // READ ME! If you add a new field to this, make sure to add it to |
| // [parse()], [optionsEqual()], [hashCode], and [toString()]. A good check is to |
| // comment out an existing field and see what breaks. Every error is a place |
| // where you will need to add code for your new field. |
| |
| /// A set of options that affects how a Dart SDK test is run in a way that may |
| /// affect its outcome. |
| /// |
| /// This includes options like "compiler" and "runtime" which fundamentally |
| /// decide how a test is executed. Options are tracked because a single test |
| /// may have different outcomes for different configurations. For example, it |
| /// may currently pass on the VM but not dart2js or vice versa. |
| /// |
| /// Options that affect how a test can be run but don't affect its outcome are |
| /// *not* stored here. Things like how test results are displayed, where logs |
| /// are written, etc. live outside of this. |
| class Configuration { |
| /// Expands a configuration name "[template]" all using [optionsJson] to a |
| /// list of configurations. |
| /// |
| /// A template is a configuration name that contains zero or more |
| /// parenthesized sections. Within the parentheses are a series of options |
| /// separated by pipes. For example: |
| /// |
| /// strong-fasta-(linux|mac|win)-(debug|release) |
| /// |
| /// Text outside of parenthesized groups is treated literally. Each |
| /// parenthesized section expands to a configuration for each of the options |
| /// separated by pipes. If a template contains multiple parenthesized |
| /// sections, configurations are created for all combinations of them. The |
| /// above template expands to: |
| /// |
| /// strong-fasta-linux-debug |
| /// strong-fasta-linux-release |
| /// strong-fasta-mac-debug |
| /// strong-fasta-mac-release |
| /// strong-fasta-win-debug |
| /// strong-fasta-win-release |
| /// |
| /// After expansion, the resulting strings (and [optionsJson]) are passed to |
| /// [parse()] to convert each one to a full configuration. |
| static List<Configuration> expandTemplate( |
| String template, Map<String, dynamic> optionsJson) { |
| if (template.isEmpty) throw FormatException("Template must not be empty."); |
| |
| var sections = <List<String>>[]; |
| var start = 0; |
| while (start < template.length) { |
| var openParen = template.indexOf("(", start); |
| |
| if (openParen == -1) { |
| // Add the last literal section. |
| sections.add([template.substring(start, template.length)]); |
| break; |
| } |
| |
| var closeParen = template.indexOf(")", openParen); |
| if (closeParen == -1) { |
| throw FormatException('Missing ")" in name template "$template".'); |
| } |
| |
| // Add the literal part before the next "(". |
| sections.add([template.substring(start, openParen)]); |
| |
| // Add the options within the parentheses. |
| sections.add(template.substring(openParen + 1, closeParen).split("|")); |
| |
| // Continue past the ")". |
| start = closeParen + 1; |
| } |
| |
| var result = <Configuration>[]; |
| |
| // Walk through every combination of every section. |
| iterateSection(String prefix, int section) { |
| // If we pinned all the sections, parse it. |
| if (section >= sections.length) { |
| try { |
| result.add(Configuration.parse(prefix, optionsJson)); |
| } on FormatException catch (ex) { |
| throw FormatException( |
| 'Could not parse expanded configuration "$prefix" from template ' |
| '"$template":\n${ex.message}'); |
| } |
| return; |
| } |
| |
| for (var i = 0; i < sections[section].length; i++) { |
| iterateSection(prefix + sections[section][i], section + 1); |
| } |
| } |
| |
| iterateSection("", 0); |
| |
| return result; |
| } |
| |
| /// Parse a single configuration with [name] with additional options defined |
| /// in [optionsJson]. |
| /// |
| /// The name should be a series of words separated by hyphens. Any word that |
| /// matches the name of an [Architecture], [Compiler], [Mode], [Runtime], or |
| /// [System] sets that option in the resulting configuration. Those options |
| /// may also be specified in the JSON map. |
| /// |
| /// Additional Boolean and string options are defined in the map. The key |
| /// names match the corresponding command-line option names, using kebab-case. |
| static Configuration parse(String name, Map<String, dynamic> optionsJson) { |
| if (name.isEmpty) throw FormatException("Name must not be empty."); |
| |
| // Infer option values from the words in the configuration name. |
| var words = name.split("-").toSet(); |
| var optionsCopy = new Map.of(optionsJson); |
| |
| T enumOption<T extends NamedEnum>( |
| String option, List<String> allowed, T Function(String) parse) { |
| // Look up the value from the words in the name. |
| T fromName; |
| for (var value in allowed) { |
| // Don't treat "none" as matchable since it's ambiguous as to whether |
| // it refers to compiler or runtime. |
| if (value == "none") continue; |
| |
| if (words.contains(value)) { |
| if (fromName != null) { |
| throw FormatException( |
| 'Found multiple values for $option ("$fromName" and "$value"), ' |
| 'in configuration name.'); |
| } |
| fromName = parse(value); |
| } |
| } |
| |
| // Look up the value from the options. |
| T fromOption; |
| if (optionsCopy.containsKey(option)) { |
| fromOption = parse(optionsCopy[option] as String); |
| optionsCopy.remove(option); |
| } |
| |
| if (fromName != null && fromOption != null) { |
| if (fromName == fromOption) { |
| throw FormatException( |
| 'Redundant $option in configuration name "$fromName" and options.'); |
| } else { |
| throw FormatException( |
| 'Found $option "$fromOption" in options and "$fromName" in ' |
| 'configuration name.'); |
| } |
| } |
| |
| return fromName ?? fromOption; |
| } |
| |
| bool boolOption(String option) { |
| if (!optionsCopy.containsKey(option)) return null; |
| |
| var value = optionsCopy.remove(option); |
| if (value == null) throw FormatException('Option "$option" was null.'); |
| if (value is! bool) { |
| throw FormatException('Option "$option" had value "$value", which is ' |
| 'not a bool.'); |
| } |
| return value as bool; |
| } |
| |
| int intOption(String option) { |
| if (!optionsCopy.containsKey(option)) return null; |
| |
| var value = optionsCopy.remove(option); |
| if (value == null) throw FormatException('Option "$option" was null.'); |
| if (value is! int) { |
| throw FormatException('Option "$option" had value "$value", which is ' |
| 'not an int.'); |
| } |
| return value as int; |
| } |
| |
| String stringOption(String option) { |
| if (!optionsCopy.containsKey(option)) return null; |
| |
| var value = optionsCopy.remove(option); |
| if (value == null) throw FormatException('Option "$option" was null.'); |
| if (value is! String) { |
| throw FormatException('Option "$option" had value "$value", which is ' |
| 'not a string.'); |
| } |
| return value as String; |
| } |
| |
| List<String> stringListOption(String option) { |
| if (!optionsCopy.containsKey(option)) return null; |
| |
| var value = optionsCopy.remove(option); |
| if (value == null) throw FormatException('Option "$option" was null.'); |
| if (value is! List) { |
| throw FormatException('Option "$option" had value "$value", which is ' |
| 'not a List.'); |
| } |
| return new List<String>.from(value as List); |
| } |
| |
| // Extract options from the name and map. |
| var architecture = |
| enumOption("architecture", Architecture.names, Architecture.find); |
| var compiler = enumOption("compiler", Compiler.names, Compiler.find); |
| var mode = enumOption("mode", Mode.names, Mode.find); |
| var runtime = enumOption("runtime", Runtime.names, Runtime.find); |
| var system = enumOption("system", System.names, System.find); |
| |
| // Fill in any missing values using defaults when possible. |
| architecture ??= Architecture.x64; |
| system ??= System.host; |
| |
| // Infer from compiler from runtime or vice versa. |
| if (compiler == null) { |
| if (runtime == null) { |
| throw FormatException( |
| 'Must specify at least one of compiler or runtime in options or ' |
| 'configuration name.'); |
| } else { |
| compiler = runtime.defaultCompiler; |
| } |
| } else { |
| if (runtime == null) { |
| runtime = compiler.defaultRuntime; |
| } else { |
| // Do nothing, specified both. |
| } |
| } |
| |
| // Infer the mode from the compiler. |
| mode ??= compiler.defaultMode; |
| |
| var configuration = Configuration( |
| name, architecture, compiler, mode, runtime, system, |
| builderTag: stringOption("builder-tag"), |
| vmOptions: stringListOption("vm-options"), |
| dart2jsOptions: stringListOption("dart2js-options"), |
| timeout: intOption("timeout"), |
| enableAsserts: boolOption("enable-asserts"), |
| isChecked: boolOption("checked"), |
| isCsp: boolOption("csp"), |
| isHostChecked: boolOption("host-checked"), |
| isMinified: boolOption("minified"), |
| previewDart2: boolOption("preview-dart-2"), |
| useAnalyzerCfe: boolOption("use-cfe"), |
| useAnalyzerFastaParser: boolOption("analyzer-use-fasta-parser"), |
| useBlobs: boolOption("use-blobs"), |
| useHotReload: boolOption("hot-reload"), |
| useHotReloadRollback: boolOption("hot-reload-rollback"), |
| useSdk: boolOption("use-sdk")); |
| |
| // Should have consumed the whole map. |
| if (optionsCopy.isNotEmpty) { |
| throw new FormatException('Unknown option "${optionsCopy.keys.first}".'); |
| } |
| |
| return configuration; |
| } |
| |
| final String name; |
| |
| final Architecture architecture; |
| |
| final Compiler compiler; |
| |
| final Mode mode; |
| |
| final Runtime runtime; |
| |
| final System system; |
| |
| final String builderTag; |
| |
| final List<String> vmOptions; |
| |
| final List<String> dart2jsOptions; |
| |
| int timeout; |
| |
| final bool enableAsserts; |
| |
| // TODO(rnystrom): Remove this when Dart 1.0 is no longer supported. |
| final bool isChecked; |
| |
| final bool isCsp; |
| |
| // TODO(rnystrom): Remove this when Dart 1.0 is no longer supported. |
| final bool isHostChecked; |
| |
| final bool isMinified; |
| |
| // TODO(rnystrom): Remove this when Dart 1.0 is no longer supported. |
| final bool previewDart2; |
| |
| // TODO(whesse): Remove these when only fasta front end is in analyzer. |
| final bool useAnalyzerCfe; |
| final bool useAnalyzerFastaParser; |
| |
| // TODO(rnystrom): What is this? |
| final bool useBlobs; |
| |
| final bool useHotReload; |
| final bool useHotReloadRollback; |
| |
| final bool useSdk; |
| |
| Configuration(this.name, this.architecture, this.compiler, this.mode, |
| this.runtime, this.system, |
| {String builderTag, |
| List<String> vmOptions, |
| List<String> dart2jsOptions, |
| int timeout, |
| bool enableAsserts, |
| bool isChecked, |
| bool isCsp, |
| bool isHostChecked, |
| bool isMinified, |
| bool previewDart2, |
| bool useAnalyzerCfe, |
| bool useAnalyzerFastaParser, |
| bool useBlobs, |
| bool useHotReload, |
| bool useHotReloadRollback, |
| bool useSdk}) |
| : builderTag = builderTag ?? "", |
| vmOptions = vmOptions ?? <String>[], |
| dart2jsOptions = dart2jsOptions ?? <String>[], |
| timeout = timeout, |
| enableAsserts = enableAsserts ?? false, |
| isChecked = isChecked ?? false, |
| isCsp = isCsp ?? false, |
| isHostChecked = isHostChecked ?? false, |
| isMinified = isMinified ?? false, |
| previewDart2 = previewDart2 ?? true, |
| useAnalyzerCfe = useAnalyzerCfe ?? false, |
| useAnalyzerFastaParser = useAnalyzerFastaParser ?? false, |
| useBlobs = useBlobs ?? false, |
| useHotReload = useHotReload ?? false, |
| useHotReloadRollback = useHotReloadRollback ?? false, |
| useSdk = useSdk ?? false; |
| |
| /// Returns `true` if this configuration's options all have the same values |
| /// as [other]. |
| bool optionsEqual(Configuration other) => |
| architecture == other.architecture && |
| compiler == other.compiler && |
| mode == other.mode && |
| runtime == other.runtime && |
| system == other.system && |
| builderTag == other.builderTag && |
| vmOptions.join(" & ") == other.vmOptions.join(" & ") && |
| dart2jsOptions.join(" & ") == other.dart2jsOptions.join(" & ") && |
| timeout == other.timeout && |
| enableAsserts == other.enableAsserts && |
| isChecked == other.isChecked && |
| isCsp == other.isCsp && |
| isHostChecked == other.isHostChecked && |
| isMinified == other.isMinified && |
| previewDart2 == other.previewDart2 && |
| useAnalyzerCfe == other.useAnalyzerCfe && |
| useAnalyzerFastaParser == other.useAnalyzerFastaParser && |
| useBlobs == other.useBlobs && |
| useHotReload == other.useHotReload && |
| useHotReloadRollback == other.useHotReloadRollback && |
| useSdk == other.useSdk; |
| |
| bool operator ==(Object other) => |
| other is Configuration && name == other.name && optionsEqual(other); |
| |
| int _toBinary(List<bool> bits) => |
| bits.fold(0, (sum, bit) => (sum << 1) ^ (bit ? 1 : 0)); |
| |
| int get hashCode => |
| name.hashCode ^ |
| architecture.hashCode ^ |
| compiler.hashCode ^ |
| mode.hashCode ^ |
| runtime.hashCode ^ |
| system.hashCode ^ |
| builderTag.hashCode ^ |
| vmOptions.join(" & ").hashCode ^ |
| dart2jsOptions.join(" & ").hashCode ^ |
| timeout.hashCode ^ |
| _toBinary([ |
| enableAsserts, |
| isChecked, |
| isCsp, |
| isHostChecked, |
| isMinified, |
| previewDart2, |
| useAnalyzerCfe, |
| useAnalyzerFastaParser, |
| useBlobs, |
| useHotReload, |
| useHotReloadRollback, |
| useSdk |
| ]); |
| |
| String toString() { |
| var buffer = new StringBuffer(); |
| buffer.write(name); |
| buffer.write("("); |
| |
| var fields = <String>[]; |
| fields.add("architecture: $architecture"); |
| fields.add("compiler: $compiler"); |
| fields.add("mode: $mode"); |
| fields.add("runtime: $runtime"); |
| fields.add("system: $system"); |
| |
| if (builderTag != "") fields.add("builder-tag: $builderTag"); |
| if (vmOptions != "") fields.add("vm-options: [${vmOptions.join(", ")}]"); |
| if (dart2jsOptions != "") |
| fields.add("dart2js-options: [${dart2jsOptions.join(", ")}]"); |
| if (timeout != 0) fields.add("timeout: $timeout"); |
| if (enableAsserts) fields.add("enable-asserts"); |
| if (isChecked) fields.add("checked"); |
| if (isCsp) fields.add("csp"); |
| if (isHostChecked) fields.add("host-checked"); |
| if (isMinified) fields.add("minified"); |
| if (previewDart2) fields.add("preview-dart-2"); |
| if (useAnalyzerCfe) fields.add("use-cfe"); |
| if (useAnalyzerFastaParser) fields.add("analyzer-use-fasta-parser"); |
| if (useBlobs) fields.add("use-blobs"); |
| if (useHotReload) fields.add("hot-reload"); |
| if (useHotReloadRollback) fields.add("hot-reload-rollback"); |
| if (useSdk) fields.add("use-sdk"); |
| |
| buffer.write(fields.join(", ")); |
| buffer.write(")"); |
| return buffer.toString(); |
| } |
| |
| String visualCompare(Configuration other) { |
| var buffer = new StringBuffer(); |
| buffer.writeln(name); |
| buffer.writeln(other.name); |
| |
| var fields = <String>[]; |
| fields.add("architecture: $architecture ${other.architecture}"); |
| fields.add("compiler: $compiler ${other.compiler}"); |
| fields.add("mode: $mode ${other.mode}"); |
| fields.add("runtime: $runtime ${other.runtime}"); |
| fields.add("system: $system ${other.system}"); |
| |
| if (builderTag != "" || other.builderTag != "") { |
| var tag = builderTag == "" ? "(none)" : builderTag; |
| var otherTag = other.builderTag == "" ? "(none)" : other.builderTag; |
| fields.add("builder-tag: $tag $otherTag"); |
| } |
| if (vmOptions != "" || other.vmOptions != "") { |
| var tag = "[${vmOptions.join(", ")}]"; |
| var otherTag = "[${other.vmOptions.join(", ")}]"; |
| fields.add("vm-options: $tag $otherTag"); |
| } |
| if (dart2jsOptions != "" || other.dart2jsOptions != "") { |
| var tag = "[${dart2jsOptions.join(", ")}]"; |
| var otherTag = "[${other.dart2jsOptions.join(", ")}]"; |
| fields.add("dart2js-options: $tag $otherTag"); |
| } |
| fields.add("timeout: $timeout ${other.timeout}"); |
| if (enableAsserts || other.enableAsserts) { |
| fields.add("enable-asserts $enableAsserts ${other.enableAsserts}"); |
| } |
| if (isChecked || other.isChecked) { |
| fields.add("checked $isChecked ${other.isChecked}"); |
| } |
| if (isCsp || other.isCsp) { |
| fields.add("csp $isCsp ${other.isCsp}"); |
| } |
| if (isHostChecked || other.isHostChecked) { |
| fields.add("isHostChecked $isHostChecked ${other.isHostChecked}"); |
| } |
| if (isMinified || other.isMinified) { |
| fields.add("isMinified $isMinified ${other.isMinified}"); |
| } |
| if (previewDart2 || other.previewDart2) { |
| fields.add("previewDart2 $previewDart2 ${other.previewDart2}"); |
| } |
| if (useAnalyzerCfe || other.useAnalyzerCfe) { |
| fields.add("useAnalyzerCfe $useAnalyzerCfe ${other.useAnalyzerCfe}"); |
| } |
| if (useAnalyzerFastaParser || other.useAnalyzerFastaParser) { |
| fields.add("useAnalyzerFastaParser " |
| "$useAnalyzerFastaParser ${other.useAnalyzerFastaParser}"); |
| } |
| if (useBlobs || other.useBlobs) { |
| fields.add("useBlobs $useBlobs ${other.useBlobs}"); |
| } |
| if (useHotReload || other.useHotReload) { |
| fields.add("useHotReload $useHotReload ${other.useHotReload}"); |
| } |
| if (isHostChecked) { |
| fields.add("host-checked $isHostChecked ${other.isHostChecked}"); |
| } |
| if (useHotReloadRollback || other.useHotReloadRollback) { |
| fields.add("useHotReloadRollback" |
| " $useHotReloadRollback ${other.useHotReloadRollback}"); |
| } |
| if (useSdk || other.useSdk) { |
| fields.add("useSdk $useSdk ${other.useSdk}"); |
| } |
| |
| buffer.write(fields.join("\n ")); |
| buffer.write("\n"); |
| return buffer.toString(); |
| } |
| } |
| |
| class Architecture extends NamedEnum { |
| static const ia32 = const Architecture._('ia32'); |
| static const x64 = const Architecture._('x64'); |
| static const arm = const Architecture._('arm'); |
| static const armv6 = const Architecture._('armv6'); |
| static const armv5te = const Architecture._('armv5te'); |
| static const arm64 = const Architecture._('arm64'); |
| static const simarm = const Architecture._('simarm'); |
| static const simarmv6 = const Architecture._('simarmv6'); |
| static const simarmv5te = const Architecture._('simarmv5te'); |
| static const simarm64 = const Architecture._('simarm64'); |
| static const simdbc = const Architecture._('simdbc'); |
| static const simdbc64 = const Architecture._('simdbc64'); |
| |
| static final List<String> names = _all.keys.toList(); |
| |
| static final _all = new Map<String, Architecture>.fromIterable([ |
| ia32, |
| x64, |
| arm, |
| armv6, |
| armv5te, |
| arm64, |
| simarm, |
| simarmv6, |
| simarmv5te, |
| simarm64, |
| simdbc, |
| simdbc64 |
| ], key: (architecture) => (architecture as Architecture).name); |
| |
| static Architecture find(String name) { |
| var architecture = _all[name]; |
| if (architecture != null) return architecture; |
| |
| throw new ArgumentError('Unknown architecture "$name".'); |
| } |
| |
| const Architecture._(String name) : super(name); |
| } |
| |
| class Compiler extends NamedEnum { |
| static const none = const Compiler._('none'); |
| static const precompiler = const Compiler._('precompiler'); |
| static const dart2js = const Compiler._('dart2js'); |
| static const dart2analyzer = const Compiler._('dart2analyzer'); |
| static const compareAnalyzerCfe = const Compiler._('compare_analyzer_cfe'); |
| static const dartdevc = const Compiler._('dartdevc'); |
| static const dartdevk = const Compiler._('dartdevk'); |
| static const appJit = const Compiler._('app_jit'); |
| static const appJitk = const Compiler._('app_jitk'); |
| static const dartk = const Compiler._('dartk'); |
| static const dartkp = const Compiler._('dartkp'); |
| static const dartkb = const Compiler._('dartkb'); |
| static const specParser = const Compiler._('spec_parser'); |
| static const fasta = const Compiler._('fasta'); |
| |
| static final List<String> names = _all.keys.toList(); |
| |
| static final _all = new Map<String, Compiler>.fromIterable([ |
| none, |
| precompiler, |
| dart2js, |
| dart2analyzer, |
| compareAnalyzerCfe, |
| dartdevc, |
| dartdevk, |
| appJit, |
| appJitk, |
| dartk, |
| dartkp, |
| dartkb, |
| specParser, |
| fasta, |
| ], key: (compiler) => (compiler as Compiler).name); |
| |
| static Compiler find(String name) { |
| var compiler = _all[name]; |
| if (compiler != null) return compiler; |
| |
| throw new ArgumentError('Unknown compiler "$name".'); |
| } |
| |
| const Compiler._(String name) : super(name); |
| |
| /// Gets the runtimes this compiler can target. |
| List<Runtime> get supportedRuntimes { |
| switch (this) { |
| case Compiler.dart2js: |
| // Note: by adding 'none' as a configuration, if the user |
| // runs test.py -c dart2js -r drt,none the dart2js_none and |
| // dart2js_drt will be duplicating work. If later we don't need 'none' |
| // with dart2js, we should remove it from here. |
| return const [ |
| Runtime.d8, |
| Runtime.jsshell, |
| Runtime.none, |
| Runtime.firefox, |
| Runtime.chrome, |
| Runtime.safari, |
| Runtime.ie9, |
| Runtime.ie10, |
| Runtime.ie11, |
| Runtime.edge, |
| Runtime.chromeOnAndroid, |
| ]; |
| |
| case Compiler.dartdevc: |
| case Compiler.dartdevk: |
| // TODO(rnystrom): Expand to support other JS execution environments |
| // (other browsers, d8) when tested and working. |
| return const [ |
| Runtime.none, |
| Runtime.chrome, |
| ]; |
| |
| case Compiler.dart2analyzer: |
| case Compiler.compareAnalyzerCfe: |
| return const [Runtime.none]; |
| case Compiler.appJit: |
| case Compiler.appJitk: |
| case Compiler.dartk: |
| case Compiler.dartkb: |
| return const [Runtime.vm, Runtime.selfCheck]; |
| case Compiler.precompiler: |
| case Compiler.dartkp: |
| return const [Runtime.dartPrecompiled]; |
| case Compiler.specParser: |
| return const [Runtime.none]; |
| case Compiler.fasta: |
| return const [Runtime.none]; |
| case Compiler.none: |
| return const [Runtime.vm, Runtime.flutter]; |
| } |
| |
| throw "unreachable"; |
| } |
| |
| /// The preferred runtime to use with this compiler if no other runtime is |
| /// specified. |
| Runtime get defaultRuntime { |
| switch (this) { |
| case Compiler.dart2js: |
| return Runtime.d8; |
| case Compiler.dartdevc: |
| case Compiler.dartdevk: |
| return Runtime.chrome; |
| case Compiler.dart2analyzer: |
| case Compiler.compareAnalyzerCfe: |
| return Runtime.none; |
| case Compiler.appJit: |
| case Compiler.appJitk: |
| case Compiler.dartk: |
| case Compiler.dartkb: |
| return Runtime.vm; |
| case Compiler.precompiler: |
| case Compiler.dartkp: |
| return Runtime.dartPrecompiled; |
| case Compiler.specParser: |
| case Compiler.fasta: |
| return Runtime.none; |
| case Compiler.none: |
| return Runtime.vm; |
| } |
| |
| throw "unreachable"; |
| } |
| |
| Mode get defaultMode { |
| switch (this) { |
| case Compiler.dart2analyzer: |
| case Compiler.compareAnalyzerCfe: |
| case Compiler.dart2js: |
| case Compiler.dartdevc: |
| case Compiler.dartdevk: |
| case Compiler.fasta: |
| return Mode.release; |
| |
| default: |
| return Mode.debug; |
| } |
| } |
| } |
| |
| class Mode extends NamedEnum { |
| static const debug = const Mode._('debug'); |
| static const product = const Mode._('product'); |
| static const release = const Mode._('release'); |
| |
| static final List<String> names = _all.keys.toList(); |
| |
| static final _all = new Map<String, Mode>.fromIterable( |
| [debug, product, release], |
| key: (mode) => (mode as Mode).name); |
| |
| static Mode find(String name) { |
| var mode = _all[name]; |
| if (mode != null) return mode; |
| |
| throw new ArgumentError('Unknown mode "$name".'); |
| } |
| |
| const Mode._(String name) : super(name); |
| |
| bool get isDebug => this == debug; |
| } |
| |
| class Runtime extends NamedEnum { |
| static const vm = const Runtime._('vm'); |
| static const flutter = const Runtime._('flutter'); |
| static const dartPrecompiled = const Runtime._('dart_precompiled'); |
| static const d8 = const Runtime._('d8'); |
| static const jsshell = const Runtime._('jsshell'); |
| static const firefox = const Runtime._('firefox'); |
| static const chrome = const Runtime._('chrome'); |
| static const safari = const Runtime._('safari'); |
| static const ie9 = const Runtime._('ie9'); |
| static const ie10 = const Runtime._('ie10'); |
| static const ie11 = const Runtime._('ie11'); |
| static const edge = const Runtime._('edge'); |
| static const chromeOnAndroid = const Runtime._('chromeOnAndroid'); |
| static const selfCheck = const Runtime._('self_check'); |
| static const none = const Runtime._('none'); |
| |
| static final List<String> names = _all.keys.toList(); |
| |
| static final _all = new Map<String, Runtime>.fromIterable([ |
| vm, |
| flutter, |
| dartPrecompiled, |
| d8, |
| jsshell, |
| firefox, |
| chrome, |
| safari, |
| ie9, |
| ie10, |
| ie11, |
| edge, |
| chromeOnAndroid, |
| selfCheck, |
| none |
| ], key: (runtime) => (runtime as Runtime).name); |
| |
| static Runtime find(String name) { |
| var runtime = _all[name]; |
| if (runtime != null) return runtime; |
| |
| throw new ArgumentError('Unknown runtime "$name".'); |
| } |
| |
| const Runtime._(String name) : super(name); |
| |
| bool get isBrowser => const [ |
| ie9, |
| ie10, |
| ie11, |
| edge, |
| safari, |
| chrome, |
| firefox, |
| chromeOnAndroid |
| ].contains(this); |
| |
| bool get isIE => name.startsWith("ie"); |
| |
| bool get isSafari => name.startsWith("safari"); |
| |
| /// Whether this runtime is a command-line JavaScript environment. |
| bool get isJSCommandLine => const [d8, jsshell].contains(this); |
| |
| /// If the runtime doesn't support `Window.open`, we use iframes instead. |
| bool get requiresIFrame => !const [ie11, ie10].contains(this); |
| |
| /// The preferred compiler to use with this runtime if no other compiler is |
| /// specified. |
| Compiler get defaultCompiler { |
| switch (this) { |
| case vm: |
| case flutter: |
| return Compiler.none; |
| |
| case dartPrecompiled: |
| return Compiler.precompiler; |
| |
| case d8: |
| case jsshell: |
| case firefox: |
| case chrome: |
| case safari: |
| case ie9: |
| case ie10: |
| case ie11: |
| case edge: |
| case chromeOnAndroid: |
| return Compiler.dart2js; |
| |
| case selfCheck: |
| return Compiler.dartk; |
| |
| case none: |
| // If we aren't running it, we probably just want to analyze it. |
| return Compiler.dart2analyzer; |
| } |
| |
| throw "unreachable"; |
| } |
| } |
| |
| class System extends NamedEnum { |
| static const android = const System._('android'); |
| static const fuchsia = const System._('fuchsia'); |
| static const linux = const System._('linux'); |
| static const mac = const System._('mac'); |
| static const win = const System._('win'); |
| |
| static final List<String> names = _all.keys.toList(); |
| |
| static final _all = new Map<String, System>.fromIterable( |
| [android, fuchsia, linux, mac, win], |
| key: (system) => (system as System).name); |
| |
| /// Gets the system of the current machine. |
| static System get host => find(Platform.operatingSystem); |
| |
| static System find(String name) { |
| var system = _all[name]; |
| if (system != null) return system; |
| |
| // Also allow dart:io's names for the operating systems. |
| switch (Platform.operatingSystem) { |
| case "macos": |
| return mac; |
| case "windows": |
| return win; |
| } |
| // TODO(rnystrom): What about ios? |
| |
| throw new ArgumentError('Unknown operating system "$name".'); |
| } |
| |
| const System._(String name) : super(name); |
| |
| /// The root directory name for build outputs on this system. |
| String get outputDirectory { |
| switch (this) { |
| case android: |
| case fuchsia: |
| case linux: |
| case win: |
| return 'out/'; |
| |
| case mac: |
| return 'xcodebuild/'; |
| } |
| |
| throw "unreachable"; |
| } |
| } |
| |
| /// Base class for an enum-like class whose values are identified by name. |
| abstract class NamedEnum { |
| final String name; |
| |
| const NamedEnum(this.name); |
| |
| String toString() => name; |
| } |