From 80f3a1492e4a757596244989231dc6af5bf920dc Mon Sep 17 00:00:00 2001 From: Julien Muchembled Date: Sat, 19 Oct 2024 03:06:55 +0200 Subject: [PATCH] Switch to hatchling Because of https://github.com/pypa/pip/issues/10978, `make install` is currently unable to install the Python code to a custom prefix (PREFIX). --- .gitignore | 14 ------ Makefile | 10 ++--- debian/common.mk | 8 +--- debian/compat | 1 - debian/control | 10 ++--- debian/rules | 17 +++++--- demo/.gitignore | 9 ++++ hatch_build.py | 36 ++++++++++++++++ pyproject.toml | 53 +++++++++++++++++++++++ setup.py | 109 ----------------------------------------------- 10 files changed, 119 insertions(+), 148 deletions(-) delete mode 100644 debian/compat create mode 100644 demo/.gitignore create mode 100644 hatch_build.py create mode 100644 pyproject.toml delete mode 100644 setup.py diff --git a/.gitignore b/.gitignore index 61ce9013..178135c2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1 @@ -*.pyc -*.pyo -*.swp -*~ -/build/ /dist/ -/re6stnet.egg-info/ -*.log -*.pid -*.db -*.state -*.crt -*.pem -demo/mbox -*.sock diff --git a/Makefile b/Makefile index dabba733..d340c924 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,9 @@ DESTDIR = / +# https://github.com/pypa/pip/issues/10978 PREFIX = /usr/local MANDIR = $(PREFIX)/share/man -UNITDIR = /lib/systemd/system -PYTHON = $(or $(shell command -v python2),python) +UNITDIR = $(PREFIX)/lib/systemd/system +PIP_INSTALL = python3 -m pip install MANPAGELIST := $(patsubst %,docs/%,re6st-conf.1 re6st-registry.1 re6stnet.8) @@ -18,7 +19,7 @@ install: install-noinit install-noinit: install-man set -e $(DESTDIR)$(PREFIX) /bin/re6stnet; [ -x $$1$$2 ] || \ - $(PYTHON) setup.py install --prefix=$(PREFIX) --root=$(DESTDIR); \ + { [ "$(PREFIX)" = /usr/local ]; $(PIP_INSTALL) --root=$(DESTDIR) .; }; \ install -d $$1/sbin; mv $$1$$2 $$1/sbin install -Dpm 0644 daemon/README.conf $(DESTDIR)/etc/re6stnet/README install -Dpm 0644 daemon/logrotate.conf $(DESTDIR)/etc/logrotate.d/re6stnet @@ -29,5 +30,4 @@ install-man: $(MANPAGELIST) done clean: - find -name '*.pyc' -delete - rm -rf build dist re6stnet.egg-info $(MANPAGELIST) + find -name __pycache__ -print0 |xargs -0 rm -rf dist $(MANPAGELIST) diff --git a/debian/common.mk b/debian/common.mk index d6b49532..205e6012 100644 --- a/debian/common.mk +++ b/debian/common.mk @@ -15,10 +15,4 @@ debian/changelog: echo "$$CHANGELOG" >$@ endif -override_dh_install: - make DESTDIR=$(TMP) PREFIX=/usr install - -# BBB: compat < 10 ; https://bugs.debian.org/879727 -override_dh_systemd_start: - dh_systemd_start --restart-after-upgrade - sed -i 's/_dh_action=try-restart/_dh_action=restart; for x in re6stnet re6st-registry; do systemctl is-enabled --quiet $$x.service || &; done/' debian/$(PACKAGE).postinst.debhelper +override_dh_auto_test: diff --git a/debian/compat b/debian/compat deleted file mode 100644 index ec635144..00000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/debian/control b/debian/control index 23d3e0ab..fe17fbb6 100644 --- a/debian/control +++ b/debian/control @@ -2,15 +2,15 @@ Source: re6stnet Maintainer: Julien Muchembled Section: net Priority: optional -Build-Depends: debhelper (>= 9.20120909), debhelper (>= 10) | dh-systemd, python (>= 2.7), python-setuptools, python-docutils | python3-docutils +Build-Depends: debhelper-compat (= 13), pybuild-plugin-pyproject, python3, python3-hatchling, python3-docutils Standards-Version: 3.9.1 -X-Python-Version: >= 2.7 +X-Python3-Version: >= 3.11 Package: re6stnet Architecture: all -Depends: ${misc:Depends}, ${python:Depends}, python-pkg-resources, python-openssl (>= 0.13), openvpn (>= 2.4), openpvn (<< 2.5~), babeld (= v1.12.1-nxd3), iproute2 | iproute, openssl -Recommends: ${python:Recommends}, logrotate -Suggests: ${python:Suggests}, ndisc6 +Depends: ${misc:Depends}, ${python3:Depends}, python3-openssl (>= 0.13), openvpn (>= 2.4), openpvn (<< 2.5~), babeld (= 1.12.1+nxd3), iproute2, openssl +Recommends: ${python3:Recommends}, logrotate +Suggests: ${python3:Suggests}, ndisc6 Conflicts: re6st-node Replaces: re6st-node Description: resilient, scalable, IPv6 network application diff --git a/debian/rules b/debian/rules index cd4f1a68..f5b8d7d8 100755 --- a/debian/rules +++ b/debian/rules @@ -2,7 +2,7 @@ # -*- makefile -*- #export DH_VERBOSE=1 -VERSION = $(shell python re6st/version.py) +VERSION = $(shell python3 re6st/version.py) # In order to build DEB snapshot package whose version is derived from current # Git revision, the `debian/changelog` file must be generated automatically, @@ -13,15 +13,18 @@ build-package: debian/changelog include debian/common.mk -override_dh_python2: - sed -i /^miniupnpc$$/d `find $(TMP)/usr -name requires.txt` - dh_python2 --recommends=miniupnpc --suggests=geoip2 +override_dh_python3: + dh_python3 --no-guessing-deps --recommends=miniupnpc --suggests=geoip2 override_dh_auto_clean: + dh_auto_clean make clean -# Do not build twice ('setup.py install' builds automatically) -override_dh_auto_build: +override_dh_auto_install: + dh_auto_install + make DESTDIR=$(TMP) PREFIX=/usr install + find $(TMP)/usr -name 'ovpn-*' -print0 | \ + xargs -0 sed -i "1s,.*,#!/usr/bin/python3 -S," %: - dh $@ --with python2,systemd --buildsystem=python_distutils + dh $@ --with python3 --buildsystem=pybuild diff --git a/demo/.gitignore b/demo/.gitignore new file mode 100644 index 00000000..6c9a4fd5 --- /dev/null +++ b/demo/.gitignore @@ -0,0 +1,9 @@ +dnsmasq.leases +*.log +*.pid +*.db +*.state +*.crt +*.pem +/mbox +*.sock diff --git a/hatch_build.py b/hatch_build.py new file mode 100644 index 00000000..5a6076e9 --- /dev/null +++ b/hatch_build.py @@ -0,0 +1,36 @@ +import tempfile +from hatchling.builders.hooks.plugin.interface import BuildHookInterface +from hatchling.metadata.plugin.interface import MetadataHookInterface + +version = {"__file__": "re6st/version.py"} +with open(version["__file__"]) as f: + code = compile(f.read(), version["__file__"], 'exec') + exec(code, version) + + +class CustomMetadataHook(MetadataHookInterface): + + def update(self, metadata): + metadata['version'] = egg_version = "0.%(revision)s" % version + metadata['readme'] = { + 'content-type': 'text/x-rst', + 'text': ".. contents::\n\n" + open('README.rst').read() + + "\n" + open('CHANGES.rst').read() + """ + +Git Revision: %s == %s +""" % (egg_version, version["short"]), + } + + +class CustomBuildHook(BuildHookInterface): + + def initialize(self, _, build_data): + f = self.__version = tempfile.NamedTemporaryFile('w') + for x in sorted(version.items()): + if not x[0].startswith("_"): + f.write("%s = %r\n" % x) + f.flush() + build_data["force_include"][f.name] = version["__file__"] + + def finalize(self, *_): + self.__version.close() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..35e9f114 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,53 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "re6stnet" +description = "Resilient, Scalable, IPv6 Network" +authors = [ + { name = "Nexedi", email = "re6stnet@erp5.org" }, +] +license = { text = "GPL-2.0-or-later" } +classifiers = [ + "Environment :: Console", + "Operating System :: POSIX :: Linux", + "Topic :: Internet", + "Topic :: System :: Networking", +] +requires-python = ">= 3.11" +dependencies = [ + "pyOpenSSL >= 0.13", + "miniupnpc", +] +dynamic = ["readme", "version"] + +[project.optional-dependencies] +geoip = ["geoip2"] +multicast = ["PyYAML"] +test = ["mock", "nemu3", "unshare", "multiping"] + +[project.scripts] +re6st-conf = "re6st.cli.conf:main" +re6stnet = "re6st.cli.node:main" +re6st-registry = "re6st.cli.registry:main" + +[project.urls] +Homepage = "http://re6st.net" + +[tool.hatch.metadata.hooks.custom] + +[tool.hatch.build.hooks.custom] + +[tool.hatch.build] +include = [ + "/re6st", + "/docs", + "/*.rst", +] +exclude = [ + "/re6st/tests", +] + +[tool.hatch.build.targets.wheel] +only-packages = true diff --git a/setup.py b/setup.py deleted file mode 100644 index 5b8482af..00000000 --- a/setup.py +++ /dev/null @@ -1,109 +0,0 @@ -"""Resilient, Scalable, IPv6 Network -""" -import os, stat -from distutils.command.build_scripts import first_line_re -from setuptools import setup, find_packages -from setuptools.command import sdist as _sdist, build_py as _build_py -from distutils import log - -version = {"__file__": "re6st/version.py"} -with open(version["__file__"]) as f: - code = compile(f.read(), version["__file__"], 'exec') - exec(code, version) - -def copy_file(self, infile, outfile, *args, **kw): - if infile == version["__file__"]: - if not self.dry_run: - log.info("generating %s -> %s", infile, outfile) - with open(outfile, "w") as f: - for x in sorted(version.items()): - if not x[0].startswith("_"): - f.write("%s = %r\n" % x) - return outfile, 1 - elif isinstance(self, build_py) and \ - os.stat(infile).st_mode & stat.S_IEXEC: - if os.path.isdir(infile) and os.path.isdir(outfile): - return outfile, 0 - # Adjust interpreter of OpenVPN hooks. - with open(infile) as src: - first_line = src.readline() - m = first_line_re.match(first_line) - if m and not self.dry_run: - log.info("copying and adjusting %s -> %s", infile, outfile) - executable = self.distribution.command_obj['build'].executable - patched = "#!%s%s\n" % (executable, m.group(1) or '') - patched += src.read() - dst = os.open(outfile, os.O_CREAT | os.O_WRONLY | os.O_TRUNC) - try: - os.write(dst, patched.encode()) - finally: - os.close(dst) - return outfile, 1 - cls, = self.__class__.__bases__ - return cls.copy_file(self, infile, outfile, *args, **kw) - -class build_py(_build_py.build_py): - copy_file = copy_file - -class sdist(_sdist.sdist): - copy_file = copy_file - -classifiers = """\ -Environment :: Console -License :: OSI Approved :: GNU General Public License (GPL) -Natural Language :: English -Operating System :: POSIX :: Linux -Programming Language :: Python :: 3 -Programming Language :: Python :: 3.11 -Topic :: Internet -Topic :: System :: Networking -""" - -egg_version = "0.%(revision)s" % version - -git_rev = """ - -Git Revision: %s == %s -""" % (egg_version, version["short"]) - -setup( - name = 're6stnet', - version = egg_version, - description = __doc__.strip(), - author = 'Nexedi', - author_email = 're6stnet@erp5.org', - url = 'http://re6st.net', - license = 'GPL 2+', - platforms = ["any"], - classifiers=classifiers.splitlines(), - python_requires = '>=3.11', - long_description = ".. contents::\n\n" + open('README.rst').read() - + "\n" + open('CHANGES.rst').read() + git_rev, - packages = find_packages(), - entry_points = { - 'console_scripts': [ - 're6st-conf=re6st.cli.conf:main', - 're6stnet=re6st.cli.node:main', - 're6st-registry=re6st.cli.registry:main', - ], - }, - package_data = { - 're6st': [ - 'ovpn-server', - 'ovpn-client', - ], - }, - # BBB: use MANIFEST.in only so that egg_info works with very old setuptools - include_package_data = True, - install_requires = ['pyOpenSSL >= 0.13', 'miniupnpc'], - extras_require = { - 'geoip': ['geoip2'], - 'multicast': ['PyYAML'], - 'test': ['mock', 'nemu3', 'unshare', 'multiping'] - }, - #dependency_links = [ - # "http://miniupnp.free.fr/files/download.php?file=miniupnpc-1.7.20120714.tar.gz#egg=miniupnpc-1.7", - # ], - zip_safe = False, - cmdclass=dict(build_py=build_py, sdist=sdist), -)