blob: c17594afe096e4c601100f974efba1f73d0f3e4a [file] [log] [blame]
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'dart:io';
import 'package:build/build.dart';
import 'package:build_runner/src/generate/terminator.dart';
import 'package:build_runner_core/build_runner_core.dart';
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 'watch_impl.dart' as watch_impl;
/// Runs all of the BuilderApplications in [builders] once.
///
/// By default, the user will be prompted to delete any files which already
/// exist but were not generated by this specific build script. The
/// [deleteFilesByDefault] option can be set to `true` to skip this prompt.
///
/// A [packageGraph] may be supplied, otherwise one will be constructed using
/// [PackageGraph.forThisPackage]. The default functionality assumes you are
/// running in the root directory of a package, with both a `pubspec.yaml` and
/// `.packages` file present.
///
/// A [reader] and [writer] may also be supplied, which can read/write assets
/// to arbitrary locations or file systems. By default they will write directly
/// to the root package directory, and will use the [packageGraph] to know where
/// to read files from.
///
/// Logging may be customized by passing a custom [logLevel] below which logs
/// will be ignored, as well as an [onLog] handler which defaults to [print].
///
/// The [terminateEventStream] is a stream which can send termination events.
/// By default the [ProcessSignal.sigint] stream is used. In this mode, it
/// will simply consume the first event and allow the build to continue.
/// Multiple termination events will cause a normal shutdown.
///
/// If [outputSymlinksOnly] is `true`, then the merged output directories will
/// contain only symlinks, which is much faster but not generally suitable for
/// deployment.
///
/// If [verbose] is `true` then verbose logging will be enabled. This changes
/// the default [logLevel] to [Level.ALL] and removes stack frame folding, among
/// other things.
Future<BuildResult> build(List<BuilderApplication> builders,
{bool deleteFilesByDefault,
bool assumeTty,
String configKey,
PackageGraph packageGraph,
RunnerAssetReader reader,
RunnerAssetWriter writer,
Resolvers resolvers,
Level logLevel,
void Function(LogRecord) onLog,
Stream terminateEventStream,
bool enableLowResourcesMode,
Set<BuildDirectory> buildDirs,
bool outputSymlinksOnly,
bool trackPerformance,
bool skipBuildScriptCheck,
bool verbose,
bool isReleaseBuild,
Map<String, Map<String, dynamic>> builderConfigOverrides,
String logPerformanceDir,
Set<BuildFilter> buildFilters}) async {
builderConfigOverrides ??= const {};
packageGraph ??= PackageGraph.forThisPackage();
var environment = OverrideableEnvironment(
IOEnvironment(
packageGraph,
assumeTty: assumeTty,
outputSymlinksOnly: outputSymlinksOnly,
),
reader: reader,
writer: writer,
onLog: onLog ?? stdIOLogListener(assumeTty: assumeTty, verbose: verbose));
var logSubscription =
LogSubscription(environment, verbose: verbose, logLevel: logLevel);
var options = await BuildOptions.create(
logSubscription,
deleteFilesByDefault: deleteFilesByDefault,
packageGraph: packageGraph,
skipBuildScriptCheck: skipBuildScriptCheck,
overrideBuildConfig:
await findBuildConfigOverrides(packageGraph, configKey),
enableLowResourcesMode: enableLowResourcesMode,
trackPerformance: trackPerformance,
logPerformanceDir: logPerformanceDir,
resolvers: resolvers,
);
var terminator = Terminator(terminateEventStream);
try {
var build = await BuildRunner.create(
options,
environment,
builders,
builderConfigOverrides,
isReleaseBuild: isReleaseBuild ?? false,
);
var result =
await build.run({}, buildDirs: buildDirs, buildFilters: buildFilters);
await build?.beforeExit();
return result;
} finally {
await terminator.cancel();
await options.logListener.cancel();
}
}
/// Same as [build], except it watches the file system and re-runs builds
/// automatically.
///
/// Call [ServeHandler.handlerFor] to create a [Handler] for use with
/// `package:shelf`. Requests for assets will be blocked while builds are
/// running then served with the latest version of the asset. Only source and
/// generated assets can be served through this handler.
///
/// The [debounceDelay] controls how often builds will run. As long as files
/// keep changing with less than that amount of time apart, builds will be put
/// off.
///
/// The [directoryWatcherFactory] allows you to inject a way of creating custom
/// `DirectoryWatcher`s. By default a normal `DirectoryWatcher` will be used.
///
/// The [terminateEventStream] is a stream which can send termination events.
/// By default the [ProcessSignal.sigint] stream is used. In this mode, the
/// first event will allow any ongoing builds to finish, and then the program
/// will complete normally. Subsequent events are not handled (and will
/// typically cause a shutdown).
Future<ServeHandler> watch(List<BuilderApplication> builders,
{bool deleteFilesByDefault,
bool assumeTty,
String configKey,
PackageGraph packageGraph,
RunnerAssetReader reader,
RunnerAssetWriter writer,
Resolvers resolvers,
Level logLevel,
void Function(LogRecord) onLog,
Duration debounceDelay,
DirectoryWatcher Function(String) directoryWatcherFactory,
Stream terminateEventStream,
bool enableLowResourcesMode,
Set<BuildDirectory> buildDirs,
bool outputSymlinksOnly,
bool trackPerformance,
bool skipBuildScriptCheck,
bool verbose,
bool isReleaseBuild,
Map<String, Map<String, dynamic>> builderConfigOverrides,
String logPerformanceDir,
Set<BuildFilter> buildFilters}) =>
watch_impl.watch(
builders,
assumeTty: assumeTty,
deleteFilesByDefault: deleteFilesByDefault,
configKey: configKey,
packageGraph: packageGraph,
reader: reader,
writer: writer,
resolvers: resolvers,
logLevel: logLevel,
onLog: onLog,
debounceDelay: debounceDelay,
directoryWatcherFactory: directoryWatcherFactory,
terminateEventStream: terminateEventStream,
enableLowResourcesMode: enableLowResourcesMode,
buildDirs: buildDirs,
outputSymlinksOnly: outputSymlinksOnly,
trackPerformance: trackPerformance,
skipBuildScriptCheck: skipBuildScriptCheck,
verbose: verbose,
builderConfigOverrides: builderConfigOverrides,
isReleaseBuild: isReleaseBuild,
logPerformanceDir: logPerformanceDir,
buildFilters: buildFilters,
);