blob: 016aa1e4fd62b1ce35ad7ca1ee9f59a86b5e1e50 [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 Rossum2f7ef911995-05-01 20:22:01 +000036
37 (and probably others :-)
Guido van Rossumae21ced1995-04-28 14:32:26 +000038 """
Guido van Rossumec8cfd41995-05-01 20:06:44 +000039 if not self.lseen:
40 self.getlocal()
41 if not self.rseen:
42 self.getremote()
Guido van Rossumae21ced1995-04-28 14:32:26 +000043 if not self.eseen:
Guido van Rossum2f7ef911995-05-01 20:22:01 +000044 if not self.lsum:
45 if not self.rsum: return '0' # Never heard of
Guido van Rossum6bb4a511995-04-28 15:26:37 +000046 else:
47 return 'N' # New remotely
Guido van Rossum2f7ef911995-05-01 20:22:01 +000048 else: # self.lsum
49 if not self.rsum: return '?' # Local only
Guido van Rossum6bb4a511995-04-28 15:26:37 +000050 # Local and remote, but no entry
51 if self.lsum == self.rsum:
52 return 'c' # Restore entry only
53 else: return 'C' # Real conflict
54 else: # self.eseen
Guido van Rossum2f7ef911995-05-01 20:22:01 +000055 if not self.lsum:
56 if self.edeleted:
57 if self.rsum: return 'R' # Removed
Guido van Rossum6bb4a511995-04-28 15:26:37 +000058 else: return 'r' # Get rid of entry
Guido van Rossum2f7ef911995-05-01 20:22:01 +000059 else: # not self.edeleted
60 if self.rsum:
Guido van Rossum6bb4a511995-04-28 15:26:37 +000061 print "warning:",
62 print self.file,
63 print "was lost"
64 return 'U'
65 else: return 'r' # Get rid of entry
Guido van Rossum2f7ef911995-05-01 20:22:01 +000066 else: # self.lsum
67 if not self.rsum:
Guido van Rossum6bb4a511995-04-28 15:26:37 +000068 if self.enew: return 'A' # New locally
69 else: return 'D' # Deleted remotely
Guido van Rossum2f7ef911995-05-01 20:22:01 +000070 else: # self.rsum
Guido van Rossum6bb4a511995-04-28 15:26:37 +000071 if self.enew:
72 if self.lsum == self.rsum:
73 return 'u'
74 else:
75 return 'C'
76 if self.lsum == self.esum:
77 if self.esum == self.rsum:
78 return '='
79 else:
80 return 'U'
81 elif self.esum == self.rsum:
82 return 'M'
83 elif self.lsum == self.rsum:
84 return 'u'
85 else:
86 return 'C'
Guido van Rossumae21ced1995-04-28 14:32:26 +000087
88 def update(self):
89 code = self.action()
Guido van Rossum8b5e0fa1995-04-28 21:48:16 +000090 if code == '=': return
Guido van Rossumae21ced1995-04-28 14:32:26 +000091 print code, self.file
Guido van Rossumba244681995-04-28 15:33:03 +000092 if code in ('U', 'N'):
Guido van Rossumae21ced1995-04-28 14:32:26 +000093 self.get()
94 elif code == 'C':
95 print "%s: conflict resolution not yet implemented" % \
96 self.file
Guido van Rossumba244681995-04-28 15:33:03 +000097 elif code == 'D':
Guido van Rossum330e8841995-04-28 17:56:32 +000098 remove(self.file)
Guido van Rossumba244681995-04-28 15:33:03 +000099 self.eseen = 0
100 elif code == 'r':
101 self.eseen = 0
102 elif code in ('c', 'u'):
Guido van Rossumd22f59f1995-04-28 15:37:22 +0000103 self.eseen = 1
Guido van Rossumba244681995-04-28 15:33:03 +0000104 self.erev = self.rrev
105 self.enew = 0
106 self.edeleted = 0
107 self.esum = self.rsum
108 self.emtime, self.ectime = os.stat(self.file)[-2:]
Guido van Rossumd22f59f1995-04-28 15:37:22 +0000109 self.extra = ''
Guido van Rossumae21ced1995-04-28 14:32:26 +0000110
111 def commit(self, message = ""):
112 code = self.action()
113 if code in ('A', 'M'):
114 self.put(message)
115 elif code == 'R':
116 print "%s: committing removes not yet implemented" % \
117 self.file
118 elif code == 'C':
119 print "%s: conflict resolution not yet implemented" % \
120 self.file
121
Guido van Rossum330e8841995-04-28 17:56:32 +0000122 def diff(self, opts = []):
Guido van Rossumec8cfd41995-05-01 20:06:44 +0000123 self.action() # To update lseen, rseen
Guido van Rossum2d2a60e1995-04-28 19:24:50 +0000124 if self.lsum == self.rsum:
125 return
Guido van Rossum330e8841995-04-28 17:56:32 +0000126 import tempfile
127 flags = ''
128 for o, a in opts:
129 flags = flags + ' ' + o + a
130 flags = flags[1:]
131 fn = self.file
132 data = self.proxy.get(fn)
133 tfn = tempfile.mktemp()
134 try:
135 tf = open(tfn, 'w')
136 tf.write(data)
137 tf.close()
138 print 'diff %s -r%s %s' % (flags, self.rrev, fn)
139 sts = os.system('diff %s %s %s' % (flags, tfn, fn))
140 if sts:
141 print '='*70
142 finally:
143 remove(tfn)
144
Guido van Rossumae21ced1995-04-28 14:32:26 +0000145 def commitcheck(self):
146 return self.action() != 'C'
147
148 def put(self, message = ""):
Guido van Rossumbafc14d1995-04-28 15:41:51 +0000149 print "Checking in", self.file, "..."
150 data = open(self.file).read()
151 messages = self.proxy.put(self.file, data, message)
152 if messages:
153 print messages
Guido van Rossum8b5e0fa1995-04-28 21:48:16 +0000154 self.setentry(self.proxy.head(self.file), self.lsum)
Guido van Rossumae21ced1995-04-28 14:32:26 +0000155
156 def get(self):
157 data = self.proxy.get(self.file)
158 f = open(self.file, 'w')
159 f.write(data)
160 f.close()
Guido van Rossum8b5e0fa1995-04-28 21:48:16 +0000161 self.setentry(self.rrev, self.rsum)
162
163 def setentry(self, erev, esum):
164 self.eseen = 0 # While we're hacking...
165 self.esum = esum
Guido van Rossumae21ced1995-04-28 14:32:26 +0000166 self.emtime, self.ectime = os.stat(self.file)[-2:]
Guido van Rossum8b5e0fa1995-04-28 21:48:16 +0000167 self.erev = erev
Guido van Rossumae21ced1995-04-28 14:32:26 +0000168 self.enew = 0
169 self.edeleted = 0
Guido van Rossum8b5e0fa1995-04-28 21:48:16 +0000170 self.eseen = 1 # Done
Guido van Rossum5f07b841995-04-26 22:57:11 +0000171
172
Guido van Rossumc218a7e1995-04-27 23:33:43 +0000173class RCVS(CVS):
174
175 FileClass = MyFile
176
177 def __init__(self):
178 CVS.__init__(self)
179
Guido van Rossumec8cfd41995-05-01 20:06:44 +0000180 def update(self, files):
181 for e in self.whichentries(files, 1):
182 e.update()
183
184 def commit(self, files, message = ""):
185 list = self.whichentries(files)
186 ok = 1
187 for e in list:
188 if not e.commitcheck():
189 ok = 0
190 if not ok:
191 print "correct above errors first"
192 return
193 if not message:
194 message = raw_input("One-liner: ")
195 for e in list:
196 e.commit(message)
197
198 def report(self, files):
199 for e in self.whichentries(files):
200 e.report()
201
202 def diff(self, files, opts):
203 for e in self.whichentries(files):
204 e.diff(opts)
205
206 def whichentries(self, files, localfilestoo = 0):
207 if files:
208 list = []
Guido van Rossumae21ced1995-04-28 14:32:26 +0000209 for file in files:
Guido van Rossumec8cfd41995-05-01 20:06:44 +0000210 if self.entries.has_key(file):
211 e = self.entries[file]
212 else:
213 e = self.FileClass(file)
214 self.entries[file] = e
215 list.append(e)
216 else:
217 list = self.entries.values()
218 for file in self.proxy.listfiles():
219 if self.entries.has_key(file):
220 continue
221 e = self.FileClass(file)
222 self.entries[file] = e
223 list.append(e)
224 if localfilestoo:
225 for file in os.listdir(os.curdir):
226 if not self.entries.has_key(file) \
227 and not self.ignored(file):
228 e = self.FileClass(file)
229 self.entries[file] = e
230 list.append(e)
231 list.sort()
232 if self.proxy:
233 for e in list:
234 if e.proxy is None:
235 e.proxy = self.proxy
236 return list
Guido van Rossumc218a7e1995-04-27 23:33:43 +0000237
238
239class rcvs(CommandFrameWork):
240
241 GlobalFlags = 'd:h:p:qv'
242 UsageMessage = \
Guido van Rossum2d2a60e1995-04-28 19:24:50 +0000243"usage: rcvs [-d directory] [-h host] [-p port] [-q] [-v] [subcommand arg ...]"
244 PostUsageMessage = \
245 "If no subcommand is given, the status of all files is listed"
Guido van Rossumc218a7e1995-04-27 23:33:43 +0000246
247 def __init__(self):
248 """Constructor."""
249 CommandFrameWork.__init__(self)
250 self.proxy = None
251 self.cvs = RCVS()
252
253 def options(self, opts):
254 self.opts = opts
255
256 def ready(self):
257 import rcsclient
258 self.proxy = rcsclient.openrcsclient(self.opts)
259 self.cvs.setproxy(self.proxy)
260 self.cvs.getentries()
Guido van Rossumc218a7e1995-04-27 23:33:43 +0000261
262 def default(self):
Guido van Rossumec8cfd41995-05-01 20:06:44 +0000263 self.cvs.report([])
Guido van Rossumc218a7e1995-04-27 23:33:43 +0000264
265 def do_update(self, opts, files):
Guido van Rossumae21ced1995-04-28 14:32:26 +0000266 """update [file] ..."""
Guido van Rossumec8cfd41995-05-01 20:06:44 +0000267 self.cvs.update(files)
Guido van Rossum6bb4a511995-04-28 15:26:37 +0000268 self.cvs.putentries()
Guido van Rossum330e8841995-04-28 17:56:32 +0000269 do_up = do_update
Guido van Rossum5f07b841995-04-26 22:57:11 +0000270
Guido van Rossumae21ced1995-04-28 14:32:26 +0000271 def do_commit(self, opts, files):
Guido van Rossumec8cfd41995-05-01 20:06:44 +0000272 """commit [-m message] [file] ..."""
273 message = ""
274 for o, a in opts:
275 if o == '-m': message = a
276 self.cvs.commit(files, message)
Guido van Rossum6bb4a511995-04-28 15:26:37 +0000277 self.cvs.putentries()
Guido van Rossum330e8841995-04-28 17:56:32 +0000278 do_com = do_commit
Guido van Rossumec8cfd41995-05-01 20:06:44 +0000279 flags_commit = 'm:'
Guido van Rossum330e8841995-04-28 17:56:32 +0000280
281 def do_diff(self, opts, files):
282 """diff [difflags] [file] ..."""
Guido van Rossumec8cfd41995-05-01 20:06:44 +0000283 self.cvs.diff(files, opts)
Guido van Rossum330e8841995-04-28 17:56:32 +0000284 do_dif = do_diff
285 flags_diff = 'cbitwcefhnlrsD:S:'
286
287
288
289def remove(fn):
290 try:
291 os.unlink(fn)
292 except os.error:
293 pass
Guido van Rossumae21ced1995-04-28 14:32:26 +0000294
Guido van Rossum5f07b841995-04-26 22:57:11 +0000295
Guido van Rossumdeb627c1995-04-27 21:28:53 +0000296def main():
Guido van Rossumc218a7e1995-04-27 23:33:43 +0000297 rcvs().run()
Guido van Rossum097c55a1995-04-27 18:07:07 +0000298
Guido van Rossum5f07b841995-04-26 22:57:11 +0000299
300if __name__ == "__main__":
Guido van Rossumdeb627c1995-04-27 21:28:53 +0000301 main()