Adding a root inode (aka supporting submodules)

pmeunier
Oct 22, 2021, 10:04 AM
RMDMAYRXYBU5OQXV5HSF6LFD4NBMKRNH5EPIVW3K5HAV6D56IG6QC

Dependencies

  • [2] GBX4AFAS Collecting conflicts in output (broken by parallel output)
  • [3] RUBSM5DR Fixing a bug when outputting changes in text format
  • [4] SAADQM3H Finer-grained detection of metadata on Windows
  • [5] OQQ4TGEM Printing modifications only once in pijul diff
  • [6] V6J6DTJC Do not compute the entire diff if all we want is --json --untracked
  • [7] 7KNPYIDU Splitting the WorkingCopy trait into a read-only record and a read/write output
  • [8] KJOOI346 Cleanup and formatting
  • [9] 2VXTRPO4 Custom diff separators
  • [10] HOTQHK5U Fixing tests
  • [11] LGEJSLTY Fixing output (including its uses in reset and pull)
  • [12] FXEDPLRI Resurrecting tests, and type cleanup (no need for Arc<RwLock<…>> anymore)
  • [13] WZVCLZKY address clippy lints
  • [14] PKIHBUGT Setting the oldest modification time to EPOCH if no file has changed
  • [15] YCEZL7VF Moving to temporary paths when outputting
  • [16] RRCSHAYZ Formatting
  • [17] P6WE7YKL Unrecord did not check whether a file already existed before adding it back
  • [18] 3KRGVQFU Do not update the mtime of unmodified files
  • [19] 246V5TYI decode existing files
  • [20] VO5OQW4W Removing anyhow in libpijul
  • [21] 6YMDOZIB Refactoring apply
  • [22] CCLLB7OI Upgrading to Sanakirja 0.15 + version bump
  • [23] 5BRU2RRW Cleanup (debugging a crash related to trees/inodes)
  • [24] XR7MNOMU file encoding in updates
  • [25] 3S6LU2U5 abstract out FileMetadata (de)serialistion
  • [26] 2RXOCWUW Making libpijul deterministic (and getting rid of `rand`)
  • [27] ZSF3YFZT encoded file deletion
  • [28] VNBLGT6G Do not output unmodified files when resetting (fix)
  • [29] I24UEJQL Various post-fire fixes
  • [30] ZAEUSICJ File deletions were not shown with their names in the metadata during record
  • [31] XA23FMQM Reset only files that have been modified
  • [32] LLT3GY6U When recording, do not consider deleted filenames as current
  • [33] 3AMEP2Y5 More convenient interface for channels
  • [34] IIV3EL2X Cleanup, formatting, and fixing the Git feature
  • [35] MDADYULS Fix a panic when switching between channels that have different files
  • [36] BD5PC25A Deleting conflict resolution vertices when the sides are deleted
  • [37] YN63NUZO Sanakirja 1.0
  • [38] I52XSRUH Massive cleanup, and simplification
  • [39] LERRJNFC Fixing the text change version of "FileMove" to include the former path
  • [40] TVVW53HZ Conflict resolution
  • [41] C4MJ7D7Q Verbose printing of conflicts to stderr
  • [42] 3I4PAA2A Making a few types and methods public
  • [43] VYHHOEYH Versions and formatting
  • [44] ADPAFSMY Proper old metadata when recording
  • [45] GJZWSXHQ Do not remove files not tracked in the new channel when outputting
  • [46] NUAOEIXM Adding inode and byte to Local
  • [47] AJEH3FSP Properly propagate errors in `libpijul::record::record` instead of unwrap()ing
  • [48] ZHABNS3S Canonicalize all paths
  • [49] DJYHARZ7 Skipping old files when recording
  • [50] SXEYMYF7 Fixing the bad changes in history (unfortunately, by rebooting).
  • [51] GHO6DWPI Refactoring iterators
  • [52] 27PYHR6L Making the get_latest_touch function (useful to make archives) public in libpijul
  • [53] G6S6PWZE Do not touch the channel if this is a partial record
  • [54] BXD3IQYN Fixing --features git
  • [55] NYOF5766 track file encoding in the record, including change text for file adds
  • [56] CCFJ7VO3 Renaming "Record" to "Hunk" in the changes
  • [*] O4DNWMPD Cleaunp and proofreading of libpijul::record

Change contents

  • edit in "pijul/src/commands/diff.rs" at line 152
    [6.1413]
    [6.1413]
    Hunk::AddRoot { .. } => "root",
    Hunk::DelRoot { .. } => "unroot",
  • edit in "pijul/src/commands/diff.rs" at line 202
    [5.985]
    [5.985]
    Hunk::AddRoot { .. } | Hunk::DelRoot { .. } => true
  • edit in "libpijul/src/unrecord/working_copy.rs" at line 62
    [11.227747]
    [11.227747]
    debug!("source = {:?}, dest = {:?}", source, dest);
  • replacement in "libpijul/src/unrecord/working_copy.rs" at line 93
    [11.228745][11.228745:228839]()
    stack.push((source, dest));
    stack.push((grandparent, source_parent));
    [11.228745]
    [11.228839]
    if grandparent.is_root() || grandparent.start == grandparent.end {
    return_value = restore_inode(txn, changes, source, dest, Inode::ROOT, salt)?;
    } else {
    stack.push((source, dest));
    stack.push((grandparent, source_parent));
    }
  • replacement in "libpijul/src/tests/add_file.rs" at line 56
    [11.30752][11.30752:30810](),[11.30810][10.1394:1501]()
    let (key, _, name) = it.next().unwrap().unwrap();
    let key_ = get_inode_vertex(&txn, &channel.graph, Position::ROOT)?;
    assert_eq!(key, key_);
    [11.30752]
    [11.456129]
    let (_, _, name) = it.next().unwrap().unwrap();
  • replacement in "libpijul/src/tests/add_file.rs" at line 846
    [10.2518][10.2518:2566]()
    let txn = env.arc_txn_begin().unwrap();
    [10.2518]
    [10.2566]
    let env2 = pristine::sanakirja::Pristine::new_anon()?;
    let txn = env2.arc_txn_begin().unwrap();
  • edit in "libpijul/src/tests/add_file.rs" at line 860
    [10.3132]
    [10.3132]
    {
    let txn_ = txn.write();
    let mut f = std::fs::File::create("add_file2.dot")?;
    crate::pristine::debug(&*txn_, &txn_.graph(&*channel.read()), &mut f)?;
    }
  • edit in "libpijul/src/tests/add_file.rs" at line 866
    [10.3133]
    [10.3133]
    // Check that there's a name conflict.
    assert_eq!(repo.list_files().len(), 8);
  • edit in "libpijul/src/record.rs" at line 73
    [11.41156]
    [11.489652]
    new_root: Arc<Mutex<Option<ChangePosition>>>,
  • edit in "libpijul/src/record.rs" at line 106
    [11.41498]
    [11.490405]
    new_root: Arc<Mutex<Option<ChangePosition>>>,
  • edit in "libpijul/src/record.rs" at line 118
    [11.41728]
    [11.490934]
    new_root: Arc::new(Mutex::new(None)),
  • edit in "libpijul/src/record.rs" at line 147
    [11.42400]
    [11.42400]
    new_root: self.new_root.clone(),
  • replacement in "libpijul/src/record.rs" at line 346
    [11.46637][11.46637:46638]()
    [11.46637]
    [11.492928]
    info!("Starting to record");
  • edit in "libpijul/src/record.rs" at line 355
    [11.96917]
    [11.46989]
    let mut root_vertices = Vec::new();
  • edit in "libpijul/src/record.rs" at line 361
    [11.493385][11.493385:493422](),[11.493422][11.47069:47097](),[11.47127][11.493422:493487](),[11.493422][11.493422:493487]()
    self.recorded_inodes
    .lock()
    .insert(Inode::ROOT, Position::OPTION_ROOT);
  • replacement in "libpijul/src/record.rs" at line 365
    [11.97005][11.47316:47351](),[11.47316][11.47316:47351](),[11.47351][11.493487:493534](),[11.493487][11.493487:493534](),[11.493534][11.47352:47420](),[11.47420][11.97006:97040](),[11.47463][11.0:29](),[11.97040][11.0:29](),[11.493623][11.0:29](),[11.29][11.493623:493660](),[11.493623][11.493623:493660](),[11.493660][11.493660:493696](),[11.493696][11.32844:32864](),[11.32864][11.493715:493753](),[11.493715][11.493715:493753]()
    debug!("TAKEN 2");
    self.delete_obsolete_children(
    &*txn,
    txn.graph(&channel),
    working_copy,
    changes,
    &item.full_path,
    Position::ROOT,
    )?;
    Position::OPTION_ROOT
    [11.97005]
    [11.97041]
    // Test for a "root" vertex below the 0 one.
    let f0 = EdgeFlags::FOLDER | EdgeFlags::BLOCK;
    let f1 = f0 | EdgeFlags::PSEUDO;
    self.recorded_inodes
    .lock()
    .insert(Inode::ROOT, Position::ROOT.to_option());
    let mut has_nonempty_root = false;
    for e in iter_adjacent(&*txn, txn.graph(&*channel), Vertex::ROOT, f0, f1)? {
    let e = e?;
    let child = txn.find_block(txn.graph(&*channel), e.dest()).unwrap();
    if child.start == child.end {
    let grandchild =
    iter_adjacent(&*txn, txn.graph(&*channel), *child, f0, f1)?
    .next()
    .unwrap()?
    .dest();
    root_vertices.push(grandchild);
    self.delete_obsolete_children(
    &*txn,
    txn.graph(&channel),
    working_copy,
    changes,
    &item.full_path,
    grandchild,
    )?;
    } else {
    has_nonempty_root = true
    }
    }
    if has_nonempty_root && !root_vertices.is_empty() {
    // This repository is mixed between "zero" roots,
    // and new-style-roots.
    root_vertices.push(Position::ROOT)
    }
    Position::ROOT.to_option()
  • replacement in "libpijul/src/record.rs" at line 444
    [11.495196][11.495196:495237](),[11.495237][11.49041:49088](),[11.49088][11.97574:97652](),[11.49184][11.11697:11740](),[11.97652][11.11697:11740](),[11.495237][11.11697:11740](),[11.11740][11.49185:49235](),[11.49235][11.97653:97683](),[11.49274][11.495346:495373](),[11.97683][11.495346:495373](),[11.495346][11.495346:495373](),[11.495373][11.49275:49308](),[11.49308][11.495373:495449](),[11.495373][11.495373:495449](),[11.495449][11.1585:1610](),[11.1610][11.495449:495465](),[11.495449][11.495449:495465]()
    // Move on to the next step.
    debug!("TAKING LOCK {}", line!());
    let txn = txn.read();
    let channel = channel.r.read();
    self.push_children::<_, _, C>(
    &*txn,
    &*channel,
    working_copy,
    &mut item,
    &mut components,
    vertex,
    &mut stack,
    prefix,
    changes,
    )?;
    [11.495196]
    [11.49309]
    if root_vertices.is_empty() {
    // Move on to the next step.
    debug!("TAKING LOCK {}", line!());
    let txn = txn.read();
    let channel = channel.r.read();
    self.push_children::<_, _, C>(
    &*txn,
    &*channel,
    working_copy,
    &mut item,
    &mut components,
    vertex,
    &mut stack,
    prefix,
    changes,
    )?;
    } else {
    for vertex in root_vertices {
    let txn = txn.read();
    let channel = channel.r.read();
    self.push_children::<_, _, C>(
    &*txn,
    &*channel,
    working_copy,
    &mut item,
    &mut components,
    vertex.to_option(),
    &mut stack,
    prefix,
    changes,
    )?;
    }
    }
  • edit in "libpijul/src/record.rs" at line 547
    [11.51363]
    [11.51363]
    if child.start == child.end {
    // This is an empty name, i.e. the grandchild is a root vertex.
    continue;
    }
  • replacement in "libpijul/src/record.rs" at line 617
    [11.53953][11.53953:54005]()
    debug!("push_children, item = {:?}", item);
    [11.53953]
    [11.54005]
    debug!("push_children, vertex = {:?}, item = {:?}", vertex, item);
  • replacement in "libpijul/src/record.rs" at line 628
    [11.54427][11.54427:54518]()
    if fileid_.parent_inode < fileid.parent_inode || fileid_.basename.is_empty() {
    [11.54427]
    [11.54518]
    assert!(fileid_.parent_inode >= fileid.parent_inode);
    if fileid_.basename.is_empty() {
  • edit in "libpijul/src/record.rs" at line 648
    [11.55233]
    [11.55233]
    debug!("full_path = {:?}, meta = {:?}", full_path, meta);
  • edit in "libpijul/src/record.rs" at line 677
    [11.56093]
    [11.56093]
    debug!("push_children done");
  • edit in "libpijul/src/record.rs" at line 706
    [11.56806]
    [7.1845]
    fn add_root_if_needed(
    &mut self,
    v_papa: Position<Option<ChangeId>>,
    ) -> Position<Option<ChangeId>> {
    let mut contents = self.contents.lock();
    if v_papa.change == Some(ChangeId::ROOT) {
    let mut new_root = self.new_root.lock();
    if let Some(pos) = *new_root {
    Position { change: None, pos }
    } else {
    contents.push(0);
    let pos = ChangePosition(contents.len().into());
    contents.push(0);
    let pos2 = ChangePosition(contents.len().into());
    contents.push(0);
    self.actions.push(Hunk::FileAdd {
    add_name: Atom::NewVertex(NewVertex {
    up_context: vec![v_papa],
    down_context: vec![],
    start: pos2,
    end: pos2,
    flag: EdgeFlags::FOLDER | EdgeFlags::BLOCK,
    inode: v_papa,
    }),
    add_inode: Atom::NewVertex(NewVertex {
    up_context: vec![Position {
    change: None,
    pos: pos2,
    }],
    down_context: vec![],
    start: pos,
    end: pos,
    flag: EdgeFlags::FOLDER | EdgeFlags::BLOCK,
    inode: v_papa,
    }),
    contents: None,
    path: "/".to_string(),
    encoding: None,
    });
    *new_root = Some(pos);
    Position { change: None, pos }
    }
    } else {
    v_papa
    }
    }
  • edit in "libpijul/src/record.rs" at line 760
    [11.495974]
    [11.97960]
    // If we're inserting at the root, add an extra "root
    // directory" empty vertex.
    let item_v_papa = self.add_root_if_needed(item.v_papa);
  • replacement in "libpijul/src/record.rs" at line 812
    [11.498073][11.498073:498120]()
    up_context: vec![item.v_papa],
    [11.498073]
    [11.498120]
    up_context: vec![item_v_papa],
  • replacement in "libpijul/src/record.rs" at line 872
    [11.499734][11.499734:499833]()
    "record_existing_file {:?}: {:?} {:?}",
    item.full_path, item.inode, vertex
    [11.499734]
    [11.499833]
    "record_existing_file {:?}: {:?} {:?} {:?}",
    item.full_path, item.inode, vertex, new_papa,
  • edit in "libpijul/src/record.rs" at line 876
    [11.499882][11.58136:58181](),[11.58181][11.499919:500045](),[11.499919][11.499919:500045]()
    let mut former_parents = Vec::new();
    let f0 = EdgeFlags::FOLDER | EdgeFlags::PARENT;
    let f1 = EdgeFlags::all();
    let mut is_deleted = true;
  • replacement in "libpijul/src/record.rs" at line 878
    [11.98198][11.58270:58442](),[11.58270][11.58270:58442](),[11.58442][11.49753:49796](),[11.1378][11.49753:49796](),[11.1378][11.33350:33382](),[11.28511][11.33350:33382](),[11.49796][11.33350:33382](),[11.33350][11.33350:33382](),[11.33382][11.49797:49892](),[11.49892][11.33439:33479](),[11.33439][11.33439:33479](),[11.33479][11.49893:49952](),[11.49952][11.500308:500452](),[11.500308][11.500308:500452](),[11.500452][11.58443:58546](),[11.58546][11.6515:6542](),[11.6515][11.6515:6542](),[11.6542][11.2008:2180](),[11.2180][11.361:393](),[11.361][11.361:393](),[11.393][11.1397:1469](),[11.1469][11.6645:6677](),[11.58619][11.6645:6677](),[11.6645][11.6645:6677](),[11.6677][11.2181:2212](),[11.2212][11.6708:6726](),[11.6708][11.6708:6726](),[11.6726][11.11969:12022](),[11.33653][11.11969:12022](),[11.50149][11.11969:12022](),[11.11969][11.11969:12022](),[11.500855][11.773:905](),[11.905][11.58620:58744](),[11.50251][11.495:509](),[11.58744][11.495:509](),[11.495][11.495:509](),[11.509][11.33752:33790](),[11.1571][11.33752:33790](),[11.28702][11.33752:33790](),[11.33752][11.33752:33790](),[11.33790][11.50252:50317](),[11.50317][11.1470:1519](),[11.1519][11.394:450](),[11.204][11.394:450](),[11.450][11.238:272](),[11.238][11.238:272](),[11.272][11.2213:2247](),[11.2247][11.50318:50377](),[11.272][11.50318:50377](),[11.50377][11.329:370](),[11.329][11.329:370](),[11.370][11.501198:501222](),[11.501198][11.501198:501222]()
    for name_ in iter_adjacent(
    &*txn_,
    txn_.graph(&*channel_),
    vertex.inode_vertex(),
    f0,
    f1,
    )? {
    debug!("name_ = {:?}", name_);
    let name_ = name_?;
    if !name_.flag().contains(EdgeFlags::PARENT) {
    debug!("continue");
    continue;
    }
    if name_.flag().contains(EdgeFlags::DELETED) {
    debug!("is_deleted {:?}: {:?}", item.full_path, name_);
    is_deleted = true;
    break;
    }
    let name_dest = txn_
    .find_block_end(txn_.graph(&*channel_), name_.dest())
    .unwrap();
    let mut meta = Vec::new();
    let FileMetadata {
    basename,
    metadata,
    encoding,
    } = changes
    .get_file_meta(
    |p| txn_.get_external(&p).unwrap().map(From::from),
    *name_dest,
    &mut meta,
    )
    .map_err(RecordError::Changestore)?;
    debug!(
    "former basename of {:?}: {:?} {:?}",
    vertex, basename, metadata
    );
    if let Some(v_papa) =
    iter_adjacent(&*txn_, txn_.graph(&*channel_), *name_dest, f0, f1)?.next()
    {
    let v_papa = v_papa?;
    if !v_papa.flag().contains(EdgeFlags::DELETED) {
    former_parents.push(Parent {
    basename: basename.to_string(),
    metadata,
    encoding,
    parent: v_papa.dest().to_option(),
    })
    }
    }
    }
    [11.98198]
    [11.501222]
    let (former_parents, is_deleted) =
    collect_former_parents::<C, W, T>(changes, &*txn_, &*channel_, vertex)?;
  • replacement in "libpijul/src/record.rs" at line 886
    [11.501478][11.501478:501527](),[11.501527][11.58888:59113](),[11.59113][11.501772:501816](),[11.501772][11.501772:501816](),[11.501939][11.501939:501992](),[11.501992][11.33791:33842](),[11.33842][11.502032:502061](),[11.502032][11.502032:502061](),[11.502061][11.59114:59142](),[11.59142][11.538:570](),[11.570][11.502116:502171](),[11.1612][11.502116:502171](),[11.28742][11.502116:502171](),[11.33879][11.502116:502171](),[11.59186][11.502116:502171](),[11.502116][11.502116:502171](),[11.502171][11.59187:59226](),[11.59226][11.1521:1521](),[11.1521][11.1522:1578](),[11.1578][11.33880:33899](),[11.2309][11.33880:33899](),[11.59226][11.33880:33899](),[11.502254][11.33880:33899](),[11.12093][11.502273:502359](),[11.33899][11.502273:502359](),[11.502273][11.502273:502359](),[11.502359][11.59227:59346](),[11.59346][11.98199:98238](),[11.59393][11.452:517](),[11.98238][11.452:517](),[11.452][11.452:517](),[11.517][11.502452:502466](),[11.1500][11.502452:502466](),[11.28844][11.502452:502466](),[11.502452][11.502452:502466](),[11.502466][11.59394:59475](),[11.1773][11.502529:502569](),[11.28918][11.502529:502569](),[11.33970][11.502529:502569](),[11.59475][11.502529:502569](),[11.502529][11.502529:502569](),[11.502569][11.73:117](),[11.117][11.1102:1160](),[11.12123][11.1102:1160](),[11.1160][11.12179:12236](),[11.12179][11.12179:12236](),[11.12236][11.502635:502673](),[11.502635][11.502635:502673](),[11.502673][11.59476:59522](),[11.59522][11.502723:502779](),[11.502723][11.502723:502779](),[11.502779][11.59523:59583](),[11.59583][11.502834:502914](),[11.502834][11.502834:502914](),[11.502914][11.58:90](),[11.90][11.502914:503008](),[11.502914][11.502914:503008](),[11.503008][11.118:149](),[11.149][9.274:304](),[11.149][11.503008:503028](),[9.304][11.503008:503028](),[11.503008][11.503008:503028](),[11.503028][11.59584:59630](),[11.59630][11.1551:1644](),[11.1551][11.1551:1644](),[11.1644][11.59631:59780](),[11.59780][11.224:257](),[11.224][11.224:257](),[11.257][11.59781:59869](),[11.59869][11.353:379](),[11.353][11.353:379](),[11.379][11.1736:1776](),[11.1736][11.1736:1776](),[11.1776][11.2801:2878](),[11.503028][11.2801:2878](),[11.2878][11.59870:59956](),[11.59956][11.2972:2991](),[11.2972][11.2972:2991](),[11.2991][11.503104:503118](),[11.503104][11.503104:503118]()
    debug!("new_meta = {:?}", new_meta);
    if former_parents.len() > 1
    || former_parents[0].basename != item.basename
    || former_parents[0].metadata != item.metadata
    || former_parents[0].parent != item.v_papa
    || is_deleted
    {
    debug!("new_papa = {:?}", new_papa);
    self.record_moved_file::<_, _, W>(
    changes,
    &*txn_,
    &*channel_,
    &item,
    vertex,
    new_papa.unwrap(),
    former_parents[0].encoding.clone(),
    )?
    }
    if new_meta.is_file()
    && (self.force_rediff
    || modified_since_last_commit(
    &*txn_,
    &*channel_,
    &working_copy,
    &item.full_path,
    )?)
    {
    let mut ret = retrieve(&*txn_, txn_.graph(&*channel_), vertex)?;
    let mut b = Vec::new();
    let encoding = working_copy
    .decode_file(&item.full_path, &mut b)
    .map_err(RecordError::WorkingCopy)?;
    debug!("diffing…");
    let len = self.actions.len();
    self.diff(
    changes,
    &*txn_,
    &*channel_,
    diff_algorithm,
    item.full_path.clone(),
    item.inode,
    vertex.to_option(),
    &mut ret,
    &b,
    &encoding,
    diff_sep,
    )?;
    if self.actions.len() > len {
    if let Ok(last_modified) = working_copy.modified_time(&item.full_path) {
    if self.oldest_change == std::time::SystemTime::UNIX_EPOCH {
    self.oldest_change = last_modified;
    } else {
    self.oldest_change = self.oldest_change.min(last_modified);
    }
    }
    }
    debug!(
    "new actions: {:?}, total {:?}",
    &self.actions.len() - len,
    self.actions.len()
    );
    }
    [11.501478]
    [11.503118]
    self.record_nondeleted(
    &*txn_,
    diff_algorithm,
    diff_sep,
    &*channel_,
    working_copy,
    changes,
    item,
    new_papa,
    vertex,
    new_meta,
    &former_parents,
    is_deleted,
    )?
  • edit in "libpijul/src/record.rs" at line 908
    [11.29100]
    [11.2310]
    changes,
    )?
    }
    Ok(())
    }
    fn record_nondeleted<
    T: ChannelTxnT + TreeTxnT<TreeError = <T as GraphTxnT>::GraphError>,
    W: WorkingCopyRead + Clone,
    C: ChangeStore,
    >(
    &mut self,
    txn: &T,
    diff_algorithm: diff::Algorithm,
    diff_sep: &regex::bytes::Regex,
    channel: &T::Channel,
    working_copy: W,
    changes: &C,
    item: &RecordItem,
    new_papa: Option<Position<Option<ChangeId>>>,
    vertex: Position<ChangeId>,
    new_meta: InodeMetadata,
    former_parents: &[Parent],
    is_deleted: bool,
    ) -> Result<(), RecordError<C::Error, W::Error, T::GraphError>>
    where
    <W as crate::working_copy::WorkingCopyRead>::Error: 'static,
    {
    if former_parents.len() > 1
    || former_parents[0].basename != item.basename
    || former_parents[0].metadata != item.metadata
    || former_parents[0].parent != item.v_papa
    || is_deleted
    {
    debug!("new_papa = {:?}", new_papa);
    self.record_moved_file::<_, _, W>(
  • edit in "libpijul/src/record.rs" at line 945
    [11.2335]
    [11.29100]
    txn,
    channel,
    &item,
    vertex,
    new_papa.unwrap(),
    former_parents[0].encoding.clone(),
  • edit in "libpijul/src/record.rs" at line 952
    [11.29115]
    [11.503301]
    }
    if new_meta.is_file()
    && (self.force_rediff
    || modified_since_last_commit(txn, channel, &working_copy, &item.full_path)?)
    {
    let mut ret = retrieve(txn, txn.graph(channel), vertex)?;
    let mut b = Vec::new();
    let encoding = working_copy
    .decode_file(&item.full_path, &mut b)
    .map_err(RecordError::WorkingCopy)?;
    debug!("diffing…");
    let len = self.actions.len();
    self.diff(
    changes,
    txn,
    channel,
    diff_algorithm,
    item.full_path.clone(),
    item.inode,
    vertex.to_option(),
    &mut ret,
    &b,
    &encoding,
    diff_sep,
    )?;
    if self.actions.len() > len {
    if let Ok(last_modified) = working_copy.modified_time(&item.full_path) {
    if self.oldest_change == std::time::SystemTime::UNIX_EPOCH {
    self.oldest_change = last_modified;
    } else {
    self.oldest_change = self.oldest_change.min(last_modified);
    }
    }
    }
    debug!(
    "new actions: {:?}, total {:?}",
    &self.actions.len() - len,
    self.actions.len()
    );
  • replacement in "libpijul/src/record.rs" at line 1008
    [11.36029][11.0:48]()
    debug!("record_moved_file {:?}", item);
    [11.36029]
    [11.98271]
    debug!("record_moved_file {:?} {:?}", item, vertex);
  • edit in "libpijul/src/record.rs" at line 1083
    [11.244][11.244:245]()
  • edit in "libpijul/src/record.rs" at line 1116
    [58.5]
    [11.510565]
    fn collect_former_parents<C: ChangeStore, W: WorkingCopyRead, T: ChannelTxnT>(
    changes: &C,
    txn: &T,
    channel: &T::Channel,
    vertex: Position<ChangeId>,
    ) -> Result<(Vec<Parent>, bool), RecordError<C::Error, W::Error, T::GraphError>>
    where
    W::Error: 'static,
    {
    let mut former_parents = Vec::new();
    let f0 = EdgeFlags::FOLDER | EdgeFlags::PARENT;
    let f1 = EdgeFlags::all();
    let mut is_deleted = true;
    for name_ in iter_adjacent(txn, txn.graph(channel), vertex.inode_vertex(), f0, f1)? {
    debug!("name_ = {:?}", name_);
    let name_ = name_?;
    if !name_.flag().contains(EdgeFlags::PARENT) {
    debug!("continue");
    continue;
    }
    if name_.flag().contains(EdgeFlags::DELETED) {
    debug!("is_deleted {:?}", name_);
    is_deleted = true;
    break;
    }
    let name_dest = txn
    .find_block_end(txn.graph(channel), name_.dest())
    .unwrap();
    let mut meta = Vec::new();
    let FileMetadata {
    basename,
    metadata,
    encoding,
    } = changes
    .get_file_meta(
    |p| txn.get_external(&p).unwrap().map(From::from),
    *name_dest,
    &mut meta,
    )
    .map_err(RecordError::Changestore)?;
    debug!(
    "former basename of {:?}: {:?} {:?}",
    vertex, basename, metadata
    );
    if let Some(v_papa) = iter_adjacent(txn, txn.graph(channel), *name_dest, f0, f1)?.next() {
    let v_papa = v_papa?;
    if !v_papa.flag().contains(EdgeFlags::DELETED) {
    former_parents.push(Parent {
    basename: basename.to_string(),
    metadata,
    encoding,
    parent: v_papa.dest().to_option(),
    })
    }
    }
    }
    Ok((former_parents, is_deleted))
    }
  • replacement in "libpijul/src/record.rs" at line 1288
    [11.513998][11.513998:514044]()
    "grandparent_dest {:?} {:?}",
    [11.513998]
    [11.514044]
    "grandparent_dest {:?} {:?}, parent_pos = {:?}",
  • replacement in "libpijul/src/record.rs" at line 1290
    [11.514078][11.514078:514135]()
    std::str::from_utf8(&previous_name[2..])
    [11.514078]
    [11.514135]
    std::str::from_utf8(&previous_name[2..]),
    parent_pos,
  • replacement in "libpijul/src/record.rs" at line 1293
    [11.514150][11.52391:52475]()
    let grandparent_changed = parent_pos != grandparent.dest().to_option();
    [11.514150]
    [4.302]
    let grandparent_changed = if parent_pos.change == Some(ChangeId::ROOT) {
    !is_root_vertex(txn, channel, grandparent.dest())?
    } else {
    parent_pos != grandparent.dest().to_option()
    };
  • edit in "libpijul/src/record.rs" at line 1400
    [11.518269]
    [11.518269]
    }
    fn is_root_vertex<T: GraphTxnT>(
    txn: &T,
    channel: &T::Graph,
    v: Position<ChangeId>,
    ) -> Result<bool, TxnErr<T::GraphError>> {
    for parent in iter_adjacent(
    txn,
    channel,
    v.inode_vertex(),
    EdgeFlags::FOLDER | EdgeFlags::PARENT,
    EdgeFlags::FOLDER | EdgeFlags::PARENT | EdgeFlags::PSEUDO | EdgeFlags::BLOCK,
    )? {
    let p = parent?.dest();
    let p = txn.find_block_end(channel, p).unwrap();
    if p.start == p.end {
    return Ok(true);
    } else {
    return Ok(false);
    }
    }
    Ok(false)
  • edit in "libpijul/src/pristine/vertex.rs" at line 172
    [11.8][11.8:9]()
  • edit in "libpijul/src/pristine/vertex.rs" at line 173
    [11.10][11.10:11]()
  • edit in "libpijul/src/pristine/inode_metadata.rs" at line 9
    [11.641952]
    [11.642172]
    pub const DIR: Self = InodeMetadata(DIR_BIT);
  • replacement in "libpijul/src/output/output.rs" at line 168
    [11.20226][11.673931:673967](),[11.76470][11.673931:673967](),[11.82151][11.673931:673967](),[11.673931][11.673931:673967]()
    let mut conflicts = Vec::new();
    [11.76470]
    [11.76471]
    let mut state = OutputState {
    done_vertices: HashMap::default(),
    actual_moves: Vec::new(),
    conflicts: Vec::new(),
    output_name_conflicts,
    work: work.clone(),
    done_inodes: HashSet::new(),
    salt,
    if_modified_after,
    next_prefix_basename: prefix.next(),
    is_following_prefix: true,
    pending_change_id,
    };
  • replacement in "libpijul/src/output/output.rs" at line 184
    [11.76556][11.674044:674094](),[11.674044][11.674044:674094](),[11.674094][11.906:980](),[11.980][11.76557:76578](),[11.76578][11.102074:102151](),[11.102151][11.76673:76810](),[11.76673][11.76673:76810](),[11.76810][11.1077:1133](),[11.1077][11.1077:1133](),[11.1133][11.76811:76841](),[11.76841][11.102152:102191](),[11.102191][11.0:76](),[11.76][11.76962:76972](),[11.102257][11.76962:76972](),[11.76962][11.76962:76972](),[11.76972][11.1188:1225](),[11.1188][11.1188:1225]()
    let mut next_prefix_basename = prefix.next();
    let mut is_first_none = true;
    if next_prefix_basename.is_none() {
    let dead = {
    let txn_ = txn.read();
    let channel = channel.read();
    let graph = txn_.graph(&*channel);
    collect_dead_files(&*txn_, graph, pending_change_id, Inode::ROOT)?
    };
    debug!("dead (line {}) = {:?}", line!(), dead);
    if !dead.is_empty() {
    let mut txn = txn.write();
    kill_dead_files::<T, R, P>(&mut *txn, &channel, &repo, &dead)?;
    }
    is_first_none = false;
    }
    [11.76556]
    [11.76973]
    state.kill_dead_files::<_, _, P>(repo, &txn, &channel)?;
  • replacement in "libpijul/src/output/output.rs" at line 196
    [11.431][11.77236:77270](),[11.77236][11.77236:77270]()
    next_prefix_basename,
    [11.431]
    [11.77270]
    state.next_prefix_basename,
  • edit in "libpijul/src/output/output.rs" at line 201
    [11.674618][11.77313:77359](),[11.77359][11.4546:4634]()
    let mut done_inodes = HashSet::default();
    let mut done_vertices: HashMap<_, (Vertex<ChangeId>, String)> = HashMap::default();
  • edit in "libpijul/src/output/output.rs" at line 203
    [11.674819][11.674819:674858]()
    let mut actual_moves = Vec::new();
  • replacement in "libpijul/src/output/output.rs" at line 206
    [11.675018][11.675018:675065]()
    next_prefix_basename = prefix.next();
    [11.675018]
    [11.675065]
    state.next_prefix_basename = prefix.next();
  • replacement in "libpijul/src/output/output.rs" at line 208
    [11.675107][11.675107:675153](),[11.675153][11.77408:77422](),[11.77422][11.102327:102365]()
    debug!("files: {:?} {:?}", a, b);
    {
    let txn = txn.read();
    [11.675107]
    [11.102365]
    sort_conflicting_names(&txn, &channel, &mut b);
    state.output_name(repo, changes, &txn, &channel, &mut next_files, a, b)?;
    }
    std::mem::swap(&mut files, &mut next_files);
    }
    stop.store(true, std::sync::atomic::Ordering::Relaxed);
    let o = output_loop(repo, changes, txn, channel, work, stop, 0);
    for t in threads {
    state.conflicts.extend(t.join().unwrap()?.into_iter());
    }
    state.conflicts.extend(o?.into_iter());
    for (a, b) in state.actual_moves.iter() {
    repo.rename(a, b).map_err(OutputError::WorkingCopy)?
    }
    Ok(state.conflicts)
    }
    fn sort_conflicting_names<T: ChannelTxnT + Send + Sync + 'static>(
    txn: &ArcTxn<T>,
    channel: &ChannelRef<T>,
    b: &mut [(Vertex<ChangeId>, OutputItem)],
    ) {
    debug!("files: {:?}", b);
    let txn = txn.read();
    let channel = channel.read();
    b.sort_unstable_by(|u, v| {
    txn.get_changeset(txn.changes(&channel), &u.0.change)
    .unwrap()
    .cmp(
    &txn.get_changeset(txn.changes(&channel), &v.0.change)
    .unwrap(),
    )
    });
    }
    struct OutputState<'a> {
    actual_moves: Vec<(String, String)>,
    output_name_conflicts: bool,
    done_vertices: HashMap<Position<ChangeId>, (Vertex<ChangeId>, String)>,
    conflicts: Vec<Conflict>,
    work: Arc<crossbeam_deque::Injector<(OutputItem, String, Option<String>)>>,
    done_inodes: HashSet<Inode>,
    salt: u64,
    if_modified_after: Option<std::time::SystemTime>,
    next_prefix_basename: Option<&'a str>,
    is_following_prefix: bool,
    pending_change_id: ChangeId,
    }
    impl<'a> OutputState<'a> {
    fn kill_dead_files<
    T: TreeMutTxnT
    + ChannelMutTxnT
    + GraphMutTxnT<GraphError = <T as TreeTxnT>::TreeError>
    + Send
    + Sync
    + 'static,
    R: WorkingCopy + Clone + Send + Sync + 'static,
    P: ChangeStore + Clone + 'static,
    >(
    &mut self,
    repo: &R,
    txn: &ArcTxn<T>,
    channel: &ChannelRef<T>,
    ) -> Result<(), OutputError<P::Error, T::TreeError, R::Error>> {
    if self.next_prefix_basename.is_none() && self.is_following_prefix {
    let dead = {
    let txn_ = txn.read();
  • replacement in "libpijul/src/output/output.rs" at line 277
    [11.102411][11.77524:77878](),[11.77524][11.77524:77878]()
    b.sort_unstable_by(|u, v| {
    txn.get_changeset(txn.changes(&channel), &u.0.change)
    .unwrap()
    .cmp(
    &txn.get_changeset(txn.changes(&channel), &v.0.change)
    .unwrap(),
    )
    });
    [11.102411]
    [11.77878]
    let graph = txn_.graph(&*channel);
    collect_dead_files(&*txn_, graph, self.pending_change_id, Inode::ROOT)?
    };
    debug!("dead (line {}) = {:?}", line!(), dead);
    if !dead.is_empty() {
    let mut txn = txn.write();
    kill_dead_files::<T, R, P>(&mut *txn, &channel, &repo, &dead)?;
  • replacement in "libpijul/src/output/output.rs" at line 285
    [11.77892][11.675466:675559](),[11.675466][11.675466:675559](),[11.675559][11.4635:4713](),[11.1332][11.675611:675655](),[11.4713][11.675611:675655](),[11.675611][11.675611:675655](),[11.675655][8.120:401](),[8.401][11.4714:4765](),[11.675741][11.4714:4765](),[11.4765][11.675791:675914](),[11.675791][11.675791:675914](),[11.675914][11.4766:4823](),[11.4823][11.675914:676028](),[11.675914][11.675914:676028](),[11.676028][8.402:569](),[8.569][11.4867:4886](),[11.4867][11.4867:4886]()
    let mut is_first_name = true;
    for (name_key, mut output_item) in b {
    let name_entry = match done_vertices.entry(output_item.pos) {
    Entry::Occupied(e) => {
    debug!(
    "pos already visited: {:?} {:?} {:?} {:?}",
    a,
    output_item.pos,
    e.get(),
    name_key
    );
    if e.get().0 != name_key {
    conflicts.push(Conflict::MultipleNames {
    pos: output_item.pos,
    path: e.get().1.clone(),
    });
    }
    continue;
    }
    Entry::Vacant(e) => {
    debug!("first visit {:?} {:?}", a, output_item.pos);
    e
    }
    };
    [11.77892]
    [11.82271]
    self.is_following_prefix = false;
    }
    Ok(())
    }
  • replacement in "libpijul/src/output/output.rs" at line 290
    [11.82272][11.77893:77935](),[11.77935][11.102412:102454](),[11.77986][11.119905:120070](),[11.102454][11.119905:120070](),[11.82312][11.119905:120070](),[11.120070][11.82474:82532](),[11.82474][11.82474:82532](),[11.82532][11.77987:78028]()
    let output_item_inode = {
    let txn = txn.read();
    if let Some(inode) = txn.get_revinodes(&output_item.pos, None)? {
    Some((*inode, *txn.get_inodes(inode, None)?.unwrap()))
    } else {
    None
    }
    };
    [11.82272]
    [11.82555]
    fn make_inode(
    &mut self,
    a: &str,
    name_key: Vertex<ChangeId>,
    output_item: &mut OutputItem,
    is_first_name: &mut bool,
    ) -> MakeInode {
    let name_entry = match self.done_vertices.entry(output_item.pos) {
    Entry::Occupied(e) => {
    debug!(
    "pos already visited: {:?} {:?} {:?} {:?}",
    a,
    output_item.pos,
    e.get(),
    name_key
    );
    if e.get().0 != name_key {
    // The same inode has more than one name.
    self.conflicts.push(Conflict::MultipleNames {
    pos: output_item.pos,
    path: e.get().1.clone(),
    });
    }
    return MakeInode::AlreadyOutput;
    }
    Entry::Vacant(e) => {
    debug!("first visit {:?} {:?}", a, output_item.pos);
    e
    }
    };
    let name = if !*is_first_name {
    // Multiple inodes share the same name.
    if self.output_name_conflicts {
    let name = make_conflicting_name(&a, name_key);
    self.conflicts.push(Conflict::Name { path: name.clone() });
    name
    } else {
    debug!("not outputting {:?} {:?}", a, name_key);
    self.conflicts.push(Conflict::Name {
    path: a.to_string(),
    });
    return MakeInode::NameConflict;
    }
    } else {
    *is_first_name = false;
    a.to_string()
    };
    debug!("name = {:?} {:?}", name, name_key);
    let file_name = path::file_name(&name).unwrap();
    path::push(&mut output_item.path, file_name);
    name_entry.insert((name_key, output_item.path.clone()));
    MakeInode::Ok(name)
    }
  • replacement in "libpijul/src/output/output.rs" at line 344
    [11.82556][11.82556:82618](),[11.82618][11.676216:676268](),[11.676216][11.676216:676268]()
    if let Some((inode, _)) = output_item_inode {
    if !done_inodes.insert(inode) {
    [11.82556]
    [11.676268]
    fn output_name<
    T: TreeMutTxnT
    + ChannelMutTxnT
    + GraphMutTxnT<GraphError = <T as TreeTxnT>::TreeError>
    + Send
    + Sync
    + 'static,
    R: WorkingCopy + Clone + Send + Sync + 'static,
    P: ChangeStore + Send + Clone + 'static,
    >(
    &mut self,
    repo: &R,
    changes: &P,
    txn: &ArcTxn<T>,
    channel: &ChannelRef<T>,
    next_files: &mut HashMap<String, Vec<(Vertex<ChangeId>, OutputItem)>>,
    a: String,
    b: Vec<(Vertex<ChangeId>, OutputItem)>,
    ) -> Result<(), OutputError<P::Error, T::TreeError, R::Error>> {
    let mut is_first_name = true;
    for (name_key, mut output_item) in b {
    debug!("name_key = {:?} {:?}", name_key, output_item);
    let name = match self.make_inode(&a, name_key, &mut output_item, &mut is_first_name) {
    MakeInode::Ok(file_name) => file_name,
    MakeInode::AlreadyOutput => continue,
    MakeInode::NameConflict => break,
    };
    let output_item_inode = {
    let txn = txn.read();
    if let Some(inode) = txn.get_revinodes(&output_item.pos, None)? {
    if !self.done_inodes.insert(*inode) {
  • replacement in "libpijul/src/output/output.rs" at line 378
    [11.676402][11.676402:676982]()
    }
    let name = if !is_first_name {
    if output_name_conflicts {
    let name = make_conflicting_name(&a, name_key);
    conflicts.push(Conflict::Name { path: name.clone() });
    name
    } else {
    debug!("not outputting {:?} {:?}", a, name_key);
    conflicts.push(Conflict::Name {
    path: a.to_string(),
    });
    break;
    }
    [11.676402]
    [11.676982]
    Some((*inode, *txn.get_inodes(inode, None)?.unwrap()))
  • replacement in "libpijul/src/output/output.rs" at line 380
    [11.677007][11.677007:677226](),[11.677226][11.4887:4962](),[11.4962][11.432:559](),[11.677226][11.432:559](),[11.559][11.677226:677310](),[11.677226][11.677226:677310](),[11.677310][11.560:614](),[11.614][11.20283:20338](),[11.677310][11.20283:20338](),[11.20338][11.78029:78062](),[11.78062][11.102455:102482](),[11.78096][11.677476:677510](),[11.102482][11.677476:677510](),[11.677476][11.677476:677510](),[11.677510][11.82619:82658](),[11.82658][11.677510:677537](),[11.677510][11.677510:677537](),[11.677537][11.615:645](),[11.645][11.677537:677608](),[11.677537][11.677537:677608](),[11.677608][11.3605:3631](),[11.3631][11.677608:677628](),[11.677608][11.677608:677628](),[11.677628][11.78097:78144](),[11.78144][11.677628:677697](),[11.677628][11.677628:677697](),[11.677697][11.78145:78178](),[11.78178][11.102483:102584](),[11.102584][11.78297:78421](),[11.78297][11.78297:78421](),[11.4719][11.677788:677856](),[11.58151][11.677788:677856](),[11.78421][11.677788:677856](),[11.82758][11.677788:677856](),[11.677788][11.677788:677856](),[11.677856][11.78422:78464](),[11.78464][11.102585:102636](),[11.102636][11.77:165](),[11.165][11.78609:78631](),[11.102714][11.78609:78631](),[11.78609][11.78609:78631](),[11.20406][11.677912:677955](),[11.78631][11.677912:677955](),[11.677912][11.677912:677955]()
    is_first_name = false;
    a.clone()
    };
    let file_name = path::file_name(&name).unwrap();
    path::push(&mut output_item.path, file_name);
    name_entry.insert((name_key, output_item.path.clone()));
    if let Some(ref mut tmp) = output_item.tmp {
    path::push(tmp, file_name);
    }
    let path = std::mem::replace(&mut output_item.path, String::new());
    let mut tmp = output_item.tmp.take();
    let inode = move_or_create::<T, R, P>(
    txn.clone(),
    &repo,
    &output_item,
    output_item_inode,
    &path,
    &mut tmp,
    &file_name,
    &mut actual_moves,
    salt,
    )?;
    debug!("inode = {:?}", inode);
    if next_prefix_basename.is_none() && is_first_none {
    let dead = {
    let txn_ = txn.read();
    let channel = channel.read();
    collect_dead_files(&*txn_, txn_.graph(&*channel), pending_change_id, inode)?
    };
    debug!("dead (line {}) = {:?}", line!(), dead);
    if !dead.is_empty() {
    let mut txn = txn.write();
    kill_dead_files::<T, R, P>(&mut *txn, &channel, &repo, &dead)?;
    }
    is_first_none = false;
    [11.677007]
    [11.677955]
    None
  • replacement in "libpijul/src/output/output.rs" at line 382
    [11.678044][11.678044:678091]()
    if output_item.meta.is_dir() {
    [11.677973]
    [11.646]
    };
    let file_name = path::file_name(&name).unwrap();
    let mut tmp = output_item.tmp.take().map(|mut tmp| {
    path::push(&mut tmp, file_name);
    tmp
    });
    let path = std::mem::replace(&mut output_item.path, String::new());
    let inode = move_or_create::<T, R, P>(
    txn.clone(),
    &repo,
    &output_item,
    output_item_inode,
    &path,
    &mut tmp,
    &file_name,
    &mut self.actual_moves,
    self.salt,
    )?;
    debug!("inode = {:?}", inode);
    self.kill_dead_files::<_, _, P>(repo, txn, channel)?;
    if output_item.meta.is_dir() {
    if !path.is_empty() {
  • edit in "libpijul/src/output/output.rs" at line 408
    [11.20515][11.78632:78654](),[11.78654][11.102715:102815](),[11.102815][11.78772:79053](),[11.78772][11.78772:79053](),[11.79053][11.757:801](),[11.801][11.79053:79264](),[11.79053][11.79053:79264]()
    {
    let txn = txn.read();
    let channel = channel.read();
    collect_children(
    &*txn,
    &*changes,
    txn.graph(&*channel),
    output_item.pos,
    inode,
    &path,
    tmp.as_deref(),
    next_prefix_basename,
    &mut next_files,
    )?;
    }
    debug!("setting permissions for {:?}", path);
  • edit in "libpijul/src/output/output.rs" at line 410
    [11.79405][11.678486:678511](),[11.82824][11.678486:678511](),[11.678486][11.678486:678511](),[11.678511][11.102816:102886](),[11.102886][11.882:967](),[11.79485][11.882:967](),[11.967][11.963:1052](),[11.1297][11.963:1052](),[11.79557][11.963:1052](),[11.2574][11.963:1052](),[11.1052][11.2574:2596](),[11.2574][11.2574:2596]()
    } else {
    if needs_output(repo, if_modified_after, &path) {
    work.push((output_item.clone(), path.clone(), tmp.clone()));
    } else {
    debug!("Not outputting {:?}", path)
    }
  • replacement in "libpijul/src/output/output.rs" at line 411
    [11.678720][11.678720:678892]()
    if output_item.is_zombie {
    conflicts.push(Conflict::ZombieFile {
    path: name.to_string(),
    })
    [11.678720]
    [11.678892]
    let txn = txn.read();
    let channel = channel.read();
    collect_children(
    &*txn,
    &*changes,
    txn.graph(&*channel),
    output_item.pos,
    inode,
    &path,
    tmp.as_deref(),
    self.next_prefix_basename,
    next_files,
    )?;
    } else {
    if needs_output(repo, self.if_modified_after, &path) {
    self.work
    .push((output_item.clone(), path.clone(), tmp.clone()));
    } else {
    debug!("Not outputting {:?}", path)
  • edit in "libpijul/src/output/output.rs" at line 431
    [11.678910]
    [11.679059]
    }
    if output_item.is_zombie {
    self.conflicts.push(Conflict::ZombieFile {
    path: name.to_string(),
    })
  • replacement in "libpijul/src/output/output.rs" at line 438
    [11.679083][11.679083:679142](),[11.79565][11.79565:79625](),[11.79625][11.102887:102956](),[11.1045][11.79694:79717](),[11.102956][11.79694:79717](),[11.79694][11.79694:79717](),[11.79717][2.134:192](),[2.192][11.679209:679215](),[11.21082][11.679209:679215](),[11.79744][11.679209:679215](),[11.679209][11.679209:679215](),[11.679215][2.193:231](),[2.231][11.1046:1147](),[11.79753][11.1046:1147]()
    std::mem::swap(&mut files, &mut next_files);
    }
    stop.store(true, std::sync::atomic::Ordering::Relaxed);
    let o = output_loop(repo, changes, txn, channel, work, stop, 0);
    for t in threads {
    conflicts.extend(t.join().unwrap()?.into_iter());
    }
    conflicts.extend(o?.into_iter());
    for (a, b) in actual_moves.iter() {
    repo.rename(a, b).map_err(OutputError::WorkingCopy)?
    [11.679083]
    [11.1147]
    Ok(())
  • replacement in "libpijul/src/output/output.rs" at line 440
    [11.1153][11.679215:679233](),[11.79753][11.679215:679233](),[11.679215][11.679215:679233]()
    Ok(conflicts)
    [11.1153]
    [11.679233]
    }
    enum MakeInode {
    AlreadyOutput,
    NameConflict,
    Ok(String),
  • replacement in "libpijul/src/output/mod.rs" at line 101
    [11.24839][11.686875:686908](),[11.86337][11.686875:686908](),[11.686875][11.686875:686908]()
    debug!("path = {:?}", path);
    [11.86337]
    [11.56008]
    debug!("path = {:?}, inode_pos = {:?}", path, inode_pos);
  • edit in "libpijul/src/output/mod.rs" at line 110
    [11.86385]
    [11.122019]
    debug!("e = {:?}", e);
  • replacement in "libpijul/src/output/mod.rs" at line 112
    [11.56162][11.687480:687519](),[11.58558][11.687480:687519](),[11.86454][11.687480:687519](),[11.122089][11.687480:687519](),[11.687480][11.687480:687519](),[11.687519][11.1478:1556](),[11.1556][11.3999:4014](),[11.4014][11.1556:1604](),[11.1556][11.1556:1604](),[11.1604][11.17583:17652](),[11.17583][11.17583:17652]()
    let mut name_buf = Vec::new();
    let FileMetadata {
    basename,
    metadata: perms,
    ..
    } = changes
    .get_file_meta(
    |h| txn.get_external(&h).unwrap().map(|x| x.into()),
    [11.122089]
    [11.17652]
    if name_vertex.start != name_vertex.end {
    debug!("name_vertex: {:?} {:?}", e, name_vertex);
    collect(
    txn,
    changes,
    channel,
    inode,
    path,
    tmp,
    prefix_basename,
    files,
    name_vertex,
    )?
    } else {
    let inode_pos = iter_adjacent(
    txn,
    channel,
  • replacement in "libpijul/src/output/mod.rs" at line 130
    [11.17682][11.17682:17727](),[11.17727][11.86543:86600](),[11.122198][11.86543:86600](),[11.86543][11.86543:86600](),[11.687814][11.687814:688082](),[11.688145][11.688145:688203](),[11.688346][11.56334:56407](),[11.56407][11.86601:86622](),[11.86622][11.122199:122225](),[11.122225][11.56454:56555](),[11.56454][11.56454:56555](),[11.56555][11.86623:86634](),[11.86634][11.56565:56591](),[11.56565][11.56565:56591](),[11.56591][11.86635:86654](),[11.86654][11.56609:56626](),[11.56609][11.56609:56626](),[11.56626][11.86655:86688]()
    &mut name_buf,
    )
    .map_err(PristineOutputError::Changestore)?;
    debug!("filename: {:?} {:?}", perms, basename);
    let mut name = path.to_string();
    if let Some(next) = prefix_basename {
    if next != basename {
    continue;
    }
    }
    path::push(&mut name, basename);
    debug!("name_vertex: {:?} {:?}", e, name_vertex);
    let child = if let Some(child) = iter_adjacent(
    txn,
    channel,
    *name_vertex,
    EdgeFlags::FOLDER,
    EdgeFlags::FOLDER | EdgeFlags::BLOCK | EdgeFlags::PSEUDO,
    )?
    .next()
    {
    child?
    } else {
    let mut edge = None;
    [11.17682]
    [11.86688]
    EdgeFlags::FOLDER,
    EdgeFlags::FOLDER | EdgeFlags::PSEUDO | EdgeFlags::BLOCK,
    )?
    .next()
    .unwrap()?
    .dest();
  • replacement in "libpijul/src/output/mod.rs" at line 139
    [11.86750][11.122226:122256]()
    *name_vertex,
    [11.86750]
    [11.688474]
    inode_pos.inode_vertex(),
  • replacement in "libpijul/src/output/mod.rs" at line 141
    [11.688509][11.56687:56721]()
    EdgeFlags::all(),
    [11.688509]
    [11.86751]
    EdgeFlags::FOLDER | EdgeFlags::PSEUDO | EdgeFlags::BLOCK,
  • replacement in "libpijul/src/output/mod.rs" at line 144
    [11.86796][11.122257:122316](),[11.122316][11.86853:86934](),[11.86853][11.86853:86934]()
    if !e.flag().contains(EdgeFlags::PARENT) {
    edge = Some(e);
    break;
    }
    [11.86796]
    [11.86934]
    debug!("e = {:?}", e);
    let name_vertex = txn.find_block(channel, e.dest()).unwrap();
    collect(
    txn,
    changes,
    channel,
    inode,
    path,
    tmp,
    prefix_basename,
    files,
    name_vertex,
    )?
  • replacement in "libpijul/src/output/mod.rs" at line 158
    [11.86948][11.86948:86983](),[11.86983][11.688898:688970](),[11.688898][11.688898:688970](),[11.688970][11.122317:122404](),[11.962][11.689072:689115](),[11.3292][11.689072:689115](),[11.56894][11.689072:689115](),[11.87069][11.689072:689115](),[11.122404][11.689072:689115](),[11.689072][11.689072:689115]()
    let e = edge.unwrap();
    let mut f = std::fs::File::create("debug_output").unwrap();
    debug_root(txn, channel, e.dest().inode_vertex(), &mut f, false).unwrap();
    panic!("no child");
    };
    [11.86948]
    [11.689115]
    }
    }
    Ok(())
    }
  • replacement in "libpijul/src/output/mod.rs" at line 163
    [11.689116][11.689116:689154](),[11.689352][11.4958:5018](),[11.5018][11.689409:689426](),[11.689409][11.689409:689426]()
    debug!("child: {:?}", child);
    let v = files.entry(name).or_insert_with(Vec::new);
    v.push((
    [11.689116]
    [11.122405]
    fn collect<T: GraphTxnT, P: ChangeStore>(
    txn: &T,
    changes: &P,
    channel: &T::Graph,
    inode: Inode,
    path: &str,
    tmp: Option<&str>,
    prefix_basename: Option<&str>,
    files: &mut HashMap<String, Vec<(Vertex<ChangeId>, OutputItem)>>,
    name_vertex: &Vertex<ChangeId>,
    ) -> Result<(), PristineOutputError<P::Error, T::GraphError>> {
    let mut name_buf = Vec::new();
    let FileMetadata {
    basename,
    metadata: perms,
    ..
    } = changes
    .get_file_meta(
    |h| txn.get_external(&h).unwrap().map(|x| x.into()),
  • replacement in "libpijul/src/output/mod.rs" at line 183
    [11.122431][11.689451:689547](),[11.689451][11.689451:689547](),[11.689547][11.1427:1471](),[11.1471][11.689547:689576](),[11.689547][11.689547:689576](),[11.689576][11.122432:122534](),[11.87135][11.689709:689736](),[11.122534][11.689709:689736](),[11.689709][11.689709:689736]()
    OutputItem {
    parent: inode,
    path: path.to_string(),
    tmp: tmp.map(String::from),
    meta: perms,
    pos: child.dest(),
    is_zombie: is_zombie(txn, channel, child.dest())?,
    },
    ));
    [11.122431]
    [11.689736]
    &mut name_buf,
    )
    .map_err(PristineOutputError::Changestore)?;
    debug!("filename: {:?} {:?}", perms, basename);
    let mut name = path.to_string();
    if let Some(next) = prefix_basename {
    if next != basename {
    return Ok(());
    }
  • edit in "libpijul/src/output/mod.rs" at line 193
    [11.689742]
    [11.689742]
    path::push(&mut name, basename);
    let child = if let Some(child) = iter_adjacent(
    txn,
    channel,
    *name_vertex,
    EdgeFlags::FOLDER,
    EdgeFlags::FOLDER | EdgeFlags::BLOCK | EdgeFlags::PSEUDO,
    )?
    .next()
    {
    child?
    } else {
    let mut edge = None;
    for e in iter_adjacent(
    txn,
    channel,
    *name_vertex,
    EdgeFlags::FOLDER,
    EdgeFlags::all(),
    )? {
    let e = e?;
    if !e.flag().contains(EdgeFlags::PARENT) {
    edge = Some(e);
    break;
    }
    }
    let e = edge.unwrap();
    let mut f = std::fs::File::create("debug_output").unwrap();
    debug_root(txn, channel, e.dest().inode_vertex(), &mut f, false).unwrap();
    panic!("no child");
    };
    debug!("child: {:?}", child);
    let v = files.entry(name).or_insert_with(Vec::new);
    v.push((
    *name_vertex,
    OutputItem {
    parent: inode,
    path: path.to_string(),
    tmp: tmp.map(String::from),
    meta: perms,
    pos: child.dest(),
    is_zombie: is_zombie(txn, channel, child.dest())?,
    },
    ));
  • edit in "libpijul/src/fs.rs" at line 568
    [11.752522]
    [11.752522]
    adj2: Option<AdjacentIterator<'txn, T>>,
  • replacement in "libpijul/src/fs.rs" at line 578
    [11.752809][11.109481:109603]()
    let child = match self.adj.next()? {
    Ok(child) => child,
    Err(e) => return Some(Err(e.0)),
    [11.752809]
    [11.109603]
    let dest = loop {
    debug!("adj2 = {:?}", self.adj2.is_some());
    if let Some(mut adj2) = self.adj2.take() {
    match adj2.next() {
    None => {}
    Some(Ok(ch)) => {
    self.adj2 = Some(adj2);
    break self.txn.find_block(self.channel, ch.dest()).unwrap();
    }
    Some(Err(e)) => return Some(Err(e.0)),
    }
    }
    match self.adj.next() {
    Some(Ok(child)) => {
    let d = self.txn.find_block(self.channel, child.dest()).unwrap();
    if d.start == d.end {
    match iter_adjacent(
    self.txn,
    self.channel,
    *d,
    EdgeFlags::FOLDER,
    EdgeFlags::FOLDER | EdgeFlags::PSEUDO | EdgeFlags::BLOCK,
    )
    .and_then(|mut it| it.next().unwrap())
    .and_then(|x| {
    iter_adjacent(
    self.txn,
    self.channel,
    x.dest().inode_vertex(),
    EdgeFlags::FOLDER,
    EdgeFlags::FOLDER | EdgeFlags::PSEUDO | EdgeFlags::BLOCK,
    )
    }) {
    Ok(adj) => self.adj2 = Some(adj),
    Err(e) => return Some(Err(e.0)),
    }
    } else {
    break d;
    }
    }
    Some(Err(e)) => return Some(Err(e.0)),
    None => return None,
    }
  • replacement in "libpijul/src/fs.rs" at line 622
    [11.109614][11.131879:131956]()
    let dest = self.txn.find_block(self.channel, child.dest()).unwrap();
    [11.109614]
    [11.109690]
    debug!("dest = {:?}", dest);
  • edit in "libpijul/src/fs.rs" at line 685
    [11.110831]
    [11.754401]
    adj2: None,
  • replacement in "libpijul/src/fs.rs" at line 907
    [11.761369][11.761369:761401]()
    while !v.change.is_root() {
    [11.761369]
    [11.761401]
    'outer: while !v.change.is_root() {
  • edit in "libpijul/src/fs.rs" at line 929
    [11.114156]
    [11.133151]
    if name.dest().is_root() {
    break 'outer;
    }
  • edit in "libpijul/src/fs.rs" at line 968
    [11.762898]
    [11.762898]
    if name.start == name.end {
    // Non-zero root vertex
    assert!(next.change.is_root());
    break;
    }
  • edit in "libpijul/src/change.rs" at line 561
    [11.847507]
    [11.2919]
    Hunk::AddRoot { change } => Hunk::DelRoot {
    change: change.inverse(hash),
    },
    Hunk::DelRoot { change } => Hunk::AddRoot {
    change: change.inverse(hash),
    },
  • edit in "libpijul/src/change.rs" at line 755
    [11.2045]
    [11.852249]
    },
    AddRoot {
    change: Atom,
  • edit in "libpijul/src/change.rs" at line 759
    [11.852256]
    [11.852256]
    DelRoot {
    change: Atom,
    },
  • edit in "libpijul/src/change.rs" at line 847
    [11.4889]
    [11.855085]
    Hunk::AddRoot { change } | Hunk::DelRoot { change } => Some(change),
  • edit in "libpijul/src/change.rs" at line 910
    [11.5597]
    [11.857285]
    Hunk::AddRoot { ref change } | Hunk::DelRoot { ref change } => Some(change),
  • edit in "libpijul/src/change.rs" at line 992
    [11.6340]
    [11.860058]
    Hunk::AddRoot { ref change } | Hunk::DelRoot { ref change } => Some(change),
  • edit in "libpijul/src/change.rs" at line 1111
    [11.6947]
    [11.863349]
    Hunk::AddRoot { .. } | Hunk::DelRoot { .. } => "/",
  • edit in "libpijul/src/change.rs" at line 1224
    [11.866586]
    [11.122493]
    BaseHunk::AddRoot { change } => BaseHunk::AddRoot { change: f(change)? },
    BaseHunk::DelRoot { change } => BaseHunk::DelRoot { change: f(change)? },
  • replacement in "libpijul/src/change/text_changes.rs" at line 453
    [11.4295][11.2861:2981](),[11.51864][11.2861:2981](),[11.2981][11.5417:5444](),[11.5444][3.101:197]()
    let FileMetadata {
    basename: name,
    metadata: perms,
    ..
    } = FileMetadata::read(&change_contents[n.start.0.into()..n.end.0.into()]);
    [11.4295]
    [11.52241]
    let (name, perms) = if n.start == n.end {
    ("", InodeMetadata::DIR)
    } else {
    let FileMetadata {
    basename: name,
    metadata: perms,
    ..
    } = FileMetadata::read(&change_contents[n.start.0.into()..n.end.0.into()]);
    (name, perms)
    };
  • edit in "libpijul/src/change/text_changes.rs" at line 589
    [11.5532]
    [11.56555]
    }
    Hunk::AddRoot { change } => {
    writeln!(w, "Root",)?;
    write_atom(&mut w, hashes, &change)?;
    }
    Hunk::DelRoot { change } => {
    writeln!(w, "Unroot",)?;
    write_atom(&mut w, hashes, &change)?;
  • edit in "libpijul/src/change/text_changes.rs" at line 1172
    [11.79917]
    [11.79917]
    _ => unimplemented!(),