use std::path::{Path, PathBuf};
use super::fetch::{
add_worktree, ensure_worktree_of_repo, fetch_tip, refresh_worktree, DOCS_CREATION_MESSAGE,
INITIAL_INDEX,
};
use super::git::Git;
use super::location::{docs_worktree_path, LedgerLocation, Repo};
use super::push::{self, PushOutcome, PushStatus};
pub const README_TEXT: &str = "Documents of the tsk ledger. Written by tsk ledger doc put.\n";
pub const README_FILE: &str = "README.md";
const INDEX_FILE: &str = "index.md";
pub struct DocsFetch {
pub location: LedgerLocation,
pub path: PathBuf,
pub pending: Vec<String>,
pub unpublished: bool,
pub replaced: bool,
}
pub fn worktree_path(repo: &Repo, state_root: &Path) -> Result<PathBuf, String> {
Ok(docs_worktree_path(state_root, &repo.ensure_clone_id()?))
}
pub fn fetch(
repo: &Repo,
state_root: &Path,
location: &LedgerLocation,
keep_local: bool,
) -> Result<DocsFetch, String> {
let clone_id = repo.ensure_clone_id()?;
let path = docs_worktree_path(state_root, &clone_id);
fetch_at(repo, location, &path, keep_local)
}
pub fn fetch_at(
repo: &Repo,
location: &LedgerLocation,
path: &Path,
keep_local: bool,
) -> Result<DocsFetch, String> {
let tip = fetch_tip(&repo.git, &location.docs())?;
fetch_at_tip(repo, location, path, keep_local, tip)
}
pub fn fetch_with_tip(
repo: &Repo,
state_root: &Path,
location: &LedgerLocation,
keep_local: bool,
tip: Option<String>,
) -> Result<DocsFetch, String> {
let clone_id = repo.ensure_clone_id()?;
let path = docs_worktree_path(state_root, &clone_id);
fetch_at_tip(repo, location, &path, keep_local, tip)
}
fn fetch_at_tip(
repo: &Repo,
location: &LedgerLocation,
path: &Path,
keep_local: bool,
tip: Option<String>,
) -> Result<DocsFetch, String> {
let docs = location.docs();
let Some(commit) = tip else {
if path.exists() {
ensure_worktree_of_repo(&Git::new(path), &repo.common_dir)?;
} else {
let commit = create_initial_commit(&repo.git)?;
add_worktree(repo, path, &commit)?;
}
return Ok(DocsFetch {
location: docs,
path: path.to_path_buf(),
pending: Vec::new(),
unpublished: true,
replaced: false,
});
};
let (pending, replaced) = if path.exists() {
refresh_worktree(repo, path, &commit, keep_local)?
} else {
add_worktree(repo, path, &commit)?;
(Vec::new(), false)
};
Ok(DocsFetch {
location: docs,
path: path.to_path_buf(),
pending,
unpublished: false,
replaced,
})
}
pub fn create_initial_commit(git: &Git) -> Result<String, String> {
let readme = git.run_stdin(["hash-object", "-w", "--stdin"], README_TEXT)?;
let index = git.run_stdin(["hash-object", "-w", "--stdin"], INITIAL_INDEX)?;
let listing = format!(
"100644 blob {}\t{}\n100644 blob {}\t{}\n",
readme, README_FILE, index, INDEX_FILE
);
let tree = git.run_stdin(["mktree"], &listing)?;
git.run_line(["commit-tree", tree.as_str(), "-m", DOCS_CREATION_MESSAGE])
}
pub fn is_seed(path: &str, body: &str) -> bool {
(path == README_FILE && body == README_TEXT) || (path == INDEX_FILE && body == INITIAL_INDEX)
}
pub fn push(
repo: &Repo,
location: &LedgerLocation,
path: &Path,
message: &str,
known_tip: Option<Option<String>>,
on_retry: &mut dyn FnMut(usize, &PushStatus),
) -> Result<PushOutcome, String> {
push::push_worktree(repo, &location.docs(), path, message, known_tip, on_retry)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_seed_files_are_recognised_and_other_text_is_not() {
assert!(is_seed("README.md", README_TEXT));
assert!(is_seed("index.md", INITIAL_INDEX));
assert!(!is_seed("index.md", "# Real index\n"));
assert!(!is_seed("notes.md", README_TEXT));
}
#[test]
fn the_readme_says_what_wrote_the_branch() {
assert_eq!(
README_TEXT,
"Documents of the tsk ledger. Written by tsk ledger doc put.\n"
);
}
}