diff --git a/CHANGELOG.md b/CHANGELOG.md index 61a503a4..9f6733a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a ### Added - Add macOS binary for releases - Add `init` command to initialize a Bender.yml file of an IP. +- Allow environment variables in dependency and sources paths. ## 0.27.4 - 2023-11-14 ### Added diff --git a/Cargo.lock b/Cargo.lock index ac857998..be091b4e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -116,6 +116,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", + "subst", "tabwriter", "tempfile", "tokio", @@ -176,9 +177,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.4.11" +version = "4.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" +checksum = "dcfab8ba68f3668e89f6ff60f5b205cea56aa7b769451a59f34b8682f51c056d" dependencies = [ "clap_builder", "clap_derive", @@ -186,9 +187,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.11" +version = "4.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" +checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9" dependencies = [ "anstream", "anstyle", @@ -449,13 +450,13 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" dependencies = [ "hermit-abi", "rustix", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -508,9 +509,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "miniz_oxide" @@ -769,6 +770,16 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "subst" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca1318e5d6716d6541696727c88d9b8dfc8cfe6afd6908e186546fd4af7f5b98" +dependencies = [ + "memchr", + "unicode-width", +] + [[package]] name = "subtle" version = "2.5.0" @@ -788,24 +799,24 @@ dependencies = [ [[package]] name = "tabwriter" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08e1173ee641651a3095fe95d86ae314cd1f959888097debce3e0f9ca532eef1" +checksum = "a327282c4f64f6dc37e3bba4c2b6842cc3a992f204fa58d917696a89f691e5f6" dependencies = [ "unicode-width", ] [[package]] name = "tempfile" -version = "3.8.1" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" dependencies = [ "cfg-if", "fastrand", "redox_syscall", "rustix", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 2d1ccbaf..2d85a1f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,3 +31,4 @@ indexmap = { version = "2", features = ["serde"] } tempfile = "3.5" glob = "0.3" walkdir = "2" +subst = "0.3" diff --git a/src/cli.rs b/src/cli.rs index e7a5d079..c36c6cc5 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -353,7 +353,7 @@ pub fn read_manifest(path: &Path) -> Result { let manifest = partial .validate() .map_err(|cause| Error::chain(format!("Error in manifest {:?}.", path), cause))?; - Ok(manifest.prefix_paths(path.parent().unwrap())) + Ok(manifest.prefix_paths(path.parent().unwrap())?) } /// Load a configuration by traversing a directory hierarchy upwards. @@ -413,7 +413,7 @@ fn load_config(from: &Path) -> Result { // Assemble and merge the default configuration. let default_cfg = PartialConfig { - database: Some(from.join(".bender")), + database: Some(from.join(".bender").to_str().unwrap().to_string()), git: Some("git".into()), overrides: None, plugins: None, @@ -445,7 +445,7 @@ fn maybe_load_config(path: &Path) -> Result> { .map_err(|cause| Error::chain(format!("Cannot open config {:?}.", path), cause))?; let partial: PartialConfig = serde_yaml::from_reader(file) .map_err(|cause| Error::chain(format!("Syntax error in config {:?}.", path), cause))?; - Ok(Some(partial.prefix_paths(path.parent().unwrap()))) + Ok(Some(partial.prefix_paths(path.parent().unwrap())?)) } /// Read a lock file. @@ -462,14 +462,14 @@ fn read_lockfile(path: &Path, root_dir: &Path) -> Result { .packages .iter() .map(|pack| { - if let LockedSource::Path(path) = &pack.1.source { + Ok(if let LockedSource::Path(path) = &pack.1.source { ( pack.0.clone(), LockedPackage { revision: pack.1.revision.clone(), version: pack.1.version.clone(), source: LockedSource::Path(if path.is_relative() { - path.clone().prefix_paths(root_dir) + path.clone().prefix_paths(root_dir)? } else { path.clone() }), @@ -478,9 +478,9 @@ fn read_lockfile(path: &Path, root_dir: &Path) -> Result { ) } else { (pack.0.clone(), pack.1.clone()) - } + }) }) - .collect(), + .collect::>()?, }) } diff --git a/src/cmd/vendor.rs b/src/cmd/vendor.rs index 1b243a0c..f52c05ec 100644 --- a/src/cmd/vendor.rs +++ b/src/cmd/vendor.rs @@ -178,7 +178,7 @@ pub fn run(sess: &Session, matches: &ArgMatches) -> Result<()> { let target_path = patch_link .clone() .to_prefix - .prefix_paths(&vendor_package.target_dir); + .prefix_paths(&vendor_package.target_dir)?; if target_path.exists() { if target_path.is_dir() { std::fs::remove_dir_all(target_path.clone()) @@ -266,8 +266,8 @@ pub fn init( let link_to = patch_link .to_prefix .clone() - .prefix_paths(&vendor_package.target_dir); - let link_from = patch_link.from_prefix.clone().prefix_paths(dep_path); + .prefix_paths(&vendor_package.target_dir)?; + let link_from = patch_link.from_prefix.clone().prefix_paths(dep_path)?; std::fs::create_dir_all(link_to.parent().unwrap()).map_err(|cause| { Error::chain( format!("Failed to create directory {:?}", link_to.parent()), @@ -281,7 +281,7 @@ pub fn init( // Check if includes exist for path in vendor_package.include_from_upstream.clone() { - if !PathBuf::from(extend_paths(&[path.clone()], dep_path)[0].clone()).exists() { + if !PathBuf::from(extend_paths(&[path.clone()], dep_path)?[0].clone()).exists() { warnln!("{} not found in upstream, continuing.", path); } } @@ -291,7 +291,7 @@ pub fn init( true => copy_recursively( &link_from, &link_to, - &extend_paths(&vendor_package.include_from_upstream, dep_path), + &extend_paths(&vendor_package.include_from_upstream, dep_path)?, &vendor_package .exclude_from_upstream .clone() @@ -364,6 +364,7 @@ pub fn apply_patches( .from_prefix .clone() .prefix_paths(git.path) + .unwrap() .is_file() { patch_link.from_prefix.as_path() @@ -404,11 +405,11 @@ pub fn diff( let link_from = patch_link .from_prefix .clone() - .prefix_paths(dep_path.as_ref()); // dep_path: path to temporary clone. link_to: targetdir/link.to + .prefix_paths(dep_path.as_ref())?; // dep_path: path to temporary clone. link_to: targetdir/link.to let link_to = patch_link .to_prefix .clone() - .prefix_paths(vendor_package.target_dir.as_ref()); + .prefix_paths(vendor_package.target_dir.as_ref())?; if !&link_to.exists() { return Err(Error::new(format!( "Could not find {}. Did you run bender vendor init?", @@ -423,7 +424,7 @@ pub fn diff( &extend_paths( &vendor_package.include_from_upstream, &vendor_package.target_dir, - ), + )?, &vendor_package .exclude_from_upstream .clone() @@ -528,7 +529,7 @@ pub fn gen_format_patch( let to_path = patch_link .to_prefix .clone() - .prefix_paths(target_dir.as_ref()); + .prefix_paths(target_dir.as_ref())?; if !&to_path.exists() { return Err(Error::new(format!( "Could not find {}. Did you run bender vendor init?", @@ -724,16 +725,19 @@ pub fn copy_recursively( } /// Prefix paths with prefix. Append ** to directories. -pub fn extend_paths(include_from_upstream: &[String], prefix: impl AsRef) -> Vec { +pub fn extend_paths( + include_from_upstream: &[String], + prefix: impl AsRef, +) -> Result> { include_from_upstream .iter() .map(|pattern| { - let pattern_long = PathBuf::from(pattern).prefix_paths(prefix.as_ref()); + let pattern_long = PathBuf::from(pattern).prefix_paths(prefix.as_ref())?; if pattern_long.is_dir() { - String::from(pattern_long.join("**").to_str().unwrap()) + Ok(String::from(pattern_long.join("**").to_str().unwrap())) } else { - String::from(pattern_long.to_str().unwrap()) + Ok(String::from(pattern_long.to_str().unwrap())) } }) - .collect() + .collect::>() } diff --git a/src/config.rs b/src/config.rs index 3b97146a..eaf69037 100644 --- a/src/config.rs +++ b/src/config.rs @@ -19,6 +19,7 @@ use indexmap::IndexMap; use semver; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; +use subst; use crate::error::*; use crate::target::TargetSpec; @@ -48,21 +49,25 @@ pub struct Manifest { } impl PrefixPaths for Manifest { - fn prefix_paths(self, prefix: &Path) -> Self { - Manifest { + fn prefix_paths(self, prefix: &Path) -> Result { + Ok(Manifest { package: self.package, - dependencies: self.dependencies.prefix_paths(prefix), - sources: self.sources.map(|src| src.prefix_paths(prefix)), + dependencies: self.dependencies.prefix_paths(prefix)?, + sources: self + .sources + .map_or(Ok::, Error>(None), |src| { + Ok(Some(src.prefix_paths(prefix)?)) + })?, export_include_dirs: self .export_include_dirs .into_iter() - .map(|src| src.prefix_paths(prefix)) - .collect(), - plugins: self.plugins.prefix_paths(prefix), + .map(|src| Ok(src.prefix_paths(prefix)?)) + .collect::>()?, + plugins: self.plugins.prefix_paths(prefix)?, frozen: self.frozen, - workspace: self.workspace.prefix_paths(prefix), - vendor_package: self.vendor_package.prefix_paths(prefix), - } + workspace: self.workspace.prefix_paths(prefix)?, + vendor_package: self.vendor_package.prefix_paths(prefix)?, + }) } } @@ -99,11 +104,11 @@ pub enum Dependency { } impl PrefixPaths for Dependency { - fn prefix_paths(self, prefix: &Path) -> Self { - match self { - Dependency::Path(p) => Dependency::Path(p.prefix_paths(prefix)), + fn prefix_paths(self, prefix: &Path) -> Result { + Ok(match self { + Dependency::Path(p) => Dependency::Path(p.prefix_paths(prefix)?), v => v, - } + }) } } @@ -146,13 +151,13 @@ pub struct Sources { } impl PrefixPaths for Sources { - fn prefix_paths(self, prefix: &Path) -> Self { - Sources { + fn prefix_paths(self, prefix: &Path) -> Result { + Ok(Sources { target: self.target, - include_dirs: self.include_dirs.prefix_paths(prefix), + include_dirs: self.include_dirs.prefix_paths(prefix)?, defines: self.defines, - files: self.files.prefix_paths(prefix), - } + files: self.files.prefix_paths(prefix)?, + }) } } @@ -174,11 +179,11 @@ impl fmt::Debug for SourceFile { } impl PrefixPaths for SourceFile { - fn prefix_paths(self, prefix: &Path) -> Self { - match self { - SourceFile::File(path) => SourceFile::File(path.prefix_paths(prefix)), - SourceFile::Group(group) => SourceFile::Group(Box::new(group.prefix_paths(prefix))), - } + fn prefix_paths(self, prefix: &Path) -> Result { + Ok(match self { + SourceFile::File(path) => SourceFile::File(path.prefix_paths(prefix)?), + SourceFile::Group(group) => SourceFile::Group(Box::new(group.prefix_paths(prefix)?)), + }) } } @@ -192,15 +197,15 @@ pub struct Workspace { } impl PrefixPaths for Workspace { - fn prefix_paths(self, prefix: &Path) -> Self { - Workspace { - checkout_dir: self.checkout_dir.prefix_paths(prefix), + fn prefix_paths(self, prefix: &Path) -> Result { + Ok(Workspace { + checkout_dir: self.checkout_dir.prefix_paths(prefix)?, package_links: self .package_links .into_iter() - .map(|(k, v)| (k.prefix_paths(prefix), v)) - .collect(), - } + .map(|(k, v)| Ok((k.prefix_paths(prefix)?, v))) + .collect::>()?, + }) } } @@ -284,9 +289,9 @@ pub struct PartialManifest { /// The source files. pub sources: Option>, /// The include directories exported to dependent packages. - pub export_include_dirs: Option>, + pub export_include_dirs: Option>, /// The plugin binaries. - pub plugins: Option>, + pub plugins: Option>, /// Whether the dependencies of the manifest are frozen. pub frozen: Option, /// The workspace configuration. @@ -328,7 +333,10 @@ impl Validate for PartialManifest { }; let exp_inc_dirs = self.export_include_dirs.unwrap_or_default(); let plugins = match self.plugins { - Some(s) => s, + Some(s) => s + .iter() + .map(|(k, v)| Ok((k.clone(), env_path_from_string(v.to_string())?))) + .collect::>>()?, None => IndexMap::new(), }; let frozen = self.frozen.unwrap_or(false); @@ -348,7 +356,10 @@ impl Validate for PartialManifest { package: pkg, dependencies: deps, sources: srcs, - export_include_dirs: exp_inc_dirs, + export_include_dirs: exp_inc_dirs + .iter() + .map(|path| env_path_from_string(path.to_string())) + .collect::>>()?, plugins, frozen, workspace, @@ -371,7 +382,7 @@ impl Validate for PartialManifest { #[derive(Serialize, Deserialize, Debug)] pub struct PartialDependency { /// The path to the package. - path: Option, + path: Option, /// The git URL to the package. git: Option, /// The git revision of the package to use. Can be a commit hash, branch, @@ -395,11 +406,11 @@ impl FromStr for PartialDependency { } impl PrefixPaths for PartialDependency { - fn prefix_paths(self, prefix: &Path) -> Self { - PartialDependency { - path: self.path.prefix_paths(prefix), + fn prefix_paths(self, prefix: &Path) -> Result { + Ok(PartialDependency { + path: self.path.prefix_paths(prefix)?, ..self - } + }) } } @@ -436,7 +447,7 @@ impl Validate for PartialDependency { list ))) } else { - Ok(Dependency::Path(path)) + Ok(Dependency::Path(env_path_from_string(path)?)) } } else if let Some(git) = self.git { if let Some(rev) = self.rev { @@ -464,7 +475,7 @@ pub struct PartialSources { /// The targets for which the sources should be considered. pub target: Option, /// The directories to search for include files. - pub include_dirs: Option>, + pub include_dirs: Option>, /// The preprocessor definitions. pub defines: Option>>, /// The source file paths. @@ -486,12 +497,17 @@ impl Validate for PartialSources { type Output = Sources; type Error = Error; fn validate(self) -> Result { - let include_dirs = self.include_dirs.unwrap_or_default(); + let include_dirs: Result> = self + .include_dirs + .unwrap_or_default() + .iter() + .map(|path| env_path_from_string(path.to_string())) + .collect(); let defines = self.defines.unwrap_or_default(); let files: Result> = self.files.into_iter().map(|f| f.validate()).collect(); Ok(Sources { target: self.target.unwrap_or(TargetSpec::Wildcard), - include_dirs, + include_dirs: include_dirs?, defines, files: files?, }) @@ -502,7 +518,7 @@ impl Validate for PartialSources { #[derive(Debug)] pub enum PartialSourceFile { /// A single file. - File(PathBuf), + File(String), /// A subgroup of sources. Group(Box), } @@ -565,7 +581,7 @@ impl Validate for PartialSourceFile { type Error = Error; fn validate(self) -> Result { match self { - PartialSourceFile::File(path) => Ok(SourceFile::File(path)), + PartialSourceFile::File(path) => Ok(SourceFile::File(env_path_from_string(path)?)), PartialSourceFile::Group(srcs) => Ok(SourceFile::Group(Box::new(srcs.validate()?))), } } @@ -575,18 +591,27 @@ impl Validate for PartialSourceFile { #[derive(Serialize, Deserialize, Debug)] pub struct PartialWorkspace { /// The directory which will contain working copies of the dependencies. - pub checkout_dir: Option, + pub checkout_dir: Option, /// The locally linked packages. - pub package_links: Option>, + pub package_links: Option>, } impl Validate for PartialWorkspace { type Output = Workspace; type Error = Error; fn validate(self) -> Result { + let package_links: Result> = self + .package_links + .unwrap_or_default() + .iter() + .map(|(k, v)| Ok((env_path_from_string(k.to_string())?, v.clone()))) + .collect(); Ok(Workspace { - checkout_dir: self.checkout_dir, - package_links: self.package_links.unwrap_or_default(), + checkout_dir: match self.checkout_dir { + Some(dir) => Some(env_path_from_string(dir)?), + None => None, + }, + package_links: package_links?, }) } } @@ -600,12 +625,23 @@ pub trait Merge { /// Prefixes relative paths. pub trait PrefixPaths { /// Prefixes all paths with `prefix`. Does not touch absolute paths. - fn prefix_paths(self, prefix: &Path) -> Self; + fn prefix_paths(self, prefix: &Path) -> Result + where + Self: std::marker::Sized; } impl PrefixPaths for PathBuf { - fn prefix_paths(self, prefix: &Path) -> Self { - prefix.join(self) + fn prefix_paths(self, prefix: &Path) -> Result { + Ok(prefix.join(self)) + } +} + +impl PrefixPaths for String { + fn prefix_paths(self, prefix: &Path) -> Result { + Ok(prefix + .join(env_path_from_string(self)?) + .display() + .to_string()) } } @@ -613,8 +649,8 @@ impl PrefixPaths for Option where T: PrefixPaths, { - fn prefix_paths(self, prefix: &Path) -> Self { - self.map(|inner| inner.prefix_paths(prefix)) + fn prefix_paths(self, prefix: &Path) -> Result { + self.map_or(Ok(None), |inner| Ok(Some(inner.prefix_paths(prefix)?))) } } @@ -624,10 +660,11 @@ where K: Hash + Eq, V: PrefixPaths, { - fn prefix_paths(self, prefix: &Path) -> Self { - self.into_iter() - .map(|(k, v)| (k, v.prefix_paths(prefix))) - .collect() + fn prefix_paths(self, prefix: &Path) -> Result { + Ok(self + .into_iter() + .map(|(k, v)| Ok((k, v.prefix_paths(prefix)?))) + .collect::>()?) } } @@ -636,8 +673,11 @@ impl PrefixPaths for Vec where V: PrefixPaths, { - fn prefix_paths(self, prefix: &Path) -> Self { - self.into_iter().map(|v| v.prefix_paths(prefix)).collect() + fn prefix_paths(self, prefix: &Path) -> Result { + Ok(self + .into_iter() + .map(|v| Ok(v.prefix_paths(prefix)?)) + .collect::>()?) } } @@ -661,7 +701,7 @@ pub struct Config { #[derive(Serialize, Deserialize, Debug)] pub struct PartialConfig { /// The path to the database directory. - pub database: Option, + pub database: Option, /// The git command or path to the binary. pub git: Option, /// The dependency overrides. @@ -689,13 +729,13 @@ impl Default for PartialConfig { } impl PrefixPaths for PartialConfig { - fn prefix_paths(self, prefix: &Path) -> Self { - PartialConfig { - database: self.database.prefix_paths(prefix), - overrides: self.overrides.prefix_paths(prefix), - plugins: self.plugins.prefix_paths(prefix), + fn prefix_paths(self, prefix: &Path) -> Result { + Ok(PartialConfig { + database: self.database.prefix_paths(prefix)?, + overrides: self.overrides.prefix_paths(prefix)?, + plugins: self.plugins.prefix_paths(prefix)?, ..self - } + }) } } @@ -730,7 +770,7 @@ impl Validate for PartialConfig { fn validate(self) -> Result { Ok(Config { database: match self.database { - Some(db) => db, + Some(db) => env_path_from_string(db)?, None => return Err(Error::new("Database directory not configured")), }, git: match self.git { @@ -773,29 +813,36 @@ pub struct VendorPackage { } impl PrefixPaths for VendorPackage { - fn prefix_paths(self, prefix: &Path) -> Self { - let patch_root = self.patch_dir.prefix_paths(prefix); - VendorPackage { + fn prefix_paths(self, prefix: &Path) -> Result { + let patch_root = self.patch_dir.prefix_paths(prefix)?; + Ok(VendorPackage { name: self.name, - target_dir: self.target_dir.prefix_paths(prefix), + target_dir: self.target_dir.prefix_paths(prefix)?, upstream: self.upstream, mapping: self .mapping .into_iter() - .map(|ftl| FromToLink { - from: ftl.from, - to: ftl.to, - patch_dir: ftl.patch_dir.map(|dir| { - dir.prefix_paths(&patch_root.clone().expect( + .map(|ftl| { + Ok(FromToLink { + from: ftl.from, + to: ftl.to, + patch_dir: ftl.patch_dir.map_or( + Ok::, Error>(None), + |dir| { + Ok(Some({ + dir.prefix_paths(&patch_root.clone().expect( "A mapping has a local patch_dir, but no global patch_dir is defined.", - )) - }), + ))? + })) + }, + )?, + }) }) - .collect(), + .collect::>()?, patch_dir: patch_root, include_from_upstream: self.include_from_upstream, exclude_from_upstream: self.exclude_from_upstream, - } + }) } } @@ -805,13 +852,13 @@ pub struct PartialVendorPackage { /// External dependency name pub name: Option, /// Target folder for imported dependency - pub target_dir: Option, + pub target_dir: Option, /// Upstream dependency reference pub upstream: Option, /// Import mapping pub mapping: Option>, /// Folder containing patch files - pub patch_dir: Option, + pub patch_dir: Option, // /// Dependency containing patches // pub patch_repo: Option, /// include from upstream @@ -830,7 +877,7 @@ impl Validate for PartialVendorPackage { None => return Err(Error::new("external import name missing")), }, target_dir: match self.target_dir { - Some(target_dir) => target_dir, + Some(target_dir) => env_path_from_string(target_dir)?, None => return Err(Error::new("external import target dir missing")), }, upstream: match self.upstream { @@ -843,7 +890,10 @@ impl Validate for PartialVendorPackage { Some(mapping) => mapping, None => Vec::new(), }, - patch_dir: self.patch_dir, + patch_dir: match self.patch_dir { + Some(patch_dir) => Some(env_path_from_string(patch_dir)?), + None => None, + }, include_from_upstream: match self.include_from_upstream { Some(include_from_upstream) => include_from_upstream, None => vec![String::from("**")], @@ -907,3 +957,14 @@ pub enum LockedSource { /// A registry. Registry(String), } + +fn env_path_from_string(path_str: String) -> Result { + Ok(PathBuf::from( + subst::substitute(&path_str, &subst::Env).map_err(|cause| { + Error::chain( + format!("Unable to substitute with env: {}", path_str), + cause, + ) + })?, + )) +} diff --git a/src/main.rs b/src/main.rs index 3784e77a..a7f6caef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,7 @@ extern crate is_terminal; extern crate itertools; extern crate pathdiff; extern crate semver; +extern crate subst; extern crate tempfile; extern crate typed_arena;