pijul nest
guest [sign in]

Handle cyclic Ubuntu dependencies

pmeunier
Jun 13, 2025, 8:36 PM
BDEVQIAUBDZLH5NNXJ3HD3WK2ART4V6K2FLHMAQVAQYNXGL4TOIQC

Dependencies

  • [2] PLQ2WBZ3 Do not err when two recipes give the same output
  • [3] APRNC3CW Looking up alternatives: fixing a bug
  • [4] 6MGFBMON Debug and cleanup
  • [5] SI454P2V Documentation and cleanup
  • [6] KOWYPLMX Nix and config.toml
  • [7] HX4TXY2D Fixed-output derivations enable the network
  • [8] UWQB743K First working shell (with ocaml code)
  • [9] ODUDDQRY Adding the OCaml interface

Change contents

  • edit in src/main.rs at line 162
    [5.3392]
    [5.3392]
  • edit in src/extract.rs at line 23
    [5.17671]
    [5.3241]
    #[derive(Debug)]
    struct Vertex<'a> {
    pkg: deb::Stanza<'a>,
    downloaded: Downloaded,
    index: Option<usize>,
    lowlink: usize,
    on_stack: bool,
    scc: usize,
    deps: Vec<usize>,
    context_path: Option<Arc<PathBuf>>,
    final_path: Option<Arc<PathBuf>>,
    deps_paths: Vec<Arc<PathBuf>>,
    transitive_deps: Vec<Arc<PathBuf>>,
    transitive_deps_h: BTreeSet<Arc<PathBuf>>,
    ld_path: Vec<Arc<PathBuf>>,
    ld_path_h: BTreeSet<Arc<PathBuf>>,
    files: BTreeSet<Arc<String>>,
    }
  • edit in src/extract.rs at line 49
    [5.17725][5.19979:20068](),[5.19979][5.19979:20068]()
    let files = Arc::new(Mutex::new(HashMap::new()));
    let mut seen = HashMap::new();
  • replacement in src/extract.rs at line 50
    [5.17786][5.20122:20224](),[5.20122][5.20122:20224](),[5.20224][5.17787:17868](),[5.17868][5.20257:20322](),[5.20257][5.20257:20322](),[5.20322][5.17869:17901](),[5.17901][5.20322:20330](),[5.20322][5.20322:20330]()
    let mut stack = vec![StackElt {
    package: pkg,
    rx: None,
    deps: Vec::new(),
    transitive_deps: Vec::new(),
    transitive_deps_h: BTreeSet::new(),
    ld_path: Vec::new(),
    ld_path_h: BTreeSet::new(),
    files: BTreeSet::new(),
    }];
    [5.17786]
    [5.20396]
    let mut seen: HashMap<_, (Vec<&str>, usize)> = HashMap::new();
    let mut stack = vec![(pkg, None)];
    let mut vertices = Vec::new();
    while let Some((pkg, rx)) = stack.pop() {
    info!("{:?}", pkg);
    if let Some(rx) = rx {
    let downloaded: Result<Result<Downloaded, Error>, _> = rx.await;
    let downloaded = downloaded.unwrap()?;
    seen.get_mut(pkg.package).unwrap().1 = vertices.len();
    vertices.push(Vertex {
    downloaded,
    deps: seen
    .get(pkg.package)
    .unwrap()
    .0
    .iter()
    .map(|x| seen.get(x).unwrap().1)
    .collect(),
    pkg,
    context_path: None,
    deps_paths: Vec::new(),
    files: BTreeSet::new(),
    final_path: None,
    ld_path: Vec::new(),
    ld_path_h: BTreeSet::new(),
    index: None,
    lowlink: 0,
    on_stack: false,
    scc: 0,
    transitive_deps: Vec::new(),
    transitive_deps_h: BTreeSet::new(),
    });
    } else if !seen.contains_key(pkg.package) {
    let rx = spawn_extract(client.clone(), &pkg).await;
    let depends = pkg.depends.clone();
    let pkg_package = pkg.package;
    stack.push((pkg, Some(rx)));
    let deps = push_deps(&depends, index, &mut stack).await;
    seen.insert(pkg_package, (deps, 0));
    }
    }
    let sccs = tarjan(&mut vertices);
    debug!("sccs: {:?}", sccs);
  • replacement in src/extract.rs at line 97
    [5.20429][5.17902:17939](),[5.17939][5.20429:20501](),[5.20429][5.20429:20501]()
    let mut paths = BTreeSet::new();
    while let Some(mut elt) = stack.pop() {
    info!("{:?}", elt);
    [5.20429]
    [5.20501]
    let files = Arc::new(Mutex::new(HashMap::new()));
  • replacement in src/extract.rs at line 99
    [5.20502][5.20502:20544](),[5.20544][5.17940:17989](),[5.17989][5.20592:20643](),[5.20592][5.20592:20643](),[5.20643][5.17990:18102](),[5.18102][5.20721:20746](),[5.20721][5.20721:20746](),[5.20746][5.18103:18275](),[5.18275][5.20817:20834](),[5.20817][5.20817:20834](),[5.20834][5.18276:18441](),[5.18441][5.20910:21215](),[5.20910][5.20910:21215](),[5.21215][5.18442:18563](),[5.18563][5.3344:3540](),[5.3540][5.18665:18733](),[5.18665][5.18665:18733](),[5.18733][5.21371:21419](),[5.21371][5.21371:21419](),[5.21419][5.18734:18790]()
    if let Some(rx) = elt.rx.take() {
    let downloaded = rx.await.unwrap()?;
    info!("downloaded {:?}", elt.package);
    let final_path = elt
    .finalize(client, &files, downloaded, &mut stack, &mut result)
    .await?;
    seen.insert(
    elt.package.package,
    (elt.ld_path, elt.transitive_deps, final_path),
    );
    paths = elt.files;
    } else {
    if let Some((ld_path, transitive_deps, final_path)) = seen.get(&elt.package.package) {
    debug!("already seen {:?}", elt.package.package);
    if let Some(last) = stack.iter_mut().rev().filter(|x| x.rx.is_some()).next() {
    for ld in ld_path {
    if last.ld_path_h.insert(ld.clone()) {
    last.ld_path.push(ld.clone());
    }
    }
    for dep in transitive_deps {
    if last.transitive_deps_h.insert(dep.clone()) {
    debug!(
    "adding transitive dep: {:?} -> {:?}",
    last.package.package, dep
    );
    last.transitive_deps.push(dep.clone());
    }
    }
    last.deps.push(final_path.clone());
    [5.20502]
    [5.21419]
    for scc in sccs.iter() {
    for v in scc.iter() {
    let mut context_hasher = blake3::Hasher::new();
    context_hasher.update(vertices[*v].pkg.sha256.unwrap().as_bytes());
    for d in vertices[*v].deps.iter() {
    let w = &vertices[*d];
    if w.scc == vertices[*v].scc {
    // If in the same SCC, we can't know anything other than the SHA256.
    context_hasher.update(w.pkg.sha256.unwrap().as_bytes());
    } else {
    context_hasher
    .update(w.final_path.as_ref().unwrap().to_str().unwrap().as_bytes());
  • edit in src/extract.rs at line 112
    [5.21437][5.21437:21463](),[5.21653][5.21653:21674](),[5.21674][5.18791:18952]()
    continue;
    } else {
    seen.insert(
    elt.package.package,
    (Vec::new(), Vec::new(), Arc::new(PathBuf::new())),
    );
  • edit in src/extract.rs at line 113
    [5.21719]
    [5.21719]
    vertices[*v].context_path =
    Some(Arc::new(client.store_path.join(
    data_encoding::HEXLOWER.encode(context_hasher.finalize().as_bytes()),
    )));
    }
  • replacement in src/extract.rs at line 119
    [5.21720][5.3541:3594](),[5.3594][5.19023:19075](),[5.19023][5.19023:19075]()
    elt.spawn_extract(client.clone()).await;
    elt.push_deps(index, &mut stack).await;
    [5.21720]
    [5.19075]
    for v in scc.iter() {
    let f = finalize(&mut vertices, client, &files, *v).await?;
    vertices[*v].final_path = Some(f.clone());
    result.push(f)
  • edit in src/extract.rs at line 125
    [5.19091]
    [5.19091]
  • replacement in src/extract.rs at line 128
    [5.19125][5.19125:19169]()
    paths: paths.into_iter().collect(),
    [5.19125]
    [5.19169]
    paths: vertices.last().unwrap().files.iter().cloned().collect(),
  • edit in src/extract.rs at line 130
    [5.19176]
    [5.19176]
    }
    fn tarjan(vertices: &mut [Vertex]) -> Vec<Vec<usize>> {
    let mut sccs = Vec::new();
    let mut stack = Vec::new();
    let mut index = 0;
    struct C {
    vi: usize,
    wj: usize,
    }
    let mut call_stack = vec![C {
    vi: vertices.len() - 1,
    wj: 0,
    }];
    'outer: while let Some(mut c) = call_stack.pop() {
    if vertices[c.vi].index.is_none() {
    let ref mut v = vertices[c.vi];
    v.index = Some(index);
    v.lowlink = index;
    v.on_stack = true;
    index += 1;
    stack.push(c.vi);
    }
    while c.wj < vertices[c.vi].deps.len() {
    let wi = vertices[c.vi].deps[c.wj];
    if let Some(index) = vertices[wi].index {
    if vertices[wi].on_stack {
    vertices[c.vi].lowlink = vertices[c.vi].lowlink.min(index)
    }
    c.wj += 1;
    } else {
    c.wj += 1;
    call_stack.push(c);
    call_stack.push(C { vi: wi, wj: 0 });
    continue 'outer;
    }
    }
    if Some(vertices[c.vi].lowlink) == vertices[c.vi].index {
    let mut scc = Vec::new();
    while let Some(p) = stack.pop() {
    vertices[p].scc = sccs.len();
    vertices[p].on_stack = false;
    scc.push(p);
    if p == c.vi {
    break;
    }
    }
    sccs.push(scc)
    }
    }
    sccs
  • replacement in src/extract.rs at line 224
    [5.20002][5.24347:24426](),[5.24347][5.24347:24426](),[5.24426][5.20003:20291]()
    let mut f = std::io::BufReader::new(std::fs::File::open(&download.path)?);
    let d = match deb::Deb::read(&mut f) {
    Ok(d) => d,
    Err(e) => {
    std::fs::remove_file(&download.path).unwrap_or(());
    return Err(e.into());
    }
    };
    std::fs::create_dir_all(&path).unwrap_or(());
    match d.decompress(&mut f, &path) {
    [5.20002]
    [5.20291]
    let p = path.clone();
    let dp = download.path.clone();
    match tokio::task::spawn_blocking(move || {
    let mut f = std::io::BufReader::new(std::fs::File::open(&dp)?);
    let d = match deb::Deb::read(&mut f) {
    Ok(d) => d,
    Err(e) => {
    std::fs::remove_file(&dp).unwrap_or(());
    return Err(e.into());
    }
    };
    std::fs::create_dir_all(&p).unwrap_or(());
    d.decompress(&mut f, &p)
    })
    .await
    .unwrap()
    {
  • edit in src/extract.rs at line 243
    [5.20311][5.20311:20345]()
    download.path = path;
  • replacement in src/extract.rs at line 244
    [5.20369][5.20369:20388]()
    Ok(())
    [5.20369]
    [5.24949]
    download.path = path;
    Ok::<(), Error>(())
  • edit in src/extract.rs at line 254
    [5.20597]
    [5.24979]
    }
    async fn spawn_extract<'a>(
    client: Client,
    stanza: &deb::Stanza<'a>,
    ) -> tokio::sync::oneshot::Receiver<Result<Downloaded, Error>> {
    let url = client.url(stanza.file_name.as_deref());
    let sha256 = stanza.sha256.unwrap().to_string();
    let (tx, rx) = tokio::sync::oneshot::channel();
    tokio::spawn(async move {
    let permit = client.download_sem.clone().acquire_owned().await.unwrap();
    info!("downloading {:?}", url);
    let (mut task, _) = match client.download_url(&url, &sha256).await {
    Ok(x) => x,
    Err(e) => {
    tx.send(Err(e)).unwrap_or(());
    return Ok(());
    }
    };
    let is_extracted = std::fs::metadata(&task.path.with_extension("")).is_ok();
    info!("finished downloading {:?}", url);
    if !is_extracted {
    // Sets extension
    if let Err(e) = extract_task(&client, &mut task).await {
    info!("finished extracting {:?} {:?}", url, e);
    tx.send(Err(e)).unwrap_or(());
    } else {
    info!("finished extracting {:?}, Ok", url);
    tx.send(Ok(task)).unwrap_or(());
    }
    info!("sent {:?}", url);
    } else {
    task.path.set_extension("");
    tx.send(Ok(task)).unwrap_or(());
    }
    drop(permit);
    Ok::<_, Error>(())
    });
    rx
  • replacement in src/extract.rs at line 312
    [5.25315][5.20960:20984]()
    impl<'a> StackElt<'a> {
    [5.25315]
    [5.20984]
    impl<'a> Vertex<'a> {
  • replacement in src/extract.rs at line 321
    [5.25476][5.21427:21467]()
    for d in self.deps.iter() {
    [5.25476]
    [5.21467]
    for d in self.deps_paths.iter() {
  • replacement in src/extract.rs at line 347
    [5.26315][5.26315:26433]()
    fn add_ld_paths(&mut self, path: &Path) -> Result<(), std::io::Error> {
    let mut ld_so = path.join("etc");
    [5.26291]
    [5.26433]
    fn add_ld_paths(&mut self) -> Result<(), std::io::Error> {
    let mut ld_so = self.downloaded.path.join("etc");
  • replacement in src/extract.rs at line 380
    [5.23104][5.27145:27201](),[5.27145][5.27145:27201]()
    fn find_libs(&mut self, path: &Path, dest: &Path) {
    [5.23104]
    [5.27201]
    fn find_libs(&mut self) {
  • replacement in src/extract.rs at line 382
    [5.27241][5.27241:27306]()
    let path = path.join(ld.strip_prefix("/").unwrap());
    [5.27241]
    [5.27306]
    let path = self.downloaded.path.join(ld.strip_prefix("/").unwrap());
  • replacement in src/extract.rs at line 385
    [5.27399][5.27399:27478]()
    let path = Arc::new(dest.join(ld.strip_prefix("/").unwrap()));
    [5.27399]
    [5.23105]
    let path = Arc::new(
    self.context_path
    .as_ref()
    .unwrap()
    .join(ld.strip_prefix("/").unwrap()),
    );
  • replacement in src/extract.rs at line 472
    [5.30057][5.23810:23865]()
    for dep in self.transitive_deps.iter().rev() {
    [5.30057]
    [5.23865]
    for dep in self
    .deps_paths
    .iter()
    .chain(self.transitive_deps.iter().rev())
    {
  • edit in src/extract.rs at line 505
    [5.30632]
    [5.30632]
    }
  • replacement in src/extract.rs at line 507
    [5.30633][5.30633:30794](),[5.30794][5.24275:24354](),[5.24354][5.30858:30986](),[5.30858][5.30858:30986](),[5.30986][5.24355:24381](),[5.24381][5.30986:31089](),[5.30986][5.30986:31089]()
    async fn finalize(
    &mut self,
    client: &Client,
    files: &Files,
    downloaded: Downloaded,
    stack: &mut Vec<StackElt<'a>>,
    result: &mut Vec<Arc<PathBuf>>,
    ) -> Result<Arc<PathBuf>, Error> {
    let mut context_hasher = blake3::Hasher::new();
    context_hasher.update(self.package.sha256.unwrap().as_bytes());
    self.deps.sort();
    for d in self.deps.iter() {
    context_hasher.update(d.to_str().unwrap().as_bytes());
    [5.30633]
    [5.31089]
    async fn finalize<'a>(
    vertices: &mut [Vertex<'a>],
    client: &Client,
    files: &Files,
    v: usize,
    ) -> Result<Arc<PathBuf>, Error> {
    debug!(
    "finalize {:?} {:#?}",
    vertices[v].pkg.package, vertices[v].transitive_deps
    );
    let mut ld_path = std::mem::replace(&mut vertices[v].ld_path, Vec::new());
    let mut ld_path_h = std::mem::replace(&mut vertices[v].ld_path_h, BTreeSet::new());
    let mut transitive_deps = std::mem::replace(&mut vertices[v].transitive_deps, Vec::new());
    let mut transitive_deps_h =
    std::mem::replace(&mut vertices[v].transitive_deps_h, BTreeSet::new());
    let mut deps_paths = Vec::new();
    for dep in vertices[v].deps.clone().iter() {
    for ld in vertices[*dep].ld_path.iter() {
    if ld_path_h.insert(ld.clone()) {
    ld_path.push(ld.clone());
    }
  • replacement in src/extract.rs at line 530
    [5.31099][5.24382:24499](),[5.24499][5.31099:31238](),[5.31099][5.31099:31238]()
    debug!(
    "finalize {:?} {:#?}",
    self.package.package, self.transitive_deps
    );
    let dest = client
    .store_path
    .join(data_encoding::HEXLOWER.encode(context_hasher.finalize().as_bytes()));
    [5.31099]
    [5.24500]
    for d in vertices[*dep].transitive_deps.iter() {
    if transitive_deps_h.insert(d.clone()) {
    debug!(
    "adding transitive dep: {:?} -> {:?}",
    vertices[v].pkg.package, dep
    );
    transitive_deps.push(d.clone());
    }
    }
    deps_paths.push(if vertices[*dep].scc == vertices[v].scc {
    vertices[*dep].context_path.clone().unwrap()
    } else {
    vertices[*dep].final_path.clone().unwrap()
    })
    }
    vertices[v].ld_path = ld_path;
    vertices[v].ld_path_h = ld_path_h;
    vertices[v].transitive_deps = transitive_deps;
    vertices[v].transitive_deps_h = transitive_deps_h;
    vertices[v].deps_paths = deps_paths;
  • replacement in src/extract.rs at line 551
    [5.24501][5.24501:24557]()
    let lock = client.lock_store_path(&dest).await;
    [5.24501]
    [5.31238]
    let dest = vertices[v].context_path.clone().unwrap();
  • replacement in src/extract.rs at line 553
    [5.31239][5.31239:31341]()
    // Find the extra ld paths to look for.
    self.add_ld_paths(&downloaded.path).unwrap();
    [5.31239]
    [5.31341]
    let lock = client.lock_store_path(&*dest).await;
  • replacement in src/extract.rs at line 555
    [5.31342][5.24558:24617](),[5.24617][5.31390:31481](),[5.31390][5.31390:31481]()
    let initial_deps_len = self.transitive_deps.len();
    // Find the libs in this package.
    self.find_libs(&downloaded.path, &dest);
    [5.31342]
    [5.31481]
    // Find the extra ld paths to look for.
    vertices[v].add_ld_paths().unwrap();
  • replacement in src/extract.rs at line 558
    [5.31482][5.31482:31725]()
    let base_package_name = self.package.file_name.unwrap().split('/').last().unwrap();
    let base_package_name = Path::new(&base_package_name).with_extension("");
    let base_package_name = base_package_name.to_str().unwrap();
    [5.31482]
    [5.31725]
    let initial_deps_len = vertices[v].transitive_deps.len();
    // Find the libs in this package.
    vertices[v].find_libs();
  • replacement in src/extract.rs at line 562
    [5.31726][5.31726:31790](),[5.31790][5.24618:24992](),[5.24992][5.33466:33498](),[5.33466][5.33466:33498](),[5.34260][5.34260:34277](),[5.34277][5.24993:25046](),[5.25046][5.34318:34430](),[5.34318][5.34318:34430](),[5.34430][5.25047:25339](),[5.25339][5.34503:34561](),[5.34503][5.34503:34561]()
    let final_path = if std::fs::metadata(&dest).is_err() {
    info!("create final path for {dest:?}");
    match self
    .create_final_path(client, &files, &downloaded.path, &dest, &base_package_name)
    .await
    {
    Ok(x) => x,
    Err(e) => {
    tokio::fs::remove_dir_all(&dest).await.unwrap_or(());
    return Err(e);
    }
    }
    } else {
    info!("found, no patching: {:?}", dest);
    let mut output_hasher = blake3::Hasher::new();
    let blakesums = dest.join("blake3sums");
    let file = match tokio::fs::File::open(&blakesums).await {
    Ok(file) => file,
    Err(e) => {
    error!("Error {:?} {:?}: {:?}", blakesums, downloaded.path, e);
    return Err(e.into());
    }
    };
    hash_reader(file, &mut output_hasher).await?;
    [5.31726]
    [5.25340]
    let base_package_name = vertices[v]
    .pkg
    .file_name
    .unwrap()
    .split('/')
    .last()
    .unwrap();
    let base_package_name = Path::new(&base_package_name).with_extension("");
    let base_package_name = base_package_name.to_str().unwrap();
  • replacement in src/extract.rs at line 572
    [5.25341][5.25341:25616]()
    let r = tokio::io::BufReader::new(
    tokio::fs::File::open(&dest.join("paths")).await.unwrap(),
    );
    let mut l = r.lines();
    while let Some(l) = l.next_line().await? {
    self.files.insert(Arc::new(l));
    [5.25341]
    [5.25616]
    let final_path = if std::fs::metadata(&*dest).is_err() {
    info!("create final path for {dest:?}");
    match vertices[v]
    .create_final_path(client, &files, &dest, &base_package_name)
    .await
    {
    Ok(x) => x,
    Err(e) => {
    tokio::fs::remove_dir_all(&*dest).await.unwrap_or(());
    return Err(e);
  • edit in src/extract.rs at line 583
    [5.25630][5.25630:25631](),[5.25631][5.34561:34777](),[5.34561][5.34561:34777](),[5.34777][5.25632:25679](),[5.25679][5.34777:34778](),[5.34777][5.34777:34778](),[5.34778][5.25680:25754](),[5.25754][5.34778:34885](),[5.34778][5.34778:34885](),[5.34885][5.25755:25822](),[5.25822][5.34941:35049](),[5.34941][5.34941:35049]()
    client.store_path.join(&format!(
    "{}-{}",
    data_encoding::HEXLOWER.encode(output_hasher.finalize().as_bytes()),
    base_package_name,
    ))
    };
    let final_path = Arc::new(final_path);
    add_subst(downloaded.path.clone(), &dest, files.clone()).await?;
    // Replace prefix for all library deps we've just added,
    // in order to get a Merkle tree.
    for dep in &mut self.transitive_deps[initial_deps_len..] {
    let end = dep.strip_prefix(&dest).unwrap();
    *dep = Arc::new(final_path.join(&end));
  • replacement in src/extract.rs at line 584
    [5.35059][5.35059:35124](),[5.35124][5.25823:25887](),[5.25887][5.35187:35286](),[5.35187][5.35187:35286](),[5.35286][5.25888:25949](),[5.25949][2.0:420](),[2.420][5.35531:35549](),[5.35531][5.35531:35549](),[5.35549][2.421:445]()
    info!("symlink {:?} {:?}", downloaded.path, final_path);
    match std::os::unix::fs::symlink(&dest, &*final_path) {
    Ok(()) => (),
    Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => {
    let got = std::fs::read_link(&*final_path)?;
    debug!("Path already exists, previous value {:?}", got);
    // This situation means that we've come to the same
    // result via different build recipes.
    /*
    if dest != got {
    return Err(Error::WrongResultSymlink {
    expected: dest,
    got,
    });
    }
    */
    [5.35059]
    [5.35549]
    } else {
    info!("found, no patching: {:?}", dest);
    let mut output_hasher = blake3::Hasher::new();
    let blakesums = dest.join("blake3sums");
    let file = match tokio::fs::File::open(&blakesums).await {
    Ok(file) => file,
    Err(e) => {
    error!(
    "Error {:?} {:?}: {:?}",
    blakesums, vertices[v].downloaded.path, e
    );
    return Err(e.into());
  • replacement in src/extract.rs at line 597
    [5.35563][5.35563:35617](),[5.35617][5.25950:25991]()
    Err(e) => return Err(e.into()),
    }
    result.push(final_path.clone());
    [5.35563]
    [5.35650]
    };
    hash_reader(file, &mut output_hasher).await?;
  • replacement in src/extract.rs at line 600
    [5.35651][5.35651:35968](),[5.35968][5.25992:26109](),[5.26109][5.3618:3782](),[5.3782][5.26203:26263](),[5.26203][5.26203:26263](),[5.26263][5.36112:36130](),[5.36112][5.36112:36130](),[5.36130][5.26264:26365](),[5.26365][5.36130:36144](),[5.36130][5.36130:36144](),[5.36144][5.26366:26414]()
    // Maintenant, faire remonter les deps.
    if let Some(last) = stack.iter_mut().rev().filter(|x| x.rx.is_some()).next() {
    for ld in self.ld_path.iter() {
    if last.ld_path_h.insert(ld.clone()) {
    last.ld_path.push(ld.clone());
    }
    }
    for dep in self.transitive_deps.iter() {
    if last.transitive_deps_h.insert(dep.clone()) {
    debug!(
    "adding transitive dep: {:?} -> {:?}",
    last.package.package, dep
    );
    last.transitive_deps.push(dep.clone());
    }
    }
    for f in self.files.iter() {
    last.files.insert(f.clone());
    }
    last.deps.push(final_path.clone());
    [5.35651]
    [5.36144]
    let r =
    tokio::io::BufReader::new(tokio::fs::File::open(&dest.join("paths")).await.unwrap());
    let mut l = r.lines();
    while let Some(l) = l.next_line().await? {
    vertices[v].files.insert(Arc::new(l));
  • edit in src/extract.rs at line 606
    [5.36154][5.26415:26435](),[5.26435][5.36154:36209](),[5.36154][5.36154:36209](),[5.36209][5.26436:26459](),[5.26459][5.36224:36230](),[5.36224][5.36224:36230]()
    drop(lock);
    info!("done with {:?}", self.package.package);
    Ok(final_path)
    }
  • replacement in src/extract.rs at line 607
    [5.36233][5.3783:3839](),[5.3839][5.26539:27894](),[5.26539][5.26539:27894](),[5.27894][5.36881:36895](),[5.36881][5.36881:36895](),[5.36895][5.27895:27998]()
    async fn spawn_extract(&mut self, client: Client) {
    let client = client.clone();
    let url = client.url(self.package.file_name.as_deref());
    let sha256 = self.package.sha256.unwrap().to_string();
    let (tx, rx) = tokio::sync::oneshot::channel();
    tokio::spawn(async move {
    let permit = client.download_sem.clone().acquire_owned().await.unwrap();
    info!("downloading {:?}", url);
    let (mut task, _) = match client.download_url(&url, &sha256).await {
    Ok(x) => x,
    Err(e) => {
    tx.send(Err(e)).unwrap_or(());
    return Ok(());
    }
    };
    let is_extracted = std::fs::metadata(&task.path.with_extension("")).is_ok();
    info!("finished downloading {:?}", url);
    if !is_extracted {
    // Sets extension
    if let Err(e) = extract_task(&client, &mut task).await {
    info!("finished extracting {:?} {:?}", url, e);
    tx.send(Err(e)).unwrap_or(());
    } else {
    info!("finished extracting {:?}, Ok", url);
    tx.send(Ok(task)).unwrap_or(());
    }
    info!("sent {:?}", url);
    } else {
    task.path.set_extension("");
    tx.send(Ok(task)).unwrap_or(());
    }
    drop(permit);
    Ok::<_, Error>(())
    });
    self.rx = Some(rx);
    }
    [5.36233]
    [5.27998]
    client.store_path.join(&format!(
    "{}-{}",
    data_encoding::HEXLOWER.encode(output_hasher.finalize().as_bytes()),
    base_package_name,
    ))
    };
    let final_path = Arc::new(final_path);
  • replacement in src/extract.rs at line 615
    [5.27999][5.27999:29023](),[5.29023][3.0:49](),[3.49][5.29023:29662](),[5.29023][5.29023:29662](),[5.29662][3.50:85](),[3.85][5.29698:29724](),[5.29698][5.29698:29724](),[5.29724][5.37481:37503](),[5.37481][5.37481:37503](),[5.37503][3.86:214](),[3.214][5.37503:37521](),[5.29777][5.37503:37521](),[5.37503][5.37503:37521]()
    async fn push_deps(self, index: &'a [deb::Index], stack: &mut Vec<StackElt<'a>>) {
    let depends = self.package.depends.clone();
    stack.push(self);
    for dep in depends.iter() {
    match dep {
    deb::Dep::Simple(s) => {
    debug!("dep {:?}", s);
    let Some(dep) = multi_lookup(index, &s.name).await else {
    panic!("could not find {:?}", s.name)
    };
    stack.push(StackElt {
    package: dep,
    rx: None,
    deps: Vec::new(),
    transitive_deps: Vec::new(),
    transitive_deps_h: BTreeSet::new(),
    ld_path: Vec::new(),
    ld_path_h: BTreeSet::new(),
    files: BTreeSet::new(),
    })
    }
    deb::Dep::Alternatives { alt } => {
    debug!("alt {:?}", alt);
    let stack_len = stack.len();
    for dep in alt {
    if let Some(dep_) = multi_lookup(index, &dep.name).await {
    stack.push(StackElt {
    package: dep_,
    rx: None,
    deps: Vec::new(),
    transitive_deps: Vec::new(),
    transitive_deps_h: BTreeSet::new(),
    ld_path: Vec::new(),
    ld_path_h: BTreeSet::new(),
    files: BTreeSet::new(),
    });
    break;
    }
    }
    if stack.len() == stack_len {
    panic!("Not found: {:?}", alt);
    }
    }
    [5.27999]
    [5.29778]
    add_subst(vertices[v].downloaded.path.clone(), &dest, files.clone()).await?;
    // Replace prefix for all library deps we've just added,
    // in order to get a Merkle tree.
    for dep in &mut vertices[v].transitive_deps[initial_deps_len..] {
    let end = dep.strip_prefix(&*dest).unwrap();
    *dep = Arc::new(final_path.join(&end));
    }
    info!("symlink {:?} {:?}", vertices[v].downloaded.path, final_path);
    match std::os::unix::fs::symlink(&*dest, &*final_path) {
    Ok(()) => (),
    Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => {
    let got = std::fs::read_link(&*final_path)?;
    debug!("Path already exists, previous value {:?}", got);
    // This situation means that we've come to the same
    // result via different build recipes.
    /*
    if dest != got {
    return Err(Error::WrongResultSymlink {
    expected: dest,
    got,
    });
  • edit in src/extract.rs at line 638
    [5.29792]
    [5.29792]
    */
  • edit in src/extract.rs at line 640
    [5.29802]
    [5.29802]
    Err(e) => return Err(e.into()),
  • edit in src/extract.rs at line 642
    [5.29808]
    [5.29808]
    drop(lock);
    info!("done with {:?}", vertices[v].pkg.package);
    Ok(final_path)
    }
  • edit in src/extract.rs at line 647
    [5.29809]
    [5.29809]
    impl<'a> Vertex<'a> {
  • edit in src/extract.rs at line 652
    [5.29908][5.29908:29940]()
    downloaded_path: &Path,
  • replacement in src/extract.rs at line 663
    [5.30415][5.30415:30544]()
    debug!("create_final_path {:?}", downloaded_path);
    for (f, meta) in find_files(downloaded_path.to_path_buf())? {
    [5.30415]
    [5.30544]
    debug!("create_final_path {:?}", self.downloaded.path);
    for (f, meta) in find_files(self.downloaded.path.to_path_buf())? {
  • replacement in src/extract.rs at line 666
    [5.30579][5.30579:30644]()
    let rel = f.strip_prefix(&downloaded_path).unwrap();
    [5.30579]
    [5.30644]
    let rel = f.strip_prefix(&self.downloaded.path).unwrap();
  • replacement in src/extract.rs at line 740
    [5.33566][5.33566:33618]()
    .strip_prefix(&downloaded_path)
    [5.33566]
    [5.33618]
    .strip_prefix(&self.downloaded.path)
  • replacement in src/extract.rs at line 766
    [5.34492][5.34492:34623]()
    for (f, _) in find_dirs(downloaded_path.to_path_buf())? {
    let rel = f.strip_prefix(&downloaded_path).unwrap();
    [5.34492]
    [5.34623]
    for (f, _) in find_dirs(self.downloaded.path.to_path_buf())? {
    let rel = f.strip_prefix(&self.downloaded.path).unwrap();
  • replacement in src/extract.rs at line 780
    [5.37602][5.37602:37671](),[5.37671][5.34916:34991](),[5.34991][5.37731:37760](),[5.37731][5.37731:37760](),[5.37760][5.34992:35079](),[5.35079][5.37796:37867](),[5.37796][5.37796:37867](),[5.37867][5.35080:35114]()
    #[derive(Debug)]
    struct StackElt<'a> {
    package: deb::Stanza<'a>,
    rx: Option<tokio::sync::oneshot::Receiver<Result<Downloaded, Error>>>,
    deps: Vec<Arc<PathBuf>>,
    transitive_deps: Vec<Arc<PathBuf>>,
    transitive_deps_h: BTreeSet<Arc<PathBuf>>,
    ld_path: Vec<Arc<PathBuf>>,
    ld_path_h: BTreeSet<Arc<PathBuf>>,
    files: BTreeSet<Arc<String>>,
    [5.37602]
    [5.37867]
    async fn push_deps<'a>(
    depends: &[deb::Dep<'a>],
    index: &'a [deb::Index],
    stack: &mut Vec<(
    deb::Stanza<'a>,
    Option<tokio::sync::oneshot::Receiver<Result<Downloaded, Error>>>,
    )>,
    ) -> Vec<&'a str> {
    let mut d = Vec::new();
    for dep in depends.iter() {
    match dep {
    deb::Dep::Simple(s) => {
    debug!("dep {:?}", s);
    let Some(dep) = multi_lookup(index, &s.name).await else {
    panic!("could not find {:?}", s.name)
    };
    d.push(dep.package);
    stack.push((dep, None))
    }
    deb::Dep::Alternatives { alt } => {
    debug!("alt {:?}", alt);
    let stack_len = stack.len();
    for dep in alt {
    if let Some(dep_) = multi_lookup(index, &dep.name).await {
    d.push(dep_.package);
    stack.push((dep_, None));
    break;
    }
    }
    if stack.len() == stack_len {
    panic!("Not found: {:?}", alt);
    }
    }
    }
    }
    d
  • edit in src/container.rs at line 216
    [5.52030][5.52030:52031]()
  • replacement in src/container.rs at line 220
    [5.52217][5.52217:52348]()
    Ok(Ok(())) => std::process::exit(0),
    Ok(Err(Error::BuildReturn { status })) => std::process::exit(status),
    [5.52217]
    [5.52348]
    Ok(Ok(())) => {
    debug!("inner process ok");
    std::process::exit(0)
    }
    Ok(Err(Error::BuildReturn { status })) => {
    debug!("inner process {:?}", status);
    std::process::exit(status)
    }
  • edit in src/container.rs at line 381
    [5.57189]
    [5.57189]
    let (uid, gid) = {
    let user_ffi = CString::new(user).unwrap();
    let pw = unsafe { libc::getpwnam(user_ffi.as_ptr()) };
    assert!(!pw.is_null());
    let pw = unsafe { &*pw };
    (pw.pw_uid, pw.pw_gid)
    };
  • edit in src/container.rs at line 455
    [5.60056][5.60056:60298]()
    let (uid, gid) = {
    let user_ffi = CString::new(user).unwrap();
    let pw = unsafe { libc::getpwnam(user_ffi.as_ptr()) };
    assert!(!pw.is_null());
    let pw = unsafe { &*pw };
    (pw.pw_uid, pw.pw_gid)
    };
  • replacement in config.toml at line 3
    [5.3215][4.480:523]()
    store_path = "/home/pe/Projets/elpe/store"
    [5.3215]
    [5.3258]
    store_path = "/elpe/store"
  • edit in Cargo.lock at line 442
    [5.79647][5.79647:79662](),[5.79662][5.82191:82268]()
    ]
    [[package]]
    name = "elfedit-cli"
    version = "0.1.0"
    dependencies = [
    "clap",
    "elfedit",