1

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?

Beno Odr
  • 1,123
  • 1
  • 13
  • 27
  • Add the variable e.g., `MY_REPOS=ws-led tools-extension javt-ra` and use `$(foreach)` over it. Also, you may automatically render the individual build rules (e.g., `build-ws-led` & etc) and make the `build` target depend on it (also w/ `$(foreach)` – zaufi Feb 12 '20 at 12:10
  • @zaufi - can you please add it as answer ? – Beno Odr Feb 12 '20 at 13:57
  • The `pre` target doesn't make any sense, the `$(patsubst ...)` is a prerequisite and should be on the same line as the colon. The indented body of a recipe should be a sequence of shell commands. If you want `pre`. But your refactoring with this recipe has a number of additional problems; perhaps if you have new oi different requirements, a new separate question *just* about those would make sense. – tripleee Feb 12 '20 at 16:07
  • @tripleee This is what I try to do and you close it :) ,anyway im closing this question and open new one which more simple – Beno Odr Feb 12 '20 at 16:12
  • Yeah, in retrospect that was perhaps less than ideal. I'll update my answer to hopefully clarify what it's doing. – tripleee Feb 12 '20 at 16:14
  • @tripleee - thank you very much! – Beno Odr Feb 12 '20 at 16:17

1 Answers1

2

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.)

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • Thanks I try to add my repo to the value `repo` however the code is not compiled , I see error in this code `%/.built,$(repos))` – Beno Odr Feb 12 '20 at 13:57
  • Sorry about the typo; try again now. – tripleee Feb 12 '20 at 14:09
  • The issue is with the `$*` – Beno Odr Feb 12 '20 at 14:11
  • I've create a 'Makefile` which works for other target (using mac catlina)- GNU Make 3.81 , not sure how to check what is the issue with your code , – Beno Odr Feb 12 '20 at 14:15
  • There was a problem with the clone operation though; I have updated now to require `%/.git` to be created when you clone, and also to add a phony `clone:` to do just that for all three repos. – tripleee Feb 12 '20 at 14:15
  • I have tested this on Mojave, GNU Make 3.81 – tripleee Feb 12 '20 at 14:16
  • Partial demo, no access to Github though; but definitely no syntax errors. https://ideone.com/JoqsAr – tripleee Feb 12 '20 at 14:23
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/207675/discussion-between-beno-odr-and-tripleee). – Beno Odr Feb 12 '20 at 14:46
  • I think I miss something basic which for you is already clear ... – Beno Odr Feb 12 '20 at 14:47
  • You need a space after `patsubst`. – tripleee Feb 12 '20 at 15:10
  • I closed the question and opened new one , please have a look if you can help as this is probably too complicated and I try to make it more simple ...https://stackoverflow.com/questions/60191402/makefile-run-target-multple-times Thank you@ – Beno Odr Feb 12 '20 at 15:12