skip to Main Content

I have a makefile with the following script:

build:
    DOCKER_BUILDKIT=1 docker build --build-arg GITHUB_ACTOR=${GITHUB_ACTOR} --build-arg GITHUB_TOKEN=${GITHUB_TOKEN} -t ${DOCKER_REGISTRY}/strick:${IMAGE_BRANCH}-${IMAGE_TAG} -t ${DOCKER_REGISTRY}/strick:${IMAGE_BRANCH}-latest .

and I just realized that when ${IMAGE_BRANCH] has a slash in it, like feature/a-b-c then the docker build step will fail. I’d like to create a new env var which replaces slashes in IMAGE_BRANCH with dashes.

I tried several variants including the following

build:
    CLEANED_IMAGE_BRANCH=$(echo ${IMAGE_BRANCH} | sed 's///-/g')
    DOCKER_BUILDKIT=1 docker build --build-arg GITHUB_ACTOR=${GITHUB_ACTOR} --build-arg GITHUB_TOKEN=${GITHUB_TOKEN} -t ${DOCKER_REGISTRY}/strick:${CLEANED_IMAGE_BRANCH}-${IMAGE_TAG} -t ${DOCKER_REGISTRY}/strick:${CLEANED_IMAGE_BRANCH}-latest .

and they all seemed to fail because CLEANED_IMAGE_BRANCH ends up being an empty string.

 ❮❮❮ DOCKER_REGISTRY=docker IMAGE_BRANCH="a/b" IMAGE_TAG="lol" make build
CLEANED_IMAGE_BRANCH=
DOCKER_BUILDKIT=1 docker build --build-arg GITHUB_ACTOR= --build-arg GITHUB_TOKEN= -t docker/strick:-lol -t docker/strick:-latest .
invalid argument "docker/strick:-lol" for "-t, --tag" flag: invalid reference format
See 'docker build --help'.
make: *** [build] Error 125

What’s the correct way to perform string substitution in a makefile script?

2

Answers


  1. You could just use the subst function:

    CLEANED_IMAGE_BRANCH=$(subst /,-,$(IMAGE_BRANCH))
    

    If I run this Makefile:

    GITHUB_ACTOR=someuser
    GITHUB_TOKEN=token
    DOCKER_REGISTRY=ghcr.io
    IMAGE_BRANCH=feature/a-b-c
    IMAGE_TAG=foo
    
    CLEANED_IMAGE_BRANCH=$(subst /,-,$(IMAGE_BRANCH))
    
    build:
        echo DOCKER_BUILDKIT=1 docker build 
                --build-arg GITHUB_ACTOR=${GITHUB_ACTOR} 
                --build-arg GITHUB_TOKEN=${GITHUB_TOKEN} 
                -t ${DOCKER_REGISTRY}/strick:${CLEANED_IMAGE_BRANCH}-${IMAGE_TAG} 
                -t ${DOCKER_REGISTRY}/strick:${CLEANED_IMAGE_BRANCH}-latest .
    

    I get as output:

    echo DOCKER_BUILDKIT=1 docker build 
            --build-arg GITHUB_ACTOR=someuser 
            --build-arg GITHUB_TOKEN=token 
            -t ghcr.io/strick:feature-a-b-c-foo 
            -t ghcr.io/strick:feature-a-b-c-latest .
    DOCKER_BUILDKIT=1 docker build --build-arg GITHUB_ACTOR=someuser --build-arg GITHUB_TOKEN=token -t ghcr.io/strick:feature-a-b-c-foo -t ghcr.io/strick:feature-a-b-c-latest .
    
    Login or Signup to reply.
  2. First, when you want to pass a $ to the shell you have to escape it from make, because $ is special to make.

    Second, every logical line in the recipe is run in a separate shell so if you want shell variables set in one line to be visible in another line you have to connect them via backslash.

    build:
            CLEANED_IMAGE_BRANCH=$$(echo ${IMAGE_BRANCH} | sed 's///-/g') 
            DOCKER_BUILDKIT=1 docker build --build-arg GITHUB_ACTOR=${GITHUB_ACTOR} --build-arg GITHUB_TOKEN=${GITHUB_TOKEN} -t ${DOCKER_REGISTRY}/strick:${CLEANED_IMAGE_BRANCH}-${IMAGE_TAG} -t ${DOCKER_REGISTRY}/strick:${CLEANED_IMAGE_BRANCH}-latest .
    

    Of course using make functions is also a fine idea, as long as you’re willing to commit (or have already committed) to requiring GNU make.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search