11use std:: io:: { BufReader , Read } ;
22use std:: path:: Path ;
3+ use std:: str:: FromStr ;
34
5+ use bzip2:: read:: BzDecoder ;
46use flate2:: read:: GzDecoder ;
7+ use xz:: read:: XzDecoder ;
58use zip:: ZipArchive ;
69
710use crate :: { Error , Metadata } ;
@@ -20,7 +23,10 @@ pub enum DistributionType {
2023#[ derive( Debug , Clone , Copy ) ]
2124enum 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+
3355impl 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) ?;
0 commit comments