buildpackage_rpm: support '--git-pq-branch', '--git-rpmbuild-builddir', '--git-rpmbui...
authorwanchao-xu <wanchao.xu@samsung.com>
Fri, 19 Apr 2024 05:31:56 +0000 (13:31 +0800)
committerwanchao-xu <wanchao.xu@samsung.com>
Fri, 19 Apr 2024 06:02:08 +0000 (14:02 +0800)
Change-Id: I0b835c0c9a3af2a9ba2e016984399c8cc91d7d01
Signed-off-by: wanchao-xu <wanchao.xu@samsung.com>
docs/manpages/gbp-buildpackage-rpm.xml
gbp/config.py
gbp/scripts/buildpackage_rpm.py

index 978cd8fd1222ee805e36a1952b36ea1013894f69..aaebe548417e4c861873675cfbe9bf1a7743eac9 100644 (file)
@@ -29,6 +29,7 @@
       <arg><option>--git-native</option>[auto|on|off]</arg>
       <arg><option>--git-upstream-branch=</option><replaceable>TREEISH</replaceable></arg>
       <arg><option>--git-packaging-branch=</option><replaceable>BRANCH_NAME</replaceable></arg>
+      <arg><option>--git-pq-branch=</option><replaceable>BRANCH_NAME</replaceable></arg>
       <arg><option>--git-ignore-branch</option></arg>
       <arg><option>--git-[no-]submodules</option></arg>
       <arg><option>--git-builder=</option><replaceable>BUILD_CMD</replaceable></arg>
       <arg><option>--git-tarball-dir=</option><replaceable>DIRECTORY</replaceable></arg>
       <arg><option>--git-compression-level=</option><replaceable>LEVEL</replaceable></arg>
       <arg><option>--git-export-dir=</option><replaceable>DIRECTORY</replaceable></arg>
+      <arg><option>--git-rpmbuild-builddir</option>=<replaceable>DIRECTORY</replaceable></arg>
+      <arg><option>--git-rpmbuild-buidrootdir</option>=<replaceable>DIRECTORY</replaceable></arg>
+      <arg><option>--git-rpmbuild-rpmdir</option>=<replaceable>DIRECTORY</replaceable></arg>
+      <arg><option>--git-rpmbuild-srpmdir</option>=<replaceable>DIRECTORY</replaceable></arg>
       <arg><option>--git-export=</option><replaceable>TREEISH</replaceable></arg>
       <arg><option>--git-packaging-dir=</option><replaceable>DIRECTORY</replaceable></arg>
       <arg><option>--git-spec-file=</option><replaceable>FILEPATH</replaceable></arg>
       <arg><option>--git-arch</option>=<replaceable>ARCHITECTURE</replaceable></arg>
       <arg><option>--git-mock-options</option>=<replaceable>OPTIONS</replaceable></arg>
       <arg><option>--git-mock-root</option>=<replaceable>ROOT</replaceable></arg>
+      <arg><option>--git-[no-]patch-export</option></arg>
+      <arg><option>--git-patch-export-rev=</option><replaceable>TREEISH</replaceable></arg>
+      <arg><option>--git-patch-export-compress=</option><replaceable>THRESHOLD</replaceable></arg>
+      <arg><option>--git-patch-export-ignore-path=</option><replaceable>REGEX</replaceable></arg>
+      <arg><option>--git-patch-export-squash-until=</option><replaceable>COMMITISH</replaceable></arg>
+      <arg><option>--git-[no-]patch-numbers</option></arg>
       <arg><option>--git-spec-vcs-tag</option>=<replaceable>TAG_FORMAT</replaceable></arg>
     </cmdsynopsis>
   </refsynopsisdiv>
           </para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><option>--git-pq-branch</option>=<replaceable>BRANCH_NAME</replaceable>
+        </term>
+        <listitem>
+          <para>
+          Name (format string) of the patch-queue/development branch. This
+          makes building easier when working with separate packaging and
+          development branches.
+          </para>
+          <para>
+          If <option>--git-patch-export</option> is enabled and
+          &gbp-buildpackage-rpm; detects that the current branch has a
+          patch-queue/development branch it exports the patches from there
+          instead of the tip of the current branch (unless
+          <option>--git-patch-export-rev</option> is defined, of course).
+          Similarly, if the current branch is a patch-queue/development branch
+          &gbp-buildpackage-rpm; will automatically enable patch-export and
+          export packaging files from the packaging branch instead of the
+          current branch (unless <option>--git-export</option>) is defined.
+          </para>
+        </listitem>
+      </varlistentry>
       <varlistentry>
         <term><option>--git-ignore-branch</option>
         </term>
           </para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><option>--git-rpmbuild-builddir</option>=<replaceable>DIRECTORY</replaceable>
+        </term>
+        <term><option>--git-rpmbuild-buildrootdir</option>=<replaceable>DIRECTORY</replaceable>
+        </term>
+        <term><option>--git-rpmbuild-rpmdir</option>=<replaceable>DIRECTORY</replaceable>
+        </term>
+        <term><option>--git-rpmbuild-srpmdir</option>=<replaceable>DIRECTORY</replaceable>
+        </term>
+        <listitem>
+          <para>
+          Build subdirectory options for rpmbuild builder.
+          </para>
+        </listitem>
+      </varlistentry>
       <varlistentry>
         <term><option>--git-export-sourcedir</option>=<replaceable>DIRECTORY</replaceable>
         </term>
           </para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><option>--git-[no-]patch-export</option>
+        </term>
+        <listitem>
+          <para>
+          Create patches from the commits between the upstream version and
+          export-treeish.  That is, after exporting packaging files (from the
+          pacakging directory) &gbp-buildpackage-rpm; creates one patch per
+          commit (similar to git-format-patch) and updates the spec file in the
+          export dir. You use <option>--git-patch-export-rev</option> to
+          specify the tip commit of the patch series.
+          </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--git-patch-export-rev=</option><replaceable>TREEISH</replaceable>
+        </term>
+        <listitem>
+          <para>
+          Use <replaceable>TREEISH</replaceable> as the tip commit of the patch
+          series instead of the default - i.e. treeish from which the packaging
+          files are exported (which is defined with
+          <option>--git-export</option>.
+          </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--git-patch-export-compress=</option><replaceable>THRESHOLD</replaceable>
+        </term>
+        <listitem>
+          <para>
+          Compress (auto-generated) patches larger than given
+          <replaceable>THRESHOLD</replaceable> bytes. Special value 0 disabled
+          patch compression.
+          </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--git-patch-export-ignore-path=</option><replaceable>REGEX</replaceable>
+        </term>
+        <listitem>
+          <para>
+          Exclude changes to path(s) matching <replaceable>REGEX</replaceable>
+          in patch generation.
+          </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--git-patch-export-squash-until=</option><replaceable>COMMITISH</replaceable>
+        </term>
+        <listitem>
+          <para>
+          Squash commits up to the given <replaceable>COMMITISH</replaceable>
+          into one monolitic diff. Could be used if one wants to squash commits
+          from an upstream release up to a stable update into a single diff
+          (commits on top of the stable would generate one patch per commit as
+          usual). The format is '&lt;commit_ish&gt;[:&lt;filename_base&gt;]',
+          i.e. commitish optionally followed by a colon and the desired
+          filename base for the diff (suffix '.diff' is automatically added by
+          &gbp-buildpackage-rpm;). Magic word 'HEAD' translates to the
+          patch-export-treeish when given as the squash-point. This allows one
+          to configure gbp to always squash all commits into one monolithic
+          diff.
+          </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--git-[no-]patch-numbers</option>
+        </term>
+        <listitem>
+          <para>
+          Whether the patch files should start with a number or not.
+          </para>
+        </listitem>
+      </varlistentry>
       <varlistentry>
         <term><option>--git-spec-vcs-tag</option>=<replaceable>TAG_FORMAT</replaceable>
         </term>
index 1b0d991ad64068d0bdcefc03ea570f9e7ca51fb0..23981712900857ddcbbb8b65218f086968463150 100644 (file)
@@ -816,6 +816,11 @@ class GbpOptionParserRpm(GbpOptionParser):
         'packaging-tag': '%(vendor)s/%(version)s',
         'pq-branch': 'development/%(branch)s',
         'import-files': ['.gbp.conf', 'debian/gbp.conf'],
+        'rpmbuild-builddir': 'BUILD',
+        'rpmbuild-rpmdir': 'RPMS',
+        'rpmbuild-srpmdir': 'SRPMS',
+        'rpmbuild-buildrootdir': 'BUILDROOT',
+        'patch-export': 'False',
         'patch-export-ignore-path': '',
         'patch-export-compress': '0',
         'patch-export-squash-until': '',
@@ -868,6 +873,9 @@ class GbpOptionParserRpm(GbpOptionParser):
             'spec-file':
                 "Spec file to use, causes the packaging-dir option to be "
                 "ignored, default is '%(spec-file)s'",
+            'patch-export':
+                "Create patches between upstream and export-treeish, default "
+                "is '%(patch-export)s'",
             'patch-export-compress':
                 "Compress (auto-generated) patches larger than given number of "
                 "bytes, 0 never compresses, default is "
index 30f27f67054b91654fa23fa211b9a3a102af61e1..4d9f9da031a37c5a5fcc62935f8b4c6d491b5734 100644 (file)
@@ -37,7 +37,8 @@ from gbp.tmpfile import init_tmpdir, del_tmpdir, tempfile
 from gbp.scripts.common import ExitCodes
 from gbp.scripts.common.buildpackage import (index_name, wc_name,
                                              dump_tree, write_wc, drop_index)
-from gbp.scripts.pq_rpm import parse_spec
+from gbp.scripts.pq_rpm import update_patch_series, parse_spec
+from gbp.scripts.common.pq import is_pq_branch, pq_branch_name, pq_branch_base
 
 
 class GbpAutoGenerateError(GbpError):
@@ -130,7 +131,7 @@ def get_upstream_tree(repo, version, options):
     """Determine the upstream tree from the given options"""
     if options.upstream_tree.upper() == 'TAG':
         tag_str_fields = {'upstreamversion': version,
-                          'version': version}
+                          'vendor': 'Upstream'}
         upstream_tree = repo.version_to_tag(options.upstream_tag,
                                             tag_str_fields)
     elif options.upstream_tree.upper() == 'BRANCH':
@@ -192,6 +193,45 @@ def get_vcs_info(repo, treeish):
     return info
 
 
+def guess_export_params(repo, options):
+    """Get commit and tree from where to export packaging and patches"""
+    tree = None
+    branch = None
+    if options.export in [wc_name, index_name, 'HEAD']:
+        branch = get_current_branch(repo)
+    elif options.export in repo.get_local_branches():
+        branch = options.export
+    if branch:
+        if is_pq_branch(branch, options):
+            packaging_branch = pq_branch_base(branch, options)
+            if repo.has_branch(packaging_branch):
+                gbp.log.info("It seems you're building a development/patch-"
+                             "queue branch. Export target changed to '%s' and "
+                             "patch-export enabled!" % packaging_branch)
+                options.patch_export = True
+                if not options.patch_export_rev:
+                    options.patch_export_rev = options.export
+                options.export = packaging_branch
+            else:
+                gbp.log.warn("It seems you're building a development/patch-"
+                             "queue branch. No corresponding packaging branch "
+                             "found. Build may fail!")
+        elif options.patch_export and not options.patch_export_rev:
+            tree = get_tree(repo, options.export)
+            spec = parse_spec(options, repo, treeish=tree)
+            pq_branch = pq_branch_name(branch, options, spec.version)
+            if repo.has_branch(pq_branch):
+                gbp.log.info("Exporting patches from development/patch-queue "
+                             "branch '%s'" % pq_branch)
+                options.patch_export_rev = pq_branch
+    if tree is None:
+        tree = get_tree(repo, options.export)
+        spec = parse_spec(options, repo, treeish=tree)
+
+    # Return tree-ish object and relative spec path for for exporting packaging
+    return tree, spec.specpath
+
+
 def git_archive_build_orig(repo, spec, output_dir, options):
     """
     Build orig tarball using git-archive
@@ -226,6 +266,17 @@ def git_archive_build_orig(repo, spec, output_dir, options):
     return upstream_tree
 
 
+def export_patches(repo, spec, export_treeish, options):
+    """
+    Generate patches and update spec file
+    """
+    try:
+        upstream_tree = get_upstream_tree(repo, spec.upstreamversion, options)
+        update_patch_series(repo, spec, upstream_tree, export_treeish, options)
+    except (GitRepositoryError, GbpError) as err:
+        raise GbpAutoGenerateError(str(err))
+
+
 def is_native(repo, options):
     """Determine whether a package is native or non-native"""
     if options.native.is_auto():
@@ -250,8 +301,16 @@ def setup_builder(options, builder_args):
             builder_args.append('-ba')
         builder_args.extend([
             '--define', "_topdir %s" % os.path.abspath(options.export_dir),
+            '--define', "_builddir %%_topdir/%s" % options.build_dir,
+            '--define', "_rpmdir %%_topdir/%s" % options.rpm_dir,
+            '--define', "_srcrpmdir %%_topdir/%s" % options.srpm_dir,
+            '--define', "_buildrootdir %%_topdir/%s" % options.buildroot_dir,
             '--define', "_specdir %%_topdir/%s" % options.export_specdir,
             '--define', "_sourcedir %%_topdir/%s" % options.export_sourcedir])
+    elif options.builder.startswith('osc'):
+        builder_args.insert(0, 'build')
+        options.source_dir = ''
+        options.spec_dir = ''
 
 
 def packaging_tag_data(repo, commit, name, version, options):
@@ -382,6 +441,7 @@ def build_parser(name, prefix=None, git_treeish=None):
                                         dest="upstream_branch")
     branch_group.add_config_file_option(option_name="packaging-branch",
                                         dest="packaging_branch")
+    branch_group.add_config_file_option(option_name="pq-branch", dest="pq_branch")
     branch_group.add_boolean_config_file_option(option_name="ignore-branch",
                                                 dest="ignore_branch")
     branch_group.add_boolean_config_file_option(option_name="submodules",
@@ -422,6 +482,26 @@ def build_parser(name, prefix=None, git_treeish=None):
                                         dest="export_dir", type="path",
                                         help="Build topdir, also export the sources under "
                                         "EXPORT_DIR, default is '%(export-dir)s'")
+    export_group.add_config_file_option(option_name="rpmbuild-builddir",
+                                        dest="build_dir", type="path",
+                                        help="subdir where package is built (under "
+                                        "EXPORT_DIR), i.e. rpmbuild builddir, default is "
+                                        "'%(rpmbuild-builddir)s'")
+    export_group.add_config_file_option(option_name="rpmbuild-rpmdir",
+                                        dest="rpm_dir", type="path",
+                                        help="subdir where ready binary packages are stored "
+                                        "(under EXPORT_DIR), i.e. rpmbuild builddir, default "
+                                        "is '%(rpmbuild-rpmdir)s'")
+    export_group.add_config_file_option(option_name="rpmbuild-srpmdir",
+                                        dest="srpm_dir", type="path",
+                                        help="subdir where ready sources package is stored "
+                                        "(under EXPORT_DIR), i.e. rpmbuild srpmdir, default "
+                                        "is '%(rpmbuild-srpmdir)s'")
+    export_group.add_config_file_option(option_name="rpmbuild-buildrootdir",
+                                        dest="buildroot_dir", type="path",
+                                        help="subdir for build-time alternative root (under "
+                                        "EXPORT_DIR), i.e. rpmbuild buildrootdir, default is "
+                                        "'%(rpmbuild-buildrootdir)s'")
     export_group.add_config_file_option(option_name="export-specdir",
                                         dest="export_specdir", type="path")
     export_group.add_config_file_option(option_name="export-sourcedir",
@@ -434,6 +514,17 @@ def build_parser(name, prefix=None, git_treeish=None):
                                         dest="packaging_dir")
     export_group.add_config_file_option(option_name="spec-file",
                                         dest="spec_file")
+    export_group.add_boolean_config_file_option("patch-export", dest="patch_export")
+    export_group.add_option("--git-patch-export-rev", dest="patch_export_rev",
+                            metavar="TREEISH",
+                            help="[experimental] Export patches from treeish object TREEISH")
+    export_group.add_config_file_option("patch-export-ignore-path",
+                                        dest="patch_export_ignore_path")
+    export_group.add_config_file_option("patch-export-compress", dest="patch_export_compress")
+    export_group.add_config_file_option("patch-export-squash-until",
+                                        dest="patch_export_squash_until")
+    export_group.add_boolean_config_file_option(option_name="patch-numbers",
+                                                dest="patch_numbers")
     export_group.add_config_file_option("spec-vcs-tag", dest="spec_vcs_tag")
     return parser
 
@@ -496,9 +587,7 @@ def main(argv):
 
     try:
         init_tmpdir(options.tmp_dir, prefix='buildpackage-rpm_')
-
-        tree = get_tree(repo, options.export)
-        spec = parse_spec(options, repo, treeish=tree)
+        tree, relative_spec_path = guess_export_params(repo, options)
 
         Command(options.cleaner, shell=True)()
         if not options.ignore_new:
@@ -516,13 +605,12 @@ def main(argv):
                                "--git-packaging-branch to set the branch name.")
 
         # Dump from git to a temporary directory:
-        packaging_tree = '%s:%s' % (tree, options.packaging_dir)
-        dump_dir = tempfile.mkdtemp(prefix='packaging_')
-        gbp.log.debug("Dumping packaging files to '%s'" % dump_dir)
-        if not dump_tree(repo, dump_dir, packaging_tree, False, False):
+        dump_dir = tempfile.mkdtemp(prefix='dump_tree_')
+        gbp.log.debug("Dumping tree '%s' to '%s'" % (options.export, dump_dir))
+        if not dump_tree(repo, dump_dir, tree, options.with_submodules):
             raise GbpError
-        # Re-parse spec from dump dir to get version etc.
-        spec = rpm.SpecFile(os.path.join(dump_dir, spec.specfile))
+        # Parse spec from dump dir to get version etc.
+        spec = rpm.SpecFile(os.path.join(dump_dir, relative_spec_path))
 
         if not options.tag_only:
             # Setup builder opts
@@ -530,6 +618,14 @@ def main(argv):
             if options.use_mock:
                 setup_mock(options)
 
+            # Generate patches, if requested
+            if options.patch_export and not is_native(repo, options):
+                if options.patch_export_rev:
+                    patch_tree = get_tree(repo, options.patch_export_rev)
+                else:
+                    patch_tree = tree
+                export_patches(repo, spec, patch_tree, options)
+
             # Prepare final export dirs
             export_dir = makedir(options.export_dir)
             source_dir = makedir(os.path.join(export_dir,
@@ -555,7 +651,7 @@ def main(argv):
                 try:
                     shutil.copy2(src, dst)
                 except IOError as err:
-                    raise GbpError("Error exporting packaging files: %s" % err)
+                    raise GbpError("Error exporting files: %s" % err)
             spec.specdir = os.path.abspath(spec_dir)
 
             # Get/build the orig tarball