Skip to content

Commit 15d25c7

Browse files
authored
Add support for sdist tar,bztar and xztar formats
1 parent f25229e commit 15d25c7

6 files changed

Lines changed: 92 additions & 29 deletions

File tree

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ repository = "https://github.com/messense/python-pkginfo-rs"
1212
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1313

1414
[dependencies]
15+
bzip2 = "0.4.2"
1516
flate2 = "1.0.20"
1617
fs-err = "2.6.0"
1718
mailparse = "0.13.4"
1819
tar = "0.4.35"
20+
xz = "0.1.0"
1921
zip = "0.5.12"

src/distribution.rs

Lines changed: 57 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
use std::io::{BufReader, Read};
22
use std::path::Path;
3+
use std::str::FromStr;
34

5+
use bzip2::read::BzDecoder;
46
use flate2::read::GzDecoder;
7+
use xz::read::XzDecoder;
58
use zip::ZipArchive;
69

710
use crate::{Error, Metadata};
@@ -20,7 +23,10 @@ pub enum DistributionType {
2023
#[derive(Debug, Clone, Copy)]
2124
enum SDistType {
2225
Zip,
23-
TarGz,
26+
Tar,
27+
GzTar,
28+
BzTar,
29+
XzTar,
2430
}
2531

2632
/// Python package distribution
@@ -30,24 +36,36 @@ pub struct Distribution {
3036
metadata: Metadata,
3137
}
3238

39+
impl FromStr for SDistType {
40+
type Err = Error;
41+
42+
fn from_str(s: &str) -> Result<Self, Self::Err> {
43+
let dist_type = match s {
44+
"zip" => SDistType::Zip,
45+
"tar" => SDistType::Tar,
46+
"gz" => SDistType::GzTar,
47+
"bz2" => SDistType::BzTar,
48+
"xz" => SDistType::XzTar,
49+
_ => return Err(Error::UnknownDistributionType),
50+
};
51+
Ok(dist_type)
52+
}
53+
}
54+
3355
impl Distribution {
3456
/// Open and parse a distribution from `path`
3557
pub fn new(path: impl AsRef<Path>) -> Result<Self, Error> {
3658
let path = path.as_ref();
3759
if let Some(ext) = path.extension().and_then(|ext| ext.to_str()) {
3860
let dist_type = match ext {
39-
"zip" | "gz" => DistributionType::SDist,
61+
"zip" | "tar" | "gz" | "bz2" | "xz" => DistributionType::SDist,
4062
"egg" => DistributionType::Egg,
4163
"whl" => DistributionType::Wheel,
4264
_ => return Err(Error::UnknownDistributionType),
4365
};
4466
let metadata = match dist_type {
4567
DistributionType::SDist => {
46-
let sdist_type = match ext {
47-
"zip" => SDistType::Zip,
48-
"gz" => SDistType::TarGz,
49-
_ => return Err(Error::UnknownDistributionType),
50-
};
68+
let sdist_type: SDistType = ext.parse()?;
5169
Self::parse_sdist(path, sdist_type)
5270
}
5371
DistributionType::Egg => Self::parse_egg(path),
@@ -74,28 +92,15 @@ impl Distribution {
7492
fn parse_sdist(path: &Path, sdist_type: SDistType) -> Result<Metadata, Error> {
7593
match sdist_type {
7694
SDistType::Zip => Self::parse_zip(path, "PKG-INFO"),
77-
SDistType::TarGz => {
78-
let mut reader =
79-
tar::Archive::new(GzDecoder::new(BufReader::new(fs_err::File::open(path)?)));
80-
let metadata_file = reader
81-
.entries()?
82-
.map(|entry| -> Result<_, Error> {
83-
let entry = entry?;
84-
if entry.path()?.ends_with("PKG-INFO") {
85-
Ok(Some(entry))
86-
} else {
87-
Ok(None)
88-
}
89-
})
90-
.find_map(|x| x.transpose());
91-
if let Some(metadata_file) = metadata_file {
92-
let mut entry = metadata_file?;
93-
let mut buf = Vec::new();
94-
entry.read_to_end(&mut buf)?;
95-
Metadata::parse(&buf)
96-
} else {
97-
Err(Error::MetadataNotFound)
98-
}
95+
SDistType::GzTar => {
96+
Self::parse_tar(GzDecoder::new(BufReader::new(fs_err::File::open(path)?)))
97+
}
98+
SDistType::Tar => Self::parse_tar(BufReader::new(fs_err::File::open(path)?)),
99+
SDistType::BzTar => {
100+
Self::parse_tar(BzDecoder::new(BufReader::new(fs_err::File::open(path)?)))
101+
}
102+
SDistType::XzTar => {
103+
Self::parse_tar(XzDecoder::new(BufReader::new(fs_err::File::open(path)?)))
99104
}
100105
}
101106
}
@@ -108,6 +113,29 @@ impl Distribution {
108113
Self::parse_zip(path, ".dist-info/METADATA")
109114
}
110115

116+
fn parse_tar<R: Read>(reader: R) -> Result<Metadata, Error> {
117+
let mut reader = tar::Archive::new(reader);
118+
let metadata_file = reader
119+
.entries()?
120+
.map(|entry| -> Result<_, Error> {
121+
let entry = entry?;
122+
if entry.path()?.ends_with("PKG-INFO") {
123+
Ok(Some(entry))
124+
} else {
125+
Ok(None)
126+
}
127+
})
128+
.find_map(|x| x.transpose());
129+
if let Some(metadata_file) = metadata_file {
130+
let mut entry = metadata_file?;
131+
let mut buf = Vec::new();
132+
entry.read_to_end(&mut buf)?;
133+
Metadata::parse(&buf)
134+
} else {
135+
Err(Error::MetadataNotFound)
136+
}
137+
}
138+
111139
fn parse_zip(path: &Path, metadata_file_suffix: &str) -> Result<Metadata, Error> {
112140
let reader = BufReader::new(fs_err::File::open(path)?);
113141
let mut archive = ZipArchive::new(reader)?;

tests/fixtures/build-0.4.0.tar

90 KB
Binary file not shown.

tests/fixtures/build-0.4.0.tar.bz2

11.8 KB
Binary file not shown.

tests/fixtures/build-0.4.0.tar.xz

11.6 KB
Binary file not shown.

tests/test_distribution.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ fn test_parse_sdist_zip() {
3333
assert!(metadata.download_url.is_none());
3434
}
3535

36+
#[test]
37+
fn test_parse_sdist_tar() {
38+
let dist = Distribution::new("tests/fixtures/build-0.4.0.tar").unwrap();
39+
assert_eq!(dist.r#type(), DistributionType::SDist);
40+
let metadata = dist.metadata();
41+
assert_eq!(metadata.metadata_version, "2.1");
42+
assert_eq!(metadata.name, "build");
43+
assert!(metadata.home_page.is_none());
44+
assert!(metadata.download_url.is_none());
45+
}
46+
3647
#[test]
3748
fn test_parse_sdist_tar_gz() {
3849
let dist = Distribution::new("tests/fixtures/build-0.4.0.tar.gz").unwrap();
@@ -43,3 +54,25 @@ fn test_parse_sdist_tar_gz() {
4354
assert!(metadata.home_page.is_none());
4455
assert!(metadata.download_url.is_none());
4556
}
57+
58+
#[test]
59+
fn test_parse_sdist_tar_bz2() {
60+
let dist = Distribution::new("tests/fixtures/build-0.4.0.tar.bz2").unwrap();
61+
assert_eq!(dist.r#type(), DistributionType::SDist);
62+
let metadata = dist.metadata();
63+
assert_eq!(metadata.metadata_version, "2.1");
64+
assert_eq!(metadata.name, "build");
65+
assert!(metadata.home_page.is_none());
66+
assert!(metadata.download_url.is_none());
67+
}
68+
69+
#[test]
70+
fn test_parse_sdist_tar_xz() {
71+
let dist = Distribution::new("tests/fixtures/build-0.4.0.tar.xz").unwrap();
72+
assert_eq!(dist.r#type(), DistributionType::SDist);
73+
let metadata = dist.metadata();
74+
assert_eq!(metadata.metadata_version, "2.1");
75+
assert_eq!(metadata.name, "build");
76+
assert!(metadata.home_page.is_none());
77+
assert!(metadata.download_url.is_none());
78+
}

0 commit comments

Comments
 (0)