diff --git a/crates/mdbook-core/src/config.rs b/crates/mdbook-core/src/config.rs index b2c6862c30..5584225e95 100644 --- a/crates/mdbook-core/src/config.rs +++ b/crates/mdbook-core/src/config.rs @@ -518,6 +518,12 @@ pub struct HtmlConfig { /// If enabled, the sidebar includes navigation for headers on the current /// page. Default is `true`. pub sidebar_header_nav: bool, + /// File extensions to exclude when copying files from the source directory. + /// These files will not be copied to the output directory. + /// By default, only `.md` files are excluded. + /// Example: `["md", "rs", "toml"]` + #[serde(rename = "copy-exclude-extensions")] + pub copy_exclude_extensions: Vec, } impl Default for HtmlConfig { @@ -548,6 +554,7 @@ impl Default for HtmlConfig { redirect: HashMap::new(), hash_files: true, sidebar_header_nav: true, + copy_exclude_extensions: Vec::new(), } } } diff --git a/crates/mdbook-html/src/html_handlebars/hbs_renderer.rs b/crates/mdbook-html/src/html_handlebars/hbs_renderer.rs index 8edac3cace..c8114da13d 100644 --- a/crates/mdbook-html/src/html_handlebars/hbs_renderer.rs +++ b/crates/mdbook-html/src/html_handlebars/hbs_renderer.rs @@ -444,7 +444,12 @@ impl Renderer for HtmlHandlebars { .context("Unable to emit redirects")?; // Copy all remaining files, avoid a recursive copy from/to the book build dir - fs::copy_files_except_ext(&src_dir, destination, true, Some(&build_dir), &["md"])?; + let exclude_exts: Vec<&str> = html_config + .copy_exclude_extensions + .iter() + .map(|s| s.as_str()) + .collect(); + fs::copy_files_except_ext(&src_dir, destination, true, Some(&build_dir), &exclude_exts)?; info!("HTML book written to `{}`", destination.display()); diff --git a/guide/src/cli/build.md b/guide/src/cli/build.md index a342741798..98a187613e 100644 --- a/guide/src/cli/build.md +++ b/guide/src/cli/build.md @@ -34,7 +34,24 @@ book. Relative paths are interpreted relative to the current directory. If not specified it will default to the value of the `build.build-dir` key in `book.toml`, or to `./book`. +#### `--copy-exclude-extensions` + +The `--copy-exclude-extensions` option allows you to exclude specific file extensions +when copying files from the source directory to the build directory. This is useful when +your source directory contains symlinks to other directories with files you don't want to +include in the output. + +Provide a comma-separated list of extensions (without dots): + +```bash +mdbook build --copy-exclude-extensions rs,toml,lock +``` + +This supplements any extensions configured in `book.toml` via the +`output.html.copy-exclude-extensions` setting. + ------------------- -***Note:*** *The build command copies all files (excluding files with `.md` extension) from the source directory -into the build directory.* +***Note:*** *The build command copies all files from the source directory into the build directory. +You can exclude specific file extensions using the `--copy-exclude-extensions` flag or the +`output.html.copy-exclude-extensions` configuration option.* diff --git a/guide/src/format/configuration/renderers.md b/guide/src/format/configuration/renderers.md index 22dfd425fb..c338e4630b 100644 --- a/guide/src/format/configuration/renderers.md +++ b/guide/src/format/configuration/renderers.md @@ -111,6 +111,7 @@ site-url = "/example-book/" cname = "myproject.rs" input-404 = "not-found.md" sidebar-header-nav = true +copy-exclude-extensions = ["rs", "toml"] ``` The following configuration options are available: @@ -170,6 +171,10 @@ The following configuration options are available: Static CSS and JS files can reference each other using `{{ resource "filename" }}` directives. Defaults to `true`. - **sidebar-header-nav:** If `true`, the sidebar will contain navigation for headers on the current page. Default is `true`. +- **copy-exclude-extensions:** A list of file extensions to exclude when copying files from the source directory + to the build directory. By default, all files are copied. This is useful when your source directory contains + symlinks to other directories with files you don't want to include in the output. Provide extensions without dots. + Example: `["rs", "toml", "lock"]`. Defaults to `[]` (no exclusions). [custom domain]: https://docs.github.com/en/github/working-with-github-pages/managing-a-custom-domain-for-your-github-pages-site diff --git a/src/cmd/build.rs b/src/cmd/build.rs index 41536cae85..56fafa2a90 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -11,6 +11,7 @@ pub fn make_subcommand() -> Command { .arg_dest_dir() .arg_root_dir() .arg_open() + .arg_copy_exclude_extensions() } // Build command implementation @@ -20,6 +21,20 @@ pub fn execute(args: &ArgMatches) -> Result<()> { set_dest_dir(args, &mut book); + // Apply CLI copy-exclude-extensions to config + if let Some(exts) = args.get_one::("copy-exclude-extensions") { + let additional_exts: Vec = exts + .split(',') + .map(|s| s.trim().to_string()) + .filter(|s| !s.is_empty()) + .collect(); + + if let Ok(Some(mut html_config)) = book.config.get::("output.html") { + html_config.copy_exclude_extensions.extend(additional_exts); + book.config.set("output.html", html_config)?; + } + } + book.build()?; if args.get_flag("open") { diff --git a/src/cmd/command_prelude.rs b/src/cmd/command_prelude.rs index b2a91ae972..cb39f27b7c 100644 --- a/src/cmd/command_prelude.rs +++ b/src/cmd/command_prelude.rs @@ -38,6 +38,19 @@ pub trait CommandExt: Sized { self._arg(arg!(-o --open "Opens the compiled book in a web browser")) } + fn arg_copy_exclude_extensions(self) -> Self { + self._arg( + Arg::new("copy-exclude-extensions") + .long("copy-exclude-extensions") + .value_name("EXTENSIONS") + .help( + "Comma-separated list of file extensions to exclude when copying files\n\ + from the source directory (e.g., 'rs,toml,lock')\n\ + This supplements any extensions configured in book.toml.", + ) + ) + } + #[cfg(any(feature = "watch", feature = "serve"))] fn arg_watcher(self) -> Self { #[cfg(feature = "watch")]