blob: aeff6c88290a9645306d911d209248a9195f2f66 [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 """
Guido van Rossumec8cfd41995-05-01 20:06:44 +000037 if not self.lseen:
38 self.getlocal()
39 if not self.rseen:
40 self.getremote()
Guido van Rossumae21ced1995-04-28 14:32:26 +000041 if not self.eseen:
Guido van Rossum6bb4a511995-04-28 15:26:37 +000042 if not self.lseen:
43 if not self.rseen: return '0' # Never heard of
44 else:
45 return 'N' # New remotely
46 else: # self.lseen
47 if not self.rseen: return '?' # Local only
48 # Local and remote, but no entry
49 if self.lsum == self.rsum:
50 return 'c' # Restore entry only
51 else: return 'C' # Real conflict
52 else: # self.eseen
53 if not self.lseen:
54 if self.eremoved:
55 if self.rseen: return 'R' # Removed
56 else: return 'r' # Get rid of entry
57 else: # not self.eremoved
58 if self.rseen:
59 print "warning:",
60 print self.file,
61 print "was lost"
62 return 'U'
63 else: return 'r' # Get rid of entry
64 else: # self.lseen
65 if not self.rseen:
66 if self.enew: return 'A' # New locally
67 else: return 'D' # Deleted remotely
68 else: # self.rseen
69 if self.enew:
70 if self.lsum == self.rsum:
71 return 'u'
72 else:
73 return 'C'
74 if self.lsum == self.esum:
75 if self.esum == self.rsum:
76 return '='
77 else:
78 return 'U'
79 elif self.esum == self.rsum:
80 return 'M'
81 elif self.lsum == self.rsum:
82 return 'u'
83 else:
84 return 'C'
Guido van Rossumae21ced1995-04-28 14:32:26 +000085
86 def update(self):
87 code = self.action()
Guido van Rossum8b5e0fa1995-04-28 21:48:16 +000088 if code == '=': return
Guido van Rossumae21ced1995-04-28 14:32:26 +000089 print code, self.file
Guido van Rossumba244681995-04-28 15:33:03 +000090 if code in ('U', 'N'):
Guido van Rossumae21ced1995-04-28 14:32:26 +000091 self.get()
92 elif code == 'C':
93 print "%s: conflict resolution not yet implemented" % \
94 self.file
Guido van Rossumba244681995-04-28 15:33:03 +000095 elif code == 'D':
Guido van Rossum330e8841995-04-28 17:56:32 +000096 remove(self.file)
Guido van Rossumba244681995-04-28 15:33:03 +000097 self.eseen = 0
98 elif code == 'r':
99 self.eseen = 0
100 elif code in ('c', 'u'):
Guido van Rossumd22f59f1995-04-28 15:37:22 +0000101 self.eseen = 1
Guido van Rossumba244681995-04-28 15:33:03 +0000102 self.erev = self.rrev
103 self.enew = 0
104 self.edeleted = 0
105 self.esum = self.rsum
106 self.emtime, self.ectime = os.stat(self.file)[-2:]
Guido van Rossumd22f59f1995-04-28 15:37:22 +0000107 self.extra = ''
Guido van Rossumae21ced1995-04-28 14:32:26 +0000108
109 def commit(self, message = ""):
110 code = self.action()
111 if code in ('A', 'M'):
112 self.put(message)
113 elif code == 'R':
114 print "%s: committing removes not yet implemented" % \
115 self.file
116 elif code == 'C':
117 print "%s: conflict resolution not yet implemented" % \
118 self.file
119
Guido van Rossum330e8841995-04-28 17:56:32 +0000120 def diff(self, opts = []):
Guido van Rossumec8cfd41995-05-01 20:06:44 +0000121 self.action() # To update lseen, rseen
Guido van Rossum2d2a60e1995-04-28 19:24:50 +0000122 if self.lsum == self.rsum:
123 return
Guido van Rossum330e8841995-04-28 17:56:32 +0000124 import tempfile
125 flags = ''
126 for o, a in opts:
127 flags = flags + ' ' + o + a
128 flags = flags[1:]
129 fn = self.file
130 data = self.proxy.get(fn)
131 tfn = tempfile.mktemp()
132 try:
133 tf = open(tfn, 'w')
134 tf.write(data)
135 tf.close()
136 print 'diff %s -r%s %s' % (flags, self.rrev, fn)
137 sts = os.system('diff %s %s %s' % (flags, tfn, fn))
138 if sts:
139 print '='*70
140 finally:
141 remove(tfn)
142
Guido van Rossumae21ced1995-04-28 14:32:26 +0000143 def commitcheck(self):
144 return self.action() != 'C'
145
146 def put(self, message = ""):
Guido van Rossumbafc14d1995-04-28 15:41:51 +0000147 print "Checking in", self.file, "..."
148 data = open(self.file).read()
149 messages = self.proxy.put(self.file, data, message)
150 if messages:
151 print messages
Guido van Rossum8b5e0fa1995-04-28 21:48:16 +0000152 self.setentry(self.proxy.head(self.file), self.lsum)
Guido van Rossumae21ced1995-04-28 14:32:26 +0000153
154 def get(self):
155 data = self.proxy.get(self.file)
156 f = open(self.file, 'w')
157 f.write(data)
158 f.close()
Guido van Rossum8b5e0fa1995-04-28 21:48:16 +0000159 self.setentry(self.rrev, self.rsum)
160
161 def setentry(self, erev, esum):
162 self.eseen = 0 # While we're hacking...
163 self.esum = esum
Guido van Rossumae21ced1995-04-28 14:32:26 +0000164 self.emtime, self.ectime = os.stat(self.file)[-2:]
Guido van Rossum8b5e0fa1995-04-28 21:48:16 +0000165 self.erev = erev
Guido van Rossumae21ced1995-04-28 14:32:26 +0000166 self.enew = 0
167 self.edeleted = 0
Guido van Rossum8b5e0fa1995-04-28 21:48:16 +0000168 self.eseen = 1 # Done
Guido van Rossum5f07b841995-04-26 22:57:11 +0000169
170
Guido van Rossumc218a7e1995-04-27 23:33:43 +0000171class RCVS(CVS):
172
173 FileClass = MyFile
174
175 def __init__(self):
176 CVS.__init__(self)
177
Guido van Rossumec8cfd41995-05-01 20:06:44 +0000178 def update(self, files):
179 for e in self.whichentries(files, 1):
180 e.update()
181
182 def commit(self, files, message = ""):
183 list = self.whichentries(files)
184 ok = 1
185 for e in list:
186 if not e.commitcheck():
187 ok = 0
188 if not ok:
189 print "correct above errors first"
190 return
191 if not message:
192 message = raw_input("One-liner: ")
193 for e in list:
194 e.commit(message)
195
196 def report(self, files):
197 for e in self.whichentries(files):
198 e.report()
199
200 def diff(self, files, opts):
201 for e in self.whichentries(files):
202 e.diff(opts)
203
204 def whichentries(self, files, localfilestoo = 0):
205 if files:
206 list = []
Guido van Rossumae21ced1995-04-28 14:32:26 +0000207 for file in files:
Guido van Rossumec8cfd41995-05-01 20:06:44 +0000208 if self.entries.has_key(file):
209 e = self.entries[file]
210 else:
211 e = self.FileClass(file)
212 self.entries[file] = e
213 list.append(e)
214 else:
215 list = self.entries.values()
216 for file in self.proxy.listfiles():
217 if self.entries.has_key(file):
218 continue
219 e = self.FileClass(file)
220 self.entries[file] = e
221 list.append(e)
222 if localfilestoo:
223 for file in os.listdir(os.curdir):
224 if not self.entries.has_key(file) \
225 and not self.ignored(file):
226 e = self.FileClass(file)
227 self.entries[file] = e
228 list.append(e)
229 list.sort()
230 if self.proxy:
231 for e in list:
232 if e.proxy is None:
233 e.proxy = self.proxy
234 return list
Guido van Rossumc218a7e1995-04-27 23:33:43 +0000235
236
237class rcvs(CommandFrameWork):
238
239 GlobalFlags = 'd:h:p:qv'
240 UsageMessage = \
Guido van Rossum2d2a60e1995-04-28 19:24:50 +0000241"usage: rcvs [-d directory] [-h host] [-p port] [-q] [-v] [subcommand arg ...]"
242 PostUsageMessage = \
243 "If no subcommand is given, the status of all files is listed"
Guido van Rossumc218a7e1995-04-27 23:33:43 +0000244
245 def __init__(self):
246 """Constructor."""
247 CommandFrameWork.__init__(self)
248 self.proxy = None
249 self.cvs = RCVS()
250
251 def options(self, opts):
252 self.opts = opts
253
254 def ready(self):
255 import rcsclient
256 self.proxy = rcsclient.openrcsclient(self.opts)
257 self.cvs.setproxy(self.proxy)
258 self.cvs.getentries()
Guido van Rossumc218a7e1995-04-27 23:33:43 +0000259
260 def default(self):
Guido van Rossumec8cfd41995-05-01 20:06:44 +0000261 self.cvs.report([])
Guido van Rossumc218a7e1995-04-27 23:33:43 +0000262
263 def do_update(self, opts, files):
Guido van Rossumae21ced1995-04-28 14:32:26 +0000264 """update [file] ..."""
Guido van Rossumec8cfd41995-05-01 20:06:44 +0000265 self.cvs.update(files)
Guido van Rossum6bb4a511995-04-28 15:26:37 +0000266 self.cvs.putentries()
Guido van Rossum330e8841995-04-28 17:56:32 +0000267 do_up = do_update
Guido van Rossum5f07b841995-04-26 22:57:11 +0000268
Guido van Rossumae21ced1995-04-28 14:32:26 +0000269 def do_commit(self, opts, files):
Guido van Rossumec8cfd41995-05-01 20:06:44 +0000270 """commit [-m message] [file] ..."""
271 message = ""
272 for o, a in opts:
273 if o == '-m': message = a
274 self.cvs.commit(files, message)
Guido van Rossum6bb4a511995-04-28 15:26:37 +0000275 self.cvs.putentries()
Guido van Rossum330e8841995-04-28 17:56:32 +0000276 do_com = do_commit
Guido van Rossumec8cfd41995-05-01 20:06:44 +0000277 flags_commit = 'm:'
Guido van Rossum330e8841995-04-28 17:56:32 +0000278
279 def do_diff(self, opts, files):
280 """diff [difflags] [file] ..."""
Guido van Rossumec8cfd41995-05-01 20:06:44 +0000281 self.cvs.diff(files, opts)
Guido van Rossum330e8841995-04-28 17:56:32 +0000282 do_dif = do_diff
283 flags_diff = 'cbitwcefhnlrsD:S:'
284
285
286
287def remove(fn):
288 try:
289 os.unlink(fn)
290 except os.error:
291 pass
Guido van Rossumae21ced1995-04-28 14:32:26 +0000292
Guido van Rossum5f07b841995-04-26 22:57:11 +0000293
Guido van Rossumdeb627c1995-04-27 21:28:53 +0000294def main():
Guido van Rossumc218a7e1995-04-27 23:33:43 +0000295 rcvs().run()
Guido van Rossum097c55a1995-04-27 18:07:07 +0000296
Guido van Rossum5f07b841995-04-26 22:57:11 +0000297
298if __name__ == "__main__":
Guido van Rossumdeb627c1995-04-27 21:28:53 +0000299 main()