/[gentoo-src]/portage/bin/dispatch-conf
Gentoo

Contents of /portage/bin/dispatch-conf

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.7.2.10 - (show annotations) (download)
Thu May 12 15:20:22 2005 UTC (9 years, 2 months ago) by jstubbs
Branch: portage_2_0
Changes since 1.7.2.9: +4 -4 lines
cnf/dispatch-conf.conf bin/dispatch-conf: Removed the pager config option
and made if part of the diff command option.

bin/dodoc: Backported vapier's fix for 0-byte files causing a spurious
"file not found" error.

bin/emerge: Remove --verbose and --tree from options when using --resume as
the combination is currently broken.

bin/repoman: Added three new checks on ebuild's PROVIDEs. Optimized out a
lot of unnecessary aux_get() calls. Modified to commit an unsigned Manifest
before committing the signed one to help ensure broken digests don't make
it to rsync.

pym/portage.py: Added SCCS to the list of directories to ignore when
ignorecvs is set in cacheddir(). Drop priveleges during fetch when userpriv
is set. Added message display when changing permissions on ccache dirs.

1 #!/usr/bin/python -O
2 # Copyright 1999-2004 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
4 # $Header: /var/cvsroot/gentoo-src/portage/bin/dispatch-conf,v 1.7.2.9 2005/04/29 03:37:30 jstubbs Exp $
5
6 #
7 # dispatch-conf -- Integrate modified configs, post-emerge
8 #
9 # Jeremy Wohl (http://igmus.org)
10 #
11 # TODO
12 # dialog menus
13 #
14
15 from stat import *
16 from random import *
17 import os, shutil, sys, string, re, commands, atexit
18 sys.path = ["/usr/lib/portage/pym"]+sys.path
19
20 import portage, dispatch_conf
21
22 FIND_EXTANT_CONFIGS = "find %s/ -iname '._cfg????_*' | sed -e 's://:/:g'"
23 DIFF_CONTENTS = 'diff -Nu %s %s'
24 DIFF_CVS_INTERP = 'diff -Nu %s %s | grep "^[+-][^+-]" | grep -v "# .Header:.*"'
25 DIFF_WSCOMMENTS = 'diff -Nu %s %s | grep "^[+-][^+-]" | grep -v "^[-+]#" | grep -v "^[-+][:space:]*$"'
26
27 # We need a secure scratch dir and python does silly verbose errors on the use of tempnam
28 oldmask = os.umask(0077)
29 SCRATCH_DIR = None
30 while SCRATCH_DIR is None:
31 try:
32 mydir = "/tmp/dispatch-conf."
33 for x in range(0,8):
34 if int(random() * 3) == 0:
35 mydir += chr(int(65+random()*26.0))
36 elif int(random() * 2) == 0:
37 mydir += chr(int(97+random()*26.0))
38 else:
39 mydir += chr(int(48+random()*10.0))
40 if os.path.exists(mydir):
41 continue
42 os.mkdir(mydir)
43 SCRATCH_DIR = mydir
44 except OSError, e:
45 if e.errno != 17:
46 raise
47 os.umask(oldmask)
48
49 # Ensure the scratch dir is deleted
50 def cleanup(mydir=SCRATCH_DIR):
51 shutil.rmtree(SCRATCH_DIR)
52 atexit.register(cleanup)
53
54 MANDATORY_OPTS = [ 'archive-dir', 'diff', 'replace-cvs', 'replace-wscomments', 'merge' ]
55
56 class dispatch:
57 options = {}
58
59 def grind (self, config_paths):
60 confs = []
61 count = 0
62
63
64 self.options = dispatch_conf.read_config(MANDATORY_OPTS)
65
66 if self.options.has_key("log-file"):
67 if os.path.exists(self.options["log-file"]):
68 shutil.copyfile(self.options["log-file"], self.options["log-file"] + '.old')
69 os.remove(self.options["log-file"])
70 else:
71 self.options["log-file"] = "/dev/null"
72
73 #
74 # Build list of extant configs
75 #
76
77 for path in config_paths.split ():
78 if not os.path.exists (path):
79 continue
80
81 confs += self.massage (os.popen (FIND_EXTANT_CONFIGS % (path,)).readlines ())
82
83 if self.options['use-rcs'] == 'yes' and ((os.system( "which rcs >/dev/null 2>&1" ) == 256)
84 or (os.system( "which ci >/dev/null 2>&1" ) == 256)
85 or (os.system( "which co >/dev/null 2>&1" ) == 256)
86 or (os.system( "which rcsmerge >/dev/null 2>&1" ) == 256)):
87 print >> sys.stderr, 'dispatch-conf: Error finding all RCS utils and use-rcs=yes in config; fatal'
88 return False
89
90
91 #
92 # Remove new configs identical to current
93 # and
94 # Auto-replace configs a) whose differences are simply CVS interpolations,
95 # or b) whose differences are simply ws or comments,
96 # or c) in paths now unprotected by CONFIG_PROTECT_MASK,
97 #
98
99 def f (conf):
100 mrgconf = re.sub(r'\._cfg', '._mrg', conf['new'])
101 archive = os.path.join(self.options['archive-dir'], conf['current'].lstrip('/'))
102 if self.options['use-rcs'] == 'yes':
103 mrgfail = dispatch_conf.rcs_archive(archive, conf['current'], conf['new'], mrgconf)
104 else:
105 mrgfail = dispatch_conf.file_archive(archive, conf['current'], conf['new'], mrgconf)
106 if os.path.exists(archive + '.dist'):
107 unmodified = len(commands.getoutput(DIFF_CONTENTS % (conf['current'], archive + '.dist'))) == 0
108 else:
109 unmodified = 0
110 if os.path.exists(mrgconf):
111 if mrgfail or len(commands.getoutput(DIFF_CONTENTS % (conf['new'], mrgconf))) == 0:
112 os.unlink(mrgconf)
113 newconf = conf['new']
114 else:
115 newconf = mrgconf
116 else:
117 newconf = conf['new']
118
119 same_file = len(commands.getoutput (DIFF_CONTENTS % (conf ['current'], newconf))) == 0
120 same_cvs = len(commands.getoutput (DIFF_CVS_INTERP % (conf ['current'], newconf))) == 0
121 same_wsc = len(commands.getoutput (DIFF_WSCOMMENTS % (conf ['current'], newconf))) == 0
122
123 # Do options permit?
124 same_cvs = same_cvs and self.options['replace-cvs'] == 'yes'
125 same_wsc = same_wsc and self.options['replace-wscomments'] == 'yes'
126 unmodified = unmodified and self.options['replace-unmodified'] == 'yes'
127
128 if same_file:
129 os.unlink (conf ['new'])
130 self.post_process(conf['current'])
131 if os.path.exists(mrgconf):
132 os.unlink(mrgconf)
133 return False
134 elif unmodified or same_cvs or same_wsc or conf ['dir'] in portage.settings ['CONFIG_PROTECT_MASK'].split ():
135 self.replace(newconf, conf['current'])
136 self.post_process(conf['current'])
137 if newconf == mrgconf:
138 os.unlink(conf['new'])
139 elif os.path.exists(mrgconf):
140 os.unlink(mrgconf)
141 return False
142 else:
143 return True
144
145 confs = filter (f, confs)
146
147 #
148 # Interactively process remaining
149 #
150
151 for conf in confs:
152 count = count + 1
153
154 newconf = conf['new']
155 mrgconf = re.sub(r'\._cfg', '._mrg', newconf)
156 if os.path.exists(mrgconf):
157 newconf = mrgconf
158 show_new_diff = 0
159
160 while 1:
161 if show_new_diff:
162 os.system((self.options['diff']) % (conf['new'], mrgconf))
163 show_new_diff = 0
164 else:
165 os.system((self.options['diff']) % (conf['current'], newconf))
166
167 print
168 print '>> (%i of %i) -- %s' % (count, len(confs), conf ['current'])
169 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: ',
170
171 c = getch ()
172
173 if c == 'q':
174 sys.exit (0)
175 if c == 'h':
176 self.do_help ()
177 continue
178 elif c == 't':
179 if newconf == mrgconf:
180 newconf = conf['new']
181 elif os.path.exists(mrgconf):
182 newconf = mrgconf
183 continue
184 elif c == 'n':
185 break
186 elif c == 'm':
187 merged = SCRATCH_DIR+"/"+os.path.basename(conf['current'])
188 print
189 os.system (self.options['merge'] % (merged, conf ['current'], newconf))
190 shutil.copyfile(merged, mrgconf)
191 os.remove(merged)
192 mystat = os.lstat(conf['new'])
193 os.chmod(mrgconf, mystat[ST_MODE])
194 os.chown(mrgconf, mystat[ST_UID], mystat[ST_GID])
195 newconf = mrgconf
196 continue
197 elif c == 'l':
198 show_new_diff = 1
199 continue
200 elif c == 'e':
201 os.system(os.environ['EDITOR'] + ' ' + newconf)
202 continue
203 elif c == 'z':
204 os.unlink(conf['new'])
205 if os.path.exists(mrgconf):
206 os.unlink(mrgconf)
207 break
208 elif c == 'u':
209 self.replace(newconf, conf ['current'])
210 self.post_process(conf['current'])
211 if newconf == mrgconf:
212 os.unlink(conf['new'])
213 elif os.path.exists(mrgconf):
214 os.unlink(mrgconf)
215 break
216 else:
217 continue
218
219
220 def replace (self, newconf, curconf):
221 """Replace current config with the new/merged version. Also logs
222 the diff of what changed into the configured log file."""
223 os.system((DIFF_CONTENTS % (curconf, newconf)) + '>>' + self.options["log-file"])
224 try:
225 shutil.copyfile(newconf, curconf)
226 os.remove(newconf)
227 except (IOError, os.error), why:
228 print >> sys.stderr, 'dispatch-conf: Error renaming %s to %s: %s; fatal' % \
229 (newconf, curconf, str(why))
230
231
232 def post_process(self, curconf):
233 archive = os.path.join(self.options['archive-dir'], curconf.lstrip('/'))
234 if self.options['use-rcs'] == 'yes':
235 dispatch_conf.rcs_archive_post_process(archive)
236 else:
237 dispatch_conf.file_archive_post_process(archive)
238
239
240 def massage (self, newconfigs):
241 """Sort, rstrip, remove old versions, break into triad hash.
242
243 Triad is dictionary of current (/etc/make.conf), new (/etc/._cfg0003_make.conf)
244 and dir (/etc).
245
246 We keep ._cfg0002_conf over ._cfg0001_conf and ._cfg0000_conf.
247 """
248 h = {}
249
250 newconfigs.sort ()
251
252 for nconf in newconfigs:
253 nconf = nconf.rstrip ()
254 conf = re.sub (r'\._cfg\d+_', '', nconf)
255 dir = re.match (r'^(.+)/', nconf).group (1)
256
257 if h.has_key (conf):
258 mrgconf = re.sub(r'\._cfg', '._mrg', h[conf]['new'])
259 if os.path.exists(mrgconf):
260 os.unlink(mrgconf)
261 os.unlink(h[conf]['new'])
262
263 h [conf] = { 'current' : conf, 'dir' : dir, 'new' : nconf }
264
265 configs = h.values ()
266 configs.sort (lambda a, b: cmp(a ['current'], b ['current']))
267
268 return configs
269
270
271 def do_help (self):
272 print; print
273
274 print ' u -- update current config with new config and continue'
275 print ' z -- zap (delete) new config and continue'
276 print ' n -- skip to next config, leave all intact'
277 print ' e -- edit new config'
278 print ' m -- interactively merge current and new configs'
279 print ' l -- look at diff between pre-merged and merged configs'
280 print ' t -- toggle new config between merged and pre-merged state'
281 print ' h -- this screen'
282 print ' q -- quit'
283
284 print; print 'press any key to return to diff...',
285
286 getch ()
287
288
289 def getch ():
290 # from ASPN - Danny Yoo
291 #
292 import sys, tty, termios
293
294 fd = sys.stdin.fileno()
295 old_settings = termios.tcgetattr(fd)
296 try:
297 tty.setraw(sys.stdin.fileno())
298 ch = sys.stdin.read(1)
299 finally:
300 termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
301 return ch
302
303
304 # run
305 d = dispatch ()
306
307 if len(sys.argv) > 1:
308 # for testing
309 d.grind (string.join (sys.argv [1:]))
310 else:
311 d.grind (portage.settings ['CONFIG_PROTECT'])

  ViewVC Help
Powered by ViewVC 1.1.20