bh@271: # Copyright (C) 2007, 2008, 2009 by Intevation GmbH bh@271: # Authors: bh@271: # Bernhard Herzog bh@271: # bh@271: # This program is free software under the GPL (>=v2) bh@271: # Read the file COPYING coming with the software for details. bh@271: bh@271: """Base classes for all kdepim packagers""" bh@271: bh@271: import os bh@271: import time bh@271: import inspect bh@271: import re bh@271: import logging bh@271: bh@271: import treepkg.packager bh@271: import treepkg.subversion bh@271: bh@271: class TagDetector(object): bh@271: bh@271: """Class to automatically find SVN tags and help package them bh@271: bh@271: The tags are found using three parameters: bh@271: url -- The base url of the SVN tags directory to use bh@271: pattern -- A regular expression matching the subdirectories to bh@271: consider in the tag directory specified by the url bh@271: subdir -- A subdirectory of the directory matched by pattern to bh@271: export and use to determine revision number bh@271: bh@271: The subdir parameter is there to cope with the kdepim enterprise bh@271: tags. The URL for a tag is of the form bh@271: .../tags/kdepim/enterprise4.0.. . Each such tag has bh@271: subdirectories for kdepim, kdelibs, etc. The url and pattern are bh@271: used to match the URL for the tag, and the subdir is used to select bh@271: which part of the tag is meant. bh@271: bh@271: The subdir also determines which SVN directory's revision number is bh@271: used. Normally, just appending the subdir to the tag URL would be bh@271: enough for this, but the situation is more complex for bh@271: kdebase_workspace and kdebase_runtime, whose code comes from bh@271: different subdirectories of the kdebase-4.X-branch subdirectory (for bh@271: enterprise4 tags). Here the revision number must be taken from bh@271: kdebase-4.X-branch, but the URL to use when exporting the sources, bh@271: must refer to e.g. kdebase-4.1-branch/kdebase_workspace. To achieve bh@271: that, subdir may contain slashes to indicate subdirectories of bh@271: subdirectories, but only the first part of subdir (up to the first bh@271: slash) is used when determining the revision number. bh@271: """ bh@271: bh@271: def __init__(self, url, pattern, subdir): bh@271: self.url = url bh@271: self.pattern = re.compile(pattern) bh@271: self.subdir = subdir bh@271: bh@271: def list_tags(self): bh@271: matches = [] bh@271: if self.url: bh@271: for tag in treepkg.subversion.list_url(self.url): bh@271: if self.pattern.match(tag.rstrip("/")): bh@271: matches.append(tag) bh@271: return sorted(matches) bh@271: bh@271: def newest_tag_revision(self): bh@271: """Determines the newest tag revision and returns (tagurl, revno) bh@271: If no tag can be found, the method returns the tuple (None, None). bh@271: """ bh@271: candidates = self.list_tags() bh@271: urlrev = (None, None) bh@271: if candidates: bh@271: newest = candidates[-1] bh@271: urlrev = self.determine_revision(self.url + "/" + newest, bh@271: self.subdir) bh@271: return urlrev bh@271: bh@271: def determine_revision(self, baseurl, subdir): bh@271: urlrev = (None, None) bh@271: revision_url = baseurl + "/" + subdir.split("/")[0] bh@271: try: bh@271: revision = treepkg.subversion.last_changed_revision(revision_url) bh@271: urlrev = (baseurl + "/" + subdir, revision) bh@271: except treepkg.subversion.SubversionError: bh@271: pass bh@271: return urlrev bh@271: bh@271: bh@271: class BaseSourcePackager(treepkg.packager.SourcePackager): bh@271: bh@271: changemsg_template = None bh@271: bh@271: def __init__(self, *args, **kw): bh@271: super(BaseSourcePackager, self).__init__(*args, **kw) bh@271: self.enterprise_version = (time.strftime("%Y%m%d", time.localtime()) \ bh@271: + "." + str(self.revision)) bh@271: bh@271: def determine_package_version(self, directory): bh@271: enterprise_version = self.enterprise_version bh@271: return self.track.version_template % locals() bh@271: bh@271: def do_package(self): bh@271: pkgbaseversion, pkgbasedir = self.export_sources() bh@271: self.update_version_numbers(pkgbasedir) bh@271: bh@271: pkgbasename = self.pkg_basename + "_" + pkgbaseversion bh@271: origtargz = os.path.join(self.work_dir, bh@271: pkgbasename + ".orig.tar.gz") bh@271: self.create_tarball(origtargz, self.work_dir, bh@271: os.path.basename(pkgbasedir)) bh@271: bh@271: changemsg = self.changemsg_template % dict(revision=self.revision) bh@271: self.copy_debian_directory(pkgbasedir, pkgbaseversion, bh@271: changemsg) bh@271: bh@271: self.create_source_package(pkgbasedir, origtargz) bh@271: self.move_source_package(pkgbasename) bh@271: bh@271: bh@271: class BasePackageTrack(treepkg.packager.PackageTrack): bh@271: bh@271: extra_config_desc = [("version_template", str, "%(enterprise_version)s"), bh@271: ("tags_url", str, ""), bh@271: ("tags_pattern", str, ""), bh@271: ("tags_subdir", str, "")] bh@271: bh@271: def __init__(self, *args, **kw): bh@271: self.version_template = kw.pop("version_template") bh@271: tags_url = kw.pop("tags_url") bh@271: tags_pattern = kw.pop("tags_pattern") bh@271: tags_subdir = kw.pop("tags_subdir") bh@271: super(BasePackageTrack, self).__init__(*args, **kw) bh@271: self.tag_detector = TagDetector(tags_url, tags_pattern, tags_subdir) bh@271: bh@271: def packager_for_new_revision(self): bh@271: logging.info("Checking tags") bh@271: self.tag_url = None bh@271: tag_url, tag_revision = self.tag_detector.newest_tag_revision() bh@271: logging.info("Found: %s: %s", tag_url, tag_revision) bh@271: if tag_url is not None: bh@271: revision = (tag_revision, bh@271: self.rules_working_copy.last_changed_revision()) bh@271: logging.info("New revision is %s", revision) bh@271: if revision not in self.get_revision_numbers(): bh@271: logging.info("Revision %s has not been packaged yet", bh@271: revision) bh@271: self.tag_url = tag_url bh@271: return self.revision_packager_cls(self, tag=tag_url, *revision) bh@271: else: bh@271: logging.info("Revision %s has already been packaged.", bh@271: revision) bh@271: bh@271: return super(BasePackageTrack, self).packager_for_new_revision() bh@271: bh@271: def export_sources(self, to_dir): bh@271: if self.tag_url is not None: bh@271: self.export_tag(self.tag_url, to_dir) bh@271: else: bh@271: super(BasePackageTrack, self).export_sources(to_dir) bh@271: bh@271: def export_tag(self, tag_url, to_dir): bh@271: logging.info("Exporting sources from %s to %r", bh@271: tag_url, to_dir) bh@271: treepkg.subversion.export(tag_url, to_dir)