Hello, attached are two patches.
Patch 1: softwarechannel_sync sync the contents of two software-channels. While the existing softwarechannel_clone creates a new channel, softwarechannel_sync copies the contents from one existing channel into another. Patch 2: configchannel_sync the same for configchannels. Besides other things, these functions can be used, when working with different stages like development and production to copy the content from one channel to the other. regards, Jörg -- Jörg Steffens joerg.steff...@dass-it.de dass IT GmbH Phone: +49.221.3565666-91 http://www.dass-IT.de Fax: +49.221.3565666-10 Sitz der Gesellschaft: Köln | Amtsgericht Köln: HRB52500 Geschäftsführer: S. Dühr, M. Außendorf, Jörg Steffens, P. Storz
>From c78e91703ed17fb9c81670b0ab77ec73a26ef30f Mon Sep 17 00:00:00 2001 From: Joerg Steffens <joerg.steff...@dass-it.de> Date: Sun, 10 Jun 2012 15:45:23 +0200 Subject: [PATCH 1/2] spacecmd : enhancement add softwarechannel_sync --- spacecmd/src/lib/softwarechannel.py | 102 ++++++++++++++++++++++++++++++++++- 1 files changed, 98 insertions(+), 0 deletions(-) diff --git a/spacecmd/src/lib/softwarechannel.py b/spacecmd/src/lib/softwarechannel.py index a4e0598..786b417 100644 --- a/spacecmd/src/lib/softwarechannel.py +++ b/spacecmd/src/lib/softwarechannel.py @@ -1475,4 +1475,102 @@ def do_softwarechannel_diff(self, args): return diff( source_data, target_data, source_channel, target_channel ) +#################### + +def help_softwarechannel_sync(self): + print 'softwarechannel_sync: ' + print 'sync the packages of two software channels' + print '' + print 'usage: softwarechannel_sync SOURCE_CHANNEL TARGET_CHANNEL' + +def complete_softwarechannel_sync(self, text, line, beg, end): + parts = shlex.split(line) + if line[-1] == ' ': parts.append('') + args = len(parts) + + if args == 2: + return tab_completer(self.do_softwarechannel_list('', True), text) + if args == 3: + return tab_completer(self.do_softwarechannel_list('', True), text) + return [] + +def do_softwarechannel_sync(self, args): + options = [] + + (args, options) = parse_arguments(args, options) + + if len(args) != 1 and len(args) != 2: + self.help_softwarechannel_sync() + return + + source_channel = args[0] + if not self.check_softwarechannel( source_channel ): return + + target_channel = None + if len(args) == 2: + target_channel = args[1] + elif hasattr( self, "do_softwarechannel_getcorresponding" ): + # can a corresponding channel name be found automatically? + target_channel=self.do_softwarechannel_getcorresponding( source_channel) + if not self.check_softwarechannel( target_channel ): return + + logging.info( "syncing packages from softwarechannel "+source_channel+" to "+target_channel ) + + # use API call instead of spacecmd function + # to get detailed infos about the packages + # and not just there names + source_packages = self.client.channel.software.listAllPackages(self.session, + source_channel) + target_packages = self.client.channel.software.listAllPackages(self.session, + target_channel) + + # get the package IDs + source_package_ids = set() + for package in source_packages: + try: + source_package_ids.add(package['id']) + except KeyError: + logging.error( "failed to read key id" ) + continue + + target_package_ids = set() + for package in target_packages: + try: + target_package_ids.add(package['id']) + except KeyError: + logging.error( "failed to read key id" ) + continue + + print "packages common in both channels:" + for i in ( source_package_ids & target_package_ids ): + print self.get_package_name( i ) + print + + # check for packages only in the source channel + source_only = source_package_ids.difference(target_package_ids) + if source_only: + print 'packages to add to channel "' + target_channel + '":' + for i in source_only: + print self.get_package_name( i ) + print + + + # check for packages only in the target channel + target_only=target_package_ids.difference( source_package_ids ) + if target_only: + print 'packages to remove from channel "' + target_channel + '":' + for i in target_only: + print self.get_package_name( i ) + print + + if source_only or target_only: + if not self.user_confirm('Perform these changes to channel ' + target_channel + ' [y/N]:'): return + + self.client.channel.software.addPackages(self.session, + target_channel, + list(source_only) ) + self.client.channel.software.removePackages(self.session, + target_channel, + list(target_only) ) + # vim:ts=4:expandtab: -- 1.7.7
>From a00b22fe7e1fa00be32ff372d895067ec66c96ab Mon Sep 17 00:00:00 2001 From: Joerg Steffens <joerg.steff...@dass-it.de> Date: Sun, 10 Jun 2012 20:38:38 +0200 Subject: [PATCH 2/2] spacecmd : enhancement add configchannel_sync --- spacecmd/src/lib/configchannel.py | 126 +++++++++++++++++++++++++++++++++++++ 1 files changed, 126 insertions(+), 0 deletions(-) diff --git a/spacecmd/src/lib/configchannel.py b/spacecmd/src/lib/configchannel.py index 642e6b4..36ea376 100644 --- a/spacecmd/src/lib/configchannel.py +++ b/spacecmd/src/lib/configchannel.py @@ -1204,4 +1204,130 @@ def do_configchannel_diff(self, args): return diff( source_data, target_data, source_channel, target_channel ) +#################### + +def help_configchannel_sync(self): + print 'configchannel_sync:' + print 'sync config files between two config channels' + print '' + print 'usage: configchannel_sync SOURCE_CHANNEL TARGET_CHANNEL' + +def complete_configchannel_sync(self, text, line, beg, end): + parts = shlex.split(line) + if line[-1] == ' ': parts.append('') + args = len(parts) + + if args == 2: + return tab_completer(self.do_configchannel_list('', True), text) + if args == 3: + return tab_completer(self.do_configchannel_list('', True), text) + return [] + +def do_configchannel_sync(self, args, doreturn = False): + options = [] + + (args, options) = parse_arguments(args, options) + + if len(args) != 1 and len(args) != 2: + self.help_configchannel_sync() + return + + source_channel = args[0] + if not self.check_configchannel( source_channel ): return + + target_channel = None + if len(args) == 2: + target_channel = args[1] + elif hasattr( self, "do_configchannel_getcorresponding" ): + # can a corresponding channel name be found automatically? + target_channel=self.do_configchannel_getcorresponding( source_channel) + if not self.check_configchannel( target_channel ): return + + logging.info( "syncing files from configchannel "+source_channel+" to "+target_channel ) + + source_files = set( self.do_configchannel_listfiles( source_channel, doreturn = True ) ) + target_files = set( self.do_configchannel_listfiles( target_channel, doreturn = True ) ) + + both=source_files & target_files + if both: + print "files common in both channels:" + print "\n".join( both ) + print + + source_only=source_files.difference( target_files ) + if source_only: + print "files only in source "+source_channel + print "\n".join( source_only ) + print + + target_only=target_files.difference( source_files ) + if target_only: + print "files only in target "+target_channel + print "\n".join( target_only ) + print + + if both: + print "files that are in both channels will be overwritten in the target channel" + if source_only: + print "files only in the source channel will be added to the target channel" + if target_only: + print "files only in the target channel will be deleted" + + if not (both or source_only or target_only): + logging.info( "nothing to do" ) + return + + if not self.user_confirm('perform synchronisation [y/N]:'): return + + source_data_list = self.client.configchannel.lookupFileInfo(\ + self.session, source_channel, + list( both ) + list(source_only) ) + + for source_data in source_data_list: + if source_data.get('type') == 'file' or source_data.get('type') == 'directory': + if source_data.get('contents') and not source_data.get('binary'): + contents = source_data.get('contents').encode('base64') + else: + contents = source_data.get('contents') + target_data = { + 'contents': contents, + 'contents_enc64': True, + 'owner': source_data.get('owner'), + 'group': source_data.get('group'), + # get permissions from permissions_mode instead of permissions + 'permissions': source_data.get('permissions_mode'), + 'selinux_ctx': source_data.get('selinux_ctx'), + 'macro-start-delimiter': source_data.get('macro-start-delimiter'), + 'macro-end-delimiter': source_data.get('macro-end-delimiter'), + } + for k,v in target_data.items(): + if not v: + del target_data[k] + logging.debug( source_data.get('path') + ": " + str(target_data) ) + self.client.configchannel.createOrUpdatePath(self.session, + target_channel, + source_data.get('path'), + source_data.get('type') == 'directory', + target_data) + + elif source_data.get('type') == 'symlink': + target_data = { + 'target_path': source_data.get('target_path'), + 'selinux_ctx': source_data.get('selinux_ctx'), + } + logging.debug( source_data.get('path') + ": " + str(target_data) ) + self.client.configchannel.createOrUpdateSymlink(self.session, + target_channel, + source_data.get('path'), + target_data ) + + else: + logging.warning( "unknown file type " + source_data.type ) + + + # removing all files from target channel that did not exist on source channel + if target_only: + #self.do_configchannel_removefiles( target_channel + " " + "/.metainfo" + " ".join(target_only) ) + self.do_configchannel_removefiles( target_channel + " " + " ".join(target_only) ) + # vim:ts=4:expandtab: -- 1.7.7
_______________________________________________ Spacewalk-devel mailing list Spacewalk-devel@redhat.com https://www.redhat.com/mailman/listinfo/spacewalk-devel