This patch sends the list of patches + all their dependencies that touch a path, instead of letting the client download the dependencies after the initial download.
OGJFEWHUMFIZYBS456FPNUN3KEUDZXIJNFGPEMJGQDC7INZMHQZQC
R7X3PDL6ERX6POMBPIGHFCJVPG4QLA4LJYFDRPLXCAD45X772ASAC
ABQDWHNGSBF2REQDCGXSBFAU4RUMXYAF2KHJ5O3D32M7Z3A3FEDAC
PYTC7DPVCWKYDXXBY44BBNB4DHZ3N4OQW3EOEQ7H6Z5P5XBG2EIAC
SXEYMYF7P4RZMZ46WPL4IZUTSQ2ATBWYZX7QNVMS3SGOYXYOHAGQC
L2VH4BYK3IULLGBHXMZJWKRKDQY43QEMQRTXFJCNRDE7PODLXWTAC
MU5GSJAW65PEG3BRYUKZ7O37BPHW3MOX3S5E2RFOXKGUOJEEDQ5AC
TYAKEAJLABCZQDYAI4YBGIJNQ7HJS4DVULEGPCZOGJPJUYYNR6TAC
DDJO7X2P2BAJSXPOE6ODKAJM7GRWKPT36WWTUZ373ZWQRYU4CFIAC
S2B5MEWPPG4P6SL5NWTVAHPRJ6YPKX3VTRONYS267ZTTTPA6L3GAC
CCLLB7OIFNFYJZTG3UCI7536TOCWSCSXR67VELSB466R24WLJSDAC
DO2Y5TY5JQISUHCVNPI2FXO7WWZVJQ3LGPWF4DNADMGZRIO6PT2QC
I24UEJQLCH2SOXA4UHIYWTRDCHSOPU7AFTRUOTX7HZIAV4AZKYEQC
EUZFFJSOWV4PXDFFPDAFBHFUUMOFEU6ST7JH57YYRRR2SEOXLN6QC
A3RM526Y7LUXNYW4TL56YKQ5GVOK2R5D7JJVTSQ6TT5MEXIR6YAAC
ZWVYH7WPYOGDKWODFSAJ6R5U64DON2AVVJ2XZJKHAOMLJEFTYF3QC
UDHP4ZVBQZT2VBURB2MDCU2IZDNMCAFSIUKWRBDQ5BWMFKSN2LYQC
4XLHUME7YLJV6XUZBOW7PX62TCJXIWW2CPITXO5GZOULWGXRVDZAC
IBPVOKM5MXTGB2P7LCD75MISAYUNDPEKQAUEVCXJJWLWCX2TJZBAC
C3L2TLQWREYOM3YHL37L7PS74YGLHBEDQRSCVMYIU6HKBEPNN2SAC
L4JXJHWXYNCL4QGJXNKKTOKKTAXKKXBJUUY7HFZGEUZ5A2V5H34QC
YN63NUZO4LVJ7XPMURDULTXBVJKW5MVCTZ24R7Z52QMHO3HPDUVQC
RM225IDQR36MNBMN7OT2R562M4FUD6L34RY7A3WDBBETZIIDKZ5AC
WZVCLZKY34KQBQU6YBGJLQCDADBQ67LQVDNRVCMQVY3O3C3EIWSQC
self.download_changelist_(f, a, from, paths, &remote_txn, &remote_channel)
}
pub fn download_changelist_<
A,
T: libpijul::ChannelTxnT + libpijul::TxnTExt + libpijul::DepsTxnT + libpijul::GraphTxnT,
F: FnMut(&mut A, u64, Hash, Merkle, bool) -> Result<(), anyhow::Error>,
>(
&mut self,
mut f: F,
a: &mut A,
from: u64,
paths: &[String],
remote_txn: &T,
remote_channel: &ChannelRef<T>,
) -> Result<HashSet<Position<Hash>>, anyhow::Error> {
let store = libpijul::changestore::filesystem::FileSystem::from_root(
&self.root,
pijul_repository::max_files()?,
);
for x in remote_txn.log(&*rem, from)? {
let (n, (h, m)) = x?;
assert!(n >= from);
let h_int = remote_txn.get_internal(h)?.unwrap();
if paths_.is_empty()
|| paths_.iter().any(|x| {
remote_txn
.get_touched_files(x, Some(h_int))
if paths_.is_empty() {
for x in remote_txn.log(&*rem, from)? {
debug!("log {:?}", x);
let (n, (h, m)) = x?;
assert!(n >= from);
debug!("put_remote {:?} {:?} {:?}", n, h, m);
if tags.get(tagsi) == Some(&n) {
f(a, n, h.into(), m.into(), true)?;
tagsi += 1;
} else {
f(a, n, h.into(), m.into(), false)?;
}
}
} else {
let mut hashes = HashMap::new();
let mut stack = Vec::new();
for x in remote_txn.log(&*rem, from)? {
debug!("log {:?}", x);
let (n, (h, m)) = x?;
assert!(n >= from);
let h_int = remote_txn.get_internal(h)?.unwrap();
if paths_.is_empty()
|| paths_.iter().any(|x| {
let y = remote_txn.get_touched_files(x, Some(h_int)).unwrap();
debug!("x {:?} {:?}", x, y);
y == Some(h_int)
})
{
stack.push((*h_int, *m, n));
}
}
while let Some((h_int, m, n)) = stack.pop() {
if hashes.insert(h_int, (m, n)).is_some() {
continue;
}
for d in remote_txn.iter_dep(&h_int)? {
let (&h_int_, &d) = d?;
if h_int_ < h_int {
continue;
} else if h_int_ > h_int {
break;
}
let n = remote_txn
.get_changeset(remote_txn.changes(&*rem), &d)
.is_some()
})
{
.unwrap();
let m = remote_txn
.get_revchangeset(remote_txn.rev_changes(&*rem), &n)
.unwrap()
.unwrap()
.b;
stack.push((d, m.into(), (*n).into()))
}
}
let mut hashes: Vec<_> = hashes.into_iter().collect();
hashes.sort_by_key(|(_, (_, n))| *n);
for (h_int, (m, n)) in hashes {
let h = remote_txn.get_external(&h_int)?.unwrap();
for r in CHANGELIST_PATHS.captures_iter(&cap[3]) {
let s: String = r[1].replace("\\\"", "\"");
if let Ok((p, ambiguous)) = txn.follow_oldest_path(&repo.changes, &channel, &s)
{
if ambiguous {
bail!("Ambiguous path")
{
for r in CHANGELIST_PATHS.captures_iter(&cap[3]) {
let s: String = r[1].replace("\\\"", "\"");
if let Ok((p, ambiguous)) =
txn.follow_oldest_path(&repo.changes, &channel, &s)
{
if ambiguous {
bail!("Ambiguous path")
}
let h: libpijul::Hash = txn.get_external(&p.change)?.unwrap().into();
writeln!(o, "{}.{}", h.to_base32(), p.pos.0)?;
paths.push(s);
} else {
debug!("protocol line: {:?}", buf);
bail!("Protocol error")
let h: libpijul::Hash = txn.get_external(&p.change)?.unwrap().into();
writeln!(o, "{}.{}", h.to_base32(), p.pos.0)?;
paths.insert(p);
paths.extend(
libpijul::fs::iter_graph_descendants(&*txn, &channel.read(), p)?
.map(|x| x.unwrap()),
);
} else {
debug!("protocol line: {:?}", buf);
bail!("Protocol error")
for x in txn.log(&*channel.read(), from)? {
let (n, (h, m)) = x?;
let h_int = txn.get_internal(h)?.unwrap();
if paths.is_empty()
|| paths.iter().any(|x| {
x.change == *h_int
|| txn.get_touched_files(x, Some(h_int)).unwrap().is_some()
})
{
let h: Hash = h.into();
let m: Merkle = m.into();
if paths.is_empty() && tags.get(tagsi) == Some(&n) {
(pijul_remote::local::Local {
channel: (&cap[1]).to_string(),
root: PathBuf::new(),
changes_dir: PathBuf::new(),
pristine: pristine.clone(),
name: String::new(),
})
.download_changelist_(
|_, n, h, m, is_tag| {
if is_tag {