mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
FEATURE: support a strict mode for building.
When strict mode is off then give a warning for unset env variables and return NULL.
This commit is contained in:
parent
1365a38700
commit
aa183960d3
@ -19,6 +19,7 @@ pub enum Val {
|
||||
Str(String),
|
||||
List(Vec<Rc<Val>>),
|
||||
Tuple(Vec<(PositionedItem<String>, Rc<Val>)>),
|
||||
Env(Vec<(String, String)>),
|
||||
Macro(MacroDef),
|
||||
Module(ModuleDef),
|
||||
}
|
||||
@ -34,6 +35,7 @@ impl Val {
|
||||
&Val::Str(_) => "String".to_string(),
|
||||
&Val::List(_) => "List".to_string(),
|
||||
&Val::Tuple(_) => "Tuple".to_string(),
|
||||
&Val::Env(_) => "Env".to_string(),
|
||||
&Val::Macro(_) => "Macro".to_string(),
|
||||
&Val::Module(_) => "Module".to_string(),
|
||||
}
|
||||
@ -51,6 +53,7 @@ impl Val {
|
||||
&Val::Str(_),
|
||||
&Val::List(_),
|
||||
&Val::Tuple(_),
|
||||
&Val::Env(_),
|
||||
&Val::Macro(_),
|
||||
&Val::Module(_)
|
||||
)
|
||||
@ -165,6 +168,13 @@ impl Val {
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn is_env(&self) -> bool {
|
||||
if let &Val::Env(_) = self {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn is_list(&self) -> bool {
|
||||
if let &Val::List(_) = self {
|
||||
return true;
|
||||
@ -204,6 +214,13 @@ impl Display for Val {
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
&Val::Env(ref def) => {
|
||||
try!(write!(f, "Env(\n"));
|
||||
for v in def.iter() {
|
||||
try!(write!(f, "\t{}=\"{}\"\n", v.0, v.1));
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
125
src/build/mod.rs
125
src/build/mod.rs
@ -98,6 +98,7 @@ pub struct Builder<'a> {
|
||||
curr_file: Option<&'a str>,
|
||||
validate_mode: bool,
|
||||
pub assert_collector: AssertCollector,
|
||||
strict: bool,
|
||||
env: Rc<Val>,
|
||||
// NOTE(jwall): We use interior mutability here because we need
|
||||
// our asset cache to be shared by multiple different sub-builders.
|
||||
@ -140,6 +141,51 @@ macro_rules! eval_binary_expr {
|
||||
}
|
||||
|
||||
impl<'a> Builder<'a> {
|
||||
/// Constructs a new Builder.
|
||||
pub fn new<P: Into<PathBuf>>(root: P, cache: Rc<RefCell<assets::Cache>>) -> Self {
|
||||
Self::new_with_scope(root, cache, HashMap::new())
|
||||
}
|
||||
|
||||
/// Constructs a new Builder with a provided scope.
|
||||
pub fn new_with_scope<P: Into<PathBuf>>(
|
||||
root: P,
|
||||
cache: Rc<RefCell<assets::Cache>>,
|
||||
scope: ValueMap,
|
||||
) -> Self {
|
||||
let env_vars: Vec<(String, String)> = env::vars().collect();
|
||||
Self::new_with_env_and_scope(root, cache, scope, Rc::new(Val::Env(env_vars)))
|
||||
}
|
||||
|
||||
pub fn new_with_env_and_scope<P: Into<PathBuf>>(
|
||||
root: P,
|
||||
cache: Rc<RefCell<assets::Cache>>,
|
||||
scope: ValueMap,
|
||||
env: Rc<Val>,
|
||||
) -> Self {
|
||||
Builder {
|
||||
file: root.into(),
|
||||
curr_file: None,
|
||||
validate_mode: false,
|
||||
assert_collector: AssertCollector {
|
||||
success: true,
|
||||
summary: String::new(),
|
||||
failures: String::new(),
|
||||
},
|
||||
env: env,
|
||||
strict: true,
|
||||
assets: cache,
|
||||
build_output: scope,
|
||||
out_lock: None,
|
||||
stack: None,
|
||||
is_module: false,
|
||||
last: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_strict(&mut self, to: bool) {
|
||||
self.strict = to;
|
||||
}
|
||||
|
||||
// TOOD(jwall): This needs some unit tests.
|
||||
fn tuple_to_val(&mut self, fields: &Vec<(Token, Expression)>) -> Result<Rc<Val>, Box<Error>> {
|
||||
let mut new_fields = Vec::<(PositionedItem<String>, Rc<Val>)>::new();
|
||||
@ -185,52 +231,6 @@ impl<'a> Builder<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a new Builder.
|
||||
pub fn new<P: Into<PathBuf>>(root: P, cache: Rc<RefCell<assets::Cache>>) -> Self {
|
||||
Self::new_with_scope(root, cache, HashMap::new())
|
||||
}
|
||||
|
||||
/// Constructs a new Builder with a provided scope.
|
||||
pub fn new_with_scope<P: Into<PathBuf>>(
|
||||
root: P,
|
||||
cache: Rc<RefCell<assets::Cache>>,
|
||||
scope: ValueMap,
|
||||
) -> Self {
|
||||
let env_vars: Vec<(PositionedItem<String>, Rc<Val>)> = env::vars()
|
||||
.map(|t| {
|
||||
(
|
||||
PositionedItem::new(t.0, Position::new(0, 0, 0)),
|
||||
Rc::new(t.1.into()),
|
||||
)
|
||||
}).collect();
|
||||
Self::new_with_env_and_scope(root, cache, scope, Rc::new(Val::Tuple(env_vars)))
|
||||
}
|
||||
|
||||
pub fn new_with_env_and_scope<P: Into<PathBuf>>(
|
||||
root: P,
|
||||
cache: Rc<RefCell<assets::Cache>>,
|
||||
scope: ValueMap,
|
||||
env: Rc<Val>,
|
||||
) -> Self {
|
||||
Builder {
|
||||
file: root.into(),
|
||||
curr_file: None,
|
||||
validate_mode: false,
|
||||
assert_collector: AssertCollector {
|
||||
success: true,
|
||||
summary: String::new(),
|
||||
failures: String::new(),
|
||||
},
|
||||
env: env,
|
||||
assets: cache,
|
||||
build_output: scope,
|
||||
out_lock: None,
|
||||
stack: None,
|
||||
is_module: false,
|
||||
last: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a Val by name from previously built UCG.
|
||||
pub fn get_out_by_name(&self, name: &str) -> Option<Rc<Val>> {
|
||||
let key = PositionedItem {
|
||||
@ -442,6 +442,32 @@ impl<'a> Builder<'a> {
|
||||
return None;
|
||||
}
|
||||
|
||||
fn lookup_in_env(
|
||||
&self,
|
||||
search: &Token,
|
||||
stack: &mut VecDeque<Rc<Val>>,
|
||||
fs: &Vec<(String, String)>,
|
||||
) -> Result<(), Box<Error>> {
|
||||
for &(ref name, ref val) in fs.iter() {
|
||||
if &search.fragment == name {
|
||||
stack.push_back(Rc::new(Val::Str(val.clone())));
|
||||
return Ok(());
|
||||
} else if !self.strict {
|
||||
eprintln!(
|
||||
"Environment Variable {} not set using NULL instead.",
|
||||
search.fragment
|
||||
);
|
||||
stack.push_back(Rc::new(Val::Empty));
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
return Err(Box::new(error::BuildError::new(
|
||||
format!("Environment Variable {} not set", search.fragment),
|
||||
error::ErrorType::NoSuchSymbol,
|
||||
search.pos.clone(),
|
||||
)));
|
||||
}
|
||||
|
||||
fn lookup_in_tuple(
|
||||
&self,
|
||||
stack: &mut VecDeque<Rc<Val>>,
|
||||
@ -506,6 +532,9 @@ impl<'a> Builder<'a> {
|
||||
&Val::List(_) => {
|
||||
stack.push_back(first.clone());
|
||||
}
|
||||
&Val::Env(_) => {
|
||||
stack.push_back(first.clone());
|
||||
}
|
||||
_ => {
|
||||
// noop
|
||||
}
|
||||
@ -529,6 +558,10 @@ impl<'a> Builder<'a> {
|
||||
try!(self.lookup_in_tuple(&mut stack, sl, (&next.pos, &next.fragment), fs));
|
||||
continue;
|
||||
}
|
||||
&Val::Env(ref fs) => {
|
||||
try!(self.lookup_in_env(&next, &mut stack, fs));
|
||||
continue;
|
||||
}
|
||||
&Val::List(ref elems) => {
|
||||
try!(self.lookup_in_list(
|
||||
&mut stack,
|
||||
|
@ -82,6 +82,10 @@ impl EnvConverter {
|
||||
// This is ignored
|
||||
eprintln!("Skipping macro...");
|
||||
}
|
||||
&Val::Env(ref _fs) => {
|
||||
// This is ignored
|
||||
eprintln!("Skipping env...");
|
||||
}
|
||||
&Val::Module(ref _def) => {
|
||||
// This is ignored
|
||||
eprintln!("Skipping module...");
|
||||
|
@ -98,6 +98,10 @@ impl FlagConverter {
|
||||
// This is ignored
|
||||
eprintln!("Skipping macro...");
|
||||
}
|
||||
&Val::Env(ref _fs) => {
|
||||
// This is ignored
|
||||
eprintln!("Skipping env...");
|
||||
}
|
||||
&Val::Module(ref _def) => {
|
||||
// This is ignored
|
||||
eprintln!("Skipping module...");
|
||||
|
@ -46,6 +46,15 @@ impl JsonConverter {
|
||||
Ok(serde_json::Value::Object(mp))
|
||||
}
|
||||
|
||||
fn convert_env(&self, items: &Vec<(String, String)>) -> std::io::Result<serde_json::Value> {
|
||||
let mut mp = serde_json::Map::new();
|
||||
for &(ref k, ref v) in items.iter() {
|
||||
mp.entry(k.clone())
|
||||
.or_insert(serde_json::Value::String(v.clone()));
|
||||
}
|
||||
Ok(serde_json::Value::Object(mp))
|
||||
}
|
||||
|
||||
fn convert_value(&self, v: &Val) -> std::io::Result<serde_json::Value> {
|
||||
let jsn_val = match v {
|
||||
&Val::Boolean(b) => serde_json::Value::Bool(b),
|
||||
@ -75,6 +84,7 @@ impl JsonConverter {
|
||||
eprintln!("Skipping module encoding as null...");
|
||||
serde_json::Value::Null
|
||||
}
|
||||
&Val::Env(ref fs) => try!(self.convert_env(fs)),
|
||||
&Val::List(ref l) => try!(self.convert_list(l)),
|
||||
&Val::Tuple(ref t) => try!(self.convert_tuple(t)),
|
||||
};
|
||||
|
@ -50,6 +50,15 @@ impl TomlConverter {
|
||||
Ok(toml::Value::Table(mp))
|
||||
}
|
||||
|
||||
fn convert_env(&self, items: &Vec<(String, String)>) -> ConvertResult {
|
||||
let mut mp = toml::value::Table::new();
|
||||
for &(ref k, ref v) in items.iter() {
|
||||
mp.entry(k.clone())
|
||||
.or_insert(toml::Value::String(v.clone()));
|
||||
}
|
||||
Ok(toml::Value::Table(mp))
|
||||
}
|
||||
|
||||
fn convert_value(&self, v: &Val) -> ConvertResult {
|
||||
let toml_val = match v {
|
||||
&Val::Boolean(b) => toml::Value::Boolean(b),
|
||||
@ -69,6 +78,7 @@ impl TomlConverter {
|
||||
let err = SimpleError::new("Modules are not allowed in Toml Conversions!");
|
||||
return Err(Box::new(err));
|
||||
}
|
||||
&Val::Env(ref fs) => try!(self.convert_env(fs)),
|
||||
&Val::List(ref l) => try!(self.convert_list(l)),
|
||||
&Val::Tuple(ref t) => try!(self.convert_tuple(t)),
|
||||
};
|
||||
|
@ -23,6 +23,17 @@ impl YamlConverter {
|
||||
Ok(serde_yaml::Value::Sequence(v))
|
||||
}
|
||||
|
||||
fn convert_env(&self, items: &Vec<(String, String)>) -> std::io::Result<serde_yaml::Value> {
|
||||
let mut mp = serde_yaml::Mapping::new();
|
||||
for &(ref k, ref v) in items.iter() {
|
||||
mp.insert(
|
||||
serde_yaml::Value::String(k.clone()),
|
||||
serde_yaml::Value::String(v.clone()),
|
||||
);
|
||||
}
|
||||
Ok(serde_yaml::Value::Mapping(mp))
|
||||
}
|
||||
|
||||
fn convert_tuple(
|
||||
&self,
|
||||
items: &Vec<(ast::PositionedItem<String>, Rc<Val>)>,
|
||||
@ -58,6 +69,7 @@ impl YamlConverter {
|
||||
eprintln!("Skipping module encoding as null...");
|
||||
serde_yaml::Value::Null
|
||||
}
|
||||
&Val::Env(ref fs) => try!(self.convert_env(fs)),
|
||||
&Val::List(ref l) => try!(self.convert_list(l)),
|
||||
&Val::Tuple(ref t) => try!(self.convert_tuple(t)),
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user