diff --git a/Cargo.lock b/Cargo.lock index 305d0e4..bc25918 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -284,9 +284,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf97ba92db08df386e10c8ede66a2a0369bd277090afd8710e19e38de9ec0cd" +checksum = "1b3ba52851e73b46a4c3df1d89343741112003f0f6f13beb0dfac9e457c3fdcd" dependencies = [ "bitflags 2.4.2", "libc", @@ -377,9 +377,9 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libgit2-sys" -version = "0.16.1+1.7.1" +version = "0.16.2+1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2a2bb3680b094add03bb3732ec520ece34da31a8cd2d633d1389d0f0fb60d0c" +checksum = "ee4126d8b4ee5c9d9ea891dd875cfdc1e9d0950437179104b183d7d8a74d24e8" dependencies = [ "cc", "libc", diff --git a/Cargo.toml b/Cargo.toml index 122c669..aed59ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ description = "Utility to modify commit timestamps of a git repository" chrono = "0.4.33" chrono-tz = "0.8.5" clap = { version = "4.4.18", features = ["derive"] } -git2 = "0.18.1" +git2 = "0.18.2" iana-time-zone = "0.1.60" itertools = "0.12.1" once_cell = "1.19.0" diff --git a/src/git.rs b/src/git.rs new file mode 100644 index 0000000..dcf6179 --- /dev/null +++ b/src/git.rs @@ -0,0 +1,47 @@ +use chrono::Duration; +use git2::{Commit, Repository}; +use itertools::Itertools; +use thiserror::Error; + +use crate::time::{distribute_across_ranges_with_jitter, TimeRange}; + +#[derive(Debug, Error)] +pub(crate) enum GitErrors { + #[error("end is not a parent of start")] + NotAParent, + + #[error("{0} is not a commit hash in the repo")] + NotACommit(String), +} + +/// find the number of commits between start and end, +/// where end is a parent commit of start +fn get_no_of_commits(start: &Commit, end: &Commit) -> Result { + match start.parent_ids().find_position(|sha| sha == &end.id()) { + Some(tuple) => Ok(tuple.0.try_into().expect("commit has over 2^32 parents")), + None => Err(GitErrors::NotAParent), + } +} + +// will need to do an in memory rebase, ammending each commit with a new signature. +pub fn rebase_commits_across_timerange( + repo: &Repository, + start_sha: &str, + end_sha: &str, + ranges: &[TimeRange], + max_jitter: &Duration, +) -> Result<(), GitErrors> { + let start_commit = if let Ok(commit) = repo.find_commit_by_prefix(start_sha) { + commit + } else { + return Err(GitErrors::NotACommit(start_sha.to_string())); + }; + let end_commit = if let Ok(commit) = repo.find_commit_by_prefix(end_sha) { + commit + } else { + return Err(GitErrors::NotACommit(end_sha.to_string())); + }; + let num_commits = get_no_of_commits(&start_commit, &end_commit)?; + let times = distribute_across_ranges_with_jitter(ranges, num_commits, max_jitter); + todo!() +} diff --git a/src/main.rs b/src/main.rs index 6607505..ed50bb0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ mod args; mod err; +mod git; mod time; use chrono::prelude::*; @@ -9,13 +10,19 @@ use clap::Parser; fn main() { let cli = args::Cli::parse(); println!("{:#?}", cli); - let start_time = match cli.timezone { - Some(tz) => tz.from_local_datetime(&cli.start_time).unwrap(), - None => get_local_timezone() - .expect("Could not get local timezone") - .from_local_datetime(&cli.start_time) - .unwrap(), + let tz = cli + .timezone + .unwrap_or_else(|| get_local_timezone().expect("Could not get local timezone")); + let start_time = tz.from_local_datetime(&cli.start_time).unwrap(); + let end_time = if let Some(time) = cli.end_time { + tz.from_local_datetime(&time).unwrap() + } else { + Utc::now().with_timezone(&tz) }; + println!( + "start_time = {:#?}, end_time = {:#?}, tz = {:#?}", + start_time, end_time, tz + ) } fn get_local_timezone() -> Result { diff --git a/src/time.rs b/src/time.rs index 7a4b93a..8bda399 100644 --- a/src/time.rs +++ b/src/time.rs @@ -9,7 +9,6 @@ pub struct TimeRange { } impl TimeRange { - /// whether a time instance lies within the time range pub fn is_in_range(&self, other: &DateTime) -> bool { (self.start <= *other) && (other <= &self.end)