applyPhase2 function

Future<ApplyPhase2Result> applyPhase2({
  1. required ChangePlan plan,
  2. required PlanLocationRecord location,
  3. ProcessRunner processRunner = const ProcessRunner(),
  4. Map<String, String>? environment,
})

Implementation

Future<ApplyPhase2Result> applyPhase2({
  required ChangePlan plan,
  required PlanLocationRecord location,
  ProcessRunner processRunner = const ProcessRunner(),
  Map<String, String>? environment,
}) async {
  final before = snapshotTarget(location.canonicalDestination);
  final commands = <String>[];
  var pathsTouched = <String>[];

  for (final command in plan.regenerationCommands) {
    final commandText = ([
      command.executable,
      ...command.argumentList,
    ]).join(' ');
    ProcessResult? result;
    if (isGitInitCommand(command)) {
      final outcome = await runGitInit(
        canonicalDestination: location.canonicalDestination,
        processRunner: processRunner,
      );
      if (outcome.skipped) continue;
      if (outcome.failed) {
        return _result(
          commands,
          pathsTouched,
          failure: _failure(
            commandText,
            outcome.exitCode ?? -1,
            outcome.output ?? '',
            location.canonicalDestination,
          ),
        );
      }
    } else {
      final workingDirectory = switch (command.workingDirectoryClass) {
        WorkingDirectoryClass.target => location.canonicalDestination,
        WorkingDirectoryClass.staging => location.stagingRoot,
        WorkingDirectoryClass.userState => null,
      };
      if (workingDirectory == null) {
        return _result(
          commands,
          pathsTouched,
          failure: _failure(
            commandText,
            -1,
            'Phase 2 cannot run a user-state command.',
            location.canonicalDestination,
          ),
        );
      }
      result = await processRunner.run(
        command.executable,
        command.argumentList,
        workingDirectory: workingDirectory,
        environment: environment,
        includeParentEnvironment: true,
      );
      if (result.exitCode != 0) {
        return _result(
          commands,
          pathsTouched,
          failure: _failure(
            commandText,
            result.exitCode,
            '${result.stdout}${result.stderr}',
            location.canonicalDestination,
          ),
        );
      }
    }

    commands.add(commandText);
    final after = snapshotTarget(location.canonicalDestination);
    pathsTouched =
        after.keys.where((path) => before[path] != after[path]).toList()
          ..sort();
    final violations = outsideDeclaredSet(
      before: before,
      after: after,
      declaredSet: plan.regenerationPathSet,
    );
    if (violations.isNotEmpty) {
      return _result(commands, pathsTouched, outsideDeclaredSet: violations);
    }
  }
  return _result(commands, pathsTouched);
}