Unverified Commit 72343ee0 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] refactor build_system and targets to be context-free (#53268)

parent 4605b51a
......@@ -95,7 +95,11 @@ class AotBuilder {
kExtraFrontEndOptions: buildInfo.extraFrontEndOptions.join(','),
if (platform == TargetPlatform.ios)
kIosArchs: iosBuildArchs.map(getNameForDarwinArch).join(' ')
}
},
artifacts: globals.artifacts,
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
);
final BuildResult result = await globals.buildSystem.build(target, environment);
status?.stop();
......
......@@ -382,7 +382,7 @@ class BufferLogger extends Logger {
_timeoutConfiguration = timeoutConfiguration,
_stopwatchFactory = stopwatchFactory;
@visibleForTesting
/// Create a [BufferLogger] with test preferences.
BufferLogger.test({
Terminal terminal,
OutputPreferences outputPreferences,
......
......@@ -8,13 +8,16 @@ import 'package:async/async.dart';
import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart';
import 'package:meta/meta.dart';
import 'package:platform/platform.dart';
import 'package:pool/pool.dart';
import 'package:process/process.dart';
import '../artifacts.dart';
import '../base/file_system.dart';
import '../base/logger.dart';
import '../base/utils.dart';
import '../cache.dart';
import '../convert.dart';
import '../globals.dart' as globals;
import 'exceptions.dart';
import 'file_hash_store.dart';
import 'source.dart';
......@@ -286,6 +289,10 @@ class Environment {
@required Directory outputDir,
@required Directory cacheDir,
@required Directory flutterRootDir,
@required FileSystem fileSystem,
@required Logger logger,
@required Artifacts artifacts,
@required ProcessManager processManager,
Directory buildDir,
Map<String, String> defines = const <String, String>{},
}) {
......@@ -314,6 +321,10 @@ class Environment {
cacheDir: cacheDir,
defines: defines,
flutterRootDir: flutterRootDir,
fileSystem: fileSystem,
logger: logger,
artifacts: artifacts,
processManager: processManager,
);
}
......@@ -327,6 +338,10 @@ class Environment {
Directory flutterRootDir,
Directory buildDir,
Map<String, String> defines = const <String, String>{},
@required FileSystem fileSystem,
@required Logger logger,
@required Artifacts artifacts,
@required ProcessManager processManager,
}) {
return Environment(
projectDir: projectDir ?? testDirectory,
......@@ -335,6 +350,10 @@ class Environment {
flutterRootDir: flutterRootDir ?? testDirectory,
buildDir: buildDir,
defines: defines,
fileSystem: fileSystem,
logger: logger,
artifacts: artifacts,
processManager: processManager,
);
}
......@@ -346,6 +365,10 @@ class Environment {
@required this.cacheDir,
@required this.defines,
@required this.flutterRootDir,
@required this.processManager,
@required this.logger,
@required this.fileSystem,
@required this.artifacts,
});
/// The [Source] value which is substituted with the path to [projectDir].
......@@ -399,6 +422,14 @@ class Environment {
/// The root build directory shared by all builds.
final Directory rootBuildDir;
final ProcessManager processManager;
final Logger logger;
final Artifacts artifacts;
final FileSystem fileSystem;
}
/// The result information from the build system.
......@@ -422,7 +453,17 @@ class BuildResult {
/// The build system is responsible for invoking and ordering [Target]s.
class BuildSystem {
const BuildSystem();
const BuildSystem({
@required FileSystem fileSystem,
@required Platform platform,
@required Logger logger,
}) : _fileSystem = fileSystem,
_platform = platform,
_logger = logger;
final FileSystem _fileSystem;
final Platform _platform;
final Logger _logger;
/// Build `target` and all of its dependencies.
Future<BuildResult> build(
......@@ -436,15 +477,22 @@ class BuildSystem {
// Load file hash store from previous builds.
final FileHashStore fileCache = FileHashStore(
environment: environment,
fileSystem: globals.fs,
logger: globals.logger,
fileSystem: _fileSystem,
logger: _logger,
)..initialize();
// Perform sanity checks on build.
checkCycles(target);
final Node node = target._toNode(environment);
final _BuildInstance buildInstance = _BuildInstance(environment, fileCache, buildSystemConfig);
final _BuildInstance buildInstance = _BuildInstance(
environment: environment,
fileCache: fileCache,
buildSystemConfig: buildSystemConfig,
logger: _logger,
fileSystem: _fileSystem,
platform: _platform,
);
bool passed = true;
try {
passed = await buildInstance.invokeTarget(node);
......@@ -486,9 +534,18 @@ class BuildSystem {
/// An active instance of a build.
class _BuildInstance {
_BuildInstance(this.environment, this.fileCache, this.buildSystemConfig)
: resourcePool = Pool(buildSystemConfig.resourcePoolSize ?? globals.platform?.numberOfProcessors ?? 1);
_BuildInstance({
this.environment,
this.fileCache,
this.buildSystemConfig,
this.logger,
this.fileSystem,
Platform platform,
})
: resourcePool = Pool(buildSystemConfig.resourcePoolSize ?? platform?.numberOfProcessors ?? 1);
final Logger logger;
final FileSystem fileSystem;
final BuildSystemConfig buildSystemConfig;
final Pool resourcePool;
final Map<String, AsyncMemoizer<bool>> pending = <String, AsyncMemoizer<bool>>{};
......@@ -545,17 +602,17 @@ class _BuildInstance {
// If we're missing a depfile, wait until after evaluating the target to
// compute changes.
final bool canSkip = !node.missingDepfile &&
await node.computeChanges(environment, fileCache);
await node.computeChanges(environment, fileCache, fileSystem, logger);
if (canSkip) {
skipped = true;
globals.printTrace('Skipping target: ${node.target.name}');
logger.printTrace('Skipping target: ${node.target.name}');
updateGraph();
return passed;
}
globals.printTrace('${node.target.name}: Starting due to ${node.invalidatedReasons}');
logger.printTrace('${node.target.name}: Starting due to ${node.invalidatedReasons}');
await node.target.build(environment);
globals.printTrace('${node.target.name}: Complete');
logger.printTrace('${node.target.name}: Complete');
node.inputs
..clear()
......@@ -581,7 +638,7 @@ class _BuildInstance {
if (outputFiles.containsKey(previousOutput)) {
continue;
}
final File previousFile = globals.fs.file(previousOutput);
final File previousFile = fileSystem.file(previousOutput);
if (previousFile.existsSync()) {
previousFile.deleteSync();
}
......@@ -771,6 +828,8 @@ class Node {
Future<bool> computeChanges(
Environment environment,
FileHashStore fileHashStore,
FileSystem fileSystem,
Logger logger,
) async {
final Set<String> currentOutputPaths = <String>{
for (final File file in outputs) file.path,
......@@ -808,7 +867,7 @@ class Node {
// if this isn't a current output file there is no reason to compute the hash.
continue;
}
final File file = globals.fs.file(previousOutput);
final File file = fileSystem.file(previousOutput);
if (!file.existsSync()) {
invalidatedReasons.add(InvalidatedReason.outputMissing);
_dirty = true;
......@@ -833,7 +892,7 @@ class Node {
if (missingInputs.isNotEmpty) {
_dirty = true;
final String missingMessage = missingInputs.map((File file) => file.path).join(', ');
globals.printTrace('invalidated build due to missing files: $missingMessage');
logger.printTrace('invalidated build due to missing files: $missingMessage');
invalidatedReasons.add(InvalidatedReason.inputMissing);
}
......
......@@ -5,7 +5,6 @@
import '../artifacts.dart';
import '../base/file_system.dart';
import '../build_info.dart';
import '../globals.dart' as globals;
import 'build_system.dart';
import 'exceptions.dart';
......@@ -24,7 +23,7 @@ abstract class ResolvedFiles {
/// Collects sources for a [Target] into a single list of [FileSystemEntities].
class SourceVisitor implements ResolvedFiles {
/// Create a new [SourceVisitor] from an [Environment].
SourceVisitor(this.environment, [this.inputs = true]);
SourceVisitor(this.environment, [ this.inputs = true ]);
/// The current environment.
final Environment environment;
......@@ -56,7 +55,7 @@ class SourceVisitor implements ResolvedFiles {
final String contents = depfile.readAsStringSync();
final List<String> colonSeparated = contents.split(': ');
if (colonSeparated.length != 2) {
globals.printError('Invalid depfile: ${depfile.path}');
environment.logger.printError('Invalid depfile: ${depfile.path}');
return;
}
if (inputs) {
......@@ -78,7 +77,7 @@ class SourceVisitor implements ResolvedFiles {
.map<String>((String path) => path.replaceAllMapped(_escapeExpr, (Match match) => match.group(1)).trim())
.where((String path) => path.isNotEmpty)
.toSet()
.map((String path) => globals.fs.file(path));
.map(environment.fileSystem.file);
}
/// Visit a [Source] which contains a file URL.
......@@ -101,35 +100,36 @@ class SourceVisitor implements ResolvedFiles {
switch (rawParts.first) {
case Environment.kProjectDirectory:
segments.addAll(
globals.fs.path.split(environment.projectDir.resolveSymbolicLinksSync()));
environment.fileSystem.path.split(environment.projectDir.resolveSymbolicLinksSync()));
break;
case Environment.kBuildDirectory:
segments.addAll(globals.fs.path.split(
environment.buildDir.resolveSymbolicLinksSync()));
segments.addAll(environment.fileSystem.path.split(
environment.buildDir.resolveSymbolicLinksSync()));
break;
case Environment.kCacheDirectory:
segments.addAll(
globals.fs.path.split(environment.cacheDir.resolveSymbolicLinksSync()));
environment.fileSystem.path.split(environment.cacheDir.resolveSymbolicLinksSync()));
break;
case Environment.kFlutterRootDirectory:
// flutter root will not contain a symbolic link.
segments.addAll(
globals.fs.path.split(environment.flutterRootDir.absolute.path));
environment.fileSystem.path.split(environment.flutterRootDir.absolute.path));
break;
case Environment.kOutputDirectory:
segments.addAll(
globals.fs.path.split(environment.outputDir.resolveSymbolicLinksSync()));
environment.fileSystem.path.split(environment.outputDir.resolveSymbolicLinksSync()));
break;
default:
throw InvalidPatternException(pattern);
}
rawParts.skip(1).forEach(segments.add);
final String filePath = globals.fs.path.joinAll(segments);
final String filePath = environment.fileSystem.path.joinAll(segments);
if (!hasWildcard) {
if (optional && !globals.fs.isFileSync(filePath)) {
if (optional && !environment.fileSystem.isFileSync(filePath)) {
return;
}
sources.add(globals.fs.file(globals.fs.path.normalize(filePath)));
sources.add(environment.fileSystem.file(
environment.fileSystem.path.normalize(filePath)));
return;
}
// Perform a simple match by splitting the wildcard containing file one
......@@ -143,21 +143,21 @@ class SourceVisitor implements ResolvedFiles {
if (wildcardSegments.length > 2) {
throw InvalidPatternException(pattern);
}
if (!globals.fs.directory(filePath).existsSync()) {
if (!environment.fileSystem.directory(filePath).existsSync()) {
throw Exception('$filePath does not exist!');
}
for (final FileSystemEntity entity in globals.fs.directory(filePath).listSync()) {
final String filename = globals.fs.path.basename(entity.path);
for (final FileSystemEntity entity in environment.fileSystem.directory(filePath).listSync()) {
final String filename = environment.fileSystem.path.basename(entity.path);
if (wildcardSegments.isEmpty) {
sources.add(globals.fs.file(entity.absolute));
sources.add(environment.fileSystem.file(entity.absolute));
} else if (wildcardSegments.length == 1) {
if (filename.startsWith(wildcardSegments[0]) ||
filename.endsWith(wildcardSegments[0])) {
sources.add(globals.fs.file(entity.absolute));
sources.add(environment.fileSystem.file(entity.absolute));
}
} else if (filename.startsWith(wildcardSegments[0])) {
if (filename.substring(wildcardSegments[0].length).endsWith(wildcardSegments[1])) {
sources.add(globals.fs.file(entity.absolute));
sources.add(environment.fileSystem.file(entity.absolute));
}
}
}
......@@ -167,15 +167,16 @@ class SourceVisitor implements ResolvedFiles {
///
/// If the [Artifact] points to a directory then all child files are included.
void visitArtifact(Artifact artifact, TargetPlatform platform, BuildMode mode) {
final String path = globals.artifacts.getArtifactPath(artifact, platform: platform, mode: mode);
if (globals.fs.isDirectorySync(path)) {
final String path = environment.artifacts
.getArtifactPath(artifact, platform: platform, mode: mode);
if (environment.fileSystem.isDirectorySync(path)) {
sources.addAll(<File>[
for (FileSystemEntity entity in globals.fs.directory(path).listSync(recursive: true))
for (FileSystemEntity entity in environment.fileSystem.directory(path).listSync(recursive: true))
if (entity is File)
entity,
]);
} else {
sources.add(globals.fs.file(path));
sources.add(environment.fileSystem.file(path));
}
}
}
......
......@@ -5,7 +5,6 @@
import '../../artifacts.dart';
import '../../base/file_system.dart';
import '../../build_info.dart';
import '../../globals.dart' as globals;
import '../build_system.dart';
/// Copies the Windows desktop embedding files to the copy directory.
......@@ -40,21 +39,24 @@ class UnpackWindows extends Target {
@override
Future<void> build(Environment environment) async {
// This path needs to match the prefix in the rule below.
final String basePath = globals.artifacts.getArtifactPath(Artifact.windowsDesktopPath);
for (final File input in globals.fs.directory(basePath)
final String basePath = environment.artifacts
.getArtifactPath(Artifact.windowsDesktopPath);
for (final File input in environment.fileSystem.directory(basePath)
.listSync(recursive: true)
.whereType<File>()) {
final String outputPath = globals.fs.path.join(
final String outputPath = environment.fileSystem.path.join(
environment.projectDir.path,
'windows',
'flutter',
globals.fs.path.relative(input.path, from: basePath),
environment.fileSystem.path
.relative(input.path, from: basePath),
);
final File destinationFile = globals.fs.file(outputPath);
final File destinationFile = environment.fileSystem.file(outputPath);
if (!destinationFile.parent.existsSync()) {
destinationFile.parent.createSync(recursive: true);
}
globals.fs.file(input).copySync(destinationFile.path);
environment.fileSystem
.file(input).copySync(destinationFile.path);
}
}
}
......@@ -132,6 +132,10 @@ Future<void> buildWithAssemble({
if (dartDefines != null && dartDefines.isNotEmpty)
kDartDefines: jsonEncode(dartDefines),
},
artifacts: globals.artifacts,
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
);
final Target target = buildMode == BuildMode.debug
? const CopyFlutterBundle()
......
......@@ -151,6 +151,10 @@ class AssembleCommand extends FlutterCommand {
defines: _parseDefines(stringsArg('define')),
cacheDir: globals.cache.getRoot(),
flutterRootDir: globals.fs.directory(Cache.flutterRoot),
artifacts: globals.artifacts,
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
);
return result;
}
......
......@@ -89,7 +89,11 @@ Future<T> runInContext<T>(
platform: globals.platform,
),
AssetBundleFactory: () => AssetBundleFactory.defaultInstance,
BuildSystem: () => const BuildSystem(),
BuildSystem: () => BuildSystem(
fileSystem: globals.fs,
logger: globals.logger,
platform: globals.platform,
),
Cache: () => Cache(
fileSystem: globals.fs,
logger: globals.logger,
......
......@@ -53,6 +53,10 @@ Future<void> buildWeb(
kCspMode: csp.toString(),
kIconTreeShakerFlag: buildInfo.treeShakeIcons.toString(),
},
artifacts: globals.artifacts,
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
));
if (!result.success) {
for (final ExceptionMeasurement measurement in result.exceptions.values) {
......
......@@ -5,6 +5,7 @@
import 'dart:typed_data';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/terminal.dart';
......@@ -14,6 +15,7 @@ import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import '../../src/common.dart';
import '../../src/fake_process_manager.dart';
void main() {
Environment environment;
......@@ -29,6 +31,10 @@ void main() {
fileSystem.directory('build').createSync();
environment = Environment.test(
fileSystem.currentDirectory,
artifacts: MockArtifacts(),
processManager: FakeProcessManager.any(),
logger: logger,
fileSystem: fileSystem,
);
environment.buildDir.createSync(recursive: true);
});
......@@ -168,4 +174,6 @@ class FakeForwardingFileSystem extends ForwardingFileSystem {
@override
File file(dynamic path) => files[path] ?? super.file(path);
}
class MockFile extends Mock implements File {}
class MockArtifacts extends Mock implements Artifacts {}
......@@ -14,6 +14,7 @@ import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/testbed.dart';
void main() {
......@@ -32,6 +33,10 @@ void main() {
environment = Environment.test(
globals.fs.currentDirectory,
outputDir: outputs,
artifacts: globals.artifacts, // using real artifacts
processManager: FakeProcessManager.any(),
fileSystem: globals.fs,
logger: globals.logger,
);
visitor = SourceVisitor(environment);
environment.buildDir.createSync(recursive: true);
......@@ -212,3 +217,4 @@ void main() {
}
class MockPlatform extends Mock implements Platform {}
class MockArtifacts extends Mock implements Artifacts {}
......@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/build_system/build_system.dart';
......@@ -9,6 +10,7 @@ import 'package:flutter_tools/src/build_system/targets/android.dart';
import 'package:flutter_tools/src/build_system/targets/dart.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/cache.dart';
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import '../../../src/common.dart';
......@@ -32,7 +34,11 @@ void main() {
outputDir: globals.fs.directory('out')..createSync(),
defines: <String, String>{
kBuildMode: 'debug',
}
},
processManager: fakeProcessManager,
artifacts: MockArtifacts(),
fileSystem: globals.fs,
logger: globals.logger,
);
environment.buildDir.createSync(recursive: true);
......@@ -45,7 +51,6 @@ void main() {
hostDirectory.childFile('vm_isolate_snapshot.bin').createSync();
hostDirectory.childFile('isolate_snapshot.bin').createSync();
await const DebugAndroidApplication().build(environment);
expect(globals.fs.file(globals.fs.path.join('out', 'flutter_assets', 'isolate_snapshot_data')).existsSync(), true);
......@@ -59,7 +64,11 @@ void main() {
outputDir: globals.fs.directory('out')..createSync(),
defines: <String, String>{
kBuildMode: 'profile',
}
},
artifacts: MockArtifacts(),
processManager: fakeProcessManager,
fileSystem: globals.fs,
logger: globals.logger,
);
environment.buildDir.createSync(recursive: true);
......@@ -78,7 +87,11 @@ void main() {
outputDir: globals.fs.directory('out')..createSync(),
defines: <String, String>{
kBuildMode: 'release',
}
},
artifacts: MockArtifacts(),
processManager: fakeProcessManager,
fileSystem: globals.fs,
logger: globals.logger,
);
environment.buildDir.createSync(recursive: true);
......@@ -92,15 +105,19 @@ void main() {
});
testbed.test('AndroidAot can build provided target platform', () async {
fakeProcessManager = FakeProcessManager.list(<FakeCommand>[]);
final Environment environment = Environment.test(
globals.fs.currentDirectory,
outputDir: globals.fs.directory('out')..createSync(),
defines: <String, String>{
kBuildMode: 'release',
}
},
artifacts: MockArtifacts(),
processManager: FakeProcessManager.list(<FakeCommand>[]),
fileSystem: globals.fs,
logger: globals.logger,
);
fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
FakeCommand(command: <String>[
fakeProcessManager.addCommand(FakeCommand(command: <String>[
globals.fs.path.absolute(globals.fs.path.join('android-arm64-release', 'linux-x64', 'gen_snapshot')),
'--deterministic',
'--snapshot_kind=app-aot-elf',
......@@ -111,18 +128,21 @@ void main() {
environment.buildDir.childFile('app.dill').path,
],
)
]);
);
environment.buildDir.createSync(recursive: true);
environment.buildDir.childFile('app.dill').createSync();
environment.projectDir.childFile('.packages').writeAsStringSync('\n');
const AndroidAot androidAot = AndroidAot(TargetPlatform.android_arm64, BuildMode.release);
await androidAot.build(environment);
expect(fakeProcessManager.hasRemainingExpectations, false);
}, overrides: <Type, Generator>{
ProcessManager: () => fakeProcessManager,
});
testbed.test('kExtraGenSnapshotOptions passes values to gen_snapshot', () async {
fakeProcessManager = FakeProcessManager.list(<FakeCommand>[]);
final Environment environment = Environment.test(
globals.fs.currentDirectory,
outputDir: globals.fs.directory('out')..createSync(),
......@@ -130,9 +150,13 @@ void main() {
kBuildMode: 'release',
kExtraGenSnapshotOptions: 'foo,bar,baz=2',
kTargetPlatform: 'android-arm',
}
},
processManager: fakeProcessManager,
artifacts: MockArtifacts(),
fileSystem: globals.fs,
logger: globals.logger,
);
fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
fakeProcessManager.addCommand(
FakeCommand(command: <String>[
globals.fs.path.absolute(globals.fs.path.join('android-arm64-release', 'linux-x64', 'gen_snapshot')),
'--deterministic',
......@@ -145,8 +169,7 @@ void main() {
'--no-causal-async-stacks',
'--lazy-async-stacks',
environment.buildDir.childFile('app.dill').path
])
]);
]));
environment.buildDir.createSync(recursive: true);
environment.buildDir.childFile('app.dill').createSync();
environment.projectDir.childFile('.packages').writeAsStringSync('\n');
......@@ -163,7 +186,11 @@ void main() {
outputDir: globals.fs.directory('out')..createSync(),
defines: <String, String>{
kBuildMode: 'release',
}
},
processManager: fakeProcessManager,
artifacts: MockArtifacts(),
fileSystem: globals.fs,
logger: globals.logger,
);
environment.buildDir.createSync(recursive: true);
const AndroidAot androidAot = AndroidAot(TargetPlatform.android_arm64, BuildMode.release);
......@@ -181,3 +208,5 @@ void main() {
.childFile('app.so').existsSync(), true);
});
}
class MockArtifacts extends Mock implements Artifacts {}
\ No newline at end of file
......@@ -4,10 +4,13 @@
import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/build_system/depfile.dart';
import 'package:flutter_tools/src/build_system/targets/assets.dart';
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import '../../../src/common.dart';
......@@ -23,6 +26,10 @@ void main() {
fileSystem = MemoryFileSystem.test();
environment = Environment.test(
fileSystem.currentDirectory,
processManager: FakeProcessManager.any(),
artifacts: MockArtifacts(),
fileSystem: fileSystem,
logger: BufferLogger.test(),
);
fileSystem.file(environment.buildDir.childFile('app.dill')).createSync(recursive: true);
fileSystem.file('packages/flutter_tools/lib/src/build_system/targets/assets.dart')
......@@ -91,3 +98,5 @@ flutter:
Platform: () => platform,
});
}
class MockArtifacts extends Mock implements Artifacts {}
......@@ -43,6 +43,10 @@ void main() {
kBuildMode: getNameForBuildMode(BuildMode.profile),
kTargetPlatform: getNameForTargetPlatform(TargetPlatform.android_arm),
},
artifacts: artifacts,
processManager: processManager,
fileSystem: globals.fs,
logger: globals.logger,
);
androidEnvironment.buildDir.createSync(recursive: true);
iosEnvironment = Environment.test(
......@@ -51,6 +55,10 @@ void main() {
kBuildMode: getNameForBuildMode(BuildMode.profile),
kTargetPlatform: getNameForTargetPlatform(TargetPlatform.ios),
},
artifacts: artifacts,
processManager: processManager,
fileSystem: globals.fs,
logger: globals.logger,
);
iosEnvironment.buildDir.createSync(recursive: true);
artifacts = CachedArtifacts(
......@@ -261,6 +269,10 @@ void main() {
kBuildMode: getNameForBuildMode(BuildMode.debug),
kTargetPlatform: getNameForTargetPlatform(TargetPlatform.android_arm),
},
processManager: processManager,
artifacts: artifacts,
fileSystem: globals.fs,
logger: globals.logger,
);
final String build = testEnvironment.buildDir.path;
processManager = FakeProcessManager.list(<FakeCommand>[
......
......@@ -113,6 +113,10 @@ void main() {
return Environment.test(
fs.directory('/icon_test')..createSync(recursive: true),
defines: defines,
artifacts: mockArtifacts,
processManager: FakeProcessManager.any(),
fileSystem: fs,
logger: BufferLogger.test(),
);
}
......
......@@ -39,9 +39,16 @@ void main() {
setUp(() {
testbed = Testbed(setup: () {
environment = Environment.test(globals.fs.currentDirectory, defines: <String, String>{
kTargetPlatform: 'ios',
});
environment = Environment.test(
globals.fs.currentDirectory,
defines: <String, String>{
kTargetPlatform: 'ios',
},
processManager: processManager,
artifacts: MockArtifacts(),
logger: globals.logger,
fileSystem: globals.fs,
);
});
});
......
......@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_tools/src/artifacts.dart';
import 'package:platform/platform.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/build_system/build_system.dart';
......@@ -12,11 +13,12 @@ import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:mockito/mockito.dart';
import '../../../src/common.dart';
import '../../../src/context.dart';
import '../../../src/testbed.dart';
void main() {
Testbed testbed;
const BuildSystem buildSystem = BuildSystem();
BuildSystem buildSystem;
Environment environment;
MockPlatform mockPlatform;
......@@ -33,11 +35,20 @@ void main() {
when(mockPlatform.environment).thenReturn(Map<String, String>.unmodifiable(<String, String>{}));
testbed = Testbed(setup: () {
Cache.flutterRoot = '';
buildSystem = BuildSystem(
logger: globals.logger,
platform: globals.platform,
fileSystem: globals.fs,
);
environment = Environment.test(
globals.fs.currentDirectory,
defines: <String, String>{
kBuildMode: 'debug',
}
},
artifacts: MockArtifacts(),
processManager: FakeProcessManager.any(),
fileSystem: globals.fs,
logger: globals.logger,
);
globals.fs.file('bin/cache/artifacts/engine/linux-x64/unrelated-stuff').createSync(recursive: true);
globals.fs.file('bin/cache/artifacts/engine/linux-x64/libflutter_linux_glfw.so').createSync(recursive: true);
......@@ -105,3 +116,4 @@ void main() {
}
class MockPlatform extends Mock implements Platform {}
class MockArtifacts extends Mock implements Artifacts {}
......@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/build.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
......@@ -16,6 +17,7 @@ import 'package:process/process.dart';
import 'package:platform/platform.dart';
import '../../../src/common.dart';
import '../../../src/fake_process_manager.dart';
import '../../../src/testbed.dart';
const String _kInputPrefix = 'bin/cache/artifacts/engine/darwin-x64/FlutterMacOS.framework';
......@@ -70,8 +72,12 @@ void main() {
defines: <String, String>{
kBuildMode: 'debug',
kTargetPlatform: 'darwin-x64',
},
);
},
artifacts: MockArtifacts(),
processManager: FakeProcessManager.any(),
logger: globals.logger,
fileSystem: globals.fs,
);
}, overrides: <Type, Generator>{
ProcessManager: () => MockProcessManager(),
Platform: () => mockPlatform,
......@@ -195,6 +201,7 @@ class MockPlatform extends Mock implements Platform {}
class MockProcessManager extends Mock implements ProcessManager {}
class MockGenSnapshot extends Mock implements GenSnapshot {}
class MockXcode extends Mock implements Xcode {}
class MockArtifacts extends Mock implements Artifacts {}
class FakeProcessResult implements ProcessResult {
@override
int exitCode;
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'package:file_testing/file_testing.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/build_system/build_system.dart';
......@@ -55,7 +56,11 @@ void main() {
outputDir: globals.fs.currentDirectory.childDirectory('bar'),
defines: <String, String>{
kTargetFile: globals.fs.path.join('foo', 'lib', 'main.dart'),
}
},
artifacts: MockArtifacts(),
processManager: FakeProcessManager.any(),
logger: globals.logger,
fileSystem: globals.fs,
);
depfileService = DepfileService(
fileSystem: globals.fs,
......@@ -460,3 +465,4 @@ void main() {
}
class MockProcessManager extends Mock implements ProcessManager {}
class MockArtifacts extends Mock implements Artifacts {}
......@@ -3,102 +3,77 @@
// found in the LICENSE file.
import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/build_system/targets/windows.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import '../../../src/common.dart';
import '../../../src/fake_process_manager.dart';
import '../../../src/testbed.dart';
final Platform kWindowsPlatform = FakePlatform(
operatingSystem: 'windows',
environment: <String, String>{},
);
const List<String> kRequiredFiles = <String>[
r'C:\bin\cache\artifacts\engine\windows-x64\flutter_export.h',
r'C:\bin\cache\artifacts\engine\windows-x64\flutter_messenger.h',
r'C:\bin\cache\artifacts\engine\windows-x64\flutter_windows.dll',
r'C:\bin\cache\artifacts\engine\windows-x64\flutter_windows.dll.exp',
r'C:\bin\cache\artifacts\engine\windows-x64\flutter_windows.dll.lib',
r'C:\bin\cache\artifacts\engine\windows-x64\flutter_windows.dll.pdb',
r'C:\bin\cache\artifacts\engine\windows-x64\lutter_export.h',
r'C:\bin\cache\artifacts\engine\windows-x64\flutter_messenger.h',
r'C:\bin\cache\artifacts\engine\windows-x64\flutter_plugin_registrar.h',
r'C:\bin\cache\artifacts\engine\windows-x64\flutter_windows.h',
r'C:\bin\cache\artifacts\engine\windows-x64\icudtl.dat',
r'C:\bin\cache\artifacts\engine\windows-x64\cpp_client_wrapper\foo',
r'C:\packages\flutter_tools\lib\src\build_system\targets\windows.dart',
];
void main() {
Testbed testbed;
const BuildSystem buildSystem = BuildSystem();
Environment environment;
Platform platform;
setUpAll(() {
Cache.disableLocking();
Cache.flutterRoot = '';
});
FileSystem fileSystem;
setUp(() {
platform = MockPlatform();
when(platform.isWindows).thenReturn(true);
when(platform.isMacOS).thenReturn(false);
when(platform.isLinux).thenReturn(false);
when(platform.pathSeparator).thenReturn(r'\');
testbed = Testbed(setup: () {
environment = Environment.test(
globals.fs.currentDirectory,
);
globals.fs.file(r'C:\bin\cache\artifacts\engine\windows-x64\flutter_export.h').createSync(recursive: true);
globals.fs.file(r'C:\bin\cache\artifacts\engine\windows-x64\flutter_messenger.h').createSync();
globals.fs.file(r'C:\bin\cache\artifacts\engine\windows-x64\flutter_windows.dll').createSync();
globals.fs.file(r'C:\bin\cache\artifacts\engine\windows-x64\flutter_windows.dll.exp').createSync();
globals.fs.file(r'C:\bin\cache\artifacts\engine\windows-x64\flutter_windows.dll.lib').createSync();
globals.fs.file(r'C:\bin\cache\artifacts\engine\windows-x64\flutter_windows.dll.pdb').createSync();
globals.fs.file(r'C:\bin\cache\artifacts\engine\windows-x64\lutter_export.h').createSync();
globals.fs.file(r'C:\bin\cache\artifacts\engine\windows-x64\flutter_messenger.h').createSync();
globals.fs.file(r'C:\bin\cache\artifacts\engine\windows-x64\flutter_plugin_registrar.h').createSync();
globals.fs.file(r'C:\bin\cache\artifacts\engine\windows-x64\flutter_windows.h').createSync();
globals.fs.file(r'C:\bin\cache\artifacts\engine\windows-x64\icudtl.dat').createSync();
globals.fs.file(r'C:\bin\cache\artifacts\engine\windows-x64\cpp_client_wrapper\foo').createSync(recursive: true);
globals.fs.file(r'C:\packages\flutter_tools\lib\src\build_system\targets\windows.dart').createSync(recursive: true);
globals.fs.directory('windows').createSync();
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(style: FileSystemStyle.windows),
ProcessManager: () => FakeProcessManager.any(),
Platform: () => platform,
});
final MockArtifacts artifacts = MockArtifacts();
when(artifacts.getArtifactPath(Artifact.windowsDesktopPath))
.thenReturn(r'C:\bin\cache\artifacts\engine\windows-x64\');
fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows);
environment = Environment.test(
fileSystem.currentDirectory,
artifacts: artifacts,
processManager: FakeProcessManager.any(),
fileSystem: fileSystem,
logger: BufferLogger.test(),
);
for (final String path in kRequiredFiles) {
fileSystem.file(path).createSync(recursive: true);
}
fileSystem.directory('windows').createSync();
});
test('Copies files to correct cache directory', () => testbed.run(() async {
await buildSystem.build(const UnpackWindows(), environment);
expect(globals.fs.file(r'C:\windows\flutter\flutter_export.h').existsSync(), true);
expect(globals.fs.file(r'C:\windows\flutter\flutter_messenger.h').existsSync(), true);
expect(globals.fs.file(r'C:\windows\flutter\flutter_windows.dll').existsSync(), true);
expect(globals.fs.file(r'C:\windows\flutter\flutter_windows.dll.exp').existsSync(), true);
expect(globals.fs.file(r'C:\windows\flutter\flutter_windows.dll.lib').existsSync(), true);
expect(globals.fs.file(r'C:\windows\flutter\flutter_windows.dll.pdb').existsSync(), true);
expect(globals.fs.file(r'C:\windows\flutter\flutter_export.h').existsSync(), true);
expect(globals.fs.file(r'C:\windows\flutter\flutter_messenger.h').existsSync(), true);
expect(globals.fs.file(r'C:\windows\flutter\flutter_plugin_registrar.h').existsSync(), true);
expect(globals.fs.file(r'C:\windows\flutter\flutter_windows.h').existsSync(), true);
expect(globals.fs.file(r'C:\windows\flutter\icudtl.dat').existsSync(), true);
expect(globals.fs.file(r'C:\windows\flutter\cpp_client_wrapper\foo').existsSync(), true);
}));
test('Does not re-copy files unecessarily', () => testbed.run(() async {
await buildSystem.build(const UnpackWindows(), environment);
// Set a date in the far distant past to deal with the limited resolution
// of the windows filesystem.
final DateTime theDistantPast = DateTime(1991, 8, 23);
globals.fs.file(r'C:\windows\flutter\flutter_export.h').setLastModifiedSync(theDistantPast);
await buildSystem.build(const UnpackWindows(), environment);
expect(globals.fs.file(r'C:\windows\flutter\flutter_export.h').statSync().modified, equals(theDistantPast));
}));
testWithoutContext('UnpackWindows copies files to the correct cache directory', () async {
await const UnpackWindows().build(environment);
test('Detects changes in input cache files', () => testbed.run(() async {
await buildSystem.build(const UnpackWindows(), environment);
// Set a date in the far distant past to deal with the limited resolution
// of the windows filesystem.
final DateTime theDistantPast = DateTime(1991, 8, 23);
globals.fs.file(r'C:\windows\flutter\flutter_export.h').setLastModifiedSync(theDistantPast);
final DateTime modified = globals.fs.file(r'C:\windows\flutter\flutter_export.h').statSync().modified;
globals.fs.file(r'C:\bin\cache\artifacts\engine\windows-x64\flutter_export.h').writeAsStringSync('asd'); // modify cache.
await buildSystem.build(const UnpackWindows(), environment);
expect(globals.fs.file(r'C:\windows\flutter\flutter_export.h').statSync().modified, isNot(modified));
}));
expect(fileSystem.file(r'C:\windows\flutter\flutter_export.h'), exists);
expect(fileSystem.file(r'C:\windows\flutter\flutter_messenger.h'), exists);
expect(fileSystem.file(r'C:\windows\flutter\flutter_windows.dll'), exists);
expect(fileSystem.file(r'C:\windows\flutter\flutter_windows.dll.exp'), exists);
expect(fileSystem.file(r'C:\windows\flutter\flutter_windows.dll.lib'), exists);
expect(fileSystem.file(r'C:\windows\flutter\flutter_windows.dll.pdb'), exists);
expect(fileSystem.file(r'C:\windows\flutter\flutter_export.h'), exists);
expect(fileSystem.file(r'C:\windows\flutter\flutter_messenger.h'), exists);
expect(fileSystem.file(r'C:\windows\flutter\flutter_plugin_registrar.h'), exists);
expect(fileSystem.file(r'C:\windows\flutter\flutter_windows.h'), exists);
expect(fileSystem.file(r'C:\windows\flutter\icudtl.dat'), exists);
expect(fileSystem.file(r'C:\windows\flutter\cpp_client_wrapper\foo'), exists);
});
}
class MockPlatform extends Mock implements Platform {}
class MockArtifacts extends Mock implements Artifacts {}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment