History

all docs for git-commitgraph::file

Sebastian Thiel committed 5 years ago

Commit 8b262011 parent 23bba1c6 files · +54 −20Browse files

Showing the changes to git-commitgraph/src (5 of 6 files). Show all

Unified · Split

5 files
  1. git-commitgraph/src/file/access.rs +9 −0
  2. git-commitgraph/src/file/commit.rs +11 −12
  3. git-commitgraph/src/file/init.rs +3 −0
  4. git-commitgraph/src/file/mod.rs +9 −4
  5. git-commitgraph/src/file/verify.rs +18 −1
git-commitgraph/src/file/access.rs+9−0
@@ -9,6 +9,7 @@ use std::{ · 8 unmodified lines
9 9
10/// Access10/// Access
11impl File {11impl File {
12 /// The amount of base graphs that this file depends on.
12 pub fn base_graph_count(&self) -> u8 {13 pub fn base_graph_count(&self) -> u8 {
13 self.base_graph_count14 self.base_graph_count
14 }15 }
@@ -24,6 +25,9 @@ impl File { · 9 unmodified lines
24 Commit::new(self, pos)25 Commit::new(self, pos)
25 }26 }
26 27
28 /// The kind of hash used in this File.
29 ///
30 /// Note that it is always conforming to the hash used in the owning repository.
27 pub fn hash_kind(&self) -> HashKind {31 pub fn hash_kind(&self) -> HashKind {
28 HashKind::Sha132 HashKind::Sha1
29 }33 }
@@ -46,6 +50,7 @@ impl File { · 16 unmodified lines
46 borrowed::Id::try_from(&self.data[start..start + SHA1_SIZE]).expect("20 bytes SHA1 to be alright")50 borrowed::Id::try_from(&self.data[start..start + SHA1_SIZE]).expect("20 bytes SHA1 to be alright")
47 }51 }
48 52
53 /// Return an iterator over all object hashes stored in the base graph.
49 pub fn iter_base_graph_ids(&self) -> impl Iterator<Item = borrowed::Id<'_>> {54 pub fn iter_base_graph_ids(&self) -> impl Iterator<Item = borrowed::Id<'_>> {
50 let start = self.base_graphs_list_offset.unwrap_or(0);55 let start = self.base_graphs_list_offset.unwrap_or(0);
51 let base_graphs_list = &self.data[start..start + (SHA1_SIZE * usize::from(self.base_graph_count))];56 let base_graphs_list = &self.data[start..start + (SHA1_SIZE * usize::from(self.base_graph_count))];
@@ -54,14 +59,17 @@ impl File { · 2 unmodified lines
54 .map(|bytes| borrowed::Id::try_from(bytes).expect("20 bytes SHA1 to be alright"))59 .map(|bytes| borrowed::Id::try_from(bytes).expect("20 bytes SHA1 to be alright"))
55 }60 }
56 61
62 /// return an iterator over all commits in this file.
57 pub fn iter_commits(&self) -> impl Iterator<Item = Commit<'_>> {63 pub fn iter_commits(&self) -> impl Iterator<Item = Commit<'_>> {
58 (0..self.num_commits()).map(move |i| self.commit_at(file::Position(i)))64 (0..self.num_commits()).map(move |i| self.commit_at(file::Position(i)))
59 }65 }
60 66
67 /// Return an iterator over all object hashes stored in this file.
61 pub fn iter_ids(&self) -> impl Iterator<Item = borrowed::Id<'_>> {68 pub fn iter_ids(&self) -> impl Iterator<Item = borrowed::Id<'_>> {
62 (0..self.num_commits()).map(move |i| self.id_at(file::Position(i)))69 (0..self.num_commits()).map(move |i| self.id_at(file::Position(i)))
63 }70 }
64 71
72 /// Translate the given object hash to its position within this file, if present.
65 // copied from git-odb/src/pack/index/access.rs73 // copied from git-odb/src/pack/index/access.rs
66 pub fn lookup(&self, id: borrowed::Id<'_>) -> Option<file::Position> {74 pub fn lookup(&self, id: borrowed::Id<'_>) -> Option<file::Position> {
67 let first_byte = usize::from(id.first_byte());75 let first_byte = usize::from(id.first_byte());
@@ -94,6 +102,7 @@ impl File { · 26 unmodified lines
94 self.fan[255]102 self.fan[255]
95 }103 }
96 104
105 /// Returns the path to this file.
97 pub fn path(&self) -> &Path {106 pub fn path(&self) -> &Path {
98 &self.path107 &self.path
99 }108 }
git-commitgraph/src/file/commit.rs+11−12
@@ -11,7 +11,9 @@ use std::{ · 10 unmodified lines
11 slice::Chunks,11 slice::Chunks,
12};12};
13 13
14/// The error used in the [`file::commit`][self] module.
14#[derive(thiserror::Error, Debug)]15#[derive(thiserror::Error, Debug)]
16#[allow(missing_docs)]
15pub enum Error {17pub enum Error {
16 #[error("commit {0}'s extra edges overflows the commit-graph file's extra edges list")]18 #[error("commit {0}'s extra edges overflows the commit-graph file's extra edges list")]
17 ExtraEdgesListOverflow(owned::Id),19 ExtraEdgesListOverflow(owned::Id),
@@ -28,6 +30,7 @@ pub enum Error { · 10 unmodified lines
28const NO_PARENT: u32 = 0x7000_0000;30const NO_PARENT: u32 = 0x7000_0000;
29const EXTENDED_EDGES_MASK: u32 = 0x8000_0000;31const EXTENDED_EDGES_MASK: u32 = 0x8000_0000;
30 32
33/// A commit as stored in a [`File`].
31pub struct Commit<'a> {34pub struct Commit<'a> {
32 file: &'a File,35 file: &'a File,
33 pos: file::Position,36 pos: file::Position,
@@ -68,6 +71,7 @@ impl<'a> Commit<'a> { · 34 unmodified lines
68 self.generation71 self.generation
69 }72 }
70 73
74 /// Returns an iterator over the parent positions for lookup in the owning [Graph][crate::Graph].
71 pub fn iter_parents(&'a self) -> impl Iterator<Item = Result<graph::Position, Error>> + 'a {75 pub fn iter_parents(&'a self) -> impl Iterator<Item = Result<graph::Position, Error>> + 'a {
72 // I didn't find a combinator approach that a) was as strict as ParentIterator, b) supported76 // I didn't find a combinator approach that a) was as strict as ParentIterator, b) supported
73 // fuse-after-first-error behavior, and b) was significantly shorter or more understandable77 // fuse-after-first-error behavior, and b) was significantly shorter or more understandable
@@ -78,29 +82,23 @@ impl<'a> Commit<'a> { · 4 unmodified lines
78 }82 }
79 }83 }
80 84
81 // Allow the return value to outlive this Commit object, as it only needs to be bound by the85 /// Returns the hash of this commit.
82 // lifetime of the parent file.86 pub fn id(&self) -> borrowed::Id<'a> {
83 pub fn id<'b>(&'b self) -> borrowed::Id<'a>
84 where
85 'a: 'b,
86 {
87 self.file.id_at(self.pos)87 self.file.id_at(self.pos)
88 }88 }
89 89
90 /// Returns the first parent of this commit.
90 pub fn parent1(&self) -> Result<Option<graph::Position>, Error> {91 pub fn parent1(&self) -> Result<Option<graph::Position>, Error> {
91 self.iter_parents().next().transpose()92 self.iter_parents().next().transpose()
92 }93 }
93 94
95 /// Returns the position at which this commit is stored in the parent [File].
94 pub fn position(&self) -> file::Position {96 pub fn position(&self) -> file::Position {
95 self.pos97 self.pos
96 }98 }
97 99
98 // Allow the return value to outlive this Commit object, as it only needs to be bound by the100 /// Return the hash of the tree this commit points to.
99 // lifetime of the parent file.101 pub fn root_tree_id(&self) -> borrowed::Id<'a> {
100 pub fn root_tree_id<'b>(&'b self) -> borrowed::Id<'a>
101 where
102 'a: 'b,
103 {
104 self.root_tree_id102 self.root_tree_id
105 }103 }
106}104}
@@ -128,6 +126,7 @@ impl<'a> PartialEq for Commit<'a> { · 21 unmodified lines
128 }126 }
129}127}
130 128
129/// An iterator over parents of a [`Commit`].
131pub struct ParentIterator<'a> {130pub struct ParentIterator<'a> {
132 commit_data: &'a Commit<'a>,131 commit_data: &'a Commit<'a>,
133 state: ParentIteratorState<'a>,132 state: ParentIteratorState<'a>,
git-commitgraph/src/file/init.rs+3−0
@@ -11,7 +11,9 @@ use std::{ · 10 unmodified lines
11 11
12type ChunkId = [u8; 4];12type ChunkId = [u8; 4];
13 13
14/// The error used in [`File::at()`].
14#[derive(thiserror::Error, Debug)]15#[derive(thiserror::Error, Debug)]
16#[allow(missing_docs)]
15pub enum Error {17pub enum Error {
16 #[error("Commit-graph {:?} chunk contains {from_chunk} base graphs, but commit-graph file header claims {from_header} base graphs", BASE_GRAPHS_LIST_CHUNK_ID.as_bstr())]18 #[error("Commit-graph {:?} chunk contains {from_chunk} base graphs, but commit-graph file header claims {from_header} base graphs", BASE_GRAPHS_LIST_CHUNK_ID.as_bstr())]
17 BaseGraphMismatch { from_header: u8, from_chunk: u32 },19 BaseGraphMismatch { from_header: u8, from_chunk: u32 },
@@ -63,6 +65,7 @@ const OID_LOOKUP_CHUNK_ID: ChunkId = *b"OIDL"; · 45 unmodified lines
63const SENTINEL_CHUNK_ID: ChunkId = [0u8; 4];65const SENTINEL_CHUNK_ID: ChunkId = [0u8; 4];
64 66
65impl File {67impl File {
68 /// Try to parse the commit graph file at `path`.
66 pub fn at(path: impl AsRef<Path>) -> Result<File, Error> {69 pub fn at(path: impl AsRef<Path>) -> Result<File, Error> {
67 Self::try_from(path.as_ref())70 Self::try_from(path.as_ref())
68 }71 }
git-commitgraph/src/file/mod.rs+9−4
@@ -1,12 +1,17 @@
1//! Operations on a single commit-graph file.1//! Operations on a single commit-graph file.
2
2mod access;3mod access;
4
5///
3pub mod commit;6pub mod commit;
7pub use commit::Commit;
8
4mod init;9mod init;
10///
5pub mod verify;11pub mod verify;
6 12
7pub use init::Error;13pub use init::Error;
8 14
9pub use commit::Commit;
10use filebuffer::FileBuffer;15use filebuffer::FileBuffer;
11use git_hash::SIZE_OF_SHA1_DIGEST as SHA1_SIZE;16use git_hash::SIZE_OF_SHA1_DIGEST as SHA1_SIZE;
12use std::{17use std::{
@@ -22,7 +27,7 @@ const SIGNATURE: &[u8] = b"CGPH"; · 9 unmodified lines
22/// A single commit-graph file.27/// A single commit-graph file.
23///28///
24/// All operations on a `File` are local to that graph file. Since a commit graph can span multiple29/// All operations on a `File` are local to that graph file. Since a commit graph can span multiple
25/// files, all interesting graph operations belong on `Graph`.30/// files, all interesting graph operations belong on [`Graph`][crate::Graph].
26pub struct File {31pub struct File {
27 base_graph_count: u8,32 base_graph_count: u8,
28 base_graphs_list_offset: Option<usize>,33 base_graphs_list_offset: Option<usize>,
@@ -39,8 +44,8 @@ pub struct File { · 10 unmodified lines
39/// Commits within a graph file are sorted in lexicographical order by OID; a commit's lexigraphical position44/// Commits within a graph file are sorted in lexicographical order by OID; a commit's lexigraphical position
40/// is its position in this ordering. If a commit graph spans multiple files, each file's commits45/// is its position in this ordering. If a commit graph spans multiple files, each file's commits
41/// start at lexigraphical position 0, so it is unique across a single file but is not unique across46/// start at lexigraphical position 0, so it is unique across a single file but is not unique across
42/// the whole commit graph. Each commit also has a graph position (`graph::Position`), which is unique47/// the whole commit graph. Each commit also has a graph position ([`graph::Position`][crate::graph::Position]),
43/// across the whole commit graph. In order to avoid accidentally mixing lexigraphical positions with graph48/// which is unique /// across the whole commit graph. In order to avoid accidentally mixing lexigraphical positions with graph
44/// positions, distinct types are used for each.49/// positions, distinct types are used for each.
45#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]50#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
46pub struct Position(pub u32);51pub struct Position(pub u32);
git-commitgraph/src/file/verify.rs+18−1
@@ -12,7 +12,9 @@ use std::{ · 11 unmodified lines
12 path::Path,12 path::Path,
13};13};
14 14
15/// The error used in [`File::traverse()`].
15#[derive(thiserror::Error, Debug)]16#[derive(thiserror::Error, Debug)]
17#[allow(missing_docs)]
16pub enum Error<E: std::error::Error + 'static> {18pub enum Error<E: std::error::Error + 'static> {
17 #[error(transparent)]19 #[error(transparent)]
18 Commit(#[from] file::commit::Error),20 Commit(#[from] file::commit::Error),
@@ -36,21 +38,32 @@ pub enum Error<E: std::error::Error + 'static> { · 17 unmodified lines
36 RootTreeId { id: owned::Id, root_tree_id: owned::Id },38 RootTreeId { id: owned::Id, root_tree_id: owned::Id },
37}39}
38 40
41/// The positive result of [`File::traverse()`] providing some statistical information.
39#[derive(Clone, Debug, Eq, PartialEq)]42#[derive(Clone, Debug, Eq, PartialEq)]
40#[cfg_attr(feature = "serde1", derive(serde::Deserialize, serde::Serialize))]43#[cfg_attr(feature = "serde1", derive(serde::Deserialize, serde::Serialize))]
41pub struct Outcome {44pub struct Outcome {
45 /// The highest encountered [`file::Commit`] generation number.
42 pub max_generation: u32,46 pub max_generation: u32,
43 pub max_parents: u32,47 /// The smallest encountered [`file::Commit`] generation number.
44 pub min_generation: u32,48 pub min_generation: u32,
49 /// The highest amount parents in a single [`file::Commit`].
50 pub max_parents: u32,
51 /// The total amount of [`commits`][file::Commit] seen in the iteration.
45 pub num_commits: u32,52 pub num_commits: u32,
53 /// A mapping of `parent-count -> amount of [commits][file::Commit] with that count`.
46 pub parent_counts: HashMap<u32, u32>,54 pub parent_counts: HashMap<u32, u32>,
47}55}
48 56
57/// Verification
49impl File {58impl File {
59 /// Returns the trailing checksum over the entire content of this file.
50 pub fn checksum(&self) -> borrowed::Id<'_> {60 pub fn checksum(&self) -> borrowed::Id<'_> {
51 borrowed::Id::try_from(&self.data[self.data.len() - SHA1_SIZE..]).expect("file to be large enough for a hash")61 borrowed::Id::try_from(&self.data[self.data.len() - SHA1_SIZE..]).expect("file to be large enough for a hash")
52 }62 }
53 63
64 /// Traverse all [commits][file::Commit] stored in this file and call `processor(commit) -> Result<(), Error>` on it.
65 ///
66 /// If the `processor` fails, the iteration will be stopped and the entire call results in the respective error.
54 pub fn traverse<'a, E, Processor>(&'a self, mut processor: Processor) -> Result<Outcome, Error<E>>67 pub fn traverse<'a, E, Processor>(&'a self, mut processor: Processor) -> Result<Outcome, Error<E>>
55 where68 where
56 E: std::error::Error + 'static,69 E: std::error::Error + 'static,
@@ -118,6 +131,10 @@ impl File { · 61 unmodified lines
118 Ok(stats)131 Ok(stats)
119 }132 }
120 133
134 /// Assure the [`checksum`][File::checksum()] matches the actual checksum over all content of this file, excluding the trailing
135 /// checksum itself.
136 ///
137 /// Return the actual checksum on success or `(actual checksum, expected checksum)` if there is a mismatch.
121 pub fn verify_checksum(&self) -> Result<owned::Id, (owned::Id, owned::Id)> {138 pub fn verify_checksum(&self) -> Result<owned::Id, (owned::Id, owned::Id)> {
122 // Even though we could use git_features::hash::bytes_of_file(…), this would require using our own139 // Even though we could use git_features::hash::bytes_of_file(…), this would require using our own
123 // Error type to support io::Error and Mismatch. As we only gain progress, there probably isn't much value140 // Error type to support io::Error and Mismatch. As we only gain progress, there probably isn't much value