aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBogdano Arendartchuk <bogdano@mandriva.org>2008-06-23 15:56:37 +0000
committerBogdano Arendartchuk <bogdano@mandriva.org>2008-06-23 15:56:37 +0000
commit4c556ed6d07fbebf175f8e009c4ceb166f42fb6d (patch)
treee95dee4806d15eb555549e487e8dbb75ff1e4859
parenta068fe76ec7ad2fe3fdd1957d55f587bb7eb6f86 (diff)
downloadmgarepo-4c556ed6d07fbebf175f8e009c4ceb166f42fb6d.tar
mgarepo-4c556ed6d07fbebf175f8e009c4ceb166f42fb6d.tar.gz
mgarepo-4c556ed6d07fbebf175f8e009c4ceb166f42fb6d.tar.bz2
mgarepo-4c556ed6d07fbebf175f8e009c4ceb166f42fb6d.tar.xz
mgarepo-4c556ed6d07fbebf175f8e009c4ceb166f42fb6d.zip
Merged latest V1_6_X branch
-rw-r--r--CHANGES10
-rw-r--r--MANIFEST.in1
-rw-r--r--RepSys/commands/rpmlog.py31
-rw-r--r--RepSys/commands/submit.py76
-rw-r--r--RepSys/log.py141
-rw-r--r--RepSys/rpmutil.py93
-rwxr-xr-xcreate-srpm88
-rw-r--r--repsys-example.conf2
-rw-r--r--repsys.8198
-rw-r--r--repsys.conf1
-rwxr-xr-xsetup.py3
11 files changed, 515 insertions, 129 deletions
diff --git a/CHANGES b/CHANGES
index 3faa796..219c0a9 100644
--- a/CHANGES
+++ b/CHANGES
@@ -12,10 +12,20 @@
- fixed incompatibility with Python-2.4 on urlparse
- fixed emptylog message, which was not being shown when needed
- 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
+- allow submitting many packages at once
+- package revisions in submit are now specified with name@nnn
- fixed bad url used when using -v in getsrpm
- make 'repsys submit' without package name or revision number work again
- if REPSYS_CONF is set, /etc/repsys.conf and ~/.repsys/config will not be
readed anymore
+- sort the final changelog by enabling the option sort in the log section
+- merge the changelog found in the spec by enabling the option merge-spec
+ in the log section
- changed the built-in template to the current default.chlog
- added option -d to repsys sync, to download the missing source files
- added option -F to repsys ci to set a log message file
diff --git a/MANIFEST.in b/MANIFEST.in
index f014036..6fc5975 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,6 +1,7 @@
recursive-include RepSys *.py
include RepSys/plugins/*.txt
include repsys repsys.conf MANIFEST.in
+include repsys.8
include CHANGES
include README.LDAP
include repsys-example.conf
diff --git a/RepSys/commands/rpmlog.py b/RepSys/commands/rpmlog.py
index 5ba5fdd..3cdcc02 100644
--- a/RepSys/commands/rpmlog.py
+++ b/RepSys/commands/rpmlog.py
@@ -3,10 +3,13 @@
# This program will convert the output of "svn log" to be suitable
# for usage in an rpm %changelog session.
#
-from RepSys import Error
+from RepSys import Error, RepSysTree
from RepSys.command import *
-from RepSys.log import svn2rpm
+from RepSys.svn import SVN
+from RepSys.log import get_changelog, split_spec_changelog
+from cStringIO import StringIO
import getopt
+import os
import sys
HELP = """\
@@ -18,6 +21,9 @@ Options:
-r REV Collect logs from given revision to revision 0
-n NUM Output only last NUM entries
-T FILE %changelog template file to be used
+ -o Append old package changelog
+ -p Append changelog found in .spec file
+ -s Sort changelog entries, even from the old log
-h Show this message
Examples:
@@ -30,14 +36,31 @@ def parse_options():
parser.add_option("-r", dest="revision")
parser.add_option("-n", dest="size", type="int")
parser.add_option("-T", "--template", dest="template", type="string")
+ parser.add_option("-o", dest="oldlog", default=False,
+ action="store_true")
+ parser.add_option("-p", dest="usespec", default=False,
+ action="store_true")
+ parser.add_option("-s", dest="sort", default=False,
+ action="store_true")
opts, args = parser.parse_args()
if len(args) != 1:
raise Error, "invalid arguments"
opts.pkgdirurl = default_parent(args[0])
return opts
-def rpmlog(pkgdirurl, revision, size, template):
- sys.stdout.write(svn2rpm(pkgdirurl, revision, size, template=template))
+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")
+ rawspec = svn.cat(specurl, rev=revision)
+ spec, another = split_spec_changelog(StringIO(rawspec))
+ newlog = get_changelog(pkgdirurl, another=another, rev=revision,
+ size=size, sort=sort, template=template, oldlog=oldlog)
+ sys.stdout.writelines(newlog)
def main():
do_command(parse_options, rpmlog)
diff --git a/RepSys/commands/submit.py b/RepSys/commands/submit.py
index f1726dc..2869ff4 100644
--- a/RepSys/commands/submit.py
+++ b/RepSys/commands/submit.py
@@ -1,22 +1,18 @@
#!/usr/bin/python
from RepSys import Error, config
from RepSys.command import *
-from RepSys.rpmutil import get_spec, get_submit_info
+from RepSys.rpmutil import get_spec, get_submit_info, svn_url_rev
from RepSys.util import get_auth, execcmd, get_helper
import urllib
import getopt
import sys
import re
-
-#try:
-# import NINZ.client
-#except ImportError:
-# NINZ = None
+import subprocess
import xmlrpclib
HELP = """\
-Usage: repsys submit [OPTIONS] [URL [REVISION]]
+Usage: repsys submit [OPTIONS] [URL[@REVISION] ...]
Submits the package from URL to the submit host.
@@ -28,8 +24,8 @@ The status of the submit can visualized at:
http://kenobi.mandriva.com/bs/output.php
-If no URL and revision are specified, the latest changed revision in
-the package working copy of the current directory will be used.
+If no URL and revision are specified, the latest changed revision in the
+package working copy of the current directory will be used.
Options:
-t TARGET Submit given package URL to given target
@@ -44,37 +40,46 @@ Options:
Examples:
repsys submit
- repsys submit foo 14800
- repsys submit https://repos/svn/mdv/cooker/foo 14800
- repsys submit -r 14800 https://repos/svn/mdv/cooker/foo
+ repsys submit 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.0
+ repsys submit --define section=main/testing -t 2008.1
"""
def parse_options():
parser = OptionParser(help=HELP)
- parser.defaults["revision"] = ""
+ parser.defaults["revision"] = None
parser.add_option("-t", dest="target", default="Cooker")
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,
default=None)
- parser.add_option("--define", action="append")
+ parser.add_option("--define", action="append", default=[])
opts, args = parser.parse_args()
if not args:
- name, rev = get_submit_info(".")
- args = name, str(rev)
- print "submitting %s at revision %s..." % args
- elif len(args) > 2:
- raise Error, "invalid arguments"
- opts.pkgdirurl = default_parent(args[0])
+ name, url, rev = get_submit_info(".")
+ args = ["%s@%s" % (url, str(rev))]
+ print "Submitting %s at revision %s" % (name, rev)
+ print "URL: %s" % url
+ if opts.revision is not None:
+ # backwards compatibility with the old -r usage
+ if len(args) == 1:
+ args[0] = args[0] + "@" + opts.revision
+ else:
+ raise Error, "can't use -r REV with more than one package name"
+ del opts.revision
if len(args) == 2:
- opts.revision = re.compile(r".*?(\d+).*").sub(r"\1", args[1])
- elif len(args) == 1 and opts.revision:
- # accepts -r 3123 http://foo/bar
- pass
- elif not opts.list:
- raise Error, "provide -l or a revision number"
+ # prevent from using the old <name> <rev> syntax
+ try:
+ rev = int(args[1])
+ except ValueError:
+ # ok, it is a package name, let it pass
+ pass
+ else:
+ raise Error, "the format <name> <revision> is deprecated, "\
+ "use <name>@<revision> instead"
+ opts.urls = [default_parent(nameurl) for nameurl in args]
return opts
def list_targets(option, opt, val, parser):
@@ -87,9 +92,7 @@ def list_targets(option, opt, val, parser):
execcmd(command, show=True)
sys.exit(0)
-def submit(pkgdirurl, revision, target, list=0, define=[], submithost=None):
- #if not NINZ:
- # raise Error, "you must have NINZ installed to use this command"
+def submit(urls, target, define=[], submithost=None):
if submithost is None:
submithost = config.get("submit", "host")
if submithost is None:
@@ -101,13 +104,13 @@ def submit(pkgdirurl, revision, target, list=0, define=[], submithost=None):
del type, user, port, path, rest
# runs a create-srpm in the server through ssh, which will make a
# copy of the rpm in the export directory
- if list:
- raise Error, "unable to list targets from svn+ssh:// URLs"
createsrpm = get_helper("create-srpm")
- command = "ssh %s %s '%s' -r %s -t %s" % (
- submithost, createsrpm, pkgdirurl, revision, target)
- if define:
- command += " " + " ".join([ "--define " + x for x in define ])
+ args = ["ssh", submithost, createsrpm, "-t", target]
+ for entry in define:
+ args.append("--define")
+ args.append(entry)
+ args.extend(urls)
+ command = subprocess.list2cmdline(args)
status, output = execcmd(command)
if status == 0:
print "Package submitted!"
@@ -115,7 +118,6 @@ def submit(pkgdirurl, revision, target, list=0, define=[], submithost=None):
sys.stderr.write(output)
sys.exit(status)
-
def main():
do_command(parse_options, submit)
diff --git a/RepSys/log.py b/RepSys/log.py
index 60cf0d5..2eadbe2 100644
--- a/RepSys/log.py
+++ b/RepSys/log.py
@@ -8,6 +8,8 @@ try:
except ImportError:
raise Error, "repsys requires the package python-cheetah"
+from cStringIO import StringIO
+
import sys
import os
import re
@@ -464,29 +466,68 @@ def svn2rpm(pkgdirurl, rev=None, size=None, submit=False,
data = dump_file(releases[::-1], currentlog=currentlog, template=template)
return data
-
-
-def specfile_svn2rpm(pkgdirurl, specfile, rev=None, size=None,
- submit=False, template=None, macros=[], exported=None):
- newlines = []
+def _split_changelog(stream):
+ current = None
+ count = 0
+ def finish(entry):
+ lines = entry[2]
+ # strip newlines at the end
+ for i in xrange(len(lines)-1, -1, -1):
+ if lines[i] != "\n":
+ break
+ del lines[i]
+ return entry
+ for line in stream:
+ if line.startswith("*"):
+ if current:
+ yield finish(current)
+ fields = line.split()
+ rawdate = " ".join(fields[:5])
+ try:
+ date = time.strptime(rawdate, "* %a %b %d %Y")
+ except ValueError, e:
+ raise Error, "failed to parse spec changelog: %s" % e
+ curlines = [line]
+ current = (date, count, curlines)
+ # count used to ensure stable sorting when changelog entries
+ # have the same date, otherwise it would also compare the
+ # changelog lines
+ count -= 1
+ elif current:
+ curlines.append(line)
+ else:
+ pass # not good, but ignore
+ if current:
+ yield finish(current)
+
+def sort_changelog(stream):
+ entries = _split_changelog(stream)
+ log = StringIO()
+ for time, count, elines in sorted(entries, reverse=True):
+ log.writelines(elines)
+ log.write("\n")
+ return log
+
+def split_spec_changelog(stream):
+ chlog = StringIO()
+ spec = StringIO()
found = 0
-
- # Strip old changelogs
- for line in open(specfile):
+ for line in stream:
if line.startswith("%changelog"):
found = 1
elif not found:
- newlines.append(line)
+ spec.write(line)
+ elif found:
+ chlog.write(line)
elif line.startswith("%"):
found = 0
- newlines.append(line)
-
- # Create new changelog
- newlines.append("\n\n%changelog\n")
- newlines.append(svn2rpm(pkgdirurl, rev=rev, size=size, submit=submit,
- template=template, macros=macros, exported=exported))
+ spec.write(line)
+ spec.seek(0)
+ chlog.seek(0)
+ return spec, chlog
- # Merge old changelog, if available
+def get_old_log(pkgdirurl):
+ chlog = StringIO()
oldurl = config.get("log", "oldurl")
if oldurl:
svn = SVN()
@@ -504,20 +545,74 @@ def specfile_svn2rpm(pkgdirurl, specfile, rev=None, size=None,
logfile = os.path.join(tmpdir, "log")
if os.path.isfile(logfile):
file = open(logfile)
- newlines.append("\n")
+ chlog.write("\n") # TODO needed?
log = file.read()
log = escape_macros(log)
- newlines.append(log)
+ chlog.write(log)
file.close()
finally:
if os.path.isdir(tmpdir):
shutil.rmtree(tmpdir)
+ chlog.seek(0)
+ return chlog
+
+def get_changelog(pkgdirurl, another=None, svn=True, rev=None, size=None,
+ submit=False, sort=False, template=None, macros=[], exported=None,
+ oldlog=False):
+ """Generates the changelog for a given package URL
+
+ @another: a stream with the contents of a changelog to be merged with
+ the one generated
+ @svn: enable changelog from svn
+ @rev: generate the changelog with the changes up to the given
+ revision
+ @size: the number of revisions to be used (as in svn log --limit)
+ @submit: defines whether the latest unreleased log entries should have
+ the version parsed from the spec file
+ @sort: should changelog entries be reparsed and sorted after appending
+ the oldlog?
+ @template: the path to the cheetah template used to generate the
+ changelog from svn
+ @macros: a list of tuples containing macros to be defined when
+ parsing the version in the changelog
+ @exported: the path of a directory containing an already existing
+ checkout of the package, so that the spec file can be
+ parsed from there
+ @oldlog: if set it will try to append the old changelog file defined
+ in oldurl in repsys.conf
+ """
+ newlog = StringIO()
+ if svn:
+ rawsvnlog = svn2rpm(pkgdirurl, rev=rev, size=size, submit=submit,
+ template=template, macros=macros, exported=exported)
+ newlog.write(rawsvnlog)
+ if another:
+ newlog.writelines(another)
+ if oldlog:
+ newlog.writelines(get_old_log(pkgdirurl))
+ if sort:
+ newlog.seek(0)
+ newlog = sort_changelog(newlog)
+ newlog.seek(0)
+ return newlog
- # Write new specfile
- file = open(specfile, "w")
- file.write("".join(newlines))
- file.close()
-
+def specfile_svn2rpm(pkgdirurl, specfile, rev=None, size=None,
+ submit=False, sort=False, template=None, macros=[], exported=None):
+ fi = open(specfile)
+ spec, oldchlog = split_spec_changelog(fi)
+ fi.close()
+ another = None
+ if config.getbool("log", "merge-spec", False):
+ another = oldchlog
+ sort = sort or config.getbool("log", "sort", False)
+ chlog = get_changelog(pkgdirurl, another=another, rev=rev, size=size,
+ submit=submit, sort=sort, template=template, macros=macros,
+ exported=exported, oldlog=True)
+ fo = open(specfile, "w")
+ fo.writelines(spec)
+ fo.write("\n\n%changelog\n")
+ fo.writelines(chlog)
+ fo.close()
if __name__ == "__main__":
l = svn2rpm(sys.argv[1])
diff --git a/RepSys/rpmutil.py b/RepSys/rpmutil.py
index 46fa392..0eeee03 100644
--- a/RepSys/rpmutil.py
+++ b/RepSys/rpmutil.py
@@ -7,6 +7,7 @@ from RepSys.log import specfile_svn2rpm
from RepSys.util import execcmd
from RepSys.command import default_parent
import rpm
+import urlparse
import tempfile
import shutil
import string
@@ -34,6 +35,7 @@ def rpm_macros_defs(macros):
args = " ".join(defs)
return args
+#FIXME move it to another module
def rev_touched_url(url, rev):
svn = SVN()
info = svn.info2(url)
@@ -50,6 +52,51 @@ 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,
@@ -83,6 +130,7 @@ def get_srpm(pkgdirurl,
elif mode == "pristine":
geturl = os.path.join(pkgdirurl, "pristine")
elif mode == "current" or mode == "revision":
+ #FIXME we should handle revisions specified using @REV
geturl = os.path.join(pkgdirurl, "current")
else:
raise Error, "unsupported get_srpm mode: %s" % mode
@@ -106,9 +154,6 @@ def get_srpm(pkgdirurl,
submit = not not revision
specfile_svn2rpm(pkgdirurl, spec, revision, submit=submit,
template=template, macros=macros, exported=tmpdir)
- #FIXME revisioreal not needed if revision is None
- #FIXME use geturl instead of pkgdirurl
- revisionreal = svn.revision(pkgdirurl)
for script in scripts:
#FIXME revision can be "None"
status, output = execcmd(script, tmpdir, spec, str(revision),
@@ -123,25 +168,30 @@ def get_srpm(pkgdirurl,
(topdir, builddir, rpmdir, sourcedir, specdir,
srcrpmdir, patchdir, packager, spec, defs))
- if revision and revisionreal:
- #FIXME duplicate glob line
- srpm = glob.glob(os.path.join(srpmsdir, "*.src.rpm"))[0]
- srpminfo = SRPM(srpm)
- release = srpminfo.release
- srpmbase = os.path.basename(srpm)
- os.rename(srpm, "%s/@%s:%s" % (srpmsdir, revisionreal, srpmbase))
- srpm = glob.glob(os.path.join(srpmsdir, "*.src.rpm"))[0]
+ # copy the generated SRPMs to their target locations
+ targetsrpms = []
+ urlrev = None
+ if revname:
+ urlrev = revision or svn_url_rev(geturl)
if not targetdirs:
targetdirs = (".",)
- targetsrpms = []
- for targetdir in targetdirs:
- targetsrpm = os.path.join(os.path.realpath(targetdir),
- os.path.basename(srpm))
- targetsrpms.append(targetsrpm)
- if verbose:
- sys.stderr.write("Wrote: %s\n" % targetsrpm)
- execcmd("cp -f", srpm, targetdir)
- os.unlink(srpm)
+ srpms = glob.glob(os.path.join(srpmsdir, "*.src.rpm"))
+ if not srpms:
+ # something fishy happened
+ raise Error, "no SRPMS were found at %s" % srpmsdir
+ for srpm in srpms:
+ name = os.path.basename(srpm)
+ if revname:
+ name = "@%s:%s" % (urlrev, name)
+ for targetdir in targetdirs:
+ newpath = os.path.join(targetdir, name)
+ targetsrpms.append(newpath)
+ if os.path.exists(newpath):
+ # should we warn?
+ os.unlink(newpath)
+ shutil.copy(srpm, newpath)
+ if verbose:
+ sys.stderr.write("Wrote: %s\n" % newpath)
return targetsrpms
finally:
if os.path.isdir(tmpdir):
@@ -668,6 +718,7 @@ def get_submit_info(path):
if len(toks) < 2 or toks[-1] != "current":
raise Error, "unexpected URL received from 'svn info'"
name = toks[-2]
+ url = "/".join(toks[:-1])
# Finally, guess revision.
max = -1
@@ -686,6 +737,6 @@ def get_submit_info(path):
if max == -1:
raise Error, "revision tag not found in 'svn info' output"
- return name, max
+ return name, url, max
# vim:et:ts=4:sw=4
diff --git a/create-srpm b/create-srpm
index 0c51e97..868ac27 100755
--- a/create-srpm
+++ b/create-srpm
@@ -1,13 +1,14 @@
#!/usr/bin/python
from RepSys import Error, config, plugins
-from RepSys.rpmutil import get_srpm
+from RepSys.rpmutil import get_srpm, svn_url_rev, strip_url_rev
from RepSys.cgiutil import get_targets
from RepSys.util import mapurl, execcmd, get_helper
import sys
import os
import pwd
import optparse
+import subprocess
class CmdError(Error): pass
@@ -15,15 +16,13 @@ class CmdIface:
def author_email(self, author):
return config.get("users", author)
- def submit_package(self, packageurl, packagerev, targetname,
- dontmapurl_=0, define=[]):
+ def submit_package(self, urls, revision, targetname, dontmapurl_=0,
+ define=[]):
pw = pwd.getpwuid(os.getuid())
username = pw[0]
packager = config.get("users", username) or pw[4]
if not packager:
raise CmdError, "your email was not found"
- elif not packagerev:
- raise CmdError, "no revision provided"
elif not targetname:
raise CmdError, "no target provided"
else:
@@ -33,45 +32,48 @@ class CmdIface:
break
else:
raise CmdError, "target not found"
- try:
- tmp = int(packagerev)
- except ValueError:
- raise CmdError, "invalid revision provided"
- for allowed in target.allowed:
- if packageurl.startswith(allowed):
- break
- else:
- raise CmdError, "%s is not allowed for this target" \
- % packageurl
- newurl = packageurl
- if not dontmapurl_:
- newurl = mapurl(packageurl)
- targetsrpms = get_srpm(newurl,
- revision=packagerev,
- targetdirs=target.target,
- packager=packager,
- revname=1,
- svnlog=1,
- scripts=target.scripts,
- macros=target.macros)
-
- uploadsrpm = get_helper("upload-srpm")
- if uploadsrpm:
- upload_command = [ uploadsrpm ]
+ for url in urls:
+ for allowed in target.allowed:
+ if url.startswith(allowed):
+ break
+ else:
+ raise CmdError, "%s is not allowed for this target" \
+ % url
+ if not dontmapurl_: #FIXME don't use it!
+ urls = [mapurl(url) for url in urls]
+ uploadsrpms = []
+ for url in urls:
+ revision = revision or svn_url_rev(url)
+ url = strip_url_rev(url)
+ targetsrpms = get_srpm(url,
+ revision=revision,
+ targetdirs=target.target,
+ packager=packager,
+ svnlog=1,
+ revname=1,
+ scripts=target.scripts,
+ macros=target.macros)
+ uploadsrpms.extend(targetsrpms)
+ uploadcmd = get_helper("upload-srpm")
+ if uploadcmd:
+ upload_command = [uploadcmd]
if define:
for x in define:
upload_command.append("--define")
upload_command.append(x)
upload_command.append(targetname)
- upload_command.append(targetsrpms[0])
- status, output = execcmd(" ".join(upload_command),
- noerror=1)
- if os.path.isfile(targetsrpms[0]):
- os.unlink(targetsrpms[0])
- else:
- sys.stderr.write("warning: upload ok; temp file '%s' removed unexpectedly\n" % (targetsrpms[0]))
+ upload_command.extend(uploadsrpms)
+ command = subprocess.list2cmdline(upload_command)
+ status, output = execcmd(command, noerror=1)
+ for srpm in uploadsrpms:
+ if os.path.isfile(srpm):
+ os.unlink(srpm)
+ else:
+ sys.stderr.write("warning: temporary file "\
+ "'%s' removed unexpectedly\n" % srpm)
if status != 0:
- raise CmdError, "Failed to upload %s:\n%s" % (packageurl, output)
+ raise CmdError, "Failed to upload "\
+ "%s:\n%s" % (" ".join(urls), output)
return 1
def submit_targets(self):
@@ -79,10 +81,8 @@ class CmdIface:
def parse_options():
- usage = "create-srpm <packageurl> -t <target> [-r <revision>]"
+ usage = "create-srpm <packageurl> -t <target>"
parser = optparse.OptionParser(usage=usage)
- parser.add_option("-r", "--revision", dest="revision", type="string",
- help="the revision number")
parser.add_option("-t", "--target", type="string", dest="target",
help="target name")
parser.add_option("-M", "--nomapping", action="store_true",
@@ -92,6 +92,8 @@ def parse_options():
parser.add_option("--list", dest="list_targets", default=False,
action="store_true",
help="list submit targets available")
+ parser.add_option("-r", help="revision", dest="revision",
+ type="int", default=None)
opts, args = parser.parse_args()
if not opts.list_targets and not args:
parser.error("you must supply a package url")
@@ -107,8 +109,8 @@ def main():
for target in iface.submit_targets():
print target
else:
- iface.submit_package(args[0], opts.revision, opts.target,
- opts.urlmap, opts.define)
+ iface.submit_package(args, opts.revision, opts.target, opts.urlmap,
+ opts.define)
except Error, e:
sys.stderr.write("error: %s\n" % str(e))
sys.exit(1)
diff --git a/repsys-example.conf b/repsys-example.conf
index 99c44f5..3a9193c 100644
--- a/repsys-example.conf
+++ b/repsys-example.conf
@@ -9,6 +9,8 @@ url-map = svn\+ssh://svn\.mandriva\.com/(.*) file:///\1
[log]
oldurl = svn+ssh://svn.mandriva.com/svn/packages/misc
+sort = yes
+merge-spec = no
# controls up to which revision the rpm changelog
# will be constructed (default zero, i.e., oldest
# commit)
diff --git a/repsys.8 b/repsys.8
new file mode 100644
index 0000000..54b49cc
--- /dev/null
+++ b/repsys.8
@@ -0,0 +1,198 @@
+.\" repsys - Package repository management tool
+.TH "repsys" "8" "2008 Feb 8" "Mandriva Linux" ""
+.SH "NAME"
+repsys \- Package souces repository management tool
+.SH "SYNOPSIS"
+\fBrepsys\fP command [options] [arguments]
+.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.
+
+Detailed help on commands is available running \fBrepsys <command> \-\-help\fP.
+.SH "BASIC USAGE"
+.SS "Setup"
+\fBrepsys\fP does not handle the authentication interface used by svn. So it is usually required to setup ssh\-agent(1) if the repository access method is over SSH (svn+ssh:// URLs), or performing some simple operation in order to obtain a authentication token.
+
+.nf
+For more information related how to setup ssh-agent, see:
+http://wiki.mandriva.com/en/Development/Docs/Contributor_Tricks#SSH_configuration
+.fi
+
+Users that don't have an ssh account in the default repository URL can set the option \fBmirror\fP pointing to a non-authenticated, read-only repository (such as http://svn.mandriva.com/svn/packages/cooker).
+.SS "Examples"
+.PP
+.IP "\fBrepsys co foo\fP"
+Obtains a working copy of the package foo.
+.IP "\fBrepsys ci\fP"
+Commits pending changes in the working copy.
+.IP "\fBrepsys submit foo \-r 12345\fP"
+Requests the package foo in the revision 12345 to be built and, if successful, to be uploaded to the RPMs repository.
+.IP "\fBrepsys submit foo \-r 12345 -t 2008.0 \-\-define section=main/testing\fP"
+Will submit the package foo and, upon successful build will have its RPMs placed inside the main/testing media of the 2008.0 repository.
+.IP "\fBrepsys submit\fP"
+submit run without parameters will use package name and revision found in the working copy in the current directory.
+.SH "COMMANDS"
+For detailed help on commands run \fBrepsys <command> \-\-help\fP.
+\#TODO complete list of commands, all options, all descriptions
+.PP
+.IP "\fBco\fP"
+checkout a package
+.IP "\fBci\fP"
+commit changes
+.IP "\fBsubmit\fP"
+submit a package in a given revision for build and release
+.IP "\fBsync\fP"
+add-remove all file changes from the .spec
+.IP "\fBgetspec\fP"
+prints the spec
+.IP "\fBrpmlog\fP"
+prints the RPM changelog generated from SVN
+.IP "\fBgetsrpm\fP"
+creates the source RPM
+.IP "\fBcreate\fP"
+create the structure of a new package
+.IP "\fBchanged\fP"
+shows changes not submitted
+.IP "\fBauthoremail\fP"
+prints the e-mail of a given svn author
+.IP "\fBswitch\fP"
+relocate to mirror or upstream repository
+.IP "\fBmarkrelease\fP"
+creates a tag for a given package revision and version
+.SH "REPOSITORY LAYOUT"
+.nf
+A detailed description can be found at:
+http://wiki.mandriva.com/en/Development/Packaging/RepositorySystem
+.fi
+
+The svn repository used by \fBrepsys\fP consists of a set of branches in the top directory, followed by package directories having the internal package structure.
+
+The internal package layout contains a directory \fBcurrent/\fP, which contains the latest version of the package (equivalent to "trunk" in software repositories). The directory \fBreleases/\fP contain copies of older submitted packages that have been already released, it is organized in the \fB<version>/<release>\fP format (equivalent to "tags" directories).
+
+URLs used in \fBrepsys\fP commands refer to the package directory, and never to \fBcurrent\fP. In other words, the http://host/svn/cooker/foo is valid, whereas http://host/svn/cooker/foo/current is not.
+
+One example layout:
+
+\fB
+/packages/cooker
+ |
+ +\- 2007.0/
+ +\- 2007.1/
+ +\- 2008.0/
+ +\- cooker/
+ ...
+ +\- rsync/
+ +\- coreutils/
+ +\- make/
+ +\- foo/
+ +\- current/
+ | +\- SOURCES/
+ | +\- SPECS/
+ +\- releases/
+ ...
+ +\- 1.0
+ +\- 1mdk/
+ +\- SOURCES/
+ +\- SPECS/
+ +\- 2mdk/
+ ...
+\fP
+\#.SH "THE SUBMIT PROCESS"
+\#.SS "Connecting"
+\#.SS "Changelog generation"
+\#.SS "Uploading"
+\#.SH CHANGELOGS
+\#.SH SERVER\-SIDE SETUP
+.SH "CONFIGURATION"
+.SS "Introduction"
+The main configuration file is \fB/etc/repsys.conf\fP, it is in the .ini format. It is basically defined by a set of \fB[name]\fP sections, with a set of variables defined by \fBname = value\fP.
+
+If existing, the file ~/.repsys/config is also loaded.
+.SS "[global] section"
+.PP
+.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.
+.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"
+The directory to be used as base for temporay directories and files created by repsys.
+.IP "\fBdownload\-command = COMMAND\-FMT\fP"
+Command used to download generic remote URLs, it accepts the variables \fB$url\fP and \fB$dest\fP. It is currently used when running \fBrepsys sync \-d\fP.
+.IP "\fBsvn\-command = COMMAND\fP"
+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.
+.SS "[submit] section"
+.IP "\fBhost = HOST\fP"
+Defines the default host in which \fBrepsys submit\fP will run the submit helper.
+.IP "\fBdefault = TARGET\fP"
+The default target to be used in \fBrepsys submit\fP when the option \-t is not used.
+.SS "[submit TARGET] sections (server\-side only)"
+These sections describe each one of the sections available to submit packages, ther configuration options are:
+.IP "\fBtarget = PATH\fP"
+The path where SRPMs generated by \fBcreate\-srpm-\fP will be placed during during the submit process.
+.IP "\fBallowed = URLs\fP"
+A space\-delimited list of package URLs that will be allowed to be used with this target. The comparison is done by checking if the package URL used in submit starts with one of the URLs of this option.
+.IP "\fBscripts = PATHS\fP"
+A space\-delimited list of scripts that will be run receiving the generated SRPM as first argument. These scripts are usually used to perform small changes in the SRPM structure, increasing release number for example.
+.IP "\fBrpm\-macros = NAMES\fP"
+It points to sections in the configuration that will contain the RPM macros used when generating the SRPM of the package being submitted. These section should be named in the \fB[macros NAME]\fP format.
+.SS "[macros NAME] sections (server\-side only)"
+These sections contain variables that will be defined as RPM macros when generating the SRPM of the package being submitted.It is usually used to define the distribution suffix that will be used in package releases, such as "mdv2008.1".
+.SS "[users] section (server\-side only)"
+This section maps the usernames found in svn to their real names and e\-mails. It is used when generating the changelog based on commits in svn and by \fBauthoremail\fP. Example: \fBjoe = Joe User <joeuser@host.com>\fP.
+
+This section can be used on client\-side too, but will have no effect in generated changelogs on the server\-side.
+.SS "[helper] section"
+.IP "\fBcreate\-srpm = PATH\fP"
+The path of the script that will be run through ssh on the submit host when running \fBrepsys submit\fP.
+.IP "\fBupload\-srpm = PATH\fP"
+(server\-side only) Path of the script that will be called after the generated SRPM is copied to its target location (see target sections above) and target scripts are run.
+.SS "[log] section"
+.IP "\fBoldurl = URL\fP"
+The URL of a directory structure that will contain old changelogs of packages that will be appended to the changelog being generated by \fBrpmlog\fP or \fBgetsrpm \-l\fP.
+.IP "\fBmerge\-spec = yes/no\fP"
+If enabled, changelogs generated by \fBrepsys\fP will have the contents of the %changelog found in the .spec file of the package appended.
+.IP "\fBsort = yes/no\fP"
+If enabled, the changelog will be resorted after its generation. It is useful when changelogs found in \fBoldurl\fP or in the .spec's %changelog section are newer than those generated by SVN.
+.IP "\fBrevision\-offset = REVISION\-NUMBER\fP"
+The base revision used to generated changelogs. As in \fBsvn log -r REVISION\-OFFSET:HEAD URL\fP.
+.IP "\fBignore\-string = STRING\fP"
+Mark used to hide log messages. When it appears at the beginning of the log message, the whole changeset log is hidden. When it is found in the middle of a string, only the line will not be shown.
+.IP "\fBunignore\-string = STRING\fP"
+The complement of the previous option. When this token is found, only those lines containg this mark will be shown. It is intended to be used in very long log messages.
+.SS "[template] section"
+.IP "\fBpath = PATH\fP"
+The path of the template used to generate the changelog from svn commits.
+.SH "ENVIRONMENT VARIABLES"
+.PP
+.IP "\fBREPSYS_CONF\fP"
+Sets the configuration file to be read by \fBrepsys\fP
+.SH "FILES"
+.nf
+~/.repsys/config
+/etc/repsys.conf
+/usr/share/repsys/
+/usr/share/doc/repsys/
+.fi
+.SH "BUGS"
+URLs cannot have usernames when submitting packages.
+
+It is not possible to refer update packages without using the complete package URL.
+
+See more bugs in http://qa.mandriva.com/buglist.cgi?quicksearch=repsys
+.SH "SEE ALSO"
+mdvsys(1), svn(1), ssh\-agent(1)
+
+.nf
+http://wiki.mandriva.com/en/Development/Packaging/RepositorySystem/Quickstart
+.fi
+.SH "AUTHOR"
+.nf
+repsys was originally written by Gustavo Niemeyer <gustavo@niemeyer.net>
+for the Conectiva Linux distribution. Currently it is being mantained by
+Mandriva contributors and employees.
+.fi
diff --git a/repsys.conf b/repsys.conf
index 624c2ca..b96711b 100644
--- a/repsys.conf
+++ b/repsys.conf
@@ -1,3 +1,4 @@
+# see man 8 repsys for a description on configuration options
[global]
default_parent = svn+ssh://svn.mandriva.com/svn/packages/cooker
## uncomment it in case you don't have a account in the Mandriva cluster:
diff --git a/setup.py b/setup.py
index 7c4814c..1478b17 100755
--- a/setup.py
+++ b/setup.py
@@ -29,7 +29,8 @@ setup(name="repsys",
"compatv15.chlog",
"create-srpm",
"rebrand-mdk"]),
- ("/etc/", ["repsys.conf"])]
+ ("/etc/", ["repsys.conf"]),
+ ("share/man/man8/", ["repsys.8"])]
)
# vim:ts=4:sw=4:et