Beno Odr
Beno Odr

Reputation: 1273

Extract string from path/dir using Make

I’ve a Makefile with multiple git repo’s which I need to clone I use the following which works

clone:
    git clone https://github.company.corp/dev-wi/ws-led.git
    git clone https://github.company.corp/dev-wi/tools-extension.git
    git clone https://github.company.corp/dev-wi/javt-ra.git

While the following code works, I want to do something like this in loop for all the repos on the list

build:
    cd ws-led;  \
    docker build -t ws-led .
    cd tools-extension;  \
    docker build -t tools-extension .
    ...

For each repo I need to change dir And run the docker build , I want to avoid doing this over and over again ... I know that I need to extract the string after /dev-wi/ as this is the repo directory which I need to run docker build on. since I’ve many repo how can I do it easily ?

I try with subset however I have also the git command (in clone) so it doesn't work,any idea?

update I've created the A new makefile and use only this code (the ws-led and tools-extension is folders in the same level of of the makefile

repos := ws-led tools-extension

.PHONY: all

all: $(patsubst%,%/docker-build.log,$(repos))

%/docker-build.log: %/.git
    cd $*; docker build -t $* . >&2 | tee docker-build.log

I got error:

make: Nothing to be done forall'.`

what am I missing here ?

I try to simplify it but removing the git and let say that the folders (repo) existing on the same level of the makefile

UPDATE

Im change the makefile to be under the root

proj
  - ws-led
  — Dockerfile
 -tools-ext
 —Dockerfile    
-Makefile

I try with the following

all: pre docker-build
.PHONY: pre docker-build
repos := ws-led tools-ext

pre:
    $(patsubst %,%docker-build,$(repos))

docker-build:pre
    cd $*; docker build -t $* . >&2 | tee docker-build

when I run make I got the following error

ws-leddocker-build  ws-leddocker-build
make: ws-leddocker-build: No such file or directory

Any idea?

Upvotes: 1

Views: 201

Answers (1)

tripleee
tripleee

Reputation: 189789

Looping is generally something you want to avoid. Instead, declare a series of targets for each repo.

repos := ws-led tools-extension javt-ra

.PHONY: all clone
all: $(patsubst %,%/.built,$(repos))
clone: $(patsubst %,%/.git,$(repos))

%/.built: %/.git
    cd $*; docker build -t $* .
    touch $@

%/.git:
    git clone https://github.company.corp/dev-wi/$*.git

The .built flag file is a bit of a wart, and could usefully be replaced with something more useful, like the output from docker build.

all: $(patsubst %,%/docker-build.log,$(repos))

%/docker-build.log: %/.git
    cd $*; docker build -t $* . >&2 | tee docker-build.log

The reason we generally try to avoid loops is to allow make to do its primary job properly -- avoid rerunning commands when a target is already up to date. So, for example, if you only changed ws-led, you don't want to force the other two to be rebuilt as well.

Having said that, the $(patsubst ...) is a loop of sorts; it basically loops over repos and creates a small piece of text around each. Without the patsubst we could write

all: ws-led/.built tools-extension/.built javt-ra/.built

which simply says that to make all we need to make those three; and then

%/.built: %/.git

says that for anything matching the pattern, it depends on the same stem with /.git after it. So in an otherwise empty directory, make would find that

  • to make all, we need to make ws-led/.built, tools-extension/.built, and javt-ra/.built;
    • to make ws-led/.built, we need to make ws-led/.git;
      • to make ws-led/.git, we need to
      git clone https://github.company.corp/dev-wi/ws-led.git
      
      • then once this prerequisite is satisfied,
      cd ws-led; docker build -t ws-led .
      touch ws-led/.built
      
    • to make tools-extension/.built, we need to make tools-extension/.git;
      • to make tools-extension/.git, we need to
      git clone https://github.company.corp/dev-wi/tools-extension.git
      
      ... etc etc.

In the future, when make finds that ws-led is newer than ws-led/.built it will build it again; but if it is not, it will conclude that no work needs to be done, etc for the other targets. This is how we avoid building things needlessly; but it obviously requires that the Makefile properly contains a formalization of every relevant dependency. (In this case, you would ideally like for there to be a way to know when the Git upstream has changed and something needs to be pulled by the local Makefile; this currently simply regards everything as done if the local Git clone has not received any updates.)

Upvotes: 2

Related Questions