rs_tars2zips/
lib.rs

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}