Dartle Documentation

The Dartle Cache

For a build system to work intelligently, it needs to know what exactly it’s building. This is so that the system can sort the tasks that it needs to execute in the correct order, and avoid work that has already been done on subsequent runs.

This is what the Dartle Cache allows Dartle to achieve. The cache is implemented as a library within the Dartle project, so it’s possible to use it as a stand-alone Dart library!

For an example of using the DartleCache, check the example DartleCache CLI code, which can be used to keep track of changes on a certain directory.

DartleCache API

This section shows the most important parts of the API.

The full API can be found in pub.dev.

Caching file collections

The DartleCache can be used as a function to cache FileCollections:

import 'package:dartle/dartle_cache.dart';

final cache = DartleCache('.cache-directory');

// cache everything in the `source` dir:
main() async {
  await cache(dir('source'));
}

The next examples will omit the imports and cache declarations for brevity.

A second argument, key may be provided to scope changes. This is used in Dartle to make sure that files changes between invocations of different tasks can be recognized. For example, two tasks may have the same inputs, but that doesn’t mean that just because one task ran, the other doesn’t need to also run later, despite the fact that the previous task had cached the files.

// cache everything in the `source` dir, but only for a key `my-key`:
main() async {
  await cache(dir('source'), key: 'my-key');
}

To cache only files with a certain extension:

// cache *.txt in the `source` dir:
main() async {
  await cache(dir('source', fileExtensions: const {'.txt'}));
}

Checking for changes

The simplest way to check for changes is by calling hasChanged, which takes the same arguments as the cache function:

main() async {
  bool changed = await cache.hasChanged(dir('source'));
  print(changed);
}

To find out exactly what has changed, use findChanges instead:

main() async {
  final changes = await cache.findChanges(dir('source'));
  await for (final change in changes) {
    print('${change.entity.path} - ${change.kind}');
  }
}

This is used by Dartle to implement incremental builds.

Task invocation support

DartleCache also supports caching task invocations. For example:

main(List<String> args) async {
  await cache.cacheTaskInvocation('myTask', args);
}

To check if the invocation is the same as last time (i.e. whether the arguments are the same as last time):

main(List<String> args) async {
  bool changed =await cache.hasTaskInvocationChanged('myTask', args);
  print(changed);
}

It’s also possible to check at what time the latest invocation of a task happened:

main() async {
  DateTime? dateTime = await cache.getLatestInvocationTime('myTask');
  print(dateTime);
}

Cleaning up

To completely cleanup the cache, call clean without any arguments:

main() async {
  await cache.clean();
}

To only cleanup cached artifacts for a particular key, pass the key as an argument:

main() async {
  await cache.clean('key');
}

It’s also possible to remove only a provided FileCollection or task invocation.

main() async {
  await cache.remove(dir('source'), key: 'key');
  await cache.removeTaskInvocation('myTask');
}