Unified · Split
| @@ -20,7 +20,7 @@ impl Default for WriteReflog { · 19 unmodified lines | ||
| 20 | 20 | pub struct Reference<'a> { |
| 21 | 21 | parent: &'a Store, |
| 22 | 22 | /// The path to uniquely identify this ref within its store. |
| 23 | − pub relative_path: PathBuf, | |
| 23 | + relative_path: PathBuf, | |
| 24 | 24 | state: reference::State, |
| 25 | 25 | } |
| 26 | 26 | |
| @@ -1,6 +1,8 @@ | ||
| 1 | +use crate::transaction::FullName; | |
| 1 | 2 | use crate::{file::Reference, Kind, Target}; |
| 2 | 3 | use bstr::BString; |
| 3 | 4 | use git_hash::{oid, ObjectId}; |
| 5 | +use std::path::Path; | |
| 4 | 6 | |
| 5 | 7 | #[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash, Clone)] |
| 6 | 8 | #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] |
| @@ -33,6 +35,18 @@ impl<'a> Reference<'a> { · 26 unmodified lines | ||
| 33 | 35 | State::Id(ref oid) => Target::Peeled(oid.as_ref()), |
| 34 | 36 | } |
| 35 | 37 | } |
| 38 | + | |
| 39 | + /// Return the full name of this reference as path | |
| 40 | + pub fn relative_path(&self) -> &Path { | |
| 41 | + &self.relative_path | |
| 42 | + } | |
| 43 | + | |
| 44 | + /// Return the full validated name of the reference | |
| 45 | + pub fn name(&self) -> FullName { | |
| 46 | + use os_str_bytes::OsStrBytes; | |
| 47 | + let name = self.relative_path.as_path().to_raw_bytes(); | |
| 48 | + FullName(name.to_vec().into()) | |
| 49 | + } | |
| 36 | 50 | } |
| 37 | 51 | |
| 38 | 52 | mod iter; |
| @@ -35,7 +35,7 @@ use std::{borrow::Cow, convert::TryFrom, path::Path}; · 34 unmodified lines | ||
| 35 | 35 | /// Indicate that the given BString is a validate reference name or path that can be used as path on disk or written as target |
| 36 | 36 | /// of a symbolic reference |
| 37 | 37 | #[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)] |
| 38 | −pub struct FullName(BString); | |
| 38 | +pub struct FullName(pub(crate) BString); | |
| 39 | 39 | |
| 40 | 40 | impl TryFrom<&str> for FullName { |
| 41 | 41 | type Error = git_validate::refname::Error; |
| @@ -55,7 +55,7 @@ mod peel { · 54 unmodified lines | ||
| 55 | 55 | r.peel_to_id_in_place()?, |
| 56 | 56 | hex_to_id("134385f6d781b7e97062102c6a483440bfda2a03") |
| 57 | 57 | ); |
| 58 | − assert_eq!(r.relative_path, Path::new("refs/remotes/origin/multi-link-target3")); | |
| 58 | + assert_eq!(r.relative_path(), Path::new("refs/remotes/origin/multi-link-target3")); | |
| 59 | 59 | |
| 60 | 60 | Ok(()) |
| 61 | 61 | } |
| @@ -65,14 +65,14 @@ mod peel { · 3 unmodified lines | ||
| 65 | 65 | let store = file::store()?; |
| 66 | 66 | let mut r = store.find_one_existing("loop-a")?; |
| 67 | 67 | assert_eq!(r.kind(), git_ref::Kind::Symbolic, "there is something to peel"); |
| 68 | − assert_eq!(r.relative_path, Path::new("refs/loop-a")); | |
| 68 | + assert_eq!(r.relative_path(), Path::new("refs/loop-a")); | |
| 69 | 69 | |
| 70 | 70 | assert!(matches!( |
| 71 | 71 | r.peel_to_id_in_place().unwrap_err(), |
| 72 | 72 | git_ref::file::reference::peel::to_id::Error::Cycle { .. } |
| 73 | 73 | )); |
| 74 | 74 | assert_eq!( |
| 75 | − r.relative_path, | |
| 75 | + r.relative_path(), | |
| 76 | 76 | Path::new("refs/loop-a"), |
| 77 | 77 | "the ref is not changed on error" |
| 78 | 78 | ); |
| @@ -11,7 +11,7 @@ mod existing { · 10 unmodified lines | ||
| 11 | 11 | for (partial_name, expected_path) in &[("main", Some("refs/heads/main")), ("does-not-exist", None)] { |
| 12 | 12 | let reference = store.find_one_existing(*partial_name); |
| 13 | 13 | match expected_path { |
| 14 | − Some(expected_path) => assert_eq!(reference?.relative_path, Path::new(expected_path)), | |
| 14 | + Some(expected_path) => assert_eq!(reference?.relative_path(), Path::new(expected_path)), | |
| 15 | 15 | None => match reference { |
| 16 | 16 | Ok(_) => panic!("Expected error"), |
| 17 | 17 | Err(git_ref::file::find_one::existing::Error::NotFound(name)) => { |
| @@ -42,7 +42,7 @@ fn success() -> crate::Result { · 24 unmodified lines | ||
| 42 | 42 | ("refs/heads/main", "refs/heads/main", git_ref::Kind::Peeled), |
| 43 | 43 | ] { |
| 44 | 44 | let reference = store.find_one(*partial_name)?.expect("exists"); |
| 45 | − assert_eq!(reference.relative_path, Path::new(expected_path)); | |
| 45 | + assert_eq!(reference.relative_path(), Path::new(expected_path)); | |
| 46 | 46 | assert_eq!(reference.target().kind(), *expected_ref_kind); |
| 47 | 47 | } |
| 48 | 48 | Ok(()) |
| @@ -11,6 +11,7 @@ mod prepare_and_commit { · 10 unmodified lines | ||
| 11 | 11 | mod create { |
| 12 | 12 | use crate::file::transaction::prepare_and_commit::empty_store; |
| 13 | 13 | use bstr::ByteSlice; |
| 14 | + use git_lock::acquire::Fail; | |
| 14 | 15 | use git_ref::transaction::{Change, RefEdit, Reflog, Target}; |
| 15 | 16 | use std::{convert::TryInto, path::Path}; |
| 16 | 17 | |
| @@ -49,12 +50,12 @@ mod prepare_and_commit { · 32 unmodified lines | ||
| 49 | 50 | }, |
| 50 | 51 | name: "HEAD".try_into()?, |
| 51 | 52 | }), |
| 52 | − git_lock::acquire::Fail::Immediately, | |
| 53 | + Fail::Immediately, | |
| 53 | 54 | ); |
| 54 | 55 | let edits = t.commit()?; |
| 55 | 56 | assert_eq!(edits.len(), 1, "no split was performed"); |
| 56 | 57 | let written = store.find_one_existing(edits[0].name.to_partial())?; |
| 57 | − assert_eq!(written.relative_path, Path::new("HEAD")); | |
| 58 | + assert_eq!(written.relative_path(), Path::new("HEAD")); | |
| 58 | 59 | assert_eq!(written.kind(), git_ref::Kind::Symbolic); |
| 59 | 60 | assert_eq!(written.target().as_name(), Some(referent.as_bytes().as_bstr())); |
| 60 | 61 | assert!(!written.log_exists()?, "no revlog is written for symbolic ref"); |
| @@ -83,6 +84,7 @@ mod prepare_and_commit { · 22 unmodified lines | ||
| 83 | 84 | use crate::file::store_writable; |
| 84 | 85 | use crate::file::transaction::prepare_and_commit::empty_store; |
| 85 | 86 | use git_hash::ObjectId; |
| 87 | + use git_lock::acquire::Fail; | |
| 86 | 88 | use git_ref::{ |
| 87 | 89 | file::WriteReflog, |
| 88 | 90 | transaction::{Change, RefEdit, Target}, |
| @@ -98,7 +100,7 @@ mod prepare_and_commit { · 9 unmodified lines | ||
| 98 | 100 | change: Change::Delete { previous: None }, |
| 99 | 101 | name: "DOES_NOT_EXIST".try_into().unwrap(), |
| 100 | 102 | }), |
| 101 | − git_lock::acquire::Fail::Immediately, | |
| 103 | + Fail::Immediately, | |
| 102 | 104 | ) |
| 103 | 105 | .commit() |
| 104 | 106 | .unwrap(); |
| @@ -116,7 +118,7 @@ mod prepare_and_commit { · 11 unmodified lines | ||
| 116 | 118 | }, |
| 117 | 119 | name: "DOES_NOT_EXIST".try_into().unwrap(), |
| 118 | 120 | }), |
| 119 | − git_lock::acquire::Fail::Immediately, | |
| 121 | + Fail::Immediately, | |
| 120 | 122 | ) |
| 121 | 123 | .commit(); |
| 122 | 124 | match res { |
| @@ -128,9 +130,34 @@ mod prepare_and_commit { · 5 unmodified lines | ||
| 128 | 130 | } |
| 129 | 131 | } |
| 130 | 132 | |
| 133 | + #[test] | |
| 134 | + #[should_panic] | |
| 135 | + fn delete_reflog_only_of_symbolic_no_deref() { | |
| 136 | + let (_keep, store) = store_writable("make_repo_for_reflog.sh").unwrap(); | |
| 137 | + let head = store.find_one_existing("HEAD").unwrap(); | |
| 138 | + assert!(head.log_exists().unwrap()); | |
| 139 | + | |
| 140 | + let edits = store | |
| 141 | + .transaction( | |
| 142 | + Some(RefEdit { | |
| 143 | + change: Change::Delete { | |
| 144 | + previous: Some(Target::Peeled(ObjectId::null_sha1())), | |
| 145 | + }, | |
| 146 | + name: head.name().into(), | |
| 147 | + }), | |
| 148 | + Fail::Immediately, | |
| 149 | + ) | |
| 150 | + .commit() | |
| 151 | + .unwrap(); | |
| 152 | + | |
| 153 | + assert_eq!(edits.len(), 1); | |
| 154 | + let head = store.find_one_existing("HEAD").unwrap(); | |
| 155 | + assert!(!head.log_exists().unwrap()); | |
| 156 | + } | |
| 157 | + | |
| 131 | 158 | #[test] |
| 132 | 159 | #[ignore] |
| 133 | − fn delete_reflog_only() { | |
| 160 | + fn delete_reflog_only_of_symbolic_with_deref() { | |
| 134 | 161 | let _store = store_writable("make_repo_for_reflog.sh").unwrap(); |
| 135 | 162 | todo!("assure it won't delete the ref") |
| 136 | 163 | } |