6F6AAHK4M2IVS23TVISR5OJSTZXUSEKLOP5BMM7SUHYG2FQNTSGQC
6O43WXDAXZX3H5XDE6KOANIJXYVCK2HAC247H7PCENJT3IFURTWQC
TYAKEAJLABCZQDYAI4YBGIJNQ7HJS4DVULEGPCZOGJPJUYYNR6TAC
F2S6XETO6DQ4447O4WPAHISGTBRVWW2WZYJ633KKYWWYKW5GXBPQC
SXEYMYF7P4RZMZ46WPL4IZUTSQ2ATBWYZX7QNVMS3SGOYXYOHAGQC
OU6JOR3CDZTH2H3NTGMV3WDIAWPD3VEJI7JRY3VJ7LPDR3QOA52QC
I52XSRUH5RVHQBFWVMAQPTUSPAJ4KNVID2RMI3UGCVKFLYUO6WZAC
JL4WKA5PBKXRNAMETYO4I52QKASQ3COYHH2JKGA7W5YLIRZZH53AC
YN63NUZO4LVJ7XPMURDULTXBVJKW5MVCTZ24R7Z52QMHO3HPDUVQC
A3RM526Y7LUXNYW4TL56YKQ5GVOK2R5D7JJVTSQ6TT5MEXIR6YAAC
5OGOE4VWS5AIG4U2UYLLIGA3HY6UB7SNQOSESHNXBLET3VQXFBZAC
CCLLB7OIFNFYJZTG3UCI7536TOCWSCSXR67VELSB466R24WLJSDAC
VIHXB7SGRETFPHPYZFSRGOFRXEO4RZY57WDZSU6IAUEJRU3HPKQAC
23LVKATNTT74YKHG7KJM6SBO2IVZEV24TQ46ZJIHQ2IXONWNVXJAC
2K7JLB4Z7BS5VFNWD4DO3MKYU7VNPA5MTVHVSDI3FQZ5ICM6XM6QC
QJXNUQFJOAPQT3GUXRDTVKMJZCKFONSXUZMAZB7VC7OHDCGAVCOQC
impl TryFrom<Log> for LogIterator {
type Error = anyhow::Error;
fn try_from(cmd: Log) -> Result<LogIterator, Self::Error> {
let repo = Repository::find_root(cmd.repo_path.clone())?;
let repo_path = repo.path.clone();
let txn = repo.pristine.txn_begin()?;
let channel_name = if let Some(ref c) = cmd.channel {
c
} else {
txn.current_channel().unwrap_or(crate::DEFAULT_CHANNEL)
};
// The only situation that's disallowed is if the user's trying to apply
// path filters AND get the logs for a channel other than the one they're
// currently using (where using means the one that comprises the working copy)
if !cmd.filters.is_empty()
&& !(channel_name == txn.current_channel().unwrap_or(crate::DEFAULT_CHANNEL))
{
bail!("Currently, log filters can only be applied to the channel currently in use.")
}
let channel_ref = if let Some(channel) = txn.load_channel(channel_name)? {
channel
} else {
bail!("No such channel: {:?}", channel_name)
};
let changes = repo.changes;
let limit = cmd.limit.unwrap_or(std::usize::MAX);
let offset = cmd.offset.unwrap_or(0);
let mut id_path = repo.path.join(libpijul::DOT_DIR);
id_path.push("identities");
Ok(Self {
txn,
cmd,
changes,
repo_path,
id_path,
channel_ref,
limit,
offset,
})
}
}
#[derive(Debug, Error)]
pub enum Error<E: std::error::Error> {
#[error("pijul log couldn't find a file or directory corresponding to `{}`", 0)]
NotFound(String),
#[error(transparent)]
Txn(#[from] libpijul::pristine::sanakirja::SanakirjaError),
#[error(transparent)]
TxnErr(#[from] TxnErr<libpijul::pristine::sanakirja::SanakirjaError>),
#[error(transparent)]
Fs(#[from] libpijul::FsError<libpijul::pristine::sanakirja::SanakirjaError>),
#[error(transparent)]
Io(#[from] std::io::Error),
#[error("pijul log couldn't assemble file prefix for pattern `{}`: {} was not a file in the repository at {}", pat, canon_path.display(), repo_path.display())]
FilterPath {
pat: String,
canon_path: PathBuf,
repo_path: PathBuf,
},
#[error("pijul log couldn't assemble file prefix for pattern `{}`: the path contained invalid UTF-8", 0)]
InvalidUtf8(String),
#[error(transparent)]
E(E),
#[error(transparent)]
Filesystem(#[from] libpijul::changestore::filesystem::Error),
}
Err(_) => bail!(
"pijul log couldn't assemble file prefix for pattern `{}`; \
{} was not a file in the repository at {}",
pat,
canon_path.display(),
repo_path.display()
),
Err(_) => {
return Err(Error::FilterPath {
pat: pat.to_string(),
canon_path,
repo_path: repo_path.to_path_buf(),
})
}
Ok(None) => bail!(
"pijul log couldn't assemble file prefix for pattern `{}`; \
the path contained invalid UTF-8",
pat
),
Ok(Some(s)) => match libpijul::fs::find_inode(txn, s) {
Err(e) => bail!(
"pijul log couldn't assemble file prefix for pattern `{}`; \
no Inode found for the corresponding path. Internal error: {:?}",
pat,
e
),
Ok(inode) => {
inodes.push(inode);
}
},
Ok(None) => return Err(Error::InvalidUtf8(pat.to_string())),
Ok(Some(s)) => inodes.push(libpijul::fs::find_inode(txn, s)?),
match txn.get_external(touched_change_id)? {
Some(ser_h) => {
hashes.insert(libpijul::Hash::from(*ser_h));
}
_ => {
log::error!(
"`get_external` failed to retrieve full hash for ChangeId {:?}",
touched_change_id
);
bail!("Failed to retrieve full hash for {:?}", touched_change_id)
}
}
let ser_h = txn.get_external(touched_change_id)?.unwrap();
hashes.insert(libpijul::Hash::from(*ser_h));
impl TryFrom<Log> for LogIterator {
type Error = anyhow::Error;
fn try_from(cmd: Log) -> Result<LogIterator, Self::Error> {
let repo = Repository::find_root(cmd.repo_path.clone())?;
let repo_path = repo.path.clone();
let txn = repo.pristine.txn_begin()?;
let channel_name = if let Some(ref c) = cmd.channel {
c
} else {
txn.current_channel().unwrap_or(crate::DEFAULT_CHANNEL)
};
// The only situation that's disallowed is if the user's trying to apply
// path filters AND get the logs for a channel other than the one they're
// currently using (where using means the one that comprises the working copy)
if !cmd.filters.is_empty()
&& !(channel_name == txn.current_channel().unwrap_or(crate::DEFAULT_CHANNEL))
{
bail!("Currently, log filters can only be applied to the channel currently in use.")
}
let channel_ref = if let Some(channel) = txn.load_channel(channel_name)? {
channel
} else {
bail!("No such channel: {:?}", channel_name)
};
let changes = repo.changes;
let limit = cmd.limit.unwrap_or(std::usize::MAX);
let offset = cmd.offset.unwrap_or(0);
let mut id_path = repo.path.join(libpijul::DOT_DIR);
id_path.push("identities");
Ok(Self {
txn,
cmd,
changes,
repo_path,
id_path,
channel_ref,
limit,
offset,
})
}
}
// In order to accommodate both pretty-printing and efficient serialization to a serde
// target format, this now delegates mostly to [`LogIterator`].
// In order to accommodate both pretty-printing and efficient
// serialization to a serde target format, this now delegates
// mostly to [`LogIterator`].
LogIterator::try_from(self)?.for_each(|entry| write!(&mut stdout, "{}", entry))?
LogIterator::try_from(self)?.for_each(|entry| {
match write!(&mut stdout, "{}", entry) {
Ok(_) => Ok(()),
Err(e) if e.kind() == std::io::ErrorKind::BrokenPipe => Ok(()),
Err(e) => Err(e),
}
})?