-
Notifications
You must be signed in to change notification settings - Fork 65
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
`cargo-generate` is a very powerful project, but the `openssl` dependency is causing many issues to Windows users. Furthermore, it brings _a lot_ of heavy dependencies to `pavexc_cli`, significantly slowing down its compilation times. This PR removes the dependency from `cargo-generate` in favour of a stripped down version that only contains the feature we need in `pavex new`.
- Loading branch information
1 parent
2155773
commit 27da98b
Showing
17 changed files
with
879 additions
and
649 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
[package] | ||
name = "generate_from_path" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
anyhow = "1.0.79" | ||
toml = "0.8.8" | ||
path-absolutize = "3.1.1" | ||
tracing = "0.1.40" | ||
tempfile = "3" | ||
fs-err = "2.11.0" | ||
liquid = "0.26.4" | ||
liquid-core = "0.26.4" | ||
heck = "0.5.0-rc.1" | ||
indicatif = "0.17.7" | ||
walkdir = "2.4.0" | ||
sanitize-filename = "0.5" | ||
regex = "1.10.2" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
use crate::template::LiquidObjectResource; | ||
|
||
use crate::template::render_string_gracefully; | ||
use liquid::Parser; | ||
use std::path::{Component, Path, PathBuf}; | ||
|
||
pub fn substitute_filename( | ||
filepath: &Path, | ||
parser: &Parser, | ||
context: &mut LiquidObjectResource, | ||
) -> Result<PathBuf, anyhow::Error> { | ||
let mut path = PathBuf::new(); | ||
for elem in filepath.components() { | ||
match elem { | ||
Component::Normal(e) => { | ||
let parsed = render_string_gracefully(context, parser, e.to_str().unwrap())?; | ||
let parsed = sanitize_filename(parsed.as_str()); | ||
path.push(parsed); | ||
} | ||
other => path.push(other), | ||
} | ||
} | ||
Ok(path) | ||
} | ||
|
||
fn sanitize_filename(filename: &str) -> String { | ||
use sanitize_filename::sanitize_with_options; | ||
|
||
let options = sanitize_filename::Options { | ||
truncate: true, // true by default, truncates to 255 bytes | ||
replacement: "_", // str to replace sanitized chars/strings | ||
..sanitize_filename::Options::default() | ||
}; | ||
|
||
sanitize_with_options(filename, options) | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use liquid::{model::Value, Object}; | ||
|
||
#[test] | ||
fn should_do_happy_path() { | ||
assert_eq!( | ||
substitute_filename("{{author}}.rs", &mut prepare_context("sassman")).unwrap(), | ||
"sassman.rs" | ||
); | ||
#[cfg(unix)] | ||
assert_eq!( | ||
substitute_filename( | ||
"/tmp/project/{{author}}.rs", | ||
&mut prepare_context("sassman") | ||
) | ||
.unwrap(), | ||
"/tmp/project/sassman.rs" | ||
); | ||
#[cfg(unix)] | ||
assert_eq!( | ||
substitute_filename( | ||
"/tmp/project/{{author}}/{{author}}.rs", | ||
&mut prepare_context("sassman") | ||
) | ||
.unwrap(), | ||
"/tmp/project/sassman/sassman.rs" | ||
); | ||
#[cfg(windows)] | ||
assert_eq!( | ||
substitute_filename( | ||
"C:/tmp/project/{{author}}.rs", | ||
&mut prepare_context("sassman") | ||
) | ||
.unwrap(), | ||
"C:\\tmp\\project\\sassman.rs" | ||
); | ||
#[cfg(windows)] | ||
assert_eq!( | ||
substitute_filename( | ||
"C:/tmp/project/{{author}}/{{author}}.rs", | ||
&mut prepare_context("sassman") | ||
) | ||
.unwrap(), | ||
"C:\\tmp\\project\\sassman\\sassman.rs" | ||
); | ||
} | ||
|
||
#[test] | ||
fn should_prevent_invalid_filenames() { | ||
#[cfg(unix)] | ||
assert_eq!( | ||
substitute_filename("/tmp/project/{{author}}.rs", &mut prepare_context("s/a/s")) | ||
.unwrap(), | ||
"/tmp/project/s_a_s.rs" | ||
); | ||
#[cfg(unix)] | ||
assert_eq!( | ||
substitute_filename( | ||
"/tmp/project/{{author}}/{{author}}.rs", | ||
&mut prepare_context("s/a/s") | ||
) | ||
.unwrap(), | ||
"/tmp/project/s_a_s/s_a_s.rs" | ||
); | ||
#[cfg(windows)] | ||
assert_eq!( | ||
substitute_filename( | ||
"C:/tmp/project/{{author}}.rs", | ||
&mut prepare_context("s/a/s") | ||
) | ||
.unwrap(), | ||
"C:\\tmp\\project\\s_a_s.rs" | ||
); | ||
#[cfg(windows)] | ||
assert_eq!( | ||
substitute_filename( | ||
"C:/tmp/project/{{author}}/{{author}}.rs", | ||
&mut prepare_context("s/a/s") | ||
) | ||
.unwrap(), | ||
"C:\\tmp\\project\\s_a_s\\s_a_s.rs" | ||
); | ||
} | ||
|
||
#[test] | ||
fn should_prevent_exploitation() { | ||
#[cfg(unix)] | ||
assert_eq!( | ||
substitute_filename( | ||
"/tmp/project/{{author}}.rs", | ||
&mut prepare_context("../../etc/passwd") | ||
) | ||
.unwrap(), | ||
"/tmp/project/.._.._etc_passwd.rs" | ||
); | ||
#[cfg(unix)] | ||
assert_eq!( | ||
substitute_filename( | ||
"/tmp/project/{{author}}/main.rs", | ||
&mut prepare_context("../../etc/passwd") | ||
) | ||
.unwrap(), | ||
"/tmp/project/.._.._etc_passwd/main.rs" | ||
); | ||
#[cfg(windows)] | ||
assert_eq!( | ||
substitute_filename( | ||
"C:/tmp/project/{{author}}.rs", | ||
&mut prepare_context("../../etc/passwd") | ||
) | ||
.unwrap(), | ||
"C:\\tmp\\project\\.._.._etc_passwd.rs" | ||
); | ||
#[cfg(windows)] | ||
assert_eq!( | ||
substitute_filename( | ||
"C:/tmp/project/{{author}}/main.rs", | ||
&mut prepare_context("../../etc/passwd") | ||
) | ||
.unwrap(), | ||
"C:\\tmp\\project\\.._.._etc_passwd\\main.rs" | ||
); | ||
} | ||
|
||
//region wrapper helpers | ||
fn prepare_context(value: &str) -> LiquidObjectResource { | ||
let mut ctx = Object::default(); | ||
ctx.entry("author") | ||
.or_insert(Value::scalar(value.to_string())); | ||
|
||
ctx | ||
} | ||
|
||
fn substitute_filename(f: &str, ctx: &mut LiquidObjectResource) -> anyhow::Result<String> { | ||
let parser = Parser::default(); | ||
|
||
super::substitute_filename(f.as_ref(), &parser, ctx) | ||
.map(|p| p.to_str().unwrap().to_string()) | ||
} | ||
//endregion | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
use std::fs::remove_file; | ||
use std::path::{Path, PathBuf}; | ||
|
||
/// Takes the directory path and removes the files/directories specified in the | ||
/// `.genignore` file | ||
/// It handles all errors internally | ||
pub fn remove_unneeded_files( | ||
dir: &Path, | ||
ignored_files: &Option<Vec<String>>, | ||
verbose: bool, | ||
) -> anyhow::Result<()> { | ||
let mut items = vec![]; | ||
if let Some(ignored_files) = ignored_files { | ||
for f in ignored_files { | ||
let mut p = PathBuf::new(); | ||
p.push(dir); | ||
p.push(f); | ||
items.push(p); | ||
} | ||
} | ||
remove_dir_files(&items, verbose); | ||
Ok(()) | ||
} | ||
|
||
pub fn remove_dir_files(files: impl IntoIterator<Item = impl Into<PathBuf>>, verbose: bool) { | ||
for item in files | ||
.into_iter() | ||
.map(|i| i.into() as PathBuf) | ||
.filter(|file| file.exists()) | ||
{ | ||
let ignore_message = format!("Ignoring: {}", &item.display()); | ||
if item.is_dir() { | ||
fs_err::remove_dir_all(&item).unwrap(); | ||
if verbose { | ||
tracing::info!("{ignore_message}"); | ||
} | ||
} else if item.is_file() { | ||
remove_file(&item).unwrap(); | ||
if verbose { | ||
tracing::info!("{ignore_message}"); | ||
} | ||
} else { | ||
tracing::warn!( | ||
"The given paths are neither files nor directories! {}", | ||
&item.display() | ||
); | ||
} | ||
} | ||
} |
Oops, something went wrong.