Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

64bit dates #892

Merged
merged 14 commits into from
Jun 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cargo-smart-release/src/commit/history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub struct Segment<'a> {
pub struct Item {
pub id: gix::ObjectId,
pub message: Message,
pub commit_time: gix::actor::Time,
pub commit_time: gix::date::Time,
pub tree_id: gix::ObjectId,
pub parent_tree_id: Option<gix::ObjectId>,
}
Expand Down
6 changes: 3 additions & 3 deletions cargo-smart-release/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,8 +299,8 @@ mod tests {
}
}

pub fn time_to_offset_date_time(time: gix::actor::Time) -> OffsetDateTime {
time::OffsetDateTime::from_unix_timestamp(time.seconds_since_unix_epoch as i64)
pub fn time_to_offset_date_time(time: gix::date::Time) -> OffsetDateTime {
time::OffsetDateTime::from_unix_timestamp(time.seconds as i64)
.expect("always valid unix time")
.replace_offset(time::UtcOffset::from_whole_seconds(time.offset_in_seconds).expect("valid offset"))
.replace_offset(time::UtcOffset::from_whole_seconds(time.offset).expect("valid offset"))
}
57 changes: 57 additions & 0 deletions gitoxide-core/src/commitgraph/list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
pub(crate) mod function {
use std::borrow::Cow;
use std::ffi::OsString;

use anyhow::{bail, Context};
use gix::prelude::ObjectIdExt;
use gix::traverse::commit::Sorting;

use crate::OutputFormat;

pub fn list(
mut repo: gix::Repository,
spec: OsString,
mut out: impl std::io::Write,
format: OutputFormat,
) -> anyhow::Result<()> {
if format != OutputFormat::Human {
bail!("Only human output is currently supported");
}
let graph = repo
.commit_graph()
.context("a commitgraph is required, but none was found")?;
repo.object_cache_size_if_unset(4 * 1024 * 1024);

let spec = gix::path::os_str_into_bstr(&spec)?;
let id = repo
.rev_parse_single(spec)
.context("Only single revisions are currently supported")?;
let commits = id
.object()?
.peel_to_kind(gix::object::Kind::Commit)
.context("Need commitish as starting point")?
.id()
.ancestors()
.sorting(Sorting::ByCommitTimeNewestFirst)
.all()?;
for commit in commits {
let commit = commit?;
writeln!(
out,
"{} {} {} {}",
commit.id().shorten_or_id(),
commit.commit_time.expect("traversal with date"),
commit.parent_ids.len(),
graph.commit_by_id(commit.id).map_or_else(
|| Cow::Borrowed("<NOT IN GRAPH-CACHE>"),
|c| Cow::Owned(format!(
"{} {}",
c.root_tree_id().to_owned().attach(&repo).shorten_or_id(),
c.generation()
))
)
)?;
}
Ok(())
}
}
4 changes: 4 additions & 0 deletions gitoxide-core/src/commitgraph/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
pub mod list;
pub use list::function::list;

pub mod verify;
pub use verify::function::verify;
107 changes: 50 additions & 57 deletions gitoxide-core/src/commitgraph/verify.rs
Original file line number Diff line number Diff line change
@@ -1,77 +1,70 @@
use std::{io, path::Path};

use anyhow::{Context as AnyhowContext, Result};
use gix::commitgraph::Graph;

use crate::OutputFormat;

/// A general purpose context for many operations provided here
pub struct Context<W1: io::Write, W2: io::Write> {
pub struct Context<W1: std::io::Write, W2: std::io::Write> {
/// A stream to which to output errors
pub err: W2,
/// A stream to which to output operation results
pub out: W1,
pub output_statistics: Option<OutputFormat>,
}

impl Default for Context<Vec<u8>, Vec<u8>> {
fn default() -> Self {
pub(crate) mod function {
use std::io;

use crate::commitgraph::verify::Context;
use crate::OutputFormat;
use anyhow::{Context as AnyhowContext, Result};

pub fn verify<W1, W2>(
repo: gix::Repository,
Context {
err: Vec::new(),
out: Vec::new(),
output_statistics: None,
}
}
}
err: _err,
mut out,
output_statistics,
}: Context<W1, W2>,
) -> Result<gix::commitgraph::verify::Outcome>
where
W1: io::Write,
W2: io::Write,
{
let g = repo.commit_graph()?;

pub fn graph_or_file<W1, W2>(
path: impl AsRef<Path>,
Context {
err: _err,
mut out,
output_statistics,
}: Context<W1, W2>,
) -> Result<gix::commitgraph::verify::Outcome>
where
W1: io::Write,
W2: io::Write,
{
let g = Graph::at(path).with_context(|| "Could not open commit graph")?;
#[allow(clippy::unnecessary_wraps, unknown_lints)]
fn noop_processor(_commit: &gix::commitgraph::file::Commit<'_>) -> std::result::Result<(), std::fmt::Error> {
Ok(())
}
let stats = g
.verify_integrity(noop_processor)
.with_context(|| "Verification failure")?;

#[allow(clippy::unnecessary_wraps, unknown_lints)]
fn noop_processor(_commit: &gix::commitgraph::file::Commit<'_>) -> std::result::Result<(), std::fmt::Error> {
Ok(())
}
let stats = g
.verify_integrity(noop_processor)
.with_context(|| "Verification failure")?;
#[cfg_attr(not(feature = "serde"), allow(clippy::single_match))]
match output_statistics {
Some(OutputFormat::Human) => drop(print_human_output(&mut out, &stats)),
#[cfg(feature = "serde")]
Some(OutputFormat::Json) => serde_json::to_writer_pretty(out, &stats)?,
_ => {}
}

#[cfg_attr(not(feature = "serde"), allow(clippy::single_match))]
match output_statistics {
Some(OutputFormat::Human) => drop(print_human_output(&mut out, &stats)),
#[cfg(feature = "serde")]
Some(OutputFormat::Json) => serde_json::to_writer_pretty(out, &stats)?,
_ => {}
Ok(stats)
}

Ok(stats)
}
fn print_human_output(out: &mut impl io::Write, stats: &gix::commitgraph::verify::Outcome) -> io::Result<()> {
writeln!(out, "number of commits with the given number of parents")?;
let mut parent_counts: Vec<_> = stats.parent_counts.iter().map(|(a, b)| (*a, *b)).collect();
parent_counts.sort_by_key(|e| e.0);
for (parent_count, commit_count) in parent_counts.into_iter() {
writeln!(out, "\t{parent_count:>2}: {commit_count}")?;
}
writeln!(out, "\t->: {}", stats.num_commits)?;

fn print_human_output(out: &mut impl io::Write, stats: &gix::commitgraph::verify::Outcome) -> io::Result<()> {
writeln!(out, "number of commits with the given number of parents")?;
let mut parent_counts: Vec<_> = stats.parent_counts.iter().map(|(a, b)| (*a, *b)).collect();
parent_counts.sort_by_key(|e| e.0);
for (parent_count, commit_count) in parent_counts.into_iter() {
writeln!(out, "\t{parent_count:>2}: {commit_count}")?;
}
writeln!(out, "\t->: {}", stats.num_commits)?;
write!(out, "\nlongest path length between two commits: ")?;
if let Some(n) = stats.longest_path_length {
writeln!(out, "{n}")?;
} else {
writeln!(out, "unknown")?;
}

write!(out, "\nlongest path length between two commits: ")?;
if let Some(n) = stats.longest_path_length {
writeln!(out, "{n}")?;
} else {
writeln!(out, "unknown")?;
Ok(())
}

Ok(())
}
6 changes: 1 addition & 5 deletions gitoxide-core/src/hours/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,7 @@ pub fn estimate_hours(
let hours_for_commits = commits.iter().map(|t| &t.1).rev().tuple_windows().fold(
0_f32,
|hours, (cur, next): (&gix::actor::SignatureRef<'_>, &gix::actor::SignatureRef<'_>)| {
let change_in_minutes = (next
.time
.seconds_since_unix_epoch
.saturating_sub(cur.time.seconds_since_unix_epoch)) as f32
/ MINUTES_PER_HOUR;
let change_in_minutes = (next.time.seconds.saturating_sub(cur.time.seconds)) as f32 / MINUTES_PER_HOUR;
if change_in_minutes < MAX_COMMIT_DIFFERENCE_IN_MINUTES {
hours + change_in_minutes / MINUTES_PER_HOUR
} else {
Expand Down
9 changes: 3 additions & 6 deletions gitoxide-core/src/hours/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,9 @@ where
}
out.shrink_to_fit();
out.sort_by(|a, b| {
a.1.email.cmp(b.1.email).then(
a.1.time
.seconds_since_unix_epoch
.cmp(&b.1.time.seconds_since_unix_epoch)
.reverse(),
)
a.1.email
.cmp(b.1.email)
.then(a.1.time.seconds.cmp(&b.1.time.seconds).reverse())
});
Ok(out)
});
Expand Down
21 changes: 15 additions & 6 deletions gitoxide-core/src/repository/revision/list.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::ffi::OsString;

use anyhow::{bail, Context};
use gix::prelude::ObjectIdExt;
use gix::traverse::commit::Sorting;

use crate::OutputFormat;

Expand All @@ -20,14 +20,23 @@ pub fn list(
let id = repo
.rev_parse_single(spec)
.context("Only single revisions are currently supported")?;
let commit_id = id
let commits = id
.object()?
.peel_to_kind(gix::object::Kind::Commit)
.context("Need commitish as starting point")?
.id
.attach(&repo);
for commit in commit_id.ancestors().all()? {
writeln!(out, "{}", commit?.id().to_hex())?;
.id()
.ancestors()
.sorting(Sorting::ByCommitTimeNewestFirst)
.all()?;
for commit in commits {
let commit = commit?;
writeln!(
out,
"{} {} {}",
commit.id().shorten_or_id(),
commit.commit_time.expect("traversal with date"),
commit.parent_ids.len()
)?;
}
Ok(())
}
10 changes: 9 additions & 1 deletion gix-actor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,16 @@
#![deny(missing_docs, rust_2018_idioms)]
#![forbid(unsafe_code)]

/// The re-exported `bstr` crate.
///
/// For convenience to allow using `bstr` without adding it to own cargo manifest.
pub use bstr;
use bstr::{BStr, BString};
pub use gix_date::{time::Sign, Time};
/// The re-exported `gix-date` crate.
///
/// For convenience to allow using `gix-date` without adding it to own cargo manifest.
pub use gix_date as date;
use gix_date::Time;

mod identity;
///
Expand Down
Loading