diff options
Diffstat (limited to 'RepSys/rpmutil.py')
-rw-r--r-- | RepSys/rpmutil.py | 759 |
1 files changed, 759 insertions, 0 deletions
diff --git a/RepSys/rpmutil.py b/RepSys/rpmutil.py new file mode 100644 index 0000000..bff744b --- /dev/null +++ b/RepSys/rpmutil.py @@ -0,0 +1,759 @@ +#!/usr/bin/python +from RepSys import Error, config +from RepSys import mirror, layout, log, binrepo +from RepSys.svn import SVN +from RepSys.simplerpm import SRPM +from RepSys.util import execcmd +from RepSys.command import default_parent +import rpm +import urlparse +import tempfile +import shutil +import string +import glob +import sys +import os + +def get_spec(pkgdirurl, targetdir=".", submit=False): + svn = SVN() + tmpdir = tempfile.mktemp() + try: + geturl = layout.checkout_url(pkgdirurl, append_path="SPECS") + mirror.info(geturl) + svn.export("'%s'" % geturl, tmpdir) + speclist = glob.glob(os.path.join(tmpdir, "*.spec")) + if not speclist: + raise Error, "no spec files found" + spec = speclist[0] + shutil.copy(spec, targetdir) + name = os.path.basename(spec) + path = os.path.join(targetdir, name) + print "Wrote %s" % (name) + finally: + if os.path.isdir(tmpdir): + shutil.rmtree(tmpdir) + +def rpm_macros_defs(macros): + defs = ("--define \"%s %s\"" % macro for macro in macros) + args = " ".join(defs) + return args + +#FIXME move it to another module +def rev_touched_url(url, rev): + svn = SVN() + info = svn.info2(url) + if info is None: + raise Error, "can't fetch svn info about the URL: %s" % url + root = info["Repository Root"] + urlpath = url[len(root):] + touched = False + entries = svn.log(root, start=rev, limit=1) + entry = entries[0] + for change in entry.changed: + path = change.get("path") + if path and path.startswith(urlpath): + touched = True + return touched + +def get_srpm(pkgdirurl, + mode = "current", + targetdirs = None, + version = None, + release = None, + revision = None, + packager = "", + revname = 0, + svnlog = 0, + scripts = [], + submit = False, + template = None, + macros = [], + verbose = 0, + strict = False, + use_binrepo = False, + binrepo_check = True): + svn = SVN() + tmpdir = tempfile.mktemp() + topdir = "--define '_topdir %s'" % tmpdir + builddir = "--define '_builddir %s/%s'" % (tmpdir, "BUILD") + rpmdir = "--define '_rpmdir %s/%s'" % (tmpdir, "RPMS") + sourcedir = "--define '_sourcedir %s/%s'" % (tmpdir, "SOURCES") + specdir = "--define '_specdir %s/%s'" % (tmpdir, "SPECS") + srcrpmdir = "--define '_srcrpmdir %s/%s'" % (tmpdir, "SRPMS") + patchdir = "--define '_patchdir %s/%s'" % (tmpdir, "SOURCES") + + try: + if mode == "version": + geturl = layout.checkout_url(pkgdirurl, version=version, + release=release) + elif mode == "pristine": + geturl = layout.checkout_url(pkgdirurl, pristine=True) + elif mode == "current" or mode == "revision": + #FIXME we should handle revisions specified using @REV + geturl = layout.checkout_url(pkgdirurl) + else: + raise Error, "unsupported get_srpm mode: %s" % mode + strict = strict or config.getbool("submit", "strict-revision", False) + if strict and not rev_touched_url(geturl, revision): + #FIXME would be nice to have the revision number even when + # revision is None + raise Error, "the revision %s does not change anything "\ + "inside %s" % (revision or "HEAD", geturl) + mirror.info(geturl) + svn.export(geturl, tmpdir, rev=revision) + if use_binrepo: + binrepo_check = (binrepo_check or + config.getbool("binrepo", "getsrpm-check", False)) + download_binaries(tmpdir, geturl, revision=revision, + export=True, check=binrepo_check) + srpmsdir = os.path.join(tmpdir, "SRPMS") + os.mkdir(srpmsdir) + specsdir = os.path.join(tmpdir, "SPECS") + speclist = glob.glob(os.path.join(specsdir, "*.spec")) + if config.getbool("srpm", "run-prep", False): + makefile = os.path.join(tmpdir, "Makefile") + if os.path.exists(makefile): + execcmd("make", "-C", tmpdir, "srpm-prep") + if not speclist: + raise Error, "no spec files found" + spec = speclist[0] + if svnlog: + submit = not not revision + log.specfile_svn2rpm(pkgdirurl, spec, revision, submit=submit, + template=template, macros=macros, exported=tmpdir) + for script in scripts: + #FIXME revision can be "None" + status, output = execcmd(script, tmpdir, spec, str(revision), + noerror=1) + if status != 0: + raise Error, "script %s failed" % script + if packager: + packager = " --define 'packager %s'" % packager + + defs = rpm_macros_defs(macros) + sourcecmd = config.get("helper", "rpmbuild", "rpmbuild") + execcmd("%s -bs --nodeps %s %s %s %s %s %s %s %s %s %s" % + (sourcecmd, topdir, builddir, rpmdir, sourcedir, specdir, + srcrpmdir, patchdir, packager, spec, defs)) + + # copy the generated SRPMs to their target locations + targetsrpms = [] + urlrev = None + if revname: + urlrev = revision or layout.get_url_revision(geturl) + if not targetdirs: + targetdirs = (".",) + srpms = glob.glob(os.path.join(srpmsdir, "*.src.rpm")) + if not srpms: + # something fishy happened + raise Error, "no SRPMS were found at %s" % srpmsdir + for srpm in srpms: + name = os.path.basename(srpm) + if revname: + name = "@%s:%s" % (urlrev, name) + for targetdir in targetdirs: + newpath = os.path.join(targetdir, name) + targetsrpms.append(newpath) + if os.path.exists(newpath): + # should we warn? + os.unlink(newpath) + shutil.copy(srpm, newpath) + if verbose: + sys.stderr.write("Wrote: %s\n" % newpath) + return targetsrpms + finally: + if os.path.isdir(tmpdir): + shutil.rmtree(tmpdir) + +def patch_spec(pkgdirurl, patchfile, log=""): + #FIXME use get_spec + svn = SVN() + tmpdir = tempfile.mktemp() + try: + geturl = layout.checkout_url(pkgdirurl, append_path="SPECS") + svn.checkout(geturl, tmpdir) + speclist = glob.glob(os.path.join(tmpdir, "*.spec")) + if not speclist: + raise Error, "no spec files found" + spec = speclist[0] + status, output = execcmd("patch", spec, patchfile) + if status != 0: + raise Error, "can't apply patch:\n%s\n" % output + else: + svn.commit(tmpdir, log="") + finally: + if os.path.isdir(tmpdir): + shutil.rmtree(tmpdir) + +def put_srpm(srpmfile, markrelease=False, striplog=True, branch=None, + baseurl=None, baseold=None, logmsg=None, rename=True): + svn = SVN() + srpm = SRPM(srpmfile) + tmpdir = tempfile.mktemp() + if baseurl: + pkgurl = mirror._joinurl(baseurl, srpm.name) + else: + pkgurl = layout.package_url(srpm.name, distro=branch, + mirrored=False) + print "Importing package to %s" % pkgurl + try: + if srpm.epoch: + version = "%s:%s" % (srpm.epoch, srpm.version) + else: + version = srpm.version + versionurl = "/".join([pkgurl, "releases", version]) + releaseurl = "/".join([versionurl, srpm.release]) + currenturl = "/".join([pkgurl, "current"]) + currentdir = os.path.join(tmpdir, "current") + #FIXME when pre-commit hook fails, there's no clear way to know + # what happened + ret = svn.mkdir(pkgurl, noerror=1, log="Created package directory") + if ret or not svn.ls(currenturl, noerror=1): + svn.checkout(pkgurl, tmpdir) + svn.mkdir(os.path.join(tmpdir, "releases")) + svn.mkdir(currentdir) + svn.mkdir(os.path.join(currentdir, "SPECS")) + svn.mkdir(os.path.join(currentdir, "SOURCES")) + #svn.commit(tmpdir,log="Created package structure.") + version_exists = 1 + else: + if svn.ls(releaseurl, noerror=1): + raise Error, "release already exists" + svn.checkout("/".join([pkgurl, "current"]), tmpdir) + svn.mkdir(versionurl, noerror=1, + log="Created directory for version %s." % version) + currentdir = tmpdir + + specsdir = os.path.join(currentdir, "SPECS") + sourcesdir = os.path.join(currentdir, "SOURCES") + + unpackdir = tempfile.mktemp() + os.mkdir(unpackdir) + try: + srpm.unpack(unpackdir) + + uspecsdir = os.path.join(unpackdir, "SPECS") + usourcesdir = os.path.join(unpackdir, "SOURCES") + + uspecsentries = os.listdir(uspecsdir) + usourcesentries = os.listdir(usourcesdir) + specsentries = os.listdir(specsdir) + sourcesentries = os.listdir(sourcesdir) + + # Remove old entries + for entry in [x for x in specsentries + if x not in uspecsentries]: + if entry == ".svn": + continue + entrypath = os.path.join(specsdir, entry) + os.unlink(entrypath) + svn.remove(entrypath) + for entry in [x for x in sourcesentries + if x not in usourcesentries]: + if entry == ".svn": + continue + entrypath = os.path.join(sourcesdir, entry) + os.unlink(entrypath) + svn.remove(entrypath) + + # Copy all files + execcmd("cp -rf", uspecsdir, currentdir) + execcmd("cp -rf", usourcesdir, currentdir) + + # Add new entries + for entry in [x for x in uspecsentries + if x not in specsentries]: + entrypath = os.path.join(specsdir, entry) + svn.add(entrypath) + for entry in [x for x in usourcesentries + if x not in sourcesentries]: + entrypath = os.path.join(sourcesdir, entry) + svn.add(entrypath) + finally: + if os.path.isdir(unpackdir): + shutil.rmtree(unpackdir) + + specs = glob.glob(os.path.join(specsdir, "*.spec")) + if not specs: + raise Error, "no spec file found on %s" % specsdir + if len(specs) > 1: + raise Error, "more than one spec file found on %s" % specsdir + specpath = specs[0] + if rename: + specfile = os.path.basename(specpath) + specname = specfile[:-len(".spec")] + if specname != srpm.name: + newname = srpm.name + ".spec" + newpath = os.path.join(specsdir, newname) + sys.stderr.write("warning: renaming spec file to '%s' " + "(use -n to disable it)\n" % (newname)) + os.rename(specpath, newpath) + try: + svn.remove(specpath) + except Error: + # file not tracked + svn.revert(specpath) + svn.add(newpath) + specpath = newpath + + if striplog: + specpath = specpath + fspec = open(specpath) + spec, chlog = log.split_spec_changelog(fspec) + fspec.close() + fspec = open(specpath, "w") + fspec.writelines(spec) + fspec.close() + chlog.seek(0, os.SEEK_END) + if chlog.tell() != 0: + chlog.seek(0) + #FIXME move it to layout.py + oldurl = baseold or config.get("log", "oldurl") + pkgoldurl = mirror._joinurl(oldurl, srpm.name) + svn.mkdir(pkgoldurl, noerror=1, + log="created old log directory for %s" % srpm.name) + logtmp = tempfile.mktemp() + try: + svn.checkout(pkgoldurl, logtmp) + miscpath = os.path.join(logtmp, "log") + fmisc = open(miscpath, "w+") + fmisc.writelines(chlog) + fmisc.close() + svn.add(miscpath) + svn.commit(logtmp, + log="imported old log for %s" % srpm.name) + finally: + if os.path.isdir(logtmp): + shutil.rmtree(logtmp) + binrepo.import_binaries(currentdir, srpm.name) + svn.commit(tmpdir, + log=logmsg or ("imported package %s" % srpm.name)) + finally: + if os.path.isdir(tmpdir): + shutil.rmtree(tmpdir) + + # Do revision and pristine tag copies + pristineurl = layout.checkout_url(pkgurl, pristine=True) + svn.remove(pristineurl, noerror=1, + log="Removing previous pristine/ directory.") + currenturl = layout.checkout_url(pkgurl) + svn.copy(currenturl, pristineurl, + log="Copying release %s-%s to pristine/ directory." % + (version, srpm.release)) + if markrelease: + svn.copy(currenturl, releaseurl, + log="Copying release %s-%s to releases/ directory." % + (version, srpm.release)) + +def create_package(pkgdirurl, log="", verbose=0): + svn = SVN() + tmpdir = tempfile.mktemp() + try: + basename = layout.package_name(pkgdirurl) + if verbose: + print "Creating package directory...", + sys.stdout.flush() + ret = svn.mkdir(pkgdirurl, + log="Created package directory for '%s'." % basename) + if verbose: + print "done" + print "Checking it out...", + svn.checkout(pkgdirurl, tmpdir) + if verbose: + print "done" + print "Creating package structure...", + svn.mkdir(os.path.join(tmpdir, "current")) + svn.mkdir(os.path.join(tmpdir, "current", "SPECS")) + svn.mkdir(os.path.join(tmpdir, "current", "SOURCES")) + if verbose: + print "done" + print "Committing...", + svn.commit(tmpdir, + log="Created package structure for '%s'." % basename) + print "done" + finally: + if os.path.isdir(tmpdir): + shutil.rmtree(tmpdir) + + +def create_markrelease_log(version, release, revision): + log = """%%repsys markrelease +version: %s +release: %s +revision: %s + +%s""" % (version, release, revision, + ("Copying %s-%s to releases/ directory." % (version, release))) + return log + +def mark_release(pkgdirurl, version, release, revision): + svn = SVN() + releasesurl = layout.checkout_url(pkgdirurl, releases=True) + versionurl = "/".join([releasesurl, version]) + releaseurl = "/".join([versionurl, release]) + currenturl = layout.checkout_url(pkgdirurl) + binrepo.markrelease(currenturl, releasesurl, version, release, revision) + if svn.ls(releaseurl, noerror=1): + raise Error, "release already exists" + svn.mkdir(releasesurl, noerror=1, + log="Created releases directory.") + svn.mkdir(versionurl, noerror=1, + log="Created directory for version %s." % version) + pristineurl = layout.checkout_url(pkgdirurl, pristine=True) + svn.remove(pristineurl, noerror=1, + log="Removing previous pristine/ directory.") + svn.copy(currenturl, pristineurl, + log="Copying release %s-%s to pristine/ directory." % + (version, release)) + markreleaselog = create_markrelease_log(version, release, revision) + svn.copy(currenturl, releaseurl, rev=revision, + log=markreleaselog) + +def check_changed(pkgdirurl, all=0, show=0, verbose=0): + svn = SVN() + if all: + baseurl = pkgdirurl + packages = [] + if verbose: + print "Getting list of packages...", + sys.stdout.flush() + packages = [x[:-1] for x in svn.ls(baseurl)] + if verbose: + print "done" + if not packages: + raise Error, "couldn't get list of packages" + else: + baseurl, basename = os.path.split(pkgdirurl) + packages = [basename] + clean = [] + changed = [] + nopristine = [] + nocurrent = [] + for package in packages: + pkgdirurl = os.path.join(baseurl, package) + current = layout.checkout_url(pkgdirurl) + pristine = layout.checkout_url(pkgdirurl, pristine=True) + if verbose: + print "Checking package %s..." % package, + sys.stdout.flush() + if not svn.ls(current, noerror=1): + if verbose: + print "NO CURRENT" + nocurrent.append(package) + elif not svn.ls(pristine, noerror=1): + if verbose: + print "NO PRISTINE" + nopristine.append(package) + else: + diff = svn.diff(pristine, current) + if diff: + changed.append(package) + if verbose: + print "CHANGED" + if show: + print diff + else: + if verbose: + print "clean" + clean.append(package) + if verbose: + if not packages: + print "No packages found!" + elif all: + print "Total clean packages: %s" % len(clean) + print "Total CHANGED packages: %d" % len(changed) + print "Total NO CURRENT packages: %s" % len(nocurrent) + print "Total NO PRISTINE packages: %s" % len(nopristine) + return {"clean": clean, + "changed": changed, + "nocurrent": nocurrent, + "nopristine": nopristine} + +def checkout(pkgdirurl, path=None, revision=None, branch=None, distro=None, + spec=False, use_binrepo=False, binrepo_check=True, binrepo_link=True): + o_pkgdirurl = pkgdirurl + pkgdirurl = layout.package_url(o_pkgdirurl, distro=distro) + append = None + if spec: + append = "SPECS" + current = layout.checkout_url(pkgdirurl, branch=branch, + append_path=append) + if path is None: + path = layout.package_name(pkgdirurl) + mirror.info(current, write=True) + svn = SVN() + svn.checkout(current, path, rev=revision, show=1) + if use_binrepo: + download_binaries(path, revision=revision, symlinks=binrepo_link, + check=binrepo_check) + +def getpkgtopdir(basedir=None): + #FIXME this implementation doesn't work well with relative path names, + # which is something we need in order to have a friendlier output + if basedir is None: + basedir = os.path.curdir + while not ispkgtopdir(basedir): + if os.path.abspath(basedir) == "/": + raise Error, "can't find top package directories SOURCES and SPECS" + basedir = os.path.join(basedir, os.path.pardir) + if basedir.startswith("./"): + basedir = basedir[2:] + return basedir + +def ispkgtopdir(path=None): + if path is None: + path = os.getcwd() + names = os.listdir(path) + return (".svn" in names and "SPECS" in names and "SOURCES" in names) + +def sync(dryrun=False, ci=False, download=False): + # TODO FIXME XXX fix it! + raise Error, "sync is not expected to work these days" + svn = SVN() + topdir = getpkgtopdir() + # run svn info because svn st does not complain when topdir is not an + # working copy + svn.info(topdir) + specsdir = os.path.join(topdir, "SPECS/") + sourcesdir = os.path.join(topdir, "SOURCES/") + for path in (specsdir, sourcesdir): + if not os.path.isdir(path): + raise Error, "%s directory not found" % path + specs = glob.glob(os.path.join(specsdir, "*.spec")) + if not specs: + raise Error, "no .spec files found in %s" % specsdir + specpath = specs[0] # FIXME better way? + try: + rpm.addMacro("_topdir", os.path.abspath(topdir)) + spec = rpm.TransactionSet().parseSpec(specpath) + except rpm.error, e: + raise Error, "could not load spec file: %s" % e + sources = dict((os.path.basename(name), name) + for name, no, flags in spec.sources()) + sourcesst = dict((os.path.basename(path), (path, st)) + for st, path in svn.status(sourcesdir, noignore=True)) + toadd_br = [] + toadd_svn = [] + toremove_svn = [] + toremove_br = [] + # add the spec file itself, in case of a new package + specstl = svn.status(specpath, noignore=True) + if specstl: + specst, _ = specstl[0] + if specst == "?": + toadd_svn.append(specpath) + # add source files: + for source, url in sources.iteritems(): + sourcepath = os.path.join(sourcesdir, source) + if sourcesst.get(source): + if not os.path.islink(sourcepath): + if not binrepo.is_tracked(sourcepath): + if binrepo.is_binary(sourcepath): + toadd_br.append(sourcepath) + else: + toadd_svn.append(sourcepath) + else: + sys.stderr.write("warning: %s not found\n" % sourcepath) + elif download and not os.path.isfile(sourcepath): + print "%s not found, downloading from %s" % (sourcepath, url) + fmt = config.get("global", "download-command", + "wget -c -O '$dest' $url") + context = {"dest": sourcepath, "url": url} + try: + cmd = string.Template(fmt).substitute(context) + except KeyError, e: + raise Error, "invalid variable %r in download-command "\ + "configuration option" % e + execcmd(cmd, show=True) + if os.path.isfile(sourcepath): + if binrepo.is_binary(sourcepath): + toadd_br.append(sourcepath) + else: + toadd_svn.append(sourcepath) + else: + raise Error, "file not found: %s" % sourcepath + # rm entries not found in sources and still in svn + found = os.listdir(sourcesdir) + for entry in found: + if entry == ".svn" or entry == "sources": + continue + status = sourcesst.get(entry) + path = os.path.join(sourcesdir, entry) + if entry not in sources: + if status is None: # file is tracked by svn + toremove_svn.append(path) + elif binrepo.is_tracked(path): + toremove_br.append(path) + for path in toremove_svn: + print "D\t%s" % path + if not dryrun: + svn.remove(path, local=True) + for path in toremove_br: + print "DB\t%s" % path + if not dryrun: + binrepo.delete_pending(path) + for path in toadd_svn: + print "A\t%s" % path + if not dryrun: + svn.add(path, local=True) + for path in toadd_br: + print "AB\t%s" % path + if not dryrun: + binrepo.upload_pending(path) + if commit: + commit(topdir) + +def commit(target=".", message=None, logfile=None): + topdir = getpkgtopdir(target) + sourcesdir = os.path.join(topdir, "SOURCES") + binrepo.commit(sourcesdir) #TODO make it optional + svn = SVN() + status = svn.status(target, quiet=True) + if not status: + print "nothing to commit" + return + info = svn.info2(target) + url = info.get("URL") + if url is None: + raise Error, "working copy URL not provided by svn info" + mirrored = mirror.using_on(url) + if mirrored: + newurl = mirror.switchto_parent(svn, url, target) + print "relocated to", newurl + # we can't use the svn object here because svn --non-interactive option + # hides VISUAL + opts = [] + if message is not None: + opts.append("-m \"%s\"" % message) + if logfile is not None: + opts.append("-F \"%s\"" % logfile) + mopts = " ".join(opts) + os.system("svn ci %s %s" % (mopts, target)) + if mirrored: + print "use \"repsys switch\" in order to switch back to mirror "\ + "later" + +def spec_sources(topdir): + specs = glob.glob(os.path.join(topdir, "SPECS/*.spec")) + spec_path = specs[0] # FIXME use svn info to ensure which one + ts = rpm.ts() + spec = ts.parseSpec(spec_path) + sources = [name for name, x, y in spec.sources()] + return sources + +def download_binaries(target, pkgdirurl=None, export=False, revision=None, + symlinks=True, check=False): + refurl = pkgdirurl + if refurl is None: + refurl = binrepo.svn_root(target) + if binrepo.enabled(refurl): + binrepo.download(target, pkgdirurl, export=export, + revision=revision, symlinks=symlinks, check=check) + +def update(target=None): + svn = SVN() + info = None + svn_target = None + br_target = None + if target: + svn_target = target + else: + top = getpkgtopdir() + svn_target = top + br_target = top + if svn_target: + svn.update(svn_target, show=True) + if br_target: + info = svn.info2(svn_target) + if not br_target and not svn_target: + raise Error, "target not in SVN nor in binaries "\ + "repository: %s" % target + url = info["URL"] + download_binaries(br_target, url) + +def upload(paths): + for path in paths: + binrepo.upload(path) + +def binrepo_delete(paths, commit=False): + #TODO handle files tracked by svn + refurl = binrepo.svn_root(paths[0]) + if not binrepo.enabled(refurl): + raise Error, "binary repository is not enabled for %s" % refurl + added, deleted = binrepo.remove(paths) + if commit: + svn = SVN() + spath = binrepo.sources_path(paths[0]) + log = _sources_log(added, deleted) + svn.commit(spath, log=log) + +def switch(mirrorurl=None): + svn = SVN() + topdir = getpkgtopdir() + info = svn.info2(topdir) + wcurl = info.get("URL") + if wcurl is None: + raise Error, "working copy URL not provided by svn info" + newurl = mirror.autoswitch(svn, topdir, wcurl, mirrorurl) + print "switched to", newurl + +def get_submit_info(path): + path = os.path.abspath(path) + + # First, look for SPECS and SOURCES directories. + found = False + while path != "/": + if os.path.isdir(path): + specsdir = os.path.join(path, "SPECS") + sourcesdir = os.path.join(path, "SOURCES") + if os.path.isdir(specsdir) and os.path.isdir(sourcesdir): + found = True + break + path = os.path.dirname(path) + if not found: + raise Error, "SPECS and/or SOURCES directories not found" + + # Then, check if this is really a subversion directory. + if not os.path.isdir(os.path.join(path, ".svn")): + raise Error, "subversion directory not found" + + svn = SVN() + + # Now, extract the package name. + info = svn.info2(path) + url = info.get("URL") + if url is None: + raise Error, "missing URL from svn info %s" % path + toks = url.split("/") + if len(toks) < 2 or toks[-1] != "current": + raise Error, "unexpected URL received from 'svn info'" + name = toks[-2] + url = "/".join(toks[:-1]) + + # Finally, guess revision. + max = -1 + files = [] + files.extend(glob.glob("%s/*" % specsdir)) + files.extend(glob.glob("%s/*" % sourcesdir)) + for file in files: + try: + info = svn.info2(file) + except Error: + # possibly not tracked + continue + if info is None: + continue + rawrev = info.get("Last Changed Rev") + if rawrev: + rev = int(rawrev) + if rev > max: + max = rev + if max == -1: + raise Error, "revision tag not found in 'svn info' output" + + if mirror.using_on(url): + url = mirror.switchto_parent_url(url) + + return name, url, max + +# vim:et:ts=4:sw=4 |