diff --git a/build.sh b/build.sh index 5d1978e..1537751 100755 --- a/build.sh +++ b/build.sh @@ -9,6 +9,6 @@ CONFIG_DIR="$(dirname "$0")" && if [ -z "$4" ]; then exec flatpak-builder $3 --arch "$2" --rebuild-on-sdk-change "$BUILD_DIR" "$1" else - HASH="$("$CONFIG_DIR/hash_modules.py" "$1" "$2" | sed -n '1p')" && + HASH="$("$CONFIG_DIR/hash_modules.py" --installed "$1" "$2" | sed -n '1p')" && exec flatpak-builder $3 --arch "$2" --rebuild-on-sdk-change --gpg-sign=winebarrels@marko10-000.de --repo "$4" -s "WB_HASH='${HASH}'" "$BUILD_DIR" "$1" fi \ No newline at end of file diff --git a/build_when_required.sh b/build_when_required.sh new file mode 100755 index 0000000..60edc1e --- /dev/null +++ b/build_when_required.sh @@ -0,0 +1,8 @@ +#! /usr/bin/env bash +# Args: [] + +CONFIG_DIR="$(dirname "$0")" && +"$CONFIG_DIR/hash_modules.py" --require-build --installed "$1" "$2" && +exec "$CONFIG_DIR/build.sh" "$@" + +echo "No rebuild required." \ No newline at end of file diff --git a/hash_modules.py b/hash_modules.py index 485d814..88c39bc 100755 --- a/hash_modules.py +++ b/hash_modules.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +import configparser import hashlib +import io import itertools import json import os @@ -25,21 +27,46 @@ def list_remotes(verbose=False): return result -def commit_hashes(name, verbose=False): +def commit_hashes(name, use_local=False, verbose=False): result = [] - for i in list_remotes(verbose=verbose): - out = None - try: - out = _load_stdout(["flatpak", "remote-info", "--user", "-c", i, name]).lower() - except RuntimeError: - pass - if out is not None: - out = out.splitlines()[0] - for i in filter(lambda x: not(b"a"[0] <= x <= b"z"[0] or b"0"[0] <= x <= b"9"[0]), out): - raise ValueError("Wrong char: " + repr(bytes([i]))) - result.append(out.decode()) + if use_local: + result = [_load_stdout(["flatpak", "info", "--user", "-c", name]).lower()] + else: + for i in list_remotes(verbose=verbose): + out = None + try: + out = _load_stdout(["flatpak", "remote-info", "--user", "-c", i, name]).lower() + except RuntimeError: + pass + if out is not None: + out = out.splitlines()[0] + for i in filter(lambda x: not(b"a"[0] <= x <= b"z"[0] or b"0"[0] <= x <= b"9"[0]), out): + raise ValueError("Wrong char: " + repr(bytes([i]))) + result.append(out.decode()) if verbose: - print("Commit hashes for " + name + ": " + ", ".join(result), file=sys.stderr) + if use_local: + print("Commit local hashes for " + name + ": " + ", ".join(result), file=sys.stderr) + else: + print("Commit remote hashes for " + name + ": " + ", ".join(result), file=sys.stderr) + return result + + +def commit_metas(name, use_local=False, verbose=False): + result = [] + if use_local: + result = [_load_stdout(["flatpak", "info", "--user", "-m", name])] + else: + for i in list_remotes(verbose=verbose): + out = None + try: + out = _load_stdout(["flatpak", "remote-info", "--user", "-m", i, name]) + except RuntimeError: + pass + if out is not None: + out = out.splitlines()[0] + for i in filter(lambda x: not(b"a"[0] <= x <= b"z"[0] or b"0"[0] <= x <= b"9"[0]), out): + raise ValueError("Wrong char: " + repr(bytes([i]))) + result.append(out.decode()) return result @@ -104,25 +131,67 @@ class ModuleLoader(): tmp = tmp.encode("utf-8") return function(tmp) - def get_depends(self, arch): + def get_depends(self, arch, use_local=False, verbose=False): version_src = "/" + arch + "/" + self.content["runtime-version"] - result = [self.content["sdk"] + version_src, - self.content["runtime"] + version_src] + result = [[self.content["sdk"] + version_src], + [self.content["runtime"] + version_src]] + + # Sdk extensions + if "sdk-extensions" in self.content: + # Parse meta config + meta = [] + for i in commit_metas(self.content["sdk"] + version_src, use_local=use_local, verbose=verbose): + config = configparser.ConfigParser() + config.readfp(io.BytesIO(i)) + meta.append(config) + + # Parse extensions + for i in self.content["sdk-extensions"]: + iSplit = i.split(".") + ext_result = set() + for config in meta: + for jSize in range(1, len(iSplit) + 1): + j = ".".join(iSplit[:jSize]) + + # Try version + try: + tmp = config.get("Extension " + j, "version") + ext_result.add(i + "/" + arch + "/" + tmp) + except configparser.NoSectionError: + pass + + # Try versions + try: + tmp = config.get("Extension " + j, "versions").split(";") + ext_result = ext_result.union(set(map(lambda x: i + "/" + arch + "/" + x, tmp))) + except configparser.NoSectionError: + pass + result.append(list(ext_result)) + + # Debug output + if verbose: + print("Flatpak depends: " + "\n".join(map(repr, result)), file=sys.stderr) return result - def hashes_from_base_platforms(self, arch, function, verbose=False): + def hashes_from_base_platforms(self, arch, function, use_local=False, verbose=False): # Get source - source = None def helper_func(content): - nonlocal source - source = content - self.hash_content(helper_func) + return function(content) + sourceHash = self.hash_content(helper_func) # Build hashes - base_hashes = list(map(lambda x: list(map(lambda y: y.encode("utf-8"), commit_hashes(x, verbose=verbose))), self.get_depends(arch))) - result = list(map(lambda x: function(b"\x00".join(x) + b"\x00" + source), itertools.product(*base_hashes))) + base_hashes = [] + for i in self.get_depends(arch, use_local=use_local, verbose=verbose): + tmp = set() + for j in i: + tmp = tmp.union(set(map(lambda x: x.encode("utf-8").lower(), commit_hashes(j, use_local=use_local, verbose=verbose)))) + base_hashes.append(sorted(tmp)) + result = list(map(lambda x: function(b"\x00".join(x) + b"\x00" + sourceHash), itertools.product(*base_hashes))) if verbose: - print("Local hashes for: " + ", ".join(result), file=sys.stderr) + if use_local: + print("Local hashes for: " + ", ".join(map(bytes.decode, result)), file=sys.stderr) + else: + print("Remote hashes for: " + ", ".join(map(bytes.decode, result)), file=sys.stderr) return result def old_wb_hashes(self, arch, verbose=False): @@ -133,15 +202,15 @@ class ModuleLoader(): result += wb_hashes(self.content["id-platform"] + version_target, verbose=verbose) return result - def version_hashes(self, arch, verbose=False): + def version_hashes(self, arch, use_local=False, verbose=False): def func(data): tmp = hashlib.sha3_256() tmp.update(data) - return tmp.hexdigest() - return self.hashes_from_base_platforms(arch, func, verbose=verbose) + return tmp.hexdigest().encode() + return list(map(bytes.decode, self.hashes_from_base_platforms(arch, func, use_local=use_local, verbose=verbose))) - def required_update(self, arch, verbose=False): - own_hash = set(self.version_hashes(arch, verbose=verbose)) + def required_update(self, arch, use_local=False, verbose=False): + own_hash = set(self.version_hashes(arch, use_local=use_local, verbose=verbose)) old_hashes = set(self.old_wb_hashes(arch, verbose=verbose)) return len(own_hash.intersection(old_hashes)) == 0 @@ -149,13 +218,13 @@ class ModuleLoader(): return os.path.abspath(os.path.join(os.path.split(self.path)[0], file)) -def get_need_update(source, arch, verbose=False): +def get_need_update(source, arch, use_local=False, verbose=False): mod = ModuleLoader(source) - return mod.required_update(arch, verbose=verbose) + return mod.required_update(arch, use_local=use_local, verbose=verbose) -def get_own_hash(source, arch, verbose=False): +def get_own_hash(source, arch, use_local=False, verbose=False): mod = ModuleLoader(source) - tmp = mod.version_hashes(arch, verbose=verbose) + tmp = mod.version_hashes(arch, use_local=use_local, verbose=verbose) if len(tmp) != 1: raise ValueError("No unique version number possible.") return tmp[0] @@ -172,14 +241,16 @@ if __name__ == '__main__': help="The arch to build.") parser.add_argument("--require-build", dest="rebuild", action="store_const", const=True, default=False, help="Returns 0 when outdated.") + parser.add_argument("--installed", dest="installed", action="store_const", + const=True, default=False, help="Use installed then remote.") parser.add_argument("-v", "--verbose", dest="verbose", action="store_const", const=True, default=False, help="Verbose information to stderr.") args = parser.parse_args() if args.rebuild: - if get_need_update(args.file[0], args.arch[0], verbose=args.verbose): + if get_need_update(args.file[0], args.arch[0], use_local=args.installed, verbose=args.verbose): exit(0) else: exit(1) else: - print(get_own_hash(args.file[0], args.arch[0], verbose=args.verbose)) + print(get_own_hash(args.file[0], args.arch[0], use_local=args.installed, verbose=args.verbose))