Skip to main content

turbo_tasks_fs/embed/
dir.rs

1use std::path::Path;
2
3pub use ::include_dir::{
4    include_dir, {self},
5};
6use anyhow::Result;
7use turbo_rcstr::RcStr;
8use turbo_tasks::Vc;
9
10use crate::{DiskFileSystem, FileSystem, canonicalize_to_rcstr, embed::EmbeddedFileSystem};
11
12#[turbo_tasks::function]
13pub async fn directory_from_relative_path(
14    name: RcStr,
15    path: RcStr,
16) -> Result<Vc<Box<dyn FileSystem>>> {
17    // note: canonicalizing inside of a turbo-tasks function causes an untracked read of the root
18    // directory path (e.g. if it's a symlink), but it's okay because this codepath is only used in
19    // development and the root directory is unlikely to move.
20    let root = canonicalize_to_rcstr(Path::new(&*path))?;
21    let disk_fs = DiskFileSystem::new(name, Vc::cell(root));
22    disk_fs.await?.start_watching().await?;
23
24    Ok(Vc::upcast(disk_fs))
25}
26
27pub fn directory_from_include_dir(
28    name: RcStr,
29    dir: &'static include_dir::Dir<'static>,
30) -> Vc<Box<dyn FileSystem>> {
31    Vc::upcast(EmbeddedFileSystem::new(name, dir))
32}
33
34/// Returns an embedded [`Vc<Box<dyn FileSystem>>`][FileSystem] for the given path.
35///
36/// This will embed a directory's content into the binary and create an
37/// [`Vc<EmbeddedFileSystem>`][EmbeddedFileSystem].
38///
39/// If you enable the `dynamic_embed_contents` feature, calling the macro will return a
40/// [`Vc<DiskFileSystem>`][DiskFileSystem].
41///
42/// This enables dynamic linking (and hot reloading) of embedded files/dirs. A binary built with
43/// `dynamic_embed_contents` enabled is **is not portable**, only the directory path will be
44/// embedded into the binary.
45#[macro_export]
46macro_rules! embed_directory {
47    ($name:tt, $path:tt) => {{        // make sure the path contains `$CARGO_MANIFEST_DIR`
48        assert!($path.contains("$CARGO_MANIFEST_DIR"));
49        // make sure `CARGO_MANIFEST_DIR` is the only env variable in the path
50        assert!(!$path.replace("$CARGO_MANIFEST_DIR", "").contains('$'));
51
52        turbo_tasks_fs::embed_directory_internal!($name, $path)
53    }};
54}
55
56#[cfg(feature = "dynamic_embed_contents")]
57#[macro_export]
58#[doc(hidden)]
59macro_rules! embed_directory_internal {
60    ($name:tt, $path:tt) => {{
61        // make sure the types the `include_dir!` proc macro refers to are in scope
62        use turbo_tasks_fs::embed::include_dir;
63
64        let path = $path.replace("$CARGO_MANIFEST_DIR", env!("CARGO_MANIFEST_DIR"));
65
66        turbo_tasks_fs::embed::directory_from_relative_path($name.into(), path.into())
67    }};
68}
69
70#[cfg(not(feature = "dynamic_embed_contents"))]
71#[macro_export]
72#[doc(hidden)]
73macro_rules! embed_directory_internal {
74    ($name:tt, $path:tt) => {{
75        // make sure the types the `include_dir!` proc macro refers to are in scope
76        use turbo_tasks_fs::embed::include_dir;
77
78        static DIR: include_dir::Dir<'static> = turbo_tasks_fs::embed::include_dir!($path);
79
80        turbo_tasks_fs::embed::directory_from_include_dir($name.into(), &DIR)
81    }};
82}