diff --git a/pmb/build/buildinfo.py b/pmb/build/buildinfo.py
index 745ddaec..b812a697 100644
--- a/pmb/build/buildinfo.py
+++ b/pmb/build/buildinfo.py
@@ -67,7 +67,7 @@ def generate(args, apk_path, arch, suffix, apkbuild):
"pkgver": apkbuild["pkgver"],
"pkgrel": apkbuild["pkgrel"],
"arch": arch,
- "versions": []}
+ "versions": {}}
# Add makedepends versions
installed = pmb.chroot.apk.installed(args, suffix)
@@ -75,8 +75,7 @@ def generate(args, apk_path, arch, suffix, apkbuild):
get_depends_recursively(args, [apkbuild["pkgname"], "abuild", "build-base"]))
for pkgname in relevant:
if pkgname in installed:
- ret["versions"].append(installed[pkgname]["package"])
- ret["versions"].sort()
+ ret["versions"][pkgname] = installed[pkgname]["version"]
return ret
diff --git a/pmb/build/other.py b/pmb/build/other.py
index 605d7c6c..bffd5e19 100644
--- a/pmb/build/other.py
+++ b/pmb/build/other.py
@@ -96,8 +96,8 @@ def is_necessary(args, arch, apkbuild, apkindex_path=None):
if pmb.parse.apkindex.compare_version(version_old,
version_new) == 1:
logging.warning("WARNING: Package '" + package + "' in your aports folder"
- " has version " + version_old + ", but the binary package"
- " repositories already have version " + version_new + "!")
+ " has version " + version_new + ", but the binary package"
+ " repositories already have version " + version_old + "!")
return False
# b) Aports folder has a newer version
diff --git a/pmb/challenge/build.py b/pmb/challenge/build.py
index 3fa2bdf9..b4c5586b 100644
--- a/pmb/challenge/build.py
+++ b/pmb/challenge/build.py
@@ -21,7 +21,6 @@ import json
import os
import pmb.build
import pmb.parse.apkbuild
-import pmb.parse.other
import pmb.helpers.repo
import pmb.challenge
@@ -37,23 +36,17 @@ def build(args, apk_path):
with open(buildinfo_path) as handle:
buildinfo = json.load(handle)
- # Parse and install all packages listed in versions
- versions = {}
- for package in buildinfo["versions"]:
- split = pmb.parse.other.package_split(package)
- pkgname = split["pkgname"]
- versions[pkgname] = split
- pmb.chroot.apk.install(args, versions.keys())
+ # Install all listed packages
+ pmb.chroot.apk.install(args, buildinfo["versions"].keys())
# Verify the installed versions
installed = pmb.chroot.apk.installed(args)
- for pkgname, split in versions.items():
- package_installed = installed[pkgname]["package"]
- package_buildinfo = split["package"]
- if package_installed != package_buildinfo:
+ for pkgname, version in buildinfo["versions"].items():
+ version_installed = installed[pkgname]["version"]
+ if version_installed != version:
raise RuntimeError("Dependency " + pkgname + " version is different"
- " (installed: " + package_installed + ","
- " buildinfo: " + package_buildinfo + ")!")
+ " (installed: " + version_installed + ","
+ " buildinfo: " + version + ")!")
# Build the package
repo_before = pmb.helpers.repo.files(args)
pmb.build.package(args, buildinfo["pkgname"], buildinfo["arch"],
diff --git a/pmb/chroot/apk.py b/pmb/chroot/apk.py
index dde27c29..a4547681 100644
--- a/pmb/chroot/apk.py
+++ b/pmb/chroot/apk.py
@@ -16,11 +16,11 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pmbootstrap. If not, see .
"""
+import os
import logging
import pmb.chroot
import pmb.config
import pmb.parse.apkindex
-import pmb.parse.other
def check_min_version(args, suffix="native"):
@@ -28,23 +28,29 @@ def check_min_version(args, suffix="native"):
Check the minimum apk version, before running it the first time in the
current session (lifetime of one pmbootstrap call).
"""
+
# Skip if we already did this
if suffix in args.cache["apk_min_version_checked"]:
return
- # Read the version from apk and from the config
- pkgver = pmb.chroot.root(args, ["apk", "--version"], suffix,
- return_stdout=True)
- pkgver = pkgver.split(" ")[1].split(",")[0]
- pkgver_min = pmb.config.apk_tools_static_min_version.split("-")[0]
+ # Skip if apk is not installed yet
+ if not os.path.exists(args.work + "/chroot_" + suffix + "/sbin/apk"):
+ logging.debug("NOTE: Skipped apk version check for chroot '" + suffix +
+ "', because it is not installed yet!")
+ return
# Compare
- if pmb.parse.apkindex.compare_version(pkgver, pkgver_min) == -1:
+ version_installed = installed(args, suffix)["apk-tools"]["version"]
+ version_min = pmb.config.apk_tools_static_min_version
+ if pmb.parse.apkindex.compare_version(
+ version_installed, version_min) == -1:
raise RuntimeError("You have an outdated version of the 'apk' package"
- " manager installed (your version: " + pkgver +
- ", expected at least: " + pkgver_min + "). Delete"
+ " manager installed (your version: " + version_installed +
+ ", expected at least: " + version_min + "). Delete"
" your http cache and zap all chroots, then try again:"
" 'pmbootstrap zap -hc'")
+
+ # Mark this suffix as checked
args.cache["apk_min_version_checked"].append(suffix)
@@ -101,19 +107,19 @@ def upgrade(args, suffix="native", update_index=True):
def installed(args, suffix="native"):
"""
- Get all installed packages and their versions.
- :returns: { "hello-world": {"package": "hello-world-1-r2", "pkgrel": "2",
- "pkgver": "1", "pkgname": "hello-world"}, ...}
+ Read the list of installed packages (which has almost the same format, as
+ an APKINDEX, but with more keys).
+ :returns: a dictionary with the following structure:
+ { "postmarketos-mkinitfs":
+ {
+ "pkgname": "postmarketos-mkinitfs"
+ "version": "0.0.4-r10",
+ "depends": ["busybox-extras", "lddtree", ...],
+ "provides": ["mkinitfs=0.0.1"]
+ }, ...
+ }
"""
- check_min_version(args, suffix)
- list = pmb.chroot.user(args, ["apk", "info", "-vv"], suffix,
- return_stdout=True)
- # Parse the output into a dictionary
- ret = {}
- for line in list.split("\n"):
- if not line.rstrip():
- continue
- package = line.split(" - ")[0]
- split = pmb.parse.other.package_split(package)
- ret[split["pkgname"]] = split
- return ret
+ path = args.work + "/chroot_" + suffix + "/lib/apk/db/installed"
+ if not os.path.exists(path):
+ return {}
+ return pmb.parse.apkindex.parse(args, path)
diff --git a/pmb/parse/apkindex.py b/pmb/parse/apkindex.py
index a19f8a84..984703f9 100644
--- a/pmb/parse/apkindex.py
+++ b/pmb/parse/apkindex.py
@@ -77,7 +77,9 @@ def parse_next_block(args, path, lines, start):
for i in range(start[0], len(lines)):
# Check for empty line
start[0] = i + 1
- line = lines[i].decode()
+ line = lines[i]
+ if not isinstance(line, str):
+ line = line.decode()
if line == "\n":
end_of_block_found = True
break
@@ -182,25 +184,32 @@ def parse(args, path, strict=False):
if cache["lastmod"] == lastmod:
return cache["ret"]
- # Parse the whole APKINDEX.tar.gz file
+ # Read all lines
+ if tarfile.is_tarfile(path):
+ with tarfile.open(path, "r:gz") as tar:
+ with tar.extractfile(tar.getmember("APKINDEX")) as handle:
+ lines = handle.readlines()
+ else:
+ with open(path, "r", encoding="utf-8") as handle:
+ lines = handle.readlines()
+
+ # Parse the whole APKINDEX file
ret = {}
start = [0]
- with tarfile.open(path, "r:gz") as tar:
- with tar.extractfile(tar.getmember("APKINDEX")) as handle:
- lines = handle.readlines()
- while True:
- block = parse_next_block(args, path, lines, start)
- if not block:
- break
+ while True:
+ block = parse_next_block(args, path, lines, start)
+ if not block:
+ break
+
+ # Add the next package and all aliases
+ parse_add_block(path, strict, ret, block)
+ if "provides" in block:
+ for alias in block["provides"]:
+ split = alias.split("=")
+ if len(split) == 2:
+ parse_add_block(path, strict, ret, block, split[0],
+ split[1])
- # Add the next package and all aliases
- parse_add_block(path, strict, ret, block)
- if "provides" in block:
- for alias in block["provides"]:
- split = alias.split("=")
- if len(split) == 2:
- parse_add_block(path, strict, ret, block,
- split[0], split[1])
# Update the cache
args.cache["apkindex"][path] = {"lastmod": lastmod, "ret": ret}
diff --git a/pmb/parse/other.py b/pmb/parse/other.py
deleted file mode 100644
index b7bcb8e2..00000000
--- a/pmb/parse/other.py
+++ /dev/null
@@ -1,35 +0,0 @@
-"""
-Copyright 2017 Oliver Smith
-
-This file is part of pmbootstrap.
-
-pmbootstrap is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-pmbootstrap is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with pmbootstrap. If not, see .
-"""
-
-
-def package_split(package):
- """
- Split a full package name (as returned by `apk info -vv` and as found as
- apk file name) into its components.
- :param package: Example: "heimdall-1.4.2-r1"
- """
- split = package.split("-")
- pkgrel = split[-1][1:]
- pkgver = split[-2]
- version = "-" + pkgver + "-r" + pkgrel
- pkgname = package[:-1 * len(version)]
- return {"pkgname": pkgname,
- "pkgrel": pkgrel,
- "pkgver": pkgver,
- "package": package}