Compare commits

..

2 commits

Author SHA1 Message Date
9c54a92152 add ent sync
In a worktree with the `entomologist-data` branch checked out in it:
1. `git fetch REMOTE`
2. `git merge REMOTE/BRANCH`
3. `git push REMOTE BRANCH`

Pretty straight-forward.  If anything goes wrong we error out and ask
the human to help.
2025-07-08 10:50:37 -06:00
ccabfa4ec8 remove an old debug log message from Issue::new_comment() 2025-07-08 10:50:37 -06:00
3 changed files with 83 additions and 2 deletions

View file

@ -45,6 +45,15 @@ enum Commands {
issue_id: String,
description: Option<String>,
},
/// Sync entomologist data with remote. This fetches from the remote,
/// merges the remote entomologist data branch with the local one,
/// and pushes the result back to the remote.
Sync {
/// Name of the git remote to sync with.
#[arg(default_value_t = String::from("origin"))]
remote: String,
},
}
fn handle_command(args: &Args, issues_dir: &std::path::Path) -> anyhow::Result<()> {
@ -154,6 +163,24 @@ fn handle_command(args: &Args, issues_dir: &std::path::Path) -> anyhow::Result<(
}
}
}
Commands::Sync { remote } => {
if args.issues_dir.is_some() {
return Err(anyhow::anyhow!(
"`sync` operates on a branch, don't specify `issues_dir`"
));
}
// FIXME: Kinda bogus to re-do this thing we just did in
// `main()`. Maybe `main()` shouldn't create the worktree,
// maybe we should do it here in `handle_command()`?
// That way also each command could decide if it wants a
// read-only worktree or a read/write one.
let branch = match &args.issues_branch {
Some(branch) => branch,
None => "entomologist-data",
};
entomologist::git::sync(issues_dir, remote, branch)?;
}
}
Ok(())

View file

@ -124,6 +124,62 @@ pub fn git_commit_file(file: &std::path::Path) -> Result<(), GitError> {
Ok(())
}
pub fn git_fetch(dir: &std::path::Path, remote: &str) -> Result<(), GitError> {
let result = std::process::Command::new("git")
.args(["fetch", remote])
.current_dir(dir)
.output()?;
if !result.status.success() {
println!("stdout: {}", std::str::from_utf8(&result.stdout).unwrap());
println!("stderr: {}", std::str::from_utf8(&result.stderr).unwrap());
return Err(GitError::Oops);
}
Ok(())
}
pub fn sync(dir: &std::path::Path, remote: &str, branch: &str) -> Result<(), GitError> {
// We do all the work in a directory that's (FIXME) hopefully a
// worktree. If anything goes wrong we just fail out and ask the
// human to fix it by hand :-/
// 1. `git fetch`
// 2. `git merge REMOTE/BRANCH`
// 3. `git push REMOTE BRANCH`
git_fetch(dir, remote)?;
// Merge remote branch into local.
let result = std::process::Command::new("git")
.args(["merge", &format!("{}/{}", remote, branch)])
.current_dir(dir)
.output()?;
if !result.status.success() {
println!(
"Sync failed! Merge error! Help, a human needs to fix the mess in {:?}",
dir
);
println!("stdout: {}", std::str::from_utf8(&result.stdout).unwrap());
println!("stderr: {}", std::str::from_utf8(&result.stderr).unwrap());
return Err(GitError::Oops);
}
// Push merged branch to remote.
let result = std::process::Command::new("git")
.args(["push", remote, branch])
.current_dir(dir)
.output()?;
if !result.status.success() {
println!(
"Sync failed! Push error! Help, a human needs to fix the mess in {:?}",
dir
);
println!("stdout: {}", std::str::from_utf8(&result.stdout).unwrap());
println!("stderr: {}", std::str::from_utf8(&result.stderr).unwrap());
return Err(GitError::Oops);
}
Ok(())
}
pub fn create_orphan_branch(branch: &str) -> Result<(), GitError> {
{
let tmp_worktree = tempfile::tempdir().unwrap();

View file

@ -75,7 +75,6 @@ impl fmt::Display for State {
State::InProgress => "inprogress",
State::Done => "done",
State::WontDo => "wontdo",
};
write!(f, "{fmt_str}")
}
@ -145,7 +144,6 @@ impl Issue {
let mut dir = std::path::PathBuf::from(&self.dir);
dir.push("comments");
if !dir.exists() {
println!("creating {}", dir.to_string_lossy());
std::fs::create_dir(&dir)?;
}