diff options
author | Guido Günther <agx@sigxcpu.org> | 2015-07-01 21:44:27 +0200 |
---|---|---|
committer | Guido Günther <agx@sigxcpu.org> | 2015-08-19 17:32:59 +0200 |
commit | 422ae854873adf2f5309ee79996cd96dcbabfaca (patch) | |
tree | 066bd59e546c4cb8d07a9e30aa85a22fed12212d | |
parent | 7ce69de2d7faacce58c1d01168a29d77aee6b5c5 (diff) |
Add gbp buildpackage-rpm
This adds a minimal gbp buildpackage-rpm based on Markus Lehtonens work.
-rw-r--r-- | debian/git-buildpackage-rpm.install | 1 | ||||
-rw-r--r-- | docs/Makefile | 1 | ||||
-rw-r--r-- | docs/common.ent | 12 | ||||
-rw-r--r-- | docs/man.gbp-buildpackage-rpm.sgml | 12 | ||||
-rw-r--r-- | docs/manpages/gbp-buildpackage-rpm.sgml | 544 | ||||
-rw-r--r-- | docs/manpages/manpages.ent | 1 | ||||
-rw-r--r-- | gbp/config.py | 20 | ||||
-rw-r--r-- | gbp/scripts/buildpackage_rpm.py | 631 | ||||
-rw-r--r-- | gbp/tmpfile.py | 4 | ||||
-rw-r--r-- | packaging/git-buildpackage.spec | 1 | ||||
m--------- | tests/component/rpm/data | 0 | ||||
-rw-r--r-- | tests/component/rpm/test_buildpackage_rpm.py | 138 |
12 files changed, 1361 insertions, 4 deletions
diff --git a/debian/git-buildpackage-rpm.install b/debian/git-buildpackage-rpm.install index 2568b4c9..5178cb37 100644 --- a/debian/git-buildpackage-rpm.install +++ b/debian/git-buildpackage-rpm.install @@ -1,3 +1,4 @@ usr/lib/python2.?/dist-packages/gbp/rpm/ usr/lib/python2.7/dist-packages/gbp/scripts/import_srpm.py usr/lib/python2.7/dist-packages/gbp/scripts/pq_rpm.py +usr/lib/python2.7/dist-packages/gbp/scripts/buildpackage_rpm.py diff --git a/docs/Makefile b/docs/Makefile index 91c3b0ad..055028bd 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -12,6 +12,7 @@ MAN1S = \ gbp-import-orig \ gbp-pq \ gbp-pull \ + gbp-buildpackage-rpm \ $(NULL) MAN5S = gbp.conf diff --git a/docs/common.ent b/docs/common.ent index 005d6746..51752d90 100644 --- a/docs/common.ent +++ b/docs/common.ent @@ -4,6 +4,7 @@ <!ENTITY dhconfsection "<manvolnum>5</manvolnum>"> <!ENTITY dhemail "<email>agx@sigxcpu.org</email>"> <!ENTITY dhusername "Guido Guenther"> + <!ENTITY gbp-buildpackage "<command>gbp buildpackage</command>"> <!ENTITY gbp-import-orig "<command>gbp import-orig</command>"> <!ENTITY gbp-import-dsc "<command>gbp import-dsc</command>"> @@ -24,6 +25,17 @@ <!ENTITY debuildcmd "<command>debuild</command>"> <!ENTITY gbp.conf "<filename>gbp.conf</filename>"> + <!ENTITY rpm-firstname "<firstname>Markus</firstname>"> + <!ENTITY rpm-surname "<surname>Lehtonen</surname>"> + <!ENTITY rpm-email "<email>markus.lehtonen@linux.intel.com</email>"> + <!ENTITY rpm-username "Markus Lehtonen"> + <!ENTITY rpm-mansection "<manvolnum>1</manvolnum>"> + <!ENTITY gbp-buildpackage-rpm "<command>gbp buildpackage-rpm</command>"> + <!ENTITY gbp-import-srpm "<command>gbp import-srpm</command>"> + <!ENTITY gbp-pq-rpm "<command>gbp pq-rpm</command>"> + <!ENTITY rpmbuild "<command>rpmbuild</command>"> + <!ENTITY wget "<command>wget</command>"> + <!ENTITY debian "<productname>Debian</productname>"> <!ENTITY git "<productname>Git</productname>"> <!ENTITY dch "<productname>dch</productname>"> diff --git a/docs/man.gbp-buildpackage-rpm.sgml b/docs/man.gbp-buildpackage-rpm.sgml new file mode 100644 index 00000000..8e7bac73 --- /dev/null +++ b/docs/man.gbp-buildpackage-rpm.sgml @@ -0,0 +1,12 @@ +<!DOCTYPE reference PUBLIC "-//OASIS//DTD DocBook V4.1//EN" +[ + <!ENTITY % COMMON SYSTEM "common.ent"> + %COMMON; + <!ENTITY % MANPAGES SYSTEM "manpages/manpages.ent"> + %MANPAGES; +]> + +<reference> +<title>git-buildpackage Manual</title> +&man.gbp.buildpackage.rpm; +</reference> diff --git a/docs/manpages/gbp-buildpackage-rpm.sgml b/docs/manpages/gbp-buildpackage-rpm.sgml new file mode 100644 index 00000000..4b75113f --- /dev/null +++ b/docs/manpages/gbp-buildpackage-rpm.sgml @@ -0,0 +1,544 @@ +<refentry id="man.gbp.buildpackage.rpm"> + <refentryinfo> + <address> + &rpm-email; + </address> + <author> + &rpm-firstname; + &rpm-surname; + </author> + </refentryinfo> + <refmeta><refentrytitle>gbp-buildpackage-rpm</refentrytitle> + &dhsection; + </refmeta> + <refnamediv> + <refname>gbp-buildpackage-rpm</refname> + <refpurpose>Build RPM packages from a Git repository</refpurpose> + </refnamediv> + <refsynopsisdiv> + <cmdsynopsis> + &gbp-buildpackage-rpm; + <arg><option>--git-[no-]ignore-new</option></arg> + <arg><option>--git-tag</option></arg> + <arg><option>--git-verbose</option></arg> + <arg><option>--git-color=</option><replaceable>[auto|on|off]</replaceable></arg> + <arg><option>--git-color-scheme=</option><replaceable>COLOR_SCHEME</replaceable></arg> + <arg><option>--git-notify=</option><replaceable>[auto|on|off]</replaceable></arg> + <arg><option>--git-tmp-dir</option>=<replaceable>DIRECTORY</replaceable></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-ignore-branch</option></arg> + <arg><option>--git-[no-]submodules</option></arg> + <arg><option>--git-builder=</option><replaceable>BUILD_CMD</replaceable></arg> + <arg><option>--git-cleaner=</option><replaceable>CLEAN_CMD</replaceable></arg> + <arg><option>--git-[no-]sign-tags</option></arg> + <arg><option>--git-keyid=</option><replaceable>GPG-KEYID</replaceable></arg> + <arg><option>--git-posttag=</option><replaceable>COMMAND</replaceable></arg> + <arg><option>--git-postbuild=</option><replaceable>COMMAND</replaceable></arg> + <arg><option>--git-postexport=</option><replaceable>COMMAND</replaceable></arg> + <arg><option>--git-prebuild=</option><replaceable>COMMAND</replaceable></arg> + <arg><option>--git-[no-]build</option></arg> + <arg><option>--git-[no-]hooks</option></arg> + <arg><option>--git-packaging-tag=</option><replaceable>TAG-FORMAT</replaceable></arg> + <arg><option>--git-upstream-tag=</option><replaceable>TAG-FORMAT</replaceable></arg> + <arg><option>--git-force-create</option></arg> + <arg><option>--git-no-create-orig</option></arg> + <arg><option>--git-upstream-tree=</option><replaceable>[TAG|BRANCH|TREEISH]</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-export=</option><replaceable>TREEISH</replaceable></arg> + <arg><option>--git-export-only</option></arg> + <arg><option>--git-packaging-dir=</option><replaceable>DIRECTORY</replaceable></arg> + <arg><option>--git-[no-]pristine-tar</option></arg> + <arg><option>--git-[no-]pristine-tar-commit</option></arg> + <arg><option>--git-tag-only</option></arg> + <arg><option>--git-retag</option></arg> + <arg><option>--git-[no-]patch-export</option></arg> + </cmdsynopsis> + </refsynopsisdiv> + <refsect1> + <title>DESCRIPTION</title> + <para> + &gbp-buildpackage-rpm; is used to build RPM packages from a &git; + repository. It is an RPM counterpart for the &gbp-buildpackage; tool that + is designed for building Debian packages. + </para> + <para> + &gbp-buildpackage-rpm; will, in order: + </para> + <itemizedlist> + <listitem> + <para> + Verify that it is being executed from the proper location. + </para> + </listitem> + <listitem> + <para> + Verify that the repository doesn't contain any uncommitted source + changes. + </para> + </listitem> + <listitem> + <para> + Verify that it is being executed from the correct branch. + </para> + </listitem> + <listitem> + <para> + Export packaging files to a separate build area. + </para> + </listitem> + <listitem> + <para> + Create an orig source tarball if it doesn't exist. + </para> + </listitem> + <listitem> + <para> + Call <application>rpmbuild</application>(1) (or the application + specified via <option>--git-builder</option>), passing along all + command line arguments that don't start with --git-. + </para> + </listitem> + <listitem> + <para> + (Optionally) tag the tree after a successful build. + </para> + </listitem> + <listitem> + <para> + (Optionally) call a post build hook - e.g. to run + <productname>rpmlint</productname>. + </para> + </listitem> + <listitem> + <para> + (Optionally) call a post tag hook - e.g. to push the results to a + remote repository after creating the tag. + </para> + </listitem> + </itemizedlist> + </refsect1> + <refsect1> + <title>OPTIONS</title> + <variablelist> + <varlistentry> + <term><option>--git-[no-]ignore-new</option> + </term> + <listitem> + <para> + Don't abort if there are uncommitted changes in the source tree or + the current branch doesn't match the + <replaceable>PACKAGING-BRANCH</replaceable>. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-tag</option> + </term> + <listitem> + <para> + Add a git tag after a successful build. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-builder=<replaceable>BUILD_CMD</replaceable></option> + </term> + <listitem> + <para> + Use <replaceable>BUILD_CMD</replaceable> instead of + <command>rpmbuild -ba</command>. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-cleaner=<replaceable>CLEAN_CMD</replaceable></option> + </term> + <listitem> + <para> + Use <replaceable>CLEAN_CMD</replaceable>. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-verbose</option> + </term> + <listitem> + <para> + Verbose execution + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-color=</option><replaceable>[auto|on|off]</replaceable> + </term> + <listitem> + <para> + Whether to use colored output. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-color-scheme=</option><replaceable>COLOR_SCHEME</replaceable> + </term> + <listitem> + <para> + Colors to use in output (when color is enabled). The format for + COLOR_SCHEME is + '<debug>:<info>:<warning>:<error>'. + Numerical values and color names are accepted, empty fields imply + the default color. For example --git-color-scheme='cyan:34::' would + show debug messages in cyan, info messages in blue and other messages + in default (i.e. warning and error messages in red). + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-notify=</option><replaceable>[auto|on|off]</replaceable> + </term> + <listitem> + <para> + Whether to send a desktop notification after the build. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-upstream-branch</option>=<replaceable>BRANCH_NAME</replaceable> + </term> + <listitem> + <para> + Branch to build the orig tarball from if + <option>--git-upstream-tree</option> is set to + <replaceable>BRANCH</replaceable>. Default is + <replaceable>upstream</replaceable>. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-packaging-branch</option>=<replaceable>BRANCH_NAME</replaceable> + </term> + <listitem> + <para> + If you're not on this branch when invoking &gbp-buildpackage-rpm; it + will fail. Default is <replaceable>master</replaceable>. This is done + to make sure you don't accidentally release from a topic branch. Not + being on this branch will be ignored when using + <option>--git-ignore-new</option>. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-ignore-branch</option> + </term> + <listitem> + <para> + Don't check if the current branch matches + <replaceable>PACKAGING-BRANCH</replaceable>. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-[no-]submodules</option> + </term> + <listitem> + <para> + Include git submodules in the orig tarball. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-[no-]sign-tags</option> + </term> + <listitem> + <para> + GPG sign all created tags. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-keyid=</option><replaceable>GPG-KEYID</replaceable> + </term> + <listitem> + <para> + Use this keyid for gpg signing tags. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-posttag=</option><replaceable>COMMAND</replaceable> + </term> + <listitem> + <para> + Excecute <replaceable>COMMAND</replaceable> after tagging a new + version. + </para> + <para> + Exported environment variables are: <envar>GBP_TAG</envar> (the name + of the generated tag), <envar>GBP_BRANCH</envar> (the branch the + package was build from) and <envar>GBP_SHA1</envar> (the sha1 of the + commit the tag was created at). + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-postbuild=</option><replaceable>COMMAND</replaceable> + </term> + <listitem> + <para> + Execute <replaceable>COMMAND</replaceable> after successful + build. + </para> + <para> + Exported environment variables are: <envar>GBP_CHANGES_FILE</envar> + (the name of the generated changes file), + <envar>GBP_BUILD_DIR</envar> (the build dir). + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-postexport=</option><replaceable>COMMAND</replaceable> + </term> + <listitem> + <para> + Execute <replaceable>COMMAND</replaceable> after exporting the source + tree. + </para> + <para> + Exported environment variables are: <envar>GBP_GIT_DIR</envar> (the + repository the package is being built from), + <envar>GBP_TMP_DIR</envar> (the temporary directory where the sources + have been initially exported). + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-prebuild=</option><replaceable>COMMAND</replaceable> + </term> + <listitem> + <para> + Execute <replaceable>COMMAND</replaceable> from the build directory + before calling <application>rpmbuild</application> or the application + specified via <option>--git-builder</option>. + </para> + <para> + Exported environment variables are: <envar>GBP_GIT_DIR</envar> (the + repository the package is being built from), + <envar>GBP_BUILD_DIR</envar> (the build dir). + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-[no-]build</option> + </term> + <listitem> + <para> + Enable builder. Note: <option>--git-no-build</option> causes the + postbuild hook to be disabled, too. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-[no-]hooks</option> + </term> + <listitem> + <para> + Enable running all (cleaner, postexport, prebuild, postbuild, and + posttag) hooks. Note: the <option>--git-builder</option> command is + not affected by this option. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-packaging-tag=</option><replaceable>TAG-FORMAT</replaceable> + </term> + <listitem> + <para> + Use this tag format when tagging released versions of the package. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-upstream-tag=</option><replaceable>TAG-FORMAT</replaceable> + </term> + <listitem> + <para> + Use this tag format when looking for tags of upstream versions, + default is <replaceable>upstream/%(version)s</replaceable>. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-force-create</option> + </term> + <listitem> + <para> + Force creation of an orig tarball (overwriting a pre-existing one if + present). + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-no-create-orig</option> + </term> + <listitem> + <para> + Don't try to create any orig tarball. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-export-dir=</option><replaceable>DIRECTORY</replaceable> + </term> + <listitem> + <para> + Export the packaging files from the current branch head (or the + treeish object given via <option>--git-export</option> to + <replaceable>DIRECTORY</replaceable> before building. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-export=</option><replaceable>TREEISH</replaceable> + </term> + <listitem> + <para> + Instead of exporting the current branch head, export the treeish + object <replaceable>TREEISH</replaceable>. The special name + <replaceable>INDEX</replaceable> exports the current index, + <replaceable>WC</replaceable>) exports all files in the + current working directory. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-packaging-dir=</option><replaceable>DIRECTORY</replaceable> + </term> + <listitem> + <para> + Subdirectory that contains the RPM packaging files. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-upstream-tree=</option><replaceable>[TAG|BRANCH|TREEISH]</replaceable> + </term> + <listitem> + <para> + How to find the upstream sources used to generate the tarball. + <replaceable>TAG</replaceable> looks at a tag corresponding to the + version in the changelog. <replaceable>BRANCH</replaceable> looks at + the upstream branch given via the + <option>--git-upstream-branch</option> option. Other values are + interpreted as treeishs. + </para> + <para> + This doesn't have any effect if <option>--git-pristine-tar</option> + is being used. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-tarball-dir=</option><replaceable>DIRECTORY</replaceable> + </term> + <listitem> + <para> + Search for original tarballs in <replaceable>DIRECTORY</replaceable> + instead of generating them. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-compression-level=</option><replaceable>LEVEL</replaceable> + </term> + <listitem> + <para> + Specifies the upstream tarball compression level if an upstream + tarball needs to be built. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-tag-only</option> + </term> + <listitem> + <para> + Don't build, only tag and run post-tag hooks. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-retag</option> + </term> + <listitem> + <para> + Don't fail tag operations if a tag with the same version already + exists, but, overwrite the existing tag, instead. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-pristine-tar</option> + </term> + <listitem> + <para> + Use pristine-tar when generating the upstream tarball if it doesn't + exist. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--git-pristine-tar-commit</option> + </term> + <listitem> + <para> + Commit the pristine-tar delta to the pristine-tar branch if a new + tarball was generated and the pristine-tar data isn't already there. + </para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + <refsect1> + <title>EXAMPLES</title> + <para> + Only build a source RPM with &rpmbuild; + </para> + <screen> + &gbp-buildpackage-rpm; -bs + </screen> + <para> + Build an RPM package with &rpmbuild; on a custom branch with the uncommitted + changes included. + </para> + <screen> + &gbp-buildpackage-rpm; --git-ignore-branch --git-export=WC + </screen> + </refsect1> + <refsect1> + &man.gbp.config-files; + <para> + All options in the config files are specified without the 'git-' prefix. + </para> + </refsect1> + <refsect1> + <title>SEE ALSO</title> + <para> + <xref linkend="man.gbp.import.srpm">, + <xref linkend="man.gbp.pq.rpm">, + <citerefentry> + <refentrytitle>rpmbuild</refentrytitle> + <manvolnum>8</manvolnum> + </citerefentry>, + <xref linkend="man.gbp.conf">, + &man.seealso.common; + </para> + </refsect1> + <refsect1> + <title>AUTHOR</title> + <para> + &rpm-username; &rpm-email; + </para> + </refsect1> +</refentry> diff --git a/docs/manpages/manpages.ent b/docs/manpages/manpages.ent index 6b8ea95f..d0a6f4c3 100644 --- a/docs/manpages/manpages.ent +++ b/docs/manpages/manpages.ent @@ -12,5 +12,6 @@ <!ENTITY man.gbp.conf SYSTEM "gbp.conf.sgml"> <!ENTITY man.gbp.config-files SYSTEM "man.conffiles.sgml"> <!ENTITY man.seealso.common SYSTEM "man.seealso.sgml"> +<!ENTITY man.gbp.buildpackage.rpm SYSTEM "gbp-buildpackage-rpm.sgml"> <!ENTITY % COMMON.OPTIONS SYSTEM "man.common-options.ent"> %COMMON.OPTIONS; diff --git a/gbp/config.py b/gbp/config.py index de8a25ea..3b483c0b 100644 --- a/gbp/config.py +++ b/gbp/config.py @@ -1,6 +1,6 @@ # vim: set fileencoding=utf-8 : # -# (C) 2006,2007,2010-2012 Guido Guenther <agx@sigxcpu.org> +# (C) 2006,2007,2010-2012,2015 Guido Guenther <agx@sigxcpu.org> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or @@ -101,6 +101,7 @@ class GbpOptionParser(OptionParser): 'sign-tags' : 'False', 'force-create' : 'False', 'no-create-orig' : 'False', + 'cleaner' : '/bin/true', 'keyid' : '', 'posttag' : '', 'postbuild' : '', @@ -577,7 +578,6 @@ class GbpOptionParserDebian(GbpOptionParser): defaults = dict(GbpOptionParser.defaults) defaults.update( { 'builder' : 'debuild -i -I', - 'cleaner' : '/bin/true', } ) @@ -591,7 +591,13 @@ class GbpOptionParserRpm(GbpOptionParser): 'vendor' : 'Downstream', 'packaging-branch' : 'master', 'packaging-dir' : '', + 'packaging-tag-msg' : ('%(pkg)s (vendor)s release ' + '%(version)s'), 'packaging-tag' : 'packaging/%(version)s', + 'export-sourcedir' : 'SOURCES', + 'export-specdir' : 'SPECS', + 'export-dir' : '../rpmbuild', + 'builder' : 'rpmbuild', 'spec-file' : '', }) @@ -612,9 +618,19 @@ class GbpOptionParserRpm(GbpOptionParser): 'packaging-tag': "Format string for packaging tags, RPM counterpart of the " "'debian-tag' option, default is '%(packaging-tag)s'", + 'packaging-tag-msg': + ("Format string for packaging tag messages, " + "default is '%(packaging-tag-msg)s'"), 'spec-file': "Spec file to use, causes the packaging-dir option to be " "ignored, default is '%(spec-file)s'", + 'export-sourcedir': + "Subdir (under EXPORT_DIR) where packaging sources (other than " + "the spec file) are exported, default is " + "'%(export-sourcedir)s'", + 'export-specdir': + "Subdir (under EXPORT_DIR) where package spec file is " + "exported default is '%(export-specdir)s'", }) # vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: diff --git a/gbp/scripts/buildpackage_rpm.py b/gbp/scripts/buildpackage_rpm.py new file mode 100644 index 00000000..d613e91e --- /dev/null +++ b/gbp/scripts/buildpackage_rpm.py @@ -0,0 +1,631 @@ +# vim: set fileencoding=utf-8 : +# +# (C) 2006-2011,2015 Guido Guenther <agx@sigxcpu.org> +# (C) 2012-2015 Intel Corporation <markus.lehtonen@linux.intel.com> +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +"""Build an RPM package out of a Git repository""" + +import ConfigParser +import os +import re +import shutil +import sys +from datetime import datetime + +import gbp.log +import gbp.notifications +import gbp.rpm as rpm +from gbp.command_wrappers import Command, RunAtCommand, CommandExecFailed +from gbp.config import GbpOptionParserRpm, GbpOptionGroup +from gbp.errors import GbpError +from gbp.format import format_str +from gbp.pkg import compressor_opts +from gbp.rpm.git import GitRepositoryError, RpmGitRepository +from gbp.rpm.policy import RpmPkgPolicy +from gbp.tmpfile import init_tmpdir, del_tmpdir, tempfile +from gbp.scripts.common.buildpackage import (index_name, + git_archive_submodules, + git_archive_single, dump_tree, + write_wc, drop_index) +from gbp.scripts.pq_rpm import parse_spec + + +class GbpAutoGenerateError(GbpError): + pass + + +def makedir(path): + """Create directory""" + try: + if not os.path.exists(path): + os.makedirs(path) + except OSError as err: + raise GbpError("Cannot create dir %s: %s" % (path, err)) + return path + + +def git_archive(repo, spec, output_dir, treeish, prefix, comp_level, + with_submodules): + "Create a compressed orig tarball in output_dir using git_archive" + comp_opts = '' + if spec.orig_src['compression']: + comp_opts = compressor_opts[spec.orig_src['compression']][0] + + output = os.path.join(output_dir, spec.orig_src['filename']) + + # Remove extra slashes from prefix, will be added by git_archive_x funcs + prefix = prefix.strip('/') + try: + if repo.has_submodules(treeish) and with_submodules: + repo.update_submodules() + git_archive_submodules(repo, treeish, output, prefix, + spec.orig_src['compression'], + comp_level, comp_opts, + spec.orig_src['archive_fmt']) + + else: + git_archive_single(treeish, output, prefix, + spec.orig_src['compression'], comp_level, + comp_opts) + except (GitRepositoryError, CommandExecFailed): + gbp.log.err("Error generating submodules' archives") + return False + return True + + +def prepare_upstream_tarball(repo, spec, options, output_dir): + """Make sure we have an upstream tarball""" + # look in tarball_dir first, if found force a symlink to it + orig_file = spec.orig_src['filename'] + if options.tarball_dir: + gbp.log.debug("Looking for orig tarball '%s' at '%s'" % + (orig_file, options.tarball_dir)) + if not RpmPkgPolicy.symlink_orig(orig_file, options.tarball_dir, + output_dir, force=True): + gbp.log.info("Orig tarball '%s' not found at '%s'" % + (orig_file, options.tarball_dir)) + else: + gbp.log.info("Orig tarball '%s' found at '%s'" % + (orig_file, options.tarball_dir)) + + # build an orig unless the user forbids it, always build (and overwrite + # pre-existing) if user forces it + if options.force_create or (not options.no_create_orig and not + RpmPkgPolicy.has_orig(orig_file, output_dir)): + if not pristine_tar_build_orig(repo, orig_file, output_dir, options): + upstream_tree = git_archive_build_orig(repo, spec, output_dir, + options) + if options.pristine_tar_commit: + if repo.pristine_tar.has_commit(orig_file): + gbp.log.debug("%s already on pristine tar branch" % + orig_file) + else: + archive = os.path.join(output_dir, orig_file) + gbp.log.debug("Adding %s to pristine-tar branch" % + archive) + repo.pristine_tar.commit(archive, upstream_tree) + + +def pristine_tar_build_orig(repo, orig_file, output_dir, options): + """Build orig using pristine-tar""" + if options.pristine_tar: + if not repo.has_branch(repo.pristine_tar_branch): + gbp.log.warn('Pristine-tar branch "%s" not found' % + repo.pristine_tar.branch) + try: + repo.pristine_tar.checkout(os.path.join(output_dir, orig_file)) + return True + except CommandExecFailed: + if options.pristine_tar_commit: + gbp.log.debug("pristine-tar checkout failed, " + "will commit tarball due to " + "'--pristine-tar-commit'") + elif not options.force_create: + raise + return False + + +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} + upstream_tree = repo.version_to_tag(options.upstream_tag, + tag_str_fields) + elif options.upstream_tree.upper() == 'BRANCH': + if not repo.has_branch(options.upstream_branch): + raise GbpError("%s is not a valid branch" % options.upstream_branch) + upstream_tree = options.upstream_branch + else: + upstream_tree = get_tree(repo, options.upstream_tree) + if not repo.has_treeish(upstream_tree): + raise GbpError('Invalid upstream treeish %s' % upstream_tree) + return upstream_tree + + +def get_tree(repo, tree_name): + """ + Get/create a tree-ish to be used for exporting and diffing. Accepts + special keywords for git index and working copies. + """ + try: + if tree_name == index_name: + # Write a tree of the index + tree = repo.write_tree() + elif tree_name == 'WC': + # Write a tree of the working copy + tree = write_wc(repo) + else: + tree = tree_name + except GitRepositoryError as err: + raise GbpError(err) + if not repo.has_treeish(tree): + raise GbpError('Invalid treeish object %s' % tree) + + return tree + + +def get_current_branch(repo): + """Get the currently checked-out branch""" + try: + branch = repo.get_branch() + except GitRepositoryError: + branch = None + return branch + + +def get_vcs_info(repo, treeish): + """Get the info for spec vcs tag""" + info = {} + try: + info['tagname'] = repo.describe(treeish, longfmt=True, always=True, + abbrev=40) + info['commit'] = repo.rev_parse('%s^0' % treeish) + info['commitish'] = repo.rev_parse('%s' % treeish) + except GitRepositoryError: + # If tree is not commit-ish, expect it to be from current HEAD + info['tagname'] = repo.describe('HEAD', longfmt=True, always=True, + abbrev=40) + '-dirty' + info['commit'] = repo.rev_parse('HEAD') + '-dirty' + info['commitish'] = info['commit'] + return info + + +def git_archive_build_orig(repo, spec, output_dir, options): + """ + Build orig tarball using git-archive + + @param repo: our git repository + @type repo: L{RpmGitRepository} + @param spec: spec file of the package + @type spec: L{SpecFile} + @param output_dir: where to put the tarball + @type output_dir: C{Str} + @param options: the parsed options + @type options: C{dict} of options + @return: the tree we built the tarball from + @rtype: C{str} + """ + try: + orig_prefix = spec.orig_src['prefix'] + upstream_tree = get_upstream_tree(repo, spec.upstreamversion, options) + gbp.log.info("%s does not exist, creating from '%s'" % + (spec.orig_src['filename'], upstream_tree)) + if spec.orig_src['compression']: + gbp.log.debug("Building upstream source archive with compression " + "'%s -%s'" % (spec.orig_src['compression'], + options.comp_level)) + if not git_archive(repo, spec, output_dir, upstream_tree, + orig_prefix, options.comp_level, + options.with_submodules): + raise GbpError("Cannot create upstream tarball at '%s'" % + output_dir) + except (GitRepositoryError, GbpError) as err: + raise GbpAutoGenerateError(str(err)) + return upstream_tree + + +def is_native(repo, options): + """Determine whether a package is native or non-native""" + if repo.has_branch(options.upstream_branch): + return False + # Check remotes, too + for remote_branch in repo.get_remote_branches(): + remote, branch = remote_branch.split('/', 1) + if branch == options.upstream_branch: + gbp.log.debug("Found upstream branch '%s' from remote '%s'" % + (remote, branch)) + return False + return True + + +def setup_builder(options, builder_args): + """Setup args and options for builder script""" + if options.builder == 'rpmbuild': + if len(builder_args) == 0: + builder_args.append('-ba') + builder_args.extend([ + '--define "_topdir %s"' % os.path.abspath(options.export_dir), + '--define "_specdir %%_topdir/%s"' % options.export_specdir, + '--define "_sourcedir %%_topdir/%s"' % options.export_sourcedir]) + + +def packaging_tag_data(repo, commit, name, version, options): + """Compose packaging tag name and msg""" + version_dict = dict(version, version=rpm.compose_version_str(version)) + + # Compose tag name and message + tag_name_fields = dict(version_dict, vendor=options.vendor.lower()) + tag_name = repo.version_to_tag(options.packaging_tag, tag_name_fields) + + tag_msg = format_str(options.packaging_tag_msg, + dict(version_dict, pkg=name, + vendor=options.vendor)) + return (tag_name, tag_msg) + + +def create_packaging_tag(repo, commit, name, version, options): + """Create a packaging/release Git tag""" + tag_name, tag_msg = packaging_tag_data(repo, commit, name, version, options) + + if options.retag and repo.has_tag(tag_name): + repo.delete_tag(tag_name) + repo.create_tag(name=tag_name, msg=tag_msg, sign=options.sign_tags, + keyid=options.keyid, commit=commit) + return tag_name + + +def disable_hooks(options): + """Disable all hooks (except for builder)""" + for hook in ['cleaner', 'postexport', 'prebuild', 'postbuild', 'posttag']: + if getattr(options, hook): + gbp.log.info("Disabling '%s' hook" % hook) + setattr(options, hook, '') + + +def build_parser(name, prefix=None, git_treeish=None): + """Construct config/option parser""" + try: + parser = GbpOptionParserRpm(command=os.path.basename(name), + prefix=prefix) + except ConfigParser.ParsingError as err: + gbp.log.err(err) + return None + + tag_group = GbpOptionGroup(parser, "tag options", + "options related to git tag creation") + branch_group = GbpOptionGroup(parser, "branch options", + "branch layout options") + cmd_group = GbpOptionGroup(parser, "external command options", + "how and when to invoke external commands and hooks") + orig_group = GbpOptionGroup(parser, "orig tarball options", + "options related to the creation of the orig tarball") + export_group = GbpOptionGroup(parser, "export build-tree options", + "alternative build tree related options") + parser.add_option_group(tag_group) + parser.add_option_group(orig_group) + parser.add_option_group(branch_group) + parser.add_option_group(cmd_group) + parser.add_option_group(export_group) + + parser.add_boolean_config_file_option(option_name="ignore-new", + dest="ignore_new") + parser.add_option("--git-verbose", action="store_true", dest="verbose", + default=False, help="verbose command execution") + parser.add_config_file_option(option_name="tmp-dir", dest="tmp_dir") + parser.add_config_file_option(option_name="color", dest="color", + type='tristate') + parser.add_config_file_option(option_name="color-scheme", + dest="color_scheme") + parser.add_config_file_option(option_name="notify", dest="notify", + type='tristate') + parser.add_config_file_option(option_name="vendor", action="store", + dest="vendor") + tag_group.add_option("--git-tag", action="store_true", dest="tag", + default=False, + help="create a tag after a successful build") + tag_group.add_option("--git-tag-only", action="store_true", dest="tag_only", + default=False, + help="don't build, only tag and run the posttag hook") + tag_group.add_option("--git-retag", action="store_true", dest="retag", + default=False, help="don't fail if the tag already exists") + tag_group.add_boolean_config_file_option(option_name="sign-tags", + dest="sign_tags") + tag_group.add_config_file_option(option_name="keyid", dest="keyid") + tag_group.add_config_file_option(option_name="packaging-tag", + dest="packaging_tag") + tag_group.add_config_file_option(option_name="packaging-tag-msg", + dest="packaging_tag_msg") + tag_group.add_config_file_option(option_name="upstream-tag", + dest="upstream_tag") + orig_group.add_config_file_option(option_name="upstream-tree", + dest="upstream_tree") + orig_group.add_boolean_config_file_option(option_name="pristine-tar", + dest="pristine_tar") + orig_group.add_boolean_config_file_option(option_name="pristine-tar-commit", + dest="pristine_tar_commit") + orig_group.add_config_file_option(option_name="force-create", + dest="force_create", action="store_true", + help="force creation of upstream source tarball") + orig_group.add_config_file_option(option_name="no-create-orig", + dest="no_create_orig", action="store_true", + help="don't create upstream source tarball") + orig_group.add_config_file_option(option_name="tarball-dir", + dest="tarball_dir", type="path", + help="location to look for external tarballs") + orig_group.add_config_file_option(option_name="compression-level", + dest="comp_level", + help="Compression level, default is " + "'%(compression-level)s'") + branch_group.add_config_file_option(option_name="upstream-branch", + dest="upstream_branch") + branch_group.add_config_file_option(option_name="packaging-branch", + dest="packaging_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", + dest="with_submodules") + cmd_group.add_config_file_option(option_name="builder", dest="builder", + help="command to build the package, default is " + "'%(builder)s'") + cmd_group.add_config_file_option(option_name="cleaner", dest="cleaner", + help="command to clean the working copy, default is " + "'%(cleaner)s'") + cmd_group.add_config_file_option(option_name="prebuild", dest="prebuild", + help="command to run before a build, default is " + "'%(prebuild)s'") + cmd_group.add_config_file_option(option_name="postexport", + dest="postexport", + help="command to run after exporting the source tree, " + "default is '%(postexport)s'") + cmd_group.add_config_file_option(option_name="postbuild", dest="postbuild", + help="hook run after a successful build, default is " + "'%(postbuild)s'") + cmd_group.add_config_file_option(option_name="posttag", dest="posttag", + help="hook run after a successful tag operation, default " + "is '%(posttag)s'") + cmd_group.add_boolean_config_file_option(option_name="hooks", dest="hooks") + export_group.add_option("--git-no-build", action="store_true", + dest="no_build", + help="Don't run builder or the associated hooks") + export_group.add_config_file_option(option_name="export-dir", + 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="export-specdir", + dest="export_specdir", type="path") + export_group.add_config_file_option(option_name="export-sourcedir", + dest="export_sourcedir", type="path") + export_group.add_config_file_option("export", dest="export", + metavar="TREEISH", + help="export treeish object TREEISH, default is " + "'%(export)s'") + export_group.add_config_file_option(option_name="packaging-dir", + dest="packaging_dir") + export_group.add_config_file_option(option_name="spec-file", + dest="spec_file") + return parser + + +def parse_args(argv, prefix, git_treeish=None): + """Parse config and command line arguments""" + args = [arg for arg in argv[1:] if arg.find('--%s' % prefix) == 0] + builder_args = [arg for arg in argv[1:] if arg.find('--%s' % prefix) == -1] + + # We handle these although they don't have a --git- prefix + for arg in ["--help", "-h", "--version"]: + if arg in builder_args: + args.append(arg) + + parser = build_parser(argv[0], prefix=prefix, git_treeish=git_treeish) + if not parser: + return None, None, None + options, args = parser.parse_args(args) + + gbp.log.setup(options.color, options.verbose, options.color_scheme) + if not options.hooks: + disable_hooks(options) + if options.retag: + if not options.tag and not options.tag_only: + gbp.log.err("'--%sretag' needs either '--%stag' or '--%stag-only'" % + (prefix, prefix, prefix)) + return None, None, None + + return options, args, builder_args + + +def main(argv): + """Entry point for gbp-buildpackage-rpm""" + retval = 0 + prefix = "git-" + spec = None + + options, gbp_args, builder_args = parse_args(argv, prefix) + + if not options: + return 1 + + try: + repo = RpmGitRepository(os.path.curdir) + except GitRepositoryError: + gbp.log.err("%s is not a git repository" % (os.path.abspath('.'))) + return 1 + + # Determine tree-ish to be exported + try: + tree = get_tree(repo, options.export) + except GbpError as err: + gbp.log.err('Failed to determine export treeish: %s' % err) + return 1 + # Re-parse config options with using the per-tree config file(s) from the + # exported tree-ish + options, gbp_args, builder_args = parse_args(argv, prefix, tree) + + branch = get_current_branch(repo) + + try: + init_tmpdir(options.tmp_dir, prefix='buildpackage-rpm_') + + tree = get_tree(repo, options.export) + spec = parse_spec(options, repo, treeish=tree) + + Command(options.cleaner, shell=True)() + if not options.ignore_new: + ret, out = repo.is_clean() + if not ret: + gbp.log.err("You have uncommitted changes in your source tree:") + gbp.log.err(out) + raise GbpError("Use --git-ignore-new to ignore.") + + if not options.ignore_new and not options.ignore_branch: + if branch != options.packaging_branch: + gbp.log.err("You are not on branch '%s' but on '%s'" % + (options.packaging_branch, branch)) + raise GbpError("Use --git-ignore-branch to ignore or " + "--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): + raise GbpError + # Re-parse spec from dump dir to get version etc. + spec = rpm.SpecFile(os.path.join(dump_dir, spec.specfile)) + + if not options.tag_only: + # Setup builder opts + setup_builder(options, builder_args) + + # Prepare final export dirs + export_dir = makedir(options.export_dir) + source_dir = makedir(os.path.join(export_dir, + options.export_sourcedir)) + spec_dir = makedir(os.path.join(export_dir, options.export_specdir)) + + # Move packaging files to final export dir + gbp.log.debug("Exporting packaging files from '%s' to '%s'" % + (dump_dir, export_dir)) + for fname in os.listdir(dump_dir): + src = os.path.join(dump_dir, fname) + if fname == spec.specfile: + dst = os.path.join(spec_dir, fname) + else: + dst = os.path.join(source_dir, fname) + try: + shutil.copy2(src, dst) + except IOError as err: + raise GbpError("Error exporting packaging files: %s" % err) + spec.specdir = os.path.abspath(spec_dir) + + orig_prefix = spec.orig_src['prefix'] + # Get/build the orig tarball + if is_native(repo, options): + if spec.orig_src and not options.no_create_orig: + # Just build source archive from the exported tree + gbp.log.info("Creating (native) source archive %s from '%s'" + % (spec.orig_src['filename'], tree)) + if spec.orig_src['compression']: + gbp.log.debug("Building source archive with " + "compression '%s -%s'" % + (spec.orig_src['compression'], + options.comp_level)) + if not git_archive(repo, spec, source_dir, tree, + orig_prefix, options.comp_level, + options.with_submodules): + raise GbpError("Cannot create source tarball at '%s'" % + source_dir) + # Non-native packages: create orig tarball from upstream + elif spec.orig_src: + prepare_upstream_tarball(repo, spec, options, source_dir) + + # Run postexport hook + if options.postexport: + RunAtCommand(options.postexport, shell=True, + extra_env={'GBP_GIT_DIR': repo.git_dir, + 'GBP_TMP_DIR': export_dir} + )(dir=export_dir) + # Do actual build + if not options.no_build and not options.tag_only: + if options.prebuild: + RunAtCommand(options.prebuild, shell=True, + extra_env={'GBP_GIT_DIR': repo.git_dir, + 'GBP_BUILD_DIR': export_dir} + )(dir=export_dir) + + # Finally build the package: + if options.builder.startswith("rpmbuild"): + builder_args.append(os.path.join(spec.specdir, + spec.specfile)) + else: + builder_args.append(spec.specfile) + RunAtCommand(options.builder, builder_args, shell=True, + extra_env={'GBP_BUILD_DIR': export_dir} + )(dir=export_dir) + if options.postbuild: + changes = os.path.abspath("%s/%s.changes" % (source_dir, + spec.name)) + gbp.log.debug("Looking for changes file %s" % changes) + Command(options.postbuild, shell=True, + extra_env={'GBP_CHANGES_FILE': changes, + 'GBP_BUILD_DIR': export_dir})() + + # Tag (note: tags the exported version) + if options.tag or options.tag_only: + gbp.log.info("Tagging %s" % rpm.compose_version_str(spec.version)) + tag = create_packaging_tag(repo, tree, spec.name, spec.version, + options) + vcs_info = get_vcs_info(repo, tag) + if options.posttag: + sha = repo.rev_parse("%s^{}" % tag) + Command(options.posttag, shell=True, + extra_env={'GBP_TAG': tag, + 'GBP_BRANCH': branch, + 'GBP_SHA1': sha})() + else: + vcs_info = get_vcs_info(repo, tree) + + except CommandExecFailed: + retval = 1 + except GitRepositoryError as err: + gbp.log.err("Git command failed: %s" % err) + retval = 1 + except GbpAutoGenerateError as err: + if len(err.__str__()): + gbp.log.err(err) + retval = 2 + except GbpError as err: + if len(err.__str__()): + gbp.log.err(err) + retval = 1 + finally: + drop_index() + #del_tmpdir() + + if not options.tag_only: + if spec and options.notify: + summary = "Gbp-rpm %s" % ["failed", "successful"][not retval] + message = ("Build of %s %s %s" % (spec.name, + rpm.compose_version_str(spec.version), + ["failed", "succeeded"][not retval])) + if not gbp.notifications.notify(summary, message, options.notify): + gbp.log.err("Failed to send notification") + retval = 1 + + return retval + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/gbp/tmpfile.py b/gbp/tmpfile.py index 0e0e7338..b90527fd 100644 --- a/gbp/tmpfile.py +++ b/gbp/tmpfile.py @@ -12,8 +12,8 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, please see -# <http://www.gnu.org/licenses/> +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """Temporary directory handling""" import os diff --git a/packaging/git-buildpackage.spec b/packaging/git-buildpackage.spec index 2fe27cb6..434c2ba0 100644 --- a/packaging/git-buildpackage.spec +++ b/packaging/git-buildpackage.spec @@ -247,6 +247,7 @@ done %{python_sitelib}/gbp/scripts/*rpm*.py* %{python_sitelib}/gbp/rpm/*py* %if %{with docs} +%{_mandir}/man1/gbp-buildpackage-rpm.1* %endif diff --git a/tests/component/rpm/data b/tests/component/rpm/data -Subproject bae44ddc98ae0ed15ae078cb7c2fc597dee48da +Subproject bea3aa372447b2fca611f187c2daa55edd8cdb3 diff --git a/tests/component/rpm/test_buildpackage_rpm.py b/tests/component/rpm/test_buildpackage_rpm.py new file mode 100644 index 00000000..10c5faea --- /dev/null +++ b/tests/component/rpm/test_buildpackage_rpm.py @@ -0,0 +1,138 @@ +# vim: set fileencoding=utf-8 : +# +# (C) 2013-2015 Intel Corporation <markus.lehtonen@linux.intel.com> +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +"""Unit tests for the gbp-buildpackage-rpm tool""" + +import glob +import mock +import os +import re +import shutil +import stat +import subprocess + +from nose.tools import assert_raises, eq_, ok_ # pylint: disable=E0611 + +from gbp.git import GitRepository +from gbp.scripts.buildpackage_rpm import main as gbp_rpm +from tests.component.rpm import RpmRepoTestBase, RPM_TEST_DATA_DIR +from tests.testutils import ls_dir, ls_tar + +# Disable "Method could be a function warning" +# pylint: disable=R0201 +# Disable "Too many public methods" +# pylint: disable=R0904 + + +DATA_DIR = os.path.join(RPM_TEST_DATA_DIR, 'rpm') +ORIG_DATA_DIR = os.path.join(RPM_TEST_DATA_DIR, 'orig') + +MOCK_NOTIFICATIONS = [] + + +def mock_gbp(args): + """Wrapper for gbp-buildpackage-rpm""" + return gbp_rpm(['arg0', '--git-notify=off','--git-ignore-branch'] + + args + + ['-ba', '--clean', '--target=noarch', '--nodeps']) + +def mock_notify(summary, message, notify_opt): + """Mock notification system""" + # Auto will succeed + if notify_opt.is_auto(): + MOCK_NOTIFICATIONS.append((summary, message)) + return True + # Otherwise fail + return False + + +class TestGbpRpm(RpmRepoTestBase): + """Basic tests for gbp buildpackage-rpm""" + + @staticmethod + def ls_rpm(rpm): + """List the contents of an rpm package""" + args = ['rpm', '-q', '--qf', + '[%{FILEDIGESTS %{FILEMODES} %{FILENAMES}\n]', '-p'] + popen = subprocess.Popen(args + [rpm], stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, stderr = popen.communicate() + if popen.returncode: + raise Exception("Failed to get file metadata for %s: %s" % + (rpm, stderr)) + return sorted([(nam, mod, dig) for dig, mod, nam in + [lin.split(None, 2) for lin in stdout.splitlines()]]) + + @staticmethod + def check_rpms(directory): + """Check build results""" + # Only check files, at least for now + files = glob.glob(directory + '/*rpm') + assert files, "No rpms (%s)found in %s" % (files, directory) + for path in files: + ref_file = os.path.join(DATA_DIR, os.path.basename(path)) + eq_(TestGbpRpm.ls_rpm(path), TestGbpRpm.ls_rpm(ref_file)) + + @staticmethod + def check_and_rm_file(filepath, content): + """Check file content and remove it""" + with open(filepath) as fobj: + eq_(fobj.read(), content) + os.unlink(filepath) + + @classmethod + def setup_class(cls, **kwargs): + """Setup unit tests""" + super(TestGbpRpm, cls).setup_class(**kwargs) + + def test_outside_repo(self): + """Run outside a git repository""" + eq_(mock_gbp([]), 1) + self._check_log(0, 'gbp:error: %s is not a git repository' % + os.path.abspath('.')) + + def test_invalid_config_file(self): + """Test invalid config file""" + # Create and commit dummy invalid config file + repo = GitRepository.create('.') + with open('.gbp.conf', 'w') as conffd: + conffd.write('foobar\n') + repo.add_files('.gbp.conf') + repo.commit_all('Add conf') + eq_(mock_gbp([]), 1) + self._check_log(0, 'gbp:error: File contains no section headers.') + + def test_native_build(self): + """Basic test of native pkg""" + self.init_test_repo('gbp-test-native') + eq_(mock_gbp([]), 0) + c = os.path.abspath(os.path.curdir) + self.check_rpms('../rpmbuild/RPMS/*') + shutil.rmtree('../rpmbuild') + + """Test --git-cleaner option""" + self.init_test_repo('gbp-test-native') + + # Make repo dirty + with open('untracked-file', 'w') as fobj: + fobj.write('this file is not tracked\n') + + # Build on dirty repo should fail + eq_(mock_gbp([]), 1) + + # Build should succeed with cleaner + eq_(mock_gbp(['--git-cleaner=rm untracked-file']), 0) + |