magi-code 0.96.1

Repository-aware CLI coding agent for terminal work
Documentation
use super::*;

pub(super) fn execute_plan(
    store: &CheckpointStore,
    plan: &RestorePlan,
    cwd: &Path,
) -> RewindExecution {
    execute_plan_internal(store, plan, cwd, None)
}

pub(super) fn execute_plan_internal(
    store: &CheckpointStore,
    plan: &RestorePlan,
    cwd: &Path,
    injected_failure: Option<&str>,
) -> RewindExecution {
    execute_plan_internal_with_hooks(store, plan, cwd, injected_failure, || {}, || {}, || {})
}

fn mutation_status(
    outcome: MutationOutcome,
    committed_status: RestoreStatus,
    reason: &mut Option<String>,
) -> RestoreStatus {
    match outcome {
        MutationOutcome::Committed { warning } => {
            *reason = warning.map(str::to_string);
            committed_status
        }
        MutationOutcome::Conflict(operation_reason) => {
            *reason = Some(operation_reason.to_string());
            RestoreStatus::SkipConflict
        }
        MutationOutcome::Failed(operation_reason) => {
            *reason = Some(operation_reason.to_string());
            RestoreStatus::SkipUnavailable
        }
    }
}

pub(super) fn execute_plan_internal_with_hooks(
    store: &CheckpointStore,
    plan: &RestorePlan,
    cwd: &Path,
    injected_failure: Option<&str>,
    mut after_parent_acquired: impl FnMut(),
    mut after_target_hashed: impl FnMut(),
    mut after_quarantine_hashed: impl FnMut(),
) -> RewindExecution {
    // This is the only ambient open in the target-operation path. All later
    // reads, creates, renames, and removals use descendants of this handle.
    let (canonical_cwd, root) = open_rewind_root(cwd);
    let mut results = Vec::new();
    for operation in &plan.operations {
        let mut reason = None;
        let status = if safe_rewind_target_path(store, &canonical_cwd, &operation.relative_path)
            .is_err()
        {
            RestoreStatus::SkipUnavailable
        } else {
            match &operation.kind {
                RestoreOperationKind::Restore {
                    pre,
                    expected_current,
                } => {
                    let target = match root.as_ref() {
                        Some(root) => {
                            open_target_parent(root, &operation.relative_path, false, false)
                        }
                        None => Err(io::Error::new(ErrorKind::NotFound, "cwd unavailable")),
                    };
                    match target {
                        Err(_) => {
                            reason = Some("hash check failed".to_string());
                            RestoreStatus::SkipUnavailable
                        }
                        Ok(target) => {
                            after_parent_acquired();
                            let current = if injected_failure == Some("hash") {
                                Err(anyhow::anyhow!("injected failure"))
                            } else {
                                target_snapshot(&target).map_err(anyhow::Error::from)
                            };
                            match current {
                                Err(_) => {
                                    reason = Some("hash check failed".to_string());
                                    RestoreStatus::SkipUnavailable
                                }
                                Ok(current)
                                    if current.as_ref().map(|snapshot| snapshot.hash.as_str())
                                        != Some(expected_current.sha256.as_str()) =>
                                {
                                    RestoreStatus::SkipConflict
                                }
                                Ok(Some(current)) => {
                                    after_target_hashed();
                                    let outcome = write_rewind_blob(
                                        store,
                                        pre,
                                        &target,
                                        RewindBlobOptions {
                                            expected_current_hash: Some(&expected_current.sha256),
                                            target_mode: target_mode(&current),
                                            injected_failure,
                                            inject_final_sync_failure: injected_failure
                                                == Some("final sync"),
                                            after_quarantine_hashed: &mut after_quarantine_hashed,
                                        },
                                    );
                                    mutation_status(outcome, RestoreStatus::Restored, &mut reason)
                                }
                                Ok(None) => RestoreStatus::SkipConflict,
                            }
                        }
                    }
                }
                RestoreOperationKind::DeleteCreated { expected_current } => {
                    let target = match root.as_ref() {
                        Some(root) => {
                            open_target_parent(root, &operation.relative_path, false, false)
                        }
                        None => Err(io::Error::new(ErrorKind::NotFound, "cwd unavailable")),
                    };
                    match target {
                        Err(_) => {
                            reason = Some("hash check failed".to_string());
                            RestoreStatus::SkipUnavailable
                        }
                        Ok(target) => {
                            after_parent_acquired();
                            let current = if injected_failure == Some("hash") {
                                Err(anyhow::anyhow!("injected failure"))
                            } else {
                                target_snapshot(&target).map_err(anyhow::Error::from)
                            };
                            match current {
                                Err(_) => {
                                    reason = Some("hash check failed".to_string());
                                    RestoreStatus::SkipUnavailable
                                }
                                Ok(current)
                                    if current.as_ref().map(|snapshot| snapshot.hash.as_str())
                                        != Some(expected_current.sha256.as_str()) =>
                                {
                                    RestoreStatus::SkipConflict
                                }
                                Ok(Some(_)) => {
                                    after_target_hashed();
                                    let outcome = delete_target(
                                        &target,
                                        &expected_current.sha256,
                                        injected_failure == Some("delete"),
                                        injected_failure == Some("final sync"),
                                        &mut after_quarantine_hashed,
                                    );
                                    mutation_status(
                                        outcome,
                                        RestoreStatus::DeletedCreated,
                                        &mut reason,
                                    )
                                }
                                Ok(None) => RestoreStatus::SkipConflict,
                            }
                        }
                    }
                }
                RestoreOperationKind::ResurrectDeleted { pre } => {
                    let target = match root.as_ref() {
                        Some(root) => {
                            open_target_parent(root, &operation.relative_path, false, false)
                        }
                        None => Err(io::Error::new(ErrorKind::NotFound, "cwd unavailable")),
                    };
                    match target {
                        Ok(target) => {
                            after_parent_acquired();
                            let current = target_snapshot(&target).map_err(anyhow::Error::from);
                            match current {
                                Err(_) => {
                                    reason = Some("hash check failed".to_string());
                                    RestoreStatus::SkipUnavailable
                                }
                                Ok(Some(_)) => RestoreStatus::SkipConflict,
                                Ok(None) => {
                                    let outcome = write_rewind_blob(
                                        store,
                                        pre,
                                        &target,
                                        RewindBlobOptions {
                                            expected_current_hash: None,
                                            target_mode: None,
                                            injected_failure,
                                            inject_final_sync_failure: injected_failure
                                                == Some("final sync"),
                                            after_quarantine_hashed: &mut after_quarantine_hashed,
                                        },
                                    );
                                    mutation_status(
                                        outcome,
                                        RestoreStatus::ResurrectedDeleted,
                                        &mut reason,
                                    )
                                }
                            }
                        }
                        Err(error) if error.kind() == ErrorKind::NotFound => {
                            // Do not create missing parents until the blob has
                            // been read successfully. This keeps blob failures
                            // side-effect free while retaining capability safety.
                            let bytes = match read_rewind_blob(store, pre, injected_failure) {
                                Ok(bytes) => bytes,
                                Err(failure) => {
                                    reason = Some(failure.to_string());
                                    Vec::new()
                                }
                            };
                            if reason.is_some() {
                                RestoreStatus::SkipUnavailable
                            } else {
                                let target = match root.as_ref() {
                                    Some(root) => open_target_parent(
                                        root,
                                        &operation.relative_path,
                                        true,
                                        injected_failure == Some("ancestor sync"),
                                    ),
                                    None => {
                                        Err(io::Error::new(ErrorKind::NotFound, "cwd unavailable"))
                                    }
                                };
                                match target {
                                    Err(_) => {
                                        reason = Some("write failed".to_string());
                                        RestoreStatus::SkipUnavailable
                                    }
                                    Ok(target) => {
                                        after_parent_acquired();
                                        match target_snapshot(&target) {
                                            Err(_) => {
                                                reason = Some("hash check failed".to_string());
                                                RestoreStatus::SkipUnavailable
                                            }
                                            Ok(Some(_)) => RestoreStatus::SkipConflict,
                                            Ok(None) => {
                                                let outcome = install_new_target(
                                                    &target,
                                                    &bytes,
                                                    injected_failure == Some("write"),
                                                    injected_failure == Some("final sync"),
                                                );
                                                mutation_status(
                                                    outcome,
                                                    RestoreStatus::ResurrectedDeleted,
                                                    &mut reason,
                                                )
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        Err(_) => {
                            reason = Some("write failed".to_string());
                            RestoreStatus::SkipUnavailable
                        }
                    }
                }
                RestoreOperationKind::SkipConflict {
                    reason: operation_reason,
                } => {
                    reason = Some(sanitized_diagnostic(operation_reason.clone()));
                    RestoreStatus::SkipConflict
                }
                RestoreOperationKind::SkipUnavailable {
                    reason: operation_reason,
                } => {
                    reason = Some(sanitized_diagnostic(operation_reason.clone()));
                    RestoreStatus::SkipUnavailable
                }
            }
        };
        results.push(RestoreOperationResult {
            relative_path: operation.relative_path.clone(),
            status,
            reason,
        });
    }
    RewindExecution { results }
}

pub(super) fn read_rewind_blob(
    store: &CheckpointStore,
    blob: &SnapshotBlobRef,
    injected_failure: Option<&str>,
) -> Result<Vec<u8>, &'static str> {
    if injected_failure == Some("blob read") {
        return Err("blob read failed");
    }
    store.read_blob(blob).map_err(|_| "blob read failed")
}