diff --git a/Cargo.toml b/Cargo.toml index 864691a..af271d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ log = ["dep:log", "dep:simple_logger"] [dependencies] anyhow = "1.0.95" chrono = "0.4.41" -clap = { version = "4.5.26", features = ["derive", "wrap_help"] } +clap = { version = "4.5.26", features = ["derive"] } log = { version = "0.4.27", optional = true } rand = "0.9.1" serde = { version = "1.0.217", features = ["derive"] } diff --git a/src/bin/ent/main.rs b/src/bin/ent/main.rs index d67ef3c..655d16a 100644 --- a/src/bin/ent/main.rs +++ b/src/bin/ent/main.rs @@ -25,19 +25,6 @@ enum Commands { /// List issues. List { /// Filter string, describes issues to include in the list. - /// The filter string is composed of chunks separated by ":". - /// Each chunk is of the form "name=condition". The supported - /// names and their matching conditions are: - /// - /// "state": Comma-separated list of states to list. - /// - /// "assignee": Comma-separated list of assignees to list. - /// Defaults to all assignees if not set. - /// - /// "tag": Comma-separated list of tags to include or exclude - /// (if prefixed with "-"). If omitted, defaults to including - /// all tags and excluding none. - /// #[arg(default_value_t = String::from("state=New,Backlog,Blocked,InProgress"))] filter: String, }, @@ -77,13 +64,6 @@ enum Commands { issue_id: String, new_assignee: Option, }, - - /// Add or remove a Tag to/from an Issue, or list the Tags on an Issue. - Tag { - issue_id: String, - #[arg(allow_hyphen_values = true)] - tag: Option, - }, } /// The main function looks at the command-line arguments and determines @@ -191,17 +171,6 @@ fn handle_command( } } - if filter.include_tags.len() > 0 { - if !issue.has_any_tag(&filter.include_tags) { - continue; - } - } - if filter.exclude_tags.len() > 0 { - if issue.has_any_tag(&filter.exclude_tags) { - continue; - } - } - // This issue passed all the filters, include it in list. uuids_by_state .entry(issue.state.clone()) @@ -238,32 +207,7 @@ fn handle_command( Some(assignee) => format!(" (👉 {})", assignee), None => String::from(""), }; - let tags = match &issue.tags.len() { - 0 => String::from(""), - _ => { - // Could use `format!(" {:?}", issue.tags)` - // here, but that results in `["tag1", "TAG2", - // "i-am-also-a-tag"]` and i don't want the - // double-quotes around each tag. - let mut tags = String::from(" ["); - let mut separator = ""; - for tag in &issue.tags { - tags.push_str(separator); - tags.push_str(tag); - separator = ", "; - } - tags.push_str("]"); - tags - } - }; - println!( - "{} {} {}{}{}", - uuid, - comments, - issue.title(), - assignee, - tags - ); + println!("{} {} {}{}", uuid, comments, issue.title(), assignee); } println!(""); } @@ -461,51 +405,6 @@ fn handle_command( } } } - - Commands::Tag { issue_id, tag } => { - let issues = read_issues_database(issues_database_source)?; - let Some(issue) = issues.issues.get(issue_id) else { - return Err(anyhow::anyhow!("issue {} not found", issue_id)); - }; - match tag { - Some(tag) => { - // Add or remove tag. - let issues_database = make_issues_database( - issues_database_source, - IssuesDatabaseAccess::ReadWrite, - )?; - let mut issues = - entomologist::issues::Issues::new_from_dir(&issues_database.dir)?; - let Some(issue) = issues.get_mut_issue(issue_id) else { - return Err(anyhow::anyhow!("issue {} not found", issue_id)); - }; - if tag.len() == 0 { - return Err(anyhow::anyhow!("invalid zero-length tag")); - } - if tag.chars().nth(0).unwrap() == '-' { - let tag = &tag[1..]; - issue.remove_tag(tag)?; - } else { - issue.add_tag(tag)?; - } - } - None => { - // Just list the tags. - match &issue.tags.len() { - 0 => println!("no tags"), - _ => { - // Could use `format!(" {:?}", issue.tags)` - // here, but that results in `["tag1", "TAG2", - // "i-am-also-a-tag"]` and i don't want the - // double-quotes around each tag. - for tag in &issue.tags { - println!("{}", tag); - } - } - } - } - } - } } Ok(()) diff --git a/src/issue.rs b/src/issue.rs index bd0632c..b309cae 100644 --- a/src/issue.rs +++ b/src/issue.rs @@ -22,7 +22,6 @@ pub type IssueHandle = String; pub struct Issue { pub author: String, pub timestamp: chrono::DateTime, - pub tags: Vec, pub state: State, pub dependencies: Option>, pub assignee: Option, @@ -52,8 +51,6 @@ pub enum IssueError { EditorError, #[error("supplied description is empty")] EmptyDescription, - #[error("tag {0} not found")] - TagNotFound(String), } impl FromStr for State { @@ -100,7 +97,6 @@ impl Issue { let mut dependencies: Option> = None; let mut comments = Vec::::new(); let mut assignee: Option = None; - let mut tags = Vec::::new(); for direntry in dir.read_dir()? { if let Ok(direntry) = direntry { @@ -123,13 +119,6 @@ impl Issue { if deps.len() > 0 { dependencies = Some(deps); } - } else if file_name == "tags" { - let contents = std::fs::read_to_string(direntry.path())?; - tags = contents - .lines() - .filter(|s| s.len() > 0) - .map(|tag| String::from(tag.trim())) - .collect(); } else if file_name == "comments" && direntry.metadata()?.is_dir() { Self::read_comments(&mut comments, &direntry.path())?; } else { @@ -149,7 +138,6 @@ impl Issue { Ok(Self { author, timestamp, - tags, state: state, dependencies, assignee, @@ -204,7 +192,6 @@ impl Issue { let mut issue = Self { author: String::from(""), timestamp: chrono::Local::now(), - tags: Vec::::new(), state: State::New, dependencies: None, assignee: None, @@ -316,51 +303,6 @@ impl Issue { } Ok(()) } - - /// Add a new Tag to the Issue. Commits. - pub fn add_tag(&mut self, tag: &str) -> Result<(), IssueError> { - let tag_string = String::from(tag); - if self.tags.contains(&tag_string) { - return Ok(()); - } - self.tags.push(tag_string); - self.tags.sort(); - self.commit_tags(&format!( - "issue {} add tag {}", - self.dir.file_name().unwrap().to_string_lossy(), - tag - ))?; - Ok(()) - } - - /// Remove a Tag from the Issue. Commits. - pub fn remove_tag(&mut self, tag: &str) -> Result<(), IssueError> { - let tag_string = String::from(tag); - let Some(index) = self.tags.iter().position(|x| x == &tag_string) else { - return Err(IssueError::TagNotFound(tag_string)); - }; - self.tags.remove(index); - self.commit_tags(&format!( - "issue {} remove tag {}", - self.dir.file_name().unwrap().to_string_lossy(), - tag - ))?; - Ok(()) - } - - pub fn has_tag(&self, tag: &str) -> bool { - let tag_string = String::from(tag); - self.tags.iter().position(|x| x == &tag_string).is_some() - } - - pub fn has_any_tag(&self, tags: &std::collections::HashSet<&str>) -> bool { - for tag in tags.iter() { - if self.has_tag(tag) { - return true; - } - } - return false; - } } // This is the internal/private API of Issue. @@ -415,18 +357,6 @@ impl Issue { self.read_description()?; Ok(()) } - - fn commit_tags(&self, commit_message: &str) -> Result<(), IssueError> { - let mut tags_filename = self.dir.clone(); - tags_filename.push("tags"); - let mut tags_file = std::fs::File::create(&tags_filename)?; - for tag in &self.tags { - writeln!(tags_file, "{}", tag)?; - } - crate::git::add(&tags_filename)?; - crate::git::commit(&self.dir, commit_message)?; - Ok(()) - } } #[cfg(test)] @@ -442,11 +372,6 @@ mod tests { timestamp: chrono::DateTime::parse_from_rfc3339("2025-07-03T12:14:26-06:00") .unwrap() .with_timezone(&chrono::Local), - tags: Vec::::from([ - String::from("tag1"), - String::from("TAG2"), - String::from("i-am-also-a-tag") - ]), state: State::New, dependencies: None, assignee: None, @@ -466,7 +391,6 @@ mod tests { timestamp: chrono::DateTime::parse_from_rfc3339("2025-07-03T12:14:26-06:00") .unwrap() .with_timezone(&chrono::Local), - tags: Vec::::new(), state: State::InProgress, dependencies: None, assignee: Some(String::from("beep boop")), diff --git a/src/issues.rs b/src/issues.rs index 5c314ac..16dab55 100644 --- a/src/issues.rs +++ b/src/issues.rs @@ -100,7 +100,6 @@ mod tests { timestamp: chrono::DateTime::parse_from_rfc3339("2025-07-03T12:14:26-06:00") .unwrap() .with_timezone(&chrono::Local), - tags: Vec::::new(), state: crate::issue::State::InProgress, dependencies: None, assignee: Some(String::from("beep boop")), @@ -120,11 +119,6 @@ mod tests { timestamp: chrono::DateTime::parse_from_rfc3339("2025-07-03T12:14:26-06:00") .unwrap() .with_timezone(&chrono::Local), - tags: Vec::::from([ - String::from("tag1"), - String::from("TAG2"), - String::from("i-am-also-a-tag") - ]), state: crate::issue::State::New, dependencies: None, assignee: None, @@ -153,7 +147,6 @@ mod tests { timestamp: chrono::DateTime::parse_from_rfc3339("2025-07-03T11:59:44-06:00") .unwrap() .with_timezone(&chrono::Local), - tags: Vec::::new(), state: crate::issue::State::Done, dependencies: None, assignee: None, @@ -187,7 +180,6 @@ mod tests { timestamp: chrono::DateTime::parse_from_rfc3339("2025-07-03T11:59:44-06:00") .unwrap() .with_timezone(&chrono::Local), - tags: Vec::::new(), state: crate::issue::State::WontDo, dependencies: None, assignee: None, @@ -216,7 +208,6 @@ mod tests { timestamp: chrono::DateTime::parse_from_rfc3339("2025-07-05T13:55:49-06:00") .unwrap() .with_timezone(&chrono::Local), - tags: Vec::::new(), state: crate::issue::State::Done, dependencies: None, assignee: None, @@ -236,7 +227,6 @@ mod tests { timestamp: chrono::DateTime::parse_from_rfc3339("2025-07-05T13:55:49-06:00") .unwrap() .with_timezone(&chrono::Local), - tags: Vec::::new(), state: crate::issue::State::WontDo, dependencies: None, assignee: None, @@ -256,7 +246,6 @@ mod tests { timestamp: chrono::DateTime::parse_from_rfc3339("2025-07-05T13:55:49-06:00") .unwrap() .with_timezone(&chrono::Local), - tags: Vec::::new(), state: crate::issue::State::WontDo, dependencies: Some(vec![ crate::issue::IssueHandle::from("3fa5bfd93317ad25772680071d5ac3259cd2384f"), diff --git a/src/lib.rs b/src/lib.rs index fa820b4..b28fb74 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,8 +20,6 @@ pub enum ParseFilterError { pub struct Filter<'a> { pub include_states: std::collections::HashSet, pub include_assignees: std::collections::HashSet<&'a str>, - pub include_tags: std::collections::HashSet<&'a str>, - pub exclude_tags: std::collections::HashSet<&'a str>, } impl<'a> Filter<'a> { @@ -35,8 +33,6 @@ impl<'a> Filter<'a> { State::New, ]), include_assignees: std::collections::HashSet::<&'a str>::new(), - include_tags: std::collections::HashSet::<&'a str>::new(), - exclude_tags: std::collections::HashSet::<&'a str>::new(), }; for filter_chunk_str in filter_str.split(":") { @@ -52,29 +48,12 @@ impl<'a> Filter<'a> { f.include_states.insert(crate::issue::State::from_str(s)?); } } - "assignee" => { f.include_assignees.clear(); for s in tokens[1].split(",") { f.include_assignees.insert(s); } } - - "tag" => { - f.include_tags.clear(); - f.exclude_tags.clear(); - for s in tokens[1].split(",") { - if s.len() == 0 { - return Err(ParseFilterError::ParseError); - } - if s.chars().nth(0).unwrap() == '-' { - f.exclude_tags.insert(&s[1..]); - } else { - f.include_tags.insert(s); - } - } - } - _ => { println!("unknown filter chunk '{}'", filter_chunk_str); return Err(ParseFilterError::ParseError); diff --git a/test/0000/3943fc5c173fdf41c0a22251593cd476d96e6c9f/tags b/test/0000/3943fc5c173fdf41c0a22251593cd476d96e6c9f/tags deleted file mode 100644 index 04e82a6..0000000 --- a/test/0000/3943fc5c173fdf41c0a22251593cd476d96e6c9f/tags +++ /dev/null @@ -1,3 +0,0 @@ -tag1 -TAG2 -i-am-also-a-tag