repro-env 0.4.4

Dependency lockfiles for reproducible build environments 📦🔒
Documentation
use crate::errors::*;
use crate::pkgs::Pkg;
use crate::utils;
use flate2::read::GzDecoder;
use std::io::{BufRead, BufReader, Read};

pub fn parse_pkginfo<R: Read>(reader: R) -> Result<Pkg> {
    let reader = BufReader::new(reader);
    let mut name = None;
    let mut version = None;

    for line in reader.lines() {
        let line = line?;

        if let Some(value) = line.strip_prefix("pkgname = ") {
            name = Some(value.to_string());
        } else if let Some(value) = line.strip_prefix("pkgver = ") {
            version = Some(value.to_string());
        }
    }

    Ok(Pkg {
        name: name.context("Could not find pkgname in .PKGINFO")?,
        version: version.context("Could not find pkgver in .PKGINFO")?,
    })
}

pub fn parse<R: Read>(reader: R) -> Result<Pkg> {
    let mut r = BufReader::new(reader);
    utils::read_gzip_to_end(&mut r).context("Failed to strip signature")?;

    let gz = GzDecoder::new(r);
    let mut tar = tar::Archive::new(gz);

    for entry in tar.entries()? {
        let entry = entry?;
        let path = entry.path()?;
        if path.to_str() == Some(".PKGINFO") {
            return parse_pkginfo(entry);
        }
    }
    bail!("Failed to find .PKGINFO in package file")
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_parse_pkginfo() -> Result<()> {
        let data = br#"# Generated by abuild 3.11.1-r0
# using fakeroot version 1.31
# Thu Jul 20 10:08:19 UTC 2023
pkgname = mpfr4
pkgver = 4.2.0_p12-r0
pkgdesc = multiple-precision floating-point library
url = https://www.mpfr.org/
builddate = 1689847699
packager = Buildozer <alpine-devel@lists.alpinelinux.org>
size = 684032
arch = x86_64
origin = mpfr4
commit = 8910287059187d6e83a13dd2078a2a42ea2121f4
maintainer = Natanael Copa <ncopa@alpinelinux.org>
license = LGPL-3.0-or-later
replaces = mpfr
provides = mpfr=4.2.0_p12-r0
# automatically detected:
provides = so:libmpfr.so.6=6.2.0
depend = so:libc.musl-x86_64.so.1
depend = so:libgmp.so.10
datahash = a2c44c6b313ca65980d7f610026a71e6119d119de6cf2b78e52464d9d80bff45
"#;
        let pkg = parse_pkginfo(&data[..])?;
        assert_eq!(
            pkg,
            Pkg {
                name: "mpfr4".to_string(),
                version: "4.2.0_p12-r0".to_string(),
            }
        );
        Ok(())
    }

    #[test]
    fn test_parse_pkg() -> Result<()> {
        let pkg = parse(crate::test_data::ALPINE_APK_EXAMPLE)?;
        assert_eq!(
            pkg,
            Pkg {
                name: "alpine-base".to_string(),
                version: "3.18.3-r0".to_string(),
            }
        );
        Ok(())
    }
}