2

I'd like to parse a Terraform file named versions.tf which give provider requirements for the project. This should be in bash script. This file is formatted like this :

terraform {
  required_providers {
    archive = {
      source = "hashicorp/archive"
      version = "~> 1.3.0"
    }
    aws = {
      source = "hashicorp/aws"
      version = "~> 3.0.0"
    }
    local = {
      source = "hashicorp/local"
      version = "~> 2.0.0"
    }
    template = {
      source = "hashicorp/template"
      version = "~> 2.2.0"
    }
    random = {
      source = "hashicorp/random"
      version = "~> 3.0.1" 
    }
  }
  required_version = ">= 0.13"
}

The goal is to have 3 variables likes so in a for loop :

$name = "archive"
$source = "hashicorp/archive"
$version = "1.3.0" # we don't take care of the version constraints

The structure is almost the same for different projects we have.

I've already tried to parse it, but as I'm a noob in text parsing, nothing concrete.

I also tried to use the command terraform providers schema -json but it doesn't work while you don't have initialized the terraform script (it need to be not initialized).

As I will use the script in my corporate Jenkins pipeline, I can't access Internet and I don't have access to binaries like jq or something not "red hat" native.

Thanks you for your help !

  • Do you want the quotes `"` to be included in the variables' value? – Armali Mar 03 '21 at 19:14
  • Not a duplicate, but something here might help you. https://stackoverflow.com/q/1955505/3124333 – SiKing Mar 03 '21 at 19:50
  • 1
    For this unusual requirement, I think I'd suggest to invert the problem and write a shell script to generate the `versions.tf` instead. Shell is not a good language for implementing a robust parser, but it has convenient features for generating files with interpolated values. – Martin Atkins Mar 04 '21 at 01:36
  • @MartinAtkins Thank you for your reply. In fact, we create the versions.tf with some version requirements and then, as we currently not have a registry, we have to download the provider from a in house repository.So the versions.tf can't be generated. (or we create a JSON with the dependencies then we transform it into a version.tf, ... ) – Jean-Philippe R. Mar 04 '21 at 09:43

2 Answers2

2

This script scans for the lines with the name, which are identifiable by the third field being {, and after each of these reads the two lines with source and version, assigning to variables with the same name:

while read name _ rest
do  if [ "$rest" = "{" ]
    then    read var _ val; eval $var=$val
            read var _ val; eval $var=$val
            echo $name $source ${version#~> }
    fi
done <versions.tf
Armali
  • 18,255
  • 14
  • 57
  • 171
  • 1
    Thank you for your answer, it did pretty well the job (we just need to strictly respect the whitespace between equals ^^). I chose your reply because your script get the 3 required variables in one iteration. – Jean-Philippe R. Mar 04 '21 at 09:46
1

Might do what you wanted.

#!/usr/bin/env bash

while read -r line; do
  [[ $line != *'='* ]] && continue
  if [[ $line == *'= {' ]]; then
    line=${line%=*\{}
    printf '$name = "%s"\n' "${line% }"
  else
    printf '$%s\n' "${line//~> }"
  fi
done < versions.tf

If the required_version line needs to be omitted add

[[ $line == 'required_version'* ]] && continue

Below the line that has continue

Jetchisel
  • 7,493
  • 2
  • 19
  • 18
  • 1
    Thank you for your answer. One thing I don't precise, we need the variables in one iteration. My apologizes. Your script works perfectly if we don't take in care of this drawback. – Jean-Philippe R. Mar 04 '21 at 09:48