-
Notifications
You must be signed in to change notification settings - Fork 193
/
Makefile
461 lines (402 loc) · 18 KB
/
Makefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
#gnu makefile
# This Makefile provides macro control of the Reaction Platform microservice
# ecosystem. It performs tasks like:
#
# * Verify dependencies are present
# * Clone git projects, checkout a particular reference
# * Preconfiguration and subproject bootstrapping
# * Launching subprojects
# * Teardown tasks with varying destructiveness
#
#
# Exit codes:
#
# All failures should exit with a detailed code that can be used for
# troubleshooting. The current exit codes are:
#
# 0: Success!
# 101: Github is not configured correctly.
# 102: Required dependency is not installed.
#
###############################################################################
### Common Configuration
###############################################################################
HOOK_DIR=.reaction/project-hooks
###############################################################################
### Loaded Configuration
### Load configuration from external files. Configuration variables defined in
### later files have precedent and will overwrite those defined in previous
### files. The -include directive ensures that no error is thrown if a file is
### not found, which is the case if config.local.mk does not exist.
###############################################################################
-include config.mk config.local.mk
SUBPROJECTS=$(foreach rr,$(SUBPROJECT_REPOS),$(shell echo $(rr) | cut -d , -f 2))
###############################################################################
### Tasks
###############################################################################
all: init
###############################################################################
### Init-Project
### Initializes a project in production mode.
### Does not do common tasks shared between projects.
###############################################################################
define init-template
init-$(1): $(1) network-create dev-unlink-$(1) prebuild-$(1) build-$(1) post-build-$(1) start-$(1) post-project-start-$(1)
endef
$(foreach p,$(SUBPROJECTS),$(eval $(call init-template,$(p))))
###############################################################################
### Init-Dev-Project
### Initializes a project in development mode.
### Does not do common tasks shared between projects.
###############################################################################
define init-dev-template
init-dev-$(1): $(1) network-create dev-link-$(1) prebuild-$(1) build-$(1) post-build-$(1) start-$(1) post-project-start-$(1)
endef
$(foreach p,$(SUBPROJECTS),$(eval $(call init-dev-template,$(p))))
###############################################################################
### Init-With-System
### Init project and run the post-system hook script. This is useful for
### initializing a single project.
### Assumes dependencies are already started.
###############################################################################
define init-with-system-template
init-with-system-$(1): init-$(1) post-system-start-$(1)
endef
$(foreach p,$(SUBPROJECTS),$(eval $(call init-with-system-template,$(p))))
###############################################################################
### Init-Dev-with-System
### Init project and run the post-system hook script. This is useful for
### initializing a single project in development mode.
### Assumes dependencies are already started.
###############################################################################
define init-dev-with-system-template
init-dev-with-system-$(1): init-dev-$(1) post-system-start-$(1)
endef
$(foreach p,$(SUBPROJECTS),$(eval $(call init-dev-with-system-template,$(p))))
.PHONY: init
init: $(foreach p,$(SUBPROJECTS),init-$(p)) post-system-start
.PHONY: init-dev
init-dev: $(foreach p,$(SUBPROJECTS),init-dev-$(p)) post-system-start
###############################################################################
### Targets to verify Github is configured correctly.
###############################################################################
github-configured: dependencies
@(ssh -T [email protected] 2>&1 \
| grep "successfully authenticated" >/dev/null \
&& echo "Github login verified.") \
|| (echo "You need to configure an ssh key with access to github" \
&& echo "See https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/ for instructions" \
&& exit 101)
###############################################################################
### Verify prerequisite software is installed.
###############################################################################
is-not-installed=! (command -v $(1) >/dev/null)
define dependency-template
dependency-$(1):
@if ( $(call is-not-installed,$(1)) ); \
then \
echo "Dependency" $(1) " not found in path." \
&& exit 102; \
else \
echo "Dependency" $(1) "found."; \
fi;
endef
$(foreach pkg,$(REQUIRED_SOFTWARE),$(eval $(call dependency-template,$(pkg))))
.PHONY: dependencies
dependencies: $(foreach pkg,$(REQUIRED_SOFTWARE),dependency-$(pkg))
###############################################################################
### Create Docker Networks
### Create all networks defined in the DOCKER_NETWORKS variable.
### Networks provide a way to loosely couple the projects and allow them to
### communicate with each other. We'll use dependencies on external networks
### rather than dependencies on other projects. Networks are lightweight and
### easy to create.
###############################################################################
define network-create-template
network-create-$(1):
@docker network create "$(1)" || true
endef
$(foreach p,$(DOCKER_NETWORKS),$(eval $(call network-create-template,$(p))))
.PHONY: network-create
network-create: $(foreach p,$(DOCKER_NETWORKS),network-create-$(p))
###############################################################################
### Remove Docker Networks
### Remove all networks defined in the DOCKER_NETWORKS variable.
###############################################################################
define network-remove-template
network-remove-$(1):
@docker network rm "$(1)" || true
endef
$(foreach p,$(DOCKER_NETWORKS),$(eval $(call network-remove-template,$(p))))
.PHONY: network-remove
network-remove: $(foreach p,$(DOCKER_NETWORKS),network-remove-$(p))
###############################################################################
### Git cloning
###############################################################################
define git-clone-template
$(2):
if [ ! -d "$(2)" ] ; then \
git clone "$(1)" "$(2)"; \
cd $(2) && git checkout "$(3)"; \
fi
endef
$(foreach rr,$(SUBPROJECT_REPOS),$(eval $(call git-clone-template,$(shell echo $(rr) | cut -d , -f 1),$(shell echo $(rr) | cut -d , -f 2),$(shell echo $(rr) | cut -d , -f 3))))
.PHONY: clone
clone: github-configured $(foreach p,$(SUBPROJECTS),$(p))
###############################################################################
### Git clone all API plugins
###############################################################################
.PHONY: clone-api-plugins
clone-api-plugins:
if [ ! -d api-plugins ] ; then \
mkdir api-plugins; \
fi; \
cd api-plugins; \
for repo in $(API_PLUGIN_REPOS); do \
git clone $$repo || true; \
done;
###############################################################################
### Git Verify Clean
### Checks that the project has a clean workspace and changes won't be lost.
###############################################################################
define git-ensure-clean-diff-template
git-ensure-clean-diff-$(2): $(2)
@cd "$(2)" \
&& git diff --stat --quiet \
|| (echo "There are uncommitted changes in './$(2)'. Commit or discard changes before performing this operation."; exit 1)
endef
$(foreach rr,$(SUBPROJECT_REPOS),$(eval $(call git-ensure-clean-diff-template,$(shell echo $(rr) | cut -d , -f 1),$(shell echo $(rr) | cut -d , -f 2),$(shell echo $(rr) | cut -d , -f 3))))
.PHONY: git-ensure-clean-diff
git-ensure-clean-diff: $(foreach p,$(SUBPROJECTS),git-ensure-clean-diff-$(p))
###############################################################################
### Git checkout
### Checkout the branch configured in the platform settings.
### Does not gracefully deal with conflicts or other problems.
###############################################################################
define git-checkout-template
checkout-$(2): $(2)
cd $(2) && git fetch && git checkout "$(3)"
endef
$(foreach rr,$(SUBPROJECT_REPOS),$(eval $(call git-checkout-template,$(shell echo $(rr) | cut -d , -f 1),$(shell echo $(rr) | cut -d , -f 2),$(shell echo $(rr) | cut -d , -f 3))))
.PHONY: checkout
checkout: clone $(foreach p,$(SUBPROJECTS),checkout-$(p))
###############################################################################
### Git Update Checkouts
### Will check out the configured branch for all projects. This can be used to
### get an installation in sync with the configuration file.
### Fails on conflicts so the developer can properly commit or discard work.
###
### It is important to keep the `git-ensure-clean-diff` dependency, else
### WORK WILL BE LOST!!
###############################################################################
define git-update-checkout-template
update-checkout-$(2): git-ensure-clean-diff-$(2)
cd $(2) \
&& git fetch --tags \
&& git checkout $(3) \
&& git pull origin $(3) --ff-only
endef
$(foreach rr,$(SUBPROJECT_REPOS),$(eval $(call git-update-checkout-template,$(shell echo $(rr) | cut -d , -f 1),$(shell echo $(rr) | cut -d , -f 2),$(shell echo $(rr) | cut -d , -f 3))))
.PHONY: update-checkouts
update-checkouts: $(foreach p,$(SUBPROJECTS),update-checkout-$(p))
###############################################################################
### Pre Build Hook
### Invokes the pre-build hook in the child project directory if it exists.
### Invoked before the Docker Compose build.
###############################################################################
define prebuild-template
prebuild-$(1): $(1)
@if [ -e "$(1)/$(HOOK_DIR)/pre-build" ]; then \
echo "Running pre-build hook script for $(1)." \
&& "$(1)/$(HOOK_DIR)/pre-build"; \
else \
echo "No pre-build hook script for $(1). Skipping."; \
fi;
endef
$(foreach p,$(SUBPROJECTS),$(eval $(call prebuild-template,$(p))))
.PHONY: prebuild
prebuild: $(foreach p,$(SUBPROJECTS),prebuild-$(p))
###############################################################################
### Docker Build
### Performs `docker-compose build --no-cache --pull`
### This is a very conservative build strategy to avoid cache related build
### issues.
###############################################################################
define build-template
build-$(1): prebuild-$(1)
@cd $(1) \
&& docker-compose build --no-cache --pull
endef
$(foreach p,$(SUBPROJECTS),$(eval $(call build-template,$(p))))
.PHONY: build
build: $(foreach p,$(SUBPROJECTS),build-$(p))
###############################################################################
### Post Build Hook
### Invokes the post-build hook in the child project if existent.
### Invoke after all services in a project have been built.
###############################################################################
define post-build-template
post-build-$(1): build-$(1)
@if [ -e "$(1)/$(HOOK_DIR)/post-build" ]; then \
echo "Running post-build hook script for $(1)." \
&& "$(1)/$(HOOK_DIR)/post-build"; \
else \
echo "No post-build hook script for $(1). Skipping."; \
fi;
endef
$(foreach p,$(SUBPROJECTS),$(eval $(call post-build-template,$(p))))
.PHONY: post-build
post-build: $(foreach p,$(SUBPROJECTS),post-build-$(p))
###############################################################################
### dev-unlink
### Removes the symlinks for docker-compose development
###############################################################################
define dev-unlink-template
dev-unlink-$(1):
@cd $(1) \
&& rm -f docker-compose.override.yml \
&& echo "Removed docker development symlink for $(1)"
endef
$(foreach p,$(SUBPROJECTS),$(eval $(call dev-unlink-template,$(p))))
.PHONY: dev-unlink
dev-unlink: $(foreach p,$(SUBPROJECTS),dev-unlink-$(p))
###############################################################################
### dev-link
### Overrides default symlinks for `docker-compose` using `docker-compose.dev.yml`
###############################################################################
define dev-link-template
dev-link-$(1):
@if [ -e "$(1)/docker-compose.dev.yml" ]; then \
cd $(1) \
&& ln -sf docker-compose.dev.yml docker-compose.override.yml \
&& echo "Created docker development symlink for $(1)"; \
fi;
endef
$(foreach p,$(SUBPROJECTS),$(eval $(call dev-link-template,$(p))))
.PHONY: dev-link
dev-link: $(foreach p,$(SUBPROJECTS),dev-link-$(p))
###############################################################################
### dev
### Starts services in development mode with
### `ln -s docker-compose.dev.yml docker-compose.override.yml; docker-compose up -d`
###############################################################################
define dev-template
dev-$(1): stop-$(1) dev-link-$(1) start-$(1)
endef
$(foreach p,$(SUBPROJECTS),$(eval $(call dev-template,$(p))))
###############################################################################
### Start
### Starts services with `docker-compose up -d`
###
### Pull the specified image tags every time. Tags are constantly being updated
### to point to different image IDs, and there is less to debug if we can be
### reasonably to make sure that you're always starting the latest image with that tag.
###
### We are purposely running dc up even if dc pull fails. Our Meteor project DC
### config uses `image` as a desired image tag for `build` when in dev mode. But
### `dc pull` seems to have a bug where it doesn't treat it this way and tries
### to pull it.
###############################################################################
define start-template
start-$(1):
@cd $(1) && docker-compose pull; docker-compose up -d
endef
$(foreach p,$(SUBPROJECTS),$(eval $(call start-template,$(p))))
.PHONY: start
start: $(foreach p,$(SUBPROJECTS),start-$(p))
###############################################################################
### Post Project Start Hook
### Invokes the post-project-start hook in the child project if existent.
### Invoked after all services in a project have been started.
###############################################################################
define post-project-start-template
post-project-start-$(1):
@if [ -e "$(1)/$(HOOK_DIR)/post-project-start" ]; then \
echo "Running post-project-start hook script for $(1)." \
&& "$(1)/$(HOOK_DIR)/post-project-start"; \
else \
echo "No post-project-start hook script for $(1). Skipping."; \
fi;
endef
$(foreach p,$(SUBPROJECTS),$(eval $(call post-project-start-template,$(p))))
###############################################################################
### Post System Start Hook
### Invokes the post-system-start hook in the child projects if existent.
### Invoked after all services in the system have been started.
###
### Note: The final echo is required otherwise output of post-system-hook is
### not output.
###############################################################################
define post-system-start-template
post-system-start-$(1):
@if [ -e "$(1)/$(HOOK_DIR)/post-system-start" ]; then \
echo "Running post-system-start hook script for $(1)." \
&& "$(1)/$(HOOK_DIR)/post-system-start" \
&& echo ""; \
else \
echo "No post-system-start hook script for $(1). Skipping."; \
fi;
endef
$(foreach p,$(SUBPROJECTS),$(eval $(call post-system-start-template,$(p))))
.PHONY: post-system-start
post-system-start: $(foreach p,$(SUBPROJECTS),post-system-start-$(p))
###############################################################################
### Stop
### Stops services with `docker-compose stop`
###############################################################################
define stop-template
stop-$(1):
@cd $(1) \
&& docker-compose stop
endef
$(foreach p,$(SUBPROJECTS),$(eval $(call stop-template,$(p))))
.PHONY: stop
stop: $(foreach p,$(SUBPROJECTS),stop-$(p))
###############################################################################
### rm
### Remove containers with `docker-compose rm`
### Does not remove volumes.
###############################################################################
define rm-template
rm-$(1):
@cd $(1) \
&& docker-compose rm --stop --force
endef
$(foreach p,$(SUBPROJECTS),$(eval $(call rm-template,$(p))))
.PHONY: rm
rm: $(foreach p,$(SUBPROJECTS),rm-$(p))
###############################################################################
### Clean
### Clean services with `docker-compose rm`
### Removes all containers, volumes and local networks.
###############################################################################
define clean-template
clean-$(1):
@cd $(1) \
&& docker-compose down -v --rmi local --remove-orphans
endef
$(foreach p,$(SUBPROJECTS),$(eval $(call clean-template,$(p))))
.PHONY: clean
clean: $(foreach p,$(SUBPROJECTS),clean-$(p)) network-remove
###############################################################################
### Destroy
### Deletes project directories after removing running containers.
### WARNING: This is extremely destructive. It will remove local project
### directories. Any work that is not pushed to a remote git
### repository will be lost!
###
###############################################################################
define destroy-template
destroy-$(1): clean
@rm -Rf $(1)
endef
$(foreach p,$(SUBPROJECTS),$(eval $(call destroy-template,$(p))))
.PHONY: destroy
destroy: network-remove $(foreach p,$(SUBPROJECTS),destroy-$(p))
###############################################################################
### Dynamically list all targets.
### See: https://stackoverflow.com/a/26339924
###############################################################################
.PHONY: list
list:
@$(MAKE) -pRrq -f $(MAKEFILE_LIST) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | xargs -n 1