mirror of
https://github.com/openSUSE/osc.git
synced 2024-12-27 18:26:15 +01:00
Merge branch 'master' of git://gitorious.org/opensuse/osc
This commit is contained in:
commit
4290c5143b
9
NEWS
9
NEWS
@ -1,5 +1,9 @@
|
||||
0.127
|
||||
- --csv/--format options for results command - using format user can explicitly specify what he wants print
|
||||
|
||||
0.126
|
||||
- added VM diskimage autosetup hooks to osc
|
||||
- added VM autosetup to osc. This requires appropriate OBS version and build script version.
|
||||
- enhanced QEMU cross build support with 'armv4l' 'armv5el' 'armv6el' 'armv7el' 'armv8el' 'mips' 'mips64' 'ppc' 'ppc64' 'sh4' arch strings now supported on x86 host
|
||||
- suggest git, svn, ... if indicated, after oscerr.NoWorkingCopy
|
||||
- "osc cat" & "osc ls" now auto-expands through link.
|
||||
- fixed "osc add" after "osc delete".
|
||||
@ -24,6 +28,9 @@
|
||||
- added "--message" option to "osc branch"
|
||||
- added "osc config" command to set/get/delete a config option
|
||||
- added "--binary" and "--baseproject" options to "osc search"
|
||||
- added "-o/--offline" and "-l/--preload" options to osc build
|
||||
* osc build -l standard i586 foo.spec (to cache all dependencies)
|
||||
* osc build -o standard i586 foo.spec (to build without contacting the api)
|
||||
|
||||
0.125
|
||||
- add "osc pull" command to fetch and merge changes in the link target
|
||||
|
47
osc/build.py
47
osc/build.py
@ -32,20 +32,21 @@ change_personality = {
|
||||
}
|
||||
|
||||
can_also_build = {
|
||||
'armv4l': [ 'armv4l' ],
|
||||
'armv5el':[ 'armv4l', 'armv5el' ],
|
||||
'armv6el':[ 'armv4l', 'armv5el', 'armv6el' ],
|
||||
'armv6l' :[ 'armv4l', 'armv5el', 'armv6el' ],
|
||||
'armv7el':[ 'armv4l', 'armv5el', 'armv6el', 'armv7el' ],
|
||||
'armv7l' :[ 'armv4l', 'armv5el', 'armv6el', 'armv7el' ],
|
||||
'armv8el':[ 'armv4l', 'armv5el', 'armv6el', 'armv7el', 'armv8el'],
|
||||
'armv8l' :[ 'armv4l', 'armv5el', 'armv6el', 'armv7el', 'armv8el'],
|
||||
's390x': ['s390' ],
|
||||
'ppc64': [ 'ppc', 'ppc64', ],
|
||||
'i386': [ 'i586', 'ppc', 'ppc64', 'armv4l', 'armv5el', 'armv6el', 'armv7el', 'armv8el', 'sh4' ,'mips' ],
|
||||
'i586': [ 'i386', 'ppc', 'ppc64', 'armv4l', 'armv5el', 'armv6el', 'armv7el', 'armv8el', 'sh4' ,'mips' ],
|
||||
'i686': [ 'i586', 'ppc', 'ppc64', 'armv4l', 'armv5el', 'armv6el', 'armv7el', 'armv8el', 'sh4' ,'mips' ],
|
||||
'x86_64': ['i686', 'i586', 'i386', 'ppc', 'ppc64', 'armv4l', 'armv5el', 'armv6el', 'armv7el', 'armv8el', 'sh4' ,'mips' ],
|
||||
'armv4l': [ 'armv4l' ],
|
||||
'armv5el':[ 'armv4l', 'armv5el' ],
|
||||
'armv6el':[ 'armv4l', 'armv5el', 'armv6el' ],
|
||||
'armv6l' :[ 'armv4l', 'armv5el', 'armv6el' ],
|
||||
'armv7el':[ 'armv4l', 'armv5el', 'armv6el', 'armv7el' ],
|
||||
'armv7l' :[ 'armv4l', 'armv5el', 'armv6el', 'armv7el' ],
|
||||
'armv8el':[ 'armv4l', 'armv5el', 'armv6el', 'armv7el', 'armv8el' ],
|
||||
'armv8l' :[ 'armv4l', 'armv5el', 'armv6el', 'armv7el', 'armv8el' ],
|
||||
's390x': ['s390' ],
|
||||
'ppc64': [ 'ppc', 'ppc64' ],
|
||||
'sh4': [ 'sh4' ],
|
||||
'i386': [ 'i586', 'ppc', 'ppc64', 'armv4l', 'armv5el', 'armv6el', 'armv7el', 'armv8el', 'sh4', 'mips', 'mips64' ],
|
||||
'i586': [ 'i386', 'ppc', 'ppc64', 'armv4l', 'armv5el', 'armv6el', 'armv7el', 'armv8el', 'sh4', 'mips', 'mips64' ],
|
||||
'i686': [ 'i586', 'ppc', 'ppc64', 'armv4l', 'armv5el', 'armv6el', 'armv7el', 'armv8el', 'sh4', 'mips', 'mips64' ],
|
||||
'x86_64': ['i686', 'i586', 'i386', 'ppc', 'ppc64', 'armv4l', 'armv5el', 'armv6el', 'armv7el', 'armv8el', 'sh4', 'mips', 'mips64' ],
|
||||
}
|
||||
|
||||
# real arch of this machine
|
||||
@ -498,6 +499,12 @@ def main(opts, argv):
|
||||
if not os.path.isfile(bc_filename):
|
||||
raise oscerr.WrongOptions('--noinit is not possible, no local buildconfig file')
|
||||
print 'Use local \'%s\' file as buildconfig' % bc_filename
|
||||
elif opts.offline:
|
||||
if not os.path.isfile(bi_filename):
|
||||
raise oscerr.WrongOptions('--offline is not possible, no local buildinfo file')
|
||||
print 'Use local \'%s\' file as buildinfo' % bi_filename
|
||||
if not os.path.isfile(bc_filename):
|
||||
raise oscerr.WrongOptions('--offline is not possible, no local buildconfig file')
|
||||
else:
|
||||
print 'Getting buildinfo from server and store to %s' % bi_filename
|
||||
if not bi_file:
|
||||
@ -599,7 +606,7 @@ def main(opts, argv):
|
||||
fetcher = Fetcher(cachedir = config['packagecachedir'],
|
||||
urllist = urllist,
|
||||
api_host_options = config['api_host_options'],
|
||||
offline = opts.noinit,
|
||||
offline = opts.noinit or opts.offline,
|
||||
http_debug = config['http_debug'],
|
||||
enable_cpio = opts.cpio_bulk_download,
|
||||
cookiejar=cookiejar)
|
||||
@ -639,7 +646,9 @@ def main(opts, argv):
|
||||
os.symlink(sffn, tffn)
|
||||
|
||||
if bi.pacsuffix == 'rpm':
|
||||
if opts.no_verify or opts.noinit:
|
||||
if config['build-type'] == "xen" or config['build-type'] == "kvm" or config['build-type'] == "lxc":
|
||||
print 'Skipping verification of package signatures due to secure VM build'
|
||||
elif opts.no_verify or opts.noinit or opts.offline:
|
||||
print 'Skipping verification of package signatures'
|
||||
else:
|
||||
print 'Verifying integrity of cached packages'
|
||||
@ -658,7 +667,7 @@ def main(opts, argv):
|
||||
|
||||
verify_pacs([ i.fullfilename for i in bi.deps ], bi.keys)
|
||||
elif bi.pacsuffix == 'deb':
|
||||
if config['build-type'] == "xen" or config['build-type'] == "kvm":
|
||||
if config['build-type'] == "xen" or config['build-type'] == "kvm" or config['build-type'] == "lxc":
|
||||
print 'Skipping verification of package signatures due to secure VM build'
|
||||
elif opts.no_verify or opts.noinit:
|
||||
print 'Skipping verification of package signatures'
|
||||
@ -720,6 +729,10 @@ def main(opts, argv):
|
||||
if config['build-vmdisk-swapsize']:
|
||||
vm_options += ' --vmdisk-swapsize ' + config['build-vmdisk-swapsize']
|
||||
|
||||
if opts.preload:
|
||||
print "Preload done for selected repo/arch."
|
||||
sys.exit(0)
|
||||
|
||||
print 'Running build'
|
||||
cmd = '"%s" --root="%s" --rpmlist="%s" --dist="%s" %s --arch=%s %s %s "%s"' \
|
||||
% (config['build-cmd'],
|
||||
|
@ -784,7 +784,8 @@ class Osc(cmdln.Cmdln):
|
||||
print "Submitting patchinfo ", ', '.join(pi), " to ", ', '.join(targetprojects)
|
||||
print "\nEverything fine? Can we create the requests ? [y/n]"
|
||||
if sys.stdin.read(1) != "y":
|
||||
sys.exit("Aborted...")
|
||||
print >>sys.stderr, 'Aborted...'
|
||||
raise oscerr.UserAbort()
|
||||
|
||||
# loop via all packages to do the action
|
||||
for p in pac:
|
||||
@ -844,7 +845,7 @@ class Osc(cmdln.Cmdln):
|
||||
print 'Your working copy has local modifications.'
|
||||
repl = raw_input('Proceed without committing the local changes? (y|N) ')
|
||||
if repl != 'y':
|
||||
sys.exit(1)
|
||||
raise oscerr.UserAbort()
|
||||
elif len(args) >= 3:
|
||||
# get the arguments from the commandline
|
||||
src_project, src_package, dst_project = args[0:3]
|
||||
@ -899,7 +900,7 @@ Please submit there instead, or use --nodevelproject to force direct submission.
|
||||
repl = raw_input('Supersede the old requests? (y/n/c) ')
|
||||
if repl.lower() == 'c':
|
||||
print >>sys.stderr, 'Aborting'
|
||||
sys.exit(1)
|
||||
raise oscerr.UserAbort()
|
||||
|
||||
if not opts.message:
|
||||
difflines = []
|
||||
@ -2717,8 +2718,12 @@ Please submit there instead, or use --nodevelproject to force direct submission.
|
||||
help='Show results only for specified repo(s)')
|
||||
@cmdln.option('-a', '--arch', action='append', default = [],
|
||||
help='Show results only for specified architecture(s)')
|
||||
@cmdln.option('', '--xml', action='store_true',
|
||||
@cmdln.option('', '--xml', action='store_true', default=False,
|
||||
help='generate output in XML (former results_meta)')
|
||||
@cmdln.option('', '--csv', action='store_true', default=False,
|
||||
help='generate output in CSV format')
|
||||
@cmdln.option('', '--format', default='%(repository)s|%(arch)s|%(state)s|%(dirty)s|%(code)s|%(details)s',
|
||||
help='format string for csv output')
|
||||
def do_results(self, subcmd, opts, *args):
|
||||
"""${cmd_name}: Shows the build results of a package
|
||||
|
||||
@ -2756,12 +2761,20 @@ Please submit there instead, or use --nodevelproject to force direct submission.
|
||||
project = args[0]
|
||||
package = args[1]
|
||||
|
||||
if not opts.xml:
|
||||
func = get_results
|
||||
delim = '\n'
|
||||
else:
|
||||
if opts.xml and opts.csv:
|
||||
raise oscerr.WrongOptions("--xml and --csv are mutual exclusive")
|
||||
|
||||
if opts.xml:
|
||||
func = show_results_meta
|
||||
delim = ''
|
||||
elif opts.csv:
|
||||
def _func(*args):
|
||||
return format_results(get_package_results(*args), opts.format)
|
||||
func = _func
|
||||
delim = '\n'
|
||||
else:
|
||||
func = get_results
|
||||
delim = '\n'
|
||||
|
||||
print delim.join(func(apiurl, project, package, opts.last_build, opts.repo, opts.arch))
|
||||
|
||||
@ -3305,6 +3318,10 @@ Please submit there instead, or use --nodevelproject to force direct submission.
|
||||
|
||||
@cmdln.option('--clean', action='store_true',
|
||||
help='Delete old build root before initializing it')
|
||||
@cmdln.option('-o', '--offline', action='store_true',
|
||||
help='Start with cached prjconf and packages without contacting the api server')
|
||||
@cmdln.option('-l', '--preload', action='store_true',
|
||||
help='Preload all files into the chache for offline operation')
|
||||
@cmdln.option('--no-changelog', action='store_true',
|
||||
help='don\'t update the package changelog from a changes file')
|
||||
@cmdln.option('--rsync-src', metavar='RSYNCSRCPATH', dest='rsyncsrc',
|
||||
@ -3422,7 +3439,7 @@ Please submit there instead, or use --nodevelproject to force direct submission.
|
||||
if len(args) > 3:
|
||||
raise oscerr.WrongArgs('Too many arguments')
|
||||
|
||||
args = self.parse_repoarchdescr(args, opts.noinit, opts.alternative_project)
|
||||
args = self.parse_repoarchdescr(args, opts.noinit or opts.offline, opts.alternative_project)
|
||||
|
||||
# check for source services
|
||||
if not opts.noservice and not opts.noinit and os.listdir('.').count("_service"):
|
||||
@ -3437,6 +3454,12 @@ Please submit there instead, or use --nodevelproject to force direct submission.
|
||||
if opts.keep_pkgs and not os.path.isdir(opts.keep_pkgs):
|
||||
raise oscerr.WrongOptions('Preferred save location \'%s\' is not a directory' % opts.keep_pkgs)
|
||||
|
||||
if opts.noinit and opts.offline:
|
||||
raise oscerr.WrongOptions('--noinit and --offline are mutually exclusive')
|
||||
|
||||
if opts.offline and opts.preload:
|
||||
raise oscerr.WrongOptions('--offline and --preload are mutually exclusive')
|
||||
|
||||
print 'Building %s for %s/%s' % (args[2], args[0], args[1])
|
||||
return osc.build.main(opts, args)
|
||||
|
||||
@ -3449,6 +3472,8 @@ Please submit there instead, or use --nodevelproject to force direct submission.
|
||||
help='do not guess/verify specified repository')
|
||||
@cmdln.option('-r', '--root', action='store_true',
|
||||
help='login as root instead of abuild')
|
||||
@cmdln.option('-o', '--offline', action='store_true',
|
||||
help='Use cached data without contacting the api server')
|
||||
def do_chroot(self, subcmd, opts, *args):
|
||||
"""${cmd_name}: chroot into the buildchroot
|
||||
|
||||
@ -3472,7 +3497,7 @@ Please submit there instead, or use --nodevelproject to force direct submission.
|
||||
user = 'abuild'
|
||||
if opts.root:
|
||||
user = 'root'
|
||||
repository, arch, descr = self.parse_repoarchdescr(args, opts.noinit, opts.alternative_project)
|
||||
repository, arch, descr = self.parse_repoarchdescr(args, opts.noinit or opts.offline, opts.alternative_project)
|
||||
project = opts.alternative_project or store_read_project('.')
|
||||
if opts.local_package:
|
||||
package = os.path.splitext(descr)[0]
|
||||
|
59
osc/core.py
59
osc/core.py
@ -3,7 +3,7 @@
|
||||
# and distributed under the terms of the GNU General Public Licence,
|
||||
# either version 2, or version 3 (at your option).
|
||||
|
||||
__version__ = '0.125git'
|
||||
__version__ = '0.126git'
|
||||
|
||||
# __store_version__ is to be incremented when the format of the working copy
|
||||
# "store" changes in an incompatible way. Please add any needed migration
|
||||
@ -3483,38 +3483,53 @@ def show_prj_results_meta(apiurl, prj):
|
||||
return f.readlines()
|
||||
|
||||
|
||||
def get_results(apiurl, prj, package, lastbuild=None, repository=[], arch=[]):
|
||||
def get_package_results(apiurl, prj, package, lastbuild=None, repository=[], arch=[]):
|
||||
""" return a package results as a list of dicts """
|
||||
r = []
|
||||
result_line_templ = '%(rep)-20s %(arch)-10s %(status)s'
|
||||
|
||||
f = show_results_meta(apiurl, prj, package, lastbuild, repository, arch)
|
||||
root = ET.fromstring(''.join(f))
|
||||
|
||||
for node in root.findall('result'):
|
||||
rmap = {}
|
||||
rmap['prj'] = prj
|
||||
rmap['pac'] = package
|
||||
rmap['rep'] = node.get('repository')
|
||||
rmap['project'] = rmap['prj'] = prj
|
||||
rmap['pkg'] = rmap['package'] = rmap['pac'] = package
|
||||
rmap['repository'] = rmap['repo'] = rmap['rep'] = node.get('repository')
|
||||
rmap['arch'] = node.get('arch')
|
||||
rmap['state'] = node.get('state')
|
||||
rmap['dirty'] = node.get('dirty')
|
||||
|
||||
statusnode = node.find('status')
|
||||
try:
|
||||
rmap['status'] = statusnode.get('code')
|
||||
except:
|
||||
# code can be missing when package is too new:
|
||||
rmap['status'] = ''
|
||||
rmap['code'] = statusnode.get('code') if 'code' in statusnode.keys() else ''
|
||||
rmap['details'] = ''
|
||||
|
||||
if rmap['status'] in ['expansion error', 'broken', 'blocked', 'finished']:
|
||||
if rmap['code'] in ('expansion error', 'broken', 'blocked', 'finished'):
|
||||
details = statusnode.find('details')
|
||||
if details != None:
|
||||
rmap['status'] += ': ' + details.text
|
||||
rmap['details'] = details.text
|
||||
|
||||
if rmap['dirty'] == 'true':
|
||||
rmap['status'] = 'state is outdated (was: %s)' % rmap['status']
|
||||
rmap['dirty'] = rmap['dirty'] == 'true'
|
||||
|
||||
r.append(rmap)
|
||||
return r
|
||||
|
||||
def format_results(results, format):
|
||||
"""apply selected format on each dict in results and return it as a list of strings"""
|
||||
return (format % r for r in results)
|
||||
|
||||
def get_results(apiurl, prj, package, lastbuild=None, repository=[], arch=[]):
|
||||
r = []
|
||||
result_line_templ = '%(rep)-20s %(arch)-10s %(status)s'
|
||||
|
||||
for res in get_package_results(apiurl, prj, package, lastbuild=None, repository=[], arch=[]):
|
||||
res['status'] = res['code']
|
||||
if res['details'] != '':
|
||||
res['status'] += ': %s' % (res['details'], )
|
||||
if res['dirty']:
|
||||
res['status'] = 'state is outdated (was: %s)' % res['status']
|
||||
|
||||
r.append(result_line_templ % res)
|
||||
|
||||
r.append(result_line_templ % rmap)
|
||||
return r
|
||||
|
||||
def get_prj_results(apiurl, prj, hide_legend=False, csv=False, status_filter=None, name_filter=None, arch=None, repo=None, vertical=None):
|
||||
@ -4632,12 +4647,12 @@ def request_interactive_review(apiurl, request):
|
||||
tmpfile = None
|
||||
print request
|
||||
try:
|
||||
msg = '(a)ccept/(d)ecline/(r)evoke/(c)ancel > '
|
||||
if request.actions[0].type == 'submit':
|
||||
msg = 'd(i)ff/%s' % msg
|
||||
while True:
|
||||
repl = raw_input('d(i)ff/(a)ccept/(d)ecline/(r)evoke/(c)ancel > ')
|
||||
if repl == 'i':
|
||||
if request.actions[0].type != 'submit':
|
||||
print >>sys.stderr, 'diff is not possible for request type: \'%s\'' % request.actions[0].type
|
||||
continue
|
||||
repl = raw_input(msg)
|
||||
if repl == 'i' and request.actions[0].type == 'submit':
|
||||
if tmpfile is None:
|
||||
tmpfile = tempfile.NamedTemporaryFile()
|
||||
tmpfile.write(server_diff(apiurl, request.actions[0].dst_project, request.actions[0].dst_package, None,
|
||||
@ -4647,7 +4662,7 @@ def request_interactive_review(apiurl, request):
|
||||
subprocess.call('%s %s' % (pager, tmpfile.name), shell=True)
|
||||
elif repl == 'c':
|
||||
print >>sys.stderr, 'Aborting'
|
||||
sys.exit(1)
|
||||
raise oscerr.UserAbort()
|
||||
else:
|
||||
state_map = {'a': 'accepted', 'd': 'declined', 'r': 'revoked'}
|
||||
mo = re.search('^([adr])(?:\s+-m\s+(.*))?$', repl)
|
||||
|
10
osc/fetch.py
10
osc/fetch.py
@ -10,6 +10,7 @@ from urlgrabber.mirror import MirrorGroup
|
||||
from core import makeurl, streamfile
|
||||
from util import packagequery, cpio
|
||||
import conf
|
||||
import oscerr
|
||||
import tempfile
|
||||
try:
|
||||
from meter import TextMeter
|
||||
@ -85,9 +86,6 @@ class Fetcher:
|
||||
# for use by the failure callback
|
||||
self.curpac = pac
|
||||
|
||||
if self.offline:
|
||||
return True
|
||||
|
||||
MirrorGroup._join_url = join_url
|
||||
mg = MirrorGroup(self.gr, pac.urllist, failure_callback=(self.failureReport,(),{}))
|
||||
|
||||
@ -163,6 +161,8 @@ class Fetcher:
|
||||
for i in buildinfo.deps:
|
||||
i.makeurls(self.cachedir, self.urllist)
|
||||
if not os.path.exists(i.fullfilename):
|
||||
if self.offline:
|
||||
raise oscerr.OscIOError(None, 'Missing package \'%s\' in cache: --offline not possible.' % i.fullfilename)
|
||||
self.dirSetup(i)
|
||||
try:
|
||||
# if there isn't a progress bar, there is no output at all
|
||||
@ -193,7 +193,6 @@ class Fetcher:
|
||||
archive.read()
|
||||
for hdr in archive:
|
||||
if hdr.filename == '.errors':
|
||||
import oscerr
|
||||
archive.copyin_file(hdr.filename)
|
||||
raise oscerr.APIError('CPIO archive is incomplete (see .errors file)')
|
||||
pac = pkgs[hdr.filename.rsplit('.', 1)[0]]
|
||||
@ -234,6 +233,9 @@ class Fetcher:
|
||||
else:
|
||||
print "%s doesn't have a gpg key" % i
|
||||
|
||||
if os.path.exists(dest):
|
||||
os.unlink(dest)
|
||||
|
||||
l = i.rsplit(':', 1)
|
||||
# try key from parent project
|
||||
if len(l) > 1 and l[1] and not l[0] in buildinfo.projects:
|
||||
|
Loading…
Reference in New Issue
Block a user