@@ -304,6 +304,7 @@ class Steps(StrEnum):
304304 TESTS = "tests"
305305 CUSTOM = "custom"
306306 SOURCE_RPM = "source-rpm"
307+ FIND_SRPM = "find-srpm"
307308 RPM = "rpm"
308309 DEBS = "debs"
309310 PACKAGES = "packages"
@@ -337,6 +338,7 @@ def __init__(self, cli):
337338 self .cli = cli
338339 self ._engine = None
339340 self .distro_cache_name = ""
341+ self .current_srpm = None
340342
341343 @property
342344 def container_engine (self ):
@@ -471,7 +473,7 @@ def wants(self, step, ctx, *, force=False, top=False):
471473 if ctx .cli .no_prereqs and not top :
472474 log .info ("Running prerequisite steps disabled" )
473475 return
474- if step in self ._did_steps :
476+ if step in self ._did_steps and not force :
475477 log .info ("step already done: %s" , step )
476478 return
477479 if not self ._did_steps :
@@ -747,11 +749,59 @@ def _glob_search(ctx, pattern):
747749 return result
748750
749751
750- @Builder .set (Steps .RPM )
751- def bc_build_rpm (ctx ):
752- """Build RPMs from SRPM."""
753- srpm_glob = "ceph*.src.rpm"
754- if ctx .cli .rpm_match_sha :
752+ def _find_srpm_glob (ctx , pattern ):
753+ paths = _glob_search (ctx , pattern )
754+ if len (paths ) > 1 :
755+ raise RuntimeError (
756+ "too many matching source rpms"
757+ f" (rename or remove unwanted files matching { pattern } in the"
758+ " ceph dir and try again)"
759+ )
760+ if not paths :
761+ log .info ("No SRPM found for pattern: %s" , pattern )
762+ return None
763+ return paths [0 ]
764+
765+
766+ def _find_srpm_by_rpm_query (ctx ):
767+ log .info ("Querying spec file for rpm versions" ) # XXX: DEBUG
768+ rpmquery_args = [
769+ "rpm" , "--qf" , "%{version}-%{release}\n " , "--specfile" , "ceph.spec"
770+ ]
771+ rpmquery_cmd = ' ' .join (shlex .quote (cmd ) for cmd in rpmquery_args )
772+ cmd = _container_cmd (
773+ ctx ,
774+ [
775+ "bash" ,
776+ "-c" ,
777+ f"cd { ctx .cli .homedir } && { rpmquery_cmd } " ,
778+ ],
779+ )
780+ res = _run (cmd , check = False , capture_output = True )
781+ if res .returncode != 0 :
782+ log .warning ("Failed to list rpm versions" )
783+ return None
784+ versions = set (l .strip () for l in res .stdout .decode ().splitlines ())
785+ if len (versions ) > 1 :
786+ raise RuntimeError ("too many versions in rpm query" )
787+ version = list (versions )[0 ]
788+ filename = f'ceph-{ version } .src.rpm'
789+ # lazily reuse the glob match function to detect file presence even tho
790+ # it's not got any wildcard chars
791+ return _find_srpm_glob (ctx , filename )
792+
793+
794+ @Builder .set (Steps .FIND_SRPM )
795+ def bc_find_srpm (ctx ):
796+ """Find the current/matching Source RPM."""
797+ # side effects ctx setting current_srpm to a string when match is found.
798+ if ctx .cli .srpm_match == 'any' :
799+ ctx .current_srpm = _find_srpm_glob (ctx , "ceph*.src.rpm" )
800+ elif ctx .cli .srpm_match == 'versionglob' :
801+ # in theory we could probably drop this method now that
802+ # _find_srpm_by_rpm_query exists, but this is retained in case I missed
803+ # something and that this is noticeably faster since it doesn't need to
804+ # start a container
755805 if not ctx .cli .ceph_version :
756806 head_sha = _git_current_sha (ctx )
757807 srpm_glob = f"ceph*.g{ head_sha } .*.src.rpm"
@@ -767,22 +817,24 @@ def bc_build_rpm(ctx):
767817 ctx .cli .ceph_version
768818 )
769819 srpm_glob = f"ceph-{ srpm_version } .*.src.rpm"
770- paths = _glob_search (ctx , srpm_glob )
771- if len (paths ) > 1 :
772- raise RuntimeError (
773- "too many matching source rpms"
774- f" (rename or remove unwanted files matching { srpm_glob } in the"
775- " ceph dir and try again)"
776- )
777- if not paths :
820+ ctx .current_srpm = _find_srpm_glob (ctx , srpm_glob )
821+ else :
822+ ctx .current_srpm = _find_srpm_by_rpm_query (ctx )
823+ if ctx .current_srpm :
824+ log .info ("Found SRPM: %s" , ctx .current_srpm )
825+
826+
827+ @Builder .set (Steps .RPM )
828+ def bc_build_rpm (ctx ):
829+ """Build RPMs from SRPM."""
830+ ctx .build .wants (Steps .FIND_SRPM , ctx , force = True )
831+ if not ctx .current_srpm :
778832 # no matches. build a new srpm
779833 ctx .build .wants (Steps .SOURCE_RPM , ctx )
780- paths = _glob_search (ctx , srpm_glob )
781- if not paths :
782- raise RuntimeError (
783- f"unable to find source rpm(s) matching { srpm_glob } "
784- )
785- srpm_path = pathlib .Path (ctx .cli .homedir ) / paths [0 ]
834+ ctx .build .wants (Steps .FIND_SRPM , ctx , force = True )
835+ if not ctx .current_srpm :
836+ raise RuntimeError ("unable to find source rpm(s)" )
837+ srpm_path = pathlib .Path (ctx .cli .homedir ) / ctx .current_srpm
786838 topdir = pathlib .Path (ctx .cli .homedir ) / "rpmbuild"
787839 if ctx .cli .build_dir :
788840 topdir = (
@@ -1022,11 +1074,25 @@ def parse_cli(build_step_names):
10221074 )
10231075 parser .add_argument (
10241076 "--rpm-no-match-sha" ,
1025- dest = "rpm_match_sha" ,
1026- action = "store_false" ,
1077+ dest = "srpm_match" ,
1078+ action = "store_const" ,
1079+ const = 'any' ,
10271080 help = (
10281081 "Do not try to build RPM packages that match the SHA of the current"
10291082 " git checkout. Use any source RPM available."
1083+ " [DEPRECATED] Use --rpm-match=any"
1084+ ),
1085+ )
1086+ parser .add_argument (
1087+ "--srpm-match" ,
1088+ dest = "srpm_match" ,
1089+ choices = ("any" , "versionglob" , "auto" ),
1090+ default = "auto" ,
1091+ help = (
1092+ "Method used to detect what Source RPM (SRPM) to build:"
1093+ " 'any' looks for any ceph source rpms."
1094+ " 'versionglob' uses a glob matching against version/git id."
1095+ " 'auto' (the default) uses a version derived from ceph.spec."
10301096 ),
10311097 )
10321098 parser .add_argument (
0 commit comments