mirror of
https://git.proxmox.com/git/rustc
synced 2026-03-26 12:32:57 +00:00
130 lines
4.3 KiB
Rust
130 lines
4.3 KiB
Rust
use std::{
|
|
convert::TryFrom,
|
|
io::{BufRead, BufReader},
|
|
path::{Path, PathBuf},
|
|
};
|
|
|
|
use crate::{file, File, Graph, MAX_COMMITS};
|
|
|
|
/// The error returned by initializations functions like [`Graph::at()`].
|
|
#[derive(thiserror::Error, Debug)]
|
|
#[allow(missing_docs)]
|
|
pub enum Error {
|
|
#[error("{}", .path.display())]
|
|
File {
|
|
#[source]
|
|
err: file::Error,
|
|
path: PathBuf,
|
|
},
|
|
#[error("Commit-graph files mismatch: '{}' uses hash {hash1:?}, but '{}' uses hash {hash2:?}", .path1.display(), .path2.display())]
|
|
HashVersionMismatch {
|
|
path1: PathBuf,
|
|
hash1: gix_hash::Kind,
|
|
path2: PathBuf,
|
|
hash2: gix_hash::Kind,
|
|
},
|
|
#[error("Did not find any files that look like commit graphs at '{}'", .0.display())]
|
|
InvalidPath(PathBuf),
|
|
#[error("Could not open commit-graph file at '{}'", .path.display())]
|
|
Io {
|
|
#[source]
|
|
err: std::io::Error,
|
|
path: PathBuf,
|
|
},
|
|
#[error(
|
|
"Commit-graph files contain {0} commits altogether, but only {} commits are allowed",
|
|
MAX_COMMITS
|
|
)]
|
|
TooManyCommits(u64),
|
|
}
|
|
|
|
/// Instantiate a `Graph` from various sources.
|
|
impl Graph {
|
|
/// Instantiate a commit graph from `path` which may be a directory containing graph files or the graph file itself.
|
|
pub fn at(path: &Path) -> Result<Self, Error> {
|
|
Self::try_from(path)
|
|
}
|
|
|
|
/// Instantiate a commit graph from the directory containing all of its files.
|
|
pub fn from_commit_graphs_dir(path: &Path) -> Result<Self, Error> {
|
|
let commit_graphs_dir = path;
|
|
let chain_file_path = commit_graphs_dir.join("commit-graph-chain");
|
|
let chain_file = std::fs::File::open(&chain_file_path).map_err(|e| Error::Io {
|
|
err: e,
|
|
path: chain_file_path.clone(),
|
|
})?;
|
|
let mut files = Vec::new();
|
|
for line in BufReader::new(chain_file).lines() {
|
|
let hash = line.map_err(|e| Error::Io {
|
|
err: e,
|
|
path: chain_file_path.clone(),
|
|
})?;
|
|
let graph_file_path = commit_graphs_dir.join(format!("graph-{hash}.graph"));
|
|
files.push(File::at(&graph_file_path).map_err(|e| Error::File {
|
|
err: e,
|
|
path: graph_file_path.clone(),
|
|
})?);
|
|
}
|
|
Self::new(files)
|
|
}
|
|
|
|
/// Instantiate a commit graph from a `.git/objects/info/commit-graph` or
|
|
/// `.git/objects/info/commit-graphs/graph-*.graph` file.
|
|
pub fn from_file(path: &Path) -> Result<Self, Error> {
|
|
let file = File::at(path).map_err(|e| Error::File {
|
|
err: e,
|
|
path: path.to_owned(),
|
|
})?;
|
|
Self::new(vec![file])
|
|
}
|
|
|
|
/// Instantiate a commit graph from an `.git/objects/info` directory.
|
|
pub fn from_info_dir(info_dir: &Path) -> Result<Self, Error> {
|
|
Self::from_file(&info_dir.join("commit-graph"))
|
|
.or_else(|_| Self::from_commit_graphs_dir(&info_dir.join("commit-graphs")))
|
|
}
|
|
|
|
/// Create a new commit graph from a list of `files`.
|
|
pub fn new(files: Vec<File>) -> Result<Self, Error> {
|
|
let num_commits: u64 = files.iter().map(|f| u64::from(f.num_commits())).sum();
|
|
if num_commits > u64::from(MAX_COMMITS) {
|
|
return Err(Error::TooManyCommits(num_commits));
|
|
}
|
|
|
|
for window in files.windows(2) {
|
|
let f1 = &window[0];
|
|
let f2 = &window[1];
|
|
if f1.object_hash() != f2.object_hash() {
|
|
return Err(Error::HashVersionMismatch {
|
|
path1: f1.path().to_owned(),
|
|
hash1: f1.object_hash(),
|
|
path2: f2.path().to_owned(),
|
|
hash2: f2.object_hash(),
|
|
});
|
|
}
|
|
}
|
|
|
|
Ok(Self { files })
|
|
}
|
|
}
|
|
|
|
impl TryFrom<&Path> for Graph {
|
|
type Error = Error;
|
|
|
|
fn try_from(path: &Path) -> Result<Self, Self::Error> {
|
|
if path.is_file() {
|
|
// Assume we are looking at `.git/objects/info/commit-graph` or
|
|
// `.git/objects/info/commit-graphs/graph-*.graph`.
|
|
Self::from_file(path)
|
|
} else if path.is_dir() {
|
|
if path.join("commit-graph-chain").is_file() {
|
|
Self::from_commit_graphs_dir(path)
|
|
} else {
|
|
Self::from_info_dir(path)
|
|
}
|
|
} else {
|
|
Err(Error::InvalidPath(path.to_owned()))
|
|
}
|
|
}
|
|
}
|