mirror of
https://github.com/flutter/flutter
synced 2024-09-19 08:11:56 +00:00
This reverts commit b7f5aef11a
.
This commit is contained in:
parent
b7f5aef11a
commit
66ba4b244d
|
@ -2,24 +2,184 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:io' as io;
|
||||
import 'dart:io';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
// TODO(fujino): delete this script once PR #71244 lands on stable.
|
||||
void main(List<String> args) {
|
||||
final String scriptPath = io.Platform.script.toFilePath();
|
||||
final String scriptDir = path.dirname(scriptPath);
|
||||
final String repoRoot = path.normalize(path.join(scriptDir, '..', '..'));
|
||||
final io.ProcessResult result = io.Process.runSync(
|
||||
path.join(repoRoot, 'dev', 'tools', 'bin', 'conductor'),
|
||||
<String>['codesign', '--verify'],
|
||||
String get repoRoot => path.normalize(path.join(path.dirname(Platform.script.toFilePath()), '..', '..'));
|
||||
String get cacheDirectory => path.normalize(path.join(repoRoot, 'bin', 'cache'));
|
||||
|
||||
/// Check mime-type of file at [filePath] to determine if it is binary
|
||||
bool isBinary(String filePath) {
|
||||
final ProcessResult result = Process.runSync(
|
||||
'file',
|
||||
<String>[
|
||||
'--mime-type',
|
||||
'-b', // is binary
|
||||
filePath,
|
||||
],
|
||||
);
|
||||
if (result.exitCode != 0) {
|
||||
print('codesign script exited with code $result.exitCode');
|
||||
print('stdout:\n${result.stdout}\n');
|
||||
print('stderr:\n${result.stderr}\n');
|
||||
io.exit(1);
|
||||
}
|
||||
print('codesign script succeeded.');
|
||||
print('stdout:\n${result.stdout}');
|
||||
return (result.stdout as String).contains('application/x-mach-binary');
|
||||
}
|
||||
|
||||
/// Find every binary file in the given [rootDirectory]
|
||||
List<String> findBinaryPaths([String rootDirectory]) {
|
||||
rootDirectory ??= cacheDirectory;
|
||||
final ProcessResult result = Process.runSync(
|
||||
'find',
|
||||
<String>[
|
||||
rootDirectory,
|
||||
'-type',
|
||||
'f',
|
||||
'-perm',
|
||||
'+111', // is executable
|
||||
],
|
||||
);
|
||||
final List<String> allFiles = (result.stdout as String).split('\n').where((String s) => s.isNotEmpty).toList();
|
||||
return allFiles.where(isBinary).toList();
|
||||
}
|
||||
|
||||
/// Given the path to a stamp file, read the contents.
|
||||
///
|
||||
/// Will throw if the file doesn't exist.
|
||||
String readStamp(String filePath) {
|
||||
final File file = File(filePath);
|
||||
if (!file.existsSync()) {
|
||||
throw 'Error! Stamp file $filePath does not exist!';
|
||||
}
|
||||
return file.readAsStringSync().trim();
|
||||
}
|
||||
|
||||
/// Return whether or not the flutter cache is up to date.
|
||||
bool checkCacheIsCurrent() {
|
||||
try {
|
||||
final String dartSdkStamp = readStamp(path.join(cacheDirectory, 'engine-dart-sdk.stamp'));
|
||||
final String engineVersion = readStamp(path.join(repoRoot, 'bin', 'internal', 'engine.version'));
|
||||
return dartSdkStamp == engineVersion;
|
||||
} catch (e) {
|
||||
print(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
List<String> get binariesWithEntitlements => List<String>.unmodifiable(<String>[
|
||||
'ideviceinfo',
|
||||
'idevicename',
|
||||
'idevicescreenshot',
|
||||
'idevicesyslog',
|
||||
'libimobiledevice.6.dylib',
|
||||
'libplist.3.dylib',
|
||||
'iproxy',
|
||||
'libusbmuxd.4.dylib',
|
||||
'libssl.1.0.0.dylib',
|
||||
'libcrypto.1.0.0.dylib',
|
||||
'libzip.5.0.dylib',
|
||||
'libzip.5.dylib',
|
||||
'gen_snapshot',
|
||||
'dart',
|
||||
'flutter_tester',
|
||||
'gen_snapshot_arm64',
|
||||
'gen_snapshot_armv7',
|
||||
]);
|
||||
|
||||
List<String> get expectedEntitlements => List<String>.unmodifiable(<String>[
|
||||
'com.apple.security.cs.allow-jit',
|
||||
'com.apple.security.cs.allow-unsigned-executable-memory',
|
||||
'com.apple.security.cs.allow-dyld-environment-variables',
|
||||
'com.apple.security.network.client',
|
||||
'com.apple.security.network.server',
|
||||
'com.apple.security.cs.disable-library-validation',
|
||||
]);
|
||||
|
||||
|
||||
/// Check if the binary has the expected entitlements.
|
||||
bool hasExpectedEntitlements(String binaryPath) {
|
||||
try {
|
||||
final ProcessResult entitlementResult = Process.runSync(
|
||||
'codesign',
|
||||
<String>[
|
||||
'--display',
|
||||
'--entitlements',
|
||||
':-',
|
||||
binaryPath,
|
||||
],
|
||||
);
|
||||
|
||||
if (entitlementResult.exitCode != 0) {
|
||||
print('The `codesign --entitlements` command failed with exit code ${entitlementResult.exitCode}:\n'
|
||||
'${entitlementResult.stderr}\n');
|
||||
return false;
|
||||
}
|
||||
|
||||
bool passes = true;
|
||||
final String output = entitlementResult.stdout as String;
|
||||
for (final String entitlement in expectedEntitlements) {
|
||||
final bool entitlementExpected = binariesWithEntitlements.contains(path.basename(binaryPath));
|
||||
if (output.contains(entitlement) != entitlementExpected) {
|
||||
print('File "$binaryPath" ${entitlementExpected ? 'does not have expected' : 'has unexpected'} entitlement $entitlement.');
|
||||
passes = false;
|
||||
}
|
||||
}
|
||||
return passes;
|
||||
} catch (e) {
|
||||
print(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
if (!Platform.isMacOS) {
|
||||
print('Error! Expected operating system "macos", actual operating system '
|
||||
'is: "${Platform.operatingSystem}"');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!checkCacheIsCurrent()) {
|
||||
print(
|
||||
'Warning! Your cache is either not present or not matching your flutter\n'
|
||||
'version. Run a `flutter` command to update your cache, and re-try this\n'
|
||||
'test.');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
final List<String> unsignedBinaries = <String>[];
|
||||
final List<String> wrongEntitlementBinaries = <String>[];
|
||||
for (final String binaryPath in findBinaryPaths(cacheDirectory)) {
|
||||
print('Verifying the code signature of $binaryPath');
|
||||
final ProcessResult codeSignResult = Process.runSync(
|
||||
'codesign',
|
||||
<String>[
|
||||
'-vvv',
|
||||
binaryPath,
|
||||
],
|
||||
);
|
||||
if (codeSignResult.exitCode != 0) {
|
||||
unsignedBinaries.add(binaryPath);
|
||||
print('File "$binaryPath" does not appear to be codesigned.\n'
|
||||
'The `codesign` command failed with exit code ${codeSignResult.exitCode}:\n'
|
||||
'${codeSignResult.stderr}\n');
|
||||
continue;
|
||||
} else {
|
||||
print('Verifying entitlements of $binaryPath');
|
||||
if (!hasExpectedEntitlements(binaryPath)) {
|
||||
wrongEntitlementBinaries.add(binaryPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (unsignedBinaries.isNotEmpty) {
|
||||
print('Found ${unsignedBinaries.length} unsigned binaries:');
|
||||
unsignedBinaries.forEach(print);
|
||||
}
|
||||
|
||||
if (wrongEntitlementBinaries.isNotEmpty) {
|
||||
print('Found ${wrongEntitlementBinaries.length} binaries with unexpected entitlements:');
|
||||
wrongEntitlementBinaries.forEach(print);
|
||||
}
|
||||
|
||||
if (unsignedBinaries.isNotEmpty) {
|
||||
// TODO(jmagman): Also exit if `wrongEntitlementBinaries.isNotEmpty` after https://github.com/flutter/flutter/issues/46704 is done.
|
||||
exit(1);
|
||||
}
|
||||
|
||||
print('Verified that binaries are codesigned and have expected entitlements.');
|
||||
}
|
||||
|
|
|
@ -694,7 +694,7 @@ Future<void> _runFrameworkTests() async {
|
|||
await _pubRunTest(path.join(flutterRoot, 'dev', 'bots'), tableData: bigqueryApi?.tabledata);
|
||||
await _pubRunTest(path.join(flutterRoot, 'dev', 'devicelab'), tableData: bigqueryApi?.tabledata);
|
||||
await _pubRunTest(path.join(flutterRoot, 'dev', 'snippets'), tableData: bigqueryApi?.tabledata);
|
||||
await _pubRunTest(path.join(flutterRoot, 'dev', 'tools'), tableData: bigqueryApi?.tabledata, forceSingleCore: true);
|
||||
await _pubRunTest(path.join(flutterRoot, 'dev', 'tools'), tableData: bigqueryApi?.tabledata);
|
||||
await _pubRunTest(path.join(flutterRoot, 'dev', 'benchmarks', 'metrics_center'), tableData: bigqueryApi?.tabledata);
|
||||
await _runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'android_semantics_testing'), tableData: bigqueryApi?.tabledata);
|
||||
await _runFlutterTest(path.join(flutterRoot, 'dev', 'manual_tests'), tableData: bigqueryApi?.tabledata);
|
||||
|
|
|
@ -10,17 +10,15 @@
|
|||
import 'dart:io' as io;
|
||||
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:dev_tools/codesign.dart';
|
||||
import 'package:dev_tools/globals.dart';
|
||||
import 'package:dev_tools/roll_dev.dart';
|
||||
import 'package:dev_tools/repository.dart';
|
||||
import 'package:dev_tools/stdio.dart';
|
||||
import 'package:file/file.dart';
|
||||
import 'package:file/local.dart';
|
||||
import 'package:platform/platform.dart';
|
||||
import 'package:process/process.dart';
|
||||
import 'package:dev_tools/repository.dart';
|
||||
import 'package:dev_tools/roll_dev.dart';
|
||||
import 'package:dev_tools/stdio.dart';
|
||||
|
||||
Future<void> main(List<String> args) async {
|
||||
void main(List<String> args) {
|
||||
const FileSystem fileSystem = LocalFileSystem();
|
||||
const ProcessManager processManager = LocalProcessManager();
|
||||
const Platform platform = LocalPlatform();
|
||||
|
@ -31,12 +29,9 @@ Future<void> main(List<String> args) async {
|
|||
);
|
||||
final Checkouts checkouts = Checkouts(
|
||||
fileSystem: fileSystem,
|
||||
parentDirectory: localFlutterRoot.parent,
|
||||
platform: platform,
|
||||
processManager: processManager,
|
||||
stdio: stdio,
|
||||
);
|
||||
|
||||
final CommandRunner<void> runner = CommandRunner<void>(
|
||||
'conductor',
|
||||
'A tool for coordinating Flutter releases.',
|
||||
|
@ -44,15 +39,16 @@ Future<void> main(List<String> args) async {
|
|||
);
|
||||
|
||||
<Command<void>>[
|
||||
RollDevCommand(
|
||||
checkouts: checkouts,
|
||||
RollDev(
|
||||
fileSystem: fileSystem,
|
||||
platform: platform,
|
||||
repository: checkouts.addRepo(
|
||||
fileSystem: fileSystem,
|
||||
platform: platform,
|
||||
repoType: RepositoryType.framework,
|
||||
stdio: stdio,
|
||||
),
|
||||
CodesignCommand(
|
||||
checkouts: checkouts,
|
||||
flutterRoot: localFlutterRoot,
|
||||
stdio: stdio,
|
||||
),
|
||||
].forEach(runner.addCommand);
|
||||
|
||||
|
@ -62,9 +58,20 @@ Future<void> main(List<String> args) async {
|
|||
}
|
||||
|
||||
try {
|
||||
await runner.run(args);
|
||||
runner.run(args);
|
||||
} on Exception catch (e) {
|
||||
stdio.printError(e.toString());
|
||||
io.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
bool assertsEnabled() {
|
||||
// Verify asserts enabled
|
||||
bool assertsEnabled = false;
|
||||
|
||||
assert(() {
|
||||
assertsEnabled = true;
|
||||
return true;
|
||||
}());
|
||||
return assertsEnabled;
|
||||
}
|
||||
|
|
|
@ -1,369 +0,0 @@
|
|||
// Copyright 2014 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' as io;
|
||||
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:file/file.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:platform/platform.dart';
|
||||
import 'package:process/process.dart';
|
||||
|
||||
import './globals.dart';
|
||||
import './repository.dart';
|
||||
import './stdio.dart';
|
||||
|
||||
const List<String> expectedEntitlements = <String>[
|
||||
'com.apple.security.cs.allow-jit',
|
||||
'com.apple.security.cs.allow-unsigned-executable-memory',
|
||||
'com.apple.security.cs.allow-dyld-environment-variables',
|
||||
'com.apple.security.network.client',
|
||||
'com.apple.security.network.server',
|
||||
'com.apple.security.cs.disable-library-validation',
|
||||
];
|
||||
|
||||
const String kVerify = 'verify';
|
||||
const String kSignatures = 'signatures';
|
||||
const String kRevision = 'revision';
|
||||
const String kUpstream = 'upstream';
|
||||
|
||||
/// Command to codesign and verify the signatures of cached binaries.
|
||||
class CodesignCommand extends Command<void> {
|
||||
CodesignCommand({
|
||||
@required this.checkouts,
|
||||
@required this.flutterRoot,
|
||||
}) : assert(flutterRoot != null),
|
||||
fileSystem = checkouts.fileSystem,
|
||||
platform = checkouts.platform,
|
||||
stdio = checkouts.stdio,
|
||||
processManager = checkouts.processManager {
|
||||
argParser.addFlag(
|
||||
kVerify,
|
||||
help:
|
||||
'Only verify expected binaries exist and are codesigned with entitlements.',
|
||||
);
|
||||
argParser.addFlag(
|
||||
kSignatures,
|
||||
defaultsTo: true,
|
||||
help:
|
||||
'When off, this command will only verify the existence of binaries, and not their\n'
|
||||
'signatures or entitlements. Must be used with --verify flag.',
|
||||
);
|
||||
argParser.addOption(
|
||||
kUpstream,
|
||||
defaultsTo: FrameworkRepository.defaultUpstream,
|
||||
help: 'The git remote URL to use as the Flutter framework\'s upstream.',
|
||||
);
|
||||
argParser.addOption(
|
||||
kRevision,
|
||||
help: 'The Flutter framework revision to use.',
|
||||
);
|
||||
}
|
||||
|
||||
final Checkouts checkouts;
|
||||
final FileSystem fileSystem;
|
||||
final Platform platform;
|
||||
final ProcessManager processManager;
|
||||
final Stdio stdio;
|
||||
|
||||
/// Root directory of the Flutter repository.
|
||||
final Directory flutterRoot;
|
||||
|
||||
FrameworkRepository _framework;
|
||||
FrameworkRepository get framework => _framework ??= FrameworkRepository.localRepoAsUpstream(
|
||||
checkouts,
|
||||
upstreamPath: flutterRoot.path,
|
||||
);
|
||||
|
||||
@visibleForTesting
|
||||
set framework(FrameworkRepository framework) => _framework = framework;
|
||||
|
||||
@override
|
||||
String get name => 'codesign';
|
||||
|
||||
@override
|
||||
String get description =>
|
||||
'For codesigning and verifying the signatures of engine binaries.';
|
||||
|
||||
@override
|
||||
void run() {
|
||||
if (!platform.isMacOS) {
|
||||
throw ConductorException(
|
||||
'Error! Expected operating system "macos", actual operating system is: '
|
||||
'"${platform.operatingSystem}"');
|
||||
}
|
||||
|
||||
if (argResults['verify'] as bool != true) {
|
||||
throw ConductorException(
|
||||
'Sorry, but codesigning is not implemented yet. Please pass the '
|
||||
'--$kVerify flag to verify signatures.');
|
||||
}
|
||||
|
||||
String revision;
|
||||
if (argResults.wasParsed(kRevision)) {
|
||||
stdio.printError('Warning! When providing an arbitrary revision, the contents of the cache may not');
|
||||
stdio.printError('match the expected binaries in the conductor tool. It is preferred to check out');
|
||||
stdio.printError('the desired revision and run that version of the conductor.\n');
|
||||
revision = argResults[kRevision] as String;
|
||||
} else {
|
||||
revision = (processManager.runSync(
|
||||
<String>['git', 'rev-parse', 'HEAD'],
|
||||
workingDirectory: framework.checkoutDirectory.path,
|
||||
).stdout as String).trim();
|
||||
assert(revision.isNotEmpty);
|
||||
}
|
||||
|
||||
framework.checkout(revision);
|
||||
|
||||
// Ensure artifacts present
|
||||
framework.runFlutter(<String>['precache', '--ios', '--macos']);
|
||||
|
||||
verifyExist();
|
||||
if (argResults[kSignatures] as bool) {
|
||||
verifySignatures();
|
||||
}
|
||||
}
|
||||
|
||||
/// Binaries that are expected to be codesigned and have entitlements.
|
||||
///
|
||||
/// This list should be kept in sync with the actual contents of Flutter's
|
||||
/// cache.
|
||||
List<String> get binariesWithEntitlements {
|
||||
return <String>[
|
||||
'artifacts/engine/android-arm-profile/darwin-x64/gen_snapshot',
|
||||
'artifacts/engine/android-arm-release/darwin-x64/gen_snapshot',
|
||||
'artifacts/engine/android-arm64-profile/darwin-x64/gen_snapshot',
|
||||
'artifacts/engine/android-arm64-release/darwin-x64/gen_snapshot',
|
||||
'artifacts/engine/android-x64-profile/darwin-x64/gen_snapshot',
|
||||
'artifacts/engine/android-x64-release/darwin-x64/gen_snapshot',
|
||||
'artifacts/engine/darwin-x64-profile/gen_snapshot',
|
||||
'artifacts/engine/darwin-x64-release/gen_snapshot',
|
||||
'artifacts/engine/darwin-x64/flutter_tester',
|
||||
'artifacts/engine/darwin-x64/gen_snapshot',
|
||||
'artifacts/engine/ios-profile/gen_snapshot_arm64',
|
||||
'artifacts/engine/ios-profile/gen_snapshot_armv7',
|
||||
'artifacts/engine/ios-release/gen_snapshot_arm64',
|
||||
'artifacts/engine/ios-release/gen_snapshot_armv7',
|
||||
'artifacts/engine/ios/gen_snapshot_arm64',
|
||||
'artifacts/engine/ios/gen_snapshot_armv7',
|
||||
'artifacts/ios-deploy/ios-deploy',
|
||||
'artifacts/libimobiledevice/idevicescreenshot',
|
||||
'artifacts/libimobiledevice/idevicesyslog',
|
||||
'artifacts/libimobiledevice/libimobiledevice-1.0.6.dylib',
|
||||
'artifacts/libplist/libplist-2.0.3.dylib',
|
||||
'artifacts/openssl/libcrypto.1.1.dylib',
|
||||
'artifacts/openssl/libssl.1.1.dylib',
|
||||
'artifacts/usbmuxd/iproxy',
|
||||
'artifacts/usbmuxd/libusbmuxd-2.0.6.dylib',
|
||||
'dart-sdk/bin/dart',
|
||||
'dart-sdk/bin/dartaotruntime',
|
||||
'dart-sdk/bin/utils/gen_snapshot',
|
||||
].map((String relativePath) => fileSystem.path.join(framework.cacheDirectory, relativePath)).toList();
|
||||
}
|
||||
|
||||
/// Binaries that are only expected to be codesigned.
|
||||
///
|
||||
/// This list should be kept in sync with the actual contents of Flutter's
|
||||
/// cache.
|
||||
List<String> get binariesWithoutEntitlements {
|
||||
return <String>[
|
||||
'artifacts/engine/darwin-x64-profile/FlutterMacOS.framework/Versions/A/FlutterMacOS',
|
||||
'artifacts/engine/darwin-x64-release/FlutterMacOS.framework/Versions/A/FlutterMacOS',
|
||||
'artifacts/engine/darwin-x64/FlutterMacOS.framework/Versions/A/FlutterMacOS',
|
||||
'artifacts/engine/darwin-x64/font-subset',
|
||||
'artifacts/engine/ios-profile/Flutter.xcframework/ios-armv7_arm64/Flutter.framework/Flutter',
|
||||
'artifacts/engine/ios-profile/Flutter.xcframework/ios-x86_64-simulator/Flutter.framework/Flutter',
|
||||
'artifacts/engine/ios-release/Flutter.xcframework/ios-armv7_arm64/Flutter.framework/Flutter',
|
||||
'artifacts/engine/ios-release/Flutter.xcframework/ios-x86_64-simulator/Flutter.framework/Flutter',
|
||||
'artifacts/engine/ios/Flutter.xcframework/ios-armv7_arm64/Flutter.framework/Flutter',
|
||||
'artifacts/engine/ios/Flutter.xcframework/ios-x86_64-simulator/Flutter.framework/Flutter',
|
||||
].map((String relativePath) => fileSystem.path.join(framework.cacheDirectory, relativePath)).toList();
|
||||
}
|
||||
|
||||
/// Verify the existence of all expected binaries in cache.
|
||||
///
|
||||
/// This function ignores code signatures and entitlements, and is intended to
|
||||
/// be run on every commit. It should throw if either new binaries are added
|
||||
/// to the cache or expected binaries removed. In either case, this class'
|
||||
/// [binariesWithEntitlements] or [binariesWithoutEntitlements] lists should
|
||||
/// be updated accordingly.
|
||||
@visibleForTesting
|
||||
void verifyExist() {
|
||||
final Set<String> foundFiles = <String>{};
|
||||
for (final String binaryPath in findBinaryPaths(framework.cacheDirectory)) {
|
||||
if (binariesWithEntitlements.contains(binaryPath)) {
|
||||
foundFiles.add(binaryPath);
|
||||
} else if (binariesWithoutEntitlements.contains(binaryPath)) {
|
||||
foundFiles.add(binaryPath);
|
||||
} else {
|
||||
throw ConductorException('Found unexpected binary in cache: $binaryPath');
|
||||
}
|
||||
}
|
||||
|
||||
final List<String> allExpectedFiles = binariesWithEntitlements + binariesWithoutEntitlements;
|
||||
if (foundFiles.length < allExpectedFiles.length) {
|
||||
final List<String> unfoundFiles = allExpectedFiles.where(
|
||||
(String file) => !foundFiles.contains(file),
|
||||
).toList();
|
||||
stdio.printError('Expected binaries not found in cache:\n\n${unfoundFiles.join('\n')}\n');
|
||||
stdio.printError('If this commit is removing binaries from the cache, this test should be fixed by');
|
||||
stdio.printError('removing the relevant entry from either the `binariesWithEntitlements` or');
|
||||
stdio.printError('`binariesWithoutEntitlements` getters in dev/tools/lib/codesign.dart.');
|
||||
throw ConductorException('Did not find all expected binaries!');
|
||||
}
|
||||
|
||||
stdio.printStatus('All expected binaries present.');
|
||||
}
|
||||
|
||||
/// Verify code signatures and entitlements of all binaries in the cache.
|
||||
@visibleForTesting
|
||||
void verifySignatures() {
|
||||
final List<String> unsignedBinaries = <String>[];
|
||||
final List<String> wrongEntitlementBinaries = <String>[];
|
||||
final List<String> unexpectedBinaries = <String>[];
|
||||
|
||||
for (final String binaryPath in findBinaryPaths(framework.cacheDirectory)) {
|
||||
bool verifySignature = false;
|
||||
bool verifyEntitlements = false;
|
||||
if (binariesWithEntitlements.contains(binaryPath)) {
|
||||
verifySignature = true;
|
||||
verifyEntitlements = true;
|
||||
}
|
||||
if (binariesWithoutEntitlements.contains(binaryPath)) {
|
||||
verifySignature = true;
|
||||
}
|
||||
if (!verifySignature && !verifyEntitlements) {
|
||||
unexpectedBinaries.add(binaryPath);
|
||||
stdio.printError('Unexpected binary $binaryPath found in cache!');
|
||||
continue;
|
||||
}
|
||||
stdio.printTrace('Verifying the code signature of $binaryPath');
|
||||
final io.ProcessResult codeSignResult = processManager.runSync(
|
||||
<String>[
|
||||
'codesign',
|
||||
'-vvv',
|
||||
binaryPath,
|
||||
],
|
||||
);
|
||||
if (codeSignResult.exitCode != 0) {
|
||||
unsignedBinaries.add(binaryPath);
|
||||
stdio.printError(
|
||||
'File "$binaryPath" does not appear to be codesigned.\n'
|
||||
'The `codesign` command failed with exit code ${codeSignResult.exitCode}:\n'
|
||||
'${codeSignResult.stderr}\n');
|
||||
continue;
|
||||
}
|
||||
if (verifyEntitlements) {
|
||||
stdio.printTrace('Verifying entitlements of $binaryPath');
|
||||
if (!hasExpectedEntitlements(binaryPath)) {
|
||||
wrongEntitlementBinaries.add(binaryPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// First print all deviations from expectations
|
||||
if (unsignedBinaries.isNotEmpty) {
|
||||
stdio.printError('Found ${unsignedBinaries.length} unsigned binaries:');
|
||||
unsignedBinaries.forEach(print);
|
||||
}
|
||||
|
||||
if (wrongEntitlementBinaries.isNotEmpty) {
|
||||
stdio.printError(
|
||||
'Found ${wrongEntitlementBinaries.length} binaries with unexpected entitlements:');
|
||||
wrongEntitlementBinaries.forEach(print);
|
||||
}
|
||||
|
||||
if (unexpectedBinaries.isNotEmpty) {
|
||||
stdio.printError('Found ${unexpectedBinaries.length} unexpected binaries in the cache:');
|
||||
unexpectedBinaries.forEach(print);
|
||||
}
|
||||
|
||||
// Finally, exit on any invalid state
|
||||
if (unsignedBinaries.isNotEmpty) {
|
||||
throw ConductorException('Test failed because unsigned binaries detected.');
|
||||
}
|
||||
|
||||
if (wrongEntitlementBinaries.isNotEmpty) {
|
||||
throw ConductorException(
|
||||
'Test failed because files found with the wrong entitlements:\n'
|
||||
'${wrongEntitlementBinaries.join('\n')}');
|
||||
}
|
||||
|
||||
if (unexpectedBinaries.isNotEmpty) {
|
||||
throw ConductorException('Test failed because unexpected binaries found in the cache.');
|
||||
}
|
||||
|
||||
stdio.printStatus(
|
||||
'Verified that binaries for commit ${argResults[kRevision] as String} are codesigned and have '
|
||||
'expected entitlements.');
|
||||
}
|
||||
|
||||
List<String> _allBinaryPaths;
|
||||
/// Find every binary file in the given [rootDirectory].
|
||||
List<String> findBinaryPaths(String rootDirectory) {
|
||||
if (_allBinaryPaths != null) {
|
||||
return _allBinaryPaths;
|
||||
}
|
||||
final io.ProcessResult result = processManager.runSync(
|
||||
<String>[
|
||||
'find',
|
||||
rootDirectory,
|
||||
'-type',
|
||||
'f',
|
||||
],
|
||||
);
|
||||
final List<String> allFiles = (result.stdout as String)
|
||||
.split('\n')
|
||||
.where((String s) => s.isNotEmpty)
|
||||
.toList();
|
||||
_allBinaryPaths = allFiles.where(isBinary).toList();
|
||||
return _allBinaryPaths;
|
||||
}
|
||||
|
||||
/// Check mime-type of file at [filePath] to determine if it is binary.
|
||||
bool isBinary(String filePath) {
|
||||
final io.ProcessResult result = processManager.runSync(
|
||||
<String>[
|
||||
'file',
|
||||
'--mime-type',
|
||||
'-b', // is binary
|
||||
filePath,
|
||||
],
|
||||
);
|
||||
return (result.stdout as String).contains('application/x-mach-binary');
|
||||
}
|
||||
|
||||
/// Check if the binary has the expected entitlements.
|
||||
bool hasExpectedEntitlements(String binaryPath) {
|
||||
final io.ProcessResult entitlementResult = processManager.runSync(
|
||||
<String>[
|
||||
'codesign',
|
||||
'--display',
|
||||
'--entitlements',
|
||||
':-',
|
||||
binaryPath,
|
||||
],
|
||||
);
|
||||
|
||||
if (entitlementResult.exitCode != 0) {
|
||||
stdio.printError(
|
||||
'The `codesign --entitlements` command failed with exit code ${entitlementResult.exitCode}:\n'
|
||||
'${entitlementResult.stderr}\n');
|
||||
return false;
|
||||
}
|
||||
|
||||
bool passes = true;
|
||||
final String output = entitlementResult.stdout as String;
|
||||
for (final String entitlement in expectedEntitlements) {
|
||||
final bool entitlementExpected = binariesWithEntitlements.contains(binaryPath);
|
||||
if (output.contains(entitlement) != entitlementExpected) {
|
||||
stdio.printError(
|
||||
'File "$binaryPath" ${entitlementExpected ? 'does not have expected' : 'has unexpected'} '
|
||||
'entitlement $entitlement.');
|
||||
passes = false;
|
||||
}
|
||||
}
|
||||
return passes;
|
||||
}
|
||||
}
|
|
@ -45,7 +45,6 @@ class Git {
|
|||
return processManager.runSync(
|
||||
<String>['git', ...args],
|
||||
workingDirectory: workingDirectory,
|
||||
environment: <String, String>{'GIT_TRACE': '1'},
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:file/file.dart';
|
||||
import 'package:file/local.dart';
|
||||
import 'package:platform/platform.dart';
|
||||
|
||||
const String kIncrement = 'increment';
|
||||
const String kCommit = 'commit';
|
||||
const String kRemoteName = 'remote';
|
||||
|
@ -28,61 +24,3 @@ String stdoutToString(dynamic input) {
|
|||
final String str = input as String;
|
||||
return str.trim();
|
||||
}
|
||||
|
||||
class ConductorException implements Exception {
|
||||
ConductorException(this.message);
|
||||
|
||||
final String message;
|
||||
|
||||
@override
|
||||
String toString() => 'Exception: $message';
|
||||
}
|
||||
|
||||
Directory _flutterRoot;
|
||||
Directory get localFlutterRoot {
|
||||
if (_flutterRoot != null) {
|
||||
return _flutterRoot;
|
||||
}
|
||||
String filePath;
|
||||
const FileSystem fileSystem = LocalFileSystem();
|
||||
const Platform platform = LocalPlatform();
|
||||
|
||||
// If a test
|
||||
if (platform.script.scheme == 'data') {
|
||||
final RegExp pattern = RegExp(
|
||||
r'(file:\/\/[^"]*[/\\]dev\/tools[/\\][^"]+\.dart)',
|
||||
multiLine: true,
|
||||
);
|
||||
final Match match =
|
||||
pattern.firstMatch(Uri.decodeFull(platform.script.path));
|
||||
if (match == null) {
|
||||
throw Exception(
|
||||
'Cannot determine path of script!\n${platform.script.path}',
|
||||
);
|
||||
}
|
||||
filePath = Uri.parse(match.group(1)).path.replaceAll(r'%20', ' ');
|
||||
} else {
|
||||
filePath = platform.script.toFilePath();
|
||||
}
|
||||
final String checkoutsDirname = fileSystem.path.normalize(
|
||||
fileSystem.path.join(
|
||||
fileSystem.path.dirname(filePath),
|
||||
'..', // flutter/dev/tools
|
||||
'..', // flutter/dev
|
||||
'..', // flutter
|
||||
),
|
||||
);
|
||||
_flutterRoot = fileSystem.directory(checkoutsDirname);
|
||||
return _flutterRoot;
|
||||
}
|
||||
|
||||
bool assertsEnabled() {
|
||||
// Verify asserts enabled
|
||||
bool assertsEnabled = false;
|
||||
|
||||
assert(() {
|
||||
assertsEnabled = true;
|
||||
return true;
|
||||
}());
|
||||
return assertsEnabled;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import './stdio.dart';
|
|||
import './version.dart';
|
||||
|
||||
/// A source code repository.
|
||||
abstract class Repository {
|
||||
class Repository {
|
||||
Repository({
|
||||
@required this.name,
|
||||
@required this.upstream,
|
||||
|
@ -46,35 +46,22 @@ abstract class Repository {
|
|||
|
||||
Directory _checkoutDirectory;
|
||||
|
||||
/// Directory for the repository checkout.
|
||||
/// Lazily-loaded directory for the repository checkout.
|
||||
///
|
||||
/// Since cloning a repository takes a long time, we do not ensure it is
|
||||
/// cloned on the filesystem until this getter is accessed.
|
||||
/// Cloning a repository is time-consuming, thus the repository is not cloned
|
||||
/// until this getter is called.
|
||||
Directory get checkoutDirectory {
|
||||
if (_checkoutDirectory != null) {
|
||||
return _checkoutDirectory;
|
||||
}
|
||||
_checkoutDirectory = parentDirectory.childDirectory(name);
|
||||
if (!useExistingCheckout && _checkoutDirectory.existsSync()) {
|
||||
stdio.printTrace('Deleting $name from ${_checkoutDirectory.path}...');
|
||||
_checkoutDirectory.deleteSync(recursive: true);
|
||||
} else if (useExistingCheckout && _checkoutDirectory.existsSync()) {
|
||||
git.run(
|
||||
<String>['checkout', 'master'],
|
||||
'Checkout to master branch',
|
||||
workingDirectory: _checkoutDirectory.path,
|
||||
);
|
||||
git.run(
|
||||
<String>['pull', '--ff-only'],
|
||||
'Updating $name repo',
|
||||
workingDirectory: _checkoutDirectory.path,
|
||||
);
|
||||
if (checkoutDirectory.existsSync() && !useExistingCheckout) {
|
||||
deleteDirectory();
|
||||
}
|
||||
if (!_checkoutDirectory.existsSync()) {
|
||||
stdio.printTrace(
|
||||
'Cloning $name from $upstream to ${_checkoutDirectory.path}...');
|
||||
if (!checkoutDirectory.existsSync()) {
|
||||
stdio.printTrace('Cloning $name to ${checkoutDirectory.path}...');
|
||||
git.run(
|
||||
<String>['clone', '--', upstream, _checkoutDirectory.path],
|
||||
<String>['clone', '--', upstream, checkoutDirectory.path],
|
||||
'Cloning $name repo',
|
||||
workingDirectory: parentDirectory.path,
|
||||
);
|
||||
|
@ -85,16 +72,27 @@ abstract class Repository {
|
|||
git.run(
|
||||
<String>['checkout', channel, '--'],
|
||||
'check out branch $channel locally',
|
||||
workingDirectory: _checkoutDirectory.path,
|
||||
workingDirectory: checkoutDirectory.path,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stdio.printTrace(
|
||||
'Using existing $name repo at ${checkoutDirectory.path}...',
|
||||
);
|
||||
}
|
||||
return _checkoutDirectory;
|
||||
}
|
||||
|
||||
final String revision = reverseParse('HEAD');
|
||||
stdio
|
||||
.printTrace('Repository $name is checked out at revision "$revision".');
|
||||
return _checkoutDirectory;
|
||||
void deleteDirectory() {
|
||||
if (!checkoutDirectory.existsSync()) {
|
||||
stdio.printTrace(
|
||||
'Tried to delete ${checkoutDirectory.path} but it does not exist.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
stdio.printTrace('Deleting $name from ${checkoutDirectory.path}...');
|
||||
checkoutDirectory.deleteSync(recursive: true);
|
||||
}
|
||||
|
||||
/// The URL of the remote named [remoteName].
|
||||
|
@ -126,14 +124,6 @@ abstract class Repository {
|
|||
);
|
||||
}
|
||||
|
||||
void checkout(String revision) {
|
||||
git.run(
|
||||
<String>['checkout', revision],
|
||||
'checkout $revision',
|
||||
workingDirectory: checkoutDirectory.path,
|
||||
);
|
||||
}
|
||||
|
||||
/// Obtain the version tag of the previous dev release.
|
||||
String getFullTag(String remoteName) {
|
||||
const String glob = '*.*.*-*.*.pre';
|
||||
|
@ -152,7 +142,7 @@ abstract class Repository {
|
|||
<String>['rev-parse', ref],
|
||||
'look up the commit for the ref $ref',
|
||||
workingDirectory: checkoutDirectory.path,
|
||||
).trim();
|
||||
);
|
||||
assert(revisionHash.isNotEmpty);
|
||||
return revisionHash;
|
||||
}
|
||||
|
@ -226,6 +216,24 @@ abstract class Repository {
|
|||
);
|
||||
}
|
||||
|
||||
Version flutterVersion() {
|
||||
// Build tool
|
||||
processManager.runSync(<String>[
|
||||
fileSystem.path.join(checkoutDirectory.path, 'bin', 'flutter'),
|
||||
'help',
|
||||
]);
|
||||
// Check version
|
||||
final io.ProcessResult result = processManager.runSync(<String>[
|
||||
fileSystem.path.join(checkoutDirectory.path, 'bin', 'flutter'),
|
||||
'--version',
|
||||
'--machine',
|
||||
]);
|
||||
final Map<String, dynamic> versionJson = jsonDecode(
|
||||
globals.stdoutToString(result.stdout),
|
||||
) as Map<String, dynamic>;
|
||||
return Version.fromString(versionJson['frameworkVersion'] as String);
|
||||
}
|
||||
|
||||
/// Create an empty commit and return the revision.
|
||||
@visibleForTesting
|
||||
String authorEmptyCommit([String message = 'An empty commit']) {
|
||||
|
@ -253,120 +261,20 @@ abstract class Repository {
|
|||
///
|
||||
/// This method is for testing purposes.
|
||||
@visibleForTesting
|
||||
Repository cloneRepository(String cloneName);
|
||||
}
|
||||
|
||||
class FrameworkRepository extends Repository {
|
||||
FrameworkRepository(
|
||||
this.checkouts, {
|
||||
String name = 'framework',
|
||||
String upstream = FrameworkRepository.defaultUpstream,
|
||||
bool localUpstream = false,
|
||||
bool useExistingCheckout = false,
|
||||
}) : super(
|
||||
name: name,
|
||||
upstream: upstream,
|
||||
fileSystem: checkouts.fileSystem,
|
||||
localUpstream: localUpstream,
|
||||
parentDirectory: checkouts.directory,
|
||||
platform: checkouts.platform,
|
||||
processManager: checkouts.processManager,
|
||||
stdio: checkouts.stdio,
|
||||
useExistingCheckout: useExistingCheckout,
|
||||
);
|
||||
|
||||
/// A [FrameworkRepository] with the host conductor's repo set as upstream.
|
||||
///
|
||||
/// This is useful when testing a commit that has not been merged upstream
|
||||
/// yet.
|
||||
factory FrameworkRepository.localRepoAsUpstream(
|
||||
Checkouts checkouts, {
|
||||
String name = 'framework',
|
||||
bool useExistingCheckout = false,
|
||||
@required String upstreamPath,
|
||||
}) {
|
||||
return FrameworkRepository(
|
||||
checkouts,
|
||||
name: name,
|
||||
upstream: 'file://$upstreamPath/',
|
||||
localUpstream: false,
|
||||
useExistingCheckout: useExistingCheckout,
|
||||
);
|
||||
}
|
||||
|
||||
final Checkouts checkouts;
|
||||
static const String defaultUpstream =
|
||||
'https://github.com/flutter/flutter.git';
|
||||
|
||||
String get cacheDirectory => fileSystem.path.join(
|
||||
checkoutDirectory.path,
|
||||
'bin',
|
||||
'cache',
|
||||
);
|
||||
|
||||
@override
|
||||
Repository cloneRepository(String cloneName) {
|
||||
assert(localUpstream);
|
||||
cloneName ??= 'clone-of-$name';
|
||||
return FrameworkRepository(
|
||||
checkouts,
|
||||
return Repository(
|
||||
fileSystem: fileSystem,
|
||||
name: cloneName,
|
||||
parentDirectory: parentDirectory,
|
||||
platform: platform,
|
||||
processManager: processManager,
|
||||
stdio: stdio,
|
||||
upstream: 'file://${checkoutDirectory.path}/',
|
||||
useExistingCheckout: useExistingCheckout,
|
||||
);
|
||||
}
|
||||
|
||||
void _ensureToolReady() {
|
||||
final File toolsStamp =
|
||||
fileSystem.directory(cacheDirectory).childFile('flutter_tools.stamp');
|
||||
if (toolsStamp.existsSync()) {
|
||||
final String toolsStampHash = toolsStamp.readAsStringSync().trim();
|
||||
final String repoHeadHash = reverseParse('HEAD');
|
||||
if (toolsStampHash == repoHeadHash) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
stdio.printTrace('Building tool...');
|
||||
// Build tool
|
||||
processManager.runSync(<String>[
|
||||
fileSystem.path.join(checkoutDirectory.path, 'bin', 'flutter'),
|
||||
'help',
|
||||
]);
|
||||
}
|
||||
|
||||
io.ProcessResult runFlutter(List<String> args) {
|
||||
_ensureToolReady();
|
||||
|
||||
return processManager.runSync(<String>[
|
||||
fileSystem.path.join(checkoutDirectory.path, 'bin', 'flutter'),
|
||||
...args,
|
||||
]);
|
||||
}
|
||||
|
||||
@override
|
||||
void checkout(String revision) {
|
||||
super.checkout(revision);
|
||||
// The tool will overwrite old cached artifacts, but not delete unused
|
||||
// artifacts from a previous version. Thus, delete the entire cache and
|
||||
// re-populate.
|
||||
final Directory cache = fileSystem.directory(cacheDirectory);
|
||||
if (cache.existsSync()) {
|
||||
stdio.printTrace('Deleting cache...');
|
||||
cache.deleteSync(recursive: true);
|
||||
}
|
||||
_ensureToolReady();
|
||||
}
|
||||
|
||||
Version flutterVersion() {
|
||||
// Check version
|
||||
final io.ProcessResult result =
|
||||
runFlutter(<String>['--version', '--machine']);
|
||||
final Map<String, dynamic> versionJson = jsonDecode(
|
||||
globals.stdoutToString(result.stdout),
|
||||
) as Map<String, dynamic>;
|
||||
return Version.fromString(versionJson['frameworkVersion'] as String);
|
||||
}
|
||||
}
|
||||
|
||||
/// An enum of all the repositories that the Conductor supports.
|
||||
|
@ -377,22 +285,81 @@ enum RepositoryType {
|
|||
|
||||
class Checkouts {
|
||||
Checkouts({
|
||||
@required Platform platform,
|
||||
@required this.fileSystem,
|
||||
@required this.platform,
|
||||
@required this.processManager,
|
||||
@required this.stdio,
|
||||
@required Directory parentDirectory,
|
||||
String directoryName = 'flutter_conductor_checkouts',
|
||||
}) : assert(parentDirectory != null),
|
||||
directory = parentDirectory.childDirectory(directoryName) {
|
||||
Directory parentDirectory,
|
||||
String directoryName = 'checkouts',
|
||||
}) {
|
||||
if (parentDirectory != null) {
|
||||
directory = parentDirectory.childDirectory(directoryName);
|
||||
} else {
|
||||
String filePath;
|
||||
// If a test
|
||||
if (platform.script.scheme == 'data') {
|
||||
final RegExp pattern = RegExp(
|
||||
r'(file:\/\/[^"]*[/\\]dev\/tools[/\\][^"]+\.dart)',
|
||||
multiLine: true,
|
||||
);
|
||||
final Match match =
|
||||
pattern.firstMatch(Uri.decodeFull(platform.script.path));
|
||||
if (match == null) {
|
||||
throw Exception(
|
||||
'Cannot determine path of script!\n${platform.script.path}',
|
||||
);
|
||||
}
|
||||
filePath = Uri.parse(match.group(1)).path.replaceAll(r'%20', ' ');
|
||||
} else {
|
||||
filePath = platform.script.toFilePath();
|
||||
}
|
||||
final String checkoutsDirname = fileSystem.path.normalize(
|
||||
fileSystem.path.join(
|
||||
fileSystem.path.dirname(filePath),
|
||||
'..',
|
||||
'checkouts',
|
||||
),
|
||||
);
|
||||
directory = fileSystem.directory(checkoutsDirname);
|
||||
}
|
||||
if (!directory.existsSync()) {
|
||||
directory.createSync(recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
final Directory directory;
|
||||
Directory directory;
|
||||
final FileSystem fileSystem;
|
||||
final Platform platform;
|
||||
final ProcessManager processManager;
|
||||
final Stdio stdio;
|
||||
|
||||
Repository addRepo({
|
||||
@required RepositoryType repoType,
|
||||
@required Stdio stdio,
|
||||
@required Platform platform,
|
||||
FileSystem fileSystem,
|
||||
String upstream,
|
||||
String name,
|
||||
bool localUpstream = false,
|
||||
bool useExistingCheckout = false,
|
||||
}) {
|
||||
switch (repoType) {
|
||||
case RepositoryType.framework:
|
||||
name ??= 'framework';
|
||||
upstream ??= 'https://github.com/flutter/flutter.git';
|
||||
break;
|
||||
case RepositoryType.engine:
|
||||
name ??= 'engine';
|
||||
upstream ??= 'https://github.com/flutter/engine.git';
|
||||
break;
|
||||
}
|
||||
return Repository(
|
||||
name: name,
|
||||
upstream: upstream,
|
||||
stdio: stdio,
|
||||
platform: platform,
|
||||
fileSystem: fileSystem,
|
||||
parentDirectory: directory,
|
||||
processManager: processManager,
|
||||
localUpstream: localUpstream,
|
||||
useExistingCheckout: useExistingCheckout,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,12 +14,12 @@ import './stdio.dart';
|
|||
import './version.dart';
|
||||
|
||||
/// Create a new dev release without cherry picks.
|
||||
class RollDevCommand extends Command<void> {
|
||||
RollDevCommand({
|
||||
@required this.checkouts,
|
||||
@required this.fileSystem,
|
||||
@required this.platform,
|
||||
@required this.stdio,
|
||||
class RollDev extends Command<void> {
|
||||
RollDev({
|
||||
this.fileSystem,
|
||||
this.platform,
|
||||
this.repository,
|
||||
this.stdio,
|
||||
}) {
|
||||
argParser.addOption(
|
||||
kIncrement,
|
||||
|
@ -60,10 +60,10 @@ class RollDevCommand extends Command<void> {
|
|||
argParser.addFlag(kYes, negatable: false, abbr: 'y', help: 'Skip the confirmation prompt.');
|
||||
}
|
||||
|
||||
final Checkouts checkouts;
|
||||
final FileSystem fileSystem;
|
||||
final Platform platform;
|
||||
final Stdio stdio;
|
||||
final Repository repository;
|
||||
|
||||
@override
|
||||
String get name => 'roll-dev';
|
||||
|
@ -76,7 +76,9 @@ class RollDevCommand extends Command<void> {
|
|||
void run() {
|
||||
rollDev(
|
||||
argResults: argResults,
|
||||
repository: FrameworkRepository(checkouts),
|
||||
fileSystem: fileSystem,
|
||||
platform: platform,
|
||||
repository: repository,
|
||||
stdio: stdio,
|
||||
usage: argParser.usage,
|
||||
);
|
||||
|
@ -91,7 +93,9 @@ bool rollDev({
|
|||
@required String usage,
|
||||
@required ArgResults argResults,
|
||||
@required Stdio stdio,
|
||||
@required FrameworkRepository repository,
|
||||
@required Platform platform,
|
||||
@required FileSystem fileSystem,
|
||||
@required Repository repository,
|
||||
String remoteName = 'origin',
|
||||
}) {
|
||||
final String level = argResults[kIncrement] as String;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:io' as io;
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
|
@ -31,15 +31,9 @@ class VerboseStdio extends Stdio {
|
|||
@required this.stdin,
|
||||
}) : assert(stdout != null), assert(stderr != null), assert(stdin != null);
|
||||
|
||||
factory VerboseStdio.local() => VerboseStdio(
|
||||
stdout: io.stdout,
|
||||
stderr: io.stderr,
|
||||
stdin: io.stdin,
|
||||
);
|
||||
|
||||
final io.Stdout stdout;
|
||||
final io.Stdout stderr;
|
||||
final io.Stdin stdin;
|
||||
final Stdout stdout;
|
||||
final Stdout stderr;
|
||||
final Stdin stdin;
|
||||
|
||||
@override
|
||||
void printError(String message) {
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
// Copyright 2014 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:args/command_runner.dart';
|
||||
import 'package:file/file.dart';
|
||||
import 'package:file/local.dart';
|
||||
import 'package:platform/platform.dart';
|
||||
import 'package:process/process.dart';
|
||||
|
||||
import 'package:dev_tools/codesign.dart' show CodesignCommand;
|
||||
import 'package:dev_tools/globals.dart';
|
||||
import 'package:dev_tools/repository.dart' show Checkouts;
|
||||
|
||||
import './common.dart';
|
||||
|
||||
/// Verify all binaries in the Flutter cache are expected by Conductor.
|
||||
void main() {
|
||||
test(
|
||||
'validate the expected binaries from the conductor codesign command are present in the cache',
|
||||
() async {
|
||||
const Platform platform = LocalPlatform();
|
||||
const FileSystem fileSystem = LocalFileSystem();
|
||||
const ProcessManager processManager = LocalProcessManager();
|
||||
final TestStdio stdio = TestStdio(verbose: true);
|
||||
final Checkouts checkouts = Checkouts(
|
||||
fileSystem: fileSystem,
|
||||
parentDirectory: localFlutterRoot.parent,
|
||||
platform: platform,
|
||||
processManager: processManager,
|
||||
stdio: stdio,
|
||||
);
|
||||
|
||||
final CommandRunner<void> runner = CommandRunner<void>('codesign-test', '')
|
||||
..addCommand(
|
||||
CodesignCommand(checkouts: checkouts, flutterRoot: localFlutterRoot));
|
||||
|
||||
try {
|
||||
await runner.run(<String>[
|
||||
'codesign',
|
||||
'--verify',
|
||||
// Only verify if the correct binaries are in the cache
|
||||
'--no-signatures',
|
||||
]);
|
||||
} on ConductorException catch (e) {
|
||||
print(fixItInstructions);
|
||||
fail(e.message);
|
||||
} on Exception {
|
||||
print('stdout:\n${stdio.stdout}');
|
||||
print('stderr:\n${stdio.error}');
|
||||
rethrow;
|
||||
}
|
||||
}, onPlatform: <String, dynamic>{
|
||||
'windows': const Skip('codesign command is only supported on macos'),
|
||||
'linux': const Skip('codesign command is only supported on macos'),
|
||||
});
|
||||
}
|
||||
|
||||
const String fixItInstructions = '''
|
||||
Codesign integration test failed.
|
||||
|
||||
This means that the binary files found in the Flutter cache do not match those
|
||||
expected by the conductor tool (either an expected file was not found in the
|
||||
cache or an unexpected file was found in the cache).
|
||||
|
||||
This usually happens either during an engine roll or a change to the caching
|
||||
logic in flutter_tools. If this is a valid change, then the conductor source
|
||||
code should be updated, specifically either the [binariesWithEntitlements] or
|
||||
[binariesWithoutEntitlements] lists, depending on if the file should have macOS
|
||||
entitlements applied during codesigning.
|
||||
''';
|
|
@ -1,412 +0,0 @@
|
|||
// Copyright 2014 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:args/command_runner.dart';
|
||||
import 'package:dev_tools/codesign.dart';
|
||||
import 'package:dev_tools/globals.dart';
|
||||
import 'package:dev_tools/repository.dart';
|
||||
import 'package:file/file.dart';
|
||||
import 'package:file/memory.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:platform/platform.dart';
|
||||
|
||||
import '../../../packages/flutter_tools/test/src/fake_process_manager.dart';
|
||||
import './common.dart';
|
||||
|
||||
void main() {
|
||||
group('codesign command', () {
|
||||
const String flutterRoot = '/flutter';
|
||||
const String checkoutsParentDirectory = '$flutterRoot/dev/tools/';
|
||||
const String flutterCache =
|
||||
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework/bin/cache';
|
||||
const String flutterBin =
|
||||
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework/bin/flutter';
|
||||
const String revision = 'abcd1234';
|
||||
CommandRunner<void> runner;
|
||||
Checkouts checkouts;
|
||||
MemoryFileSystem fileSystem;
|
||||
FakePlatform platform;
|
||||
TestStdio stdio;
|
||||
FakeProcessManager processManager;
|
||||
const List<String> binariesWithEntitlements = <String>[
|
||||
'$flutterCache/dart-sdk/bin/dart',
|
||||
'$flutterCache/dart-sdk/bin/dartaotruntime',
|
||||
];
|
||||
const List<String> binariesWithoutEntitlements = <String>[
|
||||
'$flutterCache/engine/darwin-x64/font-subset',
|
||||
];
|
||||
const List<String> allBinaries = <String>[
|
||||
...binariesWithEntitlements,
|
||||
...binariesWithoutEntitlements,
|
||||
];
|
||||
|
||||
void createRunner({
|
||||
String operatingSystem = 'macos',
|
||||
List<FakeCommand> commands,
|
||||
}) {
|
||||
stdio = TestStdio();
|
||||
fileSystem = MemoryFileSystem.test();
|
||||
platform = FakePlatform(operatingSystem: operatingSystem);
|
||||
processManager = FakeProcessManager.list(commands ?? <FakeCommand>[]);
|
||||
checkouts = Checkouts(
|
||||
fileSystem: fileSystem,
|
||||
parentDirectory: fileSystem.directory(checkoutsParentDirectory),
|
||||
platform: platform,
|
||||
processManager: processManager,
|
||||
stdio: stdio,
|
||||
);
|
||||
final FakeCodesignCommand command = FakeCodesignCommand(
|
||||
checkouts: checkouts,
|
||||
binariesWithEntitlements: binariesWithEntitlements,
|
||||
binariesWithoutEntitlements: binariesWithoutEntitlements,
|
||||
flutterRoot: fileSystem.directory(flutterRoot),
|
||||
);
|
||||
runner = CommandRunner<void>('codesign-test', '')
|
||||
..addCommand(command);
|
||||
}
|
||||
|
||||
test('throws exception if not run from macos', () async {
|
||||
createRunner(operatingSystem: 'linux');
|
||||
expect(
|
||||
() async => await runner.run(<String>['codesign']),
|
||||
throwsExceptionWith('Error! Expected operating system "macos"'),
|
||||
);
|
||||
});
|
||||
|
||||
test('throws exception if verify flag is not provided', () async {
|
||||
createRunner();
|
||||
expect(
|
||||
() async => await runner.run(<String>['codesign']),
|
||||
throwsExceptionWith(
|
||||
'Sorry, but codesigning is not implemented yet. Please pass the --$kVerify flag to verify signatures'),
|
||||
);
|
||||
});
|
||||
|
||||
test('succeeds if every binary is codesigned and has correct entitlements', () async {
|
||||
final List<FakeCommand> codesignCheckCommands = <FakeCommand>[];
|
||||
for (final String bin in binariesWithEntitlements) {
|
||||
codesignCheckCommands.add(
|
||||
FakeCommand(
|
||||
command: <String>['codesign', '-vvv', bin],
|
||||
),
|
||||
);
|
||||
codesignCheckCommands.add(
|
||||
FakeCommand(
|
||||
command: <String>['codesign', '--display', '--entitlements', ':-', bin],
|
||||
stdout: expectedEntitlements.join('\n'),
|
||||
),
|
||||
);
|
||||
}
|
||||
for (final String bin in binariesWithoutEntitlements) {
|
||||
codesignCheckCommands.add(
|
||||
FakeCommand(
|
||||
command: <String>['codesign', '-vvv', bin],
|
||||
),
|
||||
);
|
||||
}
|
||||
createRunner(commands: <FakeCommand>[
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'clone',
|
||||
'--',
|
||||
'file://$flutterRoot/',
|
||||
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'rev-parse',
|
||||
'HEAD',
|
||||
], stdout: revision),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'checkout',
|
||||
revision,
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
flutterBin,
|
||||
'help',
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
flutterBin,
|
||||
'help',
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
flutterBin,
|
||||
'precache',
|
||||
'--ios',
|
||||
'--macos',
|
||||
]),
|
||||
FakeCommand(
|
||||
command: const <String>[
|
||||
'find',
|
||||
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework/bin/cache',
|
||||
'-type',
|
||||
'f',
|
||||
],
|
||||
stdout: allBinaries.join('\n'),
|
||||
),
|
||||
for (String bin in allBinaries)
|
||||
FakeCommand(
|
||||
command: <String>['file', '--mime-type', '-b', bin],
|
||||
stdout: 'application/x-mach-binary',
|
||||
),
|
||||
...codesignCheckCommands,
|
||||
]);
|
||||
await runner.run(<String>['codesign', '--$kVerify', '--$kRevision', revision]);
|
||||
expect(processManager.hasRemainingExpectations, false);
|
||||
});
|
||||
|
||||
test('fails if a single binary is not codesigned', () async {
|
||||
final List<FakeCommand> codesignCheckCommands = <FakeCommand>[];
|
||||
codesignCheckCommands.add(
|
||||
const FakeCommand(
|
||||
command: <String>['codesign', '-vvv', '$flutterCache/dart-sdk/bin/dart'],
|
||||
),
|
||||
);
|
||||
codesignCheckCommands.add(
|
||||
FakeCommand(
|
||||
command: const <String>[
|
||||
'codesign',
|
||||
'--display',
|
||||
'--entitlements',
|
||||
':-',
|
||||
'$flutterCache/dart-sdk/bin/dart',
|
||||
],
|
||||
stdout: expectedEntitlements.join('\n'),
|
||||
)
|
||||
);
|
||||
// Not signed
|
||||
codesignCheckCommands.add(
|
||||
const FakeCommand(
|
||||
command: <String>['codesign', '-vvv', '$flutterCache/dart-sdk/bin/dartaotruntime'],
|
||||
exitCode: 1,
|
||||
),
|
||||
);
|
||||
codesignCheckCommands.add(
|
||||
const FakeCommand(
|
||||
command: <String>['codesign', '-vvv', '$flutterCache/engine/darwin-x64/font-subset'],
|
||||
),
|
||||
);
|
||||
|
||||
createRunner(commands: <FakeCommand>[
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'clone',
|
||||
'--',
|
||||
'file://$flutterRoot/',
|
||||
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'rev-parse',
|
||||
'HEAD',
|
||||
], stdout: revision),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'checkout',
|
||||
revision,
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
flutterBin,
|
||||
'help',
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
flutterBin,
|
||||
'help',
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
flutterBin,
|
||||
'precache',
|
||||
'--ios',
|
||||
'--macos',
|
||||
]),
|
||||
FakeCommand(
|
||||
command: const <String>[
|
||||
'find',
|
||||
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework/bin/cache',
|
||||
'-type',
|
||||
'f',
|
||||
],
|
||||
stdout: allBinaries.join('\n'),
|
||||
),
|
||||
for (String bin in allBinaries)
|
||||
FakeCommand(
|
||||
command: <String>['file', '--mime-type', '-b', bin],
|
||||
stdout: 'application/x-mach-binary',
|
||||
),
|
||||
...codesignCheckCommands,
|
||||
]);
|
||||
expect(
|
||||
() async => await runner.run(<String>['codesign', '--$kVerify', '--$kRevision', revision]),
|
||||
throwsExceptionWith('Test failed because unsigned binaries detected.'),
|
||||
);
|
||||
expect(processManager.hasRemainingExpectations, false);
|
||||
});
|
||||
|
||||
test('fails if a single binary has the wrong entitlements', () async {
|
||||
final List<FakeCommand> codesignCheckCommands = <FakeCommand>[];
|
||||
codesignCheckCommands.add(
|
||||
const FakeCommand(
|
||||
command: <String>['codesign', '-vvv', '$flutterCache/dart-sdk/bin/dart'],
|
||||
),
|
||||
);
|
||||
codesignCheckCommands.add(
|
||||
FakeCommand(
|
||||
command: const <String>['codesign', '--display', '--entitlements', ':-', '$flutterCache/dart-sdk/bin/dart'],
|
||||
stdout: expectedEntitlements.join('\n'),
|
||||
)
|
||||
);
|
||||
codesignCheckCommands.add(
|
||||
const FakeCommand(
|
||||
command: <String>['codesign', '-vvv', '$flutterCache/dart-sdk/bin/dartaotruntime'],
|
||||
),
|
||||
);
|
||||
// No entitlements
|
||||
codesignCheckCommands.add(
|
||||
const FakeCommand(
|
||||
command: <String>['codesign', '--display', '--entitlements', ':-', '$flutterCache/dart-sdk/bin/dartaotruntime'],
|
||||
)
|
||||
);
|
||||
codesignCheckCommands.add(
|
||||
const FakeCommand(
|
||||
command: <String>['codesign', '-vvv', '$flutterCache/engine/darwin-x64/font-subset'],
|
||||
),
|
||||
);
|
||||
createRunner(commands: <FakeCommand>[
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'clone',
|
||||
'--',
|
||||
'file://$flutterRoot/',
|
||||
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'rev-parse',
|
||||
'HEAD',
|
||||
], stdout: revision),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'checkout',
|
||||
revision,
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
flutterBin,
|
||||
'help',
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
flutterBin,
|
||||
'help',
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
flutterBin,
|
||||
'precache',
|
||||
'--ios',
|
||||
'--macos',
|
||||
]),
|
||||
FakeCommand(
|
||||
command: const <String>[
|
||||
'find',
|
||||
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework/bin/cache',
|
||||
'-type',
|
||||
'f',
|
||||
],
|
||||
stdout: allBinaries.join('\n'),
|
||||
),
|
||||
for (String bin in allBinaries)
|
||||
FakeCommand(
|
||||
command: <String>['file', '--mime-type', '-b', bin],
|
||||
stdout: 'application/x-mach-binary',
|
||||
),
|
||||
...codesignCheckCommands,
|
||||
]);
|
||||
expect(
|
||||
() async => await runner.run(<String>['codesign', '--$kVerify', '--$kRevision', revision]),
|
||||
throwsExceptionWith('Test failed because files found with the wrong entitlements'),
|
||||
);
|
||||
expect(processManager.hasRemainingExpectations, false);
|
||||
});
|
||||
|
||||
test('does not check signatures or entitlements if --no-$kSignatures specified', () async {
|
||||
createRunner(commands: <FakeCommand>[
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'clone',
|
||||
'--',
|
||||
'file://$flutterRoot/',
|
||||
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'rev-parse',
|
||||
'HEAD',
|
||||
], stdout: revision),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'checkout',
|
||||
revision,
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
flutterBin,
|
||||
'help',
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
flutterBin,
|
||||
'help',
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
flutterBin,
|
||||
'precache',
|
||||
'--ios',
|
||||
'--macos',
|
||||
]),
|
||||
FakeCommand(
|
||||
command: const <String>[
|
||||
'find',
|
||||
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework/bin/cache',
|
||||
'-type',
|
||||
'f',
|
||||
],
|
||||
stdout: allBinaries.join('\n'),
|
||||
),
|
||||
for (String bin in allBinaries)
|
||||
FakeCommand(
|
||||
command: <String>['file', '--mime-type', '-b', bin],
|
||||
stdout: 'application/x-mach-binary',
|
||||
),
|
||||
]);
|
||||
try {
|
||||
await runner.run(<String>[
|
||||
'codesign',
|
||||
'--$kVerify',
|
||||
'--no-$kSignatures',
|
||||
'--$kRevision',
|
||||
revision,
|
||||
]);
|
||||
} on ConductorException {
|
||||
//print(stdio.error);
|
||||
rethrow;
|
||||
}
|
||||
expect(
|
||||
processManager.hasRemainingExpectations,
|
||||
false,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class FakeCodesignCommand extends CodesignCommand {
|
||||
FakeCodesignCommand({
|
||||
@required Checkouts checkouts,
|
||||
@required this.binariesWithEntitlements,
|
||||
@required this.binariesWithoutEntitlements,
|
||||
@required Directory flutterRoot,
|
||||
}) : super(checkouts: checkouts, flutterRoot: flutterRoot);
|
||||
|
||||
@override
|
||||
final List<String> binariesWithEntitlements;
|
||||
|
||||
@override
|
||||
final List<String> binariesWithoutEntitlements;
|
||||
}
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:file/file.dart';
|
||||
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
|
||||
import 'package:test/test.dart' as test_package show TypeMatcher;
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ import 'package:file/local.dart';
|
|||
import 'package:platform/platform.dart';
|
||||
import 'package:process/process.dart';
|
||||
|
||||
import 'package:dev_tools/globals.dart';
|
||||
import 'package:dev_tools/roll_dev.dart' show rollDev;
|
||||
import 'package:dev_tools/repository.dart';
|
||||
import 'package:dev_tools/version.dart';
|
||||
|
@ -23,8 +22,8 @@ void main() {
|
|||
const String usageString = 'Usage: flutter conductor.';
|
||||
|
||||
Checkouts checkouts;
|
||||
FrameworkRepository frameworkUpstream;
|
||||
FrameworkRepository framework;
|
||||
Repository frameworkUpstream;
|
||||
Repository framework;
|
||||
|
||||
setUp(() {
|
||||
platform = const LocalPlatform();
|
||||
|
@ -33,20 +32,22 @@ void main() {
|
|||
stdio = TestStdio(verbose: true);
|
||||
checkouts = Checkouts(
|
||||
fileSystem: fileSystem,
|
||||
parentDirectory: localFlutterRoot.parent,
|
||||
platform: platform,
|
||||
processManager: processManager,
|
||||
stdio: stdio,
|
||||
);
|
||||
|
||||
frameworkUpstream = FrameworkRepository(checkouts, localUpstream: true);
|
||||
frameworkUpstream = checkouts.addRepo(
|
||||
repoType: RepositoryType.framework,
|
||||
name: 'framework-upstream',
|
||||
stdio: stdio,
|
||||
platform: platform,
|
||||
localUpstream: true,
|
||||
fileSystem: fileSystem,
|
||||
useExistingCheckout: false,
|
||||
);
|
||||
|
||||
// This repository has [frameworkUpstream] set as its push/pull remote.
|
||||
framework = FrameworkRepository(
|
||||
checkouts,
|
||||
name: 'test-framework',
|
||||
upstream: 'file://${frameworkUpstream.checkoutDirectory.path}/',
|
||||
);
|
||||
framework = frameworkUpstream.cloneRepository('test-framework');
|
||||
});
|
||||
|
||||
test('increment m', () {
|
||||
|
@ -67,6 +68,8 @@ void main() {
|
|||
usage: usageString,
|
||||
argResults: fakeArgResults,
|
||||
stdio: stdio,
|
||||
fileSystem: fileSystem,
|
||||
platform: platform,
|
||||
repository: framework,
|
||||
),
|
||||
true,
|
||||
|
@ -104,6 +107,8 @@ void main() {
|
|||
usage: usageString,
|
||||
argResults: fakeArgResults,
|
||||
stdio: stdio,
|
||||
fileSystem: fileSystem,
|
||||
platform: platform,
|
||||
repository: framework,
|
||||
),
|
||||
true,
|
||||
|
|
|
@ -24,7 +24,7 @@ void main() {
|
|||
FakeArgResults fakeArgResults;
|
||||
MemoryFileSystem fileSystem;
|
||||
TestStdio stdio;
|
||||
FrameworkRepository repo;
|
||||
Repository repo;
|
||||
Checkouts checkouts;
|
||||
FakePlatform platform;
|
||||
FakeProcessManager processManager;
|
||||
|
@ -39,9 +39,12 @@ void main() {
|
|||
parentDirectory: fileSystem.directory(checkoutsParentDirectory),
|
||||
platform: platform,
|
||||
processManager: processManager,
|
||||
);
|
||||
repo = checkouts.addRepo(
|
||||
platform: platform,
|
||||
repoType: RepositoryType.framework,
|
||||
stdio: stdio,
|
||||
);
|
||||
repo = FrameworkRepository(checkouts);
|
||||
});
|
||||
|
||||
test('returns false if level not provided', () {
|
||||
|
@ -53,6 +56,8 @@ void main() {
|
|||
expect(
|
||||
rollDev(
|
||||
argResults: fakeArgResults,
|
||||
fileSystem: fileSystem,
|
||||
platform: platform,
|
||||
repository: repo,
|
||||
stdio: stdio,
|
||||
usage: usage,
|
||||
|
@ -70,6 +75,8 @@ void main() {
|
|||
expect(
|
||||
rollDev(
|
||||
argResults: fakeArgResults,
|
||||
fileSystem: fileSystem,
|
||||
platform: platform,
|
||||
repository: repo,
|
||||
stdio: stdio,
|
||||
usage: usage,
|
||||
|
@ -85,13 +92,8 @@ void main() {
|
|||
'clone',
|
||||
'--',
|
||||
kUpstreamRemote,
|
||||
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
|
||||
'${checkoutsParentDirectory}checkouts/framework',
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'rev-parse',
|
||||
'HEAD',
|
||||
], stdout: commit),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'remote',
|
||||
|
@ -113,6 +115,8 @@ void main() {
|
|||
try {
|
||||
rollDev(
|
||||
argResults: fakeArgResults,
|
||||
fileSystem: fileSystem,
|
||||
platform: platform,
|
||||
repository: repo,
|
||||
stdio: stdio,
|
||||
usage: usage,
|
||||
|
@ -133,13 +137,8 @@ void main() {
|
|||
'clone',
|
||||
'--',
|
||||
kUpstreamRemote,
|
||||
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
|
||||
'${checkoutsParentDirectory}checkouts/framework',
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'rev-parse',
|
||||
'HEAD',
|
||||
], stdout: commit),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'remote',
|
||||
|
@ -188,6 +187,8 @@ void main() {
|
|||
rollDev(
|
||||
usage: usage,
|
||||
argResults: fakeArgResults,
|
||||
fileSystem: fileSystem,
|
||||
platform: platform,
|
||||
repository: repo,
|
||||
stdio: stdio,
|
||||
),
|
||||
|
@ -205,13 +206,8 @@ void main() {
|
|||
'clone',
|
||||
'--',
|
||||
kUpstreamRemote,
|
||||
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
|
||||
'${checkoutsParentDirectory}checkouts/framework',
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'rev-parse',
|
||||
'HEAD',
|
||||
], stdout: commit),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'remote',
|
||||
|
@ -271,6 +267,8 @@ void main() {
|
|||
() => rollDev(
|
||||
usage: usage,
|
||||
argResults: fakeArgResults,
|
||||
fileSystem: fileSystem,
|
||||
platform: platform,
|
||||
repository: repo,
|
||||
stdio: stdio,
|
||||
),
|
||||
|
@ -285,13 +283,8 @@ void main() {
|
|||
'clone',
|
||||
'--',
|
||||
kUpstreamRemote,
|
||||
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
|
||||
'${checkoutsParentDirectory}checkouts/framework',
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'rev-parse',
|
||||
'HEAD',
|
||||
], stdout: commit),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'remote',
|
||||
|
@ -340,6 +333,8 @@ void main() {
|
|||
() => rollDev(
|
||||
usage: usage,
|
||||
argResults: fakeArgResults,
|
||||
fileSystem: fileSystem,
|
||||
platform: platform,
|
||||
repository: repo,
|
||||
stdio: stdio,
|
||||
),
|
||||
|
@ -358,13 +353,8 @@ void main() {
|
|||
'clone',
|
||||
'--',
|
||||
kUpstreamRemote,
|
||||
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
|
||||
'${checkoutsParentDirectory}checkouts/framework',
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'rev-parse',
|
||||
'HEAD',
|
||||
], stdout: commit),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'remote',
|
||||
|
@ -420,6 +410,8 @@ void main() {
|
|||
expect(
|
||||
() => rollDev(
|
||||
argResults: fakeArgResults,
|
||||
fileSystem: fileSystem,
|
||||
platform: platform,
|
||||
repository: repo,
|
||||
stdio: stdio,
|
||||
usage: usage,
|
||||
|
@ -435,13 +427,8 @@ void main() {
|
|||
'clone',
|
||||
'--',
|
||||
kUpstreamRemote,
|
||||
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
|
||||
'${checkoutsParentDirectory}checkouts/framework',
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'rev-parse',
|
||||
'HEAD',
|
||||
], stdout: commit),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'remote',
|
||||
|
@ -514,6 +501,8 @@ void main() {
|
|||
rollDev(
|
||||
usage: usage,
|
||||
argResults: fakeArgResults,
|
||||
fileSystem: fileSystem,
|
||||
platform: platform,
|
||||
repository: repo,
|
||||
stdio: stdio,
|
||||
),
|
||||
|
@ -528,13 +517,8 @@ void main() {
|
|||
'clone',
|
||||
'--',
|
||||
kUpstreamRemote,
|
||||
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
|
||||
'${checkoutsParentDirectory}checkouts/framework',
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'rev-parse',
|
||||
'HEAD',
|
||||
], stdout: commit),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'remote',
|
||||
|
@ -611,6 +595,8 @@ void main() {
|
|||
rollDev(
|
||||
usage: usage,
|
||||
argResults: fakeArgResults,
|
||||
fileSystem: fileSystem,
|
||||
platform: platform,
|
||||
repository: repo,
|
||||
stdio: stdio,
|
||||
),
|
||||
|
@ -625,13 +611,8 @@ void main() {
|
|||
'clone',
|
||||
'--',
|
||||
kUpstreamRemote,
|
||||
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
|
||||
'${checkoutsParentDirectory}checkouts/framework',
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'rev-parse',
|
||||
'HEAD',
|
||||
], stdout: commit),
|
||||
const FakeCommand(command: <String>[
|
||||
'git',
|
||||
'remote',
|
||||
|
@ -703,6 +684,8 @@ void main() {
|
|||
expect(
|
||||
rollDev(
|
||||
argResults: fakeArgResults,
|
||||
fileSystem: fileSystem,
|
||||
platform: platform,
|
||||
repository: repo,
|
||||
stdio: stdio,
|
||||
usage: usage,
|
||||
|
|
Loading…
Reference in a new issue