Removing anyhow in libpijul

[?]
Dec 6, 2020, 11:09 AM
VO5OQW4W2656DIYYRNZ3PO7TQ4JOKQ3GVWE5ALUTYVMX3WMXJOYQC

Dependencies

  • [2] Q45QHPO4 Feedback on network stuff
  • [3] 62XVBWPY remove redundant Clap attributes
  • [4] 5DVRL6MF Hard-unrecord
  • [5] LCERQSWM Cleanup
  • [6] GVQ7YSED Checking for dependencies even for a local change
  • [7] ZXTHL45O address clippy lints
  • [8] DNQHXWRZ address clippy hard errors
  • [9] 3YDPHBAN address non-controversial clippy lints
  • [10] V2MDXX62 Channel rename: do not leave the old name behind
  • [11] JP3BYVXX Fixing file paths on Windows
  • [12] 6T5ULULM Fixing conflicts with the changes from discussion #143
  • [13] 4OCC6D42 Recursive add
  • [14] 7A2TSC4P Conflict solving code (FOLDER edges)
  • [15] FYVZZNRQ Parsing UTF-8 in changes (bytes vs chars)
  • [16] QNJBR73K don't return Result for infallible functions
  • [17] 4H2XTVJ2 Fix some mistakes in the docs
  • [18] PJ7T2VFL Do not hang on locked repositories
  • [19] KWAMD2KR A few fixes in the documentation comments
  • [20] KVBLRDOU Concatenating edits with order conflict resolutions (if relevant), and parsing the text format of the result
  • [21] RJMQSZER External commands
  • [22] UNZXTNSJ Change text format: order dependencies in the order they were on the channel at record time
  • [23] SNZ3OAMC use native external subcommand support instead of hand-rolled one
  • [24] WIORLB47 Version bump
  • [25] GURIBVW6 Fixing the pager
  • [26] KDF6FJRV bigger clippy refactors
  • [27] G6YZ7U65 Version bump
  • [28] NX5I5H53 New published versions
  • [29] 43AJ37IX Getting rid of edge validation, which does not work for zombie conflicts
  • [30] L4JXJHWX pijul/*: reorganize imports and remove extern crate
  • [31] ISQJRA3O Fixing the parsing of zombie resurrection in the change text format
  • [32] R3H7D42U Debugging `pijul git`: proper error reporting
  • [33] H23LO7U7 a few more clippy lints addressed
  • [34] NLGQAH4H Credit and reset relative to current directory instead of the root
  • [35] O4DNWMPD Cleaunp and proofreading of libpijul::record
  • [36] 5BRU2RRW Cleanup (debugging a crash related to trees/inodes)
  • [37] 2K7JLB4Z No pager on Windows
  • [38] AEPEFS7O Write help for each argument
  • [39] OUWD436A Version bump
  • [40] SAGSYAPX Various version bumps
  • [41] OXMYGLW2 Printing the actual lines rather than str::lines + \n
  • [42] WZVCLZKY address clippy lints
  • [43] 7UPL3Y2A Unrecord: don't restore the same unrecorded file deletion twice in the inodes and tree tables
  • [44] BXD3IQYN Fixing --features git
  • [45] I52XSRUH Massive cleanup, and simplification
  • [46] N35L72XV Versions in Cargo.lock
  • [47] 7PM25EXL Recursive apply was written a little too fast…
  • [48] BZSC7VMY address clippy lints
  • [49] UBCBQ5FG Removing pijul/src/commands/checkout.rs (unused file), as well as litorg comments
  • [50] SXEYMYF7 Fixing the bad changes in history (unfortunately, by rebooting).
  • [51] CVAT6LN3 Fixing git import, and adding more useful feedback (with `RUST_LOG="pijul=info"`)
  • [52] OCBM7IFE New release: pijul-1.0.0-alpha.8
  • [53] JWTT77WJ Add help on subcommands
  • [54] 74HX2XZD Cleanup and debugging
  • [55] ERV3644Q Adding the block module

Change contents

  • replacement in pijul-macros/src/lib.rs at line 511
    [17.18449][17.18449:18491]()
    ) -> Result<bool, anyhow::Error>;
    [17.18449]
    [17.18491]
    ) -> Result<bool, Self::Error>;
  • replacement in pijul-macros/src/lib.rs at line 517
    [17.18606][17.18606:18648]()
    ) -> Result<bool, anyhow::Error>;
    [17.18606]
    [17.18648]
    ) -> Result<bool, Self::Error>;
  • replacement in pijul-macros/src/lib.rs at line 546
    [17.19827][17.19827:19874]()
    ) -> Result<bool, anyhow::Error> {
    [17.19827]
    [17.19874]
    ) -> Result<bool, Self::Error> {
  • replacement in pijul-macros/src/lib.rs at line 554
    [17.20095][17.20095:20142]()
    ) -> Result<bool, anyhow::Error> {
    [17.20095]
    [17.20142]
    ) -> Result<bool, Self::Error> {
  • replacement in pijul-macros/src/lib.rs at line 565
    [17.20426][17.20426:20473]()
    ) -> Result<bool, anyhow::Error> {
    [17.20426]
    [17.20473]
    ) -> Result<bool, Self::Error> {
  • replacement in pijul-macros/src/lib.rs at line 575
    [17.20764][17.20764:20811]()
    ) -> Result<bool, anyhow::Error> {
    [17.20764]
    [17.20811]
    ) -> Result<bool, Self::Error> {
  • edit in pijul/src/main.rs at line 108
    [17.85778][3.159:203](),[3.203][17.85845:85867](),[17.866][17.85845:85867](),[17.85845][17.85845:85867]()
    #[clap(setting = AppSettings::Hidden)]
    Upgrade(Upgrade),
  • edit in pijul/src/main.rs at line 241
    [17.89650][17.89650:89705]()
    SubCommand::Upgrade(upgrade) => upgrade.run(),
  • file deletion: upgrade.rs (-xw-x--x--)
    [17.93386][17.93387:93399](),[17.93399][17.93400:93400]()
    use std::collections::{HashMap, HashSet};
    use std::path::PathBuf;
    use clap::Clap;
    use libpijul::changestore::ChangeStore;
    use libpijul::{Hash, MutTxnT, MutTxnTExt, TxnT, TxnTExt};
    use crate::repository::Repository;
    #[derive(Clap, Debug)]
    pub struct Upgrade {
    #[clap(long = "repository")]
    repo_path: Option<PathBuf>,
    }
    impl Upgrade {
    pub fn run(self) -> Result<(), anyhow::Error> {
    let mut channels = HashMap::new();
    {
    let repo = Repository::find_root(self.repo_path.clone())?;
    let txn = repo.pristine.txn_begin()?;
    let mut hashes = HashSet::new();
    for channel in txn.iter_channels("") {
    let channel = channel.borrow();
    let name = channel.name();
    let e = channels.entry(name.to_string()).or_insert_with(Vec::new);
    hashes.clear();
    for (_, (h, _)) in txn.reverse_log(&channel, None) {
    if !hashes.insert(h) {
    continue;
    }
    let path = repo.changes.filename(&h);
    let change = libpijul::change::v3::LocalChange3::deserialize(
    path.to_str().unwrap(),
    Some(&h),
    )
    .unwrap();
    e.push((h, change))
    }
    }
    std::fs::rename(repo.path.join(".pijul"), repo.path.join(".pijul.old"))?;
    }
    let repo2 = Repository::init(self.repo_path)?;
    let mut txn2 = repo2.pristine.mut_txn_begin();
    let mut translations = HashMap::new();
    translations.insert(None, None);
    translations.insert(Some(Hash::None), Some(Hash::None));
    for (channel_name, mut changes) in channels {
    let mut channel = txn2.open_or_create_channel(&channel_name)?;
    while let Some((old_h, c)) = changes.pop() {
    let h = repo2.changes.save_change(&c.to_v4(&translations))?;
    translations.insert(Some(old_h), Some(h));
    txn2.apply_change(&repo2.changes, &mut channel, h)?;
    }
    }
    txn2.commit()?;
    Ok(())
    }
    }
    /// Set the repository where this command should run. Defaults to the first ancestor of the current directory that contains a `.pijul` directory.
  • edit in pijul/src/commands/mod.rs at line 59
    [17.134333][17.134333:134366](),[17.134366][4.1575:1576]()
    mod upgrade;
    pub use upgrade::*;
  • replacement in pijul/src/commands/git.rs at line 648
    [17.159258][17.159258:159611]()
    Err(e) => match e.downcast() {
    Ok(libpijul::Error::ChangeAlreadyOnChannel { hash }) => {
    error!("change already on channel: {:?}", hash);
    return Ok(txn.current_state(&channel.borrow()).unwrap());
    }
    Ok(e) => return Err(e.into()),
    Err(e) => return Err(e),
    },
    [17.159258]
    [17.159611]
    Err(libpijul::LocalApplyError::ChangeAlreadyOnChannel { hash }) => {
    error!("change already on channel: {:?}", hash);
    return Ok(txn.current_state(&channel.borrow()).unwrap());
    }
    Err(e) => return Err(e.into()),
  • replacement in pijul/src/commands/git.rs at line 692
    [17.160679][17.3959:4047]()
    ) -> Result<(usize, Option<libpijul::Hash>, Option<libpijul::Merkle>), anyhow::Error> {
    [17.160679]
    [17.160829]
    ) -> Result<
    (usize, Option<libpijul::Hash>, Option<libpijul::Merkle>),
    libpijul::LocalApplyError<T::Error>,
    > {
  • replacement in pijul/src/commands/git.rs at line 699
    [17.317][17.317:535]()
    if let Err(e) = result {
    match e.downcast() {
    Ok(libpijul::Error::FileNotInRepo { .. }) => {}
    Ok(e) => return Err(e.into()),
    Err(e) => return Err(e),
    [17.317]
    [17.535]
    use libpijul::working_copy::filesystem::*;
    match result {
    Ok(_) => {}
    Err(Error::Add(AddError::Fs(FsError::NotFound(_)))) => {}
    Err(Error::Add(AddError::Fs(FsError::AlreadyInRepo(_)))) => {}
    Err(e) => {
    error!("While adding {:?}: {}", p, e);
  • replacement in pijul/src/commands/credit.rs at line 88
    [17.6159][17.181047:181121](),[17.181047][17.181047:181121]()
    fn output_line<C: FnOnce(&mut Vec<u8>) -> Result<(), anyhow::Error>>(
    [17.6159]
    [17.181121]
    fn output_line<E, C: FnOnce(&mut Vec<u8>) -> Result<(), E>>(
  • replacement in pijul/src/commands/credit.rs at line 92
    [17.181183][17.181183:181220]()
    ) -> Result<(), anyhow::Error> {
    [17.181183]
    [17.181220]
    ) -> Result<(), E>
    where
    E: From<std::io::Error>,
    {
  • replacement in pijul/src/commands/credit.rs at line 142
    [17.182632][17.182632:182713]()
    fn output_conflict_marker(&mut self, s: &str) -> Result<(), anyhow::Error> {
    [17.182632]
    [17.182713]
    fn output_conflict_marker(&mut self, s: &str) -> Result<(), std::io::Error> {
  • edit in libpijul/src/working_copy/mod.rs at line 11
    [17.198424]
    [17.198424]
    #[derive(Debug, Error)]
    pub enum WriteError<E: std::error::Error + 'static> {
    #[error(transparent)]
    E(E),
    #[error(transparent)]
    Io(#[from] std::io::Error),
    }
  • replacement in libpijul/src/working_copy/mod.rs at line 21
    [17.198449][17.198449:199114]()
    fn create_dir_all(&mut self, path: &str) -> Result<(), anyhow::Error>;
    fn file_metadata(&self, file: &str) -> Result<InodeMetadata, anyhow::Error>;
    fn read_file(&self, file: &str, buffer: &mut Vec<u8>) -> Result<(), anyhow::Error>;
    fn modified_time(&self, file: &str) -> Result<std::time::SystemTime, anyhow::Error>;
    fn remove_path(&mut self, name: &str) -> Result<(), anyhow::Error>;
    fn rename(&mut self, former: &str, new: &str) -> Result<(), anyhow::Error>;
    fn set_permissions(&mut self, name: &str, permissions: u16) -> Result<(), anyhow::Error>;
    fn write_file<A, F: FnOnce(&mut dyn std::io::Write) -> Result<A, anyhow::Error>>(
    [17.198449]
    [17.199114]
    type Error: std::error::Error;
    fn create_dir_all(&mut self, path: &str) -> Result<(), Self::Error>;
    fn file_metadata(&self, file: &str) -> Result<InodeMetadata, Self::Error>;
    fn read_file(&self, file: &str, buffer: &mut Vec<u8>) -> Result<(), Self::Error>;
    fn modified_time(&self, file: &str) -> Result<std::time::SystemTime, Self::Error>;
    fn remove_path(&mut self, name: &str) -> Result<(), Self::Error>;
    fn rename(&mut self, former: &str, new: &str) -> Result<(), Self::Error>;
    fn set_permissions(&mut self, name: &str, permissions: u16) -> Result<(), Self::Error>;
    fn write_file<A, E: std::error::Error, F: FnOnce(&mut dyn std::io::Write) -> Result<A, E>>(
  • replacement in libpijul/src/working_copy/mod.rs at line 33
    [17.199172][17.199172:199207]()
    ) -> Result<A, anyhow::Error>;
    [17.199172]
    [17.199207]
    ) -> Result<A, WriteError<E>>;
  • edit in libpijul/src/working_copy/memory.rs at line 197
    [17.205401]
    [17.205401]
    }
    #[derive(Debug, Error)]
    pub enum Error {
    #[error("Path not found: {path}")]
    NotFound { path: String },
  • replacement in libpijul/src/working_copy/memory.rs at line 206
    [17.205434][17.205434:205510]()
    fn create_dir_all(&mut self, file: &str) -> Result<(), anyhow::Error> {
    [17.205434]
    [17.205510]
    type Error = Error;
    fn create_dir_all(&mut self, file: &str) -> Result<(), Self::Error> {
  • replacement in libpijul/src/working_copy/memory.rs at line 223
    [17.205959][17.205959:206041]()
    fn file_metadata(&self, file: &str) -> Result<InodeMetadata, anyhow::Error> {
    [17.205959]
    [17.206041]
    fn file_metadata(&self, file: &str) -> Result<InodeMetadata, Self::Error> {
  • replacement in libpijul/src/working_copy/memory.rs at line 227
    [17.206196][17.206196:206250]()
    None => Err((crate::Error::FileNotFound {
    [17.206196]
    [17.206250]
    None => Err(Error::NotFound {
  • replacement in libpijul/src/working_copy/memory.rs at line 229
    [17.206290][17.206290:206327]()
    })
    .into()),
    [17.206290]
    [17.206327]
    }),
  • replacement in libpijul/src/working_copy/memory.rs at line 232
    [17.206343][17.206343:206432]()
    fn read_file(&self, file: &str, buffer: &mut Vec<u8>) -> Result<(), anyhow::Error> {
    [17.206343]
    [17.206432]
    fn read_file(&self, file: &str, buffer: &mut Vec<u8>) -> Result<(), Self::Error> {
  • replacement in libpijul/src/working_copy/memory.rs at line 239
    [17.206862][17.186:240]()
    None => Err((crate::Error::FileNotFound {
    [17.206862]
    [17.240]
    None => Err(Error::NotFound {
  • replacement in libpijul/src/working_copy/memory.rs at line 241
    [17.280][17.280:317]()
    })
    .into()),
    [17.280]
    [17.206862]
    }),
  • replacement in libpijul/src/working_copy/memory.rs at line 244
    [17.206878][17.206878:206969]()
    fn modified_time(&self, _file: &str) -> Result<std::time::SystemTime, anyhow::Error> {
    [17.206878]
    [17.206969]
    fn modified_time(&self, _file: &str) -> Result<std::time::SystemTime, Self::Error> {
  • replacement in libpijul/src/working_copy/memory.rs at line 248
    [17.207007][17.207007:207080]()
    fn remove_path(&mut self, path: &str) -> Result<(), anyhow::Error> {
    [17.207007]
    [17.207080]
    fn remove_path(&mut self, path: &str) -> Result<(), Self::Error> {
  • replacement in libpijul/src/working_copy/memory.rs at line 253
    [17.207135][17.207135:207213]()
    fn rename(&mut self, old: &str, new: &str) -> Result<(), anyhow::Error> {
    [17.207135]
    [17.207213]
    fn rename(&mut self, old: &str, new: &str) -> Result<(), Self::Error> {
  • replacement in libpijul/src/working_copy/memory.rs at line 260
    [17.207386][17.207386:207481]()
    fn set_permissions(&mut self, file: &str, permissions: u16) -> Result<(), anyhow::Error> {
    [17.207386]
    [17.207481]
    fn set_permissions(&mut self, file: &str, permissions: u16) -> Result<(), Self::Error> {
  • replacement in libpijul/src/working_copy/memory.rs at line 273
    [17.207946][17.207946:208032]()
    fn write_file<A, F: FnOnce(&mut dyn std::io::Write) -> Result<A, anyhow::Error>>(
    [17.207946]
    [17.208032]
    fn write_file<A, E: std::error::Error, F: FnOnce(&mut dyn std::io::Write) -> Result<A, E>>(
  • replacement in libpijul/src/working_copy/memory.rs at line 277
    [17.208090][17.208090:208126]()
    ) -> Result<A, anyhow::Error> {
    [17.208090]
    [17.208126]
    ) -> Result<A, WriteError<E>> {
  • replacement in libpijul/src/working_copy/memory.rs at line 283
    [17.208288][17.208288:208321]()
    writer(contents)
    [17.208288]
    [17.208321]
    writer(contents).map_err(WriteError::E)
  • replacement in libpijul/src/working_copy/memory.rs at line 288
    [17.208459][17.208459:208507]()
    let a = writer(&mut contents)?;
    [17.208459]
    [17.208507]
    let a = writer(&mut contents).map_err(WriteError::E)?;
  • replacement in libpijul/src/working_copy/filesystem.rs at line 32
    [17.209178][17.209178:209226]()
    ) -> Result<(PathBuf, String), anyhow::Error> {
    [17.209178]
    [17.209226]
    ) -> Result<(PathBuf, String), std::io::Error> {
  • edit in libpijul/src/working_copy/filesystem.rs at line 56
    [17.209915]
    [17.209915]
    }
    #[derive(Debug, Error)]
    pub enum AddError<T: std::error::Error + 'static> {
    #[error(transparent)]
    Ignore(#[from] ignore::Error),
    #[error(transparent)]
    Io(#[from] std::io::Error),
    #[error(transparent)]
    Fs(#[from] crate::fs::FsError<T>),
  • edit in libpijul/src/working_copy/filesystem.rs at line 68
    [17.209918]
    [17.209918]
    #[derive(Debug, Error)]
    pub enum Error<C: std::error::Error + 'static, T: std::error::Error + 'static> {
    #[error(transparent)]
    Add(#[from] AddError<T>),
    #[error(transparent)]
    Record(#[from] crate::record::RecordError<C, std::io::Error, T>),
    }
  • replacement in libpijul/src/working_copy/filesystem.rs at line 95
    [17.210434][17.210434:210471]()
    ) -> Result<(), anyhow::Error> {
    [17.210434]
    [17.210471]
    ) -> Result<(), Error<C::Error, T::Error>> {
  • replacement in libpijul/src/working_copy/filesystem.rs at line 111
    [13.1792][13.1792:1829]()
    ) -> Result<(), anyhow::Error> {
    [13.1792]
    [13.1829]
    ) -> Result<(), AddError<T::Error>> {
  • replacement in libpijul/src/working_copy/filesystem.rs at line 168
    [17.211282][17.211282:211319]()
    ) -> Result<(), anyhow::Error> {
    [17.211282]
    [17.211425]
    ) -> Result<(), Error<C::Error, T::Error>> {
  • replacement in libpijul/src/working_copy/filesystem.rs at line 193
    [17.213953][17.213953:214029]()
    fn create_dir_all(&mut self, file: &str) -> Result<(), anyhow::Error> {
    [17.213953]
    [11.159]
    type Error = std::io::Error;
    fn create_dir_all(&mut self, file: &str) -> Result<(), Self::Error> {
  • replacement in libpijul/src/working_copy/filesystem.rs at line 197
    [17.214095][17.214095:214177]()
    fn file_metadata(&self, file: &str) -> Result<InodeMetadata, anyhow::Error> {
    [17.214095]
    [11.215]
    fn file_metadata(&self, file: &str) -> Result<InodeMetadata, Self::Error> {
  • replacement in libpijul/src/working_copy/filesystem.rs at line 203
    [17.214426][17.214426:214515]()
    fn read_file(&self, file: &str, buffer: &mut Vec<u8>) -> Result<(), anyhow::Error> {
    [17.214426]
    [17.214515]
    fn read_file(&self, file: &str, buffer: &mut Vec<u8>) -> Result<(), Self::Error> {
  • replacement in libpijul/src/working_copy/filesystem.rs at line 209
    [17.214660][17.214660:214750]()
    fn modified_time(&self, file: &str) -> Result<std::time::SystemTime, anyhow::Error> {
    [17.214660]
    [11.334]
    fn modified_time(&self, file: &str) -> Result<std::time::SystemTime, Self::Error> {
  • replacement in libpijul/src/working_copy/filesystem.rs at line 214
    [17.214848][17.214848:214921]()
    fn remove_path(&mut self, path: &str) -> Result<(), anyhow::Error> {
    [17.214848]
    [11.392]
    fn remove_path(&mut self, path: &str) -> Result<(), Self::Error> {
  • replacement in libpijul/src/working_copy/filesystem.rs at line 227
    [17.215297][17.215297:215378]()
    fn rename(&mut self, former: &str, new: &str) -> Result<(), anyhow::Error> {
    [17.215297]
    [11.429]
    fn rename(&mut self, former: &str, new: &str) -> Result<(), Self::Error> {
  • replacement in libpijul/src/working_copy/filesystem.rs at line 239
    [17.215737][17.215737:215832]()
    fn set_permissions(&mut self, name: &str, permissions: u16) -> Result<(), anyhow::Error> {
    [17.215737]
    [17.215832]
    fn set_permissions(&mut self, name: &str, permissions: u16) -> Result<(), Self::Error> {
  • replacement in libpijul/src/working_copy/filesystem.rs at line 254
    [17.216332][17.216332:216429]()
    fn set_permissions(&mut self, _name: &str, _permissions: u16) -> Result<(), anyhow::Error> {
    [17.216332]
    [17.216429]
    fn set_permissions(&mut self, _name: &str, _permissions: u16) -> Result<(), Self::Error> {
  • replacement in libpijul/src/working_copy/filesystem.rs at line 257
    [17.216450][17.216450:216536]()
    fn write_file<A, F: FnOnce(&mut dyn std::io::Write) -> Result<A, anyhow::Error>>(
    [17.216450]
    [17.216536]
    fn write_file<A, E: std::error::Error, F: FnOnce(&mut dyn std::io::Write) -> Result<A, E>>(
  • replacement in libpijul/src/working_copy/filesystem.rs at line 261
    [17.216594][17.216594:216630]()
    ) -> Result<A, anyhow::Error> {
    [17.216594]
    [11.541]
    ) -> Result<A, WriteError<E>> {
  • replacement in libpijul/src/working_copy/filesystem.rs at line 264
    [17.216712][17.216712:216752]()
    std::fs::create_dir_all(p)?
    [17.216712]
    [17.216752]
    std::fs::create_dir_all(p).map_err(WriteError::Io)?
  • replacement in libpijul/src/working_copy/filesystem.rs at line 267
    [17.216813][17.216813:216918]()
    let mut file = std::io::BufWriter::new(std::fs::File::create(&path)?);
    writer(&mut file)
    [17.216813]
    [17.216918]
    let mut file =
    std::io::BufWriter::new(std::fs::File::create(&path).map_err(WriteError::Io)?);
    writer(&mut file).map_err(WriteError::E)
  • replacement in libpijul/src/vertex_buffer.rs at line 15
    [17.217771][17.217771:217952]()
    fn output_line<F: FnOnce(&mut Vec<u8>) -> Result<(), anyhow::Error>>(
    &mut self,
    key: Vertex<ChangeId>,
    contents: F,
    ) -> Result<(), anyhow::Error>;
    [17.217771]
    [17.217952]
    fn output_line<E, F>(&mut self, key: Vertex<ChangeId>, contents: F) -> Result<(), E>
    where
    E: From<std::io::Error>,
    F: FnOnce(&mut Vec<u8>) -> Result<(), E>;
  • replacement in libpijul/src/vertex_buffer.rs at line 20
    [17.217953][17.217953:218097]()
    fn output_conflict_marker(&mut self, s: &str) -> Result<(), anyhow::Error>;
    fn begin_conflict(&mut self) -> Result<(), anyhow::Error> {
    [17.217953]
    [17.218097]
    fn output_conflict_marker(&mut self, s: &str) -> Result<(), std::io::Error>;
    fn begin_conflict(&mut self) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/vertex_buffer.rs at line 24
    [17.218153][17.218153:218224]()
    fn begin_zombie_conflict(&mut self) -> Result<(), anyhow::Error> {
    [17.218153]
    [17.218224]
    fn begin_zombie_conflict(&mut self) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/vertex_buffer.rs at line 27
    [17.218260][17.218260:218331]()
    fn begin_cyclic_conflict(&mut self) -> Result<(), anyhow::Error> {
    [17.218260]
    [17.218331]
    fn begin_cyclic_conflict(&mut self) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/vertex_buffer.rs at line 30
    [17.218367][17.218367:218430]()
    fn conflict_next(&mut self) -> Result<(), anyhow::Error> {
    [17.218367]
    [17.218430]
    fn conflict_next(&mut self) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/vertex_buffer.rs at line 33
    [17.218483][17.218483:218545]()
    fn end_conflict(&mut self) -> Result<(), anyhow::Error> {
    [17.218483]
    [17.218545]
    fn end_conflict(&mut self) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/vertex_buffer.rs at line 36
    [17.218599][17.218599:218668]()
    fn end_zombie_conflict(&mut self) -> Result<(), anyhow::Error> {
    [17.218599]
    [17.218668]
    fn end_zombie_conflict(&mut self) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/vertex_buffer.rs at line 39
    [17.218722][17.218722:218791]()
    fn end_cyclic_conflict(&mut self) -> Result<(), anyhow::Error> {
    [17.218722]
    [17.218791]
    fn end_cyclic_conflict(&mut self) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/vertex_buffer.rs at line 80
    [17.219820][17.219820:219993]()
    fn output_line<C: FnOnce(&mut Vec<u8>) -> Result<(), anyhow::Error>>(
    &mut self,
    _: Vertex<ChangeId>,
    c: C,
    ) -> Result<(), anyhow::Error> {
    [17.219820]
    [17.219993]
    fn output_line<E, C>(&mut self, _: Vertex<ChangeId>, c: C) -> Result<(), E>
    where
    E: From<std::io::Error>,
    C: FnOnce(&mut Vec<u8>) -> Result<(), E>,
    {
  • replacement in libpijul/src/vertex_buffer.rs at line 98
    [17.220451][17.220451:220532]()
    fn output_conflict_marker(&mut self, s: &str) -> Result<(), anyhow::Error> {
    [17.220451]
    [17.220532]
    fn output_conflict_marker(&mut self, s: &str) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/vertex_buffer.rs at line 112
    [17.220895][17.220895:220959]()
    fn begin_conflict(&mut self) -> Result<(), anyhow::Error> {
    [17.220895]
    [17.220959]
    fn begin_conflict(&mut self) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/vertex_buffer.rs at line 119
    [17.221159][17.221159:221230]()
    fn begin_zombie_conflict(&mut self) -> Result<(), anyhow::Error> {
    [17.221159]
    [17.221230]
    fn begin_zombie_conflict(&mut self) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/vertex_buffer.rs at line 126
    [17.221431][17.221431:221502]()
    fn begin_cyclic_conflict(&mut self) -> Result<(), anyhow::Error> {
    [17.221431]
    [17.221502]
    fn begin_cyclic_conflict(&mut self) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/vertex_buffer.rs at line 168
    [17.222360][17.222360:222533]()
    fn output_line<C: FnOnce(&mut Vec<u8>) -> Result<(), anyhow::Error>>(
    &mut self,
    _: Vertex<ChangeId>,
    c: C,
    ) -> Result<(), anyhow::Error> {
    [17.222360]
    [17.222533]
    fn output_line<E, C>(&mut self, _: Vertex<ChangeId>, c: C) -> Result<(), E>
    where
    E: From<std::io::Error>,
    C: FnOnce(&mut Vec<u8>) -> Result<(), E>,
    {
  • replacement in libpijul/src/vertex_buffer.rs at line 185
    [17.222923][17.222923:223004]()
    fn output_conflict_marker(&mut self, s: &str) -> Result<(), anyhow::Error> {
    [17.222923]
    [17.223004]
    fn output_conflict_marker(&mut self, s: &str) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/vertex_buffer.rs at line 196
    [17.223279][17.223279:223343]()
    fn begin_conflict(&mut self) -> Result<(), anyhow::Error> {
    [17.223279]
    [17.223343]
    fn begin_conflict(&mut self) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/vertex_buffer.rs at line 199
    [17.223399][17.223399:223470]()
    fn begin_zombie_conflict(&mut self) -> Result<(), anyhow::Error> {
    [17.223399]
    [17.223470]
    fn begin_zombie_conflict(&mut self) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/vertex_buffer.rs at line 202
    [17.223526][17.223526:223597]()
    fn begin_cyclic_conflict(&mut self) -> Result<(), anyhow::Error> {
    [17.223526]
    [17.223597]
    fn begin_cyclic_conflict(&mut self) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/unrecord/working_copy.rs at line 10
    [17.226275][17.226275:226308]()
    ) -> Result<(), anyhow::Error> {
    [17.226275]
    [17.226308]
    ) -> Result<(), T::Error> {
  • replacement in libpijul/src/unrecord/working_copy.rs at line 29
    [17.226907][17.226907:226940]()
    ) -> Result<(), anyhow::Error> {
    [17.226907]
    [17.226940]
    ) -> Result<(), super::UnrecordError<P::Error, T::Error>> {
  • replacement in libpijul/src/unrecord/working_copy.rs at line 47
    [17.227588][17.227588:227621]()
    ) -> Result<(), anyhow::Error> {
    [17.227588]
    [17.227621]
    ) -> Result<(), super::UnrecordError<P::Error, T::Error>> {
  • replacement in libpijul/src/unrecord/working_copy.rs at line 67
    [17.228382][17.228382:228471]()
    return_value = Some(restore_inode(txn, changes, source, dest, Inode::ROOT)?)
    [17.228382]
    [17.228471]
    return_value = Some(restore_inode(txn, changes, source, dest, Inode::ROOT)?);
  • replacement in libpijul/src/unrecord/working_copy.rs at line 69
    [17.228548][17.228548:228631]()
    return_value = Some(restore_inode(txn, changes, source, dest, inode)?)
    [17.228548]
    [17.228631]
    return_value = Some(restore_inode(txn, changes, source, dest, inode)?);
  • replacement in libpijul/src/unrecord/working_copy.rs at line 85
    [17.229088][17.229088:229124]()
    ) -> Result<Inode, anyhow::Error> {
    [17.229088]
    [17.229174]
    ) -> Result<Inode, super::UnrecordError<P::Error, T::Error>> {
  • replacement in libpijul/src/unrecord/working_copy.rs at line 87
    [17.229205][17.229205:229297]()
    let (_, basename) = changes.get_file_name(|h| txn.get_external(h), source, &mut name)?;
    [17.229205]
    [17.229297]
    let (_, basename) = changes
    .get_file_name(|h| txn.get_external(h), source, &mut name)
    .map_err(super::UnrecordError::Changestore)?;
  • replacement in libpijul/src/unrecord/working_copy.rs at line 99
    [17.152][17.405:467](),[17.467][17.1571:1619](),[17.259][17.1571:1619]()
    put_tree_with_rev(txn, file_id.as_file_id(), inode)?;
    put_inodes_with_rev(txn, inode, dest)?;
    [17.152]
    [17.338]
    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)?;
  • replacement in libpijul/src/unrecord/working_copy.rs at line 109
    [17.229781][17.229781:229827]()
    ) -> Result<Vertex<ChangeId>, crate::Error> {
    [17.229781]
    [17.229827]
    ) -> Result<Vertex<ChangeId>, BlockError> {
  • replacement in libpijul/src/unrecord/working_copy.rs at line 140
    [17.366][17.230794:230836](),[17.230794][17.230794:230836]()
    pub fn undo_file_reinsertion<T: MutTxnT>(
    [17.230739]
    [17.230836]
    pub fn undo_file_reinsertion<P: ChangeStore, T: MutTxnT>(
  • replacement in libpijul/src/unrecord/working_copy.rs at line 144
    [17.230916][17.230916:230949]()
    ) -> Result<(), anyhow::Error> {
    [17.230916]
    [17.230949]
    ) -> Result<(), super::UnrecordError<P::Error, T::Error>> {
  • replacement in libpijul/src/unrecord/working_copy.rs at line 150
    [17.231296][17.468:528]()
    del_inodes_with_rev(txn, inode, position)?;
    [17.231296]
    [17.231440]
    del_inodes_with_rev(txn, inode, position).map_err(super::UnrecordError::Txn)?;
  • edit in libpijul/src/unrecord/mod.rs at line 1
    [17.231493][17.231494:231549]()
    // org id IuiCX9taX7EZv/Aqz/UZc5r7v/fH7MJn3/QIj46oHwc=
  • edit in libpijul/src/unrecord/mod.rs at line 6
    [17.231671][17.231671:231689]()
    use crate::Error;
  • edit in libpijul/src/unrecord/mod.rs at line 11
    [17.231752]
    [17.231752]
    #[derive(Debug, Error)]
    pub enum UnrecordError<
    ChangestoreError: std::error::Error + 'static,
    TxnError: std::error::Error + 'static,
    > {
    #[error("Changestore error: {0}")]
    Changestore(ChangestoreError),
    #[error(transparent)]
    Txn(TxnError),
    #[error(transparent)]
    Block(#[from] crate::pristine::BlockError),
    #[error(transparent)]
    InconsistentChange(#[from] crate::pristine::InconsistentChange),
    #[error("Change not in channel: {}", hash.to_base32())]
    ChangeNotInChannel { hash: ChangeId },
    #[error("Change not in channel: {}", change_id.to_base32())]
    ChangeIsDependedUpon { change_id: ChangeId },
    #[error(transparent)]
    Missing(#[from] crate::missing_context::MissingError<TxnError>),
    #[error(transparent)]
    LocalApply(#[from] crate::apply::LocalApplyError<TxnError>),
    #[error(transparent)]
    Apply(#[from] crate::apply::ApplyError<ChangestoreError, TxnError>),
    }
  • replacement in libpijul/src/unrecord/mod.rs at line 41
    [17.231881][17.231881:231960]()
    ) -> Result<bool, anyhow::Error> {
    let change = changes.get_change(hash)?;
    [17.231881]
    [17.231960]
    ) -> Result<bool, UnrecordError<P::Error, T::Error>> {
    let change = changes
    .get_change(hash)
    .map_err(UnrecordError::Changestore)?;
  • replacement in libpijul/src/unrecord/mod.rs at line 53
    [17.232195][17.232195:232251]()
    del_channel_changes(txn, &mut channel, change_id)?;
    [17.232195]
    [17.232251]
    del_channel_changes::<T, P>(txn, &mut channel, change_id)?;
  • replacement in libpijul/src/unrecord/mod.rs at line 59
    [17.232391][17.232391:232522]()
    while txn.del_dep(change_id, None)? {}
    txn.del_external(change_id, None)?;
    txn.del_internal(*hash, None)?;
    [17.232391]
    [17.232522]
    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)?;
  • replacement in libpijul/src/unrecord/mod.rs at line 65
    [17.232625][17.232625:232676]()
    txn.del_revdep(dep, Some(change_id))?;
    [17.232625]
    [17.232676]
    txn.del_revdep(dep, Some(change_id))
    .map_err(UnrecordError::Txn)?;
  • replacement in libpijul/src/unrecord/mod.rs at line 73
    [17.232742][17.232742:232833]()
    // org id 4kyMdTywL4dWm7Vw3kXLcabNNGbFzSP3FTUptNMLPwg=
    fn del_channel_changes<T: MutTxnT>(
    [17.232742]
    [17.232833]
    fn del_channel_changes<T: MutTxnT, P: ChangeStore>(
  • replacement in libpijul/src/unrecord/mod.rs at line 78
    [17.232905][17.232905:232938]()
    ) -> Result<(), anyhow::Error> {
    [17.232905]
    [17.232938]
    ) -> Result<(), UnrecordError<P::Error, T::Error>> {
  • replacement in libpijul/src/unrecord/mod.rs at line 82
    [17.233055][17.233055:233125]()
    return Err((Error::ChangeNotOnChannel { change_id }).into());
    [17.233055]
    [17.233125]
    return Err(UnrecordError::ChangeNotInChannel { hash: change_id });
  • replacement in libpijul/src/unrecord/mod.rs at line 92
    [17.233360][17.233360:233436]()
    return Err((Error::ChangeIsDependedUpon { change_id }).into());
    [17.233360]
    [17.233436]
    return Err(UnrecordError::ChangeIsDependedUpon { change_id });
  • replacement in libpijul/src/unrecord/mod.rs at line 96
    [17.233453][17.233453:233506]()
    txn.del_changes(channel, change_id, timestamp)?;
    [17.233453]
    [17.233506]
    txn.del_changes(channel, change_id, timestamp)
    .map_err(UnrecordError::Txn)?;
  • replacement in libpijul/src/unrecord/mod.rs at line 100
    [17.233519][17.233519:233574]()
    // org id F70s1W/0AmTkJZfg47g3+OXxINmwCgXU7G5j5QZkvh8=
    [17.233519]
    [17.233574]
  • replacement in libpijul/src/unrecord/mod.rs at line 115
    [17.233982][17.233982:234037]()
    // org id UmzPcrZozUPTljK9LrlZa2FIXJwwvHpPmfRQ9uV4qTs=
    [17.233982]
    [17.234037]
  • replacement in libpijul/src/unrecord/mod.rs at line 122
    [17.234187][17.234187:234220]()
    ) -> Result<(), anyhow::Error> {
    [17.234187]
    [17.234220]
    ) -> Result<(), UnrecordError<C::Error, T::Error>> {
  • replacement in libpijul/src/unrecord/mod.rs at line 136
    [17.7506][17.234838:234862](),[17.234838][17.234838:234862]()
    )?;
    [17.7506]
    [17.234862]
    )
    .map_err(UnrecordError::Txn)?;
  • replacement in libpijul/src/unrecord/mod.rs at line 139
    [17.234880][17.234880:234960]()
    unapply_newvertex(txn, channel, change_id, &mut ws, newvertex)?
    [17.234880]
    [17.234960]
    unapply_newvertex::<T, C>(txn, channel, change_id, &mut ws, newvertex)?
  • replacement in libpijul/src/unrecord/mod.rs at line 143
    [17.234990][17.234990:235104]()
    repair_newvertex_contexts(txn, channel, &mut ws)?;
    // org id zX78t6A+99OopoXmY9luuPGgXMHwzPEPT8sYitaxNyc=
    [17.234990]
    [17.235104]
    repair_newvertex_contexts::<T, C>(txn, channel, &mut ws)?;
  • replacement in libpijul/src/unrecord/mod.rs at line 146
    [17.2017][17.2017:2074]()
    remove_zombies(txn, channel, change_id, n)?;
    [17.2017]
    [17.2074]
    remove_zombies::<T, C>(txn, channel, change_id, n)?;
  • edit in libpijul/src/unrecord/mod.rs at line 162
    [17.235718][17.235718:235773]()
    // org id ysIZl8M4RTRZyISrNO1VOKOsKxkQsZFux9RvLLl192Y=
  • replacement in libpijul/src/unrecord/mod.rs at line 181
    [17.236205][17.236205:236239]()
    fn unapply_newvertex<T: MutTxnT>(
    [17.236205]
    [17.236239]
    fn unapply_newvertex<T: MutTxnT, C: ChangeStore>(
  • replacement in libpijul/src/unrecord/mod.rs at line 187
    [17.236377][17.236377:236410]()
    ) -> Result<(), anyhow::Error> {
    [17.236377]
    [17.236410]
    ) -> Result<(), UnrecordError<C::Error, T::Error>> {
  • replacement in libpijul/src/unrecord/mod.rs at line 246
    [17.8203][17.8203:8219]()
    )?;
    [17.8203]
    [17.238504]
    )
    .map_err(UnrecordError::Txn)?;
  • replacement in libpijul/src/unrecord/mod.rs at line 258
    [17.238829][17.2496:2567]()
    working_copy::undo_file_addition(txn, change_id, new_vertex)?;
    [17.238829]
    [17.238914]
    working_copy::undo_file_addition(txn, change_id, new_vertex).map_err(UnrecordError::Txn)?;
  • replacement in libpijul/src/unrecord/mod.rs at line 263
    [17.238934][17.238934:238976]()
    fn repair_newvertex_contexts<T: MutTxnT>(
    [17.238934]
    [17.238976]
    fn repair_newvertex_contexts<T: MutTxnT, C: ChangeStore>(
  • replacement in libpijul/src/unrecord/mod.rs at line 267
    [17.239047][17.239047:239080]()
    ) -> Result<(), anyhow::Error> {
    [17.239047]
    [17.239080]
    ) -> Result<(), UnrecordError<C::Error, T::Error>> {
  • replacement in libpijul/src/unrecord/mod.rs at line 312
    [17.240305][17.240305:240360]()
    // org id TtkPh63N/jM5q98a/9yDp97cHPAUzouetXVib5fpVnY=
    [17.240305]
    [17.240360]
  • replacement in libpijul/src/unrecord/mod.rs at line 320
    [17.240557][17.240557:240590]()
    ) -> Result<(), anyhow::Error> {
    [17.240557]
    [17.240590]
    ) -> Result<(), UnrecordError<P::Error, T::Error>> {
  • replacement in libpijul/src/unrecord/mod.rs at line 357
    [17.241870][17.241870:241945]()
    working_copy::undo_file_reinsertion(txn, change_id, newedges)?
    [17.241870]
    [17.241945]
    working_copy::undo_file_reinsertion::<P, _>(txn, change_id, newedges)?
  • replacement in libpijul/src/unrecord/mod.rs at line 371
    [17.242168][17.242168:242203]()
    ) -> Result<bool, anyhow::Error> {
    [17.242168]
    [17.242203]
    ) -> Result<bool, crate::apply::ApplyError<C::Error, T::Error>> {
  • edit in libpijul/src/unrecord/mod.rs at line 395
    [17.243261]
    [17.243261]
    .map_err(crate::apply::ApplyError::Changestore)
  • replacement in libpijul/src/unrecord/mod.rs at line 404
    [17.243431][17.243431:243466]()
    ) -> Result<bool, anyhow::Error> {
    [17.243431]
    [17.243466]
    ) -> Result<bool, C::Error> {
  • replacement in libpijul/src/unrecord/mod.rs at line 422
    [17.243938][17.243938:243969]()
    fn remove_zombies<T: MutTxnT>(
    [17.243938]
    [17.243969]
    fn remove_zombies<T: MutTxnT, C: ChangeStore>(
  • replacement in libpijul/src/unrecord/mod.rs at line 427
    [17.244079][17.244079:244112]()
    ) -> Result<(), anyhow::Error> {
    [17.244079]
    [17.244112]
    ) -> Result<(), UnrecordError<C::Error, T::Error>> {
  • replacement in libpijul/src/unrecord/mod.rs at line 473
    [17.9353][17.9353:9373]()
    )?;
    [17.9353]
    [17.9373]
    )
    .map_err(UnrecordError::Txn)?;
  • replacement in libpijul/src/unrecord/mod.rs at line 490
    [17.246511][17.9726:9800]()
    put_graph_with_rev(txn, channel, f, u, v, u.change)?;
    [17.246511]
    [17.246584]
    put_graph_with_rev(txn, channel, f, u, v, u.change)
    .map_err(UnrecordError::Txn)?;
  • replacement in libpijul/src/unrecord/mod.rs at line 495
    [17.9860][17.9860:9942]()
    del_graph_with_rev(txn, channel, e.flag, v, w, e.introduced_by)?;
    [17.9860]
    [17.246762]
    del_graph_with_rev(txn, channel, e.flag, v, w, e.introduced_by)
    .map_err(UnrecordError::Txn)?;
  • edit in libpijul/src/unrecord/mod.rs at line 503
    [17.246806][17.246806:246861]()
    // org id 4dFFHO4v8n5FooqRmC0cyb1+9EjtjPMqW7wdJCUIRsU=
  • replacement in libpijul/src/unrecord/mod.rs at line 510
    [17.247082][17.247082:247115]()
    ) -> Result<(), anyhow::Error> {
    [17.247082]
    [17.247115]
    ) -> Result<(), UnrecordError<P::Error, T::Error>> {
  • edit in libpijul/src/record.rs at line 5
    [17.489024]
    [17.489024]
    use crate::diff;
  • edit in libpijul/src/record.rs at line 11
    [17.489199][17.489199:489225]()
    use crate::{diff, Error};
  • edit in libpijul/src/record.rs at line 12
    [17.489267]
    [17.489267]
    #[derive(Debug, Error)]
    pub enum RecordError<
    C: std::error::Error + 'static,
    W: std::error::Error,
    T: std::error::Error + 'static,
    > {
    #[error("Changestore error: {0}")]
    Changestore(C),
    #[error("Working copy error: {0}")]
    WorkingCopy(W),
    #[error("System time error: {0}")]
    SystemTimeError(#[from] std::time::SystemTimeError),
    #[error(transparent)]
    Txn(T),
    #[error(transparent)]
    Diff(#[from] diff::DiffError<C>),
    #[error("Path not in repository: {0}")]
    PathNotInRepo(String),
    #[error(transparent)]
    Io(#[from] std::io::Error),
    }
  • replacement in libpijul/src/record.rs at line 162
    [17.492891][17.492891:492928]()
    ) -> Result<(), anyhow::Error> {
    [17.492891]
    [17.492928]
    ) -> Result<(), RecordError<C::Error, W::Error, T::Error>> {
  • replacement in libpijul/src/record.rs at line 207
    [17.495237][17.495237:495269]()
    self.push_children(
    [17.495237]
    [17.495269]
    self.push_children::<_, _, C>(
  • replacement in libpijul/src/record.rs at line 225
    [17.495726][17.495726:495795]()
    ) -> Result<Option<Position<Option<ChangeId>>>, anyhow::Error> {
    [17.495726]
    [17.495795]
    ) -> Result<Option<Position<Option<ChangeId>>>, W::Error> {
  • replacement in libpijul/src/record.rs at line 323
    [17.499681][17.499681:499718]()
    ) -> Result<(), anyhow::Error> {
    [17.499681]
    [17.499718]
    ) -> Result<(), RecordError<C::Error, W::Error, T::Error>> {
  • replacement in libpijul/src/record.rs at line 344
    [17.500570][17.500570:500652]()
    changes.get_contents(|p| txn.get_external(p), name_dest, &mut name)?;
    [17.500570]
    [17.500652]
    changes
    .get_contents(|p| txn.get_external(p), name_dest, &mut name)
    .map_err(RecordError::Changestore)?;
  • replacement in libpijul/src/record.rs at line 383
    [17.502254][17.502254:502273]()
    )?
    [17.502254]
    [17.502273]
    )
    .map_err(RecordError::Changestore)?
  • replacement in libpijul/src/record.rs at line 392
    [17.502569][17.502569:502635]()
    working_copy.read_file(&item.full_path, &mut b)?;
    [17.502569]
    [17.502635]
    working_copy
    .read_file(&item.full_path, &mut b)
    .map_err(RecordError::WorkingCopy)?;
  • replacement in libpijul/src/record.rs at line 455
    [17.504647][17.504647:504701]()
    fn push_children<'a, T: MutTxnT, W: WorkingCopy>(
    [17.504647]
    [17.504701]
    fn push_children<'a, T: MutTxnT, W: WorkingCopy, C: ChangeStore>(
  • replacement in libpijul/src/record.rs at line 464
    [17.504935][17.504935:504972]()
    ) -> Result<(), anyhow::Error> {
    [17.504935]
    [17.504972]
    ) -> Result<(), RecordError<C::Error, W::Error, T::Error>> {
  • replacement in libpijul/src/record.rs at line 507
    [17.1661][17.506695:506821](),[17.506695][17.506695:506821]()
    return Err((Error::FileNotInRepo {
    path: prefix.to_string(),
    })
    .into());
    [17.1661]
    [17.506821]
    return Err(RecordError::PathNotInRepo(prefix.to_string()));
  • replacement in libpijul/src/record.rs at line 517
    [17.507032][17.507032:507067]()
    ) -> Result<bool, anyhow::Error> {
    [17.507032]
    [17.507067]
    ) -> Result<bool, std::time::SystemTimeError> {
  • replacement in libpijul/src/record.rs at line 546
    [17.507905][17.507905:507942]()
    ) -> Result<(), anyhow::Error> {
    [17.507905]
    [17.507942]
    ) -> Result<(), C::Error> {
  • replacement in libpijul/src/record.rs at line 549
    [17.508141][17.508141:508195]()
    item.metadata.write(&mut self.rec.contents)?;
    [17.508141]
    [17.508195]
    item.metadata.write(&mut self.rec.contents).unwrap();
  • replacement in libpijul/src/record.rs at line 628
    [17.511024][17.511024:511065]()
    ) -> Result<MovedEdges, anyhow::Error> {
    [17.511024]
    [17.511065]
    ) -> Result<MovedEdges, C::Error> {
  • edit in libpijul/src/pristine/sanakirja.rs at line 19
    [17.531485]
    [17.531485]
    #[derive(Debug, Error)]
    pub enum SanakirjaError {
    #[error(transparent)]
    Sanakirja(#[from] ::sanakirja::Error),
    #[error("Pristine locked")]
    PristineLocked,
    #[error("Pristine corrupt")]
    PristineCorrupt,
    #[error(transparent)]
    Borrow(#[from] std::cell::BorrowError),
    }
  • replacement in libpijul/src/pristine/sanakirja.rs at line 32
    [17.531501][17.531501:531574]()
    pub fn new<P: AsRef<Path>>(name: P) -> Result<Self, anyhow::Error> {
    [17.531501]
    [17.531574]
    pub fn new<P: AsRef<Path>>(name: P) -> Result<Self, SanakirjaError> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 35
    [17.531623][17.531623:531710]()
    pub unsafe fn new_nolock<P: AsRef<Path>>(name: P) -> Result<Self, anyhow::Error> {
    [17.531623]
    [17.531710]
    pub unsafe fn new_nolock<P: AsRef<Path>>(name: P) -> Result<Self, SanakirjaError> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 38
    [17.531766][17.531766:531860]()
    pub fn new_with_size<P: AsRef<Path>>(name: P, size: u64) -> Result<Self, anyhow::Error> {
    [17.531766]
    [17.83]
    pub fn new_with_size<P: AsRef<Path>>(name: P, size: u64) -> Result<Self, SanakirjaError> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 44
    [17.331][17.331:392]()
    Err(crate::Error::PristineLocked.into())
    [17.331]
    [17.392]
    Err(SanakirjaError::PristineLocked)
  • replacement in libpijul/src/pristine/sanakirja.rs at line 46
    [17.417][17.417:451]()
    Err(e.into())
    [17.417]
    [17.451]
    Err(SanakirjaError::Sanakirja(sanakirja::Error::IO(e)))
  • replacement in libpijul/src/pristine/sanakirja.rs at line 49
    [17.483][17.36470:36507]()
    Err(e) => Err(e.into()),
    [17.483]
    [17.519]
    Err(e) => Err(SanakirjaError::Sanakirja(e)),
  • replacement in libpijul/src/pristine/sanakirja.rs at line 55
    [17.532052][17.532052:532091]()
    ) -> Result<Self, anyhow::Error> {
    [17.532052]
    [17.532091]
    ) -> Result<Self, SanakirjaError> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 60
    [17.532198][17.532198:532253]()
    pub fn new_anon() -> Result<Self, anyhow::Error> {
    [17.532198]
    [17.532253]
    pub fn new_anon() -> Result<Self, SanakirjaError> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 63
    [17.532301][17.532301:532375]()
    pub fn new_anon_with_size(size: u64) -> Result<Self, anyhow::Error> {
    [17.532301]
    [17.532375]
    pub fn new_anon_with_size(size: u64) -> Result<Self, SanakirjaError> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 89
    [17.532743][17.532743:532803]()
    pub fn txn_begin(&self) -> Result<Txn, anyhow::Error> {
    [17.532743]
    [17.532803]
    pub fn txn_begin(&self) -> Result<Txn, SanakirjaError> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 120
    [17.534054][17.534054:534108]()
    Err(crate::Error::PristineCorrupt.into())
    [17.534054]
    [17.534108]
    Err(SanakirjaError::PristineCorrupt)
  • edit in libpijul/src/pristine/sanakirja.rs at line 331
    [17.542281]
    [17.542300]
    type Error = SanakirjaError;
  • replacement in libpijul/src/pristine/sanakirja.rs at line 352
    [17.542895][17.542895:542980]()
    fn hash_from_prefix(&self, s: &str) -> Result<(Hash, ChangeId), anyhow::Error> {
    [17.542895]
    [17.542980]
    fn hash_from_prefix(&self, s: &str) -> Result<(Hash, ChangeId), super::HashPrefixError> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 356
    [17.543067][17.543067:543147]()
    return Err((crate::Error::ParseError { s: s.to_string() }).into());
    [17.543067]
    [17.543147]
    return Err(super::HashPrefixError::Parse(s.to_string()));
  • replacement in libpijul/src/pristine/sanakirja.rs at line 373
    [17.543716][17.543716:543884]()
    return Err((crate::Error::AmbiguousHashPrefix {
    prefix: s.to_string(),
    })
    .into());
    [17.543716]
    [17.543884]
    return Err(super::HashPrefixError::Ambiguous(s.to_string()));
  • replacement in libpijul/src/pristine/sanakirja.rs at line 380
    [17.544005][17.544005:544126]()
    Err((crate::Error::ChangeNotFound {
    hash: s.to_string(),
    })
    .into())
    [17.544005]
    [17.544126]
    Err(super::HashPrefixError::NotFound(s.to_string()))
  • replacement in libpijul/src/pristine/sanakirja.rs at line 388
    [17.544252][17.544252:544291]()
    ) -> Result<Hash, anyhow::Error> {
    [17.544252]
    [17.544291]
    ) -> Result<Hash, super::HashPrefixError> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 393
    [17.544416][17.544416:544496]()
    return Err((crate::Error::ParseError { s: s.to_string() }).into());
    [17.544416]
    [17.544496]
    return Err(super::HashPrefixError::Parse(s.to_string()));
  • replacement in libpijul/src/pristine/sanakirja.rs at line 410
    [17.545049][17.545049:545217]()
    return Err((crate::Error::AmbiguousHashPrefix {
    prefix: s.to_string(),
    })
    .into());
    [17.545049]
    [17.545217]
    return Err(super::HashPrefixError::Ambiguous(s.to_string()));
  • replacement in libpijul/src/pristine/sanakirja.rs at line 417
    [17.545338][17.545338:545459]()
    Err((crate::Error::ChangeNotFound {
    hash: s.to_string(),
    })
    .into())
    [17.545338]
    [17.545459]
    Err(super::HashPrefixError::NotFound(s.to_string()))
  • replacement in libpijul/src/pristine/sanakirja.rs at line 812
    [17.559008][17.559008:559047]()
    ) -> Result<bool, anyhow::Error> {
    [17.559008]
    [17.559047]
    ) -> Result<bool, Self::Error> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 821
    [17.559250][17.559250:559289]()
    ) -> Result<bool, anyhow::Error> {
    [17.559250]
    [17.559289]
    ) -> Result<bool, Self::Error> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 826
    [17.559414][17.559414:559510]()
    fn put_partials(&mut self, k: &str, e: Position<ChangeId>) -> Result<bool, anyhow::Error> {
    [17.559395]
    [17.559510]
    fn put_partials(&mut self, k: &str, e: Position<ChangeId>) -> Result<bool, Self::Error> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 840
    [17.559846][17.559846:559885]()
    ) -> Result<bool, anyhow::Error> {
    [17.559846]
    [17.559885]
    ) -> Result<bool, Self::Error> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 856
    [17.560268][17.560268:560317]()
    ) -> Result<Option<Merkle>, anyhow::Error> {
    [17.560268]
    [17.560317]
    ) -> Result<Option<Merkle>, Self::Error> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 884
    [17.561234][17.561234:561273]()
    ) -> Result<bool, anyhow::Error> {
    [17.561234]
    [17.561273]
    ) -> Result<bool, Self::Error> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 918
    [17.562319][17.562319:562358]()
    ) -> Result<bool, anyhow::Error> {
    [17.562319]
    [17.562358]
    ) -> Result<bool, Self::Error> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 925
    [17.562607][17.562607:562707]()
    fn del_remote(&mut self, remote: &mut RemoteRef<Self>, k: u64) -> Result<bool, anyhow::Error> {
    [17.562607]
    [17.562707]
    fn del_remote(&mut self, remote: &mut RemoteRef<Self>, k: u64) -> Result<bool, Self::Error> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 936
    [17.563092][17.563092:563190]()
    fn open_or_create_channel(&mut self, name: &str) -> Result<ChannelRef<Self>, anyhow::Error> {
    [17.563092]
    [17.563190]
    fn open_or_create_channel(&mut self, name: &str) -> Result<ChannelRef<Self>, Self::Error> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 993
    [17.565222][17.565222:565273]()
    ) -> Result<ChannelRef<Self>, anyhow::Error> {
    [17.565222]
    [17.565273]
    ) -> Result<ChannelRef<Self>, ForkError<Self::Error>> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 1007
    [17.565672][17.565672:565984]()
    graph: self.txn.fork(&mut self.rng, &channel.graph)?,
    changes: self.txn.fork(&mut self.rng, &channel.changes)?,
    revchanges: self.txn.fork(&mut self.rng, &channel.revchanges)?,
    states: self.txn.fork(&mut self.rng, &channel.states)?,
    [17.565672]
    [17.565984]
    graph: self
    .txn
    .fork(&mut self.rng, &channel.graph)
    .map_err(|e| ForkError::Txn(e.into()))?,
    changes: self
    .txn
    .fork(&mut self.rng, &channel.changes)
    .map_err(|e| ForkError::Txn(e.into()))?,
    revchanges: self
    .txn
    .fork(&mut self.rng, &channel.revchanges)
    .map_err(|e| ForkError::Txn(e.into()))?,
    states: self
    .txn
    .fork(&mut self.rng, &channel.states)
    .map_err(|e| ForkError::Txn(e.into()))?,
  • replacement in libpijul/src/pristine/sanakirja.rs at line 1031
    [17.566324][17.566324:566455]()
    Err((crate::Error::ChannelNameExists {
    name: new_name.to_string(),
    })
    .into())
    [17.566324]
    [17.566455]
    Err(super::ForkError::ChannelNameExists(new_name.to_string()))
  • replacement in libpijul/src/pristine/sanakirja.rs at line 1039
    [17.566578][17.566578:566615]()
    ) -> Result<(), anyhow::Error> {
    [17.566578]
    [17.566615]
    ) -> Result<(), ForkError<Self::Error>> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 1050
    [17.566888][10.0:217]()
    self.txn.del(
    &mut self.rng,
    &mut self.channels,
    UnsafeSmallStr::from_small_str(channel.borrow().name.as_small_str()),
    None,
    )?;
    [17.566888]
    [17.566888]
    self.txn
    .del(
    &mut self.rng,
    &mut self.channels,
    UnsafeSmallStr::from_small_str(channel.borrow().name.as_small_str()),
    None,
    )
    .map_err(|e| ForkError::Txn(e.into()))?;
  • replacement in libpijul/src/pristine/sanakirja.rs at line 1071
    [17.567356][17.567356:567487]()
    Err((crate::Error::ChannelNameExists {
    name: new_name.to_string(),
    })
    .into())
    [17.567356]
    [17.567487]
    Err(ForkError::ChannelNameExists(new_name.to_string()))
  • replacement in libpijul/src/pristine/sanakirja.rs at line 1075
    [17.567504][17.567504:567580]()
    fn drop_channel(&mut self, name: &str) -> Result<bool, anyhow::Error> {
    [17.567504]
    [17.567580]
    fn drop_channel(&mut self, name: &str) -> Result<bool, Self::Error> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 1089
    [17.567999][17.567999:568095]()
    fn open_or_create_remote(&mut self, name: &str) -> Result<RemoteRef<Self>, anyhow::Error> {
    [17.567999]
    [17.568095]
    fn open_or_create_remote(&mut self, name: &str) -> Result<RemoteRef<Self>, Self::Error> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 1129
    [17.569566][17.569566:569654]()
    fn drop_remote(&mut self, remote: RemoteRef<Self>) -> Result<bool, anyhow::Error> {
    [17.569566]
    [17.569654]
    fn drop_remote(&mut self, remote: RemoteRef<Self>) -> Result<bool, Self::Error> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 1142
    [17.570030][17.570030:570111]()
    fn drop_named_remote(&mut self, name: &str) -> Result<bool, anyhow::Error> {
    [17.570030]
    [17.570111]
    fn drop_named_remote(&mut self, name: &str) -> Result<bool, Self::Error> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 1155
    [17.570478][17.570478:570533]()
    fn commit(mut self) -> Result<(), anyhow::Error> {
    [17.570478]
    [17.570533]
    fn commit(mut self) -> Result<(), Self::Error> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 1217
    [17.572784][17.572784:572872]()
    fn put_channel(&mut self, channel: ChannelRef<Self>) -> Result<(), anyhow::Error> {
    [17.572784]
    [17.572872]
    fn put_channel(&mut self, channel: ChannelRef<Self>) -> Result<(), SanakirjaError> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 1258
    [17.574502][17.574502:574593]()
    fn commit_channel(&mut self, channel: ChannelRef<Self>) -> Result<(), anyhow::Error> {
    [17.574502]
    [17.574593]
    fn commit_channel(&mut self, channel: ChannelRef<Self>) -> Result<(), SanakirjaError> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 1269
    [17.574894][17.574894:574980]()
    fn put_remotes(&mut self, remote: RemoteRef<Self>) -> Result<(), anyhow::Error> {
    [17.574894]
    [17.574980]
    fn put_remotes(&mut self, remote: RemoteRef<Self>) -> Result<(), ::sanakirja::Error> {
  • replacement in libpijul/src/pristine/sanakirja.rs at line 1293
    [17.575835][17.575835:575923]()
    fn commit_remote(&mut self, remote: RemoteRef<Self>) -> Result<(), anyhow::Error> {
    [17.575835]
    [17.575923]
    fn commit_remote(&mut self, remote: RemoteRef<Self>) -> Result<(), ::sanakirja::Error> {
  • replacement in libpijul/src/pristine/mod.rs at line 114
    [17.589085][17.589085:589140]()
    // org id Zm7WF9q4bHktcCg0LXmmKlQP7XVt4IkPEDuF9pREDw4=
    [17.589085]
    [17.589140]
    #[derive(Debug, Error)]
    pub enum HashPrefixError {
    #[error("Failed to parse hash prefix: {0}")]
    Parse(String),
    #[error("Ambiguous hash prefix: {0}")]
    Ambiguous(String),
    #[error("Change not found: {0}")]
    NotFound(String),
    }
    #[derive(Debug, Error)]
    pub enum ForkError<T: std::error::Error + 'static> {
    #[error("Channel name already exists: {0}")]
    ChannelNameExists(String),
    #[error(transparent)]
    Txn(T),
    }
  • edit in libpijul/src/pristine/mod.rs at line 134
    [17.589205]
    [17.589205]
    type Error: std::error::Error + Send + Sync + 'static;
  • replacement in libpijul/src/pristine/mod.rs at line 195
    [17.591137][17.591137:591226]()
    fn hash_from_prefix(&self, prefix: &str) -> Result<(Hash, ChangeId), anyhow::Error>;
    [17.591137]
    [17.591226]
    fn hash_from_prefix(&self, prefix: &str) -> Result<(Hash, ChangeId), HashPrefixError>;
  • replacement in libpijul/src/pristine/mod.rs at line 200
    [17.591329][17.591329:591367]()
    ) -> Result<Hash, anyhow::Error>;
    [17.591329]
    [17.591367]
    ) -> Result<Hash, HashPrefixError>;
  • edit in libpijul/src/pristine/mod.rs at line 346
    [17.354]
    [17.38850]
    #[derive(Error, Debug)]
    #[error("Inconsistent change")]
    pub struct InconsistentChange {}
  • replacement in libpijul/src/pristine/mod.rs at line 354
    [17.38959][17.38959:39007]()
    ) -> Result<Position<ChangeId>, crate::Error> {
    [17.38959]
    [16.0]
    ) -> Result<Position<ChangeId>, InconsistentChange> {
  • replacement in libpijul/src/pristine/mod.rs at line 359
    [17.39254][16.109:167]()
    return Err(crate::Error::InconsistentChange);
    [17.39254]
    [16.167]
    return Err(InconsistentChange {});
  • replacement in libpijul/src/pristine/mod.rs at line 513
    [17.43431][17.43431:43464]()
    ) -> Result<(), anyhow::Error> {
    [17.43431]
    [17.43464]
    ) -> Result<(), std::io::Error> {
  • edit in libpijul/src/pristine/mod.rs at line 536
    [17.609461][17.43975:44030]()
    // org id oGZWRYu9yo9VKkz4S9hipd5OpFx6kQiF5q/T9jSqp5A=
  • replacement in libpijul/src/pristine/mod.rs at line 543
    [17.44289][17.44289:44324]()
    ) -> Result<bool, anyhow::Error> {
    [17.44289]
    [17.44324]
    ) -> Result<bool, std::io::Error> {
  • replacement in libpijul/src/pristine/mod.rs at line 557
    [17.44669][17.44669:44702]()
    ) -> Result<(), anyhow::Error> {
    [17.44669]
    [17.44702]
    ) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/pristine/mod.rs at line 597
    [17.45440][17.45440:45475]()
    ) -> Result<bool, anyhow::Error> {
    [17.45440]
    [8.294]
    ) -> Result<bool, std::io::Error> {
  • replacement in libpijul/src/pristine/mod.rs at line 719
    [17.49172][17.49172:49205]()
    ) -> Result<(), anyhow::Error> {
    [17.49172]
    [17.49205]
    ) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/pristine/mod.rs at line 1079
    [17.629258][17.629258:629296]()
    ) -> Result<bool, anyhow::Error>;
    [17.629258]
    [17.629296]
    ) -> Result<bool, Self::Error>;
  • replacement in libpijul/src/pristine/mod.rs at line 1087
    [17.629546][17.629546:629584]()
    ) -> Result<bool, anyhow::Error>;
    [17.629546]
    [17.629584]
    ) -> Result<bool, Self::Error>;
  • replacement in libpijul/src/pristine/mod.rs at line 1096
    [17.629939][17.629939:629987]()
    ) -> Result<Option<Merkle>, anyhow::Error>;
    [17.629939]
    [17.629987]
    ) -> Result<Option<Merkle>, Self::Error>;
  • replacement in libpijul/src/pristine/mod.rs at line 1104
    [17.630240][17.630240:630278]()
    ) -> Result<bool, anyhow::Error>;
    [17.630240]
    [17.630278]
    ) -> Result<bool, Self::Error>;
  • replacement in libpijul/src/pristine/mod.rs at line 1116
    [17.631045][17.631045:631142]()
    fn open_or_create_channel(&mut self, name: &str) -> Result<ChannelRef<Self>, anyhow::Error>;
    [17.631045]
    [17.631142]
    fn open_or_create_channel(&mut self, name: &str) -> Result<ChannelRef<Self>, Self::Error>;
  • replacement in libpijul/src/pristine/mod.rs at line 1122
    [17.631231][17.631231:631281]()
    ) -> Result<ChannelRef<Self>, anyhow::Error>;
    [17.631231]
    [17.631281]
    ) -> Result<ChannelRef<Self>, ForkError<Self::Error>>;
  • replacement in libpijul/src/pristine/mod.rs at line 1128
    [17.631384][17.631384:631420]()
    ) -> Result<(), anyhow::Error>;
    [17.631384]
    [17.631420]
    ) -> Result<(), ForkError<Self::Error>>;
  • replacement in libpijul/src/pristine/mod.rs at line 1130
    [17.631421][17.631421:631496]()
    fn drop_channel(&mut self, name: &str) -> Result<bool, anyhow::Error>;
    [17.631421]
    [17.631496]
    fn drop_channel(&mut self, name: &str) -> Result<bool, Self::Error>;
  • replacement in libpijul/src/pristine/mod.rs at line 1133
    [17.631530][17.631530:631580]()
    fn commit(self) -> Result<(), anyhow::Error>;
    [17.631530]
    [17.636462]
    fn commit(self) -> Result<(), Self::Error>;
  • replacement in libpijul/src/pristine/mod.rs at line 1135
    [17.637894][17.637894:637989]()
    fn put_partials(&mut self, k: &str, e: Position<ChangeId>) -> Result<bool, anyhow::Error>;
    [17.636463]
    [17.637989]
    fn put_partials(&mut self, k: &str, e: Position<ChangeId>) -> Result<bool, Self::Error>;
  • replacement in libpijul/src/pristine/mod.rs at line 1137
    [17.638009][17.638009:638105](),[17.638105][17.638105:638143]()
    fn del_partials(
    &mut self,
    k: &str,
    e: Option<Position<ChangeId>>,
    ) -> Result<bool, anyhow::Error>;
    [17.637990]
    [17.638143]
    fn del_partials(&mut self, k: &str, e: Option<Position<ChangeId>>)
    -> Result<bool, Self::Error>;
  • replacement in libpijul/src/pristine/mod.rs at line 1140
    [17.638144][17.638144:638239]()
    fn open_or_create_remote(&mut self, name: &str) -> Result<RemoteRef<Self>, anyhow::Error>;
    [17.638144]
    [17.638239]
    fn open_or_create_remote(&mut self, name: &str) -> Result<RemoteRef<Self>, Self::Error>;
  • replacement in libpijul/src/pristine/mod.rs at line 1147
    [17.638359][17.638359:638397]()
    ) -> Result<bool, anyhow::Error>;
    [17.638359]
    [17.638397]
    ) -> Result<bool, Self::Error>;
  • replacement in libpijul/src/pristine/mod.rs at line 1149
    [17.638398][17.638398:638497]()
    fn del_remote(&mut self, remote: &mut RemoteRef<Self>, k: u64) -> Result<bool, anyhow::Error>;
    [17.638398]
    [17.638497]
    fn del_remote(&mut self, remote: &mut RemoteRef<Self>, k: u64) -> Result<bool, Self::Error>;
  • replacement in libpijul/src/pristine/mod.rs at line 1151
    [17.638498][17.638498:638585]()
    fn drop_remote(&mut self, remote: RemoteRef<Self>) -> Result<bool, anyhow::Error>;
    [17.638498]
    [17.638585]
    fn drop_remote(&mut self, remote: RemoteRef<Self>) -> Result<bool, Self::Error>;
  • replacement in libpijul/src/pristine/mod.rs at line 1153
    [17.638586][17.638586:638668]()
    fn drop_named_remote(&mut self, remote: &str) -> Result<bool, anyhow::Error>;
    [17.638586]
    [17.50088]
    fn drop_named_remote(&mut self, remote: &str) -> Result<bool, Self::Error>;
  • replacement in libpijul/src/pristine/mod.rs at line 1160
    [17.50207][17.50207:50240]()
    ) -> Result<(), anyhow::Error> {
    [17.50207]
    [17.50240]
    ) -> Result<(), T::Error> {
  • replacement in libpijul/src/pristine/mod.rs at line 1170
    [17.1646][17.1646:1681]()
    ) -> Result<bool, anyhow::Error> {
    [17.1646]
    [17.1681]
    ) -> Result<bool, T::Error> {
  • replacement in libpijul/src/pristine/mod.rs at line 1183
    [17.1947][17.1947:1980]()
    ) -> Result<(), anyhow::Error> {
    [17.1947]
    [17.1980]
    ) -> Result<(), T::Error> {
  • replacement in libpijul/src/pristine/mod.rs at line 1193
    [17.2155][17.2155:2190]()
    ) -> Result<bool, anyhow::Error> {
    [17.2155]
    [17.2190]
    ) -> Result<bool, T::Error> {
  • replacement in libpijul/src/pristine/mod.rs at line 1211
    [17.50582][17.50582:50615]()
    ) -> Result<(), anyhow::Error> {
    [17.50582]
    [17.50615]
    ) -> Result<(), T::Error> {
  • replacement in libpijul/src/pristine/mod.rs at line 1270
    [17.52349][17.52349:52384]()
    ) -> Result<bool, anyhow::Error> {
    [17.52349]
    [17.52384]
    ) -> Result<bool, T::Error> {
  • replacement in libpijul/src/pristine/mod.rs at line 1311
    [17.53375][17.53375:53410]()
    ) -> Result<bool, anyhow::Error> {
    [17.53375]
    [17.53410]
    ) -> Result<bool, T::Error> {
  • replacement in libpijul/src/pristine/mod.rs at line 1353
    [17.54432][17.54432:54465]()
    ) -> Result<(), anyhow::Error> {
    [17.54432]
    [17.54465]
    ) -> Result<(), T::Error> {
  • replacement in libpijul/src/pristine/mod.rs at line 1432
    [17.2138][17.2138:2171]()
    ) -> Result<(), anyhow::Error> {
    [17.2138]
    [17.2171]
    ) -> Result<(), std::io::Error> {
  • edit in libpijul/src/pristine/channel_dump.rs at line 3
    [17.650093]
    [17.650093]
    #[derive(Debug, Error)]
    pub enum ChannelDumpError<T: std::error::Error + 'static> {
    #[error(transparent)]
    Txn(T),
    #[error("Channel name already exists: {0}")]
    ChannelNameExists(String),
    }
  • replacement in libpijul/src/pristine/channel_dump.rs at line 309
    [17.661301][17.661301:661375]()
    pub fn read(&mut self, bytes: &[u8]) -> Result<bool, anyhow::Error> {
    [17.661301]
    [17.661375]
    pub fn read(&mut self, bytes: &[u8]) -> Result<bool, T::Error> {
  • replacement in libpijul/src/pristine/channel_dump.rs at line 395
    [17.665110][17.665110:665143]()
    ) -> Result<(), anyhow::Error> {
    [17.665110]
    [17.665143]
    ) -> Result<(), T::Error> {
  • edit in libpijul/src/pristine/block.rs at line 2
    [17.26]
    [17.26]
    #[derive(Debug, Error)]
    #[error("Block error: {:?}", block)]
    pub struct BlockError {
    block: Position<ChangeId>,
    }
  • replacement in libpijul/src/pristine/block.rs at line 14
    [17.191][17.191:237]()
    ) -> Result<Vertex<ChangeId>, crate::Error> {
    [17.191]
    [17.237]
    ) -> Result<Vertex<ChangeId>, BlockError> {
  • replacement in libpijul/src/pristine/block.rs at line 28
    [17.621][17.621:680]()
    return Err(crate::Error::WrongBlock { block: p });
    [17.621]
    [17.680]
    return Err(BlockError { block: p });
  • replacement in libpijul/src/pristine/block.rs at line 50
    [17.1526][17.1526:1589]()
    return Err(crate::Error::WrongBlock { block: p });
    [17.1526]
    [17.1589]
    return Err(BlockError { block: p });
  • replacement in libpijul/src/pristine/block.rs at line 59
    [17.1789][17.1789:1836]()
    Err(crate::Error::WrongBlock { block: p })
    [17.1789]
    [17.1836]
    Err(BlockError { block: p })
  • replacement in libpijul/src/pristine/block.rs at line 67
    [17.2008][17.2008:2054]()
    ) -> Result<Vertex<ChangeId>, crate::Error> {
    [17.2008]
    [17.2054]
    ) -> Result<Vertex<ChangeId>, BlockError> {
  • replacement in libpijul/src/pristine/block.rs at line 81
    [17.2477][17.2477:2536]()
    return Err(crate::Error::WrongBlock { block: p });
    [17.2477]
    [17.2536]
    return Err(BlockError { block: p });
  • replacement in libpijul/src/pristine/block.rs at line 118
    [17.3968][17.3968:4019]()
    Err(crate::Error::WrongBlock { block: p })
    [17.3968]
    [17.4019]
    Err(BlockError { block: p })
  • edit in libpijul/src/output/output.rs at line 1
    [17.671807][17.671808:671863]()
    // org id YWj26SRzNLfGg2Qeglz9QVnhMTU+0+RMuMvr6DwSA38=
  • replacement in libpijul/src/output/output.rs at line 3
    [17.671995][17.671995:672038]()
    use super::{collect_children, OutputItem};
    [17.671995]
    [17.672038]
    use super::{collect_children, OutputError, OutputItem, PristineOutputError};
  • edit in libpijul/src/output/output.rs at line 14
    [17.672377][17.672377:672432]()
    // org id LRtRE+PMuzBEsI/KgD1sy2W/K0f0HAN70rZlknlfCWs=
  • replacement in libpijul/src/output/output.rs at line 24
    [17.672755][17.672755:672810]()
    // org id 0ve7DFbo4xqHFBVPHbChT6lFMPwRxbNcxRs4Yzsb6rs=
    [17.672755]
    [17.672810]
  • replacement in libpijul/src/output/output.rs at line 37
    [17.673225][17.673225:673269]()
    ) -> Result<Vec<Conflict>, anyhow::Error> {
    [17.673225]
    [17.673269]
    ) -> Result<Vec<Conflict>, OutputError<P::Error, T::Error, R::Error>> {
  • edit in libpijul/src/output/output.rs at line 49
    [17.673483][17.673483:673538]()
    // org id MpMlEfciwimf8weu0yPEV+/uIP9ErgimOTSV8nipLRA=
  • replacement in libpijul/src/output/output.rs at line 63
    [17.673828][17.673828:673931]()
    ) -> Result<Vec<Conflict>, anyhow::Error> {
    // org id lpPIIMEW5CckD8tHjyvaRg/qw+G7csmIRQ9jxvSlOrk=
    [17.673828]
    [17.673931]
    ) -> Result<Vec<Conflict>, OutputError<P::Error, T::Error, R::Error>> {
  • replacement in libpijul/src/output/output.rs at line 82
    [17.674493][17.674493:674537]()
    kill_dead_files(txn, repo, &dead)?;
    [17.674493]
    [17.674537]
    kill_dead_files::<T, R, P>(txn, repo, &dead)?;
  • edit in libpijul/src/output/output.rs at line 91
    [17.674858][17.674858:674917]()
    // org id gsYVU8LjyrWgVuIqAeIYTdCP2GY2jK+dVUaY5EM8DZU=
  • replacement in libpijul/src/output/output.rs at line 147
    [17.677310][17.677310:677425]()
    // org id 17m71heSzJMzN/R3aNLLqJlxXhZYglRTUOrHQjDCwVs=
    let inode = move_or_create(
    [17.677310]
    [17.677425]
    let inode = move_or_create::<T, R, P>(
  • replacement in libpijul/src/output/output.rs at line 158
    [17.677856][17.677856:677912]()
    kill_dead_files(txn, repo, &dead)?;
    [17.677856]
    [17.677912]
    kill_dead_files::<T, R, P>(txn, repo, &dead)?;
  • edit in libpijul/src/output/output.rs at line 161
    [17.677973][17.677973:678044]()
    // org id 3dDmtOVITWsw6WH+WZ2gvHHNSFGeGJOf7xMvsclLv0M=
  • replacement in libpijul/src/output/output.rs at line 162
    [17.678091][17.678091:678140]()
    repo.create_dir_all(&path)?;
    [17.678091]
    [17.678140]
    repo.create_dir_all(&path)
    .map_err(OutputError::WorkingCopy)?;
  • replacement in libpijul/src/output/output.rs at line 176
    [17.678585][17.678585:678702]()
    output_file(txn, channel, changes, &output_item, &mut conflicts, w)
    })?;
    [17.678585]
    [17.678702]
    output_file::<_, _, R>(
    txn,
    channel,
    changes,
    &output_item,
    &mut conflicts,
    w,
    )
    })
    .map_err(OutputError::from)?
  • replacement in libpijul/src/output/output.rs at line 192
    [17.678910][17.678910:679059]()
    // org id 2XIp9np3LpR5M9OuJWMtiEOx57jFCeckeuAd61x3hKU=
    repo.set_permissions(&path, output_item.meta.permissions())?;
    [17.678910]
    [17.679059]
    repo.set_permissions(&path, output_item.meta.permissions())
    .map_err(OutputError::WorkingCopy)?;
  • replacement in libpijul/src/output/output.rs at line 199
    [17.679182][17.679182:679209]()
    repo.rename(a, b)?
    [17.679182]
    [17.679209]
    repo.rename(a, b).map_err(OutputError::WorkingCopy)?
  • edit in libpijul/src/output/output.rs at line 204
    [17.679236][17.679236:679291]()
    // org id zB9X/hdfYcIVLvilzZg7Z+hMNTdYgDxn8Yv0ibiwW9s=
  • replacement in libpijul/src/output/output.rs at line 214
    [17.679630][17.679630:679732]()
    // org id xBUt7AHfxqCxXNwSBliMDFiMWRNF3c0qpG6MYcEiSH4=
    fn move_or_create<T: MutTxnT, R: WorkingCopy>(
    [17.679630]
    [17.679732]
    fn move_or_create<T: MutTxnT, R: WorkingCopy, C: ChangeStore>(
  • replacement in libpijul/src/output/output.rs at line 222
    [17.679880][17.679880:679916]()
    ) -> Result<Inode, anyhow::Error> {
    [17.679880]
    [17.679916]
    ) -> Result<Inode, OutputError<C::Error, T::Error, R::Error>> {
  • replacement in libpijul/src/output/output.rs at line 229
    [17.680136][17.680136:680195]()
    // org id xS/j7ZPMIOAF9NgL2r1xaKrwJI6haZ2eBL0EQyNBgyo=
    [17.680136]
    [17.680195]
  • replacement in libpijul/src/output/output.rs at line 239
    [17.680701][17.2406:2475]()
    del_tree_with_rev(txn, parent.as_file_id(), inode)?;
    [17.680701]
    [17.680852]
    del_tree_with_rev(txn, parent.as_file_id(), inode)
    .map_err(PristineOutputError::Txn)?;
  • replacement in libpijul/src/output/output.rs at line 251
    [17.681223][17.681223:681279]()
    repo.rename(&current_name, &tmp_path)?;
    [17.681223]
    [17.681279]
    repo.rename(&current_name, &tmp_path)
    .map_err(OutputError::WorkingCopy)?;
  • replacement in libpijul/src/output/output.rs at line 258
    [17.681523][17.681523:681602]()
    crate::fs::rec_delete(txn, file_id.clone(), inode, true)?;
    [17.681523]
    [17.681602]
    crate::fs::rec_delete(txn, file_id.clone(), inode, true)
    .map_err(PristineOutputError::Fs)?;
  • replacement in libpijul/src/output/output.rs at line 261
    [17.681620][17.1662:1729](),[17.1729][17.2476:2534]()
    put_inodes_with_rev(txn, inode, output_item.pos)?;
    put_tree_with_rev(txn, file_id_, inode)?;
    [17.681620]
    [17.681836]
    put_inodes_with_rev(txn, inode, output_item.pos)
    .map_err(PristineOutputError::Txn)?;
    put_tree_with_rev(txn, file_id_, inode).map_err(PristineOutputError::Txn)?;
  • replacement in libpijul/src/output/output.rs at line 268
    [17.682008][17.682008:682083]()
    crate::fs::rec_delete(txn, file_id.clone(), inode, true)?;
    [17.682008]
    [17.682083]
    crate::fs::rec_delete(txn, file_id.clone(), inode, true)
    .map_err(PristineOutputError::Fs)?;
  • replacement in libpijul/src/output/output.rs at line 271
    [17.682097][17.1730:1793](),[17.1793][17.2535:2589]()
    put_inodes_with_rev(txn, inode, output_item.pos)?;
    put_tree_with_rev(txn, file_id_, inode)?;
    [17.682097]
    [17.682297]
    put_inodes_with_rev(txn, inode, output_item.pos).map_err(PristineOutputError::Txn)?;
    put_tree_with_rev(txn, file_id_, inode).map_err(PristineOutputError::Txn)?;
  • edit in libpijul/src/output/output.rs at line 275
    [17.682325][17.682325:682384]()
    // org id uwWMiVIILtuAREerIsrWeLRjSBFCxhZtjJRLJ1BhHqQ=
  • replacement in libpijul/src/output/output.rs at line 277
    [17.682457][17.682457:682528]()
    crate::fs::rec_delete(txn, file_id.clone(), inode, true)?;
    [17.682457]
    [17.682528]
    crate::fs::rec_delete(txn, file_id.clone(), inode, true)
    .map_err(PristineOutputError::Fs)?;
  • replacement in libpijul/src/output/output.rs at line 285
    [17.682701][17.1794:1853](),[17.1853][17.2590:2640]()
    put_inodes_with_rev(txn, inode, output_item.pos)?;
    put_tree_with_rev(txn, file_id_, inode)?;
    [17.682701]
    [17.682885]
    put_inodes_with_rev(txn, inode, output_item.pos).map_err(PristineOutputError::Txn)?;
    put_tree_with_rev(txn, file_id_, inode).map_err(PristineOutputError::Txn)?;
  • replacement in libpijul/src/output/output.rs at line 290
    [17.682911][17.682911:683010]()
    // org id GN2HnMRazrBbQEPBgPOj2kiaHsrz9CfnCmvfQnMs+gU=
    fn output_file<T: MutTxnT, P: ChangeStore>(
    [17.682911]
    [17.683010]
    fn output_file<T: MutTxnT, P: ChangeStore, W: WorkingCopy>(
  • replacement in libpijul/src/output/output.rs at line 298
    [17.683171][17.683171:683204]()
    ) -> Result<(), anyhow::Error> {
    [17.683171]
    [17.683204]
    ) -> Result<(), OutputError<P::Error, T::Error, W::Error>> {
  • replacement in libpijul/src/output/output.rs at line 302
    [17.683381][17.683381:683460]()
    alive::output_graph(changes, txn, channel, &mut f, &mut l, &mut forward)?;
    [17.683381]
    [17.683460]
    alive::output_graph(changes, txn, channel, &mut f, &mut l, &mut forward)
    .map_err(PristineOutputError::from)?;
  • replacement in libpijul/src/output/output.rs at line 308
    [17.683698][17.55840:55928]()
    del_graph_with_rev(txn, channel, edge.flag, vertex, dest, edge.introduced_by)?;
    [17.683698]
    [17.683785]
    del_graph_with_rev(txn, channel, edge.flag, vertex, dest, edge.introduced_by)
    .map_err(PristineOutputError::Txn)?;
  • replacement in libpijul/src/output/output.rs at line 313
    [17.683804][17.683804:683859]()
    // org id 4uIws8SX4Pc6k8n8Gg5W8ukCH1XvjAWIViBruFTA6rg=
    [17.683804]
    [17.683859]
  • replacement in libpijul/src/output/output.rs at line 357
    [17.685348][17.685348:685451]()
    // org id qtncQESQX2X6uNqryalEkYZlRV7d5PeDxHnU2aIx/XA=
    fn kill_dead_files<T: MutTxnT, W: WorkingCopy>(
    [17.685348]
    [17.685451]
    fn kill_dead_files<T: MutTxnT, W: WorkingCopy, C: ChangeStore>(
  • replacement in libpijul/src/output/output.rs at line 362
    [17.685544][17.685544:685577]()
    ) -> Result<(), anyhow::Error> {
    [17.685544]
    [17.685577]
    ) -> Result<(), OutputError<C::Error, T::Error, W::Error>> {
  • replacement in libpijul/src/output/output.rs at line 365
    [17.685693][17.2641:2703]()
    del_tree_with_rev(txn, fileid.as_file_id(), *inode)?;
    [17.685693]
    [17.685885]
    del_tree_with_rev(txn, fileid.as_file_id(), *inode).map_err(PristineOutputError::Txn)?;
  • replacement in libpijul/src/output/output.rs at line 368
    [17.2768][17.2768:2823]()
    del_inodes_with_rev(txn, *inode, vertex)?;
    [17.2768]
    [17.686069]
    del_inodes_with_rev(txn, *inode, vertex).map_err(PristineOutputError::Txn)?;
  • replacement in libpijul/src/output/output.rs at line 371
    [17.686114][17.686114:686151]()
    repo.remove_path(&name)?
    [17.686114]
    [17.686151]
    repo.remove_path(&name).map_err(OutputError::WorkingCopy)?
  • edit in libpijul/src/output/mod.rs at line 11
    [17.686366]
    [17.686366]
    #[derive(Debug, Error)]
    pub enum OutputError<
    ChangestoreError: std::error::Error + 'static,
    Txn: std::error::Error + 'static,
    W: std::error::Error + 'static,
    > {
    #[error("Working copy error: {0}")]
    WorkingCopy(W),
    #[error(transparent)]
    Pristine(#[from] PristineOutputError<ChangestoreError, Txn>),
    }
    #[derive(Debug, Error)]
    pub enum PristineOutputError<ChangestoreError: std::error::Error, Txn: std::error::Error + 'static>
    {
    #[error(transparent)]
    Txn(Txn),
    #[error("Changestore error: {0}")]
    Changestore(ChangestoreError),
    #[error(transparent)]
    Io(#[from] std::io::Error),
    #[error(transparent)]
    Fs(#[from] crate::fs::FsError<Txn>),
    }
    use crate::working_copy::WriteError;
    impl<C: std::error::Error, T: std::error::Error + 'static, W: std::error::Error>
    OutputError<C, T, W>
    {
    fn from(e: WriteError<Self>) -> Self {
    match e {
    WriteError::Io(e) => OutputError::Pristine(PristineOutputError::Io(e)),
    WriteError::E(e) => e,
    }
    }
    }
    #[derive(Debug, Error)]
    pub enum FileError<ChangestoreError: std::error::Error + 'static> {
    #[error(transparent)]
    Changestore(ChangestoreError),
    #[error(transparent)]
    Io(#[from] std::io::Error),
    }
    impl<C: std::error::Error, T: std::error::Error + 'static> From<FileError<C>>
    for PristineOutputError<C, T>
    {
    fn from(e: FileError<C>) -> Self {
    match e {
    FileError::Changestore(e) => PristineOutputError::Changestore(e),
    FileError::Io(e) => PristineOutputError::Io(e),
    }
    }
    }
  • replacement in libpijul/src/output/mod.rs at line 87
    [17.686842][17.686842:686875]()
    ) -> Result<(), anyhow::Error> {
    [17.686842]
    [17.686875]
    ) -> Result<(), PristineOutputError<P::Error, T::Error>> {
  • edit in libpijul/src/output/mod.rs at line 105
    [17.687287][17.687287:687350]()
    // org id Gb4FgVTFFkCPgh6xtUjeL/ntA6wAsIKhRiiX/8b4Jy8=
  • replacement in libpijul/src/output/mod.rs at line 108
    [17.687519][17.687519:687603]()
    changes.get_contents(|h| txn.get_external(h), name_vertex, &mut name_buf)?;
    [17.687519]
    [17.687603]
    changes
    .get_contents(|h| txn.get_external(h), name_vertex, &mut name_buf)
    .map_err(|e| PristineOutputError::Changestore(e))?;
  • edit in libpijul/src/output/mod.rs at line 124
    [17.688082][17.688082:688145]()
    // org id RFCdVpFfGZuILPerwkNtNS2jmRrxrMOGl0kh7aVMVmM=
  • edit in libpijul/src/output/archive.rs at line 9
    [17.690250]
    [17.690250]
    type Error: std::error::Error;
  • replacement in libpijul/src/output/archive.rs at line 11
    [17.690318][17.690318:690392]()
    fn close_file(&mut self, f: Self::File) -> Result<(), anyhow::Error>;
    [17.690318]
    [17.690392]
    fn close_file(&mut self, f: Self::File) -> Result<(), Self::Error>;
  • edit in libpijul/src/output/archive.rs at line 53
    [17.691376]
    [17.691376]
    type Error = std::io::Error;
  • replacement in libpijul/src/output/archive.rs at line 66
    [17.691768][17.691768:691846]()
    fn close_file(&mut self, file: Self::File) -> Result<(), anyhow::Error> {
    [17.691768]
    [17.691846]
    fn close_file(&mut self, file: Self::File) -> Result<(), Self::Error> {
  • edit in libpijul/src/output/archive.rs at line 76
    [17.692166]
    [17.692166]
    }
    #[derive(Debug, Error)]
    pub enum ArchiveError<
    P: std::error::Error + 'static,
    T: std::error::Error + 'static,
    A: std::error::Error + 'static,
    > {
    #[error(transparent)]
    A(A),
    #[error(transparent)]
    Txn(T),
    #[error(transparent)]
    Unrecord(#[from] crate::unrecord::UnrecordError<P, T>),
    #[error(transparent)]
    Apply(#[from] crate::apply::ApplyError<P, T>),
    #[error("State not found: {:?}", state)]
    StateNotFound { state: crate::pristine::Merkle },
    #[error(transparent)]
    File(#[from] crate::output::FileError<P>),
    #[error(transparent)]
    Output(#[from] crate::output::PristineOutputError<P, T>),
  • replacement in libpijul/src/output/archive.rs at line 106
    [17.692359][17.692359:692403]()
    ) -> Result<Vec<Conflict>, anyhow::Error> {
    [17.692359]
    [17.692403]
    ) -> Result<Vec<Conflict>, ArchiveError<P::Error, T::Error, A::Error>> {
  • replacement in libpijul/src/output/archive.rs at line 203
    [17.696086][17.696086:696127]()
    arch.close_file(f)?;
    [17.696086]
    [17.696127]
    arch.close_file(f).map_err(ArchiveError::A)?;
  • edit in libpijul/src/missing_context.rs at line 1
    [17.696460][17.696461:696516]()
    // org id 58v3AKimretz5he0vs+xqV3r0G0SNrO0HFWAzfAI/50=
  • edit in libpijul/src/missing_context.rs at line 7
    [17.696706]
    [17.696706]
    #[derive(Debug, Error)]
    pub enum MissingError<TxnError: std::error::Error + 'static> {
    #[error(transparent)]
    Txn(TxnError),
    #[error(transparent)]
    Block(#[from] BlockError),
    #[error(transparent)]
    Inconsistent(#[from] InconsistentChange),
    }
  • replacement in libpijul/src/missing_context.rs at line 24
    [17.696868][17.696868:696955]()
    ) -> Result<Option<&(Graph, HashMap<Vertex<ChangeId>, VertexId>)>, crate::Error> {
    [17.696868]
    [17.696955]
    ) -> Result<Option<&(Graph, HashMap<Vertex<ChangeId>, VertexId>)>, InconsistentChange> {
  • replacement in libpijul/src/missing_context.rs at line 33
    [17.697325][17.566:640]()
    return Err(crate::Error::InconsistentChange);
    [17.697325]
    [17.697406]
    return Err(InconsistentChange {});
  • replacement in libpijul/src/missing_context.rs at line 51
    [17.697950][17.697950:698005]()
    // org id CwY6M+Aa91RfVAJkIYG3StPNDxg5S2/Q0RJB2eWlhFg=
    [17.697950]
    [17.698005]
  • replacement in libpijul/src/missing_context.rs at line 64
    [17.698287][17.698287:698320]()
    ) -> Result<(), anyhow::Error> {
    [17.698287]
    [17.698320]
    ) -> Result<(), MissingError<T::Error>> {
  • replacement in libpijul/src/missing_context.rs at line 103
    [17.699639][17.699639:699655]()
    )?;
    [17.699639]
    [17.699655]
    )
    .map_err(MissingError::Txn)?;
  • replacement in libpijul/src/missing_context.rs at line 114
    [17.699886][17.699886:699902]()
    )?;
    [17.699886]
    [17.699902]
    )
    .map_err(MissingError::Txn)?;
  • replacement in libpijul/src/missing_context.rs at line 126
    [17.700095][17.700095:700128]()
    ) -> Result<(), anyhow::Error> {
    [17.700095]
    [17.700128]
    ) -> Result<(), MissingError<T::Error>> {
  • replacement in libpijul/src/missing_context.rs at line 142
    [17.700557][17.700557:700569]()
    )?;
    [17.700557]
    [17.700569]
    )
    .map_err(MissingError::Txn)?;
  • replacement in libpijul/src/missing_context.rs at line 147
    [17.700588][17.700588:700643]()
    // org id 33iwKoFwpXhCt1MdikUmkOn7apYc7yMUk23JBOUn5mg=
    [17.700588]
    [17.700643]
  • replacement in libpijul/src/missing_context.rs at line 159
    [17.700904][17.700904:700937]()
    ) -> Result<(), anyhow::Error> {
    [17.700904]
    [17.700937]
    ) -> Result<(), MissingError<T::Error>> {
  • replacement in libpijul/src/missing_context.rs at line 189
    [17.57371][17.57371:57387]()
    )?;
    [17.57371]
    [17.701825]
    )
    .map_err(MissingError::Txn)?;
  • replacement in libpijul/src/missing_context.rs at line 195
    [17.701854][17.701854:701909]()
    // org id GMesFpbMkVsOgAOjes5yxc060bclzWVMLh5KLd/KQc8=
    [17.701854]
    [17.701909]
  • replacement in libpijul/src/missing_context.rs at line 204
    [17.702145][17.702145:702176]()
    ) -> Result<(), anyhow::Error>
    [17.702145]
    [17.702176]
    ) -> Result<(), MissingError<T::Error>>
  • edit in libpijul/src/missing_context.rs at line 296
    [17.705750][17.705750:705805]()
    // org id OfylSf5taky9lfC0119yeNkCZSw55LxD7HNIT7E0TO8=
  • replacement in libpijul/src/missing_context.rs at line 304
    [17.706038][17.706038:706069]()
    ) -> Result<(), anyhow::Error>
    [17.706038]
    [17.706069]
    ) -> Result<(), MissingError<T::Error>>
  • replacement in libpijul/src/missing_context.rs at line 322
    [17.706666][17.706666:706721]()
    // org id ueoLxafjHlJdBaAESsgdkbWhSKPGMpMkuFiROTxbrSM=
    [17.706666]
    [17.706721]
  • replacement in libpijul/src/missing_context.rs at line 424
    [17.709559][17.709559:709590]()
    ) -> Result<(), anyhow::Error>
    [17.709559]
    [17.709590]
    ) -> Result<(), MissingError<T::Error>>
  • edit in libpijul/src/missing_context.rs at line 428
    [17.709626][17.709626:709685]()
    // org id HPoxuN+RIwX+UvJZERkZAFK6+F5MEAFM39nnpnXs9YY=
  • edit in libpijul/src/missing_context.rs at line 439
    [17.710193][17.710193:710260]()
    // org id izc8DKE2hSSCYLTpux0cTTOqoMvRdn35r2Hfrdyq82w=
  • replacement in libpijul/src/missing_context.rs at line 447
    [17.710515][17.710515:710531]()
    )?;
    [17.710515]
    [17.710531]
    )
    .map_err(MissingError::Txn)?;
  • replacement in libpijul/src/missing_context.rs at line 460
    [17.710962][17.710962:710986]()
    )?;
    [17.710962]
    [17.710986]
    )
    .map_err(MissingError::Txn)?;
  • edit in libpijul/src/missing_context.rs at line 468
    [17.711106][17.711106:711169]()
    // org id Hux8KrdJakJleVXFgumk9t/dqB3Cl95Q0HD49nlsmD4=
  • replacement in libpijul/src/missing_context.rs at line 484
    [17.711811][17.711811:711844]()
    ) -> Result<(), anyhow::Error> {
    [17.711811]
    [17.711844]
    ) -> Result<(), MissingError<T::Error>> {
  • replacement in libpijul/src/missing_context.rs at line 502
    [17.712486][17.712486:712510]()
    )?;
    [17.712486]
    [17.712510]
    )
    .map_err(MissingError::Txn)?;
  • replacement in libpijul/src/missing_context.rs at line 509
    [17.59363][17.59363:59459]()
    del_graph_with_rev(txn, channel, e.flag, dest_vertex, p, e.introduced_by)?;
    [17.59363]
    [17.712749]
    del_graph_with_rev(txn, channel, e.flag, dest_vertex, p, e.introduced_by)
    .map_err(MissingError::Txn)?;
  • replacement in libpijul/src/missing_context.rs at line 526
    [17.713044][17.713044:713075]()
    ) -> Result<(), anyhow::Error>
    [17.713044]
    [17.713075]
    ) -> Result<(), MissingError<T::Error>>
  • replacement in libpijul/src/missing_context.rs at line 579
    [17.714609][17.714609:714642]()
    ) -> Result<(), anyhow::Error> {
    [17.714609]
    [17.714642]
    ) -> Result<(), MissingError<T::Error>> {
  • replacement in libpijul/src/missing_context.rs at line 596
    [17.715820][17.715820:715840]()
    )?;
    [17.715820]
    [17.715840]
    )
    .map_err(MissingError::Txn)?;
  • replacement in libpijul/src/missing_context.rs at line 622
    [17.716619][17.60144:60224]()
    put_graph_with_rev(txn, channel, flag, parent_dest, v, change_id)?;
    [17.716619]
    [17.716698]
    put_graph_with_rev(txn, channel, flag, parent_dest, v, change_id)
    .map_err(MissingError::Txn)?;
  • replacement in libpijul/src/missing_context.rs at line 633
    [17.716852][17.716852:716885]()
    ) -> Result<(), anyhow::Error> {
    [17.716852]
    [17.716885]
    ) -> Result<(), MissingError<T::Error>> {
  • replacement in libpijul/src/lib.rs at line 94
    [17.720137][17.720137:720177]()
    pub use crate::fs::WorkingCopyIterator;
    [17.720137]
    [17.720177]
    pub use crate::apply::{ApplyError, LocalApplyError};
    pub use crate::fs::{FsError, WorkingCopyIterator};
  • replacement in libpijul/src/lib.rs at line 116
    [17.720799][17.720799:720857]()
    ) -> Result<(u64, pristine::Merkle), anyhow::Error> {
    [17.720799]
    [17.720857]
    ) -> Result<(u64, pristine::Merkle), crate::apply::ApplyError<C::Error, Self::Error>> {
  • replacement in libpijul/src/lib.rs at line 126
    [17.721167][17.721167:721204]()
    ) -> Result<(), anyhow::Error> {
    [17.721167]
    [17.721204]
    ) -> Result<(), crate::apply::ApplyError<C::Error, Self::Error>> {
  • replacement in libpijul/src/lib.rs at line 135
    [17.721471][17.721471:721529]()
    ) -> Result<(u64, pristine::Merkle), anyhow::Error> {
    [17.721471]
    [17.721529]
    ) -> Result<(u64, pristine::Merkle), crate::apply::ApplyError<C::Error, Self::Error>> {
  • replacement in libpijul/src/lib.rs at line 144
    [17.721775][17.721775:721812]()
    ) -> Result<(), anyhow::Error> {
    [17.721775]
    [17.721812]
    ) -> Result<(), crate::apply::ApplyError<C::Error, Self::Error>> {
  • replacement in libpijul/src/lib.rs at line 153
    [17.722067][17.722067:722104]()
    ) -> Result<(), anyhow::Error> {
    [17.722067]
    [17.722104]
    ) -> Result<(), crate::apply::ApplyError<C::Error, Self::Error>> {
  • replacement in libpijul/src/lib.rs at line 164
    [17.722441][17.722441:722499]()
    ) -> Result<(u64, pristine::Merkle), anyhow::Error> {
    [17.722441]
    [17.722499]
    ) -> Result<(u64, pristine::Merkle), crate::apply::LocalApplyError<Self::Error>> {
  • replacement in libpijul/src/lib.rs at line 174
    [17.722831][17.722831:722889]()
    ) -> Result<(u64, pristine::Merkle), anyhow::Error> {
    [17.722831]
    [17.722889]
    ) -> Result<(u64, pristine::Merkle), crate::apply::LocalApplyError<Self::Error>> {
  • replacement in libpijul/src/lib.rs at line 186
    [17.723283][17.723283:723320]()
    ) -> Result<(), anyhow::Error> {
    [17.723283]
    [17.723320]
    ) -> Result<(), crate::record::RecordError<C::Error, W::Error, Self::Error>> {
  • replacement in libpijul/src/lib.rs at line 197
    [17.723681][17.723681:723732]()
    ) -> Result<record::Recorded, anyhow::Error> {
    [17.723681]
    [17.723732]
    ) -> Result<record::Recorded, crate::record::RecordError<C::Error, W::Error, Self::Error>> {
  • replacement in libpijul/src/lib.rs at line 208
    [17.724094][17.724094:724143]()
    ) -> Result<pristine::Hash, anyhow::Error> {
    [17.724094]
    [17.724183]
    ) -> Result<pristine::Hash, crate::apply::ApplyError<C::Error, Self::Error>> {
  • replacement in libpijul/src/lib.rs at line 232
    [17.725022][17.725022:725076]()
    let hash = changestore.save_change(&change)?;
    [17.725022]
    [7.380]
    let hash = changestore
    .save_change(&change)
    .map_err(apply::ApplyError::Changestore)?;
  • replacement in libpijul/src/lib.rs at line 244
    [17.725363][17.725363:725402]()
    ) -> Result<bool, anyhow::Error> {
    [17.725363]
    [17.725402]
    ) -> Result<bool, unrecord::UnrecordError<C::Error, Self::Error>> {
  • replacement in libpijul/src/lib.rs at line 255
    [17.725733][17.725733:725789]()
    ) -> Result<Vec<output::Conflict>, anyhow::Error> {
    [17.725733]
    [17.725789]
    ) -> Result<Vec<output::Conflict>, output::OutputError<C::Error, Self::Error, R::Error>> {
  • replacement in libpijul/src/lib.rs at line 269
    [17.726194][17.726194:726264]()
    fn add_file(&mut self, path: &str) -> Result<(), anyhow::Error> {
    [17.726194]
    [17.726264]
    fn add_file(&mut self, path: &str) -> Result<(), fs::FsError<Self::Error>> {
  • replacement in libpijul/src/lib.rs at line 277
    [17.726545][17.726545:726614]()
    fn add_dir(&mut self, path: &str) -> Result<(), anyhow::Error> {
    [17.726545]
    [17.726614]
    fn add_dir(&mut self, path: &str) -> Result<(), fs::FsError<Self::Error>> {
  • replacement in libpijul/src/lib.rs at line 284
    [17.726871][17.726871:726950]()
    fn add(&mut self, path: &str, is_dir: bool) -> Result<(), anyhow::Error> {
    [17.726871]
    [17.726950]
    fn add(&mut self, path: &str, is_dir: bool) -> Result<(), fs::FsError<Self::Error>> {
  • replacement in libpijul/src/lib.rs at line 288
    [17.727005][17.727005:727082]()
    fn move_file(&mut self, a: &str, b: &str) -> Result<(), anyhow::Error> {
    [17.727005]
    [17.727082]
    fn move_file(&mut self, a: &str, b: &str) -> Result<(), fs::FsError<Self::Error>> {
  • replacement in libpijul/src/lib.rs at line 292
    [17.727123][17.727123:727193]()
    fn remove_file(&mut self, a: &str) -> Result<(), anyhow::Error> {
    [17.727123]
    [17.727193]
    fn remove_file(&mut self, a: &str) -> Result<(), fs::FsError<Self::Error>> {
  • replacement in libpijul/src/lib.rs at line 300
    [17.727334][17.727334:727418]()
    ) -> Result<pristine::channel_dump::ChannelFromDump<'a, Self>, anyhow::Error> {
    [17.727334]
    [17.727418]
    ) -> Result<
    pristine::channel_dump::ChannelFromDump<'a, Self>,
    pristine::channel_dump::ChannelDumpError<Self::Error>,
    > {
    use pristine::channel_dump::*;
  • replacement in libpijul/src/lib.rs at line 306
    [17.727465][17.60362:60444](),[17.60444][17.727527:727603](),[17.727527][17.727527:727603]()
    let channel = pristine::MutTxnT::open_or_create_channel(self, name)?;
    Ok(pristine::channel_dump::ChannelFromDump::new(self, channel))
    [17.727465]
    [17.727603]
    let channel = pristine::MutTxnT::open_or_create_channel(self, name)
    .map_err(ChannelDumpError::Txn)?;
    Ok(ChannelFromDump::new(self, channel))
  • replacement in libpijul/src/lib.rs at line 310
    [17.727620][17.727620:727664](),[17.727664][17.727664:727719](),[17.727719][17.727719:727740]()
    Err((Error::ChannelNameExists {
    name: name.to_string(),
    })
    .into())
    [17.727620]
    [17.727740]
    Err(ChannelDumpError::ChannelNameExists(name.to_string()))
  • replacement in libpijul/src/lib.rs at line 321
    [17.728008][17.728008:728064]()
    ) -> Result<Vec<output::Conflict>, anyhow::Error> {
    [17.728008]
    [17.728064]
    ) -> Result<Vec<output::Conflict>, output::ArchiveError<P::Error, Self::Error, A::Error>> {
  • replacement in libpijul/src/lib.rs at line 348
    [17.728757][17.728757:728813]()
    ) -> Result<Vec<output::Conflict>, anyhow::Error> {
    [17.728757]
    [17.728813]
    ) -> Result<Vec<output::Conflict>, output::ArchiveError<P::Error, Self::Error, A::Error>> {
  • replacement in libpijul/src/lib.rs at line 370
    [17.729545][17.729545:729602]()
    Err((Error::StateNotFound { state }).into())
    [17.729545]
    [17.729602]
    Err(output::ArchiveError::StateNotFound { state })
  • replacement in libpijul/src/lib.rs at line 501
    [17.731981][17.731981:732030]()
    ) -> Result<(String, bool), anyhow::Error> {
    [17.731981]
    [17.732030]
    ) -> Result<(String, bool), C::Error> {
  • replacement in libpijul/src/lib.rs at line 514
    [17.732453][17.732453:732502]()
    ) -> Result<(String, bool), anyhow::Error> {
    [17.732453]
    [17.732502]
    ) -> Result<(String, bool), C::Error> {
  • replacement in libpijul/src/lib.rs at line 527
    [17.732890][17.732890:732971]()
    ) -> Result<(pristine::Position<pristine::ChangeId>, bool), anyhow::Error> {
    [17.732890]
    [17.732971]
    ) -> Result<(pristine::Position<pristine::ChangeId>, bool), fs::FsError<C::Error>> {
  • replacement in libpijul/src/lib.rs at line 537
    [17.733275][17.733275:733312]()
    ) -> Result<(), anyhow::Error> {
    [17.733275]
    [17.733312]
    ) -> Result<(), output::FileError<C::Error>> {
  • replacement in libpijul/src/lib.rs at line 550
    [17.733724][17.733724:733780]()
    ) -> Result<Vec<output::Conflict>, anyhow::Error> {
    [17.733724]
    [17.733780]
    ) -> Result<Vec<output::Conflict>, output::ArchiveError<C::Error, Self::Error, A::Error>> {
  • replacement in libpijul/src/lib.rs at line 560
    [17.734091][17.734091:734147]()
    ) -> Result<Vec<output::Conflict>, anyhow::Error> {
    [17.734091]
    [17.734147]
    ) -> Result<Vec<output::Conflict>, output::ArchiveError<C::Error, Self::Error, A::Error>> {
  • edit in libpijul/src/fs.rs at line 1
    [17.737429][17.737430:737485]()
    // org id GEhwQUzK6088geMhP32RRVZ2gKcVn8vpgw30CsBQVAw=
  • edit in libpijul/src/fs.rs at line 20
    [17.738443][17.738443:738461]()
    use crate::Error;
  • edit in libpijul/src/fs.rs at line 22
    [5.1]
    [17.738541]
    #[derive(Debug, Error)]
    pub enum FsError<T: std::error::Error + 'static> {
    #[error("Path not found: {0}")]
    NotFound(String),
    #[error("File already in repository: {0}")]
    AlreadyInRepo(String),
    #[error(transparent)]
    Txn(T),
    }
  • replacement in libpijul/src/fs.rs at line 103
    [5.7][17.740636:740814](),[17.740636][17.740636:740814]()
    /// Find the inode corresponding to that path, or return an error if
    /// there's no such inode.
    pub fn find_inode<T: TxnT>(txn: &T, path: &str) -> Result<Inode, anyhow::Error> {
    [5.7]
    [17.740814]
    /// Find the inode corresponding to that path, if it exists.
    pub fn find_inode<T: TxnT>(txn: &T, path: &str) -> Result<Inode, FsError<T::Error>> {
  • replacement in libpijul/src/fs.rs at line 110
    [17.741040][17.741040:741140]()
    Err((Error::FileNotInRepo {
    path: path.to_string(),
    })
    .into())
    [17.741040]
    [17.741140]
    Err(FsError::NotFound(path.to_string()))
  • replacement in libpijul/src/fs.rs at line 162
    [17.742759][17.742759:742795]()
    ) -> Result<Inode, anyhow::Error> {
    [17.742759]
    [17.742795]
    ) -> Result<Inode, FsError<T::Error>> {
  • replacement in libpijul/src/fs.rs at line 175
    [17.743256][17.2824:2896]()
    del_tree_with_rev(txn, parent_id.as_file_id(), inode)?;
    [17.743256]
    [17.743414]
    del_tree_with_rev(txn, parent_id.as_file_id(), inode).map_err(FsError::Txn)?;
  • replacement in libpijul/src/fs.rs at line 177
    [17.743482][17.2897:2959]()
    del_inodes_with_rev(txn, inode, vertex)?;
    [17.743482]
    [17.743619]
    del_inodes_with_rev(txn, inode, vertex).map_err(FsError::Txn)?;
  • replacement in libpijul/src/fs.rs at line 179
    [17.743637][17.2960:3032]()
    put_tree_with_rev(txn, parent_id.as_file_id(), child)?;
    [17.743637]
    [17.743764]
    put_tree_with_rev(txn, parent_id.as_file_id(), child).map_err(FsError::Txn)?;
  • replacement in libpijul/src/fs.rs at line 183
    [17.743821][17.743821:743945]()
    Err((Error::FileAlreadyInRepo {
    path: filename.to_string(),
    })
    .into())
    [17.743821]
    [17.743945]
    Err(FsError::AlreadyInRepo(filename.to_string()))
  • replacement in libpijul/src/fs.rs at line 191
    [17.744222][17.3033:3103]()
    put_tree_with_rev(txn, parent_id.as_file_id(), child_inode)?;
    [17.744222]
    [17.744345]
    put_tree_with_rev(txn, parent_id.as_file_id(), child_inode).map_err(FsError::Txn)?;
  • replacement in libpijul/src/fs.rs at line 198
    [17.744509][17.744509:744570]()
    txn.put_tree(dir_id.as_file_id(), child_inode)?;
    [17.744509]
    [17.744570]
    txn.put_tree(dir_id.as_file_id(), child_inode)
    .map_err(FsError::Txn)?;
  • replacement in libpijul/src/fs.rs at line 210
    [17.744782][17.744782:744815]()
    ) -> Result<(), anyhow::Error> {
    [17.744782]
    [17.744815]
    ) -> Result<(), FsError<T::Error>> {
  • replacement in libpijul/src/fs.rs at line 236
    [17.745846][17.745846:745879]()
    ) -> Result<(), anyhow::Error> {
    [17.745846]
    [17.745879]
    ) -> Result<(), FsError<T::Error>> {
  • replacement in libpijul/src/fs.rs at line 246
    [17.746112][17.746112:746145]()
    ) -> Result<(), anyhow::Error> {
    [17.746112]
    [17.746145]
    ) -> Result<(), FsError<T::Error>> {
  • replacement in libpijul/src/fs.rs at line 249
    [17.746252][17.3104:3162]()
    del_tree_with_rev(txn, fileref.as_file_id(), inode)?;
    [17.746252]
    [17.746499]
    del_tree_with_rev(txn, fileref.as_file_id(), inode).map_err(FsError::Txn)?;
  • replacement in libpijul/src/fs.rs at line 270
    [17.747046][17.747046:747079]()
    ) -> Result<(), anyhow::Error> {
    [17.747046]
    [17.747079]
    ) -> Result<(), FsError<T::Error>> {
  • replacement in libpijul/src/fs.rs at line 298
    [12.67][17.3163:3230](),[17.747947][17.3163:3230]()
    assert!(txn.del_tree(file_id.as_file_id(), Some(inode))?);
    [12.67]
    [17.748177]
    assert!(txn
    .del_tree(file_id.as_file_id(), Some(inode))
    .map_err(FsError::Txn)?);
  • replacement in libpijul/src/fs.rs at line 302
    [17.748183][17.3231:3292]()
    if del_tree_with_rev(txn, parent.as_file_id(), inode)? {
    [17.748183]
    [17.3292]
    if del_tree_with_rev(txn, parent.as_file_id(), inode).map_err(FsError::Txn)? {
  • replacement in libpijul/src/fs.rs at line 304
    [17.3352][17.3352:3406]()
    del_inodes_with_rev(txn, inode, vertex)?;
    [17.3352]
    [17.748543]
    del_inodes_with_rev(txn, inode, vertex).map_err(FsError::Txn)?;
  • replacement in libpijul/src/fs.rs at line 317
    [17.748753][17.748753:748840]()
    pub fn remove_file<T: MutTxnT>(txn: &mut T, path: &str) -> Result<(), anyhow::Error> {
    [17.748753]
    [17.748840]
    pub fn remove_file<T: MutTxnT>(txn: &mut T, path: &str) -> Result<(), FsError<T::Error>> {
  • replacement in libpijul/src/fs.rs at line 614
    [17.759162][17.759162:759219]()
    ) -> Result<(Position<ChangeId>, bool), anyhow::Error> {
    [17.759162]
    [17.759219]
    ) -> Result<(Position<ChangeId>, bool), FsError<C::Error>> {
  • replacement in libpijul/src/fs.rs at line 629
    [17.759848][17.759848:759934]()
    changes.get_contents(|h| txn.get_external(h), name_dest, &mut name_buf)?;
    [17.759848]
    [17.759934]
    changes
    .get_contents(|h| txn.get_external(h), name_dest, &mut name_buf)
    .map_err(FsError::Txn)?;
  • replacement in libpijul/src/fs.rs at line 654
    [17.760725][17.760725:760849]()
    return Err((Error::FileNotInRepo {
    path: path.to_string(),
    })
    .into());
    [17.760725]
    [17.760849]
    return Err(FsError::NotFound(path.to_string()));
  • replacement in libpijul/src/fs.rs at line 666
    [17.761102][17.761102:761147]()
    ) -> Result<(String, bool), anyhow::Error> {
    [17.761102]
    [17.761147]
    ) -> Result<(String, bool), C::Error> {
  • edit in libpijul/src/find_alive.rs at line 1
    [17.763306][17.763307:763362]()
    // org id MEBHKxb8oK7gGUqwl4XgvF1rhw0vYcS2SvEcXbaqMok=
  • replacement in libpijul/src/find_alive.rs at line 3
    [17.763466][17.763466:763521]()
    // org id 7GC7Q2pCnb0s8d1hQ5JvScuZvi24ZElhM713+gpHgeY=
    [17.763466]
    [17.763521]
  • replacement in libpijul/src/find_alive.rs at line 8
    [17.763631][17.763631:763686]()
    ) -> Result<HashSet<Vertex<ChangeId>>, crate::Error> {
    [17.763631]
    [17.763686]
    ) -> Result<HashSet<Vertex<ChangeId>>, BlockError> {
  • edit in libpijul/src/find_alive.rs at line 16
    [17.763908][17.763908:763967]()
    // org id naTw4q63bu2EvVqiMcyTpsR2XgGPIlo+Xg0pAHxty50=
  • edit in libpijul/src/find_alive.rs at line 23
    [17.764231][17.764231:764294]()
    // org id rATmHVXe7ujnLJm9BtP1kGj7iFT2vIEqTj1NygT3jKg=
  • edit in libpijul/src/find_alive.rs at line 27
    [17.764479][17.764479:764546]()
    // org id zyrR2nOtEiDH3D+9lWuTt+nzSRQoz8jgKSCV9Pn6rBE=
  • edit in libpijul/src/find_alive.rs at line 41
    [17.765010][17.765010:765077]()
    // org id uQvQHlOvPqlL+IP8xnqczr279XI5bz+CUrzAi0CkA+c=
  • replacement in libpijul/src/find_alive.rs at line 46
    [17.765135][17.765135:765190]()
    // org id Pw320u7FKY4pwoQyoNx3dm1mLfOcikfMt+ObiMN9njo=
    [17.765135]
    [17.765190]
  • replacement in libpijul/src/find_alive.rs at line 51
    [17.765298][17.765298:765386]()
    ) -> Result<(HashSet<Vertex<ChangeId>>, Vec<(Vertex<ChangeId>, Edge)>), crate::Error> {
    [17.765298]
    [17.765386]
    ) -> Result<(HashSet<Vertex<ChangeId>>, Vec<(Vertex<ChangeId>, Edge)>), BlockError> {
  • edit in libpijul/src/find_alive.rs at line 60
    [17.765638][17.765638:765697]()
    // org id 4NHenXps5de4P2CKb7tHKFazsveVGn9JlzWwLKcaDfY=
  • edit in libpijul/src/find_alive.rs at line 70
    [17.766044][17.766044:766107]()
    // org id yUDemNuncRZ3JF72y4FgQuPPYbQhsyj+3Dw9xom4PyQ=
  • edit in libpijul/src/find_alive.rs at line 76
    [17.766414][17.766414:766481]()
    // org id wquayIcqrmfRuMmqB4vd/wlbkHCGqWHFKFrwWY7st9g=
  • edit in libpijul/src/find_alive.rs at line 105
    [17.767543][17.767543:767610]()
    // org id S8/CnGSbU1qxCbYJGuK142RZkxIMPWg2k8LfVRnevOY=
  • edit in libpijul/src/diff/vertex_buffer.rs at line 1
    [17.768903][17.768904:768959]()
    // org id CuLytHOw5MhIUxraqhZp3RiCvAXraOTYajmAlakyEYY=
  • edit in libpijul/src/diff/vertex_buffer.rs at line 4
    [17.769051][17.769051:769106]()
    // org id JJDR/iA4tUvr8bHYeAudspj8wfK5zy20N2fayiMztIQ=
  • edit in libpijul/src/diff/vertex_buffer.rs at line 6
    [17.769153][17.769153:769212]()
    // org id O4woWVifU6a3TB5v+SW/IS06RN6LDal4OOyCtAcxrLg=
  • edit in libpijul/src/diff/vertex_buffer.rs at line 8
    [17.769277][17.769277:769336]()
    // org id znv/E/xSBDaD0tw5tDrdhOrfa00e2i6hoX4Y0P0M1yU=
  • edit in libpijul/src/diff/vertex_buffer.rs at line 10
    [17.769393][17.769393:769452]()
    // org id VrcGilQ4pnxnCqaZ30f0AYxuMW5/PAjPKYEV0W8OS3o=
  • edit in libpijul/src/diff/vertex_buffer.rs at line 11
    [17.769489][17.769489:769548]()
    // org id tHKWG2wUrgq0sWiE8x5vHspQufWcVCF0VBQMdJ/E6PI=
  • edit in libpijul/src/diff/vertex_buffer.rs at line 12
    [17.769596][17.769596:769655]()
    // org id RtX+AmeBXlMmux4krn3hr2TC5YAQ4dUD0aQ9cG0WmPE=
  • replacement in libpijul/src/diff/vertex_buffer.rs at line 17
    [17.769828][17.769828:769883]()
    // org id BJp9ZUxNcNZGXbeuELu/m0hxjcCh0Lrworivp2DNz/I=
    [17.769828]
    [17.769883]
  • replacement in libpijul/src/diff/vertex_buffer.rs at line 32
    [17.770115][17.770115:770170]()
    // org id x2fKAxT97bw7IkKwnYnx5G3Ys3zfwC7SQzd3J/n1vPU=
    [17.770115]
    [17.770170]
  • replacement in libpijul/src/diff/vertex_buffer.rs at line 40
    [17.770318][17.770318:770373]()
    // org id CBYn0QVUhTLd+1DPhJGxeuxcQPrCqfoCj5QdyKDc7Hg=
    [17.770318]
    [17.770373]
  • replacement in libpijul/src/diff/vertex_buffer.rs at line 47
    [17.770463][17.770463:770518]()
    // org id a0AuyLQJdOXmDjcbzuLKji89Suyb79UP94XH0DGe0rs=
    [17.770463]
    [17.770518]
  • replacement in libpijul/src/diff/vertex_buffer.rs at line 55
    [17.770684][17.770684:770739]()
    // org id pMXpkacg64vkNGPaLA/BBNw5jtn7ZI+FySQGEkPivNo=
    [17.770684]
    [17.770739]
  • replacement in libpijul/src/diff/vertex_buffer.rs at line 86
    [17.771665][17.771665:771720]()
    // org id NnHmVJ1BuujNsYVWbu4O4GAsabVxPG61uPjBjwLDGXY=
    [17.771665]
    [17.771720]
  • replacement in libpijul/src/diff/vertex_buffer.rs at line 114
    [17.772640][17.772640:772695]()
    // org id Pk25wSBAZ0t4Oeyx6ZTm1xqxX4h54qK8APBYvN+cjoo=
    [17.772640]
    [17.772695]
  • replacement in libpijul/src/diff/vertex_buffer.rs at line 140
    [17.773473][17.773473:773663]()
    fn output_line<C: FnOnce(&mut Vec<u8>) -> Result<(), anyhow::Error>>(
    &mut self,
    v: crate::pristine::Vertex<ChangeId>,
    c: C,
    ) -> Result<(), anyhow::Error> {
    [17.773473]
    [17.773663]
    fn output_line<E, C>(&mut self, v: crate::pristine::Vertex<ChangeId>, c: C) -> Result<(), E>
    where
    E: From<std::io::Error>,
    C: FnOnce(&mut Vec<u8>) -> Result<(), E>,
    {
  • replacement in libpijul/src/diff/vertex_buffer.rs at line 159
    [17.774078][17.774078:774201]()
    // org id 0I3Htm1AUtdNytI0fsyZC9DaKebRuVAOWnCAp1eM4As=
    fn begin_conflict(&mut self) -> Result<(), anyhow::Error> {
    [17.774078]
    [17.774201]
    fn begin_conflict(&mut self) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/diff/vertex_buffer.rs at line 165
    [17.774324][17.774324:774395]()
    fn begin_cyclic_conflict(&mut self) -> Result<(), anyhow::Error> {
    [17.774324]
    [17.774395]
    fn begin_cyclic_conflict(&mut self) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/diff/vertex_buffer.rs at line 172
    [17.774613][17.774613:774684]()
    fn begin_zombie_conflict(&mut self) -> Result<(), anyhow::Error> {
    [17.774613]
    [17.774684]
    fn begin_zombie_conflict(&mut self) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/diff/vertex_buffer.rs at line 176
    [17.774807][17.774807:774928]()
    // org id zJgaktpjBecKJlgqzyViT+wt457sbkOEgjcJ7OGLOcU=
    fn end_conflict(&mut self) -> Result<(), anyhow::Error> {
    [17.774807]
    [17.774928]
    fn end_conflict(&mut self) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/diff/vertex_buffer.rs at line 193
    [17.775540][17.775540:775609]()
    fn end_cyclic_conflict(&mut self) -> Result<(), anyhow::Error> {
    [17.775540]
    [17.775609]
    fn end_cyclic_conflict(&mut self) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/diff/vertex_buffer.rs at line 199
    [17.775781][17.775781:775903]()
    // org id W0ejcsiNdGBeNc6omb0+BUSF8MKjBtY+mLMyyqcvPBU=
    fn conflict_next(&mut self) -> Result<(), anyhow::Error> {
    [17.775781]
    [17.775903]
    fn conflict_next(&mut self) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/diff/vertex_buffer.rs at line 212
    [17.776342][17.776342:776487]()
    // org id kwhiQGVdomF6A7ajQbYvVGPQrMY24ay2R9148GsaXPw=
    fn output_conflict_marker(&mut self, marker: &str) -> Result<(), anyhow::Error> {
    [17.776342]
    [17.776487]
    fn output_conflict_marker(&mut self, marker: &str) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/diff/vertex_buffer.rs at line 243
    [17.777384][17.777384:777439]()
    // org id JBb+2glaECLGIRa7HRodwcjfm5JxXetKLaq3zZ/Nmlk=
    [17.777384]
    [17.777439]
  • edit in libpijul/src/diff/mod.rs at line 32
    [17.794100]
    [17.794100]
    #[derive(Debug, Error)]
    pub enum DiffError<P: std::error::Error + 'static> {
    #[error(transparent)]
    Output(#[from] crate::output::FileError<P>),
    }
  • replacement in libpijul/src/diff/mod.rs at line 50
    [17.794388][17.794388:794425]()
    ) -> Result<(), anyhow::Error> {
    [17.794388]
    [17.794425]
    ) -> Result<(), DiffError<P::Error>> {
  • edit in libpijul/src/changestore/mod.rs at line 20
    [17.818010]
    [17.818010]
    type Error: std::error::Error
    + std::fmt::Debug
    + Send
    + Sync
    + From<std::str::Utf8Error>
    + From<crate::change::ChangeError>
    + 'static;
  • replacement in libpijul/src/changestore/mod.rs at line 33
    [17.818231][17.818231:818346]()
    ) -> Result<usize, anyhow::Error>;
    fn get_header(&self, h: &Hash) -> Result<ChangeHeader, anyhow::Error> {
    [17.818231]
    [17.818346]
    ) -> Result<usize, Self::Error>;
    fn get_header(&self, h: &Hash) -> Result<ChangeHeader, Self::Error> {
  • replacement in libpijul/src/changestore/mod.rs at line 41
    [17.818500][17.818500:818539](),[17.818539][17.84:166]()
    ) -> Result<usize, anyhow::Error>;
    fn get_dependencies(&self, hash: &Hash) -> Result<Vec<Hash>, anyhow::Error> {
    [17.818500]
    [17.818626]
    ) -> Result<usize, Self::Error>;
    fn get_dependencies(&self, hash: &Hash) -> Result<Vec<Hash>, Self::Error> {
  • replacement in libpijul/src/changestore/mod.rs at line 45
    [17.818687][17.167:248]()
    fn get_extra_known(&self, hash: &Hash) -> Result<Vec<Hash>, anyhow::Error> {
    [17.818687]
    [17.818773]
    fn get_extra_known(&self, hash: &Hash) -> Result<Vec<Hash>, Self::Error> {
  • replacement in libpijul/src/changestore/mod.rs at line 48
    [17.818833][17.818833:818914]()
    fn knows(&self, hash0: &Hash, hash1: &Hash) -> Result<bool, anyhow::Error> {
    [17.818833]
    [17.818914]
    fn knows(&self, hash0: &Hash, hash1: &Hash) -> Result<bool, Self::Error> {
  • replacement in libpijul/src/changestore/mod.rs at line 57
    [17.819140][17.819140:819179]()
    ) -> Result<bool, anyhow::Error> {
    [17.819140]
    [17.819179]
    ) -> Result<bool, Self::Error> {
  • replacement in libpijul/src/changestore/mod.rs at line 66
    [17.819448][17.819448:819697]()
    ) -> Result<Vec<Hash>, anyhow::Error>;
    fn save_change(&self, p: &Change) -> Result<Hash, anyhow::Error>;
    fn del_change(&self, h: &Hash) -> Result<bool, anyhow::Error>;
    fn get_change(&self, h: &Hash) -> Result<Change, anyhow::Error>;
    [17.819448]
    [17.819697]
    ) -> Result<Vec<Hash>, Self::Error>;
    fn save_change(&self, p: &Change) -> Result<Hash, Self::Error>;
    fn del_change(&self, h: &Hash) -> Result<bool, Self::Error>;
    fn get_change(&self, h: &Hash) -> Result<Change, Self::Error>;
  • replacement in libpijul/src/changestore/mod.rs at line 75
    [17.819852][17.819852:819911]()
    ) -> Result<(InodeMetadata, &'a str), anyhow::Error> {
    [17.819852]
    [17.819911]
    ) -> Result<(InodeMetadata, &'a str), Self::Error> {
  • edit in libpijul/src/changestore/memory.rs at line 5
    [17.820846][17.820846:820864]()
    use crate::Error;
  • edit in libpijul/src/changestore/memory.rs at line 22
    [17.821211]
    [17.821211]
    #[derive(Debug, Error)]
    pub enum Error {
    #[error(transparent)]
    Io(#[from] std::io::Error),
    #[error(transparent)]
    Utf8(#[from] std::str::Utf8Error),
    #[error(transparent)]
    Change(#[from] crate::change::ChangeError),
    #[error("Change not found: {:?}", hash)]
    ChangeNotFound { hash: crate::Hash },
    #[error(transparent)]
    Bincode(#[from] bincode::Error),
    }
  • edit in libpijul/src/changestore/memory.rs at line 37
    [17.821241]
    [17.821241]
    type Error = Error;
  • replacement in libpijul/src/changestore/memory.rs at line 48
    [17.821589][17.821589:821629]()
    ) -> Result<usize, anyhow::Error> {
    [17.821589]
    [17.821629]
    ) -> Result<usize, Self::Error> {
  • replacement in libpijul/src/changestore/memory.rs at line 65
    [17.822154][17.822154:822194]()
    ) -> Result<usize, anyhow::Error> {
    [17.822154]
    [17.822194]
    ) -> Result<usize, Self::Error> {
  • replacement in libpijul/src/changestore/memory.rs at line 87
    [17.822890][17.822890:822934]()
    ) -> Result<Vec<Hash>, anyhow::Error> {
    [17.822890]
    [17.822934]
    ) -> Result<Vec<Hash>, Self::Error> {
  • replacement in libpijul/src/changestore/memory.rs at line 98
    [17.823259][17.823259:823330]()
    fn save_change(&self, p: &Change) -> Result<Hash, anyhow::Error> {
    [17.823259]
    [17.823330]
    fn save_change(&self, p: &Change) -> Result<Hash, Self::Error> {
  • replacement in libpijul/src/changestore/memory.rs at line 104
    [17.823469][17.823469:823537]()
    fn del_change(&self, h: &Hash) -> Result<bool, anyhow::Error> {
    [17.823469]
    [17.823537]
    fn del_change(&self, h: &Hash) -> Result<bool, Self::Error> {
  • replacement in libpijul/src/changestore/memory.rs at line 108
    [17.823628][17.823628:823698]()
    fn get_change(&self, h: &Hash) -> Result<Change, anyhow::Error> {
    [17.823628]
    [17.823698]
    fn get_change(&self, h: &Hash) -> Result<Change, Self::Error> {
  • replacement in libpijul/src/changestore/memory.rs at line 113
    [17.823823][17.823823:823978]()
    use crate::pristine::Base32;
    Err((Error::ChangeNotFound {
    hash: h.to_base32(),
    })
    .into())
    [17.823823]
    [17.823978]
    Err(Error::ChangeNotFound { hash: *h })
  • edit in libpijul/src/changestore/filesystem.rs at line 17
    [17.824519]
    [17.824519]
    }
    #[derive(Debug, Error)]
    pub enum Error {
    #[error(transparent)]
    Io(#[from] std::io::Error),
    #[error(transparent)]
    Utf8(#[from] std::str::Utf8Error),
    #[error(transparent)]
    ChangeFile(#[from] crate::change::ChangeError),
    #[error(transparent)]
    Persist(#[from] tempfile::PersistError),
  • replacement in libpijul/src/changestore/filesystem.rs at line 79
    [17.826098][17.826098:826121]()
    anyhow::Error,
    [17.826098]
    [17.826121]
    crate::change::ChangeError,
  • replacement in libpijul/src/changestore/filesystem.rs at line 96
    [17.826612][17.826612:826649]()
    ) -> Result<(), anyhow::Error> {
    [17.826612]
    [17.826649]
    ) -> Result<(), crate::change::ChangeError> {
  • replacement in libpijul/src/changestore/filesystem.rs at line 98
    [17.826696][17.826696:826755]()
    self.save_from_buf_unchecked(buf, hash, change_id)
    [17.826696]
    [17.826755]
    self.save_from_buf_unchecked(buf, hash, change_id)?;
    Ok(())
  • replacement in libpijul/src/changestore/filesystem.rs at line 107
    [17.826891][17.826891:826928]()
    ) -> Result<(), anyhow::Error> {
    [17.826891]
    [17.826928]
    ) -> Result<(), std::io::Error> {
  • edit in libpijul/src/changestore/filesystem.rs at line 124
    [17.827463]
    [17.827463]
    type Error = Error;
  • replacement in libpijul/src/changestore/filesystem.rs at line 148
    [17.828230][17.828230:828306]()
    fn get_header(&self, h: &Hash) -> Result<ChangeHeader, anyhow::Error> {
    [17.828230]
    [17.828306]
    fn get_header(&self, h: &Hash) -> Result<ChangeHeader, Self::Error> {
  • replacement in libpijul/src/changestore/filesystem.rs at line 159
    [17.828611][17.828611:828651]()
    ) -> Result<usize, anyhow::Error> {
    [17.828611]
    [17.828651]
    ) -> Result<usize, Self::Error> {
  • replacement in libpijul/src/changestore/filesystem.rs at line 174
    [17.829117][17.829117:829157]()
    ) -> Result<usize, anyhow::Error> {
    [17.829117]
    [17.829157]
    ) -> Result<usize, Self::Error> {
  • replacement in libpijul/src/changestore/filesystem.rs at line 193
    [17.829768][17.829768:829812]()
    ) -> Result<Vec<Hash>, anyhow::Error> {
    [17.829768]
    [17.829812]
    ) -> Result<Vec<Hash>, Self::Error> {
  • replacement in libpijul/src/changestore/filesystem.rs at line 205
    [17.830156][17.830156:830227]()
    fn save_change(&self, p: &Change) -> Result<Hash, anyhow::Error> {
    [17.830156]
    [17.830227]
    fn save_change(&self, p: &Change) -> Result<Hash, Self::Error> {
  • replacement in libpijul/src/changestore/filesystem.rs at line 217
    [17.830625][17.830625:830696]()
    fn del_change(&self, hash: &Hash) -> Result<bool, anyhow::Error> {
    [17.830625]
    [17.830696]
    fn del_change(&self, hash: &Hash) -> Result<bool, Self::Error> {
  • replacement in libpijul/src/changestore/filesystem.rs at line 224
    [17.831024][17.831024:831094]()
    fn get_change(&self, h: &Hash) -> Result<Change, anyhow::Error> {
    [17.831024]
    [17.831094]
    fn get_change(&self, h: &Hash) -> Result<Change, Self::Error> {
  • edit in libpijul/src/change.rs at line 1
    [17.831311][17.831312:831385]()
    // org id 4+w2sTG9zBScwyjzB8qqUXj0dCYZg3xGYPeKsGKua2k=
    use super::Error;
  • edit in libpijul/src/change.rs at line 4
    [17.831481][17.831481:831519]()
    #[cfg(feature = "zstd")]
    pub mod v3;
  • edit in libpijul/src/change.rs at line 7
    [17.831565]
    [17.831565]
    #[cfg(feature = "text-changes")]
    mod text_changes;
    mod change_file;
    pub use change_file::*;
    #[derive(Debug, Error)]
    pub enum ChangeError {
    #[error("Version mismatch")]
    VersionMismatch,
    #[error(transparent)]
    Io(#[from] std::io::Error),
    #[error(transparent)]
    Bincode(#[from] bincode::Error),
    #[error(transparent)]
    Zstd(#[from] zstd_seekable::Error),
    #[error(transparent)]
    TomlDe(#[from] toml::de::Error),
    #[error(transparent)]
    TomlSer(#[from] toml::ser::Error),
    #[error("Missing contents for change {:?}", hash)]
    MissingContents { hash: crate::pristine::Hash },
    #[error("Change hash mismatch, claimed {:?}, computed {:?}", claimed, computed)]
    ChangeHashMismatch {
    claimed: crate::pristine::Hash,
    computed: crate::pristine::Hash,
    },
    #[error(
    "Change contents hash mismatch, claimed {:?}, computed {:?}",
    claimed,
    computed
    )]
    ContentsHashMismatch {
    claimed: crate::pristine::Hash,
    computed: crate::pristine::Hash,
    },
    }
  • replacement in libpijul/src/change.rs at line 1169
    [17.868798][17.868798:868875]()
    fn compress<W: Write>(input: &[u8], mut w: W) -> Result<(), anyhow::Error> {
    [17.868798]
    [17.868875]
    fn compress<W: Write>(input: &[u8], mut w: W) -> Result<(), ChangeError> {
  • replacement in libpijul/src/change.rs at line 1190
    [17.869478][17.869478:869516]()
    ) -> Result<u64, anyhow::Error> {
    [17.869478]
    [17.869516]
    ) -> Result<u64, ChangeError> {
  • replacement in libpijul/src/change.rs at line 1196
    [17.869757][17.869757:869812]()
    return Err(Error::VersionMismatch.into());
    [17.869757]
    [17.869812]
    return Err(ChangeError::VersionMismatch);
  • replacement in libpijul/src/change.rs at line 1206
    [17.870081][17.870081:870162]()
    pub fn serialize<W: Write>(&self, mut w: W) -> Result<Hash, anyhow::Error> {
    [17.870081]
    [17.870244]
    pub fn serialize<W: Write>(&self, mut w: W) -> Result<Hash, ChangeError> {
  • replacement in libpijul/src/change.rs at line 1254
    [17.871761][17.871761:871846]()
    pub fn check_from_buffer(buf: &[u8], hash: &Hash) -> Result<(), anyhow::Error> {
    [17.871761]
    [17.871846]
    pub fn check_from_buffer(buf: &[u8], hash: &Hash) -> Result<(), ChangeError> {
  • replacement in libpijul/src/change.rs at line 1257
    [17.871982][17.871982:872037]()
    return Err(Error::VersionMismatch.into());
    [17.871982]
    [17.872037]
    return Err(ChangeError::VersionMismatch);
  • replacement in libpijul/src/change.rs at line 1273
    [17.872645][17.872645:872697]()
    return Err((Error::ChangeHashMismatch {
    [17.872645]
    [17.872697]
    return Err((ChangeError::ChangeHashMismatch {
  • replacement in libpijul/src/change.rs at line 1295
    [17.873489][17.873489:873543]()
    return Err((Error::ContentsHashMismatch {
    [17.873489]
    [17.873543]
    return Err(ChangeError::ContentsHashMismatch {
  • replacement in libpijul/src/change.rs at line 1298
    [17.873631][17.873631:873668]()
    })
    .into());
    [17.873631]
    [17.873668]
    });
  • replacement in libpijul/src/change.rs at line 1305
    [17.873795][17.873795:873884]()
    pub fn deserialize(file: &str, hash: Option<&Hash>) -> Result<Self, anyhow::Error> {
    [17.873795]
    [17.873884]
    pub fn deserialize(file: &str, hash: Option<&Hash>) -> Result<Self, ChangeError> {
  • replacement in libpijul/src/change.rs at line 1312
    [17.874154][17.874154:874209]()
    return Err(Error::VersionMismatch.into());
    [17.874154]
    [17.874209]
    return Err(ChangeError::VersionMismatch);
  • replacement in libpijul/src/change.rs at line 1329
    [17.874826][17.874826:874886]()
    return Err((Error::ChangeHashMismatch {
    [17.874826]
    [17.874886]
    return Err(ChangeError::ChangeHashMismatch {
  • replacement in libpijul/src/change.rs at line 1332
    [17.874975][17.874975:875028]()
    })
    .into());
    [17.874975]
    [17.875028]
    });
  • replacement in libpijul/src/change.rs at line 1374
    [17.876440][17.876440:876496]()
    pub fn hash(&self) -> Result<Hash, anyhow::Error> {
    [17.876440]
    [17.876496]
    pub fn hash(&self) -> Result<Hash, bincode::Error> {
  • edit in libpijul/src/change.rs at line 1381
    [17.876662][17.876662:878745](),[17.878745][17.878745:878841](),[17.878841][17.878841:878977](),[17.878977][17.878977:880955](),[17.880955][17.880955:881040](),[17.881040][17.881040:882461](),[17.882461][17.1240:1323](),[17.1323][17.882554:885299](),[17.882554][17.882554:885299](),[17.885299][17.1324:1399](),[17.1399][17.885376:885517](),[17.885376][17.885376:885517](),[17.885517][17.1400:1470](),[17.1470][17.885589:886662](),[17.885589][17.885589:886662](),[17.886662][17.886662:886733](),[17.886733][17.886733:886865](),[17.886865][17.886865:887016](),[17.887016][17.887016:887744](),[17.887744][9.418:452](),[9.452][17.887782:888474](),[17.887782][17.887782:888474](),[17.888474][9.453:487](),[9.487][17.888512:888888](),[17.888512][17.888512:888888](),[17.888888][9.488:518](),[9.518][17.888922:889088](),[17.888922][17.888922:889088](),[17.889088][9.519:553](),[9.553][17.889126:889214](),[17.889126][17.889126:889214](),[17.889214][17.889214:889239](),[17.889239][9.554:588](),[9.588][17.889277:889551](),[17.889277][17.889277:889551](),[17.889551][9.589:619](),[9.619][17.889585:889753](),[17.889585][17.889585:889753](),[17.889753][17.889753:889841](),[17.889841][17.889841:889866](),[17.889866][9.620:654](),[9.654][17.889904:891488](),[17.889904][17.889904:891488](),[17.891488][17.891488:891541](),[17.891541][17.891541:891869](),[17.891869][17.618:648](),[17.648][17.891903:891957](),[17.891903][17.891903:891957](),[17.891957][17.891957:892039](),[17.892039][17.892039:892327](),[17.892327][17.649:679](),[17.679][17.892361:892474](),[17.892361][17.892361:892474](),[17.892474][17.892474:892643](),[17.892643][17.892643:892938](),[17.892938][9.655:685](),[9.685][17.892972:893324](),[17.892972][17.892972:893324](),[17.893324][9.686:716](),[9.716][17.893358:893723](),[17.893358][17.893358:893723](),[17.893723][17.680:710](),[17.710][17.893757:893811](),[17.893757][17.893757:893811](),[17.893811][17.1210:1292](),[17.1292][17.893811:894129](),[17.893811][17.893811:894129](),[17.894129][17.711:741](),[17.741][17.894163:894217](),[17.894163][17.894163:894217](),[17.894217][17.1293:1375](),[17.1375][17.894217:894291](),[17.894217][17.894217:894291](),[17.894291][17.66822:66993](),[17.93][17.894369:894429](),[17.66993][17.894369:894429](),[17.894369][17.894369:894429](),[17.894429][17.742:772](),[17.128][17.894486:894540](),[17.772][17.894486:894540](),[17.894486][17.894486:894540](),[17.894540][17.1376:1458](),[17.1458][17.894540:896408](),[17.894540][17.894540:896408](),[17.896408][17.129:251](),[17.251][17.896503:904855](),[17.896503][17.896503:904855](),[17.904855][17.252:912](),[17.912][17.66994:67014](),[17.931][17.904855:905077](),[17.67014][17.904855:905077](),[17.904855][17.904855:905077](),[17.905077][17.6772:6816](),[17.6816][17.905121:905792](),[17.905121][17.905121:905792](),[17.905792][17.6817:6869](),[17.6869][17.905844:905985](),[17.905844][17.905844:905985](),[17.905985][17.6870:6922](),[17.6922][17.906037:910672](),[17.906037][17.906037:910672](),[17.910672][2.4331:4375](),[2.4375][17.910672:911073](),[17.910672][17.910672:911073](),[17.911073][17.6923:6975](),[17.6975][17.911125:912754](),[17.911125][17.911125:912754](),[17.912917][17.912917:912947](),[17.912947][17.1459:1536](),[17.1536][17.912947:912973](),[17.912947][17.912947:912973](),[17.912973][17.6976:7028](),[17.7028][17.913025:914758](),[17.913025][17.913025:914758](),[17.914758][17.1537:2006](),[17.2006][17.914819:915263](),[17.914819][17.914819:915263](),[17.915263][17.2007:2613](),[17.2613][17.915427:917686](),[17.915427][17.915427:917686](),[17.917686][17.7029:7107](),[17.7107][17.917890:918425](),[17.917890][17.917890:918425](),[17.918425][2.4376:4450](),[2.4450][17.918425:919617](),[17.918425][17.918425:919617](),[17.919617][17.7108:7143](),[17.7143][17.919652:921737](),[17.919652][17.919652:921737](),[17.921737][17.921737:921783](),[17.921783][17.921783:921847](),[17.921847][17.921847:921884](),[17.921884][17.0:67](),[17.67][15.0:87](),[15.87][17.142:380](),[17.142][17.142:380](),[17.380][17.922035:922066](),[17.922035][17.922035:922066](),[17.922066][17.922066:922146](),[17.922146][17.922146:922156](),[17.922156][17.922156:922178](),[17.922178][17.922178:922247](),[17.922247][17.922247:922356](),[17.922356][17.922356:922536](),[17.922536][17.922536:922580](),[17.922580][17.922580:923124](),[17.923124][17.923124:923179](),[17.923179][17.923179:927244](),[17.927244][9.717:739](),[9.739][17.927270:930990](),[17.927270][17.927270:930990]()
    // org id SY0PPKJcw1SQ8DEsOkicihzeXjmhMRxFEiBeypeSfTY=
    use crate::changestore::*;
    use std::collections::hash_map::Entry;
    use std::collections::HashMap;
    use std::io::BufRead;
    #[cfg(feature = "text-changes")]
    impl LocalChange<Local> {
    const DEPS_LINE: &'static str = "# Dependencies\n";
    const CHANGES_LINE: &'static str = "# Changes\n";
    pub fn write_all_deps<F: FnMut(Hash) -> Result<(), anyhow::Error>>(
    &self,
    mut f: F,
    ) -> Result<(), anyhow::Error> {
    for c in self.changes.iter() {
    for c in c.iter() {
    match *c {
    Atom::NewVertex(ref n) => {
    for change in n
    .up_context
    .iter()
    .chain(n.down_context.iter())
    .map(|c| c.change)
    .chain(std::iter::once(n.inode.change))
    {
    if let Some(change) = change {
    if let Hash::None = change {
    continue;
    }
    f(change)?
    }
    }
    }
    Atom::EdgeMap(ref e) => {
    for edge in e.edges.iter() {
    for change in &[
    edge.from.change,
    edge.to.change,
    edge.introduced_by,
    e.inode.change,
    ] {
    if let Some(change) = *change {
    if let Hash::None = change {
    continue;
    }
    f(change)?
    }
    }
    }
    }
    }
    }
    }
    Ok(())
    }
    pub fn write<W: Write, C: ChangeStore, F: FnMut(&Local, Position<Option<Hash>>) -> String>(
    &self,
    changes: &C,
    hash: Option<Hash>,
    mut file_name: F,
    write_header: bool,
    mut w: W,
    ) -> Result<(), anyhow::Error> {
    if let Some(h) = hash {
    // Check if we have the full contents
    let mut hasher = Hasher::default();
    hasher.update(&self.contents);
    let hash = hasher.finish();
    if hash != self.contents_hash {
    return Err((Error::MissingContents {
    hash: h.to_base32(),
    })
    .into());
    }
    }
    if write_header {
    w.write_all(toml::ser::to_string_pretty(&self.header)?.as_bytes())?;
    w.write_all(b"\n")?;
    }
    let mut hashes = HashMap::new();
    let mut i = 2;
    let mut needs_newline = false;
    if !self.dependencies.is_empty() {
    w.write_all(Self::DEPS_LINE.as_bytes())?;
    needs_newline = true;
    for dep in self.dependencies.iter() {
    hashes.insert(*dep, i);
    writeln!(w, "[{}] {}", i, dep.to_base32())?;
    i += 1;
    }
    }
    self.write_all_deps(|change| {
    if let Entry::Vacant(e) = hashes.entry(change) {
    e.insert(i);
    if !needs_newline {
    w.write_all(Self::DEPS_LINE.as_bytes())?;
    needs_newline = true;
    }
    writeln!(w, "[{}]+{}", i, change.to_base32())?;
    i += 1;
    }
    Ok(())
    })?;
    if !self.extra_known.is_empty() {
    needs_newline = true;
    for dep in self.extra_known.iter() {
    writeln!(w, "[*] {}", dep.to_base32())?;
    i += 1;
    }
    }
    if !self.changes.is_empty() {
    if needs_newline {
    w.write_all(b"\n")?
    }
    w.write_all(Self::CHANGES_LINE.as_bytes())?;
    for (n, rec) in self.changes.iter().enumerate() {
    write!(w, "\n{}. ", n + 1)?;
    rec.write(changes, &mut file_name, &hashes, &self.contents, &mut w)?
    }
    }
    Ok(())
    }
    }
    impl Change {
    pub fn read_and_deps<R: BufRead, T: TxnT>(
    r: R,
    updatables: &mut HashMap<usize, crate::InodeUpdate>,
    txn: &T,
    channel: &ChannelRef<T>,
    ) -> Result<Self, anyhow::Error> {
    let (mut change, extra_dependencies) = Self::read_(r, updatables)?;
    let (mut deps, extra) = dependencies(txn, channel, change.hashed.changes.iter());
    deps.extend(extra_dependencies.into_iter());
    change.hashed.dependencies = deps;
    change.hashed.extra_known = extra;
    Ok(change)
    }
    pub fn read<R: BufRead>(
    r: R,
    updatables: &mut HashMap<usize, crate::InodeUpdate>,
    ) -> Result<Self, anyhow::Error> {
    Ok(Self::read_(r, updatables)?.0)
    }
    fn read_<R: BufRead>(
    mut r: R,
    updatables: &mut HashMap<usize, crate::InodeUpdate>,
    ) -> Result<(Self, HashSet<Hash>), anyhow::Error> {
    use self::text_changes::*;
    let mut section = Section::Header(String::new());
    let mut change = Change {
    offsets: Offsets::default(),
    hashed: Hashed {
    version: VERSION,
    header: ChangeHeader {
    authors: Vec::new(),
    message: String::new(),
    description: None,
    timestamp: chrono::Utc::now(),
    },
    dependencies: Vec::new(),
    extra_known: Vec::new(),
    metadata: Vec::new(),
    changes: Vec::new(),
    contents_hash: Hasher::default().finish(),
    },
    unhashed: None,
    contents: Vec::new(),
    };
    let conclude_section = |change: &mut Change,
    section: Section,
    contents: &mut Vec<u8>|
    -> Result<(), anyhow::Error> {
    match section {
    Section::Header(ref s) => {
    debug!("header = {:?}", s);
    change.header = toml::de::from_str(&s)?;
    Ok(())
    }
    Section::Deps => Ok(()),
    Section::Changes {
    mut changes,
    current,
    ..
    } => {
    if has_newvertices(&current) {
    contents.push(0)
    }
    if let Some(c) = current {
    debug!("next action = {:?}", c);
    changes.push(c)
    }
    change.changes = changes;
    Ok(())
    }
    }
    };
    let mut h = String::new();
    let mut contents = Vec::new();
    let mut deps = HashMap::new();
    let mut extra_dependencies = HashSet::new();
    while r.read_line(&mut h)? > 0 {
    debug!("h = {:?}", h);
    if h == Self::DEPS_LINE {
    let section = std::mem::replace(&mut section, Section::Deps);
    conclude_section(&mut change, section, &mut contents)?;
    } else if h == Self::CHANGES_LINE {
    let section = std::mem::replace(
    &mut section,
    Section::Changes {
    changes: Vec::new(),
    current: None,
    offsets: HashMap::new(),
    },
    );
    conclude_section(&mut change, section, &mut contents)?;
    } else {
    use regex::Regex;
    lazy_static! {
    static ref DEPS: Regex = Regex::new(r#"\[(\d*|\*)\](\+| ) *(\S*)"#).unwrap();
    static ref KNOWN: Regex = Regex::new(r#"(\S*)"#).unwrap();
    }
    match section {
    Section::Header(ref mut s) => s.push_str(&h),
    Section::Deps => {
    if let Some(d) = DEPS.captures(&h) {
    let hash = Hash::from_base32(d[3].as_bytes()).unwrap();
    if let Ok(n) = d[1].parse() {
    if &d[2] == " " {
    change.hashed.dependencies.push(hash);
    }
    deps.insert(n, hash);
    } else if &d[1] == "*" {
    change.hashed.extra_known.push(hash);
    } else {
    extra_dependencies.insert(hash);
    }
    }
    }
    Section::Changes {
    ref mut current,
    ref mut changes,
    ref mut offsets,
    } => {
    if let Some(next) =
    Record::read(updatables, current, &mut contents, &deps, offsets, &h)?
    {
    debug!("next action = {:?}", next);
    changes.push(next)
    }
    }
    }
    }
    h.clear();
    }
    conclude_section(&mut change, section, &mut contents)?;
    change.contents = contents;
    change.contents_hash = {
    let mut hasher = Hasher::default();
    hasher.update(&change.contents);
    hasher.finish()
    };
    Ok((change, extra_dependencies))
    }
    }
    #[cfg(feature = "text-changes")]
    impl Record<Option<Hash>, Local> {
    fn write<
    W: std::io::Write,
    C: ChangeStore,
    F: FnMut(&Local, Position<Option<Hash>>) -> String,
    >(
    &self,
    changes: &C,
    mut file_name: F,
    hashes: &HashMap<Hash, usize>,
    change_contents: &[u8],
    mut w: W,
    ) -> Result<(), anyhow::Error> {
    use self::text_changes::*;
    match self {
    Record::FileMove { del, add, path } => match add {
    Atom::NewVertex(ref add) => {
    let name = std::str::from_utf8(
    &change_contents[add.start.0 as usize + 2..add.end.0 as usize],
    )
    .unwrap();
    let perms = crate::pristine::InodeMetadata::from_basename(
    &change_contents[add.start.0 as usize..add.start.0 as usize + 2],
    );
    write!(w, "Moved: {:?} {:?} {:o} ", path, name, perms.0)?;
    write_pos(&mut w, hashes, del.inode())?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &del)?;
    write!(w, "up")?;
    for c in add.up_context.iter() {
    write!(w, " ")?;
    write_pos(&mut w, hashes, *c)?
    }
    write!(w, ", down")?;
    for c in add.down_context.iter() {
    write!(w, " ")?;
    write_pos(&mut w, hashes, *c)?
    }
    w.write_all(b"\n")?;
    }
    Atom::EdgeMap(_) => {
    write!(w, "Moved: {:?} ", path)?;
    write_pos(&mut w, hashes, del.inode())?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &add)?;
    write_atom(&mut w, hashes, &del)?;
    }
    },
    Record::FileDel {
    del,
    contents,
    path,
    } => {
    write!(w, "File deletion: {:?} ", path)?;
    write_pos(&mut w, hashes, del.inode())?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &del)?;
    if let Some(ref contents) = contents {
    write_atom(&mut w, hashes, &contents)?;
    writeln!(w)?;
    print_change_contents(&mut w, changes, contents, change_contents)?;
    } else {
    writeln!(w)?;
    }
    }
    Record::FileUndel {
    undel,
    contents,
    path,
    } => {
    write!(w, "File un-deletion: {:?} ", path)?;
    write_pos(&mut w, hashes, undel.inode())?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &undel)?;
    if let Some(ref contents) = contents {
    write_atom(&mut w, hashes, &contents)?;
    print_change_contents(&mut w, changes, contents, change_contents)?;
    } else {
    writeln!(w)?;
    }
    }
    Record::FileAdd {
    add_name,
    contents,
    path,
    ..
    } => {
    if let Atom::NewVertex(ref n) = add_name {
    let name = std::str::from_utf8(
    &change_contents[n.start.0 as usize + 2..n.end.0 as usize],
    )
    .unwrap();
    let perms = crate::pristine::InodeMetadata::from_basename(
    &change_contents[n.start.0 as usize..n.start.0 as usize + 2],
    );
    let parent = if let Some(p) = crate::path::parent(&path) {
    if p.is_empty() {
    "/"
    } else {
    p
    }
    } else {
    "/"
    };
    write!(
    w,
    "File addition: {:?} in {:?} {:o}\n up",
    name, parent, perms.0
    )?;
    assert!(n.down_context.is_empty());
    for c in n.up_context.iter() {
    write!(w, " ")?;
    write_pos(&mut w, hashes, *c)?
    }
    writeln!(w, ", new {}:{}", n.start.0, n.end.0)?;
    }
    if let Some(Atom::NewVertex(ref n)) = contents {
    let c = &change_contents[n.start.0 as usize..n.end.0 as usize];
    print_contents(&mut w, "+", c)?;
    if !c.ends_with(b"\n") {
    writeln!(w, "\\")?
    }
    }
    }
    Record::Edit { change, local } => {
    write!(w, "Edit in {} ", file_name(&local, change.inode()))?;
    write_pos(&mut w, hashes, change.inode())?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &change)?;
    print_change_contents(&mut w, changes, change, change_contents)?;
    }
    Record::Replacement {
    change,
    replacement,
    local,
    } => {
    write!(w, "Replacement in {} ", file_name(&local, change.inode()))?;
    write_pos(&mut w, hashes, change.inode())?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &change)?;
    write_atom(&mut w, hashes, &replacement)?;
    print_change_contents(&mut w, changes, change, change_contents)?;
    print_change_contents(&mut w, changes, replacement, change_contents)?;
    }
    Record::SolveNameConflict { name, path } => {
    write!(w, "Solving a name conflict in {:?} ", path)?;
    write_pos(&mut w, hashes, name.inode())?;
    write!(w, ": ")?;
    write_deleted_names(&mut w, changes, name)?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &name)?;
    }
    Record::UnsolveNameConflict { name, path } => {
    write!(w, "Un-solving a name conflict in {:?} ", path)?;
    write_pos(&mut w, hashes, name.inode())?;
    write!(w, ": ")?;
    write_deleted_names(&mut w, changes, name)?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &name)?;
    }
    Record::SolveOrderConflict { change, local } => {
    write!(
    w,
    "Solving an order conflict in {} ",
    file_name(&local, change.inode())
    )?;
    write_pos(&mut w, hashes, change.inode())?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &change)?;
    print_change_contents(&mut w, changes, change, change_contents)?;
    }
    Record::UnsolveOrderConflict { change, local } => {
    write!(
    w,
    "Un-solving an order conflict in {} ",
    file_name(&local, change.inode())
    )?;
    write_pos(&mut w, hashes, change.inode())?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &change)?;
    print_change_contents(&mut w, changes, change, change_contents)?;
    }
    Record::ResurrectZombies { change, local } => {
    write!(
    w,
    "Resurrecting zombie lines in {:?}:{} ",
    local.path, local.line
    )?;
    write_pos(&mut w, hashes, change.inode())?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &change)?;
    print_change_contents(&mut w, changes, change, change_contents)?;
    }
    }
    Ok(())
    }
    }
    #[cfg(feature = "text-changes")]
    impl Record<Option<Hash>, Local> {
    fn read(
    updatables: &mut HashMap<usize, crate::InodeUpdate>,
    current: &mut Option<Self>,
    mut contents_: &mut Vec<u8>,
    changes: &HashMap<usize, Hash>,
    offsets: &mut HashMap<u64, ChangePosition>,
    h: &str,
    ) -> Result<Option<Self>, Error> {
    use self::text_changes::*;
    use regex::Regex;
    lazy_static! {
    static ref FILE_ADDITION: Regex =
    Regex::new(r#"(?P<n>\d+)\. File addition: "(?P<name>[^"]*)" in "(?P<parent>[^"]*)" (?P<perm>\d+)"#).unwrap();
    static ref EDIT: Regex =
    Regex::new(r#"(\d+)\. Edit in ([^:]+):(\d+) (\d+\.\d+)"#).unwrap();
    static ref REPLACEMENT: Regex =
    Regex::new(r#"(\d+)\. Replacement in ([^:]+):(\d+) (\d+\.\d+)"#).unwrap();
    static ref FILE_DELETION: Regex =
    Regex::new(r#"(\d+)\. File deletion: "([^"]*)" (\d+\.\d+)"#).unwrap();
    static ref FILE_UNDELETION: Regex =
    Regex::new(r#"(\d+)\. File un-deletion: "([^"]*)" (\d+\.\d+)"#).unwrap();
    static ref MOVE: Regex =
    Regex::new(r#"(\d+)\. Moved: "(?P<former>[^"]*)" "(?P<new>[^"]*)" (?P<perm>\d+) (?P<inode>.*)"#).unwrap();
    static ref MOVE_: Regex = Regex::new(r#"(\d+)\. Moved: "([^"]*)" (.*)"#).unwrap();
    static ref NAME_CONFLICT: Regex = Regex::new(
    r#"(\d+)\. ((Solving)|(Un-solving)) a name conflict in "([^"]*)" (.*): .*"#
    )
    .unwrap();
    static ref ORDER_CONFLICT: Regex = Regex::new(
    r#"(\d+)\. ((Solving)|(Un-solving)) an order conflict in (.*):(\d+) (\d+\.\d+)"#
    )
    .unwrap();
    static ref ZOMBIE: Regex =
    Regex::new(r#"(\d+)\. Resurrecting zombie lines in (?P<path>"[^"]+"):(?P<line>\d+) (?P<inode>\d+\.\d+)"#)
    .unwrap();
    static ref CONTEXT: Regex = Regex::new(
    r#"up ((\d+\.\d+ )*\d+\.\d+)(, new (\d+):(\d+))?(, down ((\d+\.\d+ )*\d+\.\d+))?"#
    )
    .unwrap();
    }
    if let Some(cap) = FILE_ADDITION.captures(h) {
    if has_newvertices(current) {
    contents_.push(0)
    }
    let mut add_name = default_newvertex();
    add_name.start = ChangePosition(contents_.len() as u64);
    add_name.flag = EdgeFlags::FOLDER | EdgeFlags::BLOCK;
    let name = &cap.name("name").unwrap().as_str();
    let path = {
    let parent = cap.name("parent").unwrap().as_str();
    (if parent == "/" {
    String::new()
    } else {
    parent.to_string()
    }) + name
    };
    let meta = cap
    .name("perm")
    .unwrap()
    .as_str()
    .chars()
    .fold(0, |x, c| x * 8 + (c as u16 - b'0' as u16));
    let meta = InodeMetadata(meta);
    meta.write(&mut contents_).unwrap();
    contents_.extend(name.as_bytes());
    add_name.end = ChangePosition(contents_.len() as u64);
    let mut add_inode = default_newvertex();
    add_inode.flag = EdgeFlags::FOLDER | EdgeFlags::BLOCK;
    add_inode.up_context.push(Position {
    change: None,
    pos: ChangePosition(contents_.len() as u64),
    });
    contents_.push(0);
    add_inode.start = ChangePosition(contents_.len() as u64);
    add_inode.end = ChangePosition(contents_.len() as u64);
    contents_.push(0);
    let n = cap.name("n").unwrap().as_str().parse().unwrap();
    if let Entry::Occupied(mut e) = updatables.entry(n) {
    if let crate::InodeUpdate::Add { ref mut pos, .. } = e.get_mut() {
    *pos = add_inode.start
    }
    }
    Ok(std::mem::replace(
    current,
    Some(Record::FileAdd {
    add_name: Atom::NewVertex(add_name),
    add_inode: Atom::NewVertex(add_inode),
    contents: None,
    path,
    }),
    ))
    } else if let Some(cap) = EDIT.captures(h) {
    if has_newvertices(current) {
    contents_.push(0)
    }
    let mut v = default_newvertex();
    v.inode = parse_pos(changes, &cap[4]);
    Ok(std::mem::replace(
    current,
    Some(Record::Edit {
    change: Atom::NewVertex(v),
    local: Local {
    path: cap[2].to_string(),
    line: cap[3].parse().unwrap(),
    },
    }),
    ))
    } else if let Some(cap) = REPLACEMENT.captures(h) {
    if has_newvertices(current) {
    contents_.push(0)
    }
    let mut v = default_newvertex();
    v.inode = parse_pos(changes, &cap[4]);
    Ok(std::mem::replace(
    current,
    Some(Record::Replacement {
    change: Atom::NewVertex(v.clone()),
    replacement: Atom::NewVertex(v),
    local: Local {
    path: cap[2].to_string(),
    line: cap[3].parse().unwrap(),
    },
    }),
    ))
    } else if let Some(cap) = FILE_DELETION.captures(h) {
    if has_newvertices(current) {
    contents_.push(0)
    }
    let mut del = default_edgemap();
    del.inode = parse_pos(changes, &cap[3]);
    Ok(std::mem::replace(
    current,
    Some(Record::FileDel {
    del: Atom::EdgeMap(del),
    contents: None,
    path: cap[2].to_string(),
    }),
    ))
    } else if let Some(cap) = FILE_UNDELETION.captures(h) {
    if has_newvertices(current) {
    contents_.push(0)
    }
    let mut undel = default_edgemap();
    undel.inode = parse_pos(changes, &cap[3]);
    Ok(std::mem::replace(
    current,
    Some(Record::FileUndel {
    undel: Atom::EdgeMap(undel),
    contents: None,
    path: cap[2].to_string(),
    }),
    ))
    } else if let Some(cap) = NAME_CONFLICT.captures(h) {
    if has_newvertices(current) {
    contents_.push(0)
    }
    let mut name = default_edgemap();
    debug!("cap = {:?}", cap);
    name.inode = parse_pos(changes, &cap[6]);
    Ok(std::mem::replace(
    current,
    if &cap[2] == "Solving" {
    Some(Record::SolveNameConflict {
    name: Atom::EdgeMap(name),
    path: cap[5].to_string(),
    })
    } else {
    Some(Record::UnsolveNameConflict {
    name: Atom::EdgeMap(name),
    path: cap[5].to_string(),
    })
    },
    ))
    } else if let Some(cap) = MOVE.captures(h) {
    if has_newvertices(current) {
    contents_.push(0)
    }
    let mut add = default_newvertex();
    add.start = ChangePosition(contents_.len() as u64);
    add.flag = EdgeFlags::FOLDER | EdgeFlags::BLOCK;
    let name = cap.name("new").unwrap().as_str();
    let meta = cap
    .name("perm")
    .unwrap()
    .as_str()
    .chars()
    .fold(0, |x, c| x * 8 + (c as u16 - b'0' as u16));
    let meta = InodeMetadata(meta);
    meta.write(&mut contents_).unwrap();
    contents_.extend(name.as_bytes());
    add.end = ChangePosition(contents_.len() as u64);
    let mut del = default_edgemap();
    del.inode = parse_pos(changes, cap.name("inode").unwrap().as_str());
    Ok(std::mem::replace(
    current,
    Some(Record::FileMove {
    del: Atom::EdgeMap(del),
    add: Atom::NewVertex(add),
    path: cap[2].to_string(),
    }),
    ))
    } else if let Some(cap) = MOVE_.captures(h) {
    if has_newvertices(current) {
    contents_.push(0)
    }
    let mut add = default_edgemap();
    let mut del = default_edgemap();
    add.inode = parse_pos(changes, &cap[3]);
    del.inode = add.inode;
    Ok(std::mem::replace(
    current,
    Some(Record::FileMove {
    del: Atom::EdgeMap(del),
    add: Atom::EdgeMap(add),
    path: cap[2].to_string(),
    }),
    ))
    } else if let Some(cap) = ORDER_CONFLICT.captures(h) {
    if has_newvertices(current) {
    contents_.push(0)
    }
    Ok(std::mem::replace(
    current,
    Some(if &cap[2] == "Solving" {
    let mut v = default_newvertex();
    v.inode = parse_pos(changes, &cap[7]);
    Record::SolveOrderConflict {
    change: Atom::NewVertex(v),
    local: Local {
    path: cap[5].to_string(),
    line: cap[6].parse().unwrap(),
    },
    }
    } else {
    let mut v = default_edgemap();
    v.inode = parse_pos(changes, &cap[7]);
    Record::UnsolveOrderConflict {
    change: Atom::EdgeMap(v),
    local: Local {
    path: cap[5].to_string(),
    line: cap[6].parse().unwrap(),
    },
    }
    }),
    ))
    } else if let Some(cap) = ZOMBIE.captures(h) {
    if has_newvertices(current) {
    contents_.push(0)
    }
    let mut v = default_edgemap();
    v.inode = parse_pos(changes, &cap.name("inode").unwrap().as_str());
    Ok(std::mem::replace(
    current,
    Some(Record::ResurrectZombies {
    change: Atom::EdgeMap(v),
    local: Local {
    path: cap.name("path").unwrap().as_str().parse().unwrap(),
    line: cap.name("line").unwrap().as_str().parse().unwrap(),
    },
    }),
    ))
    } else {
    match current {
    Some(Record::FileAdd {
    ref mut contents,
    ref mut add_name,
    ..
    }) => {
    if h.starts_with('+') {
    if contents.is_none() {
    let mut v = default_newvertex();
    let inode = Position {
    change: None,
    pos: ChangePosition(contents_.len() as u64 - 1),
    };
    v.up_context.push(inode);
    v.inode = inode;
    v.start = ChangePosition(contents_.len() as u64);
    *contents = Some(Atom::NewVertex(v));
    }
    if let Some(Atom::NewVertex(ref mut contents)) = contents {
    if h.starts_with('+') {
    text_changes::parse_line_add(h, contents, contents_)
    }
    }
    } else if h.starts_with('\\') {
    if let Some(Atom::NewVertex(ref mut contents)) = contents {
    if contents_[contents.end.0 as usize - 1] == b'\n' {
    assert_eq!(contents.end.0 as usize, contents_.len());
    contents_.pop();
    contents.end.0 -= 1;
    }
    }
    } else if let Some(cap) = CONTEXT.captures(h) {
    if let Atom::NewVertex(ref mut name) = add_name {
    name.up_context = parse_pos_vec(changes, offsets, &cap[1])?;
    if let (Some(new_start), Some(new_end)) = (cap.get(4), cap.get(5)) {
    offsets.insert(new_start.as_str().parse().unwrap(), name.start);
    offsets.insert(new_end.as_str().parse().unwrap(), name.end);
    offsets.insert(
    new_end.as_str().parse::<u64>().unwrap() + 1,
    name.end + 1,
    );
    }
    }
    }
    Ok(None)
    }
    Some(Record::FileDel {
    ref mut del,
    ref mut contents,
    ..
    }) => {
    if let Some(edges) = parse_edges(changes, h) {
    if let Atom::EdgeMap(ref mut e) = del {
    if edges[0].flag.contains(EdgeFlags::FOLDER) {
    *e = EdgeMap {
    inode: e.inode,
    edges,
    }
    } else {
    *contents = Some(Atom::EdgeMap(EdgeMap {
    inode: e.inode,
    edges,
    }))
    }
    }
    }
    Ok(None)
    }
    Some(Record::FileUndel {
    ref mut undel,
    ref mut contents,
    ..
    }) => {
    if let Some(edges) = parse_edges(changes, h) {
    if let Atom::EdgeMap(ref mut e) = undel {
    if edges[0].flag.contains(EdgeFlags::FOLDER) {
    *e = EdgeMap {
    inode: e.inode,
    edges,
    }
    } else {
    *contents = Some(Atom::EdgeMap(EdgeMap {
    inode: e.inode,
    edges,
    }))
    }
    }
    }
    Ok(None)
    }
    Some(Record::FileMove {
    ref mut del,
    ref mut add,
    ..
    }) => {
    if let Some(edges) = parse_edges(changes, h) {
    if edges[0].flag.contains(EdgeFlags::DELETED) {
    *del = Atom::EdgeMap(EdgeMap {
    inode: del.inode(),
    edges,
    });
    return Ok(None);
    } else if let Atom::EdgeMap(ref mut add) = add {
    if add.edges.is_empty() {
    *add = EdgeMap {
    inode: add.inode,
    edges,
    };
    return Ok(None);
    }
    }
    } else if let Some(cap) = CONTEXT.captures(h) {
    if let Atom::NewVertex(ref mut c) = add {
    debug!("cap = {:?}", cap);
    c.up_context = parse_pos_vec(changes, offsets, &cap[1])?;
    if let Some(cap) = cap.get(7) {
    c.down_context = parse_pos_vec(changes, offsets, cap.as_str())?;
    }
    }
    }
    Ok(None)
    }
    Some(Record::Edit { ref mut change, .. }) => {
    debug!("edit {:?}", h);
    if h.starts_with("+ ") {
    if let Atom::NewVertex(ref mut change) = change {
    if change.start == change.end {
    change.start = ChangePosition(contents_.len() as u64);
    }
    text_changes::parse_line_add(h, change, contents_)
    }
    } else if h.starts_with('\\') {
    if let Atom::NewVertex(ref mut change) = change {
    if contents_[change.end.0 as usize - 1] == b'\n' {
    assert_eq!(change.end.0 as usize, contents_.len());
    contents_.pop();
    change.end.0 -= 1;
    }
    }
    } else if let Some(cap) = CONTEXT.captures(h) {
    if let Atom::NewVertex(ref mut c) = change {
    debug!("cap = {:?}", cap);
    c.up_context = parse_pos_vec(changes, offsets, &cap[1])?;
    if let Some(cap) = cap.get(7) {
    c.down_context = parse_pos_vec(changes, offsets, cap.as_str())?;
    }
    }
    } else if let Some(edges) = parse_edges(changes, h) {
    *change = Atom::EdgeMap(EdgeMap {
    inode: change.inode(),
    edges,
    });
    }
    Ok(None)
    }
    Some(Record::Replacement {
    ref mut change,
    ref mut replacement,
    ..
    }) => {
    if h.starts_with("+ ") {
    if let Atom::NewVertex(ref mut repl) = replacement {
    if repl.start == repl.end {
    repl.start = ChangePosition(contents_.len() as u64);
    }
    text_changes::parse_line_add(h, repl, contents_)
    }
    } else if h.starts_with('\\') {
    if let Atom::NewVertex(ref mut repl) = replacement {
    if contents_[repl.end.0 as usize - 1] == b'\n' {
    assert_eq!(repl.end.0 as usize, contents_.len());
    contents_.pop();
    repl.end.0 -= 1;
    }
    }
    } else if let Some(cap) = CONTEXT.captures(h) {
    debug!("cap = {:?}", cap);
    if let Atom::NewVertex(ref mut repl) = replacement {
    repl.up_context = parse_pos_vec(changes, offsets, &cap[1])?;
    if let Some(cap) = cap.get(7) {
    repl.down_context = parse_pos_vec(changes, offsets, cap.as_str())?;
    }
    }
    } else if let Some(edges) = parse_edges(changes, h) {
    *change = Atom::EdgeMap(EdgeMap {
    inode: change.inode(),
    edges,
    });
    }
    Ok(None)
    }
    Some(Record::SolveNameConflict { ref mut name, .. })
    | Some(Record::UnsolveNameConflict { ref mut name, .. }) => {
    if let Some(edges) = parse_edges(changes, h) {
    *name = Atom::EdgeMap(EdgeMap {
    edges,
    inode: name.inode(),
    })
    }
    Ok(None)
    }
    Some(Record::SolveOrderConflict { ref mut change, .. }) => {
    if h.starts_with("+ ") {
    if let Atom::NewVertex(ref mut change) = change {
    if change.start == change.end {
    change.start = ChangePosition(contents_.len() as u64);
    }
    text_changes::parse_line_add(h, change, contents_)
    }
    } else if let Some(cap) = CONTEXT.captures(h) {
    debug!("cap = {:?}", cap);
    if let Atom::NewVertex(ref mut change) = change {
    change.up_context = parse_pos_vec(changes, offsets, &cap[1])?;
    if let Some(cap) = cap.get(7) {
    change.down_context =
    parse_pos_vec(changes, offsets, cap.as_str())?;
    }
    if let (Some(new_start), Some(new_end)) = (cap.get(4), cap.get(5)) {
    let new_start = new_start.as_str().parse::<u64>().unwrap();
    let new_end = new_end.as_str().parse::<u64>().unwrap();
    change.start = ChangePosition(contents_.len() as u64);
    change.end =
    ChangePosition(contents_.len() as u64 + new_end - new_start);
    offsets.insert(new_end, change.end);
    }
    }
    }
    Ok(None)
    }
    Some(Record::UnsolveOrderConflict { ref mut change, .. }) => {
    if let Some(edges) = parse_edges(changes, h) {
    if let Atom::EdgeMap(ref mut change) = change {
    change.edges = edges
    }
    }
    Ok(None)
    }
    Some(Record::ResurrectZombies { ref mut change, .. }) => {
    if let Some(edges) = parse_edges(changes, h) {
    if let Atom::EdgeMap(ref mut change) = change {
    change.edges = edges
    }
    }
    Ok(None)
    }
    None => {
    debug!("current = {:#?}", current);
    debug!("h = {:?}", h);
    Ok(None)
    }
    }
    }
    }
    }
    #[cfg(feature = "text-changes")]
    mod text_changes {
    use super::*;
    lazy_static! {
    static ref POS: regex::Regex = regex::Regex::new(r#"(\d+)\.(\d+)"#).unwrap();
    static ref EDGE: regex::Regex =
    regex::Regex::new(r#"\s*(?P<prev>[BFD]*):(?P<flag>[BFD]*)\s+(?P<up_c>\d+)\.(?P<up_l>\d+)\s*->\s*(?P<c>\d+)\.(?P<l0>\d+):(?P<l1>\d+)/(?P<intro>\d+)\s*"#).unwrap();
    }
    pub fn default_newvertex() -> NewVertex<Option<Hash>> {
    NewVertex {
    start: ChangePosition(0),
    end: ChangePosition(0),
    flag: EdgeFlags::empty(),
    up_context: Vec::new(),
    down_context: Vec::new(),
    inode: Position {
    change: Some(Hash::None),
    pos: ChangePosition(0),
    },
    }
    }
    pub fn default_edgemap() -> EdgeMap<Option<Hash>> {
    EdgeMap {
    edges: Vec::new(),
    inode: Position {
    change: Some(Hash::None),
    pos: ChangePosition(0),
    },
    }
    }
    pub fn has_newvertices<L>(current: &Option<Record<Option<Hash>, L>>) -> bool {
    match current {
    Some(Record::FileAdd { contents: None, .. }) | None => false,
    Some(rec) => rec.iter().any(|e| matches!(e, Atom::NewVertex(_))),
    }
    }
    pub fn parse_pos_vec(
    changes: &HashMap<usize, Hash>,
    offsets: &HashMap<u64, ChangePosition>,
    s: &str,
    ) -> Result<Vec<Position<Option<Hash>>>, Error> {
    let mut v = Vec::new();
    for pos in POS.captures_iter(s) {
    let change: usize = (&pos[1]).parse().unwrap();
    let pos: u64 = (&pos[2]).parse().unwrap();
    let pos = if change == 0 {
    if let Some(&pos) = offsets.get(&pos) {
    pos
    } else {
    debug!("inconsistent change: {:?} {:?}", s, offsets);
    return Err(Error::InconsistentChange);
    }
    } else {
    ChangePosition(pos)
    };
    v.push(Position {
    change: change_ref(changes, change),
    pos,
    })
    }
    Ok(v)
    }
    fn change_ref(changes: &HashMap<usize, Hash>, change: usize) -> Option<Hash> {
    debug!("change_ref {:?} {:?}", changes, change);
    if change == 0 {
    None
    } else if change == 1 {
    Some(Hash::None)
    } else {
    Some(*changes.get(&change).unwrap())
    }
    }
    pub fn parse_pos(changes: &HashMap<usize, Hash>, s: &str) -> Position<Option<Hash>> {
    let pos = POS.captures(s).unwrap();
    let change: usize = (&pos[1]).parse().unwrap();
    let pos: u64 = (&pos[2]).parse().unwrap();
    Position {
    change: change_ref(changes, change),
    pos: ChangePosition(pos),
    }
    }
    pub fn parse_edges(
    changes: &HashMap<usize, Hash>,
    s: &str,
    ) -> Option<Vec<NewEdge<Option<Hash>>>> {
    debug!("parse_edges {:?}", s);
    let mut result = Vec::new();
    for edge in s.split(',') {
    debug!("parse edge {:?}", edge);
    if let Some(cap) = EDGE.captures(edge) {
    let previous = read_flag(cap.name("prev").unwrap().as_str());
    let flag = read_flag(cap.name("flag").unwrap().as_str());
    let change0: usize = cap.name("up_c").unwrap().as_str().parse().unwrap();
    let pos0: u64 = cap.name("up_l").unwrap().as_str().parse().unwrap();
    let change1: usize = cap.name("c").unwrap().as_str().parse().unwrap();
    let start1: u64 = cap.name("l0").unwrap().as_str().parse().unwrap();
    let end1: u64 = cap.name("l1").unwrap().as_str().parse().unwrap();
    let introduced_by: usize = cap.name("intro").unwrap().as_str().parse().unwrap();
    result.push(NewEdge {
    previous,
    flag,
    from: Position {
    change: change_ref(changes, change0),
    pos: ChangePosition(pos0),
    },
    to: Vertex {
    change: change_ref(changes, change1),
    start: ChangePosition(start1),
    end: ChangePosition(end1),
    },
    introduced_by: change_ref(changes, introduced_by),
    })
    } else {
    debug!("not parsed");
    return None;
    }
    }
    Some(result)
    }
    pub fn parse_line_add(h: &str, change: &mut NewVertex<Option<Hash>>, contents_: &mut Vec<u8>) {
    let h = h.as_bytes();
    debug!("parse_line_add {:?} {:?}", change.end, change.start);
    debug!("parse_line_add {:?}", h);
    if h.len() > 2 {
    let h = &h[2..h.len()];
    contents_.extend(h);
    } else if h.len() > 1 {
    contents_.push(b'\n');
    }
    debug!("contents_.len() = {:?}", contents_.len());
    trace!("contents_ = {:?}", contents_);
    change.end = ChangePosition(contents_.len() as u64);
    }
    pub fn print_contents<W: std::io::Write>(
    w: &mut W,
    pref: &str,
    contents: &[u8],
    ) -> Result<(), anyhow::Error> {
    if let Ok(mut contents) = std::str::from_utf8(&contents) {
    while let Some(n) = contents.as_bytes().iter().position(|&c| c == b'\n') {
    let (a, b) = contents.split_at(n + 1);
    contents = b;
    write!(w, "{} {}", pref, a)?;
    }
    if !contents.is_empty() {
    writeln!(w, "{} {}", pref, contents)?;
    }
    } else {
    writeln!(w, "{}b{}", pref, data_encoding::BASE64.encode(contents))?
    }
    Ok(())
    }
    pub fn print_change_contents<W: std::io::Write, C: ChangeStore>(
    w: &mut W,
    changes: &C,
    change: &Atom<Option<Hash>>,
    change_contents: &[u8],
    ) -> Result<(), anyhow::Error> {
    match change {
    Atom::NewVertex(ref n) => {
    let c = &change_contents[n.start.0 as usize..n.end.0 as usize];
    print_contents(w, "+", c)?;
    if !c.ends_with(b"\n") {
    writeln!(w, "\\")?
    }
    Ok(())
    }
    Atom::EdgeMap(ref n) if n.edges[0].flag.contains(EdgeFlags::DELETED) => {
    let mut buf = Vec::new();
    let mut current = None;
    for e in n.edges.iter() {
    if Some(e.to) == current {
    continue;
    }
    buf.clear();
    changes.get_contents_ext(e.to, &mut buf)?;
    print_contents(w, "-", &buf[..])?;
    current = Some(e.to)
    }
    Ok(())
    }
    _ => Ok(()),
    }
    }
    pub fn write_deleted_names<W: std::io::Write, C: ChangeStore>(
    w: &mut W,
    changes: &C,
    del: &Atom<Option<Hash>>,
    ) -> Result<(), anyhow::Error> {
    if let Atom::EdgeMap(ref e) = del {
    let mut buf = Vec::new();
    let mut is_first = true;
    for d in e.edges.iter() {
    buf.clear();
    changes.get_contents_ext(d.to, &mut buf)?;
    if !buf.is_empty() {
    let name = std::str::from_utf8(buf.split_at(2).1).unwrap();
    write!(w, "{}{:?}", if is_first { "" } else { ", " }, name)?;
    is_first = false;
    }
    }
    }
    Ok(())
    }
    pub fn write_flag<W: std::io::Write>(mut w: W, flag: EdgeFlags) -> Result<(), anyhow::Error> {
    if flag.contains(EdgeFlags::BLOCK) {
    w.write_all(b"B")?;
    }
    if flag.contains(EdgeFlags::FOLDER) {
    w.write_all(b"F")?;
    }
    if flag.contains(EdgeFlags::DELETED) {
    w.write_all(b"D")?;
    }
    assert!(!flag.contains(EdgeFlags::PARENT));
    assert!(!flag.contains(EdgeFlags::PSEUDO));
    Ok(())
    }
    pub fn read_flag(s: &str) -> EdgeFlags {
    let mut f = EdgeFlags::empty();
    for i in s.chars() {
    match i {
    'B' => f |= EdgeFlags::BLOCK,
    'F' => f |= EdgeFlags::FOLDER,
    'D' => f |= EdgeFlags::DELETED,
    c => panic!("read_flag: {:?}", c),
    }
    }
    f
    }
    pub fn write_pos<W: std::io::Write>(
    mut w: W,
    hashes: &HashMap<Hash, usize>,
    pos: Position<Option<Hash>>,
    ) -> Result<(), anyhow::Error> {
    let change = if let Some(Hash::None) = pos.change {
    1
    } else if let Some(ref c) = pos.change {
    *hashes.get(c).unwrap()
    } else {
    0
    };
    write!(w, "{}.{}", change, pos.pos.0)?;
    Ok(())
    }
    pub fn write_atom<W: std::io::Write>(
    w: &mut W,
    hashes: &HashMap<Hash, usize>,
    atom: &Atom<Option<Hash>>,
    ) -> Result<(), anyhow::Error> {
    match atom {
    Atom::NewVertex(ref n) => write_newvertex(w, hashes, n),
    Atom::EdgeMap(ref n) => write_edgemap(w, hashes, n),
    }
    }
    pub fn write_newvertex<W: std::io::Write>(
    mut w: W,
    hashes: &HashMap<Hash, usize>,
    n: &NewVertex<Option<Hash>>,
    ) -> Result<(), anyhow::Error> {
    write!(w, " up")?;
    for c in n.up_context.iter() {
    write!(w, " ")?;
    write_pos(&mut w, hashes, *c)?
    }
    write!(w, ", new {}:{}", n.start.0, n.end.0)?;
    if !n.down_context.is_empty() {
    write!(w, ", down")?;
    for c in n.down_context.iter() {
    write!(w, " ")?;
    write_pos(&mut w, hashes, *c)?
    }
    }
    w.write_all(b"\n")?;
    Ok(())
    }
    pub fn write_edgemap<W: std::io::Write>(
    mut w: W,
    hashes: &HashMap<Hash, usize>,
    n: &EdgeMap<Option<Hash>>,
    ) -> Result<(), anyhow::Error> {
    let mut is_first = true;
    for c in n.edges.iter() {
    if !is_first {
    write!(w, ", ")?;
    }
    is_first = false;
    write_flag(&mut w, c.previous)?;
    write!(w, ":")?;
    write_flag(&mut w, c.flag)?;
    write!(w, " ")?;
    write_pos(&mut w, hashes, c.from)?;
    write!(w, " -> ")?;
    write_pos(&mut w, hashes, c.to.start_pos())?;
    let h = if let Some(h) = hashes.get(c.introduced_by.as_ref().unwrap()) {
    h
    } else {
    panic!("introduced_by = {:?}, not found", c.introduced_by);
    };
    write!(w, ":{}/{}", c.to.end.0, h)?;
    }
    writeln!(w)?;
    Ok(())
    }
    #[cfg(feature = "text-changes")]
    #[derive(Debug, Clone, PartialEq, Eq)]
    pub enum Section {
    Header(String),
    Deps,
    Changes {
    changes: Vec<Record<Option<Hash>, Local>>,
    current: Option<Record<Option<Hash>, Local>>,
    offsets: HashMap<u64, ChangePosition>,
    },
    }
    }
    // org id XDu/0rcMPSdaCWLiWWDiw32Rl45EX9uwvy9vprRXJbg=
    /// An open, seekable change file.
    #[cfg(feature = "zstd")]
    pub struct ChangeFile<'a> {
    s: Option<zstd_seekable::Seekable<'a, OffFile>>,
    hashed: Hashed<Local>,
    hash: Hash,
    unhashed: Option<toml::Value>,
    }
    struct OffFile {
    f: std::fs::File,
    start: u64,
    }
    unsafe impl Send for OffFile {}
    impl std::io::Read for OffFile {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
    self.f.read(buf)
    }
    }
    impl std::io::Seek for OffFile {
    fn seek(&mut self, from: std::io::SeekFrom) -> Result<u64, std::io::Error> {
    use std::io::SeekFrom;
    let from = match from {
    SeekFrom::Start(s) => SeekFrom::Start(s + self.start),
    c => c,
    };
    self.f.seek(from)
    }
    }
    #[cfg(feature = "zstd")]
    impl<'a> ChangeFile<'a> {
    /// Open a change file from a path.
    pub fn open(hash: Hash, path: &str) -> Result<Self, anyhow::Error> {
    use std::io::Read;
    let mut r = std::fs::File::open(path)?;
    let mut buf = Vec::new();
    buf.resize(Change::OFFSETS_SIZE as usize, 0);
    r.read_exact(&mut buf)?;
    let offsets: Offsets = bincode::deserialize(&buf)?;
    if offsets.version != VERSION {
    return Err(Error::VersionMismatch.into());
    }
    buf.clear();
    buf.resize((offsets.unhashed_off - Change::OFFSETS_SIZE) as usize, 0);
    r.read_exact(&mut buf)?;
    let mut buf2 = vec![0u8; offsets.hashed_len as usize];
    let hashed: Hashed<Local> = {
    let mut s = zstd_seekable::Seekable::init_buf(&buf)?;
    s.decompress(&mut buf2, 0)?;
    bincode::deserialize(&buf2)?
    };
    buf.resize((offsets.contents_off - offsets.unhashed_off) as usize, 0);
    let unhashed = if buf.is_empty() {
    None
    } else {
    r.read_exact(&mut buf)?;
    let mut s = zstd_seekable::Seekable::init_buf(&buf)?;
    buf2.resize(offsets.unhashed_len as usize, 0);
    s.decompress(&mut buf2, 0)?;
    Some(toml::de::from_slice(&buf2)?)
    };
    let m = r.metadata()?;
    let s = if offsets.contents_off >= m.len() {
    None
    } else {
    Some(zstd_seekable::Seekable::init(Box::new(OffFile {
    f: r,
    start: offsets.contents_off,
    }))?)
    };
    Ok(ChangeFile {
    s,
    hashed,
    hash,
    unhashed,
    })
    }
    pub fn has_contents(&self) -> bool {
    self.s.is_some()
    }
    /// Reads the contents at an offset into `buf`, and returns the
    /// number of bytes read. The bounds of the change's "contents"
    /// section are not checked.
    pub fn read_contents(&mut self, offset: u64, buf: &mut [u8]) -> Result<usize, anyhow::Error> {
    debug!("read_contents {:?} {:?}", offset, buf.len());
    if let Some(ref mut s) = self.s {
    Ok(s.decompress(buf, offset)?)
    } else {
    Err((Error::MissingContents {
    hash: self.hash.to_base32(),
    })
    .into())
    }
    }
    pub fn hashed(&self) -> &Hashed<Local> {
    &self.hashed
    }
    pub fn unhashed(&self) -> &Option<toml::Value> {
    &self.unhashed
    }
    }
  • file deletion: v3.rs (-xw-x--x--)
    [17.931000][17.931001:931008](),[17.931008][17.931009:931009]()
    use super::*;
    #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
    enum Atom3<Change> {
    NewVertex(NewVertex<Change>),
    EdgeMap(EdgeMap3<Change>),
    }
    impl Atom3<Option<Hash>> {
    fn to_v4(self, translation: &HashMap<Option<Hash>, Option<Hash>>) -> Atom<Option<Hash>> {
    match self {
    Atom3::NewVertex(n) => Atom::NewVertex(NewVertex {
    up_context: n
    .up_context
    .into_iter()
    .map(|x| Position {
    change: *translation.get(&x.change).unwrap(),
    ..x
    })
    .collect(),
    down_context: n
    .down_context
    .into_iter()
    .map(|x| Position {
    change: *translation.get(&x.change).unwrap(),
    ..x
    })
    .collect(),
    flag: n.flag,
    start: n.start,
    end: n.end,
    inode: Position {
    change: *translation.get(&n.inode.change).unwrap(),
    ..n.inode
    },
    }),
    Atom3::EdgeMap(e) => Atom::EdgeMap(e.to_v4(translation)),
    }
    }
    }
    #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
    struct EdgeMap3<Change> {
    pub previous: EdgeFlags,
    pub flag: EdgeFlags,
    pub edges: Vec<NewEdge3<Change>>,
    pub inode: Position<Change>,
    }
    impl EdgeMap3<Option<Hash>> {
    fn to_v4(self, translations: &HashMap<Option<Hash>, Option<Hash>>) -> EdgeMap<Option<Hash>> {
    let flag = self.flag;
    let previous = self.previous;
    EdgeMap {
    inode: Position {
    change: *translations.get(&self.inode.change).unwrap(),
    ..self.inode
    },
    edges: self
    .edges
    .into_iter()
    .map(|e| NewEdge {
    previous,
    flag,
    from: Position {
    change: *translations.get(&e.from.change).unwrap(),
    ..e.from
    },
    to: Vertex {
    change: *translations.get(&e.to.change).unwrap(),
    ..e.to
    },
    introduced_by: *translations.get(&e.introduced_by).unwrap(),
    })
    .collect(),
    }
    }
    }
    #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
    struct NewEdge3<Change> {
    pub from: Position<Change>,
    pub to: Vertex<Change>,
    pub introduced_by: Change,
    }
    #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
    enum Record3<Hash, Local> {
    FileMove {
    del: Atom3<Hash>,
    add: Atom3<Hash>,
    confirm: Option<Atom3<Hash>>,
    path: String,
    },
    FileDel {
    del: Atom3<Hash>,
    confirm: Option<Atom3<Hash>>,
    contents: Option<Atom3<Hash>>,
    path: String,
    },
    FileUndel {
    undel: Atom3<Hash>,
    confirm: Option<Atom3<Hash>>,
    contents: Option<Atom3<Hash>>,
    path: String,
    },
    FileAdd {
    add_name: Atom3<Hash>,
    add_inode: Atom3<Hash>,
    contents: Option<Atom3<Hash>>,
    path: String,
    },
    SolveNameConflict {
    name: Atom3<Hash>,
    confirm: Option<Atom3<Hash>>,
    path: String,
    },
    UnsolveNameConflict {
    name: Atom3<Hash>,
    confirm: Option<Atom3<Hash>>,
    path: String,
    },
    Edit {
    change: Atom3<Hash>,
    local: Local,
    },
    Replacement {
    change: Atom3<Hash>,
    replacement: Atom3<Hash>,
    local: Local,
    },
    SolveOrderConflict {
    change: Atom3<Hash>,
    local: Local,
    },
    UnsolveOrderConflict {
    change: Atom3<Hash>,
    local: Local,
    },
    ResurrectZombies {
    alive: Atom3<Hash>,
    dead: Atom3<Hash>,
    local: Local,
    },
    }
    impl Record3<Option<Hash>, Local> {
    fn to_v4(
    self,
    translation: &HashMap<Option<Hash>, Option<Hash>>,
    ) -> Record<Option<Hash>, Local> {
    match self {
    Record3::FileMove {
    del,
    add,
    confirm,
    path,
    } => {
    let mut del = del.to_v4(translation);
    if let Atom::EdgeMap(ref mut e) = del {
    if let Some(Atom3::EdgeMap(c)) = confirm {
    let c = c.to_v4(translation);
    e.edges.extend(c.edges.into_iter())
    }
    }
    let add = add.to_v4(translation);
    Record::FileMove { del, add, path }
    }
    Record3::FileDel {
    del,
    confirm,
    contents,
    path,
    } => {
    let mut del = del.to_v4(translation);
    if let Atom::EdgeMap(ref mut e) = del {
    if let Some(Atom3::EdgeMap(c)) = confirm {
    let c = c.to_v4(translation);
    e.edges.extend(c.edges.into_iter())
    }
    }
    let contents = contents.map(|c| c.to_v4(translation));
    Record::FileDel {
    del,
    contents,
    path,
    }
    }
    Record3::FileUndel {
    undel,
    confirm,
    contents,
    path,
    } => {
    let mut undel = undel.to_v4(translation);
    if let Atom::EdgeMap(ref mut e) = undel {
    if let Some(Atom3::EdgeMap(c)) = confirm {
    let c = c.to_v4(translation);
    e.edges.extend(c.edges.into_iter())
    }
    }
    let contents = contents.map(|c| c.to_v4(translation));
    Record::FileUndel {
    undel,
    contents,
    path,
    }
    }
    Record3::FileAdd {
    add_name,
    add_inode,
    contents,
    path,
    } => Record::FileAdd {
    add_name: add_name.to_v4(translation),
    add_inode: add_inode.to_v4(translation),
    contents: contents.map(|c| c.to_v4(translation)),
    path,
    },
    Record3::SolveNameConflict {
    name,
    confirm,
    path,
    } => {
    let mut name = name.to_v4(translation);
    if let Atom::EdgeMap(ref mut e) = name {
    if let Some(Atom3::EdgeMap(c)) = confirm {
    let c = c.to_v4(translation);
    e.edges.extend(c.edges.into_iter())
    }
    }
    Record::SolveNameConflict { name, path }
    }
    Record3::UnsolveNameConflict {
    name,
    confirm,
    path,
    } => {
    let mut name = name.to_v4(translation);
    if let Atom::EdgeMap(ref mut e) = name {
    if let Some(Atom3::EdgeMap(c)) = confirm {
    let c = c.to_v4(translation);
    e.edges.extend(c.edges.into_iter())
    }
    }
    Record::UnsolveNameConflict { name, path }
    }
    Record3::Edit { change, local } => Record::Edit {
    change: change.to_v4(translation),
    local,
    },
    Record3::Replacement {
    change,
    replacement,
    local,
    } => Record::Replacement {
    change: change.to_v4(translation),
    replacement: replacement.to_v4(translation),
    local,
    },
    Record3::SolveOrderConflict { change, local } => Record::SolveOrderConflict {
    change: change.to_v4(translation),
    local,
    },
    Record3::UnsolveOrderConflict { change, local } => Record::UnsolveOrderConflict {
    change: change.to_v4(translation),
    local,
    },
    Record3::ResurrectZombies { alive, dead, local } => {
    let mut change = alive.to_v4(translation);
    if let Atom::EdgeMap(ref mut e) = change {
    if let Atom3::EdgeMap(c) = dead {
    let c = c.to_v4(translation);
    e.edges.extend(c.edges.into_iter())
    }
    }
    Record::ResurrectZombies { change, local }
    }
    }
    }
    }
    #[derive(Clone, Debug, PartialEq)]
    pub struct LocalChange3<Local> {
    offsets: Offsets,
    hashed: Hashed3<Local>,
    unhashed: Option<toml::Value>,
    contents: Vec<u8>,
    }
    const VERSION: u64 = 3;
    #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
    struct Hashed3<Local> {
    version: u64,
    header: ChangeHeader,
    dependencies: BTreeSet<Hash>,
    extra_known: BTreeSet<Hash>,
    metadata: Vec<u8>,
    changes: Vec<Record3<Option<Hash>, Local>>,
    contents_hash: Hash,
    }
    impl Hashed3<Local> {
    fn to_v4(self, translation: &HashMap<Option<Hash>, Option<Hash>>) -> Hashed<Local> {
    Hashed {
    version: 4,
    header: self.header,
    dependencies: self
    .dependencies
    .into_iter()
    .map(|x| translation.get(&Some(x)).unwrap().unwrap())
    .collect(),
    extra_known: self
    .extra_known
    .into_iter()
    .filter_map(|x| translation.get(&Some(x)).map(|x| x.unwrap()))
    .collect(),
    metadata: self.metadata,
    contents_hash: self.contents_hash,
    changes: self
    .changes
    .into_iter()
    .map(|x| x.to_v4(translation))
    .collect(),
    }
    }
    }
    impl LocalChange3<Local> {
    const OFFSETS_SIZE: u64 = 56;
    pub fn deserialize(file: &str, hash: Option<&Hash>) -> Result<Self, anyhow::Error> {
    use std::io::Read;
    let mut r = std::fs::File::open(file)?;
    let mut buf = vec![0u8; Self::OFFSETS_SIZE as usize];
    r.read_exact(&mut buf)?;
    let offsets: Offsets = bincode::deserialize(&buf)?;
    if offsets.version != VERSION {
    return Err(Error::VersionMismatch.into());
    }
    debug!("offsets = {:?}", offsets);
    buf.clear();
    buf.resize((offsets.unhashed_off - Self::OFFSETS_SIZE) as usize, 0);
    r.read_exact(&mut buf)?;
    let hashed: Hashed3<Local> = {
    let mut s = zstd_seekable::Seekable::init_buf(&buf[..])?;
    let mut out = vec![0u8; offsets.hashed_len as usize];
    s.decompress(&mut out[..], 0)?;
    let mut hasher = Hasher::default();
    hasher.update(&out);
    let computed_hash = hasher.finish();
    if let Some(hash) = hash {
    if &computed_hash != hash {
    return Err((Error::ChangeHashMismatch {
    claimed: *hash,
    computed: computed_hash,
    })
    .into());
    }
    }
    bincode::deserialize_from(&out[..])?
    };
    buf.clear();
    buf.resize((offsets.contents_off - offsets.unhashed_off) as usize, 0);
    let unhashed = if buf.is_empty() {
    None
    } else {
    r.read_exact(&mut buf)?;
    let mut s = zstd_seekable::Seekable::init_buf(&buf[..])?;
    let mut out = vec![0u8; offsets.unhashed_len as usize];
    s.decompress(&mut out[..], 0)?;
    Some(toml::de::from_slice(&out)?)
    };
    debug!("unhashed = {:?}", unhashed);
    buf.clear();
    buf.resize((offsets.total - offsets.contents_off) as usize, 0);
    let contents = if r.read_exact(&mut buf).is_ok() {
    let mut s = zstd_seekable::Seekable::init_buf(&buf[..])?;
    let mut contents = vec![0u8; offsets.contents_len as usize];
    s.decompress(&mut contents[..], 0)?;
    contents
    } else {
    Vec::new()
    };
    debug!("contents = {:?}", contents);
    Ok(LocalChange3 {
    offsets,
    hashed,
    unhashed,
    contents,
    })
    }
    pub fn to_v4(self, translation: &HashMap<Option<Hash>, Option<Hash>>) -> LocalChange<Local> {
    LocalChange {
    offsets: self.offsets,
    hashed: self.hashed.to_v4(translation),
    unhashed: self.unhashed,
    contents: self.contents,
    }
    }
    }
  • file addition: text_changes.rs (-xw-x--x--)
    [17.931000]
    use super::*;
    use crate::changestore::*;
    use std::collections::hash_map::Entry;
    use std::collections::HashMap;
    use std::io::BufRead;
    #[derive(Debug, Error)]
    pub enum TextDeError {
    #[error(transparent)]
    Io(#[from] std::io::Error),
    #[error(transparent)]
    TomlDe(#[from] toml::de::Error),
    #[error("Missing change [{0}]")]
    MissingChange(usize),
    }
    #[derive(Debug, Error)]
    pub enum TextSerError<C: std::error::Error + 'static> {
    #[error(transparent)]
    C(C),
    #[error(transparent)]
    Io(#[from] std::io::Error),
    #[error(transparent)]
    TomlSer(#[from] toml::ser::Error),
    #[error("Missing contents in change {:?}", h)]
    MissingContents { h: Hash },
    #[error(transparent)]
    Change(#[from] ChangeError),
    }
    impl LocalChange<Local> {
    const DEPS_LINE: &'static str = "# Dependencies\n";
    const CHANGES_LINE: &'static str = "# Changes\n";
    pub fn write_all_deps<F: FnMut(Hash) -> Result<(), ChangeError>>(
    &self,
    mut f: F,
    ) -> Result<(), ChangeError> {
    for c in self.changes.iter() {
    for c in c.iter() {
    match *c {
    Atom::NewVertex(ref n) => {
    for change in n
    .up_context
    .iter()
    .chain(n.down_context.iter())
    .map(|c| c.change)
    .chain(std::iter::once(n.inode.change))
    {
    if let Some(change) = change {
    if let Hash::None = change {
    continue;
    }
    f(change)?
    }
    }
    }
    Atom::EdgeMap(ref e) => {
    for edge in e.edges.iter() {
    for change in &[
    edge.from.change,
    edge.to.change,
    edge.introduced_by,
    e.inode.change,
    ] {
    if let Some(change) = *change {
    if let Hash::None = change {
    continue;
    }
    f(change)?
    }
    }
    }
    }
    }
    }
    }
    Ok(())
    }
    pub fn write<W: Write, C: ChangeStore, F: FnMut(&Local, Position<Option<Hash>>) -> String>(
    &self,
    changes: &C,
    hash: Option<Hash>,
    mut file_name: F,
    write_header: bool,
    mut w: W,
    ) -> Result<(), TextSerError<C::Error>> {
    if let Some(h) = hash {
    // Check if we have the full contents
    let mut hasher = Hasher::default();
    hasher.update(&self.contents);
    let hash = hasher.finish();
    if hash != self.contents_hash {
    return Err((TextSerError::MissingContents { h }).into());
    }
    }
    if write_header {
    w.write_all(toml::ser::to_string_pretty(&self.header)?.as_bytes())?;
    w.write_all(b"\n")?;
    }
    let mut hashes = HashMap::new();
    let mut i = 2;
    let mut needs_newline = false;
    if !self.dependencies.is_empty() {
    w.write_all(Self::DEPS_LINE.as_bytes())?;
    needs_newline = true;
    for dep in self.dependencies.iter() {
    hashes.insert(*dep, i);
    writeln!(w, "[{}] {}", i, dep.to_base32())?;
    i += 1;
    }
    }
    self.write_all_deps(|change| {
    if let Entry::Vacant(e) = hashes.entry(change) {
    e.insert(i);
    if !needs_newline {
    w.write_all(Self::DEPS_LINE.as_bytes())?;
    needs_newline = true;
    }
    writeln!(w, "[{}]+{}", i, change.to_base32())?;
    i += 1;
    }
    Ok(())
    })?;
    if !self.extra_known.is_empty() {
    needs_newline = true;
    for dep in self.extra_known.iter() {
    writeln!(w, "[*] {}", dep.to_base32())?;
    i += 1;
    }
    }
    if !self.changes.is_empty() {
    if needs_newline {
    w.write_all(b"\n")?
    }
    w.write_all(Self::CHANGES_LINE.as_bytes())?;
    for (n, rec) in self.changes.iter().enumerate() {
    write!(w, "\n{}. ", n + 1)?;
    rec.write(changes, &mut file_name, &hashes, &self.contents, &mut w)?
    }
    }
    Ok(())
    }
    }
    impl Change {
    pub fn read_and_deps<R: BufRead, T: TxnT>(
    r: R,
    updatables: &mut HashMap<usize, crate::InodeUpdate>,
    txn: &T,
    channel: &ChannelRef<T>,
    ) -> Result<Self, TextDeError> {
    let (mut change, extra_dependencies) = Self::read_(r, updatables)?;
    let (mut deps, extra) = dependencies(txn, channel, change.hashed.changes.iter());
    deps.extend(extra_dependencies.into_iter());
    change.hashed.dependencies = deps;
    change.hashed.extra_known = extra;
    Ok(change)
    }
    pub fn read<R: BufRead>(
    r: R,
    updatables: &mut HashMap<usize, crate::InodeUpdate>,
    ) -> Result<Self, TextDeError> {
    Ok(Self::read_(r, updatables)?.0)
    }
    fn read_<R: BufRead>(
    mut r: R,
    updatables: &mut HashMap<usize, crate::InodeUpdate>,
    ) -> Result<(Self, HashSet<Hash>), TextDeError> {
    use self::text_changes::*;
    let mut section = Section::Header(String::new());
    let mut change = Change {
    offsets: Offsets::default(),
    hashed: Hashed {
    version: VERSION,
    header: ChangeHeader {
    authors: Vec::new(),
    message: String::new(),
    description: None,
    timestamp: chrono::Utc::now(),
    },
    dependencies: Vec::new(),
    extra_known: Vec::new(),
    metadata: Vec::new(),
    changes: Vec::new(),
    contents_hash: Hasher::default().finish(),
    },
    unhashed: None,
    contents: Vec::new(),
    };
    let conclude_section = |change: &mut Change,
    section: Section,
    contents: &mut Vec<u8>|
    -> Result<(), TextDeError> {
    match section {
    Section::Header(ref s) => {
    debug!("header = {:?}", s);
    change.header = toml::de::from_str(&s)?;
    Ok(())
    }
    Section::Deps => Ok(()),
    Section::Changes {
    mut changes,
    current,
    ..
    } => {
    if has_newvertices(&current) {
    contents.push(0)
    }
    if let Some(c) = current {
    debug!("next action = {:?}", c);
    changes.push(c)
    }
    change.changes = changes;
    Ok(())
    }
    }
    };
    let mut h = String::new();
    let mut contents = Vec::new();
    let mut deps = HashMap::new();
    let mut extra_dependencies = HashSet::new();
    while r.read_line(&mut h)? > 0 {
    debug!("h = {:?}", h);
    if h == Self::DEPS_LINE {
    let section = std::mem::replace(&mut section, Section::Deps);
    conclude_section(&mut change, section, &mut contents)?;
    } else if h == Self::CHANGES_LINE {
    let section = std::mem::replace(
    &mut section,
    Section::Changes {
    changes: Vec::new(),
    current: None,
    offsets: HashMap::new(),
    },
    );
    conclude_section(&mut change, section, &mut contents)?;
    } else {
    use regex::Regex;
    lazy_static! {
    static ref DEPS: Regex = Regex::new(r#"\[(\d*|\*)\](\+| ) *(\S*)"#).unwrap();
    static ref KNOWN: Regex = Regex::new(r#"(\S*)"#).unwrap();
    }
    match section {
    Section::Header(ref mut s) => s.push_str(&h),
    Section::Deps => {
    if let Some(d) = DEPS.captures(&h) {
    let hash = Hash::from_base32(d[3].as_bytes()).unwrap();
    if let Ok(n) = d[1].parse() {
    if &d[2] == " " {
    change.hashed.dependencies.push(hash);
    }
    deps.insert(n, hash);
    } else if &d[1] == "*" {
    change.hashed.extra_known.push(hash);
    } else {
    extra_dependencies.insert(hash);
    }
    }
    }
    Section::Changes {
    ref mut current,
    ref mut changes,
    ref mut offsets,
    } => {
    if let Some(next) =
    Record::read(updatables, current, &mut contents, &deps, offsets, &h)?
    {
    debug!("next action = {:?}", next);
    changes.push(next)
    }
    }
    }
    }
    h.clear();
    }
    conclude_section(&mut change, section, &mut contents)?;
    change.contents = contents;
    change.contents_hash = {
    let mut hasher = Hasher::default();
    hasher.update(&change.contents);
    hasher.finish()
    };
    Ok((change, extra_dependencies))
    }
    }
    impl Record<Option<Hash>, Local> {
    fn write<
    W: std::io::Write,
    C: ChangeStore,
    F: FnMut(&Local, Position<Option<Hash>>) -> String,
    >(
    &self,
    changes: &C,
    mut file_name: F,
    hashes: &HashMap<Hash, usize>,
    change_contents: &[u8],
    mut w: W,
    ) -> Result<(), TextSerError<C::Error>> {
    use self::text_changes::*;
    match self {
    Record::FileMove { del, add, path } => match add {
    Atom::NewVertex(ref add) => {
    let name = std::str::from_utf8(
    &change_contents[add.start.0 as usize + 2..add.end.0 as usize],
    )
    .unwrap();
    let perms = crate::pristine::InodeMetadata::from_basename(
    &change_contents[add.start.0 as usize..add.start.0 as usize + 2],
    );
    write!(w, "Moved: {:?} {:?} {:o} ", path, name, perms.0)?;
    write_pos(&mut w, hashes, del.inode())?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &del)?;
    write!(w, "up")?;
    for c in add.up_context.iter() {
    write!(w, " ")?;
    write_pos(&mut w, hashes, *c)?
    }
    write!(w, ", down")?;
    for c in add.down_context.iter() {
    write!(w, " ")?;
    write_pos(&mut w, hashes, *c)?
    }
    w.write_all(b"\n")?;
    }
    Atom::EdgeMap(_) => {
    write!(w, "Moved: {:?} ", path)?;
    write_pos(&mut w, hashes, del.inode())?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &add)?;
    write_atom(&mut w, hashes, &del)?;
    }
    },
    Record::FileDel {
    del,
    contents,
    path,
    } => {
    write!(w, "File deletion: {:?} ", path)?;
    write_pos(&mut w, hashes, del.inode())?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &del)?;
    if let Some(ref contents) = contents {
    write_atom(&mut w, hashes, &contents)?;
    writeln!(w)?;
    print_change_contents(&mut w, changes, contents, change_contents)?;
    } else {
    writeln!(w)?;
    }
    }
    Record::FileUndel {
    undel,
    contents,
    path,
    } => {
    write!(w, "File un-deletion: {:?} ", path)?;
    write_pos(&mut w, hashes, undel.inode())?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &undel)?;
    if let Some(ref contents) = contents {
    write_atom(&mut w, hashes, &contents)?;
    print_change_contents(&mut w, changes, contents, change_contents)?;
    } else {
    writeln!(w)?;
    }
    }
    Record::FileAdd {
    add_name,
    contents,
    path,
    ..
    } => {
    if let Atom::NewVertex(ref n) = add_name {
    let name = std::str::from_utf8(
    &change_contents[n.start.0 as usize + 2..n.end.0 as usize],
    )
    .unwrap();
    let perms = crate::pristine::InodeMetadata::from_basename(
    &change_contents[n.start.0 as usize..n.start.0 as usize + 2],
    );
    let parent = if let Some(p) = crate::path::parent(&path) {
    if p.is_empty() {
    "/"
    } else {
    p
    }
    } else {
    "/"
    };
    write!(
    w,
    "File addition: {:?} in {:?} {:o}\n up",
    name, parent, perms.0
    )?;
    assert!(n.down_context.is_empty());
    for c in n.up_context.iter() {
    write!(w, " ")?;
    write_pos(&mut w, hashes, *c)?
    }
    writeln!(w, ", new {}:{}", n.start.0, n.end.0)?;
    }
    if let Some(Atom::NewVertex(ref n)) = contents {
    let c = &change_contents[n.start.0 as usize..n.end.0 as usize];
    print_contents(&mut w, "+", c)?;
    if !c.ends_with(b"\n") {
    writeln!(w, "\\")?
    }
    }
    }
    Record::Edit { change, local } => {
    write!(w, "Edit in {} ", file_name(&local, change.inode()))?;
    write_pos(&mut w, hashes, change.inode())?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &change)?;
    print_change_contents(&mut w, changes, change, change_contents)?;
    }
    Record::Replacement {
    change,
    replacement,
    local,
    } => {
    write!(w, "Replacement in {} ", file_name(&local, change.inode()))?;
    write_pos(&mut w, hashes, change.inode())?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &change)?;
    write_atom(&mut w, hashes, &replacement)?;
    print_change_contents(&mut w, changes, change, change_contents)?;
    print_change_contents(&mut w, changes, replacement, change_contents)?;
    }
    Record::SolveNameConflict { name, path } => {
    write!(w, "Solving a name conflict in {:?} ", path)?;
    write_pos(&mut w, hashes, name.inode())?;
    write!(w, ": ")?;
    write_deleted_names(&mut w, changes, name)?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &name)?;
    }
    Record::UnsolveNameConflict { name, path } => {
    write!(w, "Un-solving a name conflict in {:?} ", path)?;
    write_pos(&mut w, hashes, name.inode())?;
    write!(w, ": ")?;
    write_deleted_names(&mut w, changes, name)?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &name)?;
    }
    Record::SolveOrderConflict { change, local } => {
    write!(
    w,
    "Solving an order conflict in {} ",
    file_name(&local, change.inode())
    )?;
    write_pos(&mut w, hashes, change.inode())?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &change)?;
    print_change_contents(&mut w, changes, change, change_contents)?;
    }
    Record::UnsolveOrderConflict { change, local } => {
    write!(
    w,
    "Un-solving an order conflict in {} ",
    file_name(&local, change.inode())
    )?;
    write_pos(&mut w, hashes, change.inode())?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &change)?;
    print_change_contents(&mut w, changes, change, change_contents)?;
    }
    Record::ResurrectZombies { change, local } => {
    write!(
    w,
    "Resurrecting zombie lines in {:?}:{} ",
    local.path, local.line
    )?;
    write_pos(&mut w, hashes, change.inode())?;
    writeln!(w)?;
    write_atom(&mut w, hashes, &change)?;
    print_change_contents(&mut w, changes, change, change_contents)?;
    }
    }
    Ok(())
    }
    }
    impl Record<Option<Hash>, Local> {
    fn read(
    updatables: &mut HashMap<usize, crate::InodeUpdate>,
    current: &mut Option<Self>,
    mut contents_: &mut Vec<u8>,
    changes: &HashMap<usize, Hash>,
    offsets: &mut HashMap<u64, ChangePosition>,
    h: &str,
    ) -> Result<Option<Self>, TextDeError> {
    use self::text_changes::*;
    use regex::Regex;
    lazy_static! {
    static ref FILE_ADDITION: Regex =
    Regex::new(r#"(?P<n>\d+)\. File addition: "(?P<name>[^"]*)" in "(?P<parent>[^"]*)" (?P<perm>\d+)"#).unwrap();
    static ref EDIT: Regex =
    Regex::new(r#"(\d+)\. Edit in ([^:]+):(\d+) (\d+\.\d+)"#).unwrap();
    static ref REPLACEMENT: Regex =
    Regex::new(r#"(\d+)\. Replacement in ([^:]+):(\d+) (\d+\.\d+)"#).unwrap();
    static ref FILE_DELETION: Regex =
    Regex::new(r#"(\d+)\. File deletion: "([^"]*)" (\d+\.\d+)"#).unwrap();
    static ref FILE_UNDELETION: Regex =
    Regex::new(r#"(\d+)\. File un-deletion: "([^"]*)" (\d+\.\d+)"#).unwrap();
    static ref MOVE: Regex =
    Regex::new(r#"(\d+)\. Moved: "(?P<former>[^"]*)" "(?P<new>[^"]*)" (?P<perm>\d+) (?P<inode>.*)"#).unwrap();
    static ref MOVE_: Regex = Regex::new(r#"(\d+)\. Moved: "([^"]*)" (.*)"#).unwrap();
    static ref NAME_CONFLICT: Regex = Regex::new(
    r#"(\d+)\. ((Solving)|(Un-solving)) a name conflict in "([^"]*)" (.*): .*"#
    )
    .unwrap();
    static ref ORDER_CONFLICT: Regex = Regex::new(
    r#"(\d+)\. ((Solving)|(Un-solving)) an order conflict in (.*):(\d+) (\d+\.\d+)"#
    )
    .unwrap();
    static ref ZOMBIE: Regex =
    Regex::new(r#"(\d+)\. Resurrecting zombie lines in (?P<path>"[^"]+"):(?P<line>\d+) (?P<inode>\d+\.\d+)"#)
    .unwrap();
    static ref CONTEXT: Regex = Regex::new(
    r#"up ((\d+\.\d+ )*\d+\.\d+)(, new (\d+):(\d+))?(, down ((\d+\.\d+ )*\d+\.\d+))?"#
    )
    .unwrap();
    }
    if let Some(cap) = FILE_ADDITION.captures(h) {
    if has_newvertices(current) {
    contents_.push(0)
    }
    let mut add_name = default_newvertex();
    add_name.start = ChangePosition(contents_.len() as u64);
    add_name.flag = EdgeFlags::FOLDER | EdgeFlags::BLOCK;
    let name = &cap.name("name").unwrap().as_str();
    let path = {
    let parent = cap.name("parent").unwrap().as_str();
    (if parent == "/" {
    String::new()
    } else {
    parent.to_string()
    }) + name
    };
    let meta = cap
    .name("perm")
    .unwrap()
    .as_str()
    .chars()
    .fold(0, |x, c| x * 8 + (c as u16 - b'0' as u16));
    let meta = InodeMetadata(meta);
    meta.write(&mut contents_).unwrap();
    contents_.extend(name.as_bytes());
    add_name.end = ChangePosition(contents_.len() as u64);
    let mut add_inode = default_newvertex();
    add_inode.flag = EdgeFlags::FOLDER | EdgeFlags::BLOCK;
    add_inode.up_context.push(Position {
    change: None,
    pos: ChangePosition(contents_.len() as u64),
    });
    contents_.push(0);
    add_inode.start = ChangePosition(contents_.len() as u64);
    add_inode.end = ChangePosition(contents_.len() as u64);
    contents_.push(0);
    let n = cap.name("n").unwrap().as_str().parse().unwrap();
    if let Entry::Occupied(mut e) = updatables.entry(n) {
    if let crate::InodeUpdate::Add { ref mut pos, .. } = e.get_mut() {
    *pos = add_inode.start
    }
    }
    Ok(std::mem::replace(
    current,
    Some(Record::FileAdd {
    add_name: Atom::NewVertex(add_name),
    add_inode: Atom::NewVertex(add_inode),
    contents: None,
    path,
    }),
    ))
    } else if let Some(cap) = EDIT.captures(h) {
    if has_newvertices(current) {
    contents_.push(0)
    }
    let mut v = default_newvertex();
    v.inode = parse_pos(changes, &cap[4]);
    Ok(std::mem::replace(
    current,
    Some(Record::Edit {
    change: Atom::NewVertex(v),
    local: Local {
    path: cap[2].to_string(),
    line: cap[3].parse().unwrap(),
    },
    }),
    ))
    } else if let Some(cap) = REPLACEMENT.captures(h) {
    if has_newvertices(current) {
    contents_.push(0)
    }
    let mut v = default_newvertex();
    v.inode = parse_pos(changes, &cap[4]);
    Ok(std::mem::replace(
    current,
    Some(Record::Replacement {
    change: Atom::NewVertex(v.clone()),
    replacement: Atom::NewVertex(v),
    local: Local {
    path: cap[2].to_string(),
    line: cap[3].parse().unwrap(),
    },
    }),
    ))
    } else if let Some(cap) = FILE_DELETION.captures(h) {
    if has_newvertices(current) {
    contents_.push(0)
    }
    let mut del = default_edgemap();
    del.inode = parse_pos(changes, &cap[3]);
    Ok(std::mem::replace(
    current,
    Some(Record::FileDel {
    del: Atom::EdgeMap(del),
    contents: None,
    path: cap[2].to_string(),
    }),
    ))
    } else if let Some(cap) = FILE_UNDELETION.captures(h) {
    if has_newvertices(current) {
    contents_.push(0)
    }
    let mut undel = default_edgemap();
    undel.inode = parse_pos(changes, &cap[3]);
    Ok(std::mem::replace(
    current,
    Some(Record::FileUndel {
    undel: Atom::EdgeMap(undel),
    contents: None,
    path: cap[2].to_string(),
    }),
    ))
    } else if let Some(cap) = NAME_CONFLICT.captures(h) {
    if has_newvertices(current) {
    contents_.push(0)
    }
    let mut name = default_edgemap();
    debug!("cap = {:?}", cap);
    name.inode = parse_pos(changes, &cap[6]);
    Ok(std::mem::replace(
    current,
    if &cap[2] == "Solving" {
    Some(Record::SolveNameConflict {
    name: Atom::EdgeMap(name),
    path: cap[5].to_string(),
    })
    } else {
    Some(Record::UnsolveNameConflict {
    name: Atom::EdgeMap(name),
    path: cap[5].to_string(),
    })
    },
    ))
    } else if let Some(cap) = MOVE.captures(h) {
    if has_newvertices(current) {
    contents_.push(0)
    }
    let mut add = default_newvertex();
    add.start = ChangePosition(contents_.len() as u64);
    add.flag = EdgeFlags::FOLDER | EdgeFlags::BLOCK;
    let name = cap.name("new").unwrap().as_str();
    let meta = cap
    .name("perm")
    .unwrap()
    .as_str()
    .chars()
    .fold(0, |x, c| x * 8 + (c as u16 - b'0' as u16));
    let meta = InodeMetadata(meta);
    meta.write(&mut contents_).unwrap();
    contents_.extend(name.as_bytes());
    add.end = ChangePosition(contents_.len() as u64);
    let mut del = default_edgemap();
    del.inode = parse_pos(changes, cap.name("inode").unwrap().as_str());
    Ok(std::mem::replace(
    current,
    Some(Record::FileMove {
    del: Atom::EdgeMap(del),
    add: Atom::NewVertex(add),
    path: cap[2].to_string(),
    }),
    ))
    } else if let Some(cap) = MOVE_.captures(h) {
    if has_newvertices(current) {
    contents_.push(0)
    }
    let mut add = default_edgemap();
    let mut del = default_edgemap();
    add.inode = parse_pos(changes, &cap[3]);
    del.inode = add.inode;
    Ok(std::mem::replace(
    current,
    Some(Record::FileMove {
    del: Atom::EdgeMap(del),
    add: Atom::EdgeMap(add),
    path: cap[2].to_string(),
    }),
    ))
    } else if let Some(cap) = ORDER_CONFLICT.captures(h) {
    if has_newvertices(current) {
    contents_.push(0)
    }
    Ok(std::mem::replace(
    current,
    Some(if &cap[2] == "Solving" {
    let mut v = default_newvertex();
    v.inode = parse_pos(changes, &cap[7]);
    Record::SolveOrderConflict {
    change: Atom::NewVertex(v),
    local: Local {
    path: cap[5].to_string(),
    line: cap[6].parse().unwrap(),
    },
    }
    } else {
    let mut v = default_edgemap();
    v.inode = parse_pos(changes, &cap[7]);
    Record::UnsolveOrderConflict {
    change: Atom::EdgeMap(v),
    local: Local {
    path: cap[5].to_string(),
    line: cap[6].parse().unwrap(),
    },
    }
    }),
    ))
    } else if let Some(cap) = ZOMBIE.captures(h) {
    if has_newvertices(current) {
    contents_.push(0)
    }
    let mut v = default_edgemap();
    v.inode = parse_pos(changes, &cap.name("inode").unwrap().as_str());
    Ok(std::mem::replace(
    current,
    Some(Record::ResurrectZombies {
    change: Atom::EdgeMap(v),
    local: Local {
    path: cap.name("path").unwrap().as_str().parse().unwrap(),
    line: cap.name("line").unwrap().as_str().parse().unwrap(),
    },
    }),
    ))
    } else {
    match current {
    Some(Record::FileAdd {
    ref mut contents,
    ref mut add_name,
    ..
    }) => {
    if h.starts_with('+') {
    if contents.is_none() {
    let mut v = default_newvertex();
    let inode = Position {
    change: None,
    pos: ChangePosition(contents_.len() as u64 - 1),
    };
    v.up_context.push(inode);
    v.inode = inode;
    v.start = ChangePosition(contents_.len() as u64);
    *contents = Some(Atom::NewVertex(v));
    }
    if let Some(Atom::NewVertex(ref mut contents)) = contents {
    if h.starts_with('+') {
    text_changes::parse_line_add(h, contents, contents_)
    }
    }
    } else if h.starts_with('\\') {
    if let Some(Atom::NewVertex(ref mut contents)) = contents {
    if contents_[contents.end.0 as usize - 1] == b'\n' {
    assert_eq!(contents.end.0 as usize, contents_.len());
    contents_.pop();
    contents.end.0 -= 1;
    }
    }
    } else if let Some(cap) = CONTEXT.captures(h) {
    if let Atom::NewVertex(ref mut name) = add_name {
    name.up_context = parse_pos_vec(changes, offsets, &cap[1])?;
    if let (Some(new_start), Some(new_end)) = (cap.get(4), cap.get(5)) {
    offsets.insert(new_start.as_str().parse().unwrap(), name.start);
    offsets.insert(new_end.as_str().parse().unwrap(), name.end);
    offsets.insert(
    new_end.as_str().parse::<u64>().unwrap() + 1,
    name.end + 1,
    );
    }
    }
    }
    Ok(None)
    }
    Some(Record::FileDel {
    ref mut del,
    ref mut contents,
    ..
    }) => {
    if let Some(edges) = parse_edges(changes, h) {
    if let Atom::EdgeMap(ref mut e) = del {
    if edges[0].flag.contains(EdgeFlags::FOLDER) {
    *e = EdgeMap {
    inode: e.inode,
    edges,
    }
    } else {
    *contents = Some(Atom::EdgeMap(EdgeMap {
    inode: e.inode,
    edges,
    }))
    }
    }
    }
    Ok(None)
    }
    Some(Record::FileUndel {
    ref mut undel,
    ref mut contents,
    ..
    }) => {
    if let Some(edges) = parse_edges(changes, h) {
    if let Atom::EdgeMap(ref mut e) = undel {
    if edges[0].flag.contains(EdgeFlags::FOLDER) {
    *e = EdgeMap {
    inode: e.inode,
    edges,
    }
    } else {
    *contents = Some(Atom::EdgeMap(EdgeMap {
    inode: e.inode,
    edges,
    }))
    }
    }
    }
    Ok(None)
    }
    Some(Record::FileMove {
    ref mut del,
    ref mut add,
    ..
    }) => {
    if let Some(edges) = parse_edges(changes, h) {
    if edges[0].flag.contains(EdgeFlags::DELETED) {
    *del = Atom::EdgeMap(EdgeMap {
    inode: del.inode(),
    edges,
    });
    return Ok(None);
    } else if let Atom::EdgeMap(ref mut add) = add {
    if add.edges.is_empty() {
    *add = EdgeMap {
    inode: add.inode,
    edges,
    };
    return Ok(None);
    }
    }
    } else if let Some(cap) = CONTEXT.captures(h) {
    if let Atom::NewVertex(ref mut c) = add {
    debug!("cap = {:?}", cap);
    c.up_context = parse_pos_vec(changes, offsets, &cap[1])?;
    if let Some(cap) = cap.get(7) {
    c.down_context = parse_pos_vec(changes, offsets, cap.as_str())?;
    }
    }
    }
    Ok(None)
    }
    Some(Record::Edit { ref mut change, .. }) => {
    debug!("edit {:?}", h);
    if h.starts_with("+ ") {
    if let Atom::NewVertex(ref mut change) = change {
    if change.start == change.end {
    change.start = ChangePosition(contents_.len() as u64);
    }
    text_changes::parse_line_add(h, change, contents_)
    }
    } else if h.starts_with('\\') {
    if let Atom::NewVertex(ref mut change) = change {
    if contents_[change.end.0 as usize - 1] == b'\n' {
    assert_eq!(change.end.0 as usize, contents_.len());
    contents_.pop();
    change.end.0 -= 1;
    }
    }
    } else if let Some(cap) = CONTEXT.captures(h) {
    if let Atom::NewVertex(ref mut c) = change {
    debug!("cap = {:?}", cap);
    c.up_context = parse_pos_vec(changes, offsets, &cap[1])?;
    if let Some(cap) = cap.get(7) {
    c.down_context = parse_pos_vec(changes, offsets, cap.as_str())?;
    }
    }
    } else if let Some(edges) = parse_edges(changes, h) {
    *change = Atom::EdgeMap(EdgeMap {
    inode: change.inode(),
    edges,
    });
    }
    Ok(None)
    }
    Some(Record::Replacement {
    ref mut change,
    ref mut replacement,
    ..
    }) => {
    if h.starts_with("+ ") {
    if let Atom::NewVertex(ref mut repl) = replacement {
    if repl.start == repl.end {
    repl.start = ChangePosition(contents_.len() as u64);
    }
    text_changes::parse_line_add(h, repl, contents_)
    }
    } else if h.starts_with('\\') {
    if let Atom::NewVertex(ref mut repl) = replacement {
    if contents_[repl.end.0 as usize - 1] == b'\n' {
    assert_eq!(repl.end.0 as usize, contents_.len());
    contents_.pop();
    repl.end.0 -= 1;
    }
    }
    } else if let Some(cap) = CONTEXT.captures(h) {
    debug!("cap = {:?}", cap);
    if let Atom::NewVertex(ref mut repl) = replacement {
    repl.up_context = parse_pos_vec(changes, offsets, &cap[1])?;
    if let Some(cap) = cap.get(7) {
    repl.down_context = parse_pos_vec(changes, offsets, cap.as_str())?;
    }
    }
    } else if let Some(edges) = parse_edges(changes, h) {
    *change = Atom::EdgeMap(EdgeMap {
    inode: change.inode(),
    edges,
    });
    }
    Ok(None)
    }
    Some(Record::SolveNameConflict { ref mut name, .. })
    | Some(Record::UnsolveNameConflict { ref mut name, .. }) => {
    if let Some(edges) = parse_edges(changes, h) {
    *name = Atom::EdgeMap(EdgeMap {
    edges,
    inode: name.inode(),
    })
    }
    Ok(None)
    }
    Some(Record::SolveOrderConflict { ref mut change, .. }) => {
    if h.starts_with("+ ") {
    if let Atom::NewVertex(ref mut change) = change {
    if change.start == change.end {
    change.start = ChangePosition(contents_.len() as u64);
    }
    text_changes::parse_line_add(h, change, contents_)
    }
    } else if let Some(cap) = CONTEXT.captures(h) {
    debug!("cap = {:?}", cap);
    if let Atom::NewVertex(ref mut change) = change {
    change.up_context = parse_pos_vec(changes, offsets, &cap[1])?;
    if let Some(cap) = cap.get(7) {
    change.down_context =
    parse_pos_vec(changes, offsets, cap.as_str())?;
    }
    if let (Some(new_start), Some(new_end)) = (cap.get(4), cap.get(5)) {
    let new_start = new_start.as_str().parse::<u64>().unwrap();
    let new_end = new_end.as_str().parse::<u64>().unwrap();
    change.start = ChangePosition(contents_.len() as u64);
    change.end =
    ChangePosition(contents_.len() as u64 + new_end - new_start);
    offsets.insert(new_end, change.end);
    }
    }
    }
    Ok(None)
    }
    Some(Record::UnsolveOrderConflict { ref mut change, .. }) => {
    if let Some(edges) = parse_edges(changes, h) {
    if let Atom::EdgeMap(ref mut change) = change {
    change.edges = edges
    }
    }
    Ok(None)
    }
    Some(Record::ResurrectZombies { ref mut change, .. }) => {
    if let Some(edges) = parse_edges(changes, h) {
    if let Atom::EdgeMap(ref mut change) = change {
    change.edges = edges
    }
    }
    Ok(None)
    }
    None => {
    debug!("current = {:#?}", current);
    debug!("h = {:?}", h);
    Ok(None)
    }
    }
    }
    }
    }
    lazy_static! {
    static ref POS: regex::Regex = regex::Regex::new(r#"(\d+)\.(\d+)"#).unwrap();
    static ref EDGE: regex::Regex =
    regex::Regex::new(r#"\s*(?P<prev>[BFD]*):(?P<flag>[BFD]*)\s+(?P<up_c>\d+)\.(?P<up_l>\d+)\s*->\s*(?P<c>\d+)\.(?P<l0>\d+):(?P<l1>\d+)/(?P<intro>\d+)\s*"#).unwrap();
    }
    pub fn default_newvertex() -> NewVertex<Option<Hash>> {
    NewVertex {
    start: ChangePosition(0),
    end: ChangePosition(0),
    flag: EdgeFlags::empty(),
    up_context: Vec::new(),
    down_context: Vec::new(),
    inode: Position {
    change: Some(Hash::None),
    pos: ChangePosition(0),
    },
    }
    }
    pub fn default_edgemap() -> EdgeMap<Option<Hash>> {
    EdgeMap {
    edges: Vec::new(),
    inode: Position {
    change: Some(Hash::None),
    pos: ChangePosition(0),
    },
    }
    }
    pub fn has_newvertices<L>(current: &Option<Record<Option<Hash>, L>>) -> bool {
    match current {
    Some(Record::FileAdd { contents: None, .. }) | None => false,
    Some(rec) => rec.iter().any(|e| matches!(e, Atom::NewVertex(_))),
    }
    }
    pub fn parse_pos_vec(
    changes: &HashMap<usize, Hash>,
    offsets: &HashMap<u64, ChangePosition>,
    s: &str,
    ) -> Result<Vec<Position<Option<Hash>>>, TextDeError> {
    let mut v = Vec::new();
    for pos in POS.captures_iter(s) {
    let change: usize = (&pos[1]).parse().unwrap();
    let pos: u64 = (&pos[2]).parse().unwrap();
    let pos = if change == 0 {
    if let Some(&pos) = offsets.get(&pos) {
    pos
    } else {
    debug!("inconsistent change: {:?} {:?}", s, offsets);
    return Err(TextDeError::MissingChange(change));
    }
    } else {
    ChangePosition(pos)
    };
    v.push(Position {
    change: change_ref(changes, change),
    pos,
    })
    }
    Ok(v)
    }
    fn change_ref(changes: &HashMap<usize, Hash>, change: usize) -> Option<Hash> {
    debug!("change_ref {:?} {:?}", changes, change);
    if change == 0 {
    None
    } else if change == 1 {
    Some(Hash::None)
    } else {
    Some(*changes.get(&change).unwrap())
    }
    }
    pub fn parse_pos(changes: &HashMap<usize, Hash>, s: &str) -> Position<Option<Hash>> {
    let pos = POS.captures(s).unwrap();
    let change: usize = (&pos[1]).parse().unwrap();
    let pos: u64 = (&pos[2]).parse().unwrap();
    Position {
    change: change_ref(changes, change),
    pos: ChangePosition(pos),
    }
    }
    pub fn parse_edges(changes: &HashMap<usize, Hash>, s: &str) -> Option<Vec<NewEdge<Option<Hash>>>> {
    debug!("parse_edges {:?}", s);
    let mut result = Vec::new();
    for edge in s.split(',') {
    debug!("parse edge {:?}", edge);
    if let Some(cap) = EDGE.captures(edge) {
    let previous = read_flag(cap.name("prev").unwrap().as_str());
    let flag = read_flag(cap.name("flag").unwrap().as_str());
    let change0: usize = cap.name("up_c").unwrap().as_str().parse().unwrap();
    let pos0: u64 = cap.name("up_l").unwrap().as_str().parse().unwrap();
    let change1: usize = cap.name("c").unwrap().as_str().parse().unwrap();
    let start1: u64 = cap.name("l0").unwrap().as_str().parse().unwrap();
    let end1: u64 = cap.name("l1").unwrap().as_str().parse().unwrap();
    let introduced_by: usize = cap.name("intro").unwrap().as_str().parse().unwrap();
    result.push(NewEdge {
    previous,
    flag,
    from: Position {
    change: change_ref(changes, change0),
    pos: ChangePosition(pos0),
    },
    to: Vertex {
    change: change_ref(changes, change1),
    start: ChangePosition(start1),
    end: ChangePosition(end1),
    },
    introduced_by: change_ref(changes, introduced_by),
    })
    } else {
    debug!("not parsed");
    return None;
    }
    }
    Some(result)
    }
    pub fn parse_line_add(h: &str, change: &mut NewVertex<Option<Hash>>, contents_: &mut Vec<u8>) {
    let h = h.as_bytes();
    debug!("parse_line_add {:?} {:?}", change.end, change.start);
    debug!("parse_line_add {:?}", h);
    if h.len() > 2 {
    let h = &h[2..h.len()];
    contents_.extend(h);
    } else if h.len() > 1 {
    contents_.push(b'\n');
    }
    debug!("contents_.len() = {:?}", contents_.len());
    trace!("contents_ = {:?}", contents_);
    change.end = ChangePosition(contents_.len() as u64);
    }
    pub fn print_contents<W: std::io::Write>(
    w: &mut W,
    pref: &str,
    contents: &[u8],
    ) -> Result<(), std::io::Error> {
    if let Ok(mut contents) = std::str::from_utf8(&contents) {
    while let Some(n) = contents.as_bytes().iter().position(|&c| c == b'\n') {
    let (a, b) = contents.split_at(n + 1);
    contents = b;
    write!(w, "{} {}", pref, a)?;
    }
    if !contents.is_empty() {
    writeln!(w, "{} {}", pref, contents)?;
    }
    } else {
    writeln!(w, "{}b{}", pref, data_encoding::BASE64.encode(contents))?
    }
    Ok(())
    }
    pub fn print_change_contents<W: std::io::Write, C: ChangeStore>(
    w: &mut W,
    changes: &C,
    change: &Atom<Option<Hash>>,
    change_contents: &[u8],
    ) -> Result<(), TextSerError<C::Error>> {
    match change {
    Atom::NewVertex(ref n) => {
    let c = &change_contents[n.start.0 as usize..n.end.0 as usize];
    print_contents(w, "+", c)?;
    if !c.ends_with(b"\n") {
    writeln!(w, "\\")?
    }
    Ok(())
    }
    Atom::EdgeMap(ref n) if n.edges[0].flag.contains(EdgeFlags::DELETED) => {
    let mut buf = Vec::new();
    let mut current = None;
    for e in n.edges.iter() {
    if Some(e.to) == current {
    continue;
    }
    buf.clear();
    changes
    .get_contents_ext(e.to, &mut buf)
    .map_err(TextSerError::C)?;
    print_contents(w, "-", &buf[..])?;
    current = Some(e.to)
    }
    Ok(())
    }
    _ => Ok(()),
    }
    }
    pub fn write_deleted_names<W: std::io::Write, C: ChangeStore>(
    w: &mut W,
    changes: &C,
    del: &Atom<Option<Hash>>,
    ) -> Result<(), TextSerError<C::Error>> {
    if let Atom::EdgeMap(ref e) = del {
    let mut buf = Vec::new();
    let mut is_first = true;
    for d in e.edges.iter() {
    buf.clear();
    changes
    .get_contents_ext(d.to, &mut buf)
    .map_err(TextSerError::C)?;
    if !buf.is_empty() {
    let name = std::str::from_utf8(buf.split_at(2).1).unwrap();
    write!(w, "{}{:?}", if is_first { "" } else { ", " }, name)?;
    is_first = false;
    }
    }
    }
    Ok(())
    }
    pub fn write_flag<W: std::io::Write>(mut w: W, flag: EdgeFlags) -> Result<(), std::io::Error> {
    if flag.contains(EdgeFlags::BLOCK) {
    w.write_all(b"B")?;
    }
    if flag.contains(EdgeFlags::FOLDER) {
    w.write_all(b"F")?;
    }
    if flag.contains(EdgeFlags::DELETED) {
    w.write_all(b"D")?;
    }
    assert!(!flag.contains(EdgeFlags::PARENT));
    assert!(!flag.contains(EdgeFlags::PSEUDO));
    Ok(())
    }
    pub fn read_flag(s: &str) -> EdgeFlags {
    let mut f = EdgeFlags::empty();
    for i in s.chars() {
    match i {
    'B' => f |= EdgeFlags::BLOCK,
    'F' => f |= EdgeFlags::FOLDER,
    'D' => f |= EdgeFlags::DELETED,
    c => panic!("read_flag: {:?}", c),
    }
    }
    f
    }
    pub fn write_pos<W: std::io::Write>(
    mut w: W,
    hashes: &HashMap<Hash, usize>,
    pos: Position<Option<Hash>>,
    ) -> Result<(), std::io::Error> {
    let change = if let Some(Hash::None) = pos.change {
    1
    } else if let Some(ref c) = pos.change {
    *hashes.get(c).unwrap()
    } else {
    0
    };
    write!(w, "{}.{}", change, pos.pos.0)?;
    Ok(())
    }
    pub fn write_atom<W: std::io::Write>(
    w: &mut W,
    hashes: &HashMap<Hash, usize>,
    atom: &Atom<Option<Hash>>,
    ) -> Result<(), std::io::Error> {
    match atom {
    Atom::NewVertex(ref n) => write_newvertex(w, hashes, n),
    Atom::EdgeMap(ref n) => write_edgemap(w, hashes, n),
    }
    }
    pub fn write_newvertex<W: std::io::Write>(
    mut w: W,
    hashes: &HashMap<Hash, usize>,
    n: &NewVertex<Option<Hash>>,
    ) -> Result<(), std::io::Error> {
    write!(w, " up")?;
    for c in n.up_context.iter() {
    write!(w, " ")?;
    write_pos(&mut w, hashes, *c)?
    }
    write!(w, ", new {}:{}", n.start.0, n.end.0)?;
    if !n.down_context.is_empty() {
    write!(w, ", down")?;
    for c in n.down_context.iter() {
    write!(w, " ")?;
    write_pos(&mut w, hashes, *c)?
    }
    }
    w.write_all(b"\n")?;
    Ok(())
    }
    pub fn write_edgemap<W: std::io::Write>(
    mut w: W,
    hashes: &HashMap<Hash, usize>,
    n: &EdgeMap<Option<Hash>>,
    ) -> Result<(), std::io::Error> {
    let mut is_first = true;
    for c in n.edges.iter() {
    if !is_first {
    write!(w, ", ")?;
    }
    is_first = false;
    write_flag(&mut w, c.previous)?;
    write!(w, ":")?;
    write_flag(&mut w, c.flag)?;
    write!(w, " ")?;
    write_pos(&mut w, hashes, c.from)?;
    write!(w, " -> ")?;
    write_pos(&mut w, hashes, c.to.start_pos())?;
    let h = if let Some(h) = hashes.get(c.introduced_by.as_ref().unwrap()) {
    h
    } else {
    panic!("introduced_by = {:?}, not found", c.introduced_by);
    };
    write!(w, ":{}/{}", c.to.end.0, h)?;
    }
    writeln!(w)?;
    Ok(())
    }
    #[derive(Debug, Clone, PartialEq, Eq)]
    pub enum Section {
    Header(String),
    Deps,
    Changes {
    changes: Vec<Record<Option<Hash>, Local>>,
    current: Option<Record<Option<Hash>, Local>>,
    offsets: HashMap<u64, ChangePosition>,
    },
    }
  • file addition: change_file.rs (-xw-x--x--)
    [17.931000]
    use super::*;
    /// An open, seekable change file.
    #[cfg(feature = "zstd")]
    pub struct ChangeFile<'a> {
    s: Option<zstd_seekable::Seekable<'a, OffFile>>,
    hashed: Hashed<Local>,
    hash: Hash,
    unhashed: Option<toml::Value>,
    }
    struct OffFile {
    f: std::fs::File,
    start: u64,
    }
    unsafe impl Send for OffFile {}
    impl std::io::Read for OffFile {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
    self.f.read(buf)
    }
    }
    impl std::io::Seek for OffFile {
    fn seek(&mut self, from: std::io::SeekFrom) -> Result<u64, std::io::Error> {
    use std::io::SeekFrom;
    let from = match from {
    SeekFrom::Start(s) => SeekFrom::Start(s + self.start),
    c => c,
    };
    self.f.seek(from)
    }
    }
    #[cfg(feature = "zstd")]
    impl<'a> ChangeFile<'a> {
    /// Open a change file from a path.
    pub fn open(hash: Hash, path: &str) -> Result<Self, ChangeError> {
    use std::io::Read;
    let mut r = std::fs::File::open(path)?;
    let mut buf = Vec::new();
    buf.resize(Change::OFFSETS_SIZE as usize, 0);
    r.read_exact(&mut buf)?;
    let offsets: Offsets = bincode::deserialize(&buf)?;
    if offsets.version != VERSION {
    return Err(ChangeError::VersionMismatch);
    }
    buf.clear();
    buf.resize((offsets.unhashed_off - Change::OFFSETS_SIZE) as usize, 0);
    r.read_exact(&mut buf)?;
    let mut buf2 = vec![0u8; offsets.hashed_len as usize];
    let hashed: Hashed<Local> = {
    let mut s = zstd_seekable::Seekable::init_buf(&buf)?;
    s.decompress(&mut buf2, 0)?;
    bincode::deserialize(&buf2)?
    };
    buf.resize((offsets.contents_off - offsets.unhashed_off) as usize, 0);
    let unhashed = if buf.is_empty() {
    None
    } else {
    r.read_exact(&mut buf)?;
    let mut s = zstd_seekable::Seekable::init_buf(&buf)?;
    buf2.resize(offsets.unhashed_len as usize, 0);
    s.decompress(&mut buf2, 0)?;
    Some(toml::de::from_slice(&buf2)?)
    };
    let m = r.metadata()?;
    let s = if offsets.contents_off >= m.len() {
    None
    } else {
    Some(zstd_seekable::Seekable::init(Box::new(OffFile {
    f: r,
    start: offsets.contents_off,
    }))?)
    };
    Ok(ChangeFile {
    s,
    hashed,
    hash,
    unhashed,
    })
    }
    pub fn has_contents(&self) -> bool {
    self.s.is_some()
    }
    /// Reads the contents at an offset into `buf`, and returns the
    /// number of bytes read. The bounds of the change's "contents"
    /// section are not checked.
    pub fn read_contents(&mut self, offset: u64, buf: &mut [u8]) -> Result<usize, ChangeError> {
    debug!("read_contents {:?} {:?}", offset, buf.len());
    if let Some(ref mut s) = self.s {
    Ok(s.decompress(buf, offset)?)
    } else {
    Err(ChangeError::MissingContents { hash: self.hash })
    }
    }
    pub fn hashed(&self) -> &Hashed<Local> {
    &self.hashed
    }
    pub fn unhashed(&self) -> &Option<toml::Value> {
    &self.unhashed
    }
    }
  • edit in libpijul/src/apply.rs at line 1
    [17.944089][17.944090:944145]()
    // org id g5piHODDo9cz2FFDRisMQw4h8fj1SqTfQ3I/i2p+EGc=
  • edit in libpijul/src/apply.rs at line 7
    [17.944344][17.944344:944362]()
    use crate::Error;
  • replacement in libpijul/src/apply.rs at line 8
    [17.944404][17.944404:944459]()
    // org id Fn0IzU5GRCA4xymOneQzYPhm7xvcbR8viQt+xz5AzSU=
    [17.944404]
    [17.944459]
    use thiserror::Error;
    #[derive(Debug, Error)]
    pub enum ApplyError<ChangestoreError: std::error::Error, TxnError: std::error::Error + 'static> {
    #[error("Changestore error: {0}")]
    Changestore(ChangestoreError),
    #[error("Local change error: {err}")]
    LocalChange {
    #[from]
    err: LocalApplyError<TxnError>,
    },
    }
    #[derive(Debug, Error)]
    pub enum LocalApplyError<TxnError: std::error::Error> {
    #[error("Dependency missing: {:?}", hash)]
    DependencyMissing { hash: crate::pristine::Hash },
    #[error("Change already on channel: {:?}", hash)]
    ChangeAlreadyOnChannel { hash: crate::pristine::Hash },
    #[error("Transaction error: {0}")]
    Txn(TxnError),
    #[error(transparent)]
    Block(#[from] crate::pristine::BlockError),
    #[error(transparent)]
    InconsistentChange(#[from] crate::pristine::InconsistentChange),
    }
    impl<TxnError: std::error::Error> LocalApplyError<TxnError> {
    fn from_missing(err: MissingError<TxnError>) -> Self {
    match err {
    MissingError::Txn(e) => LocalApplyError::Txn(e),
    MissingError::Block(e) => LocalApplyError::Block(e),
    MissingError::Inconsistent(e) => LocalApplyError::InconsistentChange(e),
    }
    }
    }
  • replacement in libpijul/src/apply.rs at line 55
    [17.944880][17.944880:944924]()
    ) -> Result<(u64, Merkle), anyhow::Error> {
    [17.944880]
    [17.944924]
    ) -> Result<(u64, Merkle), ApplyError<P::Error, T::Error>> {
  • replacement in libpijul/src/apply.rs at line 59
    [17.945044][17.945044:945089]()
    let change = changes.get_change(&hash)?;
    [17.945044]
    [17.945089]
    let change = changes.get_change(&hash).map_err(ApplyError::Changestore)?;
  • replacement in libpijul/src/apply.rs at line 70
    [17.945379][17.945379:945443]()
    return Err((Error::DependencyMissing { hash }).into());
    [17.945379]
    [17.945443]
    return Err((LocalApplyError::DependencyMissing { hash }).into());
  • replacement in libpijul/src/apply.rs at line 77
    [17.67075][17.67075:67131]()
    register_change(txn, internal, hash, &change)?;
    [17.67075]
    [17.945648]
    register_change(txn, internal, hash, &change).map_err(LocalApplyError::Txn)?;
  • replacement in libpijul/src/apply.rs at line 81
    [17.945713][17.0:84]()
    apply_change_to_channel(txn, &mut channel, internal, &hash, &change, workspace)
    [17.945713]
    [17.945917]
    Ok(apply_change_to_channel(
    txn,
    &mut channel,
    internal,
    &hash,
    &change,
    workspace,
    )?)
  • replacement in libpijul/src/apply.rs at line 98
    [17.946111][17.946111:946144]()
    ) -> Result<(), anyhow::Error> {
    [17.946111]
    [17.946144]
    ) -> Result<(), ApplyError<P::Error, T::Error>> {
  • replacement in libpijul/src/apply.rs at line 106
    [17.946391][17.946391:946440]()
    let change = changes.get_change(&hash)?;
    [17.946391]
    [17.946440]
    let change = changes.get_change(&hash).map_err(ApplyError::Changestore)?;
  • replacement in libpijul/src/apply.rs at line 138
    [17.67204][17.67204:67272]()
    register_change(txn, internal, hash, &change)?;
    [17.67204]
    [17.947248]
    register_change(txn, internal, hash, &change).map_err(LocalApplyError::Txn)?;
  • replacement in libpijul/src/apply.rs at line 156
    [17.947938][17.947938:947982]()
    ) -> Result<(u64, Merkle), anyhow::Error> {
    [17.947938]
    [17.947982]
    ) -> Result<(u64, Merkle), ApplyError<P::Error, T::Error>> {
  • replacement in libpijul/src/apply.rs at line 167
    [17.948278][17.948278:948311]()
    ) -> Result<(), anyhow::Error> {
    [17.948278]
    [17.948311]
    ) -> Result<(), ApplyError<P::Error, T::Error>> {
  • replacement in libpijul/src/apply.rs at line 186
    [17.948861][17.948861:948905]()
    ) -> Result<(u64, Merkle), anyhow::Error> {
    [17.948861]
    [17.948905]
    ) -> Result<(u64, Merkle), LocalApplyError<T::Error>> {
  • replacement in libpijul/src/apply.rs at line 189
    [17.948963][17.948963:948980](),[17.948980][17.948980:949073](),[17.949073][17.949073:949104](),[17.949104][17.949104:949184](),[17.949184][17.949184:949195]()
    let merkle =
    if let Some(m) = txn.put_changes(channel, change_id, channel.apply_counter, hash)? {
    m
    } else {
    return Err((Error::ChangeAlreadyOnChannel { hash: *hash }).into());
    };
    [17.948963]
    [17.949195]
    let merkle = if let Some(m) = txn
    .put_changes(channel, change_id, channel.apply_counter, hash)
    .map_err(LocalApplyError::Txn)?
    {
    m
    } else {
    return Err(LocalApplyError::ChangeAlreadyOnChannel { hash: *hash });
    };
  • replacement in libpijul/src/apply.rs at line 214
    [17.950014][17.950014:950069]()
    |_, _, _, _| Ok(true),
    [17.950014]
    [17.950069]
    |_, _, _, _| Ok::<bool, LocalApplyError<T::Error>>(true),
  • replacement in libpijul/src/apply.rs at line 229
    [17.981][17.981:1018]()
    Ok(true)
    [17.981]
    [17.1018]
    Ok::<bool, LocalApplyError<T::Error>>(true)
  • edit in libpijul/src/apply.rs at line 231
    [17.1047][17.1047:1126]()
    // org id aNVimxa4oSqbTYJ033w2QbZTCVMG/+tO2ymc1QSWPH0=
  • replacement in libpijul/src/apply.rs at line 239
    [17.1481][17.1481:1508](),[17.1508][17.1508:1587]()
    )?
    // org id hXW9eN25ZM8EQ5B2Ew8NMra+xi7hFv6CN8no+qg8GpY=
    [17.1481]
    [17.951533]
    )
    .map_err(LocalApplyError::from_missing)?
  • replacement in libpijul/src/apply.rs at line 254
    [17.951945][17.951945:952082]()
    channel.last_modified = std::time::SystemTime::now()
    .duration_since(std::time::SystemTime::UNIX_EPOCH)?
    .as_secs();
    [17.951945]
    [17.952082]
    if let Ok(duration) =
    std::time::SystemTime::now().duration_since(std::time::SystemTime::UNIX_EPOCH)
    {
    channel.last_modified = duration.as_secs();
    }
  • replacement in libpijul/src/apply.rs at line 274
    [17.952657][17.952657:952701]()
    ) -> Result<(u64, Merkle), anyhow::Error> {
    [17.952657]
    [17.952760]
    ) -> Result<(u64, Merkle), LocalApplyError<T::Error>> {
  • replacement in libpijul/src/apply.rs at line 287
    [6.290][6.290:354]()
    return Err((Error::DependencyMissing { hash }).into());
    [6.290]
    [6.354]
    return Err((LocalApplyError::DependencyMissing { hash }).into());
  • replacement in libpijul/src/apply.rs at line 290
    [6.361][17.67329:67381](),[17.67329][17.67329:67381]()
    register_change(txn, internal, hash, &change)?;
    [6.361]
    [17.227]
    register_change(txn, internal, hash, &change).map_err(LocalApplyError::Txn)?;
  • replacement in libpijul/src/apply.rs at line 306
    [17.953616][17.953616:953660]()
    ) -> Result<(u64, Merkle), anyhow::Error> {
    [17.953616]
    [17.953660]
    ) -> Result<(u64, Merkle), LocalApplyError<T::Error>> {
  • replacement in libpijul/src/apply.rs at line 322
    [17.953986][17.953986:954019]()
    ) -> Result<(), anyhow::Error> {
    [17.953986]
    [17.954019]
    ) -> Result<(), LocalApplyError<T::Error>> {
  • replacement in libpijul/src/apply.rs at line 335
    [17.954497][17.67382:67440]()
    put_inodes_with_rev(txn, inode, vertex)?;
    [17.954497]
    [17.954554]
    put_inodes_with_rev(txn, inode, vertex).map_err(LocalApplyError::Txn)?;
  • replacement in libpijul/src/apply.rs at line 342
    [17.954864][17.3409:3478]()
    del_tree_with_rev(txn, parent.as_file_id(), inode)?;
    [17.954864]
    [17.954997]
    del_tree_with_rev(txn, parent.as_file_id(), inode).map_err(LocalApplyError::Txn)?;
  • replacement in libpijul/src/apply.rs at line 352
    [17.955259][17.955259:955275]()
    )?;
    [17.955259]
    [17.955275]
    )
    .map_err(LocalApplyError::Txn)?;
  • replacement in libpijul/src/apply.rs at line 355
    [17.955339][17.3532:3590]()
    del_inodes_with_rev(txn, inode, vertex)?;
    [17.955339]
    [17.955450]
    del_inodes_with_rev(txn, inode, vertex).map_err(LocalApplyError::Txn)?;
  • replacement in libpijul/src/apply.rs at line 369
    [17.955721][17.955721:955754]()
    ) -> Result<(), anyhow::Error> {
    [17.955721]
    [17.955754]
    ) -> Result<(), LocalApplyError<T::Error>> {
  • replacement in libpijul/src/apply.rs at line 395
    [17.956626][17.67545:67623]()
    put_graph_with_rev(txn, channel, flag, up, vertex, *change)?;
    [17.956626]
    [17.956703]
    put_graph_with_rev(txn, channel, flag, up, vertex, *change)
    .map_err(LocalApplyError::Txn)?;
  • replacement in libpijul/src/apply.rs at line 405
    [14.354][14.354:423]()
    put_graph_with_rev(txn, channel, flag, up, vertex, change)?;
    [14.354]
    [17.956816]
    put_graph_with_rev(txn, channel, flag, up, vertex, change).map_err(LocalApplyError::Txn)?;
  • replacement in libpijul/src/apply.rs at line 418
    [17.68059][17.68059:68075]()
    )?;
    [17.68059]
    [17.957404]
    )
    .map_err(LocalApplyError::Txn)?;
  • replacement in libpijul/src/apply.rs at line 428
    [17.68267][17.68267:68283]()
    )?;
    [17.68267]
    [17.957497]
    )
    .map_err(LocalApplyError::Txn)?;
  • replacement in libpijul/src/apply.rs at line 443
    [17.957790][17.957790:957823]()
    ) -> Result<(), anyhow::Error> {
    [17.957790]
    [17.957823]
    ) -> Result<(), LocalApplyError<T::Error>> {
  • replacement in libpijul/src/apply.rs at line 459
    [17.958453][17.68336:68386]()
    split_block(txn, channel, k, up.pos)?
    [17.958453]
    [17.958502]
    split_block(txn, channel, k, up.pos).map_err(LocalApplyError::Txn)?
  • replacement in libpijul/src/apply.rs at line 498
    [17.959448][17.959448:959495]()
    ) -> Result<Vertex<ChangeId>, anyhow::Error> {
    [17.959448]
    [17.69263]
    ) -> Result<Vertex<ChangeId>, LocalApplyError<T::Error>> {
  • replacement in libpijul/src/apply.rs at line 515
    [17.960068][17.69310:69358]()
    split_block(txn, channel, k, down.pos)?
    [17.960068]
    [17.960115]
    split_block(txn, channel, k, down.pos).map_err(LocalApplyError::Txn)?
  • replacement in libpijul/src/apply.rs at line 590
    [17.962677][17.962677:962732](),[17.962732][17.322:355]()
    // org id wwZDqGk+qPaB9Oabmhr4ziOpXgWClHLLbxpCOAo1zpI=
    pub(crate) fn put_newedge<T, F>(
    [17.962677]
    [17.962794]
    pub(crate) fn put_newedge<T, E, F>(
  • replacement in libpijul/src/apply.rs at line 599
    [17.962973][17.962973:963004]()
    ) -> Result<(), anyhow::Error>
    [17.962973]
    [17.963004]
    ) -> Result<(), E>
  • replacement in libpijul/src/apply.rs at line 602
    [17.963175][17.963175:963279](),[17.963279][17.963279:963317]()
    F: Fn(
    &mut T,
    &mut Channel<T>,
    Vertex<ChangeId>,
    Vertex<ChangeId>,
    ) -> Result<bool, anyhow::Error>,
    [17.963026]
    [17.963317]
    E: From<LocalApplyError<T::Error>>,
    F: Fn(&mut T, &mut Channel<T>, Vertex<ChangeId>, Vertex<ChangeId>) -> Result<bool, E>,
  • replacement in libpijul/src/apply.rs at line 606
    [17.963364][17.963364:963425]()
    ws.missing_context.load_graph(txn, channel, inode)?;
    [17.963364]
    [17.963425]
    ws.missing_context
    .load_graph(txn, channel, inode)
    .map_err(LocalApplyError::InconsistentChange)?;
  • replacement in libpijul/src/apply.rs at line 617
    [17.963660][17.963660:963721]()
    return Err(crate::Error::InconsistentChange.into());
    [17.963660]
    [17.963721]
    return Err(
    LocalApplyError::InconsistentChange(crate::pristine::InconsistentChange {}).into(),
    );
  • replacement in libpijul/src/apply.rs at line 646
    [17.964639][17.69742:69800]()
    split_block(txn, channel, target, n.to.end)?;
    [17.964639]
    [17.964696]
    split_block(txn, channel, target, n.to.end).map_err(LocalApplyError::Txn)?;
  • replacement in libpijul/src/apply.rs at line 659
    [17.965101][17.69801:69899]()
    let del = del_graph_with_rev(txn, channel, n.previous, source, target, n_introduced_by)?;
    [17.965101]
    [17.965198]
    let del = del_graph_with_rev(txn, channel, n.previous, source, target, n_introduced_by)
    .map_err(LocalApplyError::Txn)?;
  • replacement in libpijul/src/apply.rs at line 665
    [17.965798][17.69900:69979]()
    put_graph_with_rev(txn, channel, n.flag, source, target, change)?;
    [17.965798]
    [17.965876]
    put_graph_with_rev(txn, channel, n.flag, source, target, change)
    .map_err(LocalApplyError::Txn)?;
  • replacement in libpijul/src/apply.rs at line 675
    [17.966024][17.69980:70042]()
    target = find_block(txn, channel, target.end_pos())?;
    [17.966024]
    [17.966085]
    target = find_block(txn, channel, target.end_pos()).map_err(LocalApplyError::Block)?;
  • replacement in libpijul/src/apply.rs at line 690
    [17.966415][17.966415:966462]()
    ) -> Result<Vertex<ChangeId>, anyhow::Error> {
    [17.966415]
    [17.966462]
    ) -> Result<Vertex<ChangeId>, LocalApplyError<T::Error>> {
  • replacement in libpijul/src/apply.rs at line 714
    [17.967280][17.70132:70186]()
    split_block(txn, channel, source, from.pos)?;
    [17.967280]
    [17.967333]
    split_block(txn, channel, source, from.pos).map_err(LocalApplyError::Txn)?;
  • replacement in libpijul/src/apply.rs at line 728
    [17.967603][17.967603:967650]()
    ) -> Result<Vertex<ChangeId>, anyhow::Error> {
    [17.967603]
    [17.70187]
    ) -> Result<Vertex<ChangeId>, LocalApplyError<T::Error>> {
  • replacement in libpijul/src/apply.rs at line 753
    [17.968473][17.70307:70361]()
    split_block(txn, channel, target, to.start)?;
    [17.968473]
    [17.968526]
    split_block(txn, channel, target, to.start).map_err(LocalApplyError::Txn)?;
  • replacement in libpijul/src/apply.rs at line 765
    [17.968808][17.968808:968841]()
    ) -> Result<(), anyhow::Error> {
    [17.968808]
    [17.70362]
    ) -> Result<(), LocalApplyError<T::Error>> {
  • replacement in libpijul/src/apply.rs at line 798
    [17.969811][17.969811:969844]()
    ) -> Result<(), anyhow::Error> {
    [17.969811]
    [17.969844]
    ) -> Result<(), LocalApplyError<T::Error>> {
  • replacement in libpijul/src/apply.rs at line 820
    [17.970375][17.970375:970436]()
    return Err(crate::Error::InconsistentChange.into());
    [17.970375]
    [17.970436]
    return Err((InconsistentChange {}).into());
  • replacement in libpijul/src/apply.rs at line 842
    [17.70659][17.70659:70752]()
    put_graph_with_rev(txn, channel, EdgeFlags::PSEUDO, p, *c, ChangeId::ROOT)?;
    [17.70659]
    [17.971153]
    put_graph_with_rev(txn, channel, EdgeFlags::PSEUDO, p, *c, ChangeId::ROOT)
    .map_err(LocalApplyError::Txn)?;
  • replacement in libpijul/src/apply.rs at line 854
    [17.971377][17.971377:971410]()
    ) -> Result<(), anyhow::Error> {
    [17.971377]
    [17.971410]
    ) -> Result<(), LocalApplyError<T::Error>> {
  • replacement in libpijul/src/apply.rs at line 885
    [17.973164][17.973164:973185]()
    )? {
    [17.973164]
    [17.973185]
    )
    .map_err(LocalApplyError::Txn)?
    {
  • replacement in libpijul/src/apply.rs at line 896
    [17.973501][17.973501:973524]()
    )?
    [17.973501]
    [17.973524]
    )
    .map_err(LocalApplyError::from_missing)?
  • replacement in libpijul/src/apply.rs at line 909
    [17.71255][17.71255:71272]()
    )? {
    [17.71255]
    [17.973739]
    )
    .map_err(LocalApplyError::Txn)?
    {
  • replacement in libpijul/src/apply.rs at line 921
    [17.974075][17.974075:974094]()
    )?
    [17.974075]
    [17.974094]
    )
    .map_err(LocalApplyError::from_missing)?
  • replacement in libpijul/src/apply.rs at line 932
    [17.71466][17.71466:71482]()
    )?;
    [17.71466]
    [17.974222]
    )
    .map_err(LocalApplyError::Txn)?;
  • replacement in libpijul/src/apply.rs at line 945
    [17.974463][17.974463:974496]()
    ) -> Result<(), anyhow::Error> {
    [17.974463]
    [17.974496]
    ) -> Result<(), LocalApplyError<T::Error>> {
  • replacement in libpijul/src/apply.rs at line 947
    [17.974537][17.974537:974632]()
    crate::missing_context::repair_parents_of_deleted(txn, channel, &mut ws.missing_context)?;
    [17.974537]
    [17.974632]
    crate::missing_context::repair_parents_of_deleted(txn, channel, &mut ws.missing_context)
    .map_err(LocalApplyError::from_missing)?;
  • replacement in libpijul/src/apply.rs at line 971
    [17.975617][17.975617:975644]()
    )?
    [17.975617]
    [17.975644]
    )
    .map_err(LocalApplyError::from_missing)?
  • replacement in libpijul/src/apply.rs at line 996
    [17.976780][17.976780:976811]()
    )?
    [17.976780]
    [17.976811]
    )
    .map_err(LocalApplyError::from_missing)?
  • replacement in libpijul/src/apply.rs at line 1016
    [17.977570][17.977570:977597]()
    )?
    [17.977570]
    [17.977597]
    )
    .map_err(LocalApplyError::from_missing)?
  • replacement in libpijul/src/apply.rs at line 1036
    [17.7639][17.7639:7662]()
    )?
    [17.7639]
    [17.978338]
    )
    .map_err(LocalApplyError::from_missing)?
  • replacement in libpijul/src/apply.rs at line 1042
    [17.978406][17.978406:978495]()
    crate::missing_context::delete_pseudo_edges(txn, channel, &mut ws.missing_context)?;
    [17.978406]
    [17.978495]
    crate::missing_context::delete_pseudo_edges(txn, channel, &mut ws.missing_context)
    .map_err(LocalApplyError::from_missing)?;
  • replacement in libpijul/src/apply.rs at line 1054
    [17.978783][17.978783:978816]()
    ) -> Result<(), anyhow::Error> {
    [17.978783]
    [17.978816]
    ) -> Result<(), LocalApplyError<T::Error>> {
  • replacement in libpijul/src/apply.rs at line 1076
    [17.979642][17.979642:979675]()
    ) -> Result<(), anyhow::Error> {
    [17.979642]
    [17.979675]
    ) -> Result<(), LocalApplyError<T::Error>> {
  • replacement in libpijul/src/apply.rs at line 1087
    [17.979933][17.979933:979998]()
    return Err(crate::Error::InconsistentChange.into());
    [17.979933]
    [17.979998]
    return Err((crate::pristine::InconsistentChange {}).into());
  • replacement in libpijul/src/apply.rs at line 1112
    [17.980783][17.980783:980795]()
    )?;
    [17.980783]
    [17.980795]
    )
    .map_err(LocalApplyError::Txn)?;
  • replacement in libpijul/src/apply.rs at line 1123
    [17.980926][17.980926:980960]()
    ) -> Result<bool, crate::Error> {
    [17.980926]
    [17.980960]
    ) -> Result<bool, LocalApplyError<T::Error>> {
  • replacement in libpijul/src/alive/retrieve.rs at line 113
    [17.987781][17.987781:987814]()
    ) -> Result<(), anyhow::Error> {
    [17.987781]
    [17.987814]
    ) -> Result<(), T::Error> {
  • edit in libpijul/src/alive/output.rs at line 1
    [17.988425][17.988426:988481]()
    // org id rugGQSda+7h3fgWnFg5o6rrh0FxPthevqf1C7yFpDXo=
  • edit in libpijul/src/alive/output.rs at line 4
    [17.988592]
    [17.988592]
    use crate::output::FileError;
  • replacement in libpijul/src/alive/output.rs at line 8
    [17.988685][17.988685:988740]()
    // org id 83qmEYXouVuMdaYiRx+rqfb1HtaYFvovt7XmeQIpuuI=
    [17.988685]
    [17.988740]
  • edit in libpijul/src/alive/output.rs at line 15
    [17.988843]
    [17.988843]
  • replacement in libpijul/src/alive/output.rs at line 24
    [17.989052][17.989052:989085]()
    ) -> Result<(), anyhow::Error> {
    [17.989052]
    [17.989085]
    ) -> Result<(), FileError<P::Error>> {
  • edit in libpijul/src/alive/output.rs at line 32
    [17.989290][17.989290:989353]()
    // org id OQlVwkimOiJb/Ruz+/oEO0Pz1khIxRkvwN+/W8om9Nc=
  • edit in libpijul/src/alive/output.rs at line 34
    [17.989451][17.989451:989518]()
    // org id roGnEVojWYAOJ0zF3ObAAA8Kuqfjs3on9NNRV0mgRIc=
  • replacement in libpijul/src/alive/output.rs at line 50
    [17.990056][17.990056:990119]()
    // org id GmZmOnTyQotgknRlrewBJc6+O1mQfhuF2lNOYlgkys4=
    [17.990056]
    [17.990119]
  • replacement in libpijul/src/alive/output.rs at line 77
    [17.991141][17.991141:991204]()
    // org id TAF52f6cZFJyHIBx5wfYk6RR2l7NG8tOHboIyrGFakc=
    [17.991141]
    [17.991204]
  • replacement in libpijul/src/alive/output.rs at line 89
    [17.991435][17.991435:991490]()
    // org id U/M8FDWU06DAEBXf7bvPvuN33e6GPJLmgvUK84CFuJg=
    [17.991435]
    [17.991490]
  • replacement in libpijul/src/alive/output.rs at line 131
    [17.992880][17.992880:992935]()
    // org id 4fCwUx872WHp3z4W0/WwwMhX1cFRa2iPigNaXNpaEpA=
    [17.992880]
    [17.992935]
  • replacement in libpijul/src/alive/output.rs at line 138
    [17.993081][17.993081:993114]()
    ) -> Result<(), anyhow::Error> {
    [17.993081]
    [17.993114]
    ) -> Result<(), FileError<P::Error>> {
  • replacement in libpijul/src/alive/output.rs at line 140
    [17.993137][17.993137:993175]()
    vbuf.begin_cyclic_conflict()?
    [17.993137]
    [17.993175]
    vbuf.begin_cyclic_conflict()?;
  • edit in libpijul/src/alive/output.rs at line 151
    [17.993466][17.993466:993511]()
    let now = std::time::Instant::now();
  • replacement in libpijul/src/alive/output.rs at line 152
    [17.993560][17.993560:993652]()
    changes.get_contents(|p| txn.get_external(p), vertex, buf)?;
    Ok(())
    [17.993560]
    [17.993652]
    let now = std::time::Instant::now();
    let result = changes
    .get_contents(|p| txn.get_external(p), vertex, buf)
    .map(|_| ())
    .map_err(FileError::Changestore);
    crate::TIMERS.lock().unwrap().alive_contents += now.elapsed();
    result
  • edit in libpijul/src/alive/output.rs at line 160
    [17.993663][17.993663:993734]()
    crate::TIMERS.lock().unwrap().alive_contents += now.elapsed();
  • replacement in libpijul/src/alive/output.rs at line 176
    [17.994226][17.994226:994281]()
    // org id RA5o6M3qAtAD3/CSapAI6tIWd7yWNmsb/uCKXtvMf6c=
    [17.994226]
    [17.994281]
  • replacement in libpijul/src/alive/output.rs at line 184
    [17.994494][17.994494:994527]()
    ) -> Result<(), anyhow::Error> {
    [17.994494]
    [17.994527]
    ) -> Result<(), crate::output::FileError<P::Error>> {
  • edit in libpijul/src/alive/mod.rs at line 1
    [17.995164][17.995165:995220]()
    // org id ae+cN7ii/nf6mJV7ygVX+QzaT1iUIKfCuf/x9VMpjjQ=
  • replacement in libpijul/src/alive/mod.rs at line 10
    [17.995384][17.995384:995439]()
    // org id ccK061RVWq8mU8p92w938EIRcX5xf53Y/5klJaCYV5c=
    [17.995384]
    [17.995439]
  • replacement in libpijul/src/alive/mod.rs at line 29
    [17.995775][17.995775:995830]()
    // org id vnQ9DifkEHpAgUd3zjGq5N9u+oBkZGdVua6BJxF9jTg=
    [17.995775]
    [17.995830]
  • replacement in libpijul/src/alive/mod.rs at line 75
    [17.996870][17.996870:996925]()
    // org id SzNAy0qgvhYjwiibrE05FzjomcwRYrc00kLuPE6TWsA=
    [17.996870]
    [17.996925]
  • replacement in libpijul/src/alive/mod.rs at line 86
    [17.997255][17.997255:997310]()
    // org id IhdHg3+NO19nL+0XTy56j0KXgReFfEe/3TjQW3vU47s=
    [17.997255]
    [17.997310]
  • edit in libpijul/src/alive/mod.rs at line 128
    [17.998481][17.998481:998536]()
    // org id YjNtUksz6F4FDjsnoWIdFtsnyqrhhwGB81kMPoQh1y0=
  • edit in libpijul/src/alive/dfs.rs at line 1
    [17.1000429][17.1000430:1000485]()
    // org id FN4X/UQj4sOrdr1L/34stLjMnN7aRX6dGB8ovnXm4g4=
  • replacement in libpijul/src/alive/dfs.rs at line 5
    [17.1000599][17.1000599:1000654]()
    // org id a6g8r8xMc72herurxBoGK09TlqlNFesqMxOlGye7+wU=
    [17.1000599]
    [17.1000654]
  • replacement in libpijul/src/alive/dfs.rs at line 28
    [17.1001042][17.1001042:1001097]()
    // org id Evvo1XwskiRIPyqRTa8pr3UJx6bL0a0ky0UqCjDbj7k=
    [17.1001042]
    [17.1001097]
  • replacement in libpijul/src/alive/dfs.rs at line 48
    [17.1001397][17.1001397:1001452]()
    // org id rs9ua+JLr5uzyFxLi79zXVVGmVsbPAbn4+J7Pz+itfQ=
    [17.1001397]
    [17.1001452]
  • edit in libpijul/src/alive/dfs.rs at line 52
    [17.1001502][17.1001502:1001561]()
    // org id 1jLjvnQC+CzGcbSN/yGdM+O7tiu5ytCDkvQ7ddM/K8s=
  • edit in libpijul/src/alive/dfs.rs at line 53
    [17.1001602][17.1001602:1001661]()
    // org id ops5Ku702mQyuAsCratzGLyafN90+9XdMoqHYonqqiY=
  • edit in libpijul/src/alive/dfs.rs at line 54
    [17.1001685][17.1001685:1001744]()
    // org id I6sttXHyuv42p25LtpQ6rm+GHXz6XX3RSkXdPtw++rs=
  • edit in libpijul/src/alive/dfs.rs at line 55
    [17.1001773][17.1001773:1001832]()
    // org id tLdXR6Nj0fAJXI2MuYhja197v7oPjfGj5UsZwSsPFfc=
  • replacement in libpijul/src/alive/dfs.rs at line 57
    [17.1001864][17.1001864:1001919]()
    // org id ZKZCQZOOiAuzQ2hplUivR12avMGPrw2HbcBPp1dM96U=
    [17.1001864]
    [17.1001919]
  • edit in libpijul/src/alive/dfs.rs at line 148
    [17.1004414][17.1004414:1004477]()
    // org id fTBj4yfBA4uziK5nATQHePJ03VSVY5lNtqx3jpU4djc=
  • edit in libpijul/src/alive/dfs.rs at line 156
    [17.1004833][17.1004833:1004900]()
    // org id GWpsS0aAAfDTvTAz0PS0OxCQeAXMwg/YHlEzPlHN6OA=
  • edit in libpijul/src/alive/dfs.rs at line 185
    [17.1006337][17.1006337:1006404]()
    // org id +IS4jNPNEDK5HDBm4U7DLoNFfhwvHzn40JAm4tKnBHk=
  • edit in libpijul/src/alive/dfs.rs at line 199
    [17.1006964][17.1006964:1007027]()
    // org id FHiJPM0yAi0g9oxzzog93HBlJMVO+zkyPcyOIqCcvwI=
  • replacement in libpijul/src/alive/dfs.rs at line 202
    [17.1007094][17.1007094:1007149]()
    // org id iFf2gT1lTCyh5S5G9chCOQSV/yv6LUhW94o0G2+xy8s=
    [17.1007094]
    [17.1007149]
  • edit in libpijul/src/alive/dfs.rs at line 210
    [17.1007315][17.1007315:1007374]()
    // org id +ptaxUWOVF6qdFxwHAnI2hr3kJfCBRh7am0SWZ+zdOg=
  • edit in libpijul/src/alive/dfs.rs at line 213
    [17.1007495][17.1007495:1007554]()
    // org id gf22ooM9FpFRowUF1cPE6ISPMkymBIWZOjPS3Y1ktgQ=
  • edit in libpijul/src/alive/dfs.rs at line 218
    [17.1007703][17.1007703:1007762]()
    // org id I/pQaV+bTryz+byZO/sdFhxqPD1EYTVf6PbC+JNJFTM=
  • edit in libpijul/src/alive/dfs.rs at line 225
    [17.1008050][17.1008050:1008181]()
    // let mut f = std::fs::File::create("debug_alive").unwrap();
    // graph.debug_raw(&mut f).unwrap();
  • edit in libpijul/src/alive/dfs.rs at line 238
    [17.1008690][17.1008690:1008749]()
    // org id tppibf8fu/NgBP2gA4yEeGMCsZjARmQ3FsU1mfY8/VY=
  • replacement in libpijul/src/alive/dfs.rs at line 246
    [17.1008973][17.1008973:1009028]()
    // org id PAb27lKMvw3ODopZ9ed0R1+VLBapBvGicfts0Qfgoyk=
    [17.1008973]
    [17.1009028]
  • replacement in libpijul/src/alive/dfs.rs at line 263
    [17.1009549][17.1009549:1009604]()
    // org id +EtEUqu55ysMiPbQtSxlpzsP1Ghbgr/qJg/w1dYu0Tw=
    [17.1009549]
    [17.1009604]
  • edit in libpijul/src/alive/dfs.rs at line 273
    [17.1009932][17.1009932:1009991]()
    // org id UnhSWIMI7GsPiN8g1SS8LsKzx++g5mrRn7+M1c+VfV4=
  • edit in libpijul/src/alive/dfs.rs at line 274
    [17.1010050][17.1010050:1010109]()
    // org id Bd49Fx5qUr95VSDjZvf4LiwAmliSU/tlBb1NId/a1H8=
  • edit in libpijul/src/alive/dfs.rs at line 280
    [17.1010253][17.1010253:1010312]()
    // org id Kh9EOwJWoqxbWMdM/TBylYAtuhQKoDTzX9am56rGfAU=
  • edit in libpijul/src/alive/dfs.rs at line 283
    [17.1010446][17.1010446:1010509]()
    // org id eDtZjLZ89YmK+LQZwf0JXAHwC8hahJ+UmZGJJY9FPyw=
  • edit in libpijul/src/alive/dfs.rs at line 293
    [17.1010778][17.1010778:1010841]()
    // org id X+Vkv6E9j5wcfbqV6wd0zJcU5h4pk/xoB0fNy+jTt1w=
  • edit in libpijul/src/alive/dfs.rs at line 300
    [17.1011077][17.1011077:1011140]()
    // org id Jzso6NctQ7yQrJvt+kp4n6+R+C/j21VYuljDPYbovE0=
  • edit in libpijul/src/alive/dfs.rs at line 302
    [17.1011221][17.1011221:1011280]()
    // org id XJWvAQc9UuYzztlyavXZtb9f5v+8Q3s9dKVWBgc9Cnc=
  • replacement in libpijul/src/alive/dfs.rs at line 315
    [17.1011573][17.1011573:1011628]()
    // org id 99XChhgQdUuM9P0XMZXaiLSvZkshZYwisljAQKwv5ZA=
    [17.1011573]
    [17.1011628]
  • edit in libpijul/src/alive/dfs.rs at line 327
    [17.1012008][17.1012008:1012067]()
    // org id t4p2vXw81IHi1A61czKB1ySau+YllpLXCs+03dU030Q=
  • edit in libpijul/src/alive/dfs.rs at line 330
    [17.1012236][17.1012236:1012295]()
    // org id XkcQPnFnid03vRjpdNnv8fkp8TtbYYOh0VE3JOtW6xw=
  • edit in libpijul/src/alive/dfs.rs at line 345
    [17.1012726][17.1012726:1012785]()
    // org id qQ8ru9vhgn8xaCAW63XcBxFqrHy0K6dYJZQWCeoXNMA=
  • replacement in libpijul/src/alive/dfs.rs at line 357
    [17.1013072][17.1013072:1013127]()
    // org id LsKadSAjaUm19infXAsCqtTnGC1RMQq6d6h3WfZwioo=
    [17.1013072]
    [17.1013127]
  • edit in libpijul/src/alive/dfs.rs at line 374
    [17.1013695][17.1013695:1013774]()
    // org id duMgQ0jpJDLTmJMPqpgkKy6QBJyDJpNZzOsgqHhs/EI=
  • edit in libpijul/src/alive/debug.rs at line 1
    [17.1014531][17.1014532:1014587]()
    // org id rTQeEfoXKaEkHQXFyQtWhOFf2crR1lhKU0pRUjLxfb0=
  • replacement in libpijul/src/alive/debug.rs at line 18
    [17.1015080][17.1015080:1015117]()
    ) -> Result<(), anyhow::Error> {
    [17.1015080]
    [17.1015117]
    ) -> Result<(), std::io::Error> {
  • replacement in libpijul/src/alive/debug.rs at line 35
    [17.1015654][17.1015654:1015737]()
    changes.get_contents(|h| txn.get_external(h), line.vertex, &mut buf)?;
    [17.1015654]
    [17.1015737]
    changes
    .get_contents(|h| txn.get_external(h), line.vertex, &mut buf)
    .unwrap();
  • replacement in libpijul/src/alive/debug.rs at line 136
    [17.1019545][17.1019545:1019624]()
    pub fn debug_raw<W: Write>(&self, mut w: W) -> Result<(), anyhow::Error> {
    [17.1019545]
    [17.1019624]
    pub fn debug_raw<W: Write>(&self, mut w: W) -> Result<(), std::io::Error> {
  • edit in libpijul/Cargo.toml at line 99
    [17.1023083][17.1023083:1023098]()
    anyhow = "1.0"
  • edit in Cargo.lock at line 968
    [17.746][17.746:757]()
    "anyhow",