From d84ac920943e07b4dd78b8ee446f23de6859a1fe Mon Sep 17 00:00:00 2001 From: Bogdano Arendartchuk Date: Wed, 6 Jun 2007 20:41:50 +0000 Subject: Frontported fixes in mirror support from repsys-1.6 - fixed bad URLs being used when checking out from mirrors - "switch" subcommand to ease switching between mirror and real repositories - smarter "ci" --- RepSys/commands/switch.py | 32 +++++++++++++++++++ RepSys/mirror.py | 80 ++++++++++++++++++++++++++++++++++++++++++----- RepSys/rpmutil.py | 31 ++++++++++++++---- RepSys/svn.py | 13 ++++++++ repsys | 1 + 5 files changed, 144 insertions(+), 13 deletions(-) create mode 100644 RepSys/commands/switch.py diff --git a/RepSys/commands/switch.py b/RepSys/commands/switch.py new file mode 100644 index 0000000..dcbdd17 --- /dev/null +++ b/RepSys/commands/switch.py @@ -0,0 +1,32 @@ +#!/usr/bin/python +from RepSys.command import * +from RepSys.rpmutil import switch + +HELP = """\ +Usage: repsys switch [URL] + +Relocates the working copy to the base location URL. If URL is not +provided, it will use the option default_parent from repsys.conf as +default, or, if the current working copy is already based in +default_parent, it will use the location from the mirror option from +repsys.conf. + +If the current work is based in another URL, it will use default_parent. + +Options: + -h Show this message + +Examples: + repsys switch + repsys switch https://mirrors.localnetwork/svn/packages/cooker +""" + +def parse_options(): + parser = OptionParser(help=HELP) + opts, args = parser.parse_args() + if len(args): + opts.mirrorurl = args[0] + return opts + +def main(): + do_command(parse_options, switch) diff --git a/RepSys/mirror.py b/RepSys/mirror.py index a24f594..7a0bc4e 100644 --- a/RepSys/mirror.py +++ b/RepSys/mirror.py @@ -4,21 +4,51 @@ import urlparse from RepSys import config from RepSys.svn import SVN +def _normdirurl(url): + """normalize url for relocate_path needs""" + parsed = urlparse.urlparse(url) + path = os.path.normpath(parsed.path) + path += "/" # assuming we always deal with directories + newurl = urlparse.urlunparse((parsed.scheme, parsed.netloc, path, + parsed.params, parsed.query, parsed.fragment)) + return newurl + +def _joinurl(url, relpath): + parsed = urlparse.urlparse(url) + newpath = os.path.join(parsed.path, relpath) + newurl = urlparse.urlunparse((parsed.scheme, parsed.netloc, newpath, + parsed.params, parsed.query, parsed.fragment)) + return newurl + +def same_base(parent, url): + """returns true if parent is parent of url""" + parent = _normdirurl(parent) + url = _normdirurl(url) + #FIXME handle paths with/without username/password + return url.startswith(parent) + def relocate_path(oldparent, newparent, url): - subpath = url[len(oldparent)-1:] - newurl = newparent + "/" + subpath # subpath usually gets / at begining + oldparent = _normdirurl(oldparent) + newparent = _normdirurl(newparent) + url = _normdirurl(url) + subpath = url[len(oldparent):] + newurl = _joinurl(newparent, subpath) # subpath usually gets / at begining return newurl -def enabled(): +def enabled(wcurl=None): mirror = config.get("global", "mirror") default_parent = config.get("global", "default_parent") - return (mirror is not None and - default_parent is not None) + enabled = False + if mirror and default_parent: + enabled = True + if wcurl and (not same_base(mirror, wcurl)): + enabled = False + return enabled def mirror_relocate(oldparent, newparent, url, wcpath): - svn = SVN(noauth=True) + svn = SVN() newurl = relocate_path(oldparent, newparent, url) - svn.switch(newurl, url, path=wcpath, relocate="True") + svn.relocate(url, newurl, wcpath) return newurl def switchto_parent(svn, url, path): @@ -40,3 +70,39 @@ def checkout_url(url): if mirror is not None and default_parent is not None: return relocate_path(default_parent, mirror, url) return url + +def autoswitch(svn, wcpath, wcurl, newbaseurl=None): + """Switches between mirror, default_parent, or newbaseurl""" + nobase = False + mirror = config.get("global", "mirror") + default_parent = config.get("global", "default_parent") + current = default_parent + if default_parent is None: + raise Error, "the option default_parent from repsys.conf is "\ + "required" + indefault = same_base(default_parent, wcurl) + if not newbaseurl: + if not mirror: + raise Error, "an URL is needed when the option mirror "\ + "from repsys.conf is not set" + if indefault: + chosen = mirror + elif same_base(mirror, wcurl): + current = mirror + chosen = default_parent + else: + nobase = True + else: + if mirror and same_base(mirror, wcurl): + current = mirror + elif indefault: + pass # !!!! + else: + nobase = True + chosen = newbaseurl + if nobase: + raise Error, "the URL of this working copy is not based in "\ + "default_parent nor mirror URLs" + assert current != chosen + newurl = mirror_relocate(current, chosen, wcurl, wcpath) + return newurl diff --git a/RepSys/rpmutil.py b/RepSys/rpmutil.py index 39e78fc..40aa4fe 100644 --- a/RepSys/rpmutil.py +++ b/RepSys/rpmutil.py @@ -369,17 +369,23 @@ def checkout(pkgdirurl, path=None, revision=None): print "checking out from mirror", current svn.checkout(current, path, revision=SVN.makerev(revision), show=1) -def sync(dryrun=False): - svn = SVN() +def _getpkgtopdir(basedir=None): + if basedir is None: + basedir = os.getcwd() cwd = os.getcwd() dirname = os.path.basename(cwd) if dirname == "SPECS" or dirname == "SOURCES": topdir = os.pardir else: - topdir = "" + topdir = "." + return topdir + +def sync(dryrun=False): + svn = SVN() + topdir = _getpkgtopdir() # run svn info because svn st does not complain when topdir is not an # working copy - svn.info(topdir or ".") + svn.info(topdir) specsdir = os.path.join(topdir, "SPECS/") sourcesdir = os.path.join(topdir, "SOURCES/") for path in (specsdir, sourcesdir): @@ -426,11 +432,16 @@ def sync(dryrun=False): def commit(target=".", message=None): svn = SVN() + status = svn.status(target, silent=True) + if not status: + print "nothing to commit" + return info = svn.info(target) url = info.url if url is None: raise Error, "working copy URL not provided by svn info" - if mirror.enabled(): + mirrored = mirror.enabled(url) + if mirrored: newurl = mirror.switchto_parent(svn, url, target) print "relocated to", newurl try: @@ -440,10 +451,18 @@ def commit(target=".", message=None): mopt = "-m \"%s\"" % message os.system("svn ci %s %s" % (mopt, target)) finally: - if mirror.enabled(): + if mirrored: mirror.switchto_mirror(svn, newurl, target) print "relocated back to", url +def switch(mirrorurl=None): + svn = SVN() + topdir = _getpkgtopdir() + info = svn.info(topdir) + wcurl = info.url + newurl = mirror.autoswitch(svn, topdir, wcurl, mirrorurl) + print "switched to", newurl + def get_submit_info(path): path = os.path.abspath(path) diff --git a/RepSys/svn.py b/RepSys/svn.py index 2fe9ad1..575651f 100644 --- a/RepSys/svn.py +++ b/RepSys/svn.py @@ -157,6 +157,19 @@ class SVN: def exists(self, path): return self.ls(path, noerror=1) is not None + def status(self, *args, **kwargs): + # add one keywork "silent" that workaround the strange behavior of + # pysvn's get_all, which seems to be broken, this way we also have + # the same interface of svn.py from repsys 1.6.x + meth = self._cllient_wrap("status") + silent = kwargs.pop("silent", None) + st = meth(*args, **kwargs) + if silent: + unversioned = pysvn.wc_status_kind.unversioned + st = [entry for entry in st + if entry.text_status is not unversioned] + return st + def diff(self, *args, **kwargs): head = pysvn.Revision(pysvn.opt_revision_kind.head) revision1 = kwargs.pop("revision1", head) diff --git a/repsys b/repsys index 804ad05..c68df11 100755 --- a/repsys +++ b/repsys @@ -24,6 +24,7 @@ Useful commands: changed authoremail putsrpm + switch Run "repsys COMMAND --help" for more information. -- cgit v1.2.1