diff --git a/osc/commandline.py b/osc/commandline.py
index 1d61eabc..5cb218cb 100644
--- a/osc/commandline.py
+++ b/osc/commandline.py
@@ -1235,6 +1235,8 @@ class Osc(cmdln.Cmdln):
help='Try to remove also all repositories building against remove ones.')
@cmdln.option('-s', '--set', metavar='ATTRIBUTE_VALUES',
help='set attribute values')
+ @cmdln.option('--add', metavar='ATTRIBUTE_VALUES',
+ help='add to the existing attribute values')
@cmdln.option('--delete', action='store_true',
help='delete a pattern or attribute')
def do_meta(self, subcmd, opts, *args):
@@ -1306,6 +1308,9 @@ class Osc(cmdln.Cmdln):
if len(args) > max_args:
raise oscerr.WrongArgs('Too many arguments.')
+ if opts.add and opts.set:
+ self.argparse_error("Options --add and --set are mutually exclusive")
+
apiurl = self.get_api_url()
# Specific arguments
@@ -1369,7 +1374,7 @@ class Osc(cmdln.Cmdln):
raise oscerr.WrongOptions('options --revision and --message are only supported for the prj or prjconf subcommand')
# show
- if not opts.edit and not opts.file and not opts.delete and not opts.create and not opts.set:
+ if not opts.edit and not opts.file and not opts.delete and not opts.create and not opts.set and not opts.add:
if cmd == 'prj':
sys.stdout.write(decode_it(b''.join(show_project_meta(apiurl, project, rev=opts.revision, blame=opts.blame))))
elif cmd == 'pkg':
@@ -1445,16 +1450,33 @@ class Osc(cmdln.Cmdln):
template_args=None)
# create attribute entry
- if (opts.create or opts.set) and cmd == 'attribute':
+ if (opts.create or opts.set or opts.add) and cmd == 'attribute':
if not opts.attribute:
raise oscerr.WrongOptions('no attribute given to create')
- values = ''
- if opts.set:
- for i in opts.set.split(','):
- values += '%s' % _private.api.xml_escape(i)
+
aname = opts.attribute.split(":")
if len(aname) != 2:
raise oscerr.WrongOptions('Given attribute is not in "NAMESPACE:NAME" style')
+
+ values = ''
+
+ if opts.add:
+ # read the existing values from server
+ root = _private.api.get(apiurl, attributepath)
+ nodes = _private.api.find_nodes(root, "attributes", "attribute", {"namespace": aname[0], "name": aname[1]}, "value")
+ for node in nodes:
+ # append the existing values
+ value = _private.api.xml_escape(node.text)
+ values += f"{value}"
+
+ # pretend we're setting values in order to append the values we have specified on the command-line,
+ # because OBS API doesn't support extending the value list directly
+ opts.set = opts.add
+
+ if opts.set:
+ for i in opts.set.split(','):
+ values += '%s' % _private.api.xml_escape(i)
+
d = '%s' % (aname[0], aname[1], values)
url = makeurl(apiurl, attributepath)
for data in streamfile(url, http_POST, data=d):