From 9318464daaee62481f7f80105bc2ec14c9c01e16 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Sat, 22 Oct 2022 10:49:32 +0100 Subject: (derive): Support steps with &Path arguments Signed-off-by: Daniel Silverstone --- subplotlib-derive/src/lib.rs | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/subplotlib-derive/src/lib.rs b/subplotlib-derive/src/lib.rs index 86f5c5e..7aef0dc 100644 --- a/subplotlib-derive/src/lib.rs +++ b/subplotlib-derive/src/lib.rs @@ -29,6 +29,25 @@ fn ty_is_borrow_str(ty: &Type) -> bool { } } +fn ty_is_borrow_path(ty: &Type) -> bool { + if let Type::Reference(ty) = ty { + if ty.mutability.is_none() && ty.lifetime.is_none() { + if let Type::Path(pp) = &*ty.elem { + pp.path.is_ident("Path") + } else { + // not a path, so not &Path + false + } + } else { + // mutable, or a lifetime stated, so not &Path + false + } + } else { + // Not & so not &Path + false + } +} + fn ty_is_datafile(ty: &Type) -> bool { if let Type::Path(ty) = ty { ty.path.is_ident("SubplotDataFile") @@ -242,6 +261,8 @@ fn process_step(mut input: ItemFn) -> proc_macro2::TokenStream { .map(|(id, ty)| { let ty = if ty_is_borrow_str(ty) { parse_quote!(::std::string::String) + } else if ty_is_borrow_path(ty) { + parse_quote!(::std::path::PathBuf) } else { ty.clone() }; @@ -278,6 +299,13 @@ fn process_step(mut input: ItemFn) -> proc_macro2::TokenStream { self } } + } else if ty_is_borrow_path(ty) { + quote! { + pub fn #id>(mut self, value: P) -> Self { + self.#id = value.into(); + self + } + } } else { quote! { pub fn #id(mut self, value: #ty) -> Self { @@ -292,7 +320,7 @@ fn process_step(mut input: ItemFn) -> proc_macro2::TokenStream { let buildargs: Vec<_> = fields .iter() .map(|(id, ty)| { - if ty_is_borrow_str(ty) { + if ty_is_borrow_str(ty) || ty_is_borrow_path(ty) { quote! { &self.#id } -- cgit v1.2.1 From fd6afa6061b36ee8e7cd656afef8f052fe3d75da Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Sat, 22 Oct 2022 10:49:59 +0100 Subject: (rust template): Support a 'path' arg type to pass PathBufs in Signed-off-by: Daniel Silverstone --- share/rust/template/macros.rs.tera | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/share/rust/template/macros.rs.tera b/share/rust/template/macros.rs.tera index 7a65e0f..104eb23 100644 --- a/share/rust/template/macros.rs.tera +++ b/share/rust/template/macros.rs.tera @@ -8,8 +8,7 @@ {% if type in ['number', 'int', 'uint'] %}{{text}} {%- elif type in ['text', 'word']%} // "{{text | commentsafe }}" - &base64_decode("{{text | base64}}" - ) + &base64_decode("{{text | base64}}") {%- elif type in ['file'] %} { use std::path::PathBuf; @@ -21,6 +20,8 @@ .expect("Unable to find file at runtime") .clone() } + {%- elif type in ['path'] %} + std::path::PathBuf::from(base64_decode("{{ text | base64 }}")) {%- else %} /* WOAH unknown type {{step.types[name]}} */ {{text}} {%- endif %} ) -- cgit v1.2.1 From 5ce95579e42171913b0fabbb51b2beca66854ae4 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Sat, 22 Oct 2022 10:50:23 +0100 Subject: (bindings): Add path type to bindings support Signed-off-by: Daniel Silverstone --- src/bindings.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/bindings.rs b/src/bindings.rs index 8c33cc4..8e3531b 100644 --- a/src/bindings.rs +++ b/src/bindings.rs @@ -49,6 +49,10 @@ pub enum CaptureType { /// for one of the embedded files in the document, otherwise codegen will /// refuse to run. File, + + /// Paths are sequences of non-whitespace characters which will be interpreted + /// as a file-path (e.g. PathBuf) or similar when processed by a step + Path, } impl FromStr for CaptureType { @@ -62,6 +66,7 @@ impl FromStr for CaptureType { "uint" => Ok(Self::Uint), "number" => Ok(Self::Number), "file" => Ok(Self::File), + "path" => Ok(Self::Path), _ => Err(SubplotError::UnknownTypeInBinding(value.to_string())), } } @@ -77,6 +82,7 @@ impl CaptureType { Self::Uint => "uint", Self::Number => "number", Self::File => "file", + Self::Path => "path", } } @@ -89,6 +95,7 @@ impl CaptureType { Self::Uint => r"\d+", Self::Number => r"-?\d+(\.\d+)?", Self::File => r"\S+", + Self::Path => r"\S+", } } } @@ -787,6 +794,7 @@ lazy_static! { CaptureType::Uint, CaptureType::Number, CaptureType::File, + CaptureType::Path, ]).iter().copied() { // This Unwrap is okay because we shouldn't have any bugs in the // regular expressions here, and if we did, it'd be bad for everyone -- cgit v1.2.1 From 7f52ffc37e1a366f78ba3709f15b09ca22ca98c9 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Sat, 22 Oct 2022 10:50:41 +0100 Subject: (steplibrary): Update files and runcmd to use new path type Signed-off-by: Daniel Silverstone --- share/common/lib/files.yaml | 68 ++++++++++++++++++++++++---- share/common/lib/runcmd.yaml | 12 ++++- subplotlib/src/steplibrary/files.rs | 83 +++++++++++++++++++--------------- subplotlib/src/steplibrary/runcmd.rs | 12 +++-- tests/subplots/common/runcmd_test.rs | 5 +- tests/subplots/common/runcmd_test.yaml | 7 ++- 6 files changed, 130 insertions(+), 57 deletions(-) diff --git a/share/common/lib/files.yaml b/share/common/lib/files.yaml index e4d9b6b..cb39b96 100644 --- a/share/common/lib/files.yaml +++ b/share/common/lib/files.yaml @@ -18,15 +18,18 @@ python: function: files_create_from_embedded_with_other_name types: + filename_on_disk: path embedded_file: file -- when: I write "(?P.*)" to file (?P\S+) - regex: true +- when: I write "{text}" to file {filename} impl: rust: function: subplotlib::steplibrary::files::create_from_text python: function: files_create_from_text + types: + filename: path + text: text # Manage directories (distinct from files). @@ -36,6 +39,8 @@ function: subplotlib::steplibrary::files::make_directory python: function: files_make_directory + types: + path: path - when: I create directory {path} impl: @@ -43,6 +48,8 @@ function: subplotlib::steplibrary::files::make_directory python: function: files_make_directory + types: + path: path - when: I remove directory {path} impl: @@ -50,6 +57,8 @@ function: subplotlib::steplibrary::files::remove_directory python: function: files_remove_directory + types: + path: path - then: directory {path} exists impl: @@ -57,6 +66,8 @@ function: subplotlib::steplibrary::files::path_exists python: function: files_directory_exists + types: + path: path - then: directory {path} does not exist impl: @@ -64,6 +75,8 @@ function: subplotlib::steplibrary::files::path_does_not_exist python: function: files_directory_does_not_exist + types: + path: path - then: directory {path} is empty impl: @@ -71,6 +84,8 @@ function: subplotlib::steplibrary::files::path_is_empty python: function: files_directory_is_empty + types: + path: path - then: directory {path} is not empty impl: @@ -78,6 +93,8 @@ function: subplotlib::steplibrary::files::path_is_not_empty python: function: files_directory_is_not_empty + types: + path: path # File metadata management and testing. @@ -89,6 +106,7 @@ python: function: files_touch_with_timestamp types: + filename: path mtime: text - when: I remember metadata for file {filename} @@ -97,6 +115,8 @@ function: subplotlib::steplibrary::files::remember_metadata python: function: files_remember_metadata + types: + filename: path - when: I touch file {filename} impl: @@ -104,6 +124,8 @@ function: subplotlib::steplibrary::files::touch python: function: files_touch + types: + filename: path - then: file {filename} has same metadata as before impl: @@ -111,6 +133,8 @@ function: subplotlib::steplibrary::files::has_remembered_metadata python: function: files_has_remembered_metadata + types: + filename: path - then: file {filename} has different metadata from before impl: @@ -118,6 +142,8 @@ function: subplotlib::steplibrary::files::has_different_metadata python: function: files_has_different_metadata + types: + filename: path - then: file {filename} has changed from before impl: @@ -125,6 +151,8 @@ function: subplotlib::steplibrary::files::has_different_metadata python: function: files_has_different_metadata + types: + filename: path - then: file {filename} has a very recent modification time impl: @@ -132,6 +160,8 @@ function: subplotlib::steplibrary::files::mtime_is_recent python: function: files_mtime_is_recent + types: + filename: path - then: file {filename} has a very old modification time impl: @@ -139,6 +169,8 @@ function: subplotlib::steplibrary::files::mtime_is_ancient python: function: files_mtime_is_ancient + types: + filename: path # Testing file existence. @@ -148,6 +180,8 @@ function: subplotlib::steplibrary::files::file_exists python: function: files_file_exists + types: + filename: path - then: file {filename} does not exist impl: @@ -155,6 +189,8 @@ function: subplotlib::steplibrary::files::file_does_not_exist python: function: files_file_does_not_exist + types: + filename: path - then: only files (?P.+) exist impl: @@ -166,37 +202,45 @@ # Tests on file content. -- then: file (?P\S+) contains "(?P.*)" - regex: true +- then: file {filename} contains "{data}" impl: rust: function: subplotlib::steplibrary::files::file_contains python: function: files_file_contains + types: + filename: path + data: text -- then: file (?P\S+) doesn't contain "(?P.*)" - regex: true +- then: file {filename} doesn't contain "{data}" impl: rust: function: subplotlib::steplibrary::files::file_doesnt_contain python: function: files_file_doesnt_contain + types: + filename: path + data: text -- then: file (?P\S+) matches regex /(?P.*)/ - regex: true +- then: file {filename} matches regex /{regex}/ impl: rust: function: subplotlib::steplibrary::files::file_matches_regex python: function: files_file_matches_regex + types: + filename: path + regex: text -- then: file (?P\S+) matches regex "(?P.*)" - regex: true +- then: file {filename} matches regex "{regex}" impl: rust: function: subplotlib::steplibrary::files::file_matches_regex python: function: files_file_matches_regex + types: + filename: path + regex: text - then: files {filename1} and {filename2} match impl: @@ -204,3 +248,7 @@ function: subplotlib::steplibrary::files::file_match python: function: files_match + types: + filename1: path + filename2: path + diff --git a/share/common/lib/runcmd.yaml b/share/common/lib/runcmd.yaml index 5847613..7be2c05 100644 --- a/share/common/lib/runcmd.yaml +++ b/share/common/lib/runcmd.yaml @@ -23,12 +23,16 @@ rust: function: subplotlib::steplibrary::runcmd::run -- when: I run, in {dirname}, {argv0}{args:text} +- when: I run, in {dirname}, {argv0}{args} impl: python: function: runcmd_step_in rust: function: subplotlib::steplibrary::runcmd::run_in + types: + dirname: path + argv0: word + args: text - when: I try to run {argv0}{args:text} impl: @@ -37,12 +41,16 @@ rust: function: subplotlib::steplibrary::runcmd::try_to_run -- when: I try to run, in {dirname}, {argv0}{args:text} +- when: I try to run, in {dirname}, {argv0}{args} impl: python: function: runcmd_try_to_run_in rust: function: subplotlib::steplibrary::runcmd::try_to_run_in + types: + dirname: path + argv0: word + args: text # Steps to examine exit code of latest command. diff --git a/subplotlib/src/steplibrary/files.rs b/subplotlib/src/steplibrary/files.rs index 09cde56..8abe546 100644 --- a/subplotlib/src/steplibrary/files.rs +++ b/subplotlib/src/steplibrary/files.rs @@ -7,7 +7,7 @@ use std::collections::{HashMap, HashSet}; use std::ffi::OsString; use std::fs::{self, Metadata, OpenOptions}; use std::io::{self, Write}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::time::{Duration, SystemTime}; use filetime::FileTime; @@ -31,7 +31,7 @@ pub use super::datadir::Datadir; /// Because files can typically only be named in Subplot documents, we assume they /// all have names which can be rendered as utf-8 strings. pub struct Files { - metadata: HashMap, + metadata: HashMap, } impl ContextElement for Files { @@ -50,7 +50,7 @@ impl ContextElement for Files { #[step] #[context(Datadir)] pub fn create_from_embedded(context: &ScenarioContext, embedded_file: SubplotDataFile) { - let filename_on_disk = format!("{}", embedded_file.name().display()); + let filename_on_disk = PathBuf::from(format!("{}", embedded_file.name().display())); create_from_embedded_with_other_name::call(context, &filename_on_disk, embedded_file)?; } @@ -63,7 +63,7 @@ pub fn create_from_embedded(context: &ScenarioContext, embedded_file: SubplotDat #[step] pub fn create_from_embedded_with_other_name( context: &Datadir, - filename_on_disk: &str, + filename_on_disk: &Path, embedded_file: SubplotDataFile, ) { let filename_on_disk = PathBuf::from(filename_on_disk); @@ -86,7 +86,7 @@ pub fn create_from_embedded_with_other_name( /// Sets the modification time for the given filename to the provided mtime. /// If the file does not exist, it will be created. #[step] -pub fn touch_with_timestamp(context: &Datadir, filename: &str, mtime: &str) { +pub fn touch_with_timestamp(context: &Datadir, filename: &Path, mtime: &str) { let fd = format_description!( "[year]-[month]-[day] [hour]:[minute]:[second] [offset_hour]:[offset_minute]" ); @@ -112,7 +112,7 @@ pub fn touch_with_timestamp(context: &Datadir, filename: &str, mtime: &str) { /// /// Create/replace the given file with the given content. #[step] -pub fn create_from_text(context: &Datadir, text: &str, filename: &str) { +pub fn create_from_text(context: &Datadir, text: &str, filename: &Path) { context.open_write(filename)?.write_all(text.as_bytes())?; } @@ -125,7 +125,7 @@ pub fn create_from_text(context: &Datadir, text: &str, filename: &str) { #[step] #[context(Datadir)] #[context(Files)] -pub fn remember_metadata(context: &ScenarioContext, filename: &str) { +pub fn remember_metadata(context: &ScenarioContext, filename: &Path) { let full_path = context.with( |context: &Datadir| context.canonicalise_filename(filename), false, @@ -147,7 +147,7 @@ pub fn remember_metadata(context: &ScenarioContext, filename: &str) { /// This will create the named file if it does not exist, and then it will ensure that the /// file's modification time is set to the current time. #[step] -pub fn touch(context: &Datadir, filename: &str) { +pub fn touch(context: &Datadir, filename: &Path) { let full_path = context.canonicalise_filename(filename)?; let now = FileTime::now(); // If the file doesn't exist, create it @@ -167,13 +167,13 @@ pub fn touch(context: &Datadir, filename: &str) { /// /// This simple step will succeed if the given filename exists in some sense. #[step] -pub fn file_exists(context: &Datadir, filename: &str) { +pub fn file_exists(context: &Datadir, filename: &Path) { let full_path = context.canonicalise_filename(filename)?; match fs::metadata(full_path) { Ok(_) => (), Err(e) => { if matches!(e.kind(), io::ErrorKind::NotFound) { - throw!(format!("file '{}' was not found", filename)) + throw!(format!("file '{}' was not found", filename.display())) } else { throw!(e); } @@ -187,11 +187,14 @@ pub fn file_exists(context: &Datadir, filename: &str) { /// /// This simple step will succeed if the given filename does not exist in any sense. #[step] -pub fn file_does_not_exist(context: &Datadir, filename: &str) { +pub fn file_does_not_exist(context: &Datadir, filename: &Path) { let full_path = context.canonicalise_filename(filename)?; match fs::metadata(full_path) { Ok(_) => { - throw!(format!("file '{}' was unexpectedly found", filename)) + throw!(format!( + "file '{}' was unexpectedly found", + filename.display() + )) } Err(e) => { if !matches!(e.kind(), io::ErrorKind::NotFound) { @@ -229,11 +232,11 @@ pub fn only_these_exist(context: &Datadir, filenames: &str) { /// This will load the content of the named file and ensure it contains the given string. /// Note: this assumes everything is utf-8 encoded. If not, things will fail. #[step] -pub fn file_contains(context: &Datadir, filename: &str, data: &str) { +pub fn file_contains(context: &Datadir, filename: &Path, data: &str) { let full_path = context.canonicalise_filename(filename)?; let body = fs::read_to_string(full_path)?; if !body.contains(data) { - println!("file {} contains:\n{}", filename, body); + println!("file {} contains:\n{}", filename.display(), body); throw!("expected file content not found"); } } @@ -245,11 +248,11 @@ pub fn file_contains(context: &Datadir, filename: &str, data: &str) { /// This will load the content of the named file and ensure it lacks the given string. /// Note: this assumes everything is utf-8 encoded. If not, things will fail. #[step] -pub fn file_doesnt_contain(context: &Datadir, filename: &str, data: &str) { +pub fn file_doesnt_contain(context: &Datadir, filename: &Path, data: &str) { let full_path = context.canonicalise_filename(filename)?; let body = fs::read_to_string(full_path)?; if body.contains(data) { - println!("file {} contains:\n{}", filename, body); + println!("file {} contains:\n{}", filename.display(), body); throw!("unexpected file content found"); } } @@ -262,12 +265,12 @@ pub fn file_doesnt_contain(context: &Datadir, filename: &str, data: &str) { /// matches the given regular expression. This step will fail if the file is not utf-8 /// encoded, or if the regex fails to compile #[step] -pub fn file_matches_regex(context: &Datadir, filename: &str, regex: &str) { +pub fn file_matches_regex(context: &Datadir, filename: &Path, regex: &str) { let full_path = context.canonicalise_filename(filename)?; let regex = Regex::new(regex)?; let body = fs::read_to_string(full_path)?; if !regex.is_match(&body) { - println!("file {} contains:\n{}", filename, body); + println!("file {} contains:\n{}", filename.display(), body); throw!("file content does not match given regex"); } } @@ -278,7 +281,7 @@ pub fn file_matches_regex(context: &Datadir, filename: &str, regex: &str) { /// /// This loads the content of the given two files as **bytes** and checks they mach. #[step] -pub fn file_match(context: &Datadir, filename1: &str, filename2: &str) { +pub fn file_match(context: &Datadir, filename1: &Path, filename2: &Path) { let full_path1 = context.canonicalise_filename(filename1)?; let full_path2 = context.canonicalise_filename(filename2)?; let body1 = fs::read(full_path1)?; @@ -286,12 +289,12 @@ pub fn file_match(context: &Datadir, filename1: &str, filename2: &str) { if body1 != body2 { println!( "file {} contains:\n{}", - filename1, + filename1.display(), String::from_utf8_lossy(&body1) ); println!( "file {} contains:\n{}", - filename2, + filename2.display(), String::from_utf8_lossy(&body2) ); throw!("file contents do not match each other"); @@ -312,7 +315,7 @@ pub fn file_match(context: &Datadir, filename1: &str, filename2: &str) { #[step] #[context(Datadir)] #[context(Files)] -pub fn has_remembered_metadata(context: &ScenarioContext, filename: &str) { +pub fn has_remembered_metadata(context: &ScenarioContext, filename: &Path) { let full_path = context.with( |context: &Datadir| context.canonicalise_filename(filename), false, @@ -327,10 +330,13 @@ pub fn has_remembered_metadata(context: &ScenarioContext, filename: &str) { || metadata.len() != remembered.len() || metadata.is_file() != remembered.is_file() { - throw!(format!("metadata change detected for {}", filename)); + throw!(format!( + "metadata change detected for {}", + filename.display() + )); } } else { - throw!(format!("no remembered metadata for {}", filename)); + throw!(format!("no remembered metadata for {}", filename.display())); } } @@ -348,7 +354,7 @@ pub fn has_remembered_metadata(context: &ScenarioContext, filename: &str) { #[step] #[context(Datadir)] #[context(Files)] -pub fn has_different_metadata(context: &ScenarioContext, filename: &str) { +pub fn has_different_metadata(context: &ScenarioContext, filename: &Path) { let full_path = context.with( |context: &Datadir| context.canonicalise_filename(filename), false, @@ -363,10 +369,13 @@ pub fn has_different_metadata(context: &ScenarioContext, filename: &str) { && metadata.len() == remembered.len() && metadata.is_file() == remembered.is_file() { - throw!(format!("metadata change not detected for {}", filename)); + throw!(format!( + "metadata change not detected for {}", + filename.display() + )); } } else { - throw!(format!("no remembered metadata for {}", filename)); + throw!(format!("no remembered metadata for {}", filename.display())); } } @@ -376,13 +385,13 @@ pub fn has_different_metadata(context: &ScenarioContext, filename: &str) { /// /// Specifically this checks that the given file has been modified in the past 5 seconds. #[step] -pub fn mtime_is_recent(context: &Datadir, filename: &str) { +pub fn mtime_is_recent(context: &Datadir, filename: &Path) { let full_path = context.canonicalise_filename(filename)?; let metadata = fs::metadata(full_path)?; let mtime = metadata.modified()?; let diff = SystemTime::now().duration_since(mtime)?; if diff > (Duration::from_secs(5)) { - throw!(format!("{} is older than 5 seconds", filename)); + throw!(format!("{} is older than 5 seconds", filename.display())); } } @@ -392,13 +401,13 @@ pub fn mtime_is_recent(context: &Datadir, filename: &str) { /// /// Specifically this checks that the file was modified at least 39 years ago. #[step] -pub fn mtime_is_ancient(context: &Datadir, filename: &str) { +pub fn mtime_is_ancient(context: &Datadir, filename: &Path) { let full_path = context.canonicalise_filename(filename)?; let metadata = fs::metadata(full_path)?; let mtime = metadata.modified()?; let diff = SystemTime::now().duration_since(mtime)?; if diff < (Duration::from_secs(39 * 365 * 24 * 3600)) { - throw!(format!("{} is younger than 39 years", filename)); + throw!(format!("{} is younger than 39 years", filename.display())); } } @@ -408,7 +417,7 @@ pub fn mtime_is_ancient(context: &Datadir, filename: &str) { /// /// This is the equivalent of `mkdir -p` within the data directory for the scenario. #[step] -pub fn make_directory(context: &Datadir, path: &str) { +pub fn make_directory(context: &Datadir, path: &Path) { context.create_dir_all(path)?; } @@ -418,7 +427,7 @@ pub fn make_directory(context: &Datadir, path: &str) { /// /// This is the equivalent of `rm -rf` within the data directory for the scenario. #[step] -pub fn remove_directory(context: &Datadir, path: &str) { +pub fn remove_directory(context: &Datadir, path: &Path) { let full_path = context.canonicalise_filename(path)?; remove_dir_all::remove_dir_all(full_path)?; } @@ -430,7 +439,7 @@ pub fn remove_directory(context: &Datadir, path: &str) { /// This ensures that the given path exists in the data directory for the scenario and /// that it is a directory itself. #[step] -pub fn path_exists(context: &Datadir, path: &str) { +pub fn path_exists(context: &Datadir, path: &Path) { let full_path = context.canonicalise_filename(path)?; if !fs::metadata(&full_path)?.is_dir() { throw!(format!( @@ -447,7 +456,7 @@ pub fn path_exists(context: &Datadir, path: &str) { /// This ensures that the given path does not exist in the data directory. If it exists /// and is not a directory, then this will also fail. #[step] -pub fn path_does_not_exist(context: &Datadir, path: &str) { +pub fn path_does_not_exist(context: &Datadir, path: &Path) { let full_path = context.canonicalise_filename(path)?; match fs::metadata(&full_path) { Ok(_) => throw!(format!("{} exists", full_path.display())), @@ -466,7 +475,7 @@ pub fn path_does_not_exist(context: &Datadir, path: &str) { /// This checks that the given path inside the data directory exists and is an /// empty directory itself. #[step] -pub fn path_is_empty(context: &Datadir, path: &str) { +pub fn path_is_empty(context: &Datadir, path: &Path) { let full_path = context.canonicalise_filename(path)?; let mut iter = fs::read_dir(&full_path)?; match iter.next() { @@ -484,7 +493,7 @@ pub fn path_is_empty(context: &Datadir, path: &str) { /// directory itself. The step also asserts that the given directory contains at least /// one entry. #[step] -pub fn path_is_not_empty(context: &Datadir, path: &str) { +pub fn path_is_not_empty(context: &Datadir, path: &Path) { let full_path = context.canonicalise_filename(path)?; let mut iter = fs::read_dir(&full_path)?; match iter.next() { diff --git a/subplotlib/src/steplibrary/runcmd.rs b/subplotlib/src/steplibrary/runcmd.rs index b90f8b7..6692441 100644 --- a/subplotlib/src/steplibrary/runcmd.rs +++ b/subplotlib/src/steplibrary/runcmd.rs @@ -56,7 +56,9 @@ static DEFAULT_PATHS: &[&str] = &[ ]; // This us used internally to force CWD for running commands -const USE_CWD: &str = "\0USE_CWD"; +lazy_static! { + static ref USE_CWD: PathBuf = PathBuf::from("\0USE_CWD"); +} impl ContextElement for Runcmd { fn scenario_starts(&mut self) -> StepResult { @@ -229,7 +231,7 @@ pub fn run(context: &ScenarioContext, argv0: &str, args: &str) { #[step] #[context(Datadir)] #[context(Runcmd)] -pub fn run_in(context: &ScenarioContext, dirname: &str, argv0: &str, args: &str) { +pub fn run_in(context: &ScenarioContext, dirname: &Path, argv0: &str, args: &str) { try_to_run_in::call(context, dirname, argv0, args)?; exit_code_is::call(context, 0)?; } @@ -244,7 +246,7 @@ pub fn run_in(context: &ScenarioContext, dirname: &str, argv0: &str, args: &str) #[context(Datadir)] #[context(Runcmd)] pub fn try_to_run(context: &ScenarioContext, argv0: &str, args: &str) { - try_to_run_in::call(context, USE_CWD, argv0, args)?; + try_to_run_in::call(context, &USE_CWD, argv0, args)?; } /// Run the given command in the given subpath of the data directory @@ -256,7 +258,7 @@ pub fn try_to_run(context: &ScenarioContext, argv0: &str, args: &str) { #[step] #[context(Datadir)] #[context(Runcmd)] -pub fn try_to_run_in(context: &ScenarioContext, dirname: &str, argv0: &str, args: &str) { +pub fn try_to_run_in(context: &ScenarioContext, dirname: &Path, argv0: &str, args: &str) { // This is the core of runcmd and is how we handle things let argv0: PathBuf = if argv0.starts_with('.') { context.with( @@ -270,7 +272,7 @@ pub fn try_to_run_in(context: &ScenarioContext, dirname: &str, argv0: &str, args |datadir: &Datadir| Ok(datadir.base_path().to_path_buf()), false, )?; - if dirname != USE_CWD { + if dirname != USE_CWD.as_path() { datadir = datadir.join(dirname); } let mut proc = Command::new(&argv0); diff --git a/tests/subplots/common/runcmd_test.rs b/tests/subplots/common/runcmd_test.rs index 7759e5f..d3a7ca5 100644 --- a/tests/subplots/common/runcmd_test.rs +++ b/tests/subplots/common/runcmd_test.rs @@ -1,3 +1,4 @@ +use std::path::Path; use subplotlib::steplibrary::files::{self, Datadir}; use subplotlib::steplibrary::runcmd::Runcmd; @@ -8,7 +9,7 @@ use std::os::unix::fs::PermissionsExt; #[context(Datadir)] fn create_script_from_embedded( context: &ScenarioContext, - filename: &str, + filename: &Path, embedded: SubplotDataFile, ) { files::create_from_embedded_with_other_name::call(context, filename, embedded)?; @@ -20,6 +21,6 @@ fn create_script_from_embedded( } #[step] -fn prepend_to_path(context: &mut Runcmd, dirname: &str) { +fn prepend_to_path(context: &mut Runcmd, dirname: &Path) { context.prepend_to_path(dirname); } diff --git a/tests/subplots/common/runcmd_test.yaml b/tests/subplots/common/runcmd_test.yaml index daab202..e53c2d7 100644 --- a/tests/subplots/common/runcmd_test.yaml +++ b/tests/subplots/common/runcmd_test.yaml @@ -1,9 +1,12 @@ -- given: "executable script {filename} from {embedded:file}" +- given: "executable script {filename} from {embedded}" impl: python: function: create_script_from_embedded rust: function: create_script_from_embedded + types: + filename: path + embedded: file - when: "I prepend {dirname} to PATH" impl: @@ -11,3 +14,5 @@ function: runcmd_prepend_to_path rust: function: prepend_to_path + types: + dirname: path -- cgit v1.2.1