1

How can I import variables from a nested YAML to use in a Makefile. A subset of YAML could be ok, but nested is important.

I understand I could use a python or ruby or x script, but so far I dont have to use either and would like to avoid and keep universal if possible.

thanks.

Tom
  • 981
  • 11
  • 24

3 Answers3

0

I don't think there's any good way to do this. If you wanted, you could probably write a Make plugin in C that calls a YAML parser and provides an interface to the data, but unless someone has already written one it's likely not worth the time.

Functino
  • 1,939
  • 17
  • 25
0

There is a way to do it with the help of yq command-line YAML processor. It can print all or subset of paths with values in a YAML file:

yq r file.yaml -p pv "**"

We can use foreach function in make to define variables for each path:

yaml_file = file.yaml    
yaml := $(shell yq r $(yaml_file) -p pv "**" | sed 's/ /|/g' | sed 's/:|/:/g')
yaml_path_value = $(subst :, ,$(yaml_element))
yaml_path = $(word 1,$(yaml_path_value))
yaml_value = $(subst |, ,$(word 2,$(yaml_path_value)))
yaml_variable = $(eval $(yaml_path) := $(yaml_value))
$(foreach yaml_element,$(yaml),$(yaml_variable))

Make uses spaces as a separator in lists, so spaces in YAML values have to be replaced with another character (| in this example) before using foreach and then put back before defining variables.

gleb
  • 143
  • 7
0

After some research I came up with this solution, which is ok for me. It combines the https://stackoverflow.com/a/21189044/6869629 and http://make.mad-scientist.net/constructed-include-files/ approaches and adds content of the YAML files as variables to the Makefile: This is the YAML config file: project.yaml

PROJECT_NAME: test-project
ENVIRONMENT: test

and this is the Makefile:

PROJECT_CONFIG_YAML_PATH :=  "../../project.yaml"
PROJECT_CONFIG_VAR_PREFIX := "CONF_"
READ_PROJECT_CONFIG := $(shell prefix=$(PROJECT_CONFIG_VAR_PREFIX) \
                  && lf= $$(echo @|tr @ '\012')\
                  && s='[[:space:]]*' \
                  && w='[a-zA-Z0-9_]*' \
                  && fs=$$(echo @|tr @ '\034') \
                  && sed -ne "s|^\($$s\):|\1|" \
                     -e "s|^\($$s\)\($$w\)$$s:$$s[\"']\(.*\)[\"']$$s\$$|\1$$fs\2$$fs\3|p" \
                     -e "s|^\($$s\)\($$w\)$$s:$$s\(.*\)$$s\$$|\1$$fs\2$$fs\3|p"  $(PROJECT_CONFIG_YAML_PATH) | \
                  awk -F$$fs '{indent = length($$1)/2; \
                     vname[indent] = $$2; \
                     for (i in vname) {if (i > indent) {delete vname[i]}} \
                     if (length($$3) > 0) { \
                            vn=""; for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")} \
                            printf("%s%s%s=\"%s\"\n", "'$$prefix'",vn, $$2, $$3); \
                        } \
                    }'| tr '\n' '\1')
add-project-config: Makefile
    @echo "$(READ_PROJECT_CONFIG)" | tr '\1' '\n' > $@

print-%:
    @echo "$(READ_PROJECT_CONFIG)" | tr '\1' '\n'
    @echo $*=$($*) 

-include add-project-config

The print-%: target echoes the content of the YAML file, as it will be added to the Makefile and prints the variable, which has been passed as parameter.

$ make print-CONF_PROJECT_NAME results in:

CONF_PROJECT_NAME=test-project
CONF_ENVIRONMENT=test

CONF_PROJECT_NAME=test-project
Max
  • 31
  • 3