blob: aeff6c88290a9645306d911d209248a9195f2f66 [file] [log] [blame]
#! /usr/local/bin/python
"""Remote CVS -- command line interface"""
from cvslib import CVS, File
import md5
import os
import string
import sys
from cmdfw import CommandFrameWork
class MyFile(File):
def action(self):
"""Return a code indicating the update status of this file.
The possible return values are:
'=' -- everything's fine
'0' -- file doesn't exist anywhere
'?' -- exists locally only
'A' -- new locally
'R' -- deleted locally
'U' -- changed remotely, no changes locally
(includes new remotely or deleted remotely)
'M' -- changed locally, no changes remotely
'C' -- conflict: changed locally as well as remotely
(includes cases where the file has been added
or removed locally and remotely)
'D' -- deleted remotely
'N' -- new remotely
'r' -- get rid of entry
'c' -- create entry
'u' -- update entry
"""
if not self.lseen:
self.getlocal()
if not self.rseen:
self.getremote()
if not self.eseen:
if not self.lseen:
if not self.rseen: return '0' # Never heard of
else:
return 'N' # New remotely
else: # self.lseen
if not self.rseen: return '?' # Local only
# Local and remote, but no entry
if self.lsum == self.rsum:
return 'c' # Restore entry only
else: return 'C' # Real conflict
else: # self.eseen
if not self.lseen:
if self.eremoved:
if self.rseen: return 'R' # Removed
else: return 'r' # Get rid of entry
else: # not self.eremoved
if self.rseen:
print "warning:",
print self.file,
print "was lost"
return 'U'
else: return 'r' # Get rid of entry
else: # self.lseen
if not self.rseen:
if self.enew: return 'A' # New locally
else: return 'D' # Deleted remotely
else: # self.rseen
if self.enew:
if self.lsum == self.rsum:
return 'u'
else:
return 'C'
if self.lsum == self.esum:
if self.esum == self.rsum:
return '='
else:
return 'U'
elif self.esum == self.rsum:
return 'M'
elif self.lsum == self.rsum:
return 'u'
else:
return 'C'
def update(self):
code = self.action()
if code == '=': return
print code, self.file
if code in ('U', 'N'):
self.get()
elif code == 'C':
print "%s: conflict resolution not yet implemented" % \
self.file
elif code == 'D':
remove(self.file)
self.eseen = 0
elif code == 'r':
self.eseen = 0
elif code in ('c', 'u'):
self.eseen = 1
self.erev = self.rrev
self.enew = 0
self.edeleted = 0
self.esum = self.rsum
self.emtime, self.ectime = os.stat(self.file)[-2:]
self.extra = ''
def commit(self, message = ""):
code = self.action()
if code in ('A', 'M'):
self.put(message)
elif code == 'R':
print "%s: committing removes not yet implemented" % \
self.file
elif code == 'C':
print "%s: conflict resolution not yet implemented" % \
self.file
def diff(self, opts = []):
self.action() # To update lseen, rseen
if self.lsum == self.rsum:
return
import tempfile
flags = ''
for o, a in opts:
flags = flags + ' ' + o + a
flags = flags[1:]
fn = self.file
data = self.proxy.get(fn)
tfn = tempfile.mktemp()
try:
tf = open(tfn, 'w')
tf.write(data)
tf.close()
print 'diff %s -r%s %s' % (flags, self.rrev, fn)
sts = os.system('diff %s %s %s' % (flags, tfn, fn))
if sts:
print '='*70
finally:
remove(tfn)
def commitcheck(self):
return self.action() != 'C'
def put(self, message = ""):
print "Checking in", self.file, "..."
data = open(self.file).read()
messages = self.proxy.put(self.file, data, message)
if messages:
print messages
self.setentry(self.proxy.head(self.file), self.lsum)
def get(self):
data = self.proxy.get(self.file)
f = open(self.file, 'w')
f.write(data)
f.close()
self.setentry(self.rrev, self.rsum)
def setentry(self, erev, esum):
self.eseen = 0 # While we're hacking...
self.esum = esum
self.emtime, self.ectime = os.stat(self.file)[-2:]
self.erev = erev
self.enew = 0
self.edeleted = 0
self.eseen = 1 # Done
class RCVS(CVS):
FileClass = MyFile
def __init__(self):
CVS.__init__(self)
def update(self, files):
for e in self.whichentries(files, 1):
e.update()
def commit(self, files, message = ""):
list = self.whichentries(files)
ok = 1
for e in list:
if not e.commitcheck():
ok = 0
if not ok:
print "correct above errors first"
return
if not message:
message = raw_input("One-liner: ")
for e in list:
e.commit(message)
def report(self, files):
for e in self.whichentries(files):
e.report()
def diff(self, files, opts):
for e in self.whichentries(files):
e.diff(opts)
def whichentries(self, files, localfilestoo = 0):
if files:
list = []
for file in files:
if self.entries.has_key(file):
e = self.entries[file]
else:
e = self.FileClass(file)
self.entries[file] = e
list.append(e)
else:
list = self.entries.values()
for file in self.proxy.listfiles():
if self.entries.has_key(file):
continue
e = self.FileClass(file)
self.entries[file] = e
list.append(e)
if localfilestoo:
for file in os.listdir(os.curdir):
if not self.entries.has_key(file) \
and not self.ignored(file):
e = self.FileClass(file)
self.entries[file] = e
list.append(e)
list.sort()
if self.proxy:
for e in list:
if e.proxy is None:
e.proxy = self.proxy
return list
class rcvs(CommandFrameWork):
GlobalFlags = 'd:h:p:qv'
UsageMessage = \
"usage: rcvs [-d directory] [-h host] [-p port] [-q] [-v] [subcommand arg ...]"
PostUsageMessage = \
"If no subcommand is given, the status of all files is listed"
def __init__(self):
"""Constructor."""
CommandFrameWork.__init__(self)
self.proxy = None
self.cvs = RCVS()
def options(self, opts):
self.opts = opts
def ready(self):
import rcsclient
self.proxy = rcsclient.openrcsclient(self.opts)
self.cvs.setproxy(self.proxy)
self.cvs.getentries()
def default(self):
self.cvs.report([])
def do_update(self, opts, files):
"""update [file] ..."""
self.cvs.update(files)
self.cvs.putentries()
do_up = do_update
def do_commit(self, opts, files):
"""commit [-m message] [file] ..."""
message = ""
for o, a in opts:
if o == '-m': message = a
self.cvs.commit(files, message)
self.cvs.putentries()
do_com = do_commit
flags_commit = 'm:'
def do_diff(self, opts, files):
"""diff [difflags] [file] ..."""
self.cvs.diff(files, opts)
do_dif = do_diff
flags_diff = 'cbitwcefhnlrsD:S:'
def remove(fn):
try:
os.unlink(fn)
except os.error:
pass
def main():
rcvs().run()
if __name__ == "__main__":
main()