run method
Runs this command.
The return value is wrapped in a Future
if necessary and returned by
CommandRunner.runCommand
.
Implementation
@override
Future<int> run() async {
if (!isProjectMode) {
stderr.writeln('Project cache is not supported for global mode');
return 1;
}
final options = GenerateOptions.fromArgResults(argResults!);
final cacheDir = Directory(options.globalPatchOptions.cacheDir);
final patchDir = Directory(options.globalPatchOptions.patchDir);
if (!cacheDir.existsSync()) {
stderr.writeln(
'${options.globalPatchOptions.cacheDir} does not exist. Did you run `$kExecutableName pub get`?',
);
return 1;
}
if (!patchDir.existsSync()) {
await patchDir.create(recursive: true);
}
if (!(await gitExists())) {
stderr.writeln('Git is not installed');
return 1;
}
// dart format off
final shouldContinue = options.force ||
prompts.getBool(
'Generating patch files will delete all existing patch files. Do you want to continue?',
defaultsTo: true,
);
// dart format on
if (!shouldContinue) {
return 0;
}
patchDir.deleteSync(recursive: true);
patchDir.createSync(recursive: true);
final ProcessResult(
stdout: statusStdout as String,
stderr: statusStderr as String,
exitCode: statusExitCode,
) = await Process.run(
'git',
[
'status',
'-s',
],
workingDirectory: options.globalPatchOptions.cacheDir);
if (statusExitCode != 0) {
stderr.writeln('Failed to generate patch files:\n$statusStderr');
return 1;
}
if (statusStdout.isEmpty) {
stderr.writeln('No changes to generate patch files');
return 0;
}
final statusLines =
statusStdout.split('\n').where((line) => line.trim().isNotEmpty);
final patches = <({String packageName, bool isGit}), List<String>>{};
final untrackedFiles = <String>[];
for (final line in statusLines) {
final [status, path] = line.trim().split(RegExp(r'\s+'));
if (status == '??') {
untrackedFiles.add(path);
continue;
}
late final String packageName;
late final bool isGit;
if (path.startsWith('hosted')) {
final [_, _, p, ..._] = path.split('/');
packageName = p;
isGit = false;
} else if (path.startsWith('git')) {
final [_, p, ..._] = path.split('/');
packageName = p;
isGit = true;
} else {
stderr.writeln('Unsupported path: $path');
return 1;
}
final key = (packageName: packageName, isGit: isGit);
patches[key] ??= [];
if (!isGit) {
patches[key]!.add(path);
continue;
}
final gitDir = join(
options.globalPatchOptions.cacheDir,
'git',
packageName,
);
final ProcessResult(
stdout: statusStdout as String,
stderr: statusStderr as String,
exitCode: statusExitCode,
) = await Process.run('git', ['status', '-s'], workingDirectory: gitDir);
if (statusExitCode != 0) {
stderr.writeln('Failed to generate patch files:\n$statusStderr');
return 1;
}
if (statusStdout.isEmpty) {
stderr.writeln('No changes to generate patch files');
return 0;
}
final statusLines =
statusStdout.split('\n').where((line) => line.trim().isNotEmpty);
for (final line in statusLines) {
final [status, path] = line.trim().split(RegExp(r'\s+'));
if (status == '??') {
untrackedFiles.add(path);
continue;
}
patches[key]!.add(path);
}
}
// dart format off
for (final MapEntry(:key, value: filePaths) in patches.entries) {
// dart format on
final (:packageName, :isGit) = key;
late final String workingDir;
if (isGit) {
workingDir = join(
options.globalPatchOptions.cacheDir,
'git',
packageName,
);
} else {
workingDir = options.globalPatchOptions.cacheDir;
}
final ProcessResult(
stdout: diffStdout as String,
stderr: diffStderr as String,
exitCode: diffExitCode,
) = await Process.run(
'git',
[
'diff',
'--no-ext-diff',
'--no-color',
...filePaths,
],
workingDirectory: workingDir);
if (diffExitCode != 0) {
stderr.writeln('Failed to generate patch files:\n$diffStderr');
return 1;
}
final patchFile = File(
join(
patchDir.absolute.path,
isGit ? 'git' : 'hosted',
'$packageName.patch',
),
);
if (!patchFile.existsSync()) {
await patchFile.create(recursive: true);
}
await patchFile.writeAsString(diffStdout);
}
if (untrackedFiles.isNotEmpty) {
stderr.writeln('Untracked files are currently not supported:');
for (final file in untrackedFiles) {
stderr.writeln(' $file');
}
stderr.writeln(
'\nIf this is expected, try running `$kExecutableName init --force` to add them to the cache.',
);
}
return 0;
}