On Sat, May 19, 2012 at 03:23:36PM +0200, Daniel Dehennin wrote:
[..snip..] 
> +            if cp.is_empty():
> +                msg = ["New debian/changelog generated by git-dch."]
> +            else:
> +                msg=["UNRELEASED"]
> +            add_changelog_section(distribution="UNRELEASED", msg=msg,
>                                    version=version_change,
>                                    dch_options=dch_options,
>                                    repo=repo,

Leaving the UNRELEASED looks more consistent to me.
Cheers,
 -- Guido

> 
> 
> Regards.
> 
> The following changes since commit 33796f8278e4b7e81674fa7e7f90cfb076804147:
> 
>   Add minimalist debian/control object. (2012-05-18 23:35:18 +0200)
> 
> are available in the git repository at:
> 
>   git://git.baby-gnu.net/git-buildpackage 
> tags/dad/create-inexistant-changelog/rebased/on-33796f8
> 
> for you to fetch changes up to 48a9ba5b6c8f1fd3ed9e946281b82447caadad0e:
> 
>   Create debian/changelog if it does not exist. (2012-05-19 15:05:20 +0200)
> 
> ----------------------------------------------------------------
> This version of the patch is based on dad/add-minimalist-control-object/1.
> 
> Moving spawn_dch around was not necessary, nor the ChangeLogSection.
> 
> It pass full tests.
> 
> ----------------------------------------------------------------
> Daniel Dehennin (1):
>       Create debian/changelog if it does not exist.
> 
>  gbp/deb/changelog.py              |   98 +++++++++++++++++------------
>  gbp/scripts/dch.py                |   40 ++++++++++--
>  tests/11_test_changelog_create.py |  123 
> +++++++++++++++++++++++++++++++++++++
>  3 files changed, 216 insertions(+), 45 deletions(-)
>  create mode 100644 tests/11_test_changelog_create.py
> 
> 
> PATCHES:
> ========
> 
> From 33796f8278e4b7e81674fa7e7f90cfb076804147 Mon Sep 17 00:00:00 2001
> From: Daniel Dehennin <[email protected]>
> Date: Fri, 18 May 2012 19:42:16 +0200
> Subject: [PATCH 1/2] Add minimalist debian/control object.
> 
> * gbp/deb/control.py: New class Control with "name" property to get
>   package source name.
> ---
>  gbp/deb/control.py |   63 
> ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 63 insertions(+)
>  create mode 100644 gbp/deb/control.py
> 
> diff --git a/gbp/deb/control.py b/gbp/deb/control.py
> new file mode 100644
> index 0000000..f048f33
> --- /dev/null
> +++ b/gbp/deb/control.py
> @@ -0,0 +1,63 @@
> +# vim: set fileencoding=utf-8 :
> +#
> +# (C) 2012 Daniel Dehennin <[email protected]>
> +#    This program is free software; you can redistribute it and/or modify
> +#    it under the terms of the GNU General Public License as published by
> +#    the Free Software Foundation; either version 2 of the License, or
> +#    (at your option) any later version.
> +#
> +#    This program is distributed in the hope that it will be useful,
> +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
> +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +#    GNU General Public License for more details.
> +#
> +#    You should have received a copy of the GNU General Public License
> +#    along with this program; if not, write to the Free Software
> +#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  
> USA
> +"""A Debian Control"""
> +
> +import email
> +import os
> +
> +class NoControlError(Exception):
> +    """No control found"""
> +    pass
> +
> +class ParseControlError(Exception):
> +    """Problem parsing control"""
> +    pass
> +
> +class Control(object):
> +    """A Debian control"""
> +
> +    def __init__(self, filename="debian/control"):
> +        """
> +        Parse an existing control file.
> +
> +        @param filename: name of the control file
> +        @type filename: C{str}
> +        @return: Control object
> +        @rtype: C{gbp.deb.conrol.Control} object
> +        """
> +        if not os.access(filename, os.F_OK):
> +            raise NoControlError("Control file %s does not exist" % filename)
> +
> +        self.filename = filename
> +        with file(filename) as f:
> +            control = email.message_from_file(f)
> +
> +        if not control.items():
> +            raise ParseControlError("Empty control file")
> +
> +        self._control = control
> +
> +    # def __getitem__(self, item):
> +    #     return self._control[item]
> +
> +    # def __setitem__(self, item, value):
> +    #     self._control[item] = value
> +
> +    @property
> +    def name(self):
> +        """The packges name"""
> +        return self._control['Source']
> -- 
> 1.7.10
> 
> 
> From 48a9ba5b6c8f1fd3ed9e946281b82447caadad0e Mon Sep 17 00:00:00 2001
> From: Daniel Dehennin <[email protected]>
> Date: Mon, 14 May 2012 18:15:06 +0200
> Subject: [PATCH 2/2] Create debian/changelog if it does not exist.
> 
> The main purpose of this patch is to permit the creation of an empty
> changelog object.
> 
> An empty ChangeLog object can be created if the changelog file is
> inexistant, null size is not enought for "dch --create".
> 
> The main difference results in the need to:
> - guess the version number if none was provided on the command line
> - try harder to guess the commit to start from
> - take care of access to inexistant ChangeLog attributes.
> 
> * tests/11_test_changelog_create.py: Test several senarios of
>   debian/changelog creation.
> 
> * gbp/deb/changelog.py (__init__): Default changelog filename to
>   "debian/changelog". Permit to create empty changelog, take care that
>   cp['Changes'] and cp['Version'] must be strings.
>   (is_empty): Test if the changelog is present, the dch tool only support
>   "--create" when the changelog file is absent, not if its size is null.
> 
> * gbp/scripts/dch.py: Import new gbp.deb.control.
>   (spawn_dch): Set environnement variable EDITOR to /bin/true when
>   calling dch with "--create".
>   (add_changelog_section): We need to guess version from upstream is the
>   changelog is empty and no version was provided. Take care to create the
>   changelog if it's empty.
>   (guess_snapshot_commit): Can not call repo.find_version() if the
>   changelog is empty.
>   (guess_version_from_upstream): cp is None when called by
>   ChangeLog.create().
>   (main): Require the options "upstream-tree" and "upstream-branch".
>   Try hard to guess the last commit, last to merge-base.
> ---
>  gbp/deb/changelog.py              |   98 +++++++++++++++++------------
>  gbp/scripts/dch.py                |   40 ++++++++++--
>  tests/11_test_changelog_create.py |  123 
> +++++++++++++++++++++++++++++++++++++
>  3 files changed, 216 insertions(+), 45 deletions(-)
>  create mode 100644 tests/11_test_changelog_create.py
> 
> diff --git a/gbp/deb/changelog.py b/gbp/deb/changelog.py
> index 7dc51d9..dec8fc3 100644
> --- a/gbp/deb/changelog.py
> +++ b/gbp/deb/changelog.py
> @@ -62,55 +62,66 @@ class ChangeLogSection(object):
>  class ChangeLog(object):
>      """A Debian changelog"""
>  
> -    def __init__(self, contents=None, filename=None):
> +    def __init__(self, contents=None, filename="debian/changelog"):
>          """
>          Parse an existing changelog, Either contents, containing the contents
>          of a changelog file, or filename, pointing to a changelog file must 
> be
>          passed.
>          """
> -        # Check that either contents or filename is passed (but not both)
> -        if (not filename and not contents) or (filename and contents):
> -            raise Exception("Either filename or contents must be passed")
> -
> -        # If a filename was passed, check if it exists
> -        if filename and not os.access(filename, os.F_OK):
> -            raise NoChangeLogError, "Changelog %s not found" % (filename, )
> -
> -        # If no filename was passed, let's read from stdin
> -        if not filename:
> -            filename = '-'
> -
> -        # Note that if contents is None, stdin will just be closed right
> -        # away by communicate.
> -        cmd = subprocess.Popen(['dpkg-parsechangelog', '-l%s' % filename],
> -                                stdin=subprocess.PIPE,
> -                                stdout=subprocess.PIPE,
> -                                stderr=subprocess.PIPE)
> -        (output, errors) = cmd.communicate(contents)
> -        if cmd.returncode:
> -            raise ParseChangeLogError("Failed to parse changelog. "
> -                                      "dpkg-parsechangelog said:\n%s" % 
> (errors, ))
> -        # Parse the result of dpkg-parsechangelog (which looks like
> -        # email headers)
> -        cp = email.message_from_string(output)
> -        try:
> -            if ':' in cp['Version']:
> -                cp['Epoch'], cp['NoEpoch-Version'] = 
> cp['Version'].split(':', 1)
> -            else:
> -                cp['NoEpoch-Version'] = cp['Version']
> -            if '-' in cp['NoEpoch-Version']:
> -                cp['Upstream-Version'], cp['Debian-Version'] = 
> cp['NoEpoch-Version'].rsplit('-', 1)
> -            else:
> -                cp['Debian-Version'] = cp['NoEpoch-Version']
> -        except TypeError:
> -            raise ParseChangeLogError, output.split('\n')[0]
>  
> -        self._cp = cp
> +        # Parse contents first or filename if non empty.
> +        empty = False
>          if contents:
> +            read_from = '-'
>              self._contents = contents[:]
> -        else:
> +        elif os.access(filename, os.F_OK) and os.stat(filename).st_size > 0:
> +            read_from = filename
>              with file(filename) as f:
>                  self._contents = f.read()
> +        elif os.access(os.path.realpath(os.path.dirname(filename)), os.W_OK):
> +            # Use os.path.realpath to cope with
> +            # os.path.dirname('changelog') returning ''
> +            #
> +            # Empty changelog but can be created
> +            empty = True
> +        else:
> +            raise NoChangeLogError("Empty contents and changelog %s, parent 
> changelog directory not writable" % filename)
> +
> +        output = ''
> +        if not empty:
> +            # Note that if contents is None, stdin will just be closed right
> +            # away by communicate.
> +            cmd = subprocess.Popen(['dpkg-parsechangelog', '-l%s' % 
> read_from],
> +                                   stdin=subprocess.PIPE,
> +                                   stdout=subprocess.PIPE,
> +                                   stderr=subprocess.PIPE)
> +            (output, errors) = cmd.communicate(contents)
> +            if cmd.returncode:
> +                raise ParseChangeLogError("Failed to parse changelog. "
> +                                          "dpkg-parsechangelog said:\n%s" % 
> (errors, ))
> +
> +        # Parse the result of dpkg-parsechangelog (which looks like
> +        # email headers)
> +        cp = email.message_from_string(output)
> +
> +        if not empty:
> +            try:
> +                if ':' in cp['Version']:
> +                    cp['Epoch'], cp['NoEpoch-Version'] = 
> cp['Version'].split(':', 1)
> +                else:
> +                    cp['NoEpoch-Version'] = cp['Version']
> +                if '-' in cp['NoEpoch-Version']:
> +                    cp['Upstream-Version'], cp['Debian-Version'] = 
> cp['NoEpoch-Version'].rsplit('-', 1)
> +                else:
> +                    cp['Debian-Version'] = cp['NoEpoch-Version']
> +            except TypeError:
> +                raise ParseChangeLogError, output.split('\n')[0]
> +        else:
> +            cp['Changes'] = ''
> +            cp['Version'] = ''
> +
> +        self._cp = cp
> +        self.filename = filename
>  
>      def __getitem__(self, item):
>          return self._cp[item]
> @@ -204,3 +215,12 @@ class ChangeLog(object):
>          Get sections in the changelog
>          """
>          return list(self.sections_iter)
> +
> +    def is_empty(self):
> +        """
> +        Whether the changelog file does not exist
> +
> +        @return: C{True} if the changelog file is missing, C{False} otherwise
> +        @rtype: C{bool}
> +        """
> +        return not os.access(self.filename, os.F_OK)
> diff --git a/gbp/scripts/dch.py b/gbp/scripts/dch.py
> index 14dff29..e8b2817 100644
> --- a/gbp/scripts/dch.py
> +++ b/gbp/scripts/dch.py
> @@ -31,6 +31,7 @@ from gbp.errors import GbpError
>  from gbp.deb import compare_versions
>  from gbp.deb.git import GitRepositoryError, DebianGitRepository
>  from gbp.deb.changelog import ChangeLog, NoChangeLogError
> +from gbp.deb.control import Control
>  
>  user_customizations = {}
>  snapshot_re = re.compile("\s*\*\* SNAPSHOT build 
> @(?P<commit>[a-z0-9]+)\s+\*\*")
> @@ -75,6 +76,9 @@ def spawn_dch(msg=[], author=None, email=None, 
> newversion=False, version=None,
>      if author and email:
>          env = """DEBFULLNAME="%s" DEBEMAIL="%s" """ % (author, email)
>  
> +    if dch_options.find("--create") != -1:
> +        env += "EDITOR=/bin/true"
> +
>      if distribution:
>          distopt = "--distribution=%s" % distribution
>  
> @@ -124,10 +128,14 @@ def guess_version_from_upstream(repo, 
> upstream_tag_format, cp):
>  def add_changelog_section(msg, distribution, repo, options, cp,
>                            author=None, email=None, version={}, 
> dch_options=''):
>      """Add a new section to the changelog"""
> -    if not version and not cp.is_native():
> +    if not version and (cp.is_empty() or not cp.is_native()):
>          v = guess_version_from_upstream(repo, options.upstream_tag, cp)
>          if v:
>              version['version'] = v
> +    if cp.is_empty():
> +        control = Control()
> +        dch_options += " --create --package=%s" % control.name
> +
>      spawn_dch(msg=msg, newversion=True, version=version, author=author,
>                email=email, distribution=distribution, 
> dch_options=dch_options)
>  
> @@ -269,7 +277,7 @@ def guess_snapshot_commit(cp, repo, options):
>      # If the current topmost changelog entry has already been tagged rely on
>      # the version information only. The upper level relies then on the 
> version
>      # info anyway:
> -    if repo.find_version(options.debian_tag, cp.version):
> +    if not cp.is_empty() and repo.find_version(options.debian_tag, 
> cp.version):
>          return None
>      # If we didn't find a snapshot header we look at the point the changelog
>      # was last touched.
> @@ -357,6 +365,8 @@ def main(argv):
>      parser.add_option_group(custom_group)
>  
>      parser.add_boolean_config_file_option(option_name = "ignore-branch", 
> dest="ignore_branch")
> +    naming_group.add_config_file_option(option_name="upstream-tree", 
> dest="upstream_tree")
> +    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")
> @@ -429,7 +439,7 @@ def main(argv):
>              since = options.since
>          else:
>              since = ''
> -            if options.auto:
> +            if options.auto or cp.is_empty():
>                  since = guess_snapshot_commit(cp, repo, options)
>                  if since:
>                      gbp.log.info("Continuing from commit '%s'" % since)
> @@ -437,7 +447,24 @@ def main(argv):
>                  else:
>                      gbp.log.info("Couldn't find snapshot header, using 
> version info")
>              if not since:
> -                since = repo.find_version(options.debian_tag, cp['Version'])
> +                # Take care of empty debian/changelog
> +                if cp.is_empty():
> +                    pattern = options.upstream_tag % dict(version='*')
> +                    upstream = None
> +                    try:
> +                        upstream = repo.find_tag('HEAD', pattern=pattern)
> +                        gbp.log.debug('Found upstream tag %s' % upstream)
> +                    except GitRepositoryError:
> +                        gbp.log.debug('No upstream tag found, try upstream 
> branch')
> +                    if upstream == None or options.upstream_tree == 'branch':
> +                        upstream = options.upstream_branch
> +                    since = repo.get_merge_base('HEAD', upstream)
> +                    gbp.log.debug("Found merge-base %s" % since)
> +                    if since and options.snapshot:
> +                        # Snapshot can not be guessed
> +                        found_snapshot_header = True
> +                else:
> +                    since = repo.find_version(options.debian_tag, 
> cp['Version'])
>                  if not since:
>                      raise GbpError, "Version %s not found" % cp['Version']
>  
> @@ -448,16 +475,17 @@ def main(argv):
>          commits.reverse()
>  
>          # add a new changelog section if:
> -        if options.new_version or options.bpo or options.nmu or options.qa:
> +        if cp.is_empty() or options.new_version or options.bpo or 
> options.nmu or options.qa:
>              if options.bpo:
>                  version_change['increment'] = '--bpo'
>              elif  options.nmu:
>                  version_change['increment'] = '--nmu'
>              elif  options.qa:
>                  version_change['increment'] = '--qa'
> -            else:
> +            elif options.new_version:
>                  version_change['version'] = options.new_version
>              # the user wants to force a new version
> +            # or the changelog was empty and we need to guess version
>              add_section = True
>          elif cp['Distribution'] != "UNRELEASED" and not 
> found_snapshot_header and commits:
>              # the last version was a release and we have pending commits
> diff --git a/tests/11_test_changelog_create.py 
> b/tests/11_test_changelog_create.py
> new file mode 100644
> index 0000000..b613ce5
> --- /dev/null
> +++ b/tests/11_test_changelog_create.py
> @@ -0,0 +1,123 @@
> +# vim: set fileencoding=utf-8 :
> +
> +"""Test L{Changelog}'s create"""
> +
> +import unittest
> +
> +from testutils import DebianGitTestRepo
> +
> +from gbp.scripts import dch
> +from gbp.deb.changelog import ChangeLog
> +
> +import os
> +import re
> +
> +snap_header = 
> r'^test-package\s\(1.0-1~1\.gbp([0-9a-f]{6})\)\sUNRELEASED;\surgency=low'
> +snap_mark = r'\s{2}\*{2}\sSNAPSHOT\sbuild\s@'
> +
> +class TestScriptDch(DebianGitTestRepo):
> +    """Test git-dch"""
> +
> +    def setUp(self):
> +        DebianGitTestRepo.setUp(self)
> +        self.add_file("foo", "bar")
> +        self.repo.create_tag("upstream/1.0", msg="upstream version 1.0")
> +        self.repo.create_branch("debian")
> +        self.repo.set_branch("debian")
> +        self.upstream_tag = "upstream/%(version)s"
> +        self.top = os.path.abspath(os.path.curdir)
> +        os.mkdir(os.path.join(self.repo.path, "debian"))
> +        os.chdir(self.repo.path)
> +        self.add_file("debian/control", """Source: test-package\nSection: 
> test\n""")
> +
> +    def tearDown(self):
> +        os.chdir(self.top)
> +        DebianGitTestRepo.tearDown(self)
> +
> +    def test_create_from_dch_main(self):
> +        """Test dch.py like git-dch script does: must not include upstream 
> log in debian/changelog"""
> +        ret = dch.main(["--upstream-tag=%s" % self.upstream_tag, 
> "--debian-branch=debian"])
> +        self.assertEqual(ret, 0)
> +        lines = file("debian/changelog").readlines()
> +        assert "test-package (1.0-1) UNRELEASED; urgency=low\n" in lines
> +        assert """  * added debian/control\n""" in lines
> +
> +    def test_create_from_dch_main_with_auto(self):
> +        """Test dch.py like git-dch script does: guess last commit"""
> +        ret = dch.main(["--upstream-tag=%s" % self.upstream_tag, 
> "--debian-branch=debian", "-a"])
> +        self.assertEqual(ret, 0)
> +        lines = file("debian/changelog").readlines()
> +        assert "test-package (1.0-1) UNRELEASED; urgency=low\n" in lines
> +        assert """  * added debian/control\n""" in lines
> +
> +    def test_create_from_dch_main_with_snapshot(self):
> +        """Test dch.py like git-dch script does: snashot mode"""
> +        ret = dch.main(["--upstream-tag=%s" % self.upstream_tag, 
> "--debian-branch=debian", "-S"])
> +        self.assertEqual(ret, 0)
> +        lines = file("debian/changelog").readlines()
> +        header = re.search(snap_header, lines[0])
> +        self.assertEqual(header.lastindex, 1)
> +        assert re.search(snap_mark + header.group(1), lines[2])
> +        assert """  * added debian/control\n""" in lines
> +
> +    def test_create_from_dch_main_after_delete(self):
> +        """Test dch.py like git-dch script does: debian/changelog was 
> deleted"""
> +        self.add_file("debian/changelog", "fake")
> +        self.repo.remove_files("debian/changelog")
> +        self.repo.commit_files(self.repo.path, "removed debian/changelog")
> +        ret = dch.main(["--upstream-tag=%s" % self.upstream_tag, 
> "--debian-branch=debian"])
> +        self.assertEqual(ret, 0)
> +        lines = file("debian/changelog").readlines()
> +        assert "test-package (1.0-1) UNRELEASED; urgency=low\n" in lines
> +        assert """  * removed debian/changelog\n""" not in lines
> +        assert """  * UNRELEASED\n""" in lines
> +
> +    def test_create_from_dch_main_with_auto_snapshot(self):
> +        """Test dch.py like git-dch script does: guess last commit, 
> snashot"""
> +        ret = dch.main(["--upstream-tag=%s" % self.upstream_tag, 
> "--debian-branch=debian", "-a", "-S"])
> +        self.assertEqual(ret, 0)
> +        lines = file("debian/changelog").readlines()
> +        header = re.search(snap_header, lines[0])
> +        self.assertEqual(header.lastindex, 1)
> +        assert re.search(snap_mark + header.group(1), lines[2])
> +        assert """  * added debian/control\n""" in lines
> +
> +    def test_create_from_dch_main_with_auto_after_delete(self):
> +        """Test dch.py like git-dch script does: guess last commit, 
> debian/changelog was deleted"""
> +        self.add_file("debian/changelog", "fake")
> +        self.repo.remove_files("debian/changelog")
> +        self.repo.commit_files(self.repo.path, "removed debian/changelog")
> +        ret = dch.main(["--upstream-tag=%s" % self.upstream_tag, 
> "--debian-branch=debian", "-a"])
> +        self.assertEqual(ret, 0)
> +        lines = file("debian/changelog").readlines()
> +        assert "test-package (1.0-1) UNRELEASED; urgency=low\n" in lines
> +        assert """  * removed debian/changelog\n""" not in lines
> +        assert """  * UNRELEASED\n""" in lines
> +
> +    def test_create_from_dch_main_with_snapshot_after_delete(self):
> +        """Test dch.py like git-dch script does: snapshot, debian/changelog 
> was deleted"""
> +        self.add_file("debian/changelog", "fake")
> +        self.repo.remove_files("debian/changelog")
> +        self.repo.commit_files(self.repo.path, "removed debian/changelog")
> +        ret = dch.main(["--upstream-tag=%s" % self.upstream_tag, 
> "--debian-branch=debian", "-S"])
> +        self.assertEqual(ret, 0)
> +        lines = file("debian/changelog").readlines()
> +        header = re.search(snap_header, lines[0])
> +        self.assertEqual(header.lastindex, 1)
> +        assert re.search(snap_mark + header.group(1), lines[2])
> +        assert """  * removed debian/changelog\n""" not in lines
> +        assert """  * UNRELEASED\n""" in lines
> +
> +    def test_create_from_dch_main_with_auto_snapshot_after_delete(self):
> +        """Test dch.py like git-dch script does: guess last commit, 
> snapshot, debian/changelog was deleted"""
> +        self.add_file("debian/changelog", "fake")
> +        self.repo.remove_files("debian/changelog")
> +        self.repo.commit_files(self.repo.path, "removed debian/changelog")
> +        ret = dch.main(["--upstream-tag=%s" % self.upstream_tag, 
> "--debian-branch=debian", "-a", "-S"])
> +        self.assertEqual(ret, 0)
> +        lines = file("debian/changelog").readlines()
> +        header = re.search(snap_header, lines[0])
> +        self.assertEqual(header.lastindex, 1)
> +        assert re.search(snap_mark + header.group(1), lines[2])
> +        assert """  * removed debian/changelog\n""" not in lines
> +        assert """  * UNRELEASED\n""" in lines
> -- 
> 1.7.10
> 
> 
> -- 
> Daniel Dehennin
> Récupérer ma clef GPG:
> gpg --keyserver pgp.mit.edu --recv-keys 0x7A6FE2DF





--
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]

Reply via email to