Add checking of install script
PKGBUILDs may have a "install=<some_file>" line which should be checked, as the install script is used for hooks during installation. This commit adds checking of such install scripts (only if the package's PKGBUILD actually has a "install=<some_file>" defined).
This commit is contained in:
parent
130789dba8
commit
3960bb187e
1 changed files with 268 additions and 9 deletions
277
update.py
277
update.py
|
@ -32,6 +32,32 @@ STRFTIME_LOCAL_FORMAT = "%Y-%m-%dT%H:%M:%S"
|
||||||
PKG_STATE = None
|
PKG_STATE = None
|
||||||
OTHER_STATE = None
|
OTHER_STATE = None
|
||||||
|
|
||||||
|
DUMMY_PKGBUILD = """pkgname=dummy_pkg
|
||||||
|
pkgver=1.0
|
||||||
|
pkgrel=1
|
||||||
|
pkgdesc="dummy pkg"
|
||||||
|
arch=(any)
|
||||||
|
url="https://example.com"
|
||||||
|
license=('MIT')
|
||||||
|
source=()
|
||||||
|
|
||||||
|
prepare() {
|
||||||
|
echo prepare
|
||||||
|
}
|
||||||
|
|
||||||
|
build() {
|
||||||
|
echo build
|
||||||
|
}
|
||||||
|
|
||||||
|
check() {
|
||||||
|
echo check
|
||||||
|
}
|
||||||
|
|
||||||
|
package() {
|
||||||
|
echo package
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class ArchPkgVersion:
|
class ArchPkgVersion:
|
||||||
"""Holds a version (typically of an ArchLinux package) for comparison."""
|
"""Holds a version (typically of an ArchLinux package) for comparison."""
|
||||||
|
@ -697,9 +723,11 @@ def get_pkgbuild_version(
|
||||||
"makechrootpkg",
|
"makechrootpkg",
|
||||||
"-c",
|
"-c",
|
||||||
"-r",
|
"-r",
|
||||||
other_state["tmpfs_chroot"]
|
(
|
||||||
if other_state["tmpfs"]
|
other_state["tmpfs_chroot"]
|
||||||
else other_state["chroot"],
|
if other_state["tmpfs"]
|
||||||
|
else other_state["chroot"]
|
||||||
|
),
|
||||||
]
|
]
|
||||||
post_command_list = ["--", "-s", "-r", "-c", "--nobuild"]
|
post_command_list = ["--", "-s", "-r", "-c", "--nobuild"]
|
||||||
if "link_cargo_registry" in pkg_state[pkg]:
|
if "link_cargo_registry" in pkg_state[pkg]:
|
||||||
|
@ -757,9 +785,11 @@ def get_pkgbuild_version(
|
||||||
|
|
||||||
# Setup checking the PKGBUILD from within the chroot.
|
# Setup checking the PKGBUILD from within the chroot.
|
||||||
chroot_user_path = os.path.join(
|
chroot_user_path = os.path.join(
|
||||||
other_state["tmpfs_chroot"]
|
(
|
||||||
if other_state["tmpfs"]
|
other_state["tmpfs_chroot"]
|
||||||
else other_state["chroot"],
|
if other_state["tmpfs"]
|
||||||
|
else other_state["chroot"]
|
||||||
|
),
|
||||||
other_state["USER"],
|
other_state["USER"],
|
||||||
)
|
)
|
||||||
chroot_build_path = os.path.join(chroot_user_path, "build")
|
chroot_build_path = os.path.join(chroot_user_path, "build")
|
||||||
|
@ -1330,9 +1360,11 @@ def update_pkg_list(
|
||||||
"makechrootpkg",
|
"makechrootpkg",
|
||||||
"-c",
|
"-c",
|
||||||
"-r",
|
"-r",
|
||||||
other_state["tmpfs_chroot"]
|
(
|
||||||
if other_state["tmpfs"]
|
other_state["tmpfs_chroot"]
|
||||||
else other_state["chroot"],
|
if other_state["tmpfs"]
|
||||||
|
else other_state["chroot"]
|
||||||
|
),
|
||||||
]
|
]
|
||||||
post_command_list = [
|
post_command_list = [
|
||||||
"--",
|
"--",
|
||||||
|
@ -1839,6 +1871,164 @@ def signal_handler(sig, frame):
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def check_install_script(
|
||||||
|
pkg_state: dict[str, Any],
|
||||||
|
other_state: dict[str, Any],
|
||||||
|
pkg: str,
|
||||||
|
editor: str,
|
||||||
|
):
|
||||||
|
"""Returns "error", "does_not_exist", and "ok"."""
|
||||||
|
|
||||||
|
pkgdir = os.path.join(other_state["clones_dir"], pkg)
|
||||||
|
|
||||||
|
chroot_user_path = os.path.join(
|
||||||
|
(
|
||||||
|
other_state["tmpfs_chroot"]
|
||||||
|
if other_state["tmpfs"]
|
||||||
|
else other_state["chroot"]
|
||||||
|
),
|
||||||
|
other_state["USER"],
|
||||||
|
)
|
||||||
|
chroot_build_path = os.path.join(chroot_user_path, "build")
|
||||||
|
chroot_check_pkgbuild_path = os.path.join(chroot_build_path, "PKGBUILD")
|
||||||
|
chroot_check_sh_path = os.path.join(chroot_build_path, "install_check.sh")
|
||||||
|
|
||||||
|
if not prepare_user_chroot(other_state):
|
||||||
|
log_print(
|
||||||
|
f"ERROR: Failed to prepare user chroot with dummy PKGBUILD!",
|
||||||
|
other_state=other_state,
|
||||||
|
)
|
||||||
|
return "error"
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.run(
|
||||||
|
(
|
||||||
|
"/usr/bin/cp",
|
||||||
|
os.path.join(pkgdir, "PKGBUILD"),
|
||||||
|
chroot_check_pkgbuild_path,
|
||||||
|
),
|
||||||
|
check=True,
|
||||||
|
)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
log_print(
|
||||||
|
f'ERROR: Failed to check PKGBUILD install (moving PKGBUILD to chroot) for "{pkg}"!',
|
||||||
|
other_state=other_state,
|
||||||
|
)
|
||||||
|
return "error"
|
||||||
|
|
||||||
|
get_install_script = """#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
source "/build/PKGBUILD"
|
||||||
|
|
||||||
|
if [[ -n "$install" ]]; then
|
||||||
|
echo "$install"
|
||||||
|
else
|
||||||
|
echo "PKGBUILD_INSTALL_DOES_NOT_EXIST"
|
||||||
|
fi
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not create_executable_script(chroot_check_sh_path, get_install_script):
|
||||||
|
log_print(
|
||||||
|
f'ERROR: Failed to check PKGBUILD install (check PKGBUILD setup) for "{pkg}"!',
|
||||||
|
other_state=other_state,
|
||||||
|
)
|
||||||
|
return "error"
|
||||||
|
|
||||||
|
install_output = None
|
||||||
|
try:
|
||||||
|
install_output = subprocess.run(
|
||||||
|
(
|
||||||
|
"/usr/bin/env",
|
||||||
|
"sudo",
|
||||||
|
"arch-nspawn",
|
||||||
|
chroot_user_path,
|
||||||
|
"/build/install_check.sh",
|
||||||
|
),
|
||||||
|
check=True,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
log_print(
|
||||||
|
f'ERROR: Failed to check PKGBUILD install (checking PKGBUILD) for "{pkg}"!',
|
||||||
|
other_state=other_state,
|
||||||
|
)
|
||||||
|
return "error"
|
||||||
|
|
||||||
|
if (
|
||||||
|
len(install_output.stdout.strip()) == 0
|
||||||
|
or install_output.stdout.strip() == "PKGBUILD_INSTALL_DOES_NOT_EXIST"
|
||||||
|
):
|
||||||
|
return "does_not_exist"
|
||||||
|
elif not os.path.exists(
|
||||||
|
os.path.join(pkgdir, install_output.stdout.strip())
|
||||||
|
):
|
||||||
|
log_print(
|
||||||
|
f'ERROR: PKGBUILD install file specified but doesn\'t exist for "{pkg}"!',
|
||||||
|
other_state=other_state,
|
||||||
|
)
|
||||||
|
return "error"
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.run(
|
||||||
|
("/usr/bin/env", editor, install_output.stdout.strip()),
|
||||||
|
check=True,
|
||||||
|
cwd=pkgdir,
|
||||||
|
)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
log_print(
|
||||||
|
'ERROR: Failed checking install file for "{}"'.format(pkg),
|
||||||
|
other_state=other_state,
|
||||||
|
)
|
||||||
|
return "error"
|
||||||
|
return "ok"
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_user_chroot(other_state: [str, Any]):
|
||||||
|
try:
|
||||||
|
log_print(
|
||||||
|
'Running "makechrootpkg ... --nobuild" with dummy package to ensure user chroot is ready...',
|
||||||
|
other_state=other_state,
|
||||||
|
)
|
||||||
|
# Ensure ccache isn't enabled for this check.
|
||||||
|
if other_state["tmpfs"]:
|
||||||
|
cleanup_ccache(other_state["tmpfs_chroot"])
|
||||||
|
else:
|
||||||
|
cleanup_ccache(other_state["chroot"])
|
||||||
|
command_list = [
|
||||||
|
"/usr/bin/env",
|
||||||
|
"makechrootpkg",
|
||||||
|
"-c",
|
||||||
|
"-r",
|
||||||
|
(
|
||||||
|
other_state["tmpfs_chroot"]
|
||||||
|
if other_state["tmpfs"]
|
||||||
|
else other_state["chroot"]
|
||||||
|
),
|
||||||
|
]
|
||||||
|
post_command_list = ["--", "-s", "-r", "-c", "--nobuild"]
|
||||||
|
|
||||||
|
dummy_package_dir = os.path.join(
|
||||||
|
os.environ["HOME"], ".local", "share", "dummy_pkg_TEMPORARY_DIR"
|
||||||
|
)
|
||||||
|
Path(dummy_package_dir).mkdir(mode=0o700, parents=True, exist_ok=True)
|
||||||
|
dummy_package_pkgbuild = os.path.join(dummy_package_dir, "PKGBUILD")
|
||||||
|
Path(dummy_package_pkgbuild).write_text(DUMMY_PKGBUILD)
|
||||||
|
|
||||||
|
subprocess.run(
|
||||||
|
command_list + post_command_list,
|
||||||
|
check=True,
|
||||||
|
cwd=dummy_package_dir,
|
||||||
|
)
|
||||||
|
|
||||||
|
shutil.rmtree(dummy_package_dir)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""The main function."""
|
"""The main function."""
|
||||||
signal.signal(signal.SIGINT, signal_handler)
|
signal.signal(signal.SIGINT, signal_handler)
|
||||||
|
@ -2290,6 +2480,10 @@ def main():
|
||||||
pkg_state[pkg_list[i]]["state"] = "install"
|
pkg_state[pkg_list[i]]["state"] = "install"
|
||||||
pkg_state[pkg_list[i]]["build_status"] = "will_build"
|
pkg_state[pkg_list[i]]["build_status"] = "will_build"
|
||||||
i += 1
|
i += 1
|
||||||
|
log_print(
|
||||||
|
'WARNING: force_build will skip "install" script check!',
|
||||||
|
other_state=other_state,
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
elif check_pkg_build_result == "invalid":
|
elif check_pkg_build_result == "invalid":
|
||||||
continue
|
continue
|
||||||
|
@ -2300,6 +2494,71 @@ def main():
|
||||||
else: # check_pkg_build_result == "abort":
|
else: # check_pkg_build_result == "abort":
|
||||||
print_state_info_and_get_update_list(other_state, pkg_state)
|
print_state_info_and_get_update_list(other_state, pkg_state)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
install_check = check_install_script(
|
||||||
|
pkg_state, other_state, pkg_list[i], editor
|
||||||
|
)
|
||||||
|
if install_check == "does_not_exist":
|
||||||
|
pass
|
||||||
|
elif install_check == "error":
|
||||||
|
log_print(
|
||||||
|
"WARNING: Failed to check PKGBUILD install script!",
|
||||||
|
other_state=other_state,
|
||||||
|
)
|
||||||
|
pkg_state[pkg_list[i]]["state"] = "error"
|
||||||
|
pkg_state[pkg_list[i]]["build_status"] = "not_building"
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
elif install_check == "ok":
|
||||||
|
continue_on_loop_exit = False
|
||||||
|
while True:
|
||||||
|
log_print(
|
||||||
|
"install script ok? [Y/n/a(bort)/f(orce build)/b(ack)]",
|
||||||
|
other_state=other_state,
|
||||||
|
)
|
||||||
|
user_input = (
|
||||||
|
sys.stdin.buffer.readline().decode().strip().lower()
|
||||||
|
)
|
||||||
|
if user_input == "y" or len(user_input) == 0:
|
||||||
|
log_print(
|
||||||
|
"User decided install script is ok.",
|
||||||
|
other_state=other_state,
|
||||||
|
)
|
||||||
|
break
|
||||||
|
elif user_input == "n":
|
||||||
|
log_print(
|
||||||
|
"User decided install script is NOT ok.",
|
||||||
|
other_state=other_state,
|
||||||
|
)
|
||||||
|
pkg_state[pkg_list[i]]["state"] = "skip"
|
||||||
|
pkg_state[pkg_list[i]]["build_status"] = "not_building"
|
||||||
|
i += 1
|
||||||
|
continue_on_loop_exit = True
|
||||||
|
break
|
||||||
|
elif user_input == "a":
|
||||||
|
print_state_info_and_get_update_list(other_state, pkg_state)
|
||||||
|
sys.exit(1)
|
||||||
|
elif user_input == "f":
|
||||||
|
pkg_state[pkg_list[i]]["state"] = "install"
|
||||||
|
pkg_state[pkg_list[i]]["build_status"] = "will_build"
|
||||||
|
i += 1
|
||||||
|
continue_on_loop_exit = True
|
||||||
|
break
|
||||||
|
elif user_input == "b":
|
||||||
|
if i > 0:
|
||||||
|
i -= 1
|
||||||
|
continue_on_loop_exit = True
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
if continue_on_loop_exit:
|
||||||
|
continue
|
||||||
|
else: # Should be unreachable.
|
||||||
|
log_print(
|
||||||
|
"WARNING: Check PKGBUILD install script: unreachable code!",
|
||||||
|
other_state=other_state,
|
||||||
|
)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
if (
|
if (
|
||||||
skip_on_same_ver
|
skip_on_same_ver
|
||||||
|
|
Loading…
Reference in a new issue