Add a sad Python script for Ouch testing
[ouch.git] / src / extension.rs
blob35a43963cd760ae90434b5a6ae68c25633aa1f2a
1 use std::{
2     convert::TryFrom,
3     ffi::OsStr,
4     fmt::Display,
5     path::{Path, PathBuf},
6 };
8 use crate::error;
9 use CompressionFormat::*;
11 /// Represents the extension of a file, but only really caring about
12 /// compression formats (and .tar).
13 /// Ex.: Extension::new("file.tar.gz") == Extension { first_ext: Some(Tar), second_ext: Gzip }
14 #[derive(Clone, Debug, PartialEq, Eq)]
15 pub struct Extension {
16     pub first_ext: Option<CompressionFormat>,
17     pub second_ext: CompressionFormat,
20 pub fn get_extension_from_filename(filename: &str) -> Option<(&str, &str)> {
21     let path = Path::new(filename);
23     let ext = path.extension().and_then(OsStr::to_str)?;
25     let previous_extension = path
26         .file_stem()
27         .and_then(OsStr::to_str)
28         .and_then(get_extension_from_filename);
30     if let Some((_, prev)) = previous_extension {
31         Some((prev, ext))
32     } else {
33         Some(("", ext))
34     }
37 impl From<CompressionFormat> for Extension {
38     fn from(second_ext: CompressionFormat) -> Self {
39         Self {
40             first_ext: None,
41             second_ext,
42         }
43     }
46 impl Extension {
47     pub fn new(filename: &str) -> error::OuchResult<Self> {
48         let ext_from_str = |ext| match ext {
49             "zip" => Ok(Zip),
50             "tar" => Ok(Tar),
51             "gz" => Ok(Gzip),
52             "bz" | "bz2" => Ok(Bzip),
53             "xz" | "lz" | "lzma" => Ok(Lzma),
54             other => Err(error::Error::UnknownExtensionError(other.into())),
55         };
57         let (first_ext, second_ext) = match get_extension_from_filename(filename) {
58             Some(extension_tuple) => match extension_tuple {
59                 ("", snd) => (None, snd),
60                 (fst, snd) => (Some(fst), snd),
61             },
62             None => return Err(error::Error::MissingExtensionError(filename.into())),
63         };
65         let (first_ext, second_ext) = match (first_ext, second_ext) {
66             (None, snd) => {
67                 let ext = ext_from_str(snd)?;
68                 (None, ext)
69             }
70             (Some(fst), snd) => {
71                 let snd = ext_from_str(snd)?;
72                 let fst = ext_from_str(fst).ok();
73                 (fst, snd)
74             }
75         };
77         Ok(Self {
78             first_ext,
79             second_ext,
80         })
81     }
84 #[derive(Clone, PartialEq, Eq, Debug)]
85 /// Accepted extensions for input and output
86 pub enum CompressionFormat {
87     // .gz
88     Gzip,
89     // .bz
90     Bzip,
91     // .lzma
92     Lzma,
93     // .tar (technically not a compression extension, but will do for now)
94     Tar,
95     // .zip
96     Zip,
99 fn extension_from_os_str(ext: &OsStr) -> Result<CompressionFormat, error::Error> {
100     // let ext = Path::new(ext);
102     let ext = match ext.to_str() {
103         Some(str) => str,
104         None => return Err(error::Error::InvalidUnicode),
105     };
107     match ext {
108         "zip" => Ok(Zip),
109         "tar" => Ok(Tar),
110         "gz" => Ok(Gzip),
111         "bz" | "bz2" => Ok(Bzip),
112         "xz" | "lzma" | "lz" => Ok(Lzma),
113         other => Err(error::Error::UnknownExtensionError(other.into())),
114     }
117 impl TryFrom<&PathBuf> for CompressionFormat {
118     type Error = error::Error;
120     fn try_from(ext: &PathBuf) -> Result<Self, Self::Error> {
121         let ext = match ext.extension() {
122             Some(ext) => ext,
123             None => {
124                 return Err(error::Error::MissingExtensionError(String::new()));
125             }
126         };
127         extension_from_os_str(ext)
128     }
131 impl TryFrom<&str> for CompressionFormat {
132     type Error = error::Error;
134     fn try_from(filename: &str) -> Result<Self, Self::Error> {
135         let filename = Path::new(filename);
136         let ext = match filename.extension() {
137             Some(ext) => ext,
138             None => return Err(error::Error::MissingExtensionError(String::new())),
139         };
141         extension_from_os_str(ext)
142     }
145 impl Display for CompressionFormat {
146     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
147         write!(
148             f,
149             "{}",
150             match self {
151                 Gzip => ".gz",
152                 Bzip => ".bz",
153                 Lzma => ".lz",
154                 Tar => ".tar",
155                 Zip => ".zip",
156             }
157         )
158     }