| 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()
|
|---|
|
|---|