add dependency API / fix dependency representation / dependency

management via CLI
This commit is contained in:
sigil-03 2025-07-18 16:20:17 -06:00
parent 04b33eb70f
commit 8319a4f118
2 changed files with 109 additions and 10 deletions

View file

@ -99,6 +99,12 @@ enum Commands {
issue_id: String, issue_id: String,
done_time: Option<String>, done_time: Option<String>,
}, },
/// get or add a dependency to the issue
Depend {
issue_id: String,
dependency_id: Option<String>,
},
} }
fn handle_command( fn handle_command(
@ -510,6 +516,43 @@ fn handle_command(
}, },
}; };
} }
Commands::Depend {
issue_id,
dependency_id,
} => match dependency_id {
Some(dep_id) => {
let ent_db = entomologist::database::make_issues_database(
issues_database_source,
entomologist::database::IssuesDatabaseAccess::ReadWrite,
)?;
let mut issues = entomologist::issues::Issues::new_from_dir(&ent_db.dir)?;
if issues.issues.contains_key(dep_id) {
if let Some(issue) = issues.issues.get_mut(issue_id) {
issue.add_dependency(dep_id.clone())?;
} else {
Err(anyhow::anyhow!("issue {} not found", issue_id))?;
};
} else {
Err(anyhow::anyhow!("dependency {} not found", dep_id))?;
};
}
None => {
let ent_db = entomologist::database::read_issues_database(issues_database_source)?;
let Some(issue) = ent_db.issues.get(issue_id) else {
Err(anyhow::anyhow!("issue {} not found", issue_id))?
};
println!("DEPENDENCIES:");
if let Some(list) = &issue.dependencies {
for dependency in list {
println!("{}", dependency);
}
} else {
println!("NONE");
}
}
},
} }
Ok(()) Ok(())
@ -531,7 +574,7 @@ fn main() -> anyhow::Result<()> {
(Some(_), Some(_)) => { (Some(_), Some(_)) => {
return Err(anyhow::anyhow!( return Err(anyhow::anyhow!(
"don't specify both `--issues-dir` and `--issues-branch`" "don't specify both `--issues-dir` and `--issues-branch`"
)) ));
} }
}; };

View file

@ -62,6 +62,12 @@ pub enum IssueError {
StdioIsNotTerminal, StdioIsNotTerminal,
#[error("Failed to parse issue ID")] #[error("Failed to parse issue ID")]
IdError, IdError,
#[error("Dependency not found")]
DepNotFound,
#[error("Dependency already exists")]
DepExists,
#[error("Self-dependency not allowed")]
DepSelf,
} }
impl FromStr for State { impl FromStr for State {
@ -128,15 +134,8 @@ impl Issue {
std::fs::read_to_string(direntry.path())?.trim(), std::fs::read_to_string(direntry.path())?.trim(),
)?; )?;
done_time = Some(raw_done_time.into()); done_time = Some(raw_done_time.into());
} else if file_name == "dependencies" { } else if file_name == "dependencies" && direntry.metadata()?.is_dir() {
let dep_strings = std::fs::read_to_string(direntry.path())?; dependencies = Self::read_dependencies(&direntry.path())?;
let deps: Vec<IssueHandle> = dep_strings
.lines()
.map(|dep| IssueHandle::from(dep))
.collect();
if deps.len() > 0 {
dependencies = Some(deps);
}
} else if file_name == "tags" { } else if file_name == "tags" {
let contents = std::fs::read_to_string(direntry.path())?; let contents = std::fs::read_to_string(direntry.path())?;
tags = contents tags = contents
@ -199,6 +198,23 @@ impl Issue {
Ok(()) Ok(())
} }
fn read_dependencies(dir: &std::path::Path) -> Result<Option<Vec<IssueHandle>>, IssueError> {
let mut dependencies: Option<Vec<String>> = None;
for direntry in dir.read_dir()? {
if let Ok(direntry) = direntry {
match &mut dependencies {
Some(deps) => {
deps.push(direntry.file_name().into_string().unwrap());
}
None => {
dependencies = Some(vec![direntry.file_name().into_string().unwrap()]);
}
}
}
}
Ok(dependencies)
}
/// Add a new Comment to the Issue. Commits. /// Add a new Comment to the Issue. Commits.
pub fn add_comment( pub fn add_comment(
&mut self, &mut self,
@ -392,6 +408,46 @@ impl Issue {
} }
return false; return false;
} }
pub fn add_dependency(&mut self, dep: IssueHandle) -> Result<(), IssueError> {
if self.id == dep {
Err(IssueError::DepSelf)?;
}
match &mut self.dependencies {
Some(v) => v.push(dep.clone()),
None => self.dependencies = Some(vec![dep.clone()]),
}
let mut dir = std::path::PathBuf::from(&self.dir);
dir.push("dependencies");
if !dir.exists() {
std::fs::create_dir(&dir)?;
}
dir.push(dep.clone());
if !dir.exists() {
std::fs::File::create(&dir)?;
self.commit(&format!("add dep {} to issue {}", dep, self.id))?;
} else {
Err(IssueError::DepExists)?;
}
Ok(())
}
pub fn remove_dependency(&mut self, dep: IssueHandle) -> Result<(), IssueError> {
match &mut self.dependencies {
Some(v) => {
if let Some(i) = v.iter().position(|d| d == &dep) {
v.remove(i);
} else {
Err(IssueError::DepNotFound)?;
}
}
None => Err(IssueError::DepNotFound)?,
}
self.commit(&format!("remove dep {} from issue {}", dep, self.id))?;
Ok(())
}
} }
// This is the internal/private API of Issue. // This is the internal/private API of Issue.