1f06ee5fa072931fc807527535c91a46c149a6746Guido van Rossum#! /usr/bin/env python
25f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossum
34d4ee8bdb0023df9dba6f005a1e58efbf0962df0Guido van Rossum"Remote RCS -- command line interface"
44d4ee8bdb0023df9dba6f005a1e58efbf0962df0Guido van Rossum
55f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossumimport sys
65f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossumimport os
75f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossumimport getopt
85f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossumimport string
95f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossumimport md5
105f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossumimport tempfile
114d4ee8bdb0023df9dba6f005a1e58efbf0962df0Guido van Rossumfrom rcsclient import openrcsclient
125f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossum
135f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossumdef main():
14e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    sys.stdout = sys.stderr
15e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    try:
16e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        opts, rest = getopt.getopt(sys.argv[1:], 'h:p:d:qvL')
17e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        if not rest:
18e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters            cmd = 'head'
19e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        else:
20e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters            cmd, rest = rest[0], rest[1:]
21e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        if not commands.has_key(cmd):
22e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters            raise getopt.error, "unknown command"
23e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        coptset, func = commands[cmd]
24e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        copts, files = getopt.getopt(rest, coptset)
25e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    except getopt.error, msg:
26e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        print msg
27e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        print "usage: rrcs [options] command [options] [file] ..."
28e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        print "where command can be:"
29e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        print "      ci|put      # checkin the given files"
30e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        print "      co|get      # checkout"
31e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        print "      info        # print header info"
32e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        print "      head        # print revision of head branch"
33e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        print "      list        # list filename if valid"
34e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        print "      log         # print full log"
35e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        print "      diff        # diff rcs file and work file"
36e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        print "if no files are given, all remote rcs files are assumed"
37e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        sys.exit(2)
38e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    x = openrcsclient(opts)
39e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    if not files:
40e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        files = x.listfiles()
41e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    for fn in files:
42e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        try:
43e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters            func(x, copts, fn)
44e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        except (IOError, os.error), msg:
45e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters            print "%s: %s" % (fn, msg)
465f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossum
475f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossumdef checkin(x, copts, fn):
48e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    f = open(fn)
49e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    data = f.read()
50e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    f.close()
51e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    new = not x.isvalid(fn)
52e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    if not new and same(x, copts, fn, data):
53e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        print "%s: unchanged since last checkin" % fn
54e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        return
55e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    print "Checking in", fn, "..."
56e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    message = asklogmessage(new)
57e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    messages = x.put(fn, data, message)
58e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    if messages:
59e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        print messages
605f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossum
615f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossumdef checkout(x, copts, fn):
62e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    data = x.get(fn)
63e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    f = open(fn, 'w')
64e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    f.write(data)
65e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    f.close()
665f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossum
67ff99a72f53ca1007403e1bf3fcc2c6800370119bGuido van Rossumdef lock(x, copts, fn):
68e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    x.lock(fn)
69ff99a72f53ca1007403e1bf3fcc2c6800370119bGuido van Rossum
70ff99a72f53ca1007403e1bf3fcc2c6800370119bGuido van Rossumdef unlock(x, copts, fn):
71e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    x.unlock(fn)
72ff99a72f53ca1007403e1bf3fcc2c6800370119bGuido van Rossum
735f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossumdef info(x, copts, fn):
74e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    dict = x.info(fn)
75e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    keys = dict.keys()
76e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    keys.sort()
77e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    for key in keys:
78e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        print key + ':', dict[key]
79e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    print '='*70
805f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossum
815f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossumdef head(x, copts, fn):
82e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    head = x.head(fn)
83e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    print fn, head
845f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossum
855f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossumdef list(x, copts, fn):
86e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    if x.isvalid(fn):
87e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        print fn
885f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossum
895f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossumdef log(x, copts, fn):
90e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    flags = ''
91e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    for o, a in copts:
92e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        flags = flags + ' ' + o + a
93e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    flags = flags[1:]
94e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    messages = x.log(fn, flags)
95e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    print messages
965f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossum
975f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossumdef diff(x, copts, fn):
98e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    if same(x, copts, fn):
99e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        return
100e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    flags = ''
101e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    for o, a in copts:
102e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        flags = flags + ' ' + o + a
103e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    flags = flags[1:]
104e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    data = x.get(fn)
105e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    tf = tempfile.NamedTemporaryFile()
106e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    tf.write(data)
107e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    tf.flush()
108e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    print 'diff %s -r%s %s' % (flags, x.head(fn), fn)
109e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    sts = os.system('diff %s %s %s' % (flags, tf.name, fn))
110e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    if sts:
111e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        print '='*70
1125f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossum
1135f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossumdef same(x, copts, fn, data = None):
114e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    if data is None:
115e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        f = open(fn)
116e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        data = f.read()
117e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        f.close()
118e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    lsum = md5.new(data).digest()
119e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    rsum = x.sum(fn)
120e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    return lsum == rsum
1215f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossum
1225f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossumdef asklogmessage(new):
123e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    if new:
124e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        print "enter description,",
125e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    else:
126e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        print "enter log message,",
127e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    print "terminate with single '.' or end of file:"
128e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    if new:
129e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        print "NOTE: This is NOT the log message!"
130e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    message = ""
131e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    while 1:
132e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        sys.stderr.write(">> ")
133e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        sys.stderr.flush()
134e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        line = sys.stdin.readline()
135e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        if not line or line == '.\n': break
136e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        message = message + line
137e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    return message
1385f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossum
1395f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossumdef remove(fn):
140e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    try:
141e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        os.unlink(fn)
142e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    except os.error:
143e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        pass
1445f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossum
1455f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossumcommands = {
146e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        'ci': ('', checkin),
147e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        'put': ('', checkin),
148e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        'co': ('', checkout),
149e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        'get': ('', checkout),
150e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        'info': ('', info),
151e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        'head': ('', head),
152e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        'list': ('', list),
153e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        'lock': ('', lock),
154e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        'unlock': ('', unlock),
155e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        'log': ('bhLRtd:l:r:s:w:V:', log),
156e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        'diff': ('c', diff),
157e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters        }
1585f07b84796c207a0068f6ac5a0d6981d14801ff6Guido van Rossum
159547e8d8c0f480b2647eeb2453f1fb9c77db42d0eGuido van Rossumif __name__ == '__main__':
160e6ddc8b20b493fef2e7cffb2e1351fe1d238857eTim Peters    main()
161