2022-06-02 06:02:07 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
import os
|
|
|
|
import stat
|
|
|
|
import sys
|
|
|
|
import argparse
|
|
|
|
import subprocess
|
|
|
|
import re
|
|
|
|
from packaging import version
|
|
|
|
import atexit
|
|
|
|
import glob
|
|
|
|
import toml
|
|
|
|
import datetime
|
|
|
|
import time
|
|
|
|
import shutil
|
|
|
|
import getpass
|
|
|
|
import tempfile
|
2022-06-04 07:58:18 +00:00
|
|
|
from pathlib import Path
|
2022-06-02 06:02:07 +00:00
|
|
|
|
2022-06-04 08:22:29 +00:00
|
|
|
# SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
|
2022-06-02 06:02:07 +00:00
|
|
|
SUDO_PROC = False
|
|
|
|
AUR_GIT_REPO_PATH = "https://aur.archlinux.org"
|
|
|
|
AUR_GIT_REPO_PATH_TEMPLATE = AUR_GIT_REPO_PATH + "/{}.git"
|
|
|
|
GLOBAL_LOG_FILE = "log.txt"
|
2022-06-02 07:49:26 +00:00
|
|
|
DEFAULT_EDITOR = "/usr/bin/nano"
|
2022-06-02 06:02:07 +00:00
|
|
|
|
|
|
|
|
2022-09-05 12:54:40 +00:00
|
|
|
def log_print(*args, **kwargs):
|
2022-09-06 03:12:11 +00:00
|
|
|
"""Prints to stdout, then logs to GLOBAL_LOG_FILE."""
|
|
|
|
|
2022-09-05 12:54:40 +00:00
|
|
|
if "file" in kwargs:
|
|
|
|
kwargs["file"] = sys.stdout
|
|
|
|
print(*args, **kwargs)
|
2022-06-02 06:02:07 +00:00
|
|
|
with open(GLOBAL_LOG_FILE, "a", encoding="utf-8") as lf:
|
2022-09-05 12:54:40 +00:00
|
|
|
kwargs["file"] = lf
|
|
|
|
print(*args, **kwargs)
|
2022-06-02 06:02:07 +00:00
|
|
|
|
|
|
|
|
2022-06-04 07:14:37 +00:00
|
|
|
def ensure_pkg_dir_exists(pkg, pkg_state, other_state):
|
2022-09-06 03:12:11 +00:00
|
|
|
"""Ensures that an AUR-pkg-dir exists, returning False on failure.
|
|
|
|
|
|
|
|
If no such directory exists, this script attempts to clone it from the AUR.
|
|
|
|
True is returned on successful cloning.
|
|
|
|
|
|
|
|
If a file exists with the same name, returns False.
|
|
|
|
|
|
|
|
If a directory exists with the same name, returns True.
|
|
|
|
|
|
|
|
If "repo_path" is specified and the directory doesn't exist, returns False.
|
|
|
|
|
|
|
|
If "NO_REPO" is specified as "repo_path" and the directory doesn't exist,
|
|
|
|
returns False.
|
|
|
|
"""
|
|
|
|
|
2022-06-02 06:02:07 +00:00
|
|
|
log_print('Checking that dir for "{}" exists...'.format(pkg))
|
2022-06-04 08:22:29 +00:00
|
|
|
pkgdir = os.path.join(other_state["clones_dir"], pkg)
|
2022-06-04 02:46:33 +00:00
|
|
|
if os.path.isdir(pkgdir):
|
2022-06-02 06:02:07 +00:00
|
|
|
log_print('Dir for "{}" exists.'.format(pkg))
|
|
|
|
return True
|
2022-06-04 02:46:33 +00:00
|
|
|
elif os.path.exists(pkgdir):
|
|
|
|
log_print('"{}" exists but is not a dir'.format(pkgdir))
|
2022-06-02 06:02:07 +00:00
|
|
|
return False
|
|
|
|
elif "repo_path" not in pkg_state[pkg]:
|
|
|
|
pkg_state[pkg]["repo_path"] = AUR_GIT_REPO_PATH_TEMPLATE.format(pkg)
|
|
|
|
try:
|
|
|
|
subprocess.run(
|
2022-09-07 07:53:21 +00:00
|
|
|
(
|
|
|
|
"/usr/bin/env",
|
|
|
|
"git",
|
|
|
|
"clone",
|
|
|
|
pkg_state[pkg]["repo_path"],
|
|
|
|
pkgdir,
|
|
|
|
),
|
2022-06-02 06:02:07 +00:00
|
|
|
check=True,
|
|
|
|
)
|
|
|
|
except subprocess.CalledProcessError:
|
2022-06-02 07:49:26 +00:00
|
|
|
log_print(
|
2022-06-02 06:02:07 +00:00
|
|
|
'ERROR: Failed to git clone "{}" (tried repo path "{}")'.format(
|
2022-06-04 02:46:33 +00:00
|
|
|
pkgdir, pkg_state[pkg]["repo_path"]
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
return False
|
|
|
|
log_print('Created dir for "{}".'.format(pkg))
|
|
|
|
return True
|
|
|
|
elif pkg_state[pkg]["repo_path"] == "NO_REPO":
|
|
|
|
log_print('"{}" does not exist, but NO_REPO specified for repo_path')
|
|
|
|
return False
|
2022-09-06 03:12:11 +00:00
|
|
|
return False
|
2022-06-02 06:02:07 +00:00
|
|
|
|
|
|
|
|
2022-06-04 07:14:37 +00:00
|
|
|
def update_pkg_dir(pkg, pkg_state, other_state):
|
2022-09-06 03:12:11 +00:00
|
|
|
"""Updates the pkg by invoking "git pull".
|
|
|
|
|
|
|
|
If "git pull" failes, it is retried after invoking "git restore .".
|
|
|
|
|
|
|
|
If the local working directory fails to update via "git pull" (or if some
|
|
|
|
other handling of the local repository fails), then this function returns
|
|
|
|
(False, False).
|
|
|
|
|
|
|
|
(True, True) is returned if "skip_branch_up_to_date" is True for the package
|
|
|
|
and the local repository is up to date.
|
|
|
|
|
|
|
|
(True, False) is returned by default (successful "git pull"; regardless of
|
|
|
|
if an update was fetched).
|
|
|
|
"""
|
|
|
|
|
2022-06-02 06:02:07 +00:00
|
|
|
log_print('Making sure pkg dir for "{}" is up to date...'.format(pkg))
|
|
|
|
|
2022-06-04 08:22:29 +00:00
|
|
|
pkgdir = os.path.join(other_state["clones_dir"], pkg)
|
2022-06-02 06:02:07 +00:00
|
|
|
# fetch all
|
|
|
|
try:
|
|
|
|
subprocess.run(
|
2022-09-07 07:53:21 +00:00
|
|
|
("/usr/bin/env", "git", "fetch", "-p", "--all"),
|
2022-06-02 06:02:07 +00:00
|
|
|
check=True,
|
2022-06-04 02:46:33 +00:00
|
|
|
cwd=pkgdir,
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
log_print(
|
|
|
|
'ERROR: Failed to update pkg dir of "{}" (fetching).'.format(pkg)
|
|
|
|
)
|
|
|
|
return False, False
|
|
|
|
|
|
|
|
# get remotes
|
|
|
|
remotes = []
|
|
|
|
try:
|
|
|
|
result = subprocess.run(
|
2022-09-07 07:53:21 +00:00
|
|
|
("/usr/bin/env", "git", "remote"),
|
2022-06-02 06:02:07 +00:00
|
|
|
check=True,
|
2022-06-04 02:46:33 +00:00
|
|
|
cwd=pkgdir,
|
2022-06-02 06:02:07 +00:00
|
|
|
capture_output=True,
|
|
|
|
encoding="UTF-8",
|
|
|
|
)
|
|
|
|
remotes = result.stdout.split(sep="\n")
|
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
log_print(
|
|
|
|
'ERROR: Failed to update pkg dir of "{}" (getting remotes).'.format(
|
|
|
|
pkg
|
|
|
|
)
|
|
|
|
)
|
|
|
|
return False, False
|
|
|
|
remotes = list(filter(lambda s: len(s) > 0, remotes))
|
|
|
|
if len(remotes) == 0:
|
|
|
|
log_print(
|
|
|
|
'ERROR: Failed to update pkg dir of "{}" (getting remotes).'.format(
|
|
|
|
pkg
|
|
|
|
)
|
|
|
|
)
|
|
|
|
return False, False
|
|
|
|
|
|
|
|
# get remote that current branch is tracking
|
2022-09-06 03:12:11 +00:00
|
|
|
selected_remote = None
|
2022-06-02 06:02:07 +00:00
|
|
|
try:
|
|
|
|
result = subprocess.run(
|
2022-09-07 07:53:21 +00:00
|
|
|
("/usr/bin/env", "git", "status", "-sb", "--porcelain"),
|
2022-06-02 06:02:07 +00:00
|
|
|
check=True,
|
2022-06-04 02:46:33 +00:00
|
|
|
cwd=pkgdir,
|
2022-06-02 06:02:07 +00:00
|
|
|
capture_output=True,
|
|
|
|
encoding="UTF-8",
|
|
|
|
)
|
2022-09-06 03:12:11 +00:00
|
|
|
result_lines = result.stdout.split(sep="\n")
|
|
|
|
for matching_line in filter(lambda s: s.startswith("##"), result_lines):
|
|
|
|
for remote in map(lambda r: r.strip(), remotes):
|
|
|
|
if matching_line.find(remote) != -1:
|
|
|
|
selected_remote = remote
|
|
|
|
break
|
2022-06-02 06:02:07 +00:00
|
|
|
except subprocess.CalledProcessError:
|
2022-06-02 07:49:26 +00:00
|
|
|
log_print(
|
2022-07-19 03:32:06 +00:00
|
|
|
f'ERROR: Failed to update pkg dir of "{pkg}" (getting branch\'s remote).'
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
return False, False
|
2022-09-06 03:12:11 +00:00
|
|
|
if selected_remote is None or not isinstance(selected_remote, str):
|
2022-06-02 07:49:26 +00:00
|
|
|
log_print(
|
2022-07-19 03:32:06 +00:00
|
|
|
f'ERROR: Failed to update pkg dir of "{pkg}" (getting branch\'s remote).'
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
return False, False
|
|
|
|
|
|
|
|
# get hash of current branch
|
2022-09-06 03:12:11 +00:00
|
|
|
current_branch_hash = None
|
2022-06-02 06:02:07 +00:00
|
|
|
try:
|
|
|
|
result = subprocess.run(
|
2022-09-07 07:53:21 +00:00
|
|
|
("/usr/bin/env", "git", "log", "-1", "--format=format:%H"),
|
2022-06-02 06:02:07 +00:00
|
|
|
check=True,
|
2022-06-04 02:46:33 +00:00
|
|
|
cwd=pkgdir,
|
2022-06-02 06:02:07 +00:00
|
|
|
capture_output=True,
|
|
|
|
encoding="UTF-8",
|
|
|
|
)
|
|
|
|
current_branch_hash = result.stdout.strip()
|
|
|
|
except subprocess.CalledProcessError:
|
2022-06-02 07:49:26 +00:00
|
|
|
log_print(
|
2022-07-19 03:32:06 +00:00
|
|
|
f'ERROR: Failed to update pkg dir of "{pkg}" (getting current branch\'s hash).'
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
return False, False
|
2022-09-06 03:12:11 +00:00
|
|
|
if current_branch_hash is None or not isinstance(current_branch_hash, str):
|
2022-06-02 07:49:26 +00:00
|
|
|
log_print(
|
2022-07-19 03:32:06 +00:00
|
|
|
f'ERROR: Failed to update pkg dir of "{pkg}" (getting current branch\'s hash).'
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
return False, False
|
|
|
|
|
|
|
|
# get hash of remote branch
|
2022-09-06 03:12:11 +00:00
|
|
|
remote_branch_hash = None
|
2022-06-02 06:02:07 +00:00
|
|
|
try:
|
|
|
|
result = subprocess.run(
|
2022-09-07 07:53:21 +00:00
|
|
|
(
|
|
|
|
"/usr/bin/env",
|
|
|
|
"git",
|
|
|
|
"log",
|
|
|
|
"-1",
|
|
|
|
"--format=format:%H",
|
|
|
|
selected_remote,
|
|
|
|
),
|
2022-06-02 06:02:07 +00:00
|
|
|
check=True,
|
2022-06-04 02:46:33 +00:00
|
|
|
cwd=pkgdir,
|
2022-06-02 06:02:07 +00:00
|
|
|
capture_output=True,
|
|
|
|
encoding="UTF-8",
|
|
|
|
)
|
|
|
|
remote_branch_hash = result.stdout.strip()
|
|
|
|
except subprocess.CalledProcessError:
|
2022-06-02 07:49:26 +00:00
|
|
|
log_print(
|
2022-07-19 03:32:06 +00:00
|
|
|
f'ERROR: Failed to update pkg dir of "{pkg}" (getting remote branch\'s hash).'
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
return False, False
|
2022-09-06 03:12:11 +00:00
|
|
|
if remote_branch_hash is None or not isinstance(remote_branch_hash, str):
|
2022-06-02 07:49:26 +00:00
|
|
|
log_print(
|
2022-07-19 03:32:06 +00:00
|
|
|
f'ERROR: Failed to update pkg dir of "{pkg}" (getting remote branch\'s hash).'
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
return False, False
|
|
|
|
|
|
|
|
# update current branch if not same commit
|
|
|
|
if current_branch_hash != remote_branch_hash:
|
|
|
|
try:
|
2022-09-07 07:53:21 +00:00
|
|
|
subprocess.run(
|
|
|
|
("/usr/bin/env", "git", "pull"), check=True, cwd=pkgdir
|
|
|
|
)
|
2022-06-02 06:02:07 +00:00
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
try:
|
|
|
|
subprocess.run(
|
2022-09-07 07:53:21 +00:00
|
|
|
("/usr/bin/env", "git", "restore", "."),
|
2022-06-02 06:02:07 +00:00
|
|
|
check=True,
|
2022-06-04 02:46:33 +00:00
|
|
|
cwd=pkgdir,
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
subprocess.run(
|
2022-09-07 07:53:21 +00:00
|
|
|
("/usr/bin/env", "git", "pull"),
|
2022-06-02 06:02:07 +00:00
|
|
|
check=True,
|
2022-06-04 02:46:33 +00:00
|
|
|
cwd=pkgdir,
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
log_print(
|
|
|
|
'ERROR: Failed to update pkg dir of "{}".'.format(pkg)
|
|
|
|
)
|
|
|
|
return False, False
|
2022-06-04 07:14:37 +00:00
|
|
|
elif pkg_state[pkg]["skip_branch_up_to_date"]:
|
2022-06-02 06:02:07 +00:00
|
|
|
log_print(f'"{pkg}" is up to date')
|
|
|
|
return True, True
|
|
|
|
log_print('Updated pkg dir for "{}"'.format(pkg))
|
|
|
|
return True, False
|
|
|
|
|
|
|
|
|
2022-06-04 07:14:37 +00:00
|
|
|
def check_pkg_build(pkg, pkg_state, other_state, editor):
|
2022-09-06 03:12:11 +00:00
|
|
|
"""Opens the PKGBUILD in the editor, then prompts the user for an action.
|
|
|
|
|
|
|
|
Returns "ok", "not_ok", "abort", or "force_build"."""
|
|
|
|
|
2022-06-04 08:22:29 +00:00
|
|
|
pkgdir = os.path.join(other_state["clones_dir"], pkg)
|
2022-06-02 06:02:07 +00:00
|
|
|
log_print('Checking PKGBUILD for "{}"...'.format(pkg))
|
|
|
|
try:
|
2022-09-07 07:53:21 +00:00
|
|
|
subprocess.run(
|
|
|
|
("/usr/bin/env", editor, "PKGBUILD"), check=True, cwd=pkgdir
|
|
|
|
)
|
2022-06-02 06:02:07 +00:00
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
log_print('ERROR: Failed checking PKGBUILD for "{}"'.format(pkg))
|
|
|
|
return "abort"
|
|
|
|
while True:
|
|
|
|
log_print(
|
|
|
|
"PKGBUILD okay? [Y/n/c(heck again)/a(bort)/f(orce build)/b(ack)]"
|
|
|
|
)
|
|
|
|
user_input = sys.stdin.buffer.readline().decode().strip().lower()
|
|
|
|
if user_input == "y" or len(user_input) == 0:
|
|
|
|
log_print("User decided PKGBUILD is ok")
|
|
|
|
return "ok"
|
|
|
|
elif user_input == "n":
|
|
|
|
log_print("User decided PKGBUILD is not ok")
|
|
|
|
return "not_ok"
|
|
|
|
elif user_input == "c":
|
|
|
|
log_print("User will check PKGBUILD again")
|
2022-06-04 07:14:37 +00:00
|
|
|
return check_pkg_build(pkg, pkg_state, other_state, editor)
|
2022-06-02 06:02:07 +00:00
|
|
|
elif user_input == "a":
|
|
|
|
return "abort"
|
|
|
|
elif user_input == "f":
|
|
|
|
return "force_build"
|
|
|
|
elif user_input == "b":
|
|
|
|
return "back"
|
|
|
|
else:
|
|
|
|
log_print("ERROR: User gave invalid input...")
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
2022-06-04 07:14:37 +00:00
|
|
|
def check_pkg_version(pkg, pkg_state, repo, force_check_srcinfo, other_state):
|
2022-09-06 03:12:11 +00:00
|
|
|
"""Gets the installed version and pkg version and checks them.
|
|
|
|
|
|
|
|
Returns "fail" (on failure), "install" (pkg is newer), or "done"
|
|
|
|
(installed pkg is up to date)."""
|
|
|
|
|
2022-06-02 08:22:45 +00:00
|
|
|
status, current_epoch, current_version = get_pkg_current_version(
|
2022-06-04 02:46:33 +00:00
|
|
|
pkg, pkg_state, repo
|
2022-06-02 08:22:45 +00:00
|
|
|
)
|
2022-06-02 06:02:07 +00:00
|
|
|
if status != "fetched":
|
|
|
|
return status
|
|
|
|
elif current_version is None:
|
2022-06-02 07:49:26 +00:00
|
|
|
log_print(
|
2022-06-02 06:02:07 +00:00
|
|
|
'ERROR: Failed to get version from package "{}".'.format(
|
2022-06-04 02:46:33 +00:00
|
|
|
pkg_state[pkg]["pkg_name"]
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
return "fail"
|
2022-06-02 07:49:26 +00:00
|
|
|
log_print(
|
2022-06-02 06:02:07 +00:00
|
|
|
'Got version "{}:{}" for installed pkg "{}"'.format(
|
|
|
|
current_epoch if current_epoch is not None else "0",
|
|
|
|
current_version,
|
2022-06-04 02:46:33 +00:00
|
|
|
pkg_state[pkg]["pkg_name"],
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2022-06-02 08:22:45 +00:00
|
|
|
return get_srcinfo_check_result(
|
2022-07-19 03:32:06 +00:00
|
|
|
current_epoch,
|
|
|
|
current_version,
|
|
|
|
pkg,
|
|
|
|
force_check_srcinfo,
|
|
|
|
pkg_state,
|
|
|
|
other_state,
|
2022-06-02 08:22:45 +00:00
|
|
|
)
|
2022-06-02 06:02:07 +00:00
|
|
|
|
|
|
|
|
2022-06-04 07:14:37 +00:00
|
|
|
def get_srcinfo_version(pkg, other_state):
|
2022-09-06 03:12:11 +00:00
|
|
|
"""Parses .SRCINFO for verison information.
|
|
|
|
|
|
|
|
Returns (success_bool, pkgepoch, pkgver, pkgrel)
|
|
|
|
|
|
|
|
When "success_bool" is False, all other values are None.
|
|
|
|
|
|
|
|
Otherwise, all other values are str (or None if not found)."""
|
|
|
|
|
2022-06-04 08:22:29 +00:00
|
|
|
if not os.path.exists(
|
|
|
|
os.path.join(other_state["clones_dir"], pkg, ".SRCINFO")
|
|
|
|
):
|
2022-06-04 02:46:33 +00:00
|
|
|
log_print(f'ERROR: .SRCINFO does not exist for pkg "{pkg}"')
|
2022-06-02 06:02:07 +00:00
|
|
|
return False, None, None, None
|
2022-06-02 08:22:45 +00:00
|
|
|
pkgver_reprog = re.compile("^\\s*pkgver\\s*=\\s*([a-zA-Z0-9._+-]+)\\s*$")
|
2022-06-02 06:02:07 +00:00
|
|
|
pkgrel_reprog = re.compile("^\\s*pkgrel\\s*=\\s*([0-9.]+)\\s*$")
|
|
|
|
pkgepoch_reprog = re.compile("^\\s*epoch\\s*=\\s*([0-9]+)\\s*$")
|
2022-09-06 03:12:11 +00:00
|
|
|
pkgver = None
|
|
|
|
pkgrel = None
|
|
|
|
pkgepoch = None
|
2022-06-02 06:02:07 +00:00
|
|
|
with open(
|
2022-06-04 08:22:29 +00:00
|
|
|
os.path.join(other_state["clones_dir"], pkg, ".SRCINFO"),
|
|
|
|
encoding="UTF-8",
|
2022-06-02 06:02:07 +00:00
|
|
|
) as fo:
|
|
|
|
line = fo.readline()
|
|
|
|
while len(line) > 0:
|
|
|
|
pkgver_result = pkgver_reprog.match(line)
|
|
|
|
pkgrel_result = pkgrel_reprog.match(line)
|
|
|
|
pkgepoch_result = pkgepoch_reprog.match(line)
|
|
|
|
if pkgver_result:
|
|
|
|
pkgver = pkgver_result.group(1)
|
|
|
|
elif pkgrel_result:
|
|
|
|
pkgrel = pkgrel_result.group(1)
|
|
|
|
elif pkgepoch_result:
|
|
|
|
pkgepoch = pkgepoch_result.group(1)
|
|
|
|
line = fo.readline()
|
|
|
|
return True, pkgepoch, pkgver, pkgrel
|
|
|
|
|
|
|
|
|
2022-07-19 03:32:06 +00:00
|
|
|
def get_pkgbuild_version(pkg, force_check_srcinfo, pkg_state, other_state):
|
2022-09-06 03:12:11 +00:00
|
|
|
"""Gets the version of the pkg from .SRCINFO or PKGBUILD.
|
|
|
|
|
|
|
|
Returns (success, epoch, version, release).
|
|
|
|
|
|
|
|
If "success" is False, then all other values are None.
|
|
|
|
|
|
|
|
Otherwise, version and release should be a str type, but epoch may be
|
|
|
|
None."""
|
|
|
|
|
2022-06-04 08:22:29 +00:00
|
|
|
pkgdir = os.path.join(other_state["clones_dir"], pkg)
|
2022-06-04 02:46:33 +00:00
|
|
|
log_print(f'Getting version of "{pkg}"...')
|
2022-06-02 06:02:07 +00:00
|
|
|
while True and not force_check_srcinfo:
|
|
|
|
log_print("Use .SRCINFO or directly parse PKGBUILD?")
|
|
|
|
user_input = input("1 for .SRCINFO, 2 for PKGBUILD > ")
|
|
|
|
if user_input == "1" or user_input == "2":
|
|
|
|
break
|
|
|
|
# TODO support split packages
|
|
|
|
if force_check_srcinfo or user_input == "1":
|
2022-06-02 08:22:45 +00:00
|
|
|
srcinfo_fetch_success, pkgepoch, pkgver, pkgrel = get_srcinfo_version(
|
2022-06-04 07:14:37 +00:00
|
|
|
pkg, other_state
|
2022-06-02 08:22:45 +00:00
|
|
|
)
|
2022-06-02 06:02:07 +00:00
|
|
|
if not srcinfo_fetch_success:
|
2022-06-02 08:22:45 +00:00
|
|
|
log_print("ERROR: Failed to get pkg info from .SRCINFO")
|
2022-06-02 06:02:07 +00:00
|
|
|
return False, None, None, None
|
|
|
|
elif user_input == "2":
|
|
|
|
try:
|
|
|
|
log_print(
|
2022-07-19 03:32:06 +00:00
|
|
|
'Running "makechrootpkg ... --nobuild" to ensure pkgver in PKGBUILD is updated...'
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
2022-07-19 03:32:06 +00:00
|
|
|
command_list = [
|
2022-09-07 07:53:21 +00:00
|
|
|
"/usr/bin/env",
|
2022-07-19 03:32:06 +00:00
|
|
|
"makechrootpkg",
|
|
|
|
"-c",
|
|
|
|
"-r",
|
|
|
|
other_state["chroot"],
|
|
|
|
]
|
|
|
|
post_command_list = ["--", "-s", "-r", "-c", "--nobuild"]
|
|
|
|
for dep in pkg_state[pkg]["other_deps"]:
|
|
|
|
dep_fullpath = get_latest_pkg(dep, "/var/cache/pacman/pkg")
|
|
|
|
if not dep_fullpath:
|
|
|
|
log_print('ERROR: Failed to get dep "{}"'.format(dep))
|
|
|
|
sys.exit(1)
|
2022-09-07 07:53:21 +00:00
|
|
|
command_list.insert(2, "-I")
|
|
|
|
command_list.insert(3, dep_fullpath)
|
2022-07-19 03:32:06 +00:00
|
|
|
for aur_dep in pkg_state[pkg]["aur_deps"]:
|
|
|
|
aur_dep_fullpath = get_latest_pkg(
|
|
|
|
aur_dep, other_state["pkg_out_dir"]
|
|
|
|
)
|
|
|
|
if not aur_dep_fullpath:
|
|
|
|
log_print(
|
|
|
|
'ERROR: Failed to get aur_dep "{}"'.format(aur_dep)
|
|
|
|
)
|
|
|
|
sys.exit(1)
|
2022-09-07 07:53:21 +00:00
|
|
|
command_list.insert(2, "-I")
|
|
|
|
command_list.insert(3, aur_dep_fullpath)
|
2022-06-02 06:02:07 +00:00
|
|
|
subprocess.run(
|
2022-07-19 03:32:06 +00:00
|
|
|
command_list + post_command_list,
|
2022-06-02 06:02:07 +00:00
|
|
|
check=True,
|
2022-06-04 02:46:33 +00:00
|
|
|
cwd=pkgdir,
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
log_print(
|
2022-07-19 03:32:06 +00:00
|
|
|
f'ERROR: Failed to run "makechrootpkg ... --nobuild" in "{pkg}".'
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
2022-06-04 02:46:33 +00:00
|
|
|
if os.path.exists(os.path.join(pkgdir, "src")):
|
|
|
|
shutil.rmtree(os.path.join(pkgdir, "src"))
|
2022-06-02 06:02:07 +00:00
|
|
|
return False, None, None, None
|
|
|
|
|
2022-06-04 02:46:33 +00:00
|
|
|
if os.path.exists(os.path.join(pkgdir, "src")):
|
|
|
|
shutil.rmtree(os.path.join(pkgdir, "src"))
|
2022-09-06 03:12:11 +00:00
|
|
|
pkgepoch = None
|
|
|
|
pkgver = None
|
|
|
|
pkgrel = None
|
2022-06-02 06:02:07 +00:00
|
|
|
|
|
|
|
# TODO maybe sandbox sourcing the PKGBUILD
|
|
|
|
pkgbuild_output = subprocess.run(
|
2022-09-07 07:53:21 +00:00
|
|
|
(
|
|
|
|
"/usr/bin/env",
|
2022-06-02 06:02:07 +00:00
|
|
|
"bash",
|
|
|
|
"-c",
|
2022-06-04 02:46:33 +00:00
|
|
|
f"source {os.path.join(pkgdir, 'PKGBUILD')}; echo \"pkgver=$pkgver\"; echo \"pkgrel=$pkgrel\"; echo \"epoch=$epoch\"",
|
2022-09-07 07:53:21 +00:00
|
|
|
),
|
2022-06-02 06:02:07 +00:00
|
|
|
capture_output=True,
|
|
|
|
text=True,
|
|
|
|
)
|
|
|
|
output_ver_re = re.compile(
|
|
|
|
"^pkgver=([a-zA-Z0-9._+-]+)\\s*$", flags=re.M
|
|
|
|
)
|
|
|
|
output_rel_re = re.compile("^pkgrel=([0-9.]+)\\s*$", flags=re.M)
|
|
|
|
output_epoch_re = re.compile("^epoch=([0-9]+)\\s*$", flags=re.M)
|
|
|
|
|
|
|
|
match = output_ver_re.search(pkgbuild_output.stdout)
|
|
|
|
if match:
|
|
|
|
pkgver = match.group(1)
|
|
|
|
match = output_rel_re.search(pkgbuild_output.stdout)
|
|
|
|
if match:
|
|
|
|
pkgrel = match.group(1)
|
|
|
|
match = output_epoch_re.search(pkgbuild_output.stdout)
|
|
|
|
if match:
|
|
|
|
pkgepoch = match.group(1)
|
|
|
|
else:
|
|
|
|
log_print("ERROR: Unreachable code")
|
|
|
|
return False, None, None, None
|
|
|
|
|
|
|
|
if pkgver is not None and pkgrel is not None:
|
|
|
|
return True, pkgepoch, pkgver, pkgrel
|
|
|
|
else:
|
2022-06-04 08:22:29 +00:00
|
|
|
log_print('ERROR: Failed to get PKGBUILD version of "{}".'.format(pkg))
|
2022-06-02 06:02:07 +00:00
|
|
|
return False, None, None, None
|
|
|
|
|
|
|
|
|
2022-06-02 08:22:45 +00:00
|
|
|
def get_srcinfo_check_result(
|
2022-07-19 03:32:06 +00:00
|
|
|
current_epoch,
|
|
|
|
current_version,
|
|
|
|
pkg,
|
|
|
|
force_check_srcinfo,
|
|
|
|
pkg_state,
|
|
|
|
other_state,
|
2022-06-02 08:22:45 +00:00
|
|
|
):
|
2022-09-06 03:12:11 +00:00
|
|
|
"""Checks the version of the pkg against the currently installed version.
|
|
|
|
|
|
|
|
Returns "install" if the version of the pkg is newer.
|
|
|
|
|
|
|
|
Otherwise returns "done" if the version is not newer.
|
|
|
|
|
|
|
|
Returns "fail" on error."""
|
|
|
|
|
2022-06-02 08:22:45 +00:00
|
|
|
ver_success, pkgepoch, pkgver, pkgrel = get_pkgbuild_version(
|
2022-07-19 03:32:06 +00:00
|
|
|
pkg, force_check_srcinfo, pkg_state, other_state
|
2022-06-02 08:22:45 +00:00
|
|
|
)
|
2022-06-02 06:02:07 +00:00
|
|
|
if ver_success:
|
|
|
|
if current_epoch is None and pkgepoch is not None:
|
2022-06-02 07:49:26 +00:00
|
|
|
log_print(
|
2022-06-02 06:02:07 +00:00
|
|
|
'Current installed version of "{}" is out of date (missing epoch).'.format(
|
2022-06-04 02:46:33 +00:00
|
|
|
pkg_state[pkg]["pkg_name"]
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
return "install"
|
|
|
|
elif current_epoch is not None and pkgepoch is None:
|
2022-06-02 07:49:26 +00:00
|
|
|
log_print(
|
2022-06-02 06:02:07 +00:00
|
|
|
'Current installed version of "{}" is up to date (has epoch).'.format(
|
2022-06-04 02:46:33 +00:00
|
|
|
pkg_state[pkg]["pkg_name"]
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
return "done"
|
2022-06-02 08:22:45 +00:00
|
|
|
elif (
|
|
|
|
current_epoch is not None
|
|
|
|
and pkgepoch is not None
|
|
|
|
and int(current_epoch) < int(pkgepoch)
|
|
|
|
):
|
2022-06-02 07:49:26 +00:00
|
|
|
log_print(
|
2022-06-02 06:02:07 +00:00
|
|
|
'Current installed version of "{}" is out of date (older epoch).'.format(
|
2022-06-04 02:46:33 +00:00
|
|
|
pkg_state[pkg]["pkg_name"]
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
return "install"
|
2022-06-02 08:22:45 +00:00
|
|
|
elif (
|
|
|
|
pkgver is not None
|
|
|
|
and pkgrel is not None
|
|
|
|
and version.parse(current_version)
|
|
|
|
< version.parse(pkgver + "-" + pkgrel)
|
|
|
|
):
|
2022-06-02 07:49:26 +00:00
|
|
|
log_print(
|
2022-06-02 06:02:07 +00:00
|
|
|
'Current installed version of "{}" is out of date (older version).'.format(
|
2022-06-04 02:46:33 +00:00
|
|
|
pkg_state[pkg]["pkg_name"]
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
return "install"
|
|
|
|
else:
|
2022-06-02 07:49:26 +00:00
|
|
|
log_print(
|
2022-06-02 06:02:07 +00:00
|
|
|
'Current installed version of "{}" is up to date.'.format(
|
2022-06-04 02:46:33 +00:00
|
|
|
pkg_state[pkg]["pkg_name"]
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
return "done"
|
|
|
|
else:
|
2022-06-02 07:49:26 +00:00
|
|
|
log_print(
|
2022-06-02 06:02:07 +00:00
|
|
|
'ERROR: Failed to get pkg_version of "{}"'.format(
|
2022-06-04 02:46:33 +00:00
|
|
|
pkg_state[pkg]["pkg_name"]
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
return "fail"
|
|
|
|
|
2022-06-02 08:22:45 +00:00
|
|
|
|
2022-06-04 02:46:33 +00:00
|
|
|
def get_pkg_current_version(pkg, pkg_state, repo):
|
2022-09-06 03:12:11 +00:00
|
|
|
"""Fetches the version info and returns status of fetching and the version.
|
|
|
|
|
|
|
|
Returns (status, epoch, version)
|
|
|
|
|
|
|
|
"status" may be one of:
|
|
|
|
"fail", "install", "fetched"
|
|
|
|
|
|
|
|
"epoch" may be None.
|
|
|
|
|
|
|
|
"version" must be a str if "status" is "fetched". Otherwise, it is None if
|
|
|
|
"status" is "fail" or "install".
|
|
|
|
"""
|
|
|
|
|
2022-06-02 07:49:26 +00:00
|
|
|
log_print(
|
2022-06-02 06:02:07 +00:00
|
|
|
'Checking version of installed pkg "{}"...'.format(
|
2022-06-04 02:46:33 +00:00
|
|
|
pkg_state[pkg]["pkg_name"]
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
current_epoch = None
|
|
|
|
current_version = None
|
|
|
|
try:
|
|
|
|
result = subprocess.run(
|
2022-09-07 07:53:21 +00:00
|
|
|
(
|
|
|
|
"/usr/bin/env",
|
|
|
|
"bash",
|
|
|
|
"-c"
|
|
|
|
"tar -tf {} | grep '{}.*/$'".format(
|
|
|
|
repo, pkg_state[pkg]["pkg_name"]
|
|
|
|
),
|
2022-06-02 06:02:07 +00:00
|
|
|
),
|
|
|
|
check=True,
|
|
|
|
capture_output=True,
|
|
|
|
encoding="UTF-8",
|
|
|
|
)
|
|
|
|
reprog = re.compile(
|
|
|
|
"^{}-(?P<epoch>[0-9]+:)?(?P<version>[^-/: ]*-[0-9]+)/$".format(
|
2022-06-04 02:46:33 +00:00
|
|
|
pkg_state[pkg]["pkg_name"]
|
2022-06-02 06:02:07 +00:00
|
|
|
),
|
|
|
|
flags=re.MULTILINE,
|
|
|
|
)
|
|
|
|
reresult = reprog.search(result.stdout)
|
|
|
|
if reresult:
|
|
|
|
result_dict = reresult.groupdict()
|
|
|
|
if not result_dict["epoch"] is None:
|
|
|
|
current_epoch = result_dict["epoch"][:-1]
|
|
|
|
if not result_dict["version"] is None:
|
|
|
|
current_version = result_dict["version"]
|
|
|
|
else:
|
2022-06-02 07:49:26 +00:00
|
|
|
log_print(
|
2022-06-02 06:02:07 +00:00
|
|
|
"ERROR: Failed to get current version from repo for package {}".format(
|
2022-06-04 02:46:33 +00:00
|
|
|
pkg_state[pkg]["pkg_name"]
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
return "fail", None, None
|
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
log_print("Package not found, assuming building first time.")
|
|
|
|
return "install", None, None
|
|
|
|
return "fetched", current_epoch, current_version
|
|
|
|
|
|
|
|
|
|
|
|
def get_sudo_privileges():
|
2022-09-06 03:12:11 +00:00
|
|
|
"""Starts a bash loop that ensures sudo privileges are ready while this
|
|
|
|
script is active."""
|
|
|
|
|
2022-06-02 06:02:07 +00:00
|
|
|
global SUDO_PROC
|
|
|
|
if not SUDO_PROC:
|
|
|
|
log_print("sudo -v")
|
|
|
|
try:
|
2022-09-07 07:53:21 +00:00
|
|
|
subprocess.run(("/usr/bin/env", "sudo", "-v"), check=True)
|
2022-06-02 06:02:07 +00:00
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
return False
|
|
|
|
SUDO_PROC = subprocess.Popen(
|
2022-09-07 07:53:21 +00:00
|
|
|
"while true; do sudo -v; sleep 2m; done", shell=True
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
atexit.register(cleanup_sudo, sudo_proc=SUDO_PROC)
|
|
|
|
return True
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
def cleanup_sudo(sudo_proc):
|
2022-09-06 03:12:11 +00:00
|
|
|
"""Stops the bash loop keeping sudo privileges."""
|
|
|
|
|
2022-06-02 06:02:07 +00:00
|
|
|
sudo_proc.terminate()
|
|
|
|
|
|
|
|
|
|
|
|
def create_executable_script(dest_filename, script_contents):
|
2022-09-07 06:28:09 +00:00
|
|
|
"""Creates a script via use of sudo to be executed later.
|
2022-09-06 03:12:11 +00:00
|
|
|
|
|
|
|
This is currently used to set up sccache by placing custom commands in
|
|
|
|
"/usr/local/bin" for gcc and friends."""
|
|
|
|
|
2022-06-02 06:02:07 +00:00
|
|
|
tempf_name = "unknown"
|
|
|
|
with tempfile.NamedTemporaryFile(
|
|
|
|
mode="w", encoding="utf-8", delete=False
|
|
|
|
) as tempf:
|
2022-09-07 06:28:09 +00:00
|
|
|
print(script_contents, file=tempf)
|
2022-06-02 06:02:07 +00:00
|
|
|
tempf_name = tempf.name
|
|
|
|
try:
|
|
|
|
subprocess.run(
|
2022-09-07 07:53:21 +00:00
|
|
|
(
|
2022-06-02 06:02:07 +00:00
|
|
|
"/usr/bin/env",
|
2022-09-07 06:28:09 +00:00
|
|
|
"sudo",
|
|
|
|
"cp",
|
2022-06-02 06:02:07 +00:00
|
|
|
tempf_name,
|
|
|
|
dest_filename,
|
2022-09-07 07:53:21 +00:00
|
|
|
),
|
2022-09-07 06:28:09 +00:00
|
|
|
check=True,
|
|
|
|
)
|
|
|
|
subprocess.run(
|
2022-09-07 07:53:21 +00:00
|
|
|
(
|
2022-09-07 06:28:09 +00:00
|
|
|
"/usr/bin/env",
|
|
|
|
"sudo",
|
|
|
|
"chmod",
|
|
|
|
"a+rx",
|
|
|
|
dest_filename,
|
2022-09-07 07:53:21 +00:00
|
|
|
),
|
2022-06-02 06:02:07 +00:00
|
|
|
check=True,
|
|
|
|
)
|
2022-09-07 07:09:48 +00:00
|
|
|
subprocess.run(
|
2022-09-07 07:53:21 +00:00
|
|
|
(
|
2022-09-07 07:09:48 +00:00
|
|
|
"/usr/bin/env",
|
|
|
|
"rm",
|
|
|
|
"-f",
|
|
|
|
tempf_name,
|
2022-09-07 07:53:21 +00:00
|
|
|
),
|
2022-09-07 07:09:48 +00:00
|
|
|
check=True,
|
|
|
|
)
|
2022-06-02 06:02:07 +00:00
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
log_print(
|
|
|
|
f'ERROR: Failed to create executable script "{dest_filename}"'
|
|
|
|
)
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
def setup_ccache(chroot):
|
2022-09-06 03:12:11 +00:00
|
|
|
"""Sets up the chroot for ccache."""
|
|
|
|
|
2022-06-02 06:02:07 +00:00
|
|
|
# set up ccache stuff
|
|
|
|
try:
|
|
|
|
subprocess.run(
|
2022-09-07 07:53:21 +00:00
|
|
|
(
|
|
|
|
"/usr/bin/env",
|
2022-06-02 06:02:07 +00:00
|
|
|
"sudo",
|
|
|
|
"sed",
|
|
|
|
"-i",
|
|
|
|
"/^BUILDENV=/s/!ccache/ccache/",
|
|
|
|
f"{chroot}/root/etc/makepkg.conf",
|
2022-09-07 07:53:21 +00:00
|
|
|
),
|
2022-06-02 06:02:07 +00:00
|
|
|
check=True,
|
|
|
|
)
|
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
log_print("ERROR: Failed to enable ccache in makepkg.conf")
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
def cleanup_ccache(chroot):
|
2022-09-06 03:12:11 +00:00
|
|
|
"""Unsets up the chroot for ccache."""
|
|
|
|
|
2022-06-02 06:02:07 +00:00
|
|
|
# cleanup ccache stuff
|
|
|
|
try:
|
|
|
|
subprocess.run(
|
2022-09-07 07:53:21 +00:00
|
|
|
(
|
|
|
|
"/usr/bin/env",
|
2022-06-02 06:02:07 +00:00
|
|
|
"sudo",
|
|
|
|
"sed",
|
|
|
|
"-i",
|
|
|
|
"/^BUILDENV=/s/ ccache/ !ccache/",
|
|
|
|
f"{chroot}/root/etc/makepkg.conf",
|
2022-09-07 07:53:21 +00:00
|
|
|
),
|
2022-06-02 06:02:07 +00:00
|
|
|
check=True,
|
|
|
|
)
|
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
log_print("ERROR: Failed to disable ccache in makepkg.conf")
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
def setup_sccache(chroot):
|
2022-09-06 03:12:11 +00:00
|
|
|
"""Sets up sccache for the chroot."""
|
|
|
|
|
2022-06-02 06:02:07 +00:00
|
|
|
sccache_script = """#!/usr/bin/env sh
|
|
|
|
export PATH=${PATH/:\/usr\/local\/bin/}
|
|
|
|
/usr/bin/env sccache $(basename "$0") "$@"
|
|
|
|
"""
|
|
|
|
if (
|
|
|
|
not create_executable_script(
|
|
|
|
f"{chroot}/root/usr/local/bin/gcc", sccache_script
|
|
|
|
)
|
|
|
|
or not create_executable_script(
|
|
|
|
f"{chroot}/root/usr/local/bin/g++", sccache_script
|
|
|
|
)
|
2022-09-07 05:30:12 +00:00
|
|
|
or not create_executable_script(
|
|
|
|
f"{chroot}/root/usr/local/bin/cc", sccache_script
|
|
|
|
)
|
|
|
|
or not create_executable_script(
|
|
|
|
f"{chroot}/root/usr/local/bin/c++", sccache_script
|
|
|
|
)
|
2022-09-07 06:06:05 +00:00
|
|
|
or not create_executable_script(
|
|
|
|
f"{chroot}/root/usr/local/bin/cpp", sccache_script
|
|
|
|
)
|
2022-06-02 06:02:07 +00:00
|
|
|
or not create_executable_script(
|
|
|
|
f"{chroot}/root/usr/local/bin/clang", sccache_script
|
|
|
|
)
|
|
|
|
or not create_executable_script(
|
|
|
|
f"{chroot}/root/usr/local/bin/clang++", sccache_script
|
|
|
|
)
|
|
|
|
or not create_executable_script(
|
|
|
|
f"{chroot}/root/usr/local/bin/rustc", sccache_script
|
|
|
|
)
|
|
|
|
):
|
|
|
|
log_print("ERROR: Failed to set up sccache wrapper scripts")
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
def cleanup_sccache(chroot):
|
2022-09-06 03:12:11 +00:00
|
|
|
"""Unsets up sccache for the chroot."""
|
|
|
|
|
2022-06-02 06:02:07 +00:00
|
|
|
# cleanup sccache stuff
|
|
|
|
try:
|
|
|
|
subprocess.run(
|
2022-09-07 07:53:21 +00:00
|
|
|
(
|
|
|
|
"/usr/bin/env",
|
2022-06-02 06:02:07 +00:00
|
|
|
"sudo",
|
|
|
|
"rm",
|
|
|
|
"-f",
|
|
|
|
f"{chroot}/root/usr/local/bin/gcc",
|
|
|
|
f"{chroot}/root/usr/local/bin/g++",
|
2022-09-07 05:30:12 +00:00
|
|
|
f"{chroot}/root/usr/local/bin/cc",
|
|
|
|
f"{chroot}/root/usr/local/bin/c++",
|
2022-09-07 06:06:05 +00:00
|
|
|
f"{chroot}/root/usr/local/bin/cpp",
|
2022-06-02 06:02:07 +00:00
|
|
|
f"{chroot}/root/usr/local/bin/clang",
|
|
|
|
f"{chroot}/root/usr/local/bin/clang++",
|
|
|
|
f"{chroot}/root/usr/local/bin/rustc",
|
2022-09-07 07:53:21 +00:00
|
|
|
),
|
2022-06-02 06:02:07 +00:00
|
|
|
check=False,
|
|
|
|
)
|
|
|
|
except BaseException:
|
|
|
|
log_print("WARNING: Failed to cleanup sccache files")
|
|
|
|
|
|
|
|
|
|
|
|
def update_pkg_list(
|
|
|
|
pkgs,
|
|
|
|
pkg_state,
|
2022-06-04 07:14:37 +00:00
|
|
|
other_state,
|
2022-06-02 06:02:07 +00:00
|
|
|
signing_gpg_dir,
|
|
|
|
signing_gpg_key_fp,
|
|
|
|
signing_gpg_pass,
|
|
|
|
no_store,
|
|
|
|
):
|
2022-09-06 03:12:11 +00:00
|
|
|
"""For each package to build: builds it, signs it, and moves it to
|
|
|
|
"pkg_out_dir"."""
|
|
|
|
|
2022-06-02 06:02:07 +00:00
|
|
|
if not get_sudo_privileges():
|
|
|
|
log_print("ERROR: Failed to get sudo privileges")
|
|
|
|
sys.exit(1)
|
|
|
|
for pkg in pkgs:
|
2022-06-04 08:22:29 +00:00
|
|
|
pkgdir = os.path.join(other_state["clones_dir"], pkg)
|
2022-06-02 06:02:07 +00:00
|
|
|
log_print(f'Building "{pkg}"...')
|
|
|
|
if "ccache_dir" in pkg_state[pkg]:
|
2022-06-04 08:22:29 +00:00
|
|
|
cleanup_sccache(other_state["chroot"])
|
|
|
|
setup_ccache(other_state["chroot"])
|
2022-06-02 06:02:07 +00:00
|
|
|
else:
|
2022-06-04 08:22:29 +00:00
|
|
|
cleanup_ccache(other_state["chroot"])
|
2022-06-02 06:02:07 +00:00
|
|
|
if "sccache_dir" in pkg_state[pkg]:
|
2022-06-04 08:22:29 +00:00
|
|
|
setup_sccache(other_state["chroot"])
|
2022-06-02 06:02:07 +00:00
|
|
|
else:
|
2022-06-04 08:22:29 +00:00
|
|
|
cleanup_sccache(other_state["chroot"])
|
2022-06-02 06:02:07 +00:00
|
|
|
|
|
|
|
command_list = [
|
2022-09-07 07:53:21 +00:00
|
|
|
"/usr/bin/env",
|
2022-06-02 06:02:07 +00:00
|
|
|
"makechrootpkg",
|
|
|
|
"-c",
|
|
|
|
"-r",
|
2022-06-04 08:22:29 +00:00
|
|
|
other_state["chroot"],
|
2022-06-02 06:02:07 +00:00
|
|
|
]
|
|
|
|
post_command_list = [
|
|
|
|
"--",
|
|
|
|
"--syncdeps",
|
|
|
|
"--noconfirm",
|
|
|
|
"--log",
|
|
|
|
"--holdver",
|
|
|
|
]
|
|
|
|
for dep in pkg_state[pkg]["other_deps"]:
|
|
|
|
dep_fullpath = get_latest_pkg(dep, "/var/cache/pacman/pkg")
|
|
|
|
if not dep_fullpath:
|
|
|
|
log_print('ERROR: Failed to get dep "{}"'.format(dep))
|
|
|
|
sys.exit(1)
|
2022-09-07 07:53:21 +00:00
|
|
|
command_list.insert(2, "-I")
|
|
|
|
command_list.insert(3, dep_fullpath)
|
2022-06-02 06:02:07 +00:00
|
|
|
for aur_dep in pkg_state[pkg]["aur_deps"]:
|
2022-06-04 08:22:29 +00:00
|
|
|
aur_dep_fullpath = get_latest_pkg(
|
|
|
|
aur_dep, other_state["pkg_out_dir"]
|
|
|
|
)
|
2022-06-02 06:02:07 +00:00
|
|
|
if not aur_dep_fullpath:
|
|
|
|
log_print('ERROR: Failed to get aur_dep "{}"'.format(aur_dep))
|
|
|
|
sys.exit(1)
|
2022-09-07 07:53:21 +00:00
|
|
|
command_list.insert(2, "-I")
|
|
|
|
command_list.insert(3, aur_dep_fullpath)
|
2022-06-02 06:02:07 +00:00
|
|
|
if "ccache_dir" in pkg_state[pkg]:
|
2022-09-07 07:53:21 +00:00
|
|
|
command_list.insert(2, "-d")
|
|
|
|
command_list.insert(3, f'{pkg_state[pkg]["ccache_dir"]}:/ccache')
|
2022-06-02 06:02:07 +00:00
|
|
|
post_command_list.insert(1, "CCACHE_DIR=/ccache")
|
|
|
|
elif "sccache_dir" in pkg_state[pkg]:
|
2022-09-07 07:53:21 +00:00
|
|
|
command_list.insert(2, "-d")
|
|
|
|
command_list.insert(3, f'{pkg_state[pkg]["sccache_dir"]}:/sccache')
|
2022-06-02 06:02:07 +00:00
|
|
|
post_command_list.insert(1, "SCCACHE_DIR=/sccache")
|
|
|
|
post_command_list.insert(
|
|
|
|
2, f'SCCACHE_CACHE_SIZE={pkg_state[pkg]["sccache_cache_size"]}'
|
|
|
|
)
|
|
|
|
post_command_list.insert(3, "RUSTC_WRAPPER=/usr/bin/sccache")
|
|
|
|
nowstring = datetime.datetime.now(datetime.timezone.utc).strftime(
|
|
|
|
"%Y-%m-%d_%H-%M-%S_%Z"
|
|
|
|
)
|
|
|
|
# log_print(f"Using command list: {command_list + post_command_list}") # DEBUG
|
|
|
|
with open(
|
2022-06-04 08:22:29 +00:00
|
|
|
os.path.join(
|
|
|
|
other_state["logs_dir"], "{}_stdout_{}".format(pkg, nowstring)
|
|
|
|
),
|
2022-06-02 06:02:07 +00:00
|
|
|
"w",
|
|
|
|
) as log_stdout, open(
|
2022-06-04 08:22:29 +00:00
|
|
|
os.path.join(
|
|
|
|
other_state["logs_dir"], "{}_stderr_{}".format(pkg, nowstring)
|
|
|
|
),
|
2022-06-02 06:02:07 +00:00
|
|
|
"w",
|
|
|
|
) as log_stderr:
|
|
|
|
try:
|
|
|
|
subprocess.run(
|
|
|
|
command_list + post_command_list,
|
|
|
|
check=True,
|
2022-06-04 02:46:33 +00:00
|
|
|
cwd=pkgdir,
|
2022-06-02 06:02:07 +00:00
|
|
|
stdout=log_stdout,
|
|
|
|
stderr=log_stderr,
|
|
|
|
)
|
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
log_print(
|
|
|
|
'ERROR: Failed to build pkg "{}" in chroot'.format(pkg)
|
|
|
|
)
|
|
|
|
pkg_state[pkg]["build_status"] = "fail"
|
|
|
|
continue
|
|
|
|
|
|
|
|
if no_store:
|
|
|
|
pkg_state[pkg]["build_status"] = "success"
|
|
|
|
continue
|
|
|
|
|
2022-06-04 08:22:29 +00:00
|
|
|
pkg_list = glob.glob(
|
|
|
|
os.path.join(other_state["clones_dir"], pkg, "*.pkg.tar*")
|
|
|
|
)
|
2022-06-02 06:02:07 +00:00
|
|
|
|
|
|
|
log_print("Signing package...")
|
|
|
|
for gpkg in pkg_list:
|
|
|
|
try:
|
|
|
|
command_list = [
|
|
|
|
"gpg",
|
|
|
|
"--batch",
|
|
|
|
"--passphrase-fd",
|
|
|
|
"0",
|
|
|
|
"--pinentry-mode",
|
|
|
|
"loopback",
|
|
|
|
"--default-key",
|
|
|
|
signing_gpg_key_fp,
|
|
|
|
"--detach-sign",
|
|
|
|
gpkg,
|
|
|
|
]
|
|
|
|
subprocess.run(
|
|
|
|
command_list,
|
|
|
|
check=True,
|
2022-06-04 08:22:29 +00:00
|
|
|
cwd=os.path.join(other_state["clones_dir"], pkg),
|
2022-06-02 06:02:07 +00:00
|
|
|
input=signing_gpg_pass,
|
|
|
|
text=True,
|
|
|
|
env={"GNUPGHOME": signing_gpg_dir},
|
|
|
|
)
|
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
log_print(f'ERROR: Failed to sign pkg "{pkg}"')
|
|
|
|
|
|
|
|
log_print("Adding built pkgs to repo...")
|
|
|
|
try:
|
2022-06-04 08:22:29 +00:00
|
|
|
command_list = ["repo-add", other_state["repo"]]
|
2022-06-02 06:02:07 +00:00
|
|
|
for gpkg in pkg_list:
|
|
|
|
command_list.append(gpkg)
|
|
|
|
subprocess.run(command_list, check=True)
|
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
log_print(
|
|
|
|
'ERROR: Failed to add built pkg(s) "{}" to repo.'.format(pkg)
|
|
|
|
)
|
|
|
|
pkg_state[pkg]["build_status"] = "add_fail"
|
|
|
|
continue
|
|
|
|
|
2022-06-04 07:14:37 +00:00
|
|
|
log_print(f'Signing "{other_state["repo"]}"...')
|
2022-06-02 06:02:07 +00:00
|
|
|
try:
|
|
|
|
subprocess.run(
|
2022-09-07 07:53:21 +00:00
|
|
|
(
|
2022-06-02 06:02:07 +00:00
|
|
|
"/usr/bin/rm",
|
|
|
|
"-f",
|
2022-06-04 08:22:29 +00:00
|
|
|
str(
|
|
|
|
os.path.join(
|
|
|
|
other_state["pkg_out_dir"],
|
|
|
|
f"{other_state['repo']}.sig",
|
|
|
|
)
|
|
|
|
),
|
2022-09-07 07:53:21 +00:00
|
|
|
)
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
subprocess.run(
|
2022-09-07 07:53:21 +00:00
|
|
|
(
|
|
|
|
"/usr/bin/env",
|
|
|
|
"gpg",
|
2022-06-02 06:02:07 +00:00
|
|
|
"--batch",
|
|
|
|
"--passphrase-fd",
|
|
|
|
"0",
|
|
|
|
"--pinentry-mode",
|
|
|
|
"loopback",
|
|
|
|
"--default-key",
|
|
|
|
signing_gpg_key_fp,
|
|
|
|
"--detach-sign",
|
2022-06-04 08:22:29 +00:00
|
|
|
str(
|
|
|
|
os.path.join(
|
2022-09-07 07:53:21 +00:00
|
|
|
other_state["pkg_out_dir"], other_state["repo"]
|
2022-06-04 08:22:29 +00:00
|
|
|
)
|
|
|
|
),
|
2022-09-07 07:53:21 +00:00
|
|
|
),
|
2022-06-02 06:02:07 +00:00
|
|
|
check=True,
|
|
|
|
input=signing_gpg_pass,
|
|
|
|
text=True,
|
|
|
|
env={"GNUPGHOME": signing_gpg_dir},
|
|
|
|
)
|
2022-06-04 07:14:37 +00:00
|
|
|
repo_sig_name = f"{other_state['repo']}.sig"
|
2022-06-02 08:16:49 +00:00
|
|
|
if repo_sig_name.rfind("/") != -1:
|
|
|
|
repo_sig_name = repo_sig_name.rsplit(sep="/", maxsplit=1)[1]
|
2022-06-02 08:00:31 +00:00
|
|
|
subprocess.run(
|
2022-09-07 07:53:21 +00:00
|
|
|
(
|
|
|
|
"/usr/bin/env",
|
|
|
|
"ln",
|
2022-06-02 08:00:31 +00:00
|
|
|
"-sf",
|
2022-06-02 08:16:49 +00:00
|
|
|
repo_sig_name,
|
2022-06-04 08:22:29 +00:00
|
|
|
str(
|
|
|
|
os.path.join(
|
2022-09-07 07:53:21 +00:00
|
|
|
other_state["pkg_out_dir"], other_state["repo"]
|
2022-06-04 08:22:29 +00:00
|
|
|
)
|
|
|
|
).removesuffix(".tar")
|
2022-06-02 08:22:45 +00:00
|
|
|
+ ".sig",
|
2022-09-07 07:53:21 +00:00
|
|
|
)
|
2022-06-02 08:00:31 +00:00
|
|
|
)
|
2022-06-02 06:02:07 +00:00
|
|
|
except subprocess.CalledProcessError:
|
2022-06-04 07:14:37 +00:00
|
|
|
log_print(f'WARNING: Failed to sign "{other_state["repo"]}"')
|
2022-06-02 06:02:07 +00:00
|
|
|
|
|
|
|
pkg_state[pkg]["build_status"] = "success"
|
|
|
|
|
|
|
|
log_print("Moving pkg to pkgs directory...")
|
|
|
|
for f in pkg_list:
|
|
|
|
log_print(f'Moving "{f}"...')
|
2022-06-04 08:22:29 +00:00
|
|
|
os.rename(
|
|
|
|
f, os.path.join(other_state["pkg_out_dir"], os.path.basename(f))
|
|
|
|
)
|
2022-06-02 06:02:07 +00:00
|
|
|
sig_name = f + ".sig"
|
|
|
|
if os.path.exists(sig_name):
|
|
|
|
log_print(f'Moving "{sig_name}"...')
|
|
|
|
os.rename(
|
|
|
|
sig_name,
|
2022-06-04 08:22:29 +00:00
|
|
|
os.path.join(
|
|
|
|
other_state["pkg_out_dir"], os.path.basename(sig_name)
|
|
|
|
),
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
for pkg in pkgs:
|
|
|
|
log_print(f'"{pkg}" status: {pkg_state[pkg]["build_status"]}')
|
|
|
|
|
|
|
|
|
|
|
|
def get_latest_pkg(pkg, cache_dir):
|
2022-09-06 03:12:11 +00:00
|
|
|
"""Gets the latest pkg from the specified "cache_dir" and return its
|
|
|
|
filename."""
|
|
|
|
|
2022-06-02 06:02:07 +00:00
|
|
|
globbed = glob.glob(os.path.join(cache_dir, pkg + "*"))
|
|
|
|
if len(globbed) > 0:
|
|
|
|
globbed.sort()
|
|
|
|
reprog = re.compile(
|
|
|
|
".*"
|
|
|
|
+ pkg
|
|
|
|
+ "-[0-9a-zA-Z.+_:]+-[0-9a-zA-Z.+_]+-(any|x86_64).pkg.tar.(xz|gz|zst)$"
|
|
|
|
)
|
|
|
|
result = list(filter(lambda x: reprog.match(x), globbed))
|
|
|
|
if len(result) == 0:
|
|
|
|
return None
|
|
|
|
else:
|
|
|
|
return result[-1]
|
|
|
|
else:
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
def confirm_result(pkg, state_result):
|
2022-09-06 03:12:11 +00:00
|
|
|
"""Prompts the user the action to take for a pkg after checking its
|
|
|
|
PKGBUILD.
|
|
|
|
|
|
|
|
Returns "continue", "recheck", "force_build", "skip", "back", or "abort"."""
|
|
|
|
|
2022-06-02 06:02:07 +00:00
|
|
|
while True:
|
2022-06-02 07:49:26 +00:00
|
|
|
log_print(
|
2022-06-02 06:02:07 +00:00
|
|
|
'Got "{}" for pkg "{}", action: [C(ontinue), r(echeck), f(orce build),\
|
|
|
|
s(kip), b(ack) a(abort)]'.format(
|
|
|
|
state_result, pkg
|
|
|
|
)
|
|
|
|
)
|
|
|
|
user_input = sys.stdin.buffer.readline().decode().strip().lower()
|
|
|
|
if user_input == "c" or len(user_input) == 0:
|
|
|
|
return "continue"
|
|
|
|
elif user_input == "r":
|
|
|
|
return "recheck"
|
|
|
|
elif user_input == "f":
|
|
|
|
return "force_build"
|
|
|
|
elif user_input == "s":
|
|
|
|
return "skip"
|
|
|
|
elif user_input == "b":
|
|
|
|
return "back"
|
|
|
|
elif user_input == "a":
|
|
|
|
return "abort"
|
|
|
|
else:
|
|
|
|
log_print("Got invalid input")
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
|
|
def print_state_info_and_get_update_list(pkg_state):
|
2022-09-06 03:12:11 +00:00
|
|
|
"""Prints the current "checked" state of all pkgs in the config."""
|
|
|
|
|
2022-06-02 06:02:07 +00:00
|
|
|
to_update = []
|
|
|
|
log_print("package state:")
|
|
|
|
for (pkg_name, pkg_dict) in pkg_state.items():
|
|
|
|
if "state" in pkg_dict:
|
|
|
|
log_print(f" {pkg_name:40}: {pkg_dict['state']}")
|
|
|
|
if pkg_dict["state"] == "install":
|
|
|
|
to_update.append(pkg_name)
|
|
|
|
else:
|
|
|
|
log_print(f" {pkg_name:40}: not reached")
|
|
|
|
return to_update
|
|
|
|
|
|
|
|
|
|
|
|
def test_gpg_passphrase(signing_gpg_dir, signing_key_fp, passphrase):
|
2022-09-06 03:12:11 +00:00
|
|
|
"""Checks if the given gpg passphrase works with the gpg signing key."""
|
|
|
|
|
2022-06-02 06:02:07 +00:00
|
|
|
with tempfile.NamedTemporaryFile() as tempnf:
|
|
|
|
tempnf.write(b"Test file content")
|
|
|
|
tempnf.flush()
|
|
|
|
try:
|
|
|
|
subprocess.run(
|
2022-09-07 07:53:21 +00:00
|
|
|
(
|
|
|
|
"/usr/bin/env",
|
2022-06-02 06:02:07 +00:00
|
|
|
"gpg",
|
|
|
|
"--batch",
|
|
|
|
"--passphrase-fd",
|
|
|
|
"0",
|
|
|
|
"--pinentry-mode",
|
|
|
|
"loopback",
|
|
|
|
"--default-key",
|
|
|
|
signing_key_fp,
|
|
|
|
"--detach-sign",
|
|
|
|
tempnf.name,
|
2022-09-07 07:53:21 +00:00
|
|
|
),
|
2022-06-02 06:02:07 +00:00
|
|
|
check=True,
|
|
|
|
input=passphrase,
|
|
|
|
text=True,
|
|
|
|
env={"GNUPGHOME": signing_gpg_dir},
|
|
|
|
)
|
|
|
|
os.remove(tempnf.name + ".sig")
|
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
log_print("ERROR: Failed to sign test file with gpg")
|
|
|
|
return False
|
|
|
|
log_print("Verified passphrase works by signing dummy test file")
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
2022-06-04 08:15:52 +00:00
|
|
|
def validate_and_verify_paths(other_state):
|
2022-09-06 03:12:11 +00:00
|
|
|
"""Checks and validates/ensures that certain directories exist."""
|
|
|
|
|
2022-06-04 08:22:29 +00:00
|
|
|
if not os.path.exists(other_state["chroot"]):
|
|
|
|
log_print(
|
|
|
|
f"ERROR: chroot at \"{other_state['chroot']}\" does not exist"
|
|
|
|
)
|
2022-06-04 08:15:52 +00:00
|
|
|
sys.exit(1)
|
|
|
|
log_print("Ensuring pkgs directory exists...")
|
2022-06-04 08:22:29 +00:00
|
|
|
if not os.path.exists(other_state["pkg_out_dir"]):
|
|
|
|
pkg_out_dir_path = Path(other_state["pkg_out_dir"])
|
2022-06-04 08:15:52 +00:00
|
|
|
pkg_out_dir_path.mkdir(parents=True)
|
2022-06-04 08:22:29 +00:00
|
|
|
if not os.path.exists(other_state["gpg_home"]):
|
|
|
|
log_print(
|
|
|
|
f"ERROR: checkingGPG at \"{other_state['gpg_home']}\" does not exist"
|
|
|
|
)
|
2022-06-04 08:15:52 +00:00
|
|
|
sys.exit(1)
|
2022-06-04 08:22:29 +00:00
|
|
|
if "signing_gpg_dir" in other_state and not os.path.exists(
|
|
|
|
other_state["signing_gpg_dir"]
|
|
|
|
):
|
|
|
|
log_print(
|
|
|
|
f"ERROR: signingGPG at \"{other_state['signing_gpg_dir']}\" does not exist"
|
|
|
|
)
|
2022-06-04 08:17:15 +00:00
|
|
|
sys.exit(1)
|
2022-06-04 08:15:52 +00:00
|
|
|
log_print("Ensuring logs directory exists...")
|
2022-06-04 08:22:29 +00:00
|
|
|
if other_state["logs_dir"] is None:
|
2022-06-04 08:15:52 +00:00
|
|
|
log_print('ERROR: "logs_dir" was not specified!')
|
|
|
|
sys.exit(1)
|
2022-06-04 08:22:29 +00:00
|
|
|
if not os.path.exists(other_state["logs_dir"]):
|
|
|
|
logs_dir_path = Path(other_state["logs_dir"])
|
2022-06-04 08:15:52 +00:00
|
|
|
logs_dir_path.mkdir(parents=True)
|
|
|
|
log_print("Ensuring clones directory exists...")
|
2022-06-04 08:22:29 +00:00
|
|
|
if not os.path.exists(other_state["clones_dir"]):
|
|
|
|
clones_dir_path = Path(other_state["clones_dir"])
|
2022-06-04 08:15:52 +00:00
|
|
|
clones_dir_path.mkdir(parents=True)
|
|
|
|
|
|
|
|
|
2022-06-02 06:02:07 +00:00
|
|
|
if __name__ == "__main__":
|
2022-06-02 07:49:26 +00:00
|
|
|
editor = None
|
2022-06-02 06:02:07 +00:00
|
|
|
parser = argparse.ArgumentParser(description="Update AUR pkgs")
|
|
|
|
parser.add_argument(
|
|
|
|
"--config", help="Info and pkg(s) to update in a .toml config"
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"-p", "--pkg", action="append", help="Pkg(s) to update", metavar="pkg"
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"--no-skip",
|
|
|
|
action="append",
|
|
|
|
help="Pkg(s) to not skip if up to date",
|
|
|
|
metavar="noskip",
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"-e",
|
|
|
|
"--editor",
|
2022-06-02 07:45:50 +00:00
|
|
|
default=None,
|
2022-06-02 06:02:07 +00:00
|
|
|
help="editor to use when viewing PKGBUILDs",
|
|
|
|
metavar="editor",
|
|
|
|
)
|
|
|
|
parser.add_argument("--chroot", help="Chroot to build in")
|
|
|
|
parser.add_argument("--pkg-dir", help="Destination for built pkgs")
|
|
|
|
parser.add_argument("--repo", help="repository tar file")
|
|
|
|
parser.add_argument("--gpg-dir", help="gpg home for checking signatures")
|
|
|
|
parser.add_argument("--logs-dir", help="dir to put logs")
|
|
|
|
parser.add_argument(
|
|
|
|
"--no-update", help="Do not update chroot", action="store_true"
|
|
|
|
)
|
|
|
|
parser.add_argument("--signing-gpg-dir", help="gpg home for signing key")
|
|
|
|
parser.add_argument(
|
|
|
|
"--signing-gpg-key-fp", help="gpg fingerprint for signing key"
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"--no-store",
|
|
|
|
action="store_true",
|
|
|
|
help="Don't sign built package and add to repo",
|
|
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
if (
|
|
|
|
args.pkg
|
|
|
|
and not args.config
|
|
|
|
and (
|
|
|
|
not args.chroot
|
|
|
|
or not args.pkg_dir
|
|
|
|
or not args.repo
|
|
|
|
or not args.gpg_dir
|
|
|
|
or not args.logs_dir
|
|
|
|
)
|
|
|
|
):
|
2022-06-02 07:49:26 +00:00
|
|
|
log_print(
|
2022-06-02 06:02:07 +00:00
|
|
|
"ERROR: --pkg requires also --chroot, --pkg_dir, --repo, --gpg_dir, and --logs_dir"
|
|
|
|
)
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
pkg_state = {}
|
2022-06-04 02:46:33 +00:00
|
|
|
other_state = {}
|
2022-06-04 08:22:29 +00:00
|
|
|
other_state["logs_dir"] = None
|
2022-06-02 06:02:07 +00:00
|
|
|
if args.pkg and not args.config:
|
|
|
|
for pkg in args.pkg:
|
|
|
|
pkg_state[pkg] = {}
|
|
|
|
pkg_state[pkg]["aur_deps"] = []
|
2022-06-04 08:22:29 +00:00
|
|
|
other_state["chroot"] = args.chroot
|
|
|
|
other_state["pkg_out_dir"] = args.pkg_dir
|
|
|
|
other_state["repo"] = args.repo
|
|
|
|
other_state["gpg_home"] = args.gpg_dir
|
|
|
|
other_state["logs_dir"] = args.logs_dir
|
2022-06-02 06:02:07 +00:00
|
|
|
if args_logs_dir is not None:
|
|
|
|
GLOBAL_LOG_FILE = args_logs_dir + "/update.py_logs"
|
|
|
|
log_print(
|
|
|
|
f"{datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M %Z')}"
|
|
|
|
)
|
|
|
|
log_print(f"Set GLOBAL_LOG_FILE to {GLOBAL_LOG_FILE}")
|
2022-06-04 08:22:29 +00:00
|
|
|
other_state["signing_gpg_dir"] = args.signing_gpg_dir
|
|
|
|
other_state["signing_gpg_key_fp"] = args.signing_gpg_key_fp
|
2022-06-02 06:02:07 +00:00
|
|
|
if args_signing_gpg_key_fp is None:
|
|
|
|
log_print(
|
|
|
|
'ERROR: Signing key fingerprint "signing_gpg_key_fp" not present in config'
|
|
|
|
)
|
|
|
|
sys.exit(1)
|
|
|
|
if args_signing_gpg_dir is not None and not args.no_store:
|
2022-06-04 08:22:29 +00:00
|
|
|
other_state["signing_gpg_pass"] = getpass.getpass(
|
|
|
|
"gpg signing key pass: "
|
|
|
|
)
|
2022-06-02 06:02:07 +00:00
|
|
|
if not test_gpg_passphrase(
|
2022-06-04 08:22:29 +00:00
|
|
|
other_state["signing_gpg_dir"],
|
|
|
|
other_state["signing_gpg_key_fp"],
|
|
|
|
other_state["signing_gpg_pass"],
|
2022-06-02 06:02:07 +00:00
|
|
|
):
|
|
|
|
sys.exit(1)
|
|
|
|
elif args.config:
|
|
|
|
d = toml.load(args.config)
|
|
|
|
for entry in d["entry"]:
|
|
|
|
pkg_state[entry["name"]] = {}
|
|
|
|
if "aur_deps" in entry:
|
|
|
|
pkg_state[entry["name"]]["aur_deps"] = entry["aur_deps"]
|
|
|
|
else:
|
|
|
|
pkg_state[entry["name"]]["aur_deps"] = []
|
|
|
|
if "repo_path" in entry:
|
|
|
|
pkg_state[entry["name"]]["repo_path"] = entry["repo_path"]
|
|
|
|
if "pkg_name" in entry:
|
|
|
|
pkg_state[entry["name"]]["pkg_name"] = entry["pkg_name"]
|
|
|
|
else:
|
|
|
|
pkg_state[entry["name"]]["pkg_name"] = entry["name"]
|
|
|
|
if "ccache_dir" in entry:
|
|
|
|
pkg_state[entry["name"]]["ccache_dir"] = entry["ccache_dir"]
|
|
|
|
elif "sccache_dir" in entry:
|
|
|
|
pkg_state[entry["name"]]["sccache_dir"] = entry["sccache_dir"]
|
|
|
|
if "sccache_cache_size" in entry:
|
|
|
|
pkg_state[entry["name"]]["sccache_cache_size"] = entry[
|
|
|
|
"sccache_cache_size"
|
|
|
|
]
|
|
|
|
else:
|
|
|
|
pkg_state[entry["name"]]["sccache_cache_size"] = "5G"
|
|
|
|
if "other_deps" in entry:
|
|
|
|
pkg_state[entry["name"]]["other_deps"] = entry["other_deps"]
|
|
|
|
else:
|
|
|
|
pkg_state[entry["name"]]["other_deps"] = []
|
|
|
|
if "skip_branch_up_to_date" in entry and not (
|
|
|
|
not args.no_skip is None and entry["name"] in args.no_skip
|
|
|
|
):
|
|
|
|
pkg_state[entry["name"]]["skip_branch_up_to_date"] = True
|
|
|
|
else:
|
|
|
|
pkg_state[entry["name"]]["skip_branch_up_to_date"] = False
|
2022-06-04 08:22:29 +00:00
|
|
|
other_state["chroot"] = d["chroot"]
|
|
|
|
other_state["pkg_out_dir"] = d["pkg_out_dir"]
|
|
|
|
other_state["repo"] = d["repo"]
|
|
|
|
other_state["gpg_home"] = d["gpg_dir"]
|
|
|
|
other_state["logs_dir"] = d["logs_dir"]
|
|
|
|
other_state["clones_dir"] = d["clones_dir"]
|
|
|
|
if other_state["logs_dir"] is not None:
|
|
|
|
GLOBAL_LOG_FILE = other_state["logs_dir"] + "/update.py_logs"
|
2022-06-02 06:02:07 +00:00
|
|
|
log_print(
|
|
|
|
f"{datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M %Z')}"
|
|
|
|
)
|
|
|
|
log_print(f"Set GLOBAL_LOG_FILE to {GLOBAL_LOG_FILE}")
|
|
|
|
if args.pkg:
|
|
|
|
to_keep = [args_pkg for args_pkg in args.pkg]
|
|
|
|
removal = []
|
|
|
|
for existing in pkg_state.keys():
|
|
|
|
if existing in to_keep:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
removal.append(existing)
|
|
|
|
for to_remove in removal:
|
|
|
|
del pkg_state[to_remove]
|
|
|
|
|
|
|
|
if "signing_gpg_dir" in d and not args.no_store:
|
2022-06-04 08:22:29 +00:00
|
|
|
other_state["signing_gpg_dir"] = d["signing_gpg_dir"]
|
|
|
|
other_state["signing_gpg_key_fp"] = d["signing_gpg_key_fp"]
|
|
|
|
other_state["signing_gpg_pass"] = getpass.getpass(
|
|
|
|
"gpg signing key pass: "
|
|
|
|
)
|
2022-06-02 06:02:07 +00:00
|
|
|
if not test_gpg_passphrase(
|
2022-06-04 08:22:29 +00:00
|
|
|
other_state["signing_gpg_dir"],
|
|
|
|
other_state["signing_gpg_key_fp"],
|
|
|
|
other_state["signing_gpg_pass"],
|
2022-06-02 06:02:07 +00:00
|
|
|
):
|
|
|
|
sys.exit(1)
|
2022-06-02 07:45:50 +00:00
|
|
|
if "editor" in d:
|
|
|
|
editor = d["editor"]
|
2022-06-02 06:02:07 +00:00
|
|
|
else:
|
|
|
|
log_print('ERROR: At least "--config" or "--pkg" must be specified')
|
|
|
|
sys.exit(1)
|
|
|
|
|
2022-06-04 08:15:52 +00:00
|
|
|
validate_and_verify_paths(other_state)
|
|
|
|
|
2022-06-02 07:45:50 +00:00
|
|
|
if args.editor is not None:
|
|
|
|
editor = args.editor
|
|
|
|
|
2022-06-02 07:49:26 +00:00
|
|
|
if editor is None:
|
|
|
|
editor = DEFAULT_EDITOR
|
|
|
|
|
2022-06-04 08:22:29 +00:00
|
|
|
os.putenv("CHROOT", os.path.realpath(other_state["chroot"]))
|
|
|
|
os.putenv("GNUPGHOME", os.path.realpath(other_state["gpg_home"]))
|
|
|
|
if not os.path.exists(other_state["logs_dir"]):
|
|
|
|
os.makedirs(other_state["logs_dir"])
|
|
|
|
elif not os.path.isdir(other_state["logs_dir"]):
|
2022-06-02 06:02:07 +00:00
|
|
|
log_print(
|
2022-06-04 08:22:29 +00:00
|
|
|
'ERROR: logs_dir "{}" must be a directory'.format(
|
|
|
|
other_state["logs_dir"]
|
|
|
|
)
|
2022-06-02 06:02:07 +00:00
|
|
|
)
|
|
|
|
sys.exit(1)
|
2022-07-20 02:32:26 +00:00
|
|
|
|
|
|
|
if not args.no_update:
|
|
|
|
log_print("Updating the chroot...")
|
|
|
|
try:
|
|
|
|
subprocess.run(
|
2022-09-07 07:53:21 +00:00
|
|
|
(
|
|
|
|
"/usr/bin/env",
|
2022-07-20 02:32:26 +00:00
|
|
|
"arch-nspawn",
|
|
|
|
"{}/root".format(other_state["chroot"]),
|
|
|
|
"pacman",
|
|
|
|
"-Syu",
|
2022-09-07 07:53:21 +00:00
|
|
|
),
|
2022-07-20 02:32:26 +00:00
|
|
|
check=True,
|
|
|
|
)
|
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
log_print("ERROR: Failed to update the chroot")
|
|
|
|
sys.exit(1)
|
|
|
|
|
2022-06-02 06:02:07 +00:00
|
|
|
pkg_list = [temp_pkg_name for temp_pkg_name in pkg_state.keys()]
|
|
|
|
i = 0
|
2022-07-05 02:56:29 +00:00
|
|
|
furthest_checked = 0
|
|
|
|
going_back = False
|
2022-06-02 06:02:07 +00:00
|
|
|
while i < len(pkg_list):
|
2022-07-05 02:56:29 +00:00
|
|
|
if i > furthest_checked:
|
|
|
|
furthest_checked = i
|
2022-06-04 07:14:37 +00:00
|
|
|
if not ensure_pkg_dir_exists(pkg_list[i], pkg_state, other_state):
|
2022-06-02 06:02:07 +00:00
|
|
|
print_state_info_and_get_update_list(pkg_state)
|
|
|
|
sys.exit(1)
|
|
|
|
if (
|
|
|
|
"repo_path" not in pkg_state[pkg_list[i]]
|
|
|
|
or pkg_state[pkg_list[i]]["repo_path"] != "NO_REPO"
|
|
|
|
):
|
|
|
|
update_pkg_dir_count = 0
|
|
|
|
update_pkg_dir_success = False
|
|
|
|
while update_pkg_dir_count < 5:
|
2022-06-02 08:22:45 +00:00
|
|
|
(success, skip_on_same_ver) = update_pkg_dir(
|
2022-06-04 07:14:37 +00:00
|
|
|
pkg_list[i], pkg_state, other_state
|
2022-06-02 08:22:45 +00:00
|
|
|
)
|
2022-06-02 06:02:07 +00:00
|
|
|
if success:
|
|
|
|
update_pkg_dir_success = True
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
time.sleep(1)
|
|
|
|
update_pkg_dir_count += 1
|
|
|
|
if not update_pkg_dir_success:
|
|
|
|
log_print('Failed to update pkg dir for "{}"', pkg_list[i])
|
|
|
|
print_state_info_and_get_update_list(pkg_state)
|
|
|
|
sys.exit(1)
|
2022-07-05 02:56:29 +00:00
|
|
|
if skip_on_same_ver and i >= furthest_checked:
|
2022-06-02 08:22:45 +00:00
|
|
|
check_pkg_version_result = check_pkg_version(
|
2022-06-04 08:22:29 +00:00
|
|
|
pkg_list[i], pkg_state, other_state["repo"], True, other_state
|
2022-06-02 08:22:45 +00:00
|
|
|
)
|
2022-06-02 06:02:07 +00:00
|
|
|
if check_pkg_version_result != "install":
|
2022-06-02 08:22:45 +00:00
|
|
|
log_print(f"Pkg {pkg_list[i]} is up to date, skipping...")
|
2022-06-02 06:02:07 +00:00
|
|
|
pkg_state[pkg_list[i]]["state"] = "up to date"
|
|
|
|
i += 1
|
|
|
|
continue
|
2022-06-04 08:22:29 +00:00
|
|
|
check_pkg_build_result = check_pkg_build(
|
|
|
|
pkg_list[i], pkg_state, other_state, editor
|
|
|
|
)
|
2022-06-04 02:46:33 +00:00
|
|
|
if check_pkg_build_result == "ok":
|
|
|
|
pass
|
|
|
|
elif check_pkg_build_result == "not_ok":
|
|
|
|
pkg_state[pkg_list[i]]["state"] = "skip"
|
|
|
|
i += 1
|
|
|
|
continue
|
|
|
|
elif check_pkg_build_result == "force_build":
|
|
|
|
pkg_state[pkg_list[i]]["state"] = "install"
|
|
|
|
i += 1
|
|
|
|
continue
|
|
|
|
elif check_pkg_build_result == "invalid":
|
|
|
|
continue
|
|
|
|
elif check_pkg_build_result == "back":
|
|
|
|
if i > 0:
|
|
|
|
i -= 1
|
|
|
|
continue
|
|
|
|
else: # check_pkg_build_result == "abort":
|
|
|
|
print_state_info_and_get_update_list(pkg_state)
|
|
|
|
sys.exit(1)
|
2022-06-02 06:02:07 +00:00
|
|
|
while True:
|
2022-07-05 02:56:29 +00:00
|
|
|
if (
|
|
|
|
skip_on_same_ver
|
|
|
|
and check_pkg_version_result is not None
|
|
|
|
and i >= furthest_checked
|
|
|
|
):
|
2022-06-02 06:02:07 +00:00
|
|
|
state_result = check_pkg_version_result
|
|
|
|
else:
|
2022-06-02 08:22:45 +00:00
|
|
|
state_result = check_pkg_version(
|
2022-06-04 08:22:29 +00:00
|
|
|
pkg_list[i],
|
|
|
|
pkg_state,
|
|
|
|
other_state["repo"],
|
|
|
|
False,
|
|
|
|
other_state,
|
2022-06-02 08:22:45 +00:00
|
|
|
)
|
2022-06-02 06:02:07 +00:00
|
|
|
confirm_result_result = confirm_result(pkg_list[i], state_result)
|
|
|
|
if confirm_result_result == "continue":
|
|
|
|
pkg_state[pkg_list[i]]["state"] = state_result
|
|
|
|
break
|
|
|
|
elif confirm_result_result == "recheck":
|
|
|
|
check_pkg_version_result = None
|
|
|
|
continue
|
|
|
|
elif confirm_result_result == "force_build":
|
|
|
|
pkg_state[pkg_list[i]]["state"] = "install"
|
|
|
|
break
|
|
|
|
elif confirm_result_result == "skip":
|
|
|
|
pkg_state[pkg_list[i]]["state"] = "skip"
|
|
|
|
break
|
|
|
|
elif confirm_result_result == "back":
|
|
|
|
if i > 0:
|
|
|
|
i -= 1
|
|
|
|
going_back = True
|
|
|
|
break
|
|
|
|
else: # confirm_result_result == "abort"
|
|
|
|
print_state_info_and_get_update_list(pkg_state)
|
|
|
|
sys.exit(1)
|
|
|
|
if going_back:
|
2022-07-05 02:56:29 +00:00
|
|
|
going_back = False
|
2022-06-02 06:02:07 +00:00
|
|
|
else:
|
|
|
|
i += 1
|
|
|
|
|
|
|
|
log_print("Showing current actions:")
|
|
|
|
pkgs_to_update = print_state_info_and_get_update_list(pkg_state)
|
|
|
|
if len(pkgs_to_update) > 0:
|
|
|
|
log_print("Continue? [Y/n]")
|
|
|
|
user_input = sys.stdin.buffer.readline().decode().strip().lower()
|
|
|
|
if user_input == "y" or len(user_input) == 0:
|
|
|
|
if args.no_update:
|
|
|
|
log_print("Updating (without updating chroot)...")
|
|
|
|
else:
|
|
|
|
log_print("Updating...")
|
|
|
|
update_pkg_list(
|
|
|
|
pkgs_to_update,
|
|
|
|
pkg_state,
|
2022-06-04 07:14:37 +00:00
|
|
|
other_state,
|
2022-06-04 08:22:29 +00:00
|
|
|
"" if args.no_store else other_state["signing_gpg_dir"],
|
|
|
|
"" if args.no_store else other_state["signing_gpg_key_fp"],
|
|
|
|
"" if args.no_store else other_state["signing_gpg_pass"],
|
2022-06-02 06:02:07 +00:00
|
|
|
args.no_store,
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
log_print("Canceled.")
|
|
|
|
else:
|
|
|
|
log_print("No packages to update, done.")
|