diff options
Diffstat (limited to 'RepSys')
-rw-r--r-- | RepSys/binrepo.py | 425 | ||||
-rw-r--r-- | RepSys/commands/co.py | 7 | ||||
-rw-r--r-- | RepSys/commands/del.py | 30 | ||||
-rw-r--r-- | RepSys/commands/getsrpm.py | 7 | ||||
-rw-r--r-- | RepSys/commands/sync.py | 3 | ||||
-rw-r--r-- | RepSys/commands/up.py | 22 | ||||
-rw-r--r-- | RepSys/commands/upload.py | 39 | ||||
-rw-r--r-- | RepSys/rpmutil.py | 185 |
8 files changed, 687 insertions, 31 deletions
diff --git a/RepSys/binrepo.py b/RepSys/binrepo.py new file mode 100644 index 0000000..9fbd19e --- /dev/null +++ b/RepSys/binrepo.py @@ -0,0 +1,425 @@ +from RepSys import Error, RepSysTree, config +from RepSys.util import execcmd +from RepSys.svn import SVN +from RepSys.mirror import same_base + +import os +import string +import stat +import sha +import shutil +import re +import tempfile +import urlparse +from cStringIO import StringIO + +#TODO logging for markrelease + +DEFAULT_TARBALLS_REPO = "/tarballs" +BINLIST_PENDING = "repsys-upload" +BINLIST_DELETE = "repsys-delete" + +class ChecksumError(Error): + pass + +def copy_rsync(sources, dest, sourcehost=None, desthost=None, + archive=False, recurse=False): + """Simple inteface for rsync""" + args = ["rsync", "-i", "--log-format=\"%i %n\""] + if archive: + args.append("-a") + if recurse: + args.append("-r") + if sourcehost: + # "svn.mandriva.com:/foo/a /foo/b" + #TODO space escaping needed for sources + args.append("\"" + sourcehost + ":" + " ".join(sources) + "\"") + else: + args.extend(sources) + if desthost: + args.append(desthost + ":" + dest) + else: + args.append(dest) + execcmd(show=True, *args) + +def makedirs_remote(path, host): + tmpdir = tempfile.mkdtemp(prefix="repsys-makedirs") + try: + newpath = os.path.normpath(tmpdir + "/" + path) + os.makedirs(newpath) + copy_rsync(sources=[tmpdir + "/"], dest="/", desthost=host, recurse=True) + finally: + if os.path.exists(tmpdir): + shutil.rmtree(tmpdir) + +def copy(sources, dest, sourcehost=None, desthost=None, makedirs=False, + hardlink=False): + """rsync-like copy + + Note that a copy between two dirs will result in overwriting the + latter. + """ + if desthost is None: + # we only need dest to contain the host name + try: + desthost, dpath = dest.split(":", 1) + except ValueError: + dpath = dest + if makedirs: + if desthost: + makedirs_remote(dpath, desthost) + else: + try: + os.makedirs(dpath) + except OSError, e: + if e.errno != 17: # already exists + raise + if sourcehost or desthost: + copy_rsync(sources=sources, sourcehost=sourcehost, dest=dpath, + desthost=desthost, recurse=True, archive=True) + else: + opts = "-a" + if hardlink: + opts += "l" + for source in sources: + if os.path.isdir(source) and os.path.exists(dpath): + #FIXME ugly workaround to behave consistently between + # remote and local copies: + try: + os.rmdir(dpath) + except OSError, e: + raise Error, "can't overwrite directory: %s" % e + execcmd("cp %s %s %s" % (opts, source, dpath)) + +def svn_basedir(target): + svn = SVN() + info = svn.info2(target) + if info is None: + # unversioned resource + newtarget = os.path.dirname(target) + info = svn.info2(newtarget) + assert info is not None, "svn_basedir should not be used with a "\ + "non-versioned directory" + root = info["Repository Root"] + url = info["URL"] + kind = info["Node Kind"] + path = url[len(root):] + if kind == "directory": + return path + return os.path.dirname(path) + +def svn_root(target): + svn = SVN() + info = svn.info2(target) + if info is None: + newtarget = os.path.dirname(target) + info = svn.info2(newtarget) + assert info is not None + return info["Repository Root"] + +def enabled(url): + use = config.getbool("global", "use-binaries-repository", False) + default_parent = config.get("global", "default_parent", None) + if url and use and default_parent and same_base(url, default_parent): + return True + return False + +def target_url(path=None): + from RepSys.rpmutil import get_submit_info + base = config.get("global", "binaries-repository", None) + if base is None: + default_parent = config.get("global", "default_parent", None) + if default_parent is None: + raise Error, "no binaries-repository nor default_parent "\ + "configured" + comps = urlparse.urlparse(default_parent) + base = comps[1] + ":" + DEFAULT_TARBALLS_REPO + if path: + target = os.path.normpath(base + "/" + svn_basedir(path)) + else: + target = base + return target + +def file_hash(path): + sum = sha.new() + f = open(path) + while True: + block = f.read(4096) + if not block: + break + sum.update(block) + f.close() + return sum.hexdigest() + +def check_hash(path, sum): + newsum = file_hash(path) + if newsum != sum: + raise ChecksumError, "different checksums for %s: expected %s, "\ + "but %s was found" % (path, sum, newsum) + +def parse_sources_stream(stream): + entries = {} + for rawline in stream: + line = rawline.strip() + try: + sum, name = line.split(None, 1) + except ValueError: + # failed to unpack, line format error + raise Error, "invalid line in sources file: %s" % rawline + entries[name] = sum + return entries + +def parse_sources(path, force=False): + if not os.path.exists(path) and not force: + return {} + basedir = os.path.dirname(path) + spath = os.path.join(basedir, "sources") + f = open(spath) + entries = parse_sources_stream(f) + f.close() + return entries + +def dump_sources(path, entries): + f = open(path, "w") + for name in sorted(entries.keys()): + #FIXME Unicode! + sum = entries[name] + f.write(sum + " " + name + "\n") + f.close() + +def sources_path(path): + # returns the 'sources' file path for a give file path or directory + sname = config.get("binrepo", "sources-file", "sources") + sdir = path + if not os.path.isdir(path): + sdir = os.path.dirname(path) + spath = os.path.join(sdir, "sources") + return spath + +def get_chksum(path): + sha1 = sha.new() + f = open(path) + while True: + data = f.read(4096) + if not data: + break + sha1.update(data) + f.close() + digest = sha1.hexdigest() + return digest + +def update_sources(paths): + spath = sources_path(paths[0]) + entries = parse_sources(spath) + added = [] + deleted = [] + for path in paths: + name = os.path.basename(path) + if os.path.exists(path): + entries[name] = get_chksum(path) + added.append(name) + else: + deleted.append(name) + entries.pop(name, None) + dump_sources(spath, entries) + return added, deleted + +def is_binary(path): + raw = config.get("binrepo", "upload-match", + "\.(gz|bz2|zip|Z|tar|xar|rpm|7z|lzma)$") + maxsize = config.getint("binrepo", "upload-match-size", "1048576") + expr = re.compile(raw) + name = os.path.basename(path) + if expr.search(name): + return True + st = os.stat(path) + if st[stat.ST_SIZE] >= maxsize: # 1MiB + return True + return False + +def find_binaries(paths): + new = [] + for path in paths: + if os.path.isdir(path): + for name in os.listdir(path): + fpath = os.path.join(path, name) + if is_binary(fpath): + new.append(fpath) + else: + if is_binary(path): + new.append(path) + return new + +def is_tracked(path): + spath = sources_path(path) + entries = parse_sources(spath) + name = os.path.basename(path) + return name in entries + +def upload(paths, auto=False): + base = config.get("binrepo", "upload-command", + "/usr/share/repsys/binrepo-upload") + if auto: + paths = find_binaries(paths) + else: + for path in paths: + if os.path.isdir(path): + raise Error, "can't upload directories, try with -a" + if not paths: + raise Error, "nothing to upload" # is it an error? + target = target_url(paths[0]) + copy(sources=paths, dest=target, makedirs=True) + ad = update_sources(paths) + return ad + +def _binary_list_path(dirpath, name): + fpath = os.path.join(dirpath, ".svn", name) + return fpath + +def _append_binary_list(path, listname): + if os.path.isdir(path): + raise Error, "only files can be uploaded" + basedir = os.path.dirname(path) + ppath = _binary_list_path(basedir, listname) + f = open(ppath, "a+") + f.write(os.path.basename(path) + "\n") + f.close() + +def _get_binary_list(dirpath, listname): + ppath = _binary_list_path(dirpath, listname) + if not os.path.exists(ppath): + return [] + f = open(ppath) + entries = [line.rstrip() for line in f] + f.close() + return entries + +def _delete_binary_list(dirpath, listname): + ppath = _binary_list_path(dirpath, listname) + if os.path.exists(ppath): + os.unlink(ppath) + +def upload_pending(path): + _append_binary_list(path, BINLIST_PENDING) + +def delete_pending(path): + _append_binary_list(path, BINLIST_DELETE) + +def commit(dirpath): + fetch = (lambda listname: + [os.path.join(dirpath, name) for name in + _get_binary_list(dirpath, listname)]) + pending = fetch(BINLIST_PENDING) + delete = fetch(BINLIST_DELETE) + if pending: + upload(pending) + _delete_binary_list(dirpath, BINLIST_PENDING) + if delete: + remove(delete) + _delete_binary_list(dirpath, BINLIST_DELETE) + +def remove(paths): + # we don't care what will happen to the sources file in the tarballs + # repository, we just remove the reference to it + spath = sources_path(paths[0]) + entries = parse_sources(spath) + for path in paths: + if os.path.exists(path): + name = os.path.basename(path) + if name not in entries: + raise Error, "the file %s is not in the sources list" % path + try: + os.unlink(path) + except (OSError, IOError), e: + raise Error, "failed to unlink file: %s" % e + ad = update_sources(paths) + return ad + +def remove_from_sources(path): + #FIXME merge with remove() and update_sources() + spath = sources_path(path) + entries = parse_sources(spath) + name = os.path.basename(path) + try: + del entries[name] + except KeyError: + pass + dump_sources(spath, entries) + +def markrelease(srcurl, desturl, version, release, revision): + svn = SVN() + target_root = target_url() + source = target_url(srcurl) + root = svn_root(srcurl) + relpath = desturl[len(root):] + target = os.path.normpath(target_root + "/" + relpath) + #XXX rsync doesn't support remote paths in both src and dest, so we + # assume we can do it only locally + # so we strip the hostname: + spath = source[source.find(":")+1:] + tpath = target[target.find(":")+1:] + tmproot = target_root[target_root.find(":")+1:] + sname = config.get("binrepo", "sources-file", "sources") + sourcesurl = os.path.join(srcurl, sname) + try: + stream = StringIO(svn.cat(sourcesurl, rev=revision)) + except Error: + # we don't have a sources file, so there is nothing to copy + return + entries = parse_sources_stream(stream) + paths = [os.path.join(spath, name) for name in entries] + # we use target_url as tmproot trying to be 'hardlink friendly' + tmpdir = tempfile.mkdtemp(prefix="repsys-markrelease-", dir=tmproot) + try: + # Check if the files we are going to markrelease are the right + # ones. + # We copy them to a temporary directory in order to be sure it will + # not be changed after we have checked it. Note the comment about + # being 'hardlink friendly': we are assuming rsync will also be + # hardlink friendly and will create another file even to just + # change some file in current/. Of course a dangerous assumption. + copy(paths, tmpdir, makedirs=True) + tmppaths = [] + for name, sum in entries.iteritems(): + path = os.path.join(tmpdir, name) + try: + check_hash(path, sum) + except ChecksumError, e: + raise Error, "can't create release: %s" % e + tmppaths.append(path) + copy(tmppaths, tpath, makedirs=True, hardlink=True) + finally: + shutil.rmtree(tmpdir) + +def download(target, url=None, check=True): + targeturl = target_url(url or target) + spath = sources_path(target) + if not os.path.exists(spath): + # we don't have external sources + return + entries = parse_sources(spath) + try: + host, path = targeturl.split(":", 1) + except ValueError: + host = None + path = targeturl + if os.path.isdir(target): + paths = [os.path.join(path, name) for name, sum in entries.iteritems()] + targetdir = target + else: + paths = [os.path.join(path, os.path.basename(target))] + name = os.path.basename(target) + targetdir = os.path.dirname(target) + if name not in entries: + raise Error, "file not uploaded yet (not found in "\ + "sources file): %s" % target + copy(sources=paths, sourcehost=host, dest=targetdir) + yield "Checking files" + if check: + for path in paths: + name = os.path.basename(path) + bpath = os.path.join(targetdir, name) + sum = entries[name] + check_hash(bpath, sum) + yield "Done" + diff --git a/RepSys/commands/co.py b/RepSys/commands/co.py index 830b7e7..f0b916a 100644 --- a/RepSys/commands/co.py +++ b/RepSys/commands/co.py @@ -16,6 +16,9 @@ repository. Options: -r REV Revision to checkout -o Do not use the mirror (use official server) + -S Do not download sources from the binaries repository + -C Do not check integrity of files fetched from the binary + repository -h Show this message Examples: @@ -29,6 +32,10 @@ def parse_options(): parser.add_option("-r", dest="revision") parser.add_option("-o", dest="use_mirror", default=True, action="store_false") + parser.add_option("-S", dest="use_binrepo", default=True, + action="store_false") + parser.add_option("-C", dest="binrepo_check", default=True, + action="store_false") opts, args = parser.parse_args() if len(args) not in (1, 2): raise Error, "invalid arguments" diff --git a/RepSys/commands/del.py b/RepSys/commands/del.py new file mode 100644 index 0000000..2c6902e --- /dev/null +++ b/RepSys/commands/del.py @@ -0,0 +1,30 @@ +from RepSys import Error +from RepSys.command import * +from RepSys.rpmutil import binrepo_delete + +HELP = """\ +Usage: repsys del [OPTIONS] [PATH] + +Remove a given file from the binary sources repository. + +Changes in the sources file will be left uncommited. + +Options: + -c automatically commit the 'sources' file + -h help + +""" + +def parse_options(): + parser = OptionParser(help=HELP) + parser.add_option("-c", dest="commit", default=False, + action="store_true") + opts, args = parser.parse_args() + if len(args): + opts.paths = args + else: + raise Error, "you need to provide a path" + return opts + +def main(): + do_command(parse_options, binrepo_delete) diff --git a/RepSys/commands/getsrpm.py b/RepSys/commands/getsrpm.py index f9a63d2..d6ee8eb 100644 --- a/RepSys/commands/getsrpm.py +++ b/RepSys/commands/getsrpm.py @@ -30,6 +30,9 @@ Options: -l Use subversion log to build rpm %changelog -T FILE Template to be used to generate the %changelog -h Show this message + -S Do not download sources from the binary repository + -C Do not check integrity of files fetched from the binary + repository --strict Check if the given revision contains changes in REPPKGURL Examples: @@ -74,6 +77,10 @@ def parse_options(): parser.add_option("-n", dest="revname", action="store_true") parser.add_option("-l", dest="svnlog", action="store_true") parser.add_option("-T", dest="template", type="string", default=None) + parser.add_option("-S", dest="use_binrepo", default=True, + action="store_false") + parser.add_option("-C", dest="binrepo_check", default=True, + action="store_false") parser.add_option("--strict", dest="strict", default=False, action="store_true") opts, args = parser.parse_args() diff --git a/RepSys/commands/sync.py b/RepSys/commands/sync.py index a51db22..fecf08d 100644 --- a/RepSys/commands/sync.py +++ b/RepSys/commands/sync.py @@ -11,6 +11,7 @@ from the spec file. "No changes are commited." Options: + -c Commit the changes, as in ci --dry-run Print results without changing the working copy --download -d Try to download the source files not found @@ -24,6 +25,8 @@ def parse_options(): parser = OptionParser(help=HELP) parser.add_option("--dry-run", dest="dryrun", default=False, action="store_true") + parser.add_option("-c", dest="ci", default=False, + action="store_true") parser.add_option("-d", "--download", dest="download", default=False, action="store_true") opts, args = parser.parse_args() diff --git a/RepSys/commands/up.py b/RepSys/commands/up.py new file mode 100644 index 0000000..02a1a9f --- /dev/null +++ b/RepSys/commands/up.py @@ -0,0 +1,22 @@ +from RepSys import Error +from RepSys.command import * +from RepSys.rpmutil import update + +HELP = """\ +Usage: repsys up [PATH] + +Update the package working copy and synchronize all binaries. + +Options: + -h help +""" + +def parse_options(): + parser = OptionParser(help=HELP) + opts, args = parser.parse_args() + if args: + opts.target = args[0] + return opts + +def main(): + do_command(parse_options, update) diff --git a/RepSys/commands/upload.py b/RepSys/commands/upload.py new file mode 100644 index 0000000..49840a6 --- /dev/null +++ b/RepSys/commands/upload.py @@ -0,0 +1,39 @@ +from RepSys import Error +from RepSys.command import * +from RepSys.rpmutil import upload + +HELP = """\ +Usage: repsys upload [OPTIONS] [PATH] + +Upload a given file to the binary sources repository. + +It will also update the contents of the 'sources' file and left it +uncommited. + +If the path is a directory, all the contents of the directory will be +uploaded or removed. + +Options: + -a find all possible binary sources inside PATH + -c automatically commit the 'sources' file + -A do not 'svn add' the 'sources' file + -h help + +""" + +def parse_options(): + parser = OptionParser(help=HELP) + parser.add_option("-c", dest="commit", default=False, + action="store_true") + parser.add_option("-A", dest="addsources", default=True, + action="store_false") + parser.add_option("-a", dest="auto", default=False, action="store_true") + opts, args = parser.parse_args() + if len(args): + opts.paths = args + else: + raise Error, "you need to provide a path" + return opts + +def main(): + do_command(parse_options, upload) diff --git a/RepSys/rpmutil.py b/RepSys/rpmutil.py index 3bb1b50..46fa392 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 mirror, binrepo from RepSys.svn import SVN from RepSys.simplerpm import SRPM from RepSys.log import specfile_svn2rpm @@ -64,7 +64,9 @@ def get_srpm(pkgdirurl, template = None, macros = [], verbose = 0, - strict = False): + strict = False, + use_binrepo = False, + binrepo_check = True): svn = SVN() tmpdir = tempfile.mktemp() topdir = "--define '_topdir %s'" % tmpdir @@ -91,6 +93,8 @@ def get_srpm(pkgdirurl, raise Error, "the revision %s does not change anything "\ "inside %s" % (revision or "HEAD", geturl) svn.export(geturl, tmpdir, rev=revision) + if use_binrepo: + download_binaries(tmpdir, geturl, check=binrepo_check) srpmsdir = os.path.join(tmpdir, "SRPMS") os.mkdir(srpmsdir) specsdir = os.path.join(tmpdir, "SPECS") @@ -308,6 +312,10 @@ def mark_release(pkgdirurl, version, release, revision): releasesurl = "/".join([pkgdirurl, "releases"]) versionurl = "/".join([releasesurl, version]) releaseurl = "/".join([versionurl, release]) + currenturl = os.path.join(pkgdirurl, "current") + cursources = os.path.join(currenturl, "SOURCES") + relsources = os.path.join(releaseurl, "SOURCES") + binrepo.markrelease(cursources, relsources, version, release, revision) if svn.ls(releaseurl, noerror=1): raise Error, "release already exists" svn.mkdir(releasesurl, noerror=1, @@ -317,7 +325,6 @@ def mark_release(pkgdirurl, version, release, revision): pristineurl = os.path.join(pkgdirurl, "pristine") svn.remove(pristineurl, noerror=1, log="Removing previous pristine/ directory.") - currenturl = os.path.join(pkgdirurl, "current") svn.copy(currenturl, pristineurl, log="Copying release %s-%s to pristine/ directory." % (version, release)) @@ -385,7 +392,8 @@ 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, use_mirror=True, + use_binrepo=False, binrepo_check=True): o_pkgdirurl = pkgdirurl pkgdirurl = default_parent(o_pkgdirurl) current = os.path.join(pkgdirurl, "current") @@ -398,24 +406,34 @@ def checkout(pkgdirurl, path=None, revision=None, use_mirror=True): print "checking out from mirror", current svn = SVN() svn.checkout(current, path, rev=revision, show=1) - -def _getpkgtopdir(basedir=None): + if use_binrepo: + download_binaries(path, 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.getcwd() - cwd = os.getcwd() - dirname = os.path.basename(cwd) - if dirname == "SPECS" or dirname == "SOURCES": - topdir = os.pardir - else: - topdir = "" - return topdir + 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 sync(dryrun=False, download=False): +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): svn = SVN() - topdir = _getpkgtopdir() + 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): @@ -434,15 +452,21 @@ def sync(dryrun=False, download=False): 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 = [] + toadd_br = [] + toadd_svn = [] + toremove_svn = [] + toremove_br = [] for source, url in sources.iteritems(): sourcepath = os.path.join(sourcesdir, source) - pst = sourcesst.get(source) - if pst: + if sourcesst.get(source): if os.path.isfile(sourcepath): - toadd.append(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, skipping\n" % sourcepath) + 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", @@ -455,29 +479,47 @@ def sync(dryrun=False, download=False): "configuration option" % e execcmd(cmd, show=True) if os.path.isfile(sourcepath): - toadd.append(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) - toremove = [] for entry in found: - if entry == ".svn": + if entry == ".svn" or entry == "sources": continue status = sourcesst.get(entry) - if status is None and entry not in sources: - path = os.path.join(sourcesdir, entry) - toremove.append(path) - for path in toremove: + 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 toadd: + 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: @@ -504,9 +546,90 @@ def commit(target=".", message=None, logfile=None): print "use \"repsys switch\" in order to switch back to mirror "\ "later" +def download_binaries(target, pkgdirurl=None, check=True): + refurl = pkgdirurl + if refurl is None: + refurl = binrepo.svn_root(target) + if binrepo.enabled(refurl): + sourcesdir = "SOURCES" + url = None + bintarget = os.path.join(target, sourcesdir) + if pkgdirurl: + url = os.path.join(pkgdirurl, sourcesdir) + for status in binrepo.download(bintarget, url, check): + print status + +def update(target=None): + svn = SVN() + svn_target = None + br_target = None + if target: + info = svn.info2(target) + spath = binrepo.sources_path(target) + if info is None: + # probably something kept in the binary repository + if os.path.exists(spath): + entries = binrepo.parse_sources(spath) + name = os.path.basename(target) + if name in entries: + br_target = target + svn_target = spath + else: + svn_target = target + if info["Node Kind"] == "directory": + if os.path.exists(spath): + br_target = target + else: + top = getpkgtopdir() + svn_target = top + br_target = os.path.join(top, "SOURCES") + if not br_target and not svn_target: + raise Error, "target not in SVN nor in binaries "\ + "repository: %s" % target + if svn_target: + svn.update(svn_target, show=True) + if br_target: + for status in binrepo.download(br_target): + print status + +def _sources_log(added, deleted): + lines = ["SILENT: changed sources list:\n"] + for name in added: + lines.append("A\t" + name) + for name in deleted: + lines.append("D\t" + name) + log = "\n".join(lines) + return log + +def upload(paths, auto=False, commit=False, addsources=False): + if auto and not paths: + topdir = getpkgtopdir() + paths = [os.path.join(topdir, "SOURCES")] + added, deleted = binrepo.upload(paths, auto) + if addsources or commit: + svn = SVN() + spath = binrepo.sources_path(paths[0]) + if addsources: + svn.add(spath) + if commit: + log = _sources_log(added, deleted) + svn.commit(spath, log=log) + +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() + topdir = getpkgtopdir() info = svn.info2(topdir) wcurl = info.get("URL") if wcurl is None: |