aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--.travis.yml6
-rw-r--r--HACKING4
-rw-r--r--Makefile21
-rw-r--r--README.md (renamed from README)10
-rwxr-xr-xbin/git-pbuilder32
-rw-r--r--debian/changelog259
-rw-r--r--debian/control14
-rw-r--r--debian/docs2
-rw-r--r--debian/gbp.completion1
-rw-r--r--debian/gbp.conf1
-rw-r--r--debian/git-buildpackage-rpm.install1
-rw-r--r--debian/git-buildpackage-rpm.manpages1
-rw-r--r--debian/git-buildpackage.postrm2
-rw-r--r--debian/git-buildpackage.preinst2
-rw-r--r--debian/git-buildpackage.zsh-completion8
-rwxr-xr-xdebian/rules22
-rwxr-xr-xdebian/tests/smoke-rpm12
-rw-r--r--docs/Makefile12
-rw-r--r--docs/chapters/building.sgml4
-rw-r--r--docs/chapters/import.sgml163
-rw-r--r--docs/chapters/intro.sgml2
-rw-r--r--docs/common.ent4
-rw-r--r--docs/man.gbp-rpm-ch.sgml11
-rw-r--r--docs/manpages/gbp-buildpackage-rpm.sgml1
-rw-r--r--docs/manpages/gbp-buildpackage.sgml20
-rw-r--r--docs/manpages/gbp-clone.sgml65
-rw-r--r--docs/manpages/gbp-create-remote-repo.sgml9
-rw-r--r--docs/manpages/gbp-dch.sgml97
-rw-r--r--docs/manpages/gbp-import-dsc.sgml16
-rw-r--r--docs/manpages/gbp-import-dscs.sgml4
-rw-r--r--docs/manpages/gbp-import-orig.sgml85
-rw-r--r--docs/manpages/gbp-import-srpm.sgml1
-rw-r--r--docs/manpages/gbp-pq.sgml32
-rw-r--r--docs/manpages/gbp-rpm-ch.sgml355
-rw-r--r--docs/manpages/gbp.conf.sgml21
-rw-r--r--docs/manpages/manpages.ent1
-rwxr-xr-xexamples/gbp-posttag-push123
-rwxr-xr-xexamples/jenkins-scratchbuilder2
-rw-r--r--examples/wrap_cl.py1
-rwxr-xr-xexamples/zeitgeist-git.py28
-rw-r--r--gbp.conf2
-rw-r--r--gbp/command_wrappers.py84
-rw-r--r--gbp/config.py739
-rw-r--r--gbp/dch.py11
-rw-r--r--gbp/deb/__init__.py15
-rw-r--r--gbp/deb/changelog.py18
-rw-r--r--gbp/deb/control.py3
-rw-r--r--gbp/deb/dscfile.py26
-rw-r--r--gbp/deb/format.py18
-rw-r--r--gbp/deb/git.py129
-rw-r--r--gbp/deb/policy.py6
-rw-r--r--gbp/deb/pristinetar.py6
-rw-r--r--gbp/deb/source.py7
-rw-r--r--gbp/deb/upstreamsource.py28
-rw-r--r--gbp/deb/uscan.py17
-rw-r--r--gbp/errors.py1
-rw-r--r--gbp/format.py3
-rw-r--r--gbp/git/__init__.py15
-rw-r--r--gbp/git/args.py2
-rw-r--r--gbp/git/commit.py3
-rw-r--r--gbp/git/errors.py2
-rw-r--r--gbp/git/fastimport.py21
-rw-r--r--gbp/git/modifier.py16
-rw-r--r--gbp/git/repository.py297
-rw-r--r--gbp/git/vfs.py3
-rw-r--r--gbp/log.py11
-rw-r--r--gbp/notifications.py4
-rw-r--r--gbp/patch_series.py46
-rw-r--r--gbp/pkg/__init__.py48
-rw-r--r--gbp/pkg/pristinetar.py8
-rw-r--r--gbp/rpm/__init__.py2
-rw-r--r--gbp/rpm/changelog.py261
-rw-r--r--gbp/rpm/git.py3
-rw-r--r--gbp/rpm/lib_rpm.py5
-rw-r--r--gbp/rpm/policy.py134
-rwxr-xr-xgbp/scripts/buildpackage.py217
-rw-r--r--gbp/scripts/buildpackage_rpm.py15
-rwxr-xr-xgbp/scripts/clone.py50
-rw-r--r--gbp/scripts/common/__init__.py7
-rw-r--r--gbp/scripts/common/buildpackage.py12
-rw-r--r--gbp/scripts/common/hook.py33
-rw-r--r--gbp/scripts/common/import_orig.py24
-rw-r--r--gbp/scripts/common/pq.py20
-rwxr-xr-xgbp/scripts/config.py12
-rw-r--r--gbp/scripts/create_remote_repo.py144
-rw-r--r--gbp/scripts/dch.py127
-rw-r--r--gbp/scripts/import_dsc.py305
-rw-r--r--gbp/scripts/import_dscs.py16
-rw-r--r--gbp/scripts/import_orig.py292
-rwxr-xr-xgbp/scripts/import_srpm.py13
-rwxr-xr-xgbp/scripts/pq.py152
-rwxr-xr-xgbp/scripts/pq_rpm.py25
-rwxr-xr-xgbp/scripts/pull.py10
-rw-r--r--gbp/scripts/rpm_ch.py450
-rw-r--r--gbp/scripts/supercommand.py14
-rw-r--r--gbp/tmpfile.py3
-rw-r--r--gbp/tristate.py13
-rw-r--r--packaging/git-buildpackage.spec1
-rw-r--r--requirements.txt7
-rw-r--r--setup.cfg7
-rwxr-xr-x[-rw-r--r--]setup.py51
-rw-r--r--tests/01_test_help.py52
-rw-r--r--tests/02_test_upstream_source_tar_unpack.py19
-rw-r--r--tests/03_test_dch_guess_version.py4
-rw-r--r--tests/04_test_submodules.py25
-rw-r--r--tests/05_test_detection.py2
-rw-r--r--tests/06_test_upstream_source.py3
-rw-r--r--tests/07_test_fastimport.py8
-rw-r--r--tests/08_test_patch.py2
-rw-r--r--tests/09_test_write_tree.py8
-rw-r--r--tests/10_test_get_upstream_tree.py8
-rw-r--r--tests/11_test_dch_main.py54
-rw-r--r--tests/12_test_deb.py61
-rw-r--r--tests/13_test_gbp_pq.py183
-rw-r--r--tests/14_test_gbp_import_dscs.py5
-rw-r--r--tests/15_test_DebianSource.py1
-rw-r--r--tests/16_test_supercommand.py2
-rw-r--r--tests/17_test_dch_guess_documented_commit.py5
-rw-r--r--tests/18_test_Config.py22
-rw-r--r--tests/19_test_gbp_scripts_config.py24
-rw-r--r--tests/21_test_command_wrappers.py15
-rw-r--r--tests/22_test_gbp_buildpackage.py8
-rw-r--r--tests/23_test_dch_extract_bts_cmds.py3
-rw-r--r--tests/24_test_gbp_import_orig.py31
-rw-r--r--tests/25_test_broken_gbp_conf.py58
-rw-r--r--tests/26_test_dch_extract_thanks.py40
-rw-r--r--tests/component/__init__.py30
-rw-r--r--tests/component/deb/__init__.py4
m---------tests/component/deb/data0
-rw-r--r--tests/component/deb/test_buildpackage.py59
-rw-r--r--tests/component/deb/test_clone.py74
-rw-r--r--tests/component/deb/test_import_dsc.py33
-rw-r--r--tests/component/deb/test_import_orig.py192
-rw-r--r--tests/component/rpm/__init__.py6
-rw-r--r--tests/component/rpm/test_buildpackage_rpm.py46
-rw-r--r--tests/component/rpm/test_import_srpm.py6
-rw-r--r--tests/component/rpm/test_pq_rpm.py30
-rw-r--r--tests/component/rpm/test_rpm_ch.py337
-rw-r--r--tests/context.py10
-rw-r--r--tests/doctests/__init__.py0
-rw-r--r--tests/doctests/test_Changelog.py (renamed from tests/test_Changelog.py)23
-rw-r--r--tests/doctests/test_Config.py (renamed from tests/test_Config.py)25
-rw-r--r--tests/doctests/test_Control.py (renamed from tests/test_Control.py)4
-rw-r--r--tests/doctests/test_GitModifier.py (renamed from tests/test_GitModifier.py)6
-rw-r--r--tests/doctests/test_GitRepository.py (renamed from tests/test_GitRepository.py)170
-rw-r--r--tests/doctests/test_GitVfs.py (renamed from tests/test_GitVfs.py)3
-rw-r--r--tests/doctests/test_PristineTar.py (renamed from tests/test_PristineTar.py)50
-rw-r--r--tests/doctests/test_create_remote_repo.py122
-rw-r--r--tests/test_rpm_changelog.py226
-rw-r--r--tests/testutils/__init__.py11
-rw-r--r--tests/testutils/data.py35
-rw-r--r--tests/testutils/debiangittestrepo.py10
-rw-r--r--tests/testutils/gbplogtester.py1
154 files changed, 5829 insertions, 1798 deletions
diff --git a/.gitignore b/.gitignore
index 9c66267..94c9c6e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,8 @@ gbp.egg-info/
nosetests.xml
*~
*.sw?
+\#*#
+.#*
docs/*.1
docs/*.5
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..cfae53b
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,6 @@
+---
+language: python
+python:
+ - "2.7"
+install: "pip install -r requirements.txt"
+script: flake8
diff --git a/HACKING b/HACKING
index 2c542d3..bb90b0c 100644
--- a/HACKING
+++ b/HACKING
@@ -2,7 +2,7 @@ Running the Tests
-----------------
The tests are run via
- python setup.py nosetests
+ make
To also run the component tests, you need to initialize the git submodules once
via:
@@ -17,7 +17,7 @@ Building the API Docs
---------------------
You can build the API docs using
- epydoc -v --config=setup.cfg
+ make apidocs
Contributing Patches
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..5926091
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,21 @@
+all: syntax-check test
+
+test:
+ export GIT_AUTHOR_NAME="Gbp Tests"; \
+ export GIT_AUTHOR_EMAIL=tests@example.com; \
+ export GIT_COMMITTER_NAME=$$GIT_AUTHOR_NAME; \
+ export GIT_COMMITTER_EMAIL=$$GIT_AUTHOR_EMAIL; \
+ PYTHONPATH=. \
+ python setup.py nosetests --with-xcoverage
+
+syntax-check:
+ #flake8 -j1
+
+docs:
+ make -C docs
+
+apidocs:
+ mkdir -p build
+ epydoc -v --config=setup.cfg
+
+.PHONY: docs
diff --git a/README b/README.md
index 9242c07..e5a1540 100644
--- a/README
+++ b/README.md
@@ -3,18 +3,20 @@ Git-buildpackage
This is a bunch of scripts to ease the development of Debian packages with git.
For more documentation on how to use these tools, see the manual online at:
- http://honk.sigxcpu.org/projects/git-buildpackage/manual-html/gbp.html
+ http://honk.sigxcpu.org/projects/git-buildpackage/manual-html/gbp.html
On Debian systems, this can be found in
/usr/share/doc/git-buildpackage/manual-html.
The API documentation of the gbp module can be found at:
- http://honk.sigxcpu.org/projects/git-buildpackage/apidocs/
+ http://honk.sigxcpu.org/projects/git-buildpackage/apidocs
The mailing list is at:
- http://lists.sigxcpu.org/mailman/listinfo/git-buildpackage
- git-buildpackage at lists.sigxcpu.org
+ * http://lists.sigxcpu.org/mailman/listinfo/git-buildpackage
+ * git-buildpackage at lists.sigxcpu.org
See the HACKING document for details on contributing to gbp development.
+
+[![Build Status](https://travis-ci.org/agx/git-buildpackage.svg?branch=master)](https://travis-ci.org/agx/git-buildpackage)
diff --git a/bin/git-pbuilder b/bin/git-pbuilder
index 57644e6..a998456 100755
--- a/bin/git-pbuilder
+++ b/bin/git-pbuilder
@@ -1,12 +1,12 @@
#!/bin/bash
-# $Id: git-pbuilder,v 1.40 2016/01/23 23:59:19 eagle Exp $
+# $Id: git-pbuilder,v 1.42 2016/08/13 21:21:07 eagle Exp $
#
-# git-pbuilder -- Wrapper around pbuilder for gbp buildpackage
+# Wrapper around pbuilder for gbp buildpackage
#
# Note that this script requires bash, not a POSIX shell, because it uses bash
-# arrays to handle GIT_PBUILDER_OPTIONS. It's otherwise quite difficult to
-# get the contents of that environment variable to undergo the correct amount
-# of shell expansion.
+# arrays to handle GIT_PBUILDER_OPTIONS and GIT_PBUILDER_PDEBUILDOPTIONS.
+# It's otherwise quite difficult to get the contents of that environment
+# variable to undergo the correct amount of shell expansion.
#
# Written by Russ Allbery <eagle@eyrie.org>
# Based on the example in the git-buildpackage documentation
@@ -78,7 +78,7 @@ if expr "$DIST" : '.*-backports$' >/dev/null; then
# -backports. Backports was incorporated into the main mirrors as of
# wheezy.
case $DIST in
- squeeze|oldstable)
+ squeeze)
BACKPORTS='http://backports.debian.org/debian-backports'
;;
*)
@@ -104,8 +104,10 @@ if [ ! -x /usr/sbin/"$BUILDER" ]; then
fi
# Default options come from the environment. Use eval to parse
-# GIT_PBUILDER_OPTIONS into an array since some arguments may have quoting.
+# GIT_PBUILDER_OPTIONS and GIT_PBUILDER_PDEBUILDOPTIONS into arrays, since
+# some arguments may have quoting.
eval "OPTIONS=( $GIT_PBUILDER_OPTIONS )"
+eval "PDEBUILDOPTS=( $GIT_PBUILDER_PDEBUILDOPTIONS )"
OUTPUT_DIR="${GIT_PBUILDER_OUTPUT_DIR:-../}"
# How we handle options depends on what type of builder we're using. Ignore
@@ -325,10 +327,10 @@ done
# seems to pass everything through properly.
if [ no = "$GIT_PBUILDER_AUTOCONF" ] ; then
pdebuild --pbuilder "$BUILDER" --debbuildopts "$DEBBUILDOPTS" \
- -- "${OPTIONS[@]}"
+ "${PDEBUILDOPTS[@]}" -- "${OPTIONS[@]}"
else
pdebuild --buildresult "$OUTPUT_DIR" --pbuilder "$BUILDER" \
- --debbuildopts "$DEBBUILDOPTS" -- "${OPTIONS[@]}"
+ --debbuildopts "$DEBBUILDOPTS" "${PDEBUILDOPTS[@]}" -- "${OPTIONS[@]}"
fi
status="$?"
if [ -n "`ls ../*_source.changes`" ] && [ true != "$source_only" ] ; then
@@ -429,9 +431,8 @@ B<--othermirror> parameter to the builder:
deb http://backports.debian.org/debian-backports $DIST main
The first will be used for most distributions, and the second for
-C<squeeze-backports> or C<oldstable-backports>. If the distribution ends in
-C<-lts>, the following will be added as an B<--othermirror> parameter to the
-builder:
+C<squeeze-backports>. If the distribution ends in C<-lts>, the following will
+be added as an B<--othermirror> parameter to the builder:
deb http://ftp.debian.org/debian $DIST main
@@ -499,6 +500,13 @@ Where to put the result of the build. The default is C<..> (the parent
directory). This setting is ignored if GIT_PBUILDER_AUTOCONF is set to
C<no>.
+=item GIT_PBUILDER_PDEBUILDOPTIONS
+
+Add additional options for B<pdebuild> itself (such as
+B<--use-pdebuild-internal>). The contents of this variable will undergo
+shell expansion, so any arguments containing shell metacharacters or
+whitespace need to be quoted in the value of the environment variable.
+
=item PBUILDER_BASE
Set this environment variable to change the default location for the
diff --git a/debian/changelog b/debian/changelog
index fcc9044..c99ccaa 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,10 +1,261 @@
-git-buildpackage (0.7.5~bpo8+1) jessie-backports; urgency=medium
+git-buildpackage (0.8.7~bpo8+1) jessie-backports; urgency=medium
* Rebuild for jessie-backports (Closes: #826344).
- * [e29cd4d] Opencode bash completion installation since the
- dh_bash-completion in Jessie still puts files to /etc
- -- Guido Günther <agx@sigxcpu.org> Wed, 29 Jun 2016 16:14:16 +0200
+ -- Guido Günther <agx@sigxcpu.org> Fri, 09 Dec 2016 09:47:19 +0100
+
+git-buildpackage (0.8.7) unstable; urgency=medium
+
+ [ Guido Günther ]
+ * [924f809] Build-depend on libdistro-info-perl.
+ This silences the testsuite and unbreaks the build on Ubuntu
+ (Closes: #842960)
+ * [36b8a58] rpm: don't warn about deprecated $repo/.gbp.conf.
+ People use it a lot with rpm based tools so don't warn there until we
+ clearly suggested a better location.
+ * [3c498e1] docs: Don't suggest deprecated section names in examples
+ * [42657fc] docs: Rework "upstream uses git" section
+ * [ced46db] tests: Move doctests to subdir
+ * [ea5775a] commands: allow to fall back to error reason if stderr is empty.
+ Use this in PristineTar and SrcRpmFile to give better error messages if
+ the command doesn't even get to print to stderr (i.e. missing on disk).
+ (Closes: #842592)
+ * [4cacaeb] Avoid printing deprecation twice. Some tools reparse the
+ config. We don't want another deprecation in this case.
+ * [039a286] Avoid deprecation outside of Debian package repositories. E.g.
+ ~ might have a .gbp.conf for the user and might be git managed.
+ * [acf7a73] Avoid deprecation on bash completion
+ * [6f75d7c] Fix new flake8 errors. (Closes: #844932)
+ * [420e299] DebianGitRepository: Handle dot escaping as specified in DEP-14
+ (Closes: #843840)
+ * [d360a6d] DebianGitRepository: simplify version mangling '%' is not valid
+ in a Debian version number and we only want single character replacements
+ for now.
+ * [7ed5e2b] DebianGitRepository: Unmangle version. When mapping from a git
+ tag to a Debian version unamngle it.
+ * [0b317ee] docs: Use version mangling with care
+ * [c96a5b4] docs: Recommend DEP-14
+ * [9cb3966] examples/gbp-posttag-push: allow to upload packages too after
+ pushing all the git data to the remote end. Making one more custom
+ packaging script obsolete.
+
+ [ Jonas Meurer ]
+ * [dd5c3bc] Add version mangling.
+ This allows to replace characters in upstream version numbers. I.e.
+ replace '-' by '.'. (Closes: #842638)
+
+ -- Guido Günther <agx@sigxcpu.org> Mon, 28 Nov 2016 08:39:35 +0100
+
+git-buildpackage (0.8.6) unstable; urgency=medium
+
+ * [a35d7d6] buildpackage: handle <vendor>/master
+ * [12fda23] create-remote-repo: print proper error message on missing
+ remote-configs instead of printing the exception to the console.
+ * [e917d3a] config: Turn dict of config files into a list so we get a fixed
+ order with all Python versions
+ * [c092d73] config: warn on deprecated $REPO/.gbp.conf location. The file
+ is deprecated at least since 2012 but we never warned about it. Warning
+ can be disabled via GBP_DISABLE_GBP_CONF_DEPRECTATION.
+ * [507ae50] import-orig: Document --rollback option
+ * [eb3be92] import-orig: Give some context on --merge-mode=replace option
+
+ -- Guido Günther <agx@sigxcpu.org> Sun, 23 Oct 2016 17:16:23 +0200
+
+git-buildpackage (0.8.5) unstable; urgency=medium
+
+ [ Guido Günther ]
+ * Fixes:
+ * [7c964ea] buildpackage: add back export-dir options
+ (Closes: #839581)
+
+ * Improvements:
+ * [9817e89] posttag-push: Print branches we push to
+
+ * Cleanups:
+ * [a5a8a1c] pq: remove redundancies in --pq-from code paths
+ * [59dce12] pq: introduce pq_on_upstream_tag
+ * [f31bcd2] pq: make TestFromTAG tests silent
+ * [c1ab85a] test_pq_rpm: flake8 clean
+ * [86068d4] test_pq_rpm.py: don't spew on stderr
+ * [46787e3] test_buildpackage_rpm.py: flake8 clean
+ * [f96c8e1] tests: capture stderr in gbp rpm-ch component tests - reduces
+ spurious output
+ * [e4c893d] tests: capture stderr in gbp import_srpm component tests -
+ reduces spurious output
+ * [43beb38] GitRepository.archive: use _git_inout instead of the
+ deprecated _git_getoutput that spews to stderr This silences a spurious
+ output to stderr in test_buildpackage_rpm
+ * [55e8c8f] GitRepository.list_submodules: use _git_inout and check exit
+ status.
+ * [53f9f40] test_buildpackage_rpm: check that we fail subtarball
+ generation correctly
+ * [f87c21c] tests/buildpackage: test --git-export-dir
+
+ [ Linn Crosetto ]
+ * [c1b32fa] dch: avoid adding section in snapshot mode if distribution is
+ UNRELEASED. (Closes: #838714)
+
+ -- Guido Günther <agx@sigxcpu.org> Mon, 10 Oct 2016 18:06:32 +0200
+
+git-buildpackage (0.8.4) unstable; urgency=medium
+
+ [ Maximiliano Curia ]
+ * [e615c65] pq: Handle unmerged debian branches. This allows one to import
+ the patch-queue branch onto the upstream tag.
+ (Closes: #834726)
+ * [f6433f9] pq: Ensure we are working in the right git directory.
+
+ [ Guido Günther ]
+ * [6909bb1] Unbreak gbp-pq manpage generation
+ * flake8 cleaniness
+ * [7a7068d] create_remote_repo: allow one to create non bare repositories
+ (Closes: #837158)
+ * [98cea5f] import_orig: Use gbp.scripts.common.hook
+ * [5ff1be8] test_rpm_ch: use GIT_AUTHOR_* env vars.
+ * [98ea945] flake8: Ignore rpm related files for now. This makes it easier
+ to integrate changes from git-buildpackage-rpm.
+ * [3ded91b] Move doc generation and test invocation to separate Makefile
+ * [2845359] Switch from pychecker to flake8. The later is maintained and
+ has more checks Use '-j1' for now since otherwise we need /dev/shm access
+ which fails in a pbuilder chroot with EPERM.
+ * [264090e] Rename README to README.md to get Markdown formatting
+ * [2809284] dch: document which options can't be set via gbp.conf
+ * [2122d8b] dch: document --security
+ * [ef7ca4a] config: allow one to specify short options
+ * [3feba49] dch: make urgency a config file option so it can be set via
+ gbp.conf (Closes: #837680)
+ * [fdcee06] dch: add missing short opts to manpage
+ * [dbb9623] Unbreak patch delta output broken by "pq: Ensure we are working
+ in the right git directory"
+ * [3e26d02] Vcs-Git: use https transport
+ * [74c7bc0] autopkgtest: Skip build if setuptools is not available
+ * [6ec588a] pq: restrict choices of pq-from to 'DEBIAN' and 'TAG'
+
+ [ Markus Lehtonen ]
+ * [c6b32c8] Command: redirect stdout/stderr to sys.stdout/stderr.
+ * [245b443] tests: capture stderr in buildpackage-rpm unit tests.
+ Reduces spurious output from rpmbuild. (Closes: #829690)
+
+ -- Guido Günther <agx@sigxcpu.org> Tue, 27 Sep 2016 18:56:12 +0200
+
+git-buildpackage (0.8.3) unstable; urgency=medium
+
+ * Upload to unstable
+ * [51620e9] import-orig: export version information to postimport hook
+ (Closes: #833429)
+ * [086ff78] Drop dependencies on sp and jade.
+ Thanks to Neil Roeth
+ * [bf46e26] Update to git-pbuilder 1.42
+ * [99e7703] import_orig: Properly abort merge on rollbacks.
+ If merging fails we need to call "git merge --abort"
+ * [a868977] tests: match env vars values in hook checks too
+ * [fae6456] tests: only check gbp related env vars in hooks.
+ This avoids test failures when env vars contain newlines
+
+ -- Guido Günther <agx@sigxcpu.org> Fri, 26 Aug 2016 14:18:17 +0200
+
+git-buildpackage (0.8.2) experimental; urgency=medium
+
+ * [1f0013c] import-orig: Switch to Debian branch before merging in changes
+ otherwise we'd always merge into the current working copy
+ (Closes: #832016)
+ * [a52aff5] download_orig: unlink file before raising the exception
+ otherwise we would not clean up
+ * [3d261da] import_orig: Only try rollbacks if necessary.
+ * [61e659d] pq: strip comments with multiple leading whitespace. Really
+ Closes: #825536
+ * [68940fb] pq: Retry patch with whitespace fixup on failure. This helps
+ patches with CRLF line endings and we don't lose anything since we'd
+ failed otherwise anyway. (Closes: #833066)
+ * [e2671b9] docs: fix --postclone and --hooks options of git-clone.
+ Thanks to IOhannes m zmoelnig for pointing this out
+ * [e68a0a1] docs: Document --postclone hook behaviour with debian/gbp.conf
+ Thanks to IOhannes m zmoelnig for pointing this out
+ (Closes: #833143)
+
+ -- Guido Günther <agx@sigxcpu.org> Tue, 02 Aug 2016 19:26:33 +0200
+
+git-buildpackage (0.8.1) experimental; urgency=medium
+
+ [ Guido Günther ]
+ * [3a5a497] import_dsc: Use the same patch options as dpkg-source for 1.0
+ packages (except for creating backup files) (Closes: #670099)
+ * [8d84fd3] dch: Match 'thanks' case insensitive (Closes: #746753)
+ * [29f16ca] Unbreak autopkgtest by setting git user and email
+ * [2b33349] import_orig: Drop duplicate log message when rolling back a branch
+ * [7ba43f6] Improve check for empty_repository.
+ Based on a patch by Carlos Maddela (Closes: #791472)
+ * [55fd73a] Remove outdated ref on git-import-dsc
+ * [1fae819] Use proper test fixtures.
+ (Closes: #723888)
+ * [95c8c53] clone: add postclone hook (Closes: #812816, #812815)
+ * [491adcf] clone: document missing directory option
+
+ [ Michael Elovskikh ]
+ * [a6311e6] Added option `never` to dch `--spawn-editor` choices
+
+ -- Guido Günther <agx@sigxcpu.org> Fri, 08 Jul 2016 15:44:28 +0200
+
+git-buildpackage (0.8.0) experimental; urgency=medium
+
+ [ Markus Lehtonen ]
+ * [c5cfb5e] Introduce gbp-rpm-ch.
+ Initial version of gbp rpm-ch command, a tool for maintaining
+ RPM changelogs. The new command supports %changelog section inside spec
+ files as well as separate changelog files ("OBS style"). (Closes: #808027)
+
+ [ Guido Günther ]
+ * [b4b7f9f] clone: Be a bit more verbose and let the user know that we
+ started cloning
+ * [1f58d21] PatchSeries: Strip comment from patch names (Closes: #825536)
+ * [1989c32] pq: Report number of imported patches
+ * [dcb145f] Use existing option as example in gbp-buildpackage manpage.
+ Thanks to Nicolas Braud-Santoni (Closes: #828703)
+ * [f1c64e2] manpages: add examples for gbp {clone,import-dsc}
+ * [83dfa67] GitRepository: Deleting a non-existing branch should not throw
+ an error
+ * [ba7b087] docs: Clarify some gbp pq options
+ * [ebc6b91] import_orig: Recover from import errors by winding back branches
+ and tags to their pre-error states (Closes: #828838)
+ * [4964234] dch: Log version number when preparing a snapshot
+ (Closes: #829025)
+ * [7a6641a] import-dsc: Don't fail on 1.0 non-native packages without a
+ Debian version
+ (Closes: #829070)
+ * [8c4460c] Actually install gbp-rpm-ch and unbreak manpage generation
+ * [d92b656] tests: Omit build dependend variables from epydocs
+ based on a patch from Sascha Steinbiss (Closes: #827546)
+ * [d977377] Set date in manpages based on last changelog entry
+ for reproducibility. This can be reverted once ocbook2man is fixed
+ (#800797).
+ Thanks to Sascha Steinbiss for the patch
+ * [53f37eb] import-orig: Make default import message more gbp-dch friendly.
+ * [312c9b9] Use imperative for git messages as suggested in gh:#26.
+ * [2bc3801] import_dsc: don't assume component tarballs have the correct name.
+ (Closes: #829458)
+ * [bc3805c] import_orig: add support for importing additional tarballs.
+ We expect the additional tarballs to be located next to the orig tarball
+ and to be already named properly. (Closes: #561071)
+ * [870c901] Docs: Clarify on possible key names and priorities in gbp.conf
+ * [7a521d4] Handle Ctrl-C more gracefully
+ * [b540c98] additional tarballs: allow one to configure components via gbp.conf
+ * [1d4d4a2] config: Allow one to give list values in plural form
+ * [700e164] config: Properly abort on config file parsing errors
+ instead of printing an exception on the console
+ * [3b4912d] config: always use 'gbp <cmd>' in help output.
+ The {git,gbp}- versions went away ages ago
+ * [f545010] Give more instructions when config is unparseable
+ and make return codes and messages consistent.
+ (Closes: #733640)
+ * [a0ed81b] Require python 2.7. It's the default up to Wheezy
+ (Closes: #685031)
+
+ [ Otto Kekäläinen ]
+ * [af16f59] Fix simple spelling errors in comments and strings
+ * [f28a26b] Fix spelling of existant->existent in function names, strings
+ and comments
+
+ -- Guido Günther <agx@sigxcpu.org> Mon, 04 Jul 2016 21:47:42 +0200
git-buildpackage (0.7.5) unstable; urgency=medium
diff --git a/debian/control b/debian/control
index ffc9f19..c903ceb 100644
--- a/debian/control
+++ b/debian/control
@@ -3,15 +3,15 @@ Section: vcs
Priority: optional
Maintainer: Guido Günther <agx@sigxcpu.org>
Build-Depends:
- bash-completion (>= 1:2.1-4~),
+ bash-completion (>= 1:2.1-4.2~),
debhelper (>= 9~),
dh-python,
docbook-utils,
+ flake8,
gtk-doc-tools,
- jade,
+ libdistro-info-perl,
perl,
- pychecker,
- python (>> 2.6.6-3~),
+ python (>> 2.7.3),
python-coverage,
python-dateutil,
python-epydoc,
@@ -32,11 +32,11 @@ Build-Depends:
rpm,
unzip,
zipmerge
-Standards-Version: 3.9.6
-Vcs-Git: git://honk.sigxcpu.org/git/git-buildpackage.git
+Standards-Version: 3.9.8
+Vcs-Git: https://git.sigxcpu.org/cgit/git-buildpackage/
Vcs-Browser: https://git.sigxcpu.org/cgit/git-buildpackage/
Homepage: https://honk.sigxcpu.org/piki/projects/git-buildpackage/
-X-Python-Version: >= 2.6
+X-Python-Version: >= 2.7
Package: git-buildpackage
Architecture: all
diff --git a/debian/docs b/debian/docs
index ce06068..00356a6 100644
--- a/debian/docs
+++ b/debian/docs
@@ -1,3 +1,3 @@
-README
+README.md
docs/manual-html/
build/apidocs/
diff --git a/debian/gbp.completion b/debian/gbp.completion
index 546a654..3cbf64b 100644
--- a/debian/gbp.completion
+++ b/debian/gbp.completion
@@ -23,6 +23,7 @@ _gbp_tags ()
_gbp_options ()
{
+ GBP_DISABLE_GBP_CONF_DEPRECTATION=true \
GBP_DISABLE_SECTION_DEPRECTATION=true \
gbp "${1}" --help | sed -ne 's/^ \+\(\(\-[a-z]\), \)\?\(\-\-[a-z\-]\+\=\?\).*/\2 \3/p'
}
diff --git a/debian/gbp.conf b/debian/gbp.conf
index 4a5c645..2eab728 100644
--- a/debian/gbp.conf
+++ b/debian/gbp.conf
@@ -1,3 +1,2 @@
[DEFAULT]
debian-branch = debian/jessie-backports
-dist = jessie
diff --git a/debian/git-buildpackage-rpm.install b/debian/git-buildpackage-rpm.install
index 54d7f95..437bf3a 100644
--- a/debian/git-buildpackage-rpm.install
+++ b/debian/git-buildpackage-rpm.install
@@ -3,3 +3,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
+usr/lib/python2.7/dist-packages/gbp/scripts/rpm_ch.py
diff --git a/debian/git-buildpackage-rpm.manpages b/debian/git-buildpackage-rpm.manpages
index fcc58e6..183ab2f 100644
--- a/debian/git-buildpackage-rpm.manpages
+++ b/debian/git-buildpackage-rpm.manpages
@@ -1,3 +1,4 @@
docs/gbp-import-srpm.1
docs/gbp-pq-rpm.1
docs/gbp-buildpackage-rpm.1
+docs/gbp-rpm-ch.1
diff --git a/debian/git-buildpackage.postrm b/debian/git-buildpackage.postrm
index e777126..67b835a 100644
--- a/debian/git-buildpackage.postrm
+++ b/debian/git-buildpackage.postrm
@@ -1,5 +1,5 @@
#!/bin/sh
-# postrm script for libvirt-daemon-system
+# postrm script for git-buildpackage
#
# see: dh_installdeb(1)
diff --git a/debian/git-buildpackage.preinst b/debian/git-buildpackage.preinst
index 6e0f06f..a3f6b2b 100644
--- a/debian/git-buildpackage.preinst
+++ b/debian/git-buildpackage.preinst
@@ -1,5 +1,5 @@
#!/bin/sh
-# preinst script for libvirt-daemon-system
+# preinst script for git-buildpackage
#
# see: dh_installdeb(1)
diff --git a/debian/git-buildpackage.zsh-completion b/debian/git-buildpackage.zsh-completion
index 8c7d98d..7f0b50d 100644
--- a/debian/git-buildpackage.zsh-completion
+++ b/debian/git-buildpackage.zsh-completion
@@ -76,7 +76,7 @@ _gbp-buildpackage() {
__gbp_tag_format_options git-
__gbp_tag_sign_options git-
_arguments \
- '--git-ignore-new[build with uncommited changes in the source tree]' \
+ '--git-ignore-new[build with uncommitted changes in the source tree]' \
'--git-no-ignore-new[negates --git-ignore-new]' \
'--git-tag[create a tag after a successful build]' \
'--git-tag-only[do not build, only tag and run the posttag hook]' \
@@ -157,7 +157,7 @@ _gbp-dch () {
'--git-author[Use git name configuration for changelog signature]' \
'(--multimaint-merge --no-multimaint-merge)--multimaint-merge[Merge commits by maintainer]' \
'(--multimaint-merge --no-multimaint-merge)--multimaint-merge[Do not merge commits by maintainer]' \
- '--spawn-editor=[Spawn an editor]:when:(always snapshot release)' \
+ '--spawn-editor=[Spawn an editor]:when:(always never snapshot release)' \
'--commit-msg=[Commit message format string]' \
'--commit[Commit the generated changelog]' \
'*:Paths:_files -/'
@@ -321,7 +321,7 @@ _gbp-buildpackage() {
__gbp_tag_format_options git-
__gbp_tag_sign_options git-
_arguments \
- '--git-ignore-new[build with uncommited changes in the source tree]' \
+ '--git-ignore-new[build with uncommitted changes in the source tree]' \
'--git-no-ignore-new[negates --git-ignore-new]' \
'--git-tag[create a tag after a successful build]' \
'--git-tag-only[do not build, only tag and run the posttag hook]' \
@@ -402,7 +402,7 @@ _gbp-dch () {
'--git-author[Use git name configuration for changelog signature]' \
'(--multimaint-merge --no-multimaint-merge)--multimaint-merge[Merge commits by maintainer]' \
'(--multimaint-merge --no-multimaint-merge)--multimaint-merge[Do not merge commits by maintainer]' \
- '--spawn-editor=[Spawn an editor]:when:(always snapshot release)' \
+ '--spawn-editor=[Spawn an editor]:when:(always never snapshot release)' \
'--commit-msg=[Commit message format string]' \
'--commit[Commit the generated changelog]' \
'*:Paths:_files -/'
diff --git a/debian/rules b/debian/rules
index 5e15385..00702d4 100755
--- a/debian/rules
+++ b/debian/rules
@@ -10,41 +10,27 @@ EXAMPLE_SCRIPTS=\
DEB_COMPRESS_EXCLUDE=$(EXAMPLE_SCRIPTS)
ZSH_COMPDIR = /usr/share/zsh/vendor-completions/
-BASH_COMPDIR = /usr/share/bash-completion/completions
PYCHECKER_ARGS=-boptparse --no-override --no-shadowbuiltin
%:
- dh $@ --with python2
+ dh $@ --with python2 --buildsystem=python_distutils
override_dh_auto_test:
ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
dh_auto_test
- export GIT_AUTHOR_NAME="Gbp Tests"; \
- export GIT_AUTHOR_EMAIL=tests@example.com; \
- export GIT_COMMITTER_NAME=$$GIT_AUTHOR_NAME; \
- export GIT_COMMITTER_EMAIL=$$GIT_AUTHOR_EMAIL; \
- PYTHONPATH=. \
- python setup.py nosetests --with-xcoverage
-
- PYTHONPATH=. pychecker $(PYCHECKER_ARGS) -q \
- gbp gbp.scripts gbp.git gbp.deb
+ make
else
@echo "Checks disabled via DEB_BUILD_OPTIONS"
endif
override_dh_auto_build:
dh_auto_build
- epydoc -v --config=setup.cfg
- make -C docs/
+ make apidocs docs
override_dh_auto_install:
dh_auto_install
- mkdir -p debian/git-buildpackage/$(BASH_COMPDIR)
-
- install -m644 debian/gbp.completion \
- debian/git-buildpackage/$(BASH_COMPDIR)/gbp
-
+ dh_bash-completion
mkdir -p debian/git-buildpackage/$(ZSH_COMPDIR)
install -m644 debian/git-buildpackage.zsh-completion \
debian/git-buildpackage/$(ZSH_COMPDIR)/_gbp
diff --git a/debian/tests/smoke-rpm b/debian/tests/smoke-rpm
index 41b8828..75b4798 100755
--- a/debian/tests/smoke-rpm
+++ b/debian/tests/smoke-rpm
@@ -4,6 +4,8 @@ set -e
set -x
git init .
+git config user.email "you@example.com"
+git config user.name "Doesnot Matter"
git add .
git commit -m"Smoketest" -a
cat <<EOF >> ~/.rpmmacros
@@ -11,8 +13,10 @@ cat <<EOF >> ~/.rpmmacros
%python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; import sys; sys.stdout.write(get_python_lib(1).replace('dist-', 'site-'))")
EOF
-# Build an RPM of ourselfes
-gbp buildpackage-rpm --git-packaging-dir=packaging/ -bb --nodeps
-
-rm -r .git ~/.rpmmacros
+gbp buildpackage-rpm --help
+# Build an RPM of ourselfes if build-deps are available
+if python -c "import setuptools"; then
+ gbp buildpackage-rpm --git-packaging-dir=packaging/ -bb --nodeps
+ rm -r .git ~/.rpmmacros
+fi
diff --git a/docs/Makefile b/docs/Makefile
index 581e0a1..e171ccb 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -13,8 +13,9 @@ MAN1S = \
gbp-pq \
gbp-pull \
gbp-buildpackage-rpm \
- gbp-import-srpm \
- gbp-pq-rpm \
+ gbp-import-srpm \
+ gbp-pq-rpm \
+ gbp-rpm-ch \
$(NULL)
MAN5S = gbp.conf
@@ -25,8 +26,9 @@ POD_MANPAGES=git-pbuilder.1
MANPAGES=$(SGML_MANPAGES) $(POD_MANPAGES)
VERSION_ENT=version.ent
GBP_VERSION=../gbp/version.py
-DEB_VERSION=$(shell sed -ne 's/^gbp_version="\([.a-z0-9~-]\+\)"/\1/p' $(GBP_VERSION))
+DEB_VERSION=$(shell sed -ne 's/^gbp_version\s\+=\s\+"\([.a-z0-9~-]\+\)"/\1/p' $(GBP_VERSION))
CHANGELOG=../debian/changelog
+MAN_DATE=$(shell dpkg-parsechangelog -l ../debian/changelog -SDate | TZ=UTC LC_ALL=C date -f- +'%d %B %Y')
# Stuff to build docs outside Debian
HAVE_SGML2X ?= 1
@@ -34,7 +36,7 @@ GTK_DOC_CATALOG_FILE ?= /usr/share/sgml/gtk-doc/gtk-doc.cat
all: $(MANUAL) $(MANPAGES)
-$(MANUAL): manual.sgml chapters/*.sgml manpages/*.sgml
+$(MANUAL): manual.sgml chapters/*.sgml manpages/*.sgml common.ent $(VERSION_ENT)
ifeq ($(HAVE_SGML2X),1)
docbook-2-html -s local $<
else
@@ -49,12 +51,14 @@ BUILD_MAN_XREF_PAGES=$(patsubst %,buildxref/%,$(SGML_MANPAGES))
buildxref/%.1 buildxref/%.5: man.%.sgml manpages/%.sgml
docbook2man -o buildxref $<
+ sed -i -r "s/\"[^\"]+\"/\"$(MAN_DATE)\"/3" $@
manpage.refs: $(BUILD_MAN_XREF_PAGES)
cp buildxref/$@ $@
%.1 %.5: manpage.refs
docbook2man -o . man.$*.sgml
+ sed -i -r "s/\"[^\"]+\"/\"$(MAN_DATE)\"/3" $@
git-pbuilder.1: ../bin/git-pbuilder
pod2man $< $@
diff --git a/docs/chapters/building.sgml b/docs/chapters/building.sgml
index c7ac94b..a028a4c 100644
--- a/docs/chapters/building.sgml
+++ b/docs/chapters/building.sgml
@@ -61,7 +61,7 @@
<para>If you want to default to build in a separate build area, you can
specify the directory to use in the <filename>gbp.conf</filename> file.
<programlisting>
-[git-buildpackage]
+[buildpackage]
# use a build area relative to the git repository
export-dir=../build-area
# to use the same build area for all packages use an absolute path:
@@ -174,7 +174,7 @@ echo "done."
by specifying the export directory:
</para>
<programlisting>
-[git-buildpackage]
+[buildpackage]
# use a build area relative to the git repository
export-dir = ../build-area
# disable the since the sources are being exported first
diff --git a/docs/chapters/import.sgml b/docs/chapters/import.sgml
index ca2f927..b86ca84 100644
--- a/docs/chapters/import.sgml
+++ b/docs/chapters/import.sgml
@@ -89,12 +89,41 @@ by version number.
<option>--pristine-tar</option> option. This is recommended.
</para>
<para>To customize the commit message used by &gbp-import-orig;, use
- the <option>--import-msg</option> option. This string is a standard
- Python format string, into which the
- <replaceable>version</replaceable> variable is interpolated. (i.e.,
- use <replaceable>%(version)s</replaceable> in your message to get
- the imported upstream version).
+ the <option>--import-msg</option> option. This string is a
+ &pyformat;, into which the
+ <replaceable>version</replaceable> variable is
+ interpolated. (i.e., use <replaceable>%(version)s</replaceable> in
+ your message to get the imported upstream version).
</para>
+
+ <sect2>
+ <title>Recovering from errors</title>
+ <para>In case of an error &gbp-import-orig; will by default
+ rollback (undo) all changes it has done to the repository so far:
+ </para>
+ <programlisting>
+ $ &gbp; import-orig --verbose --filter='CVS/*' --filter='.bzr/*' --filter='.hg/*' --filter='.svn/*' --upstream-version=1.9 ../gif2apng-1.9.tar.gz
+ gbp:info: Importing '../gif2apng-1.9.tar.gz' to branch 'upstream' (filtering out ["'CVS/*'", "'.bzr/*'", "'.hg/*'", "'.svn/*'"])...
+ gbp:info: Source package is gif2apng
+ gbp:info: Upstream version is 1.9
+ gbp:info: Merging to 'master'
+ gbp:error: Automatic merge failed.
+ gbp:error: Error detected, Will roll back changes.
+ gbp:info: Rolling back branch upstream by resetting it to a6733c1f1e190ac0ed4774abc3466e9986a6df5e
+ gbp:info: Rolling back branch pristine-tar by resetting it to 0ee24ac614c920e30af82d602882c2ee841c88e5
+ gbp:info: Rolling back tag upstream/1.9 by deleting it
+ gbp:info: Rolling back branch master by resetting it to ce99782336e83a56e8e579b3cdadf93b0c19e1a8
+ gbp:info: Rolling back failed merge of upstream/1.9
+ gbp:error: Rolled back changes after import error.
+ </programlisting>
+ <para>
+ In this case the import failed due to a merge conflict. Other
+ reasons are running out of disk space, problems when generating
+ the pristine-tar delta. If you don't want &gbp-import-orig; to
+ undo changes made to the repository use
+ the <option>--no-rollback</option>.
+ </para>
+ </sect2>
</sect1>
<sect1 id="gbp.import.convert">
@@ -197,40 +226,95 @@ EOF
<sect1 id="gbp.import.upstream-git">
<title>When upstream uses Git</title>
<para>
- If upstream already uses git for packaging, there are several ways to handle packaging. Two of them will
- be described in a bit detail here:
+ If upstream uses &git; for development (and you don't want to
+ ignore that fact entirely), there are at least three ways to
+ handle packaging. The first one uses &git; exclusively and
+ creates the upstream tarballs from the upstream tag while the
+ second one still uses upstream tarballs but links your packaging
+ &git; history with upstreams &git; history. The third one also
+ uses a tarballs but does not link to the upstream history.
</para>
<sect2 id="gbp.import.upstream.git.notarball">
<title>No upstream tarballs</title>
- <para>If upstream doesn't build upstream tarballs, or you don't care about them, the simplest
- way is to clone upstream's repository and create a separate packaging branch in there.
+ <para>If upstream doesn't build upstream tarballs, or you
+ don't care about them, the simplest way is to clone
+ upstream's repository and create a separate packaging branch
+ in there. You will not need &gbp-import-orig; at all with
+ this workflow. &gbp-buildpackage; will handle creating the
+ upstream tarballs needed the Debian source package for you.
</para>
-
<para>
- In order to help &gbp-buildpackage; to find upstream tags, you need to specify the format
- using the <option>--git-upstream-tag</option> command line option or the the <option>upstream-tag</option>
- configuration variable.
+ For that to work you need to tell &gbp; how the
+ upstream tag format looks. Therefore you either
+ use the <option>--git-upstream-tag</option> command line option
+ or the <option>upstream-tag</option> configuration file
+ variable to specify upstream's tag format.
</para>
<para>
- A common upstream format is to put a <replaceable>v</replaceable> in front of the version number.
- In this case, the configuration option would look like:
+ A common upstream format is to put
+ a <replaceable>v</replaceable> in front of the version
+ number. In this case, the configuration option would look
+ like:
</para>
<programlisting>
-[git-buildpackage]
+[buildpackage]
upstream-tag = v%(version)s
</programlisting>
<para>
- <replaceable>version</replaceable> will be replaced with the upstream version number as read from
- <filename>debian/changelog</filename>.
+ <replaceable>version</replaceable> will be replaced with the
+ upstream version number as determined from
+ <filename>debian/changelog</filename>. The <replaceable>%()s</replaceable>
+ might be familiar from &pyformat;s.
+ </para>
+
+ <para>
+ Some upstreams use other formats though and don't separate
+ numbers by dots but rather by
+ underscore(<replaceable>_</replaceable>),
+ hyphen(<replaceable>-</replaceable>) or anything else. In
+ order to cope with that you can use version mangling of these
+ characters via substitution. The substitution works as
+ follows:
+ </para>
+<programlisting>
+[buildpackage]
+upstream-tag = v%(version%.%_)s
+</programlisting>
+ <para>
+ This means that each occurrence
+ of <replaceable>.</replaceable> will be replaced
+ by <replaceable>_</replaceable> in the upstream version
+ number. For example the upstream
+ version <replaceable>1.2.3</replaceable> as determined from
+ the <filename>debian/changelog</filename> will be looked up
+ as &git; tag <replaceable>v1_2_3</replaceable> by
+ &gbp-buildpackage;.
</para>
+ <para>
+ If you want the substitution to be the <replaceable>%</replaceable> character
+ you have to escape it. E.g. <replaceable>%(version%-%\%)s</replaceable> will replace <replaceable>-</replaceable> with
+ <replaceable>%</replaceable>, transforming <replaceable>1-A.B.C</replaceable> to <replaceable>1%A.B.C</replaceable>.
+ Only a single replacement is supported and it can only replace a single character.
+ <warning>
+ <para>
+ Since some of the possible mangling characters
+ like <replaceable>_</replaceable> and <replaceable>%</replaceable> are also used to denote epochs and tilde revisions
+ these versions can't be reconstructed when mapping from &git; tags back to &debian; versions and will therefore break other tools
+ like &gbp-dch;. So use version mangling with care. It's better to come up with a Debian compatible tag format upstream,
+ see &dep14; for the currently used expansion rules for Debian versions.
+ </para>
+ </warning>
+ </para>
+
<para>If you're using &pristine-tar;, you can make &gbp-buildpackage; commit the generated tarball back to the
pristine-tar branch by using the <option>--git-pristine-tar-commit</option> option. This will make sure
- others building your package can regenerate the tarball you generated for building the &debian; package.
+ others building your package can exactly regenerate the
+ tarball you created when building the &debian; package.
</para>
- <sect3>
+ <sect3>
<title>Step by step</title>
<para>To not make any assumptions about &gbp;'s configuration, the following steps have all options given
in its long versions on the command line. You can add these
@@ -275,7 +359,7 @@ upstream-tag = v%(version)s
</sect2>
<sect2 id="gbp.import.upstream.git.tarball">
- <title>Upstream tarballs</title>
+ <title>Upstream tarballs and linked upstream history</title>
<para>If you want to track upstream's &git; but continue to import the upstream tarballs,
e.g. to make sure the tarball uploaded
to &debian; has the same checksum as upstream's, you can use the <option>--upstream-vcs-tag</option> option
@@ -289,6 +373,35 @@ upstream-tag = v%(version)s
</para>
</sect2>
+ <sect2 id="gbp.import.upstream.git.separate">
+ <title>Upstream tarballs and separate upstream history</title>
+ <para>
+ If you want to have upstream's &git; history available but
+ don't want to link it to your packaging history you can
+ simply keep it as a separate history. E.g. if you already have
+ a &git; repository with your packaging, change into that
+ repository and do:
+<programlisting>
+ &gitcmd; remote add upstream https://upstream.example.com/upstream.git
+ &gitcmd; fetch upstream
+</programlisting>
+ This will pull in upstream's &git; history into your repo but since
+ your packaging commits and upstreams commits have no common
+ parents the two histories will stay nicely separated.
+ Of course you can browse it and cherry-pick from it but
+ any remote repos you push to will not get upstream's history
+ by default unless you push any of upstream's refs.
+ <warning>
+ <para>
+ Since &git; has a single tag namespace pushing
+ changes with <command>git push --tags</command> will
+ push upstream's tags (and therefore it's history) too so
+ be shure to only push dedicated tag names.
+ </para>
+ </warning>
+ </para>
+ </sect2>
+
</sect1>
<sect1 id="gbp.branch.naming">
<title>Branch layout</title>
@@ -298,7 +411,7 @@ upstream-tag = v%(version)s
</para>
<para>
This layout is simple to get started but falls short if one needs to maintain several versions of
- the package at the same time. Therefore the following layout is recommended:
+ the package at the same time. Therefore the following the &dep14; layout is recommended:
</para>
<variablelist>
@@ -316,17 +429,17 @@ upstream-tag = v%(version)s
</varlistentry>
<varlistentry>
<term>
- upstream/&lt;release&gt;
+ upstream/latest
</term>
<listitem>
<para>
- the upstream sources for a release matching one of the above
+ the latest upstream sources.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
- dfsg/&lt;release&gt;
+ dfsg/latest
</term>
<listitem>
<para>
diff --git a/docs/chapters/intro.sgml b/docs/chapters/intro.sgml
index 8a6ee39..b8048f9 100644
--- a/docs/chapters/intro.sgml
+++ b/docs/chapters/intro.sgml
@@ -87,7 +87,7 @@
you have to use <command>git push</command> in order to publish your
changes to remote repositories like <ulink
url="http://git.debian.org/">git.debian.org</ulink>; this can also be
- automatized with &gbp-buildpackage;'s <option>post-tag</option>
+ automated with &gbp-buildpackage;'s <option>post-tag</option>
hook.</para>
</sect1>
diff --git a/docs/common.ent b/docs/common.ent
index 6a25178..0d11807 100644
--- a/docs/common.ent
+++ b/docs/common.ent
@@ -33,6 +33,7 @@
<!ENTITY gbp-buildpackage-rpm "<command>gbp&nbsp;buildpackage-rpm</command>">
<!ENTITY gbp-import-srpm "<command>gbp&nbsp;import-srpm</command>">
<!ENTITY gbp-pq-rpm "<command>gbp&nbsp;pq-rpm</command>">
+ <!ENTITY gbp-rpm-ch "<command>gbp rpm-ch</command>">
<!ENTITY rpmbuild "<command>rpmbuild</command>">
<!ENTITY gbp-builder-mock "<command>gbp-builder-mock</command>">
<!ENTITY wget "<command>wget</command>">
@@ -55,3 +56,6 @@
<!ENTITY mock "<productname>mock</productname>">
<!ENTITY gnu "<acronym>GNU</acronym>">
<!ENTITY gpl "&gnu; <acronym>GPL</acronym>">
+
+ <!ENTITY pyformat "<ulink url='https://docs.python.org/2/library/stdtypes.html#string-formatting'><citetitle>Python format string</citetitle></ulink>">
+ <!ENTITY dep14 "<ulink url='http://dep.debian.net/deps/dep14/'><citetitle>DEP-14</citetitle></ulink>"> \ No newline at end of file
diff --git a/docs/man.gbp-rpm-ch.sgml b/docs/man.gbp-rpm-ch.sgml
new file mode 100644
index 0000000..369684d
--- /dev/null
+++ b/docs/man.gbp-rpm-ch.sgml
@@ -0,0 +1,11 @@
+<!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-rpm Manual</title>
+&man.gbp.rpm.ch;
+</reference>
diff --git a/docs/manpages/gbp-buildpackage-rpm.sgml b/docs/manpages/gbp-buildpackage-rpm.sgml
index b7138c8..ac020f8 100644
--- a/docs/manpages/gbp-buildpackage-rpm.sgml
+++ b/docs/manpages/gbp-buildpackage-rpm.sgml
@@ -639,6 +639,7 @@
<para>
<xref linkend="man.gbp.import.srpm"/>,
<xref linkend="man.gbp.pq.rpm"/>,
+ <xref linkend="man.gbp.rpm.ch">,
<citerefentry>
<refentrytitle>rpmbuild</refentrytitle>
<manvolnum>8</manvolnum>
diff --git a/docs/manpages/gbp-buildpackage.sgml b/docs/manpages/gbp-buildpackage.sgml
index 9de8d9f..5f591e9 100644
--- a/docs/manpages/gbp-buildpackage.sgml
+++ b/docs/manpages/gbp-buildpackage.sgml
@@ -52,7 +52,7 @@
<arg><option>--git-tarball-dir=</option><replaceable>DIRECTORY</replaceable></arg>
<arg><option>--git-compression=</option><replaceable>TYPE</replaceable></arg>
<arg><option>--git-compression-level=</option><replaceable>LEVEL</replaceable></arg>
- <arg><option>--git-subtarball=</option><replaceable>SUBTARBALL</replaceable></arg>
+ <arg rep='repeat'><option>--git-component=</option><replaceable>component</replaceable></arg>
<arg><option>--git-export-dir=</option><replaceable>DIRECTORY</replaceable></arg>
<arg><option>--git-export=</option><replaceable>TREEISH</replaceable></arg>
<arg><option>--git-[no-]pristine-tar</option></arg>
@@ -575,20 +575,22 @@
</listitem>
</varlistentry>
<varlistentry>
- <term><option>--git-subtarball=</option><replaceable>SUBTARBALL</replaceable>
+ <term><option>--git-component=</option><replaceable>COMPONENT</replaceable>
</term>
<listitem>
<para>
When generating tarballs create an additional original
- tarball of directory <replaceable>SUBTARBALL</replaceable>
+ tarball of directory <replaceable>COMPONENT</replaceable>
in the source tree. Using additional original tarballs is
- a feature of the 3.0 (quilt) souce format. See
+ a feature of the 3.0 (quilt) source format. See
the <command>dpkg-source</command> manpage for details. Note that the
<replaceable>--git-pristine-tar-commit</replaceable>
- option is currently incompatible with this option. It also can't be
- set via &gbp.conf; since it's considered an experimental feature and
- might change incompatibly.
- </para>
+ option is currently incompatible with this option.
+ </para>
+ <para>
+ This is considered an experimental feature and might
+ change incompatibly.
+ </para>
</listitem>
</varlistentry>
<varlistentry>
@@ -682,7 +684,7 @@
</para>
<programlisting>
[buildpackage]
- debian-dir = debian/sid
+ debian-branch = debian/sid
</programlisting>
</refsect1>
<refsect1>
diff --git a/docs/manpages/gbp-clone.sgml b/docs/manpages/gbp-clone.sgml
index 8c3cbdb..28c6ec0 100644
--- a/docs/manpages/gbp-clone.sgml
+++ b/docs/manpages/gbp-clone.sgml
@@ -28,7 +28,10 @@
<arg><option>--upstream-branch=</option><replaceable>branch_name</replaceable></arg>
<arg><option>--depth=</option><replaceable>depth</replaceable></arg>
<arg><option>--reference=</option><replaceable>repository</replaceable></arg>
- <arg choice="plain"><replaceable>remote_uri</replaceable></arg>
+ <arg><option>--postclone=</option><replaceable>COMMAND</replaceable></arg>
+ <arg><option>--[no-]hooks</option></arg>
+ <arg choice="plain"><replaceable>repository</replaceable></arg>
+ <arg><replaceable>directory</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
@@ -92,6 +95,66 @@
</listitem>
</varlistentry>
</variablelist>
+ <variablelist>
+ <varlistentry>
+ <term><option>--[no-]hooks</option></term>
+ <listitem>
+ <para>
+ Enable running hooks.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term><option>--postclone=</option><replaceable>COMMAND</replaceable></term>
+ <listitem>
+ <para>
+ Execute <replaceable>COMMAND</replaceable> after cloning the source
+ from the remote.
+ </para>
+ <para>
+ Exported environment variables are: <envar>GBP_GIT_DIR</envar> (the
+ repository the package is being built from).
+ </para>
+ <para>Note that if you clone a repository that contains a
+ hook configuration in <filename>debian/gbp.conf</filename>
+ this hook will not be run automatically to prevent execution
+ of untrusted code.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term><replaceable>repository</replaceable></term>
+ <listitem>
+ <para>
+ The (possibly remote) repository to clone from.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term><replaceable>directory</replaceable></term>
+ <listitem>
+ <para>
+ The directory to clone to.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+ <refsect1>
+ <title>EXAMPLES</title>
+ <para>
+ Clone a repository and setup a tracking branch for pristine-tar
+ as well:
+ </para>
+ <screen>
+ &gbp-clone; --pristine-tar git://honk.sigxcpu.org/git/git-buildpackage.git
+ </screen>
</refsect1>
<refsect1>
&man.gbp.config-files;
diff --git a/docs/manpages/gbp-create-remote-repo.sgml b/docs/manpages/gbp-create-remote-repo.sgml
index ae07f32..b613599 100644
--- a/docs/manpages/gbp-create-remote-repo.sgml
+++ b/docs/manpages/gbp-create-remote-repo.sgml
@@ -29,6 +29,7 @@
<arg><option>--debian-branch=</option><replaceable>branch_name</replaceable></arg>
<arg><option>--upstream-branch=</option><replaceable>branch_name</replaceable></arg>
<arg><option>--[no-]track</option></arg>
+ <arg><option>--[no-]bare</option></arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
@@ -120,6 +121,14 @@
pristine-tar branches.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--[no-]bare</option>
+ </term>
+ <listitem>
+ <para>Whether to the remote repository should be a bare
+ repository (this is the default).</para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
<refsect1>
diff --git a/docs/manpages/gbp-dch.sgml b/docs/manpages/gbp-dch.sgml
index 59f4563..798e197 100644
--- a/docs/manpages/gbp-dch.sgml
+++ b/docs/manpages/gbp-dch.sgml
@@ -26,23 +26,42 @@
<arg><option>--upstream-tag=</option><replaceable>tag-format</replaceable></arg>
<arg><option>--ignore-branch</option></arg>
<group>
- <arg><option>--snapshot</option></arg>
- <arg><option>--release</option></arg>
+ <group>
+ <arg><option>-S</option></arg>
+ <arg><option>--snapshot</option></arg>
+ </group>
+ <group>
+ <arg><option>-R</option></arg>
+ <arg><option>--release</option></arg>
+ </group>
</group>
<group>
- <arg><option>--auto</option></arg>
- <arg><option>--since=</option><replaceable>commitish</replaceable></arg>
+ <group>
+ <arg><option>-a</option></arg>
+ <arg><option>--auto</option></arg>
+ </group>
+ <group>
+ <arg><option>-s</option> <replaceable>commitish</replaceable></arg>
+ <arg><option>--since=</option><replaceable>commitish</replaceable></arg>
+ </group>
+ </group>
+ <group>
+ <arg><option>-N</option> <replaceable>version</replaceable></arg>
+ <arg><option>--new-version=</option><replaceable>version</replaceable></arg>
</group>
- <arg><option>--new-version=</option><replaceable>version</replaceable></arg>
<group>
<arg><option>--bpo</option></arg>
<arg><option>--nmu</option></arg>
<arg><option>--qa</option></arg>
+ <arg><option>--security</option></arg>
<arg><option>--team</option></arg>
</group>
<arg><option>--distribution=</option><replaceable>name</replaceable></arg>
<arg><option>--force-distribution</option></arg>
- <arg><option>--urgency=</option><replaceable>level</replaceable></arg>
+ <group>
+ <arg><option>-U</option> <replaceable>level</replaceable></arg>
+ <arg><option>--urgency=</option><replaceable>level</replaceable></arg>
+ </group>
<arg><option>--[no-]full</option></arg>
<arg><option>--[no-]meta</option></arg>
<arg><option>--meta-closes=bug-close-tags</option></arg>
@@ -53,10 +72,14 @@
<arg><option>--[no-]git-author</option></arg>
<arg><option>--[no-]multimaint</option></arg>
<arg><option>--[no-]multimaint-merge</option></arg>
- <arg><option>--spawn-editor=[always|snapshot|release]</option></arg>
+ <arg><option>--spawn-editor=[always|never|snapshot|release]</option></arg>
<arg><option>--commit-msg=</option><replaceable>msg-format</replaceable></arg>
- <arg><option>--commit</option></arg>
+ <group>
+ <arg><option>-c</option></arg>
+ <arg><option>--commit</option></arg>
+ </group>
<arg><option>--customizations=</option><replaceable>customization-file</replaceable></arg>
+ <arg><option>--verbose</option></arg>
<arg choice="plain"><replaceable>[path1 path2]</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
@@ -161,8 +184,9 @@
</term>
<listitem>
<para>
- Start reading commit messages at
- <replaceable>committish</replaceable>.
+ Start reading commit messages at
+ <replaceable>committish</replaceable>.
+ This option can't be set via &gbp.conf;.
</para>
</listitem>
</varlistentry>
@@ -171,8 +195,9 @@
<option>-a</option></term>
<listitem>
<para>
- Guess the last commit documented in the changelog from the
- snapshot banner (or from the last tag if no snapshot banner exists).
+ Guess the last commit documented in the changelog from the
+ snapshot banner (or from the last tag if no snapshot banner exists).
+ This option can't be set via &gbp.conf;.
</para>
</listitem>
</varlistentry>
@@ -256,9 +281,10 @@
<option>-R</option></term>
<listitem>
<para>
- Remove any snapshot release banners and version suffixes, set
- the current distribution to <replaceable>unstable</replaceable>, and
- open the changelog for final tweaking.
+ Remove any snapshot release banners and version suffixes, set
+ the current distribution to <replaceable>unstable</replaceable>, and
+ open the changelog for final tweaking.
+ This option can't be set via &gbp.conf;.
</para>
</listitem>
</varlistentry>
@@ -272,6 +298,7 @@
<replaceable>newversion</replaceable>. Together with
<option>--snapshot</option>, the snapshot number will be appended to
<replaceable>newversion</replaceable>.
+ This option can't be set via &gbp.conf;.
</para>
</listitem>
</varlistentry>
@@ -280,7 +307,8 @@
</term>
<listitem>
<para>
- Create a Team upload changelog entry.
+ Create a Team upload changelog entry.
+ This option can't be set via &gbp.conf;.
</para>
</listitem>
</varlistentry>
@@ -289,8 +317,9 @@
</term>
<listitem>
<para>
- Increment the Debian release number for an upload to backports, and
- add a backport upload changelog comment.
+ Increment the Debian release number for an upload to backports, and
+ add a backport upload changelog comment.
+ This option can't be set via &gbp.conf;.
</para>
</listitem>
</varlistentry>
@@ -299,7 +328,8 @@
</term>
<listitem>
<para>
- Increment the Debian release number for a non-maintainer upload.
+ Increment the Debian release number for a non-maintainer upload.
+ This option can't be set via &gbp.conf;.
</para>
</listitem>
</varlistentry>
@@ -308,8 +338,21 @@
</term>
<listitem>
<para>
- Increment the Debian release number for a Debian QA Team upload, and
- add a QA upload changelog comment.
+ Increment the Debian release number for a Debian QA Team upload, and
+ add a QA upload changelog comment.
+ This option can't be set via &gbp.conf;.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--security</option>
+ </term>
+ <listitem>
+ <para>
+ Increment the Debian release number for a Debian Security
+ Team non-maintainer upload, and add a "Security Team
+ upload" changelog comment.
+ This option can't be set via &gbp.conf;.
</para>
</listitem>
</varlistentry>
@@ -318,7 +361,8 @@
</term>
<listitem>
<para>
- Set the distribution field to <replaceable>name</replaceable>.
+ Set the distribution field to <replaceable>name</replaceable>.
+ This option can't be set via &gbp.conf;.
</para>
</listitem>
</varlistentry>
@@ -327,8 +371,9 @@
</term>
<listitem>
<para>
- Force the distribution specified with <option>--distribution</option>
- to be used, even if it doesn't match the list of known distributions.
+ Force the distribution specified with <option>--distribution</option>
+ to be used, even if it doesn't match the list of known distributions.
+ This option can't be set via &gbp.conf;.
</para>
</listitem>
</varlistentry>
@@ -390,11 +435,11 @@
</listitem>
</varlistentry>
<varlistentry>
- <term><option>--spawn-editor=<replaceable>[always|snapshot|release]</replaceable></option>
+ <term><option>--spawn-editor=<replaceable>[always|never|snapshot|release]</replaceable></option>
</term>
<listitem>
<para>
- Whether to spawn an editor: always, when doing snapshots or when
+ Whether to spawn an editor: always, never, when doing snapshots or when
doing a release.
</para>
</listitem>
diff --git a/docs/manpages/gbp-import-dsc.sgml b/docs/manpages/gbp-import-dsc.sgml
index a965913..5476b0e 100644
--- a/docs/manpages/gbp-import-dsc.sgml
+++ b/docs/manpages/gbp-import-dsc.sgml
@@ -225,6 +225,22 @@
&man.gbp.config-files;
</refsect1>
<refsect1>
+ <title>EXAMPLES</title>
+ <para>
+ Download and import a source package from a URL:
+ </para>
+ <screen>
+ &gbp-import-dsc; --download http://http.debian.net/debian/pool/main/h/hello/hello_2.10-1.dsc
+ </screen>
+ <para>
+ Download and import a source package via <command>apt-get
+ source</command> from unstable:
+ </para>
+ <screen>
+ &gbp-import-dsc; --download hello/sid
+ </screen>
+ </refsect1>
+ <refsect1>
<title>SEE ALSO</title>
<para>
diff --git a/docs/manpages/gbp-import-dscs.sgml b/docs/manpages/gbp-import-dscs.sgml
index 70cdb51..d0d1f11 100644
--- a/docs/manpages/gbp-import-dscs.sgml
+++ b/docs/manpages/gbp-import-dscs.sgml
@@ -20,7 +20,7 @@
<cmdsynopsis>
&gbp-import-dscs;
<arg><option>options</option></arg>
- <arg><option>git-import-dsc options</option></arg>
+ <arg><option>gbp import-dsc options</option></arg>
<arg choice="plain"><replaceable>pkg_1.dsc</replaceable></arg>
<arg choice="plain"><replaceable>pkg_2.dsc</replaceable></arg>
<arg choice="plain"><replaceable>...</replaceable></arg>
@@ -32,7 +32,7 @@
&gbp-import-dscs;
<arg choice="req">--debsnap</arg>
<arg><option>options</option></arg>
- <arg><option>git-import-dsc options</option></arg>
+ <arg><option>gbp import-dsc options</option></arg>
<arg choice="req"><replaceable>package</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
diff --git a/docs/manpages/gbp-import-orig.sgml b/docs/manpages/gbp-import-orig.sgml
index 5049a9e..1e86a94 100644
--- a/docs/manpages/gbp-import-orig.sgml
+++ b/docs/manpages/gbp-import-orig.sgml
@@ -30,12 +30,14 @@
<arg><option>--[no-]sign-tags</option></arg>
<arg><option>--keyid=</option><replaceable>gpg-keyid</replaceable></arg>
<arg><option>--upstream-tag=</option><replaceable>tag-format</replaceable></arg>
- <arg><option>--filter=</option><replaceable>pattern</replaceable></arg>
+ <arg rep='repeat'><option>--filter=</option><replaceable>pattern</replaceable></arg>
+ <arg rep='repeat'><option>--component=</option><replaceable>component</replaceable></arg>
<arg><option>--[no-]pristine-tar</option></arg>
<arg><option>--[no-]filter-pristine-tar</option></arg>
<arg><option>--[no-]symlink-orig</option></arg>
<arg><option>--postimport=cmd</option></arg>
<arg><option>--[no-]interactive</option></arg>
+ <arg><option>--[no-]rollback</option></arg>
<arg><option>--download</option></arg>
<group choice="plain">
<arg choice="plain"><replaceable>upstream-source</replaceable></arg>
@@ -57,9 +59,23 @@
for it unless <option>--no-interactive</option> is given.
</para>
<para>
- The sources are placed on the upstream branch (default:
- <replaceable>upstream</replaceable>), tagged and merged onto the debian
- branch (default: <replaceable>master</replaceable>).
+ The sources are placed on the upstream branch (default:
+ <replaceable>upstream</replaceable>), tagged and merged onto the
+ debian branch (default: <replaceable>master</replaceable>). This
+ is either done using <command>git merge</command> in case
+ of <option>--merge-mode=</option><replaceable>merge</replaceable>
+ (the default) or by creating a new tree that consists of the new
+ upstream version plus the <filename>debian/</filename>
+ directory. This behaviour can be enabled via
+ the <option>--merge-mode=</option><replaceable>replace</replaceable>
+ option and is preferable for source format 3.0 (quilt) packages
+ since direct modifications of the upstream sources are not
+ allowed in that format and so a 1:1 replacement of the upstream
+ sources is almost always desired.
+ </para>
+ <para>In case of an error &gbp-import-orig; will rollback (undo)
+ all changes it has done to the repository (see
+ the <option>--rollback</option> option).
</para>
</refsect1>
<refsect1>
@@ -179,7 +195,7 @@
<para>
use this format string for the commit message when importing upstream
versions, default is
- <replaceable>Imported Upstream version %(version)s</replaceable>
+ <replaceable>New upstream version %(version)s</replaceable>
</para>
</listitem>
</varlistentry>
@@ -193,6 +209,27 @@
</listitem>
</varlistentry>
<varlistentry>
+ <term><option>--component=</option><replaceable>COMPONENT</replaceable>
+ </term>
+ <listitem>
+ <para>
+ When importing the upstream tarball also look for an additional tarball
+ with component name <replaceable>COMPONENT</replaceable>. E.g. in
+ <filename>hello-debhelper_1.0.orig-foo.tar.gz</filename>
+ the component would be <replaceable>foo</replaceable>. The additional
+ tarball is expected to be in the same directory than the upstream tarball
+ and to use the same compression type.
+ </para>
+ <para>
+ Using additional original tarballs is a feature of the 3.0
+ (quilt) source format. See
+ the <command>dpkg-source</command> manpage for
+ details. This is currently considered an experimental
+ feature and might change incompatibly.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><option>--[no-]pristine-tar</option>
</term>
<listitem>
@@ -229,7 +266,35 @@
<term><option>--postimport=<replaceable>cmd</replaceable></option></term>
<listitem>
<para>
- run <replaceable>cmd</replaceable> after the import.
+ Run <replaceable>cmd</replaceable> after the import. The
+ hook gets the following environment variables passed:
+ <variablelist>
+ <varlistentry>
+ <term><envar>GBP_BRANCH</envar></term>
+ <listitem><para>
+ The name of the Debian packaging branch
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><envar>GBP_TAG</envar></term>
+ <listitem><para>
+ The name of the just created upstream tag
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><envar>GBP_UPSTREAM_VERSION</envar></term>
+ <listitem><para>
+ The just imported upstream version
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><envar>GBP_DEBIAN_VERSION</envar></term>
+ <listitem><para>
+ The Debian version of the package with a Debian
+ revision of '-1'
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
</para>
</listitem>
</varlistentry>
@@ -259,6 +324,14 @@
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--[no-]rollback</option></term>
+ <listitem>
+ <para>
+ Rollback changes in case of an error.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
<refsect1>
diff --git a/docs/manpages/gbp-import-srpm.sgml b/docs/manpages/gbp-import-srpm.sgml
index daf2d75..d51ae7d 100644
--- a/docs/manpages/gbp-import-srpm.sgml
+++ b/docs/manpages/gbp-import-srpm.sgml
@@ -232,6 +232,7 @@
<para>
<xref linkend="man.gbp.buildpackage.rpm"/>,
<xref linkend="man.gbp.pq.rpm"/>,
+ <xref linkend="man.gbp.rpm.ch">,
<xref linkend="man.gbp.conf"/>,
&man.seealso.common;
</para>
diff --git a/docs/manpages/gbp-pq.sgml b/docs/manpages/gbp-pq.sgml
index 2bb1645..265e267 100644
--- a/docs/manpages/gbp-pq.sgml
+++ b/docs/manpages/gbp-pq.sgml
@@ -29,6 +29,8 @@
<arg><option>--force</option></arg>
<arg><option>--meta-closes=bug-close-tags</option></arg>
<arg><option>--meta-closes-bugnum=bug-number-format</option></arg>
+ <arg><option>--pq-from=</option><replaceable>[DEBIAN|TAG]</replaceable></arg>
+ <arg><option>--upstream-tag=</option><replaceable>tag-format</replaceable></arg>
<group choice="plain">
<arg><option>drop</option></arg>
<arg><option>export</option></arg>
@@ -194,15 +196,16 @@
<varlistentry>
<term><option>--[no-]drop</option></term>
<listitem>
- <para>Whether to drop (delete) the patch queue branch after
+ <para>Whether to automatically drop (delete) the patch queue branch after
a successful export</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--force</option></term>
<listitem>
- <para>In case of <option>import</option>, import even if the branch already
- exists</para>
+ <para>In case of <option>import</option>, import even if the
+ patch-queue branch already exists and overwrite its
+ content with <filename>debian/patches</filename>.</para>
</listitem>
</varlistentry>
<varlistentry>
@@ -229,6 +232,29 @@
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--pq-from=</option><replaceable>[DEBIAN|TAG]</replaceable>
+ </term>
+ <listitem>
+ <para>
+ How to find the starting point for the patch queue base. The options are DEBIAN, that will use the Debian branch as the base for the patch queue branch, and TAG, that will use the corresponding upstream tag as a base for the patch queue branch.
+ </para>
+ <para>
+ This is only needed if your upstream branch is not merged in the Debian branch.
+ The default is <replaceable>DEBIAN</replaceable>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--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>
</variablelist>
</refsect1>
<refsect1>
diff --git a/docs/manpages/gbp-rpm-ch.sgml b/docs/manpages/gbp-rpm-ch.sgml
new file mode 100644
index 0000000..4e4621b
--- /dev/null
+++ b/docs/manpages/gbp-rpm-ch.sgml
@@ -0,0 +1,355 @@
+<refentry id="man.gbp.rpm.ch">
+ <refentryinfo>
+ <address>
+ &rpm-email;
+ </address>
+ <author>
+ &rpm-firstname;
+ &rpm-surname;
+ </author>
+ </refentryinfo>
+ <refmeta>
+ <refentrytitle>gbp-rpm-ch</refentrytitle>
+ &rpm-mansection;
+ </refmeta>
+ <refnamediv>
+ <refname>gbp-rpm-ch;</refname>
+ <refpurpose>Generate the RPM changelog from git commit messages</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ &gbp-rpm-ch;
+ &man.common.options.synopsis;
+ <arg><option>--tmp-dir</option>=<replaceable>DIRECTORY</replaceable></arg>
+ <arg><option>--vendor</option>=<replaceable>VENDOR</replaceable></arg>
+ <arg><option>--packaging-branch=</option><replaceable>BRANCH-NAME</replaceable></arg>
+ <arg><option>--packaging-tag=</option><replaceable>TAG-FORMAT</replaceable></arg>
+ <arg><option>--ignore-branch</option></arg>
+ <arg><option>--packaging-dir=</option><replaceable>DIRECTORY</replaceable></arg>
+ <arg><option>--changelog-file=</option><replaceable>FILEPATH</replaceable></arg>
+ <arg><option>--spec-file=</option><replaceable>FILEPATH</replaceable></arg>
+ <arg><option>--since=</option><replaceable>COMMITISH</replaceable></arg>
+ <arg><option>--no-release</option></arg>
+ <arg><option>--[no-]git-author</option></arg>
+ <arg><option>--[no-]full</option></arg>
+ <arg><option>--id-length=</option><replaceable>NUMBER</replaceable></arg>
+ <arg><option>--ignore-regex=</option><replaceable>REGEX</replaceable></arg>
+ <arg><option>--changelog-revision=</option><replaceable>REV-FORMAT</replaceable></arg>
+ <arg><option>--git-log=</option><replaceable>GIT-LOG-OPTIONS</replaceable></arg>
+ <arg><option>--spawn-editor=<replaceable>[always|release|no]</replaceable></option></arg>
+ <arg><option>--editor-cmd=</option><replaceable>EDITOR</replaceable></arg>
+ <arg><option>--customizations=</option><replaceable>CUSTOMIZATION-FILE</replaceable></arg>
+ <arg choice="plain"><replaceable>[PATH1 PATH2]</replaceable></arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+ <refsect1>
+ <title>DESCRIPTION</title>
+ <para>
+ &gbp-rpm-ch; reads git commit messages up to the current tip of the current
+ branch and updates the RPM changelog from them.
+ </para>
+ <para>
+ By default, &gbp-rpm-ch; tries to guess the last &git; commit documented in
+ the changelog. Alternatively, <option>--since</option> can be used to
+ tell &gbp-rpm-ch; at which point it should start in the &git; history, or,
+ <option>--all</option> to use all commits from the &git; history.
+ </para>
+ <para>
+ The additional path arguments can be used to restrict the repository paths
+ &gbp-rpm-ch; looks at. For even more detailed control, you can use
+ <option>--git-log</option> to restrict the generated changelog entries
+ further. E.g. by using
+ <option>--git-log=</option><replaceable>"--author=Foo Bar"</replaceable>.
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>OPTIONS</title>
+ <variablelist>
+ &man.common.options.description;
+
+ <varlistentry>
+ <term><option>--git-tmp-dir</option>=<replaceable>DIRECTORY</replaceable>
+ </term>
+ <listitem>
+ <para>
+ Base directory under which temporary directories are created.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--vendor</option>=<replaceable>VENDOR</replaceable>
+ </term>
+ <listitem>
+ <para>
+ Distribution vendor name.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--packaging-branch</option>=<replaceable>BRANCH-NAME</replaceable>
+ </term>
+ <listitem>
+ <para>
+ The branch in the Git repository the package is being developed on,
+ default is <replaceable>master</replaceable>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--ignore-branch</option>
+ </term>
+ <listitem>
+ <para>
+ Don't check if the current branch matches
+ <replaceable>PACKAGING-BRANCH</replaceable>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--packaging-tag=</option><replaceable>TAG-FORMAT</replaceable>
+ </term>
+ <listitem>
+ <para>
+ Tag format used, when tagging releases,
+ default is <replaceable>%(vendor)s/%(version)s</replaceable>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--packaging-dir=</option><replaceable>DIRECTORY</replaceable>
+ </term>
+ <listitem>
+ <para>
+ Subdirectory that contains the RPM packaging files.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--changelog-file=</option><replaceable>FILEPATH</replaceable>
+ </term>
+ <listitem>
+ <para>
+ Relative path to the changelog file to use. Special value
+ <replaceable>auto</replaceable> causes &gbp; to guess,
+ <replaceable>SPEC</replaceable> uses the spec file,
+ <replaceable>CHANGES</replaceable> uses a separate changelog file
+ (name derived spec file name with .spec suffix replaced by .changes).
+ Guessing logic is simple: use separate changelog file if it is found,
+ otherwise use the spec file.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--spec-file=</option><replaceable>FILEPATH</replaceable>
+ </term>
+ <listitem>
+ <para>
+ Relative path to the spec file to use. Special value
+ <replaceable>auto</replaceable> causes &gbp; to search and guess.
+ Other values cause the <option>--packaging-dir</option> option to be
+ ignored: the directory of the spec file is used, instead.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--since=</option><replaceable>COMMITTISH</replaceable>
+ </term>
+ <listitem>
+ <para>
+ Start reading commit messages at
+ <replaceable>COMMITTISH</replaceable>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--no-release</option>
+ </term>
+ <listitem>
+ <para>
+ Do not create a new changelog section, just update the last
+ changelog section.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--[no-]full</option>
+ </term>
+ <listitem>
+ <para>
+ Include the full commit message in the changelog output.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--git-log=</option><replaceable>GIT-LOG-OPTIONS</replaceable>
+ </term>
+ <listitem>
+ <para>
+ Options passed on verbatim to git-log(1).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--id-length=</option><replaceable>N</replaceable>
+ </term>
+ <listitem>
+ <para>
+ Include <replaceable>N</replaceable> digits of the commit id in the
+ changelog entry. Default is to not include any commit ids at all.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--ignore-regex=</option><replaceable>REGEX</replaceable>
+ </term>
+ <listitem>
+ <para>
+ Ignore lines in commit message matching
+ <replaceable>REGEX</replaceable> when generating the changelog.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--changelog-revision=</option><replaceable>REV-FORMAT</replaceable>
+ </term>
+ <listitem>
+ <para>
+ Format string to use for revision field in the changelog header. The
+ following string fields are accepted:
+ <replaceable>%(upstreamversion)s</replaceable> the upstream version;
+ <replaceable>%(release)s</replaceable> the rpm patchlevel, i.e.
+ Release; <replaceable>%(version)s</replaceable> full rpm package
+ version; <replaceable>%(tagname)s</replaceable> tag/commit, i.e.
+ basically what <command>git-describe</command> would give.
+ If empty or not defined the default from packaging policy is used.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--ignore-regex=</option><replaceable>REGEX</replaceable>
+ </term>
+ <listitem>
+ <para>
+ Ignore commit lines matching <replaceable>REGEX</replaceable>
+ when generating the changelog.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--[no-]git-author</option>
+ </term>
+ <listitem>
+ <para>
+ Use user.name and user.email from
+ <application>git-config</application>(1) for the changelog header.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--spawn-editor=<replaceable>[always|release|no]</replaceable></option>
+ </term>
+ <listitem>
+ <para>
+ Whether to spawn an editor: always, when doing a release or never.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--editor-cmd=<replaceable>EDITOR</replaceable></option>
+ </term>
+ <listitem>
+ <para>
+ The editor to use for editing the changelog.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--customizations=</option><replaceable>CUSTOMIZATION-FILE</replaceable>
+ </term>
+ <listitem>
+ <para>
+ Load Python code from <replaceable>CUSTOMIZATION-FILE</replaceable>.
+ At the moment, the only useful thing the code can do is define a
+ custom ChangelogEntryFormatter class.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+ <refsect1>
+ <title>META TAGS</title>
+ <para>
+ Additional to the above options the formatting of the new changelog entries
+ (one-per-commit) in the changelog can be modified by special tags (called
+ Meta Tags) given in the git commit message. The tags must start at the
+ first column of a commit message but can appear on any line. They are of
+ the form <option>Tagname</option>: <replaceable>VALUE</replaceable>. Valid
+ Meta Tags are:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><option>Git-Rpm-Ch</option>: <replaceable>ACTION</replaceable>
+ </term>
+ <listitem>
+ <para>
+ Supported actions are: <replaceable>Ignore</replaceable> which will
+ ignore this commit when generating new changelog entries.
+ <replaceable>Short</replaceable> which will only use the description
+ (the first line) of the commit message when generating the changelog
+ entry (useful when <option>--full</option> is given) and
+ <replaceable>Full</replaceable> which will use the full commit
+ message when generating the changelog entry (useful when
+ <option>--full</option> is not given).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>[Close|Closes|...]</option>: <replaceable>BUGNUMBER</replaceable>
+ </term>
+ <listitem>
+ <para>
+ Indicate in the changelog entry that bug
+ <replaceable>BUGNUMBER</replaceable> was addressed in this commit.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ The following git commit message:
+ </para>
+ <screen>
+ Document meta tags
+
+ so one doesn't have to consult the manual
+
+ Git-Rpm-Ch: Short
+ Closes: #636088
+ </screen>
+ <para>
+ Results in this changelog entry:
+ </para>
+ <screen>
+ - Document meta tags (Closes: #636088)
+ </screen>
+ </refsect1>
+ <refsect1>
+ &man.gbp.config-files;
+ </refsect1>
+ <refsect1>
+ <title>SEE ALSO</title>
+ <para>
+ <xref linkend="man.gbp.buildpackage.rpm">,
+ <xref linkend="man.gbp.import.srpm">,
+ <xref linkend="man.gbp.conf">,
+ &man.seealso.common;
+ <ulink url="https://honk.sigxcpu.org/cl2vcs">
+ <citetitle>Cl2vcs</citetitle></ulink>,
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>AUTHOR</title>
+ <para>
+ &rpm-username; &rpm-email;
+ </para>
+ </refsect1>
+</refentry>
diff --git a/docs/manpages/gbp.conf.sgml b/docs/manpages/gbp.conf.sgml
index 369979d..322340d 100644
--- a/docs/manpages/gbp.conf.sgml
+++ b/docs/manpages/gbp.conf.sgml
@@ -56,15 +56,17 @@
zero or one sections for each &gbp; command. Additionally, there
can be an arbitrary number of
<option>remote-config</option> sections. Comments start with a
- hash sign (<option>#</option>). The syntax is:
+ hash sign (<option>#</option>). The overall layout is:
</para>
<programlisting>
[DEFAULT]
- # This section is for global settings. Affects all commands
+ # This section is for global settings. Affects all commands.
+ # Options set here have the lowest priority.
key = value
[&lt;command&gt;]
# Specific sections for each command, like <command>buildpackage</command>
+ # Options set here have lower priority than command line options
key = value
[remote-config &lt;name&gt;]
@@ -81,15 +83,20 @@
</para>
<para>
- The <option>key=value</option> pairs of the command sections are
- named like the command-line options of the corresponding command
- with the '--' stripped off and can hold the same values (but see
- below for details). For example,
+ The keys in the
+ <option>key</option>=<parameter>value</parameter> pairs are named
+ like the command-line options of the corresponding command (with the
+ '--' stripped off) and can hold the same values, but see below for
+ details. In case of &gbp-buildpackage; and &gbp-buildpackage-rpm;
+ the key needs '--git-' instead of '--' stripped off.
+</para>
+<para>
+ For example,
the <xref linkend="man.gbp.buildpackage"/> manual page documents
the <option>--git-export-dir</option>=<parameter>directory</parameter>
option which can be turned into configuration file setting by
dropping the
- <option>--git</option> prefix:
+ <option>--git-</option> prefix:
</para>
<programlisting>
diff --git a/docs/manpages/manpages.ent b/docs/manpages/manpages.ent
index c212150..01700bb 100644
--- a/docs/manpages/manpages.ent
+++ b/docs/manpages/manpages.ent
@@ -15,5 +15,6 @@
<!ENTITY man.gbp.buildpackage.rpm SYSTEM "gbp-buildpackage-rpm.sgml">
<!ENTITY man.gbp.import.srpm SYSTEM "gbp-import-srpm.sgml">
<!ENTITY man.gbp.pq.rpm SYSTEM "gbp-pq-rpm.sgml">
+<!ENTITY man.gbp.rpm.ch SYSTEM "gbp-rpm-ch.sgml">
<!ENTITY % COMMON.OPTIONS SYSTEM "man.common-options.ent">
%COMMON.OPTIONS;
diff --git a/examples/gbp-posttag-push b/examples/gbp-posttag-push
index cd8968d..91d3eb1 100755
--- a/examples/gbp-posttag-push
+++ b/examples/gbp-posttag-push
@@ -1,7 +1,7 @@
#!/usr/bin/python
# vim: set fileencoding=utf-8 :
#
-# (C) 2009,2012,2015 Guido Guenther <agx@sigxcpu.org>
+# (C) 2009,2012,2015,2016 Guido Guenther <agx@sigxcpu.org>
#
# gbp-posttag-push: post tag hook to be called by git-buildpackage to push out
# the newly created tag and to forward the remote branch to that position
@@ -11,7 +11,7 @@
# signed.
#
# use:
-# [git-buildpackage]
+# [buildpackage]
# posttag = gbp-posttag-push
#
# Options:
@@ -21,15 +21,19 @@
from __future__ import print_function
-from six.moves import configparser
+import glob
import os
import subprocess
import sys
import gbp.log
-from gbp.config import GbpOptionParser
+from gbp.command_wrappers import Command, CommandExecFailed
+from gbp.config import GbpOptionParserDebian
from gbp.deb.git import DebianGitRepository
-
+from gbp.deb.source import DebianSource
+from gbp.errors import GbpError
+from gbp.git.vfs import GitVfs
+from gbp.scripts.common import ExitCodes
class Env(object):
@@ -44,9 +48,9 @@ def get_push_targets(env):
if not len(remote):
continue
repo, refspec = remote.split()
- repo = ".".join(repo.split('.')[1:-1]) # remote.<repo>.push
+ repo = ".".join(repo.split('.')[1:-1]) # remote.<repo>.push
try:
- remote = refspec.split(':')[1] # src:dest
+ remote = refspec.split(':')[1] # src:dest
except IndexError:
remote = refspec
dests[repo] = remote
@@ -56,10 +60,10 @@ def get_push_targets(env):
def get_pull(env):
"""where did we pull from?"""
cmd = 'git config --get branch."%s".remote' % env.branch
- remote = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True).communicate()[0].strip()
+ remote = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True).communicate()[0].strip()
if not remote:
remote = 'origin'
- return { remote: env.branch }
+ return {remote: env.branch}
def git_push_sim(*args):
@@ -69,7 +73,6 @@ def git_push_sim(*args):
def get_upstream_tag(repo, tag, tag_format):
# FIXME: This assumes the debian version is the last part after the slash:
version = tag.split('/')[-1]
- no_epoch = version.split(':')[-1]
upstream = version.rsplit('-')[0]
tag = tag_format % dict(version=upstream)
if repo.has_tag(tag):
@@ -77,16 +80,19 @@ def get_upstream_tag(repo, tag, tag_format):
return None
-def main(argv):
- env = Env()
- upstream_sha1 = None
+def build_parser(name):
+
+ # Until we moved this out of examples
+ os.environ['GBP_DISABLE_SECTION_DEPRECTATION'] = '1'
+ GbpOptionParserDebian.defaults['upload-cmd'] = ""
+ GbpOptionParserDebian.help['upload-cmd'] = "Upload command, default is '%(upload-cmd)s'"
try:
- parser = GbpOptionParser(command=os.path.basename(argv[0]), prefix='',
- usage='%prog [options] paths')
- except configparser.ParsingError as err:
- gbp.log.error(err)
- return 1
+ parser = GbpOptionParserDebian(command=os.path.basename(name),
+ usage='%prog [options]')
+ except GbpError as err:
+ gbp.log.err(err)
+ return None
parser.add_option("-d", "--dry-run", dest="dryrun", default=False,
action="store_true", help="dry run, don't push.")
@@ -98,25 +104,67 @@ def main(argv):
dest="upstream_branch")
parser.add_config_file_option(option_name="upstream-tag",
dest="upstream_tag")
+ parser.add_config_file_option(option_name="debian-tag",
+ dest="debian_tag")
+ parser.add_config_file_option(option_name="upload-cmd",
+ dest="upload_cmd")
+ 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_option("--verbose", action="store_true", dest="verbose",
default=False, help="verbose command execution")
+ return parser
- (options, args) = parser.parse_args()
- gbp.log.setup(False, options.verbose)
- repo = DebianGitRepository('.')
+def parse_args(argv):
+ parser = build_parser(argv[0])
+ if not parser:
+ return None, None
+ return parser.parse_args(argv)
+
+
+def find_changes(sourcename, version):
+ glob_ex = "../%s_%s_*.changes" % (sourcename, version)
+ gbp.log.info("Looking for changes at %s" % glob_ex)
+ return glob.glob(glob_ex)
+
+
+def upload_changes(changes, cmd, dryrun):
+ ret = 0
+ for name in changes:
+ gbp.log.info("Running %s" % " ".join([cmd, name]))
+ try:
+ if not dryrun:
+ Command(cmd, [name], shell=False)()
+ except CommandExecFailed:
+ gbp.log.err("Upload of '%s' failed." % name)
+ ret = 1
+ return ret
+
+def main(argv):
+ retval = 0
+ env = Env()
+ upstream_sha1 = None
+
+ (options, args) = parse_args(argv)
+ if not options:
+ return ExitCodes.parse_error
+
+ gbp.log.setup(options.color, options.verbose, options.color_scheme)
+
+ repo = DebianGitRepository('.')
if options.dryrun:
- print("Dry run mode. Not pushing.")
+ gbp.log.warn("Dry run mode. Not pushing, not uploading.")
repo.push = git_push_sim
repo.push_tag = git_push_sim
- for envvar in [ "GBP_TAG", "GBP_BRANCH", "GBP_SHA1" ]:
+ for envvar in ["GBP_TAG", "GBP_BRANCH", "GBP_SHA1"]:
var = os.getenv(envvar)
if var:
- env.__dict__.setdefault( "%s" % envvar.split("_")[1].lower(), var)
+ env.__dict__.setdefault("%s" % envvar.split("_")[1].lower(), var)
else:
- print("%s not set." % envvar, file=sys.stderr)
+ gbp.log.err("%s not set." % envvar, file=sys.stderr)
return 1
dests = get_push_targets(env)
@@ -128,22 +176,35 @@ def main(argv):
upstream_sha1 = repo.rev_parse("%s^{}" % upstream_tag)
if not repo.verify_tag(env.tag):
- print("Not pushing nonexistent or unsigned tag '%s'." % env.tag, file=sys.stderr)
+ gbp.log.info("Not pushing non-existent or unsigned tag '%s'." % env.tag, file=sys.stderr)
return 0
+ source = DebianSource(GitVfs(repo, env.tag))
+
for dest in dests:
- print("Pushing %s to %s" % (env.tag, dest))
+ gbp.log.info("Pushing %s to %s" % (env.tag, dest))
repo.push_tag(dest, env.tag)
- print("Pushing %s to %s" % (env.sha1, dest))
+ gbp.log.info("Pushing %s to %s %s" % (env.sha1, dest, dests[dest]))
repo.push(dest, env.sha1, dests[dest])
if options.push_upstream and upstream_tag:
- print("Pushing %s to %s" % (upstream_tag, dest))
+ gbp.log.info("Pushing %s to %s" % (upstream_tag, dest))
repo.push_tag(dest, upstream_tag)
if not repo.branch_contains("%s/%s" % (dest, options.upstream_branch),
upstream_sha1, remote=True):
- print("Pushing %s to %s" % (upstream_sha1, dest))
+ gbp.log.info("Pushing %s to %s %s" % (upstream_sha1, dest, options.upstream_branch))
repo.push(dest, upstream_sha1, options.upstream_branch)
- print("done.")
+
+ if options.upload_cmd:
+ version = repo.tag_to_version(env.tag, options.debian_tag)
+ changes = find_changes(source.sourcepkg, version)
+ if len(changes):
+ retval = upload_changes(changes, options.upload_cmd, options.dryrun)
+ else:
+ gbp.log.info("No changes file found, nothing to upload.")
+ else:
+ gbp.log.info("No upload command defined, not uploading to the archive")
+ return retval
+
if __name__ == '__main__':
sys.exit(main(sys.argv))
diff --git a/examples/jenkins-scratchbuilder b/examples/jenkins-scratchbuilder
index 83823e7..c2e32fe 100755
--- a/examples/jenkins-scratchbuilder
+++ b/examples/jenkins-scratchbuilder
@@ -32,7 +32,7 @@ git clean -dfx
# Reset the changelog
git checkout -f debian/changelog
-# Create a monitonically increasing changelog by including the build number
+# Create a monotonically increasing changelog by including the build number
gbp dch -S -a --ignore-branch --snapshot-number=${BUILD_NUMBER}
# Build the package
diff --git a/examples/wrap_cl.py b/examples/wrap_cl.py
index 5f1c0c8..c4c6f8b 100644
--- a/examples/wrap_cl.py
+++ b/examples/wrap_cl.py
@@ -8,6 +8,7 @@
import textwrap
import gbp.dch
+
def format_changelog_entry(commit_info, options, last_commit=False):
entry = gbp.dch.format_changelog_entry(commit_info, options, last_commit)
if entry:
diff --git a/examples/zeitgeist-git.py b/examples/zeitgeist-git.py
index dae1dbc..a2655e7 100755
--- a/examples/zeitgeist-git.py
+++ b/examples/zeitgeist-git.py
@@ -48,14 +48,14 @@ else:
try:
CLIENT = ZeitgeistClient()
except RuntimeError as e:
- print("Unable to connect to Zeitgeist, won't send events. Reason: '%s'" %e)
+ print("Unable to connect to Zeitgeist, won't send events. Reason: '%s'" % e)
def get_repo():
"""Get uri of remote repository and its name"""
repo = None
uri = subprocess.Popen(['git', 'config', '--get', 'remote.origin.url'],
- stdout=subprocess.PIPE).communicate()[0]
+ stdout=subprocess.PIPE).communicate()[0]
if uri:
uri = uri.strip().decode(sys.getfilesystemencoding())
@@ -65,7 +65,7 @@ def get_repo():
sep = ':'
try:
repo = unicode(uri.rsplit(sep, 1)[1])
- except IndexError: # no known separator
+ except IndexError: # no known separator
repo = uri
repo = repo.rsplit(u'.git', 1)[0]
return repo, uri
@@ -86,19 +86,19 @@ def main(argv):
origin = uri
subject = Subject.new_for_values(
- uri = uri,
- interpretation = Interpretation.DOCUMENT.TEXT_DOCUMENT.PLAIN_TEXT_DOCUMENT.SOURCE_CODE.uri,
- manifestation = Manifestation.FILE_DATA_OBJECT.uri,
- text = repo,
- origin = origin)
+ uri=uri,
+ interpretation=Interpretation.DOCUMENT.TEXT_DOCUMENT.PLAIN_TEXT_DOCUMENT.SOURCE_CODE.uri,
+ manifestation=Manifestation.FILE_DATA_OBJECT.uri,
+ text=repo,
+ origin=origin)
event = Event.new_for_values(
- timestamp = int(time.time() * 1000),
- interpretation = interpretation,
- manifestation = Manifestation.USER_ACTIVITY.uri,
- actor = "application://gitg.desktop",
- subjects = [subject])
+ timestamp=int(time.time() * 1000),
+ interpretation=interpretation,
+ manifestation=Manifestation.USER_ACTIVITY.uri,
+ actor="application://gitg.desktop",
+ subjects=[subject])
CLIENT.insert_event(event)
+
if __name__ == '__main__':
main(sys.argv)
-
diff --git a/gbp.conf b/gbp.conf
index 8291d33..35e79d8 100644
--- a/gbp.conf
+++ b/gbp.conf
@@ -47,7 +47,7 @@
#notify = off
# Transparently handle submodules
# submodules = True
-# Wheter to use cowbuilder via git-pbuilder(1)
+# Whether to use cowbuilder via git-pbuilder(1)
#pbuilder = True
# Which distribution to use with git-pbuilder
#dist = testing
diff --git a/gbp/command_wrappers.py b/gbp/command_wrappers.py
index a4643c5..f4b00b8 100644
--- a/gbp/command_wrappers.py
+++ b/gbp/command_wrappers.py
@@ -21,15 +21,48 @@ git-buildpackage and friends
import subprocess
import os
-import os.path
import signal
+import sys
+from contextlib import contextmanager
+from tempfile import TemporaryFile
+
import gbp.log as log
+
class CommandExecFailed(Exception):
"""Exception raised by the Command class"""
pass
+@contextmanager
+def proxy_stdf():
+ """
+ Circulate stdout/stderr via a proper file object. Designed to work around a
+ problem where Python nose replaces sys.stdout/stderr with a custom 'Tee'
+ object that is not a file object (compatible) and thus causes a crash with
+ Popen.
+ """
+ stdout = None
+ if not hasattr(sys.stdout, 'fileno'):
+ stdout = sys.stdout
+ sys.stdout = TemporaryFile()
+ stderr = None
+ if not hasattr(sys.stderr, 'fileno'):
+ stderr = sys.stderr
+ sys.stderr = TemporaryFile()
+ try:
+ yield
+ finally:
+ if stdout:
+ sys.stdout.seek(0)
+ stdout.write(sys.stdout.read())
+ sys.stdout = stdout
+ if stderr:
+ sys.stderr.seek(0)
+ stderr.write(sys.stderr.read())
+ sys.stderr = stderr
+
+
class Command(object):
"""
Wraps a shell command, so we don't have to store any kind of command
@@ -67,26 +100,26 @@ class Command(object):
log.debug("%s %s %s" % (self.cmd, self.args, args))
self._reset_state()
- stdout_arg = subprocess.PIPE if self.capture_stdout else None
- stderr_arg = subprocess.PIPE if self.capture_stderr else None
- cmd = [ self.cmd ] + self.args + args
+ cmd = [self.cmd] + self.args + args
if self.shell:
# subprocess.call only cares about the first argument if shell=True
cmd = " ".join(cmd)
-
- try:
- popen = subprocess.Popen(cmd,
- cwd=self.cwd,
- shell=self.shell,
- env=self.env,
- preexec_fn=default_sigpipe,
- stdout=stdout_arg,
- stderr=stderr_arg)
- (self.stdout, self.stderr) = popen.communicate()
- except OSError as err:
- self.err_reason = "execution failed: %s" % str(err)
- self.retcode = 1
- raise
+ with proxy_stdf():
+ stdout_arg = subprocess.PIPE if self.capture_stdout else sys.stdout
+ stderr_arg = subprocess.PIPE if self.capture_stderr else sys.stderr
+ try:
+ popen = subprocess.Popen(cmd,
+ cwd=self.cwd,
+ shell=self.shell,
+ env=self.env,
+ preexec_fn=default_sigpipe,
+ stdout=stdout_arg,
+ stderr=stderr_arg)
+ (self.stdout, self.stderr) = popen.communicate()
+ except OSError as err:
+ self.err_reason = "execution failed: %s" % str(err)
+ self.retcode = 1
+ raise
self.retcode = popen.returncode
if self.retcode < 0:
@@ -107,8 +140,10 @@ class Command(object):
"""
stdout = self.stdout.rstrip() if self.stdout else self.stdout
stderr = self.stderr.rstrip() if self.stderr else self.stderr
+ stderr_or_reason = self.stderr.rstrip() if self.stderr else self.err_reason
return self.run_error.format(stdout=stdout,
stderr=stderr,
+ stderr_or_reason=stderr_or_reason,
err_reason=self.err_reason)
def __call__(self, args=[], quiet=False):
@@ -117,7 +152,7 @@ class Command(object):
If run quietly it will not print an error message via the
L{gbp.log} logging API.
- Wether the command prints anything to stdout/stderr depends on
+ Whether the command prints anything to stdout/stderr depends on
the I{capture_stderr}, I{capture_stdout} instance variables.
All errors will be reported as subclass of the
@@ -142,10 +177,9 @@ class Command(object):
ret = 1
if ret:
if not quiet:
- self._log_err()
+ self._log_err()
raise CommandExecFailed(self._format_err())
-
def call(self, args, quiet=True):
"""Like L{__call__} but let the caller handle the return status.
@@ -217,7 +251,7 @@ class UnpackTarArchive(Command):
compression = '-a'
Command.__init__(self, 'tar', exclude +
- ['-C', dir, compression, '-xf', archive ])
+ ['-C', dir, compression, '-xf', archive])
self.run_error = 'Couldn\'t unpack "%s": {err_reason}' % self.archive
@@ -250,7 +284,7 @@ class RemoveTree(Command):
"Wrap rm to remove a whole directory tree"
def __init__(self, tree):
self.tree = tree
- Command.__init__(self, 'rm', [ '-rf', tree ])
+ Command.__init__(self, 'rm', ['-rf', tree])
self.run_error = 'Couldn\'t remove "%s": {err_reason}' % self.tree
@@ -283,7 +317,7 @@ class UnpackZipArchive(Command):
self.archive = archive
self.dir = dir
- Command.__init__(self, 'unzip', [ "-q", archive, '-d', dir ])
+ Command.__init__(self, 'unzip', ["-q", archive, '-d', dir])
self.run_error = 'Couldn\'t unpack "%s": {err_reason}' % self.archive
@@ -295,7 +329,7 @@ class CatenateZipArchive(Command):
def __call__(self, target):
self.run_error = 'Couldn\'t append "%s" to "%s": {err_reason}' % \
- (target, self.archive)
+ (target, self.archive)
Command.__call__(self, [target])
diff --git a/gbp/config.py b/gbp/config.py
index 3d254ee..f1f7176 100644
--- a/gbp/config.py
+++ b/gbp/config.py
@@ -1,6 +1,6 @@
-# vim: set fileencoding=utf-8 :
+# vim: set fileencoding=utf-8:
#
-# (C) 2006,2007,2010-2012,2015 Guido Guenther <agx@sigxcpu.org>
+# (C) 2006,2007,2010-2012,2015,2016 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
@@ -23,6 +23,7 @@ import errno
import os.path
import sys
+from gbp.errors import GbpError
try:
from gbp.version import gbp_version
@@ -38,10 +39,12 @@ file:///usr/share/doc/git-buildpackage/manual-html/gbp.import.html#GBP.IMPORT.CO
on howto create it otherwise use --upstream-branch to specify it.
"""
+
def expand_path(option, opt, value):
value = os.path.expandvars(value)
return os.path.expanduser(value)
+
def check_tristate(option, opt, value):
try:
val = gbp.tristate.Tristate(value)
@@ -52,14 +55,16 @@ def check_tristate(option, opt, value):
return val
-def safe_option(f):
+def save_option(f):
+ """save options on the underlying parser"""
def _decorator(self, *args, **kwargs):
obj = self
option_name = kwargs.get('option_name')
if not option_name and len(args):
option_name = args[0]
- # We're decorating GbpOption not GbpOptionParser
+ # We're decorating GbpOption but store valid_options on
+ # GbpOptionParser
if not hasattr(obj, 'valid_options'):
if not hasattr(obj, 'parser'):
raise ValueError("Can only decorete GbpOptionParser and GbpOptionGroup not %s" % obj)
@@ -78,6 +83,7 @@ class GbpOption(Option):
TYPE_CHECKER['path'] = expand_path
TYPE_CHECKER['tristate'] = check_tristate
+
class GbpOptionParser(OptionParser):
"""
Handles commandline options and parsing of config files
@@ -95,248 +101,272 @@ class GbpOptionParser(OptionParser):
@cvar def_config_files: config files we parse
@type def_config_files: dict (type, path)
"""
- defaults = { 'debian-branch' : 'master',
- 'upstream-branch' : 'upstream',
- 'upstream-tree' : 'TAG',
- 'pristine-tar' : 'False',
- 'pristine-tar-commit': 'False',
- 'filter-pristine-tar' : 'False',
- 'sign-tags' : 'False',
- 'force-create' : 'False',
- 'no-create-orig' : 'False',
- 'cleaner' : '/bin/true',
- 'keyid' : '',
- 'posttag' : '',
- 'postbuild' : '',
- 'prebuild' : '',
- 'postexport' : '',
- 'postimport' : '',
- 'hooks' : 'True',
- 'debian-tag' : 'debian/%(version)s',
- 'debian-tag-msg' : '%(pkg)s Debian release %(version)s',
- 'upstream-tag' : 'upstream/%(version)s',
- 'import-msg' : 'Imported Upstream version %(version)s',
- 'commit-msg' : 'Update changelog for %(version)s release',
- 'filter' : [],
- 'snapshot-number' : 'snapshot + 1',
- 'git-log' : '--no-merges',
- 'export' : 'HEAD',
- 'export-dir' : '',
- 'overlay' : 'False',
- 'tarball-dir' : '',
- 'ignore-new' : 'False',
- 'ignore-branch' : 'False',
- 'meta' : 'True',
- 'meta-closes' : 'Closes|LP',
- 'meta-closes-bugnum' : r'(?:bug|issue)?\#?\s?\d+',
- 'full' : 'False',
- 'id-length' : '0',
- 'git-author' : 'False',
- 'ignore-regex' : '',
- 'compression' : 'auto',
- 'compression-level': '9',
- 'remote-url-pattern' : 'ssh://git.debian.org/git/collab-maint/%(pkg)s.git',
- 'multimaint' : 'True',
- 'multimaint-merge': 'False',
- 'pbuilder' : 'False',
- 'qemubuilder' : 'False',
- 'dist' : 'sid',
- 'arch' : '',
- 'interactive' : 'True',
- 'color' : 'auto',
- 'color-scheme' : '',
- 'customizations' : '',
- 'spawn-editor' : 'release',
- 'patch-numbers' : 'True',
- 'patch-num-format': '%04d-',
- 'renumber' : 'False',
- 'notify' : 'auto',
- 'merge' : 'True',
- 'merge-mode' : 'merge',
- 'track' : 'True',
- 'author-is-committer': 'False',
- 'author-date-is-committer-date': 'False',
- 'create-missing-branches': 'False',
- 'submodules' : 'False',
- 'time-machine' : 1,
- 'pbuilder-autoconf' : 'True',
- 'pbuilder-options': '',
- 'template-dir': '',
- 'remote-config': '',
- 'allow-unauthenticated': 'False',
- 'symlink-orig': 'True',
- 'purge': 'True',
- 'drop': 'False',
- 'commit': 'False',
- 'upstream-vcs-tag': '',
- }
+ defaults = {'debian-branch': 'master',
+ 'upstream-branch': 'upstream',
+ 'upstream-tree': 'TAG',
+ 'pq-from': 'DEBIAN',
+ 'pristine-tar': 'False',
+ 'pristine-tar-commit': 'False',
+ 'filter-pristine-tar': 'False',
+ 'sign-tags': 'False',
+ 'force-create': 'False',
+ 'no-create-orig': 'False',
+ 'cleaner': '/bin/true',
+ 'keyid': '',
+ 'posttag': '',
+ 'postbuild': '',
+ 'prebuild': '',
+ 'postclone': '',
+ 'postexport': '',
+ 'postimport': '',
+ 'hooks': 'True',
+ 'debian-tag': 'debian/%(version)s',
+ 'debian-tag-msg': '%(pkg)s Debian release %(version)s',
+ 'upstream-tag': 'upstream/%(version)s',
+ 'import-msg': 'New upstream version %(version)s',
+ 'commit-msg': 'Update changelog for %(version)s release',
+ 'filter': [],
+ 'snapshot-number': 'snapshot + 1',
+ 'git-log': '--no-merges',
+ 'export': 'HEAD',
+ 'export-dir': '',
+ 'overlay': 'False',
+ 'tarball-dir': '',
+ 'ignore-new': 'False',
+ 'ignore-branch': 'False',
+ 'meta': 'True',
+ 'meta-closes': 'Closes|LP',
+ 'meta-closes-bugnum': r'(?:bug|issue)?\#?\s?\d+',
+ 'full': 'False',
+ 'id-length': '0',
+ 'git-author': 'False',
+ 'ignore-regex': '',
+ 'compression': 'auto',
+ 'compression-level': '9',
+ 'remote-url-pattern': 'ssh://git.debian.org/git/collab-maint/%(pkg)s.git',
+ 'multimaint': 'True',
+ 'multimaint-merge': 'False',
+ 'pbuilder': 'False',
+ 'qemubuilder': 'False',
+ 'dist': 'sid',
+ 'arch': '',
+ 'interactive': 'True',
+ 'color': 'auto',
+ 'color-scheme': '',
+ 'customizations': '',
+ 'spawn-editor': 'release',
+ 'patch-numbers': 'True',
+ 'patch-num-format': '%04d-',
+ 'renumber': 'False',
+ 'notify': 'auto',
+ 'merge': 'True',
+ 'merge-mode': 'merge',
+ 'track': 'True',
+ 'author-is-committer': 'False',
+ 'author-date-is-committer-date': 'False',
+ 'create-missing-branches': 'False',
+ 'submodules': 'False',
+ 'time-machine': 1,
+ 'pbuilder-autoconf': 'True',
+ 'pbuilder-options': '',
+ 'template-dir': '',
+ 'remote-config': '',
+ 'allow-unauthenticated': 'False',
+ 'symlink-orig': 'True',
+ 'purge': 'True',
+ 'drop': 'False',
+ 'commit': 'False',
+ 'upstream-vcs-tag': '',
+ 'rollback': 'True',
+ 'component': [],
+ 'bare': 'True',
+ 'urgency': 'medium',
+ }
help = {
- 'debian-branch':
- ("Branch the Debian package is being developed on, "
- "default is '%(debian-branch)s'"),
- 'upstream-branch':
- "Upstream branch, default is '%(upstream-branch)s'",
- 'upstream-tree':
- ("Where to generate the upstream tarball from "
- "(tag or branch), default is '%(upstream-tree)s'"),
- 'debian-tag':
- ("Format string for debian tags, "
- "default is '%(debian-tag)s'"),
- 'debian-tag-msg':
- ("Format string for signed debian-tag messages, "
- "default is '%(debian-tag-msg)s'"),
- 'upstream-tag':
- ("Format string for upstream tags, "
- "default is '%(upstream-tag)s'"),
- 'sign-tags':
- "Whether to sign tags, default is '%(sign-tags)s'",
- 'keyid':
- "GPG keyid to sign tags with, default is '%(keyid)s'",
- 'import-msg':
- ("Format string for commit message used to commit "
- "the upstream tarball, default is '%(import-msg)s'"),
- 'commit-msg':
- ("Format string for commit messag used to commit, "
- "the changelog, default is '%(commit-msg)s'"),
- 'pristine-tar':
- ("Use pristine-tar to create orig tarball, "
- "default is '%(pristine-tar)s'"),
- 'pristine-tar-commit':
- ("When generating a tarball commit it to the pristine-tar branch '%(pristine-tar-commit)s' "
- "default is '%(pristine-tar-commit)s'"),
- 'filter-pristine-tar':
- "Filter pristine-tar when filter option is used, default is '%(filter-pristine-tar)s'",
- 'filter':
- "Files to filter out during import (can be given multiple times), default is %(filter)s",
- 'git-author':
- "Use name and email from git-config for changelog trailer, default is '%(git-author)s'",
- 'full':
- "Include the full commit message instead of only the first line, default is '%(full)s'",
- 'meta':
- "Parse meta tags in commit messages, default is '%(meta)s'",
- 'meta-closes':
- "Meta tags for the bts close commands, default is '%(meta-closes)s'",
- 'meta-closes-bugnum':
- "Meta bug number format, default is '%(meta-closes-bugnum)s'",
- 'ignore-new':
- "Build with uncommited changes in the source tree, default is '%(ignore-new)s'",
- 'ignore-branch':
- ("Build although debian-branch != current branch, "
- "default is '%(ignore-branch)s'"),
- 'overlay':
- ("extract orig tarball when using export-dir option, "
- "default is '%(overlay)s'"),
- 'remote-url-pattern':
- ("Remote url pattern to create the repo at, "
- "default is '%(remote-url-pattern)s'"),
- 'multimaint':
- "Note multiple maintainers, default is '%(multimaint)s'",
- 'multimaint-merge':
- ("Merge commits by maintainer, "
- "default is '%(multimaint-merge)s'"),
- 'pbuilder':
- ("Invoke git-pbuilder for building, "
- "default is '%(pbuilder)s'"),
- 'dist':
- ("Build for this distribution when using git-pbuilder, "
- "default is '%(dist)s'"),
- 'arch':
- ("Build for this architecture when using git-pbuilder, "
- "default is '%(arch)s'"),
- 'qemubuilder':
- ("Invoke git-pbuilder with qemubuilder for building, "
- "default is '%(qemubuilder)s'"),
- 'interactive':
- "Run command interactively, default is '%(interactive)s'",
- 'color':
- "Whether to use colored output, default is '%(color)s'",
- 'color-scheme':
- ("Colors to use in output (when color is enabled), format "
- "is '<debug>:<info>:<warning>:<error>', e.g. "
- "'cyan:34::'. Numerical values and color names are "
- "accepted, empty fields indicate using the default."),
- 'spawn-editor':
- ("Whether to spawn an editor after adding the "
- "changelog entry, default is '%(spawn-editor)s'"),
- 'patch-numbers':
- ("Whether to number patch files, "
- "default is %(patch-numbers)s"),
- 'patch-num-format':
- ("The format specifier for patch number prefixes, "
- "default is %(patch-num-format)s"),
- 'renumber':
- ("Whether to renumber patches exported from patch queues, "
- "instead of preserving the number specified in "
- "'Gbp-Pq: Name' tags, default is %(renumber)s"),
- 'notify':
- ("Whether to send a desktop notification after the build, "
- "default is '%(notify)s'"),
- 'merge':
- ("After the import merge the result to the debian branch, "
- "default is '%(merge)s'"),
- 'merge-mode':
- ("Howto merge the new upstream sources onto the debian branch"
- "default is '%(merge-mode)s'"),
- 'track':
- ("Set up tracking for remote branches, "
- "default is '%(track)s'"),
- 'author-is-committer':
- ("Use the authors's name also as the committer's name, "
- "default is '%(author-is-committer)s'"),
- 'author-date-is-committer-date':
- ("Use the authors's date as the committer's date, "
- "default is '%(author-date-is-committer-date)s'"),
- 'create-missing-branches':
- ("Create missing branches automatically, "
- "default is '%(create-missing-branches)s'"),
- 'submodules':
- ("Transparently handle submodules in the upstream tree, "
- "default is '%(submodules)s'"),
- 'postimport':
- ("hook run after a successful import, "
- "default is '%(postimport)s'"),
- 'hooks':
- ("Enable running all hooks, default is %(hooks)s"),
- 'time-machine':
- ("don't try head commit only to apply the patch queue "
- "but look TIME_MACHINE commits back, "
- "default is '%(time-machine)d'"),
- 'pbuilder-autoconf':
- ("Wheter to configure pbuilder automatically, "
- "default is '%(pbuilder-autoconf)s'"),
- 'pbuilder-options':
- ("Options to pass to pbuilder, "
- "default is '%(pbuilder-options)s'"),
- 'template-dir':
- ("Template directory used by git init, "
- "default is '%(template-dir)s'"),
- 'remote-config':
- ("Remote defintion in gbp.conf used to create the remote "
- "repository, default is '%(remote-config)s'"),
- 'allow-unauthenticated':
- ("Don't verify integrity of downloaded source, "
- "default is '%(allow-unauthenticated)s'"),
- 'symlink-orig':
- ("Whether to creat a symlink from the upstream tarball "
- "to the orig.tar.gz if needed, default is "
- "'%(symlink-orig)s'"),
- 'purge':
- "Purge exported package build directory. Default is '%(purge)s'",
- 'drop':
- ("In case of 'export' drop the patch-queue branch "
- "after export. Default is '%(drop)s'"),
- 'commit':
- "commit changes after export, Default is '%(commit)s'",
- }
-
- def_config_files = {'/etc/git-buildpackage/gbp.conf': 'system',
- '~/.gbp.conf': 'global',
- '%(top_dir)s/.gbp.conf': None,
- '%(top_dir)s/debian/gbp.conf': 'debian',
- '%(git_dir)s/gbp.conf': None}
+ 'debian-branch':
+ "Branch the Debian package is being developed on, "
+ "default is '%(debian-branch)s'",
+ 'upstream-branch':
+ "Upstream branch, default is '%(upstream-branch)s'",
+ 'upstream-tree':
+ "Where to generate the upstream tarball from "
+ "(tag or branch), default is '%(upstream-tree)s'",
+ 'pq-from':
+ "How to find the patch queue base. DEBIAN or TAG, "
+ "the default is '%(pq-from)s'",
+ 'debian-tag':
+ "Format string for debian tags, "
+ "default is '%(debian-tag)s'",
+ 'debian-tag-msg':
+ "Format string for signed debian-tag messages, "
+ "default is '%(debian-tag-msg)s'",
+ 'upstream-tag':
+ "Format string for upstream tags, "
+ "default is '%(upstream-tag)s'",
+ 'sign-tags':
+ "Whether to sign tags, default is '%(sign-tags)s'",
+ 'keyid':
+ "GPG keyid to sign tags with, default is '%(keyid)s'",
+ 'import-msg':
+ "Format string for commit message used to commit "
+ "the upstream tarball, default is '%(import-msg)s'",
+ 'commit-msg':
+ "Format string for commit messag used to commit, "
+ "the changelog, default is '%(commit-msg)s'",
+ 'pristine-tar':
+ "Use pristine-tar to create orig tarball, "
+ "default is '%(pristine-tar)s'",
+ 'pristine-tar-commit':
+ "When generating a tarball commit it to the pristine-tar branch '%(pristine-tar-commit)s' "
+ "default is '%(pristine-tar-commit)s'",
+ 'filter-pristine-tar':
+ "Filter pristine-tar when filter option is used, default is '%(filter-pristine-tar)s'",
+ 'filter':
+ "Files to filter out during import (can be given multiple times), default is %(filter)s",
+ 'git-author':
+ "Use name and email from git-config for changelog trailer, default is '%(git-author)s'",
+ 'full':
+ "Include the full commit message instead of only the first line, default is '%(full)s'",
+ 'meta':
+ "Parse meta tags in commit messages, default is '%(meta)s'",
+ 'meta-closes':
+ "Meta tags for the bts close commands, default is '%(meta-closes)s'",
+ 'meta-closes-bugnum':
+ "Meta bug number format, default is '%(meta-closes-bugnum)s'",
+ 'ignore-new':
+ "Build with uncommitted changes in the source tree, default is '%(ignore-new)s'",
+ 'ignore-branch':
+ "Build although debian-branch != current branch, "
+ "default is '%(ignore-branch)s'",
+ 'overlay':
+ "extract orig tarball when using export-dir option, "
+ "default is '%(overlay)s'",
+ 'remote-url-pattern':
+ "Remote url pattern to create the repo at, "
+ "default is '%(remote-url-pattern)s'",
+ 'multimaint':
+ "Note multiple maintainers, default is '%(multimaint)s'",
+ 'multimaint-merge':
+ "Merge commits by maintainer, "
+ "default is '%(multimaint-merge)s'",
+ 'pbuilder':
+ "Invoke git-pbuilder for building, "
+ "default is '%(pbuilder)s'",
+ 'dist':
+ "Build for this distribution when using git-pbuilder, "
+ "default is '%(dist)s'",
+ 'arch':
+ "Build for this architecture when using git-pbuilder, "
+ "default is '%(arch)s'",
+ 'qemubuilder':
+ "Invoke git-pbuilder with qemubuilder for building, "
+ "default is '%(qemubuilder)s'",
+ 'interactive':
+ "Run command interactively, default is '%(interactive)s'",
+ 'color':
+ "Whether to use colored output, default is '%(color)s'",
+ 'color-scheme':
+ "Colors to use in output (when color is enabled), format "
+ "is '<debug>:<info>:<warning>:<error>', e.g. "
+ "'cyan:34::'. Numerical values and color names are "
+ "accepted, empty fields indicate using the default.",
+ 'spawn-editor':
+ "Whether to spawn an editor after adding the "
+ "changelog entry, default is '%(spawn-editor)s'",
+ 'patch-numbers':
+ "Whether to number patch files, "
+ "default is %(patch-numbers)s",
+ 'patch-num-format':
+ "The format specifier for patch number prefixes, "
+ "default is %(patch-num-format)s",
+ 'renumber':
+ "Whether to renumber patches exported from patch queues, "
+ "instead of preserving the number specified in "
+ "'Gbp-Pq: Name' tags, default is %(renumber)s",
+ 'notify':
+ "Whether to send a desktop notification after the build, "
+ "default is '%(notify)s'",
+ 'merge':
+ "After the import merge the result to the debian branch, "
+ "default is '%(merge)s'",
+ 'merge-mode':
+ "Howto merge the new upstream sources onto the debian branch"
+ "default is '%(merge-mode)s'",
+ 'track':
+ "Set up tracking for remote branches, "
+ "default is '%(track)s'",
+ 'author-is-committer':
+ "Use the authors's name also as the committer's name, "
+ "default is '%(author-is-committer)s'",
+ 'author-date-is-committer-date':
+ "Use the authors's date as the committer's date, "
+ "default is '%(author-date-is-committer-date)s'",
+ 'create-missing-branches':
+ "Create missing branches automatically, "
+ "default is '%(create-missing-branches)s'",
+ 'submodules':
+ "Transparently handle submodules in the upstream tree, "
+ "default is '%(submodules)s'",
+ 'postimport':
+ "hook run after a successful import, "
+ "default is '%(postimport)s'",
+ 'hooks':
+ "Enable running all hooks, default is %(hooks)s",
+ 'time-machine':
+ "don't try head commit only to apply the patch queue "
+ "but look TIME_MACHINE commits back, "
+ "default is '%(time-machine)d'",
+ 'pbuilder-autoconf':
+ "Whether to configure pbuilder automatically, "
+ "default is '%(pbuilder-autoconf)s'",
+ 'pbuilder-options':
+ "Options to pass to pbuilder, "
+ "default is '%(pbuilder-options)s'",
+ 'template-dir':
+ "Template directory used by git init, "
+ "default is '%(template-dir)s'",
+ 'remote-config':
+ "Remote defintion in gbp.conf used to create the remote "
+ "repository, default is '%(remote-config)s'",
+ 'allow-unauthenticated':
+ "Don't verify integrity of downloaded source, "
+ "default is '%(allow-unauthenticated)s'",
+ 'symlink-orig':
+ "Whether to creat a symlink from the upstream tarball "
+ "to the orig.tar.gz if needed, default is "
+ "'%(symlink-orig)s'",
+ 'purge':
+ "Purge exported package build directory. Default is '%(purge)s'",
+ 'drop':
+ "In case of 'export' drop the patch-queue branch "
+ "after export. Default is '%(drop)s'",
+ 'commit':
+ "commit changes after export, Default is '%(commit)s'",
+ 'rollback':
+ "Rollback repository changes when encountering an error",
+ 'component':
+ 'component name for additional tarballs',
+ 'bare':
+ "wether to create a bare repository on the remote side. "
+ "'Default is '%(bare)s'.",
+ 'urgency':
+ "Set urgency level, default is '%(urgency)s'"
+ }
+
+ short_opts = {
+ 'urgency': '-U',
+ }
+
+ def_config_files = [('/etc/git-buildpackage/gbp.conf', 'system'),
+ ('~/.gbp.conf', 'global'),
+ ('%(top_dir)s/.gbp.conf', None),
+ ('%(top_dir)s/debian/gbp.conf', 'debian'),
+ ('%(git_dir)s/gbp.conf', None)]
+
+ list_opts = ['filter', 'component']
@classmethod
- def get_config_files(klass, no_local=False):
+ def get_config_files(cls, no_local=False):
"""
Get list of config files from the I{GBP_CONF_FILES} environment
variable.
@@ -364,7 +394,7 @@ class GbpOptionParser(OptionParser):
>>> if conf_backup is not None: os.environ['GBP_CONF_FILES'] = conf_backup
"""
envvar = os.environ.get('GBP_CONF_FILES')
- files = envvar.split(':') if envvar else klass.def_config_files.keys()
+ files = envvar.split(':') if envvar else [f for (f, _) in cls.def_config_files]
files = [os.path.expanduser(fname) for fname in files]
if no_local:
files = [fname for fname in files if fname.startswith('/')]
@@ -382,6 +412,10 @@ class GbpOptionParser(OptionParser):
except KeyError:
# Skip if filename wasn't expanded, i.e. we're not in git repo
return
+ if (repo and
+ filename == os.path.join(repo.path, '.gbp.conf') and
+ os.path.exists(filename)):
+ self._warn_old_gbp_conf(filename)
parser.read(filename)
def _warn_old_config_section(self, oldcmd, cmd):
@@ -389,6 +423,57 @@ class GbpOptionParser(OptionParser):
gbp.log.warn("Old style config section [%s] found "
"please rename to [%s]" % (oldcmd, cmd))
+ def _warn_old_gbp_conf(self, gbp_conf):
+ if (not os.getenv("GBP_DISABLE_GBP_CONF_DEPRECTATION") and
+ not self._warned_old_gbp_conf):
+ gbp.log.warn("Deprecated configuration file found at %s, "
+ "check gbp.conf(5) for alternatives" % gbp_conf)
+ self._warned_old_gbp_conf = True
+
+ @staticmethod
+ def _listify(value):
+ """
+ >>> GbpOptionParser._listify(None)
+ []
+ >>> GbpOptionParser._listify('string')
+ ['string']
+ >>> GbpOptionParser._listify('["q", "e", "d"] ')
+ ['q', 'e', 'd']
+ >>> GbpOptionParser._listify('[')
+ Traceback (most recent call last):
+ ...
+ Error: [ is not a proper list
+ """
+ # filter can be either a list or a string, always build a list:
+ if value:
+ if value.startswith('['):
+ try:
+ return eval(value)
+ except SyntaxError:
+ raise configparser.Error("%s is not a proper list" % value)
+ else:
+ return [value]
+ else:
+ return []
+
+ def parse_lists(self):
+ """
+ Parse options that can be given as lists
+
+ Since they take multiple arguments they can also be given in plural form
+ e.g. components instead of component.
+ """
+ for opt in self.list_opts:
+ try:
+ plural_opt = opt + 's'
+ valp = self._listify(self.config.get(plural_opt, None))
+ vals = self._listify(self.config[opt])
+ if valp and vals:
+ raise configparser.Error("Found %s and %s - use only one" % (valp, vals))
+ self.config[opt] = valp or vals
+ except ValueError:
+ raise configparser.Error("Failed to parse %s: %s" % (opt, self.config[opt]))
+
def parse_config_files(self):
"""
Parse the possible config files and set appropriate values
@@ -412,7 +497,7 @@ class GbpOptionParser(OptionParser):
# Make sure we read any legacy sections prior to the real subcommands
# section i.e. read [gbp-pull] prior to [pull]
if (self.command.startswith('gbp-') or
- self.command.startswith('git-')):
+ self.command.startswith('git-')):
cmd = self.command[4:]
oldcmd = self.command
if parser.has_section(oldcmd):
@@ -437,16 +522,9 @@ class GbpOptionParser(OptionParser):
self.config.update(dict(parser._sections[section].items()))
else:
raise configparser.NoSectionError(
- "Mandatory section [%s] does not exist." % section)
+ "Mandatory section [%s] does not exist." % section)
- # filter can be either a list or a string, always build a list:
- if self.config['filter']:
- if self.config['filter'].startswith('['):
- self.config['filter'] = eval(self.config['filter'])
- else:
- self.config['filter'] = [ self.config['filter'] ]
- else:
- self.config['filter'] = []
+ self.parse_lists()
def __init__(self, command, prefix='', usage=None, sections=[]):
"""
@@ -464,15 +542,16 @@ class GbpOptionParser(OptionParser):
self.sections = sections
self.prefix = prefix
self.config = {}
- self.parse_config_files()
self.valid_options = []
+ self._warned_old_gbp_conf = False
+
+ try:
+ self.parse_config_files()
+ except configparser.ParsingError as err:
+ raise GbpError(str(err) + "\nSee 'man gbp.conf' for the format.")
- if self.command.startswith('git-') or self.command.startswith('gbp-'):
- prog = self.command
- else:
- prog = "gbp %s" % self.command
OptionParser.__init__(self, option_class=GbpOption,
- prog=prog,
+ prog="gbp %s" % self.command,
usage=usage, version='%s %s' % (self.command,
gbp_version))
@@ -480,10 +559,10 @@ class GbpOptionParser(OptionParser):
"""is option_name a boolean option"""
ret = False
try:
- if kwargs['action'] in [ 'store_true', 'store_false' ]:
- ret=True
+ if kwargs['action'] in ['store_true', 'store_false']:
+ ret = True
except KeyError:
- ret=False
+ ret = False
return ret
def _get_bool_default(self, option_name):
@@ -503,9 +582,9 @@ class GbpOptionParser(OptionParser):
except KeyError:
default = self.config[neg]
- if default.lower() in ["true", "1" ]:
+ if default.lower() in ["true", "1"]:
val = 'True'
- elif default.lower() in ["false", "0" ]:
+ elif default.lower() in ["false", "0"]:
val = 'False'
else:
raise ValueError("Boolean options must be True or False")
@@ -519,7 +598,15 @@ class GbpOptionParser(OptionParser):
default = self.config[option_name]
return default
- @safe_option
+ def get_opt_names(self, option_name):
+ names = ["--%s%s" % (self.prefix, option_name)]
+ if option_name in self.short_opts:
+ if self.prefix:
+ raise ValueError("Options with prefix cannot have a short option")
+ names.insert(0, self.short_opts[option_name])
+ return names
+
+ @save_option
def add_config_file_option(self, option_name, dest, help=None, **kwargs):
"""
set a option for the command line parser, the default is read from the config file
@@ -532,7 +619,8 @@ class GbpOptionParser(OptionParser):
"""
if not help:
help = self.help[option_name]
- OptionParser.add_option(self, "--%s%s" % (self.prefix, option_name), dest=dest,
+ opt_names = self.get_opt_names(option_name)
+ OptionParser.add_option(self, *opt_names, dest=dest,
default=self.get_default(option_name, **kwargs),
help=help % self.config, **kwargs)
@@ -579,7 +667,7 @@ class GbpOptionParser(OptionParser):
>>> GbpOptionParser._name_to_filename('debian')
'%(top_dir)s/debian/gbp.conf'
"""
- for k, v in cls.def_config_files.items():
+ for k, v in cls.def_config_files:
if name == v:
return k
else:
@@ -608,7 +696,7 @@ class GbpOptionParser(OptionParser):
class GbpOptionGroup(OptionGroup):
- @safe_option
+ @save_option
def add_config_file_option(self, option_name, dest, help=None, **kwargs):
"""
set a option for the command line parser, the default is read from the config file
@@ -621,9 +709,10 @@ class GbpOptionGroup(OptionGroup):
"""
if not help:
help = self.parser.help[option_name]
- OptionGroup.add_option(self, "--%s%s" % (self.parser.prefix, option_name), dest=dest,
- default=self.parser.get_default(option_name, **kwargs),
- help=help % self.parser.config, **kwargs)
+ opt_names = self.parser.get_opt_names(option_name)
+ OptionGroup.add_option(self, *opt_names, dest=dest,
+ default=self.parser.get_default(option_name, **kwargs),
+ help=help % self.parser.config, **kwargs)
def add_boolean_config_file_option(self, option_name, dest):
self.add_config_file_option(option_name=option_name, dest=dest, action="store_true")
@@ -636,9 +725,13 @@ class GbpOptionParserDebian(GbpOptionParser):
Handles commandline options and parsing of config files for Debian tools
"""
defaults = dict(GbpOptionParser.defaults)
- defaults.update( {
- 'builder' : 'debuild -i -I',
- } )
+ defaults.update({
+ 'builder': 'debuild -i -I',
+ })
+
+ def _warn_old_gbp_conf(self, gbp_conf):
+ if os.path.exists("debian/control"):
+ GbpOptionParser._warn_old_gbp_conf(self, gbp_conf)
class GbpOptionParserRpm(GbpOptionParser):
@@ -647,28 +740,32 @@ class GbpOptionParserRpm(GbpOptionParser):
"""
defaults = dict(GbpOptionParser.defaults)
defaults.update({
- 'tmp-dir' : '/var/tmp/gbp/',
- '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' : '',
- 'mock' : 'False',
- 'dist' : '',
- 'arch' : '',
- 'mock-root' : '',
- 'mock-options' : '',
- 'native' : 'auto',
- })
+ 'tmp-dir': '/var/tmp/gbp/',
+ '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': '',
+ 'mock': 'False',
+ 'dist': '',
+ 'arch': '',
+ 'mock-root': '',
+ 'mock-options': '',
+ 'native': 'auto',
+ 'changelog-file': 'auto',
+ 'changelog-revision': '',
+ 'spawn-editor': 'always',
+ 'editor-cmd': 'vim',
+ })
help = dict(GbpOptionParser.help)
- help.update({
+ help.update(
+ {
'tmp-dir':
"Base directory under which temporary directories are "
"created, default is '%(tmp-dir)s'",
@@ -685,8 +782,8 @@ class GbpOptionParserRpm(GbpOptionParser):
"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'"),
+ "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'",
@@ -697,23 +794,39 @@ class GbpOptionParserRpm(GbpOptionParser):
'export-specdir':
"Subdir (under EXPORT_DIR) where package spec file is "
"exported default is '%(export-specdir)s'",
- 'mock':
- ("Invoke mock for building using gbp-builder-mock, "
- "default is '%(mock)s'"),
- 'dist':
- ("Build for this distribution when using mock. E.g.: epel-6, "
- "default is '%(dist)s'"),
- 'arch':
- ("Build for this architecture when using mock, "
- "default is '%(arch)s'"),
- 'mock-root':
- ("The mock root (-r) name for building with mock: <dist>-<arch>, "
- "default is '%(mock-root)s'"),
- 'mock-options':
- ("Options to pass to mock, "
- "default is '%(mock-options)s'"),
+ 'mock':
+ "Invoke mock for building using gbp-builder-mock, "
+ "default is '%(mock)s'",
+ 'dist':
+ "Build for this distribution when using mock. E.g.: epel-6, "
+ "default is '%(dist)s'",
+ 'arch':
+ "Build for this architecture when using mock, "
+ "default is '%(arch)s'",
+ 'mock-root':
+ "The mock root (-r) name for building with mock: <dist>-<arch>, "
+ "default is '%(mock-root)s'",
+ 'mock-options':
+ "Options to pass to mock, "
+ "default is '%(mock-options)s'",
'native':
"Treat this package as native, default is '%(native)s'",
- })
+ 'changelog-file':
+ "Changelog file to be used, default is '%(changelog-file)s'",
+ 'changelog-revision':
+ "Format string for the revision field in the changelog header. "
+ "If empty or not defined the default from packaging policy is "
+ "used.",
+ 'editor-cmd':
+ "Editor command to use",
+ 'git-author':
+ "Use name and email from git-config for the changelog header, "
+ "default is '%(git-author)s'",
+ })
+
+ def _warn_old_gbp_conf(self, gbp_conf):
+ # The rpm based tools use $repo/.gbp.conf a lot, don't
+ # warn there yet
+ pass
# vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·:
diff --git a/gbp/dch.py b/gbp/dch.py
index 3dcfc85..d72152b 100644
--- a/gbp/dch.py
+++ b/gbp/dch.py
@@ -20,6 +20,7 @@ import re
MAX_CHANGELOG_LINE_LENGTH = 76
+
def extract_git_dch_cmds(lines, options):
"""Return a dictionary of all Git-Dch: commands found in lines.
The command keys will be lowercased, i.e. {'ignore' : True,
@@ -45,6 +46,7 @@ def filter_ignore_rx_matches(lines, options):
else:
return lines
+
def extract_bts_cmds(lines, opts):
"""Return a dictionary of the bug tracking system commands
contained in the the given lines. i.e. {'closed' : [1], 'fixed':
@@ -58,7 +60,7 @@ def extract_bts_cmds(lines, opts):
for line in lines:
m = bts_rx.match(line)
if m:
- bug_nums = [ bug.strip() for bug in _bug_re.findall(line, re.I) ]
+ bug_nums = [bug.strip() for bug in _bug_re.findall(line, re.I)]
try:
commands[m.group('bts')] += bug_nums
except KeyError:
@@ -72,9 +74,10 @@ def extract_thanks_info(lines, options):
"""Return a list of all of the Thanks: entries, and a list of all
of the lines that do not contain Thanks: entries."""
thanks = []
+ thanks_re = re.compile(r'thanks:\s+', re.I)
other_lines = []
for line in lines:
- if line.startswith('Thanks: '):
+ if thanks_re.match(line):
thanks.append(line.split(' ', 1)[1].strip())
else:
other_lines.append(line)
@@ -113,13 +116,13 @@ def format_changelog_entry(commit_info, options, last_commit=False):
entry[0] = '[%s] ' % commitid[0:options.idlen] + entry[0]
bts_cmds = {}
- thanks = []
+ thanks = []
if options.meta:
(bts_cmds, body) = extract_bts_cmds(body, options)
(thanks, body) = extract_thanks_info(body, options)
body = filter_ignore_rx_matches(body, options)
- if 'full' in git_dch_cmds or (options.full and not 'short' in git_dch_cmds):
+ if 'full' in git_dch_cmds or (options.full and 'short' not in git_dch_cmds):
# Add all non-blank body lines.
entry.extend([line for line in body if line.strip()])
if thanks:
diff --git a/gbp/deb/__init__.py b/gbp/deb/__init__.py
index 234d781..6a240ec 100644
--- a/gbp/deb/__init__.py
+++ b/gbp/deb/__init__.py
@@ -27,6 +27,7 @@ from gbp.git import GitRepositoryError
from gbp.deb.changelog import ChangeLog, NoChangeLogError
from gbp.deb.policy import DebianPkgPolicy
+
class DpkgCompareVersions(gbpc.Command):
dpkg = '/usr/bin/dpkg'
@@ -43,16 +44,16 @@ class DpkgCompareVersions(gbpc.Command):
@raises CommandExecFailed: if the version comparison fails
"""
self.run_error = "Couldn't compare %s with %s" % (version1, version2)
- res = self.call([ version1, 'lt', version2 ])
- if res not in [ 0, 1 ]:
+ res = self.call([version1, 'lt', version2])
+ if res not in [0, 1]:
if self.stderr:
self.run_error += ' (%s)' % self.stderr
raise gbpc.CommandExecFailed("%s: bad return code %d" % (self.run_error, res))
if res == 0:
return -1
elif res == 1:
- res = self.call([ version1, 'gt', version2 ])
- if res not in [ 0, 1 ]:
+ res = self.call([version1, 'gt', version2])
+ if res not in [0, 1]:
if self.stderr:
self.run_error += ' (%s)' % self.stderr
raise gbpc.CommandExecFailed("%s: bad return code %d" % (self.run_error, res))
@@ -80,7 +81,7 @@ def parse_changelog_repo(repo, branch, filename):
return ChangeLog(repo.show(sha))
-def orig_file(cp, compression, subtarball=None):
+def orig_file(cp, compression, component=None):
"""
The name of the orig file belonging to changelog cp
@@ -88,13 +89,13 @@ def orig_file(cp, compression, subtarball=None):
'foo_1.0.orig.tar.bz2'
>>> orig_file({'Source': 'bar', 'Upstream-Version': '0.0~git1234'}, "xz")
'bar_0.0~git1234.orig.tar.xz'
- >>> orig_file({'Source': 'bar', 'Upstream-Version': '0.0~git1234'}, "xz", subtarball="sub1")
+ >>> orig_file({'Source': 'bar', 'Upstream-Version': '0.0~git1234'}, "xz", component="sub1")
'bar_0.0~git1234.orig-sub1.tar.xz'
"""
return DebianPkgPolicy.build_tarball_name(cp['Source'],
cp['Upstream-Version'],
compression,
- subtarball=subtarball)
+ component=component)
def get_arch():
diff --git a/gbp/deb/changelog.py b/gbp/deb/changelog.py
index fa4ba10..42fcb57 100644
--- a/gbp/deb/changelog.py
+++ b/gbp/deb/changelog.py
@@ -23,10 +23,12 @@ import os
import subprocess
from gbp.command_wrappers import Command
+
class NoChangeLogError(Exception):
"""No changelog found"""
pass
+
class ParseChangeLogError(Exception):
"""Problem parsing changelog"""
pass
@@ -47,7 +49,7 @@ class ChangeLogSection(object):
return self._version
@classmethod
- def parse(klass, section):
+ def parse(cls, section):
"""
Parse one changelog section
@@ -59,7 +61,7 @@ class ChangeLogSection(object):
header = section.split('\n')[0]
package = header.split()[0]
version = header.split()[1][1:-1]
- return klass(package, version)
+ return cls(package, version)
class ChangeLog(object):
@@ -92,9 +94,9 @@ class ChangeLog(object):
def _parse(self):
"""Parse a changelog based on the already read contents."""
cmd = subprocess.Popen(['dpkg-parsechangelog', '-l-'],
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
(output, errors) = cmd.communicate(self._contents)
if cmd.returncode:
raise ParseChangeLogError("Failed to parse changelog. "
@@ -138,8 +140,8 @@ class ChangeLog(object):
@property
def version(self):
- """The full version string"""
- return self._cp['Version']
+ """The full version string"""
+ return self._cp['Version']
@property
def upstream_version(self):
@@ -198,7 +200,7 @@ class ChangeLog(object):
"""
section = ''
for line in self._contents.split('\n'):
- if line and line[0] not in [ ' ', '\t' ]:
+ if line and line[0] not in [' ', '\t']:
section += line
else:
if section:
diff --git a/gbp/deb/control.py b/gbp/deb/control.py
index 603b3de..efa92ca 100644
--- a/gbp/deb/control.py
+++ b/gbp/deb/control.py
@@ -19,14 +19,17 @@
import email
import os
+
class NoControlError(Exception):
"""No control found"""
pass
+
class ParseControlError(Exception):
"""Problem parsing control"""
pass
+
class Control(object):
"""A Debian control"""
diff --git a/gbp/deb/dscfile.py b/gbp/deb/dscfile.py
index 16133b4..e81e0bb 100644
--- a/gbp/deb/dscfile.py
+++ b/gbp/deb/dscfile.py
@@ -29,16 +29,16 @@ class DscFile(object):
compressions = r"(%s)" % '|'.join(DebianUpstreamSource.known_compressions())
pkg_re = re.compile(r'Source:\s+(?P<pkg>.+)\s*')
version_re = re.compile(r'Version:\s((?P<epoch>\d+)\:)?'
- '(?P<version>[%s]+)\s*$'
+ '(?P<version>[%s]+)\s*$'
% DebianPkgPolicy.debianversion_chars)
tar_re = re.compile(r'^\s\w+\s\d+\s+(?P<tar>[^_]+_[^_]+'
- '(\.orig)?\.tar\.%s)' % compressions)
+ '(\.orig)?\.tar\.%s)' % compressions)
add_tar_re = re.compile(r'^\s\w+\s\d+\s+(?P<tar>[^_]+_[^_]+'
'\.orig-(?P<dir>[a-z0-9-]+)\.tar\.%s)' % compressions)
diff_re = re.compile(r'^\s\w+\s\d+\s+(?P<diff>[^_]+_[^_]+'
- '\.diff.(gz|bz2))')
+ '\.diff.(gz|bz2))')
deb_tgz_re = re.compile(r'^\s\w+\s\d+\s+(?P<deb_tgz>[^_]+_[^_]+'
- '\.debian.tar.%s)' % compressions)
+ '\.debian.tar.%s)' % compressions)
format_re = re.compile(r'Format:\s+(?P<format>[0-9.]+)\s*')
def __init__(self, dscfile):
@@ -63,7 +63,7 @@ class DscFile(object):
self.upstream_version = "-".join(m.group('version').split("-")[0:-1])
self.native = False
else:
- self.native = True # Debian native package
+ self.native = True # Debian native package
self.upstream_version = m.group('version')
if m.group('epoch'):
self.epoch = m.group('epoch')
@@ -97,22 +97,30 @@ class DscFile(object):
continue
f.close()
+ # Source format 1.0 can have non-native packages without a Debian revision:
+ # e.g. http://snapshot.debian.org/archive/debian/20090801T192339Z/pool/main/l/latencytop/latencytop_0.5.dsc
+ if self.pkgformat == "1.0" and self.diff:
+ self.native = False
+ elif not self.native and not self.debian_version:
+ raise GbpError("Cannot parse Debian version number from '%s'" % self.dscfile)
+
if not self.pkg:
raise GbpError("Cannot parse package name from '%s'" % self.dscfile)
elif not self.tgz:
raise GbpError("Cannot parse archive name from '%s'" % self.dscfile)
if not self.upstream_version:
raise GbpError("Cannot parse version number from '%s'" % self.dscfile)
- if not self.native and not self.debian_version:
- raise GbpError("Cannot parse Debian version number from '%s'" % self.dscfile)
self.additional_tarballs = dict(add_tars)
def _get_version(self):
- version = [ "", self.epoch + ":" ][len(self.epoch) > 0]
+ version = ["", self.epoch + ":"][len(self.epoch) > 0]
if self.native:
version += self.upstream_version
else:
- version += "%s-%s" % (self.upstream_version, self.debian_version)
+ if self.debian_version != '':
+ version += "%s-%s" % (self.upstream_version, self.debian_version)
+ else: # possible in 1.0
+ version += "%s" % self.upstream_version
return version
version = property(_get_version)
diff --git a/gbp/deb/format.py b/gbp/deb/format.py
index b9c4eb0..2717d4b 100644
--- a/gbp/deb/format.py
+++ b/gbp/deb/format.py
@@ -16,9 +16,11 @@
# <http://www.gnu.org/licenses/>
"""Parse debian/source/format"""
+
class DebianSourceFormatError(Exception):
pass
+
class DebianSourceFormat(object):
"""
Contents of debian/source/format
@@ -47,8 +49,7 @@ class DebianSourceFormat(object):
self._version = parts[0]
if len(parts) == 2:
- if (parts[1][0] == '(' and
- parts[1][-1] == ')'):
+ if (parts[1][0] == '(' and parts[1][-1] == ')'):
self._type = parts[1][1:-1]
else:
raise DebianSourceFormatError("Cannot get source format from "
@@ -73,7 +74,7 @@ class DebianSourceFormat(object):
return "%s (%s)" % (self._version, self._type)
@classmethod
- def parse_file(klass, filename):
+ def parse_file(cls, filename):
"""
Parse debian/source/format file
@@ -94,10 +95,10 @@ class DebianSourceFormat(object):
>>> os.unlink(t.name)
"""
with open(filename) as f:
- return klass(f.read())
+ return cls(f.read())
@classmethod
- def from_content(klass, version, type, format_file=None):
+ def from_content(cls, version, type, format_file=None):
"""
Write a format file from I{type} and I{format} at
I{format_file}
@@ -107,10 +108,11 @@ class DebianSourceFormat(object):
@param format_file: the format file to create with
the above parameters
"""
- format_file = format_file or klass.format_file
- with open(klass.format_file, 'w') as f:
+ format_file = format_file or cls.format_file
+ with open(cls.format_file, 'w') as f:
f.write("%s (%s)" % (version, type))
- return klass.parse_file(klass.format_file)
+ return cls.parse_file(cls.format_file)
+
if __name__ == "__main__":
import doctest
diff --git a/gbp/deb/git.py b/gbp/deb/git.py
index a4bb85f..23d3ee7 100644
--- a/gbp/deb/git.py
+++ b/gbp/deb/git.py
@@ -21,9 +21,17 @@ from gbp.git import GitRepository, GitRepositoryError
from gbp.deb.pristinetar import DebianPristineTar
from gbp.format import format_str
+import gbp.log
+
+
class DebianGitRepository(GitRepository):
"""A git repository that holds the source of a Debian package"""
+ version_mangle_re = (r'%\(version'
+ '%(?P<M>[^%])'
+ '%(?P<R>([^%]|\\%))+'
+ '\)s')
+
def __init__(self, path):
super(DebianGitRepository, self).__init__(path)
self.pristine_tar = DebianPristineTar(self)
@@ -72,7 +80,7 @@ class DebianGitRepository(GitRepository):
"""
tag = self.version_to_tag(format, version)
legacy_tag = self._build_legacy_tag(format, version)
- if self.has_tag(tag): # new tags are injective
+ if self.has_tag(tag): # new tags are injective
# dereference to a commit object
return self.rev_parse("%s^0" % tag)
elif self.has_tag(legacy_tag):
@@ -83,7 +91,7 @@ class DebianGitRepository(GitRepository):
if line.endswith(" %s\n" % version):
# dereference to a commit object
return self.rev_parse("%s^0" % legacy_tag)
- elif line.startswith('---'): # GPG signature start
+ elif line.startswith('---'): # GPG signature start
return None
return None
@@ -124,13 +132,13 @@ class DebianGitRepository(GitRepository):
>>> DebianGitRepository._build_legacy_tag('upstream/%(version)s', '1:2.0~3')
'upstream/2.0.3'
"""
- if ':' in version: # strip of any epochs
+ if ':' in version: # strip of any epochs
version = version.split(':', 1)[1]
version = version.replace('~', '.')
return format % dict(version=version)
- @staticmethod
- def version_to_tag(format, version):
+ @classmethod
+ def version_to_tag(cls, format, version):
"""Generate a tag from a given format and a version
%(version)s provides a clean version that works as a git tag.
@@ -139,19 +147,69 @@ class DebianGitRepository(GitRepository):
hversion is useful for upstreams with tagging policies that prohibit .
characters.
+ %(version%A%B)s provides %(version)s with string 'A' replaced by 'B'.
+ This way, simple version mangling is possible via substitution.
+ Inside the substition string, '%' needs to be escaped. See the
+ examples below.
+
>>> DebianGitRepository.version_to_tag("debian/%(version)s", "0:0~0")
'debian/0%0_0'
>>> DebianGitRepository.version_to_tag("libfoo-%(hversion)s", "1.8.1")
'libfoo-1-8-1'
+ >>> DebianGitRepository.version_to_tag("v%(version%.%_)s", "1.2.3")
+ 'v1_2_3'
+ >>> DebianGitRepository.version_to_tag("%(version%-%\%)s", "0-1.2.3")
+ '0%1.2.3'
+ """
+ f, v = cls._mangle_version(format, version)
+ return format_str(f, dict(version=cls._sanitize_version(v),
+ hversion=cls._sanitize_version(v).replace('.', '-')))
+
+ @classmethod
+ def _mangle_version(cls, format, version):
+ """
+ Basic version mangling to replce single characters
+ >>> DebianGitRepository._mangle_version("%(version%-%\%)s", "0-1.2.3")
+ ('%(version)s', '0%1.2.3')
"""
- return format_str(format, dict(version=DebianGitRepository._sanitize_version(version),
- hversion=DebianGitRepository._sanitize_version(version).replace('.','-')))
+ r = re.search(cls.version_mangle_re, format)
+ if r:
+ f = re.sub(cls.version_mangle_re, "%(version)s", format)
+ v = version.replace(r.group('M'), r.group('R').replace('\%', '%'))
+ return f, v
+ else:
+ return format, version
+
+ @classmethod
+ def _unmangle_format(cls, format):
+ """
+ Reverse of _mangle_version for format
+ """
+ r = re.search(cls.version_mangle_re, format)
+ if r:
+ return re.sub(cls.version_mangle_re, "%(version)s", format)
+ else:
+ return format
+
+ @classmethod
+ def _unmangle_version(cls, format, tag):
+ """
+ Reverse of _mangle_version for version
+ """
+ r = re.search(cls.version_mangle_re, format)
+ if r:
+ v = tag.replace(r.group('R').replace('\%', '%'), r.group('M'))
+ return v
+ else:
+ return tag
@staticmethod
def _sanitize_version(version):
"""sanitize a version so git accepts it as a tag
+ as descirbed in DEP14
+
>>> DebianGitRepository._sanitize_version("0.0.0")
'0.0.0'
>>> DebianGitRepository._sanitize_version("0.0~0")
@@ -160,25 +218,47 @@ class DebianGitRepository(GitRepository):
'0%0.0'
>>> DebianGitRepository._sanitize_version("0%0~0")
'0%0_0'
+ >>> DebianGitRepository._sanitize_version("0....0")
+ '0.#.#.#.0'
+ >>> DebianGitRepository._sanitize_version("0.lock")
+ '0.#lock'
"""
- return version.replace('~', '_').replace(':', '%')
+ v = re.sub('\.(?=\.|$|lock$)', '.#', version)
+ return v.replace('~', '_').replace(':', '%')
@staticmethod
- def tag_to_version(tag, format):
+ def _unsanitize_version(tag):
+ """Reverse _sanitize_version
+
+ as descirbed in DEP14
+
+ >>> DebianGitRepository._unsanitize_version("1%0_bpo3")
+ '1:0~bpo3'
+ >>> DebianGitRepository._unsanitize_version("1%0_bpo3.#.")
+ '1:0~bpo3..'
+ """
+ return tag.replace('_', '~').replace('%', ':').replace('#', '')
+
+ @classmethod
+ def tag_to_version(cls, tag, format):
"""Extract the version from a tag
>>> DebianGitRepository.tag_to_version("upstream/1%2_3-4", "upstream/%(version)s")
'1:2~3-4'
>>> DebianGitRepository.tag_to_version("foo/2.3.4", "foo/%(version)s")
'2.3.4'
+ >>> DebianGitRepository.tag_to_version("v1-2-3", "v%(version%.%-)s")
+ '1.2.3'
+ >>> DebianGitRepository.tag_to_version("v1.#.2", "v%(version%.%-)s")
+ '1..2'
>>> DebianGitRepository.tag_to_version("foo/2.3.4", "upstream/%(version)s")
"""
- version_re = format.replace('%(version)s',
- '(?P<version>[\w_%+-.]+)')
+ f = cls._unmangle_format(format)
+ version_re = f.replace('%(version)s', '(?P<version>[\w_%+-.#]+)')
r = re.match(version_re, tag)
if r:
- version = r.group('version').replace('_', '~').replace('%', ':')
- return version
+ v = cls._unsanitize_version(r.group('version'))
+ return cls._unmangle_version(format, v)
return None
@property
@@ -191,7 +271,7 @@ class DebianGitRepository(GitRepository):
def has_pristine_tar_branch(self):
"""
- Wheter the repo has a I{pristine-tar} branch.
+ Whether the repo has a I{pristine-tar} branch.
@return: C{True} if the repo has pristine-tar commits already, C{False}
otherwise
@@ -199,4 +279,25 @@ class DebianGitRepository(GitRepository):
"""
return True if self.has_branch(self.pristine_tar_branch) else False
+ def create_pristinetar_commits(self, upstream_tree, tarball, component_tarballs):
+ """
+ Create pristine-tar commits for a package with main tarball tarball
+ and (optionl) component tarballs based on upstream_tree
+
+ @param tarball: path to main tarball
+ @param component_tarballs: C{list} of C{tuple}s of component
+ name and path to additional tarball
+ @param upstream_tree: the treeish in the git repo to create the commits against
+ """
+ components = [c for (c, t) in component_tarballs]
+ main_tree = self.tree_drop_dirs(upstream_tree, components)
+
+ for component, name in component_tarballs:
+ subtree = self.tree_get_dir(upstream_tree, component)
+ if not subtree:
+ raise GitRepositoryError("No tree for '%s' found in '%s' to create pristine tar commit from" % (component, upstream_tree))
+ gbp.log.debug("Creating pristine tar commit '%s' from '%s'" % (component, subtree))
+ self.pristine_tar.commit(name, subtree)
+ self.pristine_tar.commit(tarball, main_tree)
+
# vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·:
diff --git a/gbp/deb/policy.py b/gbp/deb/policy.py
index 7522160..75e7879 100644
--- a/gbp/deb/policy.py
+++ b/gbp/deb/policy.py
@@ -62,7 +62,7 @@ class DebianPkgPolicy(PkgPolicy):
debianversion_chars = 'a-zA-Z\\d.~+-'
@staticmethod
- def build_tarball_name(name, version, compression, dir=None, subtarball=None):
+ def build_tarball_name(name, version, compression, dir=None, component=None):
"""
Given a source package's I{name}, I{version} and I{compression}
return the name of the corresponding upstream tarball.
@@ -71,7 +71,7 @@ class DebianPkgPolicy(PkgPolicy):
'foo_1.0.orig.tar.bz2'
>>> DebianPkgPolicy.build_tarball_name('bar', '0.0~git1234', 'xz')
'bar_0.0~git1234.orig.tar.xz'
- >>> DebianPkgPolicy.build_tarball_name('bar', '0.0~git1234', 'xz', subtarball="foo")
+ >>> DebianPkgPolicy.build_tarball_name('bar', '0.0~git1234', 'xz', component="foo")
'bar_0.0~git1234.orig-foo.tar.xz'
@param name: the source package's name
@@ -86,7 +86,7 @@ class DebianPkgPolicy(PkgPolicy):
@rtype: C{str}
"""
ext = compressor_opts[compression][1]
- sub = '-{0}'.format(subtarball) if subtarball else ''
+ sub = '-{0}'.format(component) if component else ''
tarball = "%s_%s.orig%s.tar.%s" % (name, version, sub, ext)
if dir:
tarball = os.path.join(dir, tarball)
diff --git a/gbp/deb/pristinetar.py b/gbp/deb/pristinetar.py
index 09e4d4e..a80fd4b 100644
--- a/gbp/deb/pristinetar.py
+++ b/gbp/deb/pristinetar.py
@@ -20,6 +20,7 @@ from gbp.pkg import compressor_opts
from gbp.pkg.pristinetar import PristineTar
from gbp.deb import DebianPkgPolicy
+
class DebianPristineTar(PristineTar):
"""The pristine-tar branch in a Debian git repository"""
def has_commit(self, package, version, comp_type=None):
@@ -43,7 +44,7 @@ class DebianPristineTar(PristineTar):
return super(DebianPristineTar, self).has_commit(name_regexp)
- def checkout(self, package, version, comp_type, output_dir, subtarball=None):
+ def checkout(self, package, version, comp_type, output_dir, component=None):
"""
Checkout the orig tarball for package I{package} of I{version} and
compression type I{comp_type} to I{output_dir}
@@ -61,6 +62,5 @@ class DebianPristineTar(PristineTar):
version,
comp_type,
output_dir,
- subtarball=subtarball)
+ component=component)
super(DebianPristineTar, self).checkout(name)
-
diff --git a/gbp/deb/source.py b/gbp/deb/source.py
index 2466ab9..7b8ef98 100644
--- a/gbp/deb/source.py
+++ b/gbp/deb/source.py
@@ -22,6 +22,7 @@ from gbp.deb.changelog import ChangeLog
import six
+
class FileVfs(object):
def __init__(self, dir):
"""
@@ -36,9 +37,11 @@ class FileVfs(object):
flags = flags or 'r'
return open(os.path.join(self._dir, path), flags)
+
class DebianSourceError(Exception):
pass
+
class DebianSource(object):
"""
A debianized source tree
@@ -68,10 +71,10 @@ class DebianSource(object):
if f.type:
return f.type == 'native'
except IOError as e:
- pass # Fall back to changelog parsing
+ pass # Fall back to changelog parsing
try:
- return not '-' in self.changelog.version
+ return '-' not in self.changelog.version
except IOError as e:
raise DebianSourceError("Failed to determine source format: %s" % e)
diff --git a/gbp/deb/upstreamsource.py b/gbp/deb/upstreamsource.py
index ca235ef..4895627 100644
--- a/gbp/deb/upstreamsource.py
+++ b/gbp/deb/upstreamsource.py
@@ -1,6 +1,7 @@
# vim: set fileencoding=utf-8 :
#
# (C) 2013 Intel Corporation <markus.lehtonen@linux.intel.com>
+# (C) 2016 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
@@ -18,6 +19,11 @@
from gbp.pkg import UpstreamSource
from gbp.deb.policy import DebianPkgPolicy
+import gbp.command_wrappers
+
+import os
+import shutil
+import tempfile
class DebianUpstreamSource(UpstreamSource):
@@ -26,3 +32,25 @@ class DebianUpstreamSource(UpstreamSource):
super(DebianUpstreamSource, self).__init__(name,
unpacked,
DebianPkgPolicy)
+
+
+def unpack_component_tarball(dest, component, tarball, filters):
+ """
+ Unpack the tarball I{tarball} into dest naming it I{component}.
+ Apply filters during unpack.
+ """
+ olddir = os.path.abspath(os.path.curdir)
+ tmpdir = None
+ try:
+ tmpdir = os.path.abspath(tempfile.mkdtemp(dir=os.path.join(dest, '..')))
+ source = DebianUpstreamSource(tarball)
+ source.unpack(tmpdir, filters)
+
+ newdest = os.path.join(dest, component)
+ if os.path.exists(newdest):
+ shutil.rmtree(newdest)
+ shutil.move(source.unpacked, newdest)
+ finally:
+ os.chdir(olddir)
+ if tmpdir is not None:
+ gbp.command_wrappers.RemoveTree(tmpdir)()
diff --git a/gbp/deb/uscan.py b/gbp/deb/uscan.py
index 97e02ea..4613b96 100644
--- a/gbp/deb/uscan.py
+++ b/gbp/deb/uscan.py
@@ -16,11 +16,15 @@
# <http://www.gnu.org/licenses/>
"""Interface to uscan"""
-import os, re, subprocess
+import os
+import re
+import subprocess
+
class UscanError(Exception):
pass
+
class Uscan(object):
cmd = '/usr/bin/uscan'
@@ -84,7 +88,7 @@ class Uscan(object):
for n in ('package',
'upstream-version',
'upstream-url'):
- m = re.match("<%s>(.*)</%s>" % (n,n), row)
+ m = re.match("<%s>(.*)</%s>" % (n, n), row)
if m:
d[n] = m.group(1)
d["ext"] = os.path.splitext(d['upstream-url'])[1]
@@ -94,10 +98,10 @@ class Uscan(object):
# Fall back to the upstream source name otherwise
if not os.path.exists(source):
- source = "../%s" % d['upstream-url'].rsplit('/',1)[1]
+ source = "../%s" % d['upstream-url'].rsplit('/', 1)[1]
if not os.path.exists(source):
raise UscanError("Couldn't find tarball at '%s'" %
- source)
+ source)
except KeyError as e:
raise UscanError("Couldn't find '%s' in uscan output" %
e.args[0])
@@ -157,7 +161,7 @@ class Uscan(object):
msg = None
for n in ('errors', 'warnings'):
- m = re.search("<%s>(.*)</%s>" % (n,n), out, re.DOTALL)
+ m = re.search("<%s>(.*)</%s>" % (n, n), out, re.DOTALL)
if m:
msg = "Uscan failed: %s" % m.group(1)
break
@@ -166,7 +170,6 @@ class Uscan(object):
msg = "Uscan failed - debug by running 'uscan --verbose'"
raise UscanError(msg)
-
def scan(self, destdir='..'):
"""Invoke uscan to fetch a new upstream version"""
p = subprocess.Popen(['uscan', '--symlink', '--destdir=%s' % destdir,
@@ -174,7 +177,7 @@ class Uscan(object):
cwd=self._dir,
stdout=subprocess.PIPE)
out = p.communicate()[0]
- # uscan exits with 1 in case of uptodate and when an error occured.
+ # uscan exits with 1 in case of uptodate and when an error occurred.
# Don't fail in the uptodate case:
self._parse_uptodate(out)
if not self.uptodate:
diff --git a/gbp/errors.py b/gbp/errors.py
index 12627d8..d1f6e8d 100644
--- a/gbp/errors.py
+++ b/gbp/errors.py
@@ -16,6 +16,7 @@
# <http://www.gnu.org/licenses/>
"""Errors raised in gbp commands"""
+
class GbpError(Exception):
"""Generic exception raised in git-buildpackage commands"""
pass
diff --git a/gbp/format.py b/gbp/format.py
index f35f7c6..d198519 100644
--- a/gbp/format.py
+++ b/gbp/format.py
@@ -18,6 +18,7 @@
from gbp.errors import GbpError
+
def format_str(msg, args):
"""
Format a string with the given dict. Be a bit more verbose than
@@ -41,5 +42,3 @@ def format_str(msg, args):
except KeyError as e:
raise GbpError("Failed to format %s: Missing value %s in %s" %
(msg, e, args))
-
-
diff --git a/gbp/git/__init__.py b/gbp/git/__init__.py
index 81e1422..5e5240d 100644
--- a/gbp/git/__init__.py
+++ b/gbp/git/__init__.py
@@ -19,13 +19,14 @@
import calendar
import dateutil.parser
-from gbp.git.modifier import GitModifier
-from gbp.git.commit import GitCommit
-from gbp.git.errors import GitError
-from gbp.git.repository import GitRepository, GitRepositoryError
-from gbp.git.fastimport import FastImport
-from gbp.git.args import GitArgs
-from gbp.git.vfs import GitVfs
+from gbp.git.modifier import GitModifier # noqa: F401
+from gbp.git.commit import GitCommit # noqa: F401
+from gbp.git.errors import GitError # noqa: F401
+from gbp.git.repository import ( # noqa: F401
+ GitRepository, GitRepositoryError)
+from gbp.git.fastimport import FastImport # noqa: F401
+from gbp.git.args import GitArgs # noqa: F401
+from gbp.git.vfs import GitVfs # noqa: F401
def rfc822_date_to_git(rfc822_date):
diff --git a/gbp/git/args.py b/gbp/git/args.py
index 197097f..95e5011 100644
--- a/gbp/git/args.py
+++ b/gbp/git/args.py
@@ -21,6 +21,7 @@ Git command argument handling helpers
import six
import collections
+
class GitArgs(object):
"""
Handle arguments to git commands
@@ -106,4 +107,3 @@ class GitArgs(object):
else:
self.add(noopt)
return self
-
diff --git a/gbp/git/commit.py b/gbp/git/commit.py
index cfc5d0c..1a9912f 100644
--- a/gbp/git/commit.py
+++ b/gbp/git/commit.py
@@ -18,7 +18,6 @@
import re
-from gbp.git.errors import GitError
class GitCommit(object):
"""A git commit"""
@@ -44,5 +43,3 @@ class GitCommit(object):
@rtype: C{bool}
"""
return True if GitCommit.sha1_re.match(value) else False
-
-
diff --git a/gbp/git/errors.py b/gbp/git/errors.py
index 47122b8..377e468 100644
--- a/gbp/git/errors.py
+++ b/gbp/git/errors.py
@@ -16,7 +16,7 @@
# <http://www.gnu.org/licenses/>
"""Git base error exception"""
+
class GitError(Exception):
"""Exception thrown by Git related classes"""
pass
-
diff --git a/gbp/git/fastimport.py b/gbp/git/fastimport.py
index 1195fee..577ad76 100644
--- a/gbp/git/fastimport.py
+++ b/gbp/git/fastimport.py
@@ -21,12 +21,13 @@ import subprocess
import time
from gbp.errors import GbpError
+
class FastImport(object):
"""Add data to a git repository using I{git fast-import}"""
_bufsize = 1024
m_regular = 644
- m_exec = 755
+ m_exec = 755
m_symlink = 120000
def __init__(self, repo):
@@ -36,7 +37,7 @@ class FastImport(object):
"""
self._repo = repo
try:
- self._fi = subprocess.Popen([ 'git', 'fast-import', '--quiet'],
+ self._fi = subprocess.Popen(['git', 'fast-import', '--quiet'],
stdin=subprocess.PIPE, cwd=repo.path)
self._out = self._fi.stdin
except OSError as err:
@@ -112,14 +113,14 @@ class FastImport(object):
committer %(name)s <%(email)s> %(time)s
data %(length)s
%(msg)s%(from)s""" %
- { 'branch': branch,
- 'name': committer.name,
- 'email': committer.email,
- 'time': committer.date,
- 'length': length,
- 'msg': msg,
- 'from': from_,
- })
+ {'branch': branch,
+ 'name': committer.name,
+ 'email': committer.email,
+ 'time': committer.date,
+ 'length': length,
+ 'msg': msg,
+ 'from': from_,
+ })
def deleteall(self):
"""
diff --git a/gbp/git/modifier.py b/gbp/git/modifier.py
index fd25d93..cb8bec1 100644
--- a/gbp/git/modifier.py
+++ b/gbp/git/modifier.py
@@ -21,14 +21,17 @@ like committing changes or authoring a patch
"""
import six
-import calendar, datetime
+import calendar
+import datetime
from gbp.git.errors import GitError
+
class GitModifierError(GitError):
"""Exception thrown by L{GitModifier}"""
pass
+
class GitTz(datetime.tzinfo):
"""Simple class to store the utc offset only"""
def __init__(self, offset_sec=0, *args, **kwargs):
@@ -41,6 +44,7 @@ class GitTz(datetime.tzinfo):
def dst(self, dt):
return datetime.timedelta(0)
+
class GitModifier(object):
"""Stores authorship/committer information"""
def __init__(self, name=None, email=None, date=None):
@@ -64,16 +68,16 @@ class GitModifier(object):
timestamp, offset = date.split()
offset_h = int(offset[:-2])
offset_m = int(offset[-2:])
- tz = GitTz(offset_h*3600 + offset_m*60)
+ tz = GitTz(offset_h * 3600 + offset_m * 60)
self._date = datetime.datetime.fromtimestamp(int(timestamp), tz)
- elif type(date) in [ type(0), type(0.0) ]:
+ elif type(date) in [type(0), type(0.0)]:
self._date = datetime.datetime.fromtimestamp(date, tz)
elif isinstance(date, datetime.datetime):
if date.tzinfo:
self._date = date
else:
self._date = date.replace(tzinfo=tz)
- elif date != None:
+ elif date is not None:
raise ValueError("Date '%s' not timestamp, "
"datetime object or git raw date" % date)
@@ -141,7 +145,7 @@ class GitModifier(object):
>>> g.get_committer_env()['GIT_COMMITTER_NAME']
'Joey Ramone'
- @return: Commiter information suitable to use as environment variables
+ @return: Committer information suitable to use as environment variables
@rtype: C{dict}
"""
return self._get_env('committer')
@@ -154,7 +158,7 @@ class GitModifier(object):
@staticmethod
def keys():
- return [ 'name', 'email', 'date' ]
+ return ['name', 'email', 'date']
def items(self):
items = []
diff --git a/gbp/git/repository.py b/gbp/git/repository.py
index 8142a25..2f1b71b 100644
--- a/gbp/git/repository.py
+++ b/gbp/git/repository.py
@@ -96,7 +96,7 @@ class GitRepository(object):
if ret or out.strip():
raise GitRepositoryError("No Git repository at '%s': '%s'" % (self.path, out))
except GitRepositoryError:
- raise # We already have a useful error message
+ raise # We already have a useful error message
except:
raise GitRepositoryError("No Git repository at '%s'" % self.path)
self._check_bare()
@@ -136,7 +136,7 @@ class GitRepository(object):
cmd = ['git', command] + args
log.debug(cmd)
popen = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=env, cwd=cwd)
- while popen.poll() == None:
+ while popen.poll() is None:
output += popen.stdout.readlines()
output += popen.stdout.readlines()
return output, popen.returncode
@@ -207,7 +207,6 @@ class GitRepository(object):
if ret:
raise GitRepositoryError("Error running git %s: %s" % (command, stderr))
-
def _cmd_has_feature(self, command, feature):
"""
Check if the git command has certain feature enabled.
@@ -221,9 +220,9 @@ class GitRepository(object):
"""
args = GitArgs(command, '-m')
help, stderr, ret = self._git_inout('help',
- args.args,
- extra_env={'LC_ALL': 'C'},
- capture_stderr=True)
+ args.args,
+ extra_env={'LC_ALL': 'C'},
+ capture_stderr=True)
if ret:
raise GitRepositoryError("Invalid git command '%s': %s"
% (command, stderr[:-1]))
@@ -264,7 +263,7 @@ class GitRepository(object):
@property
def bare(self):
- """Wheter this is a bare repository"""
+ """Whether this is a bare repository"""
return self._bare
@property
@@ -320,6 +319,9 @@ class GitRepository(object):
@param remote: delete a remote branch
@param remote: C{bool}
"""
+ if not self.has_branch(branch):
+ return
+
args = GitArgs('-D')
args.add_true(remote, '-r')
args.add(branch)
@@ -338,8 +340,8 @@ class GitRepository(object):
@raises GitRepositoryError: if HEAD is not a symbolic ref
(e.g. when in detached HEAD state)
"""
- out, dummy, ret = self._git_inout('symbolic-ref', [ 'HEAD' ],
- capture_stderr=True)
+ out, dummy, ret = self._git_inout('symbolic-ref', ['HEAD'],
+ capture_stderr=True)
if ret:
# We don't append stderr since
# "fatal: ref HEAD is not a symbolic ref" confuses people
@@ -348,13 +350,12 @@ class GitRepository(object):
# Check if ref really exists
try:
- self._git_command('show-ref', [ ref ])
- branch = ref[11:] # strip /refs/heads
+ self._git_command('show-ref', [ref])
+ branch = ref[11:] # strip /refs/heads
except GitRepositoryError:
branch = None # empty repo
return branch
-
def has_branch(self, branch, remote=False):
"""
Check if the repository has branch named I{branch}.
@@ -370,7 +371,7 @@ class GitRepository(object):
else:
ref = 'refs/heads/%s' % branch
try:
- self._git_command('show-ref', [ ref ])
+ self._git_command('show-ref', [ref])
except GitRepositoryError:
return False
return True
@@ -387,9 +388,9 @@ class GitRepository(object):
if self.bare:
self._git_command("symbolic-ref",
- [ 'HEAD', 'refs/heads/%s' % branch ])
+ ['HEAD', 'refs/heads/%s' % branch])
else:
- self._git_command("checkout", [ branch ])
+ self._git_command("checkout", [branch])
def get_merge_branch(self, branch):
"""
@@ -403,7 +404,7 @@ class GitRepository(object):
merge = self.get_config("branch.%s.merge" % branch)
except KeyError:
return None
- remote += merge.replace("refs/heads","", 1)
+ remote += merge.replace("refs/heads", "", 1)
return remote
def get_merge_base(self, commit1, commit2):
@@ -437,7 +438,7 @@ class GitRepository(object):
@type commit: C{str}
@param verbose: whether to print a summary after the merge
@type verbose: C{bool}
- @param edit: wheter to invoke an editor to edit the merge message
+ @param edit: whether to invoke an editor to edit the merge message
@type edit: C{bool}
"""
args = GitArgs()
@@ -450,6 +451,12 @@ class GitRepository(object):
args.add(commit)
self._git_command("merge", args.args)
+ def abort_merge(self):
+ """
+ Abort a merge
+ """
+ self._git_command("merge", ["--abort"])
+
def is_fast_forward(self, from_branch, to_branch):
"""
Check if an update I{from from_branch} to I{to_branch} would be a fast
@@ -460,11 +467,12 @@ class GitRepository(object):
"""
has_local = False # local repo has new commits
has_remote = False # remote repo has new commits
- out = self._git_getoutput('rev-list', ["--left-right",
+ out = self._git_getoutput('rev-list',
+ ["--left-right",
"%s...%s" % (from_branch, to_branch),
"--"])[0]
- if not out: # both branches have the same commits
+ if not out: # both branches have the same commits
return True, True
for line in out:
@@ -489,10 +497,10 @@ class GitRepository(object):
@return: local or remote branches
@rtype: C{list}
"""
- args = [ '--format=%(refname:short)' ]
- args += [ 'refs/remotes/' ] if remote else [ 'refs/heads/' ]
+ args = ['--format=%(refname:short)']
+ args += ['refs/remotes/'] if remote else ['refs/heads/']
out = self._git_getoutput('for-each-ref', args)[0]
- return [ ref.strip() for ref in out ]
+ return [ref.strip() for ref in out]
def get_local_branches(self):
"""
@@ -503,7 +511,6 @@ class GitRepository(object):
"""
return self._get_branches(remote=False)
-
def get_remote_branches(self):
"""
Get a list of remote branches
@@ -527,11 +534,11 @@ class GitRepository(object):
@param msg: the reason for the update
@type msg: C{str}
"""
- args = [ ref, new ]
+ args = [ref, new]
if old:
- args += [ old ]
+ args += [old]
if msg:
- args = [ '-m', msg ] + args
+ args = ['-m', msg] + args
self._git_command("update-ref", args)
def branch_contains(self, branch, commit, remote=False):
@@ -550,7 +557,7 @@ class GitRepository(object):
args.add('--contains')
args.add(commit)
- out, ret = self._git_getoutput('branch', args.args)
+ out, ret = self._git_getoutput('branch', args.args)
for line in out:
# remove prefix '*' for current branch before comparing
line = line.replace('*', '')
@@ -626,12 +633,12 @@ class GitRepository(object):
@type keyid: C{str}
"""
args = []
- args += [ '-m', msg ] if msg else []
+ args += ['-m', msg] if msg else []
if sign:
- args += [ '-s' ]
- args += [ '-u', keyid ] if keyid else []
- args += [ name ]
- args += [ commit ] if commit else []
+ args += ['-s']
+ args += ['-u', keyid] if keyid else []
+ args += [name]
+ args += [commit] if commit else []
self._git_command("tag", args)
def delete_tag(self, tag):
@@ -642,10 +649,10 @@ class GitRepository(object):
@type tag: C{str}
"""
if self.has_tag(tag):
- self._git_command("tag", [ "-d", tag ])
+ self._git_command("tag", ["-d", tag])
def move_tag(self, old, new):
- self._git_command("tag", [ new, old ])
+ self._git_command("tag", [new, old])
self.delete_tag(old)
def has_tag(self, tag):
@@ -657,8 +664,8 @@ class GitRepository(object):
@return: C{True} if the repository has that tag, C{False} otherwise
@rtype: C{bool}
"""
- out, ret = self._git_getoutput('tag', [ '-l', tag ])
- return [ False, True ][len(out)]
+ out, ret = self._git_getoutput('tag', ['-l', tag])
+ return [False, True][len(out)]
def describe(self, commitish, pattern=None, longfmt=False, always=False,
abbrev=None, tags=False, exact_match=False):
@@ -684,7 +691,7 @@ class GitRepository(object):
@rtype: C{str}
"""
args = GitArgs()
- args.add_true(pattern, ['--match' , pattern])
+ args.add_true(pattern, ['--match', pattern])
args.add_true(longfmt, '--long')
# 'long' and 'abbrev=0' are incompatible, behave similar to
# 'always' and 'abbrev=0'
@@ -742,8 +749,8 @@ class GitRepository(object):
@return: tags
@rtype: C{list} of C{str}
"""
- args = [ '-l', pattern ] if pattern else []
- return [ line.strip() for line in self._git_getoutput('tag', args)[0] ]
+ args = ['-l', pattern] if pattern else []
+ return [line.strip() for line in self._git_getoutput('tag', args)[0]]
def verify_tag(self, tag):
"""
@@ -776,12 +783,12 @@ class GitRepository(object):
if self.bare:
ref = "refs/heads/%s" % self.get_branch()
- self._git_command("update-ref", [ ref, commit ])
+ self._git_command("update-ref", [ref, commit])
else:
args = ['--quiet']
if hard:
- args += [ '--hard' ]
- args += [ commit, '--' ]
+ args += ['--hard']
+ args += [commit, '--']
self._git_command("reset", args)
def _status(self, porcelain, ignore_untracked):
@@ -815,7 +822,7 @@ class GitRepository(object):
if out:
# Get a more helpful error message.
out = self._status(porcelain=False,
- ignore_untracked=ignore_untracked)
+ ignore_untracked=ignore_untracked)
return (False, "".join(out))
else:
return (True, '')
@@ -883,7 +890,7 @@ class GitRepository(object):
@rtype: C{bool}
"""
# an empty repo has no branches:
- return False if self.branch else True
+ return len(self.get_local_branches()) == 0
def rev_parse(self, name, short=0):
"""
@@ -954,9 +961,9 @@ class GitRepository(object):
@return: C{True} if the repository has that tree, C{False} otherwise
@rtype: C{bool}
"""
- _out, _err, ret = self._git_inout('ls-tree', [treeish],
- capture_stderr=True)
- return [ True, False ][ret != 0]
+ _out, _err, ret = self._git_inout('ls-tree', [treeish],
+ capture_stderr=True)
+ return [True, False][ret != 0]
def write_tree(self, index_file=None):
"""
@@ -968,7 +975,7 @@ class GitRepository(object):
@rtype: C{str}
"""
if index_file:
- extra_env = {'GIT_INDEX_FILE': index_file }
+ extra_env = {'GIT_INDEX_FILE': index_file}
else:
extra_env = None
@@ -984,17 +991,17 @@ class GitRepository(object):
Create a tree based on contents. I{contents} has the same format than
the I{GitRepository.list_tree} output.
"""
- out=''
+ out = ''
args = GitArgs('-z')
for obj in contents:
- mode, type, sha1, name = obj
- out += '%s %s %s\t%s\0' % (mode, type, sha1, name)
+ mode, type, sha1, name = obj
+ out += '%s %s %s\t%s\0' % (mode, type, sha1, name)
- sha1, err, ret = self._git_inout('mktree',
- args.args,
- out,
- capture_stderr=True)
+ sha1, err, ret = self._git_inout('mktree',
+ args.args,
+ out,
+ capture_stderr=True)
if ret:
raise GitRepositoryError("Failed to mktree: '%s'" % err)
return self.strip_sha1(sha1)
@@ -1016,7 +1023,7 @@ class GitRepository(object):
def list_tree(self, treeish, recurse=False, paths=None):
"""
Get a trees content. It returns a list of objects that match the
- 'ls-tree' output: [ mode, type, sha1, path ].
+ 'ls-tree' output: [mode, type, sha1, path].
@param treeish: the treeish object to list
@type treeish: C{str}
@@ -1031,7 +1038,7 @@ class GitRepository(object):
args.add("--")
args.add_cond(paths, paths)
- out, err, ret = self._git_inout('ls-tree', args.args, capture_stderr=True)
+ out, err, ret = self._git_inout('ls-tree', args.args, capture_stderr=True)
if ret:
raise GitRepositoryError("Failed to ls-tree '%s': '%s'" % (treeish, err))
@@ -1051,9 +1058,10 @@ class GitRepository(object):
@return: fetched config value
@rtype: C{str}
"""
- value, ret = self._git_getoutput('config', [ name ])
- if ret: raise KeyError
- return value[0][:-1] # first line with \n ending removed
+ value, ret = self._git_getoutput('config', [name])
+ if ret:
+ raise KeyError
+ return value[0][:-1] # first line with \n ending removed
def get_author_info(self):
"""
@@ -1064,11 +1072,11 @@ class GitRepository(object):
@rtype: L{GitModifier}
"""
try:
- name = self.get_config("user.name")
+ name = self.get_config("user.name")
except KeyError:
- name = os.getenv("USER")
+ name = os.getenv("USER")
try:
- email = self.get_config("user.email")
+ email = self.get_config("user.email")
except KeyError:
email = os.getenv("EMAIL")
email = os.getenv("GIT_AUTHOR_EMAIL", email)
@@ -1122,7 +1130,7 @@ class GitRepository(object):
@rtype: C{list} of C{str}
"""
out = self._git_getoutput('remote')[0]
- return [ remote.strip() for remote in out ]
+ return [remote.strip() for remote in out]
def has_remote_repo(self, name):
"""
@@ -1232,7 +1240,7 @@ class GitRepository(object):
args.add_true(tags, "--tags")
# Allow for src == '' to delete dst on the remote
- if src != None:
+ if src is not None:
refspec = src
if dst:
refspec += ':%s' % dst
@@ -1270,12 +1278,12 @@ class GitRepository(object):
extra_env = {}
if isinstance(paths, six.string_types):
- paths = [ paths ]
+ paths = [paths]
- args = [ '-f' ] if force else []
+ args = ['-f'] if force else []
if index_file:
- extra_env['GIT_INDEX_FILE'] = index_file
+ extra_env['GIT_INDEX_FILE'] = index_file
if work_tree:
extra_env['GIT_WORK_TREE'] = work_tree
@@ -1292,9 +1300,9 @@ class GitRepository(object):
@type verbose: C{bool}
"""
if isinstance(paths, six.string_types):
- paths = [ paths ]
+ paths = [paths]
- args = [] if verbose else ['--quiet']
+ args = [] if verbose else ['--quiet']
self._git_command("rm", args + paths)
def list_files(self, types=['cached']):
@@ -1306,24 +1314,23 @@ class GitRepository(object):
@return: list of files
@rtype: C{list} of C{str}
"""
- all_types = [ 'cached', 'deleted', 'others', 'ignored', 'stage'
- 'unmerged', 'killed', 'modified' ]
- args = [ '-z' ]
+ all_types = ['cached', 'deleted', 'others', 'ignored', 'stage'
+ 'unmerged', 'killed', 'modified']
+ args = ['-z']
for t in types:
if t in all_types:
- args += [ '--%s' % t ]
+ args += ['--%s' % t]
else:
raise GitRepositoryError("Unknown type '%s'" % t)
out, ret = self._git_getoutput('ls-files', args)
if ret:
raise GitRepositoryError("Error listing files: '%d'" % ret)
if out:
- return [ file for file in out[0].split('\0') if file ]
+ return [file for file in out[0].split('\0') if file]
else:
return []
-
def write_file(self, filename, filters=True):
"""
Hash a single file and write it into the object database
@@ -1366,7 +1373,7 @@ class GitRepository(object):
@type edit: C{bool}
"""
args = GitArgs()
- args.add_true(edit, '--edit')
+ args.add_true(edit, '--edit')
self._commit(msg=msg, args=args.args, author_info=author_info)
def commit_all(self, msg, author_info=None, edit=False):
@@ -1378,7 +1385,7 @@ class GitRepository(object):
@type author_info: L{GitModifier}
"""
args = GitArgs('-a')
- args.add_true(edit, '--edit')
+ args.add_true(edit, '--edit')
self._commit(msg=msg, args=args.args, author_info=author_info)
def commit_files(self, files, msg, author_info=None):
@@ -1393,7 +1400,7 @@ class GitRepository(object):
@type author_info: L{GitModifier}
"""
if isinstance(files, six.string_types):
- files = [ files ]
+ files = [files]
self._commit(msg=msg, args=files, author_info=author_info)
def commit_dir(self, unpack_dir, msg, branch, other_parents=None,
@@ -1437,19 +1444,19 @@ class GitRepository(object):
cur = None
else:
raise
- else: # emtpy repo
+ else: # empty repo
cur = None
branch = 'master'
# Build list of parents:
parents = []
if cur:
- parents = [ cur ]
+ parents.append(cur)
if other_parents:
for parent in other_parents:
sha = self.rev_parse(parent)
if sha not in parents:
- parents += [ sha ]
+ parents.append(sha)
commit = self.commit_tree(tree=tree, msg=msg, parents=parents,
author=author, committer=committer)
@@ -1478,9 +1485,9 @@ class GitRepository(object):
if val:
extra_env['GIT_COMMITTER_%s' % key.upper()] = val
- args = [ tree ]
+ args = [tree]
for parent in parents:
- args += [ '-p' , parent ]
+ args += ['-p', parent]
sha1, stderr, ret = self._git_inout('commit-tree',
args,
msg,
@@ -1522,20 +1529,20 @@ class GitRepository(object):
args.add_cond(options, options)
args.add("--")
if isinstance(paths, six.string_types):
- paths = [ paths ]
+ paths = [paths]
args.add_cond(paths, paths)
commits, ret = self._git_getoutput('log', args.args)
if ret:
where = " on %s" % paths if paths else ""
raise GitRepositoryError("Error getting commits %s..%s%s" %
- (since, until, where))
- return [ commit.strip() for commit in commits ]
+ (since, until, where))
+ return [commit.strip() for commit in commits]
def show(self, id):
"""git-show id"""
obj, stderr, ret = self._git_inout('show', ["--pretty=medium", id],
- capture_stderr=True)
+ capture_stderr=True)
if ret:
raise GitRepositoryError("can't get %s: %s" % (id, stderr.rstrip()))
return obj
@@ -1561,7 +1568,7 @@ class GitRepository(object):
raise GitRepositoryError("Error grepping log for %s: %s" %
(regex, stderr[:-1]))
if stdout:
- return [ commit.strip() for commit in stdout.split('\n')[::-1] ]
+ return [commit.strip() for commit in stdout.split('\n')[::-1]]
else:
return []
@@ -1590,7 +1597,7 @@ class GitRepository(object):
args = GitArgs('--pretty=format:%an%x00%ae%x00%ad%x00%cn%x00%ce%x00%cd%x00%s%x00%f%x00%b%x00',
'-z', '--date=raw', '--no-renames', '--name-status',
commit_sha1)
- out, err, ret = self._git_inout('show', args.args)
+ out, err, ret = self._git_inout('show', args.args)
if ret:
raise GitRepositoryError("Unable to retrieve commit info for %s"
% commitish)
@@ -1607,19 +1614,20 @@ class GitRepository(object):
files = defaultdict(list)
file_fields = fields[9:]
# For some reason git returns one extra empty field for merge commits
- if file_fields[0] == '': file_fields.pop(0)
+ if file_fields[0] == '':
+ file_fields.pop(0)
while len(file_fields) and file_fields[0] != '':
status = file_fields.pop(0).strip()
path = file_fields.pop(0)
files[status].append(path)
- return {'id' : commitish,
- 'author' : author,
- 'committer' : committer,
- 'subject' : fields[6],
- 'patchname' : fields[7],
- 'body' : fields[8],
- 'files' : files}
+ return {'id': commitish,
+ 'author': author,
+ 'committer': committer,
+ 'subject': fields[6],
+ 'patchname': fields[7],
+ 'body': fields[8],
+ 'files': files}
#{ Patches
def format_patches(self, start, end, output_dir,
@@ -1646,17 +1654,19 @@ class GitRepository(object):
options.add_cond(thread, '--thread=%s' % thread, '--no-thread')
output, ret = self._git_getoutput('format-patch', options.args)
- return [ line.strip() for line in output ]
+ return [line.strip() for line in output]
- def apply_patch(self, patch, index=True, context=None, strip=None):
+ def apply_patch(self, patch, index=True, context=None, strip=None, fix_ws=False):
"""Apply a patch using git apply"""
args = []
if context:
- args += [ '-C', context ]
+ args += ['-C', context]
if index:
args.append("--index")
- if strip != None:
- args += [ '-p', str(strip) ]
+ if fix_ws:
+ args.append("--whitespace=fix")
+ if strip is not None:
+ args += ['-p', str(strip)]
args.append(patch)
self._git_command("apply", args)
@@ -1727,7 +1737,7 @@ class GitRepository(object):
return result
#}
- def archive(self, format, prefix, output, treeish, **kwargs):
+ def archive(self, format, prefix, output, treeish, cwd=None):
"""
Create an archive from a treeish
@@ -1739,13 +1749,16 @@ class GitRepository(object):
@type output: C{str}
@param treeish: the treeish to create the archive from
@type treeish: C{str}
- @param kwargs: additional commandline options passed to git-archive
+ @param cwd: The directory to run in. Defaults to the current dir
+ @type cwd: C{str}
"""
- args = [ '--format=%s' % format, '--prefix=%s' % prefix,
- '--output=%s' % output, treeish ]
- out, ret = self._git_getoutput('archive', args, **kwargs)
+ args = ['--format=%s' % format,
+ '--prefix=%s' % prefix,
+ '--output=%s' % output,
+ treeish]
+ out, err, ret = self._git_inout('archive', args, cwd=cwd, capture_stderr=True)
if ret:
- raise GitRepositoryError("Unable to archive %s" % treeish)
+ raise GitRepositoryError("Unable to archive %s: %s" % (treeish, err.strip()))
def collect_garbage(self, auto=False):
"""
@@ -1754,7 +1767,7 @@ class GitRepository(object):
param auto: only cleanup if required
param auto: C{bool}
"""
- args = [ '--auto' ] if auto else []
+ args = ['--auto'] if auto else []
self._git_command("gc", args)
#{ Submodules
@@ -1777,7 +1790,6 @@ class GitRepository(object):
return True
return os.path.exists(os.path.join(self.path, '.gitmodules'))
-
def add_submodule(self, repo_path):
"""
Add a submodule
@@ -1785,8 +1797,7 @@ class GitRepository(object):
@param repo_path: path to submodule
@type repo_path: C{str}
"""
- self._git_command("submodule", [ "add", repo_path ])
-
+ self._git_command("submodule", ["add", repo_path])
def update_submodules(self, init=True, recursive=True, fetch=False):
"""
@@ -1802,7 +1813,7 @@ class GitRepository(object):
if not self.has_submodules():
return
- args = [ "update" ]
+ args = ["update"]
if recursive:
args.append("--recursive")
if init:
@@ -1812,7 +1823,6 @@ class GitRepository(object):
self._git_command("submodule", args)
-
def get_submodules(self, treeish, path=None, recursive=True):
"""
List the submodules of treeish
@@ -1827,18 +1837,26 @@ class GitRepository(object):
if path is None:
path = self.path
- args = [ treeish ]
+ args = [treeish]
if recursive:
args += ['-r']
- out, ret = self._git_getoutput('ls-tree', args, cwd=path)
- for line in out:
- mode, objtype, commit, name = line[:-1].split(None, 3)
+ out, err, ret = self._git_inout('ls-tree',
+ args,
+ cwd=path,
+ capture_stderr=True)
+ if ret:
+ raise GitRepositoryError("Failed to list submodules of %s: %s" %
+ (treeish, err.strip()))
+ for line in out.split('\n'):
+ if not line:
+ continue
+ mode, objtype, commit, name = line.split(None, 3)
# A submodules is shown as "commit" object in ls-tree:
if objtype == "commit":
nextpath = os.path.join(path, name)
- submodules.append( (nextpath.replace(self.path,'').lstrip('/'),
- commit) )
+ submodules.append((nextpath.replace(self.path, '').lstrip('/'),
+ commit))
if recursive:
submodules += self.get_submodules(commit, path=nextpath,
recursive=recursive)
@@ -1847,7 +1865,7 @@ class GitRepository(object):
#{ Repository Creation
@classmethod
- def create(klass, path, description=None, bare=False):
+ def create(cls, path, description=None, bare=False):
"""
Create a repository at path
@@ -1868,12 +1886,12 @@ class GitRepository(object):
if not os.path.exists(abspath):
os.makedirs(abspath)
try:
- stdout, stderr, ret = klass.__git_inout(command='init',
- args=args.args,
- input=None,
- extra_env=None,
- cwd=abspath,
- capture_stderr=True)
+ stdout, stderr, ret = cls.__git_inout(command='init',
+ args=args.args,
+ input=None,
+ extra_env=None,
+ cwd=abspath,
+ capture_stderr=True)
except Exception as excobj:
raise GitRepositoryError("Error running git init: %s" % excobj)
if ret:
@@ -1883,14 +1901,14 @@ class GitRepository(object):
with open(os.path.join(abspath, git_dir, "description"), 'w') as f:
description += '\n' if description[-1] != '\n' else ''
f.write(description)
- return klass(abspath)
+ return cls(abspath)
except OSError as err:
raise GitRepositoryError("Cannot create Git repository at '%s': %s"
% (abspath, err[1]))
return None
@classmethod
- def clone(klass, path, remote, depth=0, recursive=False, mirror=False,
+ def clone(cls, path, remote, depth=0, recursive=False, mirror=False,
bare=False, auto_name=True, reference=None):
"""
Clone a git repository at I{remote} to I{path}.
@@ -1922,7 +1940,7 @@ class GitRepository(object):
abspath, name = abspath.rsplit('/', 1)
args = GitArgs('--quiet')
- args.add_true(depth, '--depth', depth)
+ args.add_true(depth, '--depth', depth)
args.add_true(recursive, '--recursive')
args.add_true(mirror, '--mirror')
args.add_true(bare, '--bare')
@@ -1934,12 +1952,12 @@ class GitRepository(object):
os.makedirs(abspath)
try:
- stdout, stderr, ret = klass.__git_inout(command='clone',
- args=args.args,
- input=None,
- extra_env=None,
- cwd=abspath,
- capture_stderr=True)
+ stdout, stderr, ret = cls.__git_inout(command='clone',
+ args=args.args,
+ input=None,
+ extra_env=None,
+ cwd=abspath,
+ capture_stderr=True)
except Exception as excobj:
raise GitRepositoryError("Error running git clone: %s" % excobj)
if ret:
@@ -1947,7 +1965,7 @@ class GitRepository(object):
if not name:
try:
- name = remote.rstrip('/').rsplit('/',1)[1]
+ name = remote.rstrip('/').rsplit('/', 1)[1]
except IndexError:
name = remote.split(':', 1)[1]
if (mirror or bare):
@@ -1955,11 +1973,10 @@ class GitRepository(object):
name = "%s.git" % name
elif name.endswith('.git'):
name = name[:-4]
- return klass(os.path.join(abspath, name))
+ return cls(os.path.join(abspath, name))
except OSError as err:
raise GitRepositoryError("Cannot clone Git repository "
"'%s' to '%s': %s"
% (remote, abspath, err[1]))
return None
#}
-
diff --git a/gbp/git/vfs.py b/gbp/git/vfs.py
index b34e573..191cf62 100644
--- a/gbp/git/vfs.py
+++ b/gbp/git/vfs.py
@@ -17,7 +17,8 @@
"""Make blobs in a git repository accessible as file like objects"""
from six import StringIO
-from gbp.git.repository import GitRepositoryError
+from gbp.git.repository import GitRepositoryError
+
class GitVfs(object):
diff --git a/gbp/log.py b/gbp/log.py
index 9248ec9..ae4821d 100644
--- a/gbp/log.py
+++ b/gbp/log.py
@@ -124,24 +124,30 @@ def err(msg):
"""Logs a message with level ERROR on the GBP logger"""
LOGGER.error(msg)
+
def error(msg):
err(msg)
+
def warn(msg):
"""Logs a message with level WARNING on the GBP logger"""
LOGGER.warning(msg)
+
def warning(msg):
warn(msg)
+
def info(msg):
"""Logs a message with level INFO on the GBP logger"""
LOGGER.info(msg)
+
def debug(msg):
"""Logs a message with level DEBUG on the GBP logger"""
LOGGER.debug(msg)
+
def _parse_color_scheme(color_scheme=""):
"""Set logging colors"""
scheme = {}
@@ -159,9 +165,11 @@ def _parse_color_scheme(color_scheme=""):
except ValueError:
try:
scheme[level] = COLORS[color.lower()]
- except KeyError: pass
+ except KeyError:
+ pass
return scheme
+
def setup(color, verbose, color_scheme=""):
"""Basic logger setup"""
LOGGER.set_color(color)
@@ -176,4 +184,3 @@ def setup(color, verbose, color_scheme=""):
logging.setLoggerClass(GbpLogger)
LOGGER = getLogger("gbp")
-
diff --git a/gbp/notifications.py b/gbp/notifications.py
index 8ed60a8..51cbe41 100644
--- a/gbp/notifications.py
+++ b/gbp/notifications.py
@@ -19,6 +19,7 @@ import warnings
notify_module = None
+
def enable_notifications():
global notify_module
@@ -37,7 +38,7 @@ def enable_notifications():
def build_msg(cp, success):
summary = "Gbp %s" % ["failed", "successful"][success]
msg = ("Build of %s %s %s" %
- (cp['Source'], cp['Version'], ["failed", "succeeded"][success]))
+ (cp['Source'], cp['Version'], ["failed", "succeeded"][success]))
return summary, msg
@@ -67,4 +68,3 @@ def notify(summary, message, notify_opt):
return [True, False][notify_opt.is_on()]
return notify_opt.do(send_notification, summary, message)
-
diff --git a/gbp/patch_series.py b/gbp/patch_series.py
index c70809d..9469957 100644
--- a/gbp/patch_series.py
+++ b/gbp/patch_series.py
@@ -163,9 +163,11 @@ class PatchSeries(list):
"""
A series of L{Patch}es as read from a quilt series file).
"""
+ comment_re = re.compile('\s+#.*$')
+ level_re = re.compile('-p(?P<level>[0-9]+)')
@classmethod
- def read_series_file(klass, seriesfile):
+ def read_series_file(cls, seriesfile):
"""Read a series file into L{Patch} objects"""
patch_dir = os.path.dirname(seriesfile)
@@ -177,18 +179,19 @@ class PatchSeries(list):
except Exception as err:
raise GbpError("Cannot open series file: %s" % err)
- queue = klass._read_series(s, patch_dir)
+ queue = cls._read_series(s, patch_dir)
s.close()
return queue
@classmethod
- def _read_series(klass, series, patch_dir):
+ def _read_series(cls, series, patch_dir):
"""
Read patch series
- >>> PatchSeries._read_series(['a/b', \
- 'a -p1', \
- 'a/b -p2'], '.') # doctest:+NORMALIZE_WHITESPACE
+ >>> PatchSeries._read_series(['a/b',
+ ... 'a -p1 # comment',
+ ... 'a/b -p2'], '.')
+ ... # doctest:+NORMALIZE_WHITESPACE
[<gbp.patch_series.Patch path='./a/b' topic='a' >,
<gbp.patch_series.Patch path='./a' strip=1 >,
<gbp.patch_series.Patch path='./a/b' topic='a' strip=2 >]
@@ -201,7 +204,6 @@ class PatchSeries(list):
@param patch_dir: path prefix to prepend to each patch path
@type patch_dir: string
"""
-
queue = PatchSeries()
for line in series:
try:
@@ -209,7 +211,7 @@ class PatchSeries(list):
continue
except IndexError:
continue # ignore empty lines
- queue.append(klass._parse_line(line, patch_dir))
+ queue.append(cls._parse_line(line, patch_dir))
return queue
@staticmethod
@@ -227,8 +229,22 @@ class PatchSeries(list):
topic = None
return topic
- @staticmethod
- def _split_strip(line):
+ @classmethod
+ def _strip_comment(cls, line):
+ """
+ Strip a comment from a series file line
+
+ >>> PatchSeries._strip_comment("does/not matter")
+ 'does/not matter'
+ >>> PatchSeries._strip_comment("remove/the # comment # text")
+ 'remove/the'
+ >>> PatchSeries._strip_comment("leave/level/intact -p1 # comment # text")
+ 'leave/level/intact -p1'
+ """
+ return re.sub(cls.comment_re, '', line)
+
+ @classmethod
+ def _split_strip(cls, line):
"""
Separate the -p<num> option from the patch name
@@ -244,7 +260,7 @@ class PatchSeries(list):
split = line.rsplit(None, 1)
if len(split) > 1:
- m = re.match('-p(?P<level>[0-9]+)', split[1])
+ m = cls.level_re.match(split[1])
if m:
patch = split[0]
strip = int(m.group('level'))
@@ -252,7 +268,7 @@ class PatchSeries(list):
return (patch, strip)
@classmethod
- def _parse_line(klass, line, patch_dir):
+ def _parse_line(cls, line, patch_dir):
"""
Parse a single line from a series file
@@ -261,7 +277,7 @@ class PatchSeries(list):
>>> PatchSeries._parse_line("a/b", '.')
<gbp.patch_series.Patch path='./a/b' topic='a' >
"""
- line = line.rstrip()
- topic = klass._get_topic(line)
- (patch, split) = klass._split_strip(line)
+ line = cls._strip_comment(line.rstrip())
+ topic = cls._get_topic(line)
+ (patch, split) = cls._split_strip(line)
return Patch(os.path.join(patch_dir, patch), topic, split)
diff --git a/gbp/pkg/__init__.py b/gbp/pkg/__init__.py
index b693829..75975b1 100644
--- a/gbp/pkg/__init__.py
+++ b/gbp/pkg/__init__.py
@@ -27,23 +27,24 @@ import gbp.command_wrappers as gbpc
from gbp.errors import GbpError
# compression types, extra options and extensions
-compressor_opts = { 'gzip' : [ '-n', 'gz' ],
- 'bzip2' : [ '', 'bz2' ],
- 'lzma' : [ '', 'lzma' ],
- 'xz' : [ '', 'xz' ] }
+compressor_opts = {'gzip': ['-n', 'gz'],
+ 'bzip2': ['', 'bz2'],
+ 'lzma': ['', 'lzma'],
+ 'xz': ['', 'xz']}
# Map frequently used names of compression types to the internal ones:
-compressor_aliases = { 'bz2' : 'bzip2',
- 'gz' : 'gzip', }
+compressor_aliases = {'bz2': 'bzip2',
+ 'gz': 'gzip', }
# Supported archive formats
-archive_formats = [ 'tar', 'zip' ]
+archive_formats = ['tar', 'zip']
# Map combined file extensions to archive and compression format
-archive_ext_aliases = { 'tgz' : ('tar', 'gzip'),
- 'tbz2' : ('tar', 'bzip2'),
- 'tlz' : ('tar', 'lzma'),
- 'txz' : ('tar', 'xz')}
+archive_ext_aliases = {'tgz': ('tar', 'gzip'),
+ 'tbz2': ('tar', 'bzip2'),
+ 'tlz': ('tar', 'lzma'),
+ 'txz': ('tar', 'xz')}
+
def parse_archive_filename(filename):
"""
@@ -178,14 +179,15 @@ class PkgPolicy(object):
version_chars = r'[a-zA-Z\d\.\~\-\:\+]'
basename = parse_archive_filename(os.path.basename(filename))[0]
- version_filters = map(lambda x: x % version_chars,
- ( # Debian upstream tarball: package_'<version>.orig.tar.gz'
- r'^(?P<package>[a-z\d\.\+\-]+)_(?P<version>%s+)\.orig',
- # Debian native: 'package_<version>.tar.gz'
- r'^(?P<package>[a-z\d\.\+\-]+)_(?P<version>%s+)',
- # Upstream 'package-<version>.tar.gz'
- # or directory 'package-<version>':
- r'^(?P<package>[a-zA-Z\d\.\+\-]+)(-)(?P<version>[0-9]%s*)'))
+ version_filters = map(
+ lambda x: x % version_chars,
+ ( # Debian upstream tarball: package_'<version>.orig.tar.gz'
+ r'^(?P<package>[a-z\d\.\+\-]+)_(?P<version>%s+)\.orig',
+ # Debian native: 'package_<version>.tar.gz'
+ r'^(?P<package>[a-z\d\.\+\-]+)_(?P<version>%s+)',
+ # Upstream 'package-<version>.tar.gz'
+ # or directory 'package-<version>':
+ r'^(?P<package>[a-zA-Z\d\.\+\-]+)(-)(?P<version>[0-9]%s*)'))
if extra_regex:
version_filters = extra_regex + version_filters
@@ -282,8 +284,8 @@ class UpstreamSource(object):
self._orig = True
elif parts[-2] == 'tar':
if (parts[-1] in compressor_opts or
- parts[-1] in compressor_aliases):
- self._orig = True
+ parts[-1] in compressor_aliases):
+ self._orig = True
except IndexError:
self._orig = False
@@ -310,8 +312,8 @@ class UpstreamSource(object):
def unpack(self, dir, filters=[]):
"""
Unpack packed upstream sources into a given directory
- and determine the toplevel of the source tree filtering
- out files specified by filters.
+ (filtering out files specified by filters) and determine the
+ toplevel of the source tree.
"""
if self.is_dir():
raise GbpError("Cannot unpack directory %s" % self.path)
diff --git a/gbp/pkg/pristinetar.py b/gbp/pkg/pristinetar.py
index 9197789..79e1334 100644
--- a/gbp/pkg/pristinetar.py
+++ b/gbp/pkg/pristinetar.py
@@ -20,9 +20,10 @@ import os
import gbp.log
from gbp.command_wrappers import Command
+
class PristineTar(Command):
"""The pristine-tar branch in a git repository"""
- cmd='/usr/bin/pristine-tar'
+ cmd = '/usr/bin/pristine-tar'
branch = 'pristine-tar'
def __init__(self, repo):
@@ -63,7 +64,7 @@ class PristineTar(Command):
@param archive: the name of the orig archive
@type archive: C{str}
"""
- self.run_error = 'Pristine-tar couldn\'t checkout "%s": {stderr}' % os.path.basename(archive)
+ self.run_error = 'Pristine-tar couldn\'t checkout "%s": {stderr_or_reason}' % os.path.basename(archive)
self.__call__(['checkout', archive])
def commit(self, archive, upstream):
@@ -76,7 +77,6 @@ class PristineTar(Command):
@param upstream: the upstream branch to diff against
@type upstream: C{str}
"""
- self.run_error = ("Couldn't commit to '%s' with upstream '%s': {stderr}" %
+ self.run_error = ("Couldn't commit to '%s' with upstream '%s': {stderr_or_reason}" %
(self.branch, upstream))
self.__call__(['commit', archive, upstream])
-
diff --git a/gbp/rpm/__init__.py b/gbp/rpm/__init__.py
index 119d55e..5a9a668 100644
--- a/gbp/rpm/__init__.py
+++ b/gbp/rpm/__init__.py
@@ -99,7 +99,7 @@ class SrcRpmFile(object):
c = gbpc.RunAtCommand('rpm2cpio',
[self.srpmfile, '|', 'cpio', '-id'],
shell=True, capture_stderr=True)
- c.run_error = "'%s' failed: {stderr}" % (" ".join([c.cmd] + c.args))
+ c.run_error = "'%s' failed: {stderr_or_reason}" % (" ".join([c.cmd] + c.args))
c(dir=dest_dir)
diff --git a/gbp/rpm/changelog.py b/gbp/rpm/changelog.py
new file mode 100644
index 0000000..7f59816
--- /dev/null
+++ b/gbp/rpm/changelog.py
@@ -0,0 +1,261 @@
+# vim: set fileencoding=utf-8 :
+#
+# (C) 2014-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, please see
+# <http://www.gnu.org/licenses/>
+"""An RPM Changelog"""
+
+import locale
+import datetime
+import re
+
+from functools import wraps
+
+import gbp.log
+
+
+def c_locale(category):
+ def _decorator(f):
+ @wraps(f)
+ def wrapper(*args, **kwargs):
+ saved = locale.setlocale(category, None)
+ locale.setlocale(category, 'C')
+ ret = f(*args, **kwargs)
+ locale.setlocale(category, saved)
+ return ret
+ return wrapper
+ return _decorator
+
+
+class ChangelogError(Exception):
+ """Problem parsing changelog"""
+ pass
+
+
+class _ChangelogHeader(object):
+ """The header part of one changelog section"""
+
+ def __init__(self, pkgpolicy, time=None, **kwargs):
+ self._pkgpolicy = pkgpolicy
+ self._data = {'time': time}
+ self._data.update(kwargs)
+
+ def __contains__(self, key):
+ return key in self._data
+
+ def __getitem__(self, key):
+ if key in self._data:
+ return self._data[key]
+ return None
+
+ @c_locale(locale.LC_TIME)
+ def __str__(self):
+ keys = dict(self._data)
+ keys['time'] = self._data['time'].strftime(
+ self._pkgpolicy.Changelog.header_time_format)
+ try:
+ return self._pkgpolicy.Changelog.header_format % keys + '\n'
+ except KeyError as err:
+ raise ChangelogError("Unable to format changelog header, missing "
+ "property %s" % err)
+
+
+class _ChangelogEntry(object):
+ """An entry (one 'change') in an RPM changelog"""
+
+ def __init__(self, pkgpolicy, author, text):
+ """
+ @param pkgpolicy: RPM packaging policy
+ @type pkgpolicy: L{RpmPkgPolicy}
+ @param author: author of the change
+ @type author: C{str}
+ @param text: message of the changelog entry
+ @type text: C{str} or C{list} of C{str}
+ """
+ self._pkgpolicy = pkgpolicy
+ self.author = author
+ if isinstance(text, str):
+ self._text = text.splitlines()
+ else:
+ self._text = text
+ # Strip trailing empty lines
+ while text and not text[-1].strip():
+ text.pop()
+
+ def __str__(self):
+ # Currently no (re-)formatting, just raw text
+ string = ""
+ for line in self._text:
+ string += line + '\n'
+ return string
+
+
+class _ChangelogSection(object):
+ """One section (set of changes) in an RPM changelog"""
+
+ def __init__(self, pkgpolicy, *args, **kwargs):
+ self._pkgpolicy = pkgpolicy
+ self.header = _ChangelogHeader(pkgpolicy, *args, **kwargs)
+ self.entries = []
+ self._trailer = '\n'
+
+ def __str__(self):
+ text = str(self.header)
+ for entry in self.entries:
+ text += str(entry)
+ # Add "section separator"
+ text += self._trailer
+ return text
+
+ def set_header(self, *args, **kwargs):
+ """Change the section header"""
+ self.header = _ChangelogHeader(self._pkgpolicy, *args, **kwargs)
+
+ def append_entry(self, entry):
+ """Add a new entry to the end of the list of entries"""
+ self.entries.append(entry)
+ return entry
+
+
+class Changelog(object):
+ """An RPM changelog"""
+
+ def __init__(self, pkgpolicy):
+ self._pkgpolicy = pkgpolicy
+ self.sections = []
+
+ def __str__(self):
+ string = ""
+ for section in self.sections:
+ string += str(section)
+ return string
+
+ def create_entry(self, *args, **kwargs):
+ """Create and return new entry object"""
+ return _ChangelogEntry(self._pkgpolicy, *args, **kwargs)
+
+ def add_section(self, *args, **kwargs):
+ """Add new empty section"""
+ section = _ChangelogSection(self._pkgpolicy, *args, **kwargs)
+ self.sections.insert(0, section)
+ return section
+
+
+class ChangelogParser(object):
+ """Parser for RPM changelogs"""
+
+ def __init__(self, pkgpolicy):
+ self._pkgpolicy = pkgpolicy
+ self.section_match_re = pkgpolicy.Changelog.section_match_re
+ self.section_split_re = pkgpolicy.Changelog.section_split_re
+ self.header_split_re = pkgpolicy.Changelog.header_split_re
+ self.header_name_split_re = pkgpolicy.Changelog.header_name_split_re
+ self.body_name_re = pkgpolicy.Changelog.body_name_re
+
+ def raw_parse_string(self, string):
+ """Parse changelog - only splits out raw changelog sections."""
+ changelog = Changelog(self._pkgpolicy)
+ ch_section = ""
+ for line in string.splitlines():
+ if re.match(self.section_match_re, line, re.M | re.S):
+ if ch_section:
+ changelog.sections.append(ch_section)
+ ch_section = line + '\n'
+ elif ch_section:
+ ch_section += line + '\n'
+ else:
+ raise ChangelogError("First line in changelog is invalid")
+ if ch_section:
+ changelog.sections.append(ch_section)
+ return changelog
+
+ def raw_parse_file(self, changelog):
+ """Parse changelog file - only splits out raw changelog sections."""
+ try:
+ with open(changelog) as ch_file:
+ return self.raw_parse_string(ch_file.read())
+ except IOError as err:
+ raise ChangelogError("Unable to read changelog file: %s" % err)
+
+ @c_locale(locale.LC_TIME)
+ def _parse_section_header(self, text):
+ """Parse one changelog section header"""
+ # Try to split out time stamp and "changelog name"
+ match = re.match(self.header_split_re, text, re.M)
+ if not match:
+ raise ChangelogError("Unable to parse changelog header: %s" % text)
+ try:
+ time = datetime.datetime.strptime(match.group('ch_time'),
+ "%a %b %d %Y")
+ except ValueError:
+ raise ChangelogError("Unable to parse changelog header: invalid "
+ "timestamp '%s'" % match.group('ch_time'))
+ # Parse "name" part which consists of name and/or email and an optional
+ # revision
+ name_text = match.group('ch_name')
+ match = re.match(self.header_name_split_re, name_text)
+ if not match:
+ raise ChangelogError("Unable to parse changelog header: invalid "
+ "name / revision '%s'" % name_text)
+ kwargs = match.groupdict()
+ return _ChangelogSection(self._pkgpolicy, time=time, **kwargs)
+
+ def _create_entry(self, author, text):
+ """Create a new changelog entry"""
+ return _ChangelogEntry(self._pkgpolicy, author=author, text=text)
+
+ def _parse_section_entries(self, text, default_author):
+ """Parse entries from a string and add them to a section"""
+ entries = []
+ entry_text = []
+ author = default_author
+ for line in text.splitlines():
+ match = re.match(self.body_name_re, line)
+ if match:
+ if entry_text:
+ entries.append(self._create_entry(author, entry_text))
+ author = match.group('name')
+ else:
+ if line.startswith("-"):
+ if entry_text:
+ entries.append(self._create_entry(author, entry_text))
+ entry_text = [line]
+ else:
+ if not entry_text:
+ gbp.log.info("First changelog entry (%s) is garbled, "
+ "entries should start with a dash ('-')" %
+ line)
+ entry_text.append(line)
+ if entry_text:
+ entries.append(self._create_entry(author, entry_text))
+
+ return entries
+
+ def parse_section(self, text):
+ """Parse one section"""
+ # Check that the first line(s) look like a changelog header
+ match = re.match(self.section_split_re, text, re.M | re.S)
+ if not match:
+ raise ChangelogError("Doesn't look like changelog header: %s..." %
+ text.splitlines()[0])
+ # Parse header
+ section = self._parse_section_header(match.group('ch_header'))
+ header = section.header
+ # Parse entries
+ default_author = header['name'] if 'name' in header else header['email']
+ for entry in self._parse_section_entries(match.group('ch_body'),
+ default_author):
+ section.append_entry(entry)
+
+ return section
diff --git a/gbp/rpm/git.py b/gbp/rpm/git.py
index 801306e..5f11a08 100644
--- a/gbp/rpm/git.py
+++ b/gbp/rpm/git.py
@@ -15,7 +15,6 @@
# 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/>
-import re
from gbp.format import format_str
from gbp.errors import GbpError
@@ -97,7 +96,7 @@ class RpmGitRepository(GitRepository):
def has_pristine_tar_branch(self):
"""
- Wheter the repo has a I{pristine-tar} branch.
+ Whether the repo has a I{pristine-tar} branch.
@return: C{True} if the repo has pristine-tar commits already, C{False}
otherwise
diff --git a/gbp/rpm/lib_rpm.py b/gbp/rpm/lib_rpm.py
index 4abc666..5fc0354 100644
--- a/gbp/rpm/lib_rpm.py
+++ b/gbp/rpm/lib_rpm.py
@@ -26,8 +26,8 @@ try:
librpm = __import__(RpmPkgPolicy.python_rpmlib_module_name)
except ImportError:
gbp.log.warn("Failed to import '%s' as rpm python module, using host's "
- "default rpm library instead" %
- RpmPkgPolicy.python_rpmlib_module_name)
+ "default rpm library instead" %
+ RpmPkgPolicy.python_rpmlib_module_name)
import rpm as librpm
# Module initialization
@@ -44,4 +44,3 @@ def get_librpm_log(truncate=True):
if truncate:
_rpmlogfd.truncate(0)
return log
-
diff --git a/gbp/rpm/policy.py b/gbp/rpm/policy.py
index 80e0abd..b1b1337 100644
--- a/gbp/rpm/policy.py
+++ b/gbp/rpm/policy.py
@@ -17,7 +17,10 @@
"""Default packaging policy for RPM"""
import re
+
from gbp.pkg import PkgPolicy, parse_archive_filename
+from gbp.scripts.common.pq import parse_gbp_commands
+
class RpmPkgPolicy(PkgPolicy):
"""Packaging policy for RPM"""
@@ -33,15 +36,15 @@ class RpmPkgPolicy(PkgPolicy):
# Regexp for checking the validity of package name
packagename_re = re.compile("^[%s][%s%s]+$" %
- (alnum, alnum, name_whitelist_chars))
+ (alnum, alnum, name_whitelist_chars))
packagename_msg = ("Package names must be at least two characters long, "
"start with an alphanumeric and can only contain "
"alphanumerics or characters in %s" %
- list(name_whitelist_chars))
+ list(name_whitelist_chars))
# Regexp for checking the validity of package (upstream) version
upstreamversion_re = re.compile("^[0-9][%s%s]*$" %
- (alnum, version_whitelist_chars))
+ (alnum, version_whitelist_chars))
upstreamversion_msg = ("Upstream version numbers must start with a digit "
"and can only containg alphanumerics or characters "
"in %s" % list(version_whitelist_chars))
@@ -70,3 +73,128 @@ class RpmPkgPolicy(PkgPolicy):
return True
return False
+ class Changelog(object):
+ """Container for changelog related policy settings"""
+
+ # Regexps for splitting/parsing the changelog section (of
+ # Tizen / Fedora style changelogs)
+ section_match_re = r'^\*'
+ section_split_re = r'^\*\s*(?P<ch_header>\S.*?)$\n(?P<ch_body>.*)'
+ header_split_re = r'(?P<ch_time>\S.*\s[0-9]{4})\s+(?P<ch_name>\S.*$)'
+ header_name_split_re = r'(?P<name>[^<]*)\s+<(?P<email>[^>]+)>((\s*-)?\s+(?P<revision>\S+))?$'
+ body_name_re = r'\[(?P<name>.*)\]'
+
+ # Changelog header format (when writing out changelog)
+ header_format = "* %(time)s %(name)s <%(email)s> %(revision)s"
+ header_time_format = "%a %b %d %Y"
+ header_rev_format = "%(version)s"
+
+ class ChangelogEntryFormatter(object):
+ """Helper class for generating changelog entries from git commits"""
+
+ # Maximum length for a changelog entry line
+ max_entry_line_length = 76
+ # Bug tracking system related meta tags recognized from git commit msg
+ bts_meta_tags = ("Close", "Closes", "Fixes", "Fix")
+ # Regexp for matching bug tracking system ids (e.g. "bgo#123")
+ bug_id_re = r'[A-Za-z0-9#_\-]+'
+
+ @classmethod
+ def _parse_bts_tags(cls, lines, meta_tags):
+ """
+ Parse and filter out bug tracking system related meta tags from
+ commit message.
+
+ @param lines: commit message
+ @type lines: C{list} of C{str}
+ @param meta_tags: meta tags to look for
+ @type meta_tags: C{tuple} of C{str}
+ @return: bts-ids per meta tag and the non-mathced lines
+ @rtype: (C{dict}, C{list} of C{str})
+ """
+ tags = {}
+ other_lines = []
+ bts_re = re.compile(r'^(?P<tag>%s):\s*(?P<ids>.*)' %
+ ('|'.join(meta_tags)), re.I)
+ bug_id_re = re.compile(cls.bug_id_re)
+ for line in lines:
+ match = bts_re.match(line)
+ if match:
+ tag = match.group('tag')
+ ids_str = match.group('ids')
+ bug_ids = [bug_id.strip() for bug_id in
+ bug_id_re.findall(ids_str)]
+ if tag in tags:
+ tags[tag] += bug_ids
+ else:
+ tags[tag] = bug_ids
+ else:
+ other_lines.append(line)
+ return (tags, other_lines)
+
+ @classmethod
+ def _extra_filter(cls, lines, ignore_re):
+ """
+ Filter out specific lines from the commit message.
+
+ @param lines: commit message
+ @type lines: C{list} of C{str}
+ @param ignore_re: regexp for matching ignored lines
+ @type ignore_re: C{str}
+ @return: filtered commit message
+ @rtype: C{list} of C{str}
+ """
+ if ignore_re:
+ match = re.compile(ignore_re)
+ return [line for line in lines if not match.match(line)]
+ else:
+ return lines
+
+ @classmethod
+ def compose(cls, commit_info, **kwargs):
+ """
+ Generate a changelog entry from a git commit.
+
+ @param commit_info: info about the commit
+ @type commit_info: C{commit_info} object from
+ L{gbp.git.repository.GitRepository.get_commit_info()}.
+ @param kwargs: additional arguments to the compose() method,
+ currently we recognize 'full', 'id_len' and 'ignore_re'
+ @type kwargs: C{dict}
+ @return: formatted changelog entry
+ @rtype: C{list} of C{str}
+ """
+ # Parse and filter out gbp command meta-tags
+ cmds, body = parse_gbp_commands(commit_info, 'gbp-rpm-ch',
+ ('ignore', 'short', 'full'), ())
+ body = body.splitlines()
+ if 'ignore' in cmds:
+ return None
+
+ # Parse and filter out bts-related meta-tags
+ bts_tags, body = cls._parse_bts_tags(body, cls.bts_meta_tags)
+
+ # Additional filtering
+ body = cls._extra_filter(body, kwargs['ignore_re'])
+
+ # Generate changelog entry
+ subject = commit_info['subject']
+ commitid = commit_info['id']
+ if kwargs['id_len']:
+ text = ["- [%s] %s" % (commitid[0:kwargs['id_len']], subject)]
+ else:
+ text = ["- %s" % subject]
+
+ # Add all non-filtered-out lines from commit message, unless 'short'
+ if (kwargs['full'] or 'full' in cmds) and 'short' not in cmds:
+ # Add all non-blank body lines.
+ text.extend([" " + line for line in body if line.strip()])
+
+ # Add bts tags and ids in the end
+ for tag, ids in bts_tags.iteritems():
+ bts_msg = " (%s: %s)" % (tag, ', '.join(ids))
+ if len(text[-1]) + len(bts_msg) >= cls.max_entry_line_length:
+ text.append(" ")
+ text[-1] += bts_msg
+
+ return text
diff --git a/gbp/scripts/buildpackage.py b/gbp/scripts/buildpackage.py
index ced5348..a0efa42 100755
--- a/gbp/scripts/buildpackage.py
+++ b/gbp/scripts/buildpackage.py
@@ -1,4 +1,3 @@
-
# vim: set fileencoding=utf-8 :
#
# (C) 2006-2016 Guido Günther <agx@sigxcpu.org>
@@ -18,9 +17,8 @@
#
"""Build a Debian package out of a Git repository"""
-from six.moves import configparser
import errno
-import os, os.path
+import os
import shutil
import sys
import time
@@ -42,17 +40,20 @@ from gbp.scripts.common.buildpackage import (index_name, wc_name,
git_archive_submodules,
git_archive_single, dump_tree,
write_wc, drop_index)
+from gbp.scripts.common import ExitCodes
+from gbp.scripts.common.hook import Hook
from gbp.pkg import compressor_opts, compressor_aliases, parse_archive_filename
-#{ upstream tarball preparation
-def git_archive(repo, cp, output_dir, treeish, comp_type, comp_level, with_submodules, subtarball=None):
+
+# upstream tarball preparation
+def git_archive(repo, cp, output_dir, treeish, comp_type, comp_level, with_submodules, component=None):
"create a compressed orig tarball in output_dir using git_archive"
try:
comp_opts = compressor_opts[comp_type][0]
except KeyError:
raise GbpError("Unsupported compression type '%s'" % comp_type)
- output = os.path.join(output_dir, du.orig_file(cp, comp_type, subtarball=subtarball))
+ output = os.path.join(output_dir, du.orig_file(cp, comp_type, component=component))
prefix = "%s-%s" % (cp['Source'], cp['Upstream-Version'])
try:
@@ -89,8 +90,8 @@ def prepare_upstream_tarball(repo, cp, options, tarball_dir, output_dir):
options.tarball_dir)
orig_files = [du.orig_file(cp, options.comp_type)]
- if options.subtarballs:
- orig_files += [du.orig_file(cp, options.comp_type, sub) for sub in options.subtarballs]
+ if options.components:
+ orig_files += [du.orig_file(cp, options.comp_type, c) for c in options.components]
# look in tarball_dir first, if found force a symlink to it
if options.tarball_dir:
@@ -123,9 +124,8 @@ def pristine_tar_commit(repo, cp, options, output_dir, orig_file, upstream_tree)
archive)
repo.pristine_tar.commit(archive, upstream_tree)
-#}
-#{ Functions to handle export-dir
+# Functions to handle export-dir
def write_tree(repo, options):
"""
Write a tree of the index or working copy if necessary
@@ -207,10 +207,10 @@ def extract_orig(orig_tarball, dest_dir):
if os.path.exists(underlay_debian_dir) and os.path.exists(format_file):
format = DebianSourceFormat.parse_file(format_file)
if format.version in ['2.0', '3.0']:
- gbp.log.info("Removing debian/ from unpacked upstream source at %s" % underlay_debian_dir)
+ gbp.log.info("Removing debian/ from unpacked upstream "
+ "source at %s" % underlay_debian_dir)
shutil.rmtree(underlay_debian_dir)
-#}
def source_vfs(repo, options, tree):
"""Init source package info either from git or from working copy"""
@@ -220,7 +220,7 @@ def source_vfs(repo, options, tree):
source = DebianSource(GitVfs(repo, tree))
else:
source = DebianSource('.')
- source.is_native() # check early if this works
+ source.is_native() # check early if this works
except Exception as e:
raise GbpError("Can't determine package type: %s" % e)
return source
@@ -253,26 +253,27 @@ def pristine_tar_build_orig(repo, cp, output_dir, options):
repo.pristine_tar.branch)
# Make sure the upstream tree exists, it might not be there in
- # case of subtarballs since we don't keep a ref to it
- if options.subtarballs:
+ # case of components since we don't keep a ref to it
+ if options.components:
try:
upstream_tag = repo.version_to_tag(options.upstream_tag, cp.upstream_version)
tree_name = "%s^{tree}" % upstream_tag
- repo.tree_drop_dirs(tree_name, options.subtarballs)
+ repo.tree_drop_dirs(tree_name, options.components)
except GitRepositoryError:
- raise GbpError("Couldn't find upstream tree '%s' to create orig tarball via pristine-tar" % tree_name)
+ raise GbpError("Couldn't find upstream tree '%s' to create "
+ "orig tarball via pristine-tar" % tree_name)
try:
repo.pristine_tar.checkout(cp.name,
cp.upstream_version,
options.comp_type,
output_dir)
- for subtarball in options.subtarballs:
+ for component in options.components:
repo.pristine_tar.checkout(cp.name,
cp.upstream_version,
options.comp_type,
output_dir,
- subtarball=subtarball)
+ component=component)
return True
except CommandExecFailed:
if options.pristine_tar_commit:
@@ -321,26 +322,27 @@ def git_archive_build_orig(repo, cp, output_dir, options):
upstream_tree))
gbp.log.debug("Building upstream tarball with compression '%s -%s'" %
(options.comp_type, options.comp_level))
- main_tree = repo.tree_drop_dirs(upstream_tree, options.subtarballs)
+ main_tree = repo.tree_drop_dirs(upstream_tree, options.components)
if not git_archive(repo, cp, output_dir, main_tree,
options.comp_type,
options.comp_level,
options.with_submodules):
raise GbpError("Cannot create upstream tarball at '%s'" % output_dir)
- for subtarball in options.subtarballs:
- subtree = repo.tree_get_dir(upstream_tree, subtarball)
+ for component in options.components:
+ subtree = repo.tree_get_dir(upstream_tree, component)
if not subtree:
- raise GbpError("No tree for '%s' found in '%s' to create subtarball from" % (subtarball, upstream_tree))
- gbp.log.info("Creating subtarball '%s' from '%s'" % (du.orig_file(cp,
- options.comp_type,
- subtarball=subtarball),
- subtree))
+ raise GbpError("No tree for '%s' found in '%s' to create additional tarball from"
+ % (component, upstream_tree))
+ gbp.log.info("Creating additional tarball '%s' from '%s'"
+ % (du.orig_file(cp, options.comp_type, component=component),
+ subtree))
if not git_archive(repo, cp, output_dir, subtree,
options.comp_type,
options.comp_level,
options.with_submodules,
- subtarball=subtarball):
- raise GbpError("Cannot create upstream component tarball %s at '%s'" % (subtarball, output_dir))
+ component=component):
+ raise GbpError("Cannot create additional tarball %s at '%s'"
+ % (component, output_dir))
return upstream_tree
@@ -410,7 +412,7 @@ def get_pbuilder_dist(options, repo, native=False):
vendor = du.get_vendor().lower()
suite = parts[1]
if vendor == parts[0]:
- dist = '' if suite == 'sid' else suite
+ dist = '' if suite in ['sid', 'master'] else suite
else:
dist = '%s_%s' % (parts[0], suite)
elif len(parts) == 1 and native and branch in ['master', 'sid']:
@@ -487,32 +489,32 @@ def changes_file_suffix(dpkg_args):
return os.getenv('ARCH', None) or du.get_arch()
-def md(a, b):
- "Merge two dictionaires a and b"
- c = a.copy()
- c.update(b)
- return c
-
-
def build_parser(name, prefix=None):
try:
parser = GbpOptionParserDebian(command=os.path.basename(name), prefix=prefix)
- except configparser.ParsingError as err:
+ except GbpError 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")
+ tag_group = GbpOptionGroup(parser,
+ "tag options",
+ "options related to git tag creation")
+ orig_group = GbpOptionGroup(parser,
+ "orig tarball options",
+ "options related to the creation of the orig tarball")
+ 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")
+ export_group = GbpOptionGroup(parser,
+ "export build-tree options",
+ "alternative build tree related options")
+ for group in [tag_group, orig_group, branch_group, cmd_group, export_group]:
+ parser.add_option_group(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="color", dest="color", type='tristate')
@@ -520,11 +522,11 @@ def build_parser(name, prefix=None):
dest="color_scheme")
parser.add_config_file_option(option_name="notify", dest="notify", type='tristate')
tag_group.add_option("--git-tag", action="store_true", dest="tag", default=False,
- help="create a tag after a successful build")
+ 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")
+ 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")
+ 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="debian-tag", dest="debian_tag")
@@ -535,44 +537,53 @@ def build_parser(name, prefix=None):
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",
- help="force creation of orig tarball", action="store_true")
+ help="force creation of orig tarball", action="store_true")
orig_group.add_config_file_option(option_name="no-create-orig", dest="no_create_orig",
- help="don't create orig tarball", action="store_true")
+ help="don't create orig tarball", action="store_true")
orig_group.add_config_file_option(option_name="tarball-dir", dest="tarball_dir", type="path",
- help="location to look for external tarballs")
+ help="location to look for external tarballs")
orig_group.add_config_file_option(option_name="compression", dest="comp_type",
- help="Compression type, default is '%(compression)s'")
+ help="Compression type, default is '%(compression)s'")
orig_group.add_config_file_option(option_name="compression-level", dest="comp_level",
- help="Compression level, default is '%(compression-level)s'")
- orig_group.add_option("--git-subtarball", action="append", metavar='SUBTARBALL',
- dest="subtarballs", help="subtarsball to generate, can be given multiple times", default=[])
+ help="Compression level, default is '%(compression-level)s'")
+ orig_group.add_config_file_option("component", action="append", metavar='COMPONENT',
+ dest="components")
branch_group.add_config_file_option(option_name="upstream-branch", dest="upstream_branch")
branch_group.add_config_file_option(option_name="debian-branch", dest="debian_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")
+ 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 Debian package, default is '%(builder)s'")
+ help="command to build the Debian 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'")
+ help="command to clean the working copy, "
+ "default is '%(cleaner)s'")
cmd_group.add_config_file_option(option_name="prebuild", dest="prebuild",
- help="hook to run before a build, default is '%(prebuild)s'")
+ help="hook to run before a build, "
+ "default is '%(prebuild)s'")
cmd_group.add_config_file_option(option_name="postexport", dest="postexport",
- help="hook to run after exporting the source tree, default is '%(postexport)s'")
+ help="hook 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'")
+ 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'")
+ help="hook run after a successful tag operation, "
+ "default is '%(posttag)s'")
cmd_group.add_boolean_config_file_option(option_name="pbuilder", dest="use_pbuilder")
cmd_group.add_boolean_config_file_option(option_name="qemubuilder", dest="use_qemubuilder")
cmd_group.add_config_file_option(option_name="dist", dest="pbuilder_dist")
cmd_group.add_config_file_option(option_name="arch", dest="pbuilder_arch")
- cmd_group.add_boolean_config_file_option(option_name = "pbuilder-autoconf", dest="pbuilder_autoconf")
+ cmd_group.add_boolean_config_file_option(option_name="pbuilder-autoconf",
+ dest="pbuilder_autoconf")
cmd_group.add_config_file_option(option_name="pbuilder-options", dest="pbuilder_options")
cmd_group.add_boolean_config_file_option(option_name="hooks", dest="hooks")
export_group.add_config_file_option(option_name="export-dir", dest="export_dir", type="path",
- help="before building the package export the source into EXPORT_DIR, default is '%(export-dir)s'")
+ help="before building the package export the source into EXPORT_DIR, "
+ "default is '%(export-dir)s'")
export_group.add_config_file_option("export", dest="export",
- help="export treeish object TREEISH, default is '%(export)s'", metavar="TREEISH")
+ help="export treeish object TREEISH, "
+ "default is '%(export)s'", metavar="TREEISH")
export_group.add_boolean_config_file_option(option_name="purge", dest="purge")
export_group.add_option("--git-dont-purge", action="store_true", dest="dont_purge", default=False,
help="deprecated, use --git-no-purge instead")
@@ -581,11 +592,11 @@ def build_parser(name, prefix=None):
def parse_args(argv, prefix):
- args = [ arg for arg in argv[1:] if arg.find('--%s' % prefix) == 0 ]
- dpkg_args = [ arg for arg in argv[1:] if arg.find('--%s' % prefix) == -1 ]
+ args = [arg for arg in argv[1:] if arg.find('--%s' % prefix) == 0]
+ dpkg_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" ]:
+ for arg in ["--help", "-h", "--version"]:
if arg in dpkg_args:
args.append(arg)
@@ -599,7 +610,8 @@ def parse_args(argv, prefix):
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))
+ gbp.log.err("'--%sretag' needs either '--%stag' or '--%stag-only'"
+ % (prefix, prefix, prefix))
return None, None, None
if options.overlay and not options.export_dir:
@@ -611,22 +623,13 @@ def parse_args(argv, prefix):
gbp.log.warning("--git-dont-purge is depreceted, use --git-no-purge instead")
options.purge = False
- if options.subtarballs and options.pristine_tar_commit:
- gbp.log.warning("Subtarballs specified, pristine-tar-commit not yet supported - disabling it.")
+ if options.components and options.pristine_tar_commit:
+ gbp.log.warning("Components specified, pristine-tar-commit not yet supported - disabling it.")
options.pristine_tar_commit = False
return options, args, dpkg_args
-class Hook(RunAtCommand):
- "A hook run during the build"
- def __init__(self, name, *args, **kwargs):
- if 'shell' not in kwargs:
- kwargs['shell'] = True
- RunAtCommand.__init__(self, *args, **kwargs)
- self.run_error = '%s-hook %s' % (name, self.run_error)
-
-
def main(argv):
retval = 0
prefix = "git-"
@@ -637,15 +640,13 @@ def main(argv):
options, gbp_args, dpkg_args = parse_args(argv, prefix)
if not options:
- return 1
+ return ExitCodes.parse_error
try:
repo = DebianGitRepository(os.path.curdir)
except GitRepositoryError:
gbp.log.err("%s is not a git repository" % (os.path.abspath('.')))
return 1
- else:
- repo_dir = os.path.abspath(os.path.curdir)
try:
Command(options.cleaner, shell=True)()
@@ -700,9 +701,9 @@ def main(argv):
# Run postexport hook
if options.postexport:
Hook('Postexport', options.postexport,
- extra_env=md(hook_env,
- {'GBP_GIT_DIR': repo.git_dir,
- 'GBP_TMP_DIR': tmp_dir})
+ extra_env=Hook.md(hook_env,
+ {'GBP_GIT_DIR': repo.git_dir,
+ 'GBP_TMP_DIR': tmp_dir})
)(dir=tmp_dir)
major = (source.changelog.debian_version if source.is_native()
@@ -716,23 +717,21 @@ def main(argv):
if not source.is_native() and options.postexport:
prepare_upstream_tarball(repo, source.changelog, options, tarball_dir,
output_dir)
-
- if options.export_dir:
build_dir = export_dir
else:
- build_dir = repo_dir
+ build_dir = repo.path
if options.prebuild:
Hook('Prebuild', options.prebuild,
- extra_env=md(hook_env,
- {'GBP_GIT_DIR': repo.git_dir,
- 'GBP_BUILD_DIR': build_dir})
+ extra_env=Hook.md(hook_env,
+ {'GBP_GIT_DIR': repo.git_dir,
+ 'GBP_BUILD_DIR': build_dir})
)(dir=build_dir)
# Finally build the package:
RunAtCommand(options.builder, dpkg_args, shell=True,
- extra_env=md(build_env,
- {'GBP_BUILD_DIR': build_dir})
+ extra_env=Hook.md(build_env,
+ {'GBP_BUILD_DIR': build_dir})
)(dir=build_dir)
if options.postbuild:
changes = os.path.abspath("%s/../%s_%s_%s.changes" %
@@ -742,9 +741,9 @@ def main(argv):
changes_file_suffix(dpkg_args)))
gbp.log.debug("Looking for changes file %s" % changes)
Hook('Postbuild', options.postbuild,
- extra_env=md(hook_env,
- {'GBP_CHANGES_FILE': changes,
- 'GBP_BUILD_DIR': build_dir})
+ extra_env=Hook.md(hook_env,
+ {'GBP_CHANGES_FILE': changes,
+ 'GBP_BUILD_DIR': build_dir})
)()
if options.tag or options.tag_only:
tag = repo.version_to_tag(options.debian_tag, source.changelog.version)
@@ -762,11 +761,14 @@ def main(argv):
if options.posttag:
sha = repo.rev_parse("%s^{}" % tag)
Hook('Posttag', options.posttag,
- extra_env=md(hook_env,
- {'GBP_TAG': tag,
- 'GBP_BRANCH': branch or '(no branch)',
- 'GBP_SHA1': sha})
+ extra_env=Hook.md(hook_env,
+ {'GBP_TAG': tag,
+ 'GBP_BRANCH': branch or '(no branch)',
+ 'GBP_SHA1': sha})
)()
+ except KeyboardInterrupt:
+ retval = 1
+ gbp.log.err("Interrupted. Aborting.")
except CommandExecFailed:
retval = 1
except (GbpError, GitRepositoryError) as err:
@@ -793,6 +795,7 @@ def main(argv):
return retval
+
if __name__ == '__main__':
sys.exit(main(sys.argv))
diff --git a/gbp/scripts/buildpackage_rpm.py b/gbp/scripts/buildpackage_rpm.py
index 00582df..6d50977 100644
--- a/gbp/scripts/buildpackage_rpm.py
+++ b/gbp/scripts/buildpackage_rpm.py
@@ -18,7 +18,6 @@
#
"""Build an RPM package out of a Git repository"""
-from six.moves import configparser
import os
import shutil
import sys
@@ -34,6 +33,7 @@ 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 import ExitCodes
from gbp.scripts.common.buildpackage import (index_name, wc_name,
git_archive_submodules,
git_archive_single, dump_tree,
@@ -78,8 +78,8 @@ def git_archive(repo, spec, output_dir, treeish, prefix, comp_level,
git_archive_single(treeish, output, prefix,
spec.orig_src['compression'], comp_level,
comp_opts, spec.orig_src['archive_fmt'])
- except (GitRepositoryError, CommandExecFailed):
- gbp.log.err("Error generating submodules' archives")
+ except (GitRepositoryError, CommandExecFailed) as e:
+ gbp.log.err("Error generating submodules' archives: %s" % e)
return False
return True
@@ -317,7 +317,7 @@ def build_parser(name, prefix=None, git_treeish=None):
try:
parser = GbpOptionParserRpm(command=os.path.basename(name),
prefix=prefix)
- except configparser.ParsingError as err:
+ except GbpError as err:
gbp.log.err(err)
return None
@@ -479,7 +479,7 @@ def main(argv):
options, gbp_args, builder_args = parse_args(argv, prefix)
if not options:
- return 1
+ return ExitCodes.parse_error
try:
repo = RpmGitRepository(os.path.curdir)
@@ -622,7 +622,9 @@ def main(argv):
'GBP_SHA1': sha})()
else:
vcs_info = get_vcs_info(repo, tree)
-
+ except KeyboardInterrupt:
+ retval = 1
+ gbp.log.err("Interrupted. Aborting.")
except CommandExecFailed:
retval = 1
except GitRepositoryError as err:
@@ -652,5 +654,6 @@ def main(argv):
return retval
+
if __name__ == '__main__':
sys.exit(main(sys.argv))
diff --git a/gbp/scripts/clone.py b/gbp/scripts/clone.py
index 216bf99..63b1468 100755
--- a/gbp/scripts/clone.py
+++ b/gbp/scripts/clone.py
@@ -19,13 +19,14 @@
#
"""Clone a Git repository and set it up for gbp"""
-from six.moves import configparser
import sys
-import os, os.path
+import os
from gbp.config import (GbpOptionParser, GbpOptionGroup)
from gbp.deb.git import DebianGitRepository
from gbp.git import (GitRepository, GitRepositoryError)
from gbp.errors import GbpError
+from gbp.scripts.common import ExitCodes
+from gbp.scripts.common.hook import Hook
import gbp.log
@@ -33,12 +34,14 @@ def build_parser(name):
try:
parser = GbpOptionParser(command=os.path.basename(name), prefix='',
usage='%prog [options] repository - clone a remote repository')
- except configparser.ParsingError as err:
+ except GbpError as err:
gbp.log.err(err)
return None
branch_group = GbpOptionGroup(parser, "branch options", "branch tracking and layout options")
+ cmd_group = GbpOptionGroup(parser, "external command options", "how and when to invoke hooks")
parser.add_option_group(branch_group)
+ parser.add_option_group(cmd_group)
branch_group.add_option("--all", action="store_true", dest="all", default=False,
help="track all branches, not only debian and upstream")
@@ -49,6 +52,10 @@ def build_parser(name):
help="git history depth (for creating shallow clones)")
branch_group.add_option("--reference", action="store", dest="reference", default=None,
help="git reference repository (use local copies where possible)")
+ cmd_group.add_config_file_option(option_name="postclone", dest="postclone",
+ help="hook to run after cloning the source tree, "
+ "default is '%(postclone)s'")
+ cmd_group.add_boolean_config_file_option(option_name="hooks", dest="hooks")
parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False,
help="verbose command execution")
@@ -58,7 +65,7 @@ def build_parser(name):
return parser
-def parse_args (argv):
+def parse_args(argv):
parser = build_parser(argv[0])
if not parser:
return None, None
@@ -73,7 +80,7 @@ def main(argv):
(options, args) = parse_args(argv)
if not options:
- return 1
+ return ExitCodes.parse_error
if len(args) < 2:
gbp.log.err("Need a repository to clone.")
@@ -90,12 +97,14 @@ def main(argv):
pass
try:
+ gbp.log.info("Cloning from '%s'%s" % (source, " into '%s'" % clone_to if not auto_name else ''))
repo = DebianGitRepository.clone(clone_to, source, options.depth,
- auto_name=auto_name,reference=options.reference)
+ auto_name=auto_name, reference=options.reference)
os.chdir(repo.path)
# Reparse the config files of the cloned repository so we pick up the
- # branch information from there:
+ # branch information from there but don't overwrite hooks:
+ postclone = options.postclone
(options, args) = parse_args(argv)
# Track all branches:
@@ -103,22 +112,30 @@ def main(argv):
remotes = repo.get_remote_branches()
for remote in remotes:
local = remote.replace("origin/", "", 1)
- if not repo.has_branch(local) and \
- local != "HEAD":
- repo.create_branch(local, remote)
- else: # only track gbp's default branches
- branches = [ options.debian_branch, options.upstream_branch ]
+ if (not repo.has_branch(local) and
+ local != "HEAD"):
+ repo.create_branch(local, remote)
+ else: # only track gbp's default branches
+ branches = [options.debian_branch, options.upstream_branch]
if options.pristine_tar:
- branches += [ repo.pristine_tar_branch ]
+ branches += [repo.pristine_tar_branch]
gbp.log.debug('Will track branches: %s' % branches)
for branch in branches:
remote = 'origin/%s' % branch
- if repo.has_branch(remote, remote=True) and \
- not repo.has_branch(branch):
- repo.create_branch(branch, remote)
+ if (repo.has_branch(remote, remote=True) and
+ not repo.has_branch(branch)):
+ repo.create_branch(branch, remote)
repo.set_branch(options.debian_branch)
+ if postclone:
+ Hook('Postclone', options.postclone,
+ extra_env={'GBP_GIT_DIR': repo.git_dir},
+ )()
+
+ except KeyboardInterrupt:
+ retval = 1
+ gbp.log.err("Interrupted. Aborting.")
except GitRepositoryError as err:
gbp.log.err("Git command failed: %s" % err)
retval = 1
@@ -129,6 +146,7 @@ def main(argv):
return retval
+
if __name__ == '__main__':
sys.exit(main(sys.argv))
diff --git a/gbp/scripts/common/__init__.py b/gbp/scripts/common/__init__.py
index a24bb62..dcf9197 100644
--- a/gbp/scripts/common/__init__.py
+++ b/gbp/scripts/common/__init__.py
@@ -15,3 +15,10 @@
# along with this program; if not, please see
# <http://www.gnu.org/licenses/>
"""Parts shared between the deb and rpm commands"""
+
+
+class ExitCodes(object):
+ ok = 0,
+ failed = 1 # All other errors
+ no_value = 2 # Value does not exist (gbp config only)
+ parse_error = 3 # Failed to parse configuration file
diff --git a/gbp/scripts/common/buildpackage.py b/gbp/scripts/common/buildpackage.py
index 676ee74..72489e5 100644
--- a/gbp/scripts/common/buildpackage.py
+++ b/gbp/scripts/common/buildpackage.py
@@ -1,6 +1,6 @@
# vim: set fileencoding=utf-8 :
#
-# (C) 2006-2011 Guido Guenther <agx@sigxcpu.org>
+# (C) 2006-2011, 2016 Guido Guenther <agx@sigxcpu.org>
# (C) 2012 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
@@ -18,11 +18,13 @@
#
"""Common functionality for Debian and RPM buildpackage scripts"""
-import os, os.path
+import os
+import os.path
import pipes
import tempfile
import shutil
from gbp.command_wrappers import (CatenateTarArchive, CatenateZipArchive)
+from gbp.git import GitRepositoryError
from gbp.errors import GbpError
import gbp.log
@@ -112,7 +114,7 @@ def git_archive_single(treeish, output, prefix, comp_type, comp_level, comp_opts
raise GbpError("Error creating %s: %d" % (output, ret))
-#{ Functions to handle export-dir
+# Functions to handle export-dir
def dump_tree(repo, export_dir, treeish, with_submodules, recursive=True):
"dump a tree to output_dir"
output_dir = os.path.dirname(export_dir)
@@ -147,11 +149,11 @@ def dump_tree(repo, export_dir, treeish, with_submodules, recursive=True):
ret = pipe.copy('', '')
os.chdir(top)
if ret:
- raise GbpError("Error in dump_tree archive pipe in submodule %s" % subdir)
+ raise GbpError("Error in dump_tree archive pipe in submodule %s" % subdir)
except OSError as err:
gbp.log.err("Error dumping tree to %s: %s" % (output_dir, err[0]))
return False
- except GbpError as err:
+ except (GitRepositoryError, GbpError) as err:
gbp.log.err(err)
return False
except Exception as e:
diff --git a/gbp/scripts/common/hook.py b/gbp/scripts/common/hook.py
new file mode 100644
index 0000000..7867b26
--- /dev/null
+++ b/gbp/scripts/common/hook.py
@@ -0,0 +1,33 @@
+# vim: set fileencoding=utf-8 :
+#
+# (C) 2016 Guido Günther <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
+# (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, please see
+# <http://www.gnu.org/licenses/>
+"""Common code for runniing hooks"""
+
+from gbp.command_wrappers import RunAtCommand
+
+
+class Hook(RunAtCommand):
+ "A hook run by one of the scripts"
+ def __init__(self, name, cmd, extra_env):
+ RunAtCommand.__init__(self, cmd, shell=True, extra_env=extra_env)
+ self.run_error = '%s-hook %s' % (name, self.run_error)
+
+ @staticmethod
+ def md(a, b):
+ "Merge two dictionaires a and b into a new one"
+ c = a.copy()
+ c.update(b)
+ return c
diff --git a/gbp/scripts/common/import_orig.py b/gbp/scripts/common/import_orig.py
index b2f45bb..eaa38b7 100644
--- a/gbp/scripts/common/import_orig.py
+++ b/gbp/scripts/common/import_orig.py
@@ -23,7 +23,6 @@ import tempfile
import gbp.command_wrappers as gbpc
import gbp.log
-from gbp.pkg import UpstreamSource
from gbp.errors import GbpError
from gbp.deb.upstreamsource import DebianUpstreamSource
@@ -31,10 +30,11 @@ from gbp.deb.upstreamsource import DebianUpstreamSource
# line editing and history capabilities. However, if readline is not
# available, raw_input will still work.
try:
- import readline
+ import readline # noqa: F401
except ImportError:
pass
+
def orig_needs_repack(upstream_source, options):
"""
Determine if the upstream sources needs to be repacked
@@ -80,7 +80,7 @@ def ask_package_name(default, name_validator_func, err_msg):
"""
while True:
sourcepackage = raw_input("What will be the source package name? [%s] " % default)
- if not sourcepackage: # No input, use the default.
+ if not sourcepackage: # No input, use the default.
sourcepackage = default
# Valid package name, return it.
if name_validator_func(sourcepackage):
@@ -99,7 +99,7 @@ def ask_package_version(default, ver_validator_func, err_msg):
"""
while True:
version = raw_input("What is the upstream version? [%s] " % default)
- if not version: # No input, use the default.
+ if not version: # No input, use the default.
version = default
# Valid version, return it.
if ver_validator_func(version):
@@ -116,13 +116,13 @@ def repacked_tarball_name(source, name, version):
# Repacked orig tarball needs a different name since there's already
# one with that name
name = os.path.join(
- os.path.dirname(source.path),
- os.path.basename(source.path).replace(".tar", ".gbp.tar"))
+ os.path.dirname(source.path),
+ os.path.basename(source.path).replace(".tar", ".gbp.tar"))
else:
# Repacked sources or other archives get canonical name
name = os.path.join(
- os.path.dirname(source.path),
- "%s_%s.orig.tar.bz2" % (name, version))
+ os.path.dirname(source.path),
+ "%s_%s.orig.tar.bz2" % (name, version))
return name
@@ -130,9 +130,9 @@ def repack_source(source, name, version, tmpdir, filters):
"""Repack the source tree"""
name = repacked_tarball_name(source, name, version)
repacked = source.pack(name, filters)
- if source.is_orig(): # the tarball was filtered on unpack
+ if source.is_orig(): # the tarball was filtered on unpack
repacked.unpacked = source.unpacked
- else: # otherwise unpack the generated tarball get a filtered tree
+ else: # otherwise unpack the generated tarball get a filtered tree
if tmpdir:
cleanup_tmp_tree(tmpdir)
tmpdir = tempfile.mkdtemp(dir='../')
@@ -149,7 +149,7 @@ def download_orig(url):
@rtype: DebianUpstreamSource
@raises GbpError: on all errors
"""
- CHUNK_SIZE=4096
+ CHUNK_SIZE = 4096
try:
import requests
@@ -171,8 +171,8 @@ def download_orig(url):
for d in r.iter_content(CHUNK_SIZE):
target_fd.write(d)
except Exception as e:
- raise GbpError("Failed to download %s: %s" % (url, e))
if os.path.exists(target):
os.unlink(target)
+ raise GbpError("Failed to download %s: %s" % (url, e))
return DebianUpstreamSource(target)
diff --git a/gbp/scripts/common/pq.py b/gbp/scripts/common/pq.py
index 5580426..fca4ec3 100644
--- a/gbp/scripts/common/pq.py
+++ b/gbp/scripts/common/pq.py
@@ -176,6 +176,7 @@ def write_patch_file(filename, commit_info, diff):
DEFAULT_PATCH_NUM_PREFIX_FORMAT = "%04d-"
+
def format_patch(outdir, repo, commit_info, series, numbered=True,
path_exclude_regex=None, topic='', name=None, renumber=False,
patch_num_prefix_format=DEFAULT_PATCH_NUM_PREFIX_FORMAT):
@@ -188,10 +189,10 @@ def format_patch(outdir, repo, commit_info, series, numbered=True,
try:
num_prefix = str(patch_num_prefix_format) % (len(series) + 1) \
- if numbered else ''
+ if numbered else ''
except Exception:
- gbp.log.warn("Bad format format string '%s', " \
- "falling back to default '%s'" % \
+ gbp.log.warn("Bad format format string '%s', "
+ "falling back to default '%s'" %
(str(patch_num_prefix_format),
DEFAULT_PATCH_NUM_PREFIX_FORMAT))
num_prefix = DEFAULT_PATCH_NUM_PREFIX_FORMAT % (len(series) + 1)
@@ -200,7 +201,7 @@ def format_patch(outdir, repo, commit_info, series, numbered=True,
if renumber:
# Remove any existing numeric prefix if the patch
# should be renumbered
- name = re.sub('^\d+[-_]*', '', name)
+ name = re.sub('^\d+[-_]*', '', name)
else:
# Otherwise, clear proposed prefix
num_prefix = ''
@@ -214,9 +215,8 @@ def format_patch(outdir, repo, commit_info, series, numbered=True,
filepath = os.path.join(outdir, filename)
# Make sure that we don't overwrite existing patches in the series
if filepath in series:
- presuffix = '-%d' % \
- len([p for p in series \
- if p.startswith(os.path.splitext(filepath)[0])])
+ presuffix = '-%d' % len([p for p in series
+ if p.startswith(os.path.splitext(filepath)[0])])
filename = num_prefix + base + presuffix + suffix
filepath = os.path.join(outdir, filename)
@@ -316,7 +316,11 @@ def apply_and_commit_patch(repo, patch, fallback_author, topic=None, name=None):
else:
gbp.log.warn("Patch '%s' has no authorship information" % patch_fn)
- repo.apply_patch(patch.path, strip=patch.strip)
+ try:
+ repo.apply_patch(patch.path, strip=patch.strip)
+ except GitRepositoryError:
+ gbp.log.warn("Patch %s failed to apply, retrying with whitespace fixup" % patch_fn)
+ repo.apply_patch(patch.path, strip=patch.strip, fix_ws=True)
tree = repo.write_tree()
msg = "%s\n\n%s" % (patch.subject, patch.long_desc)
if topic:
diff --git a/gbp/scripts/config.py b/gbp/scripts/config.py
index 3856c82..9ff3118 100755
--- a/gbp/scripts/config.py
+++ b/gbp/scripts/config.py
@@ -17,11 +17,12 @@
#
"""Query and display config file values"""
-from six.moves import configparser
import sys
-import os, os.path
+import os
from gbp.config import GbpOptionParser
+from gbp.errors import GbpError
from gbp.scripts.supercommand import import_command
+from gbp.scripts.common import ExitCodes
import gbp.log
@@ -29,7 +30,7 @@ def build_parser(name):
try:
parser = GbpOptionParser(command=os.path.basename(name), prefix='',
usage='%prog [options] command[.optionname] - display configuration settings')
- except configparser.ParsingError as err:
+ except GbpError as err:
gbp.log.err(err)
return None
@@ -117,6 +118,10 @@ def main(argv):
retval = 1
(options, args) = parse_args(argv)
+
+ if options is None:
+ return ExitCodes.parse_error
+
gbp.log.setup(options.color, options.verbose, options.color_scheme)
if not args:
@@ -131,6 +136,7 @@ def main(argv):
retval = print_cmd_values(query, value_printer)
return retval
+
if __name__ == '__main__':
sys.exit(main(sys.argv))
diff --git a/gbp/scripts/create_remote_repo.py b/gbp/scripts/create_remote_repo.py
index 539c18d..67eaec6 100644
--- a/gbp/scripts/create_remote_repo.py
+++ b/gbp/scripts/create_remote_repo.py
@@ -20,15 +20,14 @@
from __future__ import print_function
-from six.moves import configparser
import sys
-import os, os.path
+import os
from six.moves import urllib
import subprocess
-import tty, termios
+import tty
+import termios
import re
-
-import six
+from six.moves import configparser
from gbp.deb.changelog import ChangeLog, NoChangeLogError
from gbp.command_wrappers import (CommandExecFailed, GitCommand)
@@ -36,8 +35,11 @@ from gbp.config import (GbpOptionParserDebian, GbpOptionGroup)
from gbp.errors import GbpError
from gbp.git import GitRepositoryError
from gbp.deb.git import DebianGitRepository
+from gbp.scripts.common import ExitCodes
+
import gbp.log
+
def print_config(remote, branches):
"""
Print out the git config to push to the newly created repo.
@@ -68,45 +70,11 @@ def print_config(remote, branches):
remote = %s
merge = refs/heads/%s""" % (branch, remote['name'], branch))
-def sort_dict(d):
- """Return a sorted list of (key, value) tuples"""
- s = []
- for key in sorted(six.iterkeys(d)):
- s.append((key, d[key]))
- return s
-def parse_url(remote_url, name, pkg, template_dir=None):
+def parse_url(remote_url, name, pkg, template_dir=None, bare=True):
"""
Sanity check our remote URL
- >>> sort_dict(parse_url("ssh://host/path/%(pkg)s", "origin", "package"))
- [('base', ''), ('dir', '/path/package'), ('host', 'host'), ('name', 'origin'), ('pkg', 'package'), ('port', None), ('scheme', 'ssh'), ('template-dir', None), ('url', 'ssh://host/path/package')]
-
- >>> sort_dict(parse_url("ssh://host:22/path/repo.git", "origin", "package"))
- [('base', ''), ('dir', '/path/repo.git'), ('host', 'host'), ('name', 'origin'), ('pkg', 'package'), ('port', '22'), ('scheme', 'ssh'), ('template-dir', None), ('url', 'ssh://host:22/path/repo.git')]
-
- >>> sort_dict(parse_url("ssh://host:22/~/path/%(pkg)s.git", "origin", "package"))
- [('base', '~/'), ('dir', 'path/package.git'), ('host', 'host'), ('name', 'origin'), ('pkg', 'package'), ('port', '22'), ('scheme', 'ssh'), ('template-dir', None), ('url', 'ssh://host:22/~/path/package.git')]
-
- >>> sort_dict(parse_url("ssh://host:22/~user/path/%(pkg)s.git", "origin", "package", "/doesnot/exist"))
- [('base', '~user/'), ('dir', 'path/package.git'), ('host', 'host'), ('name', 'origin'), ('pkg', 'package'), ('port', '22'), ('scheme', 'ssh'), ('template-dir', '/doesnot/exist'), ('url', 'ssh://host:22/~user/path/package.git')]
-
- >>> parse_url("git://host/repo.git", "origin", "package")
- Traceback (most recent call last):
- ...
- GbpError: URL must use ssh protocol.
- >>> parse_url("ssh://host/path/repo", "origin", "package")
- Traceback (most recent call last):
- ...
- GbpError: URL needs to contain either a repository name or '%(pkg)s'
- >>> parse_url("ssh://host:asdf/path/%(pkg)s.git", "origin", "package")
- Traceback (most recent call last):
- ...
- GbpError: URL contains invalid port.
- >>> parse_url("ssh://host/~us er/path/%(pkg)s.git", "origin", "package")
- Traceback (most recent call last):
- ...
- GbpError: URL contains invalid ~username expansion.
"""
frags = urllib.parse.urlparse(remote_url)
if frags.scheme in ['ssh', 'git+ssh', '']:
@@ -114,7 +82,7 @@ def parse_url(remote_url, name, pkg, template_dir=None):
else:
raise GbpError("URL must use ssh protocol.")
- if not '%(pkg)s' in remote_url and not remote_url.endswith(".git"):
+ if '%(pkg)s' not in remote_url and not remote_url.endswith(".git"):
raise GbpError("URL needs to contain either a repository name or '%(pkg)s'")
if ":" in frags.netloc:
@@ -135,45 +103,50 @@ def parse_url(remote_url, name, pkg, template_dir=None):
base = ""
path = frags.path
- remote = { 'pkg' : pkg,
- 'url' : remote_url % { 'pkg': pkg },
- 'dir' : path % { 'pkg': pkg },
- 'base': base,
- 'host': host,
- 'port': port,
- 'name': name,
- 'scheme': scheme,
- 'template-dir': template_dir}
+ remote = {'pkg': pkg,
+ 'url': remote_url % {'pkg': pkg},
+ 'dir': path % {'pkg': pkg},
+ 'base': base,
+ 'host': host,
+ 'port': port,
+ 'name': name,
+ 'scheme': scheme,
+ 'template-dir': template_dir,
+ 'bare': bare}
return remote
def build_remote_script(remote, branch):
"""
Create the script that will be run on the remote side
- >>> build_remote_script({'base': 'base', 'dir': 'dir', 'pkg': 'pkg', 'template-dir': None}, 'branch')
- '\\nset -e\\numask 002\\nif [ -d base"dir" ]; then\\n echo "Repository at "basedir" already exists - giving up."\\n exit 1\\nfi\\nmkdir -p base"dir"\\ncd base"dir"\\ngit init --bare --shared\\necho "pkg packaging" > description\\necho "ref: refs/heads/branch" > HEAD\\n'
- >>> build_remote_script({'base': 'base', 'dir': 'dir', 'pkg': 'pkg', 'template-dir': '/doesnot/exist'}, 'branch')
- '\\nset -e\\numask 002\\nif [ -d base"dir" ]; then\\n echo "Repository at "basedir" already exists - giving up."\\n exit 1\\nfi\\nmkdir -p base"dir"\\ncd base"dir"\\ngit init --bare --shared --template=/doesnot/exist\\necho "pkg packaging" > description\\necho "ref: refs/heads/branch" > HEAD\\n'
"""
args = remote
args['branch'] = branch
- args['git-init-args'] = '--bare --shared'
+ args['git-init-args'] = '--shared'
+ if args['bare']:
+ args['git-init-args'] += ' --bare'
+ args['checkout_cmd'] = ''
+ args['git_dir'] = '.'
+ else:
+ args['checkout_cmd'] = 'git checkout -f'
+ args['git_dir'] = '.git'
if args['template-dir']:
args['git-init-args'] += (' --template=%s'
- % args['template-dir'])
- remote_script_pattern = ['',
- 'set -e',
- 'umask 002',
- 'if [ -d %(base)s"%(dir)s" ]; then',
- ' echo "Repository at \"%(base)s%(dir)s\" already exists - giving up."',
- ' exit 1',
- 'fi',
- 'mkdir -p %(base)s"%(dir)s"',
- 'cd %(base)s"%(dir)s"',
- 'git init %(git-init-args)s',
- 'echo "%(pkg)s packaging" > description',
- 'echo "ref: refs/heads/%(branch)s" > HEAD',
- '' ]
+ % args['template-dir'])
+ remote_script_pattern = \
+ ['',
+ 'set -e',
+ 'umask 002',
+ 'if [ -d %(base)s"%(dir)s" ]; then',
+ ' echo "Repository at \"%(base)s%(dir)s\" already exists - giving up."',
+ ' exit 1',
+ 'fi',
+ 'mkdir -p %(base)s"%(dir)s"',
+ 'cd %(base)s"%(dir)s"',
+ 'git init %(git-init-args)s',
+ 'echo "%(pkg)s packaging" > %(git_dir)s/description',
+ 'echo "ref: refs/heads/%(branch)s" > %(git_dir)s/HEAD',
+ '']
remote_script = '\n'.join(remote_script_pattern) % args
return remote_script
@@ -212,7 +185,7 @@ def read_yn():
if old_settings:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
- if ch in ( 'y', 'Y' ):
+ if ch in ('y', 'Y'):
return True
else:
return False
@@ -237,7 +210,7 @@ def build_parser(name, sections=[]):
usage='%prog [options] - '
'create a remote repository',
sections=sections)
- except configparser.ParsingError as err:
+ except (GbpError, configparser.NoSectionError) as err:
gbp.log.err(err)
return None
@@ -255,6 +228,8 @@ def build_parser(name, sections=[]):
dest="pristine_tar")
branch_group.add_boolean_config_file_option(option_name="track",
dest='track')
+ branch_group.add_boolean_config_file_option(option_name="bare",
+ dest='bare')
parser.add_option("-v", "--verbose",
action="store_true",
dest="verbose",
@@ -291,7 +266,7 @@ def parse_args(argv, sections=[]):
# section to parse, this makes e.g. --help work as expected:
for arg in argv:
if arg.startswith('--remote-config='):
- sections = ['remote-config %s' % arg.split('=',1)[1]]
+ sections = ['remote-config %s' % arg.split('=', 1)[1]]
break
else:
sections = []
@@ -308,11 +283,10 @@ def main(argv):
changelog = 'debian/changelog'
cmd = []
- try:
- options, args = parse_args(argv)
- except Exception as e:
- print("%s" % e, file=sys.stderr)
- return 1
+ options, args = parse_args(argv)
+
+ if not options:
+ return ExitCodes.parse_error
gbp.log.setup(options.color, options.verbose, options.color_scheme)
try:
@@ -324,12 +298,12 @@ def main(argv):
try:
branches = []
- for branch in [ options.debian_branch, options.upstream_branch ]:
+ for branch in [options.debian_branch, options.upstream_branch]:
if repo.has_branch(branch):
- branches += [ branch ]
+ branches += [branch]
if repo.has_pristine_tar_branch() and options.pristine_tar:
- branches += [ repo.pristine_tar_branch ]
+ branches += [repo.pristine_tar_branch]
try:
cp = ChangeLog(filename=changelog)
@@ -345,7 +319,8 @@ def main(argv):
remote = parse_url(options.remote_url,
options.name,
pkg,
- options.template_dir)
+ options.template_dir,
+ options.bare)
if repo.has_remote_repo(options.name):
raise GbpError("You already have a remote name '%s' defined for this repository." % options.name)
@@ -374,8 +349,10 @@ def main(argv):
else:
gbp.log.info("You can now add:")
print_config(remote, branches)
- gbp.log.info("to your .git/config to 'gbp-pull' and 'git push' in the future.")
-
+ gbp.log.info("to your .git/config to 'gbp pull' and 'git push' in the future.")
+ except KeyboardInterrupt:
+ retval = 1
+ gbp.log.err("Interrupted. Aborting.")
except CommandExecFailed:
retval = 1
except (GbpError, GitRepositoryError) as err:
@@ -385,6 +362,7 @@ def main(argv):
return retval
+
if __name__ == '__main__':
sys.exit(main(sys.argv))
diff --git a/gbp/scripts/dch.py b/gbp/scripts/dch.py
index 230d908..2835ea9 100644
--- a/gbp/scripts/dch.py
+++ b/gbp/scripts/dch.py
@@ -19,7 +19,6 @@
from __future__ import print_function
-from six.moves import configparser
import os.path
import re
import sys
@@ -33,6 +32,7 @@ from gbp.deb import compare_versions
from gbp.deb.source import DebianSource, DebianSourceError
from gbp.deb.git import GitRepositoryError, DebianGitRepository
from gbp.deb.changelog import ChangeLog, NoChangeLogError
+from gbp.scripts.common import ExitCodes
user_customizations = {}
snapshot_re = re.compile("\s*\*\* SNAPSHOT build @(?P<commit>[a-z0-9]+)\s+\*\*")
@@ -61,11 +61,15 @@ def get_author_email(repo, use_git_config):
author = email = None
if use_git_config:
- try: author = repo.get_config('user.name')
- except KeyError: pass
+ try:
+ author = repo.get_config('user.name')
+ except KeyError:
+ pass
- try: email = repo.get_config('user.email')
- except KeyError: pass
+ try:
+ email = repo.get_config('user.email')
+ except KeyError:
+ pass
return author, email
@@ -81,7 +85,7 @@ def fixup_section(repo, use_git_author, options, dch_options):
author, email = get_author_email(repo, use_git_author)
used_options = ['distribution', 'urgency']
opts = []
- mainttrailer_opts = [ '--nomainttrailer', '--mainttrailer', '-t' ]
+ mainttrailer_opts = ['--nomainttrailer', '--mainttrailer', '-t']
# This must not be done for snapshots or snapshots changelog entries
# will not be concatenated
@@ -100,7 +104,7 @@ def fixup_section(repo, use_git_author, options, dch_options):
break
else:
opts.append(mainttrailer_opts[0])
- ChangeLog.spawn_dch(msg='', author=author, email=email, dch_options=dch_options+opts)
+ ChangeLog.spawn_dch(msg='', author=author, email=email, dch_options=dch_options + opts)
def snapshot_version(version):
@@ -118,12 +122,12 @@ def snapshot_version(version):
"""
try:
(release, suffix) = version.rsplit('~', 1)
- (snapshot, commit) = suffix.split('.', 1)
+ (snapshot, commit) = suffix.split('.', 1)
if not commit.startswith('gbp'):
raise ValueError
else:
snapshot = int(snapshot)
- except ValueError: # not a snapshot release
+ except ValueError: # not a snapshot release
release = version
snapshot = 0
return release, snapshot
@@ -143,13 +147,13 @@ def mangle_changelog(changelog, cp, snapshot=''):
cr = open(changelog, 'r')
print("%(Source)s (%(MangledVersion)s) "
- "%(Distribution)s; urgency=%(urgency)s\n" % cp, file=cw)
+ "%(Distribution)s; urgency=%(urgency)s\n" % cp, file=cw)
- cr.readline() # skip version and empty line
+ cr.readline() # skip version and empty line
cr.readline()
line = cr.readline()
if snapshot_re.match(line):
- cr.readline() # consume the empty line after the snapshot header
+ cr.readline() # consume the empty line after the snapshot header
line = ''
if snapshot:
@@ -191,7 +195,8 @@ def do_snapshot(changelog, repo, next_snapshot):
cp['MangledVersion'] = "%s~%s" % (release, suffix)
mangle_changelog(changelog, cp, commit)
- return snapshot, commit
+ return snapshot, commit, cp['MangledVersion']
+
def parse_commit(repo, commitid, opts, last_commit=False):
"""Parse a commit and return message, author, and author email"""
@@ -286,10 +291,10 @@ def process_editor_option(options):
elif options.release:
states.append("release")
- if options.spawn_editor in states:
- return "sensible-editor"
- else:
+ if options.spawn_editor == 'never' or options.spawn_editor not in states:
return None
+ else:
+ return "sensible-editor"
def changelog_commit_msg(options, version):
@@ -300,7 +305,7 @@ def build_parser(name):
try:
parser = GbpOptionParserDebian(command=os.path.basename(name),
usage='%prog [options] paths')
- except configparser.ParsingError as err:
+ except GbpError as err:
gbp.log.err(err)
return None
@@ -320,15 +325,17 @@ def build_parser(name):
parser.add_option_group(naming_group)
parser.add_option_group(custom_group)
- parser.add_boolean_config_file_option(option_name = "ignore-branch", dest="ignore_branch")
+ parser.add_boolean_config_file_option(option_name="ignore-branch", dest="ignore_branch")
naming_group.add_config_file_option(option_name="upstream-branch", dest="upstream_branch")
naming_group.add_config_file_option(option_name="debian-branch", dest="debian_branch")
naming_group.add_config_file_option(option_name="upstream-tag", dest="upstream_tag")
naming_group.add_config_file_option(option_name="debian-tag", dest="debian_tag")
naming_group.add_config_file_option(option_name="snapshot-number", dest="snapshot_number",
- help="expression to determine the next snapshot number, default is '%(snapshot-number)s'")
+ help="expression to determine the next snapshot number, "
+ "default is '%(snapshot-number)s'")
parser.add_config_file_option(option_name="git-log", dest="git_log",
- help="options to pass to git-log, default is '%(git-log)s'")
+ help="options to pass to git-log, "
+ "default is '%(git-log)s'")
parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False,
help="verbose command execution")
parser.add_config_file_option(option_name="color", dest="color", type='tristate')
@@ -336,42 +343,49 @@ def build_parser(name):
dest="color_scheme")
range_group.add_option("-s", "--since", dest="since", help="commit to start from (e.g. HEAD^^^, debian/0.4.3)")
range_group.add_option("-a", "--auto", action="store_true", dest="auto", default=False,
- help="autocomplete changelog from last snapshot or tag")
+ help="autocomplete changelog from last snapshot or tag")
version_group.add_option("-R", "--release", action="store_true", dest="release", default=False,
- help="mark as release")
+ help="mark as release")
version_group.add_option("-S", "--snapshot", action="store_true", dest="snapshot", default=False,
- help="mark as snapshot build")
+ help="mark as snapshot build")
version_group.add_option("-D", "--distribution", dest="distribution", help="Set distribution")
version_group.add_option("--force-distribution", action="store_true", dest="force_distribution", default=False,
- help="Force the provided distribution to be used, even if it doesn't match the list of known distributions")
+ help="Force the provided distribution to be used, "
+ "even if it doesn't match the list of known distributions")
version_group.add_option("-N", "--new-version", dest="new_version",
- help="use this as base for the new version number")
- version_group.add_option("-U", "--urgency", dest="urgency", help="Set urgency level")
+ help="use this as base for the new version number")
+ version_group.add_config_file_option("urgency", dest="urgency")
version_group.add_option("--bpo", dest="bpo", action="store_true", default=False,
- help="Increment the Debian release number for an upload to backports, and add a backport upload changelog comment.")
+ help="Increment the Debian release number for an upload to backports, "
+ "and add a backport upload changelog comment.")
version_group.add_option("--nmu", dest="nmu", action="store_true", default=False,
- help="Increment the Debian release number for a non-maintainer upload")
+ help="Increment the Debian release number for a non-maintainer upload")
version_group.add_option("--qa", dest="qa", action="store_true", default=False,
- help="Increment the Debian release number for a Debian QA Team upload, and add a QA upload changelog comment.")
+ help="Increment the Debian release number for a Debian QA Team upload, "
+ "and add a QA upload changelog comment.")
version_group.add_option("--team", dest="team", action="store_true", default=False,
- help="Increment the Debian release number for a Debian Team upload, and add a Team upload changelog comment.")
+ help="Increment the Debian release number for a Debian Team upload, "
+ "and add a Team upload changelog comment.")
version_group.add_option("--security", dest="security", action="store_true", default=False,
- help="Increment the Debian release number for a security upload and add a security upload changelog comment.")
+ help="Increment the Debian release number for a security upload and "
+ "add a security upload changelog comment.")
version_group.add_boolean_config_file_option(option_name="git-author", dest="use_git_author")
commit_group.add_boolean_config_file_option(option_name="meta", dest="meta")
commit_group.add_config_file_option(option_name="meta-closes", dest="meta_closes")
commit_group.add_config_file_option(option_name="meta-closes-bugnum", dest="meta_closes_bugnum")
commit_group.add_boolean_config_file_option(option_name="full", dest="full")
commit_group.add_config_file_option(option_name="id-length", dest="idlen",
- help="include N digits of the commit id in the changelog entry, default is '%(id-length)s'",
- type="int", metavar="N")
+ help="include N digits of the commit id in the changelog entry, "
+ "default is '%(id-length)s'",
+ type="int", metavar="N")
commit_group.add_config_file_option(option_name="ignore-regex", dest="ignore_regex",
- help="Ignore commit lines matching regex, default is '%(ignore-regex)s'")
+ help="Ignore commit lines matching regex, "
+ "default is '%(ignore-regex)s'")
commit_group.add_boolean_config_file_option(option_name="multimaint", dest="multimaint")
commit_group.add_boolean_config_file_option(option_name="multimaint-merge", dest="multimaint_merge")
commit_group.add_config_file_option(option_name="spawn-editor", dest="spawn_editor")
parser.add_config_file_option(option_name="commit-msg",
- dest="commit_msg")
+ dest="commit_msg")
parser.add_option("-c", "--commit", action="store_true", dest="commit", default=False,
help="commit changelog file after generating")
@@ -381,15 +395,13 @@ def build_parser(name):
custom_group.add_config_file_option(option_name="customizations",
dest="customization_file",
help=help_msg)
-
-
return parser
def parse_args(argv):
parser = build_parser(argv[0])
if not parser:
- return None, None
+ return [None] * 4
(options, args) = parser.parse_args(argv[1:])
gbp.log.setup(options.color, options.verbose, options.color_scheme)
@@ -397,6 +409,7 @@ def parse_args(argv):
editor_cmd = process_editor_option(options)
return options, args, dch_options, editor_cmd
+
def main(argv):
ret = 0
changelog = 'debian/changelog'
@@ -405,9 +418,11 @@ def main(argv):
version_change = {}
branch = None
-
options, args, dch_options, editor_cmd = parse_args(argv)
+ if not options:
+ return ExitCodes.parse_error
+
try:
try:
repo = DebianGitRepository('.')
@@ -440,7 +455,7 @@ def main(argv):
msg = "Starting from first commit"
gbp.log.info(msg)
found_snapshot_banner = has_snapshot_banner(cp)
- else: # Fallback: continue from last tag
+ else: # Fallback: continue from last tag
since = repo.find_version(options.debian_tag, cp['Version'])
if not since:
raise GbpError("Version %s not found" % cp['Version'])
@@ -451,9 +466,10 @@ def main(argv):
options=options.git_log.split(" "))
commits.reverse()
+ add_section = False
# add a new changelog section if:
if (options.new_version or options.bpo or options.nmu or options.qa or
- options.team or options.security):
+ options.team or options.security):
if options.bpo:
version_change['increment'] = '--bpo'
elif options.nmu:
@@ -468,14 +484,13 @@ def main(argv):
version_change['version'] = options.new_version
# the user wants to force a new version
add_section = True
- elif cp['Distribution'] != "UNRELEASED" and not found_snapshot_banner and commits:
- # the last version was a release and we have pending commits
- add_section = True
- elif options.snapshot and not found_snapshot_banner:
- # the user want to switch to snapshot mode
- add_section = True
- else:
- add_section = False
+ elif cp['Distribution'] != "UNRELEASED" and not found_snapshot_banner:
+ if commits:
+ # the last version was a release and we have pending commits
+ add_section = True
+ if options.snapshot:
+ # the user want to switch to snapshot mode
+ add_section = True
if add_section and not version_change and not source.is_native():
# Get version from upstream if none provided
@@ -488,7 +503,7 @@ def main(argv):
for c in commits:
i += 1
parsed = parse_commit(repo, c, options,
- last_commit = i == len(commits))
+ last_commit=(i == len(commits)))
commit_msg, (commit_author, commit_email) = parsed
if not commit_msg:
# Some commits can be ignored
@@ -507,7 +522,6 @@ def main(argv):
else:
cp.add_entry(commit_msg, commit_author, commit_email, dch_options)
-
# Show a message if there were no commits (not even ignored
# commits).
if not commits:
@@ -527,8 +541,8 @@ def main(argv):
do_release(changelog, repo, cp, use_git_author=options.use_git_author,
dch_options=dch_options)
elif options.snapshot:
- (snap, version) = do_snapshot(changelog, repo, options.snapshot_number)
- gbp.log.info("Changelog has been prepared for snapshot #%d at %s" % (snap, version))
+ (snap, commit, version) = do_snapshot(changelog, repo, options.snapshot_number)
+ gbp.log.info("Changelog %s (snapshot #%d) prepared up to %s" % (version, snap, commit[:7]))
if editor_cmd:
gbpc.Command(editor_cmd, ["debian/changelog"])()
@@ -541,8 +555,10 @@ def main(argv):
# Commit the changes to the changelog file
msg = changelog_commit_msg(options, version)
repo.commit_files([changelog], msg)
- gbp.log.info("Changelog has been committed for version %s" % version)
-
+ gbp.log.info("Changelog committed for version %s" % version)
+ except KeyboardInterrupt:
+ ret = 1
+ gbp.log.err("Interrupted. Aborting.")
except (gbpc.CommandExecFailed,
GbpError,
GitRepositoryError,
@@ -553,6 +569,7 @@ def main(argv):
ret = 1
return ret
+
if __name__ == "__main__":
sys.exit(main(sys.argv))
diff --git a/gbp/scripts/import_dsc.py b/gbp/scripts/import_dsc.py
index 1765d97..aa734e8 100644
--- a/gbp/scripts/import_dsc.py
+++ b/gbp/scripts/import_dsc.py
@@ -1,6 +1,6 @@
# vim: set fileencoding=utf-8 :
#
-# (C) 2006, 2007, 2011, 2012, 2015 Guido Guenther <agx@sigxcpu.org>
+# (C) 2006, 2007, 2011, 2012, 2015, 2016 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
@@ -16,7 +16,6 @@
# <http://www.gnu.org/licenses/>
"""Import a Debian source package into a Git repository"""
-from six.moves import configparser
import sys
import re
import os
@@ -27,7 +26,7 @@ import pipes
import time
import gbp.command_wrappers as gbpc
from gbp.deb.dscfile import DscFile
-from gbp.deb.upstreamsource import DebianUpstreamSource
+from gbp.deb.upstreamsource import DebianUpstreamSource, unpack_component_tarball
from gbp.deb.git import (DebianGitRepository, GitRepositoryError)
from gbp.deb.changelog import ChangeLog
from gbp.git import rfc822_date_to_git
@@ -35,27 +34,16 @@ from gbp.git.modifier import GitModifier
from gbp.config import (GbpOptionParserDebian, GbpOptionGroup,
no_upstream_branch_msg)
from gbp.errors import GbpError
+from gbp.scripts.common import ExitCodes
import gbp.log
+
class SkipImport(Exception):
pass
-def generate_pristine_tarballs(repo, src, upstream_tree):
- subdirs = src.additional_tarballs.keys()
- main_tree = repo.tree_drop_dirs(upstream_tree, subdirs)
-
- for dir, tarball in src.additional_tarballs.items():
- subtree = repo.tree_get_dir(upstream_tree, dir)
- if not subtree:
- raise GbpError("No tree for '%s' found in '%s' to create pristine tar commit from" % (dir, upstream_tree))
- gbp.log.debug("Creating pristine tar commit '%s' from '%s'" % (dir, subtree))
- repo.pristine_tar.commit(tarball, subtree)
- repo.pristine_tar.commit(src.tgz, main_tree)
-
-
def download_source(pkg, dirs, unauth):
- opts = [ '--download-only' ]
+ opts = ['--download-only']
if unauth:
opts.append('--allow-unauthenticated')
@@ -76,9 +64,14 @@ def download_source(pkg, dirs, unauth):
def apply_patch(diff):
"Apply patch to a source tree"
+ patch_opts = ['-N', '-p1', '-F0', '-u', '-t',
+ '-Vnever', '-g0', '-z.gbp.orig',
+ '--quiet']
+
pipe = pipes.Template()
- pipe.prepend('gunzip -c %s' % diff, '.-')
- pipe.append('patch -p1 --quiet', '-.')
+ pipe.prepend('gunzip -c %s' % diff, '.-')
+ pipe.append('patch %s' % ' '.join(patch_opts), '-.')
+
try:
ret = pipe.copy('', '')
if ret:
@@ -144,6 +137,7 @@ def check_parents(repo, branch, tag):
return parents
+
def apply_debian_patch(repo, unpack_dir, src, options, tag):
"""apply the debian patch and tag appropriately"""
try:
@@ -166,9 +160,9 @@ def apply_debian_patch(repo, unpack_dir, src, options, tag):
author = get_author_from_changelog(unpack_dir)
committer = get_committer_from_author(author, options)
commit = repo.commit_dir(unpack_dir,
- "Imported Debian patch %s" % src.version,
- branch = options.debian_branch,
- other_parents = parents,
+ "Import Debian patch %s" % src.version,
+ branch=options.debian_branch,
+ other_parents=parents,
author=author,
committer=committer)
if not options.skip_debian_tag:
@@ -187,13 +181,15 @@ def apply_debian_patch(repo, unpack_dir, src, options, tag):
def print_dsc(dsc):
if dsc.native:
- gbp.log.debug("Debian Native Package %s")
+ gbp.log.debug("Debian Native Package")
gbp.log.debug("Version: %s" % dsc.upstream_version)
gbp.log.debug("Debian tarball: %s" % dsc.tgz)
else:
gbp.log.debug("Upstream version: %s" % dsc.upstream_version)
gbp.log.debug("Debian version: %s" % dsc.debian_version)
gbp.log.debug("Upstream tarball: %s" % dsc.tgz)
+ if dsc.additional_tarballs:
+ gbp.log.debug("Additional tarballs: %s" % ", ".join(dsc.additional_tarballs.values()))
if dsc.diff:
gbp.log.debug("Debian patch: %s" % dsc.diff)
if dsc.deb_tgz:
@@ -221,18 +217,17 @@ def build_parser(name):
try:
parser = GbpOptionParserDebian(command=os.path.basename(name), prefix='',
usage='%prog [options] /path/to/package.dsc')
- except configparser.ParsingError as err:
+ except GbpError as err:
gbp.log.err(err)
return None
import_group = GbpOptionGroup(parser, "import options",
- "pristine-tar and filtering")
+ "pristine-tar and filtering")
tag_group = GbpOptionGroup(parser, "tag options",
- "options related to git tag creation")
+ "options related to git tag creation")
branch_group = GbpOptionGroup(parser, "version and branch naming options",
- "version number and branch layout options")
-
- for group in [import_group, branch_group, tag_group ]:
+ "version number and branch layout options")
+ for group in [import_group, branch_group, tag_group]:
parser.add_option_group(group)
parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False,
@@ -243,38 +238,37 @@ def build_parser(name):
parser.add_option("--download", action="store_true", dest="download", default=False,
help="download source package")
branch_group.add_config_file_option(option_name="debian-branch",
- dest="debian_branch")
+ dest="debian_branch")
branch_group.add_config_file_option(option_name="upstream-branch",
- dest="upstream_branch")
+ dest="upstream_branch")
branch_group.add_boolean_config_file_option(option_name="create-missing-branches",
- dest="create_missing_branches")
+ dest="create_missing_branches")
tag_group.add_boolean_config_file_option(option_name="sign-tags",
- dest="sign_tags")
+ dest="sign_tags")
tag_group.add_config_file_option(option_name="keyid",
- dest="keyid")
+ dest="keyid")
tag_group.add_config_file_option(option_name="debian-tag",
- dest="debian_tag")
+ dest="debian_tag")
tag_group.add_config_file_option(option_name="upstream-tag",
- dest="upstream_tag")
- tag_group.add_option("--skip-debian-tag",dest="skip_debian_tag",
+ dest="upstream_tag")
+ tag_group.add_option("--skip-debian-tag", dest="skip_debian_tag",
action="store_true", default=False,
help="Don't add a tag after importing the Debian patch")
-
import_group.add_config_file_option(option_name="filter",
- dest="filters", action="append")
+ dest="filters", action="append")
import_group.add_boolean_config_file_option(option_name="pristine-tar",
- dest="pristine_tar")
+ dest="pristine_tar")
import_group.add_option("--allow-same-version", action="store_true",
- dest="allow_same_version", default=False,
- help="allow to import already imported version")
+ dest="allow_same_version", default=False,
+ help="allow to import already imported version")
import_group.add_boolean_config_file_option(option_name="author-is-committer",
- dest="author_committer")
+ dest="author_committer")
import_group.add_boolean_config_file_option(option_name="author-date-is-committer-date",
- dest="author_committer_date")
+ dest="author_committer_date")
import_group.add_boolean_config_file_option(option_name="allow-unauthenticated",
- dest="allow_unauthenticated")
+ dest="allow_unauthenticated")
return parser
@@ -296,123 +290,123 @@ def main(argv):
options, args = parse_args(argv)
if not options:
- return 1
+ return ExitCodes.parse_error
try:
if len(args) != 1:
gbp.log.err("Need to give exactly one package to import. Try --help.")
raise GbpError
+ try:
+ repo = DebianGitRepository('.')
+ is_empty = repo.is_empty()
+
+ (clean, out) = repo.is_clean()
+ if not clean and not is_empty:
+ gbp.log.err("Repository has uncommitted changes, commit these first: ")
+ raise GbpError(out)
+ except GitRepositoryError:
+ # no repo found, create one
+ needs_repo = True
+ is_empty = True
+
+ pkg = args[0]
+ if options.download:
+ dsc = download_source(pkg,
+ dirs=dirs,
+ unauth=options.allow_unauthenticated)
else:
- try:
- repo = DebianGitRepository('.')
- is_empty = repo.is_empty()
-
- (clean, out) = repo.is_clean()
- if not clean and not is_empty:
- gbp.log.err("Repository has uncommitted changes, commit these first: ")
- raise GbpError(out)
- except GitRepositoryError:
- # no repo found, create one
- needs_repo = True
- is_empty = True
-
- pkg = args[0]
- if options.download:
- dsc = download_source(pkg,
- dirs=dirs,
- unauth=options.allow_unauthenticated)
+ dsc = pkg
+
+ src = DscFile.parse(dsc)
+ if src.pkgformat not in ['1.0', '3.0']:
+ raise GbpError("Importing %s source format not yet supported." % src.pkgformat)
+ if options.verbose:
+ print_dsc(src)
+
+ if needs_repo:
+ if os.path.exists(src.pkg):
+ raise GbpError("Directory '%s' already exists. If you want to import into it, "
+ "please change into this directory otherwise move it away first."
+ % src.pkg)
+ gbp.log.info("No git repository found, creating one.")
+ repo = DebianGitRepository.create(src.pkg)
+ os.chdir(repo.path)
+
+ if repo.bare:
+ disable_pristine_tar(options, "Bare repository")
+
+ dirs['tmp'] = os.path.abspath(tempfile.mkdtemp(dir='..'))
+ upstream = DebianUpstreamSource(src.tgz)
+ upstream.unpack(dirs['tmp'], options.filters)
+ for (component, tarball) in src.additional_tarballs.items():
+ gbp.log.info("Found component tarball '%s'" % os.path.basename(tarball))
+ unpack_component_tarball(upstream.unpacked, component, tarball, options.filters)
+
+ format = [(options.upstream_tag, "Upstream"), (options.debian_tag, "Debian")][src.native]
+ tag = repo.version_to_tag(format[0], src.upstream_version)
+ msg = "%s version %s" % (format[1], src.upstream_version)
+
+ if repo.find_version(options.debian_tag, src.version):
+ gbp.log.warn("Version %s already imported." % src.version)
+ if options.allow_same_version:
+ gbp.log.info("Moving tag of version '%s' since import forced" % src.version)
+ move_tag_stamp(repo, options.debian_tag, src.version)
else:
- dsc = pkg
-
- src = DscFile.parse(dsc)
- if src.pkgformat not in [ '1.0', '3.0' ]:
- raise GbpError("Importing %s source format not yet supported." % src.pkgformat)
- if options.verbose:
- print_dsc(src)
-
- if needs_repo:
- if os.path.exists(src.pkg):
- raise GbpError("Directory '%s' already exists. If you want to import into it, "
- "please change into this directory otherwise move it away first."
- % src.pkg)
- gbp.log.info("No git repository found, creating one.")
- repo = DebianGitRepository.create(src.pkg)
- os.chdir(repo.path)
-
- if repo.bare:
- disable_pristine_tar(options, "Bare repository")
-
- dirs['tmp'] = os.path.abspath(tempfile.mkdtemp(dir='..'))
- upstream = DebianUpstreamSource(src.tgz)
- upstream.unpack(dirs['tmp'], options.filters)
- for tarball in src.additional_tarballs.values():
- gbp.log.info("Found component tarball '%s'" % os.path.basename(tarball))
- subtarball = DebianUpstreamSource(tarball)
- subtarball.unpack(upstream.unpacked, options.filters)
-
- format = [(options.upstream_tag, "Upstream"), (options.debian_tag, "Debian")][src.native]
- tag = repo.version_to_tag(format[0], src.upstream_version)
- msg = "%s version %s" % (format[1], src.upstream_version)
-
- if repo.find_version(options.debian_tag, src.version):
- gbp.log.warn("Version %s already imported." % src.version)
- if options.allow_same_version:
- gbp.log.info("Moving tag of version '%s' since import forced" % src.version)
- move_tag_stamp(repo, options.debian_tag, src.version)
- else:
- raise SkipImport
-
- if not repo.find_version(format[0], src.upstream_version):
- gbp.log.info("Tag %s not found, importing %s tarball" % (tag, format[1]))
- if is_empty:
- branch = None
- else:
- branch = [options.upstream_branch,
- options.debian_branch][src.native]
- if not repo.has_branch(branch):
- if options.create_missing_branches:
- gbp.log.info("Creating missing branch '%s'" % branch)
- repo.create_branch(branch)
- else:
- gbp.log.err(no_upstream_branch_msg % branch +
- "\nAlso check the --create-missing-branches option.")
- raise GbpError
-
- if src.native:
- author = get_author_from_changelog(upstream.unpacked)
- committer = get_committer_from_author(author, options)
- else:
- author = committer = {}
-
- commit = repo.commit_dir(upstream.unpacked,
- "Imported %s" % msg,
- branch,
- author=author,
- committer=committer)
-
- if not (src.native and options.skip_debian_tag):
- repo.create_tag(name=tag,
- msg=msg,
- commit=commit,
- sign=options.sign_tags,
- keyid=options.keyid)
- if not src.native:
- if is_empty:
- repo.create_branch(options.upstream_branch, commit)
- if options.pristine_tar:
- generate_pristine_tarballs(repo, src, options.upstream_branch)
- if (not repo.has_branch(options.debian_branch)
- and (is_empty or options.create_missing_branches)):
- repo.create_branch(options.debian_branch, commit)
+ raise SkipImport
+
+ if not repo.find_version(format[0], src.upstream_version):
+ gbp.log.info("Tag %s not found, importing %s tarball" % (tag, format[1]))
+ if is_empty:
+ branch = None
+ else:
+ branch = [options.upstream_branch,
+ options.debian_branch][src.native]
+ if not repo.has_branch(branch):
+ if options.create_missing_branches:
+ gbp.log.info("Creating missing branch '%s'" % branch)
+ repo.create_branch(branch)
+ else:
+ gbp.log.err(no_upstream_branch_msg % branch +
+ "\nAlso check the --create-missing-branches option.")
+ raise GbpError
+
+ if src.native:
+ author = get_author_from_changelog(upstream.unpacked)
+ committer = get_committer_from_author(author, options)
+ else:
+ author = committer = {}
+
+ commit = repo.commit_dir(upstream.unpacked,
+ "Import %s" % msg,
+ branch,
+ author=author,
+ committer=committer)
+
+ if not (src.native and options.skip_debian_tag):
+ repo.create_tag(name=tag,
+ msg=msg,
+ commit=commit,
+ sign=options.sign_tags,
+ keyid=options.keyid)
if not src.native:
- if src.diff or src.deb_tgz:
- apply_debian_patch(repo, upstream.unpacked, src, options,
- tag)
- else:
- gbp.log.warn("Didn't find a diff to apply.")
- if repo.get_branch() == options.debian_branch or is_empty:
- # Update HEAD if we modified the checked out branch
- repo.force_head(options.debian_branch, hard=True)
+ if is_empty:
+ repo.create_branch(options.upstream_branch, commit)
+ if options.pristine_tar:
+ repo.create_pristinetar_commits(options.upstream_branch,
+ src.tgz,
+ src.additional_tarballs.items())
+ if (not repo.has_branch(options.debian_branch) and
+ (is_empty or options.create_missing_branches)):
+ repo.create_branch(options.debian_branch, commit)
+ if not src.native:
+ if src.diff or src.deb_tgz:
+ apply_debian_patch(repo, upstream.unpacked, src, options,
+ tag)
+ else:
+ gbp.log.warn("Didn't find a diff to apply.")
+ if repo.get_branch() == options.debian_branch or is_empty:
+ # Update HEAD if we modified the checked out branch
+ repo.force_head(options.debian_branch, hard=True)
except KeyboardInterrupt:
ret = 1
gbp.log.err("Interrupted. Aborting.")
@@ -430,7 +424,7 @@ def main(argv):
finally:
os.chdir(dirs['top'])
- for d in [ 'tmp', 'download' ]:
+ for d in ['tmp', 'download']:
if d in dirs:
gbpc.RemoveTree(dirs[d])()
@@ -438,6 +432,7 @@ def main(argv):
gbp.log.info("Version '%s' imported under '%s'" % (src.version, src.pkg))
return ret
+
if __name__ == '__main__':
sys.exit(main(sys.argv))
diff --git a/gbp/scripts/import_dscs.py b/gbp/scripts/import_dscs.py
index ea1b610..b49110c 100644
--- a/gbp/scripts/import_dscs.py
+++ b/gbp/scripts/import_dscs.py
@@ -29,6 +29,7 @@ from gbp.scripts import import_dsc
from gbp.config import GbpOptionParser
import gbp.log
+
class DscCompareVersions(DpkgCompareVersions):
def __init__(self):
DpkgCompareVersions.__init__(self)
@@ -51,8 +52,8 @@ def fetch_snapshots(pkg, downloaddir):
gbp.log.info("Downloading snapshots of '%s' to '%s'..." %
(pkg, downloaddir))
- debsnap = gbpc.Command("debsnap", [ '--force', '--destdir=%s' %
- (downloaddir), pkg])
+ debsnap = gbpc.Command("debsnap", ['--force', '--destdir=%s' %
+ (downloaddir), pkg])
try:
debsnap()
except gbpc.CommandExecFailed:
@@ -68,6 +69,7 @@ def fetch_snapshots(pkg, downloaddir):
return [os.path.join(downloaddir, dsc) for dsc in dscs]
+
def set_gbp_conf_files():
"""
Filter out all gbp.conf files that are local to the git repository and set
@@ -78,13 +80,14 @@ def set_gbp_conf_files():
os.environ['GBP_CONF_FILES'] = gbp_conf_files
gbp.log.debug("Setting GBP_CONF_FILES to '%s'" % gbp_conf_files)
+
def print_help():
print("""Usage: gbp import-dscs [options] [gbp-import-dsc options] /path/to/dsc1 [/path/to/dsc2] ...
gbp import-dscs --debsnap [options] [gbp-import-dsc options] package
Options:
- --debsnap: use debsnap command to download packages
+ --debsnap: use debsnap command to download packages
--ignore-repo-config ignore gbp.conf in git repo
""")
@@ -129,7 +132,7 @@ def main(argv):
if use_debsnap:
dirs['tmp'] = os.path.abspath(tempfile.mkdtemp())
- dscs = [ DscFile.parse(f) for f in fetch_snapshots(pkg, dirs['tmp']) ]
+ dscs = [DscFile.parse(f) for f in fetch_snapshots(pkg, dirs['tmp'])]
dscs.sort(cmp=dsc_cmp)
importer = GitImportDsc(import_args)
@@ -154,7 +157,9 @@ def main(argv):
for dsc in dscs[1:]:
if importer.importdsc(dsc):
raise GbpError("Failed to import '%s'" % dscs[0].dscfile)
-
+ except KeyboardInterrupt:
+ ret = 1
+ gbp.log.err("Interrupted. Aborting.")
except (GbpError, gbpc.CommandExecFailed, GitRepositoryError) as err:
if str(err):
gbp.log.err(err)
@@ -168,6 +173,7 @@ def main(argv):
gbp.log.info('Everything imported under %s' % dirs['pkg'])
return ret
+
if __name__ == '__main__':
sys.exit(main(sys.argv))
diff --git a/gbp/scripts/import_orig.py b/gbp/scripts/import_orig.py
index a442d66..0eea6b9 100644
--- a/gbp/scripts/import_orig.py
+++ b/gbp/scripts/import_orig.py
@@ -1,6 +1,6 @@
# vim: set fileencoding=utf-8 :
#
-# (C) 2006, 2007, 2009, 2011, 2015 Guido Guenther <agx@sigxcpu.org>
+# (C) 2006, 2007, 2009, 2011, 2015, 2016 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
@@ -17,23 +17,154 @@
#
"""Import a new upstream version into a Git repository"""
-from six.moves import configparser
import os
import sys
import tempfile
import gbp.command_wrappers as gbpc
from gbp.deb import (DebianPkgPolicy, parse_changelog_repo)
-from gbp.deb.upstreamsource import DebianUpstreamSource
+from gbp.deb.upstreamsource import DebianUpstreamSource, unpack_component_tarball
from gbp.deb.uscan import (Uscan, UscanError)
from gbp.deb.changelog import ChangeLog, NoChangeLogError
from gbp.deb.git import (GitRepositoryError, DebianGitRepository)
from gbp.config import GbpOptionParserDebian, GbpOptionGroup, no_upstream_branch_msg
from gbp.errors import GbpError
+from gbp.pkg import parse_archive_filename
from gbp.format import format_str
import gbp.log
+from gbp.scripts.common import ExitCodes
from gbp.scripts.common.import_orig import (orig_needs_repack, cleanup_tmp_tree,
ask_package_name, ask_package_version,
repack_source, is_link_target, download_orig)
+from gbp.scripts.common.hook import Hook
+
+
+class RollbackError(GitRepositoryError):
+ """
+ An error raised if the actual rollback failed
+ """
+ def __init__(self, errors):
+ self.msg = "Automatic rollback failed"
+ super(RollbackError, self).__init__(self.msg)
+ self.errors = errors
+
+ def __str__(self):
+ return "%s %s" % (self.msg, self.errors)
+
+
+class ImportOrigDebianGitRepository(DebianGitRepository):
+ """
+ Like a DebianGitRepository but can also perform rollbacks and knows
+ about some of the inner workings upstream vcs_tag, …
+ """
+ def __init__(self, *args, **kwargs):
+ self.rollbacks = []
+ self.rollback_errors = []
+ DebianGitRepository.__init__(self, *args, **kwargs)
+
+ def has_rollbacks(self):
+ return len(self.rollbacks) > 0
+
+ def vcs_tag_parent(self, vcs_tag_format, version):
+ """If linking to the upstream VCS get the commit id"""
+ if vcs_tag_format:
+ return [self.rev_parse("%s^{}" % self.version_to_tag(vcs_tag_format, version))],
+ else:
+ return None
+
+ def rrr(self, refname, action, reftype):
+ """
+ Remember ref for rollback
+
+ @param refname: ref to roll back
+ @param action: the rollback action (delete, reset, ...)
+ @param reftype: the reference type (tag, branch, ...)
+ """
+ sha = None
+
+ if action == 'reset':
+ try:
+ sha = self.rev_parse(refname)
+ except GitRepositoryError as err:
+ gbp.log.warning("Failed to rev-parse %s: %s" % (refname, err))
+ elif action == 'delete':
+ pass
+ elif action == 'abortmerge':
+ pass
+ else:
+ raise GbpError("Unknown action %s for %s %s" % (action, reftype, refname))
+ self.rollbacks.append((refname, reftype, action, sha))
+
+ def rrr_branch(self, branchname, action='reset-or-delete'):
+ if action == 'reset-or-delete':
+ if self.has_branch(branchname):
+ return self.rrr(branchname, 'reset', 'branch')
+ else:
+ return self.rrr(branchname, 'delete', 'branch')
+ else:
+ return self.rrr(branchname, action, 'branch')
+
+ def rrr_tag(self, tagname, action='delete'):
+ return self.rrr(tagname, action, 'tag')
+
+ def rrr_merge(self, commit, action='abortmerge'):
+ return self.rrr(commit, action, 'commit')
+
+ def rollback(self):
+ """
+ Perform a complete rollback
+
+ Try to roll back as much as possible and remember what failed.
+ """
+ for (name, reftype, action, sha) in self.rollbacks:
+ try:
+ if action == 'delete':
+ gbp.log.info('Rolling back %s %s by deleting it' % (reftype, name))
+ if reftype == 'tag':
+ self.delete_tag(name)
+ elif reftype == 'branch':
+ self.delete_branch(name)
+ else:
+ raise GitRepositoryError("Don't know how to delete %s %s" % (reftype, name))
+ elif action == 'reset' and reftype == 'branch':
+ gbp.log.info('Rolling back branch %s by resetting it to %s' % (name, sha))
+ self.update_ref("refs/heads/%s" % name, sha, msg="gbp import-orig: failure rollback of %s" % name)
+ elif action == 'abortmerge':
+ gbp.log.info('Rolling back failed merge of %s' % name)
+ self.abort_merge()
+ else:
+ raise GitRepositoryError("Don't know how to %s %s %s" % (action, reftype, name))
+ except GitRepositoryError as e:
+ self.rollback_errors.append((name, reftype, action, sha, e))
+ if self.rollback_errors:
+ raise RollbackError(self.rollback_errors)
+
+ # Wrapped methods for rollbacks
+ def create_tag(self, *args, **kwargs):
+ name = kwargs['name']
+ ret = super(ImportOrigDebianGitRepository, self).create_tag(*args, **kwargs)
+ self.rrr_tag(name)
+ return ret
+
+ def commit_dir(self, *args, **kwargs):
+ import_branch = kwargs['branch']
+ self.rrr_branch(import_branch)
+ return super(ImportOrigDebianGitRepository, self).commit_dir(*args, **kwargs)
+
+ def create_branch(self, *args, **kwargs):
+ branch = kwargs['branch']
+ ret = super(ImportOrigDebianGitRepository, self).create_branch(*args, **kwargs)
+ self.rrr_branch(branch, 'delete')
+ return ret
+
+ def merge(self, *args, **kwargs):
+ commit = args[0] if args else kwargs['commit']
+ try:
+ return super(ImportOrigDebianGitRepository, self).merge(*args, **kwargs)
+ except GitRepositoryError:
+ # Only cleanup in the error case to undo working copy
+ # changes. Resetting the refs handles the other cases.
+ self.rrr_merge(commit)
+ raise
def prepare_pristine_tar(archive, pkg, version):
@@ -58,7 +189,7 @@ def prepare_pristine_tar(archive, pkg, version):
return None
ext = os.path.splitext(archive)[1]
- if ext in ['.tgz', '.tbz2', '.tlz', '.txz' ]:
+ if ext in ['.tgz', '.tbz2', '.tlz', '.txz']:
ext = ".%s" % ext[2:]
link = "../%s_%s.orig.tar%s" % (pkg, version, ext)
@@ -124,12 +255,12 @@ def detect_name_and_version(repo, source, options):
def find_source(use_uscan, args):
- """Find the tarball to import - either via uscan or via command line argument
+ """Find the main tarball to import - either via uscan or via command line argument
@return: upstream source filename or None if nothing to import
@rtype: string
@raise GbpError: raised on all detected errors
- >>> find_source(False, ['too', 'much'])
+ >>> find_source(False, ['too', 'many'])
Traceback (most recent call last):
...
GbpError: More than one archive specified. Try --help.
@@ -164,13 +295,12 @@ def find_source(use_uscan, args):
else:
gbp.log.info("package is up to date, nothing to do.")
return None
- if len(args) > 1: # source specified
+ if len(args) > 1: # source specified
raise GbpError("More than one archive specified. Try --help.")
elif len(args) == 0:
raise GbpError("No archive to import specified. Try --help.")
else:
- archive = DebianUpstreamSource(args[0])
- return archive
+ return DebianUpstreamSource(args[0])
def debian_branch_merge(repo, tag, version, options):
@@ -188,9 +318,16 @@ def debian_branch_merge(repo, tag, version, options):
cp = ChangeLog(filename='debian/changelog')
if cp.has_epoch():
epoch = '%s:' % cp.epoch
- info = {'version': "%s%s-1" % (epoch, version)}
- env = {'GBP_BRANCH': options.debian_branch}
- gbpc.Command(format_str(options.postimport, info), extra_env=env, shell=True)()
+ debian_version = "%s%s-1" % (epoch, version)
+ info = {'version': debian_version}
+ env = {'GBP_BRANCH': options.debian_branch,
+ 'GBP_TAG': tag,
+ 'GBP_UPSTREAM_VERSION': version,
+ 'GBP_DEBIAN_VERSION': debian_version,
+ }
+ Hook('Postimport',
+ format_str(options.postimport, info),
+ extra_env=env)()
def debian_branch_merge_by_replace(repo, tag, version, options):
@@ -218,21 +355,42 @@ def debian_branch_merge_by_replace(repo, tag, version, options):
repo.force_head(commit, hard=True)
+def get_component_tarballs(name, version, tarball, components):
+ """
+ Figure out the paths to the component tarballs based on the main
+ tarball.
+ """
+ tarballs = []
+ for component in components:
+ (_, _, comp_type) = parse_archive_filename(tarball)
+ cname = DebianPkgPolicy.build_tarball_name(name,
+ version,
+ comp_type,
+ os.path.dirname(tarball),
+ component)
+ tarballs.append((component, cname))
+ if not os.path.exists(cname):
+ raise GbpError("Can not find component tarball %s" % cname)
+ return tarballs
+
+
def debian_branch_merge_by_merge(repo, tag, version, options):
gbp.log.info("Merging to '%s'" % options.debian_branch)
+ branch = repo.get_branch()
+ repo.set_branch(options.debian_branch)
try:
repo.merge(tag)
except GitRepositoryError:
- raise GbpError("Merge failed, please resolve.")
- repo.set_branch(options.debian_branch)
+ raise GbpError("Automatic merge failed.")
+ repo.set_branch(branch)
def set_bare_repo_options(options):
"""Modify options for import into a bare repository"""
if options.pristine_tar or options.merge:
gbp.log.info("Bare repository: setting %s%s options"
- % (["", " '--no-pristine-tar'"][options.pristine_tar],
- ["", " '--no-merge'"][options.merge]))
+ % (["", " '--no-pristine-tar'"][options.pristine_tar],
+ ["", " '--no-merge'"][options.merge]))
options.pristine_tar = False
options.merge = False
@@ -241,52 +399,56 @@ def build_parser(name):
try:
parser = GbpOptionParserDebian(command=os.path.basename(name), prefix='',
usage='%prog [options] /path/to/upstream-version.tar.gz | --uscan')
- except configparser.ParsingError as err:
+ except GbpError as err:
gbp.log.err(err)
return None
import_group = GbpOptionGroup(parser, "import options",
- "pristine-tar and filtering")
+ "pristine-tar and filtering")
tag_group = GbpOptionGroup(parser, "tag options",
- "options related to git tag creation")
+ "options related to git tag creation")
branch_group = GbpOptionGroup(parser, "version and branch naming options",
- "version number and branch layout options")
- cmd_group = GbpOptionGroup(parser, "external command options", "how and when to invoke external commands and hooks")
-
- for group in [import_group, branch_group, tag_group, cmd_group ]:
+ "version number and branch layout options")
+ cmd_group = GbpOptionGroup(parser, "external command options",
+ "how and when to invoke external commands and hooks")
+ for group in [import_group, branch_group, tag_group, cmd_group]:
parser.add_option_group(group)
branch_group.add_option("-u", "--upstream-version", dest="version",
- help="Upstream Version")
+ help="Upstream Version")
branch_group.add_config_file_option(option_name="debian-branch",
- dest="debian_branch")
+ dest="debian_branch")
branch_group.add_config_file_option(option_name="upstream-branch",
- dest="upstream_branch")
+ dest="upstream_branch")
branch_group.add_config_file_option(option_name="upstream-vcs-tag", dest="vcs_tag",
- help="Upstream VCS tag add to the merge commit")
+ help="Upstream VCS tag add to the merge commit")
branch_group.add_boolean_config_file_option(option_name="merge", dest="merge")
branch_group.add_config_file_option(option_name="merge-mode", dest="merge_mode")
tag_group.add_boolean_config_file_option(option_name="sign-tags",
- dest="sign_tags")
+ dest="sign_tags")
tag_group.add_config_file_option(option_name="keyid",
- dest="keyid")
+ dest="keyid")
tag_group.add_config_file_option(option_name="upstream-tag",
- dest="upstream_tag")
+ dest="upstream_tag")
import_group.add_config_file_option(option_name="filter",
- dest="filters", action="append")
+ dest="filters", action="append")
import_group.add_boolean_config_file_option(option_name="pristine-tar",
- dest="pristine_tar")
+ dest="pristine_tar")
import_group.add_boolean_config_file_option(option_name="filter-pristine-tar",
- dest="filter_pristine_tar")
+ dest="filter_pristine_tar")
import_group.add_config_file_option(option_name="import-msg",
- dest="import_msg")
+ dest="import_msg")
import_group.add_boolean_config_file_option(option_name="symlink-orig",
dest="symlink_orig")
+ import_group.add_config_file_option("component", action="append", metavar='COMPONENT',
+ dest="components")
cmd_group.add_config_file_option(option_name="postimport", dest="postimport")
parser.add_boolean_config_file_option(option_name="interactive",
dest='interactive')
+ parser.add_boolean_config_file_option(option_name="rollback",
+ dest="rollback")
parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False,
help="verbose command execution")
parser.add_config_file_option(option_name="color", dest="color", type='tristate')
@@ -343,20 +505,19 @@ def main(argv):
tmpdir = ''
pristine_orig = None
linked = False
+ repo = None
(options, args) = parse_args(argv)
if not options:
- return 1
+ return ExitCodes.parse_error
try:
try:
- repo = DebianGitRepository('.')
+ repo = ImportOrigDebianGitRepository('.')
except GitRepositoryError:
raise GbpError("%s is not a git repository" % (os.path.abspath('.')))
- # an empty repo has now branches:
- initial_branch = repo.get_branch()
- is_empty = False if initial_branch else True
+ is_empty = repo.is_empty()
if not repo.has_branch(options.upstream_branch) and not is_empty:
raise GbpError(no_upstream_branch_msg % options.upstream_branch)
@@ -366,7 +527,7 @@ def main(argv):
gbp.log.err("Repository has uncommitted changes, commit these first: ")
raise GbpError(out)
- # Download the source
+ # Download the main tarball
if options.download:
source = download_orig(args[0])
else:
@@ -374,7 +535,13 @@ def main(argv):
if not source:
return ret
+ # The main tarball
(sourcepackage, version) = detect_name_and_version(repo, source, options)
+ # Additionl tarballs we expect to exist
+ component_tarballs = get_component_tarballs(sourcepackage,
+ version,
+ source.path,
+ options.components)
tag = repo.version_to_tag(options.upstream_tag, version)
if repo.has_tag(tag):
@@ -387,10 +554,12 @@ def main(argv):
tmpdir = tempfile.mkdtemp(dir='../')
source.unpack(tmpdir, options.filters)
gbp.log.debug("Unpacked '%s' to '%s'" % (source.path, source.unpacked))
+ for (component, tarball) in component_tarballs:
+ unpack_component_tarball(source.unpacked, component, tarball, options.filters)
if orig_needs_repack(source, options):
gbp.log.debug("Filter pristine-tar: repacking '%s' from '%s'" % (source.path, source.unpacked))
- (source, tmpdir) = repack_source(source, sourcepackage, version, tmpdir, options.filters)
+ (source, tmpdir) = repack_source(source, sourcepackage, version, tmpdir, options.filters)
(pristine_orig, linked) = prepare_pristine_tar(source.path,
sourcepackage,
@@ -404,32 +573,30 @@ def main(argv):
pass
try:
- upstream_branch = [ options.upstream_branch, 'master' ][is_empty]
+ import_branch = options.upstream_branch
filter_msg = ["", " (filtering out %s)"
% options.filters][len(options.filters) > 0]
gbp.log.info("Importing '%s' to branch '%s'%s..." % (source.path,
- upstream_branch,
+ import_branch,
filter_msg))
gbp.log.info("Source package is %s" % sourcepackage)
gbp.log.info("Upstream version is %s" % version)
- import_branch = [ options.upstream_branch, None ][is_empty]
msg = upstream_import_commit_msg(options, version)
- if options.vcs_tag:
- parents = [repo.rev_parse("%s^{}" % repo.version_to_tag(options.vcs_tag, version))]
- else:
- parents = None
-
commit = repo.commit_dir(source.unpacked,
msg=msg,
branch=import_branch,
- other_parents=parents,
+ other_parents=repo.vcs_tag_parent(options.vcs_tag, version),
+ create_missing_branch=is_empty,
)
if options.pristine_tar:
if pristine_orig:
- repo.pristine_tar.commit(pristine_orig, upstream_branch)
+ repo.rrr_branch('pristine-tar')
+ repo.create_pristinetar_commits(import_branch,
+ pristine_orig,
+ component_tarballs)
else:
gbp.log.warn("'%s' not an archive, skipping pristine-tar" % source.path)
@@ -438,19 +605,19 @@ def main(argv):
commit=commit,
sign=options.sign_tags,
keyid=options.keyid)
+
if is_empty:
- repo.create_branch(options.upstream_branch, rev=commit)
- repo.force_head(options.upstream_branch, hard=True)
- if options.debian_branch != 'master':
- repo.rename_branch('master', options.debian_branch)
+ repo.create_branch(branch=options.debian_branch, rev=commit)
+ repo.force_head(options.debian_branch, hard=True)
elif options.merge:
+ repo.rrr_branch(options.debian_branch)
debian_branch_merge(repo, tag, version, options)
# Update working copy and index if we've possibly updated the
# checked out branch
current_branch = repo.get_branch()
- if current_branch in [ options.upstream_branch,
- repo.pristine_tar_branch]:
+ if current_branch in [options.upstream_branch,
+ repo.pristine_tar_branch]:
repo.force_head(current_branch, hard=True)
except (gbpc.CommandExecFailed, GitRepositoryError) as err:
msg = str(err) or 'Unknown error, please report a bug'
@@ -459,6 +626,16 @@ def main(argv):
if str(err):
gbp.log.err(err)
ret = 1
+ if repo and repo.has_rollbacks() and options.rollback:
+ gbp.log.err("Error detected, Will roll back changes.")
+ try:
+ repo.rollback()
+ # Make sure the very last line as an error message
+ gbp.log.err("Rolled back changes after import error.")
+ except Exception as e:
+ gbp.log.error("%s" % e)
+ gbp.log.error("Clean up manually and please report a bug: %s" %
+ repo.rollback_errors)
if pristine_orig and linked and not options.symlink_orig:
os.unlink(pristine_orig)
@@ -470,6 +647,7 @@ def main(argv):
gbp.log.info("Successfully imported version %s of %s" % (version, source.path))
return ret
+
if __name__ == "__main__":
sys.exit(main(sys.argv))
diff --git a/gbp/scripts/import_srpm.py b/gbp/scripts/import_srpm.py
index 5013ba6..c4b3a48 100755
--- a/gbp/scripts/import_srpm.py
+++ b/gbp/scripts/import_srpm.py
@@ -17,7 +17,6 @@
# <http://www.gnu.org/licenses/>
"""Import an RPM source package into a Git repository"""
-from six.moves import configparser
import sys
import re
import os
@@ -37,6 +36,7 @@ from gbp.git.modifier import GitModifier
from gbp.config import (GbpOptionParserRpm, GbpOptionGroup,
no_upstream_branch_msg)
from gbp.errors import GbpError
+from gbp.scripts.common import ExitCodes
import gbp.log
from gbp.pkg import parse_archive_filename
@@ -123,7 +123,7 @@ def build_parser(name):
prefix='',
usage='%prog [options] /path/to/package'
'.src.rpm')
- except configparser.ParsingError as err:
+ except GbpError as err:
gbp.log.err(err)
return None
@@ -205,6 +205,8 @@ def main(argv):
skipped = False
options, args = parse_args(argv)
+ if not options:
+ return ExitCodes.parse_error
if len(args) != 1:
gbp.log.err("Need to give exactly one package to import. Try --help.")
@@ -356,7 +358,7 @@ def main(argv):
src_vendor = "Native" if options.native else "Upstream"
msg = "%s version %s" % (src_vendor, spec.upstreamversion)
src_commit = repo.commit_dir(sources.unpacked,
- "Imported %s" % msg,
+ "Import %s" % msg,
branch,
author=author,
committer=committer,
@@ -399,7 +401,7 @@ def main(argv):
if options.orphan_packaging or not sources:
commit = repo.commit_dir(dirs['packaging_base'],
- "Imported %s" % msg,
+ "Import %s" % msg,
branch,
author=author,
committer=committer,
@@ -417,7 +419,7 @@ def main(argv):
shutil.copy2(os.path.join(dirs['packaging'], fname),
pkgsubdir)
commit = repo.commit_dir(sources.unpacked,
- "Imported %s" % msg,
+ "Import %s" % msg,
branch,
other_parents=[src_commit],
author=author,
@@ -461,6 +463,7 @@ def main(argv):
gbp.log.info("Version '%s' imported under '%s'" % (ver_str, spec.name))
return ret
+
if __name__ == '__main__':
sys.exit(main(sys.argv))
diff --git a/gbp/scripts/pq.py b/gbp/scripts/pq.py
index 5dfe4c2..945cf1e 100755
--- a/gbp/scripts/pq.py
+++ b/gbp/scripts/pq.py
@@ -17,7 +17,6 @@
#
"""Manage Debian patches on a patch queue branch"""
-from six.moves import configparser
import errno
import os
import shutil
@@ -25,20 +24,23 @@ import sys
import tempfile
import re
from gbp.config import GbpOptionParserDebian
-from gbp.git import (GitRepositoryError, GitRepository)
+from gbp.deb.source import DebianSource
+from gbp.deb.git import DebianGitRepository
+from gbp.git import GitRepositoryError
from gbp.command_wrappers import (GitCommand, CommandExecFailed)
from gbp.errors import GbpError
import gbp.log
from gbp.patch_series import (PatchSeries, Patch)
from gbp.scripts.common.pq import (is_pq_branch, pq_branch_name, pq_branch_base,
- parse_gbp_commands, format_patch,
- switch_to_pq_branch, apply_single_patch,
- apply_and_commit_patch, switch_pq,
- drop_pq, get_maintainer_from_control)
+ parse_gbp_commands, format_patch,
+ switch_to_pq_branch, apply_single_patch,
+ apply_and_commit_patch, switch_pq,
+ drop_pq, get_maintainer_from_control)
+from gbp.scripts.common import ExitCodes
from gbp.dch import extract_bts_cmds
PATCH_DIR = "debian/patches/"
-SERIES_FILE = os.path.join(PATCH_DIR,"series")
+SERIES_FILE = os.path.join(PATCH_DIR, "series")
def parse_old_style_topic(commit_info):
@@ -145,7 +147,7 @@ def format_series_diff(added, removed, options):
return msg
-def commit_patches(repo, branch, patches, options):
+def commit_patches(repo, branch, patches, options, patch_dir):
"""
Commit chanages exported from patch queue
"""
@@ -156,12 +158,12 @@ def commit_patches(repo, branch, patches, options):
vfs = gbp.git.vfs.GitVfs(repo, branch)
try:
oldseries = vfs.open('debian/patches/series')
- oldpatches = [ p.strip() for p in oldseries.readlines() ]
+ oldpatches = [p.strip() for p in oldseries.readlines()]
oldseries.close()
except IOError:
# No series file yet
oldpatches = []
- newpatches = [ p[len(PATCH_DIR):] for p in patches ]
+ newpatches = [p[len(patch_dir):] for p in patches]
# FIXME: handle case were only the contents of the patches changed
added, removed = compare_series(oldpatches, newpatches)
@@ -171,8 +173,29 @@ def commit_patches(repo, branch, patches, options):
return added, removed
+def find_upstream_commit(repo, branch, upstream_tag):
+ """
+ Find commit corresponding upstream version based on changelog
+ """
+ vfs = gbp.git.vfs.GitVfs(repo, branch)
+ cl = DebianSource(vfs).changelog
+ upstream_commit = repo.find_version(upstream_tag, cl.upstream_version)
+ if not upstream_commit:
+ raise GbpError("Couldn't find upstream version %s" %
+ cl.upstream_version)
+ return upstream_commit
+
+
+def pq_on_upstream_tag(pq_from):
+ """Return True if the patch queue is based on the uptream tag,
+ False if its based on the debian packaging branch"""
+ return True if pq_from.upper() == 'TAG' else False
+
+
def export_patches(repo, branch, options):
"""Export patches from the pq branch into a patch series"""
+ patch_dir = os.path.join(repo.path, PATCH_DIR)
+ series_file = os.path.join(repo.path, SERIES_FILE)
if is_pq_branch(branch):
base = pq_branch_base(branch)
gbp.log.info("On '%s', switching to '%s'" % (branch, base))
@@ -181,21 +204,26 @@ def export_patches(repo, branch, options):
pq_branch = pq_branch_name(branch)
try:
- shutil.rmtree(PATCH_DIR)
+ shutil.rmtree(patch_dir)
except OSError as e:
if e.errno != errno.ENOENT:
raise GbpError("Failed to remove patch dir: %s" % e.strerror)
else:
- gbp.log.debug("%s does not exist." % PATCH_DIR)
+ gbp.log.debug("%s does not exist." % patch_dir)
+
+ if pq_on_upstream_tag(options.pq_from):
+ base = find_upstream_commit(repo, branch, options.upstream_tag)
+ else:
+ base = branch
- patches = generate_patches(repo, branch, pq_branch, PATCH_DIR, options)
+ patches = generate_patches(repo, base, pq_branch, patch_dir, options)
if patches:
- with open(SERIES_FILE, 'w') as seriesfd:
+ with open(series_file, 'w') as seriesfd:
for patch in patches:
- seriesfd.write(os.path.relpath(patch, PATCH_DIR) + '\n')
+ seriesfd.write(os.path.relpath(patch, patch_dir) + '\n')
if options.commit:
- added, removed = commit_patches(repo, branch, patches, options)
+ added, removed = commit_patches(repo, branch, patches, options, patch_dir)
if added:
what = 'patches' if len(added) > 1 else 'patch'
gbp.log.info("Added %s %s to patch series" % (what, ', '.join(added)))
@@ -203,7 +231,7 @@ def export_patches(repo, branch, options):
what = 'patches' if len(removed) > 1 else 'patch'
gbp.log.info("Removed %s %s from patch series" % (what, ', '.join(removed)))
else:
- GitCommand('status')(['--', PATCH_DIR])
+ GitCommand('status', cwd=repo.path)(['--', PATCH_DIR])
else:
gbp.log.info("No patches on '%s' - nothing to do." % pq_branch)
@@ -211,7 +239,7 @@ def export_patches(repo, branch, options):
drop_pq(repo, branch)
-def safe_patches(series):
+def safe_patches(series, repo):
"""
Safe the current patches in a temporary directory
below .git/
@@ -224,7 +252,7 @@ def safe_patches(series):
src = os.path.dirname(series)
name = os.path.basename(series)
- tmpdir = tempfile.mkdtemp(dir='.git/', prefix='gbp-pq')
+ tmpdir = tempfile.mkdtemp(dir=repo.git_dir, prefix='gbp-pq')
patches = os.path.join(tmpdir, 'patches')
series = os.path.join(patches, name)
@@ -234,19 +262,25 @@ def safe_patches(series):
return (tmpdir, series)
-def import_quilt_patches(repo, branch, series, tries, force):
+def import_quilt_patches(repo, branch, series, tries, force, pq_from,
+ upstream_tag):
"""
apply a series of quilt patches in the series file 'series' to branch
the patch-queue branch for 'branch'
@param repo: git repository to work on
- @param branch: branch to base pqtch queue on
- @param series; series file to read patches from
+ @param branch: branch to base patch queue on
+ @param series: series file to read patches from
@param tries: try that many times to apply the patches going back one
commit in the branches history after each failure.
@param force: import the patch series even if the branch already exists
+ @param pq_from: what to use as the starting point for the pq branch.
+ DEBIAN indicates the current branch, TAG indicates that
+ the corresponding upstream tag should be used.
+ @param upstream_tag: upstream tag template to use
"""
tmpdir = None
+ series = os.path.join(repo.path, series)
if is_pq_branch(branch):
if force:
@@ -267,11 +301,16 @@ def import_quilt_patches(repo, branch, series, tries, force):
% pq_branch)
maintainer = get_maintainer_from_control(repo)
- commits = repo.get_commits(num=tries, first_parent=True)
+ if pq_on_upstream_tag(pq_from):
+ commits = [find_upstream_commit(repo, branch, upstream_tag)]
+ else: # pq_from == 'DEBIAN'
+ commits = repo.get_commits(num=tries, first_parent=True)
# If we go back in history we have to safe our pq so we always try to apply
# the latest one
- if len(commits) > 1:
- tmpdir, series = safe_patches(series)
+ # If we are using the upstream_tag, we always need a copy of the patches
+ if len(commits) > 1 or pq_on_upstream_tag(pq_from):
+ if os.path.exists(series):
+ tmpdir, series = safe_patches(series, repo)
queue = PatchSeries.read_series_file(series)
@@ -300,7 +339,7 @@ def import_quilt_patches(repo, branch, series, tries, force):
else:
# All patches applied successfully
break
- i-=1
+ i -= 1
else:
raise GbpError("Couldn't apply patches")
@@ -308,31 +347,44 @@ def import_quilt_patches(repo, branch, series, tries, force):
gbp.log.debug("Remove temporary patch safe '%s'" % tmpdir)
shutil.rmtree(tmpdir)
+ return len(queue)
+
+
+def rebase_pq(repo, branch, pq_from, upstream_tag):
-def rebase_pq(repo, branch):
if is_pq_branch(branch):
base = pq_branch_base(branch)
else:
switch_to_pq_branch(repo, branch)
base = branch
- GitCommand("rebase")([base])
+
+ if pq_on_upstream_tag(pq_from):
+ _from = find_upstream_commit(repo, base, upstream_tag)
+ else:
+ _from = base
+
+ GitCommand("rebase", cwd=repo.path)([_from])
+
+
+def usage_msg():
+ return """%prog [options] action - maintain patches on a patch queue branch
+Actions:
+ export export the patch queue associated to the current branch
+ into a quilt patch series in debian/patches/ and update the
+ series file.
+ import create a patch queue branch from quilt patches in debian/patches.
+ rebase switch to patch queue branch associated to the current
+ branch and rebase against current branch.
+ drop drop (delete) the patch queue associated to the current branch.
+ apply apply a patch
+ switch switch to patch-queue branch and vice versa"""
def build_parser(name):
try:
parser = GbpOptionParserDebian(command=os.path.basename(name),
- usage="%prog [options] action - maintain patches on a patch queue branch\n"
- "Actions:\n"
- " export export the patch queue associated to the current branch\n"
- " into a quilt patch series in debian/patches/ and update the\n"
- " series file.\n"
- " import create a patch queue branch from quilt patches in debian/patches.\n"
- " rebase switch to patch queue branch associated to the current\n"
- " branch and rebase against current branch.\n"
- " drop drop (delete) the patch queue associated to the current branch.\n"
- " apply apply a patch\n"
- " switch switch to patch-queue branch and vice versa")
- except configparser.ParsingError as err:
+ usage=usage_msg())
+ except GbpError as err:
gbp.log.err(err)
return None
@@ -352,6 +404,8 @@ def build_parser(name):
dest="color_scheme")
parser.add_config_file_option(option_name="meta-closes", dest="meta_closes")
parser.add_config_file_option(option_name="meta-closes-bugnum", dest="meta_closes_bugnum")
+ parser.add_config_file_option(option_name="pq-from", dest="pq_from", choices=['DEBIAN', 'TAG'])
+ parser.add_config_file_option(option_name="upstream-tag", dest="upstream_tag")
return parser
@@ -367,7 +421,7 @@ def main(argv):
(options, args) = parse_args(argv)
if not options:
- return 1
+ return ExitCodes.parse_error
gbp.log.setup(options.color, options.verbose, options.color_scheme)
@@ -390,7 +444,7 @@ def main(argv):
return 1
try:
- repo = GitRepository(os.path.curdir)
+ repo = DebianGitRepository(os.path.curdir)
except GitRepositoryError:
gbp.log.err("%s is not a git repository" % (os.path.abspath('.')))
return 1
@@ -402,20 +456,25 @@ def main(argv):
elif action == "import":
series = SERIES_FILE
tries = options.time_machine if (options.time_machine > 0) else 1
- import_quilt_patches(repo, current, series, tries, options.force)
+ num = import_quilt_patches(repo, current, series, tries,
+ options.force, options.pq_from,
+ options.upstream_tag)
current = repo.get_branch()
- gbp.log.info("Patches listed in '%s' imported on '%s'" %
- (series, current))
+ gbp.log.info("%d patches listed in '%s' imported on '%s'" %
+ (num, series, current))
elif action == "drop":
drop_pq(repo, current)
elif action == "rebase":
- rebase_pq(repo, current)
+ rebase_pq(repo, current, options.pq_from, options.upstream_tag)
elif action == "apply":
patch = Patch(patchfile)
maintainer = get_maintainer_from_control(repo)
apply_single_patch(repo, current, patch, maintainer, options.topic)
elif action == "switch":
switch_pq(repo, current)
+ except KeyboardInterrupt:
+ retval = 1
+ gbp.log.err("Interrupted. Aborting.")
except CommandExecFailed:
retval = 1
except (GbpError, GitRepositoryError) as err:
@@ -425,5 +484,6 @@ def main(argv):
return retval
+
if __name__ == '__main__':
sys.exit(main(sys.argv))
diff --git a/gbp/scripts/pq_rpm.py b/gbp/scripts/pq_rpm.py
index 660807a..9a32c1c 100755
--- a/gbp/scripts/pq_rpm.py
+++ b/gbp/scripts/pq_rpm.py
@@ -18,7 +18,6 @@
#
"""manage patches in a patch queue"""
-from six.moves import configparser
import bz2
import errno
import gzip
@@ -37,10 +36,12 @@ from gbp.patch_series import PatchSeries, Patch
from gbp.pkg import parse_archive_filename
from gbp.rpm import (SpecFile, NoSpecError, guess_spec, guess_spec_repo,
spec_from_repo)
+from gbp.scripts.common import ExitCodes
from gbp.scripts.common.pq import (is_pq_branch, pq_branch_name, pq_branch_base,
parse_gbp_commands, format_patch, format_diff,
switch_to_pq_branch, apply_single_patch, apply_and_commit_patch,
drop_pq, switch_pq)
+
from gbp.scripts.common.buildpackage import dump_tree
@@ -54,6 +55,7 @@ def is_ancestor(repo, parent, child):
merge_base = None
return merge_base == parent_sha1
+
def generate_patches(repo, start, end, outdir, options):
"""
Generate patch files from git
@@ -99,7 +101,7 @@ def generate_patches(repo, start, end, outdir, options):
'gbp-rpm',
('ignore'),
('if', 'ifarch'))
- if not 'ignore' in cmds:
+ if 'ignore' not in cmds:
patch_fn = format_patch(outdir, repo, info, patches,
options.patch_numbers)
if patch_fn:
@@ -222,7 +224,7 @@ def safe_patches(queue):
if len(queue) > 0:
gbp.log.debug("Safeing patches '%s' in '%s'" %
- (os.path.dirname(queue[0].path), tmpdir))
+ (os.path.dirname(queue[0].path), tmpdir))
for patch in queue:
base, _archive_fmt, comp = parse_archive_filename(patch.path)
uncompressors = {'gzip': gzip.open, 'bzip2': bz2.BZ2File}
@@ -314,7 +316,7 @@ def import_spec_patches(repo, options):
if not queue:
return
gbp.log.info("Trying to apply patches from branch '%s' onto '%s'" %
- (base, upstream_commit))
+ (base, upstream_commit))
for patch in queue:
gbp.log.debug("Applying %s" % patch.path)
apply_and_commit_patch(repo, patch, packager)
@@ -323,8 +325,8 @@ def import_spec_patches(repo, options):
repo.delete_branch(pq_branch)
raise GbpError('Import failed: %s' % err)
- gbp.log.info("Patches listed in '%s' imported on '%s'" % (spec.specfile,
- pq_branch))
+ gbp.log.info("%d patches listed in '%s' imported on '%s'" % (len(queue), spec.specfile,
+ pq_branch))
def rebase_pq(repo, options):
@@ -360,8 +362,8 @@ drop Drop (delete) the patch queue /devel branch associated to
apply Apply a patch
switch Switch to patch-queue branch and vice versa.""")
- except configparser.ParsingError as err:
- gbp.log.err('Invalid config file: %s' % err)
+ except GbpError as err:
+ gbp.log.err(err)
return None
parser.add_boolean_config_file_option(option_name="patch-numbers",
@@ -398,7 +400,7 @@ def main(argv):
(options, args) = parse_args(argv)
if not options:
- return 1
+ return ExitCodes.parse_error
gbp.log.setup(options.color, options.verbose, options.color_scheme)
@@ -443,6 +445,9 @@ def main(argv):
apply_single_patch(repo, current, patch, fallback_author=None)
elif action == "switch":
switch_pq(repo, current)
+ except KeyboardInterrupt:
+ retval = 1
+ gbp.log.err("Interrupted. Aborting.")
except CommandExecFailed:
retval = 1
except GitRepositoryError as err:
@@ -457,6 +462,6 @@ def main(argv):
return retval
+
if __name__ == '__main__':
sys.exit(main(sys.argv))
-
diff --git a/gbp/scripts/pull.py b/gbp/scripts/pull.py
index 67b2ab1..004156b 100755
--- a/gbp/scripts/pull.py
+++ b/gbp/scripts/pull.py
@@ -19,7 +19,6 @@
#
"""Pull remote changes and fast forward debian, upstream and pristine-tar branch"""
-from six.moves import configparser
import sys
import os
import os.path
@@ -28,6 +27,7 @@ from gbp.config import (GbpOptionParser, GbpOptionGroup)
from gbp.errors import GbpError
from gbp.git import GitRepositoryError
from gbp.deb.git import DebianGitRepository
+from gbp.scripts.common import ExitCodes
import gbp.log
@@ -75,7 +75,7 @@ def build_parser(name):
try:
parser = GbpOptionParser(command=os.path.basename(name), prefix='',
usage='%prog [options] - safely update a repository from remote')
- except configparser.ParsingError as err:
+ except GbpError as err:
gbp.log.err(err)
return None
@@ -112,7 +112,7 @@ def main(argv):
(options, args) = parse_args(argv)
if not options:
- return 1
+ return ExitCodes.parse_error
gbp.log.setup(options.color, options.verbose, options.color_scheme)
@@ -159,6 +159,9 @@ def main(argv):
Command("gbp-pq")(["import"])
repo.set_branch(current)
+ except KeyboardInterrupt:
+ retval = 1
+ gbp.log.err("Interrupted. Aborting.")
except CommandExecFailed:
retval = 1
except (GbpError, GitRepositoryError) as err:
@@ -168,6 +171,7 @@ def main(argv):
return retval
+
if __name__ == '__main__':
sys.exit(main(sys.argv))
diff --git a/gbp/scripts/rpm_ch.py b/gbp/scripts/rpm_ch.py
new file mode 100644
index 0000000..eae4721
--- /dev/null
+++ b/gbp/scripts/rpm_ch.py
@@ -0,0 +1,450 @@
+# vim: set fileencoding=utf-8 :
+#
+# (C) 2007, 2008, 2009, 2010, 2013 Guido Guenther <agx@sigxcpu.org>
+# (C) 2014-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, please see
+# <http://www.gnu.org/licenses/>
+#
+"""Generate RPM changelog entries from git commit messages"""
+
+from datetime import datetime
+import os.path
+import pwd
+import re
+import sys
+import socket
+
+import gbp.command_wrappers as gbpc
+import gbp.log
+from gbp.config import GbpOptionParserRpm, GbpOptionGroup
+from gbp.errors import GbpError
+from gbp.rpm import (guess_spec, NoSpecError, SpecFile, split_version_str,
+ compose_version_str)
+from gbp.rpm.changelog import Changelog, ChangelogParser, ChangelogError
+from gbp.rpm.git import GitRepositoryError, RpmGitRepository
+from gbp.rpm.policy import RpmPkgPolicy
+from gbp.scripts.common import ExitCodes
+from gbp.tmpfile import init_tmpdir, del_tmpdir
+
+
+ChangelogEntryFormatter = RpmPkgPolicy.ChangelogEntryFormatter
+
+
+class ChangelogFile(object):
+ """Container for changelog file, whether it be a standalone changelog
+ or a spec file"""
+
+ def __init__(self, file_path):
+ parser = ChangelogParser(RpmPkgPolicy)
+
+ if os.path.splitext(file_path)[1] == '.spec':
+ gbp.log.debug("Using spec file '%s' as changelog" % file_path)
+ self._file = SpecFile(file_path)
+ self.changelog = parser.raw_parse_string(self._file.get_changelog())
+ else:
+ self._file = os.path.abspath(file_path)
+ if not os.path.exists(file_path):
+ gbp.log.info("Changelog '%s' not found, creating new "
+ "changelog file" % file_path)
+ self.changelog = Changelog(RpmPkgPolicy)
+ else:
+ gbp.log.debug("Using changelog file '%s'" % file_path)
+ self.changelog = parser.raw_parse_file(self._file)
+
+ # Parse topmost section and try to determine the start commit
+ if self.changelog.sections:
+ self.changelog.sections[0] = parser.parse_section(
+ self.changelog.sections[0])
+
+ def write(self):
+ """Write changelog file to disk"""
+ if isinstance(self._file, SpecFile):
+ self._file.set_changelog(str(self.changelog))
+ self._file.write_spec_file()
+ else:
+ with open(self._file, 'w') as fobj:
+ fobj.write(str(self.changelog))
+
+ @property
+ def path(self):
+ """File path"""
+ if isinstance(self._file, SpecFile):
+ return self._file.specpath
+ else:
+ return self._file
+
+def load_customizations(customization_file):
+ """Load user defined customizations file"""
+ # Load customization file
+ if not customization_file:
+ return
+ customizations = {}
+ try:
+ execfile(customization_file, customizations, customizations)
+ except Exception as err:
+ raise GbpError("Failed to load customization file: %s" % err)
+
+ # Set customization classes / functions
+ global ChangelogEntryFormatter
+ if 'ChangelogEntryFormatter' in customizations:
+ ChangelogEntryFormatter = customizations.get('ChangelogEntryFormatter')
+
+
+def determine_editor(options):
+ """Determine text editor"""
+
+ # Check if we need to spawn an editor
+ states = ['always']
+ if options.release:
+ states.append('release')
+ if options.spawn_editor not in states:
+ return None
+
+ # Determine the correct editor
+ if options.editor_cmd:
+ return options.editor_cmd
+ elif 'EDITOR' in os.environ:
+ return os.environ['EDITOR']
+ else:
+ return 'vi'
+
+
+def check_branch(repo, options):
+ """Check the current git branch"""
+ try:
+ branch = repo.get_branch()
+ except GitRepositoryError:
+ branch = None
+ if options.packaging_branch != branch and not options.ignore_branch:
+ gbp.log.err("You are not on branch '%s' but on '%s'" %
+ (options.packaging_branch, branch))
+ raise GbpError("Use --ignore-branch to ignore or "
+ "--packaging-branch to set the branch name.")
+
+
+def parse_spec_file(repo, options):
+ """Find and parse spec file"""
+ if options.spec_file:
+ spec_path = os.path.join(repo.path, options.spec_file)
+ spec = SpecFile(spec_path)
+ else:
+ spec = guess_spec(os.path.join(repo.path, options.packaging_dir),
+ True, os.path.basename(repo.path) + '.spec')
+ options.packaging_dir = spec.specdir
+ return spec
+
+
+def parse_changelog_file(repo, spec, options):
+ """Find and parse changelog file"""
+ changes_file_name = os.path.splitext(spec.specfile)[0] + '.changes'
+ changes_file_path = os.path.join(options.packaging_dir, changes_file_name)
+
+ # Determine changelog file path
+ if options.changelog_file == "SPEC":
+ changelog_path = spec.specpath
+ elif options.changelog_file == "CHANGES":
+ changelog_path = changes_file_path
+ elif options.changelog_file == 'auto':
+ if os.path.exists(changes_file_path):
+ changelog_path = changes_file_path
+ else:
+ changelog_path = spec.specpath
+ else:
+ changelog_path = os.path.join(repo.path, options.changelog_file)
+
+ return ChangelogFile(changelog_path)
+
+
+def guess_commit(section, repo, options):
+ """Guess the last commit documented in a changelog header"""
+
+ if not section:
+ return None
+ header = section.header
+
+ # Try to parse the fields from the header revision
+ rev_re = '^%s$' % re.sub(r'%\((\S+?)\)s', r'(?P<\1>\S+)',
+ options.changelog_revision)
+ match = re.match(rev_re, header['revision'], re.I)
+ fields = match.groupdict() if match else {}
+
+ # First, try to find tag-name, if present
+ if 'tagname' in fields:
+ gbp.log.debug("Trying to find tagname %s" % fields['tagname'])
+ try:
+ return repo.rev_parse("%s^0" % fields['tagname'])
+ except GitRepositoryError:
+ gbp.log.warn("Changelog points to tagname '%s' which is not found "
+ "in the git repository" % fields['tagname'])
+
+ # Next, try to find packaging tag matching the version
+ tag_str_fields = {'vendor': options.vendor}
+ if 'version' in fields:
+ gbp.log.debug("Trying to find packaging tag for version '%s'" %
+ fields['version'])
+ full_version = fields['version']
+ tag_str_fields.update(split_version_str(full_version))
+ elif 'upstreamversion' in fields:
+ gbp.log.debug("Trying to find packaging tag for version '%s'" %
+ fields['upstreamversion'])
+ tag_str_fields['upstreamversion'] = fields['upstreamversion']
+ if 'release' in fields:
+ tag_str_fields['release'] = fields['release']
+ commit = repo.find_version(options.packaging_tag,
+ tag_str_fields)
+ if commit:
+ return commit
+ else:
+ gbp.log.info("Couldn't find packaging tag for version %s" %
+ header['revision'])
+
+ # As a last resort we look at the timestamp
+ timestamp = header['time'].isoformat()
+ last = repo.get_commits(num=1, options="--until='%s'" % timestamp)
+ if last:
+ gbp.log.info("Using commit (%s) before the last changelog timestamp "
+ "(%s)" % (last, timestamp))
+ return last[0]
+ return None
+
+
+def get_start_commit(changelog, repo, options):
+ """Get the start commit from which to generate new entries"""
+ if options.since:
+ since = options.since
+ else:
+ if changelog.sections:
+ since = guess_commit(changelog.sections[0], repo, options)
+ else:
+ since = None
+ if not since:
+ raise GbpError("Couldn't determine starting point from "
+ "changelog, please use the '--since' option")
+ gbp.log.info("Continuing from commit '%s'" % since)
+ return since
+
+
+def get_author(repo, use_git_config):
+ """Get author and email from git configuration"""
+ author = email = None
+
+ if use_git_config:
+ modifier = repo.get_author_info()
+ author = modifier.name
+ email = modifier.email
+
+ passwd_data = pwd.getpwuid(os.getuid())
+ if not author:
+ # On some distros (Ubuntu, at least) the gecos field has it's own
+ # internal structure of comma-separated fields
+ author = passwd_data.pw_gecos.split(',')[0].strip()
+ if not author:
+ author = passwd_data.pw_name
+ if not email:
+ if 'EMAIL' in os.environ:
+ email = os.environ['EMAIL']
+ else:
+ email = "%s@%s" % (passwd_data.pw_name, socket.getfqdn())
+
+ return author, email
+
+
+def entries_from_commits(changelog, repo, commits, options):
+ """Generate a list of formatted changelog entries from a list of commits"""
+ entries = []
+ for commit in commits:
+ info = repo.get_commit_info(commit)
+ entry_text = ChangelogEntryFormatter.compose(info, full=options.full,
+ ignore_re=options.ignore_regex, id_len=options.idlen)
+ if entry_text:
+ entries.append(changelog.create_entry(author=info['author'].name,
+ text=entry_text))
+ return entries
+
+
+def update_changelog(changelog, entries, repo, spec, options):
+ """Update the changelog with a range of commits"""
+ # Get info for section header
+ now = datetime.now()
+ name, email = get_author(repo, options.git_author)
+ rev_str_fields = dict(spec.version,
+ version=compose_version_str(spec.version),
+ vendor=options.vendor,
+ tagname=repo.describe('HEAD', longfmt=True,
+ always=True))
+ try:
+ revision = options.changelog_revision % rev_str_fields
+ except KeyError as err:
+ raise GbpError("Unable to construct revision field: unknown key "
+ "%s, only %s are accepted" % (err, rev_str_fields.keys()))
+
+ # Add a new changelog section if new release or an empty changelog
+ if options.release or not changelog.sections:
+ top_section = changelog.add_section(time=now, name=name,
+ email=email, revision=revision)
+ else:
+ # Re-use already parsed top section
+ top_section = changelog.sections[0]
+ top_section.set_header(time=now, name=name,
+ email=email, revision=revision)
+
+ # Add new entries to the topmost section
+ for entry in entries:
+ top_section.append_entry(entry)
+
+
+def build_parser(name):
+ """Construct command line parser"""
+ try:
+ parser = GbpOptionParserRpm(command=os.path.basename(name),
+ prefix='', usage='%prog [options] paths')
+ except GbpError as err:
+ gbp.log.error(err)
+ return None
+
+ range_grp = GbpOptionGroup(parser, "commit range options",
+ "which commits to add to the changelog")
+ format_grp = GbpOptionGroup(parser, "changelog entry formatting",
+ "how to format the changelog entries")
+ naming_grp = GbpOptionGroup(parser, "naming",
+ "branch names, tag formats, directory and file naming")
+ parser.add_option_group(range_grp)
+ parser.add_option_group(format_grp)
+ parser.add_option_group(naming_grp)
+
+ # Non-grouped options
+ parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
+ help="verbose command execution")
+ 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="tmp-dir", dest="tmp_dir")
+ parser.add_config_file_option(option_name="vendor", action="store",
+ dest="vendor")
+ parser.add_config_file_option(option_name="git-log", dest="git_log",
+ help="options to pass to git-log, default is '%(git-log)s'")
+ parser.add_boolean_config_file_option(option_name="ignore-branch",
+ dest="ignore_branch")
+ parser.add_config_file_option(option_name="customizations",
+ dest="customization_file",
+ help="Load Python code from CUSTOMIZATION_FILE. At the "
+ "moment, the only useful thing the code can do is define a "
+ "custom ChangelogEntryFormatter class.")
+
+ # Naming group options
+ naming_grp.add_config_file_option(option_name="packaging-branch",
+ dest="packaging_branch")
+ naming_grp.add_config_file_option(option_name="packaging-tag",
+ dest="packaging_tag")
+ naming_grp.add_config_file_option(option_name="packaging-dir",
+ dest="packaging_dir")
+ naming_grp.add_config_file_option(option_name="changelog-file",
+ dest="changelog_file")
+ naming_grp.add_config_file_option(option_name="spec-file", dest="spec_file")
+ # Range group options
+ range_grp.add_option("-s", "--since", dest="since",
+ help="commit to start from (e.g. HEAD^^^, release/0.1.2)")
+ # Formatting group options
+ format_grp.add_option("--no-release", action="store_false", default=True,
+ dest="release",
+ help="no release, just update the last changelog section")
+ format_grp.add_boolean_config_file_option(option_name="git-author",
+ dest="git_author")
+ format_grp.add_boolean_config_file_option(option_name="full", dest="full")
+ format_grp.add_config_file_option(option_name="id-length", dest="idlen",
+ help="include N digits of the commit id in the changelog "
+ "entry, default is '%(id-length)s'",
+ type="int", metavar="N")
+ format_grp.add_config_file_option(option_name="ignore-regex",
+ dest="ignore_regex",
+ help="Ignore lines in commit message matching regex, "
+ "default is '%(ignore-regex)s'")
+ format_grp.add_config_file_option(option_name="changelog-revision",
+ dest="changelog_revision")
+ format_grp.add_config_file_option(option_name="spawn-editor",
+ dest="spawn_editor")
+ format_grp.add_config_file_option(option_name="editor-cmd",
+ dest="editor_cmd")
+ return parser
+
+def parse_args(argv):
+ """Parse command line and config file options"""
+ parser = build_parser(argv[0])
+ if not parser:
+ return None, None
+
+ options, args = parser.parse_args(argv[1:])
+
+ if not options.changelog_revision:
+ options.changelog_revision = RpmPkgPolicy.Changelog.header_rev_format
+
+ gbp.log.setup(options.color, options.verbose, options.color_scheme)
+
+ return options, args
+
+def main(argv):
+ """Script main function"""
+ options, args = parse_args(argv)
+ if not options:
+ return ExitCodes.parse_error
+
+ try:
+ init_tmpdir(options.tmp_dir, prefix='rpm-ch_')
+
+ load_customizations(options.customization_file)
+ editor_cmd = determine_editor(options)
+
+ repo = RpmGitRepository('.')
+ check_branch(repo, options)
+
+ # Find and parse spec file
+ spec = parse_spec_file(repo, options)
+
+ # Find and parse changelog file
+ ch_file = parse_changelog_file(repo, spec, options)
+ since = get_start_commit(ch_file.changelog, repo, options)
+
+ # Get range of commits from where to generate changes
+ if args:
+ gbp.log.info("Only looking for changes in '%s'" % ", ".join(args))
+ commits = repo.get_commits(since=since, until='HEAD', paths=args,
+ options=options.git_log.split(" "))
+ commits.reverse()
+ if not commits:
+ gbp.log.info("No changes detected from %s to %s." % (since, 'HEAD'))
+
+ # Do the actual update
+ entries = entries_from_commits(ch_file.changelog, repo, commits,
+ options)
+ update_changelog(ch_file.changelog, entries, repo, spec, options)
+
+ # Write to file
+ ch_file.write()
+
+ if editor_cmd:
+ gbpc.Command(editor_cmd, [ch_file.path])()
+
+ except (GbpError, GitRepositoryError, ChangelogError, NoSpecError) as err:
+ if len(err.__str__()):
+ gbp.log.err(err)
+ return 1
+ finally:
+ del_tmpdir()
+
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main(sys.argv))
diff --git a/gbp/scripts/supercommand.py b/gbp/scripts/supercommand.py
index 2d0a9f4..c2bcfb2 100644
--- a/gbp/scripts/supercommand.py
+++ b/gbp/scripts/supercommand.py
@@ -26,7 +26,8 @@ import sys
# Command is this module and common/ is shared code
# so we don't allow these to be imported:
-invalid_modules = [ 'common', 'supercommand' ]
+invalid_modules = ['common', 'supercommand']
+
def sanitize(cmd):
"""
@@ -35,6 +36,7 @@ def sanitize(cmd):
"""
return cmd.replace('-', '_')
+
def usage():
print("""
Usage:
@@ -50,6 +52,7 @@ The most commonly used commands are:
Use '--list-cmds' to list all available commands.
""")
+
def version(prog):
try:
from gbp.version import gbp_version
@@ -64,7 +67,7 @@ def import_command(cmd):
"""
modulename = sanitize(cmd)
if (not re.match(r'[a-z][a-z0-9_]', modulename) or
- modulename in invalid_modules):
+ modulename in invalid_modules):
raise ImportError('Illegal module name %s' % modulename)
return __import__('gbp.scripts.%s' % modulename, fromlist='main', level=0)
@@ -75,7 +78,7 @@ def pymod_to_cmd(mod):
>>> pymod_to_cmd('/x/y/z/a_cmd.py')
'a-cmd'
"""
- return os.path.basename(mod.rsplit('.', 1)[0]).replace('_','-')
+ return os.path.basename(mod.rsplit('.', 1)[0]).replace('_', '-')
def get_available_commands(path):
@@ -125,10 +128,10 @@ def supercommand(argv=None):
elif cmd == 'help':
usage()
return 0
- elif cmd in [ '--version', 'version' ]:
+ elif cmd in ['--version', 'version']:
version(argv[0])
return 0
- elif cmd in [ '--list-cmds', 'list-cmds' ]:
+ elif cmd in ['--list-cmds', 'list-cmds']:
list_available_commands()
return 0
@@ -143,6 +146,7 @@ def supercommand(argv=None):
return module.main(args)
+
if __name__ == '__main__':
sys.exit(supercommand())
diff --git a/gbp/tmpfile.py b/gbp/tmpfile.py
index d49380c..755967b 100644
--- a/gbp/tmpfile.py
+++ b/gbp/tmpfile.py
@@ -26,6 +26,7 @@ from gbp.errors import GbpError
_old_tempdirs = []
+
def init_tmpdir(path, prefix):
"""Initialize a temporary directory structure"""
try:
@@ -42,6 +43,7 @@ def init_tmpdir(path, prefix):
tempfile.tempdir = tmpdir
return tmpdir
+
def del_tmpdir():
"""Remove tempdir and restore tempfile module"""
if _old_tempdirs:
@@ -51,4 +53,3 @@ def del_tmpdir():
tempfile.tempdir = _old_tempdirs.pop()
# vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·:
-
diff --git a/gbp/tristate.py b/gbp/tristate.py
index 4630029..d6ff810 100644
--- a/gbp/tristate.py
+++ b/gbp/tristate.py
@@ -19,27 +19,28 @@
A switch with three states: on|off|auto
"""
+
class Tristate(object):
"""Tri-state value: on, off or auto """
- ON = True # state is on == do it
+ ON = True # state is on == do it
OFF = False # state is off == don't do it
AUTO = -1 # autodetect == do if possible
# We accept true as alias for on and false as alias for off
- _VALID_NAMES = [ 'on', 'off', 'true', 'false', 'auto' ]
+ _VALID_NAMES = ['on', 'off', 'true', 'false', 'auto']
def __init__(self, val):
- if type(val) in [ type(t) for t in (True, 1) ]:
+ if type(val) in [type(t) for t in (True, 1)]:
if val > 0:
self._state = self.ON
elif val < 0:
self._state = self.AUTO
else:
self._state = self.OFF
- elif type(val) in [ type(t) for t in ("", u"") ]:
- if val.lower() in [ 'on', 'true' ]:
+ elif type(val) in [type(t) for t in ("", u"")]:
+ if val.lower() in ['on', 'true']:
self._state = self.ON
- elif val.lower() in [ 'auto' ]:
+ elif val.lower() in ['auto']:
self._state = self.AUTO
else:
self._state = self.OFF
diff --git a/packaging/git-buildpackage.spec b/packaging/git-buildpackage.spec
index fcf03f1..d184b32 100644
--- a/packaging/git-buildpackage.spec
+++ b/packaging/git-buildpackage.spec
@@ -249,6 +249,7 @@ done
%{_mandir}/man1/gbp-buildpackage-rpm.1*
%{_mandir}/man1/gbp-pq-rpm.1*
%{_mandir}/man1/gbp-import-srpm.1*
+%{_mandir}/man1/gbp-rpm-ch.1*
%endif
diff --git a/requirements.txt b/requirements.txt
index 02e8e95..bd47cda 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,6 +1,7 @@
-six>=1.9.0
-nose>=0.11.1
coverage>=2.85
+flake8>=3
+mock
+nose>=0.11.1
nosexcover>=1.0.7
python-dateutil
-mock
+six>=1.9.0
diff --git a/setup.cfg b/setup.cfg
index d443f2a..64c042a 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -13,6 +13,9 @@ target = build/apidocs/
fail-on = docstring_warning
modules = gbp, tests/test_*.py
-[pep8]
+[flake8]
# E501: ignore line length
-ignore=E501
+# E265: block comment should start with '# '
+ignore=E501,E265
+builtins=unicode,execfile,raw_input
+exclude=*rpm*,svn,CVS,.bzr,.hg,.git,__pycache__,.tox,.eggs,*.egg
diff --git a/setup.py b/setup.py
index bbc0ba8..a8f2a33 100644..100755
--- a/setup.py
+++ b/setup.py
@@ -34,41 +34,48 @@ def fetch_version():
version = line.split(' ')[1].strip()
break
except OSError:
- pass # Failing is fine, we just can't print the version then
+ pass # Failing is fine, we just can't print the version then
with open('gbp/version.py', 'w') as f:
f.write('"The current gbp version number"\n')
- f.write('gbp_version="%s"\n' % version)
+ f.write('gbp_version = "%s"\n' % version)
return version
def readme():
- with open('README') as file:
+ with open('README.md') as file:
return file.read()
-setup(name = "gbp",
- version = fetch_version(),
- author = u'Guido Günther',
- author_email = 'agx@sigxcpu.org',
- url = 'https://honk.sigxcpu.org/piki/projects/git-buildpackage/',
- description = 'Suite to help with Debian packages in Git repositories',
- license = 'GPLv2+',
- long_description = readme(),
- classifiers = [
+
+def setup_requires():
+ if os.getenv('WITHOUT_NOSETESTS'):
+ return []
+ else:
+ return ['nose>=0.11.1', 'coverage>=2.85', 'nosexcover>=1.0.7']
+
+
+setup(name="gbp",
+ version=fetch_version(),
+ author=u'Guido Günther',
+ author_email='agx@sigxcpu.org',
+ url='https://honk.sigxcpu.org/piki/projects/git-buildpackage/',
+ description='Suite to help with Debian packages in Git repositories',
+ license='GPLv2+',
+ long_description=readme(),
+ classifiers=[
'Environment :: Console',
'Programming Language :: Python :: 2',
'Topic :: Software Development :: Version Control :: Git',
'Operating System :: POSIX :: Linux',
],
- scripts = ['bin/git-pbuilder',
- 'bin/gbp-builder-mock'],
- packages = find_packages(exclude=['tests', 'tests.*']),
- data_files = [("/etc/git-buildpackage/", ["gbp.conf"]),],
- requires = ["six"],
- setup_requires=['nose>=0.11.1', 'coverage>=2.85', 'nosexcover>=1.0.7'] if \
- os.getenv('WITHOUT_NOSETESTS') is None else [],
- entry_points = {
- 'console_scripts': [ 'gbp = gbp.scripts.supercommand:supercommand' ],
+ scripts=['bin/git-pbuilder',
+ 'bin/gbp-builder-mock'],
+ packages=find_packages(exclude=['tests', 'tests.*']),
+ data_files=[("/etc/git-buildpackage/", ["gbp.conf"]), ],
+ requires=["six"],
+ setup_requires=setup_requires(),
+ entry_points={
+ 'console_scripts': ['gbp=gbp.scripts.supercommand:supercommand'],
},
-)
+ )
diff --git a/tests/01_test_help.py b/tests/01_test_help.py
index b0bb9a1..8cfa3d2 100644
--- a/tests/01_test_help.py
+++ b/tests/01_test_help.py
@@ -2,36 +2,34 @@
"""Check if --help works"""
-from . import context
+from . import context # noqa: F401
-import unittest
+from .testutils.data import TestCaseWithData
-class TestHelp(unittest.TestCase):
+
+class TestHelp(TestCaseWithData):
"""Test help output of gbp commands"""
- def testHelp(self):
- for script in ['buildpackage',
- 'clone',
- 'config',
- 'create_remote_repo',
- 'dch',
- 'import_orig',
- 'import_dsc',
- 'pull',
- 'pq']:
- module = 'gbp.scripts.%s' % script
- m = __import__(module, globals(), locals(), ['main'], 0)
- self.assertRaises(SystemExit,
- m.main,
- ['doesnotmatter', '--help'])
-
- """Test help output of RPM-specific commands"""
- def testHelpRpm(self):
- for script in ['import_srpm']:
- module = 'gbp.scripts.%s' % script
- m = __import__(module, globals(), locals(), ['main'], 0)
- self.assertRaises(SystemExit,
- m.main,
- ['doesnotmatter', '--help'])
+ deb_cmds = ['buildpackage',
+ 'config',
+ 'create_remote_repo',
+ 'dch',
+ 'import_orig',
+ 'import_dsc',
+ 'pull',
+ 'pq']
+
+ rpm_cmds = ['buildpackage_rpm',
+ 'import_srpm',
+ 'rpm_ch',
+ 'pq_rpm']
+
+ @TestCaseWithData.feed(deb_cmds + rpm_cmds)
+ def testHelp(self, script):
+ module = 'gbp.scripts.%s' % script
+ m = __import__(module, globals(), locals(), ['main'], 0)
+ self.assertRaises(SystemExit,
+ m.main,
+ ['doesnotmatter', '--help'])
# vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·:
diff --git a/tests/02_test_upstream_source_tar_unpack.py b/tests/02_test_upstream_source_tar_unpack.py
index 02b5043..ec4983d 100644
--- a/tests/02_test_upstream_source_tar_unpack.py
+++ b/tests/02_test_upstream_source_tar_unpack.py
@@ -12,6 +12,7 @@ import six
import gbp.pkg
+
class TestUnpack(unittest.TestCase):
"""Make sure we unpack gzip and bzip2 archives correctly"""
archive_prefix = "archive"
@@ -26,10 +27,10 @@ class TestUnpack(unittest.TestCase):
assert os.path.exists(target), "%s does not exist" % target
def _create_archive(self, comp):
- filelist = [ 'README', 'setup.py' ]
+ filelist = ['README.md', 'setup.py']
name = "%s_0.1.tar.%s" % (self.archive_prefix, comp)
- t = tarfile.open(name= name, mode='w:%s' % comp)
+ t = tarfile.open(name=name, mode='w:%s' % comp)
for f in filelist:
t.add(os.path.join(self.top, f),
os.path.join(self._unpack_dir(comp), f))
@@ -41,7 +42,7 @@ class TestUnpack(unittest.TestCase):
self.top = context.projectdir
context.chdir(self.dir)
self.archives = {}
- for ext in [ "gz", "bz2" ]:
+ for ext in ["gz", "bz2"]:
self.archives[ext] = self._create_archive(ext)
def tearDown(self):
@@ -50,12 +51,12 @@ class TestUnpack(unittest.TestCase):
def test_upstream_source_type(self):
for (comp, archive) in six.iteritems(self.archives):
source = gbp.pkg.UpstreamSource(archive[0])
- assert source.is_orig() == True
- assert source.is_dir() == False
- assert source.unpacked == None
+ assert source.is_orig() is True
+ assert source.is_dir() is False
+ assert source.unpacked is None
source.unpack(".")
- assert source.is_orig() == True
- assert source.is_dir() == False
+ assert source.is_orig() is True
+ assert source.is_dir() is False
assert type(source.unpacked) == str
def test_upstream_source_unpack(self):
@@ -71,7 +72,7 @@ class TestUnpack(unittest.TestCase):
self._check_files(archive[1], comp)
def test_upstream_source_unpack_filtered(self):
- exclude = "README"
+ exclude = "README.md"
for (comp, archive) in six.iteritems(self.archives):
source = gbp.pkg.UpstreamSource(archive[0])
diff --git a/tests/03_test_dch_guess_version.py b/tests/03_test_dch_guess_version.py
index 49b0e41..bd4389f 100644
--- a/tests/03_test_dch_guess_version.py
+++ b/tests/03_test_dch_guess_version.py
@@ -2,11 +2,12 @@
"""Test L{Changelog}'s guess_version_from_upstream"""
-from . import context
+from . import context # noqa: F401
from . import testutils
from gbp.scripts import dch
+
class TestGuessVersionFromUpstream(testutils.DebianGitTestRepo):
"""Test guess_version_from_upstream"""
@@ -17,7 +18,6 @@ class TestGuessVersionFromUpstream(testutils.DebianGitTestRepo):
uversion = '1.1'
upstream_branch = 'upstream'
-
self.add_file('doesnot', 'matter')
self.repo.create_branch('upstream')
tag = self.repo.version_to_tag(tagformat, uversion)
diff --git a/tests/04_test_submodules.py b/tests/04_test_submodules.py
index 34dc991..5cd8610 100644
--- a/tests/04_test_submodules.py
+++ b/tests/04_test_submodules.py
@@ -27,6 +27,7 @@ TMPDIR = None
TESTFILE_NAME = "testfile"
TESTDIR_NAME = "testdir"
+
class Submodule(object):
"""Class representing remote repo for Git submodule"""
def __init__(self, name, tmpdir):
@@ -53,6 +54,7 @@ def teardown():
"""Test module teardown"""
context.teardown()
+
def test_empty_has_submodules():
"""Test empty repo for submodules"""
ok_(not REPO.has_submodules())
@@ -87,6 +89,7 @@ def test_add_submodule():
REPO.add_submodule(SUBMODULES[0].dir)
REPO.commit_all(msg='Added submodule %s' % SUBMODULES[0].dir)
+
def test_has_submodules():
"""Check for submodules"""
ok_(REPO.has_submodules())
@@ -97,8 +100,8 @@ def test_has_submodules():
def test_get_submodules():
"""Check for submodules list of (name, hash)"""
modules = REPO.get_submodules("master")[0]
- eq_(modules[0] , 'test_submodule')
- eq_(len(modules[1]) , 40)
+ eq_(modules[0], 'test_submodule')
+ eq_(len(modules[1]), 40)
def test_dump_tree():
@@ -122,14 +125,15 @@ def test_dump_tree():
def test_create_tarballs():
"""Create an upstream tarball"""
# Tarball with submodules
- changelog = { "Source": "test", "Upstream-Version": "0.1" }
+ changelog = {"Source": "test", "Upstream-Version": "0.1"}
ok_(buildpackage.git_archive(REPO, changelog, str(TMPDIR), "HEAD", "bzip2",
"9", True))
# Tarball without submodules
- changelog = { "Source": "test", "Upstream-Version": "0.2" }
+ changelog = {"Source": "test", "Upstream-Version": "0.2"}
ok_(buildpackage.git_archive(REPO, changelog, str(TMPDIR), "HEAD", "bzip2",
"9", False))
+
def test_create_zip_archives():
"""Create an upstream zip archive"""
git_archive_submodules(REPO, 'HEAD', 'with-submodules.zip', 'test',
@@ -143,30 +147,33 @@ def test_create_zip_archives():
contents = ls_zip('without-submodules.zip')
ok_('test/test_submodule/testfile' not in contents)
+
def test_check_tarfiles():
"""Check the contents of the created tarfile"""
# Check tarball with submodules
tarobj = tarfile.open(TMPDIR.join("test_0.1.orig.tar.bz2"), 'r:*')
files = tarobj.getmembers()
- ok_("test-0.1/.gitmodules" in [ f.name for f in files ])
- eq_(len(files) , 10)
+ ok_("test-0.1/.gitmodules" in [f.name for f in files])
+ eq_(len(files), 10)
# Check tarball without submodules
tarobj = tarfile.open(TMPDIR.join("test_0.2.orig.tar.bz2"), 'r:*')
files = tarobj.getmembers()
- ok_(("test-0.2/%s" % TESTFILE_NAME) in [ f.name for f in files ])
- eq_(len(files) , 6)
+ ok_(("test-0.2/%s" % TESTFILE_NAME) in [f.name for f in files])
+ eq_(len(files), 6)
+
def test_add_whitespace_submodule():
"""Add a second submodule with name containing whitespace"""
REPO.add_submodule(SUBMODULES[1].dir)
REPO.commit_all(msg='Added submodule %s' % SUBMODULES[0].dir)
+
def test_get_more_submodules():
"""Check for submodules list of (name, hash)"""
module = REPO.get_submodules("master")
eq_(len(module), len(SUBMODULE_NAMES))
for module in REPO.get_submodules("master"):
- eq_(len(module[1]) , 40)
+ eq_(len(module[1]), 40)
ok_(os.path.basename(module[0]) in SUBMODULE_NAMES)
diff --git a/tests/05_test_detection.py b/tests/05_test_detection.py
index 9b902e1..2355f1f 100644
--- a/tests/05_test_detection.py
+++ b/tests/05_test_detection.py
@@ -10,6 +10,7 @@ from gbp.scripts import buildpackage
from gbp.deb import (DebianPkgPolicy, orig_file)
from gbp.errors import GbpError
+
class MockGitRepository:
def __init__(self, with_branch=False, subject=None):
self.with_branch = with_branch
@@ -27,6 +28,7 @@ class MockGitRepository:
def get_commit_info(self, commit):
return {'subject': self.subject}
+
class TestDetection(unittest.TestCase):
def setUp(self):
self.tmpdir = context.new_tmpdir(__name__)
diff --git a/tests/06_test_upstream_source.py b/tests/06_test_upstream_source.py
index 3a6f92e..18f6fbd 100644
--- a/tests/06_test_upstream_source.py
+++ b/tests/06_test_upstream_source.py
@@ -12,6 +12,7 @@ import zipfile
from gbp.pkg import UpstreamSource
+
class TestDir(unittest.TestCase):
def setUp(self):
self.tmpdir = context.new_tmpdir(__name__)
@@ -29,6 +30,7 @@ class TestDir(unittest.TestCase):
def tearDown(self):
context.teardown()
+
class TestTar(unittest.TestCase):
"""Test if packing tar archives works"""
def _check_tar(self, us, positive=[], negative=[]):
@@ -92,4 +94,3 @@ class TestZip(unittest.TestCase):
self.assertEqual(source.guess_version(), ('gbp', '0.1'))
source.unpack(str(self.tmpdir))
self.assertNotEqual(source.unpacked, None)
-
diff --git a/tests/07_test_fastimport.py b/tests/07_test_fastimport.py
index dcd63f9..2c52a81 100644
--- a/tests/07_test_fastimport.py
+++ b/tests/07_test_fastimport.py
@@ -14,21 +14,25 @@ fastimport = None
tf_name = 'testfile'
tl_name = 'a_testlink'
+
def setup():
global repo
tmpdir = context.new_tmpdir(__name__)
repo = gbp.git.GitRepository.create(tmpdir.join('test_repo'))
+
def teardown():
context.teardown()
+
def test_init_fastimport():
"""Create a fastimport object"""
global fastimport
fastimport = gbp.git.FastImport(repo)
assert fastimport, "Failed to init FastImport"
+
def test_add_file():
"""Add a file via fastimport"""
author = repo.get_author_info()
@@ -39,15 +43,18 @@ def test_add_file():
open(testfile),
os.path.getsize(testfile))
+
def test_add_symlink():
"""Add a symbolic link via fastimport"""
author = repo.get_author_info()
fastimport.start_commit('master', author, "a 2nd commit")
fastimport.add_symlink(tl_name, tf_name)
+
def test_close():
fastimport.close()
+
def test_result():
repo.force_head('master', hard=True)
@@ -57,4 +64,3 @@ def test_result():
assert os.path.exists(testfile), "%s doesn't exist" % testfile
assert os.path.lexists(testlink), "%s doesn't exist" % testlink
assert os.readlink(testlink) == tf_name
-
diff --git a/tests/08_test_patch.py b/tests/08_test_patch.py
index df1d43d..bc9a507 100644
--- a/tests/08_test_patch.py
+++ b/tests/08_test_patch.py
@@ -2,7 +2,7 @@
"""Test L{Patch} class"""
-from . import context
+from . import context # noqa: 401
import os
import unittest
diff --git a/tests/09_test_write_tree.py b/tests/09_test_write_tree.py
index bad362c..0ec0ccb 100644
--- a/tests/09_test_write_tree.py
+++ b/tests/09_test_write_tree.py
@@ -4,7 +4,7 @@
from __future__ import print_function
-from . import context
+from . import context # noqa: 401
from . import testutils
import os
@@ -25,8 +25,8 @@ class TestWriteTree(testutils.DebianGitTestRepo):
paths.append(path)
return paths
- def test_write_tree_index_nonexistant(self):
- """Write out index file to nonexistant dir"""
+ def test_write_tree_index_nonexistent(self):
+ """Write out index file to non-existent dir"""
paths = self._write_testtree()
self.repo.add_files(paths)
self.assertRaises(gbp.git.GitRepositoryError,
@@ -62,7 +62,7 @@ class TestWriteTree(testutils.DebianGitTestRepo):
self.assertEqual(len(commit), 40)
# commit the same tree again using the previous commit as parent
self.repo.commit_tree(sha1, "second commit", parents=[commit])
- # commit the same tree again using a non existant parent
+ # commit the same tree again using a non-existent parent
self.assertRaises(gbp.errors.GbpError,
self.repo.commit_tree,
sha1,
diff --git a/tests/10_test_get_upstream_tree.py b/tests/10_test_get_upstream_tree.py
index 08a0f05..bf5e700 100644
--- a/tests/10_test_get_upstream_tree.py
+++ b/tests/10_test_get_upstream_tree.py
@@ -2,12 +2,13 @@
"""Test L{buildpackage}'s get_upstream_tree method"""
-from . import context
+from . import context # noqa: 401
from . import testutils
import gbp.errors
import gbp.scripts.buildpackage as buildpackage
+
class MockOptions(object):
def __init__(self,
upstream_branch=None,
@@ -17,6 +18,7 @@ class MockOptions(object):
self.upstream_tree = upstream_tree
self.upstream_tag = upstream_tag
+
class TestGetUpstreamTree(testutils.DebianGitTestRepo):
def test_valid_upstream_branch(self):
"""Get upstream tree from a valid upstream branch"""
@@ -60,7 +62,7 @@ class TestGetUpstreamTree(testutils.DebianGitTestRepo):
"""Get upstream tree from a valid tag"""
self.add_file('foo')
self.repo.rev_parse('master')
- cp = { 'Upstream-Version': '1.0~rc3' }
+ cp = {'Upstream-Version': '1.0~rc3'}
self.repo.create_tag('upstream/1.0_rc3')
options = MockOptions(upstream_tree="TAG",
upstream_tag="upstream/%(version)s")
@@ -70,7 +72,7 @@ class TestGetUpstreamTree(testutils.DebianGitTestRepo):
def test_invalid_tag(self):
"""Getting upstream tree from an invalid tag must fail"""
self.add_file('foo')
- cp = { 'Upstream-Version': '1.0~rc3' }
+ cp = {'Upstream-Version': '1.0~rc3'}
options = MockOptions(upstream_tree="TAG",
upstream_tag="upstream/%(version)s")
self.assertRaises(gbp.errors.GbpError,
diff --git a/tests/11_test_dch_main.py b/tests/11_test_dch_main.py
index 7e2a197..e9b6400 100644
--- a/tests/11_test_dch_main.py
+++ b/tests/11_test_dch_main.py
@@ -50,7 +50,6 @@ cl_debian = """test-package (0.9-1) unstable; urgency=%s
class TestScriptDch(DebianGitTestRepo):
"""Test git-dch"""
-
def setUp(self):
DebianGitTestRepo.setUp(self)
self.add_file("foo", "bar")
@@ -70,11 +69,9 @@ class TestScriptDch(DebianGitTestRepo):
"--upstream-branch=upstream", "--id-length=0", "--spawn-editor=/bin/true"]
self.repo.create_tag(deb_tag, msg=deb_tag_msg, commit="HEAD~1")
-
def tearDown(self):
DebianGitTestRepo.tearDown(self)
-
def run_dch(self, dch_options=None):
# Take care to copy the list
options = self.options[:]
@@ -84,14 +81,12 @@ class TestScriptDch(DebianGitTestRepo):
self.assertEqual(ret, 0)
return open("debian/changelog").readlines()
-
def test_dch_main_new_upstream_version(self):
"""Test dch.py like gbp dch script does: new upstream version"""
lines = self.run_dch()
self.assertEqual("test-package (1.0-1) UNRELEASED; urgency=%s\n" % default_urgency, lines[0])
self.assertIn(""" * added debian/control\n""", lines)
-
def test_dch_main_new_upstream_version_with_release(self):
"""Test dch.py like gbp dch script does: new upstream version - release"""
options = ["--release"]
@@ -99,7 +94,6 @@ class TestScriptDch(DebianGitTestRepo):
self.assertEqual("test-package (1.0-1) %s; urgency=%s\n" % (os_codename, default_urgency), lines[0])
self.assertIn(""" * added debian/control\n""", lines)
-
def test_dch_main_new_upstream_version_with_auto(self):
"""Test dch.py like gbp dch script does: new upstream version - guess last commit"""
options = ["--auto"]
@@ -107,7 +101,6 @@ class TestScriptDch(DebianGitTestRepo):
self.assertEqual("test-package (1.0-1) UNRELEASED; urgency=%s\n" % default_urgency, lines[0])
self.assertIn(""" * added debian/control\n""", lines)
-
def test_dch_main_new_upstream_version_with_snapshot(self):
"""Test dch.py like gbp dch script does: new upstream version - snapshot mode"""
options = ["--snapshot"]
@@ -118,7 +111,6 @@ class TestScriptDch(DebianGitTestRepo):
self.assertIsNotNone(re.search(snap_mark + header.group(1), lines[2]))
self.assertIn(""" * added debian/control\n""", lines)
-
def test_dch_main_new_upstream_version_with_2_snapshots_auto(self):
"""Test dch.py like gbp dch script does: new upstream version - two snapshots - auto"""
options = ["--snapshot"]
@@ -141,7 +133,6 @@ class TestScriptDch(DebianGitTestRepo):
self.assertIn(""" * added debian/control\n""", lines)
self.assertIn(""" * added debian/compat\n""", lines)
-
def test_dch_main_new_upstream_version_with_2_snapshots_commit_auto(self):
"""Test dch.py like gbp dch script does: new upstream version - two committed snapshots - auto"""
options = ["--commit"]
@@ -163,12 +154,11 @@ class TestScriptDch(DebianGitTestRepo):
self.assertIsNotNone(re.search(snap_mark + header2.group(1), lines[2]))
self.assertIn(""" * added debian/control\n""", lines)
self.assertIn(""" * added debian/compat\n""", lines)
- # First snapshot entry must have disapear
+ # First snapshot entry must have disappeared
self.assertNotIn(header1.group(0) + "\n", lines)
# But its changelog must be included in the new one
self.assertIn(""" * TEST-COMMITTED-SNAPSHOT\n""", lines)
-
def test_dch_main_new_upstream_version_with_auto_release(self):
"""Test dch.py like gbp dch script does: new upstream version - auto - release"""
options = ["--auto", "--release"]
@@ -176,10 +166,9 @@ class TestScriptDch(DebianGitTestRepo):
self.assertEqual("test-package (1.0-1) %s; urgency=%s\n" % (os_codename, default_urgency), lines[0])
self.assertIn(""" * added debian/control\n""", lines)
-
def test_dch_main_new_upstream_version_with_auto_snapshot(self):
"""Test dch.py like gbp dch script does: new upstream version - auto - snapshot mode"""
- options = [ "--auto", "--snapshot" ]
+ options = ["--auto", "--snapshot"]
options.append("--snapshot")
lines = self.run_dch(options)
header = re.search(snap_header_1, lines[0])
@@ -188,7 +177,6 @@ class TestScriptDch(DebianGitTestRepo):
self.assertIsNotNone(re.search(snap_mark + header.group(1), lines[2]))
self.assertIn(""" * added debian/control\n""", lines)
-
def test_dch_main_new_upstream_version_with_snapshot_release(self):
"""Test dch.py like gbp dch script does: new upstream version - snapshot - release"""
options = ["--snapshot", "--release"]
@@ -196,7 +184,6 @@ class TestScriptDch(DebianGitTestRepo):
self.assertRaises(SystemExit, self.run_dch, options)
self.assertTrue("'--snapshot' and '--release' are incompatible options" in c.output())
-
def test_dch_main_new_upstream_version_with_distribution(self):
"""Test dch.py like gbp dch script does: new upstream version - set distribution"""
options = ["--distribution=testing", "--force-distribution"]
@@ -204,7 +191,6 @@ class TestScriptDch(DebianGitTestRepo):
self.assertEqual("test-package (1.0-1) testing; urgency=%s\n" % default_urgency, lines[0])
self.assertIn(""" * added debian/control\n""", lines)
-
def test_dch_main_new_upstream_version_with_release_distribution(self):
"""Test dch.py like gbp dch script does: new upstream version - release - set distribution"""
options = ["--release", "--distribution=testing", "--force-distribution"]
@@ -212,7 +198,6 @@ class TestScriptDch(DebianGitTestRepo):
self.assertEqual("test-package (1.0-1) testing; urgency=%s\n" % default_urgency, lines[0])
self.assertIn(""" * added debian/control\n""", lines)
-
def test_dch_main_new_upstream_version_with_snapshot_distribution(self):
"""Test dch.py like gbp dch script does: new upstream version - snapshot mode - do not set distribution"""
options = ["--snapshot", "--distribution=testing"]
@@ -223,7 +208,6 @@ class TestScriptDch(DebianGitTestRepo):
self.assertIsNotNone(re.search(snap_mark + header.group(1), lines[2]))
self.assertIn(""" * added debian/control\n""", lines)
-
def test_dch_main_new_upstream_version_with_2_snapshots_auto_distribution(self):
"""Test dch.py like gbp dch script does: new upstream version - two snapshots - do not set distribution"""
options = ["--snapshot", "--distribution=testing"]
@@ -249,7 +233,6 @@ class TestScriptDch(DebianGitTestRepo):
# we do not commit
self.assertNotIn(""" * TEST-COMMITTED-SNAPSHOT\n""", lines)
-
def test_dch_main_new_upstream_version_with_2_snapshots_commit_auto_distribution(self):
"""Test dch.py like gbp dch script does: new upstream version - two committed snapshots - do not set distribution"""
options = ["--commit"]
@@ -272,12 +255,11 @@ class TestScriptDch(DebianGitTestRepo):
self.assertIsNotNone(re.search(snap_mark + header2.group(1), lines[2]))
self.assertIn(""" * added debian/control\n""", lines)
self.assertIn(""" * added debian/compat\n""", lines)
- # First snapshot entry must have disapear
+ # First snapshot entry must have disappeared
self.assertNotIn(header1.group(0) + "\n", lines)
# But its changelog must be included in the new one
self.assertIn(""" * TEST-COMMITTED-SNAPSHOT\n""", lines)
-
def test_dch_main_new_upstream_version_with_urgency(self):
"""Test dch.py like gbp dch script does: new upstream version - set urgency"""
options = ["--urgency=emergency"]
@@ -285,7 +267,6 @@ class TestScriptDch(DebianGitTestRepo):
self.assertEqual("test-package (1.0-1) UNRELEASED; urgency=emergency\n", lines[0])
self.assertIn(""" * added debian/control\n""", lines)
-
def test_dch_main_new_upstream_version_with_release_urgency(self):
"""Test dch.py like gbp dch script does: new upstream version - release - set urgency"""
options = ["--release", "--urgency=emergency"]
@@ -293,10 +274,9 @@ class TestScriptDch(DebianGitTestRepo):
self.assertEqual("test-package (1.0-1) %s; urgency=emergency\n" % os_codename, lines[0])
self.assertIn(""" * added debian/control\n""", lines)
-
def test_dch_main_new_upstream_version_with_snapshot_urgency(self):
"""Test dch.py like gbp dch script does: new upstream version - snapshot mode - set urgency"""
- options = ["--snapshot", "--urgency=emergency"]
+ options = ["--snapshot", "--urgency=emergency"]
lines = self.run_dch(options)
header = re.search(snap_header_1, lines[0])
self.assertIsNotNone(header)
@@ -304,7 +284,6 @@ class TestScriptDch(DebianGitTestRepo):
self.assertIsNotNone(re.search(snap_mark + header.group(1), lines[2]))
self.assertIn(""" * added debian/control\n""", lines)
-
def test_dch_main_increment_debian_version(self):
"""Test dch.py like gbp dch script does: increment debian version"""
self.repo.delete_tag("debian/0.9-1")
@@ -314,7 +293,6 @@ class TestScriptDch(DebianGitTestRepo):
self.assertEqual("test-package (%s) UNRELEASED; urgency=%s\n" % (new_version_0_9, default_urgency), lines[0])
self.assertIn(""" * added debian/control\n""", lines)
-
def test_dch_main_increment_debian_version_with_release(self):
"""Test dch.py like gbp dch script does: increment debian version - release"""
self.repo.delete_tag("upstream/1.0")
@@ -323,7 +301,6 @@ class TestScriptDch(DebianGitTestRepo):
self.assertEqual("test-package (%s) %s; urgency=%s\n" % (new_version_0_9, os_codename, default_urgency), lines[0])
self.assertIn(""" * added debian/control\n""", lines)
-
def test_dch_main_increment_debian_version_with_auto(self):
"""Test dch.py like gbp dch script does: increment debian version - guess last commit"""
self.repo.delete_tag("upstream/1.0")
@@ -332,7 +309,6 @@ class TestScriptDch(DebianGitTestRepo):
self.assertEqual("test-package (%s) UNRELEASED; urgency=%s\n" % (new_version_0_9, default_urgency), lines[0])
self.assertIn(""" * added debian/control\n""", lines)
-
def test_dch_main_increment_debian_version_with_snapshot(self):
"""Test dch.py like gbp dch script does: increment debian version - snapshot mode"""
self.repo.delete_tag("upstream/1.0")
@@ -344,20 +320,18 @@ class TestScriptDch(DebianGitTestRepo):
self.assertIsNotNone(re.search(snap_mark + header.group(1), lines[2]))
self.assertIn(""" * added debian/control\n""", lines)
-
def test_dch_main_increment_debian_version_with_auto_release(self):
"""Test dch.py like gbp dch script does: increment debian version - auto - release"""
self.repo.delete_tag("upstream/1.0")
- options = ["--auto", "--release"]
+ options = ["--auto", "--release"]
lines = self.run_dch(options)
self.assertEqual("test-package (%s) %s; urgency=%s\n" % (new_version_0_9, os_codename, default_urgency), lines[0])
self.assertIn(""" * added debian/control\n""", lines)
-
def test_dch_main_increment_debian_version_with_auto_snapshot(self):
"""Test dch.py like gbp dch script does: increment debian version - auto - snapshot mode"""
self.repo.delete_tag("upstream/1.0")
- options = ["--auto", "--snapshot"]
+ options = ["--auto", "--snapshot"]
lines = self.run_dch(options)
header = re.search(snap_header_0_9, lines[0])
self.assertIsNotNone(header)
@@ -365,6 +339,21 @@ class TestScriptDch(DebianGitTestRepo):
self.assertIsNotNone(re.search(snap_mark + header.group(1), lines[2]))
self.assertIn(""" * added debian/control\n""", lines)
+ def test_dch_main_unreleased_debian_version_with_snapshot(self):
+ """Test dch.py like gbp dch script does: snapshot mode with unreleased debian version"""
+ new_version_1_0 = '1.0-1'
+ options = ["--commit"]
+ options.append("--commit-msg=UNRELEASED-version")
+ lines = self.run_dch()
+ header = re.search(r"\(%s\) UNRELEASED" % new_version_1_0, lines[0])
+ self.assertIsNotNone(header)
+ options = ["--snapshot", "--auto"]
+ lines = self.run_dch(options)
+ header = re.search(snap_header_1, lines[0])
+ self.assertIsNotNone(header)
+ self.assertEqual(header.lastindex, 1)
+ self.assertIsNotNone(re.search(snap_mark + header.group(1), lines[2]))
+ self.assertIn(""" * added debian/control\n""", lines)
def test_dch_main_closes_default(self):
options = ["--meta"]
@@ -374,7 +363,6 @@ class TestScriptDch(DebianGitTestRepo):
self.assertIn(""" * test debian closes commit (Closes: #123456)\n""",
lines)
-
def test_dch_main_closes_non_debian_bug_numbers(self):
self.add_file("closes", "test file",
msg="""test non-debian closes 1\n\nCloses: EX-123""")
diff --git a/tests/12_test_deb.py b/tests/12_test_deb.py
index 50955bd..b62435d 100644
--- a/tests/12_test_deb.py
+++ b/tests/12_test_deb.py
@@ -2,16 +2,19 @@
"""Test L{gbp.deb}"""
-from . import context
+from . import context # noqa: 401
-import os, tempfile, unittest
+import os
+import tempfile
+import unittest
import gbp.deb
from gbp.deb.dscfile import DscFile
from gbp.command_wrappers import CommandExecFailed
-class TestDscFile(unittest.TestCase):
+
+class Test30DscFile(unittest.TestCase):
"""Test L{gbp.deb.DscFile}"""
content = """Format: 3.0 (quilt)
@@ -28,24 +31,24 @@ Vcs-Browser: http://git.debian.org/?p=pkg-libvirt/libvirt.git
Vcs-Git: git://git.debian.org/git/pkg-libvirt/libvirt.git
Build-Depends: cdbs (>= 0.4.90~), debhelper (>= 7), libxml2-dev, libncurses5-dev, libreadline-dev, zlib1g-dev, libgcrypt11-dev, libgnutls-dev, python-all-dev (>= 2.6.6-3~), libavahi-client-dev, libsasl2-dev, libxen-dev [i386 amd64], lvm2 [linux-any], open-iscsi [linux-any], libparted0-dev (>= 2.2), parted (>= 2.2), libdevmapper-dev [linux-any], uuid-dev, libudev-dev [linux-any], libhal-dev [!linux-any], libpciaccess-dev, module-init-tools [linux-any], policykit-1, libcap-ng-dev [linux-any], libnl-dev [linux-any], libyajl-dev, libpcap0.8-dev, libnuma-dev [amd64 i386 ia64 mips mipsel powerpc], radvd [linux-any], libnetcf-dev [linux-any], dwarves, libxml2-utils, dnsmasq-base, openssh-client, netcat-openbsd
Build-Conflicts: dpkg-dev (= 1.15.3)
-Package-List:
+Package-List:
libvirt-bin deb admin optional
libvirt-dev deb libdevel optional
libvirt-doc deb doc optional
libvirt0 deb libs optional
libvirt0-dbg deb debug extra
python-libvirt deb python optional
-Checksums-Sha1:
+Checksums-Sha1:
3743dc4f3e58d5912a98f568c3e854d97d81f216 20054618 libvirt_0.9.12.orig.tar.gz
3743dc4f3e58d5912a98f568c3e854d97d81f123 20054618 libvirt_0.9.12.orig-foo.tar.gz
3743dc4f3e58d5912a98f568c3e854d97d81f123 20054618 libvirt_0.9.12.orig-bar.tar.gz
a7ffa64c18a5ee448c98b1dc894a0a27e1670357 35935 libvirt_0.9.12-4.debian.tar.gz
-Checksums-Sha256:
+Checksums-Sha256:
298ffc7f2a6d6e78aae46f11a0980f4bc17fa2928f5de6cd9e8abaf5990336e7 20054618 libvirt_0.9.12.orig.tar.gz
298ffc7f2a6d6e78aae46f11a0980f4bc17fa2928f5de6cd9e8abaf599033123 20054618 libvirt_0.9.12.orig-foo.tar.gz
298ffc7f2a6d6e78aae46f11a0980f4bc17fa2928f5de6cd9e8abaf599033123 20054618 libvirt_0.9.12.orig-bar.tar.gz
e75110c493995ba5366e751f20f3842f30674c3918357fa6eb83175d0afbec31 35935 libvirt_0.9.12-4.debian.tar.gz
-Files:
+Files:
5e842bc55733ceba60c64767580ff3e4 20054618 libvirt_0.9.12.orig.tar.gz
5e842bc55733ceba60c64767580ff123 20054618 libvirt_0.9.12.orig-foo.tar.gz
5e842bc55733ceba60c64767580ff123 20054618 libvirt_0.9.12.orig-bar.tar.gz
@@ -72,6 +75,49 @@ Files:
'libvirt_0.9.12.orig-%s.tar.gz' % s)
+class Test10DscNonNativeFile(unittest.TestCase):
+ """Test L{gbp.deb.DscFile}"""
+
+ content = """Format: 1.0
+Source: latencytop
+Binary: latencytop
+Architecture: any
+Version: 0.5
+Maintainer: Giacomo Catenazzi <cate@debian.org>
+Homepage: http://www.latencytop.org/
+Standards-Version: 3.8.2
+Build-Depends: cdbs, debhelper (>= 5), pkg-config, libncursesw5-dev, libglib2.0-dev, libgtk2.0-dev
+Package-List:
+ latencytop deb utils extra arch=any
+Checksums-Sha1:
+ cfd8a83fa40e630cf680d96a186ff4fdbf6f22c8 25374 latencytop_0.5.orig.tar.gz
+ 1fa907254c61c73679fd173c828327e9a2273c31 1978 latencytop_0.5.diff.gz
+Checksums-Sha256:
+ 9e7f72fbea7bd918e71212a1eabaad8488d2c602205d2e3c95d62cd57e9203ef 25374 latencytop_0.5.orig.tar.gz
+ 66342c4d55ae31e529bdcdf88d41a7d114b355f438b0d10efb107f3aef1a0db6 1978 latencytop_0.5.diff.gz
+Files:
+ 73bb3371c6ee0b0e68e25289027e865c 25374 latencytop_0.5.orig.tar.gz
+ bf7afb3e0d68b0e33e5abf4f1542af71 1978 latencytop_0.5.diff.gz
+"""
+
+ def setUp(self):
+ with tempfile.NamedTemporaryFile(delete=False) as self.dscfile:
+ self.dscfile.write(self.content)
+
+ def tearDown(self):
+ os.unlink(self.dscfile.name)
+
+ def test_dscfile_parse(self):
+ """Test parsing a a 1.0 non-native dsc file without debian revision"""
+ dsc = DscFile.parse(self.dscfile.name)
+ self.assertEqual(dsc.version, '0.5')
+ self.assertEqual(dsc.native, False)
+ self.assertEqual(os.path.basename(dsc.tgz), 'latencytop_0.5.orig.tar.gz')
+ self.assertEqual(os.path.basename(dsc.deb_tgz), '')
+ self.assertEqual(os.path.basename(dsc.diff), 'latencytop_0.5.diff.gz')
+ self.assertEqual(dsc.additional_tarballs, {}),
+
+
@unittest.skipIf(not os.path.exists('/usr/bin/dpkg'), 'Dpkg not found')
class TestDpkgCompareVersions(unittest.TestCase):
"""Test L{gbp.deb.DpkgCompareVersions}"""
@@ -93,4 +139,3 @@ class TestDpkgCompareVersions(unittest.TestCase):
def testBadVersion(self):
self.assertRaises(CommandExecFailed, self.cmp, '_', '_ _')
-
diff --git a/tests/13_test_gbp_pq.py b/tests/13_test_gbp_pq.py
index 8e8d2c3..be87f90 100644
--- a/tests/13_test_gbp_pq.py
+++ b/tests/13_test_gbp_pq.py
@@ -21,7 +21,9 @@ from . import testutils
import os
import unittest
-from gbp.scripts.pq import generate_patches, export_patches
+from gbp.command_wrappers import GitCommand
+from gbp.scripts.pq import (generate_patches, export_patches,
+ import_quilt_patches, rebase_pq, SERIES_FILE)
import gbp.scripts.common.pq as pq
import gbp.patch_series
@@ -117,7 +119,7 @@ class TestWritePatch(testutils.DebianGitTestRepo):
self.assertEqual(len(changes), len(expected_patches))
d = context.new_tmpdir(__name__)
- expected_paths = [os.path.join(str(d), n) for n in expected_patches ]
+ expected_paths = [os.path.join(str(d), n) for n in expected_patches]
# Commit changes
for c in changes:
@@ -148,14 +150,14 @@ class TestWritePatch(testutils.DebianGitTestRepo):
renumber = False
patch_num_format = '%04d-'
- expected_patches = [ 'gbptest/added-foo.patch',
- 'gbptest/patchname.diff' ]
+ expected_patches = ['gbptest/added-foo.patch',
+ 'gbptest/patchname.diff']
- changes = [ ('foo', 'foo', ("added foo\n\n"
- "Gbp-Pq: Topic gbptest")),
- ('baz', 'baz', ("added bar\n\n"
- "Gbp-Pq: Topic gbptest\n"
- "Gbp-Pq: Name patchname.diff")) ]
+ changes = [('foo', 'foo', ("added foo\n\n"
+ "Gbp-Pq: Topic gbptest")),
+ ('baz', 'baz', ("added bar\n\n"
+ "Gbp-Pq: Topic gbptest\n"
+ "Gbp-Pq: Name patchname.diff"))]
self._test_generate_patches(changes, expected_patches, opts)
@@ -167,14 +169,14 @@ class TestWritePatch(testutils.DebianGitTestRepo):
renumber = True
patch_num_format = '%02d_'
- expected_patches = [ 'gbptest/01_added-foo.patch',
- 'gbptest/02_patchname.diff' ]
+ expected_patches = ['gbptest/01_added-foo.patch',
+ 'gbptest/02_patchname.diff']
- changes = [ ('foo', 'foo', ("added foo\n\n"
- "Gbp-Pq: Topic gbptest")),
- ('baz', 'baz', ("added bar\n\n"
- "Gbp-Pq: Topic gbptest\n"
- "Gbp-Pq: Name 099-patchname.diff")) ]
+ changes = [('foo', 'foo', ("added foo\n\n"
+ "Gbp-Pq: Topic gbptest")),
+ ('baz', 'baz', ("added bar\n\n"
+ "Gbp-Pq: Topic gbptest\n"
+ "Gbp-Pq: Name 099-patchname.diff"))]
self._test_generate_patches(changes, expected_patches, opts)
@@ -186,22 +188,22 @@ class TestWritePatch(testutils.DebianGitTestRepo):
renumber = True
patch_num_format = '%02d_'
- expected_patches = [ 'gbptest/added-foo.patch',
- 'gbptest/patchname.diff',
- 'gbptest/patchname-1.diff',
- 'gbptest/patchname-2.diff' ]
-
- changes = [ ('foo', 'foo', ("added foo\n\n"
- "Gbp-Pq: Topic gbptest")),
- ('baz', 'baz', ("added bar\n\n"
- "Gbp-Pq: Topic gbptest\n"
- "Gbp-Pq: Name 099-patchname.diff")),
- ('qux', 'qux', ("added qux\n\n"
- "Gbp-Pq: Topic gbptest\n"
- "Gbp-Pq: Name 100-patchname.diff")),
- ('norf', 'norf', ("added norf\n\n"
- "Gbp-Pq: Topic gbptest\n"
- "Gbp-Pq: Name 101-patchname.diff")) ]
+ expected_patches = ['gbptest/added-foo.patch',
+ 'gbptest/patchname.diff',
+ 'gbptest/patchname-1.diff',
+ 'gbptest/patchname-2.diff']
+
+ changes = [('foo', 'foo', ("added foo\n\n"
+ "Gbp-Pq: Topic gbptest")),
+ ('baz', 'baz', ("added bar\n\n"
+ "Gbp-Pq: Topic gbptest\n"
+ "Gbp-Pq: Name 099-patchname.diff")),
+ ('qux', 'qux', ("added qux\n\n"
+ "Gbp-Pq: Topic gbptest\n"
+ "Gbp-Pq: Name 100-patchname.diff")),
+ ('norf', 'norf', ("added norf\n\n"
+ "Gbp-Pq: Topic gbptest\n"
+ "Gbp-Pq: Name 101-patchname.diff"))]
self._test_generate_patches(changes, expected_patches, opts)
@@ -210,6 +212,7 @@ class TestExport(testutils.DebianGitTestRepo):
class Options(object):
drop = True
patch_numbers = False
+ pq_from = 'DEBIAN'
def setUp(self):
testutils.DebianGitTestRepo.setUp(self)
@@ -252,5 +255,121 @@ class TestParseGbpCommand(unittest.TestCase):
self.assertEquals(body, 'Foo')
+class TestFromTAG(testutils.DebianGitTestRepo):
+ """Test L{gbp.pq}'s pq-from=TAG"""
+
+ class Options(object):
+ commit = True
+ drop = False
+ force = False
+ meta_closes = 'Closes|LP'
+ meta_closes_bugnum = r'(?:bug|issue)?\#?\s?\d+'
+ patch_num_format = '%04d-'
+ patch_numbers = False
+ pq_from = 'TAG'
+ renumber = False
+ upstream_tag = 'upstream/%(version)s'
+
+ def git_create_empty_branch(self, branch):
+ GitCommand('checkout', cwd=self.repo.path)(['-q', '--orphan', branch])
+ GitCommand('rm', cwd=self.repo.path)(['-rf', '.'])
+
+ def setUp(self):
+ testutils.DebianGitTestRepo.setUp(self)
+ self.add_file('debian/control')
+ self.add_file(
+ 'debian/changelog',
+ 'foo (0.0.1-1) UNRELEASED; urgency=medium\n'
+ '\n'
+ ' * Initial foo\n'
+ '\n'
+ ' -- Mr. T. S. <t@example.com> '
+ 'Thu, 01 Jan 1970 00:00:00 +0000\n'
+ )
+ self.git_create_empty_branch('bar')
+ self.add_file('foo', 'foo')
+ self.repo.create_tag('upstream/0.0.1')
+ self.repo.set_branch('master')
+
+ def test_empty(self):
+
+ import_quilt_patches(self.repo,
+ branch=self.repo.get_branch(),
+ series=SERIES_FILE,
+ tries=1,
+ force=TestFromTAG.Options.force,
+ pq_from=TestFromTAG.Options.pq_from,
+ upstream_tag=TestFromTAG.Options.upstream_tag)
+ diff = self.repo.diff(self.repo.get_branch(), 'upstream/0.0.1')
+ self.assertEqual('', diff)
+ diff = self.repo.diff(self.repo.get_branch(), 'master')
+ self.assertNotEqual('', diff)
+
+ rebase_pq(self.repo,
+ branch=self.repo.get_branch(),
+ pq_from=TestFromTAG.Options.pq_from,
+ upstream_tag=TestFromTAG.Options.upstream_tag)
+ diff = self.repo.diff(self.repo.get_branch(), 'upstream/0.0.1')
+ self.assertEqual('', diff)
+ diff = self.repo.diff(self.repo.get_branch(), 'master')
+ self.assertNotEqual('', diff)
+
+ export_patches(self.repo,
+ branch=self.repo.get_branch(),
+ options=TestFromTAG.Options())
+ diff = self.repo.diff(self.repo.get_branch(), self.repo.head)
+ self.assertEqual('', diff)
+
+ def test_adding_patch(self):
+ import_quilt_patches(self.repo,
+ branch=self.repo.get_branch(),
+ series=SERIES_FILE,
+ tries=1,
+ force=TestFromTAG.Options.force,
+ pq_from=TestFromTAG.Options.pq_from,
+ upstream_tag=TestFromTAG.Options.upstream_tag)
+ self.add_file('bar', 'bar', 'added bar')
+ export_patches(self.repo,
+ branch=self.repo.get_branch(),
+ options=TestFromTAG.Options())
+ self.assertTrue(os.path.exists(os.path.join(self.repo.path,
+ os.path.dirname(SERIES_FILE),
+ 'added-bar.patch')))
+ rebase_pq(self.repo,
+ branch=self.repo.get_branch(),
+ pq_from=TestFromTAG.Options.pq_from,
+ upstream_tag=TestFromTAG.Options.upstream_tag)
+ export_patches(self.repo,
+ branch=self.repo.get_branch(),
+ options=TestFromTAG.Options())
+ self.assertTrue(os.path.exists(os.path.join(self.repo.path,
+ os.path.dirname(SERIES_FILE),
+ 'added-bar.patch')))
+ # New upstream release
+ self.repo.set_branch('bar')
+ GitCommand('cherry-pick', cwd=self.repo.path)(['patch-queue/master'])
+ self.repo.create_tag('upstream/0.0.2')
+ self.repo.set_branch('master')
+ self.add_file(
+ 'debian/changelog',
+ 'foo (0.0.2-1) UNRELEASED; urgency=medium\n'
+ '\n'
+ ' * Initial foo\n'
+ '\n'
+ ' -- Mr. T. S. <t@example.com> '
+ 'Thu, 01 Jan 1970 00:00:00 +0000\n'
+ )
+ rebase_pq(self.repo,
+ branch=self.repo.get_branch(),
+ pq_from=TestFromTAG.Options.pq_from,
+ upstream_tag=TestFromTAG.Options.upstream_tag)
+ export_patches(self.repo,
+ branch=self.repo.get_branch(),
+ options=TestFromTAG.Options())
+ self.assertFalse(os.path.exists(os.path.join(self.repo.path,
+ os.path.dirname(SERIES_FILE),
+ 'added-bar.patch')))
+
+
def _patch_path(name):
return os.path.join(context.projectdir, 'tests/data', name)
diff --git a/tests/14_test_gbp_import_dscs.py b/tests/14_test_gbp_import_dscs.py
index b646f5c..35b2e38 100644
--- a/tests/14_test_gbp_import_dscs.py
+++ b/tests/14_test_gbp_import_dscs.py
@@ -23,6 +23,7 @@ import gbp.scripts.import_dscs as import_dscs
from gbp.errors import GbpError
+
class StubGitImportDsc(object):
"""
A Stub for GitImportDsc.
@@ -40,6 +41,7 @@ class StubGitImportDsc(object):
"""
return 1 if dsc.filename == self.failfile else 0
+
class DscStub(object):
def __init__(self, filename, version):
self.filename = filename
@@ -53,10 +55,12 @@ class DscStub(object):
version = filename[4]
return cls(filename, version)
+
# hook up stubs
import_dscs.GitImportDsc = StubGitImportDsc
import_dscs.DscFile = DscStub
+
class TestImportDscs(testutils.DebianGitTestRepo):
"""Test L{gbp.scripts.import_dscs}'s """
@@ -93,4 +97,3 @@ class TestImportDscs(testutils.DebianGitTestRepo):
gbp.log.err = self.orig_err
testutils.DebianGitTestRepo.tearDown(self)
context.teardown()
-
diff --git a/tests/15_test_DebianSource.py b/tests/15_test_DebianSource.py
index 8cfe585..a9f43d3 100644
--- a/tests/15_test_DebianSource.py
+++ b/tests/15_test_DebianSource.py
@@ -24,6 +24,7 @@ from gbp.deb.source import DebianSource, DebianSourceError
from gbp.deb.format import DebianSourceFormat
from gbp.git.vfs import GitVfs
+
class TestDebianSource(testutils.DebianGitTestRepo):
"""Test L{gbp.deb.source}'s """
diff --git a/tests/16_test_supercommand.py b/tests/16_test_supercommand.py
index 2552977..65f4b10 100644
--- a/tests/16_test_supercommand.py
+++ b/tests/16_test_supercommand.py
@@ -19,6 +19,7 @@ import sys
import unittest
import gbp.scripts.supercommand
+
class TestSuperCommand(unittest.TestCase):
def test_import(self):
@@ -52,4 +53,3 @@ class TestSuperCommand(unittest.TestCase):
def test_missing_arg(self):
self.assertEqual(gbp.scripts.supercommand.supercommand(
['argv0']), 1)
-
diff --git a/tests/17_test_dch_guess_documented_commit.py b/tests/17_test_dch_guess_documented_commit.py
index cda816d..146ede8 100644
--- a/tests/17_test_dch_guess_documented_commit.py
+++ b/tests/17_test_dch_guess_documented_commit.py
@@ -2,11 +2,12 @@
"""Test L{Changelog}'s guess_version_from_upstream"""
-from . import context
+from . import context # noqa: 401
from . import testutils
from gbp.scripts import dch
+
class TestGuessDocumentedCommit(testutils.DebianGitTestRepo):
def setUp(self):
self.version = '1.0-1'
@@ -19,7 +20,7 @@ class TestGuessDocumentedCommit(testutils.DebianGitTestRepo):
Guess the commit to start from from the snapshot banner
"""
cp = testutils.MockedChangeLog(self.version,
- "*** SNAPSHOT build @12345 ***")
+ "*** SNAPSHOT build @12345 ***")
guessed_commit = dch.guess_documented_commit(cp, None, None)
self.assertEqual(guessed_commit, '12345')
diff --git a/tests/18_test_Config.py b/tests/18_test_Config.py
index 306999f..54c00be 100644
--- a/tests/18_test_Config.py
+++ b/tests/18_test_Config.py
@@ -109,3 +109,25 @@ class TestConfigParser(unittest.TestCase, GbpLogTester):
self.assertTrue('upstream-branch' in params)
self.assertTrue('debian-branch' in params)
self.assertTrue('color' in params)
+
+ def test_short_option_with_prefix(self):
+ """Options with short options can't have a prefix"""
+ class TestOptonParser(GbpOptionParser):
+ list_opts = []
+ defaults = {'withshort': 'foo'}
+ short_opts = {'withshort': '-S'}
+ parser = TestOptonParser('cmd', prefix='p')
+ with self.assertRaisesRegexp(ValueError, "Options with prefix cannot have a short option"):
+ parser.add_config_file_option(option_name="withshort", dest="with_short", help="foo")
+
+ def test_short_option(self):
+ class TestOptionParser(GbpOptionParser):
+ list_opts = []
+ defaults = {'withshort': 'foo'}
+ short_opts = {'withshort': '-S'}
+
+ parser = TestOptionParser('cmd')
+ parser.add_config_file_option(option_name="withshort", dest="with_short", help="foo")
+ self.assertItemsEqual(['withshort'], parser.valid_options)
+ self.assertTrue(parser.has_option("--withshort"))
+ self.assertTrue(parser.has_option("-S"))
diff --git a/tests/19_test_gbp_scripts_config.py b/tests/19_test_gbp_scripts_config.py
index ae84561..209fcf5 100644
--- a/tests/19_test_gbp_scripts_config.py
+++ b/tests/19_test_gbp_scripts_config.py
@@ -70,7 +70,7 @@ class TestGbpConfigCommand(unittest.TestCase):
self.assertEqual(ret, 0)
def test_print_cmd_single_value_override(self):
- """Can we fetch a single configuration value that is overriden by config"""
+ """Can we fetch a single configuration value that is overridden by config"""
printstub = self.SingleValuePrintStub()
query = 'config.color-scheme'
ret = gbp.scripts.config.print_cmd_values(query, printstub)
@@ -79,23 +79,23 @@ class TestGbpConfigCommand(unittest.TestCase):
def test_print_cmd_all_values(self):
"""Can we fetch the configuration for all commands"""
- for cmd in [ 'buildpackage',
- 'clone',
- 'config',
- 'create_remote_repo',
- 'dch',
- 'import_dsc',
- 'import_orig',
- 'pq',
- 'pull' ]:
+ for cmd in ['buildpackage',
+ 'clone',
+ 'config',
+ 'create_remote_repo',
+ 'dch',
+ 'import_dsc',
+ 'import_orig',
+ 'pq',
+ 'pull']:
printstub = self.AllValuesPrintStub(cmd)
ret = gbp.scripts.config.print_cmd_values(cmd, printstub)
self.assertIn('%s.color' % cmd, printstub.result.keys())
self.assertEquals(printstub.result['%s.color' % cmd], 'auto')
self.assertEqual(ret, 0)
- def test_unexistent_cmds(self):
- """Unexisting commands should print no values"""
+ def test_nonexistent_cmds(self):
+ """Non-existing commands should print no values"""
for cmd in ["import_dscs", "supercommand"]:
printstub = self.AllValuesPrintStub(cmd)
ret = gbp.scripts.config.print_cmd_values(cmd, printstub)
diff --git a/tests/21_test_command_wrappers.py b/tests/21_test_command_wrappers.py
index 4dfbb48..fd442c8 100644
--- a/tests/21_test_command_wrappers.py
+++ b/tests/21_test_command_wrappers.py
@@ -63,6 +63,21 @@ class TestCommandWrapperFailures(unittest.TestCase, GbpLogTester):
self.assertEqual(self.false.stderr, '')
self.assertEqual(self.false.stdout, 'we have a problem')
+ def test_log_use_err_or_reason_for_error_messge_reason(self):
+ self.false.run_error = "AFAIK {stderr_or_reason}"
+ with self.assertRaises(CommandExecFailed):
+ self.false.__call__()
+ self.log_tester._check_log(0, "gbp:error: AFAIK execution failed: .Errno 2. No such file or directory")
+ self.assertEqual(self.false.retcode, 1)
+
+ @patch_popen(stderr='we have a problem', returncode=1)
+ def test_log_use_err_or_reason_for_error_messge_error(self, create_mock):
+ self.false.run_error = "Erpel {stderr_or_reason}"
+ with self.assertRaises(CommandExecFailed):
+ self.false.__call__()
+ self.log_tester._check_log(0, "gbp:error: Erpel we have a problem")
+ self.assertEqual(self.false.retcode, 1)
+
@patch_popen(returncode=0)
def test_no_log_on_success(self, create_mock):
self.false.__call__()
diff --git a/tests/22_test_gbp_buildpackage.py b/tests/22_test_gbp_buildpackage.py
index 79645ac..35f9570 100644
--- a/tests/22_test_gbp_buildpackage.py
+++ b/tests/22_test_gbp_buildpackage.py
@@ -34,6 +34,14 @@ class TestGbpBuildpackageDep14(DebianGitTestRepo):
patch.assert_called_once_with()
@patch('gbp.deb.get_vendor', return_value='Debian')
+ def test_get_pbuilder_dist_dep14_debian_master(self, patch):
+ branch = 'debian/master'
+ self.repo.create_branch(branch)
+ self.repo.set_branch(branch)
+ self.assertEqual(get_pbuilder_dist(self.options, self.repo), '')
+ patch.assert_called_once_with()
+
+ @patch('gbp.deb.get_vendor', return_value='Debian')
def test_get_pbuilder_dist_dep14_debian_suite(self, patch):
branch = 'debian/squeeze-lts'
self.repo.create_branch(branch)
diff --git a/tests/23_test_dch_extract_bts_cmds.py b/tests/23_test_dch_extract_bts_cmds.py
index 3acff5e..e1fb7e0 100644
--- a/tests/23_test_dch_extract_bts_cmds.py
+++ b/tests/23_test_dch_extract_bts_cmds.py
@@ -14,16 +14,17 @@
# <http://www.gnu.org/licenses/>
"""Test gbp.dch.extract_bts_cmds()"""
-import os
import unittest
from gbp.dch import extract_bts_cmds
+
class OptionsStub:
def __init__(self):
self.meta_closes = "Closes|LP"
self.meta_closes_bugnum = r'(?:bug|issue)?\#?\s?\d+'
+
class TestExtractBTSCmds(unittest.TestCase):
def test_debian_commands(self):
"""Test default BTS command extraction that is applicable to Debian"""
diff --git a/tests/24_test_gbp_import_orig.py b/tests/24_test_gbp_import_orig.py
new file mode 100644
index 0000000..93b656b
--- /dev/null
+++ b/tests/24_test_gbp_import_orig.py
@@ -0,0 +1,31 @@
+# vim: set fileencoding=utf-8 :
+"""Test L{gbp.command_wrappers.Command}'s tarball unpack"""
+
+from gbp.scripts.import_orig import (ImportOrigDebianGitRepository, GbpError)
+from . testutils import DebianGitTestRepo
+
+
+class TestImportOrigGitRepository(DebianGitTestRepo):
+
+ def setUp(self):
+ DebianGitTestRepo.setUp(self, ImportOrigDebianGitRepository)
+
+ def test_empty_rollback(self):
+ self.repo.rollback()
+ self.assertEquals(self.repo.rollback_errors, [])
+
+ def test_rrr_delete_tag(self):
+ self.repo.rrr('doesnotmatter', 'delete', 'tag')
+ self.assertEquals(self.repo.rollbacks, [('doesnotmatter', 'tag', 'delete', None)])
+ self.repo.rollback()
+ self.assertEquals(self.repo.rollback_errors, [])
+
+ def test_rrr_delete_branch(self):
+ self.repo.rrr('doesnotmatter', 'delete', 'branch')
+ self.assertEquals(self.repo.rollbacks, [('doesnotmatter', 'branch', 'delete', None)])
+ self.repo.rollback()
+ self.assertEquals(self.repo.rollback_errors, [])
+
+ def test_rrr_unknown_action(self):
+ with self.assertRaisesRegexp(GbpError, "Unknown action unknown for tag doesnotmatter"):
+ self.repo.rrr('doesnotmatter', 'unknown', 'tag')
diff --git a/tests/25_test_broken_gbp_conf.py b/tests/25_test_broken_gbp_conf.py
new file mode 100644
index 0000000..79d551f
--- /dev/null
+++ b/tests/25_test_broken_gbp_conf.py
@@ -0,0 +1,58 @@
+# vim: set fileencoding=utf-8 :
+
+"""Check if we fail correcdtly on broken gbp.conf"""
+
+from . import context
+
+from . testutils.data import TestCaseWithData
+from . testutils.gbplogtester import GbpLogTester
+
+import os
+import unittest
+
+
+class TestBrokenConfig(TestCaseWithData, GbpLogTester):
+ """Test that broken config gives a sensible error for all commands"""
+
+ cmds = ['buildpackage',
+ 'clone',
+ 'config',
+ 'create_remote_repo',
+ 'dch',
+ 'import_orig',
+ 'import_dsc',
+ 'pull',
+ 'pq',
+ 'import_srpm',
+ 'buildpackage_rpm',
+ 'pq_rpm',
+ 'rpm_ch']
+
+ def __init__(self, methodName='runTest'):
+ unittest.TestCase.__init__(self, methodName)
+ GbpLogTester.__init__(self)
+
+ def setUp(self):
+ tmpdir = str(context.new_tmpdir('bar'))
+ confname = os.path.join(tmpdir, 'gbp.conf')
+ with open(confname, 'w') as f:
+ f.write("this is a broken config\n")
+ os.environ['GBP_CONF_FILES'] = confname
+ self._capture_log(True)
+
+ def tearDown(self):
+ del os.environ['GBP_CONF_FILES']
+
+ @TestCaseWithData.feed(cmds)
+ def testBrokenConf(self, cmd):
+ module = 'gbp.scripts.%s' % cmd
+ try:
+ m = __import__(module, globals(), locals(), ['main'], 0)
+ ret = m.main([cmd, '--help'])
+ self.assertEquals(ret, 3)
+ except Exception as e:
+ self.assertTrue(False, "Caught '%s'" % e)
+ self._check_log(-1, "See 'man gbp.conf' for the format.")
+ self._clear_log()
+
+# vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·:
diff --git a/tests/26_test_dch_extract_thanks.py b/tests/26_test_dch_extract_thanks.py
new file mode 100644
index 0000000..f0da01d
--- /dev/null
+++ b/tests/26_test_dch_extract_thanks.py
@@ -0,0 +1,40 @@
+# vim: set fileencoding=utf-8 :
+#
+# (C) 2015 Jonathan Toppins <jtoppins@cumulusnetworks.com>
+# (C) 2016 Guido Günther <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
+# (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, please see
+# <http://www.gnu.org/licenses/>
+"""Test gbp.dch.extract_thanks_info()"""
+
+import unittest
+
+from gbp.dch import extract_thanks_info
+
+
+class OptionsStub:
+ def __init__(self):
+ self.meta_closes = "Closes|LP"
+ self.meta_closes_bugnum = r'(?:bug|issue)?\#?\s?\d+'
+
+
+class TestExtractThanks(unittest.TestCase):
+ def test_debian_commands(self):
+ """Test default thanks extraction"""
+ lines = """
+thAnks: a lot
+Thanks: everyone"""
+
+ lines += " \n" # Add some trailing whitespace
+ bugs, dummy = extract_thanks_info(lines.split('\n'), None)
+ self.assertEquals(bugs, ['a lot', 'everyone'])
diff --git a/tests/component/__init__.py b/tests/component/__init__.py
index b6ba796..5850803 100644
--- a/tests/component/__init__.py
+++ b/tests/component/__init__.py
@@ -20,6 +20,7 @@
Module for testing individual command line tools of the git-buildpackage suite
"""
+import hashlib
import os
import shutil
import tempfile
@@ -205,3 +206,32 @@ class ComponentTestBase(unittest.TestCase, GbpLogTester):
for (h, s) in rem:
n = repo.rev_parse(h)
ok_(n == s, "Head '%s' points to %s' instead of '%s'" % (h, n, s))
+
+ @staticmethod
+ def hash_file(filename):
+ h = hashlib.md5()
+ with open(filename, 'rb') as f:
+ buf = f.read()
+ h.update(buf)
+ return h.hexdigest()
+
+ @staticmethod
+ def check_hook_vars(name, expected):
+ """
+ Check that a hook had the given vars in
+ it's environment.
+ This assumes the hook was set too
+ printenv > hookname.out
+ """
+ with open('%s.out' % name) as f:
+ parsed = dict([line[:-1].split('=', 1) for line in f.readlines() if line.startswith("GBP_")])
+
+ for var in expected:
+ if len(var) == 2:
+ k, v = var
+ else:
+ k, v = var, None
+ ok_(k in parsed, "%s not found in %s" % (k, parsed))
+ if v is not None:
+ ok_(v == parsed[k],
+ "Got %s not expected value %s for %s" % (parsed[k], v, k))
diff --git a/tests/component/deb/__init__.py b/tests/component/deb/__init__.py
index 8e91ce2..030a482 100644
--- a/tests/component/deb/__init__.py
+++ b/tests/component/deb/__init__.py
@@ -24,9 +24,7 @@ from tests.component import ComponentTestGitRepository
DEB_TEST_SUBMODULE = os.path.join('tests', 'component', 'deb', 'data')
DEB_TEST_DATA_DIR = os.path.abspath(DEB_TEST_SUBMODULE)
+
def setup():
"""Test Module setup"""
ComponentTestGitRepository.check_testdata(DEB_TEST_SUBMODULE)
-
-
-
diff --git a/tests/component/deb/data b/tests/component/deb/data
-Subproject b53e6ec2a785e1d9df3fbb2590f8fe974362910
+Subproject a70cc571c3ebe5d47b7bd4a8f6b41c157c930d9
diff --git a/tests/component/deb/test_buildpackage.py b/tests/component/deb/test_buildpackage.py
index 19dfa82..74d1fbb 100644
--- a/tests/component/deb/test_buildpackage.py
+++ b/tests/component/deb/test_buildpackage.py
@@ -31,42 +31,32 @@ from gbp.scripts.buildpackage import main as buildpackage
class TestBuildpackage(ComponentTestBase):
"""Test building a debian package"""
- def check_hook_vars(self, name, vars):
- """
- Check that a hook hat the given vars in
- it's environment.
- This assumes the hook was set too
- printenv > hookname.oug
- """
- env = []
- with open('%s.out' % name) as f:
- env = [line.split('=')[0] for line in f.readlines()]
-
- for var in vars:
- ok_(var in env, "%s not found in %s" % (var, env))
-
@staticmethod
def _dsc_name(pkg, version, dir):
return os.path.join(DEB_TEST_DATA_DIR,
dir,
'%s_%s.dsc' % (pkg, version))
- def _test_buildpackage(self, pkg, dir, version):
+ def _test_buildpackage(self, pkg, dir, version, opts=[]):
dsc = self._dsc_name(pkg, version, dir)
assert import_dsc(['arg0', dsc]) == 0
ComponentTestGitRepository(pkg)
+ prebuild_out = os.path.join(os.path.abspath(pkg), 'prebuild.out')
+ postbuild_out = os.path.join(os.path.abspath(pkg), 'postbuild.out')
os.chdir(pkg)
- ret = buildpackage(['arg0',
- '--git-prebuild=printenv > prebuild.out',
- '--git-postbuild=printenv > postbuild.out',
- '--git-builder=/bin/true',
- '--git-cleaner=/bin/true'])
+
+ args = ['arg0',
+ '--git-prebuild=printenv > %s' % prebuild_out,
+ '--git-postbuild=printenv > %s' % postbuild_out,
+ '--git-builder=/bin/true',
+ '--git-cleaner=/bin/true'] + opts
+ ret = buildpackage(args)
ok_(ret == 0, "Building the package failed")
- eq_(os.path.exists('prebuild.out'), True)
+ eq_(os.path.exists(prebuild_out), True)
+ eq_(os.path.exists(postbuild_out), True)
self.check_hook_vars('prebuild', ["GBP_BUILD_DIR",
"GBP_GIT_DIR",
- "GBP_GIT_DIR",
"GBP_BUILD_DIR"])
self.check_hook_vars('postbuild', ["GBP_CHANGES_FILE",
@@ -75,11 +65,11 @@ class TestBuildpackage(ComponentTestBase):
"GBP_BUILD_DIR"])
def test_debian_buildpackage(self):
- """Test that building a native debian package works"""
+ """Test that building a native debian package works"""
self._test_buildpackage('git-buildpackage', 'dsc-native', '0.4.14')
def test_non_native_buildpackage(self):
- """Test that building a native debian package works"""
+ """Test that building a source 3.0 debian package works"""
self._test_buildpackage('hello-debhelper', 'dsc-3.0', '2.8-1')
def test_tag_only(self):
@@ -102,11 +92,11 @@ class TestBuildpackage(ComponentTestBase):
ok_(ret == 0, "Building the package failed")
eq_(os.path.exists('posttag.out'), True)
eq_(os.path.exists('builder-run.stamp'), False)
- self.check_hook_vars('posttag', ["GBP_TAG",
- "GBP_BRANCH",
+ self.check_hook_vars('posttag', [("GBP_TAG", "debian/0.4.14"),
+ ("GBP_BRANCH", "master"),
"GBP_SHA1"])
- def test_subtarball_generation(self):
+ def test_component_generation(self):
"""Test that generating tarball and additional tarball works without pristine-tar"""
pkg = 'hello-debhelper'
dsc = self._dsc_name(pkg, '2.8-1', 'dsc-3.0-additional-tarballs')
@@ -120,7 +110,7 @@ class TestBuildpackage(ComponentTestBase):
for t in tarballs:
self.assertFalse(os.path.exists(t), "Tarball %s must not exist" % t)
ret = buildpackage(['arg0',
- '--git-subtarball=foo',
+ '--git-component=foo',
'--git-no-pristine-tar',
'--git-posttag=printenv > posttag.out',
'--git-builder=touch builder-run.stamp',
@@ -129,7 +119,7 @@ class TestBuildpackage(ComponentTestBase):
for t in tarballs:
self.assertTrue(os.path.exists(t), "Tarball %s not found" % t)
- def test_pristinetar_subtarball_generation(self):
+ def test_pristinetar_component_generation(self):
"""Test that generating tarball and additional tarball works with pristine-tar"""
pkg = 'hello-debhelper'
dsc = self._dsc_name(pkg, '2.8-1', 'dsc-3.0-additional-tarballs')
@@ -143,7 +133,7 @@ class TestBuildpackage(ComponentTestBase):
for t in tarballs:
self.assertFalse(os.path.exists(t), "Tarball %s must not exist" % t)
ret = buildpackage(['arg0',
- '--git-subtarball=foo',
+ '--git-component=foo',
'--git-pristine-tar',
'--git-posttag=printenv > posttag.out',
'--git-builder=touch builder-run.stamp',
@@ -151,3 +141,12 @@ class TestBuildpackage(ComponentTestBase):
ok_(ret == 0, "Building the package failed")
for t in tarballs:
self.assertTrue(os.path.exists(t), "Tarball %s not found" % t)
+
+ def test_export_dir_buildpackage(self):
+ """Test that building with a export dir works"""
+ self._test_buildpackage('hello-debhelper',
+ 'dsc-3.0',
+ '2.8-1',
+ ['--git-export-dir=../foo'],
+ )
+ ok_(os.path.exists('../foo'))
diff --git a/tests/component/deb/test_clone.py b/tests/component/deb/test_clone.py
new file mode 100644
index 0000000..0c3ba2c
--- /dev/null
+++ b/tests/component/deb/test_clone.py
@@ -0,0 +1,74 @@
+# vim: set fileencoding=utf-8 :
+#
+# (C) 2016 Guido Günther <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
+# (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, please see
+# <http://www.gnu.org/licenses/>
+
+import os
+
+from tests.component import (ComponentTestBase,
+ ComponentTestGitRepository)
+from tests.component.deb import DEB_TEST_DATA_DIR
+
+from nose.tools import ok_
+
+from gbp.scripts.import_dsc import main as import_dsc
+from gbp.scripts.clone import main as clone
+
+
+class TestClone(ComponentTestBase):
+ """Test cloning from a remote"""
+
+ def test_clone_nonempty(self):
+ """Test that cloning into an existing dir fails"""
+ def _dsc(version):
+ return os.path.join(DEB_TEST_DATA_DIR,
+ 'dsc-native',
+ 'git-buildpackage_%s.dsc' % version)
+
+ # Build up somethng we can clone from
+ dsc = _dsc('0.4.14')
+ assert import_dsc(['arg0', dsc]) == 0
+ repo = ComponentTestGitRepository('git-buildpackage')
+ self._check_repo_state(repo, 'master', ['master'])
+ assert len(repo.get_commits()) == 1
+
+ ok_(clone(['arg0', repo.path]) == 1,
+ "Cloning did no fail as expected")
+ self._check_log(-2, "gbp:error: Git command failed: Error running git clone: fatal: destination path 'git-buildpackage' already exists and is not an empty directory.")
+
+ def test_clone_native(self):
+ """Test that cloning of debian native packages works"""
+ def _dsc(version):
+ return os.path.join(DEB_TEST_DATA_DIR,
+ 'dsc-native',
+ 'git-buildpackage_%s.dsc' % version)
+
+ # Build up somethng we can clone from
+ dsc = _dsc('0.4.14')
+ assert import_dsc(['arg0', dsc]) == 0
+ repo = ComponentTestGitRepository('git-buildpackage')
+ self._check_repo_state(repo, 'master', ['master'])
+ assert len(repo.get_commits()) == 1
+
+ dest = os.path.join(self._tmpdir,
+ 'cloned_repo')
+ clone(['arg0',
+ '--postclone=printenv > postclone.out',
+ repo.path, dest])
+ cloned = ComponentTestGitRepository(dest)
+ self._check_repo_state(cloned, 'master', ['master'])
+ assert len(cloned.get_commits()) == 1
+ self.check_hook_vars('postclone', ["GBP_GIT_DIR"])
diff --git a/tests/component/deb/test_import_dsc.py b/tests/component/deb/test_import_dsc.py
index 615ef97..bc10962 100644
--- a/tests/component/deb/test_import_dsc.py
+++ b/tests/component/deb/test_import_dsc.py
@@ -17,7 +17,6 @@
# <http://www.gnu.org/licenses/>
import os
-import hashlib
from tests.component import (ComponentTestBase,
ComponentTestGitRepository)
@@ -33,15 +32,7 @@ from gbp.deb.dscfile import DscFile
class TestImportDsc(ComponentTestBase):
"""Test importing of debian source packages"""
- @staticmethod
- def _hash_file(filename):
- h = hashlib.md5()
- with open(filename, 'rb') as f:
- buf = f.read()
- h.update(buf)
- return h.hexdigest()
-
- def test_debian_import(self):
+ def test_import_debian_native(self):
"""Test that importing of debian native packages works"""
def _dsc(version):
return os.path.join(DEB_TEST_DATA_DIR,
@@ -120,7 +111,7 @@ class TestImportDsc(ComponentTestBase):
ok_(commits == expected, "Found %d commit instead of %d" % (commits, expected))
dsc = DscFile.parse(dscfile)
- # Check if we can rebuild the tarball and subtarball
+ # Check if we can rebuild the tarball and component
ptars = [('hello-debhelper_2.8.orig.tar.gz', 'pristine-tar', '', dsc.tgz),
('hello-debhelper_2.8.orig-foo.tar.gz', 'pristine-tar^', 'foo', dsc.additional_tarballs['foo'])]
@@ -128,9 +119,9 @@ class TestImportDsc(ComponentTestBase):
outdir = os.path.abspath('.')
for f, w, s, o in ptars:
eq_(repo.get_subject(w), 'pristine-tar data for %s' % f)
- old = self._hash_file(o)
- p.checkout('hello-debhelper', '2.8', 'gzip', outdir, subtarball=s)
- new = self._hash_file(os.path.join(outdir, f))
+ old = self.hash_file(o)
+ p.checkout('hello-debhelper', '2.8', 'gzip', outdir, component=s)
+ new = self.hash_file(os.path.join(outdir, f))
eq_(old, new, "Checksum %s of regenerated tarball %s does not match original %s" %
(f, old, new))
@@ -155,3 +146,17 @@ class TestImportDsc(ComponentTestBase):
dsc]) == 1
self._check_log(0, "gbp:error: Directory 'hello-debhelper' already exists. If you want to import into it, "
"please change into this directory otherwise move it away first")
+
+ def test_import_10(self):
+ """Test if importing a 1.0 source format package works"""
+ def _dsc(version):
+ return os.path.join(DEB_TEST_DATA_DIR,
+ 'dsc-1.0',
+ 'hello-debhelper_%s.dsc' % version)
+
+ dsc = _dsc('2.6-2')
+ assert import_dsc(['arg0', dsc]) == 0
+ repo = ComponentTestGitRepository('hello-debhelper')
+ self._check_repo_state(repo, 'master', ['master', 'upstream'],
+ tags=['upstream/2.6', 'debian/2.6-2'])
+ assert len(repo.get_commits()) == 2
diff --git a/tests/component/deb/test_import_orig.py b/tests/component/deb/test_import_orig.py
index 6ed5da8..c4e1bad 100644
--- a/tests/component/deb/test_import_orig.py
+++ b/tests/component/deb/test_import_orig.py
@@ -18,38 +18,142 @@
import os
-from tests.component import ComponentTestBase
+from mock import patch, DEFAULT
+
+from tests.component import (ComponentTestBase,
+ ComponentTestGitRepository)
from tests.component.deb import DEB_TEST_DATA_DIR
+from gbp.scripts.import_dsc import main as import_dsc
from gbp.scripts.import_orig import main as import_orig
-from gbp.git.repository import GitRepository
+from gbp.deb.pristinetar import DebianPristineTar
+from gbp.deb.dscfile import DscFile
+from gbp.git.repository import GitRepository, GitRepositoryError
+
+from nose.tools import ok_, eq_
+
-from nose.tools import ok_
+def raise_if_tag_match(match):
+ def wrapped(*args, **kwargs):
+ if len(args) > 0 and args[0].startswith(match) or kwargs.get('name', '').startswith(match):
+ raise GitRepositoryError('this is a create tag error mock for %s %s' % (match, kwargs))
+ return DEFAULT
+ return wrapped
class TestImportOrig(ComponentTestBase):
- """Test importing of new upstream sources"""
+ """Test importing of new upstream versions"""
pkg = "hello-debhelper"
def_branches = ['master', 'upstream', 'pristine-tar']
- def _orig(self, version):
+ def _orig(self, version, dir='dsc-3.0'):
return os.path.join(DEB_TEST_DATA_DIR,
- 'dsc-3.0',
+ dir,
'%s_%s.orig.tar.gz' % (self.pkg, version))
+ def _dsc(self, version, dir='dsc-3.0'):
+ return os.path.join(DEB_TEST_DATA_DIR,
+ dir,
+ '%s_%s.dsc' % (self.pkg, version))
+
def test_initial_import(self):
"""Test that importing into an empty repo works"""
repo = GitRepository.create(self.pkg)
os.chdir(self.pkg)
orig = self._orig('2.6')
ok_(import_orig(['arg0', '--no-interactive', '--pristine-tar', orig]) == 0)
-
self._check_repo_state(repo, 'master', self.def_branches,
tags=['upstream/2.6'])
+ def test_update(self):
+ """
+ Test that importing a new version works
+ """
+ dsc = self._dsc('2.6-2')
+ ok_(import_dsc(['arg0', '--pristine-tar', dsc]) == 0)
+ repo = ComponentTestGitRepository(self.pkg)
+ os.chdir(self.pkg)
+ self._check_repo_state(repo, 'master', ['master', 'upstream', 'pristine-tar'])
+
+ orig = self._orig('2.8')
+ ok_(import_orig(['arg0',
+ '--postimport=printenv > postimport.out',
+ '--no-interactive', '--pristine-tar', orig]) == 0)
+ self._check_repo_state(repo, 'master', ['master', 'upstream', 'pristine-tar'],
+ tags=['debian/2.6-2', 'upstream/2.6', 'upstream/2.8'])
+ eq_(os.path.exists('postimport.out'), True)
+ self.check_hook_vars('postimport', [("GBP_BRANCH", "master"),
+ ("GBP_TAG", "upstream/2.8"),
+ ("GBP_UPSTREAM_VERSION", "2.8"),
+ ("GBP_DEBIAN_VERSION", "2.8-1")])
+
+ def test_update_component_tarballs(self):
+ """
+ Test importing new version with additional tarballs works
+ """
+ dsc = self._dsc('2.6-2')
+ ok_(import_dsc(['arg0', '--pristine-tar', dsc]) == 0)
+ repo = ComponentTestGitRepository(self.pkg)
+ os.chdir(self.pkg)
+ self._check_repo_state(repo, 'master', ['master', 'upstream', 'pristine-tar'])
+
+ # Import 2.8
+ orig = self._orig('2.8', dir='dsc-3.0-additional-tarballs')
+ ok_(import_orig(['arg0', '--component=foo', '--no-interactive', '--pristine-tar', orig]) == 0)
+ self._check_repo_state(repo, 'master', ['master', 'upstream', 'pristine-tar'],
+ tags=['debian/2.6-2', 'upstream/2.6', 'upstream/2.8'])
+ for file in ['foo/test1', 'foo/test2']:
+ ok_(file in repo.ls_tree('HEAD'),
+ "Could not find component tarball file %s in %s" % (file, repo.ls_tree('HEAD')))
+ ok_(file in repo.ls_tree('upstream'),
+ "Could not find component tarball file %s in %s" % (file, repo.ls_tree('HEAD')))
+
+ dsc = DscFile.parse(self._dsc('2.8-1', dir='dsc-3.0-additional-tarballs'))
+ # Check if we can rebuild the upstream tarball and additional tarball
+ ptars = [('hello-debhelper_2.8.orig.tar.gz', 'pristine-tar', '', dsc.tgz),
+ ('hello-debhelper_2.8.orig-foo.tar.gz', 'pristine-tar^', 'foo', dsc.additional_tarballs['foo'])]
+
+ p = DebianPristineTar(repo)
+ outdir = os.path.abspath('.')
+ for f, w, s, o in ptars:
+ eq_(repo.get_subject(w), 'pristine-tar data for %s' % f)
+ old = self.hash_file(o)
+ p.checkout('hello-debhelper', '2.8', 'gzip', outdir, component=s)
+ out = os.path.join(outdir, f)
+ new = self.hash_file(out)
+ eq_(old, new, "Checksum %s of regenerated tarball %s does not match original %s" %
+ (f, old, new))
+ os.unlink(out)
+
+ # Import 2.9
+ orig = self._orig('2.9', dir='dsc-3.0-additional-tarballs')
+ ok_(import_orig(['arg0', '--component=foo', '--no-interactive', '--pristine-tar', orig]) == 0)
+ self._check_repo_state(repo, 'master', ['master', 'upstream', 'pristine-tar'],
+ tags=['debian/2.6-2', 'upstream/2.6', 'upstream/2.8', 'upstream/2.9'])
+ for file in ['foo/test1', 'foo/test2', 'foo/test3']:
+ ok_(file in repo.ls_tree('HEAD'),
+ "Could not find component tarball file %s in %s" % (file, repo.ls_tree('HEAD')))
+ ok_(file in repo.ls_tree('upstream'),
+ "Could not find component tarball file %s in %s" % (file, repo.ls_tree('HEAD')))
+
+ dsc = DscFile.parse(self._dsc('2.9-1', dir='dsc-3.0-additional-tarballs'))
+ # Check if we can rebuild the upstream tarball and additional tarball
+ ptars = [('hello-debhelper_2.9.orig.tar.gz', 'pristine-tar', '', dsc.tgz),
+ ('hello-debhelper_2.9.orig-foo.tar.gz', 'pristine-tar^', 'foo', dsc.additional_tarballs['foo'])]
+
+ p = DebianPristineTar(repo)
+ outdir = os.path.abspath('.')
+ for f, w, s, o in ptars:
+ eq_(repo.get_subject(w), 'pristine-tar data for %s' % f)
+ old = self.hash_file(o)
+ p.checkout('hello-debhelper', '2.9', 'gzip', outdir, component=s)
+ new = self.hash_file(os.path.join(outdir, f))
+ eq_(old, new, "Checksum %s of regenerated tarball %s does not match original %s" %
+ (f, old, new))
+
def test_tag_exists(self):
- """Test that importing an already importet version fails"""
+ """Test that importing an already imported version fails"""
repo = GitRepository.create(self.pkg)
os.chdir(self.pkg)
orig = self._orig('2.6')
@@ -61,3 +165,75 @@ class TestImportOrig(ComponentTestBase):
self._check_log(0, "gbp:error: Upstream tag 'upstream/2.6' already exists")
# Check that the second import didn't change any refs
self.check_refs(repo, heads)
+
+ def test_update_fail_create_upstream_tag(self):
+ """
+ Test that we can recover from a failure to create the upstream
+ tag
+ """
+ repo = GitRepository.create(self.pkg)
+ os.chdir(self.pkg)
+
+ dsc = self._dsc('2.6-2')
+ ok_(import_dsc(['arg0', '--pristine-tar', dsc]) == 0)
+ self._check_repo_state(repo, 'master', ['master', 'upstream', 'pristine-tar'])
+
+ heads = self.rem_refs(repo, self.def_branches)
+
+ orig = self._orig('2.8')
+ with patch('gbp.git.repository.GitRepository.create_tag',
+ side_effect=GitRepositoryError('this is a create tag error mock')):
+ ok_(import_orig(['arg0', '--no-interactive', '--pristine-tar', orig]) == 1)
+ self._check_repo_state(repo, 'master', ['master', 'upstream', 'pristine-tar'],
+ tags=['debian/2.6-2', 'upstream/2.6'])
+ self.check_refs(repo, heads)
+
+ def test_update_fail_merge(self):
+ """
+ Test that we can recover from a failed merge
+ """
+ repo = GitRepository.create(self.pkg)
+ os.chdir(self.pkg)
+
+ dsc = self._dsc('2.6-2')
+ ok_(import_dsc(['arg0', '--pristine-tar', dsc]) == 0)
+ self._check_repo_state(repo, 'master', ['master', 'upstream', 'pristine-tar'])
+
+ heads = self.rem_refs(repo, self.def_branches)
+
+ orig = self._orig('2.8')
+ with patch('gbp.scripts.import_orig.debian_branch_merge',
+ side_effect=GitRepositoryError('this is a fail merge error mock')):
+ ok_(import_orig(['arg0', '--no-interactive', '--pristine-tar', orig]) == 1)
+ self._check_repo_state(repo, 'master', ['master', 'upstream', 'pristine-tar'],
+ tags=['debian/2.6-2', 'upstream/2.6'])
+ self.check_refs(repo, heads)
+
+ @patch('gbp.git.repository.GitRepository.create_tag',
+ side_effect=raise_if_tag_match('upstream/'))
+ def test_initial_import_fail_create_upstream_tag(self, RepoMock):
+ """
+ Test that we can recover from a failure to create the upstream
+ tag on initial import
+ """
+ repo = GitRepository.create(self.pkg)
+ os.chdir(self.pkg)
+ orig = self._orig('2.6')
+ ok_(import_orig(['arg0', '--no-interactive', orig]) == 1)
+
+ self._check_repo_state(repo, None, [], tags=[])
+
+ def test_initial_import_fail_create_debian_branch(self):
+ """
+ Test that we can recover from creating the Debian branch on
+ initial import
+ """
+ repo = GitRepository.create(self.pkg)
+ os.chdir(self.pkg)
+ orig = self._orig('2.6')
+
+ with patch('gbp.git.repository.GitRepository.create_branch',
+ side_effect=GitRepositoryError('this is a create branch error mock')):
+ ok_(import_orig(['arg0', '--no-interactive', '--pristine-tar', orig]) == 1)
+
+ self._check_repo_state(repo, None, [], tags=[])
diff --git a/tests/component/rpm/__init__.py b/tests/component/rpm/__init__.py
index 52ab4b8..db776e3 100644
--- a/tests/component/rpm/__init__.py
+++ b/tests/component/rpm/__init__.py
@@ -16,16 +16,12 @@
# <http://www.gnu.org/licenses/>
"""Test module for RPM command line tools of the git-buildpackage suite"""
-import six
-
from nose.tools import nottest
import os
import shutil
from glob import glob
-from xml.dom import minidom
from gbp.command_wrappers import Command
-from gbp.git import GitRepositoryError
from tests.component import ComponentTestBase, ComponentTestGitRepository
@@ -33,10 +29,12 @@ from tests.component import ComponentTestBase, ComponentTestGitRepository
RPM_TEST_DATA_SUBMODULE = os.path.join('tests', 'component', 'rpm', 'data')
RPM_TEST_DATA_DIR = os.path.abspath(RPM_TEST_DATA_SUBMODULE)
+
def setup():
"""Test Module setup"""
ComponentTestGitRepository.check_testdata(RPM_TEST_DATA_SUBMODULE)
+
class RpmRepoTestBase(ComponentTestBase):
"""Baseclass for tests run in a Git repository with packaging data"""
diff --git a/tests/component/rpm/test_buildpackage_rpm.py b/tests/component/rpm/test_buildpackage_rpm.py
index 4f0c290..71ff7b7 100644
--- a/tests/component/rpm/test_buildpackage_rpm.py
+++ b/tests/component/rpm/test_buildpackage_rpm.py
@@ -26,12 +26,12 @@ import stat
import subprocess
from nose import SkipTest
-from nose.tools import assert_raises, eq_, ok_ # pylint: disable=E0611
+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_tar, ls_zip
+from tests.testutils import ls_tar, ls_zip, capture
# Disable "Method could be a function warning"
# pylint: disable=R0201
@@ -47,8 +47,10 @@ MOCK_NOTIFICATIONS = []
def mock_gbp(args):
"""Wrapper for gbp-buildpackage-rpm"""
- return gbp_rpm(['arg0', '--git-notify=off'] + args +
- ['-ba', '--clean', '--target=noarch', '--nodeps'])
+ with capture.capture_stderr():
+ return gbp_rpm(['arg0', '--git-notify=off'] + args +
+ ['-ba', '--clean', '--target=noarch', '--nodeps'])
+
def mock_notify(summary, message, notify_opt):
"""Mock notification system"""
@@ -75,7 +77,7 @@ class TestGbpRpm(RpmRepoTestBase):
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()]])
+ [lin.split(None, 2) for lin in stdout.splitlines()]])
@staticmethod
def check_rpms(directory):
@@ -104,18 +106,7 @@ class TestGbpRpm(RpmRepoTestBase):
"""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.')
+ os.path.abspath('.'))
def test_native_build(self):
"""Basic test of native pkg"""
@@ -224,7 +215,7 @@ class TestGbpRpm(RpmRepoTestBase):
eq_(mock_gbp(['--git-tag', '--git-packaging-tag=rel-tag']), 1)
# Re-tag
- eq_(mock_gbp(['--git-retag', '--git-packaging-tag=rel-tag']), 1)
+ eq_(mock_gbp(['--git-retag', '--git-packaging-tag=rel-tag']), 3)
self._check_log(-1, "gbp:error: '--git-retag' needs either '--git-tag'")
eq_(mock_gbp(['--git-tag', '--git-packaging-tag=rel-tag',
@@ -256,8 +247,8 @@ class TestGbpRpm(RpmRepoTestBase):
# Dummy update to upstream branch
pkg_branch = repo.get_branch()
upstr_branch = 'upstream'
- orig_files = ['gbp-test/' + path for \
- path in repo.ls_tree(upstr_branch)] + ['gbp-test']
+ orig_files = ['gbp-test/' + path for
+ path in repo.ls_tree(upstr_branch)] + ['gbp-test']
repo.set_branch(upstr_branch)
with open('new-file', 'w') as fobj:
fobj.write('New file\n')
@@ -329,7 +320,7 @@ class TestGbpRpm(RpmRepoTestBase):
eq_(len(repo.get_commits(until='pristine-tar')), 2)
shutil.rmtree('../rpmbuild')
- # Second time no pristine-tar should not be commited
+ # Second time no pristine-tar should not be committed
eq_(mock_gbp(['--git-pristine-tar-commit']), 0)
eq_(len(repo.get_commits(until='pristine-tar')), 2)
@@ -384,7 +375,7 @@ class TestGbpRpm(RpmRepoTestBase):
sub_files = sub_repo.ls_tree('HEAD')
upstr_files = ['gbp-test/' + path for
- path in repo.ls_tree(upstr_branch)]
+ path in repo.ls_tree(upstr_branch)]
# Test the "no" option
eq_(mock_gbp(['--git-no-submodules', '--git-upstream-tree=%s' %
@@ -398,7 +389,7 @@ class TestGbpRpm(RpmRepoTestBase):
upstr_branch, '--git-ignore-new']), 0)
tar_files = ls_tar('../rpmbuild/SOURCES/gbp-test-1.1.tar.bz2', False)
ref_files = upstr_files + ['gbp-test/gbp-test-native.repo/' + path for
- path in sub_files]
+ path in sub_files]
self.check_files(ref_files, tar_files)
shutil.rmtree('../rpmbuild')
@@ -407,6 +398,10 @@ class TestGbpRpm(RpmRepoTestBase):
repo.create('gbp-test-native.repo')
eq_(mock_gbp(['--git-submodules', '--git-upstream-tree=%s' %
upstr_branch, '--git-ignore-new']), 2)
+ self._check_log(-2,
+ ".*Error generating submodules' archives: "
+ "Failed to list submodules of [0-9a-f]{40}: fatal: "
+ "not a tree object")
def test_option_submodules_native(self):
"""Test the --git-submodules option for native packages"""
@@ -426,7 +421,7 @@ class TestGbpRpm(RpmRepoTestBase):
zip_files = ls_zip('../rpmbuild/SOURCES/gbp-test-native-1.0.zip', False)
ref_files = master_files + \
['gbp-test-native-1.0/gbp-test-native2.repo/' + path for
- path in sub_files]
+ path in sub_files]
self.check_files(ref_files, zip_files)
# Test submodule failure
@@ -551,7 +546,7 @@ class TestGbpRpm(RpmRepoTestBase):
# Test exporting of some other commit than HEAD
eq_(mock_gbp(['--git-export=release/1.0-1']), 0)
eq_(os.listdir('../rpmbuild/RPMS/noarch'),
- ['gbp-test-1.0-1.noarch.rpm'])
+ ['gbp-test-1.0-1.noarch.rpm'])
self.check_rpms('../rpmbuild/RPMS/*')
# Modify one tracked file, create one untracked and one ignored file
@@ -613,4 +608,3 @@ class TestGbpRpm(RpmRepoTestBase):
# Packaging dir should be taken from spec file if it is defined
eq_(mock_gbp(['--git-packaging-dir=foo',
'--git-spec-file=packaging/gbp-test-native.spec']), 0)
-
diff --git a/tests/component/rpm/test_import_srpm.py b/tests/component/rpm/test_import_srpm.py
index 31a18a5..bc94258 100644
--- a/tests/component/rpm/test_import_srpm.py
+++ b/tests/component/rpm/test_import_srpm.py
@@ -29,6 +29,7 @@ from gbp.rpm import SrcRpmFile
from tests.component import ComponentTestBase
from tests.component.rpm import RPM_TEST_DATA_DIR as DATA_DIR
+from tests.testutils import capture_stderr
# Disable "Method could be a function warning"
# pylint: disable=R0201
@@ -36,7 +37,8 @@ from tests.component.rpm import RPM_TEST_DATA_DIR as DATA_DIR
def mock_import(args):
"""Wrapper for import-srpm"""
# Call import-orig-rpm with added arg0
- return import_srpm.main(['arg0'] + args)
+ with capture_stderr():
+ return import_srpm.main(['arg0'] + args)
class TestImportPacked(ComponentTestBase):
@@ -274,7 +276,7 @@ class TestDownloadImport(ComponentTestBase):
self._check_repo_state(repo, 'master', ['master', 'upstream'])
def test_nonexistent_url(self):
- """Test graceful failure when trying download from nonexistent url"""
+ """Test graceful failure when trying download from non-existent url"""
srpm = 'http://honk.sigxcpu.org/does/not/exist'
# Do not connect to remote, mock failure
import_srpm.urlopen = Mock()
diff --git a/tests/component/rpm/test_pq_rpm.py b/tests/component/rpm/test_pq_rpm.py
index 3746fb9..e1d97b7 100644
--- a/tests/component/rpm/test_pq_rpm.py
+++ b/tests/component/rpm/test_pq_rpm.py
@@ -18,13 +18,14 @@
import os
import tempfile
-from nose.tools import assert_raises, eq_, ok_ # pylint: disable=E0611
+from nose.tools import assert_raises, eq_, ok_ # pylint: disable=E0611
from gbp.scripts.pq_rpm import main as pq
from gbp.git import GitRepository
from gbp.command_wrappers import GitCommand
from tests.component.rpm import RpmRepoTestBase
+from tests.testutils import capture_stderr
# Disable "Method could be a function warning"
# pylint: disable=R0201
@@ -35,6 +36,7 @@ def mock_pq(args):
# Call pq-rpm with added arg0
return pq(['arg0'] + args)
+
class TestPqRpm(RpmRepoTestBase):
"""Basic tests for gbp-pq-rpm"""
@@ -53,23 +55,14 @@ class TestPqRpm(RpmRepoTestBase):
# Test invalid cmdline options
with assert_raises(SystemExit):
- mock_pq(['--invalid-arg=123'])
+ with capture_stderr() as c:
+ mock_pq(['--invalid-arg=123'])
def test_import_outside_repo(self):
"""Run pq-rpm when not in a git repository"""
eq_(mock_pq(['export']), 1)
self._check_log(0, 'gbp:error: %s is not a git repository' %
- os.path.abspath(os.getcwd()))
-
- def test_invalid_config_file(self):
- """Test invalid config file"""
- # Create dummy invalid config file and run pq-rpm
- GitRepository.create('.')
- with open('.gbp.conf', 'w') as conffd:
- conffd.write('foobar\n')
- eq_(mock_pq(['foo']), 1)
- self._check_log(0, 'gbp:error: Invalid config file: File contains no '
- 'section headers.')
+ os.path.abspath(os.getcwd()))
def test_import_export(self):
"""Basic test for patch import and export"""
@@ -327,7 +320,7 @@ class TestPqRpm(RpmRepoTestBase):
eq_(mock_pq(['export']), 0)
files = ['.gbp.conf', '.gitignore', 'bar.tar.gz', 'foo.txt',
'gbp-test.spec', 'my.patch',
- '%s-to-%s.diff' % (upstr_rev, merge_rev), '0002-my2.patch']
+ '%s-to-%s.diff' % (upstr_rev, merge_rev), '0002-my2.patch']
self._check_repo_state(repo, 'master', branches, files)
def test_import_unapplicable_patch(self):
@@ -339,10 +332,10 @@ class TestPqRpm(RpmRepoTestBase):
patch_file.write('-this-does\n+not-apply\n')
eq_(mock_pq(['import']), 1)
self._check_log(-2, "("
- "Aborting|"
- "Please, commit your changes or stash them|"
- "gbp:error: Import failed.* You have local changes"
- ")")
+ "Aborting|"
+ "Please, commit your changes or stash them|"
+ "gbp:error: Import failed.* You have local changes"
+ ")")
self._check_repo_state(repo, 'master', branches)
# Now commit the changes to the patch and try again
@@ -351,4 +344,3 @@ class TestPqRpm(RpmRepoTestBase):
eq_(mock_pq(['import']), 1)
self._check_log(-2, "gbp:error: Import failed: Error running git apply")
self._check_repo_state(repo, 'master', branches)
-
diff --git a/tests/component/rpm/test_rpm_ch.py b/tests/component/rpm/test_rpm_ch.py
new file mode 100644
index 0000000..3fa5436
--- /dev/null
+++ b/tests/component/rpm/test_rpm_ch.py
@@ -0,0 +1,337 @@
+# 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, please see
+# <http://www.gnu.org/licenses/>
+"""Tests for the gbp-rpm-ch tool"""
+
+import os
+import re
+from nose.tools import assert_raises, eq_, ok_ # pylint: disable=E0611
+
+from gbp.scripts.rpm_ch import main as rpm_ch
+from gbp.git import GitRepository
+from tests.testutils import capture_stderr
+
+from tests.component.rpm import RpmRepoTestBase
+
+# Disable "Method could be a function warning"
+# pylint: disable=R0201
+
+
+def mock_ch(args):
+ """Wrapper for gbp-rpm-ch"""
+ with capture_stderr():
+ return rpm_ch(['arg0', '--packaging-branch=master',
+ '--spawn-editor=never'] + args)
+
+
+class TestRpmCh(RpmRepoTestBase):
+ """Basic tests for gbp-rpm-ch"""
+
+ def setUp(self):
+ """Test case setup"""
+ super(TestRpmCh, self).setUp()
+ # Set environment so that commits succeed without git config
+ os.environ['GIT_AUTHOR_NAME'] = 'My Name'
+ os.environ['GIT_COMMITTER_NAME'] = 'My Name'
+ os.environ['EMAIL'] = 'me@example.com'
+
+ @staticmethod
+ def read_file(filename):
+ """Read file to a list"""
+ with open(filename) as fobj:
+ return fobj.readlines()
+
+ def test_invalid_args(self):
+ """See that gbp-rpm-ch fails gracefully when called with invalid args"""
+ GitRepository.create('.')
+
+ with assert_raises(SystemExit):
+ mock_ch(['--invalid-opt'])
+
+ def test_import_outside_repo(self):
+ """Run gbp-rpm-ch when not in a git repository"""
+ eq_(mock_ch([]), 1)
+ self._check_log(0, 'gbp:error: No Git repository at ')
+
+ def test_update_spec_changelog(self):
+ """Test updating changelog in spec"""
+ repo = self.init_test_repo('gbp-test')
+ eq_(mock_ch([]), 0)
+ eq_(repo.status(), {' M': ['gbp-test.spec']})
+
+ def test_update_changes_file(self):
+ """Test updating a separate changes file"""
+ repo = self.init_test_repo('gbp-test-native')
+ eq_(mock_ch([]), 0)
+ eq_(repo.status(), {' M': ['packaging/gbp-test-native.changes']})
+
+ def test_create_spec_changelog(self):
+ """Test creating changelog in spec file"""
+ repo = self.init_test_repo('gbp-test2')
+ orig_content = self.read_file('packaging/gbp-test2.spec')
+
+ # Fails if no starting point is given
+ eq_(mock_ch([]), 1)
+ self._check_log(-1, "gbp:error: Couldn't determine starting point")
+
+ # Give starting point
+ eq_(mock_ch(['--since=HEAD^']), 0)
+ eq_(repo.status(), {' M': ['packaging/gbp-test2.spec']})
+ content = self.read_file('packaging/gbp-test2.spec')
+ # Should contain 4 lines (%changelog, header, 1 entry and an empty line)
+ eq_(len(content), len(orig_content) + 4)
+
+ def test_create_changes_file(self):
+ """Test creating a separate changes file"""
+ repo = self.init_test_repo('gbp-test2')
+
+ # Fails if no starting point is given
+ eq_(mock_ch(['--changelog-file=CHANGES']), 1)
+ self._check_log(-1, "gbp:error: Couldn't determine starting point")
+
+ # Give starting point
+ eq_(mock_ch(['--since=HEAD^', '--changelog-file=CHANGES']), 0)
+ eq_(repo.status(), {'??': ['packaging/gbp-test2.changes']})
+ content = self.read_file('packaging/gbp-test2.changes')
+ # Should contain 3 lines (header, 1 entry and an empty line)
+ eq_(len(content), 3)
+
+ def test_option_changelog_file(self):
+ """Test the --changelog-file cmdline option"""
+ repo = self.init_test_repo('gbp-test-native')
+
+ # Guess changelog file
+ eq_(mock_ch(['--changelog-file=CHANGES']), 0)
+ eq_(repo.status(), {' M': ['packaging/gbp-test-native.changes']})
+
+ # Use spec file as changelog
+ eq_(mock_ch(['--changelog-file=SPEC', '--since=HEAD^']), 0)
+ eq_(repo.status(), {' M': ['packaging/gbp-test-native.changes',
+ 'packaging/gbp-test-native.spec']})
+
+ # Arbitrary name
+ eq_(mock_ch(['--changelog-file=foo.changes', '--since=HEAD^']), 0)
+ eq_(repo.status(), {' M': ['packaging/gbp-test-native.changes',
+ 'packaging/gbp-test-native.spec'],
+ '??': ['foo.changes']})
+
+ def test_option_spec_file(self):
+ """Test the --spec-file cmdline option"""
+ repo = self.init_test_repo('gbp-test2')
+
+ eq_(mock_ch(['--spec-file=foo.spec']), 1)
+ self._check_log(-1, "gbp:error: Unable to read spec file")
+
+ eq_(mock_ch(['--spec-file=']), 1)
+ self._check_log(-1, "gbp:error: Multiple spec files found")
+
+ eq_(mock_ch(['--spec-file=packaging/gbp-test2.spec', '--since=HEAD^']),
+ 0)
+ eq_(repo.status(), {' M': ['packaging/gbp-test2.spec']})
+
+ def test_option_packaging_dir(self):
+ """Test the --packaging-dir cmdline option"""
+ repo = self.init_test_repo('gbp-test-native')
+
+ eq_(mock_ch(['--packaging-dir=foo']), 1)
+ self._check_log(-1, "gbp:error: No spec file found")
+
+ # Packaging dir should be taken from spec file if it is defined
+ eq_(mock_ch(['--packaging-dir', 'foo', '--spec-file',
+ 'packaging/gbp-test-native.spec']), 0)
+ eq_(repo.status(), {' M': ['packaging/gbp-test-native.changes']})
+
+ def test_branch_options(self):
+ """Test the --packaging-branch and --ignore-branch cmdline options"""
+ self.init_test_repo('gbp-test-native')
+
+ eq_(mock_ch(['--packaging-branch=foo']), 1)
+ self._check_log(-2, "gbp:error: You are not on branch 'foo'")
+
+ eq_(mock_ch(['--packaging-branch=foo', '--ignore-branch']), 0)
+
+ def test_option_no_release(self):
+ """Test the --no-release cmdline option"""
+ self.init_test_repo('gbp-test-native')
+ orig_content = self.read_file('packaging/gbp-test-native.changes')
+
+ eq_(mock_ch(['--no-release']), 0)
+ content = self.read_file('packaging/gbp-test-native.changes')
+ # Only one line (entry) added
+ eq_(len(content), len(orig_content) + 1)
+
+ def test_author(self):
+ """Test determining the author name/email"""
+ repo = self.init_test_repo('gbp-test-native')
+
+ # Test taking email address from env
+ os.environ['EMAIL'] = 'user@host.com'
+ eq_(mock_ch([]), 0)
+ header = self.read_file('packaging/gbp-test-native.changes')[0]
+ ok_(re.match(r'.+ <user@host\.com> .+', header))
+
+ # Missing git config setting should not cause a failure
+ del os.environ['EMAIL']
+ del os.environ['GIT_AUTHOR_NAME']
+ os.environ['GIT_CONFIG_NOSYSTEM'] = '1'
+ os.environ['HOME'] = os.path.abspath('.')
+ eq_(mock_ch(['--git-author', '--since=HEAD^1']), 0)
+
+ # Test the --git-author option
+ saved_author = os.environ.get('GIT_AUTHOR_NAME')
+ saved_email = os.environ.get('GIT_AUTHOR_EMAIL')
+ os.environ['GIT_AUTHOR_NAME'] = 'John Doe'
+ os.environ['GIT_AUTHOR_EMAIL'] = 'jd@host.com'
+ with open(os.path.join(repo.git_dir, 'config'), 'a') as fobj:
+ fobj.write('[user]\n name=John Doe\n email=jd@host.com\n')
+ eq_(mock_ch(['--git-author', '--since=HEAD^']), 0)
+ header = self.read_file('packaging/gbp-test-native.changes')[0]
+ ok_(re.match(r'.+ John Doe <jd@host\.com> .+', header), header)
+ if saved_author:
+ os.environ['GIT_AUTHOR_NAME'] = saved_author
+ if saved_email:
+ os.environ['GIT_AUTHOR_EMAIL'] = saved_email
+
+ def test_option_full(self):
+ """Test the --full cmdline option"""
+ repo = self.init_test_repo('gbp-test-native')
+ orig_content = self.read_file('packaging/gbp-test-native.changes')
+
+ eq_(mock_ch(['--full', '--since=HEAD^']), 0)
+ commit_msg_body = repo.get_commit_info('HEAD')['body']
+ full_msg = [line for line in commit_msg_body.splitlines() if line]
+ content = self.read_file('packaging/gbp-test-native.changes')
+ # New lines: header, 1 entry "header", entry "body" from commit message
+ # and one empty line
+ eq_(len(content), len(orig_content) + 3 + len(full_msg))
+
+ def test_option_ignore_regex(self):
+ """Test the --ignore-regex cmdline option"""
+ repo = self.init_test_repo('gbp-test-native')
+ orig_content = self.read_file('packaging/gbp-test-native.changes')
+
+ eq_(mock_ch(['--full', '--since', 'HEAD^', '--ignore-regex',
+ 'Signed-off-by:.*']), 0)
+ commit_msg_body = repo.get_commit_info('HEAD')['body']
+ full_msg = [line for line in commit_msg_body.splitlines() if
+ (line and not line.startswith('Signed-off-by:'))]
+ content = self.read_file('packaging/gbp-test-native.changes')
+ # New lines: header, 1 entry "header", filtered entry "body" from
+ # commit message and one empty line
+ eq_(len(content), len(orig_content) + 3 + len(full_msg))
+
+ def test_option_id_len(self):
+ """Test the --id-len cmdline option"""
+ repo = self.init_test_repo('gbp-test-native')
+
+ eq_(mock_ch(['--id-len=10']), 0)
+ commit_id = repo.rev_parse('HEAD', 10)
+ content = self.read_file('packaging/gbp-test-native.changes')
+ ok_(content[1].startswith('- [%s] ' % commit_id))
+
+ def test_option_changelog_revision(self):
+ """Test the --id-len cmdline option"""
+ self.init_test_repo('gbp-test-native')
+
+ # Test invalid format (unknown field)
+ eq_(mock_ch(['--changelog-revision=%(unknown_field)s']), 1)
+ self._check_log(-1, 'gbp:error: Unable to construct revision field')
+
+ # Test acceptable format
+ eq_(mock_ch(['--changelog-revision=foobar']), 0)
+ header = self.read_file('packaging/gbp-test-native.changes')[0]
+ ok_(re.match(r'.+ foobar$', header))
+
+ def test_option_editor_cmd(self):
+ """Test the --editor-cmd and --spawn-editor cmdline options"""
+ repo = self.init_test_repo('gbp-test-native')
+ eq_(mock_ch(['--spawn-editor=release', '--editor-cmd=rm']), 0)
+ eq_(repo.status(), {' D': ['packaging/gbp-test-native.changes']})
+
+ repo.force_head('HEAD', hard=True)
+ ok_(repo.is_clean())
+
+ os.environ['EDITOR'] = 'rm'
+ eq_(mock_ch(['--spawn-editor=always', '--editor-cmd=']),
+ 0)
+
+ def test_user_customizations(self):
+ """Test the user customizations"""
+ repo = self.init_test_repo('gbp-test-native')
+
+ # Non-existent customization file
+ eq_(mock_ch(['--customizations=customizations.py']), 1)
+
+ # Create user customizations file
+ with open('customizations.py', 'w') as fobj:
+ fobj.write("class ChangelogEntryFormatter(object):\n")
+ fobj.write(" @classmethod\n")
+ fobj.write(" def compose(cls, commit_info, **kwargs):\n")
+ fobj.write(" return ['- %s' % commit_info['id']]\n")
+
+ eq_(mock_ch(['--customizations=customizations.py']), 0)
+ entry = self.read_file('packaging/gbp-test-native.changes')[1]
+ sha = repo.rev_parse('HEAD')
+ eq_(entry, '- %s\n' % sha)
+
+ def test_paths(self):
+ """Test tracking of certain paths only"""
+ repo = self.init_test_repo('gbp-test-native')
+ orig_content = self.read_file('packaging/gbp-test-native.changes')
+
+ # Add new commit with known content
+ with open('new-file.txt', 'w') as fobj:
+ fobj.write('this is new content\n')
+ repo.add_files('new-file.txt')
+ repo.commit_staged('Add new file')
+
+ # Only track a non-existent file
+ eq_(mock_ch(['--since=HEAD^', 'non-existent-path']), 0)
+ content = self.read_file('packaging/gbp-test-native.changes')
+ # New lines: header and one empty line, no entries
+ eq_(len(content), len(orig_content) + 2)
+
+ # Track existing file
+ repo.force_head('HEAD', hard=True)
+ eq_(mock_ch(['--since=HEAD^', 'new-file.txt']), 0)
+ content = self.read_file('packaging/gbp-test-native.changes')
+ # New lines: header, one entry line and one empty line
+ eq_(len(content), len(orig_content) + 3)
+
+ def test_commit_guessing(self):
+ """Basic tests for guessing the starting point"""
+ repo = self.init_test_repo('gbp-test-native')
+
+ # Check 'tagname' that is not found
+ eq_(mock_ch(['--changelog-revision=%(tagname)s']), 0)
+ self._check_log(0, 'gbp:warning: Changelog points to tagname')
+
+ # Check 'upstreamversion' and 'release' fields
+ repo.force_head('HEAD', hard=True)
+ eq_(mock_ch(['--changelog-revision=%(upstreamversion)s-%(release)s']),
+ 0)
+
+ def test_commit_guessing_fail(self):
+ """Test for failure of start commit guessing"""
+ self.init_test_repo('gbp-test-native')
+
+ # Add "very old" header to changelog
+ with open('packaging/gbp-test-native.changes', 'w') as ch_fp:
+ ch_fp.write('* Sat Jan 01 2000 User <user@host.com> 123\n- foo\n')
+ # rpm-ch should fail by not being able to find any commits before the
+ # last changelog section
+ eq_(mock_ch([]), 1)
+ self._check_log(-1, "gbp:error: Couldn't determine starting point")
diff --git a/tests/context.py b/tests/context.py
index cc3e25d..413227c 100644
--- a/tests/context.py
+++ b/tests/context.py
@@ -8,8 +8,8 @@ import tempfile
sys.path.insert(0, os.path.abspath('..'))
-import gbp
-import gbp.log
+import gbp # noqa: E402
+import gbp.log # noqa: E402
gbp.log.setup(False, False)
@@ -20,19 +20,22 @@ projectdir = os.path.dirname(os.path.dirname(os.path.abspath(gbp.__file__)))
_chdir_backup = None
_tmpdirs = []
+
def chdir(dir):
global _chdir_backup
if not _chdir_backup:
_chdir_backup = os.path.abspath(os.curdir)
os.chdir(str(dir))
+
def new_tmpdir(name):
global _tmpdirs
- prefix='gbp_%s_' % name
+ prefix = 'gbp_%s_' % name
tmpdir = TmpDir(prefix)
_tmpdirs.append(tmpdir)
return tmpdir
+
def teardown():
if _chdir_backup:
os.chdir(_chdir_backup)
@@ -40,6 +43,7 @@ def teardown():
tmpdir.rmdir()
del _tmpdirs[:]
+
class TmpDir(object):
def __init__(self, suffix='', prefix='tmp'):
diff --git a/tests/doctests/__init__.py b/tests/doctests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/doctests/__init__.py
diff --git a/tests/test_Changelog.py b/tests/doctests/test_Changelog.py
index e66b42f..9525e76 100644
--- a/tests/test_Changelog.py
+++ b/tests/doctests/test_Changelog.py
@@ -3,7 +3,7 @@
"""
Test L{gbp.deb.changelog.ChangeLog}
"""
-from . import context
+from .. import context # noqa: 401
import os
import nose
@@ -30,14 +30,14 @@ git-buildpackage (0.5.31) unstable; urgency=low
-- Guido Günther <agx@sigxcpu.org> Wed, 28 Sep 2011 20:21:34 +0200
"""
-cl_upstream="""python-dateutil (1.0-1) unstable; urgency=low
+cl_upstream = """python-dateutil (1.0-1) unstable; urgency=low
* Initial release (Closes: #386256)
-- Guido Günther <agx@sigxcpu.org> Wed, 6 Sep 2006 10:33:06 +0200
"""
-cl_epoch="""xserver-xorg-video-nv (1:1.2.0-3) unstable; urgency=low
+cl_epoch = """xserver-xorg-video-nv (1:1.2.0-3) unstable; urgency=low
[ Steve Langasek ]
* Upload to unstable
@@ -45,11 +45,13 @@ cl_epoch="""xserver-xorg-video-nv (1:1.2.0-3) unstable; urgency=low
-- David Nusinow <dnusinow@debian.org> Mon, 18 Sep 2006 19:57:45 -0400
"""
+
def setup():
"""Setup test module"""
if not os.path.exists('/usr/bin/debchange'):
raise nose.SkipTest('debchange tool not present')
+
def test_parse_debian_only():
"""
Parse a the changelog of debian only package
@@ -82,6 +84,7 @@ def test_parse_debian_only():
>>> cl.upstream_version
"""
+
def test_parse_no_eopch():
"""
Parse a the changelog of a package without eopch
@@ -118,6 +121,7 @@ def test_parse_no_eopch():
False
"""
+
def test_parse_eopch():
"""
Parse a the changelog of a package without epoch
@@ -155,6 +159,7 @@ def test_parse_eopch():
True
"""
+
def test_parse_name():
"""
Methods tested:
@@ -169,6 +174,7 @@ def test_parse_name():
'git-buildpackage'
"""
+
def test_parse_last_mod():
"""
Test author, email and date of last modification
@@ -191,6 +197,7 @@ def test_parse_last_mod():
'Mon, 17 Oct 2011 10:15:22 +0200'
"""
+
def test_parse_sections():
"""
Test if we can parse sections out of the changelog
@@ -215,9 +222,10 @@ def test_parse_sections():
'0.5.31'
"""
+
def test_add_section():
"""
- Test if we can add a section to an existant changelog
+ Test if we can add a section to an existing changelog
Methods tested:
- L{gbp.deb.changelog.ChangeLog.__init__}
@@ -229,7 +237,7 @@ def test_add_section():
>>> import tempfile
>>> import shutil
>>> import gbp.deb.changelog
- >>> from .testutils import OsReleaseFile
+ >>> from ..testutils import OsReleaseFile
>>> os_release = OsReleaseFile('/etc/lsb-release')
>>> olddir = os.path.abspath(os.path.curdir)
>>> testdir = tempfile.mkdtemp(prefix='gbp-test-changelog-')
@@ -261,9 +269,10 @@ def test_add_section():
>>> shutil.rmtree(testdir, ignore_errors=True)
"""
+
def test_add_entry():
"""
- Test if we can add an entry to an existant changelog
+ Test if we can add an entry to an existing changelog
Methods tested:
- L{gbp.deb.changelog.ChangeLog.__init__}
@@ -275,7 +284,7 @@ def test_add_entry():
>>> import tempfile
>>> import shutil
>>> import gbp.deb.changelog
- >>> from .testutils import OsReleaseFile
+ >>> from ..testutils import OsReleaseFile
>>> os_release = OsReleaseFile('/etc/lsb-release')
>>> olddir = os.path.abspath(os.path.curdir)
>>> testdir = tempfile.mkdtemp(prefix='gbp-test-changelog-')
diff --git a/tests/test_Config.py b/tests/doctests/test_Config.py
index d4291a7..d985d83 100644
--- a/tests/test_Config.py
+++ b/tests/doctests/test_Config.py
@@ -5,7 +5,8 @@ Test L{gbp.config.GbpOptionParser}
Test L{gbp.config.GbpOptionParserDebian}
"""
-from . import context
+from .. import context # noqa: F401
+
def test_option_parser():
"""
@@ -20,6 +21,7 @@ def test_option_parser():
>>> c.add_boolean_config_file_option(option_name='track', dest='track')
"""
+
def test_option_parser_debian():
"""
Methods tested:
@@ -34,6 +36,7 @@ def test_option_parser_debian():
>>> c.add_config_file_option(option_name='builder', dest='builder', help='foo')
"""
+
def test_option_group():
"""
Methods tested:
@@ -47,11 +50,12 @@ def test_option_group():
>>> g.add_boolean_config_file_option(option_name='track', dest='track')
"""
+
def test_tristate():
"""
Methods tested:
- L{gbp.config.GbpOptionParser.add_config_file_option}
-
+
>>> import gbp.config
>>> c = gbp.config.GbpOptionParser('tristate')
>>> c.add_config_file_option(option_name="color", dest="color", type='tristate')
@@ -60,6 +64,7 @@ def test_tristate():
auto
"""
+
def test_filter():
"""
The filter option should always parse as a list
@@ -80,3 +85,19 @@ def test_filter():
['this', 'is', 'a', 'list']
>>> del os.environ['GBP_CONF_FILES']
"""
+
+
+def test_filters():
+ """
+ The filter can be given in plural form
+ >>> import os
+ >>> from gbp.config import GbpOptionParser
+ >>> tmpdir = str(context.new_tmpdir('bar'))
+ >>> confname = os.path.join(tmpdir, 'gbp.conf')
+ >>> GbpOptionParser._set_config_file_value('bar', 'filters', '["abc", "def"]\\n', filename=confname)
+ >>> os.environ['GBP_CONF_FILES'] = confname
+ >>> parser = GbpOptionParser('bar')
+ >>> parser.config['filter']
+ ['abc', 'def']
+ >>> del os.environ['GBP_CONF_FILES']
+ """
diff --git a/tests/test_Control.py b/tests/doctests/test_Control.py
index aad7a98..3e1b082 100644
--- a/tests/test_Control.py
+++ b/tests/doctests/test_Control.py
@@ -4,7 +4,7 @@
Test L{gbp.deb.control.Control}
"""
-from . import context
+from .. import context # noqa: 401
cl_debian = """Source: git-buildpackage
Section: vcs
@@ -40,6 +40,7 @@ Description: Suite to help with Debian packages in Git repositories
* gbp-create-remote-repo: create remote repositories
"""
+
def test_parse_control():
"""
Parse a the control of debian package
@@ -72,6 +73,7 @@ def test_parse_control():
"""
+
def test_no_control_error():
"""
Raise an error if no control file exist or is empty
diff --git a/tests/test_GitModifier.py b/tests/doctests/test_GitModifier.py
index 8e7930e..06a31c7 100644
--- a/tests/test_GitModifier.py
+++ b/tests/doctests/test_GitModifier.py
@@ -4,7 +4,8 @@
Test L{gbp.git.GitModifier}
"""
-from . import context
+from .. import context # noqa: F401
+
def test_author():
"""
@@ -38,6 +39,7 @@ def test_author():
>>> modifier['date']
"""
+
def test_date():
"""
Methods tested:
@@ -69,6 +71,7 @@ def test_date():
'+0000'
"""
+
def test_dict():
"""
Test C{dict} interface
@@ -79,4 +82,3 @@ def test_dict():
>>> sorted(modifier.items())
[('date', '1 +0000'), ('email', 'bar'), ('name', 'foo')]
"""
-
diff --git a/tests/test_GitRepository.py b/tests/doctests/test_GitRepository.py
index fed8b02..bd7c005 100644
--- a/tests/test_GitRepository.py
+++ b/tests/doctests/test_GitRepository.py
@@ -5,21 +5,33 @@ Test L{gbp.git.GitRepository}
This testcase creates several repositores:
- - A repository at L{repo_dir} called I{repo}
- - A bare repository at L{bare_dir} called I{bare}
- - A clone of I{repo} below L{clone_dir} called I{clone}
- - A mirror of I{repo} below L{mirror_clone_dir} called I{mirror}
+ - A repository at I{dirs['repo']} called I{repo}
+ - A bare repository at I{dirs['bare']} called I{bare}
+ - A clone of I{repo} below I{dirs['clone']} called I{clone}
+ - A mirror of I{repo} below I{mirror_dirs['clone']} called I{mirror}
"""
-from . import context
+from .. import context
import gbp.log
gbp.log.setup(color=False, verbose=True)
-repo_dir, bare_dir, clone_dir, mirror_clone_dir = list(map(
- lambda x, tmpdir=context.new_tmpdir(__name__): tmpdir.join(x),
- ['repo', 'bare', 'clone', 'mirror_clone']))
+dirs = {}
+subdirs = ['repo', 'bare', 'clone', 'mirror_clone']
+
+
+def setup_module():
+ tmpdir = context.new_tmpdir(__name__)
+ for s in subdirs:
+ dirs[s] = tmpdir.join(s)
+
+
+def teardown_module():
+ for s in subdirs:
+ del dirs[s]
+ context.teardown()
+
def test_create():
"""
@@ -33,10 +45,10 @@ def test_create():
- L{gbp.git.GitRepository.git_dir}
>>> import os, gbp.git
- >>> repo = gbp.git.GitRepository.create(repo_dir)
- >>> repo.path == repo_dir
+ >>> repo = gbp.git.GitRepository.create(dirs['repo'])
+ >>> repo.path == dirs['repo']
True
- >>> repo.git_dir == os.path.join(repo_dir, '.git')
+ >>> repo.git_dir == os.path.join(dirs['repo'], '.git')
True
>>> type(repo) == gbp.git.GitRepository
True
@@ -52,7 +64,7 @@ def test_empty():
- L{gbp.git.GitRepository.is_empty}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.get_branch()
>>> repo.branch
>>> repo.is_empty()
@@ -73,7 +85,7 @@ def test_add_files():
- L{gbp.git.GitRepository.head}
>>> import gbp.git, shutil, os
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> ret = shutil.copy(os.path.join(repo.path, ".git/HEAD"),
... os.path.join(repo.path, "testfile"))
>>> repo.is_clean()[0]
@@ -97,13 +109,14 @@ def test_branch_master():
Methods tested:
- L{gbp.git.GitRepository.get_branch}
>>> import gbp.git, shutil
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.get_branch()
'master'
>>> repo.branch
'master'
"""
+
def test_clean():
"""
Remove untracked files from the working tree
@@ -112,7 +125,7 @@ def test_clean():
- L{gbp.git.GitRepository.clean}
>>> import gbp.git, shutil, os
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> ret = shutil.copy(os.path.join(repo.path, ".git/HEAD"),
... os.path.join(repo.path, "testclean"))
>>> repo.clean(dry_run=True)
@@ -123,6 +136,7 @@ def test_clean():
True
"""
+
def test_create_branch():
"""
Create a branch name I{foo}
@@ -132,7 +146,7 @@ def test_create_branch():
- L{gbp.git.GitRepository.branch_contains}
>>> import gbp.git, shutil
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.create_branch("foo")
>>> repo.branch_contains("foo", 'HEAD')
True
@@ -140,6 +154,7 @@ def test_create_branch():
False
"""
+
def test_delete_branch():
"""
Create a branch named I{foo2} and delete it
@@ -149,7 +164,7 @@ def test_delete_branch():
- L{gbp.git.GitRepository.delete_branch}
>>> import gbp.git, shutil
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.create_branch("bar")
>>> repo.delete_branch("bar")
>>> repo.delete_branch("master")
@@ -158,6 +173,7 @@ def test_delete_branch():
GitRepositoryError: Can't delete the branch you're on
"""
+
def test_set_branch():
"""
Switch to branch named I{foo}
@@ -168,7 +184,7 @@ def test_set_branch():
- L{gbp.git.GitRepository.branch}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.set_branch("foo")
>>> repo.get_branch() == "foo"
True
@@ -187,7 +203,7 @@ def test_rename_branch():
- L{gbp.git.GitRepository.delete_branch}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.create_branch("baz")
>>> repo.rename_branch("baz", "bax")
>>> repo.delete_branch("bax")
@@ -200,7 +216,7 @@ def test_set_upstream_branch():
>>> import os, shutil
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> os.makedirs(os.path.join(repo.git_dir, 'refs/remotes/origin'))
>>> ret = shutil.copy(os.path.join(repo.git_dir, 'refs/heads/master'), \
os.path.join(repo.git_dir, 'refs/remotes/origin/'))
@@ -216,12 +232,13 @@ def test_set_upstream_branch():
GitRepositoryError: Branch origin/bla doesn't exist!
"""
+
def test_get_upstream_branch():
"""
Get info about upstream branches set in test_set_upstream_branch
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.get_upstream_branch('master')
'origin/master'
>>> repo.get_upstream_branch('foo')
@@ -231,6 +248,7 @@ def test_get_upstream_branch():
GitRepositoryError: Branch bla doesn't exist!
"""
+
def test_tag():
"""
Create a tag named I{tag} and check its existance
@@ -242,7 +260,7 @@ def test_tag():
- L{gbp.git.GitRepository.get_tags}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.create_tag("tag")
>>> repo.has_tag("tag")
True
@@ -259,6 +277,7 @@ def test_tag():
['tag', 'tag2']
"""
+
def test_describe():
"""
Describe commit-ish
@@ -267,7 +286,7 @@ def test_describe():
- L{gbp.git.GitRepository.describe}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> sha = repo.rev_parse('HEAD')
>>> repo.describe('HEAD')
'tag2'
@@ -292,6 +311,7 @@ def test_describe():
>>> repo.create_tag('tag2', msg='foo')
"""
+
def test_find_tag():
"""
Find tags
@@ -300,7 +320,7 @@ def test_find_tag():
- L{gbp.git.GitRepository.find_tag}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.find_tag('HEAD')
'tag2'
>>> repo.find_tag('HEAD', pattern='foo*')
@@ -309,6 +329,7 @@ def test_find_tag():
GitRepositoryError: Can't describe HEAD. Git error: fatal: No names found, cannot describe anything.
"""
+
def test_find_branch_tag():
"""
Find the closest tags on a certain branch to a given commit
@@ -317,7 +338,7 @@ def test_find_branch_tag():
- L{gbp.git.GitRepository.find_branch_tag}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.find_branch_tag('HEAD', 'master', 'tag*')
'tag2'
>>> repo.find_branch_tag('HEAD', 'master', 'v*') # doctest:+ELLIPSIS
@@ -326,6 +347,7 @@ def test_find_branch_tag():
GitRepositoryError: Can't describe .... Git error: fatal: No names found, cannot describe anything.
"""
+
def test_move_tag():
"""
Move a tag
@@ -335,7 +357,7 @@ def test_move_tag():
- L{gbp.git.GitRepository.has_tag}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.move_tag("tag", "moved")
>>> repo.has_tag("tag")
False
@@ -343,6 +365,7 @@ def test_move_tag():
True
"""
+
def test_delete_tag():
"""
Delete tags
@@ -352,7 +375,7 @@ def test_delete_tag():
- L{gbp.git.GitRepository.has_tag}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.has_tag("moved")
True
>>> repo.delete_tag("moved")
@@ -360,6 +383,7 @@ def test_delete_tag():
False
"""
+
def test_get_obj_type():
"""
Find commit SHA1 related to tags
@@ -370,7 +394,7 @@ def test_get_obj_type():
- L{gbp.git.GitRepository.delete_tag}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.create_tag("tag3", "tag msg")
>>> repo.get_obj_type("tag3")
'tag'
@@ -381,6 +405,7 @@ def test_get_obj_type():
>>> repo.delete_tag("tag3")
"""
+
def test_list_files():
"""
List files in the index
@@ -393,7 +418,7 @@ def test_list_files():
- L{gbp.git.GitRepository.force_head}
>>> import gbp.git, os, shutil
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> src = os.path.join(repo.path, ".git/HEAD")
>>> dst = os.path.join(repo.path, "testfile")
>>> repo.list_files()
@@ -426,6 +451,7 @@ def test_list_files():
[]
"""
+
def test_get_commits():
"""
Test listing commits
@@ -434,7 +460,7 @@ def test_get_commits():
- L{gbp.git.GitRepository.get_commits}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> commits = repo.get_commits()
>>> type(commits) == list and len(commits) == 2
True
@@ -466,7 +492,7 @@ def test_get_commit_info():
>>> import gbp.git
>>> from datetime import datetime
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> info = repo.get_commit_info('HEAD')
>>> info['id']
'HEAD'
@@ -491,6 +517,7 @@ def test_get_commit_info():
'foo'
"""
+
def test_diff():
"""
Test git-diff
@@ -499,7 +526,7 @@ def test_diff():
- L{gbp.git.GitRepository.diff}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> len(repo.diff('HEAD~1', 'HEAD')) > 3
True
>>> len(repo.diff('HEAD~1', 'HEAD', 'testfile')) > 3
@@ -512,19 +539,21 @@ def test_diff():
True
"""
+
def test_diff_status():
"""
Methods tested:
- L{gbp.git.GitRepository.diff_status}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.diff_status("HEAD", "HEAD") # doctest:+ELLIPSIS
defaultdict(<... 'list'>, {})
>>> repo.diff_status("HEAD~1", "HEAD") # doctest:+ELLIPSIS
defaultdict(<... 'list'>, {'M': ['testfile']})
"""
+
def test_mirror_clone():
"""
Mirror a repository
@@ -537,9 +566,9 @@ def test_mirror_clone():
- L{gbp.git.GitRepository.branch}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.set_branch('master')
- >>> mirror = gbp.git.GitRepository.clone(mirror_clone_dir, repo.path, mirror=True)
+ >>> mirror = gbp.git.GitRepository.clone(dirs['mirror_clone'], repo.path, mirror=True)
>>> mirror.is_empty()
False
>>> mirror.branch
@@ -554,6 +583,7 @@ def test_mirror_clone():
>>> mirror.force_head('foo^')
"""
+
def test_clone():
"""
Clone a repository
@@ -570,9 +600,9 @@ def test_clone():
- L{gbp.git.GitRepository.has_remote_repo}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.set_branch('master')
- >>> clone = gbp.git.GitRepository.clone(clone_dir, repo.path)
+ >>> clone = gbp.git.GitRepository.clone(dirs['clone'], repo.path)
>>> clone.is_empty()
False
>>> clone.branch
@@ -600,6 +630,7 @@ def test_clone():
False
"""
+
def test_get_remotes():
"""
Merge a branch
@@ -609,19 +640,20 @@ def test_get_remotes():
>>> import os
>>> import gbp.git.repository
- >>> repo = gbp.git.repository.GitRepository(os.path.join(clone_dir, 'repo'))
+ >>> repo = gbp.git.repository.GitRepository(os.path.join(dirs['clone'], 'repo'))
>>> remotes = repo.get_remotes()
>>> len(remotes)
1
>>> origin = remotes['origin']
>>> origin.name
'origin'
- >>> origin.fetch_url == repo_dir
+ >>> origin.fetch_url == dirs['repo']
True
- >>> origin.push_urls == [repo_dir]
+ >>> origin.push_urls == [dirs['repo']]
True
"""
+
def test_merge():
"""
Merge a branch
@@ -631,11 +663,12 @@ def test_merge():
- L{gbp.git.GitRepository.set_branch}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.set_branch('master')
>>> repo.merge('foo')
"""
+
def test_pull():
"""
Pull from a remote repository
@@ -645,7 +678,7 @@ def test_pull():
- L{gbp.git.GitRepository.pull}
>>> import gbp.git, os
- >>> d = os.path.join(clone_dir, 'repo')
+ >>> d = os.path.join(dirs['clone'], 'repo')
>>> clone = gbp.git.GitRepository(d)
>>> clone.set_branch('master')
>>> clone.pull()
@@ -653,6 +686,7 @@ def test_pull():
>>> clone.pull('origin', all_remotes=True)
"""
+
def test_fetch():
"""
Fetch from a remote repository
@@ -665,7 +699,7 @@ def test_fetch():
- L{gbp.git.GitRepository.remove_remote_repo}
>>> import gbp.git, os
- >>> d = os.path.join(clone_dir, 'repo')
+ >>> d = os.path.join(dirs['clone'], 'repo')
>>> clone = gbp.git.GitRepository(d)
>>> clone.fetch()
>>> clone.push()
@@ -676,7 +710,7 @@ def test_fetch():
>>> clone.push_tag('origin', 'tag3')
>>> clone.create_tag('tag4')
>>> clone.push('origin', 'master', tags=True)
- >>> clone.add_remote_repo('foo', repo_dir)
+ >>> clone.add_remote_repo('foo', dirs['repo'])
>>> clone.fetch('foo')
>>> clone.fetch('foo', tags=True)
>>> clone.fetch('foo', refspec='refs/heads/master')
@@ -684,6 +718,7 @@ def test_fetch():
>>> clone.remove_remote_repo('foo')
"""
+
def test_create_bare():
"""
Create a bare repository
@@ -693,10 +728,10 @@ def test_create_bare():
- L{gbp.git.GitRepository.is_empty}
>>> import gbp.git
- >>> bare = gbp.git.GitRepository.create(bare_dir, bare=True, description="msg")
- >>> bare.path == bare_dir
+ >>> bare = gbp.git.GitRepository.create(dirs['bare'], bare=True, description="msg")
+ >>> bare.path == dirs['bare']
True
- >>> bare.git_dir[:-1] == bare_dir
+ >>> bare.git_dir[:-1] == dirs['bare']
True
>>> type(bare) == gbp.git.GitRepository
True
@@ -706,9 +741,10 @@ def test_create_bare():
(True, '')
"""
-def test_nonexistant():
+
+def test_nonexistent():
"""
- Check that accessing a non existant repository fails.
+ Check that accessing a non-existent repository fails.
Methods tested:
- L{gbp.git.GitRepository.__init__}
@@ -720,6 +756,7 @@ def test_nonexistant():
GitRepositoryError: No Git repository at '/does/not/exist'
"""
+
def test_create_noperm():
"""
Check that creating a repository at a path that isn't writeable fails
@@ -734,6 +771,7 @@ def test_create_noperm():
GitRepositoryError: Cannot create Git repository at '/does/not/exist': Permission denied
"""
+
def test_checkout():
"""
Checkout treeishs
@@ -749,7 +787,7 @@ def test_checkout():
- L{gbp.git.GitRepository.tags}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.checkout('master')
>>> repo.branch
'master'
@@ -774,6 +812,7 @@ def test_checkout():
>>> repo.branch
"""
+
def test_gc():
"""
Test garbace collection
@@ -782,10 +821,11 @@ def test_gc():
- L{gbp.git.GitRepository.collect_garbage}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.collect_garbage()
"""
+
def test_grep_log():
"""
Test grepping through commit messages
@@ -794,7 +834,7 @@ def test_grep_log():
- L{gbp.git.GitRepository.grep_log}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.set_branch('master')
>>> len(repo.grep_log('foo')) == 2
True
@@ -808,6 +848,7 @@ def test_grep_log():
GitRepositoryError: Error grepping log for foo: fatal: bad revision 'doesnotexist'
"""
+
def test_is_ff():
"""
Test if branch is fast forwardable
@@ -816,7 +857,7 @@ def test_is_ff():
- L{gbp.git.GitRepository.is_fast_forward}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.is_fast_forward('master', 'foo')
(True, True)
>>> repo.create_branch('ff', 'HEAD^')
@@ -826,6 +867,7 @@ def test_is_ff():
(False, True)
"""
+
def test_update_ref():
"""
Test updating a reference
@@ -834,7 +876,7 @@ def test_update_ref():
- L{gbp.git.GitRepository.update_ref}
>>> import gbp.git, os
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.update_ref('new_ref', 'master', msg='update')
>>> os.path.exists(os.path.join(repo.git_dir, 'new_ref'))
True
@@ -851,7 +893,7 @@ def test_make_tree():
- L{gbp.git.GitRepository.make_tree}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> sha1 = repo.write_file('testfile')
>>> sha1
'19af7398c894bc5e86e17259317e4db519e9241f'
@@ -876,12 +918,13 @@ def test_update_submodules():
- L{gbp.git.GitRepository.update_submodules}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo.has_submodules()
False
>>> repo.update_submodules()
"""
+
def test_get_merge_base():
"""
Find the common ancestor of two objects
@@ -890,7 +933,7 @@ def test_get_merge_base():
- L{gbp.git.GitRepository.get_merge_base}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> sha1 = repo.get_merge_base('master', 'foo')
>>> len(sha1)
40
@@ -900,13 +943,14 @@ def test_get_merge_base():
GitRepositoryError: Failed to get common ancestor: fatal: Not a valid object name doesnotexist
"""
+
def test_status():
r"""
Methods tested:
- L{gbp.git.GitRepository.status}
>>> import gbp.git, os, shutil
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> fname = os.path.join(repo.path, "test_status")
>>> ret = shutil.copy(os.path.join(repo.path, ".git/HEAD"), fname)
>>> list(repo.status().items())
@@ -922,13 +966,14 @@ def test_status():
[('R ', ['test_status\x00test_statusnew'])]
"""
+
def test_cmd_has_feature():
r"""
Methods tested:
- L{gbp.git.GitRepository._cmd_has_feature}
>>> import gbp.git
- >>> repo = gbp.git.GitRepository(repo_dir)
+ >>> repo = gbp.git.GitRepository(dirs['repo'])
>>> repo._cmd_has_feature("commit", "a")
True
>>> repo._cmd_has_feature("commit", "reuse-message")
@@ -951,11 +996,4 @@ def test_cmd_has_feature():
True
"""
-def test_teardown():
- """
- Perform the teardown
-
- >>> context.teardown()
- """
-
# vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·:
diff --git a/tests/test_GitVfs.py b/tests/doctests/test_GitVfs.py
index a88282f..fb845e5 100644
--- a/tests/test_GitVfs.py
+++ b/tests/doctests/test_GitVfs.py
@@ -6,10 +6,11 @@ Test L{gbp.git.GitVfs}
import gbp.log
-from . import context
+from .. import context # noqa: F401
gbp.log.setup(color=False, verbose=True)
+
def test_read():
"""
Create a repository
diff --git a/tests/test_PristineTar.py b/tests/doctests/test_PristineTar.py
index 150dbcf..ab94ca1 100644
--- a/tests/test_PristineTar.py
+++ b/tests/doctests/test_PristineTar.py
@@ -1,5 +1,4 @@
# vim: set fileencoding=utf-8 :
-
"""
Test pristine-tar related methods in
@@ -11,16 +10,26 @@ and
This testcase creates this reposity:
- - A repository at L{repo_dir} called I{repo}
+ - A repository at I{dirs['repo']} called I{repo}
"""
-from . import context
-
import os
+from .. import context
+
-repo_dir = context.new_tmpdir(__name__).join('repo')
test_data = os.path.join(context.projectdir, "tests/test_PristineTar_data")
+dirs = {}
+
+
+def setup_module():
+ dirs['repo'] = context.new_tmpdir(__name__).join('repo')
+
+
+def teardown_module():
+ del dirs['repo']
+ context.teardown()
+
def test_create():
"""
@@ -30,9 +39,10 @@ def test_create():
- L{gbp.deb.git.DebianGitRepository.create}
>>> import os, gbp.deb.git
- >>> repo = gbp.deb.git.DebianGitRepository.create(repo_dir)
+ >>> repo = gbp.deb.git.DebianGitRepository.create(dirs['repo'])
"""
+
def test_empty_repo():
"""
Empty repos have no branch pristine-tar branch
@@ -42,13 +52,14 @@ def test_empty_repo():
- L{gbp.deb.pristinetar.DebianPristineTar.has_commit}
>>> import gbp.deb.git
- >>> repo = gbp.deb.git.DebianGitRepository(repo_dir)
+ >>> repo = gbp.deb.git.DebianGitRepository(dirs['repo'])
>>> repo.has_pristine_tar_branch()
False
>>> repo.pristine_tar.has_commit('upstream', '1.0', 'gzip')
False
"""
+
def test_commit_dir():
"""
Empty repos have no branch pristine-tar branch
@@ -58,11 +69,12 @@ def test_commit_dir():
- L{gbp.git.repository.GitRepository.create_branch}
>>> import gbp.deb.git
- >>> repo = gbp.deb.git.DebianGitRepository(repo_dir)
+ >>> repo = gbp.deb.git.DebianGitRepository(dirs['repo'])
>>> commit = repo.commit_dir(test_data, msg="initial commit", branch=None)
>>> repo.create_branch('upstream')
"""
+
def test_create_tarball():
"""
Create a tarball from a git tree
@@ -71,11 +83,12 @@ def test_create_tarball():
- L{gbp.deb.git.DebianGitRepository.archive}
>>> import gbp.deb.git
- >>> repo = gbp.deb.git.DebianGitRepository(repo_dir)
+ >>> repo = gbp.deb.git.DebianGitRepository(dirs['repo'])
>>> repo.archive('tar', 'upstream/', '../upstream_1.0.orig.tar', 'upstream')
- >>> gbp.command_wrappers.Command('gzip', [ '-n', '%s/../upstream_1.0.orig.tar' % repo_dir])()
+ >>> gbp.command_wrappers.Command('gzip', [ '-n', '%s/../upstream_1.0.orig.tar' % dirs['repo']])()
"""
+
def test_pristine_tar_commit():
"""
Commit the delta to the pristine-tar branch
@@ -84,10 +97,11 @@ def test_pristine_tar_commit():
- L{gbp.deb.pristinetar.DebianPristineTar.commit}
>>> import gbp.deb.git
- >>> repo = gbp.deb.git.DebianGitRepository(repo_dir)
+ >>> repo = gbp.deb.git.DebianGitRepository(dirs['repo'])
>>> repo.pristine_tar.commit('../upstream_1.0.orig.tar.gz', 'upstream')
"""
+
def test_pristine_has_commit():
"""
Find delta on the pristine tar branch
@@ -97,7 +111,7 @@ def test_pristine_has_commit():
- L{gbp.pkg.pristinetar.PristineTar.get_commit}
>>> import gbp.deb.git
- >>> repo = gbp.deb.git.DebianGitRepository(repo_dir)
+ >>> repo = gbp.deb.git.DebianGitRepository(dirs['repo'])
>>> repo.pristine_tar.has_commit('upstream', '1.0', 'bzip2')
False
>>> repo.pristine_tar.has_commit('upstream', '1.0', 'gzip')
@@ -110,6 +124,7 @@ def test_pristine_has_commit():
True
"""
+
def test_pristine_tar_checkout():
"""
Checkout a tarball using pristine-tar
@@ -118,10 +133,11 @@ def test_pristine_tar_checkout():
- L{gbp.deb.pristinetar.DebianPristineTar.checkout}
>>> import gbp.deb.git
- >>> repo = gbp.deb.git.DebianGitRepository(repo_dir)
+ >>> repo = gbp.deb.git.DebianGitRepository(dirs['repo'])
>>> repo.pristine_tar.checkout('upstream', '1.0', 'gzip', '..')
"""
+
def test_pristine_tar_checkout_nonexistent():
"""
Checkout a tarball that does not exist using pristine-tar
@@ -130,7 +146,7 @@ def test_pristine_tar_checkout_nonexistent():
- L{gbp.deb.pristinetar.DebianPristineTar.checkout}
>>> import gbp.deb.git
- >>> repo = gbp.deb.git.DebianGitRepository(repo_dir)
+ >>> repo = gbp.deb.git.DebianGitRepository(dirs['repo'])
>>> repo.pristine_tar.checkout('upstream', '1.1', 'gzip', '..')
Traceback (most recent call last):
...
@@ -138,11 +154,5 @@ def test_pristine_tar_checkout_nonexistent():
pristine-tar: git show refs/heads/pristine-tar:upstream_1.1.orig.tar.gz.delta failed
"""
-def test_teardown():
- """
- Perform the teardown
-
- >>> context.teardown()
- """
# vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·:
diff --git a/tests/doctests/test_create_remote_repo.py b/tests/doctests/test_create_remote_repo.py
new file mode 100644
index 0000000..8188fb3
--- /dev/null
+++ b/tests/doctests/test_create_remote_repo.py
@@ -0,0 +1,122 @@
+# vim: set fileencoding=utf-8 :
+
+from gbp.scripts.create_remote_repo import (build_remote_script, # noqa: F401
+ parse_url) # noqa: F401
+
+
+def test_build_remote_script():
+ """
+ >>> build_remote_script({'base': 'base', 'dir': 'dir', 'pkg': 'pkg', 'template-dir': None, 'bare': True}, 'branch')
+ '\\nset -e\\numask 002\\nif [ -d base"dir" ]; then\\n echo "Repository at "basedir" already exists - giving up."\\n exit 1\\nfi\\nmkdir -p base"dir"\\ncd base"dir"\\ngit init --shared --bare\\necho "pkg packaging" > ./description\\necho "ref: refs/heads/branch" > ./HEAD\\n'
+ """
+
+
+def test_build_remote_script_template_dir():
+ """
+ >>> build_remote_script({'base': 'base', 'dir': 'dir', 'pkg': 'pkg', 'template-dir': '/doesnot/exist', 'bare': True}, 'branch')
+ '\\nset -e\\numask 002\\nif [ -d base"dir" ]; then\\n echo "Repository at "basedir" already exists - giving up."\\n exit 1\\nfi\\nmkdir -p base"dir"\\ncd base"dir"\\ngit init --shared --bare --template=/doesnot/exist\\necho "pkg packaging" > ./description\\necho "ref: refs/heads/branch" > ./HEAD\\n'
+ """
+
+
+def test_build_remote_script_bare():
+ """
+ >>> build_remote_script({'base': 'base', 'dir': 'dir', 'pkg': 'pkg', 'template-dir': None, 'bare': False}, 'branch')
+ '\\nset -e\\numask 002\\nif [ -d base"dir" ]; then\\n echo "Repository at "basedir" already exists - giving up."\\n exit 1\\nfi\\nmkdir -p base"dir"\\ncd base"dir"\\ngit init --shared\\necho "pkg packaging" > .git/description\\necho "ref: refs/heads/branch" > .git/HEAD\\n'
+ """
+
+
+def test_parse_url():
+ """
+ >>> url = parse_url("ssh://host/path/%(pkg)s", "origin", "package")
+ >>> url['base']
+ ''
+ >>> url['dir']
+ '/path/package'
+ >>> url['host']
+ 'host'
+ >>> url['name']
+ 'origin'
+ >>> url['pkg']
+ 'package'
+ >>> url['port']
+ >>> url['scheme']
+ 'ssh'
+ >>> url['template-dir']
+ >>> url['url']
+ 'ssh://host/path/package'
+
+ >>> url = parse_url("ssh://host:22/path/to/repo.git", "origin", "package")
+ >>> url['base']
+ ''
+ >>> url['dir']
+ '/path/to/repo.git'
+ >>> url['host']
+ 'host'
+ >>> url['name']
+ 'origin'
+ >>> url['pkg']
+ 'package'
+ >>> url['port']
+ '22'
+ >>> url['scheme']
+ 'ssh'
+ >>> url['template-dir']
+ >>> url['url']
+ 'ssh://host:22/path/to/repo.git'
+
+ >>> url = parse_url("ssh://host:22/~/path/%(pkg)s.git", "origin", "package")
+ >>> url['dir']
+ 'path/package.git'
+ >>> url['host']
+ 'host'
+ >>> url['name']
+ 'origin'
+ >>> url['pkg']
+ 'package'
+ >>> url['port']
+ '22'
+ >>> url['scheme']
+ 'ssh'
+ >>> url['template-dir']
+ >>> url['url']
+ 'ssh://host:22/~/path/package.git'
+ >>> url['bare']
+ True
+
+ >>> url = parse_url("ssh://host:22/~user/path/%(pkg)s.git", "origin", "package", "/doesnot/exist", bare=False)
+ >>> url['dir']
+ 'path/package.git'
+ >>> url['host']
+ 'host'
+ >>> url['name']
+ 'origin'
+ >>> url['pkg']
+ 'package'
+ >>> url['port']
+ '22'
+ >>> url['scheme']
+ 'ssh'
+ >>> url['template-dir']
+ '/doesnot/exist'
+ >>> url['url']
+ 'ssh://host:22/~user/path/package.git'
+ >>> url['bare']
+ False
+
+ >>> parse_url("git://host/repo.git", "origin", "package")
+ Traceback (most recent call last):
+ ...
+ GbpError: URL must use ssh protocol.
+ >>> parse_url("ssh://host/path/repo", "origin", "package")
+ Traceback (most recent call last):
+ ...
+ GbpError: URL needs to contain either a repository name or '%(pkg)s'
+ >>> parse_url("ssh://host:asdf/path/%(pkg)s.git", "origin", "package")
+ Traceback (most recent call last):
+ ...
+ GbpError: URL contains invalid port.
+ >>> parse_url("ssh://host/~us er/path/%(pkg)s.git", "origin", "package")
+ Traceback (most recent call last):
+ ...
+ GbpError: URL contains invalid ~username expansion.
+ """
diff --git a/tests/test_rpm_changelog.py b/tests/test_rpm_changelog.py
new file mode 100644
index 0000000..3e74804
--- /dev/null
+++ b/tests/test_rpm_changelog.py
@@ -0,0 +1,226 @@
+# vim: set fileencoding=utf-8 :
+#
+# (C) 2014-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, please see
+# <http://www.gnu.org/licenses/>
+"""Test RPM changelog classes and parsing"""
+
+from datetime import datetime
+from nose.tools import assert_raises, eq_, ok_ # pylint: disable=E0611
+from tempfile import NamedTemporaryFile
+
+from gbp.rpm.changelog import _ChangelogHeader, _ChangelogEntry
+from gbp.rpm.changelog import _ChangelogSection, Changelog
+from gbp.rpm.changelog import ChangelogParser, ChangelogError
+from gbp.rpm.policy import RpmPkgPolicy
+
+
+class TestChangelogHeader(object):
+ """Test the _ChangelogHeader class"""
+
+ def test_str_format(self):
+ """Basic test for header"""
+ time = datetime(2014, 01, 29, 12, 13, 14)
+ header = _ChangelogHeader(RpmPkgPolicy, time, name="John Doe",
+ email="user@host.com", revision="1")
+ eq_(str(header), "* Wed Jan 29 2014 John Doe <user@host.com> 1\n")
+
+ def test_str_format_err(self):
+ """Test missing properties"""
+ time = datetime(2014, 01, 29, 12, 13, 14)
+ header = _ChangelogHeader(RpmPkgPolicy, time, name="John", revision="1")
+ with assert_raises(ChangelogError):
+ str(header)
+
+ def test_container(self):
+ """Test the container methods of the class"""
+ header = _ChangelogHeader(RpmPkgPolicy, datetime(2014, 1, 1), name="N",
+ revision="1")
+ # Test __getitem__()
+ eq_(header['name'], "N")
+ eq_(header['email'], None)
+ # Test __contains__()
+ ok_('name' in header)
+ ok_('foo' not in header)
+
+
+class TestChangelogEntry(object):
+ """Test the _ChangelogEntry class"""
+
+ def test_str_format(self):
+ """Basic test"""
+ entry = _ChangelogEntry(RpmPkgPolicy, author="John Doe",
+ text="- foo\n bar")
+ eq_(str(entry), "- foo\n bar\n")
+
+
+class TestChangelogSection(object):
+ """Test the _ChangelogSection class"""
+
+ def setup(self):
+ """Initialize test"""
+ time = datetime(2014, 01, 29, 12, 13, 14)
+ self.default_sect = _ChangelogSection(RpmPkgPolicy, time, name="J. D.",
+ email="u@h", revision="1")
+ entry = _ChangelogEntry(RpmPkgPolicy, "J. D.", "- my change")
+ self.default_sect.entries = [entry]
+
+ def test_str_format(self):
+ """Basic test"""
+ section = self.default_sect
+ eq_(str(section), "* Wed Jan 29 2014 J. D. <u@h> 1\n- my change\n\n")
+
+ def test_append_entry(self):
+ """Test add_entry() method"""
+ section = self.default_sect
+ entry = _ChangelogEntry(RpmPkgPolicy, author="",
+ text="- another\n change")
+ new_entry = section.append_entry(entry)
+ eq_(str(section), "* Wed Jan 29 2014 J. D. <u@h> 1\n- my change\n"
+ "- another\n change\n\n")
+ eq_(new_entry, section.entries[-1])
+
+ def test_set_header(self):
+ """Test set_header() method"""
+ section = self.default_sect
+ time = datetime(2014, 01, 30)
+ section.set_header(time=time, name="Jane", email="u@h", revision="1.1")
+ eq_(str(section), "* Thu Jan 30 2014 Jane <u@h> 1.1\n- my change\n\n")
+
+
+class TestChangelogParser(object):
+ """Test the default changelog parser"""
+
+ cl_default_style = """\
+* Wed Jan 29 2014 Markus Lehtonen <markus.lehtonen@linux.intel.com> 0.3-1
+- Version bump
+- Drop foo.patch
+
+* Tue Jan 28 2014 Markus Lehtonen <markus.lehtonen@linux.intel.com> 0.2
+- Update to 0.2
+
+* Mon Jan 27 2014 Markus Lehtonen <markus.lehtonen@linux.intel.com> 0.1
+- Initial version
+"""
+ cl_with_authors = """\
+* Wed Jan 29 2014 Markus Lehtonen <markus.lehtonen@linux.intel.com> 0.3-1
+[Markus Lehtonen]
+- Version bump
+[John Doe]
+- Bug fix
+"""
+ # Invalid timestamp / name
+ cl_broken_header_1 = """\
+* Wed Jan 29 2014Markus Lehtonen <markus.lehtonen@linux.intel.com> 0.3-1
+- Version bump
+"""
+ # Whitespace before the asterisk in the header
+ cl_broken_header_2 = """\
+ * Wed Jan 29 2014 Markus Lehtonen <markus.lehtonen@linux.intel.com> 0.3-1
+- Version bump
+"""
+ # Invalid timestamp
+ cl_broken_header_3 = """\
+* Wed Jan 32 2014 Markus Lehtonen <markus.lehtonen@linux.intel.com> 0.3-1
+- Version bump
+"""
+ # Missing email
+ cl_broken_header_4 = """\
+* Wed Jan 29 2014 Markus Lehtonen 0.3-1
+- Version bump
+"""
+ # Garbage before section header
+ cl_broken_header_5 = """\
+---garbage---
+* Wed Jan 29 2014 Markus Lehtonen <markus.lehtonen@linux.intel.com> 0.3-1
+- Version bump
+"""
+
+ parser = ChangelogParser(RpmPkgPolicy)
+
+ def test_parse_changelog(self):
+ """Basic tests for successful parsing"""
+ # Raw parsing of changelog
+ changelog = self.parser.raw_parse_string(self.cl_default_style)
+ eq_(len(changelog.sections), 3)
+
+ # Check that re-creating the changelog doesn't mangle it
+ eq_(str(changelog), self.cl_default_style)
+
+ # Parse and check section
+ section = self.parser.parse_section(changelog.sections[0])
+
+ eq_(section.header['time'], datetime(2014, 1, 29))
+ eq_(section.header['name'], "Markus Lehtonen")
+ eq_(section.header['email'], "markus.lehtonen@linux.intel.com")
+ eq_(section.header['revision'], "0.3-1")
+
+ # Check that re-creating section doesn't mangle it
+ eq_(str(section), changelog.sections[0])
+
+ def test_parse_authors(self):
+ """Test parsing of authors from changelog entries"""
+ section = self.parser.parse_section(self.cl_with_authors)
+ eq_(section.entries[0].author, "Markus Lehtonen")
+ eq_(section.entries[1].author, "John Doe")
+
+ def test_parse_changelog_file(self):
+ """Basic tests for parsing a file"""
+ # Create file and parse it
+ tmpfile = NamedTemporaryFile()
+ tmpfile.write(self.cl_default_style)
+ tmpfile.file.flush()
+ changelog = self.parser.raw_parse_file(tmpfile.name)
+ # Check parsing results
+ eq_(len(changelog.sections), 3)
+ eq_(str(changelog), self.cl_default_style)
+ # Cleanup
+ tmpfile.close()
+
+ def test_parse_section_fail(self):
+ """Basic tests for failures of changelog section parsing"""
+ with assert_raises(ChangelogError):
+ self.parser.parse_section(self.cl_broken_header_1)
+
+ with assert_raises(ChangelogError):
+ self.parser.parse_section(self.cl_broken_header_2)
+
+ with assert_raises(ChangelogError):
+ self.parser.parse_section(self.cl_broken_header_3)
+
+ with assert_raises(ChangelogError):
+ self.parser.parse_section(self.cl_broken_header_4)
+
+ def test_parse_changelog_fail(self):
+ """Basic tests for changelog parsing failures"""
+ with assert_raises(ChangelogError):
+ self.parser.raw_parse_string(self.cl_broken_header_5)
+
+
+class TestChangelog(object):
+ """Unit tests for the Changelog class"""
+
+ def basic_test(self):
+ """Test basic initialization"""
+ changelog = Changelog(RpmPkgPolicy)
+ eq_(str(changelog), "")
+
+ def test_add_section(self):
+ """Test the add_section() method"""
+ changelog = Changelog(RpmPkgPolicy)
+ time = datetime(2014, 01, 30)
+ new_section = changelog.add_section(time=time, name="Jane Doe",
+ email="j@doe.com", revision="1.2")
+ eq_(str(changelog), "* Thu Jan 30 2014 Jane Doe <j@doe.com> 1.2\n\n")
+ eq_(new_section, changelog.sections[0])
diff --git a/tests/testutils/__init__.py b/tests/testutils/__init__.py
index 60765af..cc5e4cb 100644
--- a/tests/testutils/__init__.py
+++ b/tests/testutils/__init__.py
@@ -1,6 +1,6 @@
# vim: set fileencoding=utf-8 :
-from .. import context
+from .. import context # noqa: F401
import os
import shutil
@@ -21,6 +21,7 @@ __all__ = ['GbpLogTester', 'DebianGitTestRepo', 'OsReleaseFile',
'MockedChangeLog', 'get_dch_default_urgency', 'capture_stderr',
'ls_dir', 'ls_tar', 'ls_zip']
+
class OsReleaseFile(object):
"""Repesents a simple file with key-value pairs"""
@@ -38,7 +39,7 @@ class OsReleaseFile(object):
self._values[key] = value.strip()
except IOError as err:
gbp.log.info('Failed to read OS release file %s: %s' %
- (filename, err))
+ (filename, err))
def __getitem__(self, key):
if key in self._values:
@@ -54,6 +55,7 @@ class OsReleaseFile(object):
def __repr__(self):
return repr(self._values)
+
class MockedChangeLog(ChangeLog):
contents = """foo (%s) experimental; urgency=low
@@ -61,7 +63,7 @@ class MockedChangeLog(ChangeLog):
-- Debian Maintainer <maint@debian.org> Sat, 01 Jan 2012 00:00:00 +0100"""
- def __init__(self, version, changes = "a important change"):
+ def __init__(self, version, changes="a important change"):
ChangeLog.__init__(self,
contents=self.contents % (version, changes))
@@ -101,6 +103,7 @@ def ls_dir(directory, directories=True):
contents.update(['%s%s' % (prefix, dname) for dname in dirs])
return contents
+
def ls_tar(tarball, directories=True):
"""List the contents of tar archive"""
tmpdir = tempfile.mkdtemp()
@@ -111,6 +114,7 @@ def ls_tar(tarball, directories=True):
finally:
shutil.rmtree(tmpdir)
+
def ls_zip(archive, directories=True):
"""List the contents of zip file"""
tmpdir = tempfile.mkdtemp()
@@ -120,4 +124,3 @@ def ls_zip(archive, directories=True):
return ls_dir(tmpdir, directories)
finally:
shutil.rmtree(tmpdir)
-
diff --git a/tests/testutils/data.py b/tests/testutils/data.py
new file mode 100644
index 0000000..c9e233d
--- /dev/null
+++ b/tests/testutils/data.py
@@ -0,0 +1,35 @@
+# vim: set fileencoding=utf-8 :
+#
+# (C) 2016 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
+# (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, please see
+# <http://www.gnu.org/licenses/>
+
+from functools import wraps
+
+import unittest
+
+
+class TestCaseWithData(unittest.TestCase):
+ @staticmethod
+ def feed(data):
+ def wrapper(fn):
+ @wraps(fn)
+ def feed_item(self, *args):
+ for d in data:
+ try:
+ fn(self, *((d,) + args))
+ except self.failureException as e:
+ raise self.failureException(e.message + " with data %s" % repr(d))
+ return feed_item
+ return wrapper
diff --git a/tests/testutils/debiangittestrepo.py b/tests/testutils/debiangittestrepo.py
index 61456f1..9a9ee07 100644
--- a/tests/testutils/debiangittestrepo.py
+++ b/tests/testutils/debiangittestrepo.py
@@ -7,14 +7,18 @@ import unittest
import gbp.deb.git
+
class DebianGitTestRepo(unittest.TestCase):
"""Scratch repo for a single unit test"""
- def setUp(self):
+ def setUp(self, repo_cls=None):
self.tmpdir = context.new_tmpdir(__name__)
+ if repo_cls is None:
+ repo_cls = gbp.deb.git.DebianGitRepository
+
repodir = self.tmpdir.join('test_repo')
- self.repo = gbp.deb.git.DebianGitRepository.create(repodir)
+ self.repo = repo_cls.create(repodir)
def tearDown(self):
context.teardown()
@@ -36,6 +40,6 @@ class DebianGitTestRepo(unittest.TestCase):
os.makedirs(d)
with open(path, 'w+') as f:
- content == None or f.write(content)
+ content is None or f.write(content)
self.repo.add_files(name, force=True)
self.repo.commit_files(path, msg or "added %s" % name)
diff --git a/tests/testutils/gbplogtester.py b/tests/testutils/gbplogtester.py
index 3b4e92e..6bb173f 100644
--- a/tests/testutils/gbplogtester.py
+++ b/tests/testutils/gbplogtester.py
@@ -6,6 +6,7 @@ from nose.tools import ok_, assert_less
import gbp.log
+
class GbpLogTester(object):
"""
Helper class for tests that need to capture logging output