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