@@ -33,18 +33,39 @@ CLEAN_FS?=
33
33
# Default: include.mk
34
34
INCLUDE_MAKEFILE? =include.mk
35
35
36
+ # Optional additional directories to be added to PATH in format
37
+ # `/path/to/dir/:/path/to/other/dir`. Gets inserted first, thus gets searched
38
+ # first.
39
+ # No default value.
40
+ EXTRA_PATH? =
41
+
36
42
# # core.mxenv
37
43
38
- # Python interpreter to use.
44
+ # Primary Python interpreter to use. It is used to create the
45
+ # virtual environment if `VENV_ENABLED` and `VENV_CREATE` are set to `true`.
39
46
# Default: python3
40
- PYTHON_BIN ? =python3
47
+ PRIMARY_PYTHON ? =python3
41
48
42
49
# Minimum required Python version.
43
- # Default: 3.7
44
- PYTHON_MIN_VERSION? =3.7
50
+ # Default: 3.9
51
+ PYTHON_MIN_VERSION? =3.9
52
+
53
+ # Install packages using the given package installer method.
54
+ # Supported are `pip` and `uv`. If uv is used, its global availability is
55
+ # checked. Otherwise, it is installed, either in the virtual environment or
56
+ # using the `PRIMARY_PYTHON`, dependent on the `VENV_ENABLED` setting. If
57
+ # `VENV_ENABLED` and uv is selected, uv is used to create the virtual
58
+ # environment.
59
+ # Default: pip
60
+ PYTHON_PACKAGE_INSTALLER? =uv
61
+
62
+ # Flag whether to use a global installed 'uv' or install
63
+ # it in the virtual environment.
64
+ # Default: false
65
+ MXENV_UV_GLOBAL? =false
45
66
46
67
# Flag whether to use virtual environment. If `false`, the
47
- # interpreter according to `PYTHON_BIN ` found in `PATH` is used.
68
+ # interpreter according to `PRIMARY_PYTHON ` found in `PATH` is used.
48
69
# Default: true
49
70
VENV_ENABLED? =true
50
71
@@ -59,7 +80,7 @@ VENV_CREATE?=true
59
80
# target folder for the virtual environment. If `VENV_ENABLED` is `true` and
60
81
# `VENV_CREATE` is false it is expected to point to an existing virtual
61
82
# environment. If `VENV_ENABLED` is `false` it is ignored.
62
- # Default: venv
83
+ # Default: . venv
63
84
VENV_FOLDER? =venv
64
85
65
86
# mxdev to install in virtual environment.
@@ -76,12 +97,19 @@ MXMAKE?=mxmake
76
97
# Default: mx.ini
77
98
PROJECT_CONFIG? =mx.ini
78
99
100
+ # # core.packages
101
+
102
+ # Allow prerelease and development versions.
103
+ # By default, the package installer only finds stable versions.
104
+ # Default: false
105
+ PACKAGES_ALLOW_PRERELEASES? =false
106
+
79
107
# # qa.test
80
108
81
109
# The command which gets executed. Defaults to the location the
82
110
# :ref:`run-tests` template gets rendered to if configured.
83
111
# Default: .mxmake/files/run-tests.sh
84
- TEST_COMMAND? =$(VENV_FOLDER ) /bin/python -m yafowil. tests.__init__
112
+ TEST_COMMAND? =$(VENV_FOLDER ) /bin/pytest src/ yafowil/ tests
85
113
86
114
# Additional Python requirements for running tests to be
87
115
# installed (via pip).
@@ -100,7 +128,7 @@ TEST_DEPENDENCY_TARGETS?=
100
128
COVERAGE_COMMAND? =\
101
129
$(VENV_FOLDER ) /bin/coverage run \
102
130
--source src/yafowil \
103
- -m yafowil. tests.__init__ \
131
+ -m pytest src/ yafowil/ tests \
104
132
&& $(VENV_FOLDER ) /bin/coverage report --fail-under=99
105
133
106
134
# # i18n.gettext
@@ -127,6 +155,10 @@ LINGUA_SEARCH_PATH?=src/yafowil
127
155
# No default value.
128
156
LINGUA_PLUGINS? =
129
157
158
+ # Command line options passed to `pot-create`
159
+ # No default value.
160
+ LINGUA_OPTIONS? =
161
+
130
162
# #############################################################################
131
163
# END SETTINGS - DO NOT EDIT BELOW THIS LINE
132
164
# #############################################################################
@@ -139,6 +171,8 @@ CHECK_TARGETS?=
139
171
TYPECHECK_TARGETS? =
140
172
FORMAT_TARGETS? =
141
173
174
+ export PATH: =$(if $(EXTRA_PATH ) ,$(EXTRA_PATH ) :,)$(PATH )
175
+
142
176
# Defensive settings for make: https://tech.davis-hansson.com/p/make/
143
177
SHELL: =bash
144
178
.ONESHELL :
@@ -155,48 +189,66 @@ MXMAKE_FOLDER?=.mxmake
155
189
# Sentinel files
156
190
SENTINEL_FOLDER? =$(MXMAKE_FOLDER ) /sentinels
157
191
SENTINEL? =$(SENTINEL_FOLDER ) /about.txt
158
- $(SENTINEL ) :
192
+ $(SENTINEL ) : $( firstword $( MAKEFILE_LIST ) )
159
193
@mkdir -p $(SENTINEL_FOLDER )
160
194
@echo " Sentinels for the Makefile process." > $(SENTINEL )
161
195
162
196
# #############################################################################
163
197
# mxenv
164
198
# #############################################################################
165
199
166
- # Check if given Python is installed
167
- ifeq (,$(shell which $(PYTHON_BIN ) ) )
168
- $(error "PYTHON=$(PYTHON_BIN) not found in $(PATH)")
169
- endif
200
+ export OS: =$(OS )
170
201
171
- # Check if given Python version is ok
172
- PYTHON_VERSION_OK =$(shell $(PYTHON_BIN ) -c "import sys; print((int(sys.version_info[0]) , int(sys.version_info[1])) >= tuple(map(int, '$(PYTHON_MIN_VERSION ) '.split('.'))))")
173
- ifeq ($(PYTHON_VERSION_OK ) ,0)
174
- $(error "Need Python >= $(PYTHON_MIN_VERSION)")
202
+ # Determine the executable path
203
+ ifeq ("$(VENV_ENABLED ) ", "true")
204
+ export VIRTUAL_ENV =$(abspath $(VENV_FOLDER ) )
205
+ ifeq ("$(OS ) ", "Windows_NT")
206
+ VENV_EXECUTABLE_FOLDER =$(VIRTUAL_ENV ) /Scripts
207
+ else
208
+ VENV_EXECUTABLE_FOLDER =$(VIRTUAL_ENV ) /bin
175
209
endif
176
-
177
- # Check if venv folder is configured if venv is enabled
178
- ifeq ( $( shell [[ " $( VENV_ENABLED ) " == "true" && " $( VENV_FOLDER ) " == "" ]] && echo "true") ,"true")
179
- $(error "VENV_FOLDER must be configured if VENV_ENABLED is true" )
210
+ export PATH: = $( VENV_EXECUTABLE_FOLDER ) : $( PATH )
211
+ MXENV_PYTHON =python
212
+ else
213
+ MXENV_PYTHON = $( PRIMARY_PYTHON )
180
214
endif
181
215
182
- # determine the executable path
183
- ifeq ("$(VENV_ENABLED ) ", "true ")
184
- MXENV_PATH = $( VENV_FOLDER ) /bin/
216
+ # Determine the package installer
217
+ ifeq ("$(PYTHON_PACKAGE_INSTALLER ) ","uv ")
218
+ PYTHON_PACKAGE_COMMAND =uv pip
185
219
else
186
- MXENV_PATH =
220
+ PYTHON_PACKAGE_COMMAND = $( MXENV_PYTHON ) -m pip
187
221
endif
188
222
189
223
MXENV_TARGET: =$(SENTINEL_FOLDER ) /mxenv.sentinel
190
224
$(MXENV_TARGET ) : $(SENTINEL )
225
+ @$(PRIMARY_PYTHON ) -c " import sys; vi = sys.version_info; sys.exit(1 if (int(vi[0]), int(vi[1])) >= tuple(map(int, '$( PYTHON_MIN_VERSION) '.split('.'))) else 0)" \
226
+ && echo " Need Python >= $( PYTHON_MIN_VERSION) " && exit 1 || :
227
+ @[[ " $( VENV_ENABLED) " == " true" && " $( VENV_FOLDER) " == " " ]] \
228
+ && echo " VENV_FOLDER must be configured if VENV_ENABLED is true" && exit 1 || :
229
+ @[[ " $( VENV_ENABLED) $( PYTHON_PACKAGE_INSTALLER) " == " falseuv" ]] \
230
+ && echo " Package installer uv does not work with a global Python interpreter." && exit 1 || :
191
231
ifeq ("$(VENV_ENABLED ) ", "true")
192
232
ifeq ("$(VENV_CREATE ) ", "true")
193
- @echo "Setup Python Virtual Environment under '$(VENV_FOLDER)'"
194
- @$(PYTHON_BIN) -m venv $(VENV_FOLDER)
233
+ ifeq ("$(PYTHON_PACKAGE_INSTALLER )$(MXENV_UV_GLOBAL ) ","uvtrue")
234
+ @echo "Setup Python Virtual Environment using package 'uv' at '$(VENV_FOLDER)'"
235
+ @uv venv -p $(PRIMARY_PYTHON) --seed $(VENV_FOLDER)
236
+ else
237
+ @echo "Setup Python Virtual Environment using module 'venv' at '$(VENV_FOLDER)'"
238
+ @$(PRIMARY_PYTHON) -m venv $(VENV_FOLDER)
239
+ @$(MXENV_PYTHON) -m ensurepip -U
240
+ endif
241
+ endif
242
+ else
243
+ @echo "Using system Python interpreter"
195
244
endif
245
+ ifeq ("$(PYTHON_PACKAGE_INSTALLER )$(MXENV_UV_GLOBAL ) ","uvfalse")
246
+ @echo "Install uv"
247
+ @$(MXENV_PYTHON) -m pip install uv
196
248
endif
197
- @$(MXENV_PATH)pip install -U pip setuptools wheel
198
- @$(MXENV_PATH)pip install -U $(MXDEV)
199
- @$(MXENV_PATH)pip install -U $(MXMAKE)
249
+ @$(PYTHON_PACKAGE_COMMAND) install -U pip setuptools wheel
250
+ @echo "Install/Update MXStack Python packages"
251
+ @$(PYTHON_PACKAGE_COMMAND) install -U $(MXDEV) $(MXMAKE)
200
252
@touch $(MXENV_TARGET)
201
253
202
254
.PHONY : mxenv
@@ -213,8 +265,8 @@ ifeq ("$(VENV_CREATE)", "true")
213
265
@rm -rf $(VENV_FOLDER)
214
266
endif
215
267
else
216
- @$(MXENV_PATH)pip uninstall -y $(MXDEV)
217
- @$(MXENV_PATH)pip uninstall -y $(MXMAKE)
268
+ @$(PYTHON_PACKAGE_COMMAND) uninstall -y $(MXDEV)
269
+ @$(PYTHON_PACKAGE_COMMAND) uninstall -y $(MXMAKE)
218
270
endif
219
271
220
272
INSTALL_TARGETS+ =mxenv
@@ -233,13 +285,11 @@ MXMAKE_FILES?=$(MXMAKE_FOLDER)/files
233
285
234
286
# set environment variables for mxmake
235
287
define set_mxfiles_env
236
- @export MXMAKE_MXENV_PATH=$(1 )
237
- @export MXMAKE_FILES=$(2 )
288
+ @export MXMAKE_FILES=$(1 )
238
289
endef
239
290
240
291
# unset environment variables for mxmake
241
292
define unset_mxfiles_env
242
- @unset MXMAKE_MXENV_PATH
243
293
@unset MXMAKE_FILES
244
294
endef
245
295
@@ -256,9 +306,9 @@ FILES_TARGET:=requirements-mxdev.txt
256
306
$(FILES_TARGET ) : $(PROJECT_CONFIG ) $(MXENV_TARGET ) $(SOURCES_TARGET ) $(LOCAL_PACKAGE_FILES )
257
307
@echo " Create project files"
258
308
@mkdir -p $(MXMAKE_FILES )
259
- $(call set_mxfiles_env,$(MXENV_PATH ) , $( MXMAKE_FILES ) )
260
- @$( MXENV_PATH ) mxdev -n -c $(PROJECT_CONFIG )
261
- $(call unset_mxfiles_env, $( MXENV_PATH ) , $( MXMAKE_FILES ) )
309
+ $(call set_mxfiles_env,$(MXMAKE_FILES ) )
310
+ @mxdev -n -c $(PROJECT_CONFIG )
311
+ $(call unset_mxfiles_env)
262
312
@test -e $(MXMAKE_FILES ) /pip.conf && cp $(MXMAKE_FILES ) /pip.conf $(VENV_FOLDER ) /pip.conf || :
263
313
@touch $(FILES_TARGET )
264
314
@@ -287,11 +337,21 @@ ADDITIONAL_SOURCES_TARGETS?=
287
337
288
338
INSTALLED_PACKAGES =$(MXMAKE_FILES ) /installed.txt
289
339
340
+ ifeq ("$(PACKAGES_ALLOW_PRERELEASES ) ","true")
341
+ ifeq ("$(PYTHON_PACKAGE_INSTALLER ) ","uv")
342
+ PACKAGES_PRERELEASES=--prerelease =allow
343
+ else
344
+ PACKAGES_PRERELEASES =--pre
345
+ endif
346
+ else
347
+ PACKAGES_PRERELEASES =
348
+ endif
349
+
290
350
PACKAGES_TARGET: =$(INSTALLED_PACKAGES )
291
351
$(PACKAGES_TARGET ) : $(FILES_TARGET ) $(ADDITIONAL_SOURCES_TARGETS )
292
352
@echo " Install python packages"
293
- @$(MXENV_PATH ) pip install -r $(FILES_TARGET )
294
- @$(MXENV_PATH ) pip freeze > $(INSTALLED_PACKAGES )
353
+ @$(PYTHON_PACKAGE_COMMAND ) install $( PACKAGES_PRERELEASES ) -r $(FILES_TARGET )
354
+ @$(PYTHON_PACKAGE_COMMAND ) freeze > $(INSTALLED_PACKAGES )
295
355
@touch $(PACKAGES_TARGET )
296
356
297
357
.PHONY : packages
@@ -304,8 +364,8 @@ packages-dirty:
304
364
.PHONY : packages-clean
305
365
packages-clean :
306
366
@test -e $(FILES_TARGET ) \
307
- && test -e $(MXENV_PATH ) pip \
308
- && $(MXENV_PATH ) pip uninstall -y -r $(FILES_TARGET ) \
367
+ && test -e $(MXENV_PYTHON ) \
368
+ && $(MXENV_PYTHON ) -m pip uninstall -y -r $(FILES_TARGET ) \
309
369
|| :
310
370
@rm -f $(PACKAGES_TARGET )
311
371
@@ -320,22 +380,22 @@ CLEAN_TARGETS+=packages-clean
320
380
TEST_TARGET: =$(SENTINEL_FOLDER ) /test.sentinel
321
381
$(TEST_TARGET ) : $(MXENV_TARGET )
322
382
@echo " Install $( TEST_REQUIREMENTS) "
323
- @$(MXENV_PATH ) pip install $(TEST_REQUIREMENTS )
383
+ @$(PYTHON_PACKAGE_COMMAND ) install $(TEST_REQUIREMENTS )
324
384
@touch $(TEST_TARGET )
325
385
326
386
.PHONY : test
327
387
test : $(FILES_TARGET ) $(SOURCES_TARGET ) $(PACKAGES_TARGET ) $(TEST_TARGET ) $(TEST_DEPENDENCY_TARGETS )
328
- @echo " Run tests "
329
- @test -z " $( TEST_COMMAND ) " && echo " No test command defined "
330
- @test -z " $( TEST_COMMAND ) " || bash -c " $( TEST_COMMAND) "
388
+ @test -z " $( TEST_COMMAND ) " && echo " No test command defined " && exit 1 || :
389
+ @echo " Run tests using $( TEST_COMMAND ) "
390
+ @/usr/bin/env bash -c " $( TEST_COMMAND) "
331
391
332
392
.PHONY : test-dirty
333
393
test-dirty :
334
394
@rm -f $(TEST_TARGET )
335
395
336
396
.PHONY : test-clean
337
397
test-clean : test-dirty
338
- @test -e $(MXENV_PATH ) pip && $(MXENV_PATH ) pip uninstall -y $(TEST_REQUIREMENTS ) || :
398
+ @test -e $(MXENV_PYTHON ) && $(MXENV_PYTHON ) -m pip uninstall -y $(TEST_REQUIREMENTS ) || :
339
399
@rm -rf .pytest_cache
340
400
341
401
INSTALL_TARGETS+ =$(TEST_TARGET )
@@ -349,22 +409,22 @@ DIRTY_TARGETS+=test-dirty
349
409
COVERAGE_TARGET: =$(SENTINEL_FOLDER ) /coverage.sentinel
350
410
$(COVERAGE_TARGET ) : $(TEST_TARGET )
351
411
@echo " Install Coverage"
352
- @$(MXENV_PATH ) pip install -U coverage
412
+ @$(PYTHON_PACKAGE_COMMAND ) install -U coverage
353
413
@touch $(COVERAGE_TARGET )
354
414
355
415
.PHONY : coverage
356
416
coverage : $(FILES_TARGET ) $(SOURCES_TARGET ) $(PACKAGES_TARGET ) $(COVERAGE_TARGET )
357
- @echo " Run coverage"
358
- @test -z " $( COVERAGE_COMMAND ) " && echo " No coverage command defined "
359
- @test -z " $( COVERAGE_COMMAND ) " || bash -c " $( COVERAGE_COMMAND) "
417
+ @test -z " $( COVERAGE_COMMAND ) " && echo " No coverage command defined " && exit 1 || :
418
+ @echo " Run coverage using $( COVERAGE_COMMAND ) "
419
+ @/usr/bin/env bash -c " $( COVERAGE_COMMAND) "
360
420
361
421
.PHONY : coverage-dirty
362
422
coverage-dirty :
363
423
@rm -f $(COVERAGE_TARGET )
364
424
365
425
.PHONY : coverage-clean
366
426
coverage-clean : coverage-dirty
367
- @test -e $(MXENV_PATH ) pip && $(MXENV_PATH ) pip uninstall -y coverage || :
427
+ @test -e $(MXENV_PYTHON ) && $(MXENV_PYTHON ) -m pip uninstall -y coverage || :
368
428
@rm -rf .coverage htmlcov
369
429
370
430
INSTALL_TARGETS+ =$(COVERAGE_TARGET )
@@ -421,14 +481,14 @@ gettext-compile:
421
481
LINGUA_TARGET: =$(SENTINEL_FOLDER ) /lingua.sentinel
422
482
$(LINGUA_TARGET ) : $(MXENV_TARGET )
423
483
@echo " Install Lingua"
424
- @$(MXENV_PATH ) pip install chameleon lingua $(LINGUA_PLUGINS )
484
+ @$(PYTHON_PACKAGE_COMMAND ) install chameleon lingua $(LINGUA_PLUGINS )
425
485
@touch $(LINGUA_TARGET )
426
486
427
487
PHONY : lingua-extract
428
488
lingua-extract : $(LINGUA_TARGET )
429
489
@echo " Extract messages"
430
- @$( MXENV_PATH ) pot-create \
431
- " $( LINGUA_SEARCH_PATH) " \
490
+ @pot-create \
491
+ " $( LINGUA_SEARCH_PATH) " $( LINGUA_OPTIONS ) \
432
492
-o " $( GETTEXT_LOCALES_PATH) /$( GETTEXT_DOMAIN) .pot"
433
493
434
494
PHONY : lingua
@@ -440,13 +500,17 @@ lingua-dirty:
440
500
441
501
.PHONY : lingua-clean
442
502
lingua-clean : lingua-dirty
443
- @test -e $(MXENV_PATH ) pip && $(MXENV_PATH ) pip uninstall -y \
503
+ @test -e $(MXENV_PYTHON ) && $(MXENV_PYTHON ) -m pip uninstall -y \
444
504
chameleon lingua $(LINGUA_PLUGINS ) || :
445
505
446
506
INSTALL_TARGETS+ =$(LINGUA_TARGET )
447
507
DIRTY_TARGETS+ =lingua-dirty
448
508
CLEAN_TARGETS+ =lingua-clean
449
509
510
+ # #############################################################################
511
+ # Custom includes
512
+ # #############################################################################
513
+
450
514
-include $(INCLUDE_MAKEFILE )
451
515
452
516
# #############################################################################
0 commit comments