diff --git a/src/main/antlr4/io/codeka/gaia/hcl/antlr/hcl.g4 b/src/main/antlr4/io/codeka/gaia/hcl/antlr/hcl.g4 index a2d65bba4..20d2b451d 100644 --- a/src/main/antlr4/io/codeka/gaia/hcl/antlr/hcl.g4 +++ b/src/main/antlr4/io/codeka/gaia/hcl/antlr/hcl.g4 @@ -6,6 +6,7 @@ file directive : variableDirective + | outputDirective ; variableDirective @@ -13,32 +14,59 @@ variableDirective ; variableBlock - : '{' type? description? r_default? '}' + : '{' type? variableDescription? r_default? '}' + ; + +outputDirective + : 'output' identifier outputBlock + ; + +outputBlock + : '{' outputValue? outputDescription? sensitive? '}' + ; + +outputValue + : 'value' '=' expression + ; + +outputDescription + : 'description' '=' STRING + ; + +sensitive + : 'sensitive' '=' BOOLEAN ; type : 'type' '=' TYPE ; -description +variableDescription : 'description' '=' STRING ; r_default - : 'default' '=' defaultValue + : 'default' '=' expression ; -defaultValue +expression : STRING | NUMBER - | 'true' - | 'false' + | BOOLEAN + | UNQUOTED_STRING ; identifier : STRING ; +BOOLEAN + : 'true' + | '"true"' + | 'false' + | '"false"' + ; + TYPE : 'string' | '"string"' @@ -48,6 +76,10 @@ TYPE | '"bool"' ; +UNQUOTED_STRING + : [a-zA-Z0-9_.[\]-]+ + ; + /** * STRING Lexer Rule comes from the JSON grammar * https://github.com/antlr/grammars-v4/blob/master/json/JSON.g4 diff --git a/src/main/java/io/codeka/gaia/hcl/HclTreeListener.kt b/src/main/java/io/codeka/gaia/hcl/HclTreeListener.kt index cf273aa2d..5c3f57ba0 100644 --- a/src/main/java/io/codeka/gaia/hcl/HclTreeListener.kt +++ b/src/main/java/io/codeka/gaia/hcl/HclTreeListener.kt @@ -7,27 +7,50 @@ import java.util.* class HclTreeListener : hclBaseListener() { var variables: MutableList = LinkedList() + var outputs: MutableList = LinkedList() - private var current: Variable = Variable() + private var currentVariable: Variable = Variable() + private var currentOutput:Output = Output() override fun enterVariableDirective(ctx: hclParser.VariableDirectiveContext) { - this.current = Variable() - this.current.name = ctx.identifier().text + this.currentVariable = Variable() + this.currentVariable.name = ctx.identifier().text } override fun exitVariableDirective(ctx: hclParser.VariableDirectiveContext) { - this.variables.add(this.current) + this.variables.add(this.currentVariable) } override fun enterType(ctx: hclParser.TypeContext) { - this.current.type = ctx.TYPE().text + this.currentVariable.type = ctx.TYPE().text } - override fun enterDescription(ctx: hclParser.DescriptionContext) { - this.current.description = ctx.STRING().text + override fun enterVariableDescription(ctx: hclParser.VariableDescriptionContext) { + this.currentVariable.description = ctx.STRING().text } override fun enterR_default(ctx: hclParser.R_defaultContext) { - this.current.default = ctx.defaultValue().text + this.currentVariable.default = ctx.expression().text } + + override fun enterOutputDirective(ctx: hclParser.OutputDirectiveContext) { + this.currentOutput = Output(name = ctx.identifier().text) + } + + override fun exitOutputDirective(ctx: hclParser.OutputDirectiveContext) { + this.outputs.add(this.currentOutput) + } + + override fun enterOutputValue(ctx: hclParser.OutputValueContext) { + this.currentOutput.value = ctx.expression().text + } + + override fun enterOutputDescription(ctx: hclParser.OutputDescriptionContext) { + this.currentOutput.description = ctx.STRING().text + } + + override fun enterSensitive(ctx: hclParser.SensitiveContext) { + this.currentOutput.sensitive = ctx.BOOLEAN().text + } + } \ No newline at end of file diff --git a/src/main/java/io/codeka/gaia/hcl/Variable.kt b/src/main/java/io/codeka/gaia/hcl/HclTypes.kt similarity index 53% rename from src/main/java/io/codeka/gaia/hcl/Variable.kt rename to src/main/java/io/codeka/gaia/hcl/HclTypes.kt index f2aec06b9..a0027b578 100644 --- a/src/main/java/io/codeka/gaia/hcl/Variable.kt +++ b/src/main/java/io/codeka/gaia/hcl/HclTypes.kt @@ -2,3 +2,5 @@ package io.codeka.gaia.hcl data class Variable(var name: String = "", var type: String = "", var description: String = "", var default: String = ""); +data class Output(var name: String = "", var value: String = "", var description: String = "", var sensitive: String = "false"); + diff --git a/src/test/java/io/codeka/gaia/hcl/HCLParserTest.java b/src/test/java/io/codeka/gaia/hcl/HCLParserTest.java index 8094ff005..bf08cd6f5 100644 --- a/src/test/java/io/codeka/gaia/hcl/HCLParserTest.java +++ b/src/test/java/io/codeka/gaia/hcl/HCLParserTest.java @@ -16,7 +16,7 @@ class HCLParserTest { @Test - void parsing_variable_shouldWork() throws IOException { + void parsing_variables_shouldWork() throws IOException { // given // loading test file CharStream charStream = CharStreams.fromStream(new ClassPathResource("hcl/variables.tf").getInputStream()); @@ -44,4 +44,32 @@ void parsing_variable_shouldWork() throws IOException { assertThat(hclTreeListener.getVariables()).contains(stringVar, numberVar, boolVar); } + @Test + void parsing_outputs_shouldWork() throws IOException { + // given + // loading test file + CharStream charStream = CharStreams.fromStream(new ClassPathResource("hcl/outputs.tf").getInputStream()); + + // configuring antlr lexer + hclLexer lexer = new hclLexer(charStream); + + // configuring antlr parser + CommonTokenStream tokenStream = new CommonTokenStream(lexer); + hclParser parser = new hclParser(tokenStream); + + // when + // walk the AST + ParseTreeWalker walker = new ParseTreeWalker(); + var hclTreeListener = new HclTreeListener(); + walker.walk(hclTreeListener, parser.file()); + + // then + assertThat(hclTreeListener.getOutputs()).hasSize(2); + + var output1 = new Output("\"instance_ip_addr\"", "\"${aws_instance.server.private_ip}\"", "\"The private IP address of the main server instance.\"", "false"); + var output2 = new Output("\"db_password\"", "aws_db_instance.db[1].password", "\"The password for logging in to the database.\"", "true"); + + assertThat(hclTreeListener.getOutputs()).contains(output1, output2); + } + } \ No newline at end of file diff --git a/src/test/resources/hcl/outputs.tf b/src/test/resources/hcl/outputs.tf new file mode 100644 index 000000000..ed5dab1b9 --- /dev/null +++ b/src/test/resources/hcl/outputs.tf @@ -0,0 +1,10 @@ +output "instance_ip_addr" { + value = "${aws_instance.server.private_ip}" + description = "The private IP address of the main server instance." +} + +output "db_password" { + value = aws_db_instance.db[1].password + description = "The password for logging in to the database." + sensitive = true +} \ No newline at end of file