Use lexiclean crate for lexical path cleaning

I moved all the lexical path cleaning functionality into a separate
crate, so it can be used by other projects.

type: reform
This commit is contained in:
Casey Rodarmor 2020-04-21 23:03:27 -07:00
parent 323434d0aa
commit 134c241ae7
No known key found for this signature in database
GPG Key ID: 556186B153EC6FE0
9 changed files with 19 additions and 97 deletions

View File

@ -4,7 +4,8 @@ Changelog
UNRELEASED - 2020-04-22 UNRELEASED - 2020-04-22
----------------------- -----------------------
- :zap: [`xxxxxxxxxxxx`](https://github.com/casey/intermodal/commits/master) Allow positional input to `imdl torrent verify` - Fixes [#375](https://github.com/casey/intermodal/issues/375) - _Casey Rodarmor <casey@rodarmor.com>_ - :art: [`xxxxxxxxxxxx`](https://github.com/casey/intermodal/commits/master) Use `lexiclean` crate for lexical path cleaning - _Casey Rodarmor <casey@rodarmor.com>_
- :zap: [`323434d0aa21`](https://github.com/casey/intermodal/commit/323434d0aa21ebfda5be85ecd4a38a55ed3fec0a) Allow positional input to `imdl torrent verify` - Fixes [#375](https://github.com/casey/intermodal/issues/375) - _Casey Rodarmor <casey@rodarmor.com>_
- :zap: [`5ba885dbc4f2`](https://github.com/casey/intermodal/commit/5ba885dbc4f24781d6a3240ddfc0c03177b12f1e) Take input to `imdl torrent create` as positional - Fixes [#375](https://github.com/casey/intermodal/issues/375) - _Casey Rodarmor <casey@rodarmor.com>_ - :zap: [`5ba885dbc4f2`](https://github.com/casey/intermodal/commit/5ba885dbc4f24781d6a3240ddfc0c03177b12f1e) Take input to `imdl torrent create` as positional - Fixes [#375](https://github.com/casey/intermodal/issues/375) - _Casey Rodarmor <casey@rodarmor.com>_
- :wrench: [`c22df5a08326`](https://github.com/casey/intermodal/commit/c22df5a083265b03abd5531b1f5b2aad60aa68cd) Don't commit man pages - _Casey Rodarmor <casey@rodarmor.com>_ - :wrench: [`c22df5a08326`](https://github.com/casey/intermodal/commit/c22df5a083265b03abd5531b1f5b2aad60aa68cd) Don't commit man pages - _Casey Rodarmor <casey@rodarmor.com>_
- :wrench: [`4d67d3a10d17`](https://github.com/casey/intermodal/commit/4d67d3a10d17db3c63af092a936eb5994ee107b1) Don't commit the book - _Casey Rodarmor <casey@rodarmor.com>_ - :wrench: [`4d67d3a10d17`](https://github.com/casey/intermodal/commit/4d67d3a10d17db3c63af092a936eb5994ee107b1) Don't commit the book - _Casey Rodarmor <casey@rodarmor.com>_

7
Cargo.lock generated
View File

@ -499,6 +499,7 @@ dependencies = [
"ignore", "ignore",
"imdl-indicatif", "imdl-indicatif",
"lazy_static", "lazy_static",
"lexiclean",
"libc", "libc",
"log", "log",
"md5", "md5",
@ -560,6 +561,12 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lexiclean"
version = "0.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bb11deb06ea520b5110c0841c00625ee9f3369782c9fdcf22a400105b44462b"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.69" version = "0.2.69"

View File

@ -18,10 +18,11 @@ atty = "0.2.0"
chrono = "0.4.1" chrono = "0.4.1"
console = "0.10.0" console = "0.10.0"
globset = "0.4.0" globset = "0.4.0"
ignore = "0.4.14"
lazy_static = "1.4.0" lazy_static = "1.4.0"
lexiclean = "0.0.0"
libc = "0.2.0" libc = "0.2.0"
log = "0.4.8" log = "0.4.8"
ignore = "0.4.14"
md5 = "0.7.0" md5 = "0.7.0"
open = "1.4.0" open = "1.4.0"
pretty_assertions = "0.6.0" pretty_assertions = "0.6.0"

View File

@ -29,6 +29,7 @@ pub(crate) use chrono::{TimeZone, Utc};
pub(crate) use globset::{Glob, GlobMatcher}; pub(crate) use globset::{Glob, GlobMatcher};
pub(crate) use ignore::WalkBuilder; pub(crate) use ignore::WalkBuilder;
pub(crate) use indicatif::{ProgressBar, ProgressStyle}; pub(crate) use indicatif::{ProgressBar, ProgressStyle};
pub(crate) use lexiclean::Lexiclean;
pub(crate) use libc::EXIT_FAILURE; pub(crate) use libc::EXIT_FAILURE;
pub(crate) use regex::{Regex, RegexSet}; pub(crate) use regex::{Regex, RegexSet};
pub(crate) use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer}; pub(crate) use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer};
@ -59,8 +60,7 @@ pub(crate) use crate::xor_args::xor_args;
// traits // traits
pub(crate) use crate::{ pub(crate) use crate::{
input_stream::InputStream, into_u64::IntoU64, into_usize::IntoUsize, invariant::Invariant, input_stream::InputStream, into_u64::IntoU64, into_usize::IntoUsize, invariant::Invariant,
path_ext::PathExt, platform_interface::PlatformInterface, print::Print, reckoner::Reckoner, platform_interface::PlatformInterface, print::Print, reckoner::Reckoner, step::Step,
step::Step,
}; };
// structs and enums // structs and enums

View File

@ -189,7 +189,7 @@ impl Env {
return Err(Error::internal("Empty path passed to resolve")); return Err(Error::internal("Empty path passed to resolve"));
} }
Ok(self.dir().join(path).clean()) Ok(self.dir().join(path).lexiclean())
} }
pub(crate) fn write(&mut self, path: impl AsRef<Path>, contents: impl AsRef<[u8]>) -> Result<()> { pub(crate) fn write(&mut self, path: impl AsRef<Path>, contents: impl AsRef<[u8]>) -> Result<()> {

View File

@ -79,7 +79,6 @@ mod mode;
mod options; mod options;
mod output_stream; mod output_stream;
mod output_target; mod output_target;
mod path_ext;
mod piece_length_picker; mod piece_length_picker;
mod piece_list; mod piece_list;
mod platform; mod platform;

View File

@ -1,89 +0,0 @@
use crate::common::*;
use std::path::Component;
pub(crate) trait PathExt {
fn clean(self) -> PathBuf;
}
impl PathExt for &Path {
fn clean(self) -> PathBuf {
if self.components().count() <= 1 {
return self.to_owned();
}
let mut components = Vec::new();
for component in self
.components()
.filter(|component| component != &Component::CurDir)
{
if component == Component::ParentDir {
match components.last() {
Some(Component::Normal(_)) => {
components.pop();
}
Some(Component::ParentDir) | None => components.push(component),
_ => {}
}
} else {
components.push(component);
}
}
components.into_iter().collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[rustfmt::skip]
fn prefix_suffix() {
fn case(prefix: &str, suffix: &str, want: &str) {
let have = Path::new(prefix).join(Path::new(suffix)).clean();
assert_eq!(have, Path::new(want));
}
{
case("/", "foo", "/foo");
case("/", "." , "/");
case("/", "foo/./bar", "/foo/bar");
case("/foo/./bar", ".", "/foo/bar");
case("/bar", "/foo", "/foo");
case("//foo", "bar//baz", "/foo/bar/baz");
case("/", "..", "/");
case("/", "/..", "/");
case("/..", "", "/");
case("/../../../..", "../../../", "/");
case("/.", "./", "/");
case("/foo/../", "bar", "/bar");
case("/foo/bar", "..", "/foo");
case("/foo/bar/", "..", "/foo");
}
}
#[test]
#[rustfmt::skip]
fn simple() {
fn case(path: &str, want: &str) {
assert_eq!(Path::new(path).clean(), Path::new(want));
}
case("./..", "..");
case("./././.", ".");
case("./../.", "..");
case("..", "..");
case("", "");
case("foo", "foo");
case(".", ".");
case("foo/./bar", "foo/bar");
case("/foo", "/foo");
case("bar//baz", "bar/baz");
case("/..", "/");
case("../../../", "../../..");
case("./", ".");
}
}

View File

@ -107,7 +107,10 @@ impl CreateContent {
} }
fn torrent_path(input: &Path, name: &str) -> PathBuf { fn torrent_path(input: &Path, name: &str) -> PathBuf {
input.join("..").clean().join(format!("{}.torrent", name)) input
.join("..")
.lexiclean()
.join(format!("{}.torrent", name))
} }
} }

View File

@ -70,7 +70,7 @@ impl Verify {
content.clone() content.clone()
} else { } else {
match target { match target {
InputTarget::Path(path) => path.join("..").join(&metainfo.info.name).clean(), InputTarget::Path(path) => path.join("..").join(&metainfo.info.name).lexiclean(),
InputTarget::Stdin => PathBuf::from(&metainfo.info.name), InputTarget::Stdin => PathBuf::from(&metainfo.info.name),
} }
}; };