Struct git_ref::file::loose::Reference

source ·
pub struct Reference {
    pub name: FullName,
    pub target: Target,
}
Expand description

A git ref which is stored in a file.

Fields§

§name: FullName

The path to uniquely identify this ref within its store.

§target: Target

The target of the reference, either a symbolic reference by full name or an object by its id.

Implementations§

Returns true if a reflog exists in the given store.

Please note that this method shouldn’t be used to check if a log exists before trying to read it, but instead is meant to be the fastest possible way to determine if a log exists or not. If the caller needs to know if it’s readable, try to read the log instead with a reverse or forward iterator.

Return a reflog reverse iterator for this ref, reading chunks from the back into the fixed buffer buf, in the given store.

The iterator will traverse log entries from most recent to oldest, reading the underlying file in chunks from the back. Return Ok(None) if no reflog exists.

Return a reflog forward iterator for this ref and write its file contents into buf, in the given store.

The iterator will traverse log entries from oldest to newest. Return Ok(None) if no reflog exists.

Create a new reference of the given parent store with relative_path service as unique identifier at which the path_contents was read to obtain the refs value.

Examples found in repository?
src/store/file/overlay_iter.rs (line 95)
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
    fn convert_loose(&mut self, res: std::io::Result<(PathBuf, FullName)>) -> Result<Reference, Error> {
        let (refpath, name) = res.map_err(Error::Traversal)?;
        std::fs::File::open(&refpath)
            .and_then(|mut f| {
                self.buf.clear();
                f.read_to_end(&mut self.buf)
            })
            .map_err(|err| Error::ReadFileContents {
                source: err,
                path: refpath.to_owned(),
            })?;
        loose::Reference::try_from_path(name, &self.buf)
            .map_err(|err| {
                let relative_path = refpath
                    .strip_prefix(self.git_dir)
                    .ok()
                    .or_else(|| {
                        self.common_dir
                            .and_then(|common_dir| refpath.strip_prefix(common_dir).ok())
                    })
                    .expect("one of our bases contains the path");
                Error::ReferenceCreation {
                    source: err,
                    relative_path: relative_path.into(),
                }
            })
            .map(Into::into)
            .map(|r| self.strip_namespace(r))
    }
More examples
Hide additional examples
src/store/file/find.rs (line 142)
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
    fn find_inner(
        &self,
        inbetween: &str,
        partial_name: &PartialNameRef,
        packed: Option<&packed::Buffer>,
        transform: Transform,
        path_buf: &mut BString,
    ) -> Result<Option<Reference>, Error> {
        let add_refs_prefix = matches!(transform, Transform::EnforceRefsPrefix);
        let full_name = partial_name.construct_full_name_ref(add_refs_prefix, inbetween, path_buf);
        let content_buf = self.ref_contents(full_name).map_err(|err| Error::ReadFileContents {
            source: err,
            path: self.reference_path(full_name),
        })?;

        match content_buf {
            None => {
                if let Some(packed) = packed {
                    if let Some(full_name) = packed::find::transform_full_name_for_lookup(full_name) {
                        let full_name_backing;
                        let full_name = match &self.namespace {
                            Some(namespace) => {
                                full_name_backing = namespace.to_owned().into_namespaced_name(full_name);
                                full_name_backing.as_ref()
                            }
                            None => full_name,
                        };
                        if let Some(packed_ref) = packed.try_find_full_name(full_name)? {
                            let mut res: Reference = packed_ref.into();
                            if let Some(namespace) = &self.namespace {
                                res.strip_namespace(namespace);
                            }
                            return Ok(Some(res));
                        };
                    }
                }
                Ok(None)
            }
            Some(content) => Ok(Some(
                loose::Reference::try_from_path(full_name.to_owned(), &content)
                    .map(Into::into)
                    .map(|mut r: Reference| {
                        if let Some(namespace) = &self.namespace {
                            r.strip_namespace(namespace);
                        }
                        r
                    })
                    .map_err(|err| Error::ReferenceCreation {
                        source: err,
                        relative_path: full_name.to_path().to_owned(),
                    })?,
            )),
        }
    }
src/store/file/transaction/prepare.rs (line 37)
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
    fn lock_ref_and_apply_change(
        store: &file::Store,
        lock_fail_mode: git_lock::acquire::Fail,
        packed: Option<&packed::Buffer>,
        change: &mut Edit,
        has_global_lock: bool,
        direct_to_packed_refs: bool,
    ) -> Result<(), Error> {
        use std::io::Write;
        assert!(
            change.lock.is_none(),
            "locks can only be acquired once and it's all or nothing"
        );

        let existing_ref = store
            .ref_contents(change.update.name.as_ref())
            .map_err(Error::from)
            .and_then(|maybe_loose| {
                maybe_loose
                    .map(|buf| {
                        loose::Reference::try_from_path(change.update.name.clone(), &buf)
                            .map(Reference::from)
                            .map_err(Error::from)
                    })
                    .transpose()
            })
            .or_else(|err| match err {
                Error::ReferenceDecode(_) => Ok(None),
                other => Err(other),
            })
            .and_then(|maybe_loose| match (maybe_loose, packed) {
                (None, Some(packed)) => packed
                    .try_find(change.update.name.as_ref())
                    .map(|opt| opt.map(Into::into))
                    .map_err(Error::from),
                (None, None) => Ok(None),
                (maybe_loose, _) => Ok(maybe_loose),
            });
        let lock = match &mut change.update.change {
            Change::Delete { expected, .. } => {
                let (base, relative_path) = store.reference_path_with_base(change.update.name.as_ref());
                let lock = if has_global_lock {
                    None
                } else {
                    git_lock::Marker::acquire_to_hold_resource(
                        base.join(relative_path.as_ref()),
                        lock_fail_mode,
                        Some(base.clone().into_owned()),
                    )
                    .map_err(|err| Error::LockAcquire {
                        source: err,
                        full_name: "borrowchk won't allow change.name()".into(),
                    })?
                    .into()
                };

                let existing_ref = existing_ref?;
                match (&expected, &existing_ref) {
                    (PreviousValue::MustNotExist, _) => {
                        panic!("BUG: MustNotExist constraint makes no sense if references are to be deleted")
                    }
                    (PreviousValue::ExistingMustMatch(_), None)
                    | (PreviousValue::MustExist, Some(_))
                    | (PreviousValue::Any, Some(_))
                    | (PreviousValue::Any, None) => {}
                    (PreviousValue::MustExist, None) | (PreviousValue::MustExistAndMatch(_), None) => {
                        return Err(Error::DeleteReferenceMustExist {
                            full_name: change.name(),
                        })
                    }
                    (PreviousValue::MustExistAndMatch(previous), Some(existing))
                    | (PreviousValue::ExistingMustMatch(previous), Some(existing)) => {
                        let actual = existing.target.clone();
                        if *previous != actual {
                            let expected = previous.clone();
                            return Err(Error::ReferenceOutOfDate {
                                full_name: change.name(),
                                expected,
                                actual,
                            });
                        }
                    }
                }

                // Keep the previous value for the caller and ourselves. Maybe they want to keep a log of sorts.
                if let Some(existing) = existing_ref {
                    *expected = PreviousValue::MustExistAndMatch(existing.target);
                }

                lock
            }
            Change::Update { expected, new, .. } => {
                let (base, relative_path) = store.reference_path_with_base(change.update.name.as_ref());
                let obtain_lock = || {
                    git_lock::File::acquire_to_update_resource(
                        base.join(relative_path.as_ref()),
                        lock_fail_mode,
                        Some(base.clone().into_owned()),
                    )
                    .map_err(|err| Error::LockAcquire {
                        source: err,
                        full_name: "borrowchk won't allow change.name() and this will be corrected by caller".into(),
                    })
                };
                let mut lock = (!has_global_lock).then(obtain_lock).transpose()?;

                let existing_ref = existing_ref?;
                match (&expected, &existing_ref) {
                    (PreviousValue::Any, _)
                    | (PreviousValue::MustExist, Some(_))
                    | (PreviousValue::MustNotExist, None)
                    | (PreviousValue::ExistingMustMatch(_), None) => {}
                    (PreviousValue::MustExist, None) => {
                        let expected = Target::Peeled(store.object_hash.null());
                        let full_name = change.name();
                        return Err(Error::MustExist { full_name, expected });
                    }
                    (PreviousValue::MustNotExist, Some(existing)) => {
                        if existing.target != *new {
                            let new = new.clone();
                            return Err(Error::MustNotExist {
                                full_name: change.name(),
                                actual: existing.target.clone(),
                                new,
                            });
                        }
                    }
                    (PreviousValue::MustExistAndMatch(previous), Some(existing))
                    | (PreviousValue::ExistingMustMatch(previous), Some(existing)) => {
                        if *previous != existing.target {
                            let actual = existing.target.clone();
                            let expected = previous.to_owned();
                            let full_name = change.name();
                            return Err(Error::ReferenceOutOfDate {
                                full_name,
                                actual,
                                expected,
                            });
                        }
                    }

                    (PreviousValue::MustExistAndMatch(previous), None) => {
                        let expected = previous.to_owned();
                        let full_name = change.name();
                        return Err(Error::MustExist { full_name, expected });
                    }
                };

                fn new_would_change_existing(new: &Target, existing: &Target) -> (bool, bool) {
                    match (new, existing) {
                        (Target::Peeled(new), Target::Peeled(old)) => (old != new, false),
                        (Target::Symbolic(new), Target::Symbolic(old)) => (old != new, true),
                        (Target::Peeled(_), _) => (true, false),
                        (Target::Symbolic(_), _) => (true, true),
                    }
                }

                let (is_effective, is_symbolic) = if let Some(existing) = existing_ref {
                    let (effective, is_symbolic) = new_would_change_existing(new, &existing.target);
                    *expected = PreviousValue::MustExistAndMatch(existing.target);
                    (effective, is_symbolic)
                } else {
                    (true, matches!(new, Target::Symbolic(_)))
                };

                if (is_effective && !direct_to_packed_refs) || is_symbolic {
                    let mut lock = lock.take().map(Ok).unwrap_or_else(obtain_lock)?;

                    lock.with_mut(|file| match new {
                        Target::Peeled(oid) => write!(file, "{}", oid),
                        Target::Symbolic(name) => write!(file, "ref: {}", name.0),
                    })?;
                    Some(lock.close()?)
                } else {
                    None
                }
            }
        };
        change.lock = lock;
        Ok(())
    }

Return the kind of ref.

Trait Implementations§

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
This method returns an Ordering between self and other. Read more
Compares and returns the maximum of two values. Read more
Compares and returns the minimum of two values. Read more
Restrict a value to a certain interval. Read more
This method tests for self and other values to be equal, and is used by ==.
This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
This method returns an ordering between self and other values if one exists. Read more
This method tests less than (for self and other) and is used by the < operator. Read more
This method tests less than or equal to (for self and other) and is used by the <= operator. Read more
This method tests greater than (for self and other) and is used by the > operator. Read more
This method tests greater than or equal to (for self and other) and is used by the >= operator. Read more

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.