| 1 | #! /usr/bin/python |
|---|
| 2 | # -*- coding: UTF-8 -*- |
|---|
| 3 | # |
|---|
| 4 | # © 2005 Josselin Mouette <joss@debian.org> |
|---|
| 5 | # Licensed under the GNU LGPL, see /usr/share/common-licenses/LGPL-2.1 |
|---|
| 6 | |
|---|
| 7 | treefile = '%gconf-tree.xml' |
|---|
| 8 | |
|---|
| 9 | import os,tempfile,shutil,sys |
|---|
| 10 | from optparse import OptionParser |
|---|
| 11 | |
|---|
| 12 | parser = OptionParser() |
|---|
| 13 | parser.add_option("--source", dest="source_dir", default="/usr/share/gconf/defaults", |
|---|
| 14 | help="directory where to find the defaults", metavar="DIR") |
|---|
| 15 | parser.add_option("--destination", dest="dest_dir", default="/var/lib/gconf/debian.defaults", |
|---|
| 16 | help="directory where to build the GConf tree", metavar="DIR") |
|---|
| 17 | parser.add_option("--mandatory", action="store_true", default=False, dest="mandatory", |
|---|
| 18 | help="select mandatory settings directories") |
|---|
| 19 | parser.add_option("--no-signal", action="store_false", default=True, dest="signal", |
|---|
| 20 | help="do not send SIGHUP the running gconfd-2 processes") |
|---|
| 21 | |
|---|
| 22 | (options, args) = parser.parse_args() |
|---|
| 23 | |
|---|
| 24 | if options.mandatory: |
|---|
| 25 | options.source_dir="/usr/share/gconf/mandatory" |
|---|
| 26 | options.dest_dir="/var/lib/gconf/debian.mandatory" |
|---|
| 27 | |
|---|
| 28 | if not os.path.isdir(options.source_dir): |
|---|
| 29 | parser.error("Source directory does not exist.") |
|---|
| 30 | if not os.path.isdir(options.dest_dir): |
|---|
| 31 | parser.error("Destination directory does not exist.") |
|---|
| 32 | if not os.access(options.source_dir,os.R_OK|os.X_OK): |
|---|
| 33 | parser.error("Source directory is not readable.") |
|---|
| 34 | if not os.access(options.dest_dir,os.W_OK|os.X_OK): |
|---|
| 35 | parser.error("Destination directory is not writable.") |
|---|
| 36 | |
|---|
| 37 | tmp_dir=tempfile.mkdtemp(prefix="gconf-") |
|---|
| 38 | tmp_home=tmp_dir+'/home' |
|---|
| 39 | tmp_gconf=tmp_dir+'/gconf' |
|---|
| 40 | tmp_file=tmp_dir+'/temp.entries' |
|---|
| 41 | |
|---|
| 42 | save_stdout=os.dup(1) |
|---|
| 43 | os.close(1) |
|---|
| 44 | |
|---|
| 45 | def cleanup(): |
|---|
| 46 | os.dup2(save_stdout,1) |
|---|
| 47 | os.close(save_stdout) |
|---|
| 48 | shutil.rmtree(tmp_dir) |
|---|
| 49 | |
|---|
| 50 | def htmlescape(str): |
|---|
| 51 | return str.replace('&','&').replace('>','>').replace('<','<').replace('"','"') |
|---|
| 52 | |
|---|
| 53 | def int_entry(value): |
|---|
| 54 | return ' <int>' + value + '</int>\n' |
|---|
| 55 | |
|---|
| 56 | def bool_entry(value): |
|---|
| 57 | return ' <bool>' + value + '</bool>\n' |
|---|
| 58 | |
|---|
| 59 | def float_entry(value): |
|---|
| 60 | return ' <float>' + value + '</float>\n' |
|---|
| 61 | |
|---|
| 62 | def string_entry(value): |
|---|
| 63 | return ' <string>' + htmlescape(value) + '</string>\n' |
|---|
| 64 | |
|---|
| 65 | def list_entry(value): |
|---|
| 66 | ret = ' <list type="string">\n' |
|---|
| 67 | for v in value[1:-1].split(','): |
|---|
| 68 | ret += ' <value><string>' + htmlescape(v) + '</string></value>\n' |
|---|
| 69 | ret += ' </list>\n' |
|---|
| 70 | return ret |
|---|
| 71 | |
|---|
| 72 | |
|---|
| 73 | def listcmp(a,b): |
|---|
| 74 | """Number of starting similar elements in a and b""" |
|---|
| 75 | m = min(len(a),len(b)) |
|---|
| 76 | for i in range(m): |
|---|
| 77 | if a[i] != b[i]: |
|---|
| 78 | return i |
|---|
| 79 | return m |
|---|
| 80 | |
|---|
| 81 | def apply_entries(filename): |
|---|
| 82 | res=os.spawnvpe(os.P_WAIT,'gconftool-2', |
|---|
| 83 | ['gconftool-2','--direct','--config-source', |
|---|
| 84 | 'xml:merged:'+tmp_gconf,'--load',filename], |
|---|
| 85 | {'HOME': tmp_home}) |
|---|
| 86 | if res: |
|---|
| 87 | cleanup() |
|---|
| 88 | sys.exit(res) |
|---|
| 89 | |
|---|
| 90 | gconf_val = {} |
|---|
| 91 | |
|---|
| 92 | def write_and_apply_entries(filename): |
|---|
| 93 | out=file(filename,'w') |
|---|
| 94 | out.write('<gconfentryfile>\n<entrylist base="/">\n') |
|---|
| 95 | for key in gconf_val: |
|---|
| 96 | out.write('<entry>\n<key>' + key + '</key>\n<value>\n') |
|---|
| 97 | # write the current entry |
|---|
| 98 | value = gconf_val[key] |
|---|
| 99 | if value[0] == '"' and value[-1] == '"': |
|---|
| 100 | out.write(string_entry(value[1:-1])) |
|---|
| 101 | elif value in ['true','false']: |
|---|
| 102 | out.write(bool_entry(value)) |
|---|
| 103 | elif value[0] == '[' and value[-1] == ']': |
|---|
| 104 | out.write(list_entry(value)) |
|---|
| 105 | elif value.isdigit(): |
|---|
| 106 | out.write(int_entry(value)) |
|---|
| 107 | else: |
|---|
| 108 | try: |
|---|
| 109 | float(value) |
|---|
| 110 | out.write(float_entry(value)) |
|---|
| 111 | except ValueError: |
|---|
| 112 | out.write(string_entry(value)) |
|---|
| 113 | out.write('</value>\n</entry>\n') |
|---|
| 114 | out.write('</entrylist>\n</gconfentryfile>\n') |
|---|
| 115 | out.close() |
|---|
| 116 | apply_entries(filename) |
|---|
| 117 | |
|---|
| 118 | def read_entries(filename): |
|---|
| 119 | for line in file(filename): |
|---|
| 120 | l = line.rstrip('\n').split(None,1) |
|---|
| 121 | if len(l) == 2: |
|---|
| 122 | gconf_val[l[0]] = l[1] |
|---|
| 123 | |
|---|
| 124 | |
|---|
| 125 | defaults_files = os.listdir(options.source_dir) |
|---|
| 126 | defaults_files.sort() |
|---|
| 127 | for f in defaults_files: |
|---|
| 128 | realname=options.source_dir+'/'+f |
|---|
| 129 | for ext in ['.dpkg-tmp', '.bak', '.tmp', '~', '.sav', '.save']: |
|---|
| 130 | if f.endswith(ext): |
|---|
| 131 | continue |
|---|
| 132 | if f.endswith('.entries'): |
|---|
| 133 | if gconf_val: |
|---|
| 134 | write_and_apply_entries(tmp_file) |
|---|
| 135 | gconf_val={} |
|---|
| 136 | apply_entries(realname) |
|---|
| 137 | else: |
|---|
| 138 | read_entries(realname) |
|---|
| 139 | if gconf_val: |
|---|
| 140 | write_and_apply_entries(tmp_file) |
|---|
| 141 | |
|---|
| 142 | try: |
|---|
| 143 | shutil.copyfile(tmp_gconf+'/'+treefile,options.dest_dir+'/'+treefile+'.tmp') |
|---|
| 144 | os.rename(options.dest_dir+'/'+treefile+'.tmp',options.dest_dir+'/'+treefile) |
|---|
| 145 | except IOError: |
|---|
| 146 | # No %gconf-tree.xml file was created. |
|---|
| 147 | try: |
|---|
| 148 | os.remove(options.dest_dir+'/'+treefile) |
|---|
| 149 | except OSError: |
|---|
| 150 | # No existing file |
|---|
| 151 | pass |
|---|
| 152 | |
|---|
| 153 | cleanup() |
|---|
| 154 | |
|---|
| 155 | if options.signal: |
|---|
| 156 | os.system('kill -s HUP `pidof gconfd-2` >/dev/null 2>&1') |
|---|