Skip to content

Commit 048e43e

Browse files
committed
Merge branch 'push-wwxrqxuzmolm'
2 parents 68fd5b3 + 4faf10e commit 048e43e

File tree

4 files changed

+107
-67
lines changed
  • gix-ref
  • gix-transport/src/client/blocking_io

4 files changed

+107
-67
lines changed

gix-ref/src/store/file/transaction/prepare.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,8 @@ impl<'s, 'p> Transaction<'s, 'p> {
287287
..edit.update.clone()
288288
});
289289
*num_updates += 1;
290+
continue;
290291
}
291-
continue;
292292
}
293293
match edit.update.change {
294294
Change::Update {

gix-ref/tests/file/store/find.rs

+35-32
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
mod existing {
2-
use gix_ref::{PartialName, PartialNameRef};
3-
42
use crate::{file::store_at, hex_to_id};
53

64
#[test]
@@ -13,12 +11,41 @@ mod existing {
1311
Ok(())
1412
}
1513

16-
// TODO: figure this out
17-
#[test]
18-
fn possible_inputs() -> crate::Result {
19-
let store = crate::file::store()?;
20-
store.find_loose("dt1")?;
21-
store.find_loose(&String::from("dt1"))?; // Owned Strings don't have an impl for PartialName
14+
mod convert {
15+
use gix_ref::{PartialName, PartialNameRef};
16+
17+
// TODO: figure this out
18+
#[test]
19+
fn possible_inputs() -> crate::Result {
20+
let store = crate::file::store()?;
21+
store.find_loose("dt1")?;
22+
store.find_loose(&String::from("dt1"))?; // Owned Strings don't have an impl for PartialName
23+
24+
store.find_loose(&CustomType("dt1".into()))?;
25+
26+
let name = CustomName {
27+
remote: "origin",
28+
branch: "main",
29+
};
30+
store.find_loose(&name.to_partial_name())?;
31+
// TODO: this effectively needs a `Cow<'_, PartialNameRef>`, but we are not allowed to implement conversions for it.
32+
// After having been there, I don't want to have a `PartialNameCow(Cow<'_, PartialNameRef)` anymore, nor
33+
// copies of `TryFrom/TryInto` traits in our crate.
34+
// Make it work once we can implement standard traits for Cow<OurType>.
35+
// store.find_loose(&name)?;
36+
// store.find_loose(name.to_partial_name())?;
37+
store.find_loose(&name.to_partial_name_from_string())?;
38+
store.find_loose(&name.to_partial_name_from_bstring())?;
39+
store.find_loose(&name.to_full_name())?;
40+
store.find_loose(name.to_full_name().as_ref())?;
41+
store.find_loose(name.to_full_name().as_ref().as_partial_name())?;
42+
store.find_loose(&PartialName::try_from(name.remote)?.join(name.branch.into())?)?;
43+
store.find_loose(&PartialName::try_from("origin")?.join("main".into())?)?;
44+
store.find_loose(&PartialName::try_from("origin")?.join(String::from("main").as_str().into())?)?;
45+
store.find_loose(&PartialName::try_from("origin")?.join("main".into())?)?;
46+
47+
Ok(())
48+
}
2249

2350
struct CustomType(String);
2451
impl<'a> TryFrom<&'a CustomType> for &'a PartialNameRef {
@@ -28,7 +55,6 @@ mod existing {
2855
value.0.as_str().try_into()
2956
}
3057
}
31-
store.find_loose(&CustomType("dt1".into()))?;
3258

3359
struct CustomName {
3460
remote: &'static str,
@@ -61,29 +87,6 @@ mod existing {
6187
PartialName::try_from(value.to_partial_name())
6288
}
6389
}
64-
65-
let name = CustomName {
66-
remote: "origin",
67-
branch: "main",
68-
};
69-
store.find_loose(&name.to_partial_name())?;
70-
// TODO: this effectively needs a `Cow<'_, PartialNameRef>`, but we are not allowed to implement conversions for it.
71-
// After having been there, I don't want to have a `PartialNameCow(Cow<'_, PartialNameRef)` anymore, nor
72-
// copies of `TryFrom/TryInto` traits in our crate.
73-
// Make it work once we can implement standard traits for Cow<OurType>.
74-
// store.find_loose(&name)?;
75-
// store.find_loose(name.to_partial_name())?;
76-
store.find_loose(&name.to_partial_name_from_string())?;
77-
store.find_loose(&name.to_partial_name_from_bstring())?;
78-
store.find_loose(&name.to_full_name())?;
79-
store.find_loose(name.to_full_name().as_ref())?;
80-
store.find_loose(name.to_full_name().as_ref().as_partial_name())?;
81-
store.find_loose(&PartialName::try_from(name.remote)?.join(name.branch.into())?)?;
82-
store.find_loose(&PartialName::try_from("origin")?.join("main".into())?)?;
83-
store.find_loose(&PartialName::try_from("origin")?.join(String::from("main").as_str().into())?)?;
84-
store.find_loose(&PartialName::try_from("origin")?.join("main".into())?)?;
85-
86-
Ok(())
8790
}
8891
}
8992

gix-ref/tests/file/transaction/prepare_and_commit/create_or_update/mod.rs

+36
Original file line numberDiff line numberDiff line change
@@ -813,3 +813,39 @@ fn packed_refs_creation_with_packed_refs_mode_leave_keeps_original_loose_refs()
813813
);
814814
Ok(())
815815
}
816+
817+
#[test]
818+
fn packed_refs_deletion_in_deletions_and_updates_mode() -> crate::Result {
819+
let (_keep, store) = store_writable("make_packed_ref_repository.sh")?;
820+
assert!(
821+
store.try_find_loose("refs/heads/d1")?.is_none(),
822+
"no loose d1 available, it's packed"
823+
);
824+
let odb = gix_odb::at(store.git_dir().join("objects"))?;
825+
let old_id = hex_to_id("134385f6d781b7e97062102c6a483440bfda2a03");
826+
let edits = store
827+
.transaction()
828+
.packed_refs(PackedRefs::DeletionsAndNonSymbolicUpdates(Box::new(odb)))
829+
.prepare(
830+
Some(RefEdit {
831+
change: Change::Delete {
832+
expected: PreviousValue::MustExistAndMatch(Target::Peeled(old_id)),
833+
log: RefLog::AndReference,
834+
},
835+
name: "refs/heads/d1".try_into()?,
836+
deref: false,
837+
}),
838+
Fail::Immediately,
839+
Fail::Immediately,
840+
)?
841+
.commit(committer().to_ref())?;
842+
843+
assert_eq!(edits.len(), 1, "only one edit was performed in the packed refs store");
844+
845+
let packed = store.open_packed_buffer().unwrap().expect("packed refs is available");
846+
assert!(
847+
packed.try_find("refs/heads/d1")?.is_none(),
848+
"d1 should be removed from packed refs"
849+
);
850+
Ok(())
851+
}

gix-transport/src/client/blocking_io/file.rs

+35-34
Original file line numberDiff line numberDiff line change
@@ -143,45 +143,46 @@ struct ReadStdoutFailOnError {
143143
read: std::process::ChildStdout,
144144
}
145145

146+
impl std::io::Read for ReadStdoutFailOnError {
147+
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
148+
let res = self.read.read(buf);
149+
self.swap_err_if_present_in_stderr(buf.len(), res)
150+
}
151+
}
152+
153+
impl ReadStdoutFailOnError {
154+
fn swap_err_if_present_in_stderr(&self, wanted: usize, res: std::io::Result<usize>) -> std::io::Result<usize> {
155+
match self.recv.try_recv().ok() {
156+
Some(err) => Err(err),
157+
None => match res {
158+
Ok(n) if n == wanted => Ok(n),
159+
Ok(n) => {
160+
// TODO: fix this
161+
// When parsing refs this seems to happen legitimately
162+
// (even though we read packet lines only and should always know exactly how much to read)
163+
// Maybe this still happens in `read_exact()` as sometimes we just don't get enough bytes
164+
// despite knowing how many.
165+
// To prevent deadlock, we have to set a timeout which slows down legitimate parts of the protocol.
166+
// This code was specifically written to make the `cargo` test-suite pass, and we can reduce
167+
// the timeouts even more once there is a native ssh transport that is used by `cargo`, it will
168+
// be able to handle these properly.
169+
// Alternatively, one could implement something like `read2` to avoid blocking on stderr entirely.
170+
self.recv
171+
.recv_timeout(std::time::Duration::from_millis(5))
172+
.ok()
173+
.map_or(Ok(n), Err)
174+
}
175+
Err(err) => Err(self.recv.recv().ok().unwrap_or(err)),
176+
},
177+
}
178+
}
179+
}
180+
146181
fn supervise_stderr(
147182
ssh_kind: ssh::ProgramKind,
148183
stderr: std::process::ChildStderr,
149184
stdout: std::process::ChildStdout,
150185
) -> ReadStdoutFailOnError {
151-
impl ReadStdoutFailOnError {
152-
fn swap_err_if_present_in_stderr(&self, wanted: usize, res: std::io::Result<usize>) -> std::io::Result<usize> {
153-
match self.recv.try_recv().ok() {
154-
Some(err) => Err(err),
155-
None => match res {
156-
Ok(n) if n == wanted => Ok(n),
157-
Ok(n) => {
158-
// TODO: fix this
159-
// When parsing refs this seems to happen legitimately
160-
// (even though we read packet lines only and should always know exactly how much to read)
161-
// Maybe this still happens in `read_exact()` as sometimes we just don't get enough bytes
162-
// despite knowing how many.
163-
// To prevent deadlock, we have to set a timeout which slows down legitimate parts of the protocol.
164-
// This code was specifically written to make the `cargo` test-suite pass, and we can reduce
165-
// the timeouts even more once there is a native ssh transport that is used by `cargo`, it will
166-
// be able to handle these properly.
167-
// Alternatively, one could implement something like `read2` to avoid blocking on stderr entirely.
168-
self.recv
169-
.recv_timeout(std::time::Duration::from_millis(5))
170-
.ok()
171-
.map_or(Ok(n), Err)
172-
}
173-
Err(err) => Err(self.recv.recv().ok().unwrap_or(err)),
174-
},
175-
}
176-
}
177-
}
178-
impl std::io::Read for ReadStdoutFailOnError {
179-
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
180-
let res = self.read.read(buf);
181-
self.swap_err_if_present_in_stderr(buf.len(), res)
182-
}
183-
}
184-
185186
let (send, recv) = std::sync::mpsc::sync_channel(1);
186187
std::thread::Builder::new()
187188
.name("supervise ssh stderr".into())

0 commit comments

Comments
 (0)