-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hello,
I've created some extensions for spacecmd to provide a way to handle different stages like - - development - - staging - - production This is done by following functions: def do_stage_create_skel def do_stage_softwarechannel_diff def do_stage_softwarechannel_sync def do_stage_configchannel_diff def do_stage_configchannel_sync def do_stage_kickstart_diff def do_stage_activationkey_diff def do_stage_status def do_stage_dump As my initial approach (https://bugzilla.redhat.com/show_bug.cgi?id=781883) did not make it into spacecmd, so now I'm now trying to add parts of the functionality as smaller patches. First, I've a question about ret Most of my changes are none intrusive, however there is a behavior of spacecmd I'd like to change: currently, the do-functions normally have no return values at all. Because some of these functions are used by other function, a lot of them have an additional parameter "doreturn = False". If this is set to true, the result is not printed to stdout, but instead return as list of strings. As a results, some code inside the do-functions is duplicated. Because the new functionality I've created uses some functions that currently do not provide a way to return there results, I'd like to suggest following approach: instead of doing this differentiation inside each function, the functions should always return there result as list of strings. If printing is required, meaning, the function is not called from outside and not from another function, the printing is done by shell.py:postcmd, which will be called after all commands called from command line. If a function return a list of string, these will be printed to stdout. If not, it behaves like before. There is no immediate need to change the existing function, but of course, this would make the code cleaner. I've implemented this in patch TODO. Additionaly, I've implemented the functions activationkey.py:def do_activationkey_diff configchannel.py:def do_configchannel_diff kickstart.py:def do_kickstart_diff softwarechannel.py:def do_softwarechannel_diff to show differences in between two components. I'd be glad, if this patches will be applied to spacecmd. regards, Jörg Steffens - -- 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 -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.18 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAk+sKDwACgkQebMQ0f2L2xuYowCgkjr2AMzJ8gMDA3RRB1e8A+1S TPIAnRWKjya9H0+V2zyyBtKVtZ6ApALR =EMo5 -----END PGP SIGNATURE-----
From: Joerg Steffens <joerg.steff...@dass-it.de> Date: Thu, 10 May 2012 21:21:08 +0200 Subject: [PATCH] print return values --- diff --git a/spacecmd/src/bin/spacecmd b/spacecmd/src/bin/spacecmd index 6b11f5b..29970ab 100755 --- a/spacecmd/src/bin/spacecmd +++ b/spacecmd/src/bin/spacecmd @@ -122,7 +122,8 @@ if __name__ == '__main__': command += ' %s' % ' '.join("'%s'" % s for s in args[1:]) # run the command - shell.onecmd(shell.precmd(command)) + precmd = shell.precmd(command) + shell.print_result(shell.onecmd( precmd ), precmd) except KeyboardInterrupt: print print 'User Interrupt' diff --git a/spacecmd/src/lib/shell.py b/spacecmd/src/lib/shell.py index 15b7277..08e4d33 100644 --- a/spacecmd/src/lib/shell.py +++ b/spacecmd/src/lib/shell.py @@ -188,7 +188,18 @@ class SpacewalkShell(Cmd): # update the prompt with the SSM size - def postcmd(self, stop, line): + def postcmd(self, cmdresult, cmd): + self.print_result( cmdresult, cmd ) self.prompt = re.sub('##', str(len(self.ssm)), self.prompt_template) + def print_result( self, cmdresult, cmd ): + logging.debug( cmd + ": " + repr(cmdresult) ) + if cmd: + try: + for i in cmdresult: + print i + except TypeError: + pass + + # vim:ts=4:expandtab:
From: Joerg Steffens <joerg.steff...@dass-it.de> Date: Thu, 10 May 2012 21:21:08 +0200 Subject: [PATCH] add do_SPACEWALKCOMPONENT_diff functions --- diff --git a/spacecmd/src/lib/activationkey.py b/spacecmd/src/lib/activationkey.py index 2910333..41406ee 100644 --- a/spacecmd/src/lib/activationkey.py +++ b/spacecmd/src/lib/activationkey.py @@ -743,6 +743,7 @@ def do_activationkey_details(self, args): add_separator = False + result = [] for key in args: try: details = self.client.activationkey.getDetails(self.session, @@ -780,46 +781,47 @@ def do_activationkey_details(self, args): if add_separator: print self.SEPARATOR add_separator = True - print 'Key: %s' % details.get('key') - print 'Description: %s' % details.get('description') - print 'Universal Default: %s' % details.get('universal_default') - print 'Usage Limit: %s' % details.get('usage_limit') - print 'Deploy Config Channels: %s' % config_channel_deploy + result.append( 'Key: %s' % details.get('key') ) + result.append( 'Description: %s' % details.get('description') ) + result.append( 'Universal Default: %s' % details.get('universal_default') ) + result.append( 'Usage Limit: %s' % details.get('usage_limit') ) + result.append( 'Deploy Config Channels: %s' % config_channel_deploy ) - print - print 'Software Channels' - print '-----------------' - print details.get('base_channel_label') + result.append( '' ) + result.append( 'Software Channels' ) + result.append( '-----------------' ) + result.append( details.get('base_channel_label') ) for channel in sorted(details.get('child_channel_labels')): - print ' |-- %s' % channel + result.append( ' |-- %s' % channel ) - print - print 'Configuration Channels' - print '----------------------' + result.append( '' ) + result.append( 'Configuration Channels' ) + result.append( '----------------------' ) for channel in config_channels: - print channel.get('label') + result.append( channel.get('label') ) - print - print 'Entitlements' - print '------------' - print '\n'.join(sorted(details.get('entitlements'))) + result.append( '' ) + result.append( 'Entitlements' ) + result.append( '------------' ) + result.append( '\n'.join(sorted(details.get('entitlements'))) ) - print - print 'System Groups' - print '-------------' - print '\n'.join(sorted(groups)) + result.append( '' ) + result.append( 'System Groups' ) + result.append( '-------------' ) + result.append( '\n'.join(sorted(groups)) ) - print - print 'Packages' - print '--------' + result.append( '' ) + result.append( 'Packages' ) + result.append( '--------' ) for package in sorted(details.get('packages')): name = package.get('name') if package.get('arch'): name += '.%s' % package.get('arch') - print name + result.append( name ) + return result #################### @@ -1357,4 +1359,73 @@ def do_activationkey_clone(self, args): logging.error("Failed to clone %s to %s" % \ (ak, keydetails['key'])) +#################### +# activationkey helper + +def is_activationkey( self, name ): + if not name: return + return name in self.do_activationkey_list( name, True ) + +def check_activationkey( self, name ): + if not name: + logging.error( "no activationkey label given" ) + return False + if not self.is_activationkey( name ): + logging.error( "invalid activationkey label " + name ) + return False + return True + +def dump_activationkey(self, name, replacedict=None, excludes=[ "Universal Default:" ]): + content = self.do_activationkey_details( name ) + + content = get_normalized_text( content, replacedict=replacedict, excludes=excludes ) + + return content + +#################### + +def help_activationkey_diff(self): + print 'activationkeyt_diff: diff activationkeys' + print '' + print 'usage: activationkey_diff SOURCE_ACTIVATIONKEY TARGET_ACTIVATIONKEY' + +def complete_activationkey_diff(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_activationkey_list('', True), text) + if args == 3: + return tab_completer(self.do_activationkey_list('', True), text) + return [] + +def do_activationkey_diff(self, args): + options = [] + + (args, options) = parse_arguments(args, options) + + if len(args) != 1 and len(args) != 2: + self.help_activationkey_diff() + return + + source_channel = args[0] + if not self.check_activationkey( source_channel ): return + + target_channel = None + if len(args) == 2: + target_channel = args[1] + elif hasattr( self, "do_activationkey_getcorresponding" ): + # can a corresponding channel name be found automatically? + target_channel=self.do_activationkey_getcorresponding( source_channel ) + if not self.check_activationkey( target_channel ): return + + source_replacedict, target_replacedict = get_string_diff_dicts( source_channel, target_channel ) + + source_data = self.dump_activationkey( source_channel, source_replacedict ) + target_data = self.dump_activationkey( target_channel, target_replacedict ) + + return diff( source_data, target_data, source_channel, target_channel ) + + # vim:ts=4:expandtab: diff --git a/spacecmd/src/lib/configchannel.py b/spacecmd/src/lib/configchannel.py index 7410b95..884970a 100644 --- a/spacecmd/src/lib/configchannel.py +++ b/spacecmd/src/lib/configchannel.py @@ -153,32 +153,35 @@ def do_configchannel_filedetails(self, args): # grab the first item since we only do one file details = results[0] - print 'Path: %s' % details.get('path') - print 'Type: %s' % details.get('type') - print 'Revision: %i' % details.get('revision') - print 'Created: %s' % details.get('creation') - print 'Modified: %s' % details.get('modified') + result = [] + result.append( 'Path: %s' % details.get('path') ) + result.append( 'Type: %s' % details.get('type') ) + result.append( 'Revision: %i' % details.get('revision') ) + result.append( 'Created: %s' % details.get('creation') ) + result.append( 'Modified: %s' % details.get('modified') ) if details.get('type') == 'symlink': - print - print 'Target Path: %s' % details.get('target_path') + result.append( '' ) + result.append( 'Target Path: %s' % details.get('target_path') ) else: - print - print 'Owner: %s' % details.get('owner') - print 'Group: %s' % details.get('group') - print 'Mode: %s' % details.get('permissions_mode') + result.append( '' ) + result.append( 'Owner: %s' % details.get('owner') ) + result.append( 'Group: %s' % details.get('group') ) + result.append( 'Mode: %s' % details.get('permissions_mode') ) - print 'SELinux Context: %s' % details.get('selinux_ctx') + result.append( 'SELinux Context: %s' % details.get('selinux_ctx') ) if details.get('type') == 'file': - print 'MD5: %s' % details.get('md5') - print 'Binary: %s' % details.get('binary') + result.append( 'MD5: %s' % details.get('md5') ) + result.append( 'Binary: %s' % details.get('binary') ) if not details.get('binary'): - print - print 'Contents' - print '--------' - print details.get('contents') + result.append( '' ) + result.append( 'Contents' ) + result.append( '--------' ) + result.append( details.get('contents') ) + + return result #################### @@ -289,6 +292,7 @@ def do_configchannel_details(self, args): add_separator = False + result = [] for channel in args: details = self.client.configchannel.getDetails(self.session, channel) @@ -299,15 +303,16 @@ def do_configchannel_details(self, args): if add_separator: print self.SEPARATOR add_separator = True - print 'Label: %s' % details.get('label') - print 'Name: %s' % details.get('name') - print 'Description: %s' % details.get('description') + result.append( 'Label: %s' % details.get('label') ) + result.append( 'Name: %s' % details.get('name') ) + result.append( 'Description: %s' % details.get('description') ) - print - print 'Files' - print '-----' + result.append( '' ) + result.append( 'Files' ) + result.append( '-----' ) for f in files: - print f.get('path') + result.append( f.get('path') ) + return result #################### @@ -1100,4 +1105,79 @@ def do_configchannel_clone(self, args): logging.error("Failed to clone %s to %s" % \ (cc, ccdetails['label'])) +#################### +# configchannel helper + +def is_configchannel( self, name ): + if not name: return + return name in self.do_configchannel_list( name, True ) + +def check_configchannel( self, name ): + if not name: + logging.error( "no configchannel given" ) + return False + if not self.is_configchannel( name ): + logging.error( "invalid configchannel label " + name ) + return False + return True + +def dump_configchannel_filedetails(self, name, filename): + content = self.do_configchannel_filedetails( name +" "+ filename ) + return content + +def dump_configchannel(self, name, replacedict=None, excludes=[ "Revision:", "Created:", "Modified:" ]): + content = self.do_configchannel_details( name ) + + for filename in self.do_configchannel_listfiles(name, True): + content.extend( self.dump_configchannel_filedetails(name, filename) ) + + content = get_normalized_text( content, replacedict=replacedict, excludes=excludes ) + + return content + +#################### + +def help_configchannel_diff(self): + print 'configchannel_diff: diff between config channels' + print '' + print 'usage: configchannel_diff SOURCE_CHANNEL TARGET_CHANNEL' + +def complete_configchannel_diff(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_diff(self, args): + options = [] + + (args, options) = parse_arguments(args, options) + + if len(args) != 1 and len(args) != 2: + self.help_stage_configchannel_diff() + 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 + + source_replacedict, target_replacedict = get_string_diff_dicts( source_channel, target_channel ) + + source_data = self.dump_configchannel( source_channel, source_replacedict ) + target_data = self.dump_configchannel( target_channel, target_replacedict ) + + return diff( source_data, target_data, source_channel, target_channel ) + # vim:ts=4:expandtab: diff --git a/spacecmd/src/lib/kickstart.py b/spacecmd/src/lib/kickstart.py index fb51df5..ef622ec 100644 --- a/spacecmd/src/lib/kickstart.py +++ b/spacecmd/src/lib/kickstart.py @@ -287,8 +287,11 @@ def do_kickstart_details(self, args): self.client.kickstart.profile.keys.getActivationKeys(self.session, label) - variables = self.client.kickstart.profile.getVariables(self.session, - label) + try: + variables = self.client.kickstart.profile.getVariables(self.session, + label) + except: + variables = [] tree = \ self.client.kickstart.tree.getDetails(self.session, @@ -336,100 +339,103 @@ def do_kickstart_details(self, args): scripts = self.client.kickstart.profile.listScripts(self.session, label) - print 'Name: %s' % kickstart.get('name') - print 'Label: %s' % kickstart.get('label') - print 'Tree: %s' % kickstart.get('tree_label') - print 'Active: %s' % kickstart.get('active') - print 'Advanced: %s' % kickstart.get('advanced_mode') - print 'Org Default: %s' % kickstart.get('org_default') + result = [] + result.append( 'Name: %s' % kickstart.get('name') ) + result.append( 'Label: %s' % kickstart.get('label') ) + result.append( 'Tree: %s' % kickstart.get('tree_label') ) + result.append( 'Active: %s' % kickstart.get('active') ) + result.append( 'Advanced: %s' % kickstart.get('advanced_mode') ) + result.append( 'Org Default: %s' % kickstart.get('org_default') ) - print - print 'Configuration Management: %s' % config_manage - print 'Remote Commands: %s' % remote_commands + result.append( '' ) + result.append( 'Configuration Management: %s' % config_manage ) + result.append( 'Remote Commands: %s' % remote_commands ) - print - print 'Software Channels' - print '-----------------' - print base_channel.get('label') + result.append( '' ) + result.append( 'Software Channels' ) + result.append( '-----------------' ) + result.append( base_channel.get('label') ) for channel in sorted(child_channels): - print ' |-- %s' % channel + result.append( ' |-- %s' % channel ) if len(advanced_options): - print - print 'Advanced Options' - print '----------------' + result.append( '' ) + result.append( 'Advanced Options' ) + result.append( '----------------' ) for o in sorted(advanced_options, key=itemgetter('name')): if o.get('arguments'): - print '%s %s' % (o.get('name'), o.get('arguments')) + result.append( '%s %s' % (o.get('name'), o.get('arguments')) ) if len(custom_options): - print - print 'Custom Options' - print '--------------' + result.append( '' ) + result.append( 'Custom Options' ) + result.append( '--------------' ) for o in sorted(custom_options, key=itemgetter('arguments')): - print re.sub('\n', '', o.get('arguments')) + result.append( re.sub('\n', '', o.get('arguments')) ) if len(partitions): - print - print 'Partitioning' - print '------------' - print '\n'.join(partitions) + result.append( '' ) + result.append( 'Partitioning' ) + result.append( '------------' ) + result.append( '\n'.join(partitions) ) - print - print 'Software' - print '--------' - print '\n'.join(software) + result.append( '' ) + result.append( 'Software' ) + result.append( '--------' ) + result.append( '\n'.join(software) ) if len(act_keys): - print - print 'Activation Keys' - print '---------------' + result.append( '' ) + result.append( 'Activation Keys' ) + result.append( '---------------' ) for k in sorted(act_keys, key=itemgetter('key')): - print k.get('key') + result.append( k.get('key') ) if len(crypto_keys): - print - print 'Crypto Keys' - print '-----------' + result.append( '' ) + result.append( 'Crypto Keys' ) + result.append( '-----------' ) for k in sorted(crypto_keys, key=itemgetter('description')): - print k.get('description') + result.append( k.get('description') ) if len(file_preservations): - print - print 'File Preservations' - print '------------------' + result.append( '' ) + result.append( 'File Preservations' ) + result.append( '------------------' ) for fp in sorted(file_preservations, key=itemgetter('name')): - print fp.get('name') + result.append( fp.get('name') ) for profile_name in sorted(fp.get('file_names')): - print ' |-- %s' % profile_name + result.append( ' |-- %s' % profile_name ) if len(variables): - print - print 'Variables' - print '---------' + result.append( '' ) + result.append( 'Variables' ) + result.append( '---------' ) for k in sorted(variables.keys()): - print '%s = %s' % (k, str(variables[k])) + result.append( '%s = %s' % (k, str(variables[k])) ) if len(scripts): - print - print 'Scripts' - print '-------' + result.append( '' ) + result.append( 'Scripts' ) + result.append( '-------' ) add_separator = False for s in scripts: - if add_separator: print self.SEPARATOR + if add_separator: result.append( self.SEPARATOR ) add_separator = True - print 'Type: %s' % s.get('script_type') - print 'Chroot: %s' % s.get('chroot') + result.append( 'Type: %s' % s.get('script_type') ) + result.append( 'Chroot: %s' % s.get('chroot') ) if s.get('interpreter'): - print 'Interpreter: %s' % s.get('interpreter') + result.append( 'Interpreter: %s' % s.get('interpreter') ) - print - print s.get('contents') + result.append( '' ) + result.append( s.get('contents') ) + + return result #################### @@ -2136,4 +2142,72 @@ def import_kickstart_fromdetails(self, ksdetails): ksdetails['post_kopts']) return True +#################### +# kickstart helper + +def is_kickstart( self, name ): + if not name: return + return name in self.do_kickstart_list( name, True ) + +def check_kickstart( self, name ): + if not name: + logging.error( "no kickstart label given" ) + return False + if not self.is_kickstart( name ): + logging.error( "invalid kickstart label " + name ) + return False + return True + +def dump_kickstart(self, name, replacedict=None, excludes=[ "Org Default:" ]): + content = self.do_kickstart_details( name ) + + content = get_normalized_text( content, replacedict=replacedict, excludes=excludes ) + + return content + +#################### + +def help_kickstart_diff(self): + print 'kickstart_diff: diff kickstart files' + print '' + print 'usage: kickstart_diff SOURCE_CHANNEL TARGET_CHANNEL' + +def complete_kickstart_diff(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_kickstart_list('', True), text) + if args == 3: + return tab_completer(self.do_kickstart_list('', True), text) + return [] + +def do_kickstart_diff(self, args): + options = [] + + (args, options) = parse_arguments(args, options) + + if len(args) != 1 and len(args) != 2: + self.help_kickstart_diff() + return + + source_channel = args[0] + if not self.check_kickstart( source_channel ): return + + target_channel = None + if len(args) == 2: + target_channel = args[1] + elif hasattr( self, "do_kickstart_getcorresponding" ): + # can a corresponding channel name be found automatically? + target_channel=self.do_kickstart_getcorresponding( source_channel) + if not self.check_kickstart( target_channel ): return + + source_replacedict, target_replacedict = get_string_diff_dicts( source_channel, target_channel ) + + source_data = self.dump_kickstart( source_channel, source_replacedict ) + target_data = self.dump_kickstart( target_channel, target_replacedict ) + + return diff( source_data, target_data, source_channel, target_channel ) + # vim:ts=4:expandtab: diff --git a/spacecmd/src/lib/softwarechannel.py b/spacecmd/src/lib/softwarechannel.py index 48ddc0c..a4e0598 100644 --- a/spacecmd/src/lib/softwarechannel.py +++ b/spacecmd/src/lib/softwarechannel.py @@ -1399,7 +1399,7 @@ def do_softwarechannel_regenerateyumcache(self, args): if not len(args): self.help_softwarechannel_regenerateyumcache() return - + # allow globbing of software channel names channels = filter_results(self.do_softwarechannel_list('', True), args) @@ -1407,4 +1407,72 @@ def do_softwarechannel_regenerateyumcache(self, args): logging.debug('Regenerating YUM cache for %s' % channel) self.client.channel.software.regenerateYumCache(self.session, channel) +#################### +# softwarechannel helper + +def is_softwarechannel( self, name ): + if not name: return + return name in self.do_softwarechannel_list( name, True ) + +def check_softwarechannel( self, name ): + if not name: + logging.error( "no softwarechannel label given" ) + return False + if not self.is_softwarechannel( name ): + logging.error( "invalid softwarechannel label " + name ) + return False + return True + +def dump_softwarechannel(self, name, replacedict=None, excludes=[]): + content = self.do_softwarechannel_listallpackages( name, doreturn=True ) + + content = get_normalized_text( content, replacedict=replacedict, excludes=excludes ) + + return content + +#################### + +def help_softwarechannel_diff(self): + print 'softwarechannel_diff: diff softwarechannel files' + print '' + print 'usage: softwarechannel_diff SOURCE_CHANNEL TARGET_CHANNEL' + +def complete_softwarechannel_diff(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_diff(self, args): + options = [] + + (args, options) = parse_arguments(args, options) + + if len(args) != 1 and len(args) != 2: + self.help_softwarechannel_diff() + 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 + + # softwarechannel do not contain references to other components, + # therefore there is no need to use replace dicts + source_data = self.dump_softwarechannel( source_channel, None ) + target_data = self.dump_softwarechannel( target_channel, None ) + + return diff( source_data, target_data, source_channel, target_channel ) + # vim:ts=4:expandtab: diff --git a/spacecmd/src/lib/utils.py b/spacecmd/src/lib/utils.py index 6292f5a..0a7c4c5 100644 --- a/spacecmd/src/lib/utils.py +++ b/spacecmd/src/lib/utils.py @@ -23,6 +23,7 @@ import logging, os, pickle, re, readline, shlex, sys, time, xmlrpclib from datetime import datetime, timedelta +from difflib import unified_diff, SequenceMatcher from optparse import OptionParser from tempfile import mkstemp from textwrap import wrap @@ -633,6 +634,67 @@ def json_read_from_file(filename): print "could not open file %s for reading, check permissions?" % filename return None +def get_string_diff_dicts( string1, string2 ): + replace1 = {} + replace2 = {} + s = SequenceMatcher(None, string1, string2) + for tag, i1a, i1b, i2a, i2b in s.get_opcodes(): + sub1=string1[i1a:i1b] + sub2=string2[i2a:i2b] + if tag == "equal": + # equal, nothing to do + pass + elif tag == "replace": + replace1[sub1] = "DIFF("+sub1+"|"+sub2+")" + replace2[sub2] = "DIFF("+sub1+"|"+sub2+")" + else: + # "insert" or "delete" + # can't handle this + #logging.debug( "will not handle differences " + sub1 + sub2 ) + logging.debug( "Too many differences between " + string1 + " and " + string2 + ". Skipping usage of common strings." ) + return [None,None] + return [replace1,replace2] + +def replace( line, replacedict ): + if replacedict: + for source in replacedict: + line = line.replace( source, replacedict[source] ) + return line + +def get_normalized_text( text, replacedict=None, excludes=_DIFF_EXCLUDES ): + # parts of the data inside the spacewalk component information + # is not relevant for showing real differences between two instances. + # Therefore parts of the data will be modified before the real diff: + # - specific lines, starting with a defined keyword, will be excluded + # - specific character sequences will be replaced with the same text in both instances. + # Example: + # we want to compare two activationkeys from different stages: + # "1-rhel6-x86_64-dev" and "1-rhel6-x86_64-prd" + # ("dev" for "development" and "prd" for "production"). + # We assume that the "dev" activationkey "1-rhel6-x86_64-dev" + # has references to other "dev" components, + # while the "prd" activationkey "1-rhel6-x86_64-prd" + # has references to other "prd" components. + # Therefore we replace all occurrences of "dev" in "1-rhel6-x86_64-dev" + # and all occurrences of "prd" in "1-rhel6-x86_64-prd" + # with the common string "DIFF(dev|prd)". + # What differences are to be replaced is guessed + # from the name differences of there components. + # This will not work always, but it help in a lot of cases. + + normalized_text = [] + if text: + for string in text: + for line in string.split( "\n" ): + if not excludes or not line.startswith( tuple(excludes) ): + normalized_text.append( replace( line, replacedict ) ) + else: + logging.debug( "excluding line: " + line ) + return normalized_text + +def diff( source_data, target_data, source_channel, target_channel ): + return unified_diff( source_data, target_data, source_channel, target_channel ) + def file_needs_b64_enc(self, contents): # Used to check if files (config files primarily) need base64 encoding
_______________________________________________ Spacewalk-devel mailing list Spacewalk-devel@redhat.com https://www.redhat.com/mailman/listinfo/spacewalk-devel