Marcel Telka
2022-11-14 06c6b6f27d77b946e60d6593a9691dd3b9ddfaa5
make-rules: dependency detection for tox based tests

4 files modified
78 ■■■■ changed files
make-rules/environment.mk 20 ●●●●● patch | view | raw | blame | history
make-rules/setup.py.mk 40 ●●●● patch | view | raw | blame | history
make-rules/shared-macros.mk 1 ●●●● patch | view | raw | blame | history
tools/python-requires 17 ●●●● patch | view | raw | blame | history
make-rules/environment.mk
@@ -58,6 +58,24 @@
          [ $$RETVAL -ne 7 ] && echo "pkg install returned $$RETVAL" && exit 1; \
          sleep 10; \
        done; }
component-test-environment-check:: component-environment-check
    $(call separator-line,Required Additional Packages Needed for Testing Only)
    @[ -z "$(strip $(TEST_REQUIRED_PACKAGES))" ] || /usr/bin/pkg list -vH $(TEST_REQUIRED_PACKAGES:%=/%)
    $(call separator-line)
component-test-environment-prep::
    @[ -z "$(strip $(TEST_REQUIRED_PACKAGES))" ] || /usr/bin/pkg list -vH $(TEST_REQUIRED_PACKAGES:%=/%) >/dev/null || \
        { echo "Adding required packages to testing environment..."; \
        while true ; do \
          $(PFEXEC) /usr/bin/pkg install --accept -v $(TEST_REQUIRED_PACKAGES:%=/%) ; \
          RETVAL=$$? ; \
          [ $$RETVAL -eq 0 ] && break; \
          [ $$RETVAL -eq 4 ] && break; \
          [ $$RETVAL -ne 7 ] && echo "pkg install returned $$RETVAL" && exit 1; \
          sleep 10; \
        done; }
ZONENAME_PREFIX = bz
ZONENAME_ID = $(shell echo "$(WS_TOP)" | sha1sum | cut -c0-7)-$(COMPONENT_NAME)
ZONENAME = $(ZONENAME_PREFIX)-$(ZONENAME_ID)
@@ -118,3 +136,5 @@
# Short aliases for user convenience
env-check:: component-environment-check
env-prep:: component-environment-prep
test-env-check:: component-test-environment-check
test-env-prep:: component-test-environment-prep
make-rules/setup.py.mk
@@ -207,6 +207,10 @@
    done ;
endif
# Make sure the .depend-test file exists in a case the test style below does
# not provide its own recipe.
COMPONENT_POST_INSTALL_ACTION +=    $(TOUCH) $(@D)/.depend-test ;
# Define Python version specific filenames for tests.
ifeq ($(strip $(USE_COMMON_TEST_MASTER)),no)
COMPONENT_TEST_MASTER =    $(COMPONENT_TEST_RESULTS_DIR)/results-$(PYTHON_VERSION).master
@@ -220,7 +224,8 @@
# Normalize Python test results.
COMPONENT_TEST_TRANSFORMS += "-e 's/^\(Ran [0-9]\{1,\} tests\) in .*$$/\1/'"    # delete timing from test results
COMPONENT_TEST_DEP =    $(BUILD_DIR)/%/.built
COMPONENT_TEST_DEP +=    component-test-environment-prep
COMPONENT_TEST_DEP +=    $(BUILD_DIR)/%/.built
# determine the type of tests we want to run.
ifeq ($(strip $(wildcard $(COMPONENT_TEST_RESULTS_DIR)/results-*.master)),)
@@ -289,6 +294,21 @@
# tox package together with the tox-current-env plugin is needed
USERLAND_REQUIRED_PACKAGES += library/python/tox
USERLAND_REQUIRED_PACKAGES += library/python/tox-current-env
# Generate raw lists of test dependencies per Python version
COMPONENT_POST_INSTALL_ACTION += \
    cd $(@D) ; \
    ( $(COMPONENT_TEST_CMD) -qq --print-deps-to=- $(COMPONENT_TEST_TARGETS) \
        | while read l ; do \
            [ "$${l:0:2}" == "-r" ] && $(CAT) $${l\#-r} && continue ; \
            echo "$$l" ; \
        done \
        | $(GSED) -e 's/\#.*//' -e $$'s/^[ \t]*//' -e '/^$$/d' \
            -e 's/^\([a-zA-Z0-9]\([a-zA-Z0-9._-]*[a-zA-Z0-9]\)\{0,1\}\).*/\1/' ; \
    for e in $(shell $(COMPONENT_TEST_CMD) -qq --print-extras-to=- $(COMPONENT_TEST_TARGETS)) ; do \
        PYTHONPATH=$(PROTO_DIR)/$(PYTHON_DIR)/site-packages:$(PROTO_DIR)/$(PYTHON_LIB) \
            $(PYTHON) $(WS_TOOLS)/python-requires $(COMPONENT_NAME) $$e ; \
    done ) | $(GSED) -e '/^tox\(-current-env\)\?$$/d' > $(@D)/.depend-test ;
else ifeq ($(strip $(TEST_STYLE)),pytest)
COMPONENT_TEST_CMD =        $(PYTHON) -m pytest
COMPONENT_TEST_ARGS =
@@ -390,15 +410,25 @@
# Generate raw lists of runtime dependencies per Python version
COMPONENT_POST_INSTALL_ACTION += \
     PYTHONPATH=$(PROTO_DIR)/$(PYTHON_DIR)/site-packages:$(PROTO_DIR)/$(PYTHON_LIB) \
    PYTHONPATH=$(PROTO_DIR)/$(PYTHON_DIR)/site-packages:$(PROTO_DIR)/$(PYTHON_LIB) \
        $(PYTHON) $(WS_TOOLS)/python-requires $(COMPONENT_NAME) > $(@D)/.depend-runtime ;
# Convert raw per version lists of runtime dependencies to single resolved
# runtime dependency list
$(BUILD_DIR)/META.depend-runtime.res:    $(INSTALL_TARGET)
    $(CAT) $(INSTALL_TARGET:%.installed=%.depend-runtime) | LC_ALL=C $(GSORT) -u \
# runtime dependency list.  The dependency on META.depend-test.required here is
# purely to get the file created as a side effect of this target.
$(BUILD_DIR)/META.depend-runtime.res:    $(INSTALL_$(MK_BITS)) $(BUILD_DIR)/META.depend-test.required
    $(CAT) $(INSTALL_$(MK_BITS):%.installed=%.depend-runtime) | LC_ALL=C $(GSORT) -u \
        | $(GSED) -e 's/.*/depend type=require fmri=pkg:\/library\/python\/&-$$(PYV)/' > $@
# Convert raw per version lists of test dependencies to single list of
# TEST_REQUIRED_PACKAGES entries
$(BUILD_DIR)/META.depend-test.required:    $(INSTALL_$(MK_BITS))
    $(CAT) $(INSTALL_$(MK_BITS):%.installed=%.depend-test) | LC_ALL=C $(GSORT) -u \
        | $(GSED) -e 's/.*/TEST_REQUIRED_PACKAGES.python += library\/python\/&/' > $@
# Add META.depend-test.required to the generated list of REQUIRED_PACKAGES
REQUIRED_PACKAGES_TRANSFORM += -e '$$r $(BUILD_DIR)/META.depend-test.required'
# The python-requires script requires importlib_metadata for Python 3.7 to
# provide useful output.  Since we do fake bootstrap for Python 3.7 we require
# the package here unconditionally.
make-rules/shared-macros.mk
@@ -1310,6 +1310,7 @@
# Generate requirements on all built python version variants for given packages
USERLAND_REQUIRED_PACKAGES += $(foreach ver,$(PYTHON_VERSIONS),$(PYTHON_USERLAND_REQUIRED_PACKAGES:%=%-$(shell echo $(ver) | tr -d .)))
REQUIRED_PACKAGES += $(foreach ver,$(PYTHON_VERSIONS),$(PYTHON_REQUIRED_PACKAGES:%=%-$(shell echo $(ver) | tr -d .)))
TEST_REQUIRED_PACKAGES += $(foreach ver,$(PYTHON_VERSIONS),$(TEST_REQUIRED_PACKAGES.python:%=%-$(shell echo $(ver) | tr -d .)))
# Generate requirements on all built perl version variants for given packages
REQUIRED_PACKAGES += $(foreach ver,$(PERL_VERSIONS),$(PERL_REQUIRED_PACKAGES:%=%-$(shell echo $(ver) | tr -d .)))
tools/python-requires
@@ -17,6 +17,7 @@
#
# Print requirements for a package.
# Evaluated and normalized.
# With optional EXTRA parameter passed print requirements for such extra only.
#
import sys
@@ -35,13 +36,19 @@
if len(sys.argv) < 2:
    exit()
e = {'extra': sys.argv[2]} if len(sys.argv) > 2 else None
# packaging up to 21.3 raises UndefinedEnvironmentName when extra is not
# defined in environment, but marker contains it.  This should change in new
# packaging once released.  See https://github.com/pypa/packaging/pull/550.  To
# workaround this (so we do not need to handle exceptions) we pass empty extra
# in environment when we do not want any extra.
noe = {'extra': ''}
try:
    for req in requires(sys.argv[1]):
        r = Requirement(req)
        try:
            if not r.marker or r.marker.evaluate():
                print(re.sub(r"[-_.]+", "-", r.name).lower())
        except UndefinedEnvironmentName:
            pass
        m = r.marker
        if (not m and not e) or m and ((not e and m.evaluate(noe)) or (e and not m.evaluate(noe) and m.evaluate(e))):
            print(re.sub(r"[-_.]+", "-", r.name).lower())
except:
    pass