diff options
author | Lars Wirzenius <liw@liw.fi> | 2021-10-05 12:02:56 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2021-10-13 10:04:59 +0300 |
commit | 5855c963b8c1e1748f50301ddcc21a923be60240 (patch) | |
tree | 2b53f37057da8b93e9b67250de9104d7c0883795 /src | |
parent | 2459137129c64e02a2948f6c5f9e17bf56742c64 (diff) | |
download | subplot-5855c963b8c1e1748f50301ddcc21a923be60240.tar.gz |
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
Diffstat (limited to 'src')
-rw-r--r-- | src/bin/cli/mod.rs | 44 | ||||
-rw-r--r-- | src/bin/subplot.rs | 34 | ||||
-rw-r--r-- | src/doc.rs | 93 | ||||
-rw-r--r-- | src/lib.rs | 1 | ||||
-rw-r--r-- | src/resource.rs | 2 |
5 files changed, 101 insertions, 73 deletions
diff --git a/src/bin/cli/mod.rs b/src/bin/cli/mod.rs index c53da0f..84bda10 100644 --- a/src/bin/cli/mod.rs +++ b/src/bin/cli/mod.rs @@ -11,50 +11,6 @@ use std::str::FromStr; use subplot::{DataFile, Document, Style, SubplotError}; use tracing::{event, instrument, Level}; -#[instrument(level = "trace")] -pub fn load_document<P>(filename: P, style: Style) -> Result<Document> -where - P: AsRef<Path> + Debug, -{ - let filename = filename.as_ref(); - let base_path = subplot::get_basedir_from(filename); - event!( - Level::TRACE, - ?filename, - ?base_path, - "Loading document based at `{}` called `{}` with {:?}", - base_path.display(), - filename.display(), - style - ); - let doc = Document::from_file(&base_path, filename, style)?; - event!(Level::TRACE, "Loaded doc from file OK"); - - Ok(doc) -} - -#[instrument(level = "trace")] -pub fn load_document_with_pullmark<P>(filename: P, style: Style) -> Result<Document> -where - P: AsRef<Path> + Debug, -{ - let filename = filename.as_ref(); - let base_path = subplot::get_basedir_from(filename); - event!( - Level::TRACE, - ?filename, - ?base_path, - "Loading document based at `{}` called `{}` with {:?} using pullmark-cmark", - base_path.display(), - filename.display(), - style - ); - let doc = Document::from_file_with_pullmark(&base_path, filename, style)?; - event!(Level::TRACE, "Loaded doc from file OK"); - - Ok(doc) -} - pub fn extract_file<'a>(doc: &'a Document, filename: &str) -> Result<&'a DataFile> { for file in doc.files() { if file.filename() == filename { diff --git a/src/bin/subplot.rs b/src/bin/subplot.rs index 3e865fb..8d4a660 100644 --- a/src/bin/subplot.rs +++ b/src/bin/subplot.rs @@ -5,9 +5,7 @@ use anyhow::Result; use chrono::{Local, TimeZone}; use structopt::StructOpt; -use subplot::{ - generate_test_program, resource, template_spec, DataFile, Document, MarkupOpts, Style, -}; +use subplot::{codegen, load_document, resource, DataFile, Document, MarkupOpts, Style}; use tracing::{event, instrument, span, Level, Subscriber}; use std::convert::TryFrom; @@ -162,7 +160,7 @@ impl Extract { fn run(&self) -> Result<()> { let span = span!(Level::TRACE, "extract"); let _enter = span.enter(); - let doc = cli::load_document(&self.filename, Style::default())?; + let doc = load_document(&self.filename, Style::default())?; let files: Vec<&DataFile> = if self.embedded.is_empty() { doc.files() @@ -268,7 +266,7 @@ impl Metadata { fn run(&self) -> Result<()> { let span = span!(Level::TRACE, "metadata"); let _enter = span.enter(); - let mut doc = cli::load_document(&self.filename, Style::default())?; + let mut doc = load_document(&self.filename, Style::default())?; let meta = cli::Metadata::try_from(&mut doc)?; match self.output_format { cli::OutputFormat::Plain => meta.write_out(), @@ -310,7 +308,7 @@ impl Docgen { event!(Level::TRACE, "PDF output chosen"); style.typeset_links_as_notes(); } - let mut doc = cli::load_document(&self.input, style)?; + let mut doc = load_document(&self.input, style)?; event!(Level::TRACE, "Got doc, now linting it"); doc.lint()?; event!(Level::TRACE, "Doc linted ok"); @@ -415,32 +413,14 @@ impl Codegen { fn run(&self) -> Result<()> { let span = span!(Level::TRACE, "codegen"); let _enter = span.enter(); - let mut doc = cli::load_document_with_pullmark(&self.filename, Style::default())?; - doc.lint()?; - let template = doc - .meta() - .template_name() - .ok_or_else(|| anyhow::anyhow!("No template name given"))? - .to_string(); - event!(Level::TRACE, ?template); - if !doc.check_named_files_exist(&template)? || !doc.check_matched_steps_have_impl(&template) - { - event!(Level::ERROR, "Found problems in document, cannot continue"); - eprintln!("Unable to continue"); - std::process::exit(1); - } - - event!(Level::TRACE, "Generating code"); - let spec = template_spec(&doc)?; - generate_test_program(&mut doc, &spec, &self.output, &template)?; - event!(Level::TRACE, "Finished generating code"); + let output = codegen(&self.filename, &self.output)?; if self.run { - let run = match spec.run() { + let run = match output.spec.run() { None => { eprintln!( "Template {} does not specify how to run suites", - spec.template_filename().display() + output.spec.template_filename().display() ); std::process::exit(1); } @@ -1,4 +1,6 @@ use crate::ast; +use crate::generate_test_program; +use crate::get_basedir_from; use crate::visitor; use crate::DataFile; use crate::DataFiles; @@ -10,6 +12,7 @@ use crate::Scenario; use crate::ScenarioStep; use crate::Style; use crate::{bindings::CaptureType, parser::parse_scenario_snippet}; +use crate::{template_spec, TemplateSpec}; use crate::{Result, SubplotError}; use std::collections::HashSet; @@ -21,7 +24,7 @@ use std::str::FromStr; use pandoc_ast::{MutVisitor, Pandoc}; -use tracing::{event, instrument, Level}; +use tracing::{event, instrument, span, Level}; /// The set of known (special) classes which subplot will always recognise /// as being valid. @@ -421,6 +424,94 @@ impl<'a> Document { } } +/// Load a `Document` from a file. +/// +/// This version uses Pandoc to parse the Markdown. +#[instrument(level = "trace")] +pub fn load_document<P>(filename: P, style: Style) -> Result<Document> +where + P: AsRef<Path> + Debug, +{ + let filename = filename.as_ref(); + let base_path = get_basedir_from(filename); + event!( + Level::TRACE, + ?filename, + ?base_path, + "Loading document based at `{}` called `{}` with {:?}", + base_path.display(), + filename.display(), + style + ); + let doc = Document::from_file(&base_path, filename, style)?; + event!(Level::TRACE, "Loaded doc from file OK"); + + Ok(doc) +} + +/// Load a `Document` from a file. +/// +/// This version uses the `cmark-pullmark` crate to parse Markdown. +#[instrument(level = "trace")] +pub fn load_document_with_pullmark<P>(filename: P, style: Style) -> Result<Document> +where + P: AsRef<Path> + Debug, +{ + let filename = filename.as_ref(); + let base_path = get_basedir_from(filename); + event!( + Level::TRACE, + ?filename, + ?base_path, + "Loading document based at `{}` called `{}` with {:?} using pullmark-cmark", + base_path.display(), + filename.display(), + style + ); + crate::resource::add_search_path(filename.parent().unwrap()); + let doc = Document::from_file_with_pullmark(&base_path, filename, style)?; + event!(Level::TRACE, "Loaded doc from file OK"); + Ok(doc) +} + +/// Generate code for one document. +pub fn codegen(filename: &Path, output: &Path) -> Result<CodegenOutput> { + let span = span!(Level::TRACE, "codegen"); + let _enter = span.enter(); + + let mut doc = load_document_with_pullmark(filename, Style::default())?; + doc.lint()?; + let template = doc + .meta() + .template_name() + .ok_or(SubplotError::MissingTemplate)? + .to_string(); + event!(Level::TRACE, ?template); + if !doc.check_named_files_exist(&template)? || !doc.check_matched_steps_have_impl(&template) { + event!(Level::ERROR, "Found problems in document, cannot continue"); + eprintln!("Unable to continue"); + std::process::exit(1); + } + + event!(Level::TRACE, "Generating code"); + let spec = template_spec(&doc)?; + generate_test_program(&mut doc, &spec, output, &template)?; + event!(Level::TRACE, "Finished generating code"); + + Ok(CodegenOutput::new(spec, doc)) +} + +pub struct CodegenOutput { + pub spec: TemplateSpec, + pub doc: Document, +} + +impl CodegenOutput { + fn new(spec: TemplateSpec, doc: Document) -> Self { + Self { spec, doc } + } +} + fn extract_scenario(e: &[visitor::Element]) -> Result<(Option<Scenario>, usize)> { if e.is_empty() { // If we get here, it's a programming error. @@ -40,6 +40,7 @@ pub use metadata::Metadata; mod doc; pub use doc::Document; +pub use doc::{codegen, load_document, load_document_with_pullmark}; mod style; pub use style::Style; diff --git a/src/resource.rs b/src/resource.rs index 43967ef..336c4e2 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -55,7 +55,7 @@ pub fn embedded_files() -> &'static [(&'static str, &'static [u8])] { } /// Put a path at the back of the queue to search in -fn add_search_path<P: AsRef<Path>>(path: P) { +pub fn add_search_path<P: AsRef<Path>>(path: P) { SEARCH_PATHS .lock() .expect("Unable to lock SEARCH_PATHS") |