1use std::fs::File;
2use std::path::Path;
3
4use std::io;
5
6use io::BufRead;
7use io::BufReader;
8use io::Read;
9
10use io::Seek;
11use io::Write;
12
13use rs_tar2zip::tar;
14use rs_tar2zip::zip;
15
16use zip::ZipWriter;
17
18pub fn items2zip<'a, I, R, W>(items: I, zwtr: &mut ZipWriter<W>) -> Result<(), io::Error>
19where
20 R: Read + 'a,
21 I: Iterator<Item = Result<tar::Entry<'a, R>, io::Error>>,
22 W: Write + Seek,
23{
24 for ritem in items {
25 let mut item: tar::Entry<_> = ritem?;
26 rs_tar2zip::entry2zip(&mut item, zwtr)?;
27 }
28 Ok(())
29}
30
31pub fn tar2zip<R, W>(ta: R, zwtr: &mut ZipWriter<W>) -> Result<(), io::Error>
32where
33 R: BufRead,
34 W: Write + Seek,
35{
36 let mut ta = tar::Archive::new(ta);
37
38 let items = ta.entries()?;
39 items2zip(items, zwtr)
40}
41
42pub fn targz2zip<R, W>(tgz: R, zwtr: &mut ZipWriter<W>) -> Result<(), io::Error>
43where
44 R: BufRead,
45 W: Write + Seek,
46{
47 let dec = flate2::bufread::GzDecoder::new(tgz);
48 let mut ta = tar::Archive::new(dec);
49
50 let items = ta.entries()?;
51 items2zip(items, zwtr)
52}
53
54#[derive(Clone, Copy)]
55pub enum FileType {
56 Tar,
57 TarGz,
58}
59
60pub fn filename2type_default(filename: &str) -> FileType {
61 let p: &Path = filename.as_ref();
62 let ext: &str = p.extension().and_then(|o| o.to_str()).unwrap_or_default();
63 match ext {
64 "tgz" => FileType::TarGz,
65 "gz" => FileType::TarGz,
66 "tar" => FileType::Tar,
67 _ => FileType::Tar,
68 }
69}
70
71pub fn tarname2zip<T, W>(
72 filename: &str,
73 name2typ: &T,
74 zwtr: &mut ZipWriter<W>,
75) -> Result<(), io::Error>
76where
77 T: Fn(&str) -> FileType,
78 W: Write + Seek,
79{
80 let f: File = File::open(filename)?;
81 let typ: FileType = name2typ(filename);
82 let br = BufReader::new(f);
83 match typ {
84 FileType::TarGz => targz2zip(br, zwtr),
85 FileType::Tar => tar2zip(br, zwtr),
86 }
87}
88
89pub fn file2sync_all(f: &mut File) -> Result<(), io::Error> {
90 f.sync_all()
91}
92
93pub fn file2sync_data(f: &mut File) -> Result<(), io::Error> {
94 f.sync_data()
95}
96
97pub fn file2sync_none(_f: &mut File) -> Result<(), io::Error> {
98 Ok(())
99}
100
101pub fn tarname2zname_new_from_outdir_default(outdir: String) -> impl Fn(&str, &mut String) {
102 move |tarname: &str, zname: &mut String| {
103 let tpath: &Path = tarname.as_ref();
104 let noext: &str = tpath
105 .file_stem()
106 .and_then(|o| o.to_str())
107 .unwrap_or_default();
108 let noextgzp: &Path = noext.as_ref();
109 let noextgz: &str = noextgzp
110 .file_stem()
111 .and_then(|o| o.to_str())
112 .unwrap_or_default();
113 let sep: &str = std::path::MAIN_SEPARATOR_STR;
114
115 zname.clear();
116 zname.push_str(&outdir);
117 zname.push_str(sep);
118 zname.push_str(noextgz);
119 zname.push_str(".zip");
120 }
121}
122
123pub fn tarnames2zip<I, T, N, F>(
124 names: I,
125 name2typ: T,
126 tarname2zname: N,
127 file2sync: F,
128) -> Result<(), io::Error>
129where
130 I: Iterator<Item = String>,
131 T: Fn(&str) -> FileType,
132 N: Fn(&str, &mut String),
133 F: Fn(&mut File) -> Result<(), io::Error>,
134{
135 let mut zname: String = String::new();
136 for filename in names {
137 zname.clear();
138 tarname2zname(&filename, &mut zname);
139 let zfile: File = File::create(&zname)?;
140 let mut zw = ZipWriter::new(zfile);
141 tarname2zip(&filename, &name2typ, &mut zw)?;
142 let mut w: File = zw.finish()?;
143 w.flush()?;
144 file2sync(&mut w)?;
145 }
146 Ok(())
147}
148
149pub fn tarnames2zip_default<I>(names: I, outdir: String) -> Result<(), io::Error>
150where
151 I: Iterator<Item = String>,
152{
153 tarnames2zip(
154 names,
155 filename2type_default,
156 tarname2zname_new_from_outdir_default(outdir),
157 file2sync_none,
158 )
159}
160
161pub fn stdin2tarnames2zip_default(outdir: String) -> Result<(), io::Error> {
162 let i = io::stdin();
163 let l = i.lock();
164 let lines = l.lines();
165 let noerr = lines.map_while(Result::ok);
166 tarnames2zip_default(noerr, outdir)
167}