symbian-qemu-0.9.1-12/python-2.6.1/Demo/pdist/rcvs.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     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()