mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

Downloading these packages from cloud storage simplifies our deployment story because we can upload to cloud storage automatically from the buildbot. This patch also switches the responsibility for downloading the engine artifacts to update_engine.sh. Centralizing this responsibility ensures that the packages and the binaries are always in sync.
276 lines
8.0 KiB
Dart
276 lines
8.0 KiB
Dart
// Copyright 2015 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:io';
|
|
|
|
import 'package:archive/archive.dart';
|
|
import 'package:path/path.dart' as path;
|
|
|
|
import 'base/process.dart';
|
|
import 'build_configuration.dart';
|
|
import 'globals.dart';
|
|
|
|
String _getNameForHostPlatform(HostPlatform platform) {
|
|
switch (platform) {
|
|
case HostPlatform.linux:
|
|
return 'linux-x64';
|
|
case HostPlatform.mac:
|
|
return 'darwin-x64';
|
|
}
|
|
}
|
|
|
|
String _getNameForTargetPlatform(TargetPlatform platform) {
|
|
switch (platform) {
|
|
case TargetPlatform.android:
|
|
return 'android-arm';
|
|
case TargetPlatform.iOS:
|
|
return 'ios-arm';
|
|
case TargetPlatform.iOSSimulator:
|
|
return 'ios-x64';
|
|
case TargetPlatform.mac:
|
|
return 'darwin-x64';
|
|
case TargetPlatform.linux:
|
|
return 'linux-x64';
|
|
}
|
|
}
|
|
|
|
enum ArtifactType {
|
|
snapshot,
|
|
shell,
|
|
mojo,
|
|
androidClassesJar,
|
|
androidIcuData,
|
|
androidKeystore,
|
|
androidLibSkyShell,
|
|
}
|
|
|
|
class Artifact {
|
|
const Artifact._({
|
|
this.name,
|
|
this.fileName,
|
|
this.type,
|
|
this.hostPlatform,
|
|
this.targetPlatform
|
|
});
|
|
|
|
final String name;
|
|
final String fileName;
|
|
final ArtifactType type;
|
|
final HostPlatform hostPlatform;
|
|
final TargetPlatform targetPlatform;
|
|
|
|
String get platform {
|
|
if (targetPlatform != null)
|
|
return _getNameForTargetPlatform(targetPlatform);
|
|
if (hostPlatform != null)
|
|
return _getNameForHostPlatform(hostPlatform);
|
|
assert(false);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
class ArtifactStore {
|
|
static const List<Artifact> knownArtifacts = const <Artifact>[
|
|
const Artifact._(
|
|
name: 'Sky Shell',
|
|
fileName: 'SkyShell.apk',
|
|
type: ArtifactType.shell,
|
|
targetPlatform: TargetPlatform.android
|
|
),
|
|
const Artifact._(
|
|
name: 'Sky Shell',
|
|
fileName: 'sky_shell',
|
|
type: ArtifactType.shell,
|
|
targetPlatform: TargetPlatform.linux
|
|
),
|
|
const Artifact._(
|
|
name: 'Sky Snapshot',
|
|
fileName: 'sky_snapshot',
|
|
type: ArtifactType.snapshot,
|
|
hostPlatform: HostPlatform.linux
|
|
),
|
|
const Artifact._(
|
|
name: 'Sky Snapshot',
|
|
fileName: 'sky_snapshot',
|
|
type: ArtifactType.snapshot,
|
|
hostPlatform: HostPlatform.mac
|
|
),
|
|
const Artifact._(
|
|
name: 'Flutter for Mojo',
|
|
fileName: 'flutter.mojo',
|
|
type: ArtifactType.mojo,
|
|
targetPlatform: TargetPlatform.android
|
|
),
|
|
const Artifact._(
|
|
name: 'Flutter for Mojo',
|
|
fileName: 'flutter.mojo',
|
|
type: ArtifactType.mojo,
|
|
targetPlatform: TargetPlatform.linux
|
|
),
|
|
const Artifact._(
|
|
name: 'Compiled Java code',
|
|
fileName: 'classes.dex.jar',
|
|
type: ArtifactType.androidClassesJar,
|
|
targetPlatform: TargetPlatform.android
|
|
),
|
|
const Artifact._(
|
|
name: 'ICU data table',
|
|
fileName: 'icudtl.dat',
|
|
type: ArtifactType.androidIcuData,
|
|
targetPlatform: TargetPlatform.android
|
|
),
|
|
const Artifact._(
|
|
name: 'Key Store',
|
|
fileName: 'chromium-debug.keystore',
|
|
type: ArtifactType.androidKeystore,
|
|
targetPlatform: TargetPlatform.android
|
|
),
|
|
const Artifact._(
|
|
name: 'Compiled C++ code',
|
|
fileName: 'libsky_shell.so',
|
|
type: ArtifactType.androidLibSkyShell,
|
|
targetPlatform: TargetPlatform.android
|
|
),
|
|
];
|
|
|
|
static Artifact getArtifact({
|
|
ArtifactType type,
|
|
HostPlatform hostPlatform,
|
|
TargetPlatform targetPlatform
|
|
}) {
|
|
for (Artifact artifact in ArtifactStore.knownArtifacts) {
|
|
if (type != null &&
|
|
type != artifact.type)
|
|
continue;
|
|
if (hostPlatform != null &&
|
|
artifact.hostPlatform != null &&
|
|
hostPlatform != artifact.hostPlatform)
|
|
continue;
|
|
if (targetPlatform != null &&
|
|
artifact.targetPlatform != null &&
|
|
targetPlatform != artifact.targetPlatform)
|
|
continue;
|
|
return artifact;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// These values are initialized by FlutterCommandRunner on startup.
|
|
static String flutterRoot;
|
|
static String packageRoot = 'packages';
|
|
|
|
static bool get isPackageRootValid {
|
|
return FileSystemEntity.isDirectorySync(packageRoot);
|
|
}
|
|
|
|
static void ensurePackageRootIsValid() {
|
|
if (!isPackageRootValid) {
|
|
String message = '$packageRoot is not a valid directory.';
|
|
if (packageRoot == 'packages') {
|
|
if (FileSystemEntity.isFileSync('pubspec.yaml'))
|
|
message += '\nDid you run `pub get` in this directory?';
|
|
else
|
|
message += '\nDid you run this command from the same directory as your pubspec.yaml file?';
|
|
}
|
|
printError(message);
|
|
throw new ProcessExit(2);
|
|
}
|
|
}
|
|
|
|
static String _engineRevision;
|
|
|
|
static String get engineRevision {
|
|
if (_engineRevision == null) {
|
|
File revisionFile = new File(path.join(flutterRoot, 'bin', 'cache', 'engine.version'));
|
|
if (revisionFile.existsSync())
|
|
_engineRevision = revisionFile.readAsStringSync().trim();
|
|
}
|
|
return _engineRevision;
|
|
}
|
|
|
|
static Directory getBaseCacheDir() {
|
|
if (flutterRoot == null) {
|
|
printError('FLUTTER_ROOT not specified. Cannot find artifact cache.');
|
|
throw new ProcessExit(2);
|
|
}
|
|
Directory cacheDir = new Directory(path.join(flutterRoot, 'bin', 'cache', 'artifacts'));
|
|
if (!cacheDir.existsSync()) {
|
|
printError('${cacheDir.path} does not exist. Cannot find artifact cache.');
|
|
throw new ProcessExit(2);
|
|
}
|
|
return cacheDir;
|
|
}
|
|
|
|
static Future<String> getPath(Artifact artifact) async {
|
|
File cachedFile = new File(path.join(
|
|
getBaseCacheDir().path, 'engine', artifact.platform, artifact.fileName
|
|
));
|
|
if (!cachedFile.existsSync()) {
|
|
printError('File not found in the platform artifacts: ${cachedFile.path}');
|
|
throw new ProcessExit(2);
|
|
}
|
|
return cachedFile.path;
|
|
}
|
|
|
|
/// Download a file from the given URL and return the bytes.
|
|
static Future<List<int>> _downloadFile(Uri url) async {
|
|
printStatus('Downloading $url.');
|
|
|
|
HttpClient httpClient = new HttpClient();
|
|
HttpClientRequest request = await httpClient.getUrl(url);
|
|
HttpClientResponse response = await request.close();
|
|
printTrace('Received response statusCode=${response.statusCode}');
|
|
if (response.statusCode != 200)
|
|
throw new Exception(response.reasonPhrase);
|
|
|
|
BytesBuilder responseBody = new BytesBuilder(copy: false);
|
|
await for (List<int> chunk in response)
|
|
responseBody.add(chunk);
|
|
|
|
return responseBody.takeBytes();
|
|
}
|
|
|
|
/// Download a file from the given url and write it to the cache.
|
|
/// If [unzip] is true, treat the url as a zip file, and unzip it to the
|
|
/// directory given.
|
|
static Future _downloadFileToCache(Uri url, FileSystemEntity cachedFile, bool unzip) async {
|
|
if (!cachedFile.parent.existsSync())
|
|
cachedFile.parent.createSync(recursive: true);
|
|
|
|
List<int> fileBytes = await _downloadFile(url);
|
|
if (unzip) {
|
|
if (cachedFile is Directory && !cachedFile.existsSync())
|
|
cachedFile.createSync(recursive: true);
|
|
|
|
Archive archive = new ZipDecoder().decodeBytes(fileBytes);
|
|
for (ArchiveFile archiveFile in archive) {
|
|
File subFile = new File(path.join(cachedFile.path, archiveFile.name));
|
|
subFile.writeAsBytesSync(archiveFile.content, flush: true);
|
|
}
|
|
} else {
|
|
File asFile = new File(cachedFile.path);
|
|
asFile.writeAsBytesSync(fileBytes, flush: true);
|
|
}
|
|
}
|
|
|
|
static Future<String> getThirdPartyFile(String urlStr, String cacheSubdir, bool unzip) async {
|
|
Uri url = Uri.parse(urlStr);
|
|
Directory baseDir = getBaseCacheDir();
|
|
Directory cacheDir = new Directory(path.join(
|
|
baseDir.path, 'third_party', cacheSubdir));
|
|
File cachedFile = new File(
|
|
path.join(cacheDir.path, url.pathSegments[url.pathSegments.length-1]));
|
|
if (!cachedFile.existsSync()) {
|
|
try {
|
|
await _downloadFileToCache(url, cachedFile, unzip);
|
|
} catch (e) {
|
|
printError('Failed to fetch third-party artifact: $url: $e');
|
|
throw new ProcessExit(2);
|
|
}
|
|
}
|
|
return cachedFile.path;
|
|
}
|
|
}
|