1
0
Fork 1
mirror of https://gitlab.postmarketos.org/postmarketOS/pmbootstrap.git synced 2025-07-13 11:29:46 +03:00
pmbootstrap/pmb/helpers/repo.py
Oliver Smith e8c27795a8
Remove rest of 'pmbootstrap challenge' left overs (#1173)
Follow up to #1162.

* `pmb.build.buildinfo()`: Used to record the build environment. It is
  flawed because it scans the repo APKINDEX files instead of using the
  actually installed packages list. When it was implemented we were not
  able to do the latter. After this is removed, `pmb.parse.depends` can
  be simplified (it needs to be rewritten for #1122).
* `pmb.helpers.repo.diff()` and `pmb.helpers.repo.files()`: These were
  used exclusively by `pmb.build.buildinfo()`, to learn about which
  files have been changed in the local repository folder after a
  package was built. The idea was, that we could find subpackages that
  way. But this information is present in the installed package list as
  well, which is a much cleaner approach.
2018-02-01 22:03:21 +00:00

151 lines
5 KiB
Python

"""
Copyright 2018 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 <http://www.gnu.org/licenses/>.
"""
import os
import hashlib
import logging
import pmb.helpers.http
import pmb.helpers.run
def hash(url, length=8):
"""
Generate the hash, that APK adds to the APKINDEX and apk packages
in its apk cache folder. It is the "12345678" part in this example:
"APKINDEX.12345678.tar.gz".
:param length: The length of the hash in the output file.
See also: official implementation in apk-tools:
<https://git.alpinelinux.org/cgit/apk-tools/>
blob.c: apk_blob_push_hexdump(), "const char *xd"
apk_defines.h: APK_CACHE_CSUM_BYTES
database.c: apk_repo_format_cache_index()
"""
binary = hashlib.sha1(url.encode("utf-8")).digest()
xd = "0123456789abcdefghijklmnopqrstuvwxyz"
csum_bytes = int(length / 2)
ret = ""
for i in range(csum_bytes):
ret += xd[(binary[i] >> 4) & 0xf]
ret += xd[binary[i] & 0xf]
return ret
def urls(args, user_repository=True, postmarketos_mirror=True):
"""
Get a list of repository URLs, as they are in /etc/apk/repositories.
"""
ret = []
# Local user repository (for packages compiled with pmbootstrap)
if user_repository:
ret.append("/mnt/pmbootstrap-packages")
# Upstream postmarketOS binary repository
if postmarketos_mirror and args.mirror_postmarketos:
if os.path.exists(args.mirror_postmarketos):
ret.append("/mnt/postmarketos-mirror")
else:
ret.append(args.mirror_postmarketos)
# Upstream Alpine Linux repositories
directories = ["main", "community"]
if args.alpine_version == "edge":
directories.append("testing")
for dir in directories:
ret.append(args.mirror_alpine + args.alpine_version + "/" + dir)
return ret
def apkindex_files(args, arch=None):
"""
Get a list of outside paths to all resolved APKINDEX.tar.gz files for a
specific arch.
:param arch: defaults to native
"""
if not arch:
arch = args.arch_native
# Local user repository (for packages compiled with pmbootstrap)
ret = [args.work + "/packages/" + arch + "/APKINDEX.tar.gz"]
# Upstream postmarketOS binary repository
urls_todo = []
mirror = args.mirror_postmarketos
if mirror:
if os.path.exists(mirror):
ret.append(mirror + "/" + arch + "/APKINDEX.tar.gz")
else:
# Non-local path: treat it like other URLs
urls_todo.append(mirror)
# Resolve the APKINDEX.$HASH.tar.gz files
urls_todo += urls(args, False, False)
for url in urls_todo:
ret.append(args.work + "/cache_apk_" + arch + "/APKINDEX." +
hash(url) + ".tar.gz")
return ret
def update(args, force=False):
"""
Download the APKINDEX files for all URLs and architectures.
:arg force: even update when the APKINDEX file is fairly recent
"""
architectures = pmb.config.build_device_architectures
retention_hours = pmb.config.apkindex_retention_time
retention_seconds = retention_hours * 3600
outdated = {}
for url in urls(args, False):
for arch in architectures:
url_full = url + "/" + arch + "/APKINDEX.tar.gz"
cache_apk_outside = args.work + "/cache_apk_" + arch
apkindex = cache_apk_outside + "/APKINDEX." + hash(url) + ".tar.gz"
reason = None
if not os.path.exists(apkindex):
reason = "file does not exist yet"
elif force:
reason = "forced update"
elif pmb.helpers.file.is_older_than(apkindex, retention_seconds):
reason = "older than " + str(retention_hours) + "h"
if not reason:
continue
logging.debug("APKINDEX outdated (" + reason + "): " + url_full)
outdated[url_full] = apkindex
if not len(outdated):
return
# Show one message only
logging.info("Update package index (" + str(len(outdated)) + "x)")
for url, target in outdated.items():
# Download and move to right location
temp = pmb.helpers.http.download(args, url, "APKINDEX", False,
logging.DEBUG)
target_folder = os.path.dirname(target)
if not os.path.exists(target_folder):
pmb.helpers.run.root(args, ["mkdir", "-p", target_folder])
pmb.helpers.run.root(args, ["cp", temp, target])