@@ -30,6 +30,7 @@ import shutil
3030import subprocess
3131import sys
3232import time
33+ from typing import Optional , Tuple
3334
3435# local imports
3536import csmock .common .util
@@ -203,6 +204,8 @@ class MockWrapper:
203204 self .results = results
204205 self .mock_profile = props .mock_profile
205206 self .mock_root_override = props .mock_root_override
207+ self .hermetic_build = props .hermetic_build
208+ self .srpm = props .srpm
206209 self .pid = os .getpid ()
207210 self .scrub_done = props .skip_mock_init
208211 self .init_done = props .skip_mock_init
@@ -282,6 +285,17 @@ echo \"$self_pid\" > \"$lock_file\"'" \
282285 "--disable-plugin=yum_cache" ]
283286 self .def_cmd += [f"--config-opts=root={ self .mock_root_override } " ]
284287
288+ if self .hermetic_build is not None :
289+ (lockfile , repo_dir ) = self .hermetic_build
290+
291+ hermetic_cmd = [mock , "--hermetic-build" , lockfile , repo_dir , "--short-circuit=prep" , "-N" , self .srpm ]
292+ ec = self .results .exec_cmd (hermetic_cmd )
293+ if ec != 0 :
294+ self .results .error ("failed to set up hermetic chroot" , ec = ec )
295+
296+ # provide the offline repo for subsequent mock commands
297+ self .def_cmd += [f"--config-opts=offline_local_repository={ repo_dir } " ]
298+
285299 return self
286300
287301 def __exit__ (self , exc_type , exc_val , exc_tb ):
@@ -403,7 +417,8 @@ echo \"$self_pid\" > \"$lock_file\"'" \
403417 self .init_done = True
404418
405419 # run `mock --calculate-build-dependencies`
406- srpm_deps_ok = srpm is None or self .install_deps (srpm )
420+ # skip for hermetic builds (deps should be calculated prior)
421+ srpm_deps_ok = srpm is None or self .hermetic_build is not None or self .install_deps (srpm )
407422 if not srpm_deps_ok and not try_only :
408423 srpm_base = os .path .basename (srpm )
409424 self .results .error (f"failed to install build dependencies of { srpm_base } " , ec = ec_by_scrub )
@@ -422,6 +437,13 @@ echo \"$self_pid\" > \"$lock_file\"'" \
422437 if not missing_deps :
423438 # no misssing dependencies
424439 return srpm_deps_ok
440+
441+ if self .hermetic_build and missing_deps :
442+ self .results .print_with_ts (
443+ f"WARN: Proceeding with hermetic build despite missing deps: { strlist_to_shell_cmd (missing_deps )} "
444+ )
445+ return srpm_deps_ok
446+
425447 if try_only :
426448 return False
427449
@@ -476,7 +498,7 @@ class ScanProps:
476498 self .shell_cmd_to_build = None
477499 self .srpm = None
478500 self .base_srpm = None
479- self .mock_profile = None
501+ self .mock_profile : Optional [ str ] = None
480502 self .base_mock_profile = None
481503 self .mock_root_override = None
482504 self .any_tool = False
@@ -486,6 +508,7 @@ class ScanProps:
486508 self .imp_csgrep_filters = []
487509 self .cswrap_path = None
488510 self .kfp_git_url = None
511+ self .hermetic_build : Optional [Tuple ] = None
489512
490513 def enable_cswrap (self ):
491514 if self .cswrap_enabled :
@@ -862,6 +885,14 @@ exceeds the specified limit (defaults to 1024).")
862885 help = 'override the build root directory for mock (disables yum and root cache)'
863886 )
864887
888+ parser .add_argument (
889+ "--hermetic-build" ,
890+ nargs = 2 ,
891+ metavar = ("LOCKFILE" , "REPO_DIRECTORY" ),
892+ help = "perform a hermetic (fully offline) build using a pre-generated "
893+ "lockfile and offline RPM repository (see mock --hermetic-build)" ,
894+ )
895+
865896 # --skip-patches, --diff-patches, and --shell-cmd are mutually exclusive
866897 group = parser .add_mutually_exclusive_group ()
867898 group .add_argument (
@@ -996,6 +1027,17 @@ exceeds the specified limit (defaults to 1024).")
9961027
9971028 props .mock_root_override = args .mock_root_override
9981029
1030+ if args .hermetic_build is not None :
1031+ (lockfile , repo_dir ) = args .hermetic_build
1032+ require_file (parser , lockfile )
1033+ if not os .path .isdir (repo_dir ):
1034+ parser .error (f"not a directory: { repo_dir } " )
1035+ if not os .path .isdir (os .path .join (repo_dir , "repodata" )):
1036+ parser .error (f"repo directory missing repodata/: { repo_dir } " )
1037+ props .hermetic_build = (os .path .realpath (lockfile ), os .path .realpath (repo_dir ))
1038+ props .mock_profile = "hermetic-build"
1039+ props .skip_mock_init = True
1040+
9991041 # append the list of packages to install specified on command-line
10001042 for pkg in args .install :
10011043 props .install_pkgs += pkg .split ()
0 commit comments