Implement the Sanakirja concurrency model in a cross-process way

[?]
Jan 14, 2021, 2:24 PM
JL4WKA5PBKXRNAMETYO4I52QKASQ3COYHH2JKGA7W5YLIRZZH53AC

Dependencies

  • [2] WEHUTJUK Lockfile update
  • [3] GYXIF25T Proper parsing of URLs
  • [4] SQVWP4LU When clone fails, only remove directories we have created (not other directories)
  • [5] I2D35LLF More accurate recording of modification time
  • [6] VYHHOEYH Versions and formatting
  • [7] HW5Q7GGY Version bump
  • [8] B5Z4IMEU Generating Cargo.nix for pijul 1.0.0-alpha.6
  • [9] JRENVH5D Reqwest 0.11
  • [10] HKEOO4QJ Version bump
  • [11] YDKNUL6B Add `diff --short` that lists changes without showing them
  • [12] VMPAOJS2 Don't output after pushing to a local channel
  • [13] N35L72XV Versions in Cargo.lock
  • [14] TZVUNELW Documentation comments
  • [15] B3QWIGDE Fixing the Git features with the latest Pijul (+ conflicts in Cargo.toml)
  • [16] KUMJITTF Version bump in the lockfiles
  • [17] WIORLB47 Version bump
  • [18] KWAMD2KR A few fixes in the documentation comments
  • [19] BZSC7VMY address clippy lints
  • [20] OUWD436A Version bump
  • [21] UFCZKKLX Upgrading to the latest Sanakirja/Rand
  • [22] CT6FBU57 SDPX license + version bump
  • [23] BT2ZHPY4 Version bumps
  • [24] SXEYMYF7 Fixing the bad changes in history (unfortunately, by rebooting).
  • [25] 6DOXSHWG Cleanup, and version bump
  • [26] SPA2OL5I keep-changes feature (default) to avoid deleting problematic changes
  • [27] XL6Y64UP Fixing a panic when iterating over the basenames of a file
  • [28] OCBM7IFE New release: pijul-1.0.0-alpha.8
  • [29] CCLLB7OI Upgrading to Sanakirja 0.15 + version bump
  • [30] GHO6DWPI Refactoring iterators
  • [31] YX3VCEOM Version bump
  • [32] G6YZ7U65 Version bump
  • [33] WI5BS6BS New published versions
  • [34] JG3MWHEN commands/change: help messages
  • [35] 4H2XTVJ2 Fix some mistakes in the docs
  • [36] SAGSYAPX Various version bumps
  • [37] PJ7T2VFL Do not hang on locked repositories
  • [38] 3S4DR77Z Version updates
  • [39] AEPEFS7O Write help for each argument
  • [40] BJOZ25EU Deterministic Git import
  • [41] VO5OQW4W Removing anyhow in libpijul
  • [42] SNZ3OAMC use native external subcommand support instead of hand-rolled one
  • [43] JACZWIJ6 Version bump
  • [44] I52XSRUH Massive cleanup, and simplification
  • [45] LYTVEPH3 Avoid cloning into an existing path
  • [46] 5BRU2RRW Cleanup (debugging a crash related to trees/inodes)
  • [47] NX5I5H53 New published versions
  • [48] 76PCXGML Pushing to, and pulling from the local repository
  • [49] RGJWLQWB When cloning, try to init *before* setting up the path Drop (pijul::commands::clone::RepoPath)
  • [50] 3AMEP2Y5 More convenient interface for channels
  • [51] HMMMKONL Fixing alive vertices
  • [52] 5YDI33C4 Fixing pager on OSX
  • [53] ZTVNGFNT Version bump
  • [54] TPEH2XNB 1.0.0-alpha.28, with Tokio 1.0
  • [55] 367UBQ6K Forwarding SSH stderr, and progress bar for push
  • [56] VQPAUKBQ channel switch as an alias to reset
  • [57] XWETQ4DE Upgrading versions
  • [58] 23LVKATN Use pager crate for log output
  • [59] 3WIQYEIS Fixing conflicts in Cargo.lock
  • [60] XAY4DYRR Version bump
  • [61] ZQXP3HNA Version bump
  • [62] JN34NIMJ More specific error for unrecognized subcommands
  • [63] 5DVRL6MF Hard-unrecord
  • [64] R3H7D42U Debugging `pijul git`: proper error reporting
  • [*] L4JXJHWX pijul/*: reorganize imports and remove extern crate
  • [*] VNBLGT6G Do not output unmodified files when resetting (fix)
  • [*] MU5GSJAW Partial push and pull (WARNING: breaks the existing protocol)
  • [*] G6S6PWZE Do not touch the channel if this is a partial record
  • [*] K6GWUOD5 Styling progress bars
  • [*] 2K7JLB4Z No pager on Windows

Change contents

  • edit in pijul/src/repository.rs at line 7
    [66.39]
    [66.39]
    #[cfg(not(unix))]
    mod basic_lock;
    #[cfg(unix)]
    mod unix_lock;
    mod lock {
    #[cfg(not(unix))]
    pub use super::basic_lock::*;
    #[cfg(unix)]
    pub use super::unix_lock::*;
    use std::path::Path;
    pub enum Lock {
    Txn(TxnLock),
    MutTxn(MutTxnLock),
    }
  • edit in pijul/src/repository.rs at line 24
    [66.40]
    [8.7685]
    impl Lock {
    pub async fn mut_txn_lock<P: AsRef<Path>>(p: P) -> Result<Self, anyhow::Error> {
    let pp = p.as_ref().join("db_lock");
    Ok(Lock::MutTxn(mut_txn(&pp).await?))
    }
    pub async fn txn_lock<P: AsRef<Path>>(p: P) -> Result<Self, anyhow::Error> {
    let pp = p.as_ref().join("db_lock");
    Ok(Lock::Txn(txn(&pp).await?))
    }
    pub async fn commit(&mut self) -> Result<(), anyhow::Error> {
    match self {
    Lock::MutTxn(m) => m.commit().await,
    _ => Ok(()),
    }
    }
    }
    }
  • edit in pijul/src/repository.rs at line 45
    [8.21565]
    [8.21565]
    pub lock: lock::Lock,
  • replacement in pijul/src/repository.rs at line 89
    [8.22907][8.22907:23034]()
    pub fn find_root(cur: Option<PathBuf>) -> Result<Self, anyhow::Error> {
    Self::find_root_with_dot_dir(cur, DOT_DIR)
    [8.22907]
    [8.23034]
    pub async fn find_root(cur: Option<PathBuf>) -> Result<Self, anyhow::Error> {
    Self::find_root_with_dot_dir(cur, DOT_DIR, true).await
  • replacement in pijul/src/repository.rs at line 93
    [8.23041][8.23041:23076]()
    pub fn find_root_with_dot_dir(
    [8.23041]
    [8.23076]
    pub async unsafe fn find_root_immutable(cur: Option<PathBuf>) -> Result<Self, anyhow::Error> {
    Self::find_root_with_dot_dir(cur, DOT_DIR, false).await
    }
    pub async fn find_root_with_dot_dir(
  • edit in pijul/src/repository.rs at line 100
    [8.23129]
    [8.23129]
    mutable: bool,
  • replacement in pijul/src/repository.rs at line 120
    [8.23883][8.23883:23967]()
    pristine: libpijul::pristine::sanakirja::Pristine::new(&pristine_dir)?,
    [8.23883]
    [8.23967]
    lock: if mutable {
    lock::Lock::mut_txn_lock(&pristine_dir).await?
    } else {
    lock::Lock::txn_lock(&pristine_dir).await?
    },
    pristine: unsafe {
    libpijul::pristine::sanakirja::Pristine::new_nolock(&pristine_dir)?
    },
  • replacement in pijul/src/repository.rs at line 138
    [8.24299][8.24299:24382]()
    pub fn init(path: Option<std::path::PathBuf>) -> Result<Self, anyhow::Error> {
    [8.24299]
    [8.24382]
    pub async fn init(path: Option<std::path::PathBuf>) -> Result<Self, anyhow::Error> {
  • replacement in pijul/src/repository.rs at line 153
    [8.24885][8.24885:24973]()
    pristine: libpijul::pristine::sanakirja::Pristine::new(&pristine_dir)?,
    [8.24885]
    [8.24973]
    lock: lock::Lock::mut_txn_lock(&pristine_dir).await?,
    pristine: unsafe {
    libpijul::pristine::sanakirja::Pristine::new_nolock(&pristine_dir)?
    },
  • file addition: repository (dxwrx-rx-r)
    [8.21414]
  • file addition: unix_lock.rs (-xw-x--x--)
    [0.1940]
    use anyhow::bail;
    use std::io::Read;
    use std::path::Path;
    use tokio::io::{AsyncReadExt, AsyncWriteExt};
    use tokio::net::UnixStream;
    pub struct TxnLock {
    _stream: UnixStream,
    }
    pub struct MutTxnLock {
    stream: UnixStream,
    }
    const TXN_BEGIN: u8 = 0;
    const MUT_TXN_BEGIN: u8 = 1;
    const COMMIT: u8 = 2;
    const ACK: u8 = 3;
    pub async fn mut_txn<P: AsRef<Path>>(file: P) -> Result<MutTxnLock, anyhow::Error> {
    let cmd = std::env::args().next().unwrap();
    let mut process = std::process::Command::new(&cmd)
    .args(&["lock", file.as_ref().to_str().unwrap()])
    .stdout(std::process::Stdio::piped())
    .spawn()?;
    let s = process.stdout.as_mut().unwrap();
    s.read(&mut [0u8])?;
    let mut stream = UnixStream::connect(file).await?;
    stream.writable().await?;
    stream.write_all(&[MUT_TXN_BEGIN]).await?;
    let mut t = [0u8];
    stream.read_exact(&mut t).await?;
    if t[0] == ACK {
    Ok(MutTxnLock { stream })
    } else {
    bail!("Pristine locked")
    }
    }
    pub async fn txn<P: AsRef<Path>>(file: P) -> Result<TxnLock, anyhow::Error> {
    let cmd = std::env::args().next().unwrap();
    std::process::Command::new(&cmd)
    .args(&["lock", file.as_ref().to_str().unwrap()])
    .spawn()?;
    let mut stream = UnixStream::connect(file).await?;
    stream.write_all(&[TXN_BEGIN]).await?;
    let mut t = [0u8];
    stream.read_exact(&mut t).await?;
    if t[0] == ACK {
    Ok(TxnLock { _stream: stream })
    } else {
    bail!("Pristine locked")
    }
    }
    impl MutTxnLock {
    pub async fn commit(&mut self) -> Result<(), anyhow::Error> {
    self.stream.write_all(&[COMMIT]).await?;
    Ok(())
    }
    }
  • file addition: basic_lock.rs (-xw-x--x--)
    [0.1940]
    use fs2::FileExt;
    use std::fs::OpenOptions;
    use std::path::Path;
    pub struct TxnLock {
    file: std::fs::File,
    }
    pub struct MutTxnLock {
    file: std::fs::File,
    }
    pub async fn mut_txn<P: AsRef<Path>>(file: P) -> Result<MutTxnLock, anyhow::Error> {
    let file = OpenOptions::new().write(true).create(true).open(file)?;
    file.lock_exclusive()?;
    Ok(MutTxnLock { file })
    }
    pub async fn txn<P: AsRef<Path>>(file: P) -> Result<TxnLock, anyhow::Error> {
    let file = OpenOptions::new().write(true).create(true).open(file)?;
    file.lock_shared()?;
    Ok(TxnLock { file })
    }
    impl MutTxnLock {
    pub async fn commit(&mut self) -> Result<(), anyhow::Error> {
    Ok(self.file.unlock()?)
    }
    }
    impl Drop for MutTxnLock {
    fn drop(&mut self) {
    self.file.unlock().unwrap_or(())
    }
    }
    impl Drop for TxnLock {
    fn drop(&mut self) {
    self.file.unlock().unwrap_or(())
    }
    }
  • edit in pijul/src/main.rs at line 122
    [8.85778]
    [8.25]
    #[cfg(unix)]
    Lock(Lock),
  • replacement in pijul/src/main.rs at line 187
    [8.88438][8.88438:88523]()
    SubCommand::Log(l) => l.run(),
    SubCommand::Init(init) => init.run(),
    [8.88438]
    [8.88523]
    SubCommand::Log(l) => l.run().await,
    SubCommand::Init(init) => init.run().await,
  • replacement in pijul/src/main.rs at line 191
    [8.88636][8.88636:88682]()
    SubCommand::Diff(diff) => diff.run(),
    [8.88636]
    [8.88682]
    SubCommand::Diff(diff) => diff.run().await,
  • replacement in pijul/src/main.rs at line 194
    [8.88786][8.88786:88951]()
    SubCommand::Change(change) => change.run(),
    SubCommand::Channel(channel) => channel.run(),
    SubCommand::Protocol(protocol) => protocol.run(),
    [8.88786]
    [8.88951]
    SubCommand::Change(change) => change.run().await,
    SubCommand::Channel(channel) => channel.run().await,
    SubCommand::Protocol(protocol) => protocol.run().await,
  • replacement in pijul/src/main.rs at line 198
    [8.88983][8.88983:89250]()
    SubCommand::Git(git) => git.run(),
    SubCommand::Mv(mv) => mv.run(),
    SubCommand::Ls(ls) => ls.run(),
    SubCommand::Add(add) => add.run(),
    SubCommand::Remove(remove) => remove.run(),
    SubCommand::Reset(reset) => reset.run(),
    [8.88983]
    [8.89250]
    SubCommand::Git(git) => git.run().await,
    SubCommand::Mv(mv) => mv.run().await,
    SubCommand::Ls(ls) => ls.run().await,
    SubCommand::Add(add) => add.run().await,
    SubCommand::Remove(remove) => remove.run().await,
    SubCommand::Reset(reset) => reset.run().await,
  • replacement in pijul/src/main.rs at line 205
    [8.89283][8.89283:89537]()
    SubCommand::Debug(debug) => debug.run(),
    SubCommand::Fork(fork) => fork.run(),
    SubCommand::Unrecord(unrecord) => unrecord.run(),
    SubCommand::Apply(apply) => apply.run(),
    SubCommand::Remote(remote) => remote.run(),
    [8.89283]
    [8.89537]
    SubCommand::Debug(debug) => debug.run().await,
    SubCommand::Fork(fork) => fork.run().await,
    SubCommand::Unrecord(unrecord) => unrecord.run().await,
    SubCommand::Apply(apply) => apply.run().await,
    SubCommand::Remote(remote) => remote.run().await,
  • replacement in pijul/src/main.rs at line 211
    [8.89598][8.89598:89650]()
    SubCommand::Credit(credit) => credit.run(),
    [8.89598]
    [8.600]
    SubCommand::Credit(credit) => credit.run().await,
    #[cfg(unix)]
    SubCommand::Lock(lock) => lock.run().await,
  • replacement in pijul/src/commands/unrecord.rs at line 35
    [8.96125][8.96125:96177](),[8.96177][8.250:313]()
    pub fn run(self) -> Result<(), anyhow::Error> {
    let mut repo = Repository::find_root(self.repo_path)?;
    [8.96125]
    [8.96236]
    pub async fn run(self) -> Result<(), anyhow::Error> {
    let mut repo = Repository::find_root(self.repo_path).await?;
  • edit in pijul/src/commands/unrecord.rs at line 137
    [8.97615]
    [8.97615]
    repo.lock.commit().await?;
  • replacement in pijul/src/commands/reset.rs at line 29
    [8.98112][8.98112:98164](),[8.98164][8.447:472]()
    pub fn run(self) -> Result<(), anyhow::Error> {
    self.reset(true)
    [8.98112]
    [8.472]
    pub async fn run(self) -> Result<(), anyhow::Error> {
    self.reset(true).await
  • replacement in pijul/src/commands/reset.rs at line 33
    [8.479][8.479:560]()
    pub fn switch(self) -> Result<(), anyhow::Error> {
    self.reset(false)
    [8.479]
    [8.560]
    pub async fn switch(self) -> Result<(), anyhow::Error> {
    self.reset(false).await
  • replacement in pijul/src/commands/reset.rs at line 37
    [8.567][8.567:642]()
    fn reset(self, overwrite_changes: bool) -> Result<(), anyhow::Error> {
    [8.567]
    [8.98164]
    async fn reset(self, overwrite_changes: bool) -> Result<(), anyhow::Error> {
  • replacement in pijul/src/commands/reset.rs at line 39
    [8.98218][8.98218:98281]()
    let mut repo = Repository::find_root(self.repo_path)?;
    [8.98218]
    [8.98281]
    let mut repo = Repository::find_root(self.repo_path).await?;
  • edit in pijul/src/commands/reset.rs at line 109
    [67.773]
    [67.773]
    repo.lock.commit().await?;
  • edit in pijul/src/commands/reset.rs at line 166
    [68.6587]
    [68.6587]
    repo.lock.commit().await?;
  • replacement in pijul/src/commands/record.rs at line 59
    [8.102832][8.102832:102903]()
    let mut repo = Repository::find_root(self.repo_path.clone())?;
    [8.102832]
    [8.102903]
    let mut repo = Repository::find_root(self.repo_path.clone()).await?;
  • edit in pijul/src/commands/record.rs at line 156
    [8.105279]
    [8.105279]
    repo.lock.commit().await?;
  • edit in pijul/src/commands/record.rs at line 162
    [69.301]
    [5.57]
    repo.lock.commit().await?;
  • replacement in pijul/src/commands/pushpull.rs at line 33
    [8.112203][8.112203:112314]()
    pub fn run(self) -> Result<(), anyhow::Error> {
    let repo = Repository::find_root(self.repo_path)?;
    [8.112203]
    [8.112314]
    pub async fn run(self) -> Result<(), anyhow::Error> {
    let mut repo = Repository::find_root(self.repo_path).await?;
  • edit in pijul/src/commands/pushpull.rs at line 51
    [8.112970]
    [8.112970]
    repo.lock.commit().await?;
  • replacement in pijul/src/commands/pushpull.rs at line 123
    [8.1981][8.153:212](),[8.114511][8.153:212]()
    let repo = Repository::find_root(self.repo_path)?;
    [8.1981]
    [8.114570]
    let mut repo = Repository::find_root(self.repo_path).await?;
  • edit in pijul/src/commands/pushpull.rs at line 268
    [8.117458]
    [8.117458]
    repo.lock.commit().await?;
  • replacement in pijul/src/commands/pushpull.rs at line 277
    [8.117585][8.117585:117648]()
    let mut repo = Repository::find_root(self.repo_path)?;
    [8.117585]
    [8.117648]
    let mut repo = Repository::find_root(self.repo_path).await?;
  • edit in pijul/src/commands/pushpull.rs at line 476
    [8.121124]
    [8.121124]
    repo.lock.commit().await?;
  • replacement in pijul/src/commands/protocol.rs at line 49
    [8.124762][8.124762:124877]()
    pub fn run(self) -> Result<(), anyhow::Error> {
    let mut repo = Repository::find_root(self.repo_path)?;
    [8.124762]
    [8.124877]
    pub async fn run(self) -> Result<(), anyhow::Error> {
    let mut repo = Repository::find_root(self.repo_path).await?;
  • edit in pijul/src/commands/protocol.rs at line 250
    [8.133576]
    [8.133576]
    repo.lock.commit().await?;
  • edit in pijul/src/commands/mod.rs at line 59
    [8.134333]
    [8.1576]
    #[cfg(unix)]
    mod lock;
    #[cfg(unix)]
    pub use lock::*;
  • replacement in pijul/src/commands/log.rs at line 31
    [8.134895][8.134895:135006]()
    pub fn run(self) -> Result<(), anyhow::Error> {
    let repo = Repository::find_root(self.repo_path)?;
    [8.134895]
    [8.135006]
    pub async fn run(self) -> Result<(), anyhow::Error> {
    let repo = unsafe { Repository::find_root_immutable(self.repo_path).await? };
  • file addition: lock.rs (-xw-x--x--)
    [8.93386]
    use fs2::FileExt;
    use std::fs::OpenOptions;
    use std::io::Write;
    use std::path::PathBuf;
    use std::sync::Arc;
    use tokio::io::{AsyncReadExt, AsyncWriteExt};
    use tokio::net::UnixListener;
    use tokio::sync::{watch, Mutex};
    use clap::Clap;
    #[derive(Clap, Debug)]
    pub struct Lock {
    path: PathBuf,
    }
    const COMMIT: u8 = 2;
    const ACK: u8 = 3;
    const LOCKED: u8 = 4;
    impl Lock {
    pub async fn run(self) -> Result<(), anyhow::Error> {
    let lock = Arc::new(self.path.with_extension("lock"));
    let lockfile = OpenOptions::new()
    .write(true)
    .create(true)
    .open(&lock.as_ref())
    .unwrap();
    if lockfile.try_lock_exclusive().is_err() {
    return Ok(());
    }
    let listener = UnixListener::bind(&self.path).unwrap();
    println!();
    let n_clients = Arc::new(Mutex::new(0usize));
    let file = Arc::new(self.path.clone());
    let muttxn = Arc::new(Mutex::new(()));
    let (tx, active_at_last_commit) = watch::channel(0);
    let tx = std::sync::Arc::new(tx);
    let clock = Arc::new(Mutex::new(0usize));
    let txn_counter = Arc::new(Mutex::new(0usize));
    let last_commit_date = Arc::new(Mutex::new(0usize));
    loop {
    let x = listener.accept().await;
    {
    let mut f = OpenOptions::new()
    .write(true)
    .create(true)
    .append(true)
    .open("log")
    .unwrap();
    writeln!(f, "accepted").unwrap()
    }
    match x {
    Ok((mut stream, _addr)) => {
    *n_clients.lock().await += 1;
    {
    let mut f = OpenOptions::new()
    .write(true)
    .create(true)
    .append(true)
    .open("log")
    .unwrap();
    writeln!(f, "n = {:?}", *n_clients.lock().await).unwrap();
    }
    let file = file.clone();
    let muttxn = muttxn.clone();
    let mut active_at_last_commit = active_at_last_commit.clone();
    let clock = clock.clone();
    let last_commit_date = last_commit_date.clone();
    let txn_counter = txn_counter.clone();
    let n_clients = n_clients.clone();
    let tx = tx.clone();
    let lock = lock.clone();
    tokio::spawn(async move {
    let mut t = [0u8];
    while let Ok(n) = stream.read(&mut t).await {
    if n == 0 {
    break;
    }
    if t[0] == 1 {
    // muttxn
    let lock = if let Ok(guard) = muttxn.try_lock() {
    guard
    } else {
    stream.write_all(&[LOCKED]).await.unwrap_or(());
    muttxn.lock().await
    };
    while *active_at_last_commit.borrow() > 0 {
    stream.write_all(&[LOCKED]).await.unwrap_or(());
    active_at_last_commit.changed().await.unwrap();
    }
    stream.write_all(&[ACK]).await.unwrap_or(());
    if let Ok(n) = stream.read(&mut t).await {
    if n == 0 {
    break;
    }
    if t[0] == COMMIT {
    // commit
    let mut clock = clock.lock().await;
    *clock += 1;
    *last_commit_date.lock().await = *clock;
    let counter = *txn_counter.lock().await;
    tx.send(counter).unwrap();
    }
    }
    std::mem::drop(lock);
    } else {
    // txn
    *txn_counter.lock().await += 1;
    let start_date = *clock.lock().await;
    stream.write_all(&[ACK]).await.unwrap_or(());
    let n = stream.read(&mut t).await.unwrap_or(0);
    if n == 0 {
    break;
    }
    *txn_counter.lock().await -= 1;
    if start_date < *last_commit_date.lock().await {
    let last = *active_at_last_commit.borrow();
    tx.send(last - 1).unwrap();
    }
    }
    }
    {
    let mut f = OpenOptions::new()
    .write(true)
    .create(true)
    .append(true)
    .open("log")
    .unwrap();
    writeln!(f, "n = {:?}", *n_clients.lock().await).unwrap();
    }
    if *n_clients.lock().await == 1 {
    tokio::time::sleep(std::time::Duration::from_secs(1)).await;
    if *n_clients.lock().await == 1 {
    std::fs::remove_file(file.as_ref()).unwrap_or(());
    let lockfile = OpenOptions::new()
    .write(true)
    .create(true)
    .open(lock.as_ref())
    .unwrap();
    lockfile.unlock().unwrap_or(());
    std::process::exit(0)
    }
    }
    *n_clients.lock().await -= 1
    });
    }
    Err(_) => break,
    }
    }
    std::fs::remove_file(file.as_ref()).unwrap_or(());
    let lockfile = OpenOptions::new()
    .write(true)
    .create(true)
    .open(lock.as_ref())
    .unwrap();
    lockfile.unlock().unwrap_or(());
    std::process::exit(0)
    }
    }
  • replacement in pijul/src/commands/init.rs at line 18
    [8.136770][8.136770:136875]()
    pub fn run(self) -> Result<(), anyhow::Error> {
    let mut repo = Repository::init(self.path)?;
    [8.136770]
    [8.136875]
    pub async fn run(self) -> Result<(), anyhow::Error> {
    let mut repo = Repository::init(self.path).await?;
  • edit in pijul/src/commands/init.rs at line 28
    [8.137177]
    [8.137177]
    repo.lock.commit().await?;
  • replacement in pijul/src/commands/git.rs at line 37
    [8.138045][8.138045:138182]()
    pub fn run(self) -> Result<(), anyhow::Error> {
    let repo = if let Ok(repo) = Repository::find_root(self.repo_path.clone()) {
    [8.138045]
    [8.138182]
    pub async fn run(self) -> Result<(), anyhow::Error> {
    let repo = if let Ok(repo) = Repository::find_root(self.repo_path.clone()).await {
  • replacement in pijul/src/commands/git.rs at line 41
    [8.138216][8.138216:138270]()
    Repository::init(self.repo_path.clone())?
    [8.138216]
    [8.138270]
    Repository::init(self.repo_path.clone()).await?
  • replacement in pijul/src/commands/git.rs at line 65
    [8.139131][8.139131:139185]()
    import(&git, &mut env_git, &mut repo, &dag)?;
    [8.139131]
    [8.139185]
    import(&git, &mut env_git, &mut repo, &dag).await?;
  • replacement in pijul/src/commands/git.rs at line 219
    [8.143830][8.143830:143841]()
    fn import(
    [8.143830]
    [8.143841]
    async fn import(
  • edit in pijul/src/commands/git.rs at line 312
    [8.147539]
    [8.147539]
    repo.repo.lock.commit().await?;
  • replacement in pijul/src/commands/fork.rs at line 25
    [8.168309][8.168309:168420]()
    pub fn run(self) -> Result<(), anyhow::Error> {
    let repo = Repository::find_root(self.repo_path)?;
    [8.168309]
    [8.168420]
    pub async fn run(self) -> Result<(), anyhow::Error> {
    let mut repo = Repository::find_root(self.repo_path).await?;
  • edit in pijul/src/commands/fork.rs at line 40
    [8.169013]
    [8.169013]
    repo.lock.commit().await?;
  • replacement in pijul/src/commands/file_operations.rs at line 24
    [8.169351][8.169351:169474]()
    pub fn run(mut self) -> Result<(), anyhow::Error> {
    let repo = Repository::find_root(self.repo_path.clone())?;
    [8.169351]
    [8.169474]
    pub async fn run(mut self) -> Result<(), anyhow::Error> {
    let mut repo = Repository::find_root(self.repo_path.clone()).await?;
  • edit in pijul/src/commands/file_operations.rs at line 57
    [8.170571]
    [8.170571]
    repo.lock.commit().await?;
  • replacement in pijul/src/commands/file_operations.rs at line 78
    [8.170860][8.170860:170912](),[8.170912][8.394:453]()
    pub fn run(self) -> Result<(), anyhow::Error> {
    let repo = Repository::find_root(self.repo_path)?;
    [8.170860]
    [8.170979]
    pub async fn run(self) -> Result<(), anyhow::Error> {
    let repo = unsafe { Repository::find_root_immutable(self.repo_path).await? };
  • replacement in pijul/src/commands/file_operations.rs at line 104
    [8.171335][8.171335:171454]()
    pub fn run(self) -> Result<(), anyhow::Error> {
    let repo = Repository::find_root(self.repo_path.clone())?;
    [8.171335]
    [8.171454]
    pub async fn run(self) -> Result<(), anyhow::Error> {
    let mut repo = Repository::find_root(self.repo_path.clone()).await?;
  • edit in pijul/src/commands/file_operations.rs at line 151
    [8.172439]
    [8.172439]
    repo.lock.commit().await?;
  • replacement in pijul/src/commands/file_operations.rs at line 166
    [8.172614][8.172614:172733]()
    pub fn run(self) -> Result<(), anyhow::Error> {
    let repo = Repository::find_root(self.repo_path.clone())?;
    [8.172614]
    [8.172733]
    pub async fn run(self) -> Result<(), anyhow::Error> {
    let mut repo = Repository::find_root(self.repo_path.clone()).await?;
  • edit in pijul/src/commands/file_operations.rs at line 193
    [8.173517]
    [8.173517]
    repo.lock.commit().await?;
  • replacement in pijul/src/commands/diff.rs at line 35
    [8.174051][8.174051:174178]()
    pub fn run(mut self) -> Result<(), anyhow::Error> {
    let mut repo = Repository::find_root(self.repo_path.clone())?;
    [8.174051]
    [8.174178]
    pub async fn run(mut self) -> Result<(), anyhow::Error> {
    let mut repo = Repository::find_root(self.repo_path.clone()).await?;
  • replacement in pijul/src/commands/debug.rs at line 18
    [8.178019][8.178019:178130]()
    pub fn run(self) -> Result<(), anyhow::Error> {
    let repo = Repository::find_root(self.repo_path)?;
    [8.178019]
    [8.178130]
    pub async fn run(self) -> Result<(), anyhow::Error> {
    let repo = Repository::find_root(self.repo_path).await?;
  • replacement in pijul/src/commands/credit.rs at line 26
    [8.179133][8.179133:179185]()
    pub fn run(self) -> Result<(), anyhow::Error> {
    [8.179133]
    [8.179185]
    pub async fn run(self) -> Result<(), anyhow::Error> {
  • replacement in pijul/src/commands/credit.rs at line 28
    [8.179239][8.179239:179302]()
    let mut repo = Repository::find_root(self.repo_path)?;
    [8.179239]
    [8.179302]
    let mut repo = unsafe { Repository::find_root_immutable(self.repo_path).await? };
  • replacement in pijul/src/commands/clone.rs at line 68
    [8.167][4.221:275]()
    let mut repo = Repository::init(Some(path))?;
    [8.167]
    [8.184784]
    let mut repo = Repository::init(Some(path)).await?;
  • edit in pijul/src/commands/clone.rs at line 108
    [8.185801]
    [70.2373]
    repo.lock.commit().await?;
  • replacement in pijul/src/commands/channel.rs at line 35
    [8.187383][8.187383:187435]()
    pub fn run(self) -> Result<(), anyhow::Error> {
    [8.187383]
    [8.187494]
    pub async fn run(self) -> Result<(), anyhow::Error> {
  • replacement in pijul/src/commands/channel.rs at line 39
    [8.187735][8.1000:1067]()
    let repo = Repository::find_root(self.repo_path)?;
    [8.187735]
    [8.1067]
    let repo = Repository::find_root(self.repo_path).await?;
  • replacement in pijul/src/commands/channel.rs at line 54
    [8.188244][8.1129:1196]()
    let repo = Repository::find_root(self.repo_path)?;
    [8.188244]
    [8.1196]
    let mut repo = Repository::find_root(self.repo_path).await?;
  • edit in pijul/src/commands/channel.rs at line 64
    [8.188379]
    [8.188379]
    repo.lock.commit().await?;
  • replacement in pijul/src/commands/channel.rs at line 73
    [8.6398][8.6398:6426]()
    .switch()?;
    [8.6398]
    [8.1727]
    .switch()
    .await?;
  • replacement in pijul/src/commands/channel.rs at line 77
    [8.188456][8.1742:1809]()
    let repo = Repository::find_root(self.repo_path)?;
    [8.188456]
    [8.1809]
    let mut repo = Repository::find_root(self.repo_path).await?;
  • edit in pijul/src/commands/channel.rs at line 94
    [8.189246]
    [8.189246]
    repo.lock.commit().await?;
  • replacement in pijul/src/commands/change.rs at line 21
    [8.189681][8.189681:189800]()
    pub fn run(self) -> Result<(), anyhow::Error> {
    let repo = Repository::find_root(self.repo_path.clone())?;
    [8.189681]
    [8.189800]
    pub async fn run(self) -> Result<(), anyhow::Error> {
    let repo = unsafe { Repository::find_root_immutable(self.repo_path.clone()).await? };
  • replacement in pijul/src/commands/archive.rs at line 85
    [8.8987][8.8987:9061]()
    if let Ok(repo) = Repository::find_root(self.repo_path.clone()) {
    [8.8987]
    [8.192979]
    if let Ok(repo) = Repository::find_root(self.repo_path.clone()).await {
  • replacement in pijul/src/commands/apply.rs at line 27
    [8.194761][8.194761:194876]()
    pub fn run(self) -> Result<(), anyhow::Error> {
    let mut repo = Repository::find_root(self.repo_path)?;
    [8.194761]
    [8.194876]
    pub async fn run(self) -> Result<(), anyhow::Error> {
    let mut repo = Repository::find_root(self.repo_path).await?;
  • edit in pijul/src/commands/apply.rs at line 91
    [8.196337]
    [8.196337]
    repo.lock.commit().await?;
  • replacement in pijul/Cargo.toml at line 4
    [8.196462][6.0:27]()
    version = "1.0.0-alpha.32"
    [8.196462]
    [8.196488]
    version = "1.0.0-alpha.33"
  • edit in pijul/Cargo.toml at line 32
    [8.197171]
    [8.197171]
    "src/commands/lock.rs",
  • edit in pijul/Cargo.toml at line 35
    [8.197209]
    [8.197209]
    "src/repository/unix_lock.rs",
    "src/repository/basic_lock.rs",
  • replacement in pijul/Cargo.toml at line 53
    [8.197438][6.28:118]()
    libpijul = { path = "../libpijul", version = "1.0.0-alpha.29", features = [ "tarball" ] }
    [8.197438]
    [8.197523]
    libpijul = { path = "../libpijul", version = "1.0.0-alpha.30", features = [ "tarball" ] }
  • edit in pijul/Cargo.toml at line 87
    [3.2300]
    [71.309]
    fs2 = "0.4"
  • replacement in libpijul/Cargo.toml at line 4
    [8.1020894][7.0:27]()
    version = "1.0.0-alpha.29"
    [8.1020894]
    [7.27]
    version = "1.0.0-alpha.30"
  • replacement in Cargo.lock at line 519
    [8.1044908][2.465:483]()
    version = "0.3.9"
    [8.1044908]
    [8.1044926]
    version = "0.3.10"
  • replacement in Cargo.lock at line 521
    [8.1044991][2.484:562]()
    checksum = "c70be434c505aee38639abccb918163b63158a4b4bb791b45b7023044bdc3c9c"
    [8.1044991]
    [8.1045069]
    checksum = "309f13e3f4be6d5917178c84db67c0b9a09177ac16d4f9a7313a767a68adaa77"
  • replacement in Cargo.lock at line 534
    [8.1045250][2.563:581]()
    version = "0.3.9"
    [8.1045250]
    [8.1045268]
    version = "0.3.10"
  • replacement in Cargo.lock at line 536
    [8.1045333][2.582:660]()
    checksum = "f01c61843314e95f96cc9245702248733a3a3d744e43e2e755e3c7af8348a0a9"
    [8.1045333]
    [8.1045411]
    checksum = "7a3b03bd32f6ec7885edeb99acd1e47e20e34fd4dfd3c6deed6fcac8a9d28f6a"
  • replacement in Cargo.lock at line 544
    [8.1045499][2.661:679]()
    version = "0.3.9"
    [8.1045499]
    [8.1045517]
    version = "0.3.10"
  • replacement in Cargo.lock at line 546
    [8.1045582][2.680:758]()
    checksum = "db8d3b0917ff63a2a96173133c02818fac4a746b0a57569d3baca9ec0e945e08"
    [8.1045582]
    [8.1045660]
    checksum = "ed8aeae2b6ab243ebabe6f54cd4cf53054d98883d5d326128af7d57a9ca5cd3d"
  • replacement in Cargo.lock at line 550
    [8.1045699][2.759:777]()
    version = "0.3.9"
    [8.1045699]
    [8.1045717]
    version = "0.3.10"
  • replacement in Cargo.lock at line 552
    [8.1045782][2.778:856]()
    checksum = "9ee9ca2f7eb4475772cf39dd1cd06208dce2670ad38f4d9c7262b3e15f127068"
    [8.1045782]
    [8.1045860]
    checksum = "3f7836b36b7533d16fd5937311d98ba8965ab81030de8b0024c299dd5d51fb9b"
  • replacement in Cargo.lock at line 561
    [8.1045963][2.857:875]()
    version = "0.3.9"
    [8.1045963]
    [8.1045981]
    version = "0.3.10"
  • replacement in Cargo.lock at line 563
    [8.1046046][2.876:954]()
    checksum = "e37c1a51b037b80922864b8eed90692c5cd8abd4c71ce49b77146caa47f3253b"
    [8.1046046]
    [8.1046124]
    checksum = "d41234e71d5e8ca73d01563974ef6f50e516d71e18f1a2f1184742e31f5d469f"
  • replacement in Cargo.lock at line 567
    [8.1046160][2.955:973]()
    version = "0.3.9"
    [8.1046160]
    [8.1046178]
    version = "0.3.10"
  • replacement in Cargo.lock at line 569
    [8.1046243][2.974:1052]()
    checksum = "0f8719ca0e1f3c5e34f3efe4570ef2c0610ca6da85ae7990d472e9cbfba13664"
    [8.1046243]
    [8.1046321]
    checksum = "3520e0eb4e704e88d771b92d51273ee212997f0d8282f17f5d8ff1cb39104e42"
  • replacement in Cargo.lock at line 579
    [8.1046429][2.1053:1071]()
    version = "0.3.9"
    [8.1046429]
    [8.1046447]
    version = "0.3.10"
  • replacement in Cargo.lock at line 581
    [8.1046512][2.1072:1150]()
    checksum = "f6adabac1290109cfa089f79192fb6244ad2c3f1cc2281f3e1dd987592b71feb"
    [8.1046512]
    [8.1046590]
    checksum = "c72d188479368953c6c8c7140e40d7a4401674ab3b98a41e60e515d6cbdbe5de"
  • replacement in Cargo.lock at line 585
    [8.1046625][2.1151:1169]()
    version = "0.3.9"
    [8.1046625]
    [8.1046643]
    version = "0.3.10"
  • replacement in Cargo.lock at line 587
    [8.1046708][2.1170:1248]()
    checksum = "a92a0843a2ff66823a8f7c77bffe9a09be2b64e533562c412d63075643ec0038"
    [8.1046708]
    [8.1046786]
    checksum = "08944cea9021170d383287169859c0ca8147d9ec285978393109954448f33cc7"
  • replacement in Cargo.lock at line 594
    [8.1046854][2.1249:1267]()
    version = "0.3.9"
    [8.1046854]
    [8.1046872]
    version = "0.3.10"
  • replacement in Cargo.lock at line 596
    [8.1046937][2.1268:1346]()
    checksum = "036a2107cdeb57f6d7322f1b6c363dad67cd63ca3b7d1b925bdf75bd5d96cda9"
    [8.1046937]
    [8.1047015]
    checksum = "d3dd206efbe2ca683b2ce138ccdf61e1b0a63f5816dcedc9d8654c500ba0cea6"
  • replacement in Cargo.lock at line 778
    [8.1051116][8.1051116:1051134]()
    version = "2.0.1"
    [8.1050888]
    [8.1051134]
    version = "2.1.0"
  • replacement in Cargo.lock at line 780
    [8.1051199][8.1051199:1051277]()
    checksum = "3c1ad908cc71012b7bea4d0c53ba96a8cba9962f048fa68d143376143d863b7a"
    [8.1051199]
    [8.1051277]
    checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
  • replacement in Cargo.lock at line 937
    [8.560][6.2003:2030]()
    version = "1.0.0-alpha.29"
    [8.560]
    [8.729]
    version = "1.0.0-alpha.30"
  • replacement in Cargo.lock at line 1288
    [8.1064071][6.2031:2058]()
    version = "1.0.0-alpha.32"
    [8.1064071]
    [8.1064097]
    version = "1.0.0-alpha.33"
  • edit in Cargo.lock at line 1301
    [8.5827]
    [8.1064248]
    "fs2",
  • replacement in Cargo.lock at line 1437
    [8.1067251][8.1067251:1067269]()
    version = "0.1.6"
    [8.1067251]
    [8.1067269]
    version = "0.1.7"
  • replacement in Cargo.lock at line 1439
    [8.1067334][8.1067334:1067412]()
    checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a"
    [8.1067334]
    [8.1067412]
    checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"