Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 44 additions & 2 deletions csmock/csmock
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import shutil
import subprocess
import sys
import time
from typing import Optional, Tuple

# local imports
import csmock.common.util
Expand Down Expand Up @@ -203,6 +204,8 @@ class MockWrapper:
self.results = results
self.mock_profile = props.mock_profile
self.mock_root_override = props.mock_root_override
self.hermetic_build = props.hermetic_build
self.srpm = props.srpm
self.pid = os.getpid()
self.scrub_done = props.skip_mock_init
self.init_done = props.skip_mock_init
Expand Down Expand Up @@ -282,6 +285,17 @@ echo \"$self_pid\" > \"$lock_file\"'" \
"--disable-plugin=yum_cache"]
self.def_cmd += [f"--config-opts=root={self.mock_root_override}"]

if self.hermetic_build is not None:
(lockfile, repo_dir) = self.hermetic_build

hermetic_cmd = [mock, "--hermetic-build", lockfile, repo_dir, "--short-circuit=prep", "-N", self.srpm]
ec = self.results.exec_cmd(hermetic_cmd)
if ec != 0:
self.results.error("failed to set up hermetic chroot", ec=ec)

# provide the offline repo for subsequent mock commands
self.def_cmd += [f"--config-opts=offline_local_repository={repo_dir}"]

return self

def __exit__(self, exc_type, exc_val, exc_tb):
Expand Down Expand Up @@ -403,7 +417,8 @@ echo \"$self_pid\" > \"$lock_file\"'" \
self.init_done = True

# run `mock --calculate-build-dependencies`
srpm_deps_ok = srpm is None or self.install_deps(srpm)
# skip for hermetic builds (deps should be calculated prior)
srpm_deps_ok = srpm is None or self.hermetic_build is not None or self.install_deps(srpm)
if not srpm_deps_ok and not try_only:
srpm_base = os.path.basename(srpm)
self.results.error(f"failed to install build dependencies of {srpm_base}", ec=ec_by_scrub)
Expand All @@ -422,6 +437,13 @@ echo \"$self_pid\" > \"$lock_file\"'" \
if not missing_deps:
# no misssing dependencies
return srpm_deps_ok

if self.hermetic_build and missing_deps:
self.results.print_with_ts(
f"WARN: Proceeding with hermetic build despite missing deps: {strlist_to_shell_cmd(missing_deps)}"
)
return srpm_deps_ok

if try_only:
return False

Expand Down Expand Up @@ -476,7 +498,7 @@ class ScanProps:
self.shell_cmd_to_build = None
self.srpm = None
self.base_srpm = None
self.mock_profile = None
self.mock_profile: Optional[str] = None
self.base_mock_profile = None
self.mock_root_override = None
self.any_tool = False
Expand All @@ -486,6 +508,7 @@ class ScanProps:
self.imp_csgrep_filters = []
self.cswrap_path = None
self.kfp_git_url = None
self.hermetic_build: Optional[Tuple] = None

def enable_cswrap(self):
if self.cswrap_enabled:
Expand Down Expand Up @@ -862,6 +885,14 @@ exceeds the specified limit (defaults to 1024).")
help='override the build root directory for mock (disables yum and root cache)'
)

parser.add_argument(
"--hermetic-build",
nargs=2,
metavar=("LOCKFILE", "REPO_DIRECTORY"),
help="perform a hermetic (fully offline) build using a pre-generated "
"lockfile and offline RPM repository (see mock --hermetic-build)",
)

# --skip-patches, --diff-patches, and --shell-cmd are mutually exclusive
group = parser.add_mutually_exclusive_group()
group.add_argument(
Expand Down Expand Up @@ -996,6 +1027,17 @@ exceeds the specified limit (defaults to 1024).")

props.mock_root_override = args.mock_root_override

if args.hermetic_build is not None:
(lockfile, repo_dir) = args.hermetic_build
require_file(parser, lockfile)
if not os.path.isdir(repo_dir):
parser.error(f"not a directory: {repo_dir}")
if not os.path.isdir(os.path.join(repo_dir, "repodata")):
parser.error(f"repo directory missing repodata/: {repo_dir}")
props.hermetic_build = (os.path.realpath(lockfile), os.path.realpath(repo_dir))
props.mock_profile = "hermetic-build"
props.skip_mock_init = True

# append the list of packages to install specified on command-line
for pkg in args.install:
props.install_pkgs += pkg.split()
Expand Down