summaryrefslogtreecommitdiffstats
path: root/vendor/gix/src/reference
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:41:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:41:41 +0000
commit10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 (patch)
treebdffd5d80c26cf4a7a518281a204be1ace85b4c1 /vendor/gix/src/reference
parentReleasing progress-linux version 1.70.0+dfsg1-9~progress7.99u1. (diff)
downloadrustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.tar.xz
rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.zip
Merging upstream version 1.70.0+dfsg2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/gix/src/reference')
-rw-r--r--vendor/gix/src/reference/edits.rs75
-rw-r--r--vendor/gix/src/reference/errors.rs89
-rw-r--r--vendor/gix/src/reference/iter.rs127
-rw-r--r--vendor/gix/src/reference/log.rs36
-rw-r--r--vendor/gix/src/reference/mod.rs87
-rw-r--r--vendor/gix/src/reference/remote.rs49
6 files changed, 463 insertions, 0 deletions
diff --git a/vendor/gix/src/reference/edits.rs b/vendor/gix/src/reference/edits.rs
new file mode 100644
index 000000000..aadd087ba
--- /dev/null
+++ b/vendor/gix/src/reference/edits.rs
@@ -0,0 +1,75 @@
+///
+pub mod set_target_id {
+ use gix_ref::{transaction::PreviousValue, Target};
+
+ use crate::{bstr::BString, Reference};
+
+ mod error {
+ use gix_ref::FullName;
+
+ /// The error returned by [`Reference::set_target_id()`][super::Reference::set_target_id()].
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error("Cannot change symbolic reference {name:?} into a direct one by setting it to an id")]
+ SymbolicReference { name: FullName },
+ #[error(transparent)]
+ ReferenceEdit(#[from] crate::reference::edit::Error),
+ }
+ }
+ pub use error::Error;
+
+ impl<'repo> Reference<'repo> {
+ /// Set the id of this direct reference to `id` and use `reflog_message` for the reflog (if enabled in the repository).
+ ///
+ /// Note that the operation will fail on symbolic references, to change their type use the lower level reference database,
+ /// or if the reference was deleted or changed in the mean time.
+ /// Furthermore, refrain from using this method for more than a one-off change as it creates a transaction for each invocation.
+ /// If multiple reference should be changed, use [Repository::edit_references()][crate::Repository::edit_references()]
+ /// or the lower level reference database instead.
+ #[allow(clippy::result_large_err)]
+ pub fn set_target_id(
+ &mut self,
+ id: impl Into<gix_hash::ObjectId>,
+ reflog_message: impl Into<BString>,
+ ) -> Result<(), Error> {
+ match &self.inner.target {
+ Target::Symbolic(name) => return Err(Error::SymbolicReference { name: name.clone() }),
+ Target::Peeled(current_id) => {
+ let changed = self.repo.reference(
+ self.name(),
+ id,
+ PreviousValue::MustExistAndMatch(Target::Peeled(current_id.to_owned())),
+ reflog_message,
+ )?;
+ *self = changed;
+ }
+ }
+ Ok(())
+ }
+ }
+}
+
+///
+pub mod delete {
+ use gix_ref::transaction::{Change, PreviousValue, RefEdit, RefLog};
+
+ use crate::Reference;
+
+ impl<'repo> Reference<'repo> {
+ /// Delete this reference or fail if it was changed since last observed.
+ /// Note that this instance remains available in memory but probably shouldn't be used anymore.
+ pub fn delete(&self) -> Result<(), crate::reference::edit::Error> {
+ self.repo
+ .edit_reference(RefEdit {
+ change: Change::Delete {
+ expected: PreviousValue::MustExistAndMatch(self.inner.target.clone()),
+ log: RefLog::AndReference,
+ },
+ name: self.inner.name.clone(),
+ deref: false,
+ })
+ .map(|_| ())
+ }
+ }
+}
diff --git a/vendor/gix/src/reference/errors.rs b/vendor/gix/src/reference/errors.rs
new file mode 100644
index 000000000..364456fd1
--- /dev/null
+++ b/vendor/gix/src/reference/errors.rs
@@ -0,0 +1,89 @@
+///
+pub mod edit {
+ use crate::config;
+
+ /// The error returned by [edit_references(…)][crate::Repository::edit_references()], and others
+ /// which ultimately create a reference.
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error(transparent)]
+ FileTransactionPrepare(#[from] gix_ref::file::transaction::prepare::Error),
+ #[error(transparent)]
+ FileTransactionCommit(#[from] gix_ref::file::transaction::commit::Error),
+ #[error(transparent)]
+ NameValidation(#[from] gix_validate::reference::name::Error),
+ #[error("Could not interpret core.filesRefLockTimeout or core.packedRefsTimeout, it must be the number in milliseconds to wait for locks or negative to wait forever")]
+ LockTimeoutConfiguration(#[from] config::lock_timeout::Error),
+ #[error(transparent)]
+ ParseCommitterTime(#[from] crate::config::time::Error),
+ }
+}
+
+///
+pub mod peel {
+ /// The error returned by [Reference::peel_to_id_in_place(…)][crate::Reference::peel_to_id_in_place()] and
+ /// [Reference::into_fully_peeled_id(…)][crate::Reference::into_fully_peeled_id()].
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error(transparent)]
+ ToId(#[from] gix_ref::peel::to_id::Error),
+ #[error(transparent)]
+ PackedRefsOpen(#[from] gix_ref::packed::buffer::open::Error),
+ }
+}
+
+///
+pub mod head_id {
+ /// The error returned by [Repository::head_id(…)][crate::Repository::head_id()].
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error(transparent)]
+ Head(#[from] crate::reference::find::existing::Error),
+ #[error(transparent)]
+ PeelToId(#[from] crate::head::peel::Error),
+ #[error("Branch '{name}' does not have any commits")]
+ Unborn { name: gix_ref::FullName },
+ }
+}
+
+///
+pub mod head_commit {
+ /// The error returned by [Repository::head_commit(…)][crate::Repository::head_commit()].
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error(transparent)]
+ Head(#[from] crate::reference::find::existing::Error),
+ #[error(transparent)]
+ PeelToCommit(#[from] crate::head::peel::to_commit::Error),
+ }
+}
+
+///
+pub mod find {
+ ///
+ pub mod existing {
+ /// The error returned by [find_reference(…)][crate::Repository::find_reference()], and others.
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error(transparent)]
+ Find(#[from] crate::reference::find::Error),
+ #[error("The reference did not exist")]
+ NotFound,
+ }
+ }
+
+ /// The error returned by [try_find_reference(…)][crate::Repository::try_find_reference()].
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error(transparent)]
+ Find(#[from] gix_ref::file::find::Error),
+ #[error(transparent)]
+ PackedRefsOpen(#[from] gix_ref::packed::buffer::open::Error),
+ }
+}
diff --git a/vendor/gix/src/reference/iter.rs b/vendor/gix/src/reference/iter.rs
new file mode 100644
index 000000000..a2b022f64
--- /dev/null
+++ b/vendor/gix/src/reference/iter.rs
@@ -0,0 +1,127 @@
+//!
+use std::path::Path;
+
+use gix_odb::pack::Find;
+use gix_ref::file::ReferenceExt;
+
+/// A platform to create iterators over references.
+#[must_use = "Iterators should be obtained from this iterator platform"]
+pub struct Platform<'r> {
+ pub(crate) platform: gix_ref::file::iter::Platform<'r>,
+ pub(crate) repo: &'r crate::Repository,
+}
+
+/// An iterator over references, with or without filter.
+pub struct Iter<'r> {
+ inner: gix_ref::file::iter::LooseThenPacked<'r, 'r>,
+ peel: bool,
+ repo: &'r crate::Repository,
+}
+
+impl<'r> Iter<'r> {
+ fn new(repo: &'r crate::Repository, platform: gix_ref::file::iter::LooseThenPacked<'r, 'r>) -> Self {
+ Iter {
+ inner: platform,
+ peel: false,
+ repo,
+ }
+ }
+}
+
+impl<'r> Platform<'r> {
+ /// Return an iterator over all references in the repository.
+ ///
+ /// Even broken or otherwise unparsable or inaccessible references are returned and have to be handled by the caller on a
+ /// case by case basis.
+ pub fn all(&self) -> Result<Iter<'_>, init::Error> {
+ Ok(Iter::new(self.repo, self.platform.all()?))
+ }
+
+ /// Return an iterator over all references that match the given `prefix`.
+ ///
+ /// These are of the form `refs/heads` or `refs/remotes/origin`, and must not contain relative paths components like `.` or `..`.
+ // TODO: Create a custom `Path` type that enforces the requirements of git naturally, this type is surprising possibly on windows
+ // and when not using a trailing '/' to signal directories.
+ pub fn prefixed(&self, prefix: impl AsRef<Path>) -> Result<Iter<'_>, init::Error> {
+ Ok(Iter::new(self.repo, self.platform.prefixed(prefix)?))
+ }
+
+ // TODO: tests
+ /// Return an iterator over all references that are tags.
+ ///
+ /// They are all prefixed with `refs/tags`.
+ pub fn tags(&self) -> Result<Iter<'_>, init::Error> {
+ Ok(Iter::new(self.repo, self.platform.prefixed("refs/tags/")?))
+ }
+
+ // TODO: tests
+ /// Return an iterator over all local branches.
+ ///
+ /// They are all prefixed with `refs/heads`.
+ pub fn local_branches(&self) -> Result<Iter<'_>, init::Error> {
+ Ok(Iter::new(self.repo, self.platform.prefixed("refs/heads/")?))
+ }
+
+ // TODO: tests
+ /// Return an iterator over all remote branches.
+ ///
+ /// They are all prefixed with `refs/remotes`.
+ pub fn remote_branches(&self) -> Result<Iter<'_>, init::Error> {
+ Ok(Iter::new(self.repo, self.platform.prefixed("refs/remotes/")?))
+ }
+}
+
+impl<'r> Iter<'r> {
+ /// Automatically peel references before yielding them during iteration.
+ ///
+ /// This has the same effect as using `iter.map(|r| {r.peel_to_id_in_place(); r})`.
+ ///
+ /// # Note
+ ///
+ /// Doing this is necessary as the packed-refs buffer is already held by the iterator, disallowing the consumer of the iterator
+ /// to peel the returned references themselves.
+ pub fn peeled(mut self) -> Self {
+ self.peel = true;
+ self
+ }
+}
+
+impl<'r> Iterator for Iter<'r> {
+ type Item = Result<crate::Reference<'r>, Box<dyn std::error::Error + Send + Sync + 'static>>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner.next().map(|res| {
+ res.map_err(|err| Box::new(err) as Box<dyn std::error::Error + Send + Sync + 'static>)
+ .and_then(|mut r| {
+ if self.peel {
+ let handle = &self.repo;
+ r.peel_to_id_in_place(&handle.refs, |oid, buf| {
+ handle
+ .objects
+ .try_find(oid, buf)
+ .map(|po| po.map(|(o, _l)| (o.kind, o.data)))
+ })
+ .map_err(|err| Box::new(err) as Box<dyn std::error::Error + Send + Sync + 'static>)
+ .map(|_| r)
+ } else {
+ Ok(r)
+ }
+ })
+ .map(|r| crate::Reference::from_ref(r, self.repo))
+ })
+ }
+}
+
+///
+pub mod init {
+ /// The error returned by [`Platform::all()`][super::Platform::all()] or [`Platform::prefixed()`][super::Platform::prefixed()].
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error(transparent)]
+ Io(#[from] std::io::Error),
+ }
+}
+
+/// The error returned by [references()][crate::Repository::references()].
+pub type Error = gix_ref::packed::buffer::open::Error;
diff --git a/vendor/gix/src/reference/log.rs b/vendor/gix/src/reference/log.rs
new file mode 100644
index 000000000..b516e6499
--- /dev/null
+++ b/vendor/gix/src/reference/log.rs
@@ -0,0 +1,36 @@
+//!
+use gix_object::commit::MessageRef;
+use gix_ref::file::ReferenceExt;
+
+use crate::{
+ bstr::{BStr, BString, ByteVec},
+ Reference,
+};
+
+impl<'repo> Reference<'repo> {
+ /// Return a platform for obtaining iterators over reference logs.
+ pub fn log_iter(&self) -> gix_ref::file::log::iter::Platform<'_, '_> {
+ self.inner.log_iter(&self.repo.refs)
+ }
+}
+
+/// Generate a message typical for git commit logs based on the given `operation`, commit `message` and `num_parents` of the commit.
+pub fn message(operation: &str, message: &BStr, num_parents: usize) -> BString {
+ let mut out = BString::from(operation);
+ if let Some(commit_type) = commit_type_by_parents(num_parents) {
+ out.push_str(b" (");
+ out.extend_from_slice(commit_type.as_bytes());
+ out.push_byte(b')');
+ }
+ out.push_str(b": ");
+ out.extend_from_slice(&MessageRef::from_bytes(message).summary());
+ out
+}
+
+pub(crate) fn commit_type_by_parents(count: usize) -> Option<&'static str> {
+ Some(match count {
+ 0 => "initial",
+ 1 => return None,
+ _two_or_more => "merge",
+ })
+}
diff --git a/vendor/gix/src/reference/mod.rs b/vendor/gix/src/reference/mod.rs
new file mode 100644
index 000000000..e2ee0d3b2
--- /dev/null
+++ b/vendor/gix/src/reference/mod.rs
@@ -0,0 +1,87 @@
+//!
+
+use gix_odb::pack::Find;
+use gix_ref::file::ReferenceExt;
+
+use crate::{Id, Reference};
+
+pub mod iter;
+///
+pub mod remote;
+
+mod errors;
+pub use errors::{edit, find, head_commit, head_id, peel};
+
+use crate::ext::ObjectIdExt;
+
+pub mod log;
+
+pub use gix_ref::{Category, Kind};
+
+/// Access
+impl<'repo> Reference<'repo> {
+ /// Returns the attached id we point to, or `None` if this is a symbolic ref.
+ pub fn try_id(&self) -> Option<Id<'repo>> {
+ match self.inner.target {
+ gix_ref::Target::Symbolic(_) => None,
+ gix_ref::Target::Peeled(oid) => oid.to_owned().attach(self.repo).into(),
+ }
+ }
+
+ /// Returns the attached id we point to, or panic if this is a symbolic ref.
+ pub fn id(&self) -> Id<'repo> {
+ self.try_id()
+ .expect("BUG: tries to obtain object id from symbolic target")
+ }
+
+ /// Return the target to which this reference points to.
+ pub fn target(&self) -> gix_ref::TargetRef<'_> {
+ self.inner.target.to_ref()
+ }
+
+ /// Return the reference's full name.
+ pub fn name(&self) -> &gix_ref::FullNameRef {
+ self.inner.name.as_ref()
+ }
+
+ /// Turn this instances into a stand-alone reference.
+ pub fn detach(self) -> gix_ref::Reference {
+ self.inner
+ }
+}
+
+impl<'repo> std::fmt::Debug for Reference<'repo> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Debug::fmt(&self.inner, f)
+ }
+}
+
+impl<'repo> Reference<'repo> {
+ pub(crate) fn from_ref(reference: gix_ref::Reference, repo: &'repo crate::Repository) -> Self {
+ Reference { inner: reference, repo }
+ }
+}
+
+impl<'repo> Reference<'repo> {
+ /// Follow all symbolic targets this reference might point to and peel the underlying object
+ /// to the end of the chain, and return it.
+ ///
+ /// This is useful to learn where this reference is ultimately pointing to.
+ pub fn peel_to_id_in_place(&mut self) -> Result<Id<'repo>, peel::Error> {
+ let repo = &self.repo;
+ let oid = self.inner.peel_to_id_in_place(&repo.refs, |oid, buf| {
+ repo.objects
+ .try_find(oid, buf)
+ .map(|po| po.map(|(o, _l)| (o.kind, o.data)))
+ })?;
+ Ok(Id::from_id(oid, repo))
+ }
+
+ /// Similar to [`peel_to_id_in_place()`][Reference::peel_to_id_in_place()], but consumes this instance.
+ pub fn into_fully_peeled_id(mut self) -> Result<Id<'repo>, peel::Error> {
+ self.peel_to_id_in_place()
+ }
+}
+
+mod edits;
+pub use edits::{delete, set_target_id};
diff --git a/vendor/gix/src/reference/remote.rs b/vendor/gix/src/reference/remote.rs
new file mode 100644
index 000000000..dd96892e2
--- /dev/null
+++ b/vendor/gix/src/reference/remote.rs
@@ -0,0 +1,49 @@
+use crate::{config, config::tree::Branch, remote, Reference};
+
+/// Remotes
+impl<'repo> Reference<'repo> {
+ /// Find the unvalidated name of our remote for `direction` as configured in `branch.<name>.remote|pushRemote` respectively.
+ /// If `Some(<name>)` it can be used in [`Repository::find_remote(…)`][crate::Repository::find_remote()], or if `None` then
+ /// [Repository::remote_default_name()][crate::Repository::remote_default_name()] could be used in its place.
+ ///
+ /// Return `None` if no remote is configured.
+ ///
+ /// # Note
+ ///
+ /// - it's recommended to use the [`remote(…)`][Self::remote()] method as it will configure the remote with additional
+ /// information.
+ /// - `branch.<name>.pushRemote` falls back to `branch.<name>.remote`.
+ pub fn remote_name(&self, direction: remote::Direction) -> Option<remote::Name<'repo>> {
+ let name = self.name().shorten();
+ let config = &self.repo.config.resolved;
+ (direction == remote::Direction::Push)
+ .then(|| {
+ config
+ .string("branch", Some(name), Branch::PUSH_REMOTE.name)
+ .or_else(|| config.string("remote", None, config::tree::Remote::PUSH_DEFAULT.name))
+ })
+ .flatten()
+ .or_else(|| config.string("branch", Some(name), Branch::REMOTE.name))
+ .and_then(|name| name.try_into().ok())
+ }
+
+ /// Like [`remote_name(…)`][Self::remote_name()], but configures the returned `Remote` with additional information like
+ ///
+ /// - `branch.<name>.merge` to know which branch on the remote side corresponds to this one for merging when pulling.
+ ///
+ /// It also handles if the remote is a configured URL, which has no name.
+ pub fn remote(
+ &self,
+ direction: remote::Direction,
+ ) -> Option<Result<crate::Remote<'repo>, remote::find::existing::Error>> {
+ // TODO: use `branch.<name>.merge`
+ self.remote_name(direction).map(|name| match name {
+ remote::Name::Symbol(name) => self.repo.find_remote(name.as_ref()).map_err(Into::into),
+ remote::Name::Url(url) => gix_url::parse(url.as_ref()).map_err(Into::into).and_then(|url| {
+ self.repo
+ .remote_at(url)
+ .map_err(|err| remote::find::existing::Error::Find(remote::find::Error::Init(err)))
+ }),
+ })
+ }
+}