CCLLB7OIFNFYJZTG3UCI7536TOCWSCSXR67VELSB466R24WLJSDAC
MF3WAHBIH6Q2F7ZOKWPEJF6VGSKJITWLR3Z64GTD6YQZNA5EATWQC
7PM25EXLNQ6JUUIZNTAOQYNNIZNG6TJREEBUSAIC3FIOE7FHETSAC
SNZ3OAMCPUGFYON5SZHQQQK46ZZMVMJECJYEUCMG657UVLY2PNBQC
VXZNQQHCDC6MBLUMNDJVPM4I7XWTDYBPZZNCPZCA6EJ3GS5WAQGQC
KD4JIMAE6M2LFWEHFPEL4RTRV7UWYWNGGS52N2TKQ42ZNFSNLCEQC
IUGP6ZGBFLDRAKJOHFQNG67LZBDXUJ4QM25GOY3QT6GER3NVTHXQC
WKX5S4Z4DOB5S6A6X5V6ECZFCHQUMWRGX5XT4FBOG57P6HPWK7CAC
PH7B6I3U5XCACAX6VX3ZDJD2DQOQS7725R6CTOATNC26NP4VPUFQC
7T5STZYBIUN5AQPFKASNYO24QFLNBX3YCE4YIIXEQNJYR5LSZ6EQC
A7NTQINQCT6GSJZIBPWM6KD2HYGV4XBSV7FWLFYY4YKLSEOW57KQC
A6R6SGCPLFM45QNWJLISFBR3EEXVITYHCWEUOPNH4UIGIWJRTZAQC
IM6UFPOZHZTBMESRXGBALOAWJWUUDGLP2TVLSZ3RZPSJITKB3R7QC
PSKXR4QEPPVJZR777HW67IEHUPGZB44MFCNQ2KUS422Q3W22IQWAC
BE7GUCI2N6TX3P2HRMFSH7XLJKILDPOKOXKA7HWOABBFNKCKMZLAC
6RVT5X4LTRP5XHVDESXMIC2DHMT5MUQ24ZDWEBJ4XYTF6LJXK7CAC
4VWXL6KQGYGDUQRCVJCEVIV6CKJSEIYDX4YF33OX6EDNKJNEGD2AC
Y7YAFMFFJY3SQ3GYN3SS4V3FZWMH3B5L65AXQBXOR5XARSMF5JJQC
6DOXSHWGKJIMIPFCNLASGKBAJCJMJULW5HFRZAZ67EYSMXXGJ3KAC
VBMXB443FGZL6DLT6KAP2ICFCCQNXCUMDEUL67HB4CNKFMBBNSSAC
6YMDOZIB5LVYLFIDGN2WNT5JTHEAMS4TFPVDEZ3OWXWOKJOC5QDAC
SXEYMYF7P4RZMZ46WPL4IZUTSQ2ATBWYZX7QNVMS3SGOYXYOHAGQC
VO5OQW4W2656DIYYRNZ3PO7TQ4JOKQ3GVWE5ALUTYVMX3WMXJOYQC
JACZWIJ6UEL5HWZRNOOXTFXUEG67XJDPC5D72LYUPCVVJ6WB7JQAC
L4JXJHWXYNCL4QGJXNKKTOKKTAXKKXBJUUY7HFZGEUZ5A2V5H34QC
I52XSRUH5RVHQBFWVMAQPTUSPAJ4KNVID2RMI3UGCVKFLYUO6WZAC
76PCXGML77EZWTRI5E6KHLVRAFTJ2AB5YRN5EKOYNAPKTWY2KCGAC
MU5GSJAW65PEG3BRYUKZ7O37BPHW3MOX3S5E2RFOXKGUOJEEDQ5AC
Q45QHPO4HDTEZF2W4UDZSYYQ46BPEIWSW4GJILZR5HTJNLKXJABQC
FBXYP7QM7SG6P2JDJVQPPCRKJE3GVYXNQ5GVV4GRDUNG6Q4ZRDJQC
IQ4FCHPZYGTZHCQHUIRCMUI5LCHIDSJCM2AZXGRJARWLCPPLXZOQC
FMKKWCFVK5CPPP55T4VMCHSFPZ47EBK6V7D4MJ5BH55TP4UBOZXAC
YAJAXIV5VL263Z6FYLKFPROB3MQPRPH22P44GRGRVGEP56HOMBOAC
VQPAUKBQ2POZKL7CZFAZK5ZQKEBYL27XZYZWYUSH5AH25KK6DWKAC
AN7IDX26RK33ZXASXLJMD4GTFWHCTHMJ6Y5C4ROCPIH33VUT2EYQC
5DVRL6MFXQOCPOZMYSKBERMRRVUTYRL2SRGRTU2MH4IEOFCDKM3QC
SLJ3OHD4F6GJGZ3SV2D7DMR3PXYHPSI64X77KZ3RJ24EGEX6ZNQAC
ZHABNS3S6FSINO74FOI5KHYXYDTBPO4FQTTYTUS7NNKEVVNLYC4AC
WZVCLZKY34KQBQU6YBGJLQCDADBQ67LQVDNRVCMQVY3O3C3EIWSQC
4OCC6D42GZYRDLH3NSKXMJTRKXP7UZ6Z3YNGCNUT7NT6WBDBCBIAC
5BRU2RRWOQBMS2V3RQM7PRFR5UILYZ73GISHAKJA6KIZGC5M2MFAC
BD5PC25AB5MKVIYDFSDGRZ4YGX4PKW4SMZ3YAYAPNA5HLDVJUR3QC
HMMMKONLCRAXVT7SO2ITTFDOJIQKKVSRIZPXYVPDC34RCBHWMHVAC
GLMOA3PFDR7HHJ3QMVZBNNJ3CGZAF72AZ5UBNEQON37K5WFNZP6QC
PJ7T2VFLV5PYG3CV23GC2GIQETXKGC6CO74JBGREV3JC3LG5OXUAC
OJZWJUF2TCGZ7RFVY6FPKBS5P3C4BGHZDPVH775OHVNVFMJICKNQC
7UPL3Y2A5QOBU6VIUHNWEFGSGQ5CMWGDGOVLRZ53UARXG3TDGLMAC
KQTD46KVVWMJ3W6O55BEJLCVTNTDLUH6QT46AEFT7OU2SELXG4IAC
BZSC7VMYSFRXDHDDAMCDR6X67FN5VWIBOSE76BQLX7OCVOJFUA3AC
H23LO7U7MNB5GTLOUIFYAJ6DP57DM3VFBR4IBOAVPMHS356AYFPQC
6T5ULULMRGU5GJ3JQTEH2QFQN5IMP53TYFFXUT5UE6FA6WWFFMFAC
7A2TSC4PAKK3WOH3DMAJASCEC6D5JLJWNFWJTEEBE4CVS4K76PPQC
74HX2XZDHFRE7FIQ6LQZALIIKED2ABSGGBQ34ULYZ5ZBKK7UTHQQC
QNJBR73KCSCCF6FTHGZDF2K7PZQL3EFKZFOBT77KYZBMALTTW6OQC
DNQHXWRZF6EWII3RGQ6HPGFD47BOOFH4FCQHSCACBS3RLQO3DNIQC
3YDPHBANMNSK7Z5SCG745VLTP4BBQWIXCJTQOSDI6UJGYR6S45EQC
BXD3IQYNMKMI5BTANCF6NZHZP4CKPWADGJMBT2R3WTMKVKONT5QAC
ERV3644QELKOHAVNMZGRWYCPPN3XELTAH4PPFR6QKGWW73XBOOKQC
ATZ3BWSEFJBLVGDUZFESRNHVCIO6ZRZ3ALPANZSVGVO7A5BUAFQQC
LCERQSWMA2YKOPAPNZUSOQ7FLBGDHBZR33OHLYX7T4KTKULRMJDQC
XL6Y64UPFLIVRV3YVJMTTMZU7VL6SUXVE6BKL6K7DYRKVJ4X727AC
KDF6FJRVF72L274BEUJCTUKRFMNL6BDZMTVKDPEYGFX4TC3YOVSQC
UBCBQ5FGH2KASHEUPDLIKGLVVX3GSRQ4F4P2JEJZL2NX2DUSYARAC
L5PHFTIERPDAFIOSHZSMAN2CUSFM626ISMGTDYRN5KWPLXCOVPXAC
UNZXTNSJI4YRY3EQ3M4HMBKQDNYDTY6B7IZRBNYGDJXTA2UKYWRAC
43AJ37IXON6PMMYRZM6OB2MJXPYCNIWW2XBDVNBXIRH5DD7JDTVQC
GVQ7YSEDDCYYYWDJ5JUVFSBWA5EZVOZJI63KK6E46N6Y2B6LP72AC
G734WNM64AR5BLAZMN5MDPKSFTYXTUQR6MAGB32NRBC5FXFRWSJAC
SAGSYAPXQ2T6GC3B3TNRPNFTZMS7UMME6YQGSF5MOIM66S5NKB2QC
FXT5FS5WIDBA3HPTJRFGRGULZIGAWAJXT2U6RFYGDLO2PYDG4VEAC
UFCZKKLXVYQYQBYENCAFHY3ZPPSDAJJAIREZSYNQM4QNXV6G6RXAC
OUWD436ATBTZJR53B6XDSI5SXRRNZV7YGRUEA5ACHZC2RUDP7G5QC
BT2ZHPY4LTECZDNPNLX5IUAEA6CYB4RRBGVBXUNK3ARHMWQK7KHAC
#[doc(hidden)]
fn #name_get<'txn>(&'txn self, db: &Self::#name_capital, key: #key, value: Option<#value>) -> Option<#value>;
fn #name_get<'txn>(&'txn self, db: &Self::#name_capital, key: #key, value: Option<#value>) -> Result<Option<#value>, TxnErr<Self::#error>>;
let mut cursor = txn.txn.set_cursors(&db, pos).0;
super::Cursor {
cursor,
txn,
marker: std::marker::PhantomData,
if let Ok((cursor, _)) = txn.txn.set_cursors(&db, pos) {
Ok(super::Cursor {
cursor,
txn,
marker: std::marker::PhantomData,
})
} else {
Err(TxnErr(SanakirjaError::PristineCorrupt))
) -> Option<(#key, #value)> {
(unsafe { ::sanakirja::next(&self.txn, cursor) })
#post
) -> Result<Option<(#key, #value)>, TxnErr<SanakirjaError>> {
let x = if let Ok(x) = unsafe { ::sanakirja::next(&self.txn, cursor) } {
x
} else {
return Err(TxnErr(SanakirjaError::PristineCorrupt))
};
Ok(x #post)
) -> Option<(#key, #value)> {
(unsafe { ::sanakirja::prev(&self.txn, cursor) })
#post
) -> Result<Option<(#key, #value)>, TxnErr<SanakirjaError>> {
let x = if let Ok(x) = unsafe { ::sanakirja::prev(&self.txn, cursor) } {
x
} else {
return Err(TxnErr(SanakirjaError::PristineCorrupt))
};
Ok(x #post)
let txnt = next(&mut input_iter);
let txnt: proc_macro2::TokenStream = if txnt.is_empty() {
proc_macro2::TokenStream::from(quote! { TxnT })
} else {
proc_macro2::TokenStream::from_iter(txnt.into_iter())
};
let error = next(&mut input_iter);
let error: proc_macro2::TokenStream = if error.is_empty() {
proc_macro2::TokenStream::from(quote! { GraphError })
} else {
proc_macro2::TokenStream::from_iter(error.into_iter())
};
impl<T: TxnT, RT: std::ops::Deref<Target = T>> Iterator for crate::pristine::RevCursor<T, RT, T::#cursor_name, #key, #value>
impl<T: #txnt, RT: std::ops::Deref<Target = T>> Iterator for crate::pristine::RevCursor<T, RT, T::#cursor_name, #key, #value>
type Item = (#key, #value);
fn next(&mut self) -> Option<(#key, #value)> {
self.txn.#name_prev(&mut self.cursor)
type Item = Result<(#key, #value), TxnErr<T::#error>>;
fn next(&mut self) -> Option<Self::Item> {
match self.txn.#name_prev(&mut self.cursor) {
Ok(Some(x)) => Some(Ok(x)),
Ok(None) => None,
Err(e) => Some(Err(e)),
}
pub fn prev(&mut self) -> Option<(#key, #value)> {
self.txn.#name_prev(&mut self.cursor)
pub fn prev(&mut self) -> Option<Result<(#key, #value), TxnErr<T::#error>>> {
match self.txn.#name_prev(&mut self.cursor) {
Ok(Some(x)) => Some(Ok(x)),
Ok(None) => None,
Err(e) => Some(Err(e)),
}
type Item = (#key, #value);
fn next(&mut self) -> Option<(#key, #value)> {
self.txn.#name_next(&mut self.cursor)
type Item = Result<(#key, #value), TxnErr<T::#error>>;
fn next(&mut self) -> Option<Self::Item> {
match self.txn.#name_next(&mut self.cursor) {
Ok(Some(x)) => Some(Ok(x)),
Ok(None) => None,
Err(e) => Some(Err(e)),
}
) -> Result<bool, Self::Error> {
Ok(self.txn.put(&mut self.rng, &mut self.#name, k, v)?)
) -> Result<bool, TxnErr<Self::#error>> {
Ok(self.txn.put(&mut self.rng, &mut self.#name, k, v).map_err(TxnErr)?)
) -> Result<bool, Self::Error> {
Ok(self.txn.del(&mut self.rng, &mut self.#name, k, v)?)
) -> Result<bool, TxnErr<Self::#error>> {
Ok(self.txn.del(&mut self.rng, &mut self.#name, k, v).map_err(TxnErr)?)
}
#[derive(Debug, Error)]
pub enum Error {
#[error("No Pijul repository found")]
NoRepoRoot,
#[error("Cannot access working directory")]
CannotAccessWorkingDirectory,
#[error("Already in a repository")]
AlreadyInARepo,
#[error("No such channel: {}", channel)]
NoSuchChannel { channel: String },
#[error("Protocol error. Is this the correct URL?")]
ProtocolError { line: Vec<u8> },
#[error("Not authenticated")]
NotAuthenticated,
#[error("No change message")]
NoChangeMessage,
#[error("Incorrect remote: {}", name)]
IncorrectRemote { name: String },
#[error("Unknown host key")]
UnknownHostKey,
#[error("Cannot record a binary change interactively. Use -a")]
RecordBinaryChange,
#[error("Remote not found: {:?}", remote)]
RemoteNotFound { remote: String },
#[error("No global config directory")]
NoGlobalConfigDir,
#[error("Could not parse global config")]
CouldNotParseGlobal,
#[error("Remote error: {}", msg)]
Remote { msg: String },
#[error("Remote exited with status {}", status)]
RemoteExit { status: u32 },
#[error("Missing remote")]
MissingRemote,
#[error("State not found in remote: {:?}", state)]
StateNotFound { state: libpijul::pristine::Merkle },
#[error("Missing dependencies for change {:?}", h)]
MissingDep { h: libpijul::pristine::Hash },
#[error("No prefixes given. Use `.` to record the current directory.")]
NoRecordPrefixes,
#[error("HTTP error: {}", status.as_str())]
Http { status: reqwest::StatusCode },
#[error("Could not parse configuration file at {:?}", path)]
CouldNotReadConfig { path: PathBuf },
#[error("No current channel")]
NoCurrentChannel,
#[error("Cannot delete the current channel")]
CannotDeleteCurrentChannel,
#[error("Channel not found: {:?}", channel)]
ChannelNotFound { channel: String },
#[error("Cannot reset, because there are unrecorded changes")]
UnrecordedChanges,
#[error("Could not infer repository name")]
CouldNotInferRepositoryName { repo: String },
#[error("Cannot unrecord change {}, because change {} depends on it", change, dep.to_base32())]
CannotUnrecord {
change: String,
dep: libpijul::pristine::Hash,
},
pub fn current_dir() -> Result<PathBuf, Error> {
std::env::current_dir().map_err(|_| Error::CannotAccessWorkingDirectory)
pub fn current_dir() -> Result<PathBuf, anyhow::Error> {
if let Ok(cur) = std::env::current_dir() {
Ok(cur)
} else {
bail!("Cannot access working directory")
}
for (_, (h, m)) in txn.iter_remote(&remote_changes.borrow().remote, 0) {
if txn.channel_has_state(&channel, m) {
for x in txn.iter_remote(&remote_changes.borrow().remote, 0)? {
let (h, m) = x?.1;
if txn.channel_has_state(&channel, m)? {
fn load_channel<T: MutTxnTExt>(txn: &T, name: &str) -> Result<ChannelRef<T>, Error> {
if let Some(c) = txn.load_channel(name) {
fn load_channel<T: MutTxnTExt>(txn: &T, name: &str) -> Result<ChannelRef<T>, anyhow::Error> {
if let Some(c) = txn.load_channel(name)? {
)
.find(|e| e.flag.contains(EdgeFlags::PARENT | EdgeFlags::FOLDER))
.unwrap()
.dest;
)? {
let e = e?;
if e.flag.contains(EdgeFlags::PARENT | EdgeFlags::FOLDER) {
source_parent = Some(e.dest);
break;
}
}
let source_parent = source_parent.unwrap();
let inode = crate::fs::create_new_inode(txn);
put_tree_with_rev(txn, file_id.as_file_id(), inode).map_err(super::UnrecordError::Txn)?;
put_inodes_with_rev(txn, inode, dest).map_err(super::UnrecordError::Txn)?;
let inode = crate::fs::create_new_inode(txn)?;
put_tree_with_rev(txn, file_id.as_file_id(), inode)?;
put_inodes_with_rev(txn, inode, dest)?;
if let Some(inode) = txn.get_revinodes(position, None) {
del_inodes_with_rev(txn, inode, position).map_err(super::UnrecordError::Txn)?;
if let Some(inode) = txn.get_revinodes(position, None)? {
del_inodes_with_rev(txn, inode, position)?;
assert!(txn.get_revdep(change_id, None).is_none());
while txn.del_dep(change_id, None).map_err(UnrecordError::Txn)? {}
txn.del_external(change_id, None)
.map_err(UnrecordError::Txn)?;
txn.del_internal(*hash, None).map_err(UnrecordError::Txn)?;
assert!(txn.get_revdep(change_id, None)?.is_none());
while txn.del_dep(change_id, None)? {}
txn.del_external(change_id, None)?;
txn.del_internal(*hash, None)?;
) -> Result<(), UnrecordError<P::Error, T::Error>> {
let timestamp = if let Some(ts) = txn.get_changeset(&channel.changes, change_id, None) {
) -> Result<(), UnrecordError<P::Error, T::GraphError>> {
let timestamp = if let Some(ts) = txn.get_changeset(&channel.changes, change_id, None)? {
crate::apply::clean_obsolete_pseudo_edges(txn, channel, &mut ws.apply, change_id)?;
crate::apply::repair_cyclic_paths(txn, channel, &mut ws.apply)?;
crate::apply::clean_obsolete_pseudo_edges(txn, &mut channel.graph, &mut ws.apply, change_id)?;
crate::apply::repair_cyclic_paths(txn, &mut channel.graph, &mut ws.apply)?;
for e in iter_adj_all(txn, channel, a).filter(|e| {
!e.flag.contains(EdgeFlags::PARENT)
&& e.dest == b.start_pos()
&& !e.introduced_by.is_root()
&& e.introduced_by != current_id
}) {
for e in iter_adj_all(txn, channel, a)? {
let e = e?;
if e.flag.contains(EdgeFlags::PARENT)
|| e.dest != b.start_pos()
|| e.introduced_by.is_root()
|| e.introduced_by == current_id
{
continue;
}
) -> Result<(), UnrecordError<P::Error, T::Error>> {
let change_hash = txn.get_external(change_id).unwrap();
) -> Result<(), UnrecordError<P::Error, T::GraphError>> {
let change_hash = txn.get_external(change_id)?.unwrap();
let key = txn.get_inodes(inode, None).unwrap();
let changes: Vec<_> = txn.log_for_path(&channel.borrow(), key, 0).collect();
let key = txn.get_inodes(inode, None).unwrap().unwrap();
let changes: Vec<_> = txn
.log_for_path(&channel.borrow(), key, 0)
.unwrap()
.map(|x| x.unwrap())
.collect();
for x in txn_alice.iter_tree(
OwnedPathId {
parent_inode: Inode::ROOT,
basename: crate::small_string::SmallString::new(),
},
None,
) {
for x in txn_alice
.iter_tree(
OwnedPathId {
parent_inode: Inode::ROOT,
basename: crate::small_string::SmallString::new(),
},
None,
)
.unwrap()
{
for channel in txn.iter_channels("") {
for (_, (i, _)) in txn.log(&channel.borrow(), 0) {
for channel in txn.iter_channels("").unwrap() {
let channel = channel.unwrap();
for x in txn.log(&channel.borrow(), 0).unwrap() {
let (_, (i, _)) = x.unwrap();
let mut it = crate::fs::iter_graph_children(&txn, &changes, &channel, Position::ROOT);
let (key, meta, file) = it.next().unwrap();
let mut it =
crate::fs::iter_graph_children(&txn, &changes, &channel.graph, Position::ROOT).unwrap();
let (key, meta, file) = it.next().unwrap().unwrap();
let mut it = crate::fs::iter_graph_children(&txn, &changes, &channel, key);
let (file_key, _, _) = it.next().unwrap();
crate::fs::iter_paths(&txn, &channel_, file_key, |path| {
let mut it = crate::fs::iter_graph_children(&txn, &changes, &channel.graph, key).unwrap();
let (file_key, _, _) = it.next().unwrap().unwrap();
crate::fs::iter_paths(&txn, &channel_.borrow().graph, file_key, |path| {
let mut it = crate::fs::iter_basenames(&txn, &changes, &channel, key);
let (key, _, name) = it.next().unwrap();
let mut it = crate::fs::iter_basenames(&txn, &changes, &channel.graph, key).unwrap();
let (key, _, name) = it.next().unwrap().unwrap();
let mut it = crate::fs::working_copy_children(&txn, inode);
let (name, _) = it.next().unwrap();
let mut it = crate::fs::working_copy_children(&txn, inode).unwrap();
let (name, _) = it.next().unwrap().unwrap();
fn get_inodes<T: TxnT>(txn: &T, channel: &Channel<T>, inode: Inode) -> Option<Position<ChangeId>> {
if let Some(vertex) = txn.get_inodes(inode, None) {
fn get_inodes<T: ChannelTxnT + TreeTxnT<TreeError = <T as GraphTxnT>::GraphError>>(
txn: &T,
channel: &Channel<T>,
inode: Inode,
) -> Result<Option<Position<ChangeId>>, TxnErr<T::GraphError>> {
if let Some(vertex) = txn.get_inodes(inode, None)? {
) -> Result<(), RecordError<C::Error, W::Error, T::Error>> {
) -> Result<(), RecordError<C::Error, W::Error, T::GraphError>>
where
T: ChannelTxnT + TreeTxnT<TreeError = <T as GraphTxnT>::GraphError> + GraphMutTxnT,
<W as WorkingCopy>::Error: 'static,
{
for name_ in iter_adjacent(txn, &channel, vertex.inode_vertex(), f0, f1)
.filter(|e| e.flag.contains(EdgeFlags::PARENT))
{
for name_ in iter_adjacent(txn, &channel.graph, vertex.inode_vertex(), f0, f1)? {
let name_ = name_?;
if !name_.flag.contains(EdgeFlags::PARENT) {
continue;
}
for child in iter_adjacent(txn, &channel, v.inode_vertex(), f0, f1) {
let child = find_block(txn, &channel, child.dest).unwrap();
for grandchild in iter_adjacent(txn, &channel, child, f0, f1) {
for child in iter_adjacent(txn, channel, v.inode_vertex(), f0, f1)? {
let child = child?;
let child = find_block(txn, channel, child.dest).unwrap();
for grandchild in iter_adjacent(txn, channel, child, f0, f1)? {
let grandchild = grandchild?;
let needs_deletion = if let Some(inode) = txn.get_revinodes(grandchild.dest, None) {
debug!("inode = {:?} {:?}", inode, txn.get_revtree(inode, None));
if let Some(path) = crate::fs::inode_filename(txn, inode) {
working_copy.file_metadata(&path).is_err()
let needs_deletion =
if let Some(inode) = txn.get_revinodes(grandchild.dest, None)? {
debug!("inode = {:?} {:?}", inode, txn.get_revtree(inode, None));
if let Some(path) = crate::fs::inode_filename(txn, inode)? {
working_copy.file_metadata(&path).is_err()
} else {
true
}
} else if let Some(vertex) = get_inodes(txn, &channel, child_inode) {
self.record_deleted_file(txn, &channel, working_copy, &full_path, vertex)
} else if let Some(vertex) = get_inodes(txn, &channel, child_inode)? {
self.record_deleted_file(txn, &channel.graph, working_copy, &full_path, vertex)?
)
.filter(|e| e.flag.contains(EdgeFlags::FOLDER | EdgeFlags::PARENT))
{
)? {
let parent = parent?;
if !parent.flag.contains(EdgeFlags::FOLDER | EdgeFlags::PARENT) {
continue;
}
let parent_dest = find_block_end(txn, &channel, parent.dest).unwrap();
changes.get_contents(|p| txn.get_external(p), parent_dest, &mut previous_name)?;
let parent_dest = find_block_end(txn, channel, parent.dest).unwrap();
changes
.get_contents(
|p| txn.get_external(p).unwrap(),
parent_dest,
&mut previous_name,
)
.map_err(RecordError::Changestore)?;
)
.filter(|e| {
e.flag.contains(EdgeFlags::FOLDER | EdgeFlags::PARENT)
&& !e.flag.contains(EdgeFlags::PSEUDO)
}) {
)? {
let grandparent = grandparent?;
if !grandparent
.flag
.contains(EdgeFlags::FOLDER | EdgeFlags::PARENT)
|| grandparent.flag.contains(EdgeFlags::PSEUDO)
{
continue;
}
)
.filter(|e| e.flag.contains(EdgeFlags::PARENT) && !e.flag.contains(EdgeFlags::PSEUDO))
{
)? {
let grandparent = grandparent?;
if !grandparent.flag.contains(EdgeFlags::PARENT)
|| grandparent.flag.contains(EdgeFlags::PSEUDO)
{
continue;
}
}
impl std::convert::From<::sanakirja::CRCError> for SanakirjaError {
fn from(_: ::sanakirja::CRCError) -> Self {
SanakirjaError::PristineCorrupt
}
}
impl std::convert::From<::sanakirja::CRCError> for TxnErr<SanakirjaError> {
fn from(_: ::sanakirja::CRCError) -> Self {
TxnErr(SanakirjaError::PristineCorrupt)
}
}
impl std::convert::From<::sanakirja::Error> for TxnErr<SanakirjaError> {
fn from(e: ::sanakirja::Error) -> Self {
TxnErr(e.into())
}
}
impl std::convert::From<TxnErr<::sanakirja::Error>> for TxnErr<SanakirjaError> {
fn from(e: TxnErr<::sanakirja::Error>) -> Self {
TxnErr(e.0.into())
}
sanakirja_get!(graph, Vertex<ChangeId>, Edge);
fn get_external(&self, p: ChangeId) -> Option<Hash> {
sanakirja_get!(graph, Vertex<ChangeId>, Edge, GraphError);
fn get_external(&self, p: ChangeId) -> Result<Option<Hash>, TxnErr<Self::GraphError>> {
fn hash_from_prefix(&self, s: &str) -> Result<(Hash, ChangeId), super::HashPrefixError> {
let h = if let Some(h) = Hash::from_prefix(s) {
h
} else {
return Err(super::HashPrefixError::Parse(s.to_string()));
};
let mut result = None;
debug!("h = {:?}", h);
for (e, i) in self.txn.iter(&self.internal, Some((h, None))) {
debug!("{:?} {:?}", e, i);
if e < h {
continue;
} else {
let b32 = e.to_base32();
debug!("{:?}", b32);
let (b32, _) = b32.split_at(s.len().min(b32.len()));
if b32 != s {
break;
} else if result.is_none() {
result = Some((e, i))
} else {
return Err(super::HashPrefixError::Ambiguous(s.to_string()));
}
}
}
if let Some(result) = result {
Ok(result)
} else {
Err(super::HashPrefixError::NotFound(s.to_string()))
}
impl<T: ::sanakirja::Transaction> ChannelTxnT for GenericTxn<T> {
type Changeset = Db<ChangeId, u64>;
type Revchangeset = Db<u64, (ChangeId, Merkle)>;
type Channelstates = Db<Merkle, u64>;
sanakirja_get!(changeset, ChangeId, u64, GraphError);
sanakirja_get!(revchangeset, u64, (ChangeId, Merkle), GraphError);
sanakirja_cursor!(changeset, ChangeId, u64);
sanakirja_cursor_ref!(revchangeset, u64, (ChangeId, Merkle));
sanakirja_rev_cursor!(revchangeset, u64, (ChangeId, Merkle));
}
impl<T: ::sanakirja::Transaction> DepsTxnT for GenericTxn<T> {
type DepsError = SanakirjaError;
type Dep = Db<ChangeId, ChangeId>;
type Revdep = Db<ChangeId, ChangeId>;
sanakirja_table_get!(dep, ChangeId, ChangeId, DepsError);
sanakirja_table_get!(revdep, ChangeId, ChangeId, DepsError);
sanakirja_cursor_ref!(dep, ChangeId, ChangeId);
fn iter_dep_ref<RT: std::ops::Deref<Target = Self> + Clone>(
txn: RT,
p: ChangeId,
) -> Result<super::Cursor<Self, RT, Self::DepCursor, ChangeId, ChangeId>, TxnErr<Self::DepsError>>
{
Self::cursor_dep_ref(txn.clone(), &txn.dep, Some((p, None)))
fn hash_from_prefix_remote<'txn>(
&'txn self,
remote: &RemoteRef<Self>,
s: &str,
) -> Result<Hash, super::HashPrefixError> {
let remote = remote.borrow();
let h = if let Some(h) = Hash::from_prefix(s) {
h
} else {
return Err(super::HashPrefixError::Parse(s.to_string()));
};
let mut result = None;
debug!("h = {:?}", h);
for (e, _) in self.txn.iter(&remote.rev, Some((h, None))) {
debug!("{:?}", e);
if e < h {
continue;
} else {
let b32 = e.to_base32();
debug!("{:?}", b32);
let (b32, _) = b32.split_at(s.len().min(b32.len()));
if b32 != s {
break;
} else if result.is_none() {
result = Some(e)
} else {
return Err(super::HashPrefixError::Ambiguous(s.to_string()));
}
}
}
if let Some(result) = result {
Ok(result)
} else {
Err(super::HashPrefixError::NotFound(s.to_string()))
}
type Rev_touched_files = Db<ChangeId, Position<ChangeId>>;
sanakirja_iter!(touched_files, Position<ChangeId>, ChangeId);
sanakirja_iter!(rev_touched_files, ChangeId, Position<ChangeId>);
fn iter_revdep(
&self,
k: ChangeId,
) -> Result<
super::Cursor<Self, &Self, Self::DepCursor, ChangeId, ChangeId>,
TxnErr<Self::DepsError>,
> {
self.cursor_dep(&self.revdep, Some((k, None)))
}
fn iter_dep(
&self,
k: ChangeId,
) -> Result<
super::Cursor<Self, &Self, Self::DepCursor, ChangeId, ChangeId>,
TxnErr<Self::DepsError>,
> {
self.cursor_dep(&self.dep, Some((k, None)))
}
fn iter_touched(
&self,
k: Position<ChangeId>,
) -> Result<
super::Cursor<Self, &Self, Self::Touched_filesCursor, Position<ChangeId>, ChangeId>,
TxnErr<Self::DepsError>,
> {
self.cursor_touched_files(&self.touched_files, Some((k, None)))
fn iter_rev_touched(
&self,
k: ChangeId,
) -> Result<
super::Cursor<Self, &Self, Self::Rev_touched_filesCursor, ChangeId, Position<ChangeId>>,
TxnErr<Self::DepsError>,
> {
self.cursor_rev_touched_files(&self.rev_touched_files, Some((k, None)))
}
}
impl<T: ::sanakirja::Transaction> TreeTxnT for GenericTxn<T> {
type TreeError = SanakirjaError;
sanakirja_table_get!(inodes, Inode, Position<ChangeId>);
sanakirja_table_get!(revinodes, Position<ChangeId>, Inode);
sanakirja_table_get!(inodes, Inode, Position<ChangeId>, TreeError);
sanakirja_table_get!(revinodes, Position<ChangeId>, Inode, TreeError);
type Channelstates = Db<Merkle, u64>;
sanakirja_get!(changeset, ChangeId, u64);
sanakirja_get!(revchangeset, u64, (ChangeId, Merkle));
sanakirja_cursor!(changeset, ChangeId, u64);
sanakirja_cursor_ref!(revchangeset, u64, (ChangeId, Merkle));
sanakirja_rev_cursor!(revchangeset, u64, (ChangeId, Merkle));
type Dep = Db<ChangeId, ChangeId>;
type Revdep = Db<ChangeId, ChangeId>;
sanakirja_table_get!(dep, ChangeId, ChangeId);
sanakirja_table_get!(revdep, ChangeId, ChangeId);
sanakirja_cursor_ref!(dep, ChangeId, ChangeId);
sanakirja_table_get!(touched_files, Position<ChangeId>, ChangeId);
sanakirja_table_get!(rev_touched_files, ChangeId, Position<ChangeId>);
fn iter_dep_ref<RT: std::ops::Deref<Target = Self> + Clone>(
txn: RT,
p: ChangeId,
) -> super::Cursor<Self, RT, Self::DepCursor, ChangeId, ChangeId> {
Self::cursor_dep_ref(txn.clone(), &txn.dep, Some((p, None)))
}
type Touched_files = Db<Position<ChangeId>, ChangeId>;
type Rev_touched_files = Db<ChangeId, Position<ChangeId>>;
sanakirja_iter!(touched_files, Position<ChangeId>, ChangeId);
sanakirja_iter!(rev_touched_files, ChangeId, Position<ChangeId>);
fn iter_inodes(
&self,
) -> Result<
super::Cursor<Self, &Self, Self::InodesCursor, Inode, Position<ChangeId>>,
TxnErr<Self::TreeError>,
> {
self.cursor_inodes(&self.inodes, None)
}
#[cfg(debug_assertions)]
fn iter_revinodes(
&self,
) -> Result<
super::Cursor<Self, &Self, Self::RevinodesCursor, Position<ChangeId>, Inode>,
TxnErr<SanakirjaError>,
> {
self.cursor_revinodes(&self.revinodes, None)
}
fn iter_partials<'txn>(
&'txn self,
k: &str,
) -> Result<
super::Cursor<Self, &'txn Self, Self::PartialsCursor, SmallString, Position<ChangeId>>,
TxnErr<SanakirjaError>,
> {
let k0 = SmallString::from_str(k);
self.cursor_partials(&self.partials, Some((k0, None)))
}
}
impl<T: ::sanakirja::Transaction> TxnT for GenericTxn<T> {
fn hash_from_prefix(
&self,
s: &str,
) -> Result<(Hash, ChangeId), super::HashPrefixError<Self::GraphError>> {
let h = if let Some(h) = Hash::from_prefix(s) {
h
} else {
return Err(super::HashPrefixError::Parse(s.to_string()));
};
let mut result = None;
debug!("h = {:?}", h);
for x in self
.txn
.iter(&self.internal, Some((h, None)))
.map_err(|e| super::HashPrefixError::Txn(e.into()))?
{
let (e, i) = x.map_err(|e| super::HashPrefixError::Txn(e.into()))?;
debug!("{:?} {:?}", e, i);
if e < h {
continue;
} else {
let b32 = e.to_base32();
debug!("{:?}", b32);
let (b32, _) = b32.split_at(s.len().min(b32.len()));
if b32 != s {
break;
} else if result.is_none() {
result = Some((e, i))
} else {
return Err(super::HashPrefixError::Ambiguous(s.to_string()));
}
}
}
if let Some(result) = result {
Ok(result)
} else {
Err(super::HashPrefixError::NotFound(s.to_string()))
}
}
fn hash_from_prefix_remote<'txn>(
&'txn self,
remote: &RemoteRef<Self>,
s: &str,
) -> Result<Hash, super::HashPrefixError<Self::GraphError>> {
let remote = remote.borrow();
let h = if let Some(h) = Hash::from_prefix(s) {
h
} else {
return Err(super::HashPrefixError::Parse(s.to_string()));
};
let mut result = None;
debug!("h = {:?}", h);
for x in self
.txn
.iter(&remote.rev, Some((h, None)))
.map_err(|e| super::HashPrefixError::Txn(e.into()))?
{
let (e, _) = x.map_err(|e| super::HashPrefixError::Txn(e.into()))?;
debug!("{:?}", e);
if e < h {
continue;
} else {
let b32 = e.to_base32();
debug!("{:?}", b32);
let (b32, _) = b32.split_at(s.len().min(b32.len()));
if b32 != s {
break;
} else if result.is_none() {
result = Some(e)
} else {
return Err(super::HashPrefixError::Ambiguous(s.to_string()));
}
}
}
if let Some(result) = result {
Ok(result)
} else {
Err(super::HashPrefixError::NotFound(s.to_string()))
}
}
fn iter_inodes(
&self,
) -> super::Cursor<Self, &Self, Self::InodesCursor, Inode, Position<ChangeId>> {
self.cursor_inodes(&self.inodes, None)
}
#[cfg(debug_assertions)]
fn iter_revinodes(
&self,
) -> super::Cursor<Self, &Self, Self::RevinodesCursor, Position<ChangeId>, Inode> {
self.cursor_revinodes(&self.revinodes, None)
}
fn iter_revdep(
&self,
k: ChangeId,
) -> super::Cursor<Self, &Self, Self::DepCursor, ChangeId, ChangeId> {
self.cursor_dep(&self.revdep, Some((k, None)))
}
fn iter_dep(
&self,
k: ChangeId,
) -> super::Cursor<Self, &Self, Self::DepCursor, ChangeId, ChangeId> {
self.cursor_dep(&self.dep, Some((k, None)))
}
fn iter_touched(
&self,
k: Position<ChangeId>,
) -> super::Cursor<Self, &Self, Self::Touched_filesCursor, Position<ChangeId>, ChangeId> {
self.cursor_touched_files(&self.touched_files, Some((k, None)))
}
fn iter_rev_touched(
&self,
k: ChangeId,
) -> super::Cursor<Self, &Self, Self::Rev_touched_filesCursor, ChangeId, Position<ChangeId>>
{
self.cursor_rev_touched_files(&self.rev_touched_files, Some((k, None)))
}
fn iter_partials<'txn>(
&'txn self,
k: &str,
) -> super::Cursor<Self, &'txn Self, Self::PartialsCursor, SmallString, Position<ChangeId>>
{
let k0 = SmallString::from_str(k);
self.cursor_partials(&self.partials, Some((k0, None)))
}
fn last_remote(&self, remote: &Self::Remote) -> Option<(u64, (Hash, Merkle))> {
self.txn.rev_iter(remote, None).next()
fn last_remote(
&self,
remote: &Self::Remote,
) -> Result<Option<(u64, (Hash, Merkle))>, TxnErr<Self::GraphError>> {
Ok(self.txn.rev_iter(remote, None)?.next().transpose()?)
fn get_remote_state(&self, remote: &Self::Remote, n: u64) -> Option<(u64, (Hash, Merkle))> {
self.txn
.iter(remote, Some((n, None)))
.find(|(k, _)| *k >= n)
fn get_remote_state(
&self,
remote: &Self::Remote,
n: u64,
) -> Result<Option<(u64, (Hash, Merkle))>, TxnErr<Self::GraphError>> {
for x in self.txn.iter(remote, Some((n, None)))? {
let (k, m) = x?;
if k >= n {
return Ok(Some((k, m)));
}
}
Ok(None)
fn remote_has_change(&self, remote: &RemoteRef<Self>, hash: Hash) -> bool {
self.txn.get(&remote.db.borrow().rev, hash, None).is_some()
fn remote_has_change(
&self,
remote: &RemoteRef<Self>,
hash: Hash,
) -> Result<bool, TxnErr<Self::GraphError>> {
Ok(self.txn.get(&remote.db.borrow().rev, hash, None)?.is_some())
fn remote_has_state(&self, remote: &RemoteRef<Self>, m: Merkle) -> bool {
self.txn.get(&remote.db.borrow().states, m, None).is_some()
fn remote_has_state(
&self,
remote: &RemoteRef<Self>,
m: Merkle,
) -> Result<bool, TxnErr<Self::GraphError>> {
Ok(self.txn.get(&remote.db.borrow().states, m, None)?.is_some())
fn channel_has_state(&self, channel: &ChannelRef<Self>, m: Merkle) -> bool {
self.txn.get(&channel.borrow().states, m, None).is_some()
}
}
/*
impl<T> MutTxn<T> {
pub fn with_remote_mut<F: FnMut(&mut Db<u64, (Hash, Merkle)>)>(
&mut self,
name: &str,
mut f: F,
) -> Result<bool, anyhow::Error> {
let name = SmallString::from_str(name);
let name = UnsafeSmallStr::from_small_str(name.as_small_str());
if let Some((mut db0, db1, db2)) = self.txn.get(&self.remotes, name, None) {
f(&mut db0);
let mut db: ::sanakirja::Db<UnsafeSmallStr, (u64, u64, u64)> =
unsafe { std::mem::transmute(self.remotes) };
self.txn.del(&mut self.rng, &mut db, name, None)?;
self.remotes = unsafe { std::mem::transmute(db) };
self.txn
.put(&mut self.rng, &mut self.remotes, name, (db0, db1, db2))?;
Ok(true)
} else {
Ok(false)
}
}
pub fn del_remote(&mut self, name: &str) -> Result<(), anyhow::Error> {
let name = SmallString::from_str(name);
let name = UnsafeSmallStr::from_small_str(name.as_small_str());
self.txn.del(&mut self.rng, &mut self.remotes, name, None)?;
Ok(())
fn channel_has_state(
&self,
channel: &ChannelRef<Self>,
m: Merkle,
) -> Result<bool, TxnErr<Self::GraphError>> {
Ok(self.txn.get(&channel.borrow().states, m, None)?.is_some())
*/
impl MutTxnT for MutTxn<()> {
sanakirja_put_del!(internal, Hash, ChangeId);
sanakirja_put_del!(external, ChangeId, Hash);
sanakirja_put_del!(inodes, Inode, Position<ChangeId>);
sanakirja_put_del!(revinodes, Position<ChangeId>, Inode);
sanakirja_put_del!(tree, PathId, Inode, UnsafePathId::from_fileid(k), v);
sanakirja_put_del!(revtree, Inode, PathId, k, UnsafePathId::from_fileid(v),);
sanakirja_put_del!(dep, ChangeId, ChangeId);
sanakirja_put_del!(revdep, ChangeId, ChangeId);
sanakirja_put_del!(touched_files, Position<ChangeId>, ChangeId);
sanakirja_put_del!(rev_touched_files, ChangeId, Position<ChangeId>);
fn put_partials(&mut self, k: &str, e: Position<ChangeId>) -> Result<bool, Self::Error> {
let k = SmallString::from_str(k);
Ok(self.txn.put(
&mut self.rng,
&mut self.partials,
UnsafeSmallStr::from_small_str(k.as_small_str()),
e,
)?)
}
fn del_partials(
&mut self,
k: &str,
e: Option<Position<ChangeId>>,
) -> Result<bool, Self::Error> {
let k = SmallString::from_str(k);
Ok(self.txn.del(
&mut self.rng,
&mut self.partials,
UnsafeSmallStr::from_small_str(k.as_small_str()),
e,
)?)
}
impl ChannelMutTxnT for MutTxn<()> {
) -> Result<Option<Merkle>, Self::Error> {
if self.get_changeset(&channel.changes, p, None).is_none() {
) -> Result<Option<Merkle>, TxnErr<Self::GraphError>> {
if self.get_changeset(&channel.changes, p, None)?.is_none() {
}
}
impl DepsMutTxnT for MutTxn<()> {
sanakirja_put_del!(dep, ChangeId, ChangeId, DepsError);
sanakirja_put_del!(revdep, ChangeId, ChangeId, DepsError);
sanakirja_put_del!(touched_files, Position<ChangeId>, ChangeId, DepsError);
sanakirja_put_del!(rev_touched_files, ChangeId, Position<ChangeId>, DepsError);
}
impl TreeMutTxnT for MutTxn<()> {
sanakirja_put_del!(inodes, Inode, Position<ChangeId>, TreeError);
sanakirja_put_del!(revinodes, Position<ChangeId>, Inode, TreeError);
sanakirja_put_del!(
tree,
PathId,
Inode,
TreeError,
UnsafePathId::from_fileid(k),
v
);
sanakirja_put_del!(
revtree,
Inode,
PathId,
TreeError,
k,
UnsafePathId::from_fileid(v)
);
fn put_partials(
&mut self,
k: &str,
e: Position<ChangeId>,
) -> Result<bool, TxnErr<Self::TreeError>> {
let k = SmallString::from_str(k);
Ok(self.txn.put(
&mut self.rng,
&mut self.partials,
UnsafeSmallStr::from_small_str(k.as_small_str()),
e,
)?)
fn del_partials(
&mut self,
k: &str,
e: Option<Position<ChangeId>>,
) -> Result<bool, TxnErr<Self::TreeError>> {
let k = SmallString::from_str(k);
Ok(self.txn.del(
&mut self.rng,
&mut self.partials,
UnsafeSmallStr::from_small_str(k.as_small_str()),
e,
)?)
}
}
impl MutTxnT for MutTxn<()> {
/// The trait of immutable transactions.
pub trait TxnT: Sized {
type Error: std::error::Error + Send + Sync + 'static;
#[derive(Debug, Error)]
#[error(transparent)]
pub struct TxnErr<E: std::error::Error + 'static>(pub E);
pub trait GraphTxnT: Sized {
type GraphError: std::error::Error + Send + Sync + 'static;
cursor_ref!(graph, Vertex<ChangeId>, Edge);
get!(graph, Vertex<ChangeId>, Edge);
cursor_ref!(graph, Vertex<ChangeId>, Edge, GraphError);
get!(graph, Vertex<ChangeId>, Edge, GraphError);
/// Returns the external hash of an internal change identifier, if
/// the change is known.
fn get_external(&self, p: ChangeId) -> Result<Option<Hash>, TxnErr<Self::GraphError>>;
/// Returns the internal change identifier of change with external
/// hash `hash`, if the change is known.
fn get_internal(&self, p: Hash) -> Result<Option<ChangeId>, TxnErr<Self::GraphError>>;
}
get!(revchangeset, u64, (ChangeId, Merkle));
cursor_ref!(revchangeset, u64, (ChangeId, Merkle));
rev_cursor!(revchangeset, u64, (ChangeId, Merkle));
get!(revchangeset, u64, (ChangeId, Merkle), GraphError);
cursor_ref!(revchangeset, u64, (ChangeId, Merkle), GraphError);
rev_cursor!(revchangeset, u64, (ChangeId, Merkle), GraphError);
}
pub trait DepsTxnT: Sized {
type DepsError: std::error::Error + Send + Sync + 'static;
table!(revdep);
table!(dep);
table_get!(dep, ChangeId, ChangeId, DepsError);
cursor_ref!(dep, ChangeId, ChangeId, DepsError);
table_get!(revdep, ChangeId, ChangeId, DepsError);
fn iter_revdep(
&self,
p: ChangeId,
) -> Result<Cursor<Self, &Self, Self::DepCursor, ChangeId, ChangeId>, TxnErr<Self::DepsError>>;
fn iter_dep(
&self,
p: ChangeId,
) -> Result<Cursor<Self, &Self, Self::DepCursor, ChangeId, ChangeId>, TxnErr<Self::DepsError>>;
fn iter_dep_ref<RT: std::ops::Deref<Target = Self> + Clone>(
txn: RT,
p: ChangeId,
) -> Result<Cursor<Self, RT, Self::DepCursor, ChangeId, ChangeId>, TxnErr<Self::DepsError>>;
fn iter_touched(
&self,
p: Position<ChangeId>,
) -> Result<
Cursor<Self, &Self, Self::Touched_filesCursor, Position<ChangeId>, ChangeId>,
TxnErr<Self::DepsError>,
>;
fn iter_rev_touched(
&self,
p: ChangeId,
) -> Result<
Cursor<Self, &Self, Self::Rev_touched_filesCursor, ChangeId, Position<ChangeId>>,
TxnErr<Self::DepsError>,
>;
table!(touched_files);
table!(rev_touched_files);
table_get!(touched_files, Position<ChangeId>, ChangeId, DepsError);
table_get!(rev_touched_files, ChangeId, Position<ChangeId>, DepsError);
iter!(touched_files, Position<ChangeId>, ChangeId, DepsError);
iter!(rev_touched_files, ChangeId, Position<ChangeId>, DepsError);
}
table_get!(inodes, Inode, Position<ChangeId>);
table_get!(revinodes, Position<ChangeId>, Inode);
table_get!(inodes, Inode, Position<ChangeId>, TreeError);
table_get!(revinodes, Position<ChangeId>, Inode, TreeError);
cursor!(partials, SmallString, Position<ChangeId>);
cursor!(partials, SmallString, Position<ChangeId>, TreeError);
cursor!(inodes, Inode, Position<ChangeId>, TreeError);
fn iter_inodes(
&self,
) -> Result<
Cursor<Self, &Self, Self::InodesCursor, Inode, Position<ChangeId>>,
TxnErr<Self::TreeError>,
>;
table!(channels);
cursor!(channels, SmallString, (u64, u64, u64, u64, u64, u64));
#[cfg(debug_assertions)]
cursor!(revinodes, Position<ChangeId>, Inode, TreeError);
#[cfg(debug_assertions)]
fn iter_revinodes(
&self,
) -> Result<
Cursor<Self, &Self, Self::RevinodesCursor, Position<ChangeId>, Inode>,
TxnErr<Self::TreeError>,
>;
table!(revdep);
table!(dep);
table_get!(dep, ChangeId, ChangeId);
cursor_ref!(dep, ChangeId, ChangeId);
table_get!(revdep, ChangeId, ChangeId);
table!(touched_files);
table!(rev_touched_files);
table_get!(touched_files, Position<ChangeId>, ChangeId);
table_get!(rev_touched_files, ChangeId, Position<ChangeId>);
iter!(touched_files, Position<ChangeId>, ChangeId);
iter!(rev_touched_files, ChangeId, Position<ChangeId>);
/// Returns the external hash of an internal change identifier, if
/// the change is known.
fn get_external(&self, p: ChangeId) -> Option<Hash>;
/// Returns the internal change identifier of change with external
/// hash `hash`, if the change is known.
fn get_internal(&self, p: Hash) -> Option<ChangeId>;
/// The trait of immutable transactions.
pub trait TxnT:
GraphTxnT
+ ChannelTxnT
+ DepsTxnT<DepsError = <Self as GraphTxnT>::GraphError>
+ TreeTxnT<TreeError = <Self as GraphTxnT>::GraphError>
{
table!(channels);
cursor!(channels, SmallString, (u64, u64, u64, u64, u64, u64));
fn iter_channels<'txn>(&'txn self, start: &str) -> ChannelIterator<'txn, Self>;
fn iter_remotes<'txn>(&'txn self, start: &str) -> RemotesIterator<'txn, Self>;
fn iter_revdep(&self, p: ChangeId) -> Cursor<Self, &Self, Self::DepCursor, ChangeId, ChangeId>;
fn iter_dep(&self, p: ChangeId) -> Cursor<Self, &Self, Self::DepCursor, ChangeId, ChangeId>;
fn iter_dep_ref<RT: std::ops::Deref<Target = Self> + Clone>(
txn: RT,
p: ChangeId,
) -> Cursor<Self, RT, Self::DepCursor, ChangeId, ChangeId>;
fn iter_channels<'txn>(
&'txn self,
start: &str,
) -> Result<ChannelIterator<'txn, Self>, TxnErr<Self::GraphError>>;
fn iter_touched(
&self,
p: Position<ChangeId>,
) -> Cursor<Self, &Self, Self::Touched_filesCursor, Position<ChangeId>, ChangeId>;
fn iter_remotes<'txn>(
&'txn self,
start: &str,
) -> Result<RemotesIterator<'txn, Self>, TxnErr<Self::GraphError>>;
fn iter_rev_touched(
&self,
p: ChangeId,
) -> Cursor<Self, &Self, Self::Rev_touched_filesCursor, ChangeId, Position<ChangeId>>;
) -> RevCursor<Self, &'txn Self, Self::RemoteCursor, u64, (Hash, Merkle)>;
fn get_remote(&mut self, name: &str) -> Option<RemoteRef<Self>>;
fn last_remote(&self, remote: &Self::Remote) -> Option<(u64, (Hash, Merkle))>;
) -> Result<
RevCursor<Self, &'txn Self, Self::RemoteCursor, u64, (Hash, Merkle)>,
TxnErr<Self::GraphError>,
>;
fn remote_has_change(&self, remote: &RemoteRef<Self>, hash: Hash) -> bool;
fn remote_has_state(&self, remote: &RemoteRef<Self>, hash: Merkle) -> bool;
fn channel_has_state(&self, channel: &ChannelRef<Self>, hash: Merkle) -> bool;
fn last_remote(
&self,
remote: &Self::Remote,
) -> Result<Option<(u64, (Hash, Merkle))>, TxnErr<Self::GraphError>>;
cursor!(inodes, Inode, Position<ChangeId>);
fn iter_inodes(&self) -> Cursor<Self, &Self, Self::InodesCursor, Inode, Position<ChangeId>>;
fn get_remote_state(
&self,
remote: &Self::Remote,
n: u64,
) -> Result<Option<(u64, (Hash, Merkle))>, TxnErr<Self::GraphError>>;
#[cfg(debug_assertions)]
cursor!(revinodes, Position<ChangeId>, Inode);
#[cfg(debug_assertions)]
fn iter_revinodes(
fn remote_has_change(
&self,
remote: &RemoteRef<Self>,
hash: Hash,
) -> Result<bool, TxnErr<Self::GraphError>>;
fn remote_has_state(
) -> Cursor<Self, &Self, Self::RevinodesCursor, Position<ChangeId>, Inode>;
remote: &RemoteRef<Self>,
hash: Merkle,
) -> Result<bool, TxnErr<Self::GraphError>>;
fn channel_has_state(
&self,
channel: &ChannelRef<Self>,
hash: Merkle,
) -> Result<bool, TxnErr<Self::GraphError>>;
pub(crate) fn tree_path<T: TxnT>(txn: &T, v: Position<ChangeId>) -> Option<String> {
if let Some(mut inode) = txn.get_revinodes(v, None) {
pub(crate) fn tree_path<T: TreeTxnT>(
txn: &T,
v: Position<ChangeId>,
) -> Result<Option<String>, TxnErr<T::TreeError>> {
if let Some(mut inode) = txn.get_revinodes(v, None)? {
#[error("Inconsistent change")]
pub struct InconsistentChange {}
pub enum InconsistentChange<T: std::error::Error + 'static> {
#[error("Undeclared dependency")]
UndeclaredDep,
#[error(transparent)]
Txn(T),
}
impl<T: std::error::Error + 'static> std::convert::From<TxnErr<T>> for InconsistentChange<T> {
fn from(e: TxnErr<T>) -> Self {
InconsistentChange::Txn(e.0)
}
}
) -> Cursor<T, RT, T::RevchangesetCursor, u64, (ChangeId, Merkle)> {
T::cursor_revchangeset_ref(txn, &channel.revchanges, Some((from, None)))
) -> Result<Cursor<T, RT, T::RevchangesetCursor, u64, (ChangeId, Merkle)>, TxnErr<T::GraphError>> {
Ok(T::cursor_revchangeset_ref(
txn,
&channel.revchanges,
Some((from, None)),
)?)
) -> RevCursor<T, &'txn T, T::RevchangesetCursor, u64, (ChangeId, Merkle)> {
txn.rev_cursor_revchangeset(&channel.revchanges, from.map(|from| (from, None)))
) -> Result<
RevCursor<T, &'txn T, T::RevchangesetCursor, u64, (ChangeId, Merkle)>,
TxnErr<T::GraphError>,
> {
Ok(txn.rev_cursor_revchangeset(&channel.revchanges, from.map(|from| (from, None)))?)
) -> PathChangeset<'channel, 'txn, T> {
PathChangeset {
iter: txn.cursor_revchangeset(&channel.revchanges, Some((from_timestamp, None))),
) -> Result<PathChangeset<'channel, 'txn, T>, TxnErr<T::GraphError>> {
Ok(PathChangeset {
iter: txn.cursor_revchangeset(&channel.revchanges, Some((from_timestamp, None)))?,
) -> RevPathChangeset<'channel, 'txn, T> {
RevPathChangeset {
iter: txn.rev_cursor_revchangeset(&channel.revchanges, Some((from_timestamp, None))),
) -> Result<RevPathChangeset<'channel, 'txn, T>, TxnErr<T::GraphError>> {
Ok(RevPathChangeset {
iter: txn.rev_cursor_revchangeset(&channel.revchanges, Some((from_timestamp, None)))?,
let mut cursor = txn.cursor_graph(&channel.graph, Some((key, Some(edge))));
let (a_, b_) = cursor.next().unwrap();
a_.change == a.change
let mut cursor = txn.cursor_graph(&channel, Some((key, Some(edge))))?;
let (a_, b_) = cursor.next().unwrap()?;
Ok(a_.change == a.change
pub(crate) fn is_alive<T: TxnT>(txn: &T, channel: &Channel<T>, a: Vertex<ChangeId>) -> bool {
a.is_root()
|| iter_adjacent(
txn,
channel,
a,
EdgeFlags::PARENT,
EdgeFlags::all() - EdgeFlags::DELETED,
)
.any(|e| {
!e.flag.contains(EdgeFlags::PSEUDO)
&& (e.flag.contains(EdgeFlags::BLOCK) || a.is_empty())
})
pub(crate) fn is_alive<T: GraphTxnT>(
txn: &T,
channel: &T::Graph,
a: Vertex<ChangeId>,
) -> Result<bool, TxnErr<T::GraphError>> {
if a.is_root() {
return Ok(true);
}
for e in iter_adjacent(
txn,
channel,
a,
EdgeFlags::PARENT,
EdgeFlags::all() - EdgeFlags::DELETED,
)? {
let e = e?;
if !e.flag.contains(EdgeFlags::PSEUDO)
&& (e.flag.contains(EdgeFlags::BLOCK) || a.is_empty())
{
return Ok(true);
}
}
Ok(false)
pub(crate) fn make_changeid<T: TxnT>(txn: &T, h: &Hash) -> ChangeId {
if let Some(h) = txn.get_internal(*h) {
return h;
pub(crate) fn make_changeid<T: GraphTxnT>(
txn: &T,
h: &Hash,
) -> Result<ChangeId, TxnErr<T::GraphError>> {
if let Some(h) = txn.get_internal(*h)? {
return Ok(h);