| |
@@ -3377,6 +3377,9 @@
|
| |
"the dest tag"))
|
| |
parser.add_option('--ts', type='int', metavar="TIMESTAMP",
|
| |
help=_('Clone tag at last event before specific timestamp'))
|
| |
+ parser.add_option('--no-delete', action='store_false', dest="delete",
|
| |
+ default=True,
|
| |
+ help=_("Don't delete any existing content in dest tag."))
|
| |
parser.add_option('--event', type='int',
|
| |
help=_('Clone tag at a specific event'))
|
| |
parser.add_option('--repo', type='int',
|
| |
@@ -3526,6 +3529,8 @@
|
| |
inherited=True):
|
| |
dstpkgs[pkg['package_name']] = pkg
|
| |
if options.builds:
|
| |
+ # listTagged orders builds latest-first
|
| |
+ # so reversing that gives us oldest-first
|
| |
for build in reversed(session.listTagged(srctag['id'],
|
| |
event=event.get('id'),
|
| |
inherit=options.inherit_builds,
|
| |
@@ -3557,26 +3562,46 @@
|
| |
pdellist.sort(key=lambda x: x['package_name'])
|
| |
baddlist = [] # list containing new builds to be added from src tag
|
| |
bdellist = [] # list containing new builds to be removed from dst tag
|
| |
- for (pkg, dstblds) in six.iteritems(dstbldsbypkg):
|
| |
- if pkg not in srcbldsbypkg:
|
| |
- bdellist.extend(dstblds.values())
|
| |
+ if options.delete:
|
| |
+ # remove builds for packages that are absent from src tag
|
| |
+ for (pkg, dstblds) in six.iteritems(dstbldsbypkg):
|
| |
+ if pkg not in srcbldsbypkg:
|
| |
+ bdellist.extend(dstblds.values())
|
| |
+ # add and/or remove builds from dst to match src contents and order
|
| |
for (pkg, srcblds) in six.iteritems(srcbldsbypkg):
|
| |
dstblds = dstbldsbypkg[pkg]
|
| |
ablds = []
|
| |
dblds = []
|
| |
- # firstly, remove builds from dst tag
|
| |
+ # firstly, deal with extra builds in dst
|
| |
removed_nvrs = set(dstblds.keys()) - set(srcblds.keys())
|
| |
- dnvrs = []
|
| |
- for (dstnvr, dstbld) in six.iteritems(dstblds):
|
| |
- if dstnvr in removed_nvrs:
|
| |
- dnvrs.append(dstnvr)
|
| |
- dblds.append(dstbld)
|
| |
- for dnvr in dnvrs:
|
| |
- del dstblds[dnvr]
|
| |
+ bld_order = srcblds.copy()
|
| |
+ if options.delete:
|
| |
+ # mark the extra builds for deletion
|
| |
+ dnvrs = []
|
| |
+ for (dstnvr, dstbld) in six.iteritems(dstblds):
|
| |
+ if dstnvr in removed_nvrs:
|
| |
+ dnvrs.append(dstnvr)
|
| |
+ dblds.append(dstbld)
|
| |
+ # we also remove them from dstblds now so that they do not
|
| |
+ # interfere with the order comparison below
|
| |
+ for dnvr in dnvrs:
|
| |
+ del dstblds[dnvr]
|
| |
+ else:
|
| |
+ # in the no-delete case, the extra builds should be forced
|
| |
+ # to last in the tag
|
| |
+ bld_order = OrderedDict()
|
| |
+ for (dstnvr, dstbld) in six.iteritems(dstblds):
|
| |
+ if dstnvr in removed_nvrs:
|
| |
+ bld_order[dstnvr] = dstbld
|
| |
+ for (nvr, srcbld) in six.iteritems(srcblds):
|
| |
+ bld_order[nvr] = srcbld
|
| |
# secondly, add builds from src tag and adjust the order
|
| |
- for (nvr, srcbld) in six.iteritems(srcblds):
|
| |
+ for (nvr, srcbld) in six.iteritems(bld_order):
|
| |
found = False
|
| |
out_of_order = []
|
| |
+ # note that dstblds is trimmed as we go, so we are only
|
| |
+ # considering the tail corresponding to where we are at
|
| |
+ # in the srcblds loop
|
| |
for (dstnvr, dstbld) in six.iteritems(dstblds):
|
| |
if nvr == dstnvr:
|
| |
found = True
|
| |
@@ -3592,11 +3617,13 @@
|
| |
# loop
|
| |
del dstblds[nvr]
|
| |
else:
|
| |
+ # missing from dst, so we need to add it
|
| |
ablds.append(srcbld)
|
| |
baddlist.extend(ablds)
|
| |
bdellist.extend(dblds)
|
| |
baddlist.sort(key=lambda x: x['package_name'])
|
| |
bdellist.sort(key=lambda x: x['package_name'])
|
| |
+
|
| |
gaddlist = [] # list containing new groups to be added from src tag
|
| |
for (grpname, group) in six.iteritems(srcgroups):
|
| |
if grpname not in dstgroups:
|
| |
@@ -3715,103 +3742,104 @@
|
| |
force=options.force)
|
| |
if not options.test:
|
| |
session.multiCall(batch=options.batch)
|
| |
- # DEL packages.
|
| |
- ninhrtpdellist = []
|
| |
- inhrtpdellist = []
|
| |
- for pkg in pdellist:
|
| |
- if pkg['tag_name'] == dsttag['name']:
|
| |
- ninhrtpdellist.append(pkg)
|
| |
- else:
|
| |
- inhrtpdellist.append(pkg)
|
| |
- session.multicall = True
|
| |
- # delete only non-inherited packages.
|
| |
- for pkg in ninhrtpdellist:
|
| |
- # check if package have owned builds inside.
|
| |
- session.listTagged(dsttag['name'],
|
| |
- package=pkg['package_name'],
|
| |
- inherit=False)
|
| |
- bump_builds = session.multiCall(batch=options.batch)
|
| |
- if not options.test:
|
| |
+ if options.delete:
|
| |
+ # DEL packages
|
| |
+ ninhrtpdellist = []
|
| |
+ inhrtpdellist = []
|
| |
+ for pkg in pdellist:
|
| |
+ if pkg['tag_name'] == dsttag['name']:
|
| |
+ ninhrtpdellist.append(pkg)
|
| |
+ else:
|
| |
+ inhrtpdellist.append(pkg)
|
| |
session.multicall = True
|
| |
- for pkg, [builds] in zip(ninhrtpdellist, bump_builds):
|
| |
- # remove all its builds first if there are any.
|
| |
- for build in builds:
|
| |
- # add missing 'name' field.
|
| |
- build['name'] = build['package_name']
|
| |
- chgbldlist.append(('[del]',
|
| |
- build['package_name'],
|
| |
- build['nvr'],
|
| |
- koji.BUILD_STATES[build['state']],
|
| |
- build['owner_name'],
|
| |
- build['tag_name']))
|
| |
- # so delete latest build(s) from new tag.
|
| |
- if not options.test:
|
| |
- session.untagBuildBypass(dsttag['name'],
|
| |
- build,
|
| |
- force=options.force,
|
| |
- notify=options.notify)
|
| |
- # now safe to remove package itself since we resolved its builds.
|
| |
- chgpkglist.append(('[del]',
|
| |
- pkg['package_name'],
|
| |
- pkg['blocked'],
|
| |
- pkg['owner_name'],
|
| |
- pkg['tag_name']))
|
| |
- if not options.test:
|
| |
- session.packageListRemove(dsttag['name'],
|
| |
- pkg['package_name'],
|
| |
- force=False)
|
| |
- # mark as blocked inherited packages.
|
| |
- for pkg in inhrtpdellist:
|
| |
- chgpkglist.append(('[blk]',
|
| |
- pkg['package_name'],
|
| |
- pkg['blocked'],
|
| |
- pkg['owner_name'],
|
| |
- pkg['tag_name']))
|
| |
+ # delete only non-inherited packages.
|
| |
+ for pkg in ninhrtpdellist:
|
| |
+ # check if package have owned builds inside.
|
| |
+ session.listTagged(dsttag['name'],
|
| |
+ package=pkg['package_name'],
|
| |
+ inherit=False)
|
| |
+ bump_builds = session.multiCall(batch=options.batch)
|
| |
if not options.test:
|
| |
- session.packageListBlock(dsttag['name'], pkg['package_name'])
|
| |
- if not options.test:
|
| |
- session.multiCall(batch=options.batch)
|
| |
- # DEL groups.
|
| |
- if not options.test:
|
| |
- session.multicall = True
|
| |
- for group in gdellist:
|
| |
- # Only delete a group that isn't inherited
|
| |
- if group['tag_id'] == dsttag['id']:
|
| |
+ session.multicall = True
|
| |
+ for pkg, [builds] in zip(ninhrtpdellist, bump_builds):
|
| |
+ # remove all its builds first if there are any.
|
| |
+ for build in builds:
|
| |
+ # add missing 'name' field.
|
| |
+ build['name'] = build['package_name']
|
| |
+ chgbldlist.append(('[del]',
|
| |
+ build['package_name'],
|
| |
+ build['nvr'],
|
| |
+ koji.BUILD_STATES[build['state']],
|
| |
+ build['owner_name'],
|
| |
+ build['tag_name']))
|
| |
+ # so delete latest build(s) from new tag.
|
| |
+ if not options.test:
|
| |
+ session.untagBuildBypass(dsttag['name'],
|
| |
+ build,
|
| |
+ force=options.force,
|
| |
+ notify=options.notify)
|
| |
+ # now safe to remove package itself since we resolved its builds.
|
| |
+ chgpkglist.append(('[del]',
|
| |
+ pkg['package_name'],
|
| |
+ pkg['blocked'],
|
| |
+ pkg['owner_name'],
|
| |
+ pkg['tag_name']))
|
| |
if not options.test:
|
| |
- session.groupListRemove(dsttag['name'],
|
| |
- group['name'],
|
| |
- force=options.force)
|
| |
- for pkg in group['packagelist']:
|
| |
- chggrplist.append(('[del]', pkg['package'], group['name']))
|
| |
- # mark as blocked inherited groups.
|
| |
- else:
|
| |
+ session.packageListRemove(dsttag['name'],
|
| |
+ pkg['package_name'],
|
| |
+ force=False)
|
| |
+ # mark as blocked inherited packages.
|
| |
+ for pkg in inhrtpdellist:
|
| |
+ chgpkglist.append(('[blk]',
|
| |
+ pkg['package_name'],
|
| |
+ pkg['blocked'],
|
| |
+ pkg['owner_name'],
|
| |
+ pkg['tag_name']))
|
| |
if not options.test:
|
| |
- session.groupListBlock(dsttag['name'], group['name'])
|
| |
- for pkg in group['packagelist']:
|
| |
- chggrplist.append(('[blk]', pkg['package'], group['name']))
|
| |
- if not options.test:
|
| |
- session.multiCall(batch=options.batch)
|
| |
- # DEL group pkgs.
|
| |
- if not options.test:
|
| |
- session.multicall = True
|
| |
- for group in grpchanges:
|
| |
- for pkg in grpchanges[group]['dels']:
|
| |
+ session.packageListBlock(dsttag['name'], pkg['package_name'])
|
| |
+ if not options.test:
|
| |
+ session.multiCall(batch=options.batch)
|
| |
+ # DEL groups.
|
| |
+ if not options.test:
|
| |
+ session.multicall = True
|
| |
+ for group in gdellist:
|
| |
# Only delete a group that isn't inherited
|
| |
- if not grpchanges[group]['inherited']:
|
| |
- chggrplist.append(('[del]', pkg, group))
|
| |
+ if group['tag_id'] == dsttag['id']:
|
| |
if not options.test:
|
| |
- session.groupPackageListRemove(dsttag['name'],
|
| |
- group,
|
| |
- pkg,
|
| |
- force=options.force)
|
| |
+ session.groupListRemove(dsttag['name'],
|
| |
+ group['name'],
|
| |
+ force=options.force)
|
| |
+ for pkg in group['packagelist']:
|
| |
+ chggrplist.append(('[del]', pkg['package'], group['name']))
|
| |
+ # mark as blocked inherited groups.
|
| |
else:
|
| |
- chggrplist.append(('[blk]', pkg, group))
|
| |
if not options.test:
|
| |
- session.groupPackageListBlock(dsttag['name'],
|
| |
- group,
|
| |
- pkg)
|
| |
- if not options.test:
|
| |
- session.multiCall(batch=options.batch)
|
| |
+ session.groupListBlock(dsttag['name'], group['name'])
|
| |
+ for pkg in group['packagelist']:
|
| |
+ chggrplist.append(('[blk]', pkg['package'], group['name']))
|
| |
+ if not options.test:
|
| |
+ session.multiCall(batch=options.batch)
|
| |
+ # DEL group pkgs.
|
| |
+ if not options.test:
|
| |
+ session.multicall = True
|
| |
+ for group in grpchanges:
|
| |
+ for pkg in grpchanges[group]['dels']:
|
| |
+ # Only delete a group that isn't inherited
|
| |
+ if not grpchanges[group]['inherited']:
|
| |
+ chggrplist.append(('[del]', pkg, group))
|
| |
+ if not options.test:
|
| |
+ session.groupPackageListRemove(dsttag['name'],
|
| |
+ group,
|
| |
+ pkg,
|
| |
+ force=options.force)
|
| |
+ else:
|
| |
+ chggrplist.append(('[blk]', pkg, group))
|
| |
+ if not options.test:
|
| |
+ session.groupPackageListBlock(dsttag['name'],
|
| |
+ group,
|
| |
+ pkg)
|
| |
+ if not options.test:
|
| |
+ session.multiCall(batch=options.batch)
|
| |
# print final list of actions.
|
| |
if options.verbose:
|
| |
pfmt = ' %-7s %-28s %-10s %-10s %-10s\n'
|
| |
Question is if not blocking packages (or just not deleting) is what user expects.