Skip to content

Commit

Permalink
Work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
amousset committed Jul 29, 2020
1 parent 5abd2b3 commit 30c3dbe
Show file tree
Hide file tree
Showing 14 changed files with 291 additions and 587 deletions.
598 changes: 125 additions & 473 deletions rudder-lang/Cargo.lock

Large diffs are not rendered by default.

23 changes: 9 additions & 14 deletions rudder-lang/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,21 @@ name = "rudderc"
path = "src/bin/rudderc.rs"

[dependencies]
colored = "2"
env_logger = "0.7"
lazy_static = "1"
log = "0.4"
maplit = "1"
ngrammatic = "0.3"
nom = "5"
nom_locate = "2"
regex = "1"
serde = { version = "1", features = ["derive" ] }
serde_json = "1"
structopt = "0.3"
nom = "5"
toml = "0.5"
regex = "1"
lazy_static = "1"
nom_locate = "2"
colored = "1"
ngrammatic = "0.3"
log = "0.4"
env_logger = "0.7"
typed-arena = "2.0"
walkdir = "2"

[dev-dependencies]
proptest = "0.9"
test-case = "0.3"

[build-dependencies]
serde = { version = "1", features = ["derive"] }
colored = "1"
test-case = "1"
3 changes: 2 additions & 1 deletion rudder-lang/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,8 @@ impl<'src> AST<'src> {
"struct",
"list", // "string", "boolean", // should not be used
// variables
"let", "resource", // "state", // should not be used
"let",
"resource", // "state", // should not be used
// flow statements
"if",
"case",
Expand Down
60 changes: 50 additions & 10 deletions rudder-lang/src/ast/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,16 +213,56 @@ mod tests {

let mut context = value_generator(Some("let sys"));

assert!(VarContext::push_new_variable(&mut context, &value_generator(Some("let sys.windows"))).is_ok());
assert!(VarContext::push_new_variable(&mut context, &value_generator(Some("let sys.windows"))).is_ok()); // direct duplicate
assert!(VarContext::push_new_variable(&mut context, &value_generator(Some("let sys.linux"))).is_ok());
assert!(VarContext::push_new_variable(&mut context, &value_generator(Some("let sys.linux.debian_9"))).is_ok()); // push inner into existing String element
assert!(VarContext::push_new_variable(&mut context, &value_generator(Some("let sys.linux.debian_10"))).is_ok());
assert!(VarContext::push_new_variable(&mut context, &value_generator(Some("let sys.linux.debian_9"))).is_ok()); // inner non-direct duplicate
assert!(VarContext::push_new_variable(&mut context, &value_generator(Some("let sys.long.var.decl.ok"))).is_ok()); // deep nested element
assert!(VarContext::push_new_variable(&mut context, &value_generator(Some("let sys.long.var.decl.ok_too"))).is_ok()); // push deep innest element
assert!(VarContext::push_new_variable(&mut context, &value_generator(Some("let sys.long.var.decl2"))).is_ok()); // post-push deep outter element
assert!(VarContext::push_new_variable(&mut context, &value_generator(Some("let sys.linux"))).is_ok()); // outtest non-direct duplicate
assert!(VarContext::push_new_variable(
&mut context,
&value_generator(Some("let sys.windows"))
)
.is_ok());
assert!(VarContext::push_new_variable(
&mut context,
&value_generator(Some("let sys.windows"))
)
.is_ok()); // direct duplicate
assert!(VarContext::push_new_variable(
&mut context,
&value_generator(Some("let sys.linux"))
)
.is_ok());
assert!(VarContext::push_new_variable(
&mut context,
&value_generator(Some("let sys.linux.debian_9"))
)
.is_ok()); // push inner into existing String element
assert!(VarContext::push_new_variable(
&mut context,
&value_generator(Some("let sys.linux.debian_10"))
)
.is_ok());
assert!(VarContext::push_new_variable(
&mut context,
&value_generator(Some("let sys.linux.debian_9"))
)
.is_ok()); // inner non-direct duplicate
assert!(VarContext::push_new_variable(
&mut context,
&value_generator(Some("let sys.long.var.decl.ok"))
)
.is_ok()); // deep nested element
assert!(VarContext::push_new_variable(
&mut context,
&value_generator(Some("let sys.long.var.decl.ok_too"))
)
.is_ok()); // push deep innest element
assert!(VarContext::push_new_variable(
&mut context,
&value_generator(Some("let sys.long.var.decl2"))
)
.is_ok()); // post-push deep outter element
assert!(VarContext::push_new_variable(
&mut context,
&value_generator(Some("let sys.linux"))
)
.is_ok()); // outtest non-direct duplicate

let os = [
(
Expand Down
8 changes: 1 addition & 7 deletions rudder-lang/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,5 @@ pub fn compile_file(ctx: &IOContext, technique: bool) -> Result<()> {
(None, None)
};
let mut generator = new_generator(&ctx.format)?;
generator.generate(
&ast,
input_file,
output_file,
&ctx.meta_gm,
technique,
)
generator.generate(&ast, input_file, output_file, &ctx.meta_gm, technique)
}
2 changes: 1 addition & 1 deletion rudder-lang/src/generators/cfengine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ impl Generator for CFEngine {
gc: &AST,
source_file: Option<&Path>,
dest_file: Option<&Path>,
meta_gm: &Path,
_meta_gm: &Path,
policy_metadata: bool,
) -> Result<()> {
let mut files: HashMap<String, String> = HashMap::new();
Expand Down
17 changes: 1 addition & 16 deletions rudder-lang/src/generators/cfengine/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,26 +428,11 @@ impl Bundle {
Self { parameters, ..self }
}

pub fn promise(mut self, promise: Promise) -> Self {
self.add_promise(promise);
self
}

pub fn promise_group(mut self, promise_group: Vec<Promise>) -> Self {
self.add_promise_group(promise_group);
self
}

pub fn add_promise(&mut self, promise: Promise) {
match self.promises.get_mut(&promise.promise_type) {
Some(promises) => promises.push(vec![promise]),
None => {
self.promises
.insert(promise.promise_type, vec![vec![promise]]);
}
}
}

pub fn add_promise_group(&mut self, promise_group: Vec<Promise>) {
if promise_group.is_empty() {
return;
Expand Down Expand Up @@ -611,7 +596,7 @@ mod tests {
assert_eq!(
Bundle::agent("test")
.parameters(vec!["file".to_string(), "lines".to_string()])
.promise(Promise::usebundle("test", vec![]))
.promise_group(vec![Promise::usebundle("test", vec![])])
.to_string(),
"bundle agent test(file, lines) {\n\n methods:\n \"${report_data.directive_id}_0\" usebundle => test();\n\n}"
);
Expand Down
56 changes: 32 additions & 24 deletions rudder-lang/src/generators/dsc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@ impl DSC {
state_def: &StateDef,
generic_method_name: &str,
) -> Result<(String, usize)> {

// if one day several class_parameters are used as they previously were, get the relative code from this commit
// 89651a6a8a05475eabccefc23e4fe23235a7e011 . This file, line 170
match state_def.metadata.get(&Token::from("class_parameter")) {
Expand All @@ -159,7 +158,7 @@ impl DSC {
}
};
Ok((p.0.to_owned(), p_index))
},
}
_ => {
return Err(Error::User(format!(
"Generic methods should have 1 class parameter (not the case for {})",
Expand Down Expand Up @@ -204,8 +203,8 @@ impl DSC {
.map(|p| p.name.fragment())
.collect::<Vec<&str>>();


let is_dsc_supported: bool = match state_def.metadata.get(&Token::from("supported_formats")) {
let is_dsc_supported: bool = match state_def.metadata.get(&Token::from("supported_formats"))
{
Some(Value::List(parameters)) => {
let mut is_dsc_listed = false;
for p in parameters {
Expand All @@ -217,11 +216,11 @@ impl DSC {
} else {
return Err(Error::User(String::from(
"Expected value type for supported_formats metadata: String",
)))
)));
}
}
is_dsc_listed
},
}
_ => {
return Err(Error::User(format!(
"{} Generic method has no \"supported_formats\" metadata",
Expand Down Expand Up @@ -261,7 +260,12 @@ impl DSC {
// TODO variables
// TODO comments and metadata
// TODO use in_class everywhere
fn format_statement(&mut self, gc: &AST, st: &Statement, condition_content: String) -> Result<String> {
fn format_statement(
&mut self,
gc: &AST,
st: &Statement,
condition_content: String,
) -> Result<String> {
match st {
Statement::StateDeclaration(sd) => {
if let Some(var) = sd.outcome {
Expand All @@ -276,7 +280,8 @@ impl DSC {
_ => "any".to_string(),
};

let (params_formatted_str, class_param, is_dsc_gm) = self.get_method_parameters(gc, sd)?;
let (params_formatted_str, class_param, is_dsc_gm) =
self.get_method_parameters(gc, sd)?;

let condition = self.format_condition(condition_content)?;

Expand All @@ -295,14 +300,16 @@ impl DSC {
false => na_call.clone(),
};


if condition == "any" {
Ok(call)
} else {
let formatted_condition = &format!("\n $Condition = \"any.({})\"\n if (Evaluate-Class $Condition $LocalClasses $SystemClasses) {{", condition);
Ok(match is_dsc_gm {
true => format!("{}\n {}\n }} else {{\n {}\n }}", formatted_condition, call, na_call),
false => format!("{}\n {}\n }}\n", formatted_condition, call)
true => format!(
"{}\n {}\n }} else {{\n {}\n }}",
formatted_condition, call, na_call
),
false => format!("{}\n {}\n }}\n", formatted_condition, call),
})
}
}
Expand All @@ -311,16 +318,14 @@ impl DSC {
map_strings_results(
vec.iter(),
|(case, vst)| {
let condition_content = self.format_case_expr(gc, case)?;
map_strings_results(
vst.iter(),
|st| {
self.format_statement(gc, st, condition_content.clone())
},
"",
)
},
"",
let condition_content = self.format_case_expr(gc, case)?;
map_strings_results(
vst.iter(),
|st| self.format_statement(gc, st, condition_content.clone()),
"",
)
},
"",
)
}
Statement::Fail(msg) => Ok(format!(
Expand All @@ -339,7 +344,8 @@ impl DSC {
} else {
"error"
};
let content = format!(r#" $State = [ComplianceStatus]::result_{}
let content = format!(
r#" $State = [ComplianceStatus]::result_{}
$Classes = _rudder_common_report -TechniqueName $TechniqueName -Status $State -ReportId $ReportId -ComponentName "TODO" -ComponentKey "TODO" -Message "TODO" -MessageInfo "TODO" -MessageVerbose "TODO" -report:"TODO"
@{{"status" = $State; "classes" = $Classes}}
"#,
Expand Down Expand Up @@ -526,7 +532,8 @@ impl Generator for DSC {
.join(",\n");

// add default dsc parameters
let parameters: String = format!(r#"{},
let parameters: String = format!(
r#"{},
[Parameter(Mandatory=$False)] [Switch] $AuditOnly,
[Parameter(Mandatory=$True)] [String] $ReportId,
[Parameter(Mandatory=$True)] [String] $TechniqueName"#,
Expand All @@ -541,7 +548,8 @@ impl Generator for DSC {
.collect::<Result<Vec<String>>>()?
.join("\n");
// merge header + parameters + methods with technique file body
let content = format!(r#"# generated by rudder-lang
let content = format!(
r#"# generated by rudder-lang
{header}
function {resource_name}-{state_name} {{
[CmdletBinding()]
Expand Down
4 changes: 1 addition & 3 deletions rudder-lang/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1000,9 +1000,7 @@ fn pfile(i: PInput) -> PResult<PFile> {

#[cfg(test)]
pub fn test_new_pvalue(s: &str) -> PValue {
let res = pvariable_declaration(
Token::from(s).into()
).unwrap();
let res = pvariable_declaration(Token::from(s).into()).unwrap();
(res.1).1
}

Expand Down
27 changes: 16 additions & 11 deletions rudder-lang/src/parser/baseparsers.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use nom::{
branch::*, bytes::complete::*, character::complete::*, combinator::*, multi::*, sequence::*, Slice
branch::*, bytes::complete::*, character::complete::*, combinator::*, multi::*, sequence::*,
Slice,
};

use super::{error::*, token::*};
Expand Down Expand Up @@ -152,7 +153,11 @@ macro_rules! generic_sequence {
}

/// extract the parsed data once something hase been parsed
pub fn get_parsed_context<'src>(input: PInput<'src>, start: PInput<'src>, stop: PInput<'src>) -> Token<'src> {
pub fn get_parsed_context<'src>(
input: PInput<'src>,
start: PInput<'src>,
stop: PInput<'src>,
) -> Token<'src> {
let start_offset = start.location_offset() - input.location_offset();
let stop_offset = stop.location_offset() - input.location_offset();
input.slice(start_offset..stop_offset).into()
Expand Down Expand Up @@ -250,33 +255,33 @@ where
/// It extracts the longest string between a single line and everything until the parsing error
pub fn get_error_context<'src>(i: PInput<'src>, err_pos: PInput<'src>) -> PInput<'src> {
// One line, or everything else if no new line (end of file)
let line: PResult<PInput> = alt((
take_until("\n"),
rest
))(i);
let line: PResult<PInput> = alt((take_until("\n"), rest))(i);
let line = match line {
Ok((_, rest)) => Some(rest),
_ => None
_ => None,
};

// Until next text
let complete: PResult<PInput> = take_until("\n")(err_pos);
let complete = match complete {
Ok((_, rest)) => Some(rest),
_ => None
_ => None,
};

match (line, complete) {
(Some(l), Some(c)) => {
if l.location_line() > c.location_line() || (l.location_line() == c.location_line() && l.fragment().len() > c.fragment().len()) {
if l.location_line() > c.location_line()
|| (l.location_line() == c.location_line()
&& l.fragment().len() > c.fragment().len())
{
l
} else {
c
}
},
}
(Some(l), None) => l,
(None, Some(c)) => c,
(None, None) => panic!("Context should never be empty")
(None, None) => panic!("Context should never be empty"),
}
}

Expand Down
Loading

0 comments on commit 30c3dbe

Please sign in to comment.