@@ -297,6 +297,7 @@ class Steps(StrEnum):
297297 TESTS = "tests"
298298 CUSTOM = "custom"
299299 SOURCE_RPM = "source-rpm"
300+ FIND_SRPM = "find-srpm"
300301 RPM = "rpm"
301302 DEBS = "debs"
302303 PACKAGES = "packages"
@@ -330,6 +331,7 @@ def __init__(self, cli):
330331 self .cli = cli
331332 self ._engine = None
332333 self .distro_cache_name = ""
334+ self .current_srpm = None
333335
334336 @property
335337 def container_engine (self ):
@@ -456,7 +458,7 @@ def wants(self, step, ctx, *, force=False, top=False):
456458 if ctx .cli .no_prereqs and not top :
457459 log .info ("Running prerequisite steps disabled" )
458460 return
459- if step in self ._did_steps :
461+ if step in self ._did_steps and not force :
460462 log .info ("step already done: %s" , step )
461463 return
462464 if not self ._did_steps :
@@ -720,11 +722,59 @@ def _glob_search(ctx, pattern):
720722 return result
721723
722724
723- @Builder .set (Steps .RPM )
724- def bc_build_rpm (ctx ):
725- """Build RPMs from SRPM."""
726- srpm_glob = "ceph*.src.rpm"
727- if ctx .cli .rpm_match_sha :
725+ def _find_srpm_glob (ctx , pattern ):
726+ paths = _glob_search (ctx , pattern )
727+ if len (paths ) > 1 :
728+ raise RuntimeError (
729+ "too many matching source rpms"
730+ f" (rename or remove unwanted files matching { pattern } in the"
731+ " ceph dir and try again)"
732+ )
733+ if not paths :
734+ log .info ("No SRPM found for pattern: %s" , pattern )
735+ return None
736+ return paths [0 ]
737+
738+
739+ def _find_srpm_by_rpm_query (ctx ):
740+ log .info ("Querying spec file for rpm versions" ) # XXX: DEBUG
741+ rpmquery_args = [
742+ "rpm" , "--qf" , "%{version}-%{release}\n " , "--specfile" , "ceph.spec"
743+ ]
744+ rpmquery_cmd = ' ' .join (shlex .quote (cmd ) for cmd in rpmquery_args )
745+ cmd = _container_cmd (
746+ ctx ,
747+ [
748+ "bash" ,
749+ "-c" ,
750+ f"cd { ctx .cli .homedir } && { rpmquery_cmd } " ,
751+ ],
752+ )
753+ res = _run (cmd , check = False , capture_output = True )
754+ if res .returncode != 0 :
755+ log .warning ("Failed to list rpm versions" )
756+ return None
757+ versions = set (l .strip () for l in res .stdout .decode ().splitlines ())
758+ if len (versions ) > 1 :
759+ raise RuntimeError ("too many versions in rpm query" )
760+ version = list (versions )[0 ]
761+ filename = f'ceph-{ version } .src.rpm'
762+ # lazily reuse the glob match function to detect file presence even tho
763+ # it's not got any wildcard chars
764+ return _find_srpm_glob (ctx , filename )
765+
766+
767+ @Builder .set (Steps .FIND_SRPM )
768+ def bc_find_srpm (ctx ):
769+ """Find the current/matching Source RPM."""
770+ # side effects ctx setting current_srpm to a string when match is found.
771+ if ctx .cli .srpm_match == 'any' :
772+ ctx .current_srpm = _find_srpm_glob (ctx , "ceph*.src.rpm" )
773+ elif ctx .cli .srpm_match == 'versionglob' :
774+ # in theory we could probably drop this method now that
775+ # _find_srpm_by_rpm_query exists, but this is retained in case I missed
776+ # something and that this is noticeably faster since it doesn't need to
777+ # start a container
728778 if not ctx .cli .ceph_version :
729779 head_sha = _git_current_sha (ctx )
730780 srpm_glob = f"ceph*.g{ head_sha } .*.src.rpm"
@@ -740,22 +790,24 @@ def bc_build_rpm(ctx):
740790 ctx .cli .ceph_version
741791 )
742792 srpm_glob = f"ceph-{ srpm_version } .*.src.rpm"
743- paths = _glob_search (ctx , srpm_glob )
744- if len (paths ) > 1 :
745- raise RuntimeError (
746- "too many matching source rpms"
747- f" (rename or remove unwanted files matching { srpm_glob } in the"
748- " ceph dir and try again)"
749- )
750- if not paths :
793+ ctx .current_srpm = _find_srpm_glob (ctx , srpm_glob )
794+ else :
795+ ctx .current_srpm = _find_srpm_by_rpm_query (ctx )
796+ if ctx .current_srpm :
797+ log .info ("Found SRPM: %s" , ctx .current_srpm )
798+
799+
800+ @Builder .set (Steps .RPM )
801+ def bc_build_rpm (ctx ):
802+ """Build RPMs from SRPM."""
803+ ctx .build .wants (Steps .FIND_SRPM , ctx , force = True )
804+ if not ctx .current_srpm :
751805 # no matches. build a new srpm
752806 ctx .build .wants (Steps .SOURCE_RPM , ctx )
753- paths = _glob_search (ctx , srpm_glob )
754- if not paths :
755- raise RuntimeError (
756- f"unable to find source rpm(s) matching { srpm_glob } "
757- )
758- srpm_path = pathlib .Path (ctx .cli .homedir ) / paths [0 ]
807+ ctx .build .wants (Steps .FIND_SRPM , ctx , force = True )
808+ if not ctx .current_srpm :
809+ raise RuntimeError ("unable to find source rpm(s)" )
810+ srpm_path = pathlib .Path (ctx .cli .homedir ) / ctx .current_srpm
759811 topdir = pathlib .Path (ctx .cli .homedir ) / "rpmbuild"
760812 if ctx .cli .build_dir :
761813 topdir = (
@@ -991,11 +1043,25 @@ def parse_cli(build_step_names):
9911043 )
9921044 parser .add_argument (
9931045 "--rpm-no-match-sha" ,
994- dest = "rpm_match_sha" ,
995- action = "store_false" ,
1046+ dest = "srpm_match" ,
1047+ action = "store_const" ,
1048+ const = 'any' ,
9961049 help = (
9971050 "Do not try to build RPM packages that match the SHA of the current"
9981051 " git checkout. Use any source RPM available."
1052+ " [DEPRECATED] Use --rpm-match=any"
1053+ ),
1054+ )
1055+ parser .add_argument (
1056+ "--srpm-match" ,
1057+ dest = "srpm_match" ,
1058+ choices = ("any" , "versionglob" , "auto" ),
1059+ default = "auto" ,
1060+ help = (
1061+ "Method used to detect what Source RPM (SRPM) to build:"
1062+ " 'any' looks for any ceph source rpms."
1063+ " 'versionglob' uses a glob matching against version/git id."
1064+ " 'auto' (the default) uses a version derived from ceph.spec."
9991065 ),
10001066 )
10011067 parser .add_argument (
0 commit comments