Commit 47d060a1 authored by Emmanuel Milou's avatar Emmanuel Milou

add files

parent 6c09cc6d
Current authors:
Emmanuel Milou <emmanuel dot milou at savoirfairelinux dot com>
- ALSA implementation ( replaces portaudio )
- Dynamic loading of audio codecs ( shared libraries )
- Debian packages
- GTK client error handling
- Plus many portions of code in sflphoned and sflphone-gtk
- Test and debugging
Alexandre Bourget <alexandre dot bourget at savoirfairelinux dot com>
- IAX implementation
Guillaume Carmel-Archambault <guillaume.carmel-archambault at savoirfairelinux dot com>
- Presence
- Contacts
Yun Liu <yun.liu at savoirfairelinux dot com>
- Change sip library to pjsip
- Support multiple accounts registration
- Add chinese translation
- Many portions of test and debugging
Polytechnic School of Montreal:
- Jean-Francois Blanchard-Dionne <jean-francois.blanchard-dionne at polymtl dot ca>
- Ala Eddine Limame <ala-eddine.limame at polymtl dot ca>
- Alexis S. Bourrelle <bourrelle at polymtl dot ca>
- Marilyne Mercier <marilyne.mercier at polymtl dot ca>
- Jean Tessier <jean.tessier at polymtl dot ca>
- Video layer implementation
- Video conference
Pierre-Luc Beaudoin <pierre-luc.beaudoin at savoirfairelinux dot com>
- Many portions of code
- GTK client implementation
Former authors:
Yan Morin <yan dot morin at savoirfairelinux dot com>
- zeroconf integration
- sflphoned deamon
- add and improve sip core feature
- tests and debugging
Jerome Oufella <jerome dot oufella at savoirfairelinux dot com>
- Many portions of code and bug fixes
Julien Plissonneau Duquene <... at savoirfairelinux dot com>
- autotools cleanups
Jean-Philippe Barrette-LaPierre
- Autotools support and portions of code
Laurielle Lea
- Implementation of SFLphone
Sherry Yang <syangs04 at yahoo dot com>
Imran Akbar <imr at stanford dot edu>
- Working on Win32 port
Mikael Magnusson
#!/usr/bin/python -u
# vim: set fileencoding=utf-8 :
# (C) 2007,2008 Guido Guenther <>
# 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
# 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
"""Generate Debian changelog entries from git commit messages"""
import sys
import re
import os.path
import shutil
import subprocess
import gbp.command_wrappers as gbpc
from gbp.git_utils import (GitRepositoryError, GitRepository, build_tag)
from gbp.config import GbpOptionParser, GbpOptionGroup
from gbp.errors import GbpError
from gbp.deb_utils import parse_changelog
from gbp.command_wrappers import (Command, CommandExecFailed)
snapshot_re = re.compile("\s*\*\* SNAPSHOT build @(?P<commit>[a-z0-9]+)\s+\*\*")
author_re = re.compile('Author: (?P<author>.*) <(?P<email>.*)>')
bug_r = r'(?:bug)?\#?\s?\d+'
bug_re = re.compile(bug_r, re.I)
def system(cmd):
Command(cmd, shell=True)()
except CommandExecFailed:
raise GbpError
def escape_commit(msg):
return msg.replace('"','\\\"').replace("$","\$").replace("`","\`")
def spawn_dch(msg='', author=None, email=None, newversion=False, version=None, release=False, distribution=None):
distopt = ""
versionopt = ""
env = ""
if newversion:
if version:
versionopt = '--newversion=%s' % version
versionopt = '-i'
elif release:
versionopt = "--release"
msg = None
if author and email:
env = """DEBFULLNAME="%s" DEBEMAIL="%s" """ % (author, email)
if distribution:
distopt = "--distribution=%s" % distribution
cmd = '%(env)s dch --no-auto-nmu %(distopt)s %(versionopt)s ' % locals()
if type(msg) == type(''):
cmd += '"%s"' % escape_commit(msg)
def add_changelog_entry(msg, author, email):
"add aa single changelog entry"
spawn_dch(msg=msg, author=author, email=email)
def add_changelog_section(msg, distribution, author=None, email=None, version=None):
"add a new changelog section"
spawn_dch(msg=msg, newversion= True, version=version, author=author, email=email, distribution=distribution)
def fixup_trailer(repo, git_author=False):
"""fixup the changelog trailer's comitter and email address - it might
otherwise point to the last git committer instead of the person creating
the changelog"""
author = email = None
if git_author:
try: author = repo.get_config('')
except KeyError: pass
try: email = repo.get_config('')
except KeyError: pass
spawn_dch(msg='', author=author, email=email)
def head_commit():
"""get the full sha1 of the last commit on HEAD"""
commit = subprocess.Popen([ 'git', 'log', 'HEAD^..' ], stdout=subprocess.PIPE).stdout
sha = commit.readline().split()[-1]
return sha
def snapshot_version(version):
get the current release and snapshot version
Format is <debian-version>~<release>.gbp<short-commit-id>
(release, suffix) = version.rsplit('~', 1)
(snapshot, commit) = suffix.split('.', 1)
if not commit.startswith('gbp'):
raise ValueError
snapshot = int(snapshot)
except ValueError: # not a snapshot release
release = version
snapshot = 0
return release, snapshot
def mangle_changelog(changelog, cp, snapshot=''):
Mangle changelog to either add or remove snapshot markers
@param snapshot: SHA1 if snapshot header should be added/maintained, empty if it should be removed
@type snapshot: str
tmpfile = '%s.%s' % (changelog, snapshot)
cw = file(tmpfile, 'w')
cr = file(changelog, 'r')
cr.readline() # skip version and empty line
print >>cw, "%(Source)s (%(MangledVersion)s) %(Distribution)s; urgency=%(urgency)s\n" % cp
line = cr.readline()
if snapshot_re.match(line):
cr.readline() # consume the empty line after the snapshot header
line = ''
if snapshot:
print >>cw, " ** SNAPSHOT build @%s **\n" % snapshot
if line:
print >>cw, line.rstrip()
shutil.copyfileobj(cr, cw)
os.rename(tmpfile, changelog)
except OSError, e:
raise GbpError, "Error mangling changelog %s" % e
def do_release(changelog, cp):
"remove the snapshot header and set the distribution"
(release, snapshot) = snapshot_version(cp['Version'])
if snapshot:
cp['MangledVersion'] = release
mangle_changelog(changelog, cp)
# <>
# prevent doing a release
# spawn_dch(release=True)
def do_snapshot(changelog, next_snapshot):
Add new snapshot banner to most recent changelog section. The next snapshot
number is calculated by eval()'ing next_snapshot
# commit = head_commit()
cp = parse_changelog(changelog)
# <>
# clean version before generate snapshot
(release, suffix) = version.rsplit('~', 1)
(snapshot, commit) = suffix.split('.', 1)
stripped = str(int(snapshot))
commit = head_commit()
(release, snapshot) = snapshot_version(version)
snapshot = int(eval(next_snapshot))
suffix = "%d.gbp%s" % (snapshot, "".join(commit[0:6]))
cp['MangledVersion'] = "%s~%s" % (release, suffix)
mangle_changelog(changelog, cp, commit)
return snapshot, commit
def get_author(commit):
"""get the author from a commit message"""
for line in commit:
m = author_re.match(line)
if m:
def parse_commit(repo, commitid, options):
"""parse a commit and return message and author"""
msg = ''
thanks = ''
closes = ''
bugs = {}
bts_closes = re.compile(r'(?P<bts>%s):\s+%s' % (options.meta_closes, bug_r), re.I)
commit =
author, email = get_author(commit)
if not author:
raise GbpError, "can't parse author of commit %s" % commit
for line in commit:
if line.startswith(' '): # commit body
line = line[4:]
m = bts_closes.match(line)
if m:
bug_nums = [ bug.strip() for bug in bug_re.findall(line, re.I) ]
bugs['bts')] += bug_nums
except KeyError:
bugs['bts')] = bug_nums
elif line.startswith('Thanks: '):
thanks = line.split(' ', 1)[1].strip()
else: # normal commit message
if options.short and msg:
elif line.strip(): # don't add all whitespace lines
msg += line
# start of diff output:
elif line.startswith('diff '):
if options.meta:
for bts in bugs:
closes += '(%s: %s) ' % (bts, ', '.join(bugs[bts]))
if thanks:
thanks = '- thanks to %s' % thanks
msg += closes + thanks
if options.idlen:
msg = "[%s] " % commitid[0:options.idlen] + msg
return msg, (author, email)
def shortlog_to_dch(repo, commits, options):
"""convert the changes in git shortlog format to debian changelog format"""
author = 'Unknown'
for commit in commits:
msg, (author, email) = parse_commit(repo, commit, options)
add_changelog_entry(msg, author, email)
def guess_snapshot_commit(cp):
"""guess the last commit documented in the changelog from the snapshot banner"""
sr =, cp['Changes'])
if sr:
def main(argv):
ret = 0
changelog = 'debian/changelog'
until = 'HEAD'
found_snapshot_header = False
first_commit = None
parser = GbpOptionParser(command=os.path.basename(argv[0]), prefix='',
usage='%prog [options] paths')
range_group = GbpOptionGroup(parser, "commit range options", "which commits to add to the changelog")
version_group = GbpOptionGroup(parser, "release & version number options", "what version number and release to use")
commit_group = GbpOptionGroup(parser, "commit message formatting", "howto format the changelog entries")
naming_group = GbpOptionGroup(parser, "branch and tag naming", "branch names and tag formats")
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'")
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_option("-v", "--verbose", action="store_true", dest="verbose", default=False,
help="verbose command execution")
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")
version_group.add_option("-R", "--release", action="store_true", dest="release", default=False,
help="mark as release")
version_group.add_option("-S", "--snapshot", action="store_true", dest="snapshot", default=False,
help="mark as snapshot build")
version_group.add_option("-N", "--new-version", dest="new_version",
help="use this as base for the new version number")
version_group.add_config_file_option(option_name="git-author", dest="git_author", action="store_true")
version_group.add_config_file_option(option_name="no-git-author", dest="git_author", action="store_false")
commit_group.add_config_file_option(option_name="meta", dest="meta",
help="parse meta tags in commit messages, default is '%(meta)s'", action="store_true")
commit_group.add_config_file_option(option_name="meta-closes", dest="meta_closes",
help="Meta tags for the bts close commands, default is '%(meta-closes)s'")
commit_group.add_option("--full", action="store_false", dest="short", default=True,
help="include the full commit message instead of only the first line")
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")
(options, args) = parser.parse_args(argv[1:])
if options.snapshot and options.release:
parser.error("'--snapshot' and '--release' are incompatible options")
if options.since and
parser.error("'--since' and '--auto' are incompatible options")
if options.verbose:
gbpc.Command.verbose = True
repo = GitRepository('.')
except GitRepositoryError:
raise GbpError, "%s is not a git repository" % (os.path.abspath('.'))
branch = repo.get_branch()
if options.debian_branch != branch:
print >>sys.stderr, "You are not on branch '%s' but on '%s'" % (options.debian_branch, branch)
raise GbpError, "Use --debian-branch to set the branch to pick changes from"
cp = parse_changelog(changelog)
if options.since:
since = options.since
since = ''
since = guess_snapshot_commit(cp)
if since:
print "Continuing from commit '%s'" % since
found_snapshot_header = True
print "Couldn't find snapshot header, using version info"
if not since:
since = build_tag(options.debian_tag, cp['Version'])
if args:
print "Only looking for changes on '%s'" % " ".join(args)
commits = repo.commits(since, until, " ".join(args), options.git_log.split(" "))
# add a new changelog section if:
if cp['Distribution'] != "UNRELEASED" and not found_snapshot_header and commits:
# the last version was a release and we have pending commits
add_section = True
elif options.new_version or not found_snapshot_header:
# the user wants to force a new version or switch to snapshot mode
add_section = True
add_section = False
if add_section:
if commits:
first_commit = commits[0]
commits = commits[1:]
commit_msg, (commit_author, commit_email) = parse_commit(repo, first_commit, options)
commit_msg = "UNRELEASED"
commit_author = None
commit_email = None
add_changelog_section(distribution="UNRELEASED", msg=commit_msg,
version=options.new_version, author=commit_author,
if commits:
shortlog_to_dch(repo, commits, options)
fixup_trailer(repo, git_author=options.git_author)
elif not first_commit:
print "No changes detected from %s to %s." % (since, until)
if options.release:
do_release(changelog, cp)
elif options.snapshot:
(snap, version) = do_snapshot(changelog, options.snapshot_number)
print "Changelog has been prepared for snapshot #%d at %s" % (snap, version)
except (GbpError, GitRepositoryError), err:
if len(err.__str__()):
print >>sys.stderr, err
ret = 1
return ret
if __name__ == "__main__":
# vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·:
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment