Dartle
A simple task runner/build system/build library written in Dart.
Purpose
Dartle allows defining a (sometimes large) number of tasks where only a few of them are explicitly invoked by a user.
Dartle makes sure that every task that needs to run, but no others, actually run when you ask it to run one or more tasks.
Dartle knows which tasks need to run because tasks may declare their
RunCondition, which normally means a task only runs if its inputs/outputs have changed since the task's last execution.
This means that, as a user, you only need to remember a few high level task names, everything else runs automatically as needed.
Tasks on the same phase run in parallel, on their own isolates, and if a task fails, all running tasks are immediately canceled.
What can I do with Dartle?
- use it as a Dart-based task runner or build system (write tasks in Dart).
- build Dart projects using
DartleDartsupport. - use it as a file system diff tool. Know when things have changed since last cached.
- create your own build system using Dartle as a library! See
jb, for example.
Using Dartle
For example, Dartle's own build (which uses Dartle's own support for Dart) has the following tasks
(as shown by running dartle --show-tasks):
======== Showing build information only, no tasks will be executed ========
Tasks declared in this build:
==> Setup Phase:
* clean
Deletes the outputs of all other tasks in this build.
* cleanWorkingDirs
Cleanup working dir before builds. Avoids caching generated files.
==> Build Phase:
* analyzeCode [up-to-date]
Analyzes Dart source code
* build [default] [always-runs]
Runs all enabled tasks.
* checkImports [up-to-date]
Checks dart file imports are allowed
* compileExe
Compiles Dart executables declared in pubspec. Argument may specify the name(s) of the executable(s) to compile.
* distribution
Create binary executable distribution.
* format [up-to-date]
Formats all Dart source code.
* generateDartSources [up-to-date]
Generates Dart source files
* runPubGet [up-to-date]
Runs "pub get" in order to update dependencies.
* test [out-of-date]
Runs Dart tests.
==> TearDown Phase:
No tasks in this phase.
The following tasks were selected to run, in order:
generateDartSources
format
checkImports
runPubGet
analyzeCode
test
build
Note: Tasks on the same column may run in parallel.
When you invoke, say, dartle analyzeCode, Dartle will make sure that the
analyseCode task will run, but also that all its dependencies, generateDartSources,
format, checkImports and runPubGet will run first as long as their runCondition
requires them to run. If any of these tasks doesn't need to run, they are automatically
skipped.
Dartle has several RunConditions to determine when a task is up-to-date or needs to run:
RunOnChanges- run task if any inputs/outputs changed since last run.RunAtMostEvery- run task at most every T, where T is a period of time.RunToDelete- run task if any of its outputs exists.
There are also combiners like AndCondition and OrCondition (and you can define your own conditions).
For example, the runPubGet task runs if pubspec.yaml changes OR if it has not been run for
one week.
How to use
Add dartle to your dev_dependencies:
dart pub add -d dartle
Write a dartle build file
A basic
dartle.dartfile can be automatically generated by invokingdartleon a directory wheredartle.dartdoes not exist yet.
dartle.dart
import 'package:dartle/dartle.dart';
final helloTask = Task(hello, argsValidator: const ArgsCount.range(min: 0, max: 1));
final byeTask = Task(bye, dependsOn: const {'hello'});
final cleanTask = createCleanTask(tasks: {helloTask, byeTask});
main(List<String> args) async =>
run(args, tasks: {helloTask, byeTask, cleanTask}, defaultTasks: {helloTask});
/// To pass an argument to a task, use a ':' prefix, e.g.:
/// dartle hello :joe
hello(List<String> args) =>
print("Hello ${args.isEmpty ? 'World' : args[0]}!");
/// If no arguments are expected, use `_` as the function parameter.
bye(_) => print("Bye!");
Notice that the dartle.dart script should be very simple (a basic invocation to Dartle's run, ideally), so it's clear at a
glance what the tasks are.
Put any logic you may need to write for tasks (and even the task declarations) in source file inside the
dartle-src directory, as that's where Dartle looks for changes to the build (besides dartle.dart and pubspec.*).
Check Dartle's own dartle.dart file for a good example.
Run your build!
In dev mode (while you're setting up your build), use dart to run the build file directly:
dart dartle.dart <tasks>
Notice that all
dev_dependenciescan be used in your build! And all Dart tools work with it, including the Observatory and debugger, after all this is just plain Dart!
Once you're done with the basics of your build, it is recommended to install Dartle for faster performance.
To install Dartle:
dart pub global activate dartle
Now, you can run your build with the dartle command:
dartle <tasks>
dartleautomatically re-compiles thedartle.dartscript into an executable if necessary to make builds run so fast they feel instant!
To force tasks to run, use the -f | --force flag, or the -z | --reset-cache flag.
Help
The dartle command has a useful -h | --help flag.
For more help, a tutorial, reference etc. check out the Dartle Documentation.
Prior Art
Dartle is inspired by Gradle and, loosely, Make and Apache Ant.
Libraries
- dartle
- A simple build system written in Dart.
- dartle_cache
- A library exposing the mechanism used by dartle to cache resources and intelligently determine which tasks must run, and which tasks may be skipped.
- dartle_dart
- Dartle extension for building Dart projects.
- dartlex
- Dartle auxiliary library that is used to compile a 'dartle.dart' script into a binary executable automatically when it changes.