"""Do a source release for Gentoo (release a versioned ebuild file)"""
+import datetime
import glob
import logging
import optparse
GITWEB_RE = r'^((file://|git\+ssh://[A-Za-z.:@]+)?/srv/git|git://[A-Za-z.:@]+)'
GITWEB_URL = 'http://git'
+ENV_AUTODECREMENT = "AUTODECREMENT"
+ENV_AUTOINCREMENT = "AUTOINCREMENT"
ENV_CATEGORY = "CATEGORY"
ENV_CHROOT = "CHROOT_NAME"
ENV_CHROOT_USER = "CHROOT_USER"
ENV_RELEASE_BRANCH = "RELEASE_BRANCH"
ENV_RELEASE_REPO = "RELEASE_REPO"
ENV_VARIABLES = [
+ ENV_AUTODECREMENT,
+ ENV_AUTOINCREMENT,
ENV_CATEGORY,
ENV_CHROOT,
ENV_CHROOT_USER,
CATEGORY_VARIABLE = "PB_CATEGORY"
CATEGORY_RE = r'^\s*' + CATEGORY_VARIABLE + r'=\s*"?([^"]*)"?\s*$'
+SUBST_HELP = """
+Auto increment/decrement substitition variables:
+
+{time} Replaced by the date and time (UTC) when the package was built.
+ You can specify a format like {time:%Y%m%d+%H%M}
+{debversion} Replaced with the version in the changelog
+{debupstream} Replaced by the upstream portion of the version number taken
+ from debian/changelog. For example: if the version is 1.0-1,
+ this would evaluate to 1.0.
+{git-commit} Replaced with the last 7 characters of the git commit that was
+ built
+"""
+
class Ebuild(object):
"""This class represents an .ebuild file."""
version=self.version))
+class MyOptionParser(optparse.OptionParser):
+ """Derive the OptionParser class to override the format_epilog method"""
+
+ def format_epilog(self, formatter):
+ """Return the epilog including the pre-formatted auto in-/decrement"""
+ return formatter.format_epilog(self.epilog) + SUBST_HELP
+
+
+def version_substitution(logger, pattern, git_commit=None):
+ """Return a version string with the pattern substituted.
+
+ Following substitution variables are supported:
+ {debupstream} Replaced by the upstream portion of the version number
+ taken from debian/changelog. For example: if the version
+ is 1.0-1, this would evaluate to 1.0.
+ {debversion} Replaced with the version in the changelog
+ {git-commit} Replaced with the last 7 characters of the git commit that
+ was built
+ {time} Replaced by the date and time (UTC) when the package was
+ built. You can specify a format like {time:%Y%m%d+%H%M}
+ """
+ subst = dict()
+ if git_commit:
+ subst['git-commit'] = git_commit.hexsha[0:7]
+ subst['time'] = datetime.datetime.utcnow()
+ if os.path.isfile('debian/changelog'):
+ changelog_file = open('debian/changelog')
+ changelog = debian.changelog.Changelog(changelog_file, max_blocks=1)
+ subst['debupstream'] = changelog.upstream_version
+ subst['debversion'] = changelog.full_version
+ try:
+ version = pattern.format(**subst)
+ except KeyError as error:
+ key = error.args[0]
+ allowed_keys = ["{debupstream}", "{debversion}", "{git-commit}",
+ "{time}"]
+ if key in ('debupstream', 'debversion'):
+ msg = ("Cannot substitude {{{key}}} in '{pattern}', because "
+ "debian/changelog is missing. Please add a debian/changelog"
+ " file or avoid {{{key}}} in the substitution pattern.")
+ else:
+ msg = ("Key {{{key}}} from pattern '{pattern}' is not a valid "
+ "substitution. Please use one of the following allowed "
+ "substitutions: {allowed_keys}")
+ logger.error(msg.format(key=key, pattern=pattern,
+ allowed_keys=", ".join(allowed_keys)))
+ sys.exit(1)
+ return version
+
def debian2gentoo_version(debian_version):
"""Translate a Debian version into a Gentoo version.
script_name = os.path.basename(sys.argv[0])
usage = "%s [options] [release repository]" % (script_name)
epilog = "Supported environment variables: " + ", ".join(ENV_VARIABLES)
- parser = optparse.OptionParser(usage=usage, epilog=epilog)
+ parser = MyOptionParser(usage=usage, epilog=epilog)
env = os.environ
used_env = dict((k, v) for (k, v) in env.items() if k in ENV_VARIABLES)
'CRITICAL': logging.CRITICAL
}
+ parser.add_option("-a", "--auto-version", dest="auto_version",
+ action="store_true",
+ help="create a new version by automatically "
+ "increment or decrement the current version")
+ parser.add_option("--autodecrement", dest="autodecrement",
+ default=env.get(ENV_AUTODECREMENT),
+ help="pattern for auto-decrementing the version")
+ parser.add_option("--autoincrement", dest="autoincrement",
+ default=env.get(ENV_AUTOINCREMENT),
+ help="pattern for auto-incrementing the version")
parser.add_option("-b", "--branch", dest="release_branch",
default=env.get(ENV_RELEASE_BRANCH),
help="specify a branch for the release repository "
"""Main function that creates a versioned ebuild file and releases it."""
ebuilds = find_ebuilds(logger, options.category)
repo = git.Repo()
- if options.tag_from_debian:
- git_tag = tag_from_debian_changelog(logger, repo)
+ new_tag = None
+ if options.auto_version:
+ new_tag = auto_versioning(logger, repo, options.autodecrement,
+ options.autoincrement)
+ git_tag = new_tag
+ elif options.tag_from_debian:
+ new_tag = tag_from_debian_changelog(logger, repo)
+ git_tag = new_tag
else:
git_tag = get_latest_tag(logger, repo)
for ebuild in ebuilds:
"...".format(branch=branch, repo=release_repo_uri))
release_repo.git.push("origin", branch)
- if options.tag_from_debian:
- push_tag(logger, repo, git_tag, options.dry_run)
+ if new_tag:
+ push_tag(logger, repo, new_tag, options.dry_run)
finally:
if options.keep:
logger.warning("Keeping temporary git clone in {dir} as "
ebuild=" ".join(ebuild_files)))
return [Ebuild(logger, e, category) for e in ebuild_files]
+def auto_versioning(logger, repo, autodecrement, autoincrement):
+ """Increment or decrement the Debian version."""
+ if not os.path.isfile('debian/changelog'):
+ logger.error("No Debian changelog found. Please add a debian/changelog"
+ "file or disable the auto-version feature.")
+ changelog_file = open('debian/changelog')
+ changelog = debian.changelog.Changelog(changelog_file, max_blocks=1)
+ if changelog.distributions == "UNRELEASED":
+ logger.info("The distribution is set to UNRELEASED. Doing an "
+ "auto-decrement.")
+ if autodecrement is None:
+ logger.error("No auto-decrement pattern was specified.\nPlease "
+ "provide one on the command line or set {env} in "
+ "the environment.".format(env=ENV_AUTODECREMENT))
+ sys.exit(1)
+ pattern = autodecrement
+ else:
+ logger.info("The distribution is set to {distro} and therefore this "
+ "version was released. Doing an "
+ "auto-increment.".format(distro=changelog.distributions))
+ if autoincrement is None:
+ logger.error("No auto-increment pattern was specified.\nPlease "
+ "provide one on the command line or set {env} in "
+ "the environment.".format(env=ENV_AUTOINCREMENT))
+ sys.exit(1)
+ pattern = autoincrement
+ new_tag = version_substitution(logger, pattern, repo.head.commit)
+ logger.info("The pattern '{pattern}' evaluates to the version "
+ "'{version}'.".format(pattern=pattern, version=new_tag))
+ tag_head_commit(logger, repo, new_tag)
+ return new_tag
+
def tag_from_debian_changelog(logger, repo):
"""Create a tag from the version specified in debian/changelog.
Returns the name of the created tag.
'to release the ebuild file.')
msg = msg.format(commit=format_commit(current_commit), tag=new_tag)
else:
+ # TODO: Fix error message when auto-tagging
msg = ('The head commit {commit} is already tagged: {tags}\n'
'The script expects a commit without additional tags.')
msg = msg.format(commit=format_commit(current_commit),