From 5855c963b8c1e1748f50301ddcc21a923be60240 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Tue, 5 Oct 2021 12:02:56 +0300 Subject: feat: add crate subplot-build for using Subplot from build.rs Make it easy to generate test code from a subplot in another project's `build.rs` script. Move the code to load documents and generate test code from src/bin/subplot.rs and src/bin/cli/mod.rs to src/doc.rs so it can be used without using the subplot executable. Make the add_search_path function public so it can be used outside its module. The subplot executable arranged for the directory where the markdown input file resides to be added to the search path via another way. Sponsored-by: pep.foundation --- subplot-build/Cargo.toml | 19 +++++++++++ subplot-build/src/lib.rs | 83 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 subplot-build/Cargo.toml create mode 100644 subplot-build/src/lib.rs (limited to 'subplot-build') diff --git a/subplot-build/Cargo.toml b/subplot-build/Cargo.toml new file mode 100644 index 0000000..40e4bac --- /dev/null +++ b/subplot-build/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "subplot-build" +version = "0.1.0" +authors = [ + "Lars Wirzenius ", + "Daniel Silverstone ", +] +edition = "2018" +license = "GPL-3.0-or-later" +description = '''A library for using Subplot code generation from another project's +`build.rs` module.''' +homepage = "https://subplot.liw.fi/" +repository = "https://gitlab.com/subplot/subplot" + + +[dependencies] +subplot = { version="0.2.2", path = ".." } +tracing = "0.1" +tempfile = "3.1.0" diff --git a/subplot-build/src/lib.rs b/subplot-build/src/lib.rs new file mode 100644 index 0000000..89ea57d --- /dev/null +++ b/subplot-build/src/lib.rs @@ -0,0 +1,83 @@ +//! Subplot test program building from `build.rs` +//! +//! This crate provides the Subplot code generation facility in a way +//! that's meant to be easy to use from another project's `build.rs` +//! module. + +use std::env::var_os; +use std::fmt::Debug; +use std::path::{Path, PathBuf}; +use subplot::{get_basedir_from, Result}; +use tracing::{event, instrument, span, Level}; + +/// Generate code for one document, inside `build.rs`. +/// +/// The output files will be written to the directory specified in the +/// OUT_DIR environment variable. That variable is set by Cargo, when +/// a crate is built. +/// +/// Also emit instructions for Cargo so it knows to re-run `build.rs` +/// whenever the input subplot or any of the bindings or functions +/// files it refers to changes. See +/// for +/// details. +/// +/// ``` +/// use subplot_build::codegen; +/// # let dir = tempfile::tempdir().unwrap(); +/// # std::env::set_var("OUT_DIR", dir.path()); +/// +/// codegen("foo.md").ok(); // ignoring error to keep example short +/// # dir.close().unwrap() +/// ``` +#[instrument(level = "trace")] +pub fn codegen

(filename: P) -> Result<()> +where + P: AsRef + Debug, +{ + let span = span!(Level::TRACE, "codegen_buildrs"); + let _enter = span.enter(); + + event!(Level::TRACE, "Generating code in build.rs"); + + // Decide the name of the generated test program. + let out_dir = var_os("OUT_DIR").expect("OUT_DIR is not defined in the environment"); + let out_dir = Path::new(&out_dir); + let filename = filename.as_ref(); + let test_rs = + buildrs_output(out_dir, filename, "rs").expect("could not create output filename"); + + // Generate test program. + let output = subplot::codegen(filename, &test_rs)?; + + // Write instructions for Cargo to check if build scripts needs + // re-running. + let base_path = get_basedir_from(filename); + let meta = output.doc.meta(); + buildrs_deps(&base_path, &meta.bindings_filenames()); + buildrs_deps(&base_path, &meta.functions_filenames()); + buildrs_deps(&base_path, &[filename]); + + event!(Level::TRACE, "Finished generating code"); + Ok(()) +} + +fn buildrs_deps(base_path: &Path, filenames: &[&Path]) { + for filename in filenames { + let filename = base_path.join(filename); + if filename.exists() { + println!("cargo:rerun-if-changed={}", filename.display()); + } + } +} + +fn buildrs_output(dir: &Path, filename: &Path, new_extension: &str) -> Option { + if let Some(basename) = filename.file_name() { + let basename = Path::new(basename); + if let Some(stem) = basename.file_stem() { + let stem = Path::new(stem); + return Some(dir.join(stem.with_extension(new_extension))); + } + } + None +} -- cgit v1.2.1