From 5c7f585c08c8ffb944095ae031fbf82a54ba13bc Mon Sep 17 00:00:00 2001 From: Bogdano Arendartchuk Date: Thu, 17 Jul 2008 12:24:21 +0000 Subject: Allow specifying distro branches without using complete URLs Added the configuration option "repository", which will have the URL to the root of the repository. The change also allowed using mirrors in all the read-only commands. --- CHANGES | 3 + RepSys/__init__.py | 16 ---- RepSys/commands/changed.py | 4 +- RepSys/commands/co.py | 14 ++- RepSys/commands/create.py | 3 +- RepSys/commands/editlog.py | 3 +- RepSys/commands/getspec.py | 4 +- RepSys/commands/getsrpm.py | 4 +- RepSys/commands/markrelease.py | 3 +- RepSys/commands/patchspec.py | 3 +- RepSys/commands/putsrpm.py | 3 +- RepSys/commands/rpmlog.py | 10 +- RepSys/commands/submit.py | 14 ++- RepSys/layout.py | 207 +++++++++++++++++++++++++++++++++++++++++ RepSys/log.py | 8 +- RepSys/mirror.py | 81 +++++++++------- RepSys/rpmutil.py | 97 ++++++------------- create-srpm | 18 ++-- repsys | 6 +- repsys-example.conf | 2 +- repsys.8 | 16 +++- repsys.conf | 2 +- 22 files changed, 358 insertions(+), 163 deletions(-) create mode 100644 RepSys/layout.py diff --git a/CHANGES b/CHANGES index cc9966f..bcf0c5f 100644 --- a/CHANGES +++ b/CHANGES @@ -8,12 +8,15 @@ interactivity at all with ssh - fixed incompatibility with Python-2.4 on urlparse - fixed emptylog message, which was not being shown when needed +- distributions can be specified by using / in all + commands - template: hide the first release when it has only invisible lines - added initial man page - allow resorting changelog entries through the config option sort in the log section - added rpmlog options: -o to append the old changelog, -p to append the changelog found in the spec, and -s to resort all changelog entries +- rpmlog, getsrpm, getspec and changed will use the mirror if enabled - don't hide authors with only the first revision SILENTed (#41117) - allow submitting many packages at once (#28352) - package revisions in submit are now specified with name@nnn diff --git a/RepSys/__init__.py b/RepSys/__init__.py index b303065..2759e8f 100644 --- a/RepSys/__init__.py +++ b/RepSys/__init__.py @@ -11,20 +11,4 @@ del ConfigParser class Error(Exception): pass -class RepSysTree: - """ - This class just hold methods that abstract all the not-so-explicit - rules about the directory structure of a repsys repository. - """ - def fixpath(cls, url): - return re.sub("/+$", "", url) - fixpath = classmethod(fixpath) - - def pkgname(cls, pkgdirurl): - # we must remove trailling slashes in the package path because - # os.path.basename could return "" from URLs ending with "/" - fixedurl = cls.fixpath(pkgdirurl) - return os.path.basename(fixedurl) - pkgname = classmethod(pkgname) - # vim:et:ts=4:sw=4 diff --git a/RepSys/commands/changed.py b/RepSys/commands/changed.py index 62b20b6..7d05604 100644 --- a/RepSys/commands/changed.py +++ b/RepSys/commands/changed.py @@ -1,6 +1,7 @@ #!/usr/bin/python from RepSys import Error from RepSys.command import * +from RepSys.layout import package_url from RepSys.rpmutil import check_changed import getopt import sys @@ -13,6 +14,7 @@ Shows if there are pending changes since the last package release. Options: -a Check all packages in given URL -s Show differences + -M Do not use the mirror (use the main repository) -h Show this message Examples: @@ -27,7 +29,7 @@ def parse_options(): opts, args = parser.parse_args() if len(args) != 1: raise Error, "invalid arguments" - opts.pkgdirurl = default_parent(args[0]) + opts.pkgdirurl = package_url(args[0]) opts.verbose = 1 # Unconfigurable return opts diff --git a/RepSys/commands/co.py b/RepSys/commands/co.py index 830b7e7..5349049 100644 --- a/RepSys/commands/co.py +++ b/RepSys/commands/co.py @@ -13,13 +13,19 @@ Checkout the package source from the Mandriva repository. If the 'mirror' option is enabled, the package is obtained from the mirror repository. +You can specify the distro branch to checkout from by using distro/pkgname. + Options: + -d The distribution branch to checkout from + -b The package branch -r REV Revision to checkout - -o Do not use the mirror (use official server) + -M Do not use the mirror (use the main repository) -h Show this message Examples: repsys co pkgname + repsys co -d 2009.0 pkgname + repsys co 2009.0/pkgame repsys co http://repos/svn/cnc/snapshot/foo repsys co http://repos/svn/cnc/snapshot/foo foo-pkg """ @@ -27,11 +33,13 @@ Examples: def parse_options(): parser = OptionParser(help=HELP) parser.add_option("-r", dest="revision") - parser.add_option("-o", dest="use_mirror", default=True, - action="store_false") + parser.add_option("--distribution", "-d", dest="distro", default=None) + parser.add_option("--branch", "-b", dest="branch", default=None) opts, args = parser.parse_args() if len(args) not in (1, 2): raise Error, "invalid arguments" + # here we don't use package_url in order to notify the user we are + # using the mirror opts.pkgdirurl = args[0] if len(args) == 2: opts.path = args[1] diff --git a/RepSys/commands/create.py b/RepSys/commands/create.py index a8709f0..ded8abe 100644 --- a/RepSys/commands/create.py +++ b/RepSys/commands/create.py @@ -1,6 +1,7 @@ #!/usr/bin/python from RepSys import Error from RepSys.command import * +from RepSys.layout import package_url from RepSys.rpmutil import create_package import getopt import sys @@ -23,7 +24,7 @@ def parse_options(): opts, args = parser.parse_args() if len(args) != 1: raise Error, "invalid arguments" - opts.pkgdirurl = default_parent(args[0]) + opts.pkgdirurl = package_url(args[0], mirrored=False) opts.verbose = 1 # Unconfigurable return opts diff --git a/RepSys/commands/editlog.py b/RepSys/commands/editlog.py index 1962ed8..9d1afc5 100644 --- a/RepSys/commands/editlog.py +++ b/RepSys/commands/editlog.py @@ -1,6 +1,7 @@ #!/usr/bin/python from RepSys import Error from RepSys.command import * +from RepSys.layout import package_url from RepSys.svn import SVN import re @@ -24,7 +25,7 @@ def parse_options(): pkgdirurl, revision = "", args[0] else: raise Error, "invalid arguments" - opts.pkgdirurl = default_parent(pkgdirurl) + opts.pkgdirurl = package_url(pkgdirurl, mirrored=False) opts.revision = re.compile(r".*?(\d+).*").sub(r"\1", revision) return opts diff --git a/RepSys/commands/getspec.py b/RepSys/commands/getspec.py index 5e44074..6a8f7ea 100644 --- a/RepSys/commands/getspec.py +++ b/RepSys/commands/getspec.py @@ -1,6 +1,7 @@ #!/usr/bin/python from RepSys import Error from RepSys.command import * +from RepSys.layout import package_url from RepSys.rpmutil import get_spec import getopt import sys @@ -12,6 +13,7 @@ Prints the .spec file of a given package. Options: -t DIR Use DIR as target for spec file (default is ".") + -M Do not use the mirror (use the main repository) -h Show this message Examples: @@ -25,7 +27,7 @@ def parse_options(): opts, args = parser.parse_args() if len(args) != 1: raise Error, "invalid arguments" - opts.pkgdirurl = default_parent(args[0]) + opts.pkgdirurl = package_url(args[0]) return opts def main(): diff --git a/RepSys/commands/getsrpm.py b/RepSys/commands/getsrpm.py index f9a63d2..8cbe1f1 100644 --- a/RepSys/commands/getsrpm.py +++ b/RepSys/commands/getsrpm.py @@ -5,6 +5,7 @@ # from RepSys import Error, config from RepSys.command import * +from RepSys.layout import package_url from RepSys.rpmutil import get_srpm import tempfile import shutil @@ -29,6 +30,7 @@ Options: -n Rename the package to include the revision number -l Use subversion log to build rpm %changelog -T FILE Template to be used to generate the %changelog + -M Do not use the mirror (use the main repository) -h Show this message --strict Check if the given revision contains changes in REPPKGURL @@ -80,7 +82,7 @@ def parse_options(): del opts.__ignore if len(args) != 1: raise Error, "invalid arguments" - opts.pkgdirurl = default_parent(args[0]) + opts.pkgdirurl = package_url(args[0]) opts.verbose = 1 return opts diff --git a/RepSys/commands/markrelease.py b/RepSys/commands/markrelease.py index 1707f39..057cf1d 100644 --- a/RepSys/commands/markrelease.py +++ b/RepSys/commands/markrelease.py @@ -9,6 +9,7 @@ # from RepSys import Error from RepSys.command import * +from RepSys.layout import package_url from RepSys.simplerpm import SRPM from RepSys.rpmutil import mark_release from RepSys.util import get_auth @@ -60,7 +61,7 @@ def parse_options(): if len(args) != 1: raise Error, "invalid arguments" - opts.pkgdirurl = default_parent(args[0]) + opts.pkgdirurl = package_url(args[0], mirrored=False) filename = opts.filename appendname = opts.appendname diff --git a/RepSys/commands/patchspec.py b/RepSys/commands/patchspec.py index 8330cc3..9a4881b 100644 --- a/RepSys/commands/patchspec.py +++ b/RepSys/commands/patchspec.py @@ -5,6 +5,7 @@ from RepSys import Error from RepSys.rpmutil import patch_spec from RepSys.command import * +from RepSys.layout import package_url import getopt import sys @@ -27,7 +28,7 @@ def parse_options(): opts, args = parser.parse_args() if len(args) != 2: raise Error, "invalid arguments" - opts.pkgdirurl = default_parent(args[0]) + opts.pkgdirurl = package_url(args[0], mirrored=False) opts.patchfile = args[1] return opts diff --git a/RepSys/commands/putsrpm.py b/RepSys/commands/putsrpm.py index 21ad234..0717cd6 100644 --- a/RepSys/commands/putsrpm.py +++ b/RepSys/commands/putsrpm.py @@ -9,6 +9,7 @@ # from RepSys import Error from RepSys.command import * +from RepSys.layout import package_url from RepSys.rpmutil import put_srpm import getopt import sys, os @@ -34,7 +35,7 @@ def parse_options(): opts, args = parser.parse_args() if len(args) != 2: raise Error, "invalid arguments" - opts.pkgdirurl = default_parent(args[0]) + opts.pkgdirurl = package_url(args[0], mirrored=False) opts.srpmfile = args[1] return opts diff --git a/RepSys/commands/rpmlog.py b/RepSys/commands/rpmlog.py index 3cdcc02..11fe36d 100644 --- a/RepSys/commands/rpmlog.py +++ b/RepSys/commands/rpmlog.py @@ -3,7 +3,7 @@ # This program will convert the output of "svn log" to be suitable # for usage in an rpm %changelog session. # -from RepSys import Error, RepSysTree +from RepSys import Error, layout from RepSys.command import * from RepSys.svn import SVN from RepSys.log import get_changelog, split_spec_changelog @@ -24,6 +24,7 @@ Options: -o Append old package changelog -p Append changelog found in .spec file -s Sort changelog entries, even from the old log + -M Do not use the mirror (use the main repository) -h Show this message Examples: @@ -45,17 +46,14 @@ def parse_options(): opts, args = parser.parse_args() if len(args) != 1: raise Error, "invalid arguments" - opts.pkgdirurl = default_parent(args[0]) + opts.pkgdirurl = layout.package_url(args[0]) return opts def rpmlog(pkgdirurl, revision, size, template, oldlog, usespec, sort): another = None if usespec: svn = SVN() - pkgname = RepSysTree.pkgname(pkgdirurl) - #FIXME don't hardcode current/, it may already be in the URL - specurl = os.path.join(pkgdirurl, "current/SPECS", pkgname + - ".spec") + specurl = layout.package_spec_url(pkgdirurl) rawspec = svn.cat(specurl, rev=revision) spec, another = split_spec_changelog(StringIO(rawspec)) newlog = get_changelog(pkgdirurl, another=another, rev=revision, diff --git a/RepSys/commands/submit.py b/RepSys/commands/submit.py index 2869ff4..334a424 100644 --- a/RepSys/commands/submit.py +++ b/RepSys/commands/submit.py @@ -1,7 +1,8 @@ #!/usr/bin/python from RepSys import Error, config from RepSys.command import * -from RepSys.rpmutil import get_spec, get_submit_info, svn_url_rev +from RepSys.layout import package_url, distro_branch +from RepSys.rpmutil import get_spec, get_submit_info from RepSys.util import get_auth, execcmd, get_helper import urllib import getopt @@ -41,16 +42,19 @@ Options: Examples: repsys submit repsys submit foo + repsys submit 2009.1/foo repsys submit foo@14800 bar baz@11001 repsys submit https://repos/svn/mdv/cooker/foo repsys submit -l https://repos repsys submit --define section=main/testing -t 2008.1 """ +DEFAULT_TARGET = "Cooker" + def parse_options(): parser = OptionParser(help=HELP) parser.defaults["revision"] = None - parser.add_option("-t", dest="target", default="Cooker") + parser.add_option("-t", dest="target", default=None) parser.add_option("-l", action="callback", callback=list_targets) parser.add_option("-r", dest="revision", type="string", nargs=1) parser.add_option("-s", dest="submithost", type="string", nargs=1, @@ -79,7 +83,11 @@ def parse_options(): else: raise Error, "the format is deprecated, "\ "use @ instead" - opts.urls = [default_parent(nameurl) for nameurl in args] + opts.urls = [package_url(nameurl, mirrored=False) for nameurl in args] + if opts.target is None: + target = distro_branch(opts.urls[0]) or DEFAULT_TARGET + print "Implicit target: %s" % target + opts.target = target return opts def list_targets(option, opt, val, parser): diff --git a/RepSys/layout.py b/RepSys/layout.py new file mode 100644 index 0000000..a4a3846 --- /dev/null +++ b/RepSys/layout.py @@ -0,0 +1,207 @@ +""" Handles repository layout scheme and package URLs.""" + +import os +import urlparse + +from RepSys import Error, config +from RepSys.svn import SVN + +__all__ = ["package_url", "checkout_url", "repository_url", "get_url_revision"] + +def layout_dirs(): + devel_branch = config.get("global", "trunk-dir", "cooker/") + devel_branch = os.path.normpath(devel_branch) + branches_dir = config.get("global", "branches-dir", "updates/") + branches_dir = os.path.normpath(branches_dir) + return devel_branch, branches_dir + +def get_url_revision(url, retrieve=True): + """Get the revision from a given URL + + If the URL contains an explicit revision number (URL@REV), just use it + without even checking if the revision really exists. + + The parameter retrieve defines whether it must ask the SVN server for + the revision number or not when it is not found in the URL. + """ + url, rev = split_url_revision(url) + if rev is None and retrieve: + # if no revspec was found, ask the server + svn = SVN() + rev = svn.revision(url) + return rev + +def unsplit_url_revision(url, rev): + if rev is None: + newurl = url + else: + parsed = list(urlparse.urlparse(url)) + path = os.path.normpath(parsed[2]) + parsed[2] = path + "@" + str(rev) + newurl = urlparse.urlunparse(parsed) + return newurl + +def split_url_revision(url): + """Returns a tuple (url, rev) from an subversion URL with @REV + + If the revision is not present in the URL, rev is None. + """ + parsed = list(urlparse.urlparse(url)) + path = os.path.normpath(parsed[2]) + dirs = path.rsplit("/", 1) + lastname = dirs[-1] + newname = lastname + index = lastname.rfind("@") + rev = None + if index != -1: + newname = lastname[:index] + rawrev = lastname[index+1:] + if rawrev: + try: + rev = int(rawrev) + if rev < 0: + raise ValueError + except ValueError: + raise Error, "invalid revision specification on URL: %s" % url + dirs[-1] = newname + newpath = "/".join(dirs) + parsed[2] = newpath + newurl = urlparse.urlunparse(parsed) + return newurl, rev + +def checkout_url(pkgdirurl, branch=None, version=None, release=None, + releases=False, pristine=False, append_path=None): + """Get the URL of a branch of the package, defaults to current/ + + It tries to preserve revisions in the format @REV. + """ + parsed = list(urlparse.urlparse(pkgdirurl)) + path, rev = split_url_revision(parsed[2]) + if releases: + path = os.path.normpath(path + "/releases") + elif version: + assert release is not None + path = os.path.normpath(path + "/releases/" + version + "/" + release) + elif pristine: + path = os.path.join(path, "pristine") + elif branch: + path = os.path.join(path, "branches", branch) + else: + path = os.path.join(path, "current") + if append_path: + path = os.path.join(path, append_path) + path = unsplit_url_revision(path, rev) + parsed[2] = path + newurl = urlparse.urlunparse(parsed) + return newurl + +def convert_default_parent(url): + """Removes the cooker/ component from the URL""" + parsed = list(urlparse.urlparse(url)) + path = os.path.normpath(parsed[2]) + rest, last = os.path.split(path) + parsed[2] = rest + newurl = urlparse.urlunparse(parsed) + return newurl + +def remove_current(pkgdirurl): + parsed = list(urlparse.urlparse(pkgdirurl)) + path = os.path.normpath(parsed[2]) + rest, last = os.path.split(path) + if last == "current": + # FIXME this way we will not allow packages to be named "current" + path = rest + parsed[2] = path + newurl = urlparse.urlunparse(parsed) + return newurl + +def repository_url(mirrored=False): + url = None + if mirrored and config.get("global", "use-mirror"): + url = config.get("global", "mirror") + if url is None: + url = config.get("global", "repository") + if not url: + # compatibility with the default_parent configuration option + default_parent = config.get("global", "default_parent") + if default_parent is None: + raise Error, "you need to set the 'repository' " \ + "configuration option on repsys.conf" + url = convert_default_parent(default_parent) + return url + +def package_url(name_or_url, version=None, release=None, distro=None, + mirrored=True): + """Returns a tuple with the absolute package URL and its name + + @name_or_url: name, relative path, or URL of the package. In case it is + a URL, the URL will just be 'normalized'. + @version: the version to be fetched from releases/ (requires release) + @release: the release number to be fetched from releases/$version/ + @distro: the name of the repository branch inside updates/ + @mirrored: return an URL based on the mirror repository, if enabled + """ + from RepSys import mirror + if "://" in name_or_url: + pkgdirurl = mirror.normalize_path(name_or_url) + pkgdirurl = remove_current(pkgdirurl) + if mirror.using_on(pkgdirurl) and not mirrored: + pkgdirurl = mirror.relocate_path(mirror.mirror_url(), + repository_url(), pkgdirurl) + else: + name = name_or_url + devel_branch, branches_dir = layout_dirs() + if distro or "/" in name: + default_branch = branches_dir + if distro: + default_branch = os.path.join(default_branch, distro) + else: + default_branch = devel_branch # cooker + path = os.path.join(default_branch, name) + parsed = list(urlparse.urlparse(repository_url(mirrored=mirrored))) + parsed[2] = os.path.join(parsed[2], path) + pkgdirurl = urlparse.urlunparse(parsed) + return pkgdirurl + +def package_name(pkgdirurl): + """Returns the package name from a package URL + + It takes care of revision numbers""" + parsed = urlparse.urlparse(pkgdirurl) + path, rev = split_url_revision(parsed[2]) + rest, name = os.path.split(path) + return name + +def package_spec_url(pkgdirurl, *args, **kwargs): + """Returns the URL of the specfile of a given package URL + + The parameters are the same used by checkout_url, except append_path. + """ + kwargs["append_path"] = "SPECS/" + package_name(pkgdirurl) + ".spec" + specurl = checkout_url(pkgdirurl, *args, **kwargs) + return specurl + +def distro_branch(pkgdirurl): + """Tries to guess the distro branch name from a package URL""" + from RepSys.mirror import same_base + found = None + repo = repository_url() + if same_base(repo, pkgdirurl): + devel_branch, branches_dir = layout_dirs() + repo_path = urlparse.urlparse(repo)[2] + devel_path = os.path.join(repo_path, devel_branch) + branches_path = os.path.join(repo_path, branches_dir) + parsed = urlparse.urlparse(pkgdirurl) + path = os.path.normpath(parsed[2]) + if path.startswith(devel_path): + # devel_branch must be before branches_dir in order to allow + # devel_branch to be inside branches_dir, as in /branches/cooker + _, found = os.path.split(devel_branch) + elif path.startswith(branches_path): + comps = path.split("/") + if branches_path == "/": + found = comps[1] + elif len(comps) >= 2: # must be at least branch/pkgname + found = comps[branches_path.count("/")+1] + return found + diff --git a/RepSys/log.py b/RepSys/log.py index ca1d107..a1d1944 100644 --- a/RepSys/log.py +++ b/RepSys/log.py @@ -1,5 +1,5 @@ #!/usr/bin/python -from RepSys import Error, config, RepSysTree +from RepSys import Error, config, layout from RepSys.svn import SVN from RepSys.util import execcmd @@ -400,8 +400,8 @@ def svn2rpm(pkgdirurl, rev=None, size=None, submit=False, concat = config.get("log", "concat", "").split() revoffset = get_revision_offset() svn = SVN() - pkgreleasesurl = os.path.join(pkgdirurl, "releases") - pkgcurrenturl = os.path.join(pkgdirurl, "current") + pkgreleasesurl = layout.checkout_url(pkgdirurl, releases=True) + pkgcurrenturl = layout.checkout_url(pkgdirurl) releaseslog = svn.log(pkgreleasesurl, noerror=1) currentlog = svn.log(pkgcurrenturl, limit=size, start=rev, end=revoffset) @@ -535,7 +535,7 @@ def get_old_log(pkgdirurl): svn = SVN() tmpdir = tempfile.mktemp() try: - pkgname = RepSysTree.pkgname(pkgdirurl) + pkgname = layout.package_name(pkgdirurl) pkgoldurl = os.path.join(oldurl, pkgname) try: # we're using HEAD here because fixes in misc/ (oldurl) may diff --git a/RepSys/mirror.py b/RepSys/mirror.py index 20570d5..09d72de 100644 --- a/RepSys/mirror.py +++ b/RepSys/mirror.py @@ -1,10 +1,16 @@ +import sys import os import urlparse +import urllib -from RepSys import Error, config +from RepSys import Error, config, layout from RepSys.svn import SVN -def _normdirurl(url): +def mirror_url(): + mirror = config.get("global", "mirror") + return mirror + +def normalize_path(url): """normalize url for relocate_path needs""" parsed = urlparse.urlparse(url) path = os.path.normpath(parsed[2]) @@ -19,31 +25,51 @@ def _joinurl(url, relpath): parsed[3], parsed[4], parsed[5])) return newurl + +def strip_username(url): + parsed = list(urlparse.urlparse(url)) + _, parsed[1] = urllib.splituser(parsed[1]) + newurl = urlparse.urlunparse(parsed) + 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 + parent = normalize_path(parent) + url = normalize_path(url) + url = strip_username(url) return url.startswith(parent) def relocate_path(oldparent, newparent, url): - oldparent = _normdirurl(oldparent) - newparent = _normdirurl(newparent) - url = _normdirurl(url) + oldparent = normalize_path(oldparent) + newparent = normalize_path(newparent) + url = normalize_path(url) subpath = url[len(oldparent)+1:] newurl = _joinurl(newparent, subpath) # subpath usually gets / at begining return newurl def enabled(wcurl=None): - mirror = config.get("global", "mirror") - default_parent = config.get("global", "default_parent") + mirror = mirror_url() + repository = layout.repository_url() enabled = False - if mirror and default_parent: + if mirror and repository: enabled = True - if wcurl and (not same_base(mirror, wcurl)): + if wcurl and not same_base(mirror, wcurl): enabled = False return enabled +def using_on(url): + """returnes True if the URL points to the mirror repository""" + mirror = mirror_url() + if mirror: + using = same_base(mirror, url) + else: + using = False + return using + +def info(url, stream=sys.stderr): + if using_on(url): + stream.write("using mirror\n") + def mirror_relocate(oldparent, newparent, url, wcpath): svn = SVN() newurl = relocate_path(oldparent, newparent, url) @@ -52,34 +78,23 @@ def mirror_relocate(oldparent, newparent, url, wcpath): def switchto_parent(svn, url, path): """Relocates the working copy to default_parent""" - mirror = config.get("global", "mirror") - default_parent = config.get("global", "default_parent") - newurl = mirror_relocate(mirror, default_parent, url, path) + newurl = mirror_relocate(mirror_url(), layout.repository_url(), url, path) return newurl def switchto_mirror(svn, url, path): - mirror = config.get("global", "mirror") - default_parent = config.get("global", "default_parent") - newurl = mirror_relocate(default_parent, mirror, url, path) + newurl = mirror_relocate(layout.repository_url(), mirror_url(), url, path) return newurl -def checkout_url(url): - mirror = config.get("global", "mirror") - default_parent = config.get("global", "default_parent") - 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 "\ + mirror = mirror_url() + repository = layout.repository_url() + current = repository + if repository is None: + raise Error, "the option repository from repsys.conf is "\ "required" - indefault = same_base(default_parent, wcurl) + indefault = same_base(repository, wcurl) if not newbaseurl: if not mirror: raise Error, "an URL is needed when the option mirror "\ @@ -88,7 +103,7 @@ def autoswitch(svn, wcpath, wcurl, newbaseurl=None): chosen = mirror elif same_base(mirror, wcurl): current = mirror - chosen = default_parent + chosen = repository else: nobase = True else: @@ -101,7 +116,7 @@ def autoswitch(svn, wcpath, wcurl, newbaseurl=None): chosen = newbaseurl if nobase: raise Error, "the URL of this working copy is not based in "\ - "default_parent nor mirror URLs" + "repository 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 b73a9e2..32b7145 100644 --- a/RepSys/rpmutil.py +++ b/RepSys/rpmutil.py @@ -1,6 +1,6 @@ #!/usr/bin/python -from RepSys import Error, config, RepSysTree -from RepSys import mirror +from RepSys import Error, config +from RepSys import mirror, layout from RepSys.svn import SVN from RepSys.simplerpm import SRPM from RepSys.log import specfile_svn2rpm @@ -19,7 +19,7 @@ def get_spec(pkgdirurl, targetdir=".", submit=False): svn = SVN() tmpdir = tempfile.mktemp() try: - geturl = "/".join([pkgdirurl, "current", "SPECS"]) + geturl = layout.checkout_url(pkgdirurl, append_path="SPECS") svn.export("'%s'" % geturl, tmpdir) speclist = glob.glob(os.path.join(tmpdir, "*.spec")) if not speclist: @@ -52,51 +52,6 @@ def rev_touched_url(url, rev): touched = True return touched -def svn_url_rev(url, retrieve=True): - """Get the revision from a given URL - - If the URL contains an explicit revision number (URL@REV), just use it - without even checking if the revision really exists. - - The parameter retrieve defines whether it must ask the SVN server for - the revision number or not when it is not found in the URL. - """ - parsed = urlparse.urlparse(url) - path = os.path.normpath(parsed[2]) - dirs = path.rsplit("/", 1) - lastname = dirs[-1] - index = lastname.rfind("@") - rev = None - if index != -1: - rawrev = lastname[index+1:] - if rawrev: - try: - rev = int(rawrev) - if rev < 0: - raise ValueError - except ValueError: - raise Error, "invalid revision specification on URL: %s" % url - if rev is None and retrieve: - # if no revspec was found, ask the server - svn = SVN() - rev = svn.revision(url) - return rev - -def strip_url_rev(url): - """Removes the @REV from a string in the URL@REV scheme""" - parsed = list(urlparse.urlparse(url)) - path = os.path.normpath(parsed[2]) - dirs = path.rsplit("/", 1) - name = lastname = dirs[-1] - try: - index = lastname.rindex("@") - except ValueError: - pass - else: - name = lastname[:index] - parsed[2] = os.path.join(dirs[0], name) - return urlparse.urlunparse(parsed) - def get_srpm(pkgdirurl, mode = "current", targetdirs = None, @@ -121,15 +76,16 @@ def get_srpm(pkgdirurl, 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 = os.path.join(pkgdirurl, "releases", - version, release) + geturl = layout.checkout_url(pkgdirurl, version=version, + release=release) elif mode == "pristine": - geturl = os.path.join(pkgdirurl, "pristine") + geturl = layout.checkout_url(pkgdirurl, pristine=True) elif mode == "current" or mode == "revision": #FIXME we should handle revisions specified using @REV - geturl = os.path.join(pkgdirurl, "current") + geturl = layout.checkout_url(pkgdirurl) else: raise Error, "unsupported get_srpm mode: %s" % mode strict = strict or config.getbool("submit", "strict-revision", False) @@ -138,6 +94,7 @@ def get_srpm(pkgdirurl, # 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) srpmsdir = os.path.join(tmpdir, "SRPMS") os.mkdir(srpmsdir) @@ -168,7 +125,7 @@ def get_srpm(pkgdirurl, targetsrpms = [] urlrev = None if revname: - urlrev = revision or svn_url_rev(geturl) + urlrev = revision or layout.get_url_revision(geturl) if not targetdirs: targetdirs = (".",) srpms = glob.glob(os.path.join(srpmsdir, "*.src.rpm")) @@ -194,10 +151,11 @@ def get_srpm(pkgdirurl, shutil.rmtree(tmpdir) def patch_spec(pkgdirurl, patchfile, log=""): + #FIXME use get_spec svn = SVN() tmpdir = tempfile.mktemp() try: - geturl = "/".join([pkgdirurl, "current", "SPECS"]) + geturl = layout.checkout_url(pkgdirurl, append_path="SPECS") svn.checkout(geturl, tmpdir) speclist = glob.glob(os.path.join(tmpdir, "*.spec")) if not speclist: @@ -301,10 +259,10 @@ def put_srpm(pkgdirurl, srpmfile, appendname=0, log=""): shutil.rmtree(tmpdir) # Do revision and pristine tag copies - pristineurl = os.path.join(pkgdirurl, "pristine") + pristineurl = layout.checkout_url(pkgdirurl, pristine=True) svn.remove(pristineurl, noerror=1, log="Removing previous pristine/ directory.") - currenturl = os.path.join(pkgdirurl, "current") + currenturl = layout.checkout_url(pkgdirurl) svn.copy(currenturl, pristineurl, log="Copying release %s-%s to pristine/ directory." % (version, srpm.release)) @@ -316,7 +274,7 @@ def create_package(pkgdirurl, log="", verbose=0): svn = SVN() tmpdir = tempfile.mktemp() try: - basename = RepSysTree.pkgname(pkgdirurl) + basename = layout.package_name(pkgdirurl) if verbose: print "Creating package directory...", sys.stdout.flush() @@ -364,10 +322,10 @@ def mark_release(pkgdirurl, version, release, revision): log="Created releases directory.") svn.mkdir(versionurl, noerror=1, log="Created directory for version %s." % version) - pristineurl = os.path.join(pkgdirurl, "pristine") + pristineurl = layout.checkout_url(pkgdirurl, pristine=True) svn.remove(pristineurl, noerror=1, log="Removing previous pristine/ directory.") - currenturl = os.path.join(pkgdirurl, "current") + currenturl = layout.checkout_url(pkgdirurl) svn.copy(currenturl, pristineurl, log="Copying release %s-%s to pristine/ directory." % (version, release)) @@ -397,8 +355,8 @@ def check_changed(pkgdirurl, all=0, show=0, verbose=0): nocurrent = [] for package in packages: pkgdirurl = os.path.join(baseurl, package) - current = os.path.join(pkgdirurl, "current") - pristine = os.path.join(pkgdirurl, "pristine") + current = layout.checkout_url(pkgdirurl) + pristine = layout.checkout_url(pkgdirurl, pristine=True) if verbose: print "Checking package %s..." % package, sys.stdout.flush() @@ -435,17 +393,14 @@ def check_changed(pkgdirurl, all=0, show=0, verbose=0): "nocurrent": nocurrent, "nopristine": nopristine} -def checkout(pkgdirurl, path=None, revision=None, use_mirror=True): +def checkout(pkgdirurl, path=None, revision=None, branch=None, + distro=None): o_pkgdirurl = pkgdirurl - pkgdirurl = default_parent(o_pkgdirurl) - current = os.path.join(pkgdirurl, "current") + pkgdirurl = layout.package_url(o_pkgdirurl, distro=distro) + current = layout.checkout_url(pkgdirurl, branch=branch) if path is None: - _, path = os.path.split(pkgdirurl) - # if default_parent changed the URL, we can use mirrors because the - # user did not provided complete package URL - if (o_pkgdirurl != pkgdirurl) and use_mirror and mirror.enabled(): - current = mirror.checkout_url(current) - print "checking out from mirror", current + path = layout.package_name(pkgdirurl) + mirror.info(current) svn = SVN() svn.checkout(current, path, rev=revision, show=1) @@ -537,7 +492,7 @@ def commit(target=".", message=None, logfile=None): url = info.get("URL") if url is None: raise Error, "working copy URL not provided by svn info" - mirrored = mirror.enabled(url) + mirrored = mirror.using_on(url) if mirrored: newurl = mirror.switchto_parent(svn, url, target) print "relocated to", newurl diff --git a/create-srpm b/create-srpm index bc4ba06..373b072 100755 --- a/create-srpm +++ b/create-srpm @@ -1,7 +1,8 @@ #!/usr/bin/python -from RepSys import Error, config, plugins -from RepSys.rpmutil import get_srpm, svn_url_rev, strip_url_rev +from RepSys import Error, config, plugins, layout +from RepSys.mirror import strip_username +from RepSys.rpmutil import get_srpm from RepSys.cgiutil import get_targets from RepSys.util import mapurl, execcmd, get_helper import sys @@ -14,13 +15,6 @@ import urllib class CmdError(Error): pass -def strip_username(url): - parsed = list(urlparse.urlparse(url)) - userpwd, hostport = urllib.splituser(parsed[1]) - parsed[1] = hostport - newurl = urlparse.urlunparse(parsed) - return newurl - class CmdIface: def author_email(self, author): return config.get("users", author) @@ -53,10 +47,10 @@ class CmdIface: urls = [mapurl(url) for url in urls] uploadsrpms = [] for url in urls: - revision = revision or svn_url_rev(url) - url = strip_url_rev(url) + urlrev = revision or layout.get_url_revision(url) + url, _ = layout.split_url_revision(url) targetsrpms = get_srpm(url, - revision=revision, + revision=urlrev, targetdirs=target.target, packager=packager, svnlog=1, diff --git a/repsys b/repsys index 67bb180..3869119 100755 --- a/repsys +++ b/repsys @@ -1,5 +1,5 @@ #!/usr/bin/python -from RepSys import Error, plugins +from RepSys import Error, plugins, config from RepSys.command import * import getopt import sys @@ -50,8 +50,12 @@ def parse_options(): parser.add_option("--help-plugins", action="callback", callback=plugin_help) parser.add_option("--help-plugin", type="string", dest="__ignore", action="callback", callback=plugin_help) + parser.add_option("--no-mirror", "-M", action="store_false", + dest="_mirror", default=True) opts, args = parser.parse_args() + config.set("global", "use-mirror", opts._mirror and "yes" or "no") del opts.__ignore + del opts._mirror if len(args) < 1: parser.print_help(sys.stderr) sys.exit(1) diff --git a/repsys-example.conf b/repsys-example.conf index 3a9193c..93d720f 100644 --- a/repsys-example.conf +++ b/repsys-example.conf @@ -1,6 +1,6 @@ [global] verbose = no -default_parent = svn+ssh://svn.mandriva.com/svn/packages/cooker +repository = svn+ssh://svn.mandriva.com/svn/packages/ url-map = svn\+ssh://svn\.mandriva\.com/(.*) file:///\1 #tempdir = /tmp ## the command used to download files when using repsys sync -d diff --git a/repsys.8 b/repsys.8 index 54b49cc..a1b4e37 100644 --- a/repsys.8 +++ b/repsys.8 @@ -7,7 +7,7 @@ repsys \- Package souces repository management tool .SH "DESCRIPTION" \fBrepsys\fP is the tool used to manage RPM packages in a subversion repository. It is used to create, tag releases, generate .src.rpm, generate changelog, and request new package releases for build. It mostly acts as a interface to svn(1) commands and small task scripts run on the build system side over ssh(1). -Most of the \fBrepsys\fP commands operate on a given package URL, these URLs can be omitted when the configuration option \fBdefault_parent\fP is set. +Most of the \fBrepsys\fP commands operate on a given package URL, these URLs can be omitted when the configuration option \fBrepository\fP is set. Detailed help on commands is available running \fBrepsys \-\-help\fP. .SH "BASIC USAGE" @@ -24,6 +24,8 @@ Users that don't have an ssh account in the default repository URL can set the o .PP .IP "\fBrepsys co foo\fP" Obtains a working copy of the package foo. +.IP "\fBrepsys co 2009.0/mutt\fP" +Obtains a working copy of the package mutt of from the 2009.0 branch. .IP "\fBrepsys ci\fP" Commits pending changes in the working copy. .IP "\fBrepsys submit foo \-r 12345\fP" @@ -111,10 +113,12 @@ The main configuration file is \fB/etc/repsys.conf\fP, it is in the .ini format. If existing, the file ~/.repsys/config is also loaded. .SS "[global] section" .PP +.IP "\fBrepository = URL\fP" +Contains the base URL used to access packages in the svn repository when only package names are used in repsys commands. For example, if \fBrepsys co trafshow\fP is run and repository is http://host/svn/, the URL http://host/svn/cooker/trafshow will be used ("cooker" is the default branch). .IP "\fBdefault_parent = URL\fP" -Contains the base URL used to access packages in the svn repository when only package names are used in commands. For example, if \fBrepsys co trafshow\fP is run and default_parent is http://host/svn/cooker/, the URL http://host/svn/cooker/trafshow will be used. -.IP "\fBmirror = URL\fP" -The URL of an alternative and read\-only repository to be used when checking out packages. \fBrepsys ci\fP will automatically relocate to default_parent when comitting. +Points to the base URL of the development branch of the svn repository. This option is deprecated as it has been replaced by "repository". +.IP "\fBmirror = URL\fP" +The URL of an alternative and read\-only repository to be used when checking out packages. \fBrepsys ci\fP will automatically relocate to "repository" when comitting. .IP "\fBurl\-map = MATCH\-REGEXP REPLACE\-EXPR\fP" This option is used on server-side to remap remote URLs brought by the user when running \fBrepsys submit\fP to local (and probably faster) URLs. \fBMATCH\-REGEXP\fP is a Python regular expression matching the components that must be reused in the local URL. \fbREPLACE\-EXPR\fP is a replace expression that should expand in the final URL. Example: \fBsvn\+ssh://svn\.mandriva\.com/(.*) file:///\1\fP .IP "\fBtempdir = PATH\fP" @@ -125,6 +129,10 @@ Command used to download generic remote URLs, it accepts the variables \fB$url\f The base command used to execute svn(1). Runs through system(3). .IP "\fBverbose = yes/no\fP" Increase the verbosity of repsys output, printing commands being run and complete traceback when unhanlded errors happen. +.IP "\fBtrunk-dir\fP" +Points to the default branch of the distro used in commands that do not have their branch or URL specified. +.IP "\fBbranches-dir\fP" +The directory inside the repository which contains all the branches of the distro. It is used to build the URL of packages referred using the branch notation BRANCH/PACKAGE, as in \fBrepsys co 2009.0/mutt\fP. .SS "[submit] section" .IP "\fBhost = HOST\fP" Defines the default host in which \fBrepsys submit\fP will run the submit helper. diff --git a/repsys.conf b/repsys.conf index f3c7401..67c564b 100644 --- a/repsys.conf +++ b/repsys.conf @@ -1,6 +1,6 @@ # see man 8 repsys for a description on configuration options [global] -default_parent = svn+ssh://svn.mandriva.com/svn/packages/cooker +repository = svn+ssh://svn.mandriva.com/svn/packages/ ## uncomment it in case you don't have a account in the Mandriva cluster: #mirror = http://svn.mandriva.com/svn/packages/cooker/ -- cgit v1.2.1