Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to delay file system writes #3418

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions _test_common/lib/in_memory_writer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,7 @@ class InMemoryRunnerAssetWriter extends InMemoryAssetWriter
FakeWatcher.notifyWatchers(
WatchEvent(ChangeType.REMOVE, p.absolute(id.package, id.path)));
}

@override
void onBuildComplete() {}
}
3 changes: 3 additions & 0 deletions _test_common/lib/runner_asset_writer_spy.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ class RunnerAssetWriterSpy extends AssetWriterSpy implements RunnerAssetWriter {
_assetsDeleted.add(id);
return _delegate.delete(id);
}

@override
FutureOr<void> onBuildComplete() => _delegate.onBuildComplete();
}
6 changes: 5 additions & 1 deletion build_runner/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
## 2.3.3-dev
## 2.4.0-dev

- Add `--delay-writes` option to delay all writes to the end of a build. As no
intermediate build state is visible on the file system, this may improve
performance of third-party tools like the analysis server.

## 2.3.2

Expand Down
1 change: 1 addition & 0 deletions build_runner/lib/src/daemon/daemon_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ class BuildRunnerDaemonBuilder implements DaemonBuilder {
logSubscription,
packageGraph: packageGraph,
deleteFilesByDefault: daemonOptions.deleteFilesByDefault,
delayWrites: daemonOptions.delayAssetWrites,
overrideBuildConfig: overrideBuildConfig,
skipBuildScriptCheck: daemonOptions.skipBuildScriptCheck,
enableLowResourcesMode: daemonOptions.enableLowResourcesMode,
Expand Down
7 changes: 6 additions & 1 deletion build_runner/lib/src/entrypoint/base_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,12 @@ abstract class BuildRunnerCommand extends Command<int> {
'If multiple filters are applied then outputs matching any filter '
'will be built (they do not need to match all filters).')
..addMultiOption(enableExperimentOption,
help: 'A list of dart language experiments to enable.');
help: 'A list of dart language experiments to enable.')
..addFlag(
jakemac53 marked this conversation as resolved.
Show resolved Hide resolved
delayWritesOption,
help: 'Delays all file system interactions until the end of a build, '
'potentially reducing load on tools like the analysis server.',
);
}

/// Must be called inside [run] so that [argResults] is non-null.
Expand Down
1 change: 1 addition & 0 deletions build_runner/lib/src/entrypoint/build.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class BuildCommand extends BuildRunnerCommand {
trackPerformance: options.trackPerformance,
skipBuildScriptCheck: options.skipBuildScriptCheck,
logPerformanceDir: options.logPerformanceDir,
delayAssetWrites: options.delayAssetWrites,
);
if (result.status == BuildStatus.success) {
return ExitCode.success.code;
Expand Down
12 changes: 12 additions & 0 deletions build_runner/lib/src/entrypoint/options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const skipBuildScriptCheckOption = 'skip-build-script-check';
const symlinkOption = 'symlink';
const usePollingWatcherOption = 'use-polling-watcher';
const verboseOption = 'verbose';
const delayWritesOption = 'delay-writes';

enum BuildUpdatesOption { none, liveReload }

Expand Down Expand Up @@ -67,6 +68,9 @@ class SharedOptions {
/// Enables performance tracking and the `/$perf` page.
final bool trackPerformance;

/// Delay asset writes until the end of a build.
final bool delayAssetWrites;

/// A directory to log performance information to.
String? logPerformanceDir;

Expand Down Expand Up @@ -100,6 +104,7 @@ class SharedOptions {
required this.isReleaseBuild,
required this.logPerformanceDir,
required this.enableExperiments,
required this.delayAssetWrites,
});

SharedOptions.fromParsedArgs(ArgResults argResults,
Expand All @@ -122,6 +127,7 @@ class SharedOptions {
isReleaseBuild: argResults[releaseOption] as bool,
logPerformanceDir: argResults[logPerformanceOption] as String?,
enableExperiments: argResults[enableExperimentOption] as List<String>,
delayAssetWrites: argResults[delayWritesOption] as bool,
);
}

Expand All @@ -147,6 +153,7 @@ class DaemonOptions extends WatchOptions {
required String? logPerformanceDir,
required bool usePollingWatcher,
required List<String> enableExperiments,
required super.delayAssetWrites,
}) : super._(
buildFilters: buildFilters,
deleteFilesByDefault: deleteFilesByDefault,
Expand Down Expand Up @@ -202,6 +209,7 @@ class DaemonOptions extends WatchOptions {
logPerformanceDir: argResults[logPerformanceOption] as String?,
usePollingWatcher: argResults[usePollingWatcherOption] as bool,
enableExperiments: argResults[enableExperimentOption] as List<String>,
delayAssetWrites: argResults[delayWritesOption] as bool,
);
}
}
Expand Down Expand Up @@ -229,6 +237,7 @@ class WatchOptions extends SharedOptions {
required bool isReleaseBuild,
required String? logPerformanceDir,
required List<String> enableExperiments,
required super.delayAssetWrites,
}) : super._(
buildFilters: buildFilters,
deleteFilesByDefault: deleteFilesByDefault,
Expand Down Expand Up @@ -266,6 +275,7 @@ class WatchOptions extends SharedOptions {
logPerformanceDir: argResults[logPerformanceOption] as String?,
usePollingWatcher: argResults[usePollingWatcherOption] as bool,
enableExperiments: argResults[enableExperimentOption] as List<String>,
delayAssetWrites: argResults[delayWritesOption] as bool,
);
}

Expand Down Expand Up @@ -295,6 +305,7 @@ class ServeOptions extends WatchOptions {
required String? logPerformanceDir,
required bool usePollingWatcher,
required List<String> enableExperiments,
required super.delayAssetWrites,
}) : super._(
buildFilters: buildFilters,
deleteFilesByDefault: deleteFilesByDefault,
Expand Down Expand Up @@ -381,6 +392,7 @@ class ServeOptions extends WatchOptions {
logPerformanceDir: argResults[logPerformanceOption] as String?,
usePollingWatcher: argResults[usePollingWatcherOption] as bool,
enableExperiments: argResults[enableExperimentOption] as List<String>,
delayAssetWrites: argResults[delayWritesOption] as bool,
);
}
}
Expand Down
30 changes: 18 additions & 12 deletions build_runner/lib/src/generate/build.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import 'package:logging/logging.dart';
import 'package:shelf/shelf.dart';
import 'package:watcher/watcher.dart';

import '../logging/std_io_logging.dart';
import '../package_graph/build_config_overrides.dart';
import '../server/server.dart';
import 'environment.dart';
import 'watch_impl.dart' as watch_impl;

/// Runs all of the BuilderApplications in [builders] once.
Expand Down Expand Up @@ -68,7 +68,8 @@ Future<BuildResult> build(List<BuilderApplication> builders,
bool? isReleaseBuild,
Map<String, Map<String, dynamic>>? builderConfigOverrides,
String? logPerformanceDir,
Set<BuildFilter>? buildFilters}) async {
Set<BuildFilter>? buildFilters,
bool? delayAssetWrites}) async {
builderConfigOverrides ??= const {};
buildDirs ??= <BuildDirectory>{};
buildFilters ??= <BuildFilter>{};
Expand All @@ -80,20 +81,24 @@ Future<BuildResult> build(List<BuilderApplication> builders,
skipBuildScriptCheck ??= false;
trackPerformance ??= false;
verbose ??= false;
var environment = OverrideableEnvironment(
IOEnvironment(
packageGraph,
assumeTty: assumeTty,
outputSymlinksOnly: outputSymlinksOnly,
),
reader: reader,
writer: writer,
onLog: onLog ?? stdIOLogListener(assumeTty: assumeTty, verbose: verbose));

final environment = createEnvironment(
packageGraph: packageGraph,
assumeTty: assumeTty,
outputSymlinksOnly: outputSymlinksOnly,
reader: reader,
writer: writer,
delayAssetWrites: delayAssetWrites,
onLog: onLog,
verbose: verbose,
);

var logSubscription =
LogSubscription(environment, verbose: verbose, logLevel: logLevel);
var options = await BuildOptions.create(
logSubscription,
deleteFilesByDefault: deleteFilesByDefault,
delayWrites: delayAssetWrites == true,
packageGraph: packageGraph,
skipBuildScriptCheck: skipBuildScriptCheck,
overrideBuildConfig: await findBuildConfigOverrides(
Expand Down Expand Up @@ -165,7 +170,8 @@ Future<ServeHandler> watch(List<BuilderApplication> builders,
bool? isReleaseBuild,
Map<String, Map<String, dynamic>>? builderConfigOverrides,
String? logPerformanceDir,
Set<BuildFilter>? buildFilters}) =>
Set<BuildFilter>? buildFilters,
bool? delayAssetWrites}) =>
watch_impl.watch(
builders,
assumeTty: assumeTty,
Expand Down
36 changes: 36 additions & 0 deletions build_runner/lib/src/generate/environment.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import 'package:build_runner_core/build_runner_core.dart';
import 'package:logging/logging.dart';

import '../logging/std_io_logging.dart';

BuildEnvironment createEnvironment({
simolus3 marked this conversation as resolved.
Show resolved Hide resolved
required PackageGraph packageGraph,
required bool? assumeTty,
required bool outputSymlinksOnly,
required RunnerAssetReader? reader,
required RunnerAssetWriter? writer,
required bool? delayAssetWrites,
required void Function(LogRecord)? onLog,
required bool verbose,
}) {
BuildEnvironment environment = IOEnvironment(
packageGraph,
assumeTty: assumeTty,
outputSymlinksOnly: outputSymlinksOnly,
);
reader ??= environment.reader;
writer ??= environment.writer;

if (delayAssetWrites == true) {
final delayed = writer = DelayedAssetWriter(writer);
reader = delayed.reader(reader, packageGraph.root.name);
}

environment = environment.change(
reader: reader,
writer: writer,
onLog: onLog ?? stdIOLogListener(assumeTty: assumeTty, verbose: verbose),
);

return environment;
}
20 changes: 13 additions & 7 deletions build_runner/lib/src/generate/watch_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import 'package:logging/logging.dart';
import 'package:stream_transform/stream_transform.dart';
import 'package:watcher/watcher.dart';

import '../logging/std_io_logging.dart';
import '../server/server.dart';
import 'environment.dart';
import 'terminator.dart';

final _logger = Logger('Watch');
Expand Down Expand Up @@ -55,6 +55,7 @@ Future<ServeHandler> watch(
bool? isReleaseBuild,
String? logPerformanceDir,
Set<BuildFilter>? buildFilters,
bool? delayAssetWrites,
}) async {
builderConfigOverrides ??= const {};
buildDirs ??= <BuildDirectory>{};
Expand All @@ -68,12 +69,16 @@ Future<ServeHandler> watch(
trackPerformance ??= false;
verbose ??= false;

var environment = OverrideableEnvironment(
IOEnvironment(packageGraph,
assumeTty: assumeTty, outputSymlinksOnly: outputSymlinksOnly),
reader: reader,
writer: writer,
onLog: onLog ?? stdIOLogListener(assumeTty: assumeTty, verbose: verbose));
final environment = createEnvironment(
packageGraph: packageGraph,
assumeTty: assumeTty,
outputSymlinksOnly: outputSymlinksOnly,
reader: reader,
writer: writer,
delayAssetWrites: delayAssetWrites,
onLog: onLog,
verbose: verbose,
);
var logSubscription =
LogSubscription(environment, verbose: verbose, logLevel: logLevel);
overrideBuildConfig ??= await findBuildConfigOverrides(
Expand All @@ -82,6 +87,7 @@ Future<ServeHandler> watch(
var options = await BuildOptions.create(
logSubscription,
deleteFilesByDefault: deleteFilesByDefault,
delayWrites: delayAssetWrites == true,
packageGraph: packageGraph,
overrideBuildConfig: overrideBuildConfig,
debounceDelay: debounceDelay,
Expand Down
3 changes: 3 additions & 0 deletions build_runner/lib/src/watcher/delete_writer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,7 @@ class OnDeleteWriter implements RunnerAssetWriter {
Future writeAsString(AssetId id, String contents,
{Encoding encoding = utf8}) =>
_writer.writeAsString(id, contents, encoding: encoding);

@override
FutureOr<void> onBuildComplete() => _writer.onBuildComplete();
}
10 changes: 7 additions & 3 deletions build_runner/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
name: build_runner
version: 2.3.3-dev
version: 2.4.0-dev
description: A build system for Dart code generation and modular compilation.
repository: https://github.com/dart-lang/build/tree/master/build_runner

environment:
sdk: ">=2.14.0 <3.0.0"
sdk: ">=2.17.0 <3.0.0"

platforms:
linux:
Expand All @@ -19,7 +19,7 @@ dependencies:
build_config: ">=1.1.0 <1.2.0"
build_daemon: ^3.1.0
build_resolvers: ^2.0.0
build_runner_core: ^7.2.0
build_runner_core: ^8.0.0-dev
code_builder: ^4.2.0
collection: ^1.15.0
crypto: ^3.0.0
Expand Down Expand Up @@ -57,3 +57,7 @@ dev_dependencies:
test_process: ^2.0.0
_test_common:
path: ../_test_common

dependency_overrides:
build_runner_core:
path: ../build_runner_core/
11 changes: 11 additions & 0 deletions build_runner/test/entrypoint/run_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,16 @@ main() {
});
}

void testBasicBuildCommandWithDelayedWrites(String command) {
test('is supported by the $command command', () async {
var args = ['build_runner', command, 'web', '--delayed-writes'];
expect(await runSingleBuild(command, args), ExitCode.success.code);
expectOutput('web/main.dart.js', exists: true);
expectOutput('test/hello_test.dart.browser_test.dart.js',
exists: false);
});
}

void testBuildCommandWithOutput(String command) {
test('works with -o and the $command command', () async {
var outputDirName = 'foo';
Expand All @@ -126,6 +136,7 @@ main() {

for (var command in ['build', 'serve', 'watch']) {
testBasicBuildCommand(command);
testBasicBuildCommandWithDelayedWrites(command);
testBuildCommandWithOutput(command);
}

Expand Down
2 changes: 1 addition & 1 deletion build_runner/test/server/serve_integration_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ void main() {
logLevel: Level.ALL,
onLog: (record) => printOnFailure('[${record.level}] '
'${record.loggerName}: ${record.message}'),
directoryWatcherFactory: (path) => FakeWatcher(path),
directoryWatcherFactory: FakeWatcher.new,
terminateEventStream: terminateController.stream,
skipBuildScriptCheck: true,
);
Expand Down
5 changes: 4 additions & 1 deletion build_runner_core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
## 7.2.8-dev
## 8.0.0-dev

- __Breaking__: Add `onBuildComplete` to `RunnerAssetWriter`.
- Add `DelayedAssetWriter`, a writer implementation delaying all writes until
`onBuildComplete` is called.
- Raise the minimum SDK constraint to 2.18.

## 7.2.7
Expand Down
3 changes: 3 additions & 0 deletions build_runner_core/lib/src/asset/build_cache.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ class BuildCacheWriter implements RunnerAssetWriter {
@override
Future delete(AssetId id) =>
_delegate.delete(_cacheLocation(id, _assetGraph, _rootPackage));

@override
FutureOr<void> onBuildComplete() => _delegate.onBuildComplete();
}

AssetId _cacheLocation(AssetId id, AssetGraph assetGraph, String rootPackage) {
Expand Down
5 changes: 5 additions & 0 deletions build_runner_core/lib/src/asset/file_based.dart
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ class FileBasedAssetWriter implements RunnerAssetWriter {
}
});
}

@override
void onBuildComplete() {
// Nothing to do here
}
}

/// Returns the path to [id] for a given [packageGraph].
Expand Down