~repos /rust-embed

#rust#proc-macro#http

git clone https://pyrossh.dev/repos/rust-embed.git
Discussions: https://groups.google.com/g/rust-embed-devs

rust macro which loads files into the rust binary at compile time during release and loads the file from the fs during dev.


Files changed (1) hide show
  1. impl/src/lib.rs +40 -18
impl/src/lib.rs CHANGED
@@ -6,10 +6,16 @@ extern crate proc_macro;
6
6
 
7
7
  use proc_macro::TokenStream;
8
8
  use proc_macro2::TokenStream as TokenStream2;
9
+ use std::{
10
+ env,
11
+ iter::FromIterator,
9
- use std::{env, path::Path};
12
+ path::{Path, PathBuf},
13
+ };
10
14
  use syn::{Data, DeriveInput, Expr, ExprLit, Fields, Lit, Meta, MetaNameValue};
11
15
 
16
+ fn embedded(
12
- fn embedded(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includes: &[String], excludes: &[String]) -> TokenStream2 {
17
+ ident: &syn::Ident, relative_folder_path: Option<&str>, absolute_folder_path: String, prefix: Option<&str>, includes: &[String], excludes: &[String],
18
+ ) -> TokenStream2 {
13
19
  extern crate rust_embed_utils;
14
20
 
15
21
  let mut match_values = Vec::<TokenStream2>::new();
@@ -17,8 +23,8 @@ fn embedded(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, inclu
17
23
 
18
24
  let includes: Vec<&str> = includes.iter().map(AsRef::as_ref).collect();
19
25
  let excludes: Vec<&str> = excludes.iter().map(AsRef::as_ref).collect();
20
- for rust_embed_utils::FileEntry { rel_path, full_canonical_path } in rust_embed_utils::get_files(folder_path, &includes, &excludes) {
26
+ for rust_embed_utils::FileEntry { rel_path, full_canonical_path } in rust_embed_utils::get_files(absolute_folder_path.clone(), &includes, &excludes) {
21
- match_values.push(embed_file(&rel_path, &full_canonical_path));
27
+ match_values.push(embed_file(relative_folder_path.clone(), &rel_path, &full_canonical_path));
22
28
 
23
29
  list_values.push(if let Some(prefix) = prefix {
24
30
  format!("{}{}", prefix, rel_path)
@@ -153,13 +159,22 @@ fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includ
153
159
  }
154
160
  }
155
161
 
162
+ fn generate_assets(
156
- fn generate_assets(ident: &syn::Ident, folder_path: String, prefix: Option<String>, includes: Vec<String>, excludes: Vec<String>) -> TokenStream2 {
163
+ ident: &syn::Ident, relative_folder_path: Option<&str>, absolute_folder_path: String, prefix: Option<String>, includes: Vec<String>, excludes: Vec<String>,
164
+ ) -> TokenStream2 {
157
- let embedded_impl = embedded(ident, folder_path.clone(), prefix.as_deref(), &includes, &excludes);
165
+ let embedded_impl = embedded(
166
+ ident,
167
+ relative_folder_path,
168
+ absolute_folder_path.clone(),
169
+ prefix.as_deref(),
170
+ &includes,
171
+ &excludes,
172
+ );
158
173
  if cfg!(feature = "debug-embed") {
159
174
  return embedded_impl;
160
175
  }
161
176
 
162
- let dynamic_impl = dynamic(ident, folder_path, prefix.as_deref(), &includes, &excludes);
177
+ let dynamic_impl = dynamic(ident, absolute_folder_path, prefix.as_deref(), &includes, &excludes);
163
178
 
164
179
  quote! {
165
180
  #embedded_impl
@@ -167,7 +182,7 @@ fn generate_assets(ident: &syn::Ident, folder_path: String, prefix: Option<Strin
167
182
  }
168
183
  }
169
184
 
170
- fn embed_file(rel_path: &str, full_canonical_path: &str) -> TokenStream2 {
185
+ fn embed_file(folder_path: Option<&str>, rel_path: &str, full_canonical_path: &str) -> TokenStream2 {
171
186
  let file = rust_embed_utils::read_file_from_fs(Path::new(full_canonical_path)).expect("File should be readable");
172
187
  let hash = file.metadata.sha256_hash();
173
188
  let last_modified = match file.metadata.last_modified() {
@@ -183,8 +198,11 @@ fn embed_file(rel_path: &str, full_canonical_path: &str) -> TokenStream2 {
183
198
  let mimetype_tokens = TokenStream2::new();
184
199
 
185
200
  let embedding_code = if cfg!(feature = "compression") {
201
+ // Print some debugging information
202
+ let full_relative_path = PathBuf::from_iter([folder_path.expect("folder_path must be provided under `compression` feature"), rel_path]);
203
+ let full_relative_path = full_relative_path.to_string_lossy();
186
204
  quote! {
187
- rust_embed::flate!(static FILE: [u8] from #full_canonical_path);
205
+ rust_embed::flate!(static FILE: [u8] from #full_relative_path);
188
206
  let bytes = &FILE[..];
189
207
  }
190
208
  } else {
@@ -249,26 +267,30 @@ fn impl_rust_embed(ast: &syn::DeriveInput) -> TokenStream2 {
249
267
  let folder_path = shellexpand::full(&folder_path).unwrap().to_string();
250
268
 
251
269
  // Base relative paths on the Cargo.toml location
252
- let folder_path = if Path::new(&folder_path).is_relative() {
270
+ let (relative_path, absolute_folder_path) = if Path::new(&folder_path).is_relative() {
253
- Path::new(&env::var("CARGO_MANIFEST_DIR").unwrap())
271
+ let absolute_path = Path::new(&env::var("CARGO_MANIFEST_DIR").unwrap())
254
- .join(folder_path)
272
+ .join(&folder_path)
255
273
  .to_str()
256
274
  .unwrap()
257
- .to_owned()
275
+ .to_owned();
276
+ (Some(folder_path.clone()), absolute_path)
258
277
  } else {
278
+ if cfg!(feature = "compression") {
279
+ panic!("`folder` must be a relative path under `compression` feature.")
280
+ }
259
- folder_path
281
+ (None, folder_path)
260
282
  };
261
283
 
262
- if !Path::new(&folder_path).exists() {
284
+ if !Path::new(&absolute_folder_path).exists() {
263
285
  let mut message = format!(
264
286
  "#[derive(RustEmbed)] folder '{}' does not exist. cwd: '{}'",
265
- folder_path,
287
+ absolute_folder_path,
266
288
  std::env::current_dir().unwrap().to_str().unwrap()
267
289
  );
268
290
 
269
291
  // Add a message about the interpolate-folder-path feature if the path may
270
292
  // include a variable
271
- if folder_path.contains('$') && cfg!(not(feature = "interpolate-folder-path")) {
293
+ if absolute_folder_path.contains('$') && cfg!(not(feature = "interpolate-folder-path")) {
272
294
  message += "\nA variable has been detected. RustEmbed can expand variables \
273
295
  when the `interpolate-folder-path` feature is enabled.";
274
296
  }
@@ -276,7 +298,7 @@ fn impl_rust_embed(ast: &syn::DeriveInput) -> TokenStream2 {
276
298
  panic!("{}", message);
277
299
  };
278
300
 
279
- generate_assets(&ast.ident, folder_path, prefix, includes, excludes)
301
+ generate_assets(&ast.ident, relative_path.as_deref(), absolute_folder_path, prefix, includes, excludes)
280
302
  }
281
303
 
282
304
  #[proc_macro_derive(RustEmbed, attributes(folder, prefix, include, exclude))]