Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion askama_derive/src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,9 @@ impl<'a, 'h> Generator<'a, 'h> {

fn rel_path<'p>(&mut self, path: &'p Path) -> Cow<'p, Path> {
self.caller_dir()
.and_then(|caller_dir| diff_paths(path, caller_dir))
.and_then(|caller_dir| {
diff_paths(path, caller_dir, std::env::var("CARGO_MANIFEST_DIR").ok())
})
.map_or(Cow::Borrowed(path), Cow::Owned)
}

Expand Down
106 changes: 71 additions & 35 deletions askama_derive/src/generator/helpers/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,28 @@ pub(crate) fn clean(path: &Path) -> PathBuf {
}

/// Construct a relative path from a provided base directory path to the provided path.
pub(crate) fn diff_paths(path: &Path, base: &Path) -> Option<PathBuf> {
if path.is_absolute() != base.is_absolute() {
if path.is_absolute() {
pub(crate) fn diff_paths(
path: &Path,
base: &Path,
manifest_dir: Option<String>,
) -> Option<PathBuf> {
let path_is_absolute = path.is_absolute();
let base_is_absolute = base.is_absolute();
if path_is_absolute != base_is_absolute {
if path_is_absolute {
Some(PathBuf::from(path))
} else {
None
}
} else {
if base_is_absolute &&
let Some(manifest_dir) = manifest_dir &&
// If the `base` doesn't start with the same path as `CARGO_MANIFEST_DIR`, it likely
// means that we're in a macro, so better use the absolute path in this case.
!base.starts_with(manifest_dir)
{
return Some(PathBuf::from(path));
}
let mut ita = path.components();
let mut itb = base.components();
let mut comps = vec![];
Expand Down Expand Up @@ -89,37 +103,59 @@ pub(crate) fn diff_paths(path: &Path, base: &Path) -> Option<PathBuf> {

#[test]
fn test_diff_paths() {
assert_eq!(
diff_paths(Path::new("/foo/bar"), Path::new("/foo/bar/baz")),
Some("../".into())
);
assert_eq!(
diff_paths(Path::new("/foo/bar/baz"), Path::new("/foo/bar")),
Some("baz".into())
);
assert_eq!(
diff_paths(Path::new("/foo/bar/quux"), Path::new("/foo/bar/baz")),
Some("../quux".into())
);
assert_eq!(
diff_paths(Path::new("/foo/bar/baz"), Path::new("/foo/bar/quux")),
Some("../baz".into())
);
assert_eq!(
diff_paths(Path::new("/foo/bar"), Path::new("/foo/bar/quux")),
Some("../".into())
);
fn t(a: &str, b: &str) -> Option<PathBuf> {
diff_paths(Path::new(a), Path::new(b), None)
}
assert_eq!(t("/foo/bar", "/foo/bar/baz"), Some("../".into()));
assert_eq!(t("/foo/bar/baz", "/foo/bar"), Some("baz".into()));
assert_eq!(t("/foo/bar/quux", "/foo/bar/baz"), Some("../quux".into()));
assert_eq!(t("/foo/bar/baz", "/foo/bar/quux"), Some("../baz".into()));
assert_eq!(t("/foo/bar", "/foo/bar/quux"), Some("../".into()));

assert_eq!(t("/foo/bar", "baz"), Some("/foo/bar".into()));
assert_eq!(t("/foo/bar", "/baz"), Some("../foo/bar".into()));
assert_eq!(t("foo", "bar"), Some("../foo".into()));

// Windows paths are a nightmare to test...
if !cfg!(windows) {
// If the `path` doesn't belong in the same crate, we should keep an absolute path.
assert_eq!(
diff_paths(
Path::new("/askama-bugs/b/templates/empty.txt"),
Path::new("/askama-bugs/a"),
Some("/askama-bugs/b".into()),
),
Some("/askama-bugs/b/templates/empty.txt".into()),
);

assert_eq!(
diff_paths(Path::new("/foo/bar"), Path::new("baz")),
Some("/foo/bar".into())
);
assert_eq!(
diff_paths(Path::new("/foo/bar"), Path::new("/baz")),
Some("../foo/bar".into())
);
assert_eq!(
diff_paths(Path::new("foo"), Path::new("bar")),
Some("../foo".into())
);
// If it's in the same crate, relative path should be returned.
assert_eq!(
diff_paths(
Path::new("/askama-bugs/b/templates/empty.txt"),
Path::new("/askama-bugs/b"),
Some("/askama-bugs/b".into()),
),
Some("templates/empty.txt".into()),
);
} else {
// If the `path` doesn't belong in the same crate, we should keep an absolute path.
assert_eq!(
diff_paths(
Path::new("C:/askama-bugs/b/templates/empty.txt"),
Path::new("C:/askama-bugs/a"),
Some("C:/askama-bugs/b".into()),
),
Some("C:/askama-bugs/b/templates/empty.txt".into()),
);

// If it's in the same crate, relative path should be returned.
assert_eq!(
diff_paths(
Path::new("C:/askama-bugs/b/templates/empty.txt"),
Path::new("C:/askama-bugs/b"),
Some("C:/askama-bugs/b".into()),
),
Some("templates/empty.txt".into()),
);
}
}
26 changes: 26 additions & 0 deletions testing/tests/macro-include.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use std::path::{Path, PathBuf};
use std::process::Command;

// This test ensures that when `askama` template is rendered from a macro from a different crate,
// it still works.
// This is a regression test for <https://github.com/askama-rs/askama/issues/706>.
#[test]
fn test_macro_include() {
fn run_test(current_dir: PathBuf) {
let exit_status = Command::new("cargo")
.args(["check"])
.current_dir(current_dir)
.spawn()
.unwrap()
.wait()
.unwrap();
assert!(exit_status.success());
}

let Ok(cargo_home) = std::env::var("CARGO_MANIFEST_DIR") else {
panic!(">> cannot get `CARGO_MANIFEST_DIR` env variable");
};

run_test(Path::new(&cargo_home).join("tests/macro-include/b"));
run_test(Path::new(&cargo_home).join("tests/macro-include/c"));
}
9 changes: 9 additions & 0 deletions testing/tests/macro-include/a/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "a"
edition = "2024"

[lib]
## !!!!!!!! the depth of `lib.rs` in `a` is at a different depth than in crate `b`.
path = "./lib.rs"

[workspace]
8 changes: 8 additions & 0 deletions testing/tests/macro-include/a/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#[ macro_export ]
macro_rules! define_template {
() => {
#[ derive (askama::Template) ]
#[ template (path = "empty.txt") ]
struct Empty {}
}
}
12 changes: 12 additions & 0 deletions testing/tests/macro-include/b/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "b"
edition = "2024"

[lib]
path = "./src/lib.rs"

[dependencies]
a = { path = "../a" }
askama = { path = "../../../../askama" }

[workspace]
1 change: 1 addition & 0 deletions testing/tests/macro-include/b/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
::a::define_template! {}
Empty file.
12 changes: 12 additions & 0 deletions testing/tests/macro-include/c/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "c"
edition = "2024"

[lib]
path = "./lib.rs"

[dependencies]
a = { path = "../a" }
askama = { path = "../../../../askama" }

[workspace]
1 change: 1 addition & 0 deletions testing/tests/macro-include/c/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
::a::define_template! {}
Empty file.