blob: ee3ef55c9a959ce51a891bd2dd7f716757ced55a [file] [log] [blame] [edit]
import 'dart:io';
const ansiRed = '\x1b[31m';
const ansiDefault = '\x1b[39;49m';
void printError(Object? message) {
if (stderr.supportsAnsiEscapes) {
message = '$ansiRed$message$ansiDefault';
}
stderr.writeln(message);
}
class StepFailure implements Exception {
StepFailure(this.name);
String name;
@override
String toString() => 'step failed: $name';
}
abstract class Step {
/// Runs this step, raises an exception if something fails.
Future<void> run();
}
class Callback implements Step {
Callback(this.name, this.function);
String name;
Future<void> Function() function;
@override
Future<void> run() => function();
}
class Command implements Step {
Command(this.exec, this.args, this.workingDirectory);
final String exec;
final List<String> args;
final Uri workingDirectory;
@override
Future<void> run() async {
final result = await Process.run(
exec,
args,
workingDirectory: workingDirectory.toFilePath(),
runInShell: true,
);
if (result.exitCode != 0) {
printError(result.stdout);
printError(result.stderr);
final commandString = "$exec ${args.join(" ")}";
stderr.writeln('failure executing command: $commandString');
throw StepFailure(commandString);
}
}
}
class Runner {
static final gitRoot = getRepositoryRoot();
Runner(this.name, this.defaultWorkingDir);
String name;
Uri defaultWorkingDir;
final steps = <Step>[];
final cleanupSteps = <Step>[];
void chainCommand(String exec, List<String> args, {Uri? workingDirectory}) =>
_addCommand(steps, exec, args, workingDirectory: workingDirectory);
void chainCleanupCommand(String exec, List<String> args,
{Uri? workingDirectory}) =>
_addCommand(cleanupSteps, exec, args, workingDirectory: workingDirectory);
void _addCommand(List<Step> list, String exec, List<String> args,
{Uri? workingDirectory}) {
list.add(Command(exec, args, workingDirectory ?? defaultWorkingDir));
}
void chainCallback(String name, Future<void> Function() callback) {
steps.add(Callback(name, callback));
}
Future<void> run() async {
stderr.writeln('started: $name');
var error = false;
for (var step in steps) {
try {
await step.run();
} on StepFailure catch (e) {
stderr.writeln(e);
error = true;
exitCode = 1;
break;
}
}
stderr.writeln('${error ? "failed" : "complete"}: $name');
for (var step in cleanupSteps) {
try {
await step.run();
} on Exception catch (e) {
printError('ERROR: $e');
}
}
}
}
Uri getRepositoryRoot() {
final gitCommand = Process.runSync('git', ['rev-parse', '--show-toplevel']);
final output = gitCommand.stdout as String;
return Uri.directory(output.trim());
}