From 60ddc971d2d1df5133753dfaad5a07a3a225012e Mon Sep 17 00:00:00 2001 From: Jan Lindemann Date: Sun, 6 Sep 2026 21:43:17 +0200 Subject: [PATCH 1/6] make: Support INSTALL_PREFIXDIR During "make install", the packaging machinery should run "$(LOG_INSTALL) -D /opt/" but runs "mkdir -p /opt/" instead. As a consequence, the created directory is not owned by any of the created packages. This commit fixes that by introducing INSTALL_PREFIXDIR and installing it like all other directories. Signed-off-by: Jan Lindemann --- make/defs-dev.mk | 1 + make/defs-dist.mk | 1 + make/defs.mk | 2 ++ make/include.mk | 2 +- make/make.mk | 2 +- make/scripts-targets.mk | 2 +- make/so.mk | 2 +- make/yapp.mk | 2 +- 8 files changed, 9 insertions(+), 5 deletions(-) diff --git a/make/defs-dev.mk b/make/defs-dev.mk index 869ad322..db895eb8 100644 --- a/make/defs-dev.mk +++ b/make/defs-dev.mk @@ -31,6 +31,7 @@ LOG_PREFIX ?= $(PREFIX)/log JAVA_PREFIX ?= $(PREFIX) HDR_SCOPE_PREFIX ?= +INSTALL_PREFIXDIR ?= $(PREFIX) DATA_DIR ?= $(FLAVOUR_PATH_PREFIX)$(PREFIX)/data IMAGEDIR ?= $(DATA_DIR)/images JSON_DIR ?= $(DATA_DIR)/json diff --git a/make/defs-dist.mk b/make/defs-dist.mk index 03dc3574..83981fd4 100644 --- a/make/defs-dist.mk +++ b/make/defs-dist.mk @@ -31,6 +31,7 @@ LOG_PREFIX ?= $(ENV_PREFIX)/var/log JAVA_PREFIX ?= $(PREFIX) HDR_SCOPE_PREFIX ?= +INSTALL_PREFIXDIR ?= $(PREFIX) DATA_DIR ?= $(FLAVOUR_PATH_PREFIX)$(PREFIX)/data IMAGEDIR ?= $(DATA_DIR)/images JSON_DIR ?= $(DATA_DIR)/json diff --git a/make/defs.mk b/make/defs.mk index 25f014b0..2eb295f4 100644 --- a/make/defs.mk +++ b/make/defs.mk @@ -307,6 +307,8 @@ LOCAL_MKFILES ?= $(wildcard GNUmakefile makefile Makefile *.mk) LOG_QUAL_PREFIX ?= $(LOGID): # -- standard dirs and files for build and install +INSTALLATION_FILE_TYPES += PREFIX + # -- CFG INSTALLATION_FILE_TYPES += CFG CONFIG_FILE ?= $(CONFIG_DIR)/$(PROJECT).conf diff --git a/make/include.mk b/make/include.mk index b98dec5f..948fc05b 100644 --- a/make/include.mk +++ b/make/include.mk @@ -8,7 +8,7 @@ SRC_H += $(PROJ_H) $(wildcard $(HDRDIR_SCOPE_SUFFIX)/*.h) # mandatory targets all: $(PROJ_H) clean: clean.include -install: install_HDR +install: install_dir_PREFIX install_HDR # not wäry naaice ifneq ($(HDRDIR_SCOPE_SUFFIX),) diff --git a/make/make.mk b/make/make.mk index d71ca4d8..c540c447 100644 --- a/make/make.mk +++ b/make/make.mk @@ -31,7 +31,7 @@ endif ifeq ($(CREATE_PKG_CONFIG),true) all: build_PKG_CONFIG endif -install: $(DEVEL_TARGETS) +install: install_dir_PREFIX $(DEVEL_TARGETS) clean: textclean localclean doneclean clean.pkg-config test: all diff --git a/make/scripts-targets.mk b/make/scripts-targets.mk index 4b0a35d8..f59c86f3 100644 --- a/make/scripts-targets.mk +++ b/make/scripts-targets.mk @@ -1,5 +1,5 @@ all: build_EXE build_CGI -install: install_files_INIT install_EXE install_files_CGI install_files_SYSCFG +install: install_dir_PREFIX install_files_INIT install_EXE install_files_CGI install_files_SYSCFG clean:allclean localclean doneclean textclean clean.init test: all diff --git a/make/so.mk b/make/so.mk index 333b8dfa..e6594b95 100644 --- a/make/so.mk +++ b/make/so.mk @@ -18,7 +18,7 @@ include $(JWBDIR)/make/rules.mk all: $(SHOBJS) $(BUILD_SHOBJS) clean: objclean textclean localclean profclean -install: $(ALL) install_dir_LIB installso +install: $(ALL) install_dir_PREFIX install_dir_LIB installso $(BUILD_LIBDIR)/%.so: %.so install -m 755 $< $@ diff --git a/make/yapp.mk b/make/yapp.mk index 42fd2fd0..26371559 100644 --- a/make/yapp.mk +++ b/make/yapp.mk @@ -13,7 +13,7 @@ endif include $(JWBDIR)/make/exe.mk all: build_EXE -install: install_EXE +install: install_dir_PREFIX install_EXE clean: clean.yapp distclean: From fe2ae06367da8012fdcb2f23a66f557f038d3171 Mon Sep 17 00:00:00 2001 From: Jan Lindemann Date: Mon, 7 Sep 2026 05:33:33 +0200 Subject: [PATCH 2/6] make: Fix CONFIG_SUBDIR The existence of CONFIG_SUBDIR hijacks INSTALL_CFGDIR to a subdirectory (by default /etc/opt//$(CONFIG_SUBDIR)). Then std_install_rules apply, and (the bent) INSTALL_CFGDIR is installed, but its parent directory, the original $(INSTALL_CFGDIR), is not a prerequisite of install anylonger, and has no rule anymore, hence log-install is never run for it. Instead it's implicitly created by log-install -D $(INSTALL_CFGDIR). This commit gives /etc/opt/ std-install rule and variables back as CFGTOPDIR variants, and inserts it early into the install target's prerequisite list. Signed-off-by: Jan Lindemann --- make/conf.mk | 19 +++++++++++++++---- make/defs-dev.mk | 3 +++ make/defs-dist.mk | 3 +++ make/defs.mk | 1 + 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/make/conf.mk b/make/conf.mk index 651ceb76..856770b7 100644 --- a/make/conf.mk +++ b/make/conf.mk @@ -4,15 +4,26 @@ include $(JWBDIR)/make/dev-utils.mk all: clean: clean.conf -install: install_CFG install_files_SYSCFG install_files_LOGROT install_files_CRONTAB install_files_RSYSLOG \ - install_files_APACHE_CONF install_files_SYSTEMD install_files_INIT install_files_TMPFILES $(CONF_D) +install: \ + $(INSTALL_CFGTOPDIR) \ + install_CFG \ + install_files_SYSCFG \ + install_files_LOGROT \ + install_files_CRONTAB \ + install_files_RSYSLOG \ + install_files_APACHE_CONF \ + install_files_SYSTEMD \ + install_files_INIT \ + install_files_TMPFILES \ + $(CONF_D) test: all clean.conf: $(RM) -rf *~ .*.swp *.done -ifneq ($(CONFIG_SUBDIR),) -$(INSTALLED_CFG): $(INSTALL_CFGDIR) +ifneq ($(INSTALL_CFGTOPDIR),) +$(INSTALL_CFGTOPDIR): + $(INSTALL) -D -d -m $(CFGTOPDIRMODE) -o $(CFGTOPDIROWNER) -g $(CFGTOPDIRGROUP) $@ endif ifneq ($(CONF_D),) diff --git a/make/defs-dev.mk b/make/defs-dev.mk index db895eb8..15aa29da 100644 --- a/make/defs-dev.mk +++ b/make/defs-dev.mk @@ -72,6 +72,9 @@ CFGMODE ?= 660 CFGDIROWNER ?= $(EXEDIROWNER) CFGDIRGROUP ?= $(EXEDIRGROUP) CFGDIRMODE ?= $(EXEDIRMODE) +CFGTOPDIROWNER ?= $(CFGDIROWNER) +CFGTOPDIRGROUP ?= $(CFGDIRGROUP) +CFGTOPDIRMODE ?= $(CFGDIRMODE) SYSCFGOWNER ?= $(CFGOWNER) SYSCFGGROUP ?= $(CFGGROUP) SYSCFGMODE ?= $(CFGMODE) diff --git a/make/defs-dist.mk b/make/defs-dist.mk index 83981fd4..bb1602cb 100644 --- a/make/defs-dist.mk +++ b/make/defs-dist.mk @@ -72,6 +72,9 @@ CFGMODE ?= 664 CFGDIROWNER ?= $(EXEDIROWNER) CFGDIRGROUP ?= $(EXEDIRGROUP) CFGDIRMODE ?= $(EXEDIRMODE) +CFGTOPDIROWNER ?= $(CFGDIROWNER) +CFGTOPDIRGROUP ?= $(CFGDIRGROUP) +CFGTOPDIRMODE ?= $(CFGDIRMODE) SYSCFGOWNER ?= $(CFGOWNER) SYSCFGGROUP ?= $(CFGGROUP) SYSCFGMODE ?= $(CFGMODE) diff --git a/make/defs.mk b/make/defs.mk index 2eb295f4..7e778b07 100644 --- a/make/defs.mk +++ b/make/defs.mk @@ -316,6 +316,7 @@ BUILD_CFGDIR = $(TOPDIR)/conf ifeq ($(CONFIG_SUBDIR),) INSTALL_CFGDIR ?= $(CONFIG_DIR) else + INSTALL_CFGTOPDIR ?= $(CONFIG_DIR) INSTALL_CFGDIR ?= $(CONFIG_DIR)/$(CONFIG_SUBDIR) endif LOCAL_CFG ?= $(filter-out %.site.conf, $(filter-out rsyslog-%, $(wildcard *.conf *.xml *.bprof *.jw-tmpl *.ini *.yaml *.toml))) $(LOCAL_EXTRA_CFG) From ff6e13e09ff075dec6648080d1eb4b67184e8391 Mon Sep 17 00:00:00 2001 From: Jan Lindemann Date: Mon, 7 Sep 2026 06:43:56 +0200 Subject: [PATCH 3/6] lib.Types: Read __abstractmethods__ via getattr() LoadTypes._classes() reads the __abstractmethods__ attribute of each class that inspect.getmembers() returns for its debug output. mypy 2.2.0 allows this, mypy 2.3.1 doesn't: It now types those classes as type[object] instead of Any. The attribute itself is only declared on the ABCMeta metaclass, so the direct access fails the type check. Read the attribute through getattr() with an 'unknown' fallback string, and annotate the variable explicitly. The runtime behavior is unchanged, since the attribute exists whenever inspect.isabstract() is true, and the call satisfies the checker. Assisted-by: unsloth/Qwen3.8-27B-GGUF:Q4_K_M with pi.dev v0.84.2 Signed-off-by: user.email --- src/python/jw/pkg/lib/Types.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/python/jw/pkg/lib/Types.py b/src/python/jw/pkg/lib/Types.py index bfae01ad..344da9ca 100644 --- a/src/python/jw/pkg/lib/Types.py +++ b/src/python/jw/pkg/lib/Types.py @@ -102,7 +102,10 @@ class LoadTypes(Types[T]): # export self._debug(f'o "{name}" has wrong name') continue if inspect.isabstract(c): - self._debug(f'o "{name}" is abstract: {c.__abstractmethods__}') + abstract: frozenset[str] = getattr( + c, '__abstractmethods__', frozenset() + ) + self._debug(f'o "{name}" is abstract: {abstract}') continue if self.__type_filter: for tp in self.__type_filter: From 281a8f383e9a70357b4baa247e82ce1414b6b0d4 Mon Sep 17 00:00:00 2001 From: Jan Lindemann Date: Mon, 7 Sep 2026 09:06:40 +0200 Subject: [PATCH 4/6] lib.Types: Restrict LoadTypes to ABC-derived classes The previous commit reads __abstractmethods__ via a getattr() with an empty frozenset fallback, because in mypy 2.3.1 the scanned classes are typed as type[object], which does not declare the attribute. Add is_abc_class() as a TypeGuard, and skip the classes it rejects with a debug line: LoadTypes now yields only ABC-derived classes. The guard narrows to the classes that carry the attribute, so that the debug line can now read __abstractmethods__ directly. The command loaders are unaffected: every class they load is derived from AbstractCmd, and hence from ABC. For loads that rely on the name filter alone, plain classes are now skipped instead of being yielded. Assisted-by: unsloth/Qwen3.8-27B-GGUF:Q4_K_M with pi.dev v0.84.2 Signed-off-by: Jan Lindemann --- src/python/jw/pkg/lib/Types.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/python/jw/pkg/lib/Types.py b/src/python/jw/pkg/lib/Types.py index 344da9ca..6b27ea85 100644 --- a/src/python/jw/pkg/lib/Types.py +++ b/src/python/jw/pkg/lib/Types.py @@ -5,7 +5,7 @@ import os import re import sys -from typing import TYPE_CHECKING, Any, Generic, Iterable, TypeVar, override +from typing import TYPE_CHECKING, Any, Generic, Iterable, TypeGuard, TypeVar, override from .log import ERR, OFF, log, parse_log_level @@ -15,6 +15,9 @@ if TYPE_CHECKING: T = TypeVar('T') +def is_abc_class(c: type[object]) -> TypeGuard[abc.ABCMeta]: + return isinstance(c, abc.ABCMeta) + class Types(abc.ABC, Iterable[type[T]], Generic[T]): # export @override @@ -101,11 +104,11 @@ class LoadTypes(Types[T]): # export if rx is not None and not re.match(rx, member_name): self._debug(f'o "{name}" has wrong name') continue + if not is_abc_class(c): + self._debug(f'o "{name}" is not derived from ABCMeta') + continue if inspect.isabstract(c): - abstract: frozenset[str] = getattr( - c, '__abstractmethods__', frozenset() - ) - self._debug(f'o "{name}" is abstract: {abstract}') + self._debug(f'o "{name}" is abstract: {c.__abstractmethods__}') continue if self.__type_filter: for tp in self.__type_filter: From ddf310d3ad4db095a72c8e9e15e44ff2dc463b31 Mon Sep 17 00:00:00 2001 From: Jan Lindemann Date: Sun, 6 Sep 2026 21:43:17 +0200 Subject: [PATCH 5/6] make: Support INSTALL_PREFIXDIR During "make install", the packaging machinery should run "$(LOG_INSTALL) -D /opt/" but runs "mkdir -p /opt/" instead. As a consequence, the created directory is not owned by any of the created packages. This commit fixes that by introducing INSTALL_PREFIXDIR and installing it like all other directories. Signed-off-by: Jan Lindemann --- make/defs-dev.mk | 1 + make/defs-dist.mk | 1 + make/defs.mk | 2 ++ make/include.mk | 2 +- make/make.mk | 2 +- make/scripts-targets.mk | 2 +- make/so.mk | 2 +- make/yapp.mk | 2 +- 8 files changed, 9 insertions(+), 5 deletions(-) diff --git a/make/defs-dev.mk b/make/defs-dev.mk index 869ad322..db895eb8 100644 --- a/make/defs-dev.mk +++ b/make/defs-dev.mk @@ -31,6 +31,7 @@ LOG_PREFIX ?= $(PREFIX)/log JAVA_PREFIX ?= $(PREFIX) HDR_SCOPE_PREFIX ?= +INSTALL_PREFIXDIR ?= $(PREFIX) DATA_DIR ?= $(FLAVOUR_PATH_PREFIX)$(PREFIX)/data IMAGEDIR ?= $(DATA_DIR)/images JSON_DIR ?= $(DATA_DIR)/json diff --git a/make/defs-dist.mk b/make/defs-dist.mk index 03dc3574..83981fd4 100644 --- a/make/defs-dist.mk +++ b/make/defs-dist.mk @@ -31,6 +31,7 @@ LOG_PREFIX ?= $(ENV_PREFIX)/var/log JAVA_PREFIX ?= $(PREFIX) HDR_SCOPE_PREFIX ?= +INSTALL_PREFIXDIR ?= $(PREFIX) DATA_DIR ?= $(FLAVOUR_PATH_PREFIX)$(PREFIX)/data IMAGEDIR ?= $(DATA_DIR)/images JSON_DIR ?= $(DATA_DIR)/json diff --git a/make/defs.mk b/make/defs.mk index 25f014b0..2eb295f4 100644 --- a/make/defs.mk +++ b/make/defs.mk @@ -307,6 +307,8 @@ LOCAL_MKFILES ?= $(wildcard GNUmakefile makefile Makefile *.mk) LOG_QUAL_PREFIX ?= $(LOGID): # -- standard dirs and files for build and install +INSTALLATION_FILE_TYPES += PREFIX + # -- CFG INSTALLATION_FILE_TYPES += CFG CONFIG_FILE ?= $(CONFIG_DIR)/$(PROJECT).conf diff --git a/make/include.mk b/make/include.mk index b98dec5f..948fc05b 100644 --- a/make/include.mk +++ b/make/include.mk @@ -8,7 +8,7 @@ SRC_H += $(PROJ_H) $(wildcard $(HDRDIR_SCOPE_SUFFIX)/*.h) # mandatory targets all: $(PROJ_H) clean: clean.include -install: install_HDR +install: install_dir_PREFIX install_HDR # not wäry naaice ifneq ($(HDRDIR_SCOPE_SUFFIX),) diff --git a/make/make.mk b/make/make.mk index d71ca4d8..c540c447 100644 --- a/make/make.mk +++ b/make/make.mk @@ -31,7 +31,7 @@ endif ifeq ($(CREATE_PKG_CONFIG),true) all: build_PKG_CONFIG endif -install: $(DEVEL_TARGETS) +install: install_dir_PREFIX $(DEVEL_TARGETS) clean: textclean localclean doneclean clean.pkg-config test: all diff --git a/make/scripts-targets.mk b/make/scripts-targets.mk index 4b0a35d8..f59c86f3 100644 --- a/make/scripts-targets.mk +++ b/make/scripts-targets.mk @@ -1,5 +1,5 @@ all: build_EXE build_CGI -install: install_files_INIT install_EXE install_files_CGI install_files_SYSCFG +install: install_dir_PREFIX install_files_INIT install_EXE install_files_CGI install_files_SYSCFG clean:allclean localclean doneclean textclean clean.init test: all diff --git a/make/so.mk b/make/so.mk index 333b8dfa..e6594b95 100644 --- a/make/so.mk +++ b/make/so.mk @@ -18,7 +18,7 @@ include $(JWBDIR)/make/rules.mk all: $(SHOBJS) $(BUILD_SHOBJS) clean: objclean textclean localclean profclean -install: $(ALL) install_dir_LIB installso +install: $(ALL) install_dir_PREFIX install_dir_LIB installso $(BUILD_LIBDIR)/%.so: %.so install -m 755 $< $@ diff --git a/make/yapp.mk b/make/yapp.mk index 42fd2fd0..26371559 100644 --- a/make/yapp.mk +++ b/make/yapp.mk @@ -13,7 +13,7 @@ endif include $(JWBDIR)/make/exe.mk all: build_EXE -install: install_EXE +install: install_dir_PREFIX install_EXE clean: clean.yapp distclean: From f33f47c2b38ce78948a7dfb1095bbb8430460d9e Mon Sep 17 00:00:00 2001 From: Jan Lindemann Date: Mon, 7 Sep 2026 05:33:33 +0200 Subject: [PATCH 6/6] make: Fix CONFIG_SUBDIR The existence of CONFIG_SUBDIR hijacks INSTALL_CFGDIR to a subdirectory (by default /etc/opt//$(CONFIG_SUBDIR)). Then std_install_rules apply, and (the bent) INSTALL_CFGDIR is installed, but its parent directory, the original $(INSTALL_CFGDIR), is not a prerequisite of install anylonger, and has no rule anymore, hence log-install is never run for it. Instead it's implicitly created by log-install -D $(INSTALL_CFGDIR). This commit gives /etc/opt/ std-install rule and variables back as CFGTOPDIR variants, and inserts it early into the install target's prerequisite list. Signed-off-by: Jan Lindemann --- make/conf.mk | 19 +++++++++++++++---- make/defs-dev.mk | 3 +++ make/defs-dist.mk | 3 +++ make/defs.mk | 1 + 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/make/conf.mk b/make/conf.mk index 651ceb76..856770b7 100644 --- a/make/conf.mk +++ b/make/conf.mk @@ -4,15 +4,26 @@ include $(JWBDIR)/make/dev-utils.mk all: clean: clean.conf -install: install_CFG install_files_SYSCFG install_files_LOGROT install_files_CRONTAB install_files_RSYSLOG \ - install_files_APACHE_CONF install_files_SYSTEMD install_files_INIT install_files_TMPFILES $(CONF_D) +install: \ + $(INSTALL_CFGTOPDIR) \ + install_CFG \ + install_files_SYSCFG \ + install_files_LOGROT \ + install_files_CRONTAB \ + install_files_RSYSLOG \ + install_files_APACHE_CONF \ + install_files_SYSTEMD \ + install_files_INIT \ + install_files_TMPFILES \ + $(CONF_D) test: all clean.conf: $(RM) -rf *~ .*.swp *.done -ifneq ($(CONFIG_SUBDIR),) -$(INSTALLED_CFG): $(INSTALL_CFGDIR) +ifneq ($(INSTALL_CFGTOPDIR),) +$(INSTALL_CFGTOPDIR): + $(INSTALL) -D -d -m $(CFGTOPDIRMODE) -o $(CFGTOPDIROWNER) -g $(CFGTOPDIRGROUP) $@ endif ifneq ($(CONF_D),) diff --git a/make/defs-dev.mk b/make/defs-dev.mk index db895eb8..15aa29da 100644 --- a/make/defs-dev.mk +++ b/make/defs-dev.mk @@ -72,6 +72,9 @@ CFGMODE ?= 660 CFGDIROWNER ?= $(EXEDIROWNER) CFGDIRGROUP ?= $(EXEDIRGROUP) CFGDIRMODE ?= $(EXEDIRMODE) +CFGTOPDIROWNER ?= $(CFGDIROWNER) +CFGTOPDIRGROUP ?= $(CFGDIRGROUP) +CFGTOPDIRMODE ?= $(CFGDIRMODE) SYSCFGOWNER ?= $(CFGOWNER) SYSCFGGROUP ?= $(CFGGROUP) SYSCFGMODE ?= $(CFGMODE) diff --git a/make/defs-dist.mk b/make/defs-dist.mk index 83981fd4..bb1602cb 100644 --- a/make/defs-dist.mk +++ b/make/defs-dist.mk @@ -72,6 +72,9 @@ CFGMODE ?= 664 CFGDIROWNER ?= $(EXEDIROWNER) CFGDIRGROUP ?= $(EXEDIRGROUP) CFGDIRMODE ?= $(EXEDIRMODE) +CFGTOPDIROWNER ?= $(CFGDIROWNER) +CFGTOPDIRGROUP ?= $(CFGDIRGROUP) +CFGTOPDIRMODE ?= $(CFGDIRMODE) SYSCFGOWNER ?= $(CFGOWNER) SYSCFGGROUP ?= $(CFGGROUP) SYSCFGMODE ?= $(CFGMODE) diff --git a/make/defs.mk b/make/defs.mk index 2eb295f4..7e778b07 100644 --- a/make/defs.mk +++ b/make/defs.mk @@ -316,6 +316,7 @@ BUILD_CFGDIR = $(TOPDIR)/conf ifeq ($(CONFIG_SUBDIR),) INSTALL_CFGDIR ?= $(CONFIG_DIR) else + INSTALL_CFGTOPDIR ?= $(CONFIG_DIR) INSTALL_CFGDIR ?= $(CONFIG_DIR)/$(CONFIG_SUBDIR) endif LOCAL_CFG ?= $(filter-out %.site.conf, $(filter-out rsyslog-%, $(wildcard *.conf *.xml *.bprof *.jw-tmpl *.ini *.yaml *.toml))) $(LOCAL_EXTRA_CFG)