From 11c2f0a510fcf147161ae8123fba92ca366bc607 Mon Sep 17 00:00:00 2001 From: brook hong Date: Mon, 24 May 2010 19:28:44 +0800 Subject: [PATCH] implement https://features.opensuse.org/309351 --- osc/commandline.py | 364 +++++++++++++++++++++++++++++++++++++++++++++ osc/core.py | 2 +- 2 files changed, 365 insertions(+), 1 deletion(-) mode change 100644 => 100755 osc/commandline.py mode change 100644 => 100755 osc/core.py diff --git a/osc/commandline.py b/osc/commandline.py old mode 100644 new mode 100755 index f5b0a241..42266288 --- a/osc/commandline.py +++ b/osc/commandline.py @@ -948,6 +948,370 @@ Please submit there instead, or use --nodevelproject to force direct submission. print 'created request id', result + def _actionparser(option, opt_str, value, parser): + value = [] + if not hasattr(parser.values, 'actiondata'): + setattr(parser.values, 'actiondata', []) + if parser.values.actions == None: + parser.values.actions = [] + + rargs = parser.rargs + while rargs: + arg = rargs[0] + if ((arg[:2] == "--" and len(arg) > 2) or + (arg[:1] == "-" and len(arg) > 1 and arg[1] != "-")): + break + else: + value.append(arg) + del rargs[0] + + parser.values.actions.append(value[0]) + del value[0] + parser.values.actiondata.append(value) + + def _submit_request(self, args, opts, options_block): + actionxml="" + apiurl = self.get_api_url() + if len(args) == 0 and is_project_dir(os.getcwd()): + import cgi + # submit requests for multiple packages are currently handled via multiple requests + # They could be also one request with multiple actions, but that avoids to accepts parts of it. + project = store_read_project(os.curdir) + + pi = [] + pac = [] + targetprojects = [] + rdiffmsg = [] + # loop via all packages for checking their state + for p in meta_get_packagelist(apiurl, project): + if p.startswith("_patchinfo:"): + pi.append(p) + else: + # get _link info from server, that knows about the local state ... + u = makeurl(apiurl, ['source', project, p]) + f = http_GET(u) + root = ET.parse(f).getroot() + linkinfo = root.find('linkinfo') + if linkinfo == None: + print "Package ", p, " is not a source link." + sys.exit("This is currently not supported.") + if linkinfo.get('error'): + print "Package ", p, " is a broken source link." + sys.exit("Please fix this first") + t = linkinfo.get('project') + if t: + rdiff = '' + try: + rdiff = server_diff(apiurl, t, p, opts.revision, project, p, None, True) + except: + rdiff = '' + + if rdiff != '': + targetprojects.append(t) + pac.append(p) + rdiffmsg.append("old: %s/%s\nnew: %s/%s\n%s" %(t, p, project, p,rdiff)) + else: + print "Skipping package ", p, " since it has no difference with the target package." + else: + print "Skipping package ", p, " since it is a source link pointing inside the project." + if opts.diff: + print ''.join(rdiffmsg) + sys.exit(0) + + if not opts.yes: + if pi: + 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...") + + # loop via all packages to do the action + for p in pac: + s = """ %s """ % \ + (project, p, opts.revision or show_upstream_rev(apiurl, project, p), t, p, options_block) + actionxml += s + + # create submit requests for all found patchinfos + for p in pi: + for t in targetprojects: + s = """ %s """ % \ + (project, p, t, p, options_block) + actionxml += s + + return actionxml + + elif len(args) <= 2: + # try using the working copy at hand + p = findpacs(os.curdir)[0] + src_project = p.prjname + src_package = p.name + if len(args) == 0 and p.islink(): + dst_project = p.linkinfo.project + dst_package = p.linkinfo.package + elif len(args) > 0: + dst_project = args[0] + if len(args) == 2: + dst_package = args[1] + else: + dst_package = src_package + else: + sys.exit('Package \'%s\' is not a source link, so I cannot guess the submit target.\n' + 'Please provide it the target via commandline arguments.' % p.name) + + modified = [i for i in p.filenamelist if p.status(i) != ' ' and p.status(i) != '?'] + if len(modified) > 0: + print 'Your working copy has local modifications.' + repl = raw_input('Proceed without committing the local changes? (y|N) ') + if repl != 'y': + sys.exit(1) + elif len(args) >= 3: + # get the arguments from the commandline + src_project, src_package, dst_project = args[0:3] + if len(args) == 4: + dst_package = args[3] + else: + dst_package = src_package + else: + raise oscerr.WrongArgs('Incorrect number of arguments.\n\n' \ + + self.get_cmd_help('request')) + + if not opts.nodevelproject: + devloc = None + try: + devloc = show_develproject(apiurl, dst_project, dst_package) + except urllib2.HTTPError: + print >>sys.stderr, """\ +Warning: failed to fetch meta data for '%s' package '%s' (new package?) """ \ + % (dst_project, dst_package) + pass + + if devloc and \ + dst_project != devloc and \ + src_project != devloc: + print """\ +A different project, %s, is defined as the place where development +of the package %s primarily takes place. +Please submit there instead, or use --nodevelproject to force direct submission.""" \ + % (devloc, dst_package) + if not opts.diff: + sys.exit(1) + + rdiff = None + if opts.diff: + try: + rdiff = 'old: %s/%s\nnew: %s/%s' %(dst_project, dst_package, src_project, src_package) + rdiff += server_diff(apiurl, + dst_project, dst_package, opts.revision, + src_project, src_package, None, True) + except: + rdiff = '' + if opts.diff: + print rdiff + else: + reqs = get_request_list(apiurl, dst_project, dst_package, req_type='submit') + user = conf.get_apiurl_usr(apiurl) + myreqs = [ i for i in reqs if i.state.who == user ] + repl = '' + if len(myreqs) > 0: + print 'You already created the following submit request: %s.' % \ + ', '.join([str(i.reqid) for i in myreqs ]) + repl = raw_input('Supersede the old requests? (y/n/c) ') + if repl.lower() == 'c': + print >>sys.stderr, 'Aborting' + sys.exit(1) + + actionxml = """ %s """ % \ + (src_project, src_package, opts.revision or show_upstream_rev(apiurl, src_project, src_package), dst_project, dst_package, options_block) + if repl.lower() == 'y': + for req in myreqs: + change_request_state(apiurl, str(req.reqid), 'superseded', + 'superseded by %s' % result, result) + + if opts.supersede: + r = change_request_state(apiurl, + opts.supersede, 'superseded', '', result) + + #print 'created request id', result + return actionxml + + def _delete_request(self, args, opts): + if len(args) < 1: + raise oscerr.WrongArgs('Please specify at least a project.') + if len(args) > 2: + raise oscerr.WrongArgs('Too many arguments.') + + package = "" + if len(args) > 1: + package = """package="%s" """ % (args[1]) + actionxml = """ """ % (args[0], package) + return actionxml + + def _changedevel_request(self, args, opts): + if len(args) > 4: + raise oscerr.WrongArgs('Too many arguments.') + + if len(args) == 0 and is_package_dir('.') and len(conf.config['getpac_default_project']): + wd = os.curdir + devel_project = store_read_project(wd) + devel_package = package = store_read_package(wd) + project = conf.config['getpac_default_project'] + else: + if len(args) < 3: + raise oscerr.WrongArgs('Too few arguments.') + + devel_project = args[2] + project = args[0] + package = args[1] + devel_package = package + if len(args) > 3: + devel_package = args[3] + + actionxml = """ """ % \ + (devel_project, devel_package, project, package) + + return actionxml + + def _add_role(self, args, opts): + if len(args) > 4: + raise oscerr.WrongArgs('Too many arguments.') + if len(args) < 3: + raise oscerr.WrongArgs('Too few arguments.') + + apiurl = self.get_api_url() + + user = args[0] + role = args[1] + project = args[2] + if len(args) > 3: + package = args[3] + + if get_user_meta(apiurl, user) == None: + raise oscerr.WrongArgs('osc: an error occured.') + + actionxml = """ """ % \ + (project, package, user, role) + + return actionxml + + def _set_bugowner(self, args, opts): + if len(args) > 3: + raise oscerr.WrongArgs('Too many arguments.') + if len(args) < 2: + raise oscerr.WrongArgs('Too few arguments.') + + apiurl = self.get_api_url() + + user = args[0] + project = args[1] + if len(args) > 2: + package = args[2] + + if get_user_meta(apiurl, user) == None: + raise oscerr.WrongArgs('osc: an error occured.') + + actionxml = """ """ % \ + (project, package, user) + + return actionxml + + @cmdln.option('-a', '--action', action='callback', callback = _actionparser,dest = 'actions', + help='specify action type of a request, can be : submit/delete/change_devel/add_role/set_bugowner') + @cmdln.option('-m', '--message', metavar='TEXT', + help='specify message TEXT') + @cmdln.option('-r', '--revision', metavar='REV', + help='for "create", specify a certain source revision ID (the md5 sum)') + @cmdln.option('-s', '--supersede', metavar='SUPERSEDE', + help='Superseding another request by this one') + @cmdln.option('--nodevelproject', action='store_true', + help='do not follow a defined devel project ' \ + '(primary project where a package is developed)') + @cmdln.option('--cleanup', action='store_true', + help='remove package if submission gets accepted (default for home::branch projects)') + @cmdln.option('--no-cleanup', action='store_true', + help='never remove source package on accept, but update its content') + @cmdln.option('--no-update', action='store_true', + help='never touch source package on accept (will break source links)') + @cmdln.option('-d', '--diff', action='store_true', + help='show diff only instead of creating the actual request') + @cmdln.option('--yes', action='store_true', + help='proceed without asking.') + @cmdln.alias("creq") + def do_createrequest(self, subcmd, opts, *args): + """${cmd_name}: create multiple requests with a single command + + usage: + osc creq [OPTIONS] [ + -a submit SOURCEPRJ SOURCEPKG DESTPRJ [DESTPKG] + -a delete PROJECT [PACKAGE] + -a change_devel PROJECT PACKAGE DEVEL_PROJECT [DEVEL_PACKAGE] + -a add_role USER ROLE PROJECT [PACKAGE] + -a set_bugowner USER PROJECT [PACKAGE] + ] + + Option -m works for all types of request, the rest work only for submit. + example: + osc creq -a submit -a delete home:someone:branches:openSUSE:Tools -a change_devel openSUSE:Tools osc home:someone:branches:openSUSE:Tools -m ok + + This will submit all modified packages under current directory, delete project home:someone:branches:openSUSE:Tools and change the devel project to home:someone:branches:openSUSE:Tools for package osc in project openSUSE:Tools. + ${cmd_option_list} + """ + src_update = conf.config['submitrequest_on_accept_action'] or None + # we should check here for home::branch and default to update, but that would require OBS 1.7 server + if opts.cleanup: + src_update = "cleanup" + elif opts.no_cleanup: + src_update = "update" + elif opts.no_update: + src_update = "noupdate" + + options_block="" + if src_update: + options_block="""%s """ % (src_update) + + args = slash_split(args) + + apiurl = self.get_api_url() + + i = 0 + actionsxml = "" + for ai in opts.actions: + if ai == 'submit': + args = opts.actiondata[i] + i = i+1 + actionsxml += self._submit_request(args,opts, options_block) + elif ai == 'delete': + args = opts.actiondata[i] + actionsxml += self._delete_request(args,opts) + i = i+1 + elif ai == 'change_devel': + args = opts.actiondata[i] + actionsxml += self._changedevel_request(args,opts) + i = i+1 + elif ai == 'add_role': + args = opts.actiondata[i] + actionsxml += self._add_role(args,opts) + i = i+1 + elif ai == 'set_bugowner': + args = opts.actiondata[i] + actionsxml += self._set_bugowner(args,opts) + i = i+1 + else: + raise oscerr.WrongArgs('Unsupported action %s' % ai) + if actionsxml == "": + sys.exit('No actions need to be taken.') + + if not opts.message: + opts.message = edit_message() + + import cgi + xml = """ %s %s """ % \ + (actionsxml, cgi.escape(opts.message or "")) + u = makeurl(apiurl, ['request'], query='cmd=create') + f = http_POST(u, data=xml) + + root = ET.parse(f).getroot() + return root.get('id') + @cmdln.option('-m', '--message', metavar='TEXT', help='specify message TEXT') diff --git a/osc/core.py b/osc/core.py old mode 100644 new mode 100755 index d50d91a4..ac7a86c1 --- a/osc/core.py +++ b/osc/core.py @@ -1741,7 +1741,7 @@ class Request: def __str__(self): action_list="" for action in self.actions: - action_list=" %s: " % (action.type) + action_list=action_list+" %s: " % (action.type) if action.type=="submit": r="" if action.src_rev: