-
Notifications
You must be signed in to change notification settings - Fork 66
/
Makefile
850 lines (701 loc) · 40.4 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
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
CONDA_ENV_NAME ?= mlos
PYTHON_VERSION := $(shell echo "${CONDA_ENV_NAME}" | sed -r -e 's/^mlos[-]?//')
ENV_YML := conda-envs/${CONDA_ENV_NAME}.yml
# Find the non-build python files we should consider as rule dependencies.
PYTHON_FILES := $(shell find ./ -type f -name '*.py' 2>/dev/null | egrep -v -e '^./(mlos_(core|bench|viz)/)?build/' -e '^./doc/source/')
MLOS_CORE_PYTHON_FILES := $(shell find ./mlos_core/ -type f -name '*.py' 2>/dev/null | egrep -v -e '^./mlos_core/build/')
MLOS_BENCH_PYTHON_FILES := $(shell find ./mlos_bench/ -type f -name '*.py' 2>/dev/null | egrep -v -e '^./mlos_bench/build/')
MLOS_VIZ_PYTHON_FILES := $(shell find ./mlos_viz/ -type f -name '*.py' 2>/dev/null | egrep -v -e '^./mlos_viz/build/')
NOTEBOOK_FILES := $(shell find ./ -type f -name '*.ipynb' 2>/dev/null | egrep -v -e '/build/')
SCRIPT_FILES := $(shell find ./ -name '*.sh' -or -name '*.ps1' -or -name '*.cmd')
SQL_FILES := $(shell find ./ -name '*.sql')
MD_FILES := $(shell find ./ -name '*.md' | grep -v '^./doc/')
DOCKER := $(shell which docker)
# Make sure the build directory exists.
MKDIR_BUILD := $(shell test -d build || mkdir build)
# Allow overriding the default verbosity of conda for CI jobs.
#CONDA_INFO_LEVEL ?= -q
# Run make in parallel by default.
MAKEFLAGS += -j$(shell nproc 2>/dev/null || sysctl -n hw.ncpu)
#MAKEFLAGS += -Oline
.PHONY: all
all: format check test dist dist-test doc | conda-env
.PHONY: conda-env
conda-env: build/conda-env.${CONDA_ENV_NAME}.build-stamp
MLOS_CORE_CONF_FILES := mlos_core/pyproject.toml mlos_core/setup.py mlos_core/MANIFEST.in
MLOS_BENCH_CONF_FILES := mlos_bench/pyproject.toml mlos_bench/setup.py mlos_bench/MANIFEST.in
MLOS_VIZ_CONF_FILES := mlos_viz/pyproject.toml mlos_viz/setup.py mlos_viz/MANIFEST.in
MLOS_GLOBAL_CONF_FILES := setup.cfg pyproject.toml
MLOS_PKGS := mlos_core mlos_bench mlos_viz
MLOS_PKG_CONF_FILES := $(MLOS_CORE_CONF_FILES) $(MLOS_BENCH_CONF_FILES) $(MLOS_VIZ_CONF_FILES) $(MLOS_GLOBAL_CONF_FILES)
build/conda-env.${CONDA_ENV_NAME}.build-stamp: ${ENV_YML} $(MLOS_PKG_CONF_FILES)
@echo "CONDA_SOLVER: ${CONDA_SOLVER}"
@echo "CONDA_EXPERIMENTAL_SOLVER: ${CONDA_EXPERIMENTAL_SOLVER}"
@echo "CONDA_INFO_LEVEL: ${CONDA_INFO_LEVEL}"
conda env list -q | grep -q "^${CONDA_ENV_NAME} " || conda env create ${CONDA_INFO_LEVEL} -n ${CONDA_ENV_NAME} -f ${ENV_YML}
conda env update ${CONDA_INFO_LEVEL} -n ${CONDA_ENV_NAME} --prune -f ${ENV_YML}
$(MAKE) clean-format clean-check clean-test clean-doc clean-dist
touch $@
.PHONY: clean-conda-env
clean-conda-env:
conda env remove -y ${CONDA_INFO_LEVEL} -n ${CONDA_ENV_NAME}
rm -f build/conda-env.${CONDA_ENV_NAME}.build-stamp
# Since these targets potentially change the files we need to run them in sequence.
# In future versions of make we can do that by marking each as a .NOTPARALLEL psuedo target.
# But with make 4.3 that changes the entire Makefile to be serial.
# Here we make dynamic prereqs to apply to other targets that need to run in sequence.
FORMAT_PREREQS :=
.PHONY: format
format: build/format.${CONDA_ENV_NAME}.build-stamp
ifneq (,$(filter format,$(MAKECMDGOALS)))
FORMAT_PREREQS += build/format.${CONDA_ENV_NAME}.build-stamp
endif
build/format.${CONDA_ENV_NAME}.build-stamp: build/licenseheaders.${CONDA_ENV_NAME}.build-stamp
build/format.${CONDA_ENV_NAME}.build-stamp: build/isort.${CONDA_ENV_NAME}.build-stamp
build/format.${CONDA_ENV_NAME}.build-stamp: build/black.${CONDA_ENV_NAME}.build-stamp
build/format.${CONDA_ENV_NAME}.build-stamp: build/docformatter.${CONDA_ENV_NAME}.build-stamp
build/format.${CONDA_ENV_NAME}.build-stamp:
touch $@
.PHONY: licenseheaders
licenseheaders: build/licenseheaders.${CONDA_ENV_NAME}.build-stamp
ifneq (,$(filter licenseheaders,$(MAKECMDGOALS)))
FORMAT_PREREQS += build/licenseheaders.${CONDA_ENV_NAME}.build-stamp
endif
build/licenseheaders.${CONDA_ENV_NAME}.build-stamp: build/conda-env.${CONDA_ENV_NAME}.build-stamp
build/licenseheaders.${CONDA_ENV_NAME}.build-stamp: $(PYTHON_FILES)
build/licenseheaders.${CONDA_ENV_NAME}.build-stamp: $(SCRIPT_FILES)
build/licenseheaders.${CONDA_ENV_NAME}.build-stamp: $(SQL_FILES) doc/mit-license.tmpl
build/licenseheaders.${CONDA_ENV_NAME}.build-stamp: doc/mit-license.tmpl
build/licenseheaders.${CONDA_ENV_NAME}.build-stamp:
# Note: to avoid makefile dependency loops, we don't touch the setup.py
# files as that would force the conda-env to be rebuilt.
conda run -n ${CONDA_ENV_NAME} licenseheaders -t doc/mit-license.tmpl \
-E .py .sh .ps1 .sql .cmd \
-x mlos_bench/setup.py mlos_core/setup.py mlos_viz/setup.py
touch $@
.PHONY: isort
isort: build/isort.${CONDA_ENV_NAME}.build-stamp
ifneq (,$(filter isort,$(MAKECMDGOALS)))
FORMAT_PREREQS += build/isort.${CONDA_ENV_NAME}.build-stamp
endif
build/isort.${CONDA_ENV_NAME}.build-stamp: build/isort.mlos_core.${CONDA_ENV_NAME}.build-stamp
build/isort.${CONDA_ENV_NAME}.build-stamp: build/isort.mlos_bench.${CONDA_ENV_NAME}.build-stamp
build/isort.${CONDA_ENV_NAME}.build-stamp: build/isort.mlos_viz.${CONDA_ENV_NAME}.build-stamp
build/isort.${CONDA_ENV_NAME}.build-stamp:
touch $@
# NOTE: when using pattern rules (involving %) we can only add one line of
# prerequisities, so we use this pattern to compose the list as variables.
# black, licenseheaders, isort, and docformatter all alter files, so only run
# one at a time, by adding prerequisites, but only as necessary.
ISORT_COMMON_PREREQS :=
ifneq (,$(filter format licenseheaders,$(MAKECMDGOALS)))
ISORT_COMMON_PREREQS += build/licenseheaders.${CONDA_ENV_NAME}.build-stamp
endif
ISORT_COMMON_PREREQS += build/conda-env.${CONDA_ENV_NAME}.build-stamp
ISORT_COMMON_PREREQS += $(MLOS_GLOBAL_CONF_FILES)
build/isort.mlos_core.${CONDA_ENV_NAME}.build-stamp: $(MLOS_CORE_PYTHON_FILES)
build/isort.mlos_bench.${CONDA_ENV_NAME}.build-stamp: $(MLOS_BENCH_PYTHON_FILES)
build/isort.mlos_viz.${CONDA_ENV_NAME}.build-stamp: $(MLOS_VIZ_PYTHON_FILES)
build/isort.%.${CONDA_ENV_NAME}.build-stamp: $(ISORT_COMMON_PREREQS)
# Reformat python file imports with isort.
conda run -n ${CONDA_ENV_NAME} isort --verbose --only-modified --atomic -j0 $(filter %.py,$+)
touch $@
.PHONY: black
black: build/black.${CONDA_ENV_NAME}.build-stamp
ifneq (,$(filter black,$(MAKECMDGOALS)))
FORMAT_PREREQS += build/black.${CONDA_ENV_NAME}.build-stamp
endif
build/black.${CONDA_ENV_NAME}.build-stamp: build/black.mlos_core.${CONDA_ENV_NAME}.build-stamp
build/black.${CONDA_ENV_NAME}.build-stamp: build/black.mlos_bench.${CONDA_ENV_NAME}.build-stamp
build/black.${CONDA_ENV_NAME}.build-stamp: build/black.mlos_viz.${CONDA_ENV_NAME}.build-stamp
build/black.${CONDA_ENV_NAME}.build-stamp:
touch $@
# black, licenseheaders, isort, and docformatter all alter files, so only run
# one at a time, by adding prerequisites, but only as necessary.
BLACK_COMMON_PREREQS :=
ifneq (,$(filter format licenseheaders,$(MAKECMDGOALS)))
BLACK_COMMON_PREREQS += build/licenseheaders.${CONDA_ENV_NAME}.build-stamp
endif
ifneq (,$(filter format isort,$(MAKECMDGOALS)))
BLACK_COMMON_PREREQS += build/isort.${CONDA_ENV_NAME}.build-stamp
endif
BLACK_COMMON_PREREQS += build/conda-env.${CONDA_ENV_NAME}.build-stamp
BLACK_COMMON_PREREQS += $(MLOS_GLOBAL_CONF_FILES)
build/black.mlos_core.${CONDA_ENV_NAME}.build-stamp: $(MLOS_CORE_PYTHON_FILES)
build/black.mlos_bench.${CONDA_ENV_NAME}.build-stamp: $(MLOS_BENCH_PYTHON_FILES)
build/black.mlos_viz.${CONDA_ENV_NAME}.build-stamp: $(MLOS_VIZ_PYTHON_FILES)
build/black.%.${CONDA_ENV_NAME}.build-stamp: $(BLACK_COMMON_PREREQS)
# Reformat python files with black.
conda run -n ${CONDA_ENV_NAME} black $(filter %.py,$+)
touch $@
.PHONY: docformatter
docformatter: build/docformatter.${CONDA_ENV_NAME}.build-stamp
ifneq (,$(filter docformatter,$(MAKECMDGOALS)))
FORMAT_PREREQS += build/docformatter.${CONDA_ENV_NAME}.build-stamp
endif
build/docformatter.${CONDA_ENV_NAME}.build-stamp: build/docformatter.mlos_core.${CONDA_ENV_NAME}.build-stamp
build/docformatter.${CONDA_ENV_NAME}.build-stamp: build/docformatter.mlos_bench.${CONDA_ENV_NAME}.build-stamp
build/docformatter.${CONDA_ENV_NAME}.build-stamp: build/docformatter.mlos_viz.${CONDA_ENV_NAME}.build-stamp
build/docformatter.${CONDA_ENV_NAME}.build-stamp:
touch $@
# black, licenseheaders, isort, and docformatter all alter files, so only run
# one at a time, by adding prerequisites, but only as necessary.
DOCFORMATTER_COMMON_PREREQS :=
ifneq (,$(filter format licenseheaders,$(MAKECMDGOALS)))
DOCFORMATTER_COMMON_PREREQS += build/licenseheaders.${CONDA_ENV_NAME}.build-stamp
endif
ifneq (,$(filter format isort,$(MAKECMDGOALS)))
DOCFORMATTER_COMMON_PREREQS += build/isort.${CONDA_ENV_NAME}.build-stamp
endif
ifneq (,$(filter format black,$(MAKECMDGOALS)))
DOCFORMATTER_COMMON_PREREQS += build/black.${CONDA_ENV_NAME}.build-stamp
endif
DOCFORMATTER_COMMON_PREREQS += build/conda-env.${CONDA_ENV_NAME}.build-stamp
DOCFORMATTER_COMMON_PREREQS += $(MLOS_GLOBAL_CONF_FILES)
build/docformatter.mlos_core.${CONDA_ENV_NAME}.build-stamp: $(MLOS_CORE_PYTHON_FILES)
build/docformatter.mlos_bench.${CONDA_ENV_NAME}.build-stamp: $(MLOS_BENCH_PYTHON_FILES)
build/docformatter.mlos_viz.${CONDA_ENV_NAME}.build-stamp: $(MLOS_VIZ_PYTHON_FILES)
# docformatter returns non-zero when it changes anything so instead we ignore that
# return code and just have it recheck itself immediately
build/docformatter.%.${CONDA_ENV_NAME}.build-stamp: $(DOCFORMATTER_COMMON_PREREQS)
# Reformat python file docstrings with docformatter.
conda run -n ${CONDA_ENV_NAME} docformatter --in-place $(filter %.py,$+) || true
conda run -n ${CONDA_ENV_NAME} docformatter --check --diff $(filter %.py,$+)
touch $@
.PHONY: check
check: isort-check black-check docformatter-check pycodestyle pydocstyle pylint mypy # cspell markdown-link-check
.PHONY: black-check
black-check: build/black-check.mlos_core.${CONDA_ENV_NAME}.build-stamp
black-check: build/black-check.mlos_bench.${CONDA_ENV_NAME}.build-stamp
black-check: build/black-check.mlos_viz.${CONDA_ENV_NAME}.build-stamp
# Make sure black format rules run before black-check rules.
build/black-check.mlos_core.${CONDA_ENV_NAME}.build-stamp: $(MLOS_CORE_PYTHON_FILES)
build/black-check.mlos_bench.${CONDA_ENV_NAME}.build-stamp: $(MLOS_BENCH_PYTHON_FILES)
build/black-check.mlos_viz.${CONDA_ENV_NAME}.build-stamp: $(MLOS_VIZ_PYTHON_FILES)
BLACK_CHECK_COMMON_PREREQS := build/conda-env.${CONDA_ENV_NAME}.build-stamp
BLACK_CHECK_COMMON_PREREQS += $(FORMAT_PREREQS)
BLACK_CHECK_COMMON_PREREQS += $(MLOS_GLOBAL_CONF_FILES)
build/black-check.%.${CONDA_ENV_NAME}.build-stamp: $(BLACK_CHECK_COMMON_PREREQS)
# Check for import sort order.
# Note: if this fails use "make format" or "make black" to fix it.
conda run -n ${CONDA_ENV_NAME} black --verbose --check --diff $(filter %.py,$+)
touch $@
.PHONY: docformatter-check
docformatter-check: build/docformatter-check.mlos_core.${CONDA_ENV_NAME}.build-stamp
docformatter-check: build/docformatter-check.mlos_bench.${CONDA_ENV_NAME}.build-stamp
docformatter-check: build/docformatter-check.mlos_viz.${CONDA_ENV_NAME}.build-stamp
# Make sure docformatter format rules run before docformatter-check rules.
build/docformatter-check.mlos_core.${CONDA_ENV_NAME}.build-stamp: $(MLOS_CORE_PYTHON_FILES)
build/docformatter-check.mlos_bench.${CONDA_ENV_NAME}.build-stamp: $(MLOS_BENCH_PYTHON_FILES)
build/docformatter-check.mlos_viz.${CONDA_ENV_NAME}.build-stamp: $(MLOS_VIZ_PYTHON_FILES)
BLACK_CHECK_COMMON_PREREQS := build/conda-env.${CONDA_ENV_NAME}.build-stamp
BLACK_CHECK_COMMON_PREREQS += $(FORMAT_PREREQS)
BLACK_CHECK_COMMON_PREREQS += $(MLOS_GLOBAL_CONF_FILES)
build/docformatter-check.%.${CONDA_ENV_NAME}.build-stamp: $(BLACK_CHECK_COMMON_PREREQS)
# Check for import sort order.
# Note: if this fails use "make format" or "make docformatter" to fix it.
conda run -n ${CONDA_ENV_NAME} docformatter --check --diff $(filter %.py,$+)
touch $@
.PHONY: isort-check
isort-check: build/isort-check.mlos_core.${CONDA_ENV_NAME}.build-stamp
isort-check: build/isort-check.mlos_bench.${CONDA_ENV_NAME}.build-stamp
isort-check: build/isort-check.mlos_viz.${CONDA_ENV_NAME}.build-stamp
# Make sure isort format rules run before isort-check rules.
build/isort-check.mlos_core.${CONDA_ENV_NAME}.build-stamp: $(MLOS_CORE_PYTHON_FILES)
build/isort-check.mlos_bench.${CONDA_ENV_NAME}.build-stamp: $(MLOS_BENCH_PYTHON_FILES)
build/isort-check.mlos_viz.${CONDA_ENV_NAME}.build-stamp: $(MLOS_VIZ_PYTHON_FILES)
ISORT_CHECK_COMMON_PREREQS := build/conda-env.${CONDA_ENV_NAME}.build-stamp
ISORT_CHECK_COMMON_PREREQS += $(FORMAT_PREREQS)
ISORT_CHECK_COMMON_PREREQS += $(MLOS_GLOBAL_CONF_FILES)
build/isort-check.%.${CONDA_ENV_NAME}.build-stamp: $(ISORT_CHECK_COMMON_PREREQS)
# Note: if this fails use "make format" or "make isort" to fix it.
conda run -n ${CONDA_ENV_NAME} isort --only-modified --check --diff -j0 $(filter %.py,$+)
touch $@
.PHONY: pycodestyle
pycodestyle: build/pycodestyle.mlos_core.${CONDA_ENV_NAME}.build-stamp
pycodestyle: build/pycodestyle.mlos_bench.${CONDA_ENV_NAME}.build-stamp
pycodestyle: build/pycodestyle.mlos_viz.${CONDA_ENV_NAME}.build-stamp
build/pycodestyle.mlos_core.${CONDA_ENV_NAME}.build-stamp: $(MLOS_CORE_PYTHON_FILES)
build/pycodestyle.mlos_bench.${CONDA_ENV_NAME}.build-stamp: $(MLOS_BENCH_PYTHON_FILES)
build/pycodestyle.mlos_viz.${CONDA_ENV_NAME}.build-stamp: $(MLOS_VIZ_PYTHON_FILES)
PYCODESTYLE_COMMON_PREREQS := build/conda-env.${CONDA_ENV_NAME}.build-stamp
PYCODESTYLE_COMMON_PREREQS += $(FORMAT_PREREQS)
PYCODESTYLE_COMMON_PREREQS += $(MLOS_GLOBAL_CONF_FILES)
build/pycodestyle.%.${CONDA_ENV_NAME}.build-stamp: $(PYCODESTYLE_COMMON_PREREQS)
# Check for decent pep8 code style with pycodestyle.
# Note: if this fails, try using 'make format' to fix it.
conda run -n ${CONDA_ENV_NAME} pycodestyle $(filter %.py,$+)
touch $@
.PHONY: pydocstyle
pydocstyle: build/pydocstyle.mlos_core.${CONDA_ENV_NAME}.build-stamp
pydocstyle: build/pydocstyle.mlos_bench.${CONDA_ENV_NAME}.build-stamp
pydocstyle: build/pydocstyle.mlos_viz.${CONDA_ENV_NAME}.build-stamp
build/pydocstyle.mlos_core.${CONDA_ENV_NAME}.build-stamp: $(MLOS_CORE_PYTHON_FILES)
build/pydocstyle.mlos_bench.${CONDA_ENV_NAME}.build-stamp: $(MLOS_BENCH_PYTHON_FILES)
build/pydocstyle.mlos_viz.${CONDA_ENV_NAME}.build-stamp: $(MLOS_VIZ_PYTHON_FILES)
PYDOCSTYLE_COMMON_PREREQS := build/conda-env.${CONDA_ENV_NAME}.build-stamp
PYDOCSTYLE_COMMON_PREREQS += $(FORMAT_PREREQS)
PYDOCSTYLE_COMMON_PREREQS += $(MLOS_GLOBAL_CONF_FILES)
build/pydocstyle.%.${CONDA_ENV_NAME}.build-stamp: $(PYDOCSTYLE_COMMON_PREREQS)
# Check for decent pep8 doc style with pydocstyle.
conda run -n ${CONDA_ENV_NAME} pydocstyle $(filter %.py,$+)
touch $@
.PHONY: cspell
ifeq ($(DOCKER),)
cspell:
@echo "NOTE: docker is not available. Skipping cspell check."
else
cspell: build/cspell-container.build-stamp
./.devcontainer/scripts/run-cspell.sh
endif
build/cspell-container.build-stamp: $(FORMAT_PREREQS)
# Build the docker image with cspell in it.
$(MAKE) -C .devcontainer/build cspell
touch $@
.PHONY: markdown-link-check
ifeq ($(DOCKER),)
markdown-link-check:
@echo "NOTE: docker is not available. Skipping markdown-link-check check."
else
markdown-link-check: build/markdown-link-check-container.build-stamp
./.devcontainer/scripts/run-markdown-link-check.sh
endif
build/markdown-link-check-container.build-stamp: $(FORMAT_PREREQS)
# Build the docker image with markdown-link-check in it.
$(MAKE) -C .devcontainer/build markdown-link-check
touch $@
.PHONY: pylint
pylint: build/pylint.mlos_core.${CONDA_ENV_NAME}.build-stamp
pylint: build/pylint.mlos_bench.${CONDA_ENV_NAME}.build-stamp
pylint: build/pylint.mlos_viz.${CONDA_ENV_NAME}.build-stamp
build/pylint.mlos_core.${CONDA_ENV_NAME}.build-stamp: $(MLOS_CORE_PYTHON_FILES)
build/pylint.mlos_bench.${CONDA_ENV_NAME}.build-stamp: $(MLOS_BENCH_PYTHON_FILES)
build/pylint.mlos_viz.${CONDA_ENV_NAME}.build-stamp: $(MLOS_VIZ_PYTHON_FILES)
PYLINT_COMMON_PREREQS := build/conda-env.${CONDA_ENV_NAME}.build-stamp
PYLINT_COMMON_PREREQS += $(FORMAT_PREREQS)
PYLINT_COMMON_PREREQS += pyproject.toml
build/pylint.%.${CONDA_ENV_NAME}.build-stamp: $(PYLINT_COMMON_PREREQS)
conda run -n ${CONDA_ENV_NAME} pylint -j0 $(filter %.py,$+)
touch $@
.PHONY: flake8
flake8: build/flake8.mlos_core.${CONDA_ENV_NAME}.build-stamp
flake8: build/flake8.mlos_bench.${CONDA_ENV_NAME}.build-stamp
flake8: build/flake8.mlos_viz.${CONDA_ENV_NAME}.build-stamp
build/flake8.mlos_core.${CONDA_ENV_NAME}.build-stamp: $(MLOS_CORE_PYTHON_FILES)
build/flake8.mlos_bench.${CONDA_ENV_NAME}.build-stamp: $(MLOS_BENCH_PYTHON_FILES)
build/flake8.mlos_viz.${CONDA_ENV_NAME}.build-stamp: $(MLOS_VIZ_PYTHON_FILES)
FLAKE8_COMMON_PREREQS := build/conda-env.${CONDA_ENV_NAME}.build-stamp
FLAKE8_COMMON_PREREQS += $(FORMAT_PREREQS)
FLAKE8_COMMON_PREREQS += $(MLOS_GLOBAL_CONF_FILES)
build/flake8.%.${CONDA_ENV_NAME}.build-stamp: $(FLAKE8_COMMON_PREREQS)
conda run -n ${CONDA_ENV_NAME} flake8 -j0 $(filter %.py,$+)
touch $@
.PHONY: mypy
mypy: build/mypy.mlos_core.${CONDA_ENV_NAME}.build-stamp
mypy: build/mypy.mlos_bench.${CONDA_ENV_NAME}.build-stamp
mypy: build/mypy.mlos_viz.${CONDA_ENV_NAME}.build-stamp
# Run these in order.
build/mypy.mlos_core.${CONDA_ENV_NAME}.build-stamp: $(MLOS_CORE_PYTHON_FILES)
build/mypy.mlos_bench.${CONDA_ENV_NAME}.build-stamp: $(MLOS_BENCH_PYTHON_FILES) build/mypy.mlos_core.${CONDA_ENV_NAME}.build-stamp
build/mypy.mlos_viz.${CONDA_ENV_NAME}.build-stamp: $(MLOS_VIZ_PYTHON_FILES) build/mypy.mlos_bench.${CONDA_ENV_NAME}.build-stamp
MYPY_COMMON_PREREQS := build/conda-env.${CONDA_ENV_NAME}.build-stamp
MYPY_COMMON_PREREQS += $(FORMAT_PREREQS)
MYPY_COMMON_PREREQS += $(MLOS_GLOBAL_CONF_FILES)
MYPY_COMMON_PREREQS += scripts/dmypy-wrapper.sh
build/mypy.%.${CONDA_ENV_NAME}.build-stamp: $(MYPY_COMMON_PREREQS)
conda run -n ${CONDA_ENV_NAME} scripts/dmypy-wrapper.sh \
$(filter %.py,$+)
touch $@
.PHONY: test
test: pytest notebook-exec-test
PYTEST_CONF_FILES := $(MLOS_GLOBAL_CONF_FILES) conftest.py
.PHONY: pytest
pytest: conda-env build/pytest.${CONDA_ENV_NAME}.build-stamp
pytest-mlos-core: build/pytest.mlos_core.${CONDA_ENV_NAME}.needs-build-stamp
pytest-mlos-bench: build/pytest.mlos_bench.${CONDA_ENV_NAME}.needs-build-stamp
pytest-mlos-viz: build/pytest.mlos_viz.${CONDA_ENV_NAME}.needs-build-stamp
build/pytest.mlos_core.${CONDA_ENV_NAME}.needs-build-stamp: $(MLOS_CORE_PYTHON_FILES) $(MLOS_CORE_CONF_FILES)
build/pytest.mlos_core.${CONDA_ENV_NAME}.needs-build-stamp: PYTEST_MODULE := mlos_core
build/pytest.mlos_bench.${CONDA_ENV_NAME}.needs-build-stamp: $(MLOS_BENCH_PYTHON_FILES) $(MLOS_BENCH_CONF_FILES)
build/pytest.mlos_bench.${CONDA_ENV_NAME}.needs-build-stamp: PYTEST_MODULE := mlos_bench
build/pytest.mlos_viz.${CONDA_ENV_NAME}.needs-build-stamp: $(MLOS_VIZ_PYTHON_FILES) $(MLOS_VIZ_CONF_FILES)
build/pytest.mlos_viz.${CONDA_ENV_NAME}.needs-build-stamp: PYTEST_MODULE := mlos_viz
# Invividual package test rules (for tight loop dev work).
# Skip code coverage tests for these.
PYTEST_COMMON_PREREQS := build/conda-env.${CONDA_ENV_NAME}.build-stamp
PYTEST_COMMON_PREREQS += $(FORMAT_PREREQS)
PYTEST_COMMON_PREREQS += $(PYTEST_CONF_FILES)
build/pytest.%.${CONDA_ENV_NAME}.needs-build-stamp: $(PYTEST_COMMON_PREREQS)
conda run -n ${CONDA_ENV_NAME} pytest $(PYTEST_EXTRA_OPTIONS) $(PYTEST_MODULE)
touch $@
PYTEST_OPTIONS :=
# Allow optionally skipping coverage calculations during local testing to skip up inner dev loop.
SKIP_COVERAGE := $(shell echo $${SKIP_COVERAGE:-} | grep -i -x -e 1 -e true)
ifeq ($(SKIP_COVERAGE),)
PYTEST_OPTIONS += --cov=. --cov-append --cov-fail-under=92 --cov-report=xml --cov-report=html --junitxml=junit/test-results.xml --local-badge-output-dir=doc/source/badges/
endif
# Global pytest rule that also produces code coverage for the pipeline.
# NOTE: When run locally, the junit/test-results.xml will only include the
# tests from the latest run, but this file is only used for upstream reporting,
# so probably shouldn't matter.
build/pytest.${CONDA_ENV_NAME}.build-stamp: $(PYTEST_COMMON_PREREQS)
build/pytest.${CONDA_ENV_NAME}.build-stamp: $(MLOS_CORE_PYTHON_FILES) $(MLOS_CORE_CONF_FILES)
build/pytest.${CONDA_ENV_NAME}.build-stamp: $(MLOS_BENCH_PYTHON_FILES) $(MLOS_BENCH_CONF_FILES)
build/pytest.${CONDA_ENV_NAME}.build-stamp: $(MLOS_VIZ_PYTHON_FILES) $(MLOS_VIZ_CONF_FILES)
build/pytest.${CONDA_ENV_NAME}.build-stamp:
# Remove the markers for individual targets (above).
for pytest_module in $(MLOS_PKGS); do rm -f build/pytest.$${pytest_module}.${CONDA_ENV_NAME}.build-stamp; done
# Run pytest for the modules: $(MLOS_PKGS)
mkdir -p doc/source/badges/
conda run -n ${CONDA_ENV_NAME} pytest $(PYTEST_OPTIONS) $(PYTEST_EXTRA_OPTIONS) $(MLOS_PKGS)
# Global success. Mark the individual targets as done again.
for pytest_module in $(MLOS_PKGS); do touch build/pytest.$${pytest_module}.${CONDA_ENV_NAME}.build-stamp; done
touch $@
# setuptools-scm needs a longer history than Github CI workers have by default.
.PHONY: unshallow
unshallow: build/unshallow.build-stamp
build/unshallow.build-stamp:
git rev-parse --is-shallow-repository | grep -x -q false || git fetch --unshallow --quiet
touch $@
.PHONY: dist
dist: sdist bdist_wheel
.PHONY: sdist
sdist: conda-env unshallow
sdist: mlos_core/dist/tmp/mlos_core-latest.tar.gz
sdist: mlos_bench/dist/tmp/mlos_bench-latest.tar.gz
sdist: mlos_viz/dist/tmp/mlos_viz-latest.tar.gz
.PHONY: bdist_wheel
bdist_wheel: conda-env unshallow
bdist_wheel: mlos_core/dist/tmp/mlos_core-latest-py3-none-any.whl
bdist_wheel: mlos_bench/dist/tmp/mlos_bench-latest-py3-none-any.whl
bdist_wheel: mlos_viz/dist/tmp/mlos_viz-latest-py3-none-any.whl
# Make the whl files depend on the .tar.gz files, mostly to prevent conflicts
# with shared use of the their build/ trees.
mlos_core/dist/tmp/mlos_core-latest-py3-none-any.whl: MODULE_NAME := mlos_core
mlos_core/dist/tmp/mlos_core-latest-py3-none-any.whl: PACKAGE_NAME := mlos_core
mlos_core/dist/tmp/mlos_core-latest-py3-none-any.whl: mlos_core/dist/tmp/mlos_core-latest.tar.gz
mlos_core/dist/tmp/mlos_core-latest.tar.gz: $(MLOS_CORE_CONF_FILES) $(MLOS_CORE_PYTHON_FILES)
mlos_core/dist/tmp/mlos_core-latest.tar.gz: MODULE_NAME := mlos_core
mlos_core/dist/tmp/mlos_core-latest.tar.gz: PACKAGE_NAME := mlos_core
mlos_bench/dist/tmp/mlos_bench-latest-py3-none-any.whl: MODULE_NAME := mlos_bench
mlos_bench/dist/tmp/mlos_bench-latest-py3-none-any.whl: PACKAGE_NAME := mlos_bench
mlos_bench/dist/tmp/mlos_bench-latest-py3-none-any.whl: mlos_bench/dist/tmp/mlos_bench-latest.tar.gz
mlos_bench/dist/tmp/mlos_bench-latest.tar.gz: $(MLOS_BENCH_CONF_FILES) $(MLOS_BENCH_PYTHON_FILES)
mlos_bench/dist/tmp/mlos_bench-latest.tar.gz: MODULE_NAME := mlos_bench
mlos_bench/dist/tmp/mlos_bench-latest.tar.gz: PACKAGE_NAME := mlos_bench
mlos_viz/dist/tmp/mlos_viz-latest-py3-none-any.whl: MODULE_NAME := mlos_viz
mlos_viz/dist/tmp/mlos_viz-latest-py3-none-any.whl: PACKAGE_NAME := mlos_viz
mlos_viz/dist/tmp/mlos_viz-latest-py3-none-any.whl: mlos_viz/dist/tmp/mlos_viz-latest.tar.gz
mlos_viz/dist/tmp/mlos_viz-latest.tar.gz: $(MLOS_VIZ_CONF_FILES) $(MLOS_VIZ_PYTHON_FILES)
mlos_viz/dist/tmp/mlos_viz-latest.tar.gz: MODULE_NAME := mlos_viz
mlos_viz/dist/tmp/mlos_viz-latest.tar.gz: PACKAGE_NAME := mlos_viz
%-latest.tar.gz: build/conda-env.${CONDA_ENV_NAME}.build-stamp build/unshallow.build-stamp $(FORMAT_PREREQS)
mkdir -p $(MODULE_NAME)/dist/tmp
rm -f $(MODULE_NAME)/dist/$(PACKAGE_NAME)-*.tar{,.gz}
rm -f $(MODULE_NAME)/dist/tmp/$(PACKAGE_NAME)-latest.tar{,.gz}
rm -rf $(MODULE_NAME)/build/
rm -rf $(MODULE_NAME)/$(MODULE_NAME).egg-info/
cd $(MODULE_NAME)/ && conda run -n ${CONDA_ENV_NAME} python3 -m build --sdist
# Do some sanity checks on the sdist tarball output.
BASE_VERS=`conda run -n ${CONDA_ENV_NAME} python3 $(MODULE_NAME)/$(MODULE_NAME)/version.py | cut -d. -f-2 | egrep -x '[0-9.]+' || echo err-unknown-base-version` \
&& TAG_VERS=`git tag -l --sort=-version:refname | egrep -x '^v[0-9.]+' | head -n1 | sed 's/^v//' | cut -d. -f-2 | egrep -x '[0-9.]+' || echo err-unknown-tag-version` \
&& ls $(MODULE_NAME)/dist/$(PACKAGE_NAME)-*.tar.gz | grep -F -e $$BASE_VERS -e $$TAG_VERS
# Make sure tests were excluded.
! ( tar tzf $(MODULE_NAME)/dist/$(PACKAGE_NAME)-*.tar.gz | grep -m1 tests/ )
# Make sure the py.typed marker file exists.
tar tzf $(MODULE_NAME)/dist/$(PACKAGE_NAME)-*.tar.gz | grep -m1 /py.typed
# Check to make sure the mlos_bench module has the config directory.
[ "$(MODULE_NAME)" != "mlos_bench" ] || tar tzf $(MODULE_NAME)/dist/$(PACKAGE_NAME)-*.tar.gz | grep -m1 mlos_bench/config/
cd $(MODULE_NAME)/dist/tmp && ln -s ../$(PACKAGE_NAME)-*.tar.gz $(PACKAGE_NAME)-latest.tar.gz
%-latest-py3-none-any.whl: build/conda-env.${CONDA_ENV_NAME}.build-stamp build/unshallow.build-stamp $(FORMAT_PREREQS)
mkdir -p $(MODULE_NAME)/dist/tmp
rm -f $(MODULE_NAME)/dist/$(MODULE_NAME)-*-py3-none-any.whl
rm -f $(MODULE_NAME)/dist/tmp/$(MODULE_NAME)-latest-py3-none-any.whl
rm -rf $(MODULE_NAME)/build/
rm -rf $(MODULE_NAME)/$(MODULE_NAME).egg-info/
cd $(MODULE_NAME)/ && conda run -n ${CONDA_ENV_NAME} python3 -m build --wheel
# Do some sanity checks on the wheel output.
BASE_VERS=`conda run -n ${CONDA_ENV_NAME} python3 $(MODULE_NAME)/$(MODULE_NAME)/version.py | cut -d. -f-2 | egrep -o '^[0-9.]+' || echo err-unknown-base-version` \
&& TAG_VERS=`git tag -l --sort=-version:refname | egrep -x '^v[0-9.]+' | head -n1 | sed 's/^v//' | cut -d. -f-2 | egrep -x '[0-9.]+' || echo err-unknown-tag-version` \
&& ls $(MODULE_NAME)/dist/$(MODULE_NAME)-*-py3-none-any.whl | grep -F -e $$BASE_VERS -e $$TAG_VERS
# Check to make sure the tests were excluded from the wheel.
! ( unzip -t $(MODULE_NAME)/dist/$(MODULE_NAME)-*-py3-none-any.whl | grep -m1 tests/ )
# Make sure the py.typed marker file exists.
unzip -t $(MODULE_NAME)/dist/$(MODULE_NAME)-*-py3-none-any.whl | grep -m1 /py.typed
# Check to make sure the mlos_bench module has the config directory.
[ "$(MODULE_NAME)" != "mlos_bench" ] || unzip -t $(MODULE_NAME)/dist/$(MODULE_NAME)-*-py3-none-any.whl | grep -m1 mlos_bench/config/
# Check to make sure the README contents made it into the package metadata.
unzip -p $(MODULE_NAME)/dist/$(MODULE_NAME)-*-py3-none-any.whl */METADATA | egrep -v '^[A-Z][a-zA-Z-]+:' | grep -q -i '^# mlos'
# Also check that the they include the URL
unzip -p $(MODULE_NAME)/dist/$(MODULE_NAME)-*-py3-none-any.whl */METADATA | grep -q -e '](https://github.com/microsoft/MLOS/'
# Link it into place
cd $(MODULE_NAME)/dist/tmp && ln -s ../$(MODULE_NAME)-*-py3-none-any.whl $(MODULE_NAME)-latest-py3-none-any.whl
.PHONY: clean-dist-test-env
clean-dist-test-env:
# Remove any existing mlos-dist-test environment so we can start clean.
conda env remove -y ${CONDA_INFO_LEVEL} -n mlos-dist-test-$(PYTHON_VERSION) 2>/dev/null || true
rm -f build/dist-test-env.$(PYTHON_VERSION).build-stamp
.PHONY: dist-test-env
dist-test-env: dist build/dist-test-env.$(PYTHON_VERSION).build-stamp
build/dist-test-env.$(PYTHON_VERSION).build-stamp: build/conda-env.${CONDA_ENV_NAME}.build-stamp
# Use the same version of python as the one we used to build the wheels.
build/dist-test-env.$(PYTHON_VERSION).build-stamp: PYTHON_VERS_REQ=$(shell conda list -n ${CONDA_ENV_NAME} | egrep '^python\s+' | sed -r -e 's/^python[ \t]+//' | cut -d' ' -f1 | cut -d. -f1-2)
build/dist-test-env.$(PYTHON_VERSION).build-stamp: mlos_core/dist/tmp/mlos_core-latest-py3-none-any.whl
build/dist-test-env.$(PYTHON_VERSION).build-stamp: mlos_bench/dist/tmp/mlos_bench-latest-py3-none-any.whl
build/dist-test-env.$(PYTHON_VERSION).build-stamp: mlos_viz/dist/tmp/mlos_viz-latest-py3-none-any.whl
# Create a clean test environment for checking the wheel files.
$(MAKE) clean-dist-test-env
conda create -y ${CONDA_INFO_LEVEL} -n mlos-dist-test-$(PYTHON_VERSION) python=$(PYTHON_VERS_REQ)
# Install some additional dependencies necessary for clean building some of the wheels.
conda install -y ${CONDA_INFO_LEVEL} -n mlos-dist-test-$(PYTHON_VERSION) swig libpq
# Test a clean install of the mlos_core wheel.
conda run -n mlos-dist-test-$(PYTHON_VERSION) pip install "`readlink -f mlos_core/dist/tmp/mlos_core-latest-py3-none-any.whl`[full-tests]"
# Test a clean install of the mlos_bench wheel.
conda run -n mlos-dist-test-$(PYTHON_VERSION) pip install "`readlink -f mlos_bench/dist/tmp/mlos_bench-latest-py3-none-any.whl`[full-tests]"
# Test that the config dir for mlos_bench got distributed.
test -e `conda env list | grep "mlos-dist-test-$(PYTHON_VERSION) " | awk '{ print $$2 }'`/lib/python$(PYTHON_VERS_REQ)/site-packages/mlos_bench/config/README.md
# Test a clean install of the mlos_viz wheel.
conda run -n mlos-dist-test-$(PYTHON_VERSION) pip install "`readlink -f mlos_viz/dist/tmp/mlos_viz-latest-py3-none-any.whl`[full-tests]"
touch $@
.PHONY: dist-test
#dist-test: clean-dist
dist-test: dist-test-env build/dist-test.$(PYTHON_VERSION).build-stamp
# Unnecessary if we invoke it as "python3 -m pytest ..."
build/dist-test.$(PYTHON_VERSION).build-stamp: $(PYTHON_FILES) build/dist-test-env.$(PYTHON_VERSION).build-stamp
# Make sure we're using the packages from the wheel.
# Note: this will pick up the local directory and change the output if we're using PYTHONPATH=.
conda run -n mlos-dist-test-$(PYTHON_VERSION) pip list --verbose | grep mlos-core | grep ' pip'
conda run -n mlos-dist-test-$(PYTHON_VERSION) pip list --verbose | grep mlos-bench | grep ' pip'
conda run -n mlos-dist-test-$(PYTHON_VERSION) pip list --verbose | grep mlos-viz | grep ' pip'
# Run a simple test that uses the mlos_core wheel (full tests can be checked with `make test`).
conda run -n mlos-dist-test-$(PYTHON_VERSION) python3 -m pytest mlos_core/mlos_core/tests/spaces/spaces_test.py
# Run a simple test that uses the mlos_bench wheel (full tests can be checked with `make test`).
conda run -n mlos-dist-test-$(PYTHON_VERSION) python3 -m pytest mlos_bench/mlos_bench/tests/environments/mock_env_test.py
# Run a basic cli tool check.
conda run -n mlos-dist-test-$(PYTHON_VERSION) mlos_bench --help 2>&1 | grep '^usage: mlos_bench '
# Run a simple test that uses the mlos_viz wheel (full tests can be checked with `make test`).
# To do that, we need the fixtures from mlos_bench, so make those available too.
PYTHONPATH=mlos_bench conda run -n mlos-dist-test-$(PYTHON_VERSION) python3 -m pytest mlos_viz/mlos_viz/tests/test_dabl_plot.py
touch $@
clean-dist-test: clean-dist-test-env
rm -f build/dist-test-env.$(PYTHON_VERSION).build-stamp
.PHONY: publish
publish: publish-pypi
.PHONY:
publish-pypi-deps: build/publish-pypi-deps.${CONDA_ENV_NAME}.build-stamp
build/publish-pypi-deps.${CONDA_ENV_NAME}.build-stamp: build/conda-env.${CONDA_ENV_NAME}.build-stamp
conda run -n ${CONDA_ENV_NAME} pip install -U twine
touch $@
PUBLISH_DEPS := build/publish-pypi-deps.${CONDA_ENV_NAME}.build-stamp
PUBLISH_DEPS += build/pytest.${CONDA_ENV_NAME}.build-stamp
PUBLISH_DEPS += mlos_core/dist/tmp/mlos_core-latest.tar.gz
PUBLISH_DEPS += mlos_bench/dist/tmp/mlos_bench-latest.tar.gz
PUBLISH_DEPS += mlos_viz/dist/tmp/mlos_viz-latest.tar.gz
PUBLISH_DEPS += mlos_core/dist/tmp/mlos_core-latest-py3-none-any.whl
PUBLISH_DEPS += mlos_bench/dist/tmp/mlos_bench-latest-py3-none-any.whl
PUBLISH_DEPS += mlos_viz/dist/tmp/mlos_viz-latest-py3-none-any.whl
PUBLISH_DEPS += build/dist-test.$(PYTHON_VERSION).build-stamp
PUBLISH_DEPS += build/check-doc.build-stamp
PUBLISH_DEPS += build/linklint-doc.build-stamp
build/publish.${CONDA_ENV_NAME}.%.py.build-stamp: $(PUBLISH_DEPS)
# Basic sanity checks on files about to be published.
# Run "make clean-dist && make dist" if these fail.
# Check the tar count.
test `ls -1 mlos_core/dist/*.tar.gz | wc -l` -eq 1
test `ls -1 mlos_bench/dist/*.tar.gz | wc -l` -eq 1
test `ls -1 mlos_viz/dist/*.tar.gz | wc -l` -eq 1
test `ls -1 mlos_*/dist/*.tar.gz | wc -l` -eq 3
# Check the whl count.
test `ls -1 mlos_core/dist/*.whl | wc -l` -eq 1
test `ls -1 mlos_bench/dist/*.whl | wc -l` -eq 1
test `ls -1 mlos_viz/dist/*.whl | wc -l` -eq 1
test `ls -1 mlos_*/dist/*.whl | wc -l` -eq 3
# Publish the files to the specified repository.
repo_name=`echo "$@" | sed -r -e 's|build/publish\.[^.]+\.||' -e 's|\.py\.build-stamp||'` \
&& conda run -n ${CONDA_ENV_NAME} python3 -m twine upload --repository $$repo_name \
mlos_*/dist/mlos*-*.tar.gz mlos_*/dist/mlos*-*.whl
touch $@
publish-pypi: build/publish.${CONDA_ENV_NAME}.pypi.py.build-stamp
publish-test-pypi: build/publish.${CONDA_ENV_NAME}.testpypi.py.build-stamp
notebook-exec-test: build/notebook-exec-test.${CONDA_ENV_NAME}.build-stamp
build/notebook-exec-test.${CONDA_ENV_NAME}.build-stamp: build/conda-env.${CONDA_ENV_NAME}.build-stamp $(NOTEBOOK_FILES)
find . -name '*.ipynb' -not -path '*/build/*' -print0 | xargs -0 -n1 -P0 conda run -n ${CONDA_ENV_NAME} python -m jupyter execute
touch $@
build/doc-prereqs.${CONDA_ENV_NAME}.build-stamp: build/conda-env.${CONDA_ENV_NAME}.build-stamp
build/doc-prereqs.${CONDA_ENV_NAME}.build-stamp: doc/requirements.txt
conda run -n ${CONDA_ENV_NAME} pip install -U -r doc/requirements.txt
touch $@
.PHONY: doc-prereqs
doc-prereqs: build/doc-prereqs.${CONDA_ENV_NAME}.build-stamp build/unshallow.build-stamp
.PHONY: clean-doc-env
clean-doc-env:
rm -f build/doc-prereqs.build-stamp
rm -f build/doc-prereqs.${CONDA_ENV_NAME}.build-stamp
COMMON_DOC_FILES := build/doc-prereqs.${CONDA_ENV_NAME}.build-stamp doc/source/*.rst doc/source/_templates/*.rst doc/source/conf.py
SPHINX_API_RST_FILES := doc/source/index.rst doc/source/mlos_bench.run.usage.rst
ifeq ($(SKIP_COVERAGE),)
doc/build/html/index.html: build/pytest.${CONDA_ENV_NAME}.build-stamp
doc/build/html/htmlcov/index.html: build/pytest.${CONDA_ENV_NAME}.build-stamp
endif
# Treat warnings as failures.
SPHINXOPTS ?= # -v # be verbose
SPHINXOPTS += -n -W -w $(CURDIR)/doc/build/sphinx-build.warn.log -j auto
sphinx-apidoc: doc/build/html/index.html
doc/source/generated/mlos_bench.run.usage.txt: build/conda-env.${CONDA_ENV_NAME}.build-stamp
doc/source/generated/mlos_bench.run.usage.txt: $(MLOS_BENCH_PYTHON_FILES)
# Generate the help output from mlos_bench CLI for the docs.
mkdir -p doc/source/generated/
conda run -n ${CONDA_ENV_NAME} mlos_bench --help > doc/source/generated/mlos_bench.run.usage.txt
doc/build/html/index.html: build/doc-prereqs.${CONDA_ENV_NAME}.build-stamp
doc/build/html/index.html: doc/source/generated/mlos_bench.run.usage.txt
doc/build/html/index.html: $(MLOS_CORE_PYTHON_FILES)
doc/build/html/index.html: $(MLOS_BENCH_PYTHON_FILES)
doc/build/html/index.html: $(MLOS_VIZ_PYTHON_FILES)
doc/build/html/index.html: $(SPHINX_API_RST_FILES) doc/Makefile doc/source/conf.py
doc/build/html/index.html: doc/copy-source-tree-docs.sh $(MD_FILES)
@rm -rf doc/build
@mkdir -p doc/build
@rm -f doc/build/log.txt
# Make sure that at least placeholder doc badges are there.
mkdir -p doc/source/badges/
touch doc/source/badges/coverage.svg
touch doc/source/badges/tests.svg
# Copy some of the source tree markdown docs into place.
./doc/copy-source-tree-docs.sh
# Build the rst files into html.
conda run -n ${CONDA_ENV_NAME} $(MAKE) SPHINXOPTS="$(SPHINXOPTS)" -C doc/ $(MAKEFLAGS) html \
>> doc/build/log.txt 2>&1 \
|| { cat doc/build/log.txt; exit 1; }
# DONE: Add some output filtering for this so we can more easily see what went wrong.
# (e.g. skip complaints about missing .examples files)
# See check-doc
.PHONY: doc
doc: doc/build/html/.nojekyll doc-test
.PHONY: doc-test
doc-test: build/check-doc.build-stamp build/linklint-doc.build-stamp
doc/build/html/htmlcov/index.html: doc/build/html/index.html
# Make the codecov html report available for the site.
test -d htmlcov && cp -a htmlcov doc/build/html/ || true
mkdir -p doc/build/html/htmlcov
touch doc/build/html/htmlcov/index.html
doc/build/html/.nojekyll: doc/build/html/index.html doc/build/html/htmlcov/index.html
# Make sure that github pages doesn't try to run jekyll on the docs.
touch doc/build/html/.nojekyll
.PHONY: check-doc
check-doc: build/check-doc.build-stamp
build/check-doc.build-stamp: doc/build/html/index.html doc/build/html/htmlcov/index.html
# Check for a few files to make sure the docs got generated in a way we want.
test -s doc/build/html/index.html
grep -q BaseOptimizer doc/build/html/autoapi/mlos_core/optimizers/optimizer/index.html
grep -q Environment doc/build/html/autoapi/mlos_bench/environments/base_environment/index.html
grep -q plot doc/build/html/autoapi/mlos_viz/index.html
test -s doc/build/html/autoapi/mlos_core/index.html
test -s doc/build/html/autoapi/mlos_bench/index.html
test -s doc/build/html/autoapi/mlos_viz/index.html
test -s doc/build/html/autoapi/mlos_viz/dabl/index.html
grep -q -e '--config CONFIG' doc/build/html//mlos_bench.run.usage.html
# Check doc logs for errors (but skip over some known ones) ...
@cat doc/build/log.txt \
| egrep -C1 -e WARNING -e CRITICAL -e ERROR \
| egrep -v \
-e "warnings.warn\(f'\"{wd.path}\" is shallow and may cause errors'\)" \
-e "No such file or directory: '.*.examples'.( \[docutils\]\s*)?$$" \
-e "toctree contains reference to nonexisting document 'auto_examples/index'" \
-e '^make.*resetting jobserver mode' \
-e 'from cryptography.hazmat.primitives.ciphers.algorithms import' \
| grep -v '^\s*$$' \
| if grep .; then echo "Errors found in doc build. Check doc/build/log.txt for details."; cat doc/build/log.txt; exit 1; else exit 0; fi
touch $@
.PHONY: linklint-doc
ifeq ($(DOCKER),)
linklint-doc:
@echo "NOTE: linklint-doc target requires docker."
else
linklint-doc: build/linklint-doc.build-stamp
endif
build/linklint-doc.build-stamp: doc/build/html/index.html doc/build/html/htmlcov/index.html build/check-doc.build-stamp
@echo "Starting nginx docker container for serving docs."
./doc/nginx-docker.sh restart
docker port mlos-doc-nginx
nginx_port=`docker port mlos-doc-nginx | grep 0.0.0.0:8080 | cut -d/ -f1` \
&& echo nginx_port=$${nginx_port} \
&& set -x \
&& docker exec mlos-doc-nginx curl -sSf http://localhost:$${nginx_port}/index.html >/dev/null
@echo "Running linklint on the docs."
docker exec mlos-doc-nginx linklint -net -redirect -root /doc/build/html/ /@ -error -warn > doc/build/linklint.out 2>&1
@if cat doc/build/linklint.out | grep -e ^ERROR -e ^WARN | grep -v 'missing named anchors' | grep -q .; then \
echo "Found errors in the documentation:"; cat doc/build/linklint.out; exit 1; \
fi
@echo "OK"
touch $@
.PHONY: clean-doc
clean-doc:
rm -rf doc/build/ doc/global/ doc/source/api/ doc/source/generated doc/source/autoapi
rm -rf doc/source/source_tree_docs/*
.PHONY: clean-format
clean-format:
rm -f build/black.${CONDA_ENV_NAME}.build-stamp
rm -f build/black.mlos_*.${CONDA_ENV_NAME}.build-stamp
rm -f build/docformatter.${CONDA_ENV_NAME}.build-stamp
rm -f build/docformatter.mlos_*.${CONDA_ENV_NAME}.build-stamp
rm -f build/isort.${CONDA_ENV_NAME}.build-stamp
rm -f build/isort.mlos_*.${CONDA_ENV_NAME}.build-stamp
rm -f build/licenseheaders.${CONDA_ENV_NAME}.build-stamp
rm -f build/licenseheaders-prereqs.${CONDA_ENV_NAME}.build-stamp
.PHONY: clean-check
clean-check:
rm -f build/pylint.build-stamp
rm -f build/pylint.${CONDA_ENV_NAME}.build-stamp
rm -f build/pylint.mlos_*.${CONDA_ENV_NAME}.build-stamp
rm -f build/mypy.mlos_*.${CONDA_ENV_NAME}.build-stamp
rm -f build/black-check.build-stamp
rm -f build/black-check.${CONDA_ENV_NAME}.build-stamp
rm -f build/black-check.mlos_*.${CONDA_ENV_NAME}.build-stamp
rm -f build/docformatter-check.${CONDA_ENV_NAME}.build-stamp
rm -f build/docformatter-check.mlos_*.${CONDA_ENV_NAME}.build-stamp
rm -f build/isort-check.${CONDA_ENV_NAME}.build-stamp
rm -f build/isort-check.mlos_*.${CONDA_ENV_NAME}.build-stamp
rm -f build/pycodestyle.build-stamp
rm -f build/pycodestyle.${CONDA_ENV_NAME}.build-stamp
rm -f build/pycodestyle.mlos_*.${CONDA_ENV_NAME}.build-stamp
rm -f build/pydocstyle.build-stamp
rm -f build/pydocstyle.${CONDA_ENV_NAME}.build-stamp
rm -f build/pydocstyle.mlos_*.${CONDA_ENV_NAME}.build-stamp
.PHONY: clean-test
clean-test:
rm -f build/pytest.build-stamp
rm -f build/pytest.${CONDA_ENV_NAME}.build-stamp
rm -f build/pytest.mlos_*.${CONDA_ENV_NAME}.build-stamp
rm -f build/pytest.mlos_*.${CONDA_ENV_NAME}.needs-build-stamp
rm -rf .pytest_cache/
rm -f coverage.xml .coverage* build/.converage*
rm -rf htmlcov/
rm -rf junit/
rm -rf test-output.xml
.PHONY: clean-dist
clean-dist:
rm -rf dist
rm -rf mlos_core/build mlos_core/dist
rm -rf mlos_bench/build mlos_bench/dist
rm -rf mlos_viz/build mlos_viz/dist
.PHONY: clean
clean: clean-format clean-check clean-test clean-dist clean-doc clean-doc-env clean-dist-test
rm -f build/unshallow.build-stamp
rm -f .*.build-stamp
rm -f build/conda-env.build-stamp build/conda-env.*.build-stamp
rm -rf mlos_core.egg-info
rm -rf mlos_core/mlos_core.egg-info
rm -rf mlos_bench.egg-info
rm -rf mlos_bench/mlos_bench.egg-info
rm -rf mlos_viz.egg-info
rm -rf mlos_viz/mlos_viz.egg-info
rm -rf __pycache__
find . -type d -name __pycache__ -print0 | xargs -t -r -0 rm -rf
find . -type f -name '*.pyc' -print0 | xargs -t -r -0 rm -f
.PHONY: devcontainer
devcontainer:
./.devcontainer/build/build-devcontainer.sh
@echo
@echo "Run ./.devcontainer/scripts/run-devcontainer.sh to start the newly built devcontainer."