git-ward 0.2.0

Proof-before-delete archival for local Git repositories
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::Path;

pub const MANIFEST_VERSION: u32 = 3;

#[derive(Serialize, Deserialize, Clone)]
pub struct Manifest {
    pub manifest_version: u32,
    pub format: ArchiveFormat,
    pub original_path: String,
    pub archived_at: String,
    pub archived_by: String,
    pub size_bytes: u64,
    pub bundle_sha256: Option<String>,
    pub extras_sha256: Option<String>,
    pub head_sha: Option<String>,
    pub refs: Vec<RefEntry>,
    pub remotes: Vec<RemoteEntry>,
    pub first_commit: Option<String>,
    pub last_commit: Option<String>,
    pub commit_count: u64,
    pub verified_at: Option<String>,
    pub verifier_version: Option<String>,
    pub has_extras: bool,
    pub stash_count: u64,
    pub stash_shas: Vec<String>,
    pub tag_count: u64,
    pub has_hooks: bool,
    pub has_config: bool,
    #[serde(default)]
    pub has_config_worktree: bool,
    pub submodule_count: u64,
}

#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum ArchiveFormat {
    Bundle,
    Tarball,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct RefEntry {
    pub name: String,
    pub sha: String,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct RemoteEntry {
    pub name: String,
    pub url: String,
}

pub fn write(manifest: &Manifest, path: &Path) -> Result<()> {
    let json = serde_json::to_string_pretty(manifest)
        .context("Failed to serialise manifest")?;
    fs::write(path, json)
        .with_context(|| format!("Failed to write manifest to {}", path.display()))?;
    Ok(())
}

pub fn read(path: &Path) -> Result<Manifest> {
    let content = fs::read_to_string(path)
        .with_context(|| format!("Failed to read manifest {}", path.display()))?;
    let manifest: Manifest = serde_json::from_str(&content)
        .with_context(|| format!("Failed to parse manifest {}", path.display()))?;
    Ok(manifest)
}