use std::sync::Arc;
use wsb::peer::model::{PeerId, RepositoryId, WorkspaceId};
use crate::machine::MachineState;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Keep {
Here,
There,
}
pub async fn resolve(
machine: &Arc<MachineState>,
peer: &PeerId,
workspace: &WorkspaceId,
repository: &RepositoryId,
path: &str,
keep: Keep,
) -> Result<(), String> {
let (_, local) = machine
.continuity(workspace)
.await?
.ok_or_else(|| format!("no worktree open on this machine is {workspace}"))?;
local
.repository(repository)
.ok_or_else(|| format!("{repository} is not a repository of this workspace"))?;
let conflicts = machine.store.conflicts(peer, workspace)?;
if !conflicts
.iter()
.any(|row| row.repository == repository.as_str() && row.path == path)
{
return Err(format!("{path} is not in conflict with {peer}"));
}
machine.store.set_resolution(
peer,
workspace,
repository,
path,
match keep {
Keep::Here => "here",
Keep::There => "there",
},
super::service::now(),
)
}
pub async fn decide(
machine: &Arc<MachineState>,
peer: &PeerId,
workspace: &WorkspaceId,
repository: &RepositoryId,
path: &str,
keep: Keep,
) -> Result<(), String> {
difference(machine, peer, workspace, repository, path).await?;
machine.store.set_resolution(
peer,
workspace,
repository,
path,
match keep {
Keep::Here => "here",
Keep::There => "there",
},
super::service::now(),
)?;
machine.store.clear_dismissal(peer, workspace, repository, path)
}
pub async fn dismiss(
machine: &Arc<MachineState>,
peer: &PeerId,
workspace: &WorkspaceId,
repository: &RepositoryId,
path: &str,
) -> Result<(), String> {
let difference = difference(machine, peer, workspace, repository, path).await?;
machine.store.dismiss(
peer,
workspace,
repository,
path,
difference.here_hash.as_deref(),
difference.there_hash.as_deref(),
super::service::now(),
)?;
machine.store.clear_resolution(peer, workspace, repository, path)
}
pub async fn reconsider(
machine: &Arc<MachineState>,
peer: &PeerId,
workspace: &WorkspaceId,
repository: &RepositoryId,
path: &str,
) -> Result<(), String> {
machine.store.clear_dismissal(peer, workspace, repository, path)?;
machine.store.clear_resolution(peer, workspace, repository, path)
}
async fn difference(
machine: &Arc<MachineState>,
peer: &PeerId,
workspace: &WorkspaceId,
repository: &RepositoryId,
path: &str,
) -> Result<crate::machine::PlannedMove, String> {
let (_, local) = machine
.continuity(workspace)
.await?
.ok_or_else(|| format!("no worktree open on this machine is {workspace}"))?;
local
.repository(repository)
.ok_or_else(|| format!("{repository} is not a repository of this workspace"))?;
machine
.plans(peer, workspace)
.get(repository.as_str())
.and_then(|moves| moves.iter().find(|planned| planned.path == path).cloned())
.ok_or_else(|| {
format!(
"nothing differs at {path} between this machine and {peer} — \
there is no difference there to decide about"
)
})
}