mirror of
https://github.com/askama-rs/askama.git
synced 2025-09-27 21:12:54 +00:00
Track config files
This commit is contained in:
parent
aa5e200b10
commit
d3f0947d11
@ -40,6 +40,7 @@ struct ConfigKey<'a> {
|
||||
source: Cow<'a, str>,
|
||||
config_path: Option<Cow<'a, str>>,
|
||||
template_whitespace: Option<Whitespace>,
|
||||
full_config_path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl ToOwned for ConfigKey<'_> {
|
||||
@ -53,6 +54,7 @@ impl ToOwned for ConfigKey<'_> {
|
||||
.as_ref()
|
||||
.map(|s| Cow::Owned(s.as_ref().to_owned())),
|
||||
template_whitespace: self.template_whitespace,
|
||||
full_config_path: self.full_config_path.clone(),
|
||||
};
|
||||
OwnedConfigKey(Box::leak(Box::new(owned_key)))
|
||||
}
|
||||
@ -71,6 +73,7 @@ impl Config {
|
||||
config_path: Option<&str>,
|
||||
template_whitespace: Option<Whitespace>,
|
||||
config_span: Option<Span>,
|
||||
full_config_path: Option<PathBuf>,
|
||||
) -> Result<&'static Config, CompileError> {
|
||||
static CACHE: ManuallyDrop<OnceLock<OnceMap<OwnedConfigKey, &'static Config>>> =
|
||||
ManuallyDrop::new(OnceLock::new());
|
||||
@ -79,6 +82,7 @@ impl Config {
|
||||
source: source.into(),
|
||||
config_path: config_path.map(Cow::Borrowed),
|
||||
template_whitespace,
|
||||
full_config_path,
|
||||
},
|
||||
|key| {
|
||||
let config = Config::new_uncached(key.to_owned(), config_span)?;
|
||||
@ -88,6 +92,10 @@ impl Config {
|
||||
|config| *config,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn full_config_path(&self) -> Option<&Path> {
|
||||
self._key.0.full_config_path.as_deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@ -332,7 +340,7 @@ struct RawEscaper<'a> {
|
||||
pub(crate) fn read_config_file(
|
||||
config_path: Option<&str>,
|
||||
span: Option<Span>,
|
||||
) -> Result<String, CompileError> {
|
||||
) -> Result<(String, Option<PathBuf>), CompileError> {
|
||||
let root = manifest_root();
|
||||
let filename = match config_path {
|
||||
Some(config_path) => root.join(config_path),
|
||||
@ -340,19 +348,20 @@ pub(crate) fn read_config_file(
|
||||
};
|
||||
|
||||
if filename.exists() {
|
||||
fs::read_to_string(&filename).map_err(|err| {
|
||||
let content = fs::read_to_string(&filename).map_err(|err| {
|
||||
CompileError::no_file_info(
|
||||
format_args!("unable to read {}: {err}", filename.display()),
|
||||
span,
|
||||
)
|
||||
})
|
||||
})?;
|
||||
Ok((content, filename.canonicalize().ok()))
|
||||
} else if config_path.is_some() {
|
||||
Err(CompileError::no_file_info(
|
||||
format_args!("`{}` does not exist", filename.display()),
|
||||
span,
|
||||
))
|
||||
} else {
|
||||
Ok(String::new())
|
||||
Ok((String::new(), None))
|
||||
}
|
||||
}
|
||||
|
||||
@ -387,7 +396,7 @@ mod tests {
|
||||
fn test_default_config() {
|
||||
let mut root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
|
||||
root.push("templates");
|
||||
let config = Config::new("", None, None, None).unwrap();
|
||||
let config = Config::new("", None, None, None, None).unwrap();
|
||||
assert_eq!(config.dirs, vec![root]);
|
||||
}
|
||||
|
||||
@ -396,7 +405,7 @@ mod tests {
|
||||
fn test_config_dirs() {
|
||||
let mut root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
|
||||
root.push("tpl");
|
||||
let config = Config::new("[general]\ndirs = [\"tpl\"]", None, None, None).unwrap();
|
||||
let config = Config::new("[general]\ndirs = [\"tpl\"]", None, None, None, None).unwrap();
|
||||
assert_eq!(config.dirs, vec![root]);
|
||||
}
|
||||
|
||||
@ -417,7 +426,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn find_absolute() {
|
||||
let config = Config::new("", None, None, None).unwrap();
|
||||
let config = Config::new("", None, None, None, None).unwrap();
|
||||
let root = config.find_template("a.html", None, None).unwrap();
|
||||
let path = config
|
||||
.find_template("sub/b.html", Some(&root), None)
|
||||
@ -428,14 +437,14 @@ mod tests {
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn find_relative_nonexistent() {
|
||||
let config = Config::new("", None, None, None).unwrap();
|
||||
let config = Config::new("", None, None, None, None).unwrap();
|
||||
let root = config.find_template("a.html", None, None).unwrap();
|
||||
config.find_template("c.html", Some(&root), None).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn find_relative() {
|
||||
let config = Config::new("", None, None, None).unwrap();
|
||||
let config = Config::new("", None, None, None, None).unwrap();
|
||||
let root = config.find_template("sub/b.html", None, None).unwrap();
|
||||
let path = config.find_template("c.html", Some(&root), None).unwrap();
|
||||
assert_eq_rooted(&path, "sub/c.html");
|
||||
@ -443,7 +452,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn find_relative_sub() {
|
||||
let config = Config::new("", None, None, None).unwrap();
|
||||
let config = Config::new("", None, None, None, None).unwrap();
|
||||
let root = config.find_template("sub/b.html", None, None).unwrap();
|
||||
let path = config
|
||||
.find_template("sub1/d.html", Some(&root), None)
|
||||
@ -468,7 +477,7 @@ mod tests {
|
||||
"#;
|
||||
|
||||
let default_syntax = Syntax::default();
|
||||
let config = Config::new(raw_config, None, None, None).unwrap();
|
||||
let config = Config::new(raw_config, None, None, None, None).unwrap();
|
||||
assert_eq!(config.default_syntax, "foo");
|
||||
|
||||
let foo = config.syntaxes.get("foo").unwrap();
|
||||
@ -500,7 +509,7 @@ mod tests {
|
||||
"#;
|
||||
|
||||
let default_syntax = Syntax::default();
|
||||
let config = Config::new(raw_config, None, None, None).unwrap();
|
||||
let config = Config::new(raw_config, None, None, None, None).unwrap();
|
||||
assert_eq!(config.default_syntax, "foo");
|
||||
|
||||
let foo = config.syntaxes.get("foo").unwrap();
|
||||
@ -537,7 +546,7 @@ mod tests {
|
||||
default_syntax = "emoji"
|
||||
"#;
|
||||
|
||||
let config = Config::new(raw_config, None, None, None).unwrap();
|
||||
let config = Config::new(raw_config, None, None, None, None).unwrap();
|
||||
assert_eq!(config.default_syntax, "emoji");
|
||||
|
||||
let foo = config.syntaxes.get("emoji").unwrap();
|
||||
@ -565,7 +574,7 @@ mod tests {
|
||||
name = "too_short"
|
||||
block_start = "<"
|
||||
"#;
|
||||
let config = Config::new(raw_config, None, None, None);
|
||||
let config = Config::new(raw_config, None, None, None, None);
|
||||
assert_eq!(
|
||||
expect_err(config).msg,
|
||||
r#"delimiters must be at least two characters long. The opening block delimiter ("<") is too short"#,
|
||||
@ -576,7 +585,7 @@ mod tests {
|
||||
name = "contains_ws"
|
||||
block_start = " {{ "
|
||||
"#;
|
||||
let config = Config::new(raw_config, None, None, None);
|
||||
let config = Config::new(raw_config, None, None, None, None);
|
||||
assert_eq!(
|
||||
expect_err(config).msg,
|
||||
r#"delimiters may not contain white spaces. The opening block delimiter (" {{ ") contains white spaces"#,
|
||||
@ -589,7 +598,7 @@ mod tests {
|
||||
expr_start = "{{$"
|
||||
comment_start = "{{#"
|
||||
"#;
|
||||
let config = Config::new(raw_config, None, None, None);
|
||||
let config = Config::new(raw_config, None, None, None, None);
|
||||
assert_eq!(
|
||||
expect_err(config).msg,
|
||||
r#"an opening delimiter may not be the prefix of another delimiter. The block delimiter ("{{") clashes with the expression delimiter ("{{$")"#,
|
||||
@ -604,7 +613,7 @@ mod tests {
|
||||
syntax = [{ name = "default" }]
|
||||
"#;
|
||||
|
||||
let _config = Config::new(raw_config, None, None, None).unwrap();
|
||||
let _config = Config::new(raw_config, None, None, None, None).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(feature = "config")]
|
||||
@ -616,7 +625,7 @@ mod tests {
|
||||
{ name = "foo", block_start = "%%" } ]
|
||||
"#;
|
||||
|
||||
let _config = Config::new(raw_config, None, None, None).unwrap();
|
||||
let _config = Config::new(raw_config, None, None, None, None).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(feature = "config")]
|
||||
@ -628,7 +637,7 @@ mod tests {
|
||||
default_syntax = "foo"
|
||||
"#;
|
||||
|
||||
let _config = Config::new(raw_config, None, None, None).unwrap();
|
||||
let _config = Config::new(raw_config, None, None, None, None).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(feature = "config")]
|
||||
@ -643,6 +652,7 @@ mod tests {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
@ -674,11 +684,12 @@ mod tests {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(config.whitespace, Whitespace::Suppress);
|
||||
|
||||
let config = Config::new(r#""#, None, None, None).unwrap();
|
||||
let config = Config::new(r#""#, None, None, None, None).unwrap();
|
||||
assert_eq!(config.whitespace, Whitespace::Preserve);
|
||||
|
||||
let config = Config::new(
|
||||
@ -689,6 +700,7 @@ mod tests {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(config.whitespace, Whitespace::Preserve);
|
||||
@ -701,6 +713,7 @@ mod tests {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(config.whitespace, Whitespace::Minimize);
|
||||
@ -720,11 +733,12 @@ mod tests {
|
||||
None,
|
||||
Some(Whitespace::Minimize),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(config.whitespace, Whitespace::Minimize);
|
||||
|
||||
let config = Config::new(r#""#, None, Some(Whitespace::Minimize), None).unwrap();
|
||||
let config = Config::new(r#""#, None, Some(Whitespace::Minimize), None, None).unwrap();
|
||||
assert_eq!(config.whitespace, Whitespace::Minimize);
|
||||
}
|
||||
}
|
||||
|
@ -143,6 +143,14 @@ impl<'a, 'h> Generator<'a, 'h> {
|
||||
};",
|
||||
);
|
||||
|
||||
if let Some(ref full_config_path) = self.input.config.full_config_path() {
|
||||
buf.write(format_args!(
|
||||
"const _: &[askama::helpers::core::primitive::u8] =\
|
||||
askama::helpers::core::include_bytes!({:?});",
|
||||
full_config_path.display()
|
||||
));
|
||||
}
|
||||
|
||||
// Make sure the compiler understands that the generated code depends on the template files.
|
||||
let mut paths = self
|
||||
.contexts
|
||||
|
@ -1059,7 +1059,7 @@ const JINJA_EXTENSIONS: &[&str] = &["askama", "j2", "jinja", "jinja2", "rinja"];
|
||||
|
||||
#[test]
|
||||
fn get_source() {
|
||||
let path = Config::new("", None, None, None)
|
||||
let path = Config::new("", None, None, None, None)
|
||||
.and_then(|config| config.find_template("b.html", None, None))
|
||||
.unwrap();
|
||||
assert_eq!(get_template_source(&path, None).unwrap(), "bar".into());
|
||||
|
@ -260,7 +260,7 @@ pub fn derive_template(input: TokenStream12) -> TokenStream12 {
|
||||
|
||||
fn build_skeleton(buf: &mut Buffer, ast: &syn::DeriveInput) -> Result<usize, CompileError> {
|
||||
let template_args = TemplateArgs::fallback();
|
||||
let config = Config::new("", None, None, None)?;
|
||||
let config = Config::new("", None, None, None, None)?;
|
||||
let input = TemplateInput::new(ast, None, config, &template_args)?;
|
||||
let mut contexts = HashMap::default();
|
||||
let parsed = parser::Parsed::default();
|
||||
@ -315,12 +315,13 @@ fn build_template_item(
|
||||
tmpl_kind: TmplKind<'_>,
|
||||
) -> Result<usize, CompileError> {
|
||||
let config_path = template_args.config_path();
|
||||
let s = read_config_file(config_path, template_args.config_span)?;
|
||||
let (s, full_config_path) = read_config_file(config_path, template_args.config_span)?;
|
||||
let config = Config::new(
|
||||
&s,
|
||||
config_path,
|
||||
template_args.whitespace,
|
||||
template_args.config_span,
|
||||
full_config_path,
|
||||
)?;
|
||||
let input = TemplateInput::new(ast, enum_ast, config, template_args)?;
|
||||
|
||||
|
@ -2,7 +2,7 @@ use askama::Template;
|
||||
|
||||
#[derive(Template)] // this will generate the code...
|
||||
#[template(path = "hello.html")] // using the template in this path, relative
|
||||
// to the templates dir in the crate root
|
||||
// to the templates dir in the crate root
|
||||
struct HelloTemplate<'a> {
|
||||
// the name of the struct can be anything
|
||||
name: &'a str, // the field name should match the variable name
|
||||
|
Loading…
x
Reference in New Issue
Block a user