#! /usr/bin/python2 # -*- coding: utf-8 -*- # # © 2005 Josselin Mouette # Licensed under the GNU LGPL, see /usr/share/common-licenses/LGPL-2.1 treefile = '%gconf-tree.xml' import os,tempfile,shutil,sys from optparse import OptionParser import re parser = OptionParser() parser.add_option("--source", dest="source_dir", default="/usr/share/gconf/defaults", help="directory where to find the defaults", metavar="DIR") parser.add_option("--destination", dest="dest_dir", default="/var/lib/gconf/debian.defaults", help="directory where to build the GConf tree", metavar="DIR") parser.add_option("--mandatory", action="store_true", default=False, dest="mandatory", help="select mandatory settings directories") parser.add_option("--no-signal", action="store_false", default=True, dest="signal", help="do not send SIGHUP the running gconfd-2 processes") parser.add_option("--only-if-changed", action="store_true", default=False, dest="ifchanged", help="only regenerate configuration if needed") (options, args) = parser.parse_args() if 'DPKG_RUNNING_VERSION' in os.environ and options.signal: # This is what happens when we are called in an obsolete postinst/prerm script # Do nothing, it will be done in the trigger sys.exit(0) if options.mandatory: options.source_dir="/usr/share/gconf/mandatory" options.dest_dir="/var/lib/gconf/debian.mandatory" if not os.path.isdir(options.source_dir): parser.error("Source directory does not exist.") if not os.path.isdir(options.dest_dir): parser.error("Destination directory does not exist.") if not os.access(options.source_dir,os.R_OK|os.X_OK): parser.error("Source directory is not readable.") if not os.access(options.dest_dir,os.W_OK|os.X_OK): parser.error("Destination directory is not writable.") save_stdout=os.dup(1) os.close(1) def cleanup(): os.dup2(save_stdout,1) os.close(save_stdout) shutil.rmtree(tmp_dir) def htmlescape(str): return str.replace('&','&').replace('>','>').replace('<','<').replace('"','"') def int_entry(value): return ' ' + value + '\n' def bool_entry(value): return ' ' + value + '\n' def float_entry(value): return ' ' + value + '\n' def string_entry(value): return ' ' + htmlescape(value) + '\n' def int_list_entry(value): ret = ' \n' for v in value[1:-1].split(','): ret += ' ' + v + '\n' ret += ' \n' return ret def list_entry(value): if is_int_list(value): return int_list_entry(value) ret = ' \n' for v in value[1:-1].split(','): ret += ' ' + htmlescape(v) + '\n' ret += ' \n' return ret def is_int_list(value): if re.search('^\[(?:\d+,?)+\]$', value) == None: return False else: return True def listcmp(a,b): """Number of starting similar elements in a and b""" m = min(len(a),len(b)) for i in range(m): if a[i] != b[i]: return i return m def apply_entries(filename): env=os.environ.copy() env['HOME'] = tmp_home res=os.spawnvpe(os.P_WAIT,'gconftool-2', ['gconftool-2','--direct','--config-source', 'xml:merged:'+tmp_gconf,'--load',filename], env) if res: cleanup() sys.exit(res) gconf_val = {} def write_and_apply_entries(filename): out=file(filename,'w') out.write('\n\n') for key in gconf_val: out.write('\n' + key + '\n\n') # write the current entry value = gconf_val[key] if value[0] == '"' and value[-1] == '"': out.write(string_entry(value[1:-1])) elif value in ['true','false']: out.write(bool_entry(value)) elif value[0] == '[' and value[-1] == ']': out.write(list_entry(value)) elif value.isdigit(): out.write(int_entry(value)) else: try: float(value) out.write(float_entry(value)) except ValueError: out.write(string_entry(value)) out.write('\n\n') out.write('\n\n') out.close() apply_entries(filename) def read_entries(filename): for line in file(filename): l = line.rstrip('\n').split(None,1) if len(l) == 2 and not l[0].startswith('#'): gconf_val[l[0]] = l[1] defaults_files = [] for f in os.listdir(options.source_dir): for ext in ['.dpkg-tmp', '.bak', '.tmp', '~', '.sav', '.save']: if f.endswith(ext): break else: if os.path.exists(os.path.join(options.source_dir, f)): defaults_files.append(f) defaults_files.sort() if options.ifchanged: source_stamp = os.stat(options.source_dir).st_mtime for f in defaults_files: realname=os.path.join(options.source_dir,f) source_stamp = max(os.stat(realname).st_mtime,source_stamp) try: dest_stamp = os.stat(os.path.join(options.dest_dir, treefile)).st_mtime except OSError: dest_stamp = 0 if source_stamp < dest_stamp: sys.exit(0) tmp_dir=tempfile.mkdtemp(prefix="gconf-") tmp_home=tmp_dir+'/home' tmp_gconf=tmp_dir+'/gconf' tmp_file=tmp_dir+'/temp.entries' for f in defaults_files: realname=os.path.join(options.source_dir,f) if f.endswith('.entries'): if gconf_val: write_and_apply_entries(tmp_file) gconf_val={} apply_entries(realname) else: read_entries(realname) if gconf_val: write_and_apply_entries(tmp_file) try: shutil.copyfile(tmp_gconf+'/'+treefile,options.dest_dir+'/'+treefile+'.tmp') os.rename(options.dest_dir+'/'+treefile+'.tmp',options.dest_dir+'/'+treefile) except IOError: # No %gconf-tree.xml file was created. try: os.remove(options.dest_dir+'/'+treefile) except OSError: # No existing file pass cleanup() if options.signal: os.system('kill -s HUP `pidof gconfd-2` >/dev/null 2>&1')