Commit 3818c210 authored by Thomas Gambier's avatar Thomas Gambier 🚴🏼 Committed by Julien Muchembled

re6st: switch to Python 3

Co-authored-by: Julien Muchembled's avatarJulien Muchembled <jm@nexedi.com>
parent fc091d1f
# Note that this file and related scripts (bootstrap, install-eggs) don't # Note that this file and related scripts (build_python3_if_needed,
# contain anything specific to re6stnet. They could be reused as is for SlapOS. # install-eggs) don't contain anything specific to re6stnet. They could be
# reused as is for SlapOS.
# We don't strip ELF files because all dists automatically do it. # We don't strip ELF files because all dists automatically do it.
# For those that produce debug packages, these packages are anyway quite small # For those that produce debug packages, these packages are anyway quite small
...@@ -8,7 +9,6 @@ ...@@ -8,7 +9,6 @@
BUILD = $(TARGET) BUILD = $(TARGET)
PATH := $(CURDIR)/$(BUILD)/parts/chrpath/bin:$(CURDIR)/$(BUILD)/parts/file/bin:$(CURDIR)/$(BUILD)/parts/perl/bin:$(PATH) PATH := $(CURDIR)/$(BUILD)/parts/chrpath/bin:$(CURDIR)/$(BUILD)/parts/file/bin:$(CURDIR)/$(BUILD)/parts/perl/bin:$(PATH)
PYTHON = $(or $(shell command -v python2 || command -v python || command -v python3),$(error no Python found))
all: $(BUILD)/.installed.cfg all: $(BUILD)/.installed.cfg
ifneq ($(wildcard upstream.mk),) ifneq ($(wildcard upstream.mk),)
...@@ -21,11 +21,9 @@ else ...@@ -21,11 +21,9 @@ else
install: _install install: _install
endif endif
$(BUILD)/bin/buildout: $(BUILD)/.installed.cfg: $(BUILD)/buildout.cfg
cd $(BUILD) && $(PYTHON) -S $(CURDIR)/bootstrap cd $(BUILD) && $(shell ./build_python3_if_needed) bin/buildout \
buildout:relative-paths=false babeld-repository:recipe=
$(BUILD)/.installed.cfg: $(BUILD)/bin/buildout $(BUILD)/buildout.cfg
cd $(BUILD) && bin/buildout babeld-repository:recipe=
touch $@ touch $@
PROGS = $(patsubst %,$(DESTDIR)/usr/bin/%,$(BIN)) PROGS = $(patsubst %,$(DESTDIR)/usr/bin/%,$(BIN))
...@@ -39,7 +37,8 @@ $(PROGS): $(BUILD)/.installed.cfg ...@@ -39,7 +37,8 @@ $(PROGS): $(BUILD)/.installed.cfg
$(DESTDIR)/$(TARGET): $(BUILD)/.installed.cfg $(DESTDIR)/$(TARGET): $(BUILD)/.installed.cfg
rm -rf $@ && mkdir -p $@/parts rm -rf $@ && mkdir -p $@/parts
cd $(BUILD) && $(PYTHON) $(CURDIR)/install-eggs $@ $(BIN) cd $(BUILD) && parts/python3/bin/python3 \
$(CURDIR)/install-eggs $@ $(BIN)
for x in $(filter-out $(NOPART),$(shell cd $(BUILD)/parts && echo *)); \ for x in $(filter-out $(NOPART),$(shell cd $(BUILD)/parts && echo *)); \
do cp --preserve=links -r $(BUILD)/parts/$$x $@/parts; done do cp --preserve=links -r $(BUILD)/parts/$$x $@/parts; done
cd $@ && $(CURDIR)/cleanup && chmod -R u+w . cd $@ && $(CURDIR)/cleanup && chmod -R u+w .
...@@ -63,6 +62,12 @@ $(DESTDIR)/$(TARGET): $(BUILD)/.installed.cfg ...@@ -63,6 +62,12 @@ $(DESTDIR)/$(TARGET): $(BUILD)/.installed.cfg
rm $$d; ln -s /$(TARGET)$$s $$d; \ rm $$d; ln -s /$(TARGET)$$s $$d; \
done done
uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1)))
_dir = $(patsubst %/,%,$(call uniq,$(filter-out ./, $(dir $1))))
_anc = $(if $1,$1 $(call _anc,$(call _dir,$1)))
clean: clean:
find $(BUILD) -mindepth 1 -maxdepth 1 \ cd $(BUILD) && find -mindepth 1 \( \
$(patsubst %,! -name %,$(BUILD_KEEP)) |xargs rm -rf $(patsubst %, -path ./% -o,$(CLEAN_KEEP)) \
$(patsubst %, ! -path ./%,$(call _anc,$(call _dir,$(CLEAN_KEEP)))) \
-print0 \) -prune |xargs -r0 rm -r
# Maintainer: Rafael Monnerat <rafael@nexedi.com> pkgname=%PACKAGE%
pkgname=re6st-node
pkgver=%VERSION% pkgver=%VERSION%
pkgdesc="resilient, scalable, IPv6 network application" pkgdesc="resilient, scalable, IPv6 network application"
pkgrel=1 pkgrel=1
arch=('x86_64' 'i686') arch=('x86_64' 'i686')
license=('GPL') license=('GPL')
depends=(iptables iproute2) depends=(iptables iproute2)
makedepends=(python2) makedepends=(python3)
install='re6stnet.install' install='re6stnet.install'
source=(${pkgname}_${pkgver}.tar.gz) source=(${pkgname}_${pkgver}.tar.gz)
......
#!/usr/bin/python3 -S
import glob, os, shutil, sys, tarfile, tempfile, zipfile
dist = "download-cache/dist"
tmp = tempfile.mkdtemp()
try:
setuptools, = glob.glob(dist + "/setuptools-*")
if setuptools.endswith(".zip"):
zipfile.ZipFile(setuptools).extractall(tmp)
else:
tarfile.TarFile.open(setuptools, "r:*").extractall(tmp)
x, = os.listdir(tmp)
sys.path.insert(0, os.path.join(tmp, x))
from setuptools.command.easy_install import main
for x in "bin", "eggs":
try:
os.mkdir(x)
except OSError:
pass
main(["-f", dist, "-mxd", x, setuptools, "zc.buildout"])
finally:
shutil.rmtree(tmp)
with os.fdopen(os.open("bin/buildout", os.O_CREAT|os.O_WRONLY|os.O_TRUNC, 0o777), 'w') as f:
f.write("""\
#!%s -S
import os, sys
d = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))
d = os.path.dirname(d) + %r
sys.path[:0] = (%s)
from zc.buildout.buildout import main
sys.exit(main())
""" % (
sys.executable,
"/%s/" % x,
", ".join(map("d + %r".__mod__, os.listdir(x))),
))
#!/bin/sh
set -e
# This script compiles python3 if current python3 is older than python3.7 (minimum version required by buildout)
# It returns the path of the python3 executable to use
python3 -c 'import sys; sys.exit(1) if sys.version_info < (3, 7) else print(sys.executable)' && exit
build_dir=.build
ark=$PWD/opt/re6st/python3.tar.xz
mkdir -p $build_dir
cd $build_dir
if [ ! -x python ]; then
tar --strip-components=1 -xaf "$ark"
./configure
make -j4
fi >/dev/null
readlink -f python
...@@ -10,10 +10,12 @@ download-cache = download-cache ...@@ -10,10 +10,12 @@ download-cache = download-cache
develop = develop =
extensions = slapos.rebootstrap extensions = slapos.rebootstrap
newest = false newest = false
relative-paths = true
allow-picked-versions = true find-links += https://softinst171429.host.vifib.net/public/
allow-hosts += softinst171429.host.vifib.net
parts += chrpath python-bootstrap parts = re6st-ovpn chrpath
[babeld-repository] [babeld-repository]
git-executable = git-executable =
...@@ -23,12 +25,27 @@ location = ${buildout:directory}/babeld ...@@ -23,12 +25,27 @@ location = ${buildout:directory}/babeld
post-install = make clean; make version.h post-install = make clean; make version.h
environment = environment =
[python-bootstrap] # Adjust interpreter of OpenVPN hooks.
recipe = zc.recipe.egg [re6st-ovpn]
interpreter = python.tmp => re6stnet
eggs = slapos.libnetworkcache recipe = slapos.recipe.build
# https://lab.nexedi.com/nexedi/slapos.buildout/merge_requests/11 update =
scripts = dummy import os, shutil, sys
shebang = f'#!{sys.executable} -S\n'
ws = self.buildout['re6stnet'].recipe.working_set()[1]
for root, dirs, files in os.walk(ws.by_key['re6stnet'].location):
for x in files:
if x.startswith('ovpn-'):
x = os.path.join(root, x)
with open(x) as src:
if src.readline() != shebang:
y = x + '.new'
with open(y, 'w') as dst:
src.readline()
dst.write(shebang)
shutil.copyfileobj(src, dst)
shutil.copymode(x, y)
os.rename(y, x)
# Uguu, upstream buildout.cfg must be patched as it works the other way # Uguu, upstream buildout.cfg must be patched as it works the other way
# around from a packager point of view at least, thus at the end static # around from a packager point of view at least, thus at the end static
...@@ -38,13 +55,21 @@ scripts = dummy ...@@ -38,13 +55,21 @@ scripts = dummy
# ./configure --prefix=BUILD_DIRECTORY && make install # ./configure --prefix=BUILD_DIRECTORY && make install
# Instead of: # Instead of:
# ./configure --prefix=INSTALL_DIRECTORY && make install DESTDIR=BUILD_DIRECTORY # ./configure --prefix=INSTALL_DIRECTORY && make install DESTDIR=BUILD_DIRECTORY
[python2.7] [python3-common]
configure-options += configure-options +=
--prefix=%(TARGET)s/parts/${:_buildout_section_name_} --prefix=%(TARGET)s/parts/${:_buildout_section_name_}
environment += environment +=
DESTDIR=%(ROOT)s DESTDIR=%(ROOT)s
post-install =
set `echo -n ${:url} |md5sum`
ln -frs ${buildout:download-cache}/$1 ${buildout:directory}/python3.tar.xz
[openssl] [python]
# Do not rely on existing installation of what we are building.
update +=
os.environ['SSL_CERT_DIR'] = self.buildout['openssl']['certs']
[openssl-common]
shared = false shared = false
prefix = %(TARGET)s/parts/${:_buildout_section_name_} prefix = %(TARGET)s/parts/${:_buildout_section_name_}
make-options += make-options +=
...@@ -60,3 +85,7 @@ environment = ...@@ -60,3 +85,7 @@ environment =
# For old GCC like 4.8.5 on SLE 12 SP5. # For old GCC like 4.8.5 on SLE 12 SP5.
environment += environment +=
CFLAGS=-std=c99 -g -O2 CFLAGS=-std=c99 -g -O2
[versions]
zc.buildout = 3.0.1+slapos005.mr36v6
re6stnet = %(RE6STNET_VERSION)s:whl
...@@ -2,13 +2,12 @@ ...@@ -2,13 +2,12 @@
set -e set -e
pyclean() { pyclean() {
local x IFS=' local IFS='
' '
x=`dpkg -L $1` find `dpkg -L $1 |sed -n 's,[^/]*\.py$,__pycache__,p' |
rm -f `for x in $x; do sort -u` -delete 2>/dev/null
case $x in *.py) echo $x[co];; esac
done`
} }
pyclean $DPKG_MAINTSCRIPT_PACKAGE pyclean $DPKG_MAINTSCRIPT_PACKAGE
#DEBHELPER# #DEBHELPER#
...@@ -8,6 +8,7 @@ export DEB_BUILD_MAINT_OPTIONS = hardening=-format ...@@ -8,6 +8,7 @@ export DEB_BUILD_MAINT_OPTIONS = hardening=-format
include debian/common.mk include debian/common.mk
override_dh_auto_install: override_dh_auto_install:
make DESTDIR=$(TMP) PREFIX=/usr install
override_dh_link: override_dh_link:
......
#!/usr/bin/python #!/usr/bin/python3
import errno, os, shutil, sys import os, shutil, sys
path = set() path = set()
...@@ -17,7 +17,7 @@ try: ...@@ -17,7 +17,7 @@ try:
for x in sys.argv[2:]: for x in sys.argv[2:]:
x = os.path.join("bin", x) x = os.path.join("bin", x)
try: try:
exec(compile(open(x, "rb").read(), x, 'exec')) exec(compile(open(x).read(), x, 'exec'), {'__file__': x})
except Stop: except Stop:
pass pass
finally: finally:
...@@ -26,12 +26,14 @@ finally: ...@@ -26,12 +26,14 @@ finally:
dest = sys.argv[1] dest = sys.argv[1]
for x in path: for x in path:
x = os.path.relpath(x) x = os.path.relpath(x)
if not dest:
print(x)
continue
d = os.path.join(dest, x) d = os.path.join(dest, x)
try: try:
os.mkdir(os.path.basename(x)) os.mkdir(os.path.basename(x))
except OSError as e: except FileExistsError:
if e.errno != errno.EEXIST: pass
raise
if os.path.isdir(x): if os.path.isdir(x):
shutil.copytree(x, d, True) shutil.copytree(x, d, True)
else: else:
......
#!/usr/bin/env python #!/usr/bin/env python3
# #
# Copyright (C) 2016 Julien Muchembled <jm@nexedi.com> # Copyright (C) 2016 Julien Muchembled <jm@nexedi.com>
# #
...@@ -135,20 +135,20 @@ class task(_task): ...@@ -135,20 +135,20 @@ class task(_task):
return task_gen return task_gen
def __init__(self, run, depends, provides=(), def __init__(self, run, depends, provides=(),
__str_or_task = (basestring, _task)): __str_or_task = (str, _task)):
self.run = run self.run = run
self.depends = [] self.depends = []
f = [] f = []
for x in (depends,) if isinstance(depends, __str_or_task) else depends: for x in (depends,) if isinstance(depends, __str_or_task) else depends:
(f if isinstance(x, basestring) else self.depends).append(x) (f if isinstance(x, str) else self.depends).append(x)
f and self.depends.append(files(*f)) f and self.depends.append(files(*f))
self.provides = ((provides,) self.provides = ((provides,)
if isinstance(provides, basestring) or callable(provides) if isinstance(provides, str) or callable(provides)
else provides) else provides)
self.why = self, self.why = self,
def __str__(self): def __str__(self):
return self.run.__name__ return self.__name__
@property @property
def input(self): def input(self):
...@@ -162,25 +162,29 @@ class task(_task): ...@@ -162,25 +162,29 @@ class task(_task):
deps.append((dep, dep(dry_run))) deps.append((dep, dep(dry_run)))
x += dep.outputs x += dep.outputs
self.outputs = x = [] self.outputs = x = []
check_times = True
for p in self.provides: for p in self.provides:
if callable(p): if callable(p):
x += p(self) o = p(self)
if o is None:
check_times = False
else:
x += o
else: else:
x.append(p) x.append(p)
if None not in x: if check_times:
try: try:
_otime = _task._run(self) _otime = _task._run(self)
except OSError as e: except FileNotFoundError:
if e.errno != errno.ENOENT: pass
raise
else: else:
if deps: if deps:
self.why = [dep for dep, itime in deps if _otime < itime] self.why = [dep for dep, itime in deps if _otime < itime]
if self.why: if self.why:
print "# Processing %s: %s -> %s" % (self, print("# Processing %s: %s -> %s" % (self,
", ".join(map(str, self.depends)), ", ".join(map(str, self.depends)),
", ".join("<%s>" % x.__name__ if callable(x) else x ", ".join("<%s>" % x.__name__ if callable(x) else x
for x in self.provides or "?")) for x in self.provides or "?")))
if not dry_run: if not dry_run:
try: try:
self.run(self) self.run(self)
...@@ -219,14 +223,18 @@ def main(): ...@@ -219,14 +223,18 @@ def main():
sys.modules["make"] = sys.modules.pop(__name__) sys.modules["make"] = sys.modules.pop(__name__)
f = args.file f = args.file
tasks = {"__file__": f.name} g = {"__file__": f.name}
exec(compile(f.read(), f.name, "exec"), tasks) exec(compile(f.read(), f.name, "exec"), g)
tasks = {}
for k, v in g.items():
if isinstance(v, _task):
v.__name__ = k
tasks[k] = v
if args.list: if args.list:
print " ".join(sorted(k for k, v in tasks.iteritems() print(' '.join(sorted(tasks)))
if isinstance(v, _task)))
return return
for t in args.task: for t in args.task:
if not isinstance(tasks.get(t), _task): if t not in tasks:
sys.exit("%s is not a valid task." % t) sys.exit("%s is not a valid task." % t)
for t in args.task: for t in args.task:
tasks[t](args.dry_run) tasks[t](args.dry_run)
...@@ -249,18 +257,6 @@ class git(tree): ...@@ -249,18 +257,6 @@ class git(tree):
dry_run or subprocess.check_call(("git", "clone", self.url, root)) dry_run or subprocess.check_call(("git", "clone", self.url, root))
return _INF return _INF
def check_output(*args, **kw):
# BBB: 'input' arg is a backport from Python 3.4
input = kw.pop("input", None)
if input is not None:
kw["stdin"] = subprocess.PIPE
p = subprocess.Popen(stdout=subprocess.PIPE, *args, **kw)
out = p.communicate(input)[0]
if p.returncode:
raise subprocess.CalledProcessError(p.returncode,
args[0] if args else kw["args"])
return out
@contextmanager @contextmanager
def cwd(path): def cwd(path):
p = os.getcwd() p = os.getcwd()
...@@ -271,18 +267,13 @@ def cwd(path): ...@@ -271,18 +267,13 @@ def cwd(path):
os.chdir(p) os.chdir(p)
def mkdir(path): def mkdir(path):
try: os.makedirs(path, exist_ok=True)
os.makedirs(path)
except OSError as e:
if e.errno != errno.EEXIST or not os.path.isdir(path):
raise
def remove(path): def remove(path):
try: try:
os.remove(path) os.remove(path)
except OSError as e: except FileNotFoundError:
if e.errno != errno.ENOENT: pass
raise
def rmtree(path): def rmtree(path):
if os.path.exists(path): if os.path.exists(path):
...@@ -292,11 +283,9 @@ def rmtree(path): ...@@ -292,11 +283,9 @@ def rmtree(path):
def make_tar_gz(path, mtime, xform=(lambda x: x), **kw): def make_tar_gz(path, mtime, xform=(lambda x: x), **kw):
# Make reproducible tarball. Otherwise, it's really annoying that we can't # Make reproducible tarball. Otherwise, it's really annoying that we can't
# rely on 'osc status' to know whether there are real changes or not. # rely on 'osc status' to know whether there are real changes or not.
# BBB: Results differ between Python 2.6 and 2.7 because of tarfile.
__init__ = gzip.GzipFile.__init__ __init__ = gzip.GzipFile.__init__
listdir = os.listdir listdir = os.listdir
try: try:
if sys.version_info >= (2, 7):
gzip.GzipFile.__init__ = lambda *args: __init__(mtime=mtime, *args) gzip.GzipFile.__init__ = lambda *args: __init__(mtime=mtime, *args)
os.listdir = lambda path: sorted(listdir(path)) os.listdir = lambda path: sorted(listdir(path))
t = tarfile.open(path, "w:gz", **kw) t = tarfile.open(path, "w:gz", **kw)
...@@ -314,10 +303,6 @@ def make_tar_gz(path, mtime, xform=(lambda x: x), **kw): ...@@ -314,10 +303,6 @@ def make_tar_gz(path, mtime, xform=(lambda x: x), **kw):
gzip.GzipFile.__init__ = __init__ gzip.GzipFile.__init__ = __init__
os.listdir = listdir os.listdir = listdir
t.close() t.close()
if sys.version_info < (2, 7):
with open(path, "r+") as t:
t.seek(4)
gzip.write32u(t, long(mtime))
if __name__ == "__main__": if __name__ == "__main__":
sys.exit(main()) sys.exit(main())
...@@ -6,9 +6,7 @@ ...@@ -6,9 +6,7 @@
# if rebuilding for new SlapOS version but same re6stnet. # if rebuilding for new SlapOS version but same re6stnet.
# Non-obvious dependencies: # Non-obvious dependencies:
# - Debian: python-debian, python-docutils | python3-docutils # - Debian: python-debian, python3-docutils, python3-venv, iproute2
# We could avoid them by doing like for setuptools, but I'd rather go the
# opposite way: simplify the upload part by using the system setuptools.
# This "makefile" is quite smart at only rebuilding the necessary parts after # This "makefile" is quite smart at only rebuilding the necessary parts after
# some change. The main exception concerns the download-cache & extends-cache, # some change. The main exception concerns the download-cache & extends-cache,
...@@ -40,19 +38,22 @@ ...@@ -40,19 +38,22 @@
# If this way of packaging is reused for other software, postinst scripts # If this way of packaging is reused for other software, postinst scripts
# should be implemented. # should be implemented.
import os, rfc822, shutil, ssl, time, urllib import os, email, shutil, ssl, time, venv
import urllib.request, urllib.parse, urllib.error
from glob import glob from glob import glob
from cStringIO import StringIO from io import BytesIO
from subprocess import check_call from subprocess import check_call, check_output, run, DEVNULL, STDOUT
from tempfile import TemporaryDirectory
from make import * from make import *
from debian.changelog import Changelog from debian.changelog import Changelog
from debian.deb822 import Deb822 from debian.deb822 import Deb822
BOOTSTRAP_URL = "https://bootstrap.pypa.io/bootstrap-buildout.py" BOOTSTRAP = "http://www.nexedi.org/static/packages/source/slapos.buildout/zc.buildout-3.0.1%2Bslapos005.tar.gz"
PACKAGE = "re6st-node" PACKAGE = "re6st-node"
BIN = "re6st-conf re6st-registry re6stnet".split() BIN = "re6st-conf re6st-registry re6stnet".split()
BUILD_KEEP = "babeld", "buildout.cfg", "download-cache", "extends-cache" BUILD_KEEP = ("babeld", "bin/buildout", "buildout.cfg",
"download-cache", "extends-cache", "python3.tar.xz")
NOPART = "chrpath bison flex gnu-config lunzip m4 patch perl popt site_perl xz-utils".split() NOPART = "chrpath bison flex gnu-config lunzip m4 patch perl popt site_perl xz-utils".split()
TARGET = "opt/re6st" TARGET = "opt/re6st"
...@@ -66,83 +67,58 @@ re6stnet = git("re6stnet", "https://lab.nexedi.com/nexedi/re6stnet.git", ...@@ -66,83 +67,58 @@ re6stnet = git("re6stnet", "https://lab.nexedi.com/nexedi/re6stnet.git",
slapos = git("slapos", "https://lab.nexedi.com/nexedi/slapos.git", slapos = git("slapos", "https://lab.nexedi.com/nexedi/slapos.git",
ctime=False) # ignore ctime due to hardlinks to *-cache ctime=False) # ignore ctime due to hardlinks to *-cache
# The built Python can't use its certificates because its capath
# is already transformed to its installation value.
os.environ["SSL_CERT_DIR"] = ssl.get_default_verify_paths().capath
os.environ["TZ"] = "UTC"; time.tzset() os.environ["TZ"] = "UTC"; time.tzset()
@task("buildout.cfg.in", BUILD + "/buildout.cfg") def wheel():
def cfg(task): global MTIME, RE6STNET_VERSION, VERSION
cfg = open(task.input).read() % dict( wheel, = glob(BUILD + '/download-cache/dist/re6stnet-*')
SLAPOS=os.path.abspath("slapos"), MTIME = os.stat(wheel).st_mtime
ROOT="${buildout:directory}/" + os.path.relpath(ROOT, BUILD), RE6STNET_VERSION = os.path.basename(wheel).split('-', 2)[1]
TARGET="/"+TARGET)
mkdir(BUILD)
open(task.output, "w").write(cfg)
def no_wheel():
args = ["sed", "-i", r"/def _satisfied(/s/\(\bsource=\)None/\11/"]
args += glob("eggs/zc.buildout-*/zc/buildout/easy_install.py")
check_call(args)
@task((cfg, slapos), (BUILD + "/bin/buildout", BUILD + "/bin/python"))
def bootstrap(task):
try:
os.utime(task.outputs[1], None)
except OSError:
bootstrap = urllib.urlopen(BOOTSTRAP_URL).read()
mkdir(BUILD + "/download-cache")
with cwd(BUILD):
rmtree("extends-cache")
os.mkdir("extends-cache")
check_output((sys.executable, "-S", "-",
# XXX: By starting with an older version,
# we'll have the wanted version in cache.
"--setuptools-version", "40.8.0",
"--buildout-version", "2.13.8"), input=bootstrap)
no_wheel()
check_call(("bin/buildout", "buildout:extensions=",
"buildout:newest=true", "buildout:parts=python-bootstrap"))
check_call(("bin/python.tmp", "bin/buildout", "bootstrap"))
assert not glob("download-cache/dist/*.whl")
os.rename("bin/python.tmp", "bin/python")
def sdist_version(egg):
global MTIME, VERSION
MTIME = os.stat(egg).st_mtime
VERSION = "%s+slapos%s.g%s" % ( VERSION = "%s+slapos%s.g%s" % (
egg.rsplit("-", 1)[1].split(".tar.")[0], RE6STNET_VERSION,
os.getenv("SLAPOS_EPOCH", "1"), os.getenv("SLAPOS_EPOCH", "1"),
check_output(("git", "rev-parse", "--short", "HEAD"), check_output(("git", "rev-parse", "--short", "HEAD"),
cwd="slapos").strip()) cwd="slapos", text=True).strip())
tarball.provides = "%s/%s_%s.tar.gz" % (DIST, PACKAGE, VERSION), tarball.provides = "%s/%s_%s.tar.gz" % (DIST, PACKAGE, VERSION),
deb.provides = deb.provides[0], "%s/%s_%s.dsc" % (DIST, PACKAGE, VERSION) deb.provides = deb.provides[0], "%s/%s_%s.dsc" % (DIST, PACKAGE, VERSION)
mkdir(DIST) mkdir(DIST)
return egg return wheel
def sdist(task): def bootstrapped(task):
o = glob(BUILD + "/download-cache/dist/re6stnet-*") x = BUILD + '/bin/buildout'
try: try:
return sdist_version(*o), if not run((x, '-h'), stdout=DEVNULL, stderr=STDOUT).returncode:
except TypeError: return x, wheel()
return None, except Exception:
pass
@task((bootstrap, re6stnet), ("re6stnet/re6stnet.egg-info", sdist))
def sdist(task):
# XXX: We'd like to produce a reproducible tarball, so that 'make_tar_gz'
# is really useful for the main tarball.
d = BUILD + "/download-cache/dist"
g = d + "/re6stnet-*"
map(os.remove, glob(g))
check_call((os.path.abspath(task.inputs[1]), "setup.py", "sdist",
"-d", os.path.abspath(d)), cwd="re6stnet")
task.outputs[1] = sdist_version(*glob(g))
# Touch target because the current directory is used as temporary
# storage, and it is cleaned up after that setup.py runs egg_info.
os.utime(task.outputs[0], None)
@task(sdist, BUILD + "/.installed.cfg") @task((re6stnet, slapos, 'buildout.cfg.in'), bootstrapped)
def bootstrap(task):
rmtree(BUILD)
with TemporaryDirectory('venv', PACKAGE) as venv_dir:
venv.create(venv_dir, symlinks=True, with_pip=True)
check_call(('bin/pip', 'install', '--no-cache-dir',
'hatchling', 'slapos.libnetworkcache', BOOTSTRAP,
), cwd=venv_dir)
check_call((venv_dir + '/bin/hatchling', 'build', '-t', 'wheel',
'-d', os.path.abspath(BUILD + '/download-cache/dist'),
), cwd=task.inputs[0])
task.outputs += BUILD + '/bin/buildout', wheel()
cfg = open(task.inputs[2]).read() % dict(
RE6STNET_VERSION=RE6STNET_VERSION,
ROOT='${buildout:directory}/' + os.path.relpath(ROOT, BUILD),
SLAPOS=os.path.abspath('slapos'),
TARGET='/'+TARGET)
with cwd(BUILD):
os.mkdir('extends-cache')
open('buildout.cfg', 'w').write(cfg)
check_call((venv_dir + '/bin/buildout',
'buildout:extra-paths=',
'bootstrap'))
# just fix shebang
check_call((sys.executable, 'bin/buildout', 'bootstrap'))
@task(bootstrap, BUILD + "/.installed.cfg")
def buildout(task): def buildout(task):
check_call(("bin/buildout",), cwd=BUILD) check_call(("bin/buildout",), cwd=BUILD)
# Touch target in case that buildout had nothing to do. # Touch target in case that buildout had nothing to do.
...@@ -152,7 +128,7 @@ def tarfile_addfileobj(tarobj, name, dataobj, statobj): ...@@ -152,7 +128,7 @@ def tarfile_addfileobj(tarobj, name, dataobj, statobj):
tarinfo = tarobj.gettarinfo(arcname=name, fileobj=statobj) tarinfo = tarobj.gettarinfo(arcname=name, fileobj=statobj)
dataobj.seek(0, 2) dataobj.seek(0, 2)
tarinfo.size = dataobj.tell() tarinfo.size = dataobj.tell()
dataobj.reset() dataobj.seek(0)
tarobj.addfile(tarinfo, dataobj) tarobj.addfile(tarinfo, dataobj)
@task(re6stnet) @task(re6stnet)
...@@ -160,42 +136,50 @@ def upstream(task): ...@@ -160,42 +136,50 @@ def upstream(task):
check_call(("make", "-C", "re6stnet")) check_call(("make", "-C", "re6stnet"))
task.outputs = glob("re6stnet/docs/*.[1-9]") task.outputs = glob("re6stnet/docs/*.[1-9]")
@task((upstream, buildout, __file__, @task((upstream, buildout,
"Makefile.in", "cleanup", "install-eggs", "bootstrap")) "Makefile.in", "build_python3_if_needed", "cleanup", "install-eggs"))
def tarball(task): def tarball(task):
prefix = "%s-%s/" % (PACKAGE, VERSION) prefix = "%s-%s/" % (PACKAGE, VERSION)
build_keep = list(BUILD_KEEP)
build_keep += check_output((sys.executable,
os.path.relpath(task.inputs[-1], BUILD), '', 'buildout'),
text=True, cwd=BUILD).splitlines()
def xform(path): def xform(path):
if path == "re6stnet/Makefile":
path = "upstream.mk"
for p in "re6stnet/", "build/", "": for p in "re6stnet/", "build/", "":
if path.startswith(p): if path.startswith(p):
return prefix + path[len(p):] return prefix + path[len(p):]
with make_tar_gz(task.output, MTIME, xform) as t: with make_tar_gz(task.output, MTIME, xform) as t:
s = StringIO() s = BytesIO()
for k in "BIN", "NOPART", "BUILD_KEEP", "TARGET": for k in "BIN", "NOPART", "CLEAN_KEEP", "TARGET":
v = globals()[k] v = build_keep if k == "CLEAN_KEEP" else globals()[k]
s.write("%s = %s\n" % (k, v if type(v) is str else " ".join(v))) s.write(("%s = %s\n" % (
with open(task.inputs[-4]) as x: k, v if type(v) is str else ' '.join(v),
)).encode())
with open("Makefile.in", 'rb') as x:
s.write(x.read()) s.write(x.read())
tarfile_addfileobj(t, "Makefile", s, x) tarfile_addfileobj(t, "Makefile", s, x)
s.truncate(0)
s.write("override PYTHON = /%s/parts/python2.7/bin/python\n" % TARGET)
with open("re6stnet/Makefile") as x:
s.write(x.read())
tarfile_addfileobj(t, "upstream.mk", s, x)
for x in task.inputs[-3:]: for x in task.inputs[-3:]:
t.add(x) t.add(x)
t.add("re6stnet/daemon") t.add("re6stnet/daemon")
t.add("re6stnet/Makefile")
for x in upstream.outputs: for x in upstream.outputs:
t.add(x) t.add(x)
for x in BUILD_KEEP: filter_ = lambda info: None if info.name.endswith((
t.add(BUILD + "/" + x) "/.git", "/__pycache__",
)) else info
for x in build_keep:
t.add(BUILD + "/" + x, filter=filter_)
@task(sdist, "debian/changelog") @task(bootstrap, "debian/changelog")
def dch(task): def dch(task):
with cwd("re6stnet") as p: changelog = os.getcwd() + "/" + task.output
p += "/" + task.output with open("re6stnet/debian/common.mk") as mk:
check_output(("make", "-f", "-", p, check_output(("make", "-f", "-", changelog,
"PACKAGE=" + PACKAGE, "VERSION=" + VERSION), "PACKAGE=" + PACKAGE, "VERSION=" + VERSION),
input=open("debian/common.mk").read().replace(task.output, p)) input=mk.read().replace(task.output, changelog).encode(),
cwd="re6stnet")
@task((dch, tree("debian")), DIST + "/debian.tar.gz") @task((dch, tree("debian")), DIST + "/debian.tar.gz")
def deb(task): def deb(task):
...@@ -205,16 +189,17 @@ def deb(task): ...@@ -205,16 +189,17 @@ def deb(task):
d["Source"] = s["Source"] = b["Package"] = PACKAGE d["Source"] = s["Source"] = b["Package"] = PACKAGE
d["Version"] = VERSION d["Version"] = VERSION
d["Architecture"] = b["Architecture"] = "any" d["Architecture"] = b["Architecture"] = "any"
d["Build-Depends"] = s["Build-Depends"] = ( d["Build-Depends"] = s["Build-Depends"] = \
"python (>= 2.7) | python2 | python3-distutils, debhelper (>= 9.20120909)," "debhelper (>= 10), iproute2" + ''.join(
" debhelper (>= 10) | dh-systemd," # Before 3.10, pip wants distutils.
" iproute2 | iproute" ",\n python3 (>= 3.10) | python3-distutils (>= 3.7) | %s-dev" % x
) for x in "libbz2 libffi liblzma libssl zlib1g".split())
b["Depends"] = "${shlibs:Depends}, iproute2 | iproute" del s["X-Python3-Version"]
b["Depends"] = "${shlibs:Depends}, iproute2"
b["Conflicts"] = b["Provides"] = b["Replaces"] = "re6stnet" b["Conflicts"] = b["Provides"] = b["Replaces"] = "re6stnet"
patched_control = StringIO("%s\n%s" % (s, b)) patched_control = BytesIO(("%s\n%s" % (s, b)).encode('utf-8'))
open(task.outputs[1], "w").write(str(d)) open(task.outputs[1], "w").write(str(d))
date = rfc822.parsedate_tz(Changelog(open(dch.output)).date) date = email.utils.parsedate_tz(Changelog(open(dch.output)).date)
mtime = time.mktime(date[:9]) - date[9] mtime = time.mktime(date[:9]) - date[9]
# Unfortunately, OBS does not support symlinks. # Unfortunately, OBS does not support symlinks.
with make_tar_gz(task.outputs[0], mtime, dereference=True) as t: with make_tar_gz(task.outputs[0], mtime, dereference=True) as t:
...@@ -230,39 +215,21 @@ def deb(task): ...@@ -230,39 +215,21 @@ def deb(task):
upstream.difference_update((x, "debian/rules", "debian/source")) upstream.difference_update((x, "debian/rules", "debian/source"))
# check we are aware of any upstream file we override # check we are aware of any upstream file we override
assert upstream.isdisjoint(added), upstream.intersection(added) assert upstream.isdisjoint(added), upstream.intersection(added)
map(t.add, sorted(upstream)) for u in sorted(upstream):
t.add(u)
@task((sdist, __file__), DIST + "/re6stnet.spec")
def rpm(task): def _template(task):
check_call(("sed", "-r", r""" output = (open(task.inputs[-1]).read()
# https://fedoraproject.org/wiki/Packaging:Python_Appendix#Manual_byte_compilation .replace("%PACKAGE%", PACKAGE)
1i%%global __os_install_post %%(echo '%%{__os_install_post}' |grep -v brp-python-bytecompile) .replace("%TARGET%", TARGET)
/^%%define (_builddir|ver)/d .replace("%VERSION%", VERSION)
s/^(Name:\s*).*/\1%s/ )
s/^(Version:\s*).*/\1%s/ open(task.output, 'w').write(output)
s/^(Release:\s*).*/\11/
/^BuildArch:/cAutoReqProv: no\
BuildRequires: gcc-c++, make, python, iproute\
#!BuildIgnore: rpmlint-Factory\
Source: %%{name}_%%{version}.tar.gz
/^Requires:/{
/iproute/!d
}
/^Recommends:/d
s/^(Conflicts:\s*).*/\1re6stnet/
/^%%description$/a%%prep\n%%setup -q
/^%%preun$/,/^$/{
/^$/ifind /%s -type f -name '*.py[co]' -delete
}
""" % (PACKAGE, VERSION, TARGET), "re6stnet/re6stnet.spec"),
stdout=open(task.output, "w"))
@task((sdist, "PKGBUILD.in"), DIST + "/PKGBUILD") rpm, arch = (task((bootstrap, name + '.in'), DIST + '/' + name)(_template)
def arch(task): for name in ("re6stnet.spec", "PKGBUILD"))
pkgbuild = open(task.inputs[-1]).read().replace("%VERSION%", VERSION)
open(task.output, "w").write(pkgbuild)
@task((tarball, deb, rpm, arch, "re6stnet.install")) @task((tarball, deb, rpm, arch, "re6stnet.install", "re6st-node.rpmlintrc"))
def build(task): def build(task):
pass pass
......
setBadness('binary-or-shlib-defines-rpath', 0)
setBadness('wrong-script-interpreter', 0)
setBadness('summary-not-capitalized', 0)
setBadness('devel-file-in-non-devel-package', 0)
%global __brp_mangle_shebangs %{nil}
%global __brp_python_bytecompile %{nil}
%define units re6stnet.service re6st-registry.service
Summary: resilient, scalable, IPv6 network application
Name: %PACKAGE%
Version: %VERSION%
Release: 1
License: GPLv2+
Group: Applications/Internet
AutoReqProv: no
BuildRequires: gcc-c++, make, python3, iproute
#!BuildIgnore: rpmlint-Factory
Source0: %{name}_%{version}.tar.gz
Source1: %{name}.rpmlintrc
Requires: iproute
BuildRequires: python3-devel
# dependencies for compilation of python3
BuildRequires: libffi-devel
BuildRequires: (lzma-devel or liblzma-devel or xz-devel)
BuildRequires: zlib-devel
BuildRequires: (libbz2-devel or bzip2-devel)
Conflicts: re6stnet
%description
%prep
%setup -q
%build
make
%install
set $RPM_BUILD_ROOT
make install PREFIX=%_prefix MANDIR=%_mandir DESTDIR=$1 %{?_unitdir:UNITDIR=%{_unitdir}}
# Exclude man pages because they will be compressed.
find $1 -mindepth 1 -path \*%_mandir -prune -o \
-name re6st\* -prune -printf /%%P\\n > INSTALLED
export QA_RPATHS=$(( 0x0001|0x0002|0x0020 ))
%clean
rm -rf "$RPM_BUILD_ROOT" INSTALLED
%files -f INSTALLED
%_mandir/*/*
%post
if [ $1 -eq 1 ]; then
/bin/systemctl preset %{units} || :
fi >/dev/null 2>&1
%preun
if [ $1 -eq 0 ]; then
/bin/systemctl --no-reload disable %{units} || :
/bin/systemctl stop %{units} || :
fi >/dev/null 2>&1
find %TARGET% -type d -name __pycache__ -print0 |xargs -r0 rm -r
%postun
/bin/systemctl daemon-reload >/dev/null 2>&1 || :
if [ $1 -ge 1 ]; then
/bin/systemctl try-restart %{units} >/dev/null 2>&1 || :
fi
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment