aboutsummaryrefslogtreecommitdiffstats
path: root/RepSys
diff options
context:
space:
mode:
Diffstat (limited to 'RepSys')
-rwxr-xr-x[-rw-r--r--]RepSys/ConfigParser.py0
-rwxr-xr-x[-rw-r--r--]RepSys/__init__.py5
-rwxr-xr-xRepSys/binrepo.py393
-rwxr-xr-x[-rw-r--r--]RepSys/cgi/__init__.py0
-rwxr-xr-x[-rw-r--r--]RepSys/cgi/soapserver.py0
-rwxr-xr-x[-rw-r--r--]RepSys/cgi/submit.py0
-rwxr-xr-x[-rw-r--r--]RepSys/cgi/xmlrpcserver.py0
-rwxr-xr-x[-rw-r--r--]RepSys/cgiutil.py0
-rwxr-xr-x[-rw-r--r--]RepSys/command.py4
-rwxr-xr-x[-rw-r--r--]RepSys/commands/__init__.py0
-rwxr-xr-x[-rw-r--r--]RepSys/commands/authoremail.py0
-rwxr-xr-x[-rw-r--r--]RepSys/commands/changed.py4
-rwxr-xr-x[-rw-r--r--]RepSys/commands/ci.py0
-rwxr-xr-x[-rw-r--r--]RepSys/commands/co.py16
-rwxr-xr-x[-rw-r--r--]RepSys/commands/create.py0
-rwxr-xr-xRepSys/commands/del.py30
-rwxr-xr-x[-rw-r--r--]RepSys/commands/editlog.py0
-rwxr-xr-x[-rw-r--r--]RepSys/commands/getspec.py4
-rwxr-xr-x[-rw-r--r--]RepSys/commands/getsrpm.py10
-rwxr-xr-xRepSys/commands/log.py62
-rwxr-xr-x[-rw-r--r--]RepSys/commands/markrelease.py0
-rwxr-xr-x[-rw-r--r--]RepSys/commands/patchspec.py0
-rwxr-xr-x[-rw-r--r--]RepSys/commands/putsrpm.py1
-rwxr-xr-x[-rw-r--r--]RepSys/commands/rpmlog.py4
-rwxr-xr-x[-rw-r--r--]RepSys/commands/submit.py76
-rwxr-xr-x[-rw-r--r--]RepSys/commands/switch.py6
-rwxr-xr-x[-rw-r--r--]RepSys/commands/sync.py9
-rwxr-xr-xRepSys/commands/up.py22
-rwxr-xr-xRepSys/commands/upload.py28
-rwxr-xr-x[-rw-r--r--]RepSys/layout.py2
-rwxr-xr-x[-rw-r--r--]RepSys/log.py20
-rwxr-xr-x[-rw-r--r--]RepSys/mirror.py7
-rwxr-xr-x[-rw-r--r--]RepSys/plugins/__init__.py0
-rwxr-xr-x[-rw-r--r--]RepSys/plugins/ldapusers.py0
-rwxr-xr-x[-rw-r--r--]RepSys/rpmutil.py231
-rwxr-xr-x[-rw-r--r--]RepSys/simplerpm.py0
-rwxr-xr-x[-rw-r--r--]RepSys/svn.py106
-rwxr-xr-x[-rw-r--r--]RepSys/util.py52
38 files changed, 975 insertions, 117 deletions
diff --git a/RepSys/ConfigParser.py b/RepSys/ConfigParser.py
index 3b4e213..3b4e213 100644..100755
--- a/RepSys/ConfigParser.py
+++ b/RepSys/ConfigParser.py
diff --git a/RepSys/__init__.py b/RepSys/__init__.py
index 2759e8f..b0df184 100644..100755
--- a/RepSys/__init__.py
+++ b/RepSys/__init__.py
@@ -9,6 +9,11 @@ config = ConfigParser.Config()
tempfile.tempdir = config.get("global", "tempdir", None) or None # when ""
del ConfigParser
+def disable_mirror(*a, **kw):
+ config.set("global", "use-mirror", "no")
+
class Error(Exception): pass
+class SilentError(Error): pass
+
# vim:et:ts=4:sw=4
diff --git a/RepSys/binrepo.py b/RepSys/binrepo.py
new file mode 100755
index 0000000..edca9a4
--- /dev/null
+++ b/RepSys/binrepo.py
@@ -0,0 +1,393 @@
+from RepSys import Error, config, mirror, layout
+from RepSys.util import execcmd, rellink
+from RepSys.svn import SVN
+
+import sys
+import os
+import string
+import stat
+import shutil
+import re
+import tempfile
+import hashlib
+import urlparse
+import threading
+from cStringIO import StringIO
+
+DEFAULT_TARBALLS_REPO = "/tarballs"
+BINARIES_DIR_NAME = "SOURCES"
+BINARIES_CHECKOUT_NAME = "SOURCES-bin"
+
+PROP_USES_BINREPO = "mdv:uses-binrepo"
+PROP_BINREPO_REV = "mdv:binrepo-rev"
+
+BINREPOS_SECTION = "binrepos"
+
+SOURCES_FILE = "sha1.lst"
+
+class ChecksumError(Error):
+ pass
+
+def svn_baseurl(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 url
+ basepath = os.path.dirname(path)
+ baseurl = mirror.normalize_path(url + "/" + basepath)
+ return baseurl
+
+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):
+ #TODO use information from url to find out whether we have a binrepo
+ # available for this url
+ use = config.getbool("global", "use-binaries-repository", False)
+ return use
+
+def default_repo():
+ 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
+ return base
+
+def translate_url(url):
+ url = mirror.normalize_path(url)
+ main = mirror.normalize_path(layout.repository_url())
+ subpath = url[len(main)+1:]
+ # [binrepos]
+ # updates/2009.0 = svn+ssh://svn.mandriva.com/svn/binrepo/20090/
+ ## svn+ssh://svn.mandriva.com/svn/packages/2009.0/trafshow/current
+ ## would translate to
+ ## svn+ssh://svn.mandriva.com/svn/binrepo/20090/updates/trafshow/current/
+ binbase = None
+ if BINREPOS_SECTION in config.sections():
+ for option, value in config.walk(BINREPOS_SECTION):
+ if subpath.startswith(option):
+ binbase = value
+ break
+ binurl = mirror._joinurl(binbase or default_repo(), subpath)
+ return binurl
+
+def translate_topdir(path):
+ """Returns the URL in the binrepo from a given path inside a SVN
+ checkout directory.
+
+ @path: if specified, returns a URL in the binrepo whose path is the
+ same as the path inside the main repository.
+ """
+ baseurl = svn_baseurl(path)
+ binurl = translate_url(baseurl)
+ target = mirror.normalize_path(binurl)
+ return target
+
+def is_binary(path):
+ raw = config.get("binrepo", "upload-match",
+ "\.(7z|Z|bin|bz2|cpio|db|deb|egg|gem|gz|jar|jisp|lzma|"\
+ "pdf|pgn\\.gz|pk3|rpm|rpm|run|sdz|smzip|tar|tbz|"\
+ "tbz2|tgz|ttf|uqm|wad|war|xar|xpi|zip)$")
+ maxsize = config.getint("binrepo", "upload-match-size", "1048576") # 1MiB
+ 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:
+ 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 make_symlinks(source, dest):
+ todo = []
+ tomove = []
+ for name in os.listdir(source):
+ path = os.path.join(source, name)
+ if not os.path.isdir(path) and not name.startswith("."):
+ destpath = os.path.join(dest, name)
+ linkpath = rellink(path, destpath)
+ if os.path.exists(destpath):
+ if (os.path.islink(destpath) and
+ os.readlink(destpath) == linkpath):
+ continue
+ movepath = destpath + ".repsys-moved"
+ if os.path.exists(movepath):
+ raise Error, "cannot create symlink, %s already "\
+ "exists (%s too)" % (destpath, movepath)
+ tomove.append((destpath, movepath))
+ todo.append((destpath, linkpath))
+ for destpath, movepath in tomove:
+ os.rename(destpath, movepath)
+ for destpath, linkpath in todo:
+ os.symlink(linkpath, destpath)
+
+def download(targetdir, pkgdirurl=None, export=False, show=True,
+ revision=None, symlinks=True, check=False):
+ assert not export or (export and pkgdirurl)
+ svn = SVN()
+ sourcespath = os.path.join(targetdir, "SOURCES")
+ binpath = os.path.join(targetdir, BINARIES_CHECKOUT_NAME)
+ if pkgdirurl:
+ topurl = translate_url(pkgdirurl)
+ else:
+ topurl = translate_topdir(targetdir)
+ binrev = None
+ if revision:
+ if pkgdirurl:
+ binrev = mapped_revision(pkgdirurl, revision)
+ else:
+ binrev = mapped_revision(targetdir, revision, wc=True)
+ binurl = mirror._joinurl(topurl, BINARIES_DIR_NAME)
+ if export:
+ svn.export(binurl, binpath, rev=binrev, show=show)
+ else:
+ svn.checkout(binurl, binpath, rev=binrev, show=show)
+ if symlinks:
+ make_symlinks(binpath, sourcespath)
+ if check:
+ check_sources(targetdir)
+
+def import_binaries(topdir, pkgname):
+ """Import all binaries from a given package checkout
+
+ (with pending svn adds)
+
+ @topdir: the path to the svn checkout
+ """
+ svn = SVN()
+ topurl = translate_topdir(topdir)
+ sourcesdir = os.path.join(topdir, "SOURCES")
+ bintopdir = tempfile.mktemp("repsys")
+ try:
+ svn.checkout(topurl, bintopdir)
+ checkout = True
+ except Error:
+ bintopdir = tempfile.mkdtemp("repsys")
+ checkout = False
+ try:
+ bindir = os.path.join(bintopdir, BINARIES_DIR_NAME)
+ if not os.path.exists(bindir):
+ if checkout:
+ svn.mkdir(bindir)
+ else:
+ os.mkdir(bindir)
+ binaries = find_binaries([sourcesdir])
+ update = update_sources_threaded(topdir, added=binaries)
+ for path in binaries:
+ name = os.path.basename(path)
+ binpath = os.path.join(bindir, name)
+ os.rename(path, binpath)
+ try:
+ svn.remove(path)
+ except Error:
+ # file not tracked
+ svn.revert(path)
+ if checkout:
+ svn.add(binpath)
+ log = "imported binaries for %s" % pkgname
+ if checkout:
+ rev = svn.commit(bindir, log=log)
+ else:
+ rev = svn.import_(bintopdir, topurl, log=log)
+ svn.propset(PROP_USES_BINREPO, "yes", topdir)
+ svn.propset(PROP_BINREPO_REV, str(rev), topdir)
+ update.join()
+ svn.add(sources_path(topdir))
+ finally:
+ shutil.rmtree(bintopdir)
+
+def create_package_dirs(bintopdir):
+ svn = SVN()
+ binurl = mirror._joinurl(bintopdir, BINARIES_DIR_NAME)
+ silent = config.get("log", "ignore-string", "SILENT")
+ message = "%s: created binrepo package structure" % silent
+ svn.mkdir(binurl, log=message, parents=True)
+
+def parse_sources(path):
+ entries = {}
+ f = open(path)
+ for rawline in f:
+ 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 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 check_sources(topdir):
+ spath = sources_path(topdir)
+ if not os.path.exists(spath):
+ raise Error, "'%s' was not found" % spath
+ entries = parse_sources(spath)
+ for name, sum in entries.iteritems():
+ fpath = os.path.join(topdir, "SOURCES", name)
+ check_hash(fpath, sum)
+
+def file_hash(path):
+ sum = hashlib.sha1()
+ f = open(path)
+ while True:
+ block = f.read(4096)
+ if not block:
+ break
+ sum.update(block)
+ f.close()
+ return sum.hexdigest()
+
+def sources_path(topdir):
+ path = os.path.join(topdir, "SOURCES", SOURCES_FILE)
+ return path
+
+def update_sources(topdir, added=[], removed=[]):
+ path = sources_path(topdir)
+ entries = {}
+ if os.path.isfile(path):
+ entries = parse_sources(path)
+ f = open(path, "w") # open before calculating hashes
+ for name in removed:
+ entries.pop(removed)
+ for added_path in added:
+ name = os.path.basename(added_path)
+ entries[name] = file_hash(added_path)
+ for name in sorted(entries):
+ f.write("%s %s\n" % (entries[name], name))
+ f.close()
+
+def update_sources_threaded(*args, **kwargs):
+ t = threading.Thread(target=update_sources, args=args, kwargs=kwargs)
+ t.start()
+ return t
+
+def upload(path, message=None):
+ from RepSys.rpmutil import getpkgtopdir
+ svn = SVN()
+ if not os.path.exists(path):
+ raise Error, "not found: %s" % path
+ # XXX check if the path is under SOURCES/
+ paths = find_binaries([path])
+ if not paths:
+ raise Error, "'%s' does not seem to have any tarballs" % path
+ topdir = getpkgtopdir()
+ bintopdir = translate_topdir(topdir)
+ binurl = mirror._joinurl(bintopdir, BINARIES_DIR_NAME)
+ sourcesdir = os.path.join(topdir, "SOURCES")
+ bindir = os.path.join(topdir, BINARIES_CHECKOUT_NAME)
+ silent = config.get("log", "ignore-string", "SILENT")
+ if not os.path.exists(bindir):
+ try:
+ download(topdir, show=False)
+ except Error:
+ # possibly the package does not exist
+ # (TODO check whether it is really a 'path not found' error)
+ pass
+ if not os.path.exists(bindir):
+ create_package_dirs(bintopdir)
+ svn.propset(PROP_USES_BINREPO, "yes", topdir)
+ svn.commit(topdir, log="%s: created binrepo structure" % silent)
+ download(topdir, show=False)
+ for path in paths:
+ if svn.info2(path):
+ sys.stderr.write("'%s' is already tracked by svn, ignoring\n" %
+ path)
+ continue
+ name = os.path.basename(path)
+ binpath = os.path.join(bindir, name)
+ os.rename(path, binpath)
+ svn.add(binpath)
+ if not message:
+ message = "%s: new binary files %s" % (silent, " ".join(paths))
+ make_symlinks(bindir, sourcesdir)
+ update = update_sources_threaded(topdir, added=paths)
+ rev = svn.commit(binpath, log=message)
+ svn.propset(PROP_BINREPO_REV, str(rev), topdir)
+ sources = sources_path(topdir)
+ svn.add(sources)
+ update.join()
+ svn.commit(topdir + " " + sources, log=message, nonrecursive=True)
+
+def mapped_revision(target, revision, wc=False):
+ """Maps a txtrepo revision to a binrepo datespec
+
+ This datespec can is intended to be used by svn .. -r DATE.
+
+ @target: a working copy path or a URL
+ @revision: if target is a URL, the revision number used when fetching
+ svn info
+ @wc: if True indicates that 'target' must be interpreted as a
+ the path of a svn working copy, otherwise it is handled as a URL
+ """
+ svn = SVN()
+ binrev = None
+ if wc:
+ spath = sources_path(target)
+ if os.path.exists(spath):
+ infolines = svn.info(spath, xml=True)
+ if infolines:
+ rawinfo = "".join(infolines) # arg!
+ found = re.search("<date>(.*?)</date>", rawinfo).groups()
+ date = found[0]
+ else:
+ raise Error, "bogus 'svn info' for '%s'" % spath
+ else:
+ raise Error, "'%s' was not found" % spath
+ else:
+ url = mirror._joinurl(target, sources_path(""))
+ date = svn.propget("svn:date", url, rev=revision, revprop=True)
+ if not date:
+ raise Error, "no valid date available for '%s'" % url
+ binrev = "{%s}" % date
+ return binrev
+
+def markrelease(sourceurl, releasesurl, version, release, revision):
+ svn = SVN()
+ binrev = mapped_revision(sourceurl, revision)
+ binsource = translate_url(sourceurl)
+ binreleases = translate_url(releasesurl)
+ versiondir = mirror._joinurl(binreleases, version)
+ dest = mirror._joinurl(versiondir, release)
+ svn.mkdir(binreleases, noerror=1, log="created directory for releases")
+ svn.mkdir(versiondir, noerror=1, log="created directory for version %s" % version)
+ svn.copy(binsource, dest, rev=binrev,
+ log="%%markrelease ver=%s rel=%s rev=%s binrev=%s" % (version, release,
+ revision, binrev))
diff --git a/RepSys/cgi/__init__.py b/RepSys/cgi/__init__.py
index e69de29..e69de29 100644..100755
--- a/RepSys/cgi/__init__.py
+++ b/RepSys/cgi/__init__.py
diff --git a/RepSys/cgi/soapserver.py b/RepSys/cgi/soapserver.py
index 2f6b751..2f6b751 100644..100755
--- a/RepSys/cgi/soapserver.py
+++ b/RepSys/cgi/soapserver.py
diff --git a/RepSys/cgi/submit.py b/RepSys/cgi/submit.py
index 10f7cb2..10f7cb2 100644..100755
--- a/RepSys/cgi/submit.py
+++ b/RepSys/cgi/submit.py
diff --git a/RepSys/cgi/xmlrpcserver.py b/RepSys/cgi/xmlrpcserver.py
index e0851d1..e0851d1 100644..100755
--- a/RepSys/cgi/xmlrpcserver.py
+++ b/RepSys/cgi/xmlrpcserver.py
diff --git a/RepSys/cgiutil.py b/RepSys/cgiutil.py
index 35c5efb..35c5efb 100644..100755
--- a/RepSys/cgiutil.py
+++ b/RepSys/cgiutil.py
diff --git a/RepSys/command.py b/RepSys/command.py
index f1d61f7..63f2df9 100644..100755
--- a/RepSys/command.py
+++ b/RepSys/command.py
@@ -1,5 +1,5 @@
#!/usr/bin/python
-from RepSys import Error, config
+from RepSys import SilentError, Error, config
import sys, os
import urlparse
import optparse
@@ -37,6 +37,8 @@ def do_command(parse_options_func, main_func):
try:
opt = parse_options_func()
main_func(**opt.__dict__)
+ except SilentError:
+ sys.exit(1)
except Error, e:
sys.stderr.write("error: %s\n" % str(e))
sys.exit(1)
diff --git a/RepSys/commands/__init__.py b/RepSys/commands/__init__.py
index e69de29..e69de29 100644..100755
--- a/RepSys/commands/__init__.py
+++ b/RepSys/commands/__init__.py
diff --git a/RepSys/commands/authoremail.py b/RepSys/commands/authoremail.py
index f5b8b70..f5b8b70 100644..100755
--- a/RepSys/commands/authoremail.py
+++ b/RepSys/commands/authoremail.py
diff --git a/RepSys/commands/changed.py b/RepSys/commands/changed.py
index 7d05604..66c1a53 100644..100755
--- a/RepSys/commands/changed.py
+++ b/RepSys/commands/changed.py
@@ -1,5 +1,5 @@
#!/usr/bin/python
-from RepSys import Error
+from RepSys import Error, disable_mirror
from RepSys.command import *
from RepSys.layout import package_url
from RepSys.rpmutil import check_changed
@@ -26,6 +26,8 @@ def parse_options():
parser = OptionParser(help=HELP)
parser.add_option("-a", dest="all", action="store_true")
parser.add_option("-s", dest="show", action="store_true")
+ parser.add_option("-M", "--no-mirror", action="callback",
+ callback=disable_mirror)
opts, args = parser.parse_args()
if len(args) != 1:
raise Error, "invalid arguments"
diff --git a/RepSys/commands/ci.py b/RepSys/commands/ci.py
index 8d373b5..8d373b5 100644..100755
--- a/RepSys/commands/ci.py
+++ b/RepSys/commands/ci.py
diff --git a/RepSys/commands/co.py b/RepSys/commands/co.py
index 5349049..81e4140 100644..100755
--- a/RepSys/commands/co.py
+++ b/RepSys/commands/co.py
@@ -1,5 +1,5 @@
#!/usr/bin/python
-from RepSys import Error
+from RepSys import Error, disable_mirror
from RepSys.command import *
from RepSys.rpmutil import checkout
import getopt
@@ -19,7 +19,11 @@ Options:
-d The distribution branch to checkout from
-b The package branch
-r REV Revision to checkout
+ -S Do not download sources from the binaries repository
+ -L Do not make symlinks of the binaries downloaded in SOURCES/
+ -s Only checkout the SPECS/ directory
-M Do not use the mirror (use the main repository)
+ --check Check integrity of files fetched from the binary repository
-h Show this message
Examples:
@@ -33,8 +37,18 @@ Examples:
def parse_options():
parser = OptionParser(help=HELP)
parser.add_option("-r", dest="revision")
+ parser.add_option("-S", dest="use_binrepo", default=True,
+ action="store_false")
+ parser.add_option("--check", dest="binrepo_check", default=False,
+ action="store_true")
+ parser.add_option("-L", dest="binrepo_link", default=True,
+ action="store_false")
parser.add_option("--distribution", "-d", dest="distro", default=None)
parser.add_option("--branch", "-b", dest="branch", default=None)
+ parser.add_option("-s", "--spec", dest="spec", default=False,
+ action="store_true")
+ parser.add_option("-M", "--no-mirror", action="callback",
+ callback=disable_mirror)
opts, args = parser.parse_args()
if len(args) not in (1, 2):
raise Error, "invalid arguments"
diff --git a/RepSys/commands/create.py b/RepSys/commands/create.py
index ded8abe..ded8abe 100644..100755
--- a/RepSys/commands/create.py
+++ b/RepSys/commands/create.py
diff --git a/RepSys/commands/del.py b/RepSys/commands/del.py
new file mode 100755
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/editlog.py b/RepSys/commands/editlog.py
index 9d1afc5..9d1afc5 100644..100755
--- a/RepSys/commands/editlog.py
+++ b/RepSys/commands/editlog.py
diff --git a/RepSys/commands/getspec.py b/RepSys/commands/getspec.py
index 6a8f7ea..a357ef9 100644..100755
--- a/RepSys/commands/getspec.py
+++ b/RepSys/commands/getspec.py
@@ -1,5 +1,5 @@
#!/usr/bin/python
-from RepSys import Error
+from RepSys import Error, disable_mirror
from RepSys.command import *
from RepSys.layout import package_url
from RepSys.rpmutil import get_spec
@@ -24,6 +24,8 @@ Examples:
def parse_options():
parser = OptionParser(help=HELP)
parser.add_option("-t", dest="targetdir", default=".")
+ parser.add_option("-M", "--no-mirror", action="callback",
+ callback=disable_mirror)
opts, args = parser.parse_args()
if len(args) != 1:
raise Error, "invalid arguments"
diff --git a/RepSys/commands/getsrpm.py b/RepSys/commands/getsrpm.py
index 8cbe1f1..1767bb7 100644..100755
--- a/RepSys/commands/getsrpm.py
+++ b/RepSys/commands/getsrpm.py
@@ -3,7 +3,7 @@
# This program will extract given version/revision of the named package
# from the Conectiva Linux repository system.
#
-from RepSys import Error, config
+from RepSys import Error, config, disable_mirror
from RepSys.command import *
from RepSys.layout import package_url
from RepSys.rpmutil import get_srpm
@@ -32,6 +32,8 @@ Options:
-T FILE Template to be used to generate the %changelog
-M Do not use the mirror (use the main repository)
-h Show this message
+ -S Do not download sources from the binary repository
+ --check Check integrity of files fetched from the binary repository
--strict Check if the given revision contains changes in REPPKGURL
Examples:
@@ -76,6 +78,12 @@ 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("--check", dest="binrepo_check", default=False,
+ action="store_true")
+ parser.add_option("-M", "--no-mirror", action="callback",
+ callback=disable_mirror)
parser.add_option("--strict", dest="strict", default=False,
action="store_true")
opts, args = parser.parse_args()
diff --git a/RepSys/commands/log.py b/RepSys/commands/log.py
new file mode 100755
index 0000000..28df27d
--- /dev/null
+++ b/RepSys/commands/log.py
@@ -0,0 +1,62 @@
+#!/usr/bin/python
+from RepSys import config, mirror, disable_mirror
+from RepSys.command import *
+from RepSys.layout import package_url, checkout_url
+from RepSys.rpmutil import sync
+from RepSys.util import execcmd
+import sys
+import os
+
+HELP = """\
+Usage: repsys log [OPTIONS] [PACKAGE]
+
+Shows the SVN log for a given package.
+
+Options:
+ -h Show this message
+ -v Show changed paths
+ -l LIMIT Limit of log entries to show
+ -r REV Show a specific revision
+ -M Do not use the mirror (use the main repository)
+
+Examples:
+ repsys log mutt
+ repsys log 2009.1/mutt
+"""
+
+def parse_options():
+ parser = OptionParser(help=HELP)
+ parser.add_option("-v", dest="verbose", action="store_true",
+ default=False)
+ parser.add_option("-l", "--limit", dest="limit", type="int",
+ default=None)
+ parser.add_option("-r", dest="revision", type="string", default=None)
+ parser.add_option("-M", "--no-mirror", action="callback",
+ callback=disable_mirror)
+ opts, args = parser.parse_args()
+ if len(args):
+ opts.pkgdirurl = package_url(args[0])
+ else:
+ parser.error("log requires a package name")
+ return opts
+
+def svn_log(pkgdirurl, verbose=False, limit=None, revision=None):
+ mirror.info(pkgdirurl)
+ url = checkout_url(pkgdirurl)
+ svncmd = config.get("global", "svn-command", "svn")
+ args = [svncmd, "log", url]
+ if verbose:
+ args.append("-v")
+ if limit:
+ args.append("-l")
+ args.append(limit)
+ if revision:
+ args.append("-r")
+ args.append(revision)
+ if os.isatty(sys.stdin.fileno()):
+ args.append("| less")
+ rawcmd = " ".join(args)
+ execcmd(rawcmd, show=True)
+
+def main():
+ do_command(parse_options, svn_log)
diff --git a/RepSys/commands/markrelease.py b/RepSys/commands/markrelease.py
index 057cf1d..057cf1d 100644..100755
--- a/RepSys/commands/markrelease.py
+++ b/RepSys/commands/markrelease.py
diff --git a/RepSys/commands/patchspec.py b/RepSys/commands/patchspec.py
index 9a4881b..9a4881b 100644..100755
--- a/RepSys/commands/patchspec.py
+++ b/RepSys/commands/patchspec.py
diff --git a/RepSys/commands/putsrpm.py b/RepSys/commands/putsrpm.py
index 751fa0b..efe1a15 100644..100755
--- a/RepSys/commands/putsrpm.py
+++ b/RepSys/commands/putsrpm.py
@@ -22,6 +22,7 @@ Options:
-c URL The URL of the base directory where the changelog will be
placed
-s Don't strip the changelog from the spec
+ (nor import it into misc/)
-n Don't try to rename the spec file
-h Show this message
diff --git a/RepSys/commands/rpmlog.py b/RepSys/commands/rpmlog.py
index 11fe36d..238b675 100644..100755
--- 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, layout
+from RepSys import Error, layout, disable_mirror
from RepSys.command import *
from RepSys.svn import SVN
from RepSys.log import get_changelog, split_spec_changelog
@@ -43,6 +43,8 @@ def parse_options():
action="store_true")
parser.add_option("-s", dest="sort", default=False,
action="store_true")
+ parser.add_option("-M", "--no-mirror", action="callback",
+ callback=disable_mirror)
opts, args = parser.parse_args()
if len(args) != 1:
raise Error, "invalid arguments"
diff --git a/RepSys/commands/submit.py b/RepSys/commands/submit.py
index 88ff596..2924329 100644..100755
--- a/RepSys/commands/submit.py
+++ b/RepSys/commands/submit.py
@@ -1,5 +1,6 @@
#!/usr/bin/python
-from RepSys import Error, config, layout
+from RepSys import Error, config, layout, mirror
+from RepSys.svn import SVN
from RepSys.command import *
from RepSys.rpmutil import get_spec, get_submit_info
from RepSys.util import get_auth, execcmd, get_helper
@@ -8,6 +9,7 @@ import getopt
import sys
import re
import subprocess
+import uuid
import xmlrpclib
@@ -37,6 +39,8 @@ Options:
argument)
-s The host in which the package URL will be submitted
(defaults to the host in the URL)
+ -a Submit all URLs at once (depends on server-side support)
+ -i SID Use the submit identifier SID
-h Show this message
--distro The distribution branch where the packages come from
--define Defines one variable to be used by the submit scripts
@@ -63,6 +67,9 @@ def parse_options():
parser.add_option("-r", dest="revision", type="string", nargs=1)
parser.add_option("-s", dest="submithost", type="string", nargs=1,
default=None)
+ parser.add_option("-i", dest="sid", type="string", nargs=1,
+ default=None)
+ parser.add_option("-a", dest="atonce", action="store_true", default=False)
parser.add_option("--distro", dest="distro", type="string",
default=None)
parser.add_option("--define", action="append", default=[])
@@ -96,8 +103,33 @@ def parse_options():
if expanded != args:
print "Submitting: %s" % " ".join(expanded)
args = expanded
- opts.urls = [layout.package_url(nameurl, distro=opts.distro, mirrored=False)
+ # generate URLs for package names:
+ opts.urls = [mirror.strip_username(
+ layout.package_url(nameurl, distro=opts.distro, mirrored=False))
for nameurl in args]
+ # find the revision if not specified:
+ newurls = []
+ for url in opts.urls:
+ if not "@" in url:
+ print "Fetching revision..."
+ courl = layout.checkout_url(url)
+ log = SVN().log(courl, limit=1)
+ if not log:
+ raise Error, "can't find a revision for %s" % courl
+ ci = log[0]
+ print "URL:", url
+ print "Commit:",
+ print "%d | %s" % (ci.revision, ci.author),
+ if ci.lines:
+ line = " ".join(ci.lines).strip()
+ if len(line) > 57:
+ line = line[:57] + "..."
+ print "| %s" % line,
+ print
+ url = url + "@" + str(ci.revision)
+ newurls.append(url)
+ opts.urls[:] = newurls
+ # choose a target if not specified:
if opts.target is None and opts.distro is None:
target = layout.distro_branch(opts.urls[0]) or DEFAULT_TARGET
print "Implicit target: %s" % target
@@ -132,7 +164,7 @@ def list_targets(option, opt, val, parser):
execcmd(command, show=True)
sys.exit(0)
-def submit(urls, target, define=[], submithost=None):
+def submit(urls, target, define=[], submithost=None, atonce=False, sid=None):
if submithost is None:
submithost = config.get("submit", "host")
if submithost is None:
@@ -145,25 +177,33 @@ def submit(urls, target, define=[], submithost=None):
# runs a create-srpm in the server through ssh, which will make a
# copy of the rpm in the export directory
createsrpm = get_helper("create-srpm")
- args = ["ssh", submithost, createsrpm, "-t", target]
- for entry in define:
- args.append("--define")
- args.append(entry)
+ baseargs = ["ssh", submithost, createsrpm, "-t", target]
+ if not sid:
+ sid = uuid.uuid4()
+ define.append("sid=%s" % sid)
+ for entry in reversed(define):
+ baseargs.append("--define")
+ baseargs.append(entry)
+ cmdsargs = []
if len(urls) == 1:
# be compatible with server-side repsys versions older than 1.6.90
url, rev = layout.split_url_revision(urls[0])
- args.append(url)
- args.append("-r")
- args.append(str(rev))
- else:
- args.extend(urls)
- command = subprocess.list2cmdline(args)
- status, output = execcmd(command)
- if status == 0:
- print "Package submitted!"
+ baseargs.append("-r")
+ baseargs.append(str(rev))
+ baseargs.append(url)
+ cmdsargs.append(baseargs)
+ elif atonce:
+ cmdsargs.append(baseargs + urls)
else:
- sys.stderr.write(output)
- sys.exit(status)
+ cmdsargs.extend((baseargs + [url]) for url in urls)
+ for cmdargs in cmdsargs:
+ command = subprocess.list2cmdline(cmdargs)
+ status, output = execcmd(command)
+ if status == 0:
+ print "Package submitted!"
+ else:
+ sys.stderr.write(output)
+ sys.exit(status)
def main():
do_command(parse_options, submit)
diff --git a/RepSys/commands/switch.py b/RepSys/commands/switch.py
index 5cbe2d7..998ae2c 100644..100755
--- a/RepSys/commands/switch.py
+++ b/RepSys/commands/switch.py
@@ -7,8 +7,8 @@ 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
+If URL is not provided, it will use the option repository 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.
@@ -19,7 +19,7 @@ Options:
Examples:
repsys switch
- repsys switch https://mirrors.localnetwork/svn/packages/cooker
+ repsys switch https://mirrors.localnetwork/svn/packages/
"""
def parse_options():
diff --git a/RepSys/commands/sync.py b/RepSys/commands/sync.py
index a51db22..b4bdaba 100644..100755
--- a/RepSys/commands/sync.py
+++ b/RepSys/commands/sync.py
@@ -5,12 +5,13 @@ from RepSys.rpmutil import sync
HELP = """\
Usage: repsys sync
-Will add or removed from the working copy new files added or removed
-from the spec file.
+Will add or remove from the working copy those files added or removed
+in the spec file.
-"No changes are commited."
+It will not commit the changes.
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 100755
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 100755
index 0000000..6af50ea
--- /dev/null
+++ b/RepSys/commands/upload.py
@@ -0,0 +1,28 @@
+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 'binrepo.lst' file and leave it
+uncommited.
+
+If the path is a directory, all the contents of the directory will be
+uploaded or removed.
+
+Options:
+ -h help
+
+"""
+
+def parse_options():
+ parser = OptionParser(help=HELP)
+ opts, args = parser.parse_args()
+ opts.paths = args
+ return opts
+
+def main():
+ do_command(parse_options, upload)
diff --git a/RepSys/layout.py b/RepSys/layout.py
index a358c28..fb50acd 100644..100755
--- a/RepSys/layout.py
+++ b/RepSys/layout.py
@@ -117,7 +117,7 @@ def remove_current(pkgdirurl):
def repository_url(mirrored=False):
url = None
- if mirrored and config.getbool("global", "use-mirror"):
+ if mirrored and config.getbool("global", "use-mirror", "yes"):
url = config.get("global", "mirror")
if url is None:
url = config.get("global", "repository")
diff --git a/RepSys/log.py b/RepSys/log.py
index a1d1944..6cb9da1 100644..100755
--- a/RepSys/log.py
+++ b/RepSys/log.py
@@ -18,6 +18,7 @@ import locale
import glob
import tempfile
import shutil
+import subprocess
locale.setlocale(locale.LC_ALL, "C")
@@ -86,11 +87,15 @@ def getrelease(pkgdirurl, rev=None, macros=[], exported=None):
specpath = found[0]
options = rpm_macros_defs(macros)
command = (("rpm -q --qf '%%{EPOCH}:%%{VERSION}-%%{RELEASE}\n' "
- "--specfile %s %s 2>/dev/null") %
+ "--specfile %s %s") %
(specpath, options))
- status, output = execcmd(command)
- if status != 0:
- raise Error, "Error in command %s: %s" % (command, output)
+ pipe = subprocess.Popen(command, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, shell=True)
+ pipe.wait()
+ output = pipe.stdout.read()
+ error = pipe.stderr.read()
+ if pipe.returncode != 0:
+ raise Error, "Error in command %s: %s" % (command, error)
releases = output.split()
try:
epoch, vr = releases[0].split(":", 1)
@@ -514,18 +519,23 @@ def split_spec_changelog(stream):
chlog = StringIO()
spec = StringIO()
found = 0
+ visible = 0
for line in stream:
if line.startswith("%changelog"):
found = 1
elif not found:
spec.write(line)
elif found:
+ if line.strip():
+ visible = 1
chlog.write(line)
elif line.startswith("%"):
found = 0
spec.write(line)
spec.seek(0)
- chlog.seek(0)
+ if not visible:
+ # when there are only blanks in the changelog, make it empty
+ chlog = StringIO()
return spec, chlog
def get_old_log(pkgdirurl):
diff --git a/RepSys/mirror.py b/RepSys/mirror.py
index f0d2316..94720cc 100644..100755
--- a/RepSys/mirror.py
+++ b/RepSys/mirror.py
@@ -66,9 +66,12 @@ def using_on(url):
using = False
return using
-def info(url, stream=sys.stderr):
+def info(url, write=False, stream=sys.stderr):
if using_on(url):
- stream.write("using mirror\n")
+ stream.write("Using the svn mirror.\n")
+ if write:
+ stream.write("To be able to commit changes, use "
+ "'repsys switch' first.\n")
def mirror_relocate(oldparent, newparent, url, wcpath):
svn = SVN()
diff --git a/RepSys/plugins/__init__.py b/RepSys/plugins/__init__.py
index e4f4e08..e4f4e08 100644..100755
--- a/RepSys/plugins/__init__.py
+++ b/RepSys/plugins/__init__.py
diff --git a/RepSys/plugins/ldapusers.py b/RepSys/plugins/ldapusers.py
index e56371d..e56371d 100644..100755
--- a/RepSys/plugins/ldapusers.py
+++ b/RepSys/plugins/ldapusers.py
diff --git a/RepSys/rpmutil.py b/RepSys/rpmutil.py
index c11ad4e..bff744b 100644..100755
--- a/RepSys/rpmutil.py
+++ b/RepSys/rpmutil.py
@@ -1,6 +1,6 @@
#!/usr/bin/python
from RepSys import Error, config
-from RepSys import mirror, layout, log
+from RepSys import mirror, layout, log, binrepo
from RepSys.svn import SVN
from RepSys.simplerpm import SRPM
from RepSys.util import execcmd
@@ -19,12 +19,16 @@ def get_spec(pkgdirurl, targetdir=".", submit=False):
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)
@@ -65,7 +69,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
@@ -95,10 +101,19 @@ def get_srpm(pkgdirurl,
"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]
@@ -285,29 +300,32 @@ def put_srpm(srpmfile, markrelease=False, striplog=True, branch=None,
specpath = specpath
fspec = open(specpath)
spec, chlog = log.split_spec_changelog(fspec)
- chlog.seek(0)
- spec.seek(0)
fspec.close()
fspec = open(specpath, "w")
fspec.writelines(spec)
fspec.close()
- 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)
+ 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:
@@ -370,9 +388,11 @@ revision: %s
def mark_release(pkgdirurl, version, release, revision):
svn = SVN()
- releasesurl = "/".join([pkgdirurl, "releases"])
+ 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,
@@ -382,7 +402,6 @@ def mark_release(pkgdirurl, version, release, revision):
pristineurl = layout.checkout_url(pkgdirurl, pristine=True)
svn.remove(pristineurl, noerror=1,
log="Removing previous pristine/ directory.")
- currenturl = layout.checkout_url(pkgdirurl)
svn.copy(currenturl, pristineurl,
log="Copying release %s-%s to pristine/ directory." %
(version, release))
@@ -450,34 +469,51 @@ def check_changed(pkgdirurl, all=0, show=0, verbose=0):
"nocurrent": nocurrent,
"nopristine": nopristine}
-def checkout(pkgdirurl, path=None, revision=None, branch=None,
- distro=None):
+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)
- current = layout.checkout_url(pkgdirurl, branch=branch)
+ 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)
+ mirror.info(current, write=True)
svn = SVN()
svn.checkout(current, path, rev=revision, show=1)
-
-def _getpkgtopdir(basedir=None):
+ 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.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 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, download=False):
+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()
+ 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):
@@ -496,15 +532,28 @@ 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 = []
+ # 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)
- pst = sourcesst.get(source)
- if pst:
- if os.path.isfile(sourcepath):
- toadd.append(sourcepath)
+ 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, 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",
@@ -517,29 +566,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:
@@ -566,9 +633,63 @@ def commit(target=".", message=None, logfile=None):
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()
+ topdir = getpkgtopdir()
info = svn.info2(topdir)
wcurl = info.get("URL")
if wcurl is None:
diff --git a/RepSys/simplerpm.py b/RepSys/simplerpm.py
index d448c5f..d448c5f 100644..100755
--- a/RepSys/simplerpm.py
+++ b/RepSys/simplerpm.py
diff --git a/RepSys/svn.py b/RepSys/svn.py
index 985329d..d6be524 100644..100755
--- a/RepSys/svn.py
+++ b/RepSys/svn.py
@@ -1,6 +1,7 @@
-from RepSys import Error, config
+from RepSys import Error, SilentError, config
from RepSys.util import execcmd, get_auth
import sys
+import os
import re
import time
@@ -23,23 +24,63 @@ class SVN:
if not kwargs.get("show") and args[0] not in localcmds:
args = list(args)
args.append("--non-interactive")
- svn_command = config.get("global", "svn-command",
- "SVN_SSH='ssh -o \"BatchMode yes\"' svn")
+ else:
+ kwargs["geterr"] = True
+ kwargs["cleanerr"] = True
+ if kwargs.get("xml"):
+ args.append("--xml")
+ self._set_env()
+ svn_command = config.get("global", "svn-command", "svn")
cmdstr = svn_command + " " + " ".join(args)
try:
return execcmd(cmdstr, **kwargs)
except Error, e:
- if "Permission denied" in e.message:
- raise Error, ("%s\n"
- "Seems ssh-agent or ForwardAgent are not setup, see "
- "http://wiki.mandriva.com/en/Development/Docs/Contributor_Tricks#SSH_configuration"
- " for more information." % e)
- elif "authorization failed" in e.message:
- raise Error, ("%s\n"
- "Note that repsys does not support any HTTP "
- "authenticated access." % e)
+ msg = None
+ if e.args:
+ if "Permission denied" in e.args[0]:
+ msg = ("It seems ssh-agent or ForwardAgent are not setup "
+ "or your username is wrong. See "
+ "http://wiki.mandriva.com/en/Development/Docs/Contributor_Tricks#SSH_configuration"
+ " for more information.")
+ elif "authorization failed" in e.args[0]:
+ msg = ("Note that repsys does not support any HTTP "
+ "authenticated access.")
+ if kwargs.get("show") and \
+ not config.getbool("global", "verbose", 0):
+ # svn has already dumped error messages, we don't need to
+ # do it too
+ if msg:
+ sys.stderr.write("\n")
+ sys.stderr.write(msg)
+ sys.stderr.write("\n")
+ raise SilentError
+ elif msg:
+ raise Error, "%s\n%s" % (e, msg)
raise
+ def _set_env(self):
+ wrapper = "repsys-ssh"
+ repsys = config.get("global", "repsys-cmd")
+ if repsys:
+ dir = os.path.dirname(repsys)
+ path = os.path.join(dir, wrapper)
+ if os.path.exists(path):
+ wrapper = path
+ defaults = {"SVN_SSH": wrapper}
+ os.environ.update(defaults)
+ raw = config.get("global", "svn-env")
+ if raw:
+ for line in raw.split("\n"):
+ env = line.strip()
+ if not env:
+ continue
+ try:
+ name, value = env.split("=", 1)
+ except ValueError:
+ sys.stderr.write("invalid svn environment line: %r\n" % env)
+ continue
+ os.environ[name] = value
+
def _execsvn_success(self, *args, **kwargs):
status, output = self._execsvn(*args, **kwargs)
return status == 0
@@ -59,12 +100,13 @@ class SVN:
if not optional or received_kwargs.has_key("rev"):
ret = received_kwargs.get("rev")
if isinstance(ret, basestring):
- try:
- ret = int(ret)
- except ValueError:
- raise Error, "invalid revision provided"
+ if not ret.startswith("{"): # if not a datespec
+ try:
+ ret = int(ret)
+ except ValueError:
+ raise Error, "invalid revision provided"
if ret:
- cmd_args.append("-r %d" % ret)
+ cmd_args.append("-r '%s'" % ret)
def add(self, path, **kwargs):
cmd = ["add", path]
@@ -85,13 +127,29 @@ class SVN:
def mkdir(self, path, **kwargs):
cmd = ["mkdir", path]
+ if kwargs.get("parents"):
+ cmd.append("--parents")
self._add_log(cmd, kwargs)
return self._execsvn_success(*cmd, **kwargs)
+ def _execsvn_commit(self, *cmd, **kwargs):
+ status, output = self._execsvn(*cmd, **kwargs)
+ match = re.search("Committed revision (?P<rev>\\d+)\\.$", output)
+ if match:
+ rawrev = match.group("rev")
+ return int(rawrev)
+
def commit(self, path, **kwargs):
cmd = ["commit", path]
+ if kwargs.get("nonrecursive"):
+ cmd.append("-N")
self._add_log(cmd, kwargs)
- return self._execsvn_success(*cmd, **kwargs)
+ return self._execsvn_commit(*cmd, **kwargs)
+
+ def import_(self, path, url, **kwargs):
+ cmd = ["import", "'%s'" % path, "'%s'" % url]
+ self._add_log(cmd, kwargs)
+ return self._execsvn_commit(*cmd, **kwargs)
def export(self, url, targetpath, **kwargs):
cmd = ["export", "'%s'" % url, targetpath]
@@ -102,6 +160,14 @@ class SVN:
cmd = ["checkout", "'%s'" % url, targetpath]
self._add_revision(cmd, kwargs, optional=1)
return self._execsvn_success(*cmd, **kwargs)
+
+ def propget(self, propname, targets, **kwargs):
+ cmd = ["propget", propname, targets]
+ if kwargs.get("revprop"):
+ cmd.append("--revprop")
+ self._add_revision(cmd, kwargs)
+ status, output = self._execsvn(local=True, *cmd, **kwargs)
+ return output
def propset(self, propname, value, targets, **kwargs):
cmd = ["propset", propname, "'%s'" % value, targets]
@@ -125,8 +191,8 @@ class SVN:
def info(self, path, **kwargs):
cmd = ["info", path]
- status, output = self._execsvn(local=True, *cmd, **kwargs)
- if status == 0 and "Not a versioned resource" not in output:
+ status, output = self._execsvn(local=True, noerror=True, *cmd, **kwargs)
+ if "Not a versioned resource" not in output:
return output.splitlines()
return None
diff --git a/RepSys/util.py b/RepSys/util.py
index 83f2ebe..84840b9 100644..100755
--- a/RepSys/util.py
+++ b/RepSys/util.py
@@ -2,11 +2,13 @@
from RepSys import Error, config
+import subprocess
import getpass
import sys
import os
import re
import logging
+from cStringIO import StringIO
#import commands
log = logging.getLogger("repsys")
@@ -26,14 +28,35 @@ def commands_getstatusoutput(cmd):
def execcmd(*cmd, **kwargs):
cmdstr = " ".join(cmd)
if kwargs.get("show"):
- status = os.system(cmdstr)
- output = ""
+ if kwargs.get("geterr"):
+ err = StringIO()
+ pipe = subprocess.Popen(cmdstr, shell=True,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ of = pipe.stdout.fileno()
+ ef = pipe.stderr.fileno()
+ while True:
+ odata = os.read(of, 8192)
+ sys.stdout.write(odata)
+ edata = os.read(ef, 8192)
+ err.write(edata)
+ sys.stderr.write(edata)
+ status = pipe.poll()
+ if status is not None and not (odata and edata):
+ break
+ output = err.getvalue()
+ else:
+ status = os.system(cmdstr)
+ output = ""
else:
status, output = commands_getstatusoutput(
"LANG=C LANGUAGE=C LC_ALL=C "+cmdstr)
+ verbose = config.getbool("global", "verbose", 0)
if status != 0 and not kwargs.get("noerror"):
- raise Error, "command failed: %s\n%s\n" % (cmdstr, output)
- if config.getbool("global", "verbose", 0):
+ if kwargs.get("cleanerr") and not verbose:
+ raise Error, output
+ else:
+ raise Error, "command failed: %s\n%s\n" % (cmdstr, output)
+ if verbose:
print cmdstr
sys.stdout.write(output)
return status, output
@@ -92,6 +115,27 @@ def get_helper(name):
if not os.path.isfile(hpath):
log.warn("providing unexistent helper: %s", hpath)
return hpath
+
+def rellink(src, dst):
+ """Creates relative symlinks
+
+ It will find the common ancestor and append to the src path.
+ """
+ asrc = os.path.abspath(src)
+ adst = os.path.abspath(dst)
+ csrc = asrc.split(os.path.sep)
+ cdst = adst.split(os.path.sep)
+ dstname = cdst.pop()
+ i = 0
+ l = min(len(csrc), len(cdst))
+ while i < l:
+ if csrc[i] != cdst[i]:
+ break
+ i += 1
+ dstextra = len(cdst[i:])
+ steps = [os.path.pardir] * dstextra
+ steps.extend(csrc[i:])
+ return os.path.sep.join(steps)
# vim:et:ts=4:sw=4