speed-test #32
5 changed files with 181 additions and 101 deletions
|
|
@ -415,116 +415,114 @@ fn handle_command(
|
|||
Commands::Assign {
|
||||
issue_id,
|
||||
new_assignee,
|
||||
} => {
|
||||
let issues = entomologist::database::read_issues_database(issues_database_source)?;
|
||||
let Some(original_issue) = issues.issues.get(issue_id) else {
|
||||
return Err(anyhow::anyhow!("issue {} not found", issue_id));
|
||||
};
|
||||
let old_assignee: String = match &original_issue.assignee {
|
||||
Some(assignee) => assignee.clone(),
|
||||
None => String::from("None"),
|
||||
};
|
||||
println!("issue: {}", issue_id);
|
||||
match new_assignee {
|
||||
Some(new_assignee) => {
|
||||
let issues_database = entomologist::database::make_issues_database(
|
||||
issues_database_source,
|
||||
entomologist::database::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));
|
||||
};
|
||||
println!("assignee: {} -> {}", old_assignee, new_assignee);
|
||||
issue.set_assignee(new_assignee)?;
|
||||
} => match new_assignee {
|
||||
Some(new_assignee) => {
|
||||
let issues_database = entomologist::database::make_issues_database(
|
||||
issues_database_source,
|
||||
entomologist::database::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));
|
||||
};
|
||||
let old_assignee: String = match &issue.assignee {
|
||||
Some(assignee) => assignee.clone(),
|
||||
None => String::from("None"),
|
||||
};
|
||||
issue.set_assignee(new_assignee)?;
|
||||
println!("issue: {}", issue_id);
|
||||
println!("assignee: {} -> {}", old_assignee, new_assignee);
|
||||
}
|
||||
None => {
|
||||
let issues = entomologist::database::read_issues_database(issues_database_source)?;
|
||||
let Some(original_issue) = issues.issues.get(issue_id) else {
|
||||
return Err(anyhow::anyhow!("issue {} not found", issue_id));
|
||||
};
|
||||
let old_assignee: String = match &original_issue.assignee {
|
||||
Some(assignee) => assignee.clone(),
|
||||
None => String::from("None"),
|
||||
};
|
||||
println!("issue: {}", issue_id);
|
||||
println!("assignee: {}", old_assignee);
|
||||
}
|
||||
},
|
||||
|
||||
Commands::Tag { issue_id, tag } => match tag {
|
||||
Some(tag) => {
|
||||
// Add or remove tag.
|
||||
if tag.len() == 0 {
|
||||
return Err(anyhow::anyhow!("invalid zero-length tag"));
|
||||
}
|
||||
None => {
|
||||
println!("assignee: {}", old_assignee);
|
||||
let issues_database = entomologist::database::make_issues_database(
|
||||
issues_database_source,
|
||||
entomologist::database::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.chars().nth(0).unwrap() == '-' {
|
||||
let tag = &tag[1..];
|
||||
issue.remove_tag(tag)?;
|
||||
} else {
|
||||
issue.add_tag(tag)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Commands::Tag { issue_id, tag } => {
|
||||
let issues = entomologist::database::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 = entomologist::database::make_issues_database(
|
||||
issues_database_source,
|
||||
entomologist::database::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);
|
||||
}
|
||||
None => {
|
||||
// Just list the tags.
|
||||
let issues = entomologist::database::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 &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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Commands::DoneTime {
|
||||
issue_id,
|
||||
done_time,
|
||||
} => {
|
||||
let issues = entomologist::database::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 done_time {
|
||||
Some(done_time) => {
|
||||
// Add or remove tag.
|
||||
let issues_database = entomologist::database::make_issues_database(
|
||||
issues_database_source,
|
||||
entomologist::database::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));
|
||||
};
|
||||
let done_time = match chrono::DateTime::parse_from_rfc3339(done_time) {
|
||||
Ok(done_time) => done_time.with_timezone(&chrono::Local),
|
||||
Err(e) => {
|
||||
eprintln!("failed to parse done-time from {}", done_time);
|
||||
return Err(e.into());
|
||||
}
|
||||
};
|
||||
issue.set_done_time(done_time)?;
|
||||
}
|
||||
None => match &issue.done_time {
|
||||
} => match done_time {
|
||||
Some(done_time) => {
|
||||
// Add or remove tag.
|
||||
let issues_database = entomologist::database::make_issues_database(
|
||||
issues_database_source,
|
||||
entomologist::database::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));
|
||||
};
|
||||
let done_time = match chrono::DateTime::parse_from_rfc3339(done_time) {
|
||||
Ok(done_time) => done_time.with_timezone(&chrono::Local),
|
||||
Err(e) => {
|
||||
eprintln!("failed to parse done-time from {}", done_time);
|
||||
return Err(e.into());
|
||||
}
|
||||
};
|
||||
issue.set_done_time(done_time)?;
|
||||
}
|
||||
None => {
|
||||
let issues = entomologist::database::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 &issue.done_time {
|
||||
Some(done_time) => println!("done_time: {}", done_time),
|
||||
None => println!("None"),
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
Commands::Depend {
|
||||
issue_id,
|
||||
|
|
|
|||
|
|
@ -52,8 +52,8 @@ impl Comment {
|
|||
return Err(CommentError::CommentParseError);
|
||||
};
|
||||
|
||||
let author = crate::git::git_log_oldest_author(comment_dir)?;
|
||||
let creation_time = crate::git::git_log_oldest_timestamp(comment_dir)?;
|
||||
let (author, creation_time) = crate::git::git_log_oldest_author_timestamp(comment_dir)?;
|
||||
|
||||
let dir = std::path::PathBuf::from(comment_dir);
|
||||
|
||||
Ok(Self {
|
||||
|
|
|
|||
40
src/git.rs
40
src/git.rs
|
|
@ -395,6 +395,46 @@ pub fn git_log_oldest_author(path: &std::path::Path) -> Result<String, GitError>
|
|||
Ok(String::from(author_last))
|
||||
}
|
||||
|
||||
pub fn git_log_oldest_author_timestamp(
|
||||
path: &std::path::Path,
|
||||
) -> Result<(String, chrono::DateTime<chrono::Local>), GitError> {
|
||||
let mut git_dir = std::path::PathBuf::from(path);
|
||||
git_dir.pop();
|
||||
let result = std::process::Command::new("git")
|
||||
.args([
|
||||
"log",
|
||||
"--pretty=format:%at %an <%ae>",
|
||||
"--",
|
||||
&path
|
||||
.file_name()
|
||||
.ok_or(std::io::Error::from(std::io::ErrorKind::NotFound))?
|
||||
.to_string_lossy(),
|
||||
])
|
||||
.current_dir(&git_dir)
|
||||
.output()?;
|
||||
if !result.status.success() {
|
||||
println!("stdout: {}", &String::from_utf8_lossy(&result.stdout));
|
||||
println!("stderr: {}", &String::from_utf8_lossy(&result.stderr));
|
||||
return Err(GitError::Oops);
|
||||
}
|
||||
|
||||
let raw_output_str = String::from_utf8_lossy(&result.stdout);
|
||||
let Some(raw_output_last) = raw_output_str.split("\n").last() else {
|
||||
return Err(GitError::Oops);
|
||||
};
|
||||
let Some(index) = raw_output_last.find(' ') else {
|
||||
return Err(GitError::Oops);
|
||||
};
|
||||
let author_str = &raw_output_last[index + 1..];
|
||||
let timestamp_str = &raw_output_last[0..index];
|
||||
let timestamp_i64 = timestamp_str.parse::<i64>()?;
|
||||
let timestamp = chrono::DateTime::from_timestamp(timestamp_i64, 0)
|
||||
.unwrap()
|
||||
.with_timezone(&chrono::Local);
|
||||
|
||||
Ok((String::from(author_str), timestamp))
|
||||
}
|
||||
|
||||
pub fn create_orphan_branch(branch: &str) -> Result<(), GitError> {
|
||||
{
|
||||
let tmp_worktree = tempfile::tempdir().unwrap();
|
||||
|
|
|
|||
|
|
@ -166,8 +166,7 @@ impl Issue {
|
|||
Err(IssueError::IdError)?
|
||||
};
|
||||
|
||||
let author = crate::git::git_log_oldest_author(dir)?;
|
||||
let creation_time = crate::git::git_log_oldest_timestamp(dir)?;
|
||||
let (author, creation_time) = crate::git::git_log_oldest_author_timestamp(dir)?;
|
||||
|
||||
Ok(Self {
|
||||
id,
|
||||
|
|
|
|||
43
tools/time-ent
Executable file
43
tools/time-ent
Executable file
|
|
@ -0,0 +1,43 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# * Create a temporary ent issue database branch based on a specific
|
||||
# commit in `entomologist-data`.
|
||||
#
|
||||
# * Perform some ent operations on this temporary branch and measure
|
||||
# the runtime.
|
||||
#
|
||||
# * Clean up by deleteting the temporary branch.
|
||||
|
||||
set -e
|
||||
#set -x
|
||||
|
||||
|
||||
# This is a commit in the `entomologist-data` branch that we're somewhat
|
||||
# arbitrarily using here to time different `ent` operations.
|
||||
TEST_COMMIT=a33f1165d77571d770f1a1021afe4c07360247f0
|
||||
|
||||
# This is the branch that we create from the above commit and test our
|
||||
# `ent` operations on. We'll delete this branch when we're done with
|
||||
# the tests.
|
||||
TEST_BRANCH=$(mktemp --dry-run entomologist-data-XXXXXXXX)
|
||||
|
||||
|
||||
function time_ent() {
|
||||
echo timing: ent "$@"
|
||||
time -p ent -b "${TEST_BRANCH}" "$@"
|
||||
echo
|
||||
}
|
||||
|
||||
|
||||
git branch "${TEST_BRANCH}" "${TEST_COMMIT}"
|
||||
|
||||
time_ent tag 7e2a3a59fb6b77403ff1035255367607
|
||||
time_ent tag 7e2a3a59fb6b77403ff1035255367607 new-tag
|
||||
|
||||
time_ent assign 7e2a3a59fb6b77403ff1035255367607
|
||||
time_ent assign 7e2a3a59fb6b77403ff1035255367607 new-user
|
||||
|
||||
time_ent done-time 7e2a3a59fb6b77403ff1035255367607
|
||||
time_ent done-time 7e2a3a59fb6b77403ff1035255367607 2025-04-01T01:23:45-06:00
|
||||
|
||||
git branch -D "${TEST_BRANCH}"
|
||||
Loading…
Add table
Add a link
Reference in a new issue