1#![deny(missing_docs, rust_2018_idioms)]
3#![forbid(unsafe_code)]
4
5#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub enum Update {
9 Shallow(gix_hash::ObjectId),
11 Unshallow(gix_hash::ObjectId),
13}
14
15pub fn read(shallow_file: &std::path::Path) -> Result<Option<nonempty::NonEmpty<gix_hash::ObjectId>>, read::Error> {
21 use bstr::ByteSlice;
22 let buf = match std::fs::read(shallow_file) {
23 Ok(buf) => buf,
24 Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(None),
25 Err(err) => return Err(err.into()),
26 };
27
28 let mut commits = buf
29 .lines()
30 .map(gix_hash::ObjectId::from_hex)
31 .collect::<Result<Vec<_>, _>>()?;
32
33 commits.sort();
34 Ok(nonempty::NonEmpty::from_vec(commits))
35}
36
37pub mod write {
39 pub(crate) mod function {
40 use std::io::Write;
41
42 use super::Error;
43 use crate::Update;
44
45 pub fn write(
54 mut file: gix_lock::File,
55 shallow_commits: Option<nonempty::NonEmpty<gix_hash::ObjectId>>,
56 updates: &[Update],
57 ) -> Result<(), Error> {
58 let mut shallow_commits = shallow_commits.map(Vec::from).unwrap_or_default();
59 for update in updates {
60 match update {
61 Update::Shallow(id) => {
62 shallow_commits.push(*id);
63 }
64 Update::Unshallow(id) => shallow_commits.retain(|oid| oid != id),
65 }
66 }
67 if shallow_commits.is_empty() {
68 if let Err(err) = std::fs::remove_file(file.resource_path()) {
69 if err.kind() != std::io::ErrorKind::NotFound {
70 return Err(err.into());
71 }
72 }
73 drop(file);
74 return Ok(());
75 }
76 shallow_commits.sort();
77 let mut buf = Vec::<u8>::new();
78 for commit in shallow_commits {
79 commit.write_hex_to(&mut buf).map_err(Error::Io)?;
80 buf.push(b'\n');
81 }
82 file.write_all(&buf).map_err(Error::Io)?;
83 file.flush().map_err(Error::Io)?;
84 file.commit()?;
85 Ok(())
86 }
87 }
88
89 #[derive(Debug, thiserror::Error)]
91 #[allow(missing_docs)]
92 pub enum Error {
93 #[error(transparent)]
94 Commit(#[from] gix_lock::commit::Error<gix_lock::File>),
95 #[error("Could not remove an empty shallow file")]
96 RemoveEmpty(#[from] std::io::Error),
97 #[error("Failed to write object id to shallow file")]
98 Io(std::io::Error),
99 }
100}
101pub use write::function::write;
102
103pub mod read {
105 #[derive(Debug, thiserror::Error)]
107 #[allow(missing_docs)]
108 pub enum Error {
109 #[error("Could not open shallow file for reading")]
110 Io(#[from] std::io::Error),
111 #[error("Could not decode a line in shallow file as hex-encoded object hash")]
112 DecodeHash(#[from] gix_hash::decode::Error),
113 }
114}