forked from firka/flutter
Move android_sdk_downloader so I can more easily deprecate it (flutter/engine#8084)
This commit is contained in:
4
DEPS
4
DEPS
@@ -418,7 +418,7 @@ hooks = [
|
||||
'name': 'prepare_android_downloader',
|
||||
'pattern': '.',
|
||||
'condition': 'download_android_deps',
|
||||
'cwd': 'src/tools/android/android_sdk_downloader',
|
||||
'cwd': 'src/flutter/tools/android_sdk_downloader',
|
||||
'action': [
|
||||
'../../../third_party/dart/tools/sdks/dart-sdk/bin/pub', # this hook _must_ be run _after_ the dart hook.
|
||||
'get'
|
||||
@@ -431,7 +431,7 @@ hooks = [
|
||||
'action': [
|
||||
'src/third_party/dart/tools/sdks/dart-sdk/bin/dart', # this hook _must_ be run _after_ the dart hook.
|
||||
'--enable-asserts',
|
||||
'src/tools/android/android_sdk_downloader/lib/main.dart',
|
||||
'src/flutter/tools/android_sdk_downloader/lib/main.dart',
|
||||
'-y', # Accept licenses
|
||||
'--out=src/third_party/android_tools',
|
||||
'--platform=28',
|
||||
|
||||
7
engine/src/flutter/tools/android_sdk_downloader/.gitignore
vendored
Normal file
7
engine/src/flutter/tools/android_sdk_downloader/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
.DS_Store
|
||||
.atom/
|
||||
.idea
|
||||
.packages
|
||||
.pub/
|
||||
.dart_tool/
|
||||
pubspec.lock
|
||||
27
engine/src/flutter/tools/android_sdk_downloader/LICENSE
Normal file
27
engine/src/flutter/tools/android_sdk_downloader/LICENSE
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
31
engine/src/flutter/tools/android_sdk_downloader/README.md
Normal file
31
engine/src/flutter/tools/android_sdk_downloader/README.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Android SDK Downloader
|
||||
|
||||
This program assists with downloading the Android SDK and NDK artifacts for
|
||||
Flutter engine development.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
-r, --repository-xml Specifies the location of the Android Repository XML file.
|
||||
(defaults to "https://dl.google.com/android/repository/repository2-1.xml")
|
||||
|
||||
-p, --platform Specifies the Android platform version, e.g. 28
|
||||
|
||||
--platform-revision Specifies the Android platform revision, e.g. 6 for 28_r06
|
||||
|
||||
-o, --out The directory to write downloaded files to.
|
||||
|
||||
--os The OS type to download for. Defaults to current platform.
|
||||
(defaults to current platform), accepts: [windows, macos, linux]
|
||||
|
||||
--build-tools-version The build-tools version to download. Must be in format of <major>.<minor>.<micro>, e.g. 28.0.3; or <major>.<minor>.<micro>.<rc/preview>, e.g. 28.0.0.2
|
||||
|
||||
--platform-tools-version The platform-tools version to download. Must be in format of <major>.<minor>.<micro>, e.g. 28.0.1; or <major>.<minor>.<micro>.<rc/preview>, e.g. 28.0.0.2
|
||||
|
||||
--tools-version The tools version to download. Must be in format of <major>.<minor>.<micro>, e.g. 26.1.1; or <major>.<minor>.<micro>.<rc/preview>, e.g. 28.1.1.2
|
||||
|
||||
--ndk-version The ndk version to download. Must be in format of <major>.<minor>.<micro>, e.g. 28.0.3; or <major>.<minor>.<micro>.<rc/preview>, e.g. 28.0.0.2
|
||||
|
||||
-y, --[no-]accept-licenses Automatically accept Android SDK licenses.
|
||||
--[no-]overwrite Skip download if the target directory exists.
|
||||
```
|
||||
@@ -0,0 +1,155 @@
|
||||
# Specify analysis options.
|
||||
#
|
||||
# Copied from https://github.com/flutter/flutter/blob/master/analysis_options.yaml
|
||||
|
||||
analyzer:
|
||||
strong-mode:
|
||||
implicit-dynamic: false
|
||||
errors:
|
||||
# treat missing required parameters as a warning (not a hint)
|
||||
missing_required_param: warning
|
||||
# treat missing returns as a warning (not a hint)
|
||||
missing_return: warning
|
||||
# allow having TODOs in the code
|
||||
todo: ignore
|
||||
exclude:
|
||||
- 'bin/cache/**'
|
||||
# the following two are relative to the stocks example and the flutter package respectively
|
||||
# see https://github.com/dart-lang/sdk/issues/28463
|
||||
- 'lib/i18n/stock_messages_*.dart'
|
||||
- 'lib/src/http/**'
|
||||
|
||||
linter:
|
||||
rules:
|
||||
# these rules are documented on and in the same order as
|
||||
# the Dart Lint rules page to make maintenance easier
|
||||
# https://github.com/dart-lang/linter/blob/master/example/all.yaml
|
||||
- always_declare_return_types
|
||||
- always_put_control_body_on_new_line
|
||||
# - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219
|
||||
- always_require_non_null_named_parameters
|
||||
- always_specify_types
|
||||
- annotate_overrides
|
||||
# - avoid_annotating_with_dynamic # conflicts with always_specify_types
|
||||
- avoid_as
|
||||
# - avoid_bool_literals_in_conditional_expressions # not yet tested
|
||||
# - avoid_catches_without_on_clauses # we do this commonly
|
||||
# - avoid_catching_errors # we do this commonly
|
||||
- avoid_classes_with_only_static_members
|
||||
# - avoid_double_and_int_checks # only useful when targeting JS runtime
|
||||
- avoid_empty_else
|
||||
- avoid_field_initializers_in_const_classes
|
||||
- avoid_function_literals_in_foreach_calls
|
||||
# - avoid_implementing_value_types # not yet tested
|
||||
- avoid_init_to_null
|
||||
# - avoid_js_rounded_ints # only useful when targeting JS runtime
|
||||
- avoid_null_checks_in_equality_operators
|
||||
# - avoid_positional_boolean_parameters # not yet tested
|
||||
# - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356)
|
||||
- avoid_relative_lib_imports
|
||||
- avoid_renaming_method_parameters
|
||||
- avoid_return_types_on_setters
|
||||
# - avoid_returning_null # there are plenty of valid reasons to return null
|
||||
- avoid_returning_null_for_void
|
||||
# - avoid_returning_this # there are plenty of valid reasons to return this
|
||||
# - avoid_setters_without_getters # not yet tested
|
||||
# - avoid_single_cascade_in_expression_statements # not yet tested
|
||||
- avoid_slow_async_io
|
||||
- avoid_types_as_parameter_names
|
||||
# - avoid_types_on_closure_parameters # conflicts with always_specify_types
|
||||
- avoid_unused_constructor_parameters
|
||||
- avoid_void_async
|
||||
- await_only_futures
|
||||
- camel_case_types
|
||||
- cancel_subscriptions
|
||||
# - cascade_invocations # not yet tested
|
||||
# - close_sinks # not reliable enough
|
||||
# - comment_references # blocked on https://github.com/flutter/flutter/issues/20765
|
||||
# - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204
|
||||
- control_flow_in_finally
|
||||
# - curly_braces_in_flow_control_structures # not yet tested
|
||||
- directives_ordering
|
||||
- empty_catches
|
||||
- empty_constructor_bodies
|
||||
- empty_statements
|
||||
# - file_names # not yet tested
|
||||
- flutter_style_todos
|
||||
- hash_and_equals
|
||||
- implementation_imports
|
||||
# - invariant_booleans # too many false positives: https://github.com/dart-lang/linter/issues/811
|
||||
- iterable_contains_unrelated_type
|
||||
# - join_return_with_assignment # not yet tested
|
||||
- library_names
|
||||
- library_prefixes
|
||||
# - lines_longer_than_80_chars # not yet tested
|
||||
- list_remove_unrelated_type
|
||||
# - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/sdk/issues/34181
|
||||
- no_adjacent_strings_in_list
|
||||
- no_duplicate_case_values
|
||||
- non_constant_identifier_names
|
||||
# - null_closures # not yet tested
|
||||
# - omit_local_variable_types # opposite of always_specify_types
|
||||
# - one_member_abstracts # too many false positives
|
||||
# - only_throw_errors # https://github.com/flutter/flutter/issues/5792
|
||||
- overridden_fields
|
||||
- package_api_docs
|
||||
- package_names
|
||||
- package_prefixed_library_names
|
||||
# - parameter_assignments # we do this commonly
|
||||
- prefer_adjacent_string_concatenation
|
||||
- prefer_asserts_in_initializer_lists
|
||||
- prefer_collection_literals
|
||||
- prefer_conditional_assignment
|
||||
- prefer_const_constructors
|
||||
- prefer_const_constructors_in_immutables
|
||||
- prefer_const_declarations
|
||||
- prefer_const_literals_to_create_immutables
|
||||
# - prefer_constructors_over_static_methods # not yet tested
|
||||
- prefer_contains
|
||||
- prefer_equal_for_default_values
|
||||
# - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods
|
||||
- prefer_final_fields
|
||||
- prefer_final_locals
|
||||
- prefer_foreach
|
||||
# - prefer_function_declarations_over_variables # not yet tested
|
||||
- prefer_generic_function_type_aliases
|
||||
- prefer_initializing_formals
|
||||
# - prefer_int_literals # not yet tested
|
||||
# - prefer_interpolation_to_compose_strings # not yet tested
|
||||
- prefer_is_empty
|
||||
- prefer_is_not_empty
|
||||
- prefer_iterable_whereType
|
||||
# - prefer_mixin # https://github.com/dart-lang/language/issues/32
|
||||
- prefer_single_quotes
|
||||
- prefer_typing_uninitialized_variables
|
||||
- prefer_void_to_null
|
||||
# - public_member_api_docs # enabled on a case-by-case basis; see e.g. packages/analysis_options.yaml
|
||||
- recursive_getters
|
||||
- slash_for_doc_comments
|
||||
- sort_constructors_first
|
||||
- sort_pub_dependencies
|
||||
- sort_unnamed_constructors_first
|
||||
- super_goes_last
|
||||
- test_types_in_equals
|
||||
- throw_in_finally
|
||||
# - type_annotate_public_apis # subset of always_specify_types
|
||||
- type_init_formals
|
||||
# - unawaited_futures # too many false positives
|
||||
- unnecessary_brace_in_string_interps
|
||||
- unnecessary_const
|
||||
- unnecessary_getters_setters
|
||||
# - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498
|
||||
- unnecessary_new
|
||||
- unnecessary_null_aware_assignments
|
||||
- unnecessary_null_in_if_null_operators
|
||||
- unnecessary_overrides
|
||||
- unnecessary_parenthesis
|
||||
- unnecessary_statements
|
||||
- unnecessary_this
|
||||
- unrelated_type_equality_checks
|
||||
- use_rethrow_when_possible
|
||||
# - use_setters_to_change_properties # not yet tested
|
||||
# - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182
|
||||
# - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review
|
||||
- valid_regexps
|
||||
# - void_checks # not yet tested
|
||||
220
engine/src/flutter/tools/android_sdk_downloader/lib/main.dart
Normal file
220
engine/src/flutter/tools/android_sdk_downloader/lib/main.dart
Normal file
@@ -0,0 +1,220 @@
|
||||
// Copyright 2013 The Flutter 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:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:args/args.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'src/android_repository.dart';
|
||||
import 'src/checksums.dart';
|
||||
import 'src/http.dart';
|
||||
import 'src/options.dart';
|
||||
import 'src/zip.dart';
|
||||
|
||||
const String _kAndroidRepositoryXml = 'https://dl.google.com/android/repository/repository2-1.xml';
|
||||
|
||||
|
||||
Future<void> main(List<String> args) async {
|
||||
final ArgParser argParser = ArgParser()
|
||||
..addOption(
|
||||
'repository-xml',
|
||||
abbr: 'r',
|
||||
help: 'Specifies the location of the Android Repository XML file.',
|
||||
defaultsTo: _kAndroidRepositoryXml,
|
||||
)
|
||||
..addOption(
|
||||
'platform',
|
||||
abbr: 'p',
|
||||
help: 'Specifies the Android platform version, e.g. 28',
|
||||
)
|
||||
..addOption(
|
||||
'platform-revision',
|
||||
help: 'Specifies the Android platform revision, e.g. 6 for 28_r06',
|
||||
)
|
||||
..addOption(
|
||||
'out',
|
||||
abbr: 'o',
|
||||
help: 'The directory to write downloaded files to.',
|
||||
defaultsTo: '.',
|
||||
)
|
||||
..addOption(
|
||||
'os',
|
||||
help: 'The OS type to download for. Defaults to current platform.',
|
||||
defaultsTo: Platform.operatingSystem,
|
||||
allowed: osTypeMap.keys,
|
||||
)
|
||||
..addOption(
|
||||
'build-tools-version',
|
||||
help: 'The build-tools version to download. Must be in format of '
|
||||
'<major>.<minor>.<micro>, e.g. 28.0.3; '
|
||||
'or <major>.<minor>.<micro>.<rc/preview>, e.g. 28.0.0.2',
|
||||
)
|
||||
..addOption(
|
||||
'platform-tools-version',
|
||||
help: 'The platform-tools version to download. Must be in format of '
|
||||
'<major>.<minor>.<micro>, e.g. 28.0.1; '
|
||||
'or <major>.<minor>.<micro>.<rc/preview>, e.g. 28.0.0.2',
|
||||
)
|
||||
..addOption(
|
||||
'tools-version',
|
||||
help: 'The tools version to download. Must be in format of '
|
||||
'<major>.<minor>.<micro>, e.g. 26.1.1; '
|
||||
'or <major>.<minor>.<micro>.<rc/preview>, e.g. 28.1.1.2',
|
||||
)
|
||||
..addOption(
|
||||
'ndk-version',
|
||||
help: 'The ndk version to download. Must be in format of '
|
||||
'<major>.<minor>.<micro>, e.g. 28.0.3; '
|
||||
'or <major>.<minor>.<micro>.<rc/preview>, e.g. 28.0.0.2',
|
||||
)
|
||||
..addFlag('accept-licenses',
|
||||
abbr: 'y',
|
||||
defaultsTo: false,
|
||||
help: 'Automatically accept Android SDK licenses.')
|
||||
..addFlag(
|
||||
'overwrite',
|
||||
defaultsTo: false,
|
||||
help: 'Skip download if the target directory exists.',
|
||||
);
|
||||
|
||||
final bool help = args.contains('-h')
|
||||
|| args.contains('--help')
|
||||
|| (args.isNotEmpty && args.first == 'help');
|
||||
if (help) {
|
||||
print(argParser.usage);
|
||||
return;
|
||||
}
|
||||
|
||||
final Options options = Options.parseAndValidate(args, argParser);
|
||||
|
||||
final AndroidRepository androidRepository = await _getAndroidRepository(options.repositoryXmlUri);
|
||||
assert(androidRepository.platforms.isNotEmpty);
|
||||
assert(androidRepository.buildTools.isNotEmpty);
|
||||
|
||||
if (!options.acceptLicenses) {
|
||||
for (final AndroidRepositoryLicense license in androidRepository.licenses) {
|
||||
print('================================================================================\n\n');
|
||||
print(license.text);
|
||||
stdout.write('Do you accept? (Y/n): ');
|
||||
final String result = stdin.readLineSync().trim().toLowerCase();
|
||||
if (result != '' && result.startsWith('y') == false) {
|
||||
print('Ending.');
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await options.outDirectory.create(recursive: true);
|
||||
|
||||
final Directory tempDir = await Directory(options.outDirectory.path).createTemp();
|
||||
await tempDir.create(recursive: true);
|
||||
|
||||
final Directory ndkDir = Directory(path.join(options.outDirectory.path, 'ndk'));
|
||||
final Directory sdkDir = Directory(path.join(options.outDirectory.path, 'sdk'));
|
||||
final Directory platformDir = Directory(path.join(sdkDir.path, 'platforms', 'android-${options.platformApiLevel}'));
|
||||
final Directory buildToolsDir = Directory(path.join(sdkDir.path, 'build-tools', options.buildToolsRevision.raw));
|
||||
final Directory platformToolsDir = Directory(path.join(sdkDir.path, 'platform-tools'));
|
||||
final Directory toolsDir = Directory(path.join(sdkDir.path, 'tools'));
|
||||
|
||||
final Map<String, String> checksums =
|
||||
await loadChecksums(options.outDirectory);
|
||||
|
||||
print('Downloading Android SDK and NDK artifacts...');
|
||||
final List<Future<void>> futures = <Future<void>>[];
|
||||
|
||||
futures.add(downloadArchive(
|
||||
androidRepository.platforms,
|
||||
OptionsRevision(null, options.platformRevision),
|
||||
options.repositoryBase,
|
||||
tempDir,
|
||||
checksumToSkip: options.overwrite ? null : checksums[platformDir.path],
|
||||
).then((ArchiveDownloadResult result) {
|
||||
if (result != ArchiveDownloadResult.empty) {
|
||||
return unzipFile(result.zipFileName, platformDir).then((_) {
|
||||
checksums[platformDir.path] = result.checksum;
|
||||
return writeChecksums(checksums, options.outDirectory);
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
futures.add(downloadArchive(
|
||||
androidRepository.buildTools,
|
||||
options.buildToolsRevision,
|
||||
options.repositoryBase,
|
||||
tempDir,
|
||||
osType: options.osType,
|
||||
checksumToSkip: options.overwrite ? null : checksums[buildToolsDir.path],
|
||||
).then((ArchiveDownloadResult result) {
|
||||
if (result != ArchiveDownloadResult.empty) {
|
||||
return unzipFile(result.zipFileName, buildToolsDir).then((_) {
|
||||
checksums[buildToolsDir.path] = result.checksum;
|
||||
return writeChecksums(checksums, options.outDirectory);
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
futures.add(downloadArchive(
|
||||
androidRepository.platformTools,
|
||||
options.platformToolsRevision,
|
||||
options.repositoryBase,
|
||||
tempDir,
|
||||
osType: options.osType,
|
||||
checksumToSkip: options.overwrite ? null : checksums[platformToolsDir.path],
|
||||
).then((ArchiveDownloadResult result) {
|
||||
if (result != ArchiveDownloadResult.empty) {
|
||||
return unzipFile(result.zipFileName, platformToolsDir).then((_) {
|
||||
checksums[platformToolsDir.path] = result.checksum;
|
||||
return writeChecksums(checksums, options.outDirectory);
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
futures.add(downloadArchive(
|
||||
androidRepository.tools,
|
||||
options.toolsRevision,
|
||||
options.repositoryBase,
|
||||
tempDir,
|
||||
osType: options.osType,
|
||||
checksumToSkip: options.overwrite ? null : checksums[toolsDir.path],
|
||||
).then((ArchiveDownloadResult result) {
|
||||
if (result != ArchiveDownloadResult.empty) {
|
||||
return unzipFile(result.zipFileName, toolsDir).then((_) {
|
||||
checksums[toolsDir.path] = result.checksum;
|
||||
return writeChecksums(checksums, options.outDirectory);
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
futures.add(downloadArchive(
|
||||
androidRepository.ndkBundles,
|
||||
options.ndkRevision,
|
||||
options.repositoryBase,
|
||||
tempDir,
|
||||
osType: options.osType,
|
||||
checksumToSkip: options.overwrite ? null : checksums[ndkDir.path],
|
||||
).then((ArchiveDownloadResult result) {
|
||||
if (result != ArchiveDownloadResult.empty) {
|
||||
return unzipFile(result.zipFileName, ndkDir).then((_) {
|
||||
checksums[ndkDir.path] = result.checksum;
|
||||
return writeChecksums(checksums, options.outDirectory);
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
await Future.wait<void>(futures);
|
||||
await tempDir.delete(recursive: true);
|
||||
}
|
||||
|
||||
Future<AndroidRepository> _getAndroidRepository(Uri repositoryXmlUri) async {
|
||||
final StringBuffer repoXmlBuffer = StringBuffer();
|
||||
Future<void> _repositoryXmlHandler(HttpClientResponse response) async {
|
||||
await response.transform(utf8.decoder).forEach(repoXmlBuffer.write);
|
||||
}
|
||||
|
||||
await httpGet(repositoryXmlUri, _repositoryXmlHandler);
|
||||
|
||||
return parseAndroidRepositoryXml(repoXmlBuffer.toString());
|
||||
}
|
||||
@@ -0,0 +1,416 @@
|
||||
// Copyright 2013 The Flutter 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 'package:xml/xml.dart' as xml show parse;
|
||||
import 'package:xml/xml.dart';
|
||||
|
||||
// see https://android.googlesource.com/platform/tools/base/+/master/sdklib/src/main/java/com/android/sdklib/repository/sdk-repository-10.xsd
|
||||
|
||||
const String _kXsi = 'http://www.w3.org/2001/XMLSchema-instance';
|
||||
const String _kSdk = 'http://schemas.android.com/sdk/android/repo/repository2/01';
|
||||
|
||||
void _debugCheckElement(
|
||||
XmlElement element,
|
||||
String name, {
|
||||
String namespace,
|
||||
}) {
|
||||
assert(element != null);
|
||||
assert(element.name.local == name, '${element.name.local} != $name');
|
||||
assert(element.name.namespaceUri == namespace,
|
||||
'${element.name.namespaceUri} != $namespace');
|
||||
}
|
||||
|
||||
XmlElement _firstOrDefault(Iterable<XmlElement> list) {
|
||||
if (list?.isEmpty == true) {
|
||||
return null;
|
||||
}
|
||||
return list.first;
|
||||
}
|
||||
|
||||
String _getChildText(
|
||||
XmlElement parent,
|
||||
String childName, {
|
||||
String def = '',
|
||||
String namespace,
|
||||
}) {
|
||||
final String value = _firstOrDefault(
|
||||
parent.findElements(
|
||||
childName,
|
||||
namespace: namespace,
|
||||
),
|
||||
)?.text;
|
||||
return value ?? def;
|
||||
}
|
||||
|
||||
OSType _parseHostType(String value) {
|
||||
switch (value) {
|
||||
case 'linux':
|
||||
return OSType.linux;
|
||||
case 'windows':
|
||||
return OSType.windows;
|
||||
case 'macosx':
|
||||
return OSType.mac;
|
||||
default:
|
||||
return OSType.any;
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses a the Android SDK's https://dl.google.com/android/repository/repository2-1.xml
|
||||
/// into an [AndroidRepository] object.
|
||||
AndroidRepository parseAndroidRepositoryXml(String rawXml) {
|
||||
final XmlDocument doc = xml.parse(rawXml);
|
||||
return AndroidRepository.fromXml(doc.rootElement);
|
||||
}
|
||||
|
||||
XmlElement _getTypeDetails(XmlElement parent) {
|
||||
final XmlElement typeDetails =
|
||||
_firstOrDefault(parent.findAllElements('type-details'));
|
||||
if (typeDetails == null) {
|
||||
throw StateError('Missing <type-details>.');
|
||||
}
|
||||
return typeDetails;
|
||||
}
|
||||
|
||||
String _getTypeDetailsType(XmlElement typeDetails) {
|
||||
return typeDetails.getAttribute('type', namespace: _kXsi);
|
||||
}
|
||||
|
||||
Iterable<XmlElement> _getArchives(XmlElement parent) {
|
||||
assert(parent != null);
|
||||
final XmlElement archives =
|
||||
_firstOrDefault(parent.findAllElements('archives'));
|
||||
if (archives == null) {
|
||||
return null;
|
||||
}
|
||||
return archives.findElements('archive');
|
||||
}
|
||||
|
||||
/// Object class for https://dl.google.com/android/repository/repository2-1.xml.
|
||||
class AndroidRepository {
|
||||
const AndroidRepository(
|
||||
this.licenses,
|
||||
this.platforms,
|
||||
this.buildTools,
|
||||
this.platformTools,
|
||||
this.tools,
|
||||
this.ndkBundles,
|
||||
) : assert(licenses != null),
|
||||
assert(platforms != null),
|
||||
assert(buildTools != null),
|
||||
assert(platformTools != null),
|
||||
assert(tools != null),
|
||||
assert(ndkBundles != null);
|
||||
|
||||
/// Parses the `<sdk-repository>` element.
|
||||
factory AndroidRepository.fromXml(XmlElement element) {
|
||||
_debugCheckElement(element, 'sdk-repository', namespace: _kSdk);
|
||||
final List<AndroidRepositoryLicense> licenses =
|
||||
<AndroidRepositoryLicense>[];
|
||||
final List<AndroidRepositoryPlatform> platforms =
|
||||
<AndroidRepositoryPlatform>[];
|
||||
final List<AndroidRepositoryRemotePackage> buildTools =
|
||||
<AndroidRepositoryRemotePackage>[];
|
||||
final List<AndroidRepositoryRemotePackage> platformTools =
|
||||
<AndroidRepositoryRemotePackage>[];
|
||||
final List<AndroidRepositoryRemotePackage> tools =
|
||||
<AndroidRepositoryRemotePackage>[];
|
||||
|
||||
final List<AndroidRepositoryRemotePackage> ndkBundles =
|
||||
<AndroidRepositoryRemotePackage>[];
|
||||
for (final XmlElement child in element.children.whereType<XmlElement>()) {
|
||||
switch (child.name.local) {
|
||||
case 'license':
|
||||
licenses.add(AndroidRepositoryLicense.fromXml(child));
|
||||
break;
|
||||
case 'remotePackage':
|
||||
final XmlElement typeDetails = _getTypeDetails(child);
|
||||
switch (_getTypeDetailsType(typeDetails)) {
|
||||
case 'sdk:platformDetailsType':
|
||||
platforms.add(
|
||||
AndroidRepositoryPlatform.fromXml(child, typeDetails),
|
||||
);
|
||||
break;
|
||||
case 'generic:genericDetailsType':
|
||||
final String path = child.getAttribute('path');
|
||||
if (path.startsWith('build-tools;')) {
|
||||
buildTools.add(AndroidRepositoryRemotePackage.fromXml(child));
|
||||
} else if (path.startsWith('platform-tools')) {
|
||||
platformTools
|
||||
.add(AndroidRepositoryRemotePackage.fromXml(child));
|
||||
} else if (path.startsWith('tools')) {
|
||||
tools.add(AndroidRepositoryRemotePackage.fromXml(child));
|
||||
} else if (path.startsWith('ndk-bundle')) {
|
||||
ndkBundles.add(AndroidRepositoryRemotePackage.fromXml(child));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return AndroidRepository(
|
||||
licenses,
|
||||
platforms,
|
||||
buildTools,
|
||||
platformTools,
|
||||
tools,
|
||||
ndkBundles,
|
||||
);
|
||||
}
|
||||
|
||||
/// Licenses from the repository XML.
|
||||
final List<AndroidRepositoryLicense> licenses;
|
||||
|
||||
/// Platform information from the repository XML.
|
||||
final List<AndroidRepositoryPlatform> platforms;
|
||||
|
||||
/// Build tools information from the repostiory XML.
|
||||
final List<AndroidRepositoryRemotePackage> buildTools;
|
||||
|
||||
/// Platform tools information from the repostiory XML.
|
||||
final List<AndroidRepositoryRemotePackage> platformTools;
|
||||
|
||||
/// Tools information from the repostiory XML.
|
||||
final List<AndroidRepositoryRemotePackage> tools;
|
||||
|
||||
/// Tools information from the repostiory XML.
|
||||
final List<AndroidRepositoryRemotePackage> ndkBundles;
|
||||
}
|
||||
|
||||
/// Object class for the `<license>` element in the Android repo XML.
|
||||
///
|
||||
/// This node contains license information for the packages in the SDK.
|
||||
class AndroidRepositoryLicense {
|
||||
/// Creates a new RepositoryLicense holder.
|
||||
const AndroidRepositoryLicense(this.id, this.text)
|
||||
: assert(id != null),
|
||||
assert(text != null);
|
||||
|
||||
/// Parses a `<license>` element.
|
||||
factory AndroidRepositoryLicense.fromXml(XmlElement element) {
|
||||
_debugCheckElement(element, 'license');
|
||||
return AndroidRepositoryLicense(element.getAttribute('id'), element.text);
|
||||
}
|
||||
|
||||
/// The identifier for this license.
|
||||
final String id;
|
||||
|
||||
/// The text of the license.
|
||||
final String text;
|
||||
}
|
||||
|
||||
/// Object class for the `<remotePackage>` nodes in the repo XML.
|
||||
///
|
||||
/// These nodes contain information about where to download the zipped
|
||||
/// binaries for various components of the SDK.
|
||||
class AndroidRepositoryRemotePackage {
|
||||
const AndroidRepositoryRemotePackage(
|
||||
this.revision,
|
||||
this.displayName,
|
||||
this.archives, {
|
||||
this.isObsolete = false,
|
||||
}) : assert(revision != null),
|
||||
assert(displayName != null),
|
||||
assert(archives != null),
|
||||
assert(isObsolete != null);
|
||||
|
||||
factory AndroidRepositoryRemotePackage.fromXml(XmlElement element) {
|
||||
_debugCheckElement(element, 'remotePackage');
|
||||
|
||||
return AndroidRepositoryRemotePackage(
|
||||
AndroidRepositoryRevision.fromXml(
|
||||
_firstOrDefault(element.findElements('revision'))),
|
||||
_getChildText(element, 'display-name'),
|
||||
_getArchives(element)
|
||||
.map(
|
||||
(XmlElement archive) => AndroidRepositoryArchive.fromXml(archive),
|
||||
)
|
||||
.toList(),
|
||||
isObsolete: element.getAttribute('obsolete') == 'true',
|
||||
);
|
||||
}
|
||||
|
||||
/// The `<revision>` element, if any.
|
||||
final AndroidRepositoryRevision revision;
|
||||
|
||||
/// The `<display-name>` element.
|
||||
final String displayName;
|
||||
|
||||
/// The list of archives available for this package.
|
||||
final List<AndroidRepositoryArchive> archives;
|
||||
|
||||
/// Whether this package is marked as obsolete.
|
||||
final bool isObsolete;
|
||||
|
||||
@override
|
||||
String toString() => '$runtimeType{revision: $revision, displayName: $displayName, archives: $archives}';
|
||||
}
|
||||
|
||||
/// Object class for instances of `<remotePackage>` elements that are for the
|
||||
/// platform package.
|
||||
class AndroidRepositoryPlatform extends AndroidRepositoryRemotePackage {
|
||||
const AndroidRepositoryPlatform(
|
||||
AndroidRepositoryRevision revision,
|
||||
String displayName,
|
||||
List<AndroidRepositoryArchive> archives,
|
||||
this.apiLevel, {
|
||||
bool isObsolete = false,
|
||||
}) : assert(apiLevel != null),
|
||||
super(revision, displayName, archives, isObsolete: isObsolete);
|
||||
|
||||
/// Parses an platform from a `<remotePackage>` element.
|
||||
factory AndroidRepositoryPlatform.fromXml(
|
||||
XmlElement element,
|
||||
XmlElement typeDetails,
|
||||
) {
|
||||
_debugCheckElement(element, 'remotePackage');
|
||||
assert(typeDetails != null);
|
||||
|
||||
return AndroidRepositoryPlatform(
|
||||
AndroidRepositoryRevision.fromXml(
|
||||
_firstOrDefault(element.findElements('revision'))),
|
||||
_getChildText(element, 'display-name'),
|
||||
_getArchives(element)
|
||||
.map(
|
||||
(XmlElement archive) => AndroidRepositoryArchive.fromXml(archive),
|
||||
)
|
||||
.toList(),
|
||||
int.parse(_getChildText(typeDetails, 'api-level', def: '0')),
|
||||
isObsolete: element.getAttribute('obsolete') == 'true',
|
||||
);
|
||||
}
|
||||
|
||||
/// The API level for this Platform.
|
||||
final int apiLevel;
|
||||
|
||||
@override
|
||||
String toString() => '$runtimeType{revision: $revision, displayName: $displayName, archives: $archives, apiLevel: $apiLevel}';
|
||||
}
|
||||
|
||||
/// The OS types supported by Android.
|
||||
enum OSType {
|
||||
/// Any OS is supported.
|
||||
any,
|
||||
|
||||
/// Suppoorts Linux only.
|
||||
linux,
|
||||
|
||||
/// Supports macOS only.
|
||||
mac,
|
||||
|
||||
/// Supports windows only.
|
||||
windows,
|
||||
}
|
||||
|
||||
/// Object class for the `<archive>` element in the Android repo XML.
|
||||
///
|
||||
/// Contains information about the size, checksum, and location of a binary
|
||||
/// zip archive. Optionally contains information about what host OS is
|
||||
/// supported.
|
||||
class AndroidRepositoryArchive {
|
||||
/// Creates a new AndroidRepositoryArchive.
|
||||
const AndroidRepositoryArchive(
|
||||
this.size,
|
||||
this.checksum,
|
||||
this.url, {
|
||||
this.hostOS = OSType.any,
|
||||
}) : assert(size != null),
|
||||
assert(checksum != null),
|
||||
assert(url != null),
|
||||
assert(hostOS != null);
|
||||
|
||||
/// Parses an `<archive>` element.
|
||||
factory AndroidRepositoryArchive.fromXml(XmlElement element) {
|
||||
_debugCheckElement(element, 'archive');
|
||||
final XmlElement complete =
|
||||
_firstOrDefault(element.findElements('complete'));
|
||||
if (complete == null) {
|
||||
throw StateError('Found <archive> element without a <complete> node!');
|
||||
}
|
||||
|
||||
return AndroidRepositoryArchive(
|
||||
int.parse(_getChildText(complete, 'size', def: '0')),
|
||||
_getChildText(complete, 'checksum'),
|
||||
_getChildText(complete, 'url'),
|
||||
hostOS: _parseHostType(_getChildText(element, 'host-os')),
|
||||
);
|
||||
}
|
||||
|
||||
/// The download size in bytes of the archive.
|
||||
final int size;
|
||||
|
||||
/// The SHA-1 checksum of the archive.
|
||||
final String checksum;
|
||||
|
||||
/// The absolute or relative URL of the file.
|
||||
final String url;
|
||||
|
||||
/// The OS type, if applicable, for this archive.
|
||||
final OSType hostOS;
|
||||
|
||||
@override
|
||||
String toString() => '$runtimeType{size: $size, checksum: $checksum, url: $url, hostOS: $hostOS}';
|
||||
}
|
||||
|
||||
/// Object class for a `<revision>` node in the Android repo XML.
|
||||
///
|
||||
/// Contains information about the revision of the archive.
|
||||
///
|
||||
/// In the case of the platform package, this is the revision of the platform.
|
||||
///
|
||||
/// In all other cases, this basically works like semver.
|
||||
class AndroidRepositoryRevision {
|
||||
/// Creates a new Android repository revision object. All values are required.
|
||||
const AndroidRepositoryRevision(
|
||||
this.major, [
|
||||
this.minor = 0,
|
||||
this.micro = 0,
|
||||
this.preview = 0,
|
||||
]) : assert(major != null),
|
||||
assert(minor != null),
|
||||
assert(micro != null),
|
||||
assert(preview != null);
|
||||
|
||||
/// Parses a `<revision>` element from the Android repository XML.
|
||||
factory AndroidRepositoryRevision.fromXml(XmlElement element) {
|
||||
if (element == null) {
|
||||
return const AndroidRepositoryRevision(0);
|
||||
}
|
||||
_debugCheckElement(element, 'revision');
|
||||
return AndroidRepositoryRevision(
|
||||
int.tryParse(_getChildText(element, 'major', def: '0')),
|
||||
int.tryParse(_getChildText(element, 'minor', def: '0')),
|
||||
int.tryParse(_getChildText(element, 'micro', def: '0')),
|
||||
);
|
||||
}
|
||||
|
||||
/// The major revision value.
|
||||
final int major;
|
||||
|
||||
/// The minor revision value.
|
||||
final int minor;
|
||||
|
||||
/// The micro revision.
|
||||
final int micro;
|
||||
|
||||
/// Preview/Release candidate version. A value of 0 indicates that
|
||||
/// this is not a preview.
|
||||
final int preview;
|
||||
|
||||
/// Whether this revision represents a preview or release.
|
||||
bool get isPreview => preview > 0;
|
||||
|
||||
bool matches(int major, int minor, int micro, [int preview = 0]) {
|
||||
return this.major == major &&
|
||||
this.minor == minor &&
|
||||
this.micro == micro &&
|
||||
this.preview == preview;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => '$runtimeType:{$major.$minor.$micro.$preview}';
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright 2013 The Flutter 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:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
Future<Map<String, String>> loadChecksums(Directory directory) async {
|
||||
final File checksumFile = File(path.join(directory.path, 'checksums.json'));
|
||||
if (!checksumFile.existsSync()) {
|
||||
return <String, String>{};
|
||||
}
|
||||
final Map<String, String> result = <String, String>{};
|
||||
final Map<String, dynamic> jsonResult =
|
||||
json.decode(await checksumFile.readAsString());
|
||||
for (final String key in jsonResult.keys) {
|
||||
result[key] = jsonResult[key];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<void> writeChecksums(
|
||||
Map<String, String> checksums,
|
||||
Directory directory,
|
||||
) async {
|
||||
final File checksumFile = File(path.join(directory.path, 'checksums.json'));
|
||||
const JsonEncoder encoder = JsonEncoder.withIndent(' ');
|
||||
await checksumFile.writeAsString(encoder.convert(checksums));
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
// Copyright 2013 The Flutter 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:io';
|
||||
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'android_repository.dart';
|
||||
import 'options.dart';
|
||||
|
||||
typedef HttpResponseHandler = Future<void> Function(HttpClientResponse);
|
||||
|
||||
Future<void> httpGet(
|
||||
Uri url,
|
||||
HttpResponseHandler handler,
|
||||
) async {
|
||||
assert(url != null);
|
||||
assert(handler != null);
|
||||
|
||||
final HttpClient httpClient = HttpClient();
|
||||
|
||||
try {
|
||||
final HttpClientRequest request = await httpClient.getUrl(url);
|
||||
final HttpClientResponse response = await request.close();
|
||||
await handler(response);
|
||||
} finally {
|
||||
httpClient.close();
|
||||
}
|
||||
}
|
||||
|
||||
class DownloadTracker {
|
||||
DownloadTracker(this.name, this.total) : received = 0;
|
||||
|
||||
final String name;
|
||||
final int total;
|
||||
int received;
|
||||
|
||||
String get percent => '${((received / total) * 100).round()}'.padLeft(3) + '%';
|
||||
|
||||
@override
|
||||
String toString() => '$name: $received/$total ($percent).';
|
||||
}
|
||||
|
||||
final Map<String, DownloadTracker> _downloadTrackers =
|
||||
<String, DownloadTracker>{};
|
||||
void _printDownloadTrackers() {
|
||||
for (final DownloadTracker tracker in _downloadTrackers.values) {
|
||||
stdout.write(
|
||||
'${tracker.name.replaceAll('Android ', '')}: ${tracker.percent} ');
|
||||
}
|
||||
|
||||
if (_downloadTrackers.values
|
||||
.every((DownloadTracker tracker) => tracker.received == tracker.total)) {
|
||||
stdout.writeln();
|
||||
print('Downloads complete.');
|
||||
} else {
|
||||
stdout.write('\r');
|
||||
}
|
||||
}
|
||||
|
||||
class ArchiveDownloadResult {
|
||||
const ArchiveDownloadResult(this.zipFileName, this.checksum);
|
||||
|
||||
static const ArchiveDownloadResult empty = ArchiveDownloadResult(null, null);
|
||||
|
||||
final String zipFileName;
|
||||
final String checksum;
|
||||
}
|
||||
|
||||
Future<ArchiveDownloadResult> downloadArchive(
|
||||
List<AndroidRepositoryRemotePackage> packages,
|
||||
OptionsRevision revision,
|
||||
String repositoryBase,
|
||||
Directory outDirectory, {
|
||||
OSType osType,
|
||||
int apiLevel,
|
||||
String checksumToSkip,
|
||||
}) async {
|
||||
AndroidRepositoryRemotePackage package;
|
||||
for (final AndroidRepositoryRemotePackage p in packages) {
|
||||
if (apiLevel != null && p is AndroidRepositoryPlatform) {
|
||||
if (p.apiLevel != apiLevel) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (p.revision.matches(
|
||||
revision.major, revision.minor, revision.micro, revision.preview)) {
|
||||
package = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (package == null) {
|
||||
throw StateError('Could not find package matching arguments: '
|
||||
'$revision, $osType, $apiLevel');
|
||||
}
|
||||
|
||||
final String displayName = package.displayName;
|
||||
final AndroidRepositoryArchive archive = osType == null
|
||||
? package.archives.first
|
||||
: package.archives.firstWhere(
|
||||
(AndroidRepositoryArchive archive) => archive.hostOS == osType,
|
||||
);
|
||||
|
||||
if (archive.checksum == checksumToSkip) {
|
||||
print('Skipping $displayName, checksum matches current asset.');
|
||||
return ArchiveDownloadResult.empty;
|
||||
}
|
||||
|
||||
Uri uri = Uri.parse(archive.url);
|
||||
if (!uri.isAbsolute) {
|
||||
uri = Uri.parse(repositoryBase + archive.url);
|
||||
}
|
||||
|
||||
_downloadTrackers[displayName] = DownloadTracker(displayName, archive.size);
|
||||
final String outFileName = path.join(outDirectory.path, archive.url);
|
||||
final IOSink tempFileSink = File(outFileName).openWrite();
|
||||
|
||||
Future<void> _handlePlatformZip(HttpClientResponse response) async {
|
||||
await for (List<int> data in response) {
|
||||
_downloadTrackers[displayName].received += data.length;
|
||||
tempFileSink.add(data);
|
||||
_printDownloadTrackers();
|
||||
}
|
||||
await tempFileSink.close();
|
||||
}
|
||||
|
||||
await httpGet(uri, _handlePlatformZip);
|
||||
return ArchiveDownloadResult(outFileName, archive.checksum);
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
// Copyright 2013 The Flutter 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:io';
|
||||
|
||||
import 'package:args/args.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import 'android_repository.dart';
|
||||
|
||||
const Map<String, OSType> osTypeMap = <String, OSType>{
|
||||
'windows': OSType.windows,
|
||||
'macos': OSType.mac,
|
||||
'linux': OSType.linux,
|
||||
};
|
||||
|
||||
class OptionsRevision {
|
||||
const OptionsRevision(
|
||||
this.raw, [
|
||||
this.major = 0,
|
||||
this.minor = 0,
|
||||
this.micro = 0,
|
||||
this.preview = 0,
|
||||
]);
|
||||
|
||||
/// Accepted formats: 1.2.3 or 1.2.3.4
|
||||
factory OptionsRevision.fromRaw(String raw) {
|
||||
final List<String> rawParts = raw.split('.');
|
||||
if (rawParts == null || (rawParts.length != 3 && rawParts.length != 4)) {
|
||||
throw ArgumentError('Invalid revision string $raw.');
|
||||
}
|
||||
return OptionsRevision(
|
||||
raw,
|
||||
int.parse(rawParts[0]),
|
||||
int.parse(rawParts[1]),
|
||||
int.parse(rawParts[2]),
|
||||
rawParts.length == 4 ? int.parse(rawParts[3]) : 0,
|
||||
);
|
||||
}
|
||||
|
||||
final String raw;
|
||||
final int major;
|
||||
final int minor;
|
||||
final int micro;
|
||||
final int preview;
|
||||
}
|
||||
|
||||
class Options {
|
||||
const Options({
|
||||
@required this.platformApiLevel,
|
||||
@required this.platformRevision,
|
||||
@required this.repositoryXml,
|
||||
@required this.repositoryXmlUri,
|
||||
@required this.buildToolsRevision,
|
||||
@required this.platformToolsRevision,
|
||||
@required this.toolsRevision,
|
||||
@required this.ndkRevision,
|
||||
@required this.outDirectory,
|
||||
@required this.repositoryBase,
|
||||
@required this.osType,
|
||||
this.acceptLicenses = false,
|
||||
this.overwrite = false,
|
||||
});
|
||||
|
||||
static Options parseAndValidate(List<String> args, ArgParser argParser) {
|
||||
final ArgResults argResults = argParser.parse(args);
|
||||
final int platformApiLevel = int.parse(argResults['platform']);
|
||||
final int platformRevision = int.parse(argResults['platform-revision']);
|
||||
final Directory outDirectory = Directory(argResults['out']);
|
||||
|
||||
final String rawRepositoryXmlUri = argResults['repository-xml'];
|
||||
final Uri repositoryXmlUri = Uri.tryParse(rawRepositoryXmlUri);
|
||||
final int lastSlash = rawRepositoryXmlUri.lastIndexOf('/');
|
||||
final String repositoryBase =
|
||||
rawRepositoryXmlUri.substring(0, lastSlash + 1);
|
||||
|
||||
if (repositoryXmlUri == null) {
|
||||
throw ArgumentError(
|
||||
'Error: could not parse $rawRepositoryXmlUri as a valid URL.');
|
||||
}
|
||||
|
||||
String getRawVersion(String argName) {
|
||||
final String raw = argResults[argName];
|
||||
if (raw?.isEmpty == true) {
|
||||
print('Could not parse required argument $argName.');
|
||||
print(argParser.usage);
|
||||
exit(-1);
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
final String rawBuildToolsVersion = getRawVersion('build-tools-version');
|
||||
final String rawPlatformToolsVersion =
|
||||
getRawVersion('platform-tools-version');
|
||||
final String rawToolsVersion = getRawVersion('tools-version');
|
||||
final String rawNdkVersion = getRawVersion('ndk-version');
|
||||
|
||||
return Options(
|
||||
platformApiLevel: platformApiLevel,
|
||||
platformRevision: platformRevision,
|
||||
outDirectory: outDirectory,
|
||||
repositoryXml: rawRepositoryXmlUri,
|
||||
repositoryXmlUri: repositoryXmlUri,
|
||||
repositoryBase: repositoryBase,
|
||||
buildToolsRevision: OptionsRevision.fromRaw(rawBuildToolsVersion),
|
||||
platformToolsRevision: OptionsRevision.fromRaw(rawPlatformToolsVersion),
|
||||
toolsRevision: OptionsRevision.fromRaw(rawToolsVersion),
|
||||
ndkRevision: OptionsRevision.fromRaw(rawNdkVersion),
|
||||
osType: osTypeMap[argResults['os']],
|
||||
acceptLicenses: argResults['accept-licenses'],
|
||||
overwrite: argResults['overwrite'],
|
||||
);
|
||||
}
|
||||
|
||||
final int platformApiLevel;
|
||||
final String repositoryXml;
|
||||
final Uri repositoryXmlUri;
|
||||
final int platformRevision;
|
||||
final OptionsRevision buildToolsRevision;
|
||||
final OptionsRevision platformToolsRevision;
|
||||
final OptionsRevision toolsRevision;
|
||||
final OptionsRevision ndkRevision;
|
||||
final String repositoryBase;
|
||||
final Directory outDirectory;
|
||||
final OSType osType;
|
||||
final bool acceptLicenses;
|
||||
final bool overwrite;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright 2013 The Flutter 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:io';
|
||||
|
||||
// TODO(dnfield): if/when a streaming unzip routine is available for Dart, use that instead.
|
||||
|
||||
Future<void> unzipFile(String file, Directory outDir) async {
|
||||
await outDir.parent.create(recursive: true);
|
||||
final Directory tempDir = await outDir.parent.createTemp();
|
||||
|
||||
String command;
|
||||
List<String> args;
|
||||
if (Platform.isWindows) {
|
||||
command = 'powershell.exe -nologo -noprofile -command '
|
||||
'"& { '
|
||||
'Add-Type -A \'System.IO.Compression.FileSystem\'; '
|
||||
'[IO.Compression.ZipFile]::ExtractToDirectory(\'$file\', \'${tempDir.path}\'); '
|
||||
'}"';
|
||||
args = <String>[];
|
||||
} else {
|
||||
command = 'unzip';
|
||||
args = <String>[
|
||||
file,
|
||||
'-d',
|
||||
tempDir.path,
|
||||
];
|
||||
}
|
||||
final ProcessResult result = await Process.run(command, args);
|
||||
if (result.exitCode != 0) {
|
||||
throw Exception('Failed to unzip archive!');
|
||||
}
|
||||
final Directory dir = await tempDir.list().first;
|
||||
if (await outDir.exists()) {
|
||||
await outDir.delete(recursive: true);
|
||||
}
|
||||
await dir.rename(outDir.path);
|
||||
await tempDir.delete();
|
||||
}
|
||||
12
engine/src/flutter/tools/android_sdk_downloader/pubspec.yaml
Normal file
12
engine/src/flutter/tools/android_sdk_downloader/pubspec.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
name: 'android_sdk_downloader'
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
# The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite.
|
||||
sdk: ">=2.0.0-dev.68.0 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
args: ^1.5.1
|
||||
meta: ^1.1.6
|
||||
path: ^1.6.2
|
||||
xml: ^3.2.3
|
||||
Reference in New Issue
Block a user