Compare commits

..

14 commits

3 changed files with 24 additions and 115 deletions

View file

@ -6,8 +6,8 @@ edition = "2024"
[dependencies]
anyhow = "1.0.95"
clap = { version = "4.5.26", features = ["derive"] }
mktemp = "0.5.1"
rand = "0.9.1"
serde = { version = "1.0.217", features = ["derive"] }
tempfile = "3.20.0"
thiserror = "2.0.11"
toml = "0.8.19"

View file

@ -4,12 +4,8 @@ use clap::Parser;
#[command(version, about, long_about = None)]
struct Args {
/// Directory containing issues.
#[arg(short = 'd', long)]
issues_dir: Option<String>,
/// Branch containing issues.
#[arg(short = 'b', long)]
issues_branch: Option<String>,
#[arg(short, long)]
issues_dir: String,
/// Type of behavior/output.
#[command(subcommand)]
@ -28,11 +24,14 @@ enum Commands {
},
}
fn handle_command(args: &Args, issues_dir: &std::path::Path) -> anyhow::Result<()> {
match &args.command {
fn main() -> anyhow::Result<()> {
let args: Args = Args::parse();
// println!("{:?}", args);
match args.command {
Commands::List => {
let issues =
entomologist::issues::Issues::new_from_dir(std::path::Path::new(issues_dir))?;
entomologist::issues::Issues::new_from_dir(std::path::Path::new(&args.issues_dir))?;
for (uuid, issue) in issues.issues.iter() {
println!("{} {} ({:?})", uuid, issue.title, issue.state);
}
@ -47,31 +46,3 @@ fn handle_command(args: &Args, issues_dir: &std::path::Path) -> anyhow::Result<(
Ok(())
}
fn main() -> anyhow::Result<()> {
let args: Args = Args::parse();
// println!("{:?}", args);
if let (Some(_), Some(_)) = (&args.issues_dir, &args.issues_branch) {
return Err(anyhow::anyhow!(
"don't specify both `--issues-dir` and `--issues-branch`"
));
}
if let Some(dir) = &args.issues_dir {
let dir = std::path::Path::new(dir);
handle_command(&args, dir)?;
} else {
let branch = match &args.issues_branch {
Some(branch) => branch,
None => "entomologist-data",
};
if !entomologist::git::git_branch_exists(branch)? {
entomologist::git::create_orphan_branch(branch)?;
}
let worktree = entomologist::git::Worktree::new(branch)?;
handle_command(&args, worktree.path())?;
}
Ok(())
}

View file

@ -8,41 +8,6 @@ pub enum GitError {
Oops,
}
#[derive(Debug)]
/// `Worktree` is a struct that manages a temporary directory containing
/// a checkout of a specific branch. The worktree is removed and pruned
/// when the `Worktree` struct is dropped.
pub struct Worktree {
path: tempfile::TempDir,
}
impl Drop for Worktree {
fn drop(&mut self) {
let _result = std::process::Command::new("git")
.args(["worktree", "remove", &self.path.path().to_string_lossy()])
.output();
}
}
impl Worktree {
pub fn new(branch: &str) -> Result<Worktree, GitError> {
let path = tempfile::tempdir()?;
let result = std::process::Command::new("git")
.args(["worktree", "add", &path.path().to_string_lossy(), branch])
.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(Self { path })
}
pub fn path(&self) -> &std::path::Path {
self.path.as_ref()
}
}
pub fn checkout_branch_in_worktree(
branch: &str,
worktree_dir: &std::path::Path,
@ -82,17 +47,10 @@ pub fn git_remove_branch(branch: &str) -> Result<(), GitError> {
Ok(())
}
pub fn git_branch_exists(branch: &str) -> Result<bool, GitError> {
let result = std::process::Command::new("git")
.args(["show-ref", "--quiet", branch])
.output()?;
return Ok(result.status.success());
}
pub fn create_orphan_branch(branch: &str) -> Result<(), GitError> {
{
let tmp_worktree = tempfile::tempdir().unwrap();
create_orphan_branch_at_path(branch, tmp_worktree.path())?;
let tmp_worktree = mktemp::Temp::new_path();
create_orphan_branch_at_path(branch, &tmp_worktree.to_path_buf())?;
}
// The temp dir is now removed / cleaned up.
@ -107,14 +65,16 @@ pub fn create_orphan_branch(branch: &str) -> Result<(), GitError> {
Ok(())
}
fn create_orphan_branch_at_path(
pub fn create_orphan_branch_at_path(
branch: &str,
worktree_path: &std::path::Path,
worktree_path: &std::path::PathBuf,
) -> Result<(), GitError> {
let worktree_dir = worktree_path.to_string_lossy();
let Some(worktree_dir) = worktree_path.to_str() else {
return Err(GitError::Oops);
};
let result = std::process::Command::new("git")
.args(["worktree", "add", "--orphan", "-b", branch, &worktree_dir])
.args(["worktree", "add", "--orphan", "-b", branch, worktree_dir])
.output()?;
if !result.status.success() {
println!("stdout: {}", std::str::from_utf8(&result.stdout).unwrap());
@ -122,7 +82,7 @@ fn create_orphan_branch_at_path(
return Err(GitError::Oops);
}
let mut readme_filename = std::path::PathBuf::from(worktree_path);
let mut readme_filename = worktree_path.clone();
readme_filename.push("README.md");
let mut readme = std::fs::File::create(readme_filename)?;
write!(
@ -132,7 +92,7 @@ fn create_orphan_branch_at_path(
let result = std::process::Command::new("git")
.args(["add", "README.md"])
.current_dir(worktree_path)
.current_dir(worktree_dir)
.output()?;
if !result.status.success() {
println!("stdout: {}", std::str::from_utf8(&result.stdout).unwrap());
@ -159,19 +119,12 @@ mod tests {
#[test]
fn test_worktree() {
let mut p = std::path::PathBuf::new();
{
let worktree = Worktree::new("origin/main").unwrap();
p.push(worktree.path());
assert!(p.exists());
let mut p2 = p.clone();
p2.push("README.md");
assert!(p2.exists());
let temp_worktree = mktemp::Temp::new_path();
checkout_branch_in_worktree("origin/main", temp_worktree.as_path()).unwrap();
// The temporary worktree directory is removed when the Temp variable is dropped.
}
// The temporary worktree directory is removed when the Temp variable is dropped.
assert!(!p.exists());
git_worktree_prune().unwrap();
}
#[test]
@ -182,19 +135,4 @@ mod tests {
create_orphan_branch(&branch).unwrap();
git_remove_branch(&branch).unwrap();
}
#[test]
fn test_branch_exists_0() {
let r = git_branch_exists("main").unwrap();
assert_eq!(r, true);
}
#[test]
fn test_branch_exists_1() {
let rnd: u128 = rand::random();
let mut branch = std::string::String::from("entomologist-missing-branch-");
branch.push_str(&format!("{:0x}", rnd));
let r = git_branch_exists(&branch).unwrap();
assert_eq!(r, false);
}
}