use crate::errors::OxenHttpError;
use crate::helpers::get_repo;
use crate::params::{app_data, path_param};
use actix_web::{HttpRequest, HttpResponse, web};
use liboxen::error::OxenError;
use liboxen::repositories;
use liboxen::repositories::fsck::{RebuildDirHashesStats, rebuild_dir_hash_db};
use liboxen::view::versions::CleanCorruptedVersionsResult;
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Debug)]
pub struct RebuildDirHashesQuery {
pub commit_id: Option<String>,
pub branch: Option<String>,
}
#[derive(Serialize, Debug)]
pub struct RebuildDirHashesResponse {
pub status_message: String,
pub stats: RebuildDirHashesStats,
}
pub async fn rebuild_dir_hashes(
req: HttpRequest,
query: web::Query<RebuildDirHashesQuery>,
) -> actix_web::Result<HttpResponse, OxenHttpError> {
let app_data = app_data(&req)?;
let namespace = path_param(&req, "namespace")?.to_string();
let repo_name = path_param(&req, "repo_name")?.to_string();
let repo = get_repo(app_data, &namespace, &repo_name)?;
let commit = if let Some(commit_id) = &query.commit_id {
repositories::commits::get_by_id(&repo, commit_id)?
.ok_or_else(|| OxenError::RevisionNotFound(commit_id.clone().into()))?
} else if let Some(branch_name) = &query.branch {
let branch = repositories::branches::get_by_name(&repo, branch_name)?;
repositories::commits::get_by_id(&repo, &branch.commit_id)?
.ok_or_else(|| OxenError::RevisionNotFound(branch.commit_id.clone().into()))?
} else {
repositories::commits::head_commit(&repo)?
};
log::info!(
"rebuild_dir_hashes: {namespace}/{repo_name} commit={}",
commit.id
);
let stats = tokio::task::spawn_blocking(move || rebuild_dir_hash_db(&repo, &commit))
.await
.map_err(OxenError::from)??;
let response = RebuildDirHashesResponse {
status_message: format!(
"Rebuilt dir_hash_db for commit {} ({} directories)",
stats.commit_id, stats.dirs_written
),
stats,
};
Ok(HttpResponse::Ok().json(response))
}
#[derive(Deserialize, Debug)]
pub struct CleanQuery {
#[serde(default)]
pub dry_run: bool,
}
#[derive(Serialize, Debug)]
pub struct CleanResponse {
pub status_message: String,
pub result: CleanCorruptedVersionsResult,
}
pub async fn clean(
req: HttpRequest,
query: web::Query<CleanQuery>,
) -> actix_web::Result<HttpResponse, OxenHttpError> {
let app_data = app_data(&req)?;
let namespace = path_param(&req, "namespace")?.to_string();
let repo_name = path_param(&req, "repo_name")?.to_string();
let repo = get_repo(app_data, &namespace, &repo_name)?;
let dry_run = query.dry_run;
log::info!("fsck clean: {namespace}/{repo_name} dry_run={dry_run}");
let version_store = repo.version_store();
let result = version_store.clean_corrupted_versions(dry_run).await?;
let status_message = if dry_run {
format!(
"Scanned {} version files; {} corrupted (dry run, nothing removed)",
result.scanned, result.corrupted
)
} else {
format!(
"Scanned {} version files; {} corrupted, {} removed",
result.scanned, result.corrupted, result.cleaned
)
};
Ok(HttpResponse::Ok().json(CleanResponse {
status_message,
result,
}))
}