]> git.proxmox.com Git - mirror_edk2.git/blob - AppPkg/Applications/Python/Python-2.7.2/Demo/pdist/rcvs.py
EmbeddedPkg: Extend NvVarStoreFormattedLib LIBRARY_CLASS
[mirror_edk2.git] / AppPkg / Applications / Python / Python-2.7.2 / Demo / pdist / rcvs.py
1 #! /usr/bin/env python
2
3 """Remote CVS -- command line interface"""
4
5 # XXX To do:
6 #
7 # Bugs:
8 # - if the remote file is deleted, "rcvs update" will fail
9 #
10 # Functionality:
11 # - cvs rm
12 # - descend into directories (alraedy done for update)
13 # - conflict resolution
14 # - other relevant commands?
15 # - branches
16 #
17 # - Finesses:
18 # - retain file mode's x bits
19 # - complain when "nothing known about filename"
20 # - edit log message the way CVS lets you edit it
21 # - cvs diff -rREVA -rREVB
22 # - send mail the way CVS sends it
23 #
24 # Performance:
25 # - cache remote checksums (for every revision ever seen!)
26 # - translate symbolic revisions to numeric revisions
27 #
28 # Reliability:
29 # - remote locking
30 #
31 # Security:
32 # - Authenticated RPC?
33
34
35 from cvslib import CVS, File
36 import md5
37 import os
38 import string
39 import sys
40 from cmdfw import CommandFrameWork
41
42
43 DEF_LOCAL = 1 # Default -l
44
45
46 class MyFile(File):
47
48 def action(self):
49 """Return a code indicating the update status of this file.
50
51 The possible return values are:
52
53 '=' -- everything's fine
54 '0' -- file doesn't exist anywhere
55 '?' -- exists locally only
56 'A' -- new locally
57 'R' -- deleted locally
58 'U' -- changed remotely, no changes locally
59 (includes new remotely or deleted remotely)
60 'M' -- changed locally, no changes remotely
61 'C' -- conflict: changed locally as well as remotely
62 (includes cases where the file has been added
63 or removed locally and remotely)
64 'D' -- deleted remotely
65 'N' -- new remotely
66 'r' -- get rid of entry
67 'c' -- create entry
68 'u' -- update entry
69
70 (and probably others :-)
71 """
72 if not self.lseen:
73 self.getlocal()
74 if not self.rseen:
75 self.getremote()
76 if not self.eseen:
77 if not self.lsum:
78 if not self.rsum: return '0' # Never heard of
79 else:
80 return 'N' # New remotely
81 else: # self.lsum
82 if not self.rsum: return '?' # Local only
83 # Local and remote, but no entry
84 if self.lsum == self.rsum:
85 return 'c' # Restore entry only
86 else: return 'C' # Real conflict
87 else: # self.eseen
88 if not self.lsum:
89 if self.edeleted:
90 if self.rsum: return 'R' # Removed
91 else: return 'r' # Get rid of entry
92 else: # not self.edeleted
93 if self.rsum:
94 print "warning:",
95 print self.file,
96 print "was lost"
97 return 'U'
98 else: return 'r' # Get rid of entry
99 else: # self.lsum
100 if not self.rsum:
101 if self.enew: return 'A' # New locally
102 else: return 'D' # Deleted remotely
103 else: # self.rsum
104 if self.enew:
105 if self.lsum == self.rsum:
106 return 'u'
107 else:
108 return 'C'
109 if self.lsum == self.esum:
110 if self.esum == self.rsum:
111 return '='
112 else:
113 return 'U'
114 elif self.esum == self.rsum:
115 return 'M'
116 elif self.lsum == self.rsum:
117 return 'u'
118 else:
119 return 'C'
120
121 def update(self):
122 code = self.action()
123 if code == '=': return
124 print code, self.file
125 if code in ('U', 'N'):
126 self.get()
127 elif code == 'C':
128 print "%s: conflict resolution not yet implemented" % \
129 self.file
130 elif code == 'D':
131 remove(self.file)
132 self.eseen = 0
133 elif code == 'r':
134 self.eseen = 0
135 elif code in ('c', 'u'):
136 self.eseen = 1
137 self.erev = self.rrev
138 self.enew = 0
139 self.edeleted = 0
140 self.esum = self.rsum
141 self.emtime, self.ectime = os.stat(self.file)[-2:]
142 self.extra = ''
143
144 def commit(self, message = ""):
145 code = self.action()
146 if code in ('A', 'M'):
147 self.put(message)
148 return 1
149 elif code == 'R':
150 print "%s: committing removes not yet implemented" % \
151 self.file
152 elif code == 'C':
153 print "%s: conflict resolution not yet implemented" % \
154 self.file
155
156 def diff(self, opts = []):
157 self.action() # To update lseen, rseen
158 flags = ''
159 rev = self.rrev
160 # XXX should support two rev options too!
161 for o, a in opts:
162 if o == '-r':
163 rev = a
164 else:
165 flags = flags + ' ' + o + a
166 if rev == self.rrev and self.lsum == self.rsum:
167 return
168 flags = flags[1:]
169 fn = self.file
170 data = self.proxy.get((fn, rev))
171 sum = md5.new(data).digest()
172 if self.lsum == sum:
173 return
174 import tempfile
175 tf = tempfile.NamedTemporaryFile()
176 tf.write(data)
177 tf.flush()
178 print 'diff %s -r%s %s' % (flags, rev, fn)
179 sts = os.system('diff %s %s %s' % (flags, tf.name, fn))
180 if sts:
181 print '='*70
182
183 def commitcheck(self):
184 return self.action() != 'C'
185
186 def put(self, message = ""):
187 print "Checking in", self.file, "..."
188 data = open(self.file).read()
189 if not self.enew:
190 self.proxy.lock(self.file)
191 messages = self.proxy.put(self.file, data, message)
192 if messages:
193 print messages
194 self.setentry(self.proxy.head(self.file), self.lsum)
195
196 def get(self):
197 data = self.proxy.get(self.file)
198 f = open(self.file, 'w')
199 f.write(data)
200 f.close()
201 self.setentry(self.rrev, self.rsum)
202
203 def log(self, otherflags):
204 print self.proxy.log(self.file, otherflags)
205
206 def add(self):
207 self.eseen = 0 # While we're hacking...
208 self.esum = self.lsum
209 self.emtime, self.ectime = 0, 0
210 self.erev = ''
211 self.enew = 1
212 self.edeleted = 0
213 self.eseen = 1 # Done
214 self.extra = ''
215
216 def setentry(self, erev, esum):
217 self.eseen = 0 # While we're hacking...
218 self.esum = esum
219 self.emtime, self.ectime = os.stat(self.file)[-2:]
220 self.erev = erev
221 self.enew = 0
222 self.edeleted = 0
223 self.eseen = 1 # Done
224 self.extra = ''
225
226
227 SENDMAIL = "/usr/lib/sendmail -t"
228 MAILFORM = """To: %s
229 Subject: CVS changes: %s
230
231 ...Message from rcvs...
232
233 Committed files:
234 %s
235
236 Log message:
237 %s
238 """
239
240
241 class RCVS(CVS):
242
243 FileClass = MyFile
244
245 def __init__(self):
246 CVS.__init__(self)
247
248 def update(self, files):
249 for e in self.whichentries(files, 1):
250 e.update()
251
252 def commit(self, files, message = ""):
253 list = self.whichentries(files)
254 if not list: return
255 ok = 1
256 for e in list:
257 if not e.commitcheck():
258 ok = 0
259 if not ok:
260 print "correct above errors first"
261 return
262 if not message:
263 message = raw_input("One-liner: ")
264 committed = []
265 for e in list:
266 if e.commit(message):
267 committed.append(e.file)
268 self.mailinfo(committed, message)
269
270 def mailinfo(self, files, message = ""):
271 towhom = "sjoerd@cwi.nl, jack@cwi.nl" # XXX
272 mailtext = MAILFORM % (towhom, string.join(files),
273 string.join(files), message)
274 print '-'*70
275 print mailtext
276 print '-'*70
277 ok = raw_input("OK to mail to %s? " % towhom)
278 if string.lower(string.strip(ok)) in ('y', 'ye', 'yes'):
279 p = os.popen(SENDMAIL, "w")
280 p.write(mailtext)
281 sts = p.close()
282 if sts:
283 print "Sendmail exit status %s" % str(sts)
284 else:
285 print "Mail sent."
286 else:
287 print "No mail sent."
288
289 def report(self, files):
290 for e in self.whichentries(files):
291 e.report()
292
293 def diff(self, files, opts):
294 for e in self.whichentries(files):
295 e.diff(opts)
296
297 def add(self, files):
298 if not files:
299 raise RuntimeError, "'cvs add' needs at least one file"
300 list = []
301 for e in self.whichentries(files, 1):
302 e.add()
303
304 def rm(self, files):
305 if not files:
306 raise RuntimeError, "'cvs rm' needs at least one file"
307 raise RuntimeError, "'cvs rm' not yet imlemented"
308
309 def log(self, files, opts):
310 flags = ''
311 for o, a in opts:
312 flags = flags + ' ' + o + a
313 for e in self.whichentries(files):
314 e.log(flags)
315
316 def whichentries(self, files, localfilestoo = 0):
317 if files:
318 list = []
319 for file in files:
320 if self.entries.has_key(file):
321 e = self.entries[file]
322 else:
323 e = self.FileClass(file)
324 self.entries[file] = e
325 list.append(e)
326 else:
327 list = self.entries.values()
328 for file in self.proxy.listfiles():
329 if self.entries.has_key(file):
330 continue
331 e = self.FileClass(file)
332 self.entries[file] = e
333 list.append(e)
334 if localfilestoo:
335 for file in os.listdir(os.curdir):
336 if not self.entries.has_key(file) \
337 and not self.ignored(file):
338 e = self.FileClass(file)
339 self.entries[file] = e
340 list.append(e)
341 list.sort()
342 if self.proxy:
343 for e in list:
344 if e.proxy is None:
345 e.proxy = self.proxy
346 return list
347
348
349 class rcvs(CommandFrameWork):
350
351 GlobalFlags = 'd:h:p:qvL'
352 UsageMessage = \
353 "usage: rcvs [-d directory] [-h host] [-p port] [-q] [-v] [subcommand arg ...]"
354 PostUsageMessage = \
355 "If no subcommand is given, the status of all files is listed"
356
357 def __init__(self):
358 """Constructor."""
359 CommandFrameWork.__init__(self)
360 self.proxy = None
361 self.cvs = RCVS()
362
363 def close(self):
364 if self.proxy:
365 self.proxy._close()
366 self.proxy = None
367
368 def recurse(self):
369 self.close()
370 names = os.listdir(os.curdir)
371 for name in names:
372 if name == os.curdir or name == os.pardir:
373 continue
374 if name == "CVS":
375 continue
376 if not os.path.isdir(name):
377 continue
378 if os.path.islink(name):
379 continue
380 print "--- entering subdirectory", name, "---"
381 os.chdir(name)
382 try:
383 if os.path.isdir("CVS"):
384 self.__class__().run()
385 else:
386 self.recurse()
387 finally:
388 os.chdir(os.pardir)
389 print "--- left subdirectory", name, "---"
390
391 def options(self, opts):
392 self.opts = opts
393
394 def ready(self):
395 import rcsclient
396 self.proxy = rcsclient.openrcsclient(self.opts)
397 self.cvs.setproxy(self.proxy)
398 self.cvs.getentries()
399
400 def default(self):
401 self.cvs.report([])
402
403 def do_report(self, opts, files):
404 self.cvs.report(files)
405
406 def do_update(self, opts, files):
407 """update [-l] [-R] [file] ..."""
408 local = DEF_LOCAL
409 for o, a in opts:
410 if o == '-l': local = 1
411 if o == '-R': local = 0
412 self.cvs.update(files)
413 self.cvs.putentries()
414 if not local and not files:
415 self.recurse()
416 flags_update = '-lR'
417 do_up = do_update
418 flags_up = flags_update
419
420 def do_commit(self, opts, files):
421 """commit [-m message] [file] ..."""
422 message = ""
423 for o, a in opts:
424 if o == '-m': message = a
425 self.cvs.commit(files, message)
426 self.cvs.putentries()
427 flags_commit = 'm:'
428 do_com = do_commit
429 flags_com = flags_commit
430
431 def do_diff(self, opts, files):
432 """diff [difflags] [file] ..."""
433 self.cvs.diff(files, opts)
434 flags_diff = 'cbitwcefhnlr:sD:S:'
435 do_dif = do_diff
436 flags_dif = flags_diff
437
438 def do_add(self, opts, files):
439 """add file ..."""
440 if not files:
441 print "'rcvs add' requires at least one file"
442 return
443 self.cvs.add(files)
444 self.cvs.putentries()
445
446 def do_remove(self, opts, files):
447 """remove file ..."""
448 if not files:
449 print "'rcvs remove' requires at least one file"
450 return
451 self.cvs.remove(files)
452 self.cvs.putentries()
453 do_rm = do_remove
454
455 def do_log(self, opts, files):
456 """log [rlog-options] [file] ..."""
457 self.cvs.log(files, opts)
458 flags_log = 'bhLNRtd:s:V:r:'
459
460
461 def remove(fn):
462 try:
463 os.unlink(fn)
464 except os.error:
465 pass
466
467
468 def main():
469 r = rcvs()
470 try:
471 r.run()
472 finally:
473 r.close()
474
475
476 if __name__ == "__main__":
477 main()