Use pathlib.Path instead of os.path

This commit is contained in:
Matthieu Gautier 2024-04-30 12:52:29 +02:00
parent 06cad66925
commit 908b90190c
25 changed files with 264 additions and 269 deletions

View File

@ -2,6 +2,7 @@
import os, sys import os, sys
import argparse import argparse
from pathlib import Path
from .dependencies import Dependency from .dependencies import Dependency
from .configs import ConfigInfo from .configs import ConfigInfo
@ -22,6 +23,7 @@ def parse_args():
parser.add_argument( parser.add_argument(
"--working-dir", "--working-dir",
default=".", default=".",
type=Path,
help=( help=(
"Directory where kiwix-build puts all its files " "Directory where kiwix-build puts all its files "
"(source, archive and build)\n" "(source, archive and build)\n"
@ -31,6 +33,7 @@ def parse_args():
parser.add_argument( parser.add_argument(
"--build-dir", "--build-dir",
default=".", default=".",
type=Path,
help=( help=(
"Directory where kiwix-build puts all build files.\n" "Directory where kiwix-build puts all build files.\n"
"build-dir can be absolute path or a relative (to working-dir) one." "build-dir can be absolute path or a relative (to working-dir) one."
@ -152,7 +155,7 @@ def parse_args():
def main(): def main():
options = parse_args() options = parse_args()
options.working_dir = os.path.abspath(options.working_dir) options.working_dir = options.working_dir.absolute()
_global.set_options(options) _global.set_options(options)
neutralEnv = buildenv.NeutralEnv(options.get_build_dir) neutralEnv = buildenv.NeutralEnv(options.get_build_dir)
_global.set_neutralEnv(neutralEnv) _global.set_neutralEnv(neutralEnv)

View File

@ -2,20 +2,21 @@ import os, sys, shutil
import subprocess import subprocess
import platform import platform
import distro import distro
from pathlib import Path
from .utils import pj, download_remote, escape_path from .utils import download_remote, escape_path
from ._global import neutralEnv, option from ._global import neutralEnv, option
class NeutralEnv: class NeutralEnv:
def __init__(self, dummy_run): def __init__(self, dummy_run):
self.working_dir = option("working_dir") self.working_dir: Path = option("working_dir")
self.source_dir = pj(self.working_dir, "SOURCE") self.source_dir: Path = self.working_dir / "SOURCE"
self.archive_dir = pj(self.working_dir, "ARCHIVE") self.archive_dir: Path = self.working_dir / "ARCHIVE"
self.toolchain_dir = pj(self.working_dir, "TOOLCHAINS") self.toolchain_dir: Path = self.working_dir / "TOOLCHAINS"
self.log_dir = pj(self.working_dir, "LOGS") self.log_dir: Path = self.working_dir / "LOGS"
for d in (self.source_dir, self.archive_dir, self.toolchain_dir, self.log_dir): for d in (self.source_dir, self.archive_dir, self.toolchain_dir, self.log_dir):
os.makedirs(d, exist_ok=True) d.mkdir(parents=True, exist_ok=True)
self.detect_platform() self.detect_platform()
if dummy_run: if dummy_run:
# If this is for a dummy run, we will not run anything. # If this is for a dummy run, we will not run anything.
@ -73,29 +74,28 @@ class NeutralEnv:
class BuildEnv: class BuildEnv:
def __init__(self, configInfo): def __init__(self, configInfo):
self.configInfo = configInfo self.configInfo = configInfo
self.base_build_dir = pj(option("working_dir"), option("build_dir")) self.base_build_dir: Path = option("working_dir") / option("build_dir")
build_dir = ( build_dir = (
configInfo.arch_name if option("use_target_arch_name") else configInfo.name configInfo.arch_name if option("use_target_arch_name") else configInfo.name
) )
build_dir = f"BUILD_{build_dir}" build_dir = f"BUILD_{build_dir}"
self.build_dir = pj(self.base_build_dir, build_dir) self.build_dir: Path = self.base_build_dir / build_dir
self.install_dir = pj(self.build_dir, "INSTALL") self.install_dir: Path = self.build_dir / "INSTALL"
self.toolchain_dir = pj(self.build_dir, "TOOLCHAINS") self.toolchain_dir: Path = self.build_dir / "TOOLCHAINS"
self.log_dir = pj(self.build_dir, "LOGS") self.log_dir: Path = self.build_dir / "LOGS"
for d in (self.build_dir, self.install_dir, self.toolchain_dir, self.log_dir): for d in (self.build_dir, self.install_dir, self.toolchain_dir, self.log_dir):
os.makedirs(d, exist_ok=True) d.mkdir(parents=True, exist_ok=True)
self.libprefix = option("libprefix") or self._detect_libdir() self.libprefix = option("libprefix") or self._detect_libdir()
def clean_intermediate_directories(self): def clean_intermediate_directories(self):
for subdir in os.listdir(self.build_dir): for subpath in self.build_dir.iterdir():
subpath = pj(self.build_dir, subdir)
if subpath == self.install_dir: if subpath == self.install_dir:
continue continue
if os.path.isdir(subpath): if subpath.isdir():
shutil.rmtree(subpath) shutil.rmtree(subpath)
else: else:
os.remove(subpath) subpath.unlink()
def _is_debianlike(self): def _is_debianlike(self):
return os.path.isfile("/etc/debian_version") return os.path.isfile("/etc/debian_version")
@ -122,35 +122,35 @@ class BuildEnv:
def get_env(self, *, cross_comp_flags, cross_compilers, cross_path): def get_env(self, *, cross_comp_flags, cross_compilers, cross_path):
env = self.configInfo.get_env() env = self.configInfo.get_env()
pkgconfig_path = pj(self.install_dir, self.libprefix, "pkgconfig") pkgconfig_path = self.install_dir / self.libprefix / "pkgconfig"
env["PKG_CONFIG_PATH"].append(pkgconfig_path) env["PKG_CONFIG_PATH"].append(pkgconfig_path)
env["PATH"].insert(0, pj(self.install_dir, "bin")) env["PATH"].insert(0, self.install_dir / "bin")
env["LD_LIBRARY_PATH"].extend( env["LD_LIBRARY_PATH"].extend(
[ [
pj(self.install_dir, "lib"), self.install_dir / "lib",
pj(self.install_dir, self.libprefix), self.install_dir / self.libprefix,
] ]
) )
env["QMAKE_CXXFLAGS"] = " ".join( env["QMAKE_CXXFLAGS"] = " ".join(
[escape_path("-I" + pj(self.install_dir, "include")), env["QMAKE_CXXFLAGS"]] [escape_path(f"-I{self.install_dir / 'include'}"), env["QMAKE_CXXFLAGS"]]
) )
env["CPPFLAGS"] = " ".join( env["CPPFLAGS"] = " ".join(
[escape_path("-I" + pj(self.install_dir, "include")), env["CPPFLAGS"]] [escape_path(f"-I{self.install_dir / 'include'}"), env["CPPFLAGS"]]
) )
env["QMAKE_LFLAGS"] = " ".join( env["QMAKE_LFLAGS"] = " ".join(
[ [
escape_path("-L" + pj(self.install_dir, "lib")), escape_path(f"-L{self.install_dir / 'lib'}"),
escape_path("-L" + pj(self.install_dir, self.libprefix)), escape_path(f"-L{self.install_dir / self.libprefix}"),
env["QMAKE_LFLAGS"], env["QMAKE_LFLAGS"],
] ]
) )
env["LDFLAGS"] = " ".join( env["LDFLAGS"] = " ".join(
[ [
escape_path("-L" + pj(self.install_dir, "lib")), escape_path(f"-L{self.install_dir / 'lib'}"),
escape_path("-L" + pj(self.install_dir, self.libprefix)), escape_path(f"-L{self.install_dir / self.libprefix}"),
env["LDFLAGS"], env["LDFLAGS"],
] ]
) )

View File

@ -1,5 +1,5 @@
from pathlib import Path
from .base import ConfigInfo, MetaConfigInfo from .base import ConfigInfo, MetaConfigInfo
from kiwixbuild.utils import pj
from kiwixbuild._global import get_target_step, option from kiwixbuild._global import get_target_step, option
@ -30,9 +30,7 @@ class AndroidConfigInfo(ConfigInfo):
def binaries(self): def binaries(self):
install_path = self.install_path install_path = self.install_path
binaries = { binaries = {k: install_path / "bin" / v for k, v in self.binaries_name.items()}
k: pj(install_path, "bin", v) for k, v in self.binaries_name.items()
}
binaries["PKGCONFIG"] = "pkg-config" binaries["PKGCONFIG"] = "pkg-config"
return binaries return binaries
@ -41,7 +39,7 @@ class AndroidConfigInfo(ConfigInfo):
return get_target_step("android-ndk", self.name) return get_target_step("android-ndk", self.name)
@property @property
def install_path(self): def install_path(self) -> Path:
return self.ndk_builder.install_path return self.ndk_builder.install_path
def get_cross_config(self): def get_cross_config(self):
@ -56,7 +54,7 @@ class AndroidConfigInfo(ConfigInfo):
"exe_wrapper_def": "", "exe_wrapper_def": "",
"install_path": self.install_path, "install_path": self.install_path,
"binaries": self.binaries(), "binaries": self.binaries(),
"root_path": pj(self.install_path, "sysroot"), "root_path": self.install_path / "sysroot",
"extra_libs": extra_libs, "extra_libs": extra_libs,
"extra_cflags": extra_cflags, "extra_cflags": extra_cflags,
"host_machine": { "host_machine": {
@ -71,17 +69,17 @@ class AndroidConfigInfo(ConfigInfo):
def get_env(self): def get_env(self):
env = super().get_env() env = super().get_env()
root_path = pj(self.install_path, "sysroot") root_path = self.install_path / "sysroot"
env["PKG_CONFIG_LIBDIR"] = pj(root_path, "lib", "pkgconfig") env["PKG_CONFIG_LIBDIR"] = root_path / "lib" / "pkgconfig"
env["NDK_DEBUG"] = "0" env["NDK_DEBUG"] = "0"
return env return env
def get_bin_dir(self): def get_bin_dir(self):
return [pj(self.install_path, "bin")] return [self.install_path / "bin"]
def set_comp_flags(self, env): def set_comp_flags(self, env):
super().set_comp_flags(env) super().set_comp_flags(env)
root_path = pj(self.install_path, "sysroot") root_path = self.install_path / "sysroot"
march = "-march={}".format(self.march) if hasattr(self, "march") else "" march = "-march={}".format(self.march) if hasattr(self, "march") else ""
env["CFLAGS"] = ( env["CFLAGS"] = (
"-fPIC -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64 --sysroot={} {} ".format( "-fPIC -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64 --sysroot={} {} ".format(

View File

@ -1,6 +1,6 @@
from .base import ConfigInfo, MixedMixin from .base import ConfigInfo, MixedMixin
from kiwixbuild.utils import pj from pathlib import Path
from kiwixbuild._global import get_target_step from kiwixbuild._global import get_target_step
@ -36,7 +36,7 @@ class ArmConfigInfo(ConfigInfo):
return get_target_step(self.build, "neutral") return get_target_step(self.build, "neutral")
@property @property
def root_path(self): def root_path(self) -> Path:
return self.toolchain.build_path return self.toolchain.build_path
@property @property
@ -54,7 +54,7 @@ class ArmConfigInfo(ConfigInfo):
("LDSHARED", "g++ -shared"), ("LDSHARED", "g++ -shared"),
) )
) )
binaries = {k: pj(self.root_path, "bin", v) for k, v in binaries} binaries = {k: self.root_path / "bin" / v for k, v in binaries}
binaries["PKGCONFIG"] = "pkg-config" binaries["PKGCONFIG"] = "pkg-config"
return binaries return binaries
@ -72,19 +72,19 @@ class ArmConfigInfo(ConfigInfo):
yield "--host={}".format(self.arch_full) yield "--host={}".format(self.arch_full)
def get_bin_dir(self): def get_bin_dir(self):
return [pj(self.root_path, "bin")] return [self.root_path / "bin"]
def get_env(self): def get_env(self):
env = super().get_env() env = super().get_env()
env["LD_LIBRARY_PATH"][0:0] = [ env["LD_LIBRARY_PATH"][0:0] = [
pj(self.root_path, self.arch_full, "lib64"), self.root_path / self.arch_full / "lib64",
pj(self.root_path, "lib"), self.root_path / "lib",
] ]
env["PKG_CONFIG_LIBDIR"] = pj(self.root_path, "lib", "pkgconfig") env["PKG_CONFIG_LIBDIR"] = self.root_path / "lib" / "pkgconfig"
env["QEMU_LD_PREFIX"] = pj(self.root_path, self.arch_full, "libc") env["QEMU_LD_PREFIX"] = self.root_path / self.arch_full / "libc"
env["QEMU_SET_ENV"] = "LD_LIBRARY_PATH={}".format( env["QEMU_SET_ENV"] = "LD_LIBRARY_PATH={}".format(
":".join( ":".join(
[pj(self.root_path, self.arch_full, "lib"), str(env["LD_LIBRARY_PATH"])] [self.root_path / self.arch_full / "lib", str(env["LD_LIBRARY_PATH"])]
) )
) )
return env return env
@ -164,7 +164,7 @@ class Aarch64(ArmConfigInfo):
cpu = "aarch64" cpu = "aarch64"
@property @property
def root_path(self): def root_path(self) -> Path:
return self.toolchain.build_path return self.toolchain.build_path

View File

@ -1,13 +1,14 @@
import os, sys import os, sys
import subprocess import subprocess
from pathlib import Path
from kiwixbuild.dependencies import Dependency from kiwixbuild.dependencies import Dependency
from kiwixbuild.utils import pj, remove_duplicates, DefaultEnv from kiwixbuild.utils import remove_duplicates, DefaultEnv
from kiwixbuild.buildenv import BuildEnv from kiwixbuild.buildenv import BuildEnv
from kiwixbuild._global import neutralEnv, option, target_steps from kiwixbuild._global import neutralEnv, option, target_steps
_SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) _SCRIPT_DIR = Path(__file__).resolve().parent
TEMPLATES_DIR = pj(os.path.dirname(_SCRIPT_DIR), "templates") TEMPLATES_DIR = _SCRIPT_DIR.parent / "templates"
class _MetaConfig(type): class _MetaConfig(type):
@ -81,7 +82,7 @@ class ConfigInfo(metaclass=_MetaConfig):
return {} return {}
def get_include_dirs(self): def get_include_dirs(self):
return [pj(self.buildEnv.install_dir, "include")] return [self.buildEnv.install_dir / "include"]
def get_env(self): def get_env(self):
return DefaultEnv() return DefaultEnv()
@ -100,13 +101,11 @@ class ConfigInfo(metaclass=_MetaConfig):
def _gen_crossfile(self, name, outname=None): def _gen_crossfile(self, name, outname=None):
if outname is None: if outname is None:
outname = name outname = name
crossfile = pj(self.buildEnv.build_dir, outname) crossfile = self.buildEnv.build_dir / outname
template_file = pj(TEMPLATES_DIR, name) template_file = TEMPLATES_DIR / name
with open(template_file, "r") as f: template = template_file.read_text()
template = f.read()
content = template.format(**self.get_cross_config()) content = template.format(**self.get_cross_config())
with open(crossfile, "w") as outfile: crossfile.write_text(content)
outfile.write(content)
return crossfile return crossfile
def finalize_setup(self): def finalize_setup(self):
@ -155,22 +154,22 @@ def MixedMixin(static_name):
def get_include_dirs(self): def get_include_dirs(self):
return [ return [
pj(self.buildEnv.install_dir, "include"), self.buildEnv.install_dir / "include",
pj(self.static_buildEnv.install_dir, "include"), self.static_buildEnv.install_dir / "include",
] ]
def get_env(self): def get_env(self):
env = super().get_env() env = super().get_env()
env["PATH"].insert(0, pj(self.static_buildEnv.install_dir, "bin")) env["PATH"].insert(0, self.static_buildEnv.install_dir / "bin")
pkgconfig_path = pj( pkgconfig_path = (
self.static_buildEnv.install_dir, self.static_buildEnv.install_dir
self.static_buildEnv.libprefix, / self.static_buildEnv.libprefix
"pkgconfig", / "pkgconfig"
) )
env["PKG_CONFIG_PATH"].append(pkgconfig_path) env["PKG_CONFIG_PATH"].append(pkgconfig_path)
env["CPPFLAGS"] = " ".join( env["CPPFLAGS"] = " ".join(
[ [
"-I" + pj(self.static_buildEnv.install_dir, "include"), f"-I{self.static_buildEnv.install_dir / 'include'}",
env["CPPFLAGS"], env["CPPFLAGS"],
] ]
) )

View File

@ -1,7 +1,7 @@
import os import os
from .base import ConfigInfo from .base import ConfigInfo
from kiwixbuild.utils import which, pj from kiwixbuild.utils import which
class I586ConfigInfo(ConfigInfo): class I586ConfigInfo(ConfigInfo):

View File

@ -1,7 +1,8 @@
from pathlib import Path
import subprocess import subprocess
from kiwixbuild._global import option from kiwixbuild._global import option
from kiwixbuild.utils import pj, xrun_find from kiwixbuild.utils import xrun_find
from .base import ConfigInfo, MetaConfigInfo, MixedMixin from .base import ConfigInfo, MetaConfigInfo, MixedMixin
from kiwixbuild.dependencies.apple_xcframework import AppleXCFramework from kiwixbuild.dependencies.apple_xcframework import AppleXCFramework
@ -29,10 +30,12 @@ class AppleConfigInfo(ConfigInfo):
return self.target return self.target
@property @property
def root_path(self): def root_path(self) -> Path:
if self._root_path is None: if self._root_path is None:
command = "xcrun --sdk {} --show-sdk-path".format(self.sdk_name) command = "xcrun --sdk {} --show-sdk-path".format(self.sdk_name)
self._root_path = subprocess.check_output(command, shell=True)[:-1].decode() self._root_path = Path(
subprocess.check_output(command, shell=True)[:-1].decode()
)
return self._root_path return self._root_path
def __str__(self): def __str__(self):
@ -133,7 +136,7 @@ class AppleConfigInfo(ConfigInfo):
) )
def get_bin_dir(self): def get_bin_dir(self):
return [pj(self.root_path, "bin")] return [self.root_path / "bin"]
@property @property
def binaries(self): def binaries(self):

View File

@ -1,6 +1,6 @@
from pathlib import Path
from .base import ConfigInfo, MixedMixin from .base import ConfigInfo, MixedMixin
from kiwixbuild.utils import pj
from kiwixbuild._global import get_target_step from kiwixbuild._global import get_target_step
@ -31,7 +31,7 @@ class MuslConfigInfo(ConfigInfo):
return get_target_step(self.build, "neutral") return get_target_step(self.build, "neutral")
@property @property
def root_path(self): def root_path(self) -> Path:
return self.toolchain.build_path return self.toolchain.build_path
@property @property
@ -49,7 +49,7 @@ class MuslConfigInfo(ConfigInfo):
("LDSHARED", "g++ -shared"), ("LDSHARED", "g++ -shared"),
) )
) )
binaries = {k: pj(self.root_path, "bin", v) for k, v in binaries} binaries = {k: self.root_path / "bin" / v for k, v in binaries}
binaries["PKGCONFIG"] = "pkg-config" binaries["PKGCONFIG"] = "pkg-config"
return binaries return binaries
@ -69,26 +69,26 @@ class MuslConfigInfo(ConfigInfo):
return [f"--host={self.arch_full}"] return [f"--host={self.arch_full}"]
def get_bin_dir(self): def get_bin_dir(self):
return [pj(self.root_path, "bin")] return [self.root_path / "bin"]
def get_env(self): def get_env(self):
env = super().get_env() env = super().get_env()
env["LD_LIBRARY_PATH"][0:0] = [ env["LD_LIBRARY_PATH"][0:0] = [
pj(self.root_path, self.arch_full, "lib64"), self.root_path / self.arch_full / "lib64",
pj(self.root_path, "lib"), self.root_path / "lib",
] ]
env["PKG_CONFIG_LIBDIR"] = pj(self.root_path, "lib", "pkgconfig") env["PKG_CONFIG_LIBDIR"] = self.root_path / "lib" / "pkgconfig"
env["QEMU_LD_PREFIX"] = pj(self.root_path, self.arch_full, "libc") env["QEMU_LD_PREFIX"] = self.root_path / self.arch_full / "libc"
env["QEMU_SET_ENV"] = "LD_LIBRARY_PATH={}".format( env["QEMU_SET_ENV"] = "LD_LIBRARY_PATH={}".format(
":".join( ":".join(
[pj(self.root_path, self.arch_full, "lib"), str(env["LD_LIBRARY_PATH"])] [self.root_path / self.arch_full / "lib", str(env["LD_LIBRARY_PATH"])]
) )
) )
return env return env
def set_comp_flags(self, env): def set_comp_flags(self, env):
super().set_comp_flags(env) super().set_comp_flags(env)
env["LD_LIBRARY_PATH"].insert(0, pj(self.root_path, self.arch_full, "lib")) env["LD_LIBRARY_PATH"].insert(0, self.root_path / self.arch_full / "lib")
env["CFLAGS"] = ( env["CFLAGS"] = (
" -fPIC -Wp,-D_FORTIFY_SOURCE=2 -fexceptions --param=ssp-buffer-size=4 " " -fPIC -Wp,-D_FORTIFY_SOURCE=2 -fexceptions --param=ssp-buffer-size=4 "
+ env["CFLAGS"] + env["CFLAGS"]

View File

@ -1,6 +1,5 @@
from .base import ConfigInfo, MixedMixin from .base import ConfigInfo, MixedMixin
from kiwixbuild.utils import pj
from kiwixbuild._global import option, neutralEnv from kiwixbuild._global import option, neutralEnv
from kiwixbuild.configs.ios import MIN_MACOS_VERSION from kiwixbuild.configs.ios import MIN_MACOS_VERSION
import sysconfig import sysconfig

View File

@ -1,6 +1,6 @@
from pathlib import Path
from .base import ConfigInfo from .base import ConfigInfo
from kiwixbuild.utils import pj
from kiwixbuild._global import get_target_step from kiwixbuild._global import get_target_step
@ -37,11 +37,11 @@ class WasmConfigInfo(ConfigInfo):
return get_target_step("emsdk", self.name) return get_target_step("emsdk", self.name)
@property @property
def install_path(self): def install_path(self) -> Path:
return self.wasm_sdk.install_path return self.wasm_sdk.install_path
@property @property
def root_path(self): def root_path(self) -> Path:
return self.install_path return self.install_path
@property @property
@ -56,7 +56,7 @@ class WasmConfigInfo(ConfigInfo):
("LD", "wasm-ld"), ("LD", "wasm-ld"),
) )
binaries = { binaries = {
k: pj(self.install_path, "upstream", "emscripten", v) for k, v in binaries k: self.install_path / "upstream" / "emscripten" / v for k, v in binaries
} }
binaries["PKGCONFIG"] = "pkg-config" binaries["PKGCONFIG"] = "pkg-config"
return binaries return binaries
@ -75,20 +75,20 @@ class WasmConfigInfo(ConfigInfo):
return "emmake" return "emmake"
def get_bin_dir(self): def get_bin_dir(self):
return [pj(self.install_path, "bin")] return [self.install_path / "bin"]
def get_env(self): def get_env(self):
env = super().get_env() env = super().get_env()
env["PATH"].extend( env["PATH"].extend(
[ [
self.install_path, self.install_path,
pj(self.install_path, "upstream", "emscripten"), self.install_path / "upstream" / "emscripten",
pj(self.install_path, "node", "14.18.2_64bit", "bin"), self.install_path / "node" / "14.18.2_64bit" / "bin",
] ]
) )
env["EMSDK"] = self.install_path env["EMSDK"] = self.install_path
env["EMSDK_NODE"] = pj( env["EMSDK_NODE"] = (
self.install_path, "node", "14.18.2_64bit", "bin", "node" self.install_path / "node" / "14.18.2_64bit" / "bin" / "node"
) )
return env return env

View File

@ -1,7 +1,9 @@
import subprocess import subprocess
from pathlib import Path
from .base import ConfigInfo from .base import ConfigInfo
from kiwixbuild.utils import which, pj from kiwixbuild.utils import which
from kiwixbuild._global import neutralEnv from kiwixbuild._global import neutralEnv
@ -40,12 +42,12 @@ class Win32ConfigInfo(ConfigInfo):
self.buildEnv.meson_crossfile = self._gen_crossfile("meson_cross_file.txt") self.buildEnv.meson_crossfile = self._gen_crossfile("meson_cross_file.txt")
@property @property
def root_path(self): def root_path(self) -> Path:
root_paths = { root_paths = {
"fedora": "/usr/i686-w64-mingw32/sys-root/mingw", "fedora": "/usr/i686-w64-mingw32/sys-root/mingw",
"debian": "/usr/i686-w64-mingw32", "debian": "/usr/i686-w64-mingw32",
} }
return root_paths[neutralEnv("distname")] return Path(root_paths[neutralEnv("distname")])
@property @property
def binaries(self): def binaries(self):
@ -80,11 +82,11 @@ class Win32ConfigInfo(ConfigInfo):
env[k] = v env[k] = v
def get_bin_dir(self): def get_bin_dir(self):
return [pj(self.root_path, "bin")] return [self.root_path / "bin"]
def get_env(self): def get_env(self):
env = super().get_env() env = super().get_env()
env["PKG_CONFIG_LIBDIR"] = pj(self.root_path, "lib", "pkgconfig") env["PKG_CONFIG_LIBDIR"] = self.root_path / "lib" / "pkgconfig"
env["LIBS"] = " ".join(self.extra_libs) + " " + env["LIBS"] env["LIBS"] = " ".join(self.extra_libs) + " " + env["LIBS"]
return env return env

View File

@ -1,7 +1,8 @@
import subprocess import subprocess
from pathlib import Path
from .base import ConfigInfo from .base import ConfigInfo
from kiwixbuild.utils import which, pj from kiwixbuild.utils import which
from kiwixbuild._global import neutralEnv from kiwixbuild._global import neutralEnv
@ -44,12 +45,12 @@ class Win64ConfigInfo(ConfigInfo):
self.buildEnv.meson_crossfile = self._gen_crossfile("meson_cross_file.txt") self.buildEnv.meson_crossfile = self._gen_crossfile("meson_cross_file.txt")
@property @property
def root_path(self): def root_path(self) -> Path:
root_paths = { root_paths = {
"fedora": "/usr/x86_64-w64-mingw32/sys-root/mingw", "fedora": "/usr/x86_64-w64-mingw32/sys-root/mingw",
"debian": "/usr/x86_64-w64-mingw32", "debian": "/usr/x86_64-w64-mingw32",
} }
return root_paths[neutralEnv("distname")] return Path(root_paths[neutralEnv("distname")])
@property @property
def binaries(self): def binaries(self):
@ -84,11 +85,11 @@ class Win64ConfigInfo(ConfigInfo):
env[k] = v env[k] = v
def get_bin_dir(self): def get_bin_dir(self):
return [pj(self.root_path, "bin")] return [self.root_path / "bin"]
def get_env(self): def get_env(self):
env = super().get_env() env = super().get_env()
env["PKG_CONFIG_LIBDIR"] = pj(self.root_path, "lib", "pkgconfig") env["PKG_CONFIG_LIBDIR"] = self.root_path / "lib" / "pkgconfig"
env["LIBS"] = " ".join(self.extra_libs) + " " + env["LIBS"] env["LIBS"] = " ".join(self.extra_libs) + " " + env["LIBS"]
return env return env

View File

@ -1,7 +1,6 @@
from .base import ConfigInfo from .base import ConfigInfo
import sysconfig import sysconfig
from kiwixbuild.utils import pj
from kiwixbuild._global import get_target_step from kiwixbuild._global import get_target_step

View File

@ -1,9 +1,8 @@
import os
import shutil import shutil
from pathlib import Path from pathlib import Path
from kiwixbuild.configs import ConfigInfo from kiwixbuild.configs import ConfigInfo
from kiwixbuild.utils import pj, run_command from kiwixbuild.utils import run_command
from .base import Dependency, NoopSource, Builder as BaseBuilder from .base import Dependency, NoopSource, Builder as BaseBuilder
@ -48,11 +47,11 @@ class AppleXCFramework(Dependency):
return [(target, "libkiwix") for target in AppleXCFramework.subConfigNames] return [(target, "libkiwix") for target in AppleXCFramework.subConfigNames]
@property @property
def final_path(self): def final_path(self) -> Path:
return pj(self.buildEnv.install_dir, "lib", "CoreKiwix.xcframework") return self.buildEnv.install_dir / "lib" / "CoreKiwix.xcframework"
def _remove_if_exists(self, context): def _remove_if_exists(self, context):
if not os.path.exists(self.final_path): if not self.final_path.exists():
return return
shutil.rmtree(self.final_path) shutil.rmtree(self.final_path)
@ -64,8 +63,8 @@ class AppleXCFramework(Dependency):
static_ars = [] static_ars = []
cfg = ConfigInfo.get_config(target) cfg = ConfigInfo.get_config(target)
lib_dir = pj(cfg.buildEnv.install_dir, "lib") lib_dir = cfg.buildEnv.install_dir / "lib"
static_ars = [str(f) for f in Path(lib_dir).glob("*.a")] static_ars = [str(f) for f in lib_dir.glob("*.a")]
# create merged.a from all *.a in install_dir/lib # create merged.a from all *.a in install_dir/lib
command = ["libtool", "-static", "-o", "merged.a", *static_ars] command = ["libtool", "-static", "-o", "merged.a", *static_ars]
@ -73,7 +72,7 @@ class AppleXCFramework(Dependency):
# will be included in xcframework # will be included in xcframework
if target in self.ios_subconfigs: if target in self.ios_subconfigs:
xcf_libs.append(pj(lib_dir, "merged.a")) xcf_libs.append(lib_dir / "merged.a")
return xcf_libs return xcf_libs
@ -82,12 +81,12 @@ class AppleXCFramework(Dependency):
libs = [] libs = []
for target in configs: for target in configs:
cfg = ConfigInfo.get_config(target) cfg = ConfigInfo.get_config(target)
libs.append(pj(cfg.buildEnv.install_dir, "lib", "merged.a")) libs.append(cfg.buildEnv.install_dir / "lib" / "merged.a")
fat_dir = pj(self.buildEnv.build_dir, folder_name) fat_dir = self.buildEnv.build_dir / folder_name
os.makedirs(fat_dir, exist_ok=True) fad_dir.mkdir(parents=True, exist_ok=True)
output_merged = pj(fat_dir, "merged.a") output_merged = fat_dir / "merged.a"
command = ["lipo", "-create", "-output", output_merged, *libs] command = ["lipo", "-create", "-output", output_merged, *libs]
run_command(command, self.buildEnv.build_dir, context) run_command(command, self.buildEnv.build_dir, context)
@ -102,7 +101,7 @@ class AppleXCFramework(Dependency):
"-library", "-library",
lib, lib,
"-headers", "-headers",
pj(ref_conf.buildEnv.install_dir, "include"), ref_conf.buildEnv.install_dir / "include",
] ]
command += ["-output", self.final_path] command += ["-output", self.final_path]
run_command(command, self.buildEnv.build_dir, context) run_command(command, self.buildEnv.build_dir, context)

View File

@ -1,10 +1,10 @@
import subprocess import subprocess
import os
import shutil import shutil
import time import time
from pathlib import Path
from os import environ
from kiwixbuild.utils import ( from kiwixbuild.utils import (
pj,
Context, Context,
SkipCommand, SkipCommand,
WarningMessage, WarningMessage,
@ -17,7 +17,7 @@ from kiwixbuild.utils import (
from kiwixbuild.versions import main_project_versions, base_deps_versions from kiwixbuild.versions import main_project_versions, base_deps_versions
from kiwixbuild._global import neutralEnv, option, get_target_step from kiwixbuild._global import neutralEnv, option, get_target_step
SCRIPT_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) SCRIPT_DIR = Path(__file__).resolve().parent.parent
class _MetaDependency(type): class _MetaDependency(type):
@ -71,23 +71,23 @@ class Source:
return self.target.full_name() return self.target.full_name()
@property @property
def source_path(self): def source_path(self) -> Path:
return pj(neutralEnv("source_dir"), self.source_dir) return neutralEnv("source_dir") / self.source_dir
@property @property
def _log_dir(self): def _log_dir(self) -> Path:
return neutralEnv("log_dir") return neutralEnv("log_dir")
def _patch(self, context): def _patch(self, context):
context.try_skip(self.source_path) context.try_skip(self.source_path)
for p in self.patches: for p in self.patches:
patch_file_path = pj(SCRIPT_DIR, "patches", p) patch_file_path = SCRIPT_DIR / "patches" / p
patch_command = [*neutralEnv("patch_command"), "-p1", "-i", patch_file_path] patch_command = [*neutralEnv("patch_command"), "-p1", "-i", patch_file_path]
run_command(patch_command, self.source_path, context) run_command(patch_command, self.source_path, context)
def command(self, name, function, *args): def command(self, name, function, *args):
print(" {} {} : ".format(name, self.name), end="", flush=True) print(" {} {} : ".format(name, self.name), end="", flush=True)
log = pj(self._log_dir, "cmd_{}_{}.log".format(name, self.name)) log = self._log_dir / "cmd_{}_{}.log".format(name, self.name)
context = Context(name, log, True) context = Context(name, log, True)
try: try:
start_time = time.time() start_time = time.time()
@ -126,8 +126,8 @@ class ReleaseDownload(Source):
return (self.archive,) return (self.archive,)
@property @property
def extract_path(self): def extract_path(self) -> Path:
return pj(neutralEnv("source_dir"), self.source_dir) return neutralEnv("source_dir") / self.source_dir
def _download(self, context): def _download(self, context):
context.try_skip(neutralEnv("archive_dir"), self.full_name) context.try_skip(neutralEnv("archive_dir"), self.full_name)
@ -145,11 +145,11 @@ class ReleaseDownload(Source):
def _extract(self, context): def _extract(self, context):
context.try_skip(self.extract_path) context.try_skip(self.extract_path)
if os.path.exists(self.extract_path): if self.extract_path.exists():
shutil.rmtree(self.extract_path) shutil.rmtree(self.extract_path)
for archive in self.archives: for archive in self.archives:
extract_archive( extract_archive(
pj(neutralEnv("archive_dir"), archive.name), neutralEnv("archive_dir") / archive.name,
neutralEnv("source_dir"), neutralEnv("source_dir"),
topdir=self.archive_top_dir, topdir=self.archive_top_dir,
name=self.source_dir, name=self.source_dir,
@ -180,8 +180,8 @@ class GitClone(Source):
return self.git_dir return self.git_dir
@property @property
def git_path(self): def git_path(self) -> Path:
return pj(neutralEnv("source_dir"), self.source_dir) return neutralEnv("source_dir") / self.source_dir
@property @property
def git_ref(self): def git_ref(self):
@ -228,7 +228,7 @@ class GitClone(Source):
raise WarningMessage("Cannot update, please check log for information") raise WarningMessage("Cannot update, please check log for information")
def prepare(self): def prepare(self):
if not os.path.exists(self.git_path): if not self.git_path.exists():
self.command("gitinit", self._git_init) self.command("gitinit", self._git_init)
else: else:
self.command("gitupdate", self._git_update) self.command("gitupdate", self._git_update)
@ -254,23 +254,23 @@ class Builder:
return self.target.name return self.target.name
@property @property
def source_path(self): def source_path(self) -> Path:
base_source_path = self.source.source_path base_source_path = self.source.source_path
if self.subsource_dir: if self.subsource_dir:
return pj(base_source_path, self.subsource_dir) return base_source_path / self.subsource_dir
return base_source_path return base_source_path
@property @property
def build_path(self): def build_path(self) -> Path:
return pj(self.buildEnv.build_dir, self.target.full_name()) return self.buildEnv.build_dir / self.target.full_name()
@property @property
def _log_dir(self): def _log_dir(self) -> Path:
return self.buildEnv.log_dir return self.buildEnv.log_dir
def command(self, name, function, *args): def command(self, name, function, *args):
print(" {} {} : ".format(name, self.name), end="", flush=True) print(" {} {} : ".format(name, self.name), end="", flush=True)
log = pj(self._log_dir, "cmd_{}_{}.log".format(name, self.name)) log = self._log_dir / "cmd_{}_{}.log".format(name, self.name)
context = Context(name, log, self.target.force_native_build) context = Context(name, log, self.target.force_native_build)
if self.target.force_build: if self.target.force_build:
context.no_skip = True context.no_skip = True
@ -357,8 +357,8 @@ class TcCopyBuilder(Builder):
src_subdir = None src_subdir = None
@property @property
def build_path(self): def build_path(self) -> Path:
return pj(self.buildEnv.toolchain_dir, self.target.full_name()) return self.buildEnv.toolchain_dir / self.target.full_name()
def build(self): def build(self):
self.command("copy", self._copy) self.command("copy", self._copy)
@ -366,7 +366,7 @@ class TcCopyBuilder(Builder):
def _copy(self, context): def _copy(self, context):
context.try_skip(self.build_path) context.try_skip(self.build_path)
if self.src_subdir: if self.src_subdir:
source_path = pj(self.source_path, self.src_subdir) source_path = self.source_path / self.src_subdir
else: else:
source_path = self.source_path source_path = self.source_path
copy_tree(source_path, self.build_path) copy_tree(source_path, self.build_path)
@ -406,7 +406,7 @@ class MakeBuilder(Builder):
if not self.target.force_native_build: if not self.target.force_native_build:
yield from self.buildEnv.configInfo.configure_options yield from self.buildEnv.configInfo.configure_options
yield from ("--prefix", self.buildEnv.install_dir) yield from ("--prefix", self.buildEnv.install_dir)
yield from ("--libdir", pj(self.buildEnv.install_dir, self.buildEnv.libprefix)) yield from ("--libdir", self.buildEnv.install_dir / self.buildEnv.libprefix)
def set_configure_env(self, env): def set_configure_env(self, env):
dep_conf_env = self.configure_env dep_conf_env = self.configure_env
@ -423,7 +423,7 @@ class MakeBuilder(Builder):
context.try_skip(self.build_path) context.try_skip(self.build_path)
command = [ command = [
*self.buildEnv.configure_wrapper, *self.buildEnv.configure_wrapper,
pj(self.source_path, self.configure_script), self.source_path / self.configure_script,
*self.all_configure_options, *self.all_configure_options,
] ]
env = self.get_env(cross_comp_flags=True, cross_compilers=True, cross_path=True) env = self.get_env(cross_comp_flags=True, cross_compilers=True, cross_path=True)
@ -494,10 +494,10 @@ class QMakeBuilder(MakeBuilder):
@property @property
def env_options(self): def env_options(self):
if "QMAKE_CC" in os.environ: if "QMAKE_CC" in environ:
yield f"QMAKE_CC={os.environ['QMAKE_CC']}" yield f"QMAKE_CC={environ['QMAKE_CC']}"
if "QMAKE_CXX" in os.environ: if "QMAKE_CXX" in environ:
yield f"QMAKE_CXX={os.environ['QMAKE_CXX']}" yield f"QMAKE_CXX={environ['QMAKE_CXX']}"
def _configure(self, context): def _configure(self, context):
context.try_skip(self.build_path) context.try_skip(self.build_path)
@ -545,9 +545,9 @@ class MesonBuilder(Builder):
def _configure(self, context): def _configure(self, context):
context.try_skip(self.build_path) context.try_skip(self.build_path)
if os.path.exists(self.build_path): if self.build_path.exists():
shutil.rmtree(self.build_path) shutil.rmtree(self.build_path)
os.makedirs(self.build_path) self.build_path.mkdir(parents=True)
cross_options = [] cross_options = []
if not self.target.force_native_build and self.buildEnv.meson_crossfile: if not self.target.force_native_build and self.buildEnv.meson_crossfile:
cross_options += ["--cross-file", self.buildEnv.meson_crossfile] cross_options += ["--cross-file", self.buildEnv.meson_crossfile]

View File

@ -1,6 +1,7 @@
from .base import Dependency, ReleaseDownload, MakeBuilder, MesonBuilder from .base import Dependency, ReleaseDownload, MakeBuilder, MesonBuilder
from kiwixbuild.utils import pj, Remotefile, extract_archive from pathlib import Path
from kiwixbuild.utils import Remotefile, extract_archive
from kiwixbuild._global import get_target_step, neutralEnv from kiwixbuild._global import get_target_step, neutralEnv
import os, shutil import os, shutil
import fileinput import fileinput
@ -31,25 +32,25 @@ class Icu(Dependency):
def _extract(self, context): def _extract(self, context):
context.try_skip(self.extract_path) context.try_skip(self.extract_path)
if os.path.exists(self.extract_path): if self.extract_path.exists():
shutil.rmtree(self.extract_path) shutil.rmtree(self.extract_path)
extract_archive( extract_archive(
pj(neutralEnv("archive_dir"), self.archive_src.name), neutralEnv("archive_dir") / self.archive_src.name,
neutralEnv("source_dir"), neutralEnv("source_dir"),
topdir=None, topdir=None,
name=self.source_dir, name=self.source_dir,
) )
shutil.rmtree( shutil.rmtree(
pj(neutralEnv("source_dir"), self.source_dir, "source", "data") neutralEnv("source_dir") / self.source_dir / "source" / "data"
) )
extract_archive( extract_archive(
pj(neutralEnv("archive_dir"), self.archive_data.name), neutralEnv("archive_dir") / self.archive_data.name,
pj(neutralEnv("source_dir"), self.source_dir, "source"), neutralEnv("source_dir") / self.source_dir / "source",
topdir="data", topdir="data",
name="data", name="data",
) )
extract_archive( extract_archive(
pj(neutralEnv("archive_dir"), self.meson_patch.name), neutralEnv("archive_dir") / self.meson_patch.name,
neutralEnv("source_dir"), neutralEnv("source_dir"),
topdir="icu", topdir="icu",
name=self.source_dir, name=self.source_dir,
@ -69,9 +70,8 @@ class Icu(Dependency):
class Builder(MesonBuilder): class Builder(MesonBuilder):
def set_env(self, env): def set_env(self, env):
env["ICU_DATA_FILTER_FILE"] = pj( env["ICU_DATA_FILTER_FILE"] = (
os.path.dirname(os.path.realpath(__file__)), Path(__file__).resolve().parent / "icu4c_data_filter.json"
"icu4c_data_filter.json",
) )
else: else:
@ -105,18 +105,15 @@ class Icu(Dependency):
yield "--with-data-packaging=archive" yield "--with-data-packaging=archive"
def set_env(self, env): def set_env(self, env):
env["ICU_DATA_FILTER_FILE"] = pj( env["ICU_DATA_FILTER_FILE"] = (
os.path.dirname(os.path.realpath(__file__)), Path(__file__).resolve().parent / "icu4c_data_filter.json"
"icu4c_data_filter.json",
) )
def _post_configure_script(self, context): def _post_configure_script(self, context):
if self.buildEnv.configInfo.build != "wasm": if self.buildEnv.configInfo.build != "wasm":
context.skip() context.skip()
context.try_skip(self.build_path) context.try_skip(self.build_path)
for line in fileinput.input( for line in fileinput.input(self.build_path / "Makefile", inplace=True):
pj(self.build_path, "Makefile"), inplace=True
):
if line == "#DATASUBDIR = data\n": if line == "#DATASUBDIR = data\n":
print("DATASUBDIR = data") print("DATASUBDIR = data")
else: else:

View File

@ -1,7 +1,7 @@
import os import os
from kiwixbuild.configs import ConfigInfo from kiwixbuild.configs import ConfigInfo
from kiwixbuild.utils import pj, copy_tree, run_command from kiwixbuild.utils import copy_tree, run_command
from kiwixbuild._global import option from kiwixbuild._global import option
from .base import Dependency, NoopSource, Builder as BaseBuilder from .base import Dependency, NoopSource, Builder as BaseBuilder
@ -19,29 +19,29 @@ class IOSFatLib(Dependency):
def _copy_headers(self, context): def _copy_headers(self, context):
plt = ConfigInfo.get_config("iOS_{}".format(option("ios_arch")[0])) plt = ConfigInfo.get_config("iOS_{}".format(option("ios_arch")[0]))
include_src = pj(plt.buildEnv.install_dir, "include") include_src = plt.buildEnv.install_dir / "include"
include_dst = pj(self.buildEnv.install_dir, "include") include_dst = self.buildEnv.install_dir / "include"
copy_tree(include_src, include_dst) copy_tree(include_src, include_dst)
def _merge_libs(self, context): def _merge_libs(self, context):
lib_dirs = [] lib_dirs = []
for arch in option("ios_arch"): for arch in option("ios_arch"):
plt = ConfigInfo.get_config("iOS_{}".format(arch)) plt = ConfigInfo.get_config("iOS_{}".format(arch))
lib_dirs.append(pj(plt.buildEnv.install_dir, "lib")) lib_dirs.append(plt.buildEnv.install_dir / "lib")
libs = [] libs = []
for f in os.listdir(lib_dirs[0]): for f in lib_dirs[0].iterdir():
if os.path.islink(pj(lib_dirs[0], f)): if f.is_symlink():
continue continue
if f.endswith(".a") or f.endswith(".dylib"): if f.suffix in (".a", ".dylib"):
libs.append(f) libs.append(f)
os.makedirs(pj(self.buildEnv.install_dir, "lib"), exist_ok=True) (self.buildEnv.install_dir / "lib").mkdir(parents=True, exist_ok=True)
for l in libs: for l in libs:
command = [ command = [
"lipo", "lipo",
"-create", "-create",
*[pj(d, l) for d in lib_dirs], *[d / l for d in lib_dirs],
"-output", "-output",
pj(self.buildEnv.install_dir, "lib", l), self.buildEnv.install_dir / "lib" / l,
] ]
run_command(command, self.buildEnv.install_dir, context) run_command(command, self.buildEnv.install_dir, context)

View File

@ -4,7 +4,7 @@ from .base import (
MakeBuilder, MakeBuilder,
) )
from kiwixbuild.utils import Remotefile, pj, run_command from kiwixbuild.utils import Remotefile, run_command
from kiwixbuild._global import get_target_step from kiwixbuild._global import get_target_step
@ -44,5 +44,5 @@ class LibMagic(Dependency):
cross_comp_flags=True, cross_compilers=True, cross_path=True cross_comp_flags=True, cross_compilers=True, cross_path=True
) )
libmagic_native_builder = get_target_step("libmagic", "native_static") libmagic_native_builder = get_target_step("libmagic", "native_static")
env["PATH"].insert(0, pj(libmagic_native_builder.build_path, "src")) env["PATH"].insert(0, libmagic_native_builder.build_path / "src")
run_command(command, self.build_path, context, env=env) run_command(command, self.build_path, context, env=env)

View File

@ -1,6 +1,6 @@
from .base import Dependency, ReleaseDownload, Builder as BaseBuilder from .base import Dependency, ReleaseDownload, Builder as BaseBuilder
from kiwixbuild.utils import Remotefile, pj from kiwixbuild.utils import Remotefile
from shutil import copy2 from shutil import copy2
@ -21,8 +21,8 @@ class Mustache(Dependency):
def _copy_header(self, context): def _copy_header(self, context):
context.try_skip(self.build_path) context.try_skip(self.build_path)
copy2( copy2(
pj(self.source_path, "mustache.hpp"), self.source_path / "mustache.hpp",
pj(self.buildEnv.install_dir, "include"), self.buildEnv.install_dir / "include",
) )
def set_flatpak_buildsystem(self, module): def set_flatpak_buildsystem(self, module):

View File

@ -1,6 +1,6 @@
from .base import Dependency, ReleaseDownload, MakeBuilder, QMakeBuilder from .base import Dependency, ReleaseDownload, MakeBuilder, QMakeBuilder
from kiwixbuild.utils import Remotefile, pj from kiwixbuild.utils import Remotefile
class Qt(Dependency): class Qt(Dependency):
@ -32,7 +32,7 @@ class Qt(Dependency):
yield from ("-prefix", self.buildEnv.install_dir) yield from ("-prefix", self.buildEnv.install_dir)
yield from ( yield from (
"-libdir", "-libdir",
pj(self.buildEnv.install_dir, self.buildEnv.libprefix), self.buildEnv.install_dir / self.buildEnv.libprefix,
) )
@property @property

View File

@ -1,7 +1,6 @@
import os from pathlib import Path
from .base import Dependency, ReleaseDownload, Builder from .base import Dependency, ReleaseDownload, Builder
from kiwixbuild.utils import Remotefile, add_execution_right, run_command, pj from kiwixbuild.utils import Remotefile, add_execution_right, run_command
class android_ndk(Dependency): class android_ndk(Dependency):
@ -24,8 +23,8 @@ class android_ndk(Dependency):
class Builder(Builder): class Builder(Builder):
@property @property
def install_path(self): def install_path(self) -> Path:
return pj(self.buildEnv.toolchain_dir, self.target.full_name()) return self.buildEnv.toolchain_dir / self.target.full_name()
@property @property
def api(self): def api(self):
@ -45,7 +44,7 @@ class android_ndk(Dependency):
def _build_toolchain(self, context): def _build_toolchain(self, context):
context.try_skip(self.build_path) context.try_skip(self.build_path)
script = pj(self.source_path, "build/tools/make_standalone_toolchain.py") script = self.source_path / "build/tools/make_standalone_toolchain.py"
add_execution_right(script) add_execution_right(script)
command = [ command = [
script, script,
@ -62,23 +61,21 @@ class android_ndk(Dependency):
def _fix_permission_right(self, context): def _fix_permission_right(self, context):
context.try_skip(self.build_path) context.try_skip(self.build_path)
bin_dirs = [ bin_dirs = [
pj(self.install_path, "bin"), self.install_path / "bin",
pj(self.install_path, self.arch_full, "bin"), self.install_pat / self.arch_full / "bin",
pj( self.install_path
self.install_path, / "libexec"
"libexec", / "gcc"
"gcc", / self.arch_full
self.arch_full, / self.target.gccver,
self.target.gccver,
),
] ]
for root, dirs, files in os.walk(self.install_path): for root, dirs, files in self.install_path.walk():
if not root in bin_dirs: if not root in bin_dirs:
continue continue
for file_ in files: for file_ in files:
file_path = pj(root, file_) file_path = root / file_
if os.path.islink(file_path): if file_path.is_symlink():
continue continue
add_execution_right(file_path) add_execution_right(file_path)

View File

@ -1,5 +1,6 @@
from pathlib import Path
from .base import Dependency, ReleaseDownload, Builder from .base import Dependency, ReleaseDownload, Builder
from kiwixbuild.utils import pj, Remotefile, run_command, copy_tree from kiwixbuild.utils import Remotefile, run_command, copy_tree
class emsdk(Dependency): class emsdk(Dependency):
@ -20,8 +21,8 @@ class emsdk(Dependency):
class Builder(Builder): class Builder(Builder):
@property @property
def install_path(self): def install_path(self) -> Path:
return pj(self.buildEnv.toolchain_dir, self.target.full_name()) return self.buildEnv.toolchain_dir / self.target.full_name()
def _copy_source(self, context): def _copy_source(self, context):
context.try_skip(self.build_path) context.try_skip(self.build_path)

View File

@ -1,6 +1,6 @@
from .base import Dependency, ReleaseDownload, MakeBuilder from .base import Dependency, ReleaseDownload, MakeBuilder
from kiwixbuild.utils import Remotefile, pj from kiwixbuild.utils import Remotefile
from kiwixbuild._global import neutralEnv from kiwixbuild._global import neutralEnv
@ -17,7 +17,7 @@ class Xapian(Dependency):
@property @property
def configure_options(self): def configure_options(self):
if neutralEnv("distname") == "Windows": if neutralEnv("distname") == "Windows":
compile_script = pj(self.source_path, "compile") compile_script = self.source_path / "compile"
return [ return [
'CC="cl -nologo"', 'CC="cl -nologo"',
'CXX=f"{compile_script} cl -nologo"', 'CXX=f"{compile_script} cl -nologo"',

View File

@ -206,9 +206,8 @@ class FlatpakBuilder:
m["sources"] = temp m["sources"] = temp
manifest["modules"] = modules manifest["modules"] = modules
manifest_name = "{}.json".format(MANIFEST["app-id"]) manifest_name = "{}.json".format(MANIFEST["app-id"])
manifest_path = pj(self.config.buildEnv.build_dir, manifest_name) manifest_path = self.config.buildEnv.build_dir / manifest_name
with open(manifest_path, "w") as f: manifest_path.write_text(json.dumps(manifest, indent=4))
f.write(json.dumps(manifest, indent=4))
def copy_patches(self): def copy_patches(self):
sourceDefs = (tDef for tDef in target_steps() if tDef[0] == "source") sourceDefs = (tDef for tDef in target_steps() if tDef[0] == "source")
@ -217,15 +216,15 @@ class FlatpakBuilder:
if not hasattr(source, "patches"): if not hasattr(source, "patches"):
continue continue
for p in source.patches: for p in source.patches:
path = pj(SCRIPT_DIR, "patches", p) path = SCRIPT_DIR / "patches" / p
os.makedirs( (self.config.buildEnv.build_dir / "patches").mkdir(
pj(self.config.buildEnv.build_dir, "patches"), exist_ok=True parents=True, exist_ok=True
) )
dest = pj(self.config.buildEnv.build_dir, "patches", p) dest = self.config.buildEnv.build_dir / "patches" / p
copyfile(path, dest) copyfile(path, dest)
def build(self): def build(self):
log = pj(self.config.buildEnv.log_dir, "cmd_build_flatpak.log") log = self.config.buildEnv.log_dir / "cmd_build_flatpak.log"
context = Context("build", log, False) context = Context("build", log, False)
command = [ command = [
"flatpak-builder", "flatpak-builder",
@ -247,12 +246,11 @@ class FlatpakBuilder:
) )
context._finalise() context._finalise()
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
with open(log, "r") as f: print(log.read_text())
print(f.read())
raise StopBuild() raise StopBuild()
def bundle(self): def bundle(self):
log = pj(self.config.buildEnv.log_dir, "cmd_bundle_flatpak.log") log = self.config.buildEnv.log_dir / "cmd_bundle_flatpak.log"
context = Context("bundle", log, False) context = Context("bundle", log, False)
app_id = MANIFEST["app-id"] app_id = MANIFEST["app-id"]
command = ["flatpak", "build-bundle", "repo", f"{app_id}.flatpak", app_id] command = ["flatpak", "build-bundle", "repo", f"{app_id}.flatpak", app_id]
@ -265,8 +263,7 @@ class FlatpakBuilder:
) )
context._finalise() context._finalise()
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
with open(log, "r") as f: print(log.read_text())
print(f.read())
raise StopBuild() raise StopBuild()
def _get_packages(self): def _get_packages(self):

View File

@ -1,4 +1,3 @@
import os.path
import hashlib import hashlib
import tarfile, zipfile import tarfile, zipfile
import tempfile import tempfile
@ -9,15 +8,12 @@ import urllib.error
import ssl import ssl
import subprocess import subprocess
import re import re
from pathlib import Path
from collections import namedtuple, defaultdict from collections import namedtuple, defaultdict
from kiwixbuild._global import neutralEnv, option from kiwixbuild._global import neutralEnv, option
def pj(*args):
return os.path.normpath(os.path.join(*args))
COLORS = { COLORS = {
"OK": "\033[92m", "OK": "\033[92m",
"WARNING": "\033[93m", "WARNING": "\033[93m",
@ -46,7 +42,7 @@ def xrun_find(name):
regex_space = re.compile(r"((?<!\\) )") regex_space = re.compile(r"((?<!\\) )")
def escape_path(path): def escape_path(path: Path):
path = str(path) path = str(path)
return regex_space.sub(r"\ ", path) return regex_space.sub(r"\ ", path)
@ -87,7 +83,7 @@ class PathArray(list):
super().__init__(value.split(self.separator)) super().__init__(value.split(self.separator))
def __str__(self): def __str__(self):
return self.separator.join(self) return self.separator.join((str(v) for v in self))
def remove_duplicates(iterable, key_function=None): def remove_duplicates(iterable, key_function=None):
@ -102,12 +98,12 @@ def remove_duplicates(iterable, key_function=None):
yield elem yield elem
def get_sha256(path): def get_sha256(path: Path):
progress_chars = "/-\\|" progress_chars = "/-\\|"
current = 0 current = 0
batch_size = 1024 * 8 batch_size = 1024 * 8
sha256 = hashlib.sha256() sha256 = hashlib.sha256()
with open(path, "br") as f: with path.open("br") as f:
while True: while True:
batch = f.read(batch_size) batch = f.read(batch_size)
if not batch: if not batch:
@ -130,30 +126,37 @@ def print_progress(progress):
print(text, end="") print(text, end="")
def add_execution_right(file_path): def add_execution_right(file_path: Path):
current_permissions = stat.S_IMODE(os.lstat(file_path).st_mode) current_permissions = stat.S_IMODE(os.lstat(file_path).st_mode)
os.chmod(file_path, current_permissions | stat.S_IXUSR) file_path.chmod(current_permissions | stat.S_IXUSR)
def copy_tree(src, dst, post_copy_function=None): def copy_tree(src: Path, dst: Path, post_copy_function=None):
os.makedirs(dst, exist_ok=True) dst.mkdir(parents=True, exist_ok=True)
for root, dirs, files in os.walk(src): for root, dirs, files in src.walk():
r = os.path.relpath(root, src) r = root.relative_to(src)
dstdir = pj(dst, r) dstdir = dst / r
os.makedirs(dstdir, exist_ok=True) dstdir.mkdir(exist_ok=True)
for f in files: for f in files:
dstfile = pj(dstdir, f) dstfile = dstdir / f
shutil.copy2(pj(root, f), dstfile, follow_symlinks=False) shutil.copy2(root / f, dstfile, follow_symlinks=False)
if post_copy_function is not None: if post_copy_function is not None:
post_copy_function(dstfile) post_copy_function(dstfile)
def download_remote(what, where): class Remotefile(namedtuple("Remotefile", ("name", "sha256", "url"))):
file_path = pj(where, what.name) def __new__(cls, name, sha256, url=None):
if os.path.exists(file_path): if url is None:
url = REMOTE_PREFIX + name
return super().__new__(cls, name, sha256, url)
def download_remote(what: Remotefile, where: Path):
file_path = where / what.name
if file_path.exists():
if what.sha256 == get_sha256(file_path): if what.sha256 == get_sha256(file_path):
raise SkipCommand() raise SkipCommand()
os.remove(file_path) file_path.unlink()
if option("no_cert_check"): if option("no_cert_check"):
context = ssl.create_default_context() context = ssl.create_default_context()
@ -165,8 +168,8 @@ def download_remote(what, where):
extra_args = {"context": context} if sys.version_info >= (3, 4, 3) else {} extra_args = {"context": context} if sys.version_info >= (3, 4, 3) else {}
progress_chars = "/-\\|" progress_chars = "/-\\|"
try: try:
with urllib.request.urlopen(what.url, **extra_args) as resource, open( with urllib.request.urlopen(what.url, **extra_args) as resource, file_path.open(
file_path, "wb" "wb"
) as file: ) as file:
tsize = resource.info().get("Content-Length", None) tsize = resource.info().get("Content-Length", None)
if tsize is not None: if tsize is not None:
@ -190,7 +193,7 @@ def download_remote(what, where):
if not what.sha256: if not what.sha256:
print("Sha256 for {} not set, do no verify download".format(what.name)) print("Sha256 for {} not set, do no verify download".format(what.name))
elif what.sha256 != get_sha256(file_path): elif what.sha256 != get_sha256(file_path):
os.remove(file_path) file_path.unlink()
raise StopBuild("Sha 256 doesn't correspond") raise StopBuild("Sha 256 doesn't correspond")
@ -218,13 +221,6 @@ class StopBuild(BaseCommandResult):
pass pass
class Remotefile(namedtuple("Remotefile", ("name", "sha256", "url"))):
def __new__(cls, name, sha256, url=None):
if url is None:
url = REMOTE_PREFIX + name
return super().__new__(cls, name, sha256, url)
class Context: class Context:
def __init__(self, command_name, log_file, force_native_build): def __init__(self, command_name, log_file, force_native_build):
self.command_name = command_name self.command_name = command_name
@ -236,24 +232,28 @@ class Context:
def skip(self, msg=""): def skip(self, msg=""):
raise SkipCommand(msg) raise SkipCommand(msg)
def try_skip(self, path, extra_name=""): def try_skip(self, path: Path, extra_name=""):
if self.no_skip: if self.no_skip:
return return
if extra_name: if extra_name:
extra_name = "_{}".format(extra_name) extra_name = "_{}".format(extra_name)
self.autoskip_file = pj(path, ".{}{}_ok".format(self.command_name, extra_name)) self.autoskip_file = path / ".{}{}_ok".format(self.command_name, extra_name)
if os.path.exists(self.autoskip_file): if self.autoskip_file.exists():
raise SkipCommand() raise SkipCommand()
def _finalise(self): def _finalise(self):
if self.autoskip_file is not None: if self.autoskip_file is not None:
os.makedirs(os.path.dirname(self.autoskip_file), exist_ok=True) self.autoskip_file.parent.mkdir(parents=True, exist_ok=True)
with open(self.autoskip_file, "w"): self.autoskip_file.touch()
pass
def extract_archive(archive_path, dest_dir, topdir=None, name=None): def extract_archive(archive_path: Path, dest_dir: Path, topdir=None, name=None):
is_zip_archive = archive_path.endswith(".zip") """Extract an archive to dest_dir.
This archive can be a zip or a tar archive.
If topdir is given, only this directory (and sub files/dirs) will be extracted.
If name is given, the topdir will be extracted under this name.
"""
is_zip_archive = archive_path.suffix == ".zip"
archive = None archive = None
try: try:
if is_zip_archive: if is_zip_archive:
@ -283,40 +283,39 @@ def extract_archive(archive_path, dest_dir, topdir=None, name=None):
members_to_extract = [ members_to_extract = [
m for m in members if getname(m).startswith(topdir + "/") m for m in members if getname(m).startswith(topdir + "/")
] ]
os.makedirs(dest_dir, exist_ok=True) dest_dir.mkdir(parents=True, exist_ok=True)
with tempfile.TemporaryDirectory( with tempfile.TemporaryDirectory(
prefix=os.path.basename(archive_path), dir=dest_dir prefix=archive_path.name, dir=dest_dir
) as tmpdir: ) as tmpdir:
tmpdir_path = Path(tmpdir)
if is_zip_archive: if is_zip_archive:
_members_to_extract = [getname(m) for m in members_to_extract] _members_to_extract = [getname(m) for m in members_to_extract]
else: else:
_members_to_extract = members_to_extract _members_to_extract = members_to_extract
archive.extractall(path=tmpdir, members=_members_to_extract) archive.extractall(path=tmpdir_path, members=_members_to_extract)
if is_zip_archive: if is_zip_archive:
for member in members_to_extract: for member in members_to_extract:
if isdir(member): if isdir(member):
continue continue
perm = (member.external_attr >> 16) & 0x1FF perm = (member.external_attr >> 16) & 0x1FF
if perm: if perm:
os.chmod(pj(tmpdir, getname(member)), perm) (tmpdir_path / getname(member)).chmod(perm)
name = name or topdir name = name or topdir
shutil.copytree( shutil.copytree(
pj(tmpdir, topdir), tmpdir_path / topdir,
pj(dest_dir, name), dest_dir / name,
symlinks=True, symlinks=True,
dirs_exist_ok=True, dirs_exist_ok=True,
) )
# Be sure that all directory in tmpdir are writable to allow correct suppersion of it # Be sure that all directory in tmpdir are writable to allow correct suppersion of it
for root, dirs, _files in os.walk(tmpdir): for root, dirs, _files in tmpdir_path.walk():
for d in dirs: for d in dirs:
os.chmod( (root / d).chmod(stat.S_IWRITE | stat.S_IREAD | stat.S_IEXEC)
pj(root, d), stat.S_IWRITE | stat.S_IREAD | stat.S_IEXEC
)
else: else:
if name: if name:
dest_dir = pj(dest_dir, name) dest_dir = dest_dir / name
os.makedirs(dest_dir) dest_dir.mkdir(parents=True)
archive.extractall(path=dest_dir) archive.extractall(path=dest_dir)
finally: finally:
if archive is not None: if archive is not None:
@ -328,6 +327,7 @@ def run_command(command, cwd, context, *, env=None, input=None):
if env is None: if env is None:
env = DefaultEnv() env = DefaultEnv()
log = None log = None
command = [str(v) for v in command]
try: try:
if not option("verbose"): if not option("verbose"):
log = open(context.log_file, "w") log = open(context.log_file, "w")