mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-25 18:49:50 -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),
|
Str(String),
|
||||||
List(Vec<Rc<Val>>),
|
List(Vec<Rc<Val>>),
|
||||||
Tuple(Vec<(PositionedItem<String>, Rc<Val>)>),
|
Tuple(Vec<(PositionedItem<String>, Rc<Val>)>),
|
||||||
|
Env(Vec<(String, String)>),
|
||||||
Macro(MacroDef),
|
Macro(MacroDef),
|
||||||
Module(ModuleDef),
|
Module(ModuleDef),
|
||||||
}
|
}
|
||||||
@ -34,6 +35,7 @@ impl Val {
|
|||||||
&Val::Str(_) => "String".to_string(),
|
&Val::Str(_) => "String".to_string(),
|
||||||
&Val::List(_) => "List".to_string(),
|
&Val::List(_) => "List".to_string(),
|
||||||
&Val::Tuple(_) => "Tuple".to_string(),
|
&Val::Tuple(_) => "Tuple".to_string(),
|
||||||
|
&Val::Env(_) => "Env".to_string(),
|
||||||
&Val::Macro(_) => "Macro".to_string(),
|
&Val::Macro(_) => "Macro".to_string(),
|
||||||
&Val::Module(_) => "Module".to_string(),
|
&Val::Module(_) => "Module".to_string(),
|
||||||
}
|
}
|
||||||
@ -51,6 +53,7 @@ impl Val {
|
|||||||
&Val::Str(_),
|
&Val::Str(_),
|
||||||
&Val::List(_),
|
&Val::List(_),
|
||||||
&Val::Tuple(_),
|
&Val::Tuple(_),
|
||||||
|
&Val::Env(_),
|
||||||
&Val::Macro(_),
|
&Val::Macro(_),
|
||||||
&Val::Module(_)
|
&Val::Module(_)
|
||||||
)
|
)
|
||||||
@ -165,6 +168,13 @@ impl Val {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_env(&self) -> bool {
|
||||||
|
if let &Val::Env(_) = self {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_list(&self) -> bool {
|
pub fn is_list(&self) -> bool {
|
||||||
if let &Val::List(_) = self {
|
if let &Val::List(_) = self {
|
||||||
return true;
|
return true;
|
||||||
@ -204,6 +214,13 @@ impl Display for Val {
|
|||||||
}
|
}
|
||||||
write!(f, ")")
|
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>,
|
curr_file: Option<&'a str>,
|
||||||
validate_mode: bool,
|
validate_mode: bool,
|
||||||
pub assert_collector: AssertCollector,
|
pub assert_collector: AssertCollector,
|
||||||
|
strict: bool,
|
||||||
env: Rc<Val>,
|
env: Rc<Val>,
|
||||||
// NOTE(jwall): We use interior mutability here because we need
|
// NOTE(jwall): We use interior mutability here because we need
|
||||||
// our asset cache to be shared by multiple different sub-builders.
|
// our asset cache to be shared by multiple different sub-builders.
|
||||||
@ -140,6 +141,51 @@ macro_rules! eval_binary_expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Builder<'a> {
|
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.
|
// TOOD(jwall): This needs some unit tests.
|
||||||
fn tuple_to_val(&mut self, fields: &Vec<(Token, Expression)>) -> Result<Rc<Val>, Box<Error>> {
|
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();
|
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.
|
/// Returns a Val by name from previously built UCG.
|
||||||
pub fn get_out_by_name(&self, name: &str) -> Option<Rc<Val>> {
|
pub fn get_out_by_name(&self, name: &str) -> Option<Rc<Val>> {
|
||||||
let key = PositionedItem {
|
let key = PositionedItem {
|
||||||
@ -442,6 +442,32 @@ impl<'a> Builder<'a> {
|
|||||||
return None;
|
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(
|
fn lookup_in_tuple(
|
||||||
&self,
|
&self,
|
||||||
stack: &mut VecDeque<Rc<Val>>,
|
stack: &mut VecDeque<Rc<Val>>,
|
||||||
@ -506,6 +532,9 @@ impl<'a> Builder<'a> {
|
|||||||
&Val::List(_) => {
|
&Val::List(_) => {
|
||||||
stack.push_back(first.clone());
|
stack.push_back(first.clone());
|
||||||
}
|
}
|
||||||
|
&Val::Env(_) => {
|
||||||
|
stack.push_back(first.clone());
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// noop
|
// noop
|
||||||
}
|
}
|
||||||
@ -529,6 +558,10 @@ impl<'a> Builder<'a> {
|
|||||||
try!(self.lookup_in_tuple(&mut stack, sl, (&next.pos, &next.fragment), fs));
|
try!(self.lookup_in_tuple(&mut stack, sl, (&next.pos, &next.fragment), fs));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
&Val::Env(ref fs) => {
|
||||||
|
try!(self.lookup_in_env(&next, &mut stack, fs));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
&Val::List(ref elems) => {
|
&Val::List(ref elems) => {
|
||||||
try!(self.lookup_in_list(
|
try!(self.lookup_in_list(
|
||||||
&mut stack,
|
&mut stack,
|
||||||
|
@ -82,6 +82,10 @@ impl EnvConverter {
|
|||||||
// This is ignored
|
// This is ignored
|
||||||
eprintln!("Skipping macro...");
|
eprintln!("Skipping macro...");
|
||||||
}
|
}
|
||||||
|
&Val::Env(ref _fs) => {
|
||||||
|
// This is ignored
|
||||||
|
eprintln!("Skipping env...");
|
||||||
|
}
|
||||||
&Val::Module(ref _def) => {
|
&Val::Module(ref _def) => {
|
||||||
// This is ignored
|
// This is ignored
|
||||||
eprintln!("Skipping module...");
|
eprintln!("Skipping module...");
|
||||||
|
@ -98,6 +98,10 @@ impl FlagConverter {
|
|||||||
// This is ignored
|
// This is ignored
|
||||||
eprintln!("Skipping macro...");
|
eprintln!("Skipping macro...");
|
||||||
}
|
}
|
||||||
|
&Val::Env(ref _fs) => {
|
||||||
|
// This is ignored
|
||||||
|
eprintln!("Skipping env...");
|
||||||
|
}
|
||||||
&Val::Module(ref _def) => {
|
&Val::Module(ref _def) => {
|
||||||
// This is ignored
|
// This is ignored
|
||||||
eprintln!("Skipping module...");
|
eprintln!("Skipping module...");
|
||||||
|
@ -46,6 +46,15 @@ impl JsonConverter {
|
|||||||
Ok(serde_json::Value::Object(mp))
|
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> {
|
fn convert_value(&self, v: &Val) -> std::io::Result<serde_json::Value> {
|
||||||
let jsn_val = match v {
|
let jsn_val = match v {
|
||||||
&Val::Boolean(b) => serde_json::Value::Bool(b),
|
&Val::Boolean(b) => serde_json::Value::Bool(b),
|
||||||
@ -75,6 +84,7 @@ impl JsonConverter {
|
|||||||
eprintln!("Skipping module encoding as null...");
|
eprintln!("Skipping module encoding as null...");
|
||||||
serde_json::Value::Null
|
serde_json::Value::Null
|
||||||
}
|
}
|
||||||
|
&Val::Env(ref fs) => try!(self.convert_env(fs)),
|
||||||
&Val::List(ref l) => try!(self.convert_list(l)),
|
&Val::List(ref l) => try!(self.convert_list(l)),
|
||||||
&Val::Tuple(ref t) => try!(self.convert_tuple(t)),
|
&Val::Tuple(ref t) => try!(self.convert_tuple(t)),
|
||||||
};
|
};
|
||||||
|
@ -50,6 +50,15 @@ impl TomlConverter {
|
|||||||
Ok(toml::Value::Table(mp))
|
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 {
|
fn convert_value(&self, v: &Val) -> ConvertResult {
|
||||||
let toml_val = match v {
|
let toml_val = match v {
|
||||||
&Val::Boolean(b) => toml::Value::Boolean(b),
|
&Val::Boolean(b) => toml::Value::Boolean(b),
|
||||||
@ -69,6 +78,7 @@ impl TomlConverter {
|
|||||||
let err = SimpleError::new("Modules are not allowed in Toml Conversions!");
|
let err = SimpleError::new("Modules are not allowed in Toml Conversions!");
|
||||||
return Err(Box::new(err));
|
return Err(Box::new(err));
|
||||||
}
|
}
|
||||||
|
&Val::Env(ref fs) => try!(self.convert_env(fs)),
|
||||||
&Val::List(ref l) => try!(self.convert_list(l)),
|
&Val::List(ref l) => try!(self.convert_list(l)),
|
||||||
&Val::Tuple(ref t) => try!(self.convert_tuple(t)),
|
&Val::Tuple(ref t) => try!(self.convert_tuple(t)),
|
||||||
};
|
};
|
||||||
|
@ -23,6 +23,17 @@ impl YamlConverter {
|
|||||||
Ok(serde_yaml::Value::Sequence(v))
|
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(
|
fn convert_tuple(
|
||||||
&self,
|
&self,
|
||||||
items: &Vec<(ast::PositionedItem<String>, Rc<Val>)>,
|
items: &Vec<(ast::PositionedItem<String>, Rc<Val>)>,
|
||||||
@ -58,6 +69,7 @@ impl YamlConverter {
|
|||||||
eprintln!("Skipping module encoding as null...");
|
eprintln!("Skipping module encoding as null...");
|
||||||
serde_yaml::Value::Null
|
serde_yaml::Value::Null
|
||||||
}
|
}
|
||||||
|
&Val::Env(ref fs) => try!(self.convert_env(fs)),
|
||||||
&Val::List(ref l) => try!(self.convert_list(l)),
|
&Val::List(ref l) => try!(self.convert_list(l)),
|
||||||
&Val::Tuple(ref t) => try!(self.convert_tuple(t)),
|
&Val::Tuple(ref t) => try!(self.convert_tuple(t)),
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user