From dce2a2da519d4ccb752de0da018599e97ce21f46 Mon Sep 17 00:00:00 2001 From: Fabian Groffen Date: Tue, 10 Apr 2007 15:34:22 +0000 Subject: [PATCH] " " -> "\t" Mixing them in Python is asking for trouble. In fact, even Python didn't know what to do with this file anymore. svn path=/main/branches/prefix/; revision=6365 --- bin/dispatch-conf | 628 +++++++++++++++++++++++----------------------- 1 file changed, 314 insertions(+), 314 deletions(-) diff --git a/bin/dispatch-conf b/bin/dispatch-conf index 2c9f25446..c4ef6d495 100755 --- a/bin/dispatch-conf +++ b/bin/dispatch-conf @@ -19,350 +19,350 @@ from stat import * from random import * import atexit, commands, os, re, shutil, stat, sys try: - import portage + import portage except ImportError: from os import path as osp sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) - import portage + import portage import dispatch_conf, portage_const from portage.process import find_binary FIND_EXTANT_CONFIGS = "find '%s' %s -iname '._cfg????_%s' ! -iname '.*~' ! -iname '.*.bak'" -DIFF_CONTENTS = 'diff -Nu %s %s' -DIFF_CVS_INTERP = 'diff -Nu %s %s | grep "^[+-][^+-]" | grep -v "# .Header:.*"' -DIFF_WSCOMMENTS = 'diff -Nu %s %s | grep "^[+-][^+-]" | grep -v "^[-+]#" | grep -v "^[-+][:space:]*$"' +DIFF_CONTENTS = 'diff -Nu %s %s' +DIFF_CVS_INTERP = 'diff -Nu %s %s | grep "^[+-][^+-]" | grep -v "# .Header:.*"' +DIFF_WSCOMMENTS = 'diff -Nu %s %s | grep "^[+-][^+-]" | grep -v "^[-+]#" | grep -v "^[-+][:space:]*$"' # We need a secure scratch dir and python does silly verbose errors on the use of tempnam oldmask = os.umask(0077) SCRATCH_DIR = None while SCRATCH_DIR is None: - try: - mydir = portage_const.EPREFIX+"/var/tmp/dispatch-conf." - for x in range(0,8): - if int(random() * 3) == 0: - mydir += chr(int(65+random()*26.0)) - elif int(random() * 2) == 0: - mydir += chr(int(97+random()*26.0)) - else: - mydir += chr(int(48+random()*10.0)) - if os.path.exists(mydir): - continue - os.mkdir(mydir) - SCRATCH_DIR = mydir - except OSError, e: - if e.errno != 17: - raise + try: + mydir = portage_const.EPREFIX+"/var/tmp/dispatch-conf." + for x in range(0,8): + if int(random() * 3) == 0: + mydir += chr(int(65+random()*26.0)) + elif int(random() * 2) == 0: + mydir += chr(int(97+random()*26.0)) + else: + mydir += chr(int(48+random()*10.0)) + if os.path.exists(mydir): + continue + os.mkdir(mydir) + SCRATCH_DIR = mydir + except OSError, e: + if e.errno != 17: + raise os.umask(oldmask) # Ensure the scratch dir is deleted def cleanup(mydir=SCRATCH_DIR): - shutil.rmtree(mydir) + shutil.rmtree(mydir) atexit.register(cleanup) MANDATORY_OPTS = [ 'archive-dir', 'diff', 'replace-cvs', 'replace-wscomments', 'merge' ] class dispatch: - options = {} - - def grind (self, config_paths): - confs = [] - count = 0 - - - self.options = portage.dispatch_conf.read_config(MANDATORY_OPTS) - - if self.options.has_key("log-file"): - if os.path.isfile(self.options["log-file"]): - shutil.copy(self.options["log-file"], self.options["log-file"] + '.old') - if os.path.isfile(self.options["log-file"]) \ - or not os.path.exists(self.options["log-file"]): - open(self.options["log-file"], 'w').close() # Truncate it - os.chmod(self.options["log-file"], 0600) - else: - self.options["log-file"] = "/dev/null" - - # - # Build list of extant configs - # - - for path in config_paths.split (): - path = portage.normalize_path(portage_const.EPREFIX + path) - try: - mymode = os.stat(path).st_mode - except OSError: - continue - basename = "*" - find_opts = "" - if not stat.S_ISDIR(mymode): - path, basename = os.path.split(path) - find_opts = "-maxdepth 1" - - confs += self.massage(os.popen(FIND_EXTANT_CONFIGS % (path, find_opts, basename)).readlines()) - - if self.options['use-rcs'] == 'yes' and ((os.system( "which rcs >/dev/null 2>&1" ) == 256) - or (os.system( "which ci >/dev/null 2>&1" ) == 256) - or (os.system( "which co >/dev/null 2>&1" ) == 256) - or (os.system( "which rcsmerge >/dev/null 2>&1" ) == 256)): - print >> sys.stderr, 'dispatch-conf: Error finding all RCS utils and use-rcs=yes in config; fatal' - return False - - - # config file freezing support - frozen_files = set(self.options.get("frozen-files", "").split()) - auto_zapped = [] - - # - # Remove new configs identical to current - # and - # Auto-replace configs a) whose differences are simply CVS interpolations, - # or b) whose differences are simply ws or comments, - # or c) in paths now unprotected by CONFIG_PROTECT_MASK, - # - - def f (conf): - mrgconf = re.sub(r'\._cfg', '._mrg', conf['new']) - archive = os.path.join(self.options['archive-dir'], conf['current'].lstrip('/')) - if self.options['use-rcs'] == 'yes': - mrgfail = portage.dispatch_conf.rcs_archive(archive, conf['current'], conf['new'], mrgconf) - else: - mrgfail = portage.dispatch_conf.file_archive(archive, conf['current'], conf['new'], mrgconf) - if os.path.exists(archive + '.dist'): - unmodified = len(commands.getoutput(DIFF_CONTENTS % (conf['current'], archive + '.dist'))) == 0 - else: - unmodified = 0 - if os.path.exists(mrgconf): - if mrgfail or len(commands.getoutput(DIFF_CONTENTS % (conf['new'], mrgconf))) == 0: - os.unlink(mrgconf) - newconf = conf['new'] - else: - newconf = mrgconf - else: - newconf = conf['new'] - - mystatus, myoutput = commands.getstatusoutput( - DIFF_CONTENTS % (conf ['current'], newconf)) - same_file = 0 == len(myoutput) - if mystatus >> 8 == 2: - # Binary files differ - same_cvs = False - same_wsc = False - else: - same_cvs = 0 == len(commands.getoutput( - DIFF_CVS_INTERP % (conf ['current'], newconf))) - same_wsc = 0 == len(commands.getoutput( - DIFF_WSCOMMENTS % (conf ['current'], newconf))) - - # Do options permit? - same_cvs = same_cvs and self.options['replace-cvs'] == 'yes' - same_wsc = same_wsc and self.options['replace-wscomments'] == 'yes' - unmodified = unmodified and self.options['replace-unmodified'] == 'yes' - - if same_file: - os.unlink (conf ['new']) - self.post_process(conf['current']) - if os.path.exists(mrgconf): - os.unlink(mrgconf) - return False - elif conf['current'] in frozen_files: - """Frozen files are automatically zapped. The new config has - already been archived with a .new suffix. When zapped, it is - left with the .new suffix (post_process is skipped), since it - hasn't been merged into the current config.""" - auto_zapped.append(conf['current']) - os.unlink(conf['new']) - try: - os.unlink(mrgconf) - except OSError: - pass - return False - elif unmodified or same_cvs or same_wsc or conf ['dir'] in portage.settings ['CONFIG_PROTECT_MASK'].split (): - self.replace(newconf, conf['current']) - self.post_process(conf['current']) - if newconf == mrgconf: - os.unlink(conf['new']) - elif os.path.exists(mrgconf): - os.unlink(mrgconf) - return False - else: - return True - - confs = filter (f, confs) - - # - # Interactively process remaining - # - - for conf in confs: - count = count + 1 - - newconf = conf['new'] - mrgconf = re.sub(r'\._cfg', '._mrg', newconf) - if os.path.exists(mrgconf): - newconf = mrgconf - show_new_diff = 0 - - while 1: - if show_new_diff: - os.system((self.options['diff']) % (conf['new'], mrgconf)) - show_new_diff = 0 - else: - os.system((self.options['diff']) % (conf['current'], newconf)) - - print - print '>> (%i of %i) -- %s' % (count, len(confs), conf ['current']) - print '>> q quit, h help, n next, e edit-new, z zap-new, u use-new\n m merge, t toggle-merge, l look-merge: ', - - c = getch () - - if c == 'q': - sys.exit (0) - if c == 'h': - self.do_help () - continue - elif c == 't': - if newconf == mrgconf: - newconf = conf['new'] - elif os.path.exists(mrgconf): - newconf = mrgconf - continue - elif c == 'n': - break - elif c == 'm': - merged = SCRATCH_DIR+"/"+os.path.basename(conf['current']) - print - ret = os.system (self.options['merge'] % (merged, conf ['current'], newconf)) - if ret: - print "Failure running 'merge' command" - continue - shutil.copyfile(merged, mrgconf) - os.remove(merged) - mystat = os.lstat(conf['new']) - os.chmod(mrgconf, mystat[ST_MODE]) - os.chown(mrgconf, mystat[ST_UID], mystat[ST_GID]) - newconf = mrgconf - continue - elif c == 'l': - show_new_diff = 1 - continue - elif c == 'e': - if not os.environ.has_key('EDITOR'): - os.environ['EDITOR']='nano' - os.system(os.environ['EDITOR'] + ' ' + newconf) - continue - elif c == 'z': - os.unlink(conf['new']) - if os.path.exists(mrgconf): - os.unlink(mrgconf) - break - elif c == 'u': - self.replace(newconf, conf ['current']) - self.post_process(conf['current']) - if newconf == mrgconf: - os.unlink(conf['new']) - elif os.path.exists(mrgconf): - os.unlink(mrgconf) - break - else: - continue - - if auto_zapped: - print - print " One or more updates are frozen and have been automatically zapped:" - print - for frozen in auto_zapped: - print " * '%s'" % frozen - print - - def replace (self, newconf, curconf): - """Replace current config with the new/merged version. Also logs - the diff of what changed into the configured log file.""" - os.system((DIFF_CONTENTS % (curconf, newconf)) + '>>' + self.options["log-file"]) - try: - shutil.copyfile(newconf, curconf) - os.remove(newconf) - except (IOError, os.error), why: - print >> sys.stderr, 'dispatch-conf: Error renaming %s to %s: %s; fatal' % \ - (newconf, curconf, str(why)) - - - def post_process(self, curconf): - archive = os.path.join(self.options['archive-dir'], curconf.lstrip('/')) - if self.options['use-rcs'] == 'yes': - portage.dispatch_conf.rcs_archive_post_process(archive) - else: - portage.dispatch_conf.file_archive_post_process(archive) - - - def massage (self, newconfigs): - """Sort, rstrip, remove old versions, break into triad hash. - - Triad is dictionary of current (/etc/make.conf), new (/etc/._cfg0003_make.conf) - and dir (/etc). - - We keep ._cfg0002_conf over ._cfg0001_conf and ._cfg0000_conf. - """ - h = {} - - newconfigs.sort () - - for nconf in newconfigs: - nconf = nconf.rstrip () - conf = re.sub (r'\._cfg\d+_', '', nconf) - dir = re.match (r'^(.+)/', nconf).group (1) - - if h.has_key (conf): - mrgconf = re.sub(r'\._cfg', '._mrg', h[conf]['new']) - if os.path.exists(mrgconf): - os.unlink(mrgconf) - os.unlink(h[conf]['new']) - - h [conf] = { 'current' : conf, 'dir' : dir, 'new' : nconf } - - configs = h.values () - configs.sort (lambda a, b: cmp(a ['current'], b ['current'])) - - return configs - - - def do_help (self): - print; print - - print ' u -- update current config with new config and continue' - print ' z -- zap (delete) new config and continue' - print ' n -- skip to next config, leave all intact' - print ' e -- edit new config' - print ' m -- interactively merge current and new configs' - print ' l -- look at diff between pre-merged and merged configs' - print ' t -- toggle new config between merged and pre-merged state' - print ' h -- this screen' - print ' q -- quit' - - print; print 'press any key to return to diff...', - - getch () + options = {} + + def grind (self, config_paths): + confs = [] + count = 0 + + + self.options = portage.dispatch_conf.read_config(MANDATORY_OPTS) + + if self.options.has_key("log-file"): + if os.path.isfile(self.options["log-file"]): + shutil.copy(self.options["log-file"], self.options["log-file"] + '.old') + if os.path.isfile(self.options["log-file"]) \ + or not os.path.exists(self.options["log-file"]): + open(self.options["log-file"], 'w').close() # Truncate it + os.chmod(self.options["log-file"], 0600) + else: + self.options["log-file"] = "/dev/null" + + # + # Build list of extant configs + # + + for path in config_paths.split (): + path = portage.normalize_path(portage_const.EPREFIX + path) + try: + mymode = os.stat(path).st_mode + except OSError: + continue + basename = "*" + find_opts = "" + if not stat.S_ISDIR(mymode): + path, basename = os.path.split(path) + find_opts = "-maxdepth 1" + + confs += self.massage(os.popen(FIND_EXTANT_CONFIGS % (path, find_opts, basename)).readlines()) + + if self.options['use-rcs'] == 'yes' and ((os.system( "which rcs >/dev/null 2>&1" ) == 256) + or (os.system( "which ci >/dev/null 2>&1" ) == 256) + or (os.system( "which co >/dev/null 2>&1" ) == 256) + or (os.system( "which rcsmerge >/dev/null 2>&1" ) == 256)): + print >> sys.stderr, 'dispatch-conf: Error finding all RCS utils and use-rcs=yes in config; fatal' + return False + + + # config file freezing support + frozen_files = set(self.options.get("frozen-files", "").split()) + auto_zapped = [] + + # + # Remove new configs identical to current + # and + # Auto-replace configs a) whose differences are simply CVS interpolations, + # or b) whose differences are simply ws or comments, + # or c) in paths now unprotected by CONFIG_PROTECT_MASK, + # + + def f (conf): + mrgconf = re.sub(r'\._cfg', '._mrg', conf['new']) + archive = os.path.join(self.options['archive-dir'], conf['current'].lstrip('/')) + if self.options['use-rcs'] == 'yes': + mrgfail = portage.dispatch_conf.rcs_archive(archive, conf['current'], conf['new'], mrgconf) + else: + mrgfail = portage.dispatch_conf.file_archive(archive, conf['current'], conf['new'], mrgconf) + if os.path.exists(archive + '.dist'): + unmodified = len(commands.getoutput(DIFF_CONTENTS % (conf['current'], archive + '.dist'))) == 0 + else: + unmodified = 0 + if os.path.exists(mrgconf): + if mrgfail or len(commands.getoutput(DIFF_CONTENTS % (conf['new'], mrgconf))) == 0: + os.unlink(mrgconf) + newconf = conf['new'] + else: + newconf = mrgconf + else: + newconf = conf['new'] + + mystatus, myoutput = commands.getstatusoutput( + DIFF_CONTENTS % (conf ['current'], newconf)) + same_file = 0 == len(myoutput) + if mystatus >> 8 == 2: + # Binary files differ + same_cvs = False + same_wsc = False + else: + same_cvs = 0 == len(commands.getoutput( + DIFF_CVS_INTERP % (conf ['current'], newconf))) + same_wsc = 0 == len(commands.getoutput( + DIFF_WSCOMMENTS % (conf ['current'], newconf))) + + # Do options permit? + same_cvs = same_cvs and self.options['replace-cvs'] == 'yes' + same_wsc = same_wsc and self.options['replace-wscomments'] == 'yes' + unmodified = unmodified and self.options['replace-unmodified'] == 'yes' + + if same_file: + os.unlink (conf ['new']) + self.post_process(conf['current']) + if os.path.exists(mrgconf): + os.unlink(mrgconf) + return False + elif conf['current'] in frozen_files: + """Frozen files are automatically zapped. The new config has + already been archived with a .new suffix. When zapped, it is + left with the .new suffix (post_process is skipped), since it + hasn't been merged into the current config.""" + auto_zapped.append(conf['current']) + os.unlink(conf['new']) + try: + os.unlink(mrgconf) + except OSError: + pass + return False + elif unmodified or same_cvs or same_wsc or conf ['dir'] in portage.settings ['CONFIG_PROTECT_MASK'].split (): + self.replace(newconf, conf['current']) + self.post_process(conf['current']) + if newconf == mrgconf: + os.unlink(conf['new']) + elif os.path.exists(mrgconf): + os.unlink(mrgconf) + return False + else: + return True + + confs = filter (f, confs) + + # + # Interactively process remaining + # + + for conf in confs: + count = count + 1 + + newconf = conf['new'] + mrgconf = re.sub(r'\._cfg', '._mrg', newconf) + if os.path.exists(mrgconf): + newconf = mrgconf + show_new_diff = 0 + + while 1: + if show_new_diff: + os.system((self.options['diff']) % (conf['new'], mrgconf)) + show_new_diff = 0 + else: + os.system((self.options['diff']) % (conf['current'], newconf)) + + print + print '>> (%i of %i) -- %s' % (count, len(confs), conf ['current']) + print '>> q quit, h help, n next, e edit-new, z zap-new, u use-new\n m merge, t toggle-merge, l look-merge: ', + + c = getch () + + if c == 'q': + sys.exit (0) + if c == 'h': + self.do_help () + continue + elif c == 't': + if newconf == mrgconf: + newconf = conf['new'] + elif os.path.exists(mrgconf): + newconf = mrgconf + continue + elif c == 'n': + break + elif c == 'm': + merged = SCRATCH_DIR+"/"+os.path.basename(conf['current']) + print + ret = os.system (self.options['merge'] % (merged, conf ['current'], newconf)) + if ret: + print "Failure running 'merge' command" + continue + shutil.copyfile(merged, mrgconf) + os.remove(merged) + mystat = os.lstat(conf['new']) + os.chmod(mrgconf, mystat[ST_MODE]) + os.chown(mrgconf, mystat[ST_UID], mystat[ST_GID]) + newconf = mrgconf + continue + elif c == 'l': + show_new_diff = 1 + continue + elif c == 'e': + if not os.environ.has_key('EDITOR'): + os.environ['EDITOR']='nano' + os.system(os.environ['EDITOR'] + ' ' + newconf) + continue + elif c == 'z': + os.unlink(conf['new']) + if os.path.exists(mrgconf): + os.unlink(mrgconf) + break + elif c == 'u': + self.replace(newconf, conf ['current']) + self.post_process(conf['current']) + if newconf == mrgconf: + os.unlink(conf['new']) + elif os.path.exists(mrgconf): + os.unlink(mrgconf) + break + else: + continue + + if auto_zapped: + print + print " One or more updates are frozen and have been automatically zapped:" + print + for frozen in auto_zapped: + print " * '%s'" % frozen + print + + def replace (self, newconf, curconf): + """Replace current config with the new/merged version. Also logs + the diff of what changed into the configured log file.""" + os.system((DIFF_CONTENTS % (curconf, newconf)) + '>>' + self.options["log-file"]) + try: + shutil.copyfile(newconf, curconf) + os.remove(newconf) + except (IOError, os.error), why: + print >> sys.stderr, 'dispatch-conf: Error renaming %s to %s: %s; fatal' % \ + (newconf, curconf, str(why)) + + + def post_process(self, curconf): + archive = os.path.join(self.options['archive-dir'], curconf.lstrip('/')) + if self.options['use-rcs'] == 'yes': + portage.dispatch_conf.rcs_archive_post_process(archive) + else: + portage.dispatch_conf.file_archive_post_process(archive) + + + def massage (self, newconfigs): + """Sort, rstrip, remove old versions, break into triad hash. + + Triad is dictionary of current (/etc/make.conf), new (/etc/._cfg0003_make.conf) + and dir (/etc). + + We keep ._cfg0002_conf over ._cfg0001_conf and ._cfg0000_conf. + """ + h = {} + + newconfigs.sort () + + for nconf in newconfigs: + nconf = nconf.rstrip () + conf = re.sub (r'\._cfg\d+_', '', nconf) + dir = re.match (r'^(.+)/', nconf).group (1) + + if h.has_key (conf): + mrgconf = re.sub(r'\._cfg', '._mrg', h[conf]['new']) + if os.path.exists(mrgconf): + os.unlink(mrgconf) + os.unlink(h[conf]['new']) + + h [conf] = { 'current' : conf, 'dir' : dir, 'new' : nconf } + + configs = h.values () + configs.sort (lambda a, b: cmp(a ['current'], b ['current'])) + + return configs + + + def do_help (self): + print; print + + print ' u -- update current config with new config and continue' + print ' z -- zap (delete) new config and continue' + print ' n -- skip to next config, leave all intact' + print ' e -- edit new config' + print ' m -- interactively merge current and new configs' + print ' l -- look at diff between pre-merged and merged configs' + print ' t -- toggle new config between merged and pre-merged state' + print ' h -- this screen' + print ' q -- quit' + + print; print 'press any key to return to diff...', + + getch () def getch (): - # from ASPN - Danny Yoo - # - import sys, tty, termios + # from ASPN - Danny Yoo + # + import sys, tty, termios - fd = sys.stdin.fileno() - old_settings = termios.tcgetattr(fd) - try: - tty.setraw(sys.stdin.fileno()) - ch = sys.stdin.read(1) - finally: - termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) - return ch + fd = sys.stdin.fileno() + old_settings = termios.tcgetattr(fd) + try: + tty.setraw(sys.stdin.fileno()) + ch = sys.stdin.read(1) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + return ch # run d = dispatch () if len(sys.argv) > 1: - # for testing - d.grind (" ".join(sys.argv[1:])) + # for testing + d.grind (" ".join(sys.argv[1:])) else: - d.grind (portage.settings ['CONFIG_PROTECT']) + d.grind (portage.settings ['CONFIG_PROTECT']) -- 2.26.2