blob: 9d14ad4943ffed076ce5b42eb059400e62c11f55 [file] [log] [blame]
Guido van Rossum097c55a1995-04-27 18:07:07 +00001#! /usr/local/bin/python
2
Guido van Rossumc218a7e1995-04-27 23:33:43 +00003"""Remote CVS -- command line interface"""
Guido van Rossum097c55a1995-04-27 18:07:07 +00004
Guido van Rossumc218a7e1995-04-27 23:33:43 +00005from cvslib import CVS, File
Guido van Rossum5f07b841995-04-26 22:57:11 +00006import md5
7import os
8import string
9import sys
Guido van Rossumc218a7e1995-04-27 23:33:43 +000010from cmdfw import CommandFrameWork
Guido van Rossum5f07b841995-04-26 22:57:11 +000011
12
Guido van Rossumc218a7e1995-04-27 23:33:43 +000013class MyFile(File):
Guido van Rossum5f07b841995-04-26 22:57:11 +000014
Guido van Rossumae21ced1995-04-28 14:32:26 +000015 def action(self):
16 """Return a code indicating the update status of this file.
17
18 The possible return values are:
Guido van Rossumc218a7e1995-04-27 23:33:43 +000019
Guido van Rossumae21ced1995-04-28 14:32:26 +000020 '=' -- everything's fine
21 '0' -- file doesn't exist anywhere
22 '?' -- exists locally only
23 'A' -- new locally
24 'R' -- deleted locally
25 'U' -- changed remotely, no changes locally
Guido van Rossum6bb4a511995-04-28 15:26:37 +000026 (includes new remotely or deleted remotely)
Guido van Rossumae21ced1995-04-28 14:32:26 +000027 'M' -- changed locally, no changes remotely
28 'C' -- conflict: changed locally as well as remotely
29 (includes cases where the file has been added
30 or removed locally and remotely)
Guido van Rossumba244681995-04-28 15:33:03 +000031 'D' -- deleted remotely
32 'N' -- new remotely
Guido van Rossum6bb4a511995-04-28 15:26:37 +000033 'r' -- get rid of entry
34 'c' -- create entry
35 'u' -- update entry
Guido van Rossumae21ced1995-04-28 14:32:26 +000036 """
37 if not self.eseen:
Guido van Rossum6bb4a511995-04-28 15:26:37 +000038 if not self.lseen:
39 if not self.rseen: return '0' # Never heard of
40 else:
41 return 'N' # New remotely
42 else: # self.lseen
43 if not self.rseen: return '?' # Local only
44 # Local and remote, but no entry
45 if self.lsum == self.rsum:
46 return 'c' # Restore entry only
47 else: return 'C' # Real conflict
48 else: # self.eseen
49 if not self.lseen:
50 if self.eremoved:
51 if self.rseen: return 'R' # Removed
52 else: return 'r' # Get rid of entry
53 else: # not self.eremoved
54 if self.rseen:
55 print "warning:",
56 print self.file,
57 print "was lost"
58 return 'U'
59 else: return 'r' # Get rid of entry
60 else: # self.lseen
61 if not self.rseen:
62 if self.enew: return 'A' # New locally
63 else: return 'D' # Deleted remotely
64 else: # self.rseen
65 if self.enew:
66 if self.lsum == self.rsum:
67 return 'u'
68 else:
69 return 'C'
70 if self.lsum == self.esum:
71 if self.esum == self.rsum:
72 return '='
73 else:
74 return 'U'
75 elif self.esum == self.rsum:
76 return 'M'
77 elif self.lsum == self.rsum:
78 return 'u'
79 else:
80 return 'C'
Guido van Rossumae21ced1995-04-28 14:32:26 +000081
82 def update(self):
83 code = self.action()
Guido van Rossum8b5e0fa1995-04-28 21:48:16 +000084 if code == '=': return
Guido van Rossumae21ced1995-04-28 14:32:26 +000085 print code, self.file
Guido van Rossumba244681995-04-28 15:33:03 +000086 if code in ('U', 'N'):
Guido van Rossumae21ced1995-04-28 14:32:26 +000087 self.get()
88 elif code == 'C':
89 print "%s: conflict resolution not yet implemented" % \
90 self.file
Guido van Rossumba244681995-04-28 15:33:03 +000091 elif code == 'D':
Guido van Rossum330e8841995-04-28 17:56:32 +000092 remove(self.file)
Guido van Rossumba244681995-04-28 15:33:03 +000093 self.eseen = 0
94 elif code == 'r':
95 self.eseen = 0
96 elif code in ('c', 'u'):
Guido van Rossumd22f59f1995-04-28 15:37:22 +000097 self.eseen = 1
Guido van Rossumba244681995-04-28 15:33:03 +000098 self.erev = self.rrev
99 self.enew = 0
100 self.edeleted = 0
101 self.esum = self.rsum
102 self.emtime, self.ectime = os.stat(self.file)[-2:]
Guido van Rossumd22f59f1995-04-28 15:37:22 +0000103 self.extra = ''
Guido van Rossumae21ced1995-04-28 14:32:26 +0000104
105 def commit(self, message = ""):
106 code = self.action()
107 if code in ('A', 'M'):
108 self.put(message)
109 elif code == 'R':
110 print "%s: committing removes not yet implemented" % \
111 self.file
112 elif code == 'C':
113 print "%s: conflict resolution not yet implemented" % \
114 self.file
115
Guido van Rossum330e8841995-04-28 17:56:32 +0000116 def diff(self, opts = []):
Guido van Rossum2d2a60e1995-04-28 19:24:50 +0000117 if self.lsum == self.rsum:
118 return
Guido van Rossum330e8841995-04-28 17:56:32 +0000119 import tempfile
120 flags = ''
121 for o, a in opts:
122 flags = flags + ' ' + o + a
123 flags = flags[1:]
124 fn = self.file
125 data = self.proxy.get(fn)
126 tfn = tempfile.mktemp()
127 try:
128 tf = open(tfn, 'w')
129 tf.write(data)
130 tf.close()
131 print 'diff %s -r%s %s' % (flags, self.rrev, fn)
132 sts = os.system('diff %s %s %s' % (flags, tfn, fn))
133 if sts:
134 print '='*70
135 finally:
136 remove(tfn)
137
Guido van Rossumae21ced1995-04-28 14:32:26 +0000138 def commitcheck(self):
139 return self.action() != 'C'
140
141 def put(self, message = ""):
Guido van Rossumbafc14d1995-04-28 15:41:51 +0000142 print "Checking in", self.file, "..."
143 data = open(self.file).read()
144 messages = self.proxy.put(self.file, data, message)
145 if messages:
146 print messages
Guido van Rossum8b5e0fa1995-04-28 21:48:16 +0000147 self.setentry(self.proxy.head(self.file), self.lsum)
Guido van Rossumae21ced1995-04-28 14:32:26 +0000148
149 def get(self):
150 data = self.proxy.get(self.file)
151 f = open(self.file, 'w')
152 f.write(data)
153 f.close()
Guido van Rossum8b5e0fa1995-04-28 21:48:16 +0000154 self.setentry(self.rrev, self.rsum)
155
156 def setentry(self, erev, esum):
157 self.eseen = 0 # While we're hacking...
158 self.esum = esum
Guido van Rossumae21ced1995-04-28 14:32:26 +0000159 self.emtime, self.ectime = os.stat(self.file)[-2:]
Guido van Rossum8b5e0fa1995-04-28 21:48:16 +0000160 self.erev = erev
Guido van Rossumae21ced1995-04-28 14:32:26 +0000161 self.enew = 0
162 self.edeleted = 0
Guido van Rossum8b5e0fa1995-04-28 21:48:16 +0000163 self.eseen = 1 # Done
Guido van Rossum5f07b841995-04-26 22:57:11 +0000164
165
Guido van Rossumc218a7e1995-04-27 23:33:43 +0000166class RCVS(CVS):
167
168 FileClass = MyFile
169
170 def __init__(self):
171 CVS.__init__(self)
172
173 def checkfiles(self, files):
174 if not files:
175 def ok(file, self=self):
176 e = self.entries[file]
177 return e.eseen or e.rseen
178 files[:] = filter(ok, self.entries.keys())
179 files.sort()
Guido van Rossumae21ced1995-04-28 14:32:26 +0000180 if not files:
181 print "no files to be processed"
182 return 1
183 else:
184 return None
185 else:
186 sts = None
187 for file in files:
188 if not self.entries.has_key(file):
189 print "%s: nothing known" % file
190 sts = 1
191 return sts
Guido van Rossumc218a7e1995-04-27 23:33:43 +0000192
193
194class rcvs(CommandFrameWork):
195
196 GlobalFlags = 'd:h:p:qv'
197 UsageMessage = \
Guido van Rossum2d2a60e1995-04-28 19:24:50 +0000198"usage: rcvs [-d directory] [-h host] [-p port] [-q] [-v] [subcommand arg ...]"
199 PostUsageMessage = \
200 "If no subcommand is given, the status of all files is listed"
Guido van Rossumc218a7e1995-04-27 23:33:43 +0000201
202 def __init__(self):
203 """Constructor."""
204 CommandFrameWork.__init__(self)
205 self.proxy = None
206 self.cvs = RCVS()
207
208 def options(self, opts):
209 self.opts = opts
210
211 def ready(self):
212 import rcsclient
213 self.proxy = rcsclient.openrcsclient(self.opts)
214 self.cvs.setproxy(self.proxy)
215 self.cvs.getentries()
216 self.cvs.getlocalfiles()
217 self.cvs.getremotefiles(self.proxy)
218
219 def default(self):
Guido van Rossumae21ced1995-04-28 14:32:26 +0000220 files = []
221 if self.cvs.checkfiles(files):
222 return 1
Guido van Rossum6bb4a511995-04-28 15:26:37 +0000223 for file in files:
224 print self.cvs.entries[file].action(), file
Guido van Rossumc218a7e1995-04-27 23:33:43 +0000225
226 def do_update(self, opts, files):
Guido van Rossumae21ced1995-04-28 14:32:26 +0000227 """update [file] ..."""
228 if self.cvs.checkfiles(files):
229 return 1
Guido van Rossumc218a7e1995-04-27 23:33:43 +0000230 for file in files:
231 if not self.cvs.entries.has_key(file):
232 print "%s: not found" % file
233 else:
234 self.cvs.entries[file].update()
Guido van Rossum6bb4a511995-04-28 15:26:37 +0000235 self.cvs.putentries()
Guido van Rossum330e8841995-04-28 17:56:32 +0000236 do_up = do_update
Guido van Rossum5f07b841995-04-26 22:57:11 +0000237
Guido van Rossumae21ced1995-04-28 14:32:26 +0000238 def do_commit(self, opts, files):
239 """commit [file] ..."""
240 if self.cvs.checkfiles(files):
241 return 1
242 sts = 0
243 for file in files:
Guido van Rossum6bb4a511995-04-28 15:26:37 +0000244 if not self.cvs.entries[file].commitcheck():
Guido van Rossumae21ced1995-04-28 14:32:26 +0000245 sts = 1
246 if sts:
247 return sts
248 message = raw_input("One-liner: ")
249 for file in files:
Guido van Rossum6bb4a511995-04-28 15:26:37 +0000250 self.cvs.entries[file].commit(message)
251 self.cvs.putentries()
Guido van Rossum330e8841995-04-28 17:56:32 +0000252 do_com = do_commit
253
254 def do_diff(self, opts, files):
255 """diff [difflags] [file] ..."""
256 if self.cvs.checkfiles(files):
257 return 1
258 for file in files:
259 self.cvs.entries[file].diff(opts)
260 do_dif = do_diff
261 flags_diff = 'cbitwcefhnlrsD:S:'
262
263
264
265def remove(fn):
266 try:
267 os.unlink(fn)
268 except os.error:
269 pass
Guido van Rossumae21ced1995-04-28 14:32:26 +0000270
Guido van Rossum5f07b841995-04-26 22:57:11 +0000271
Guido van Rossumdeb627c1995-04-27 21:28:53 +0000272def main():
Guido van Rossumc218a7e1995-04-27 23:33:43 +0000273 rcvs().run()
Guido van Rossum097c55a1995-04-27 18:07:07 +0000274
Guido van Rossum5f07b841995-04-26 22:57:11 +0000275
276if __name__ == "__main__":
Guido van Rossumdeb627c1995-04-27 21:28:53 +0000277 main()