Skip to content

Commit

Permalink
feat: improved output format (#126)
Browse files Browse the repository at this point in the history
  • Loading branch information
RomainMuller authored May 10, 2023
1 parent 1ca198e commit 169a091
Show file tree
Hide file tree
Showing 15 changed files with 764 additions and 505 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ homepage = "https://github.com/iph/noctilucent#readme"

[dependencies]
anyhow = "1.0.70"
base64 = "0.21.0"
clap = "4.2.1"
indexmap = { version = "1.9.3", features = ["serde"] }
nom = "7.0.0"
Expand Down
11 changes: 11 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::HashMap;
use std::io::Write;
use std::process::Command;
use std::{fs, io};

use serde::Deserialize;
Expand Down Expand Up @@ -53,6 +54,16 @@ fn main() -> io::Result<()> {
)?;
}

// Install some TypeScript stuff in the right places for IDE comfort. Silently ignore if failing...
let npm_exit = Command::new("npm")
.args(["install", "--no-save", "aws-cdk-lib", "@types/node"])
.current_dir("tests/end-to-end")
.status()
.unwrap();
if !npm_exit.success() {
eprintln!("npm install failed with {npm_exit:?}");
}

Ok(())
}

Expand Down
2 changes: 1 addition & 1 deletion src/ir/importer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl ImportInstruction {
];

import_instructions.reserve(type_names.len());
for type_name in type_names.iter() {
for type_name in &type_names {
import_instructions.push(ImportInstruction {
name: type_name.service.to_string(),
path: vec![
Expand Down
86 changes: 42 additions & 44 deletions src/ir/resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::TransmuteError;
use indexmap::IndexMap;
use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::convert::TryInto;
use std::ops::Deref;
use topological_sort::TopologicalSort;

Expand Down Expand Up @@ -37,11 +38,11 @@ pub enum ResourceIr {
Split(String, Box<ResourceIr>),
Ref(Reference),
Sub(Vec<ResourceIr>),
Map(Box<ResourceIr>, Box<ResourceIr>, Box<ResourceIr>),
Map(String, Box<ResourceIr>, Box<ResourceIr>),
Base64(Box<ResourceIr>),
ImportValue(Box<ResourceIr>),
ImportValue(String),
GetAZs(Box<ResourceIr>),
Select(i64, Box<ResourceIr>),
Select(usize, Box<ResourceIr>),
Cidr(Box<ResourceIr>, Box<ResourceIr>, Box<ResourceIr>),
}

Expand Down Expand Up @@ -186,11 +187,10 @@ impl<'t> ResourceTranslator<'t> {
second_level_key,
} => {
let rt = self.with_complexity(Structure::Simple(CfnType::String));
let map_name_str = rt.translate(map_name)?;
let top_level_key_str = rt.translate(top_level_key)?;
let second_level_key_str = rt.translate(second_level_key)?;
Ok(ResourceIr::Map(
Box::new(map_name_str),
map_name,
Box::new(top_level_key_str),
Box::new(second_level_key_str),
))
Expand Down Expand Up @@ -240,19 +240,23 @@ impl<'t> ResourceTranslator<'t> {
let ir = self.translate(x)?;
Ok(ResourceIr::Base64(Box::new(ir)))
}
IntrinsicFunction::ImportValue(x) => {
let ir = self.translate(x)?;
Ok(ResourceIr::ImportValue(Box::new(ir)))
}
IntrinsicFunction::ImportValue(name) => Ok(ResourceIr::ImportValue(name)),
IntrinsicFunction::Select { index, list } => {
let index = match index {
ResourceValue::String(x) => match x.parse::<i64>() {
ResourceValue::String(x) => match x.parse::<usize>() {
Ok(x) => x,
Err(_) => {
return Err(TransmuteError::new("index must be int for Select"))
}
},
ResourceValue::Number(x) => x,
ResourceValue::Number(x) => match x.try_into() {
Ok(x) => x,
Err(cause) => {
return Err(TransmuteError::new(format!(
"index is too large for Select: {cause}"
)))
}
},
_ => return Err(TransmuteError::new("index must be int for Select")),
};

Expand Down Expand Up @@ -421,10 +425,10 @@ fn order(resource_instructions: Vec<ResourceInstruction>) -> Vec<ResourceInstruc
for resource_instruction in resource_instructions {
topo.insert(resource_instruction.name.to_string());

for dep in resource_instruction.dependencies.iter() {
for dep in &resource_instruction.dependencies {
topo.add_dependency(dep, resource_instruction.name.to_string());
}
for (_, property) in resource_instruction.properties.iter() {
for (_, property) in &resource_instruction.properties {
find_dependencies(&resource_instruction.name, property, &mut topo)
}
hash.insert(resource_instruction.name.to_string(), resource_instruction);
Expand Down Expand Up @@ -452,7 +456,8 @@ fn find_references(resource: &ResourceIr) -> Option<Vec<String>> {
| ResourceIr::Bool(_)
| ResourceIr::Number(_)
| ResourceIr::Double(_)
| ResourceIr::String(_) => Option::None,
| ResourceIr::String(_)
| ResourceIr::ImportValue(_) => None,

ResourceIr::Array(_, arr) => {
let mut v = Vec::with_capacity(arr.len());
Expand All @@ -462,7 +467,7 @@ fn find_references(resource: &ResourceIr) -> Option<Vec<String>> {
}
}

Option::Some(v)
Some(v)
}
ResourceIr::Object(_, hash) => {
let mut v = Vec::with_capacity(hash.len());
Expand All @@ -472,7 +477,7 @@ fn find_references(resource: &ResourceIr) -> Option<Vec<String>> {
}
}

Option::Some(v)
Some(v)
}
ResourceIr::If(_, x, y) => {
let mut v = Vec::with_capacity(2);
Expand All @@ -483,7 +488,7 @@ fn find_references(resource: &ResourceIr) -> Option<Vec<String>> {
v.extend(vec);
}

Option::Some(v)
Some(v)
}
ResourceIr::Join(_, arr) => {
let mut v = Vec::new();
Expand All @@ -493,13 +498,13 @@ fn find_references(resource: &ResourceIr) -> Option<Vec<String>> {
}
}

Option::Some(v)
Some(v)
}
ResourceIr::Split(_, ir) => find_references(ir),
ResourceIr::Ref(x) => match x.origin {
Origin::Parameter | Origin::Condition | Origin::PseudoParameter(_) => Option::None,
Origin::LogicalId => Option::Some(vec![x.name.to_string()]),
Origin::GetAttribute(_) => Option::Some(vec![x.name.to_string()]),
Origin::Parameter | Origin::Condition | Origin::PseudoParameter(_) => None,
Origin::LogicalId => Some(vec![x.name.to_string()]),
Origin::GetAttribute(_) => Some(vec![x.name.to_string()]),
},
ResourceIr::Sub(arr) => {
let mut v = Vec::new();
Expand All @@ -509,23 +514,19 @@ fn find_references(resource: &ResourceIr) -> Option<Vec<String>> {
}
}

Option::Some(v)
Some(v)
}
ResourceIr::Map(x, y, z) => {
ResourceIr::Map(_, y, z) => {
let mut v = Vec::new();
if let Some(vec) = find_references(x.deref()) {
v.extend(vec);
}
if let Some(vec) = find_references(y.deref()) {
v.extend(vec);
}
if let Some(vec) = find_references(z.deref()) {
v.extend(vec);
}
Option::Some(v)
Some(v)
}
ResourceIr::Base64(x) => find_references(x.deref()),
ResourceIr::ImportValue(x) => find_references(x.deref()),
ResourceIr::Select(_, x) => find_references(x.deref()),
ResourceIr::GetAZs(x) => find_references(x.deref()),
ResourceIr::Cidr(x, y, z) => {
Expand All @@ -539,7 +540,7 @@ fn find_references(resource: &ResourceIr) -> Option<Vec<String>> {
if let Some(vec) = find_references(z.deref()) {
v.extend(vec);
}
Option::Some(v)
Some(v)
}
}
}
Expand All @@ -554,7 +555,8 @@ fn find_dependencies(
| ResourceIr::Bool(_)
| ResourceIr::Number(_)
| ResourceIr::Double(_)
| ResourceIr::String(_) => {}
| ResourceIr::String(_)
| ResourceIr::ImportValue(_) => {}

ResourceIr::Array(_, arr) => {
for x in arr {
Expand Down Expand Up @@ -590,17 +592,13 @@ fn find_dependencies(
find_dependencies(resource_name, x, topo);
}
}
ResourceIr::Map(x, y, z) => {
find_dependencies(resource_name, x.deref(), topo);
ResourceIr::Map(_, y, z) => {
find_dependencies(resource_name, y.deref(), topo);
find_dependencies(resource_name, z.deref(), topo);
}
ResourceIr::Base64(x) => {
find_dependencies(resource_name, x.deref(), topo);
}
ResourceIr::ImportValue(x) => {
find_dependencies(resource_name, x.deref(), topo);
}
ResourceIr::Select(_, x) => {
find_dependencies(resource_name, x.deref(), topo);
}
Expand Down Expand Up @@ -629,9 +627,9 @@ mod tests {
let ir_instruction = ResourceInstruction {
name: "A".to_string(),
condition: None,
metadata: Option::None,
deletion_policy: Option::None,
update_policy: Option::None,
metadata: None,
deletion_policy: None,
update_policy: None,
dependencies: Vec::new(),
resource_type: "".to_string(),
referrers: HashSet::default(),
Expand All @@ -642,9 +640,9 @@ mod tests {
name: "B".to_string(),
condition: None,
dependencies: Vec::new(),
metadata: Option::None,
deletion_policy: Option::None,
update_policy: Option::None,
metadata: None,
deletion_policy: None,
update_policy: None,
resource_type: "".to_string(),
referrers: HashSet::default(),
properties: create_property(
Expand All @@ -664,9 +662,9 @@ mod tests {
let mut ir_instruction = ResourceInstruction {
name: "A".to_string(),
condition: None,
metadata: Option::None,
deletion_policy: Option::None,
update_policy: Option::None,
metadata: None,
deletion_policy: None,
update_policy: None,
dependencies: vec!["foo".to_string()],
resource_type: "".to_string(),
referrers: HashSet::default(),
Expand Down
5 changes: 3 additions & 2 deletions src/parser/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub enum IntrinsicFunction {
cidr_bits: ResourceValue,
},
FindInMap {
map_name: ResourceValue,
map_name: String,
top_level_key: ResourceValue,
second_level_key: ResourceValue,
},
Expand All @@ -25,7 +25,7 @@ pub enum IntrinsicFunction {
value_if_true: ResourceValue,
value_if_false: ResourceValue,
},
ImportValue(ResourceValue),
ImportValue(String),
Join {
sep: String,
list: ResourceValue,
Expand Down Expand Up @@ -58,6 +58,7 @@ static INTRINSIC_FUNCTION_TAGS: &[&str] = &[
"FindInMap",
"GetAtt",
"GetAZs",
"If",
"ImportValue",
"Join",
"Select",
Expand Down
14 changes: 7 additions & 7 deletions src/parser/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,9 @@ pub enum DeletionPolicy {
impl fmt::Display for DeletionPolicy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Delete => write!(f, "Delete"),
Self::Retain => write!(f, "Retain"),
Self::Snapshot => write!(f, "Snapshot"),
Self::Delete => write!(f, "DELETE"),
Self::Retain => write!(f, "RETAIN"),
Self::Snapshot => write!(f, "SNAPSHOT"),
}
}
}
Expand Down Expand Up @@ -272,7 +272,7 @@ mod test {
ResourceValue::from_value(json!({"Fn::FindInMap": [MAP_NAME, FIRST_KEY, SECOND_KEY]}))
.unwrap(),
IntrinsicFunction::FindInMap {
map_name: ResourceValue::String(MAP_NAME.to_string()),
map_name: MAP_NAME.to_string(),
top_level_key: ResourceValue::String(FIRST_KEY.to_string()),
second_level_key: ResourceValue::String(SECOND_KEY.to_string())
}
Expand All @@ -287,7 +287,7 @@ mod test {
)
.unwrap(),
IntrinsicFunction::FindInMap {
map_name: ResourceValue::String(MAP_NAME.to_string()),
map_name: MAP_NAME.to_string(),
top_level_key: ResourceValue::String(FIRST_KEY.to_string()),
second_level_key: ResourceValue::String(SECOND_KEY.to_string())
}
Expand Down Expand Up @@ -353,14 +353,14 @@ mod test {
const SHARED_VALUE: &str = "SharedValue.ToImport";
assert_eq!(
ResourceValue::from_value(json!({ "Fn::ImportValue": SHARED_VALUE })).unwrap(),
IntrinsicFunction::ImportValue(ResourceValue::String(SHARED_VALUE.to_string())).into(),
IntrinsicFunction::ImportValue(SHARED_VALUE.into()).into(),
);
assert_eq!(
ResourceValue::from_value(
serde_yaml::from_str(&format!("!ImportValue {SHARED_VALUE}")).unwrap()
)
.unwrap(),
IntrinsicFunction::ImportValue(ResourceValue::String(SHARED_VALUE.to_string())).into(),
IntrinsicFunction::ImportValue(SHARED_VALUE.into()).into(),
);
}

Expand Down
3 changes: 2 additions & 1 deletion src/synthesizer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::io;

use crate::ir::CloudformationProgramIr;

mod output;
pub mod typescript_synthesizer;

pub trait Synthesizer {
Expand All @@ -10,7 +11,7 @@ pub trait Synthesizer {

impl CloudformationProgramIr {
#[inline(always)]
pub fn synthesize(self, using: &dyn Synthesizer, into: &mut dyn io::Write) -> io::Result<()> {
pub fn synthesize(self, using: &dyn Synthesizer, into: &mut impl io::Write) -> io::Result<()> {
using.synthesize(self, into)
}
}
Loading

0 comments on commit 169a091

Please sign in to comment.