]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Initial revision
authorGuido van Rossum <guido@python.org>
Wed, 26 Apr 1995 22:57:11 +0000 (22:57 +0000)
committerGuido van Rossum <guido@python.org>
Wed, 26 Apr 1995 22:57:11 +0000 (22:57 +0000)
Demo/pdist/RCSProxy.py [new file with mode: 0755]
Demo/pdist/README [new file with mode: 0644]
Demo/pdist/cvslib.py [new file with mode: 0755]
Demo/pdist/rcvs.py [new file with mode: 0755]
Demo/pdist/rrcs.py [new file with mode: 0755]

diff --git a/Demo/pdist/RCSProxy.py b/Demo/pdist/RCSProxy.py
new file mode 100755 (executable)
index 0000000..0a12157
--- /dev/null
@@ -0,0 +1,285 @@
+#! /usr/local/bin/python
+
+"""RCS Proxy.
+
+Provide a simplified interface on RCS files, locally or remotely.
+The functionality is geared towards implementing some sort of
+remote CVS like utility.  It is modeled after the similar module
+FSProxy.
+
+The module defines three classes:
+
+RCSProxyLocal  -- used for local access
+RCSProxyServer -- used on the server side of remote access
+RCSProxyClient -- used on the client side of remote access
+
+The remote classes are instantiated with an IP address and an optional
+verbosity flag.
+"""
+
+import server
+import client
+import md5
+import os
+import fnmatch
+import string
+import tempfile
+
+
+okchars = string.letters + string.digits + '-_=+.'
+
+
+class RCSProxyLocal:
+       
+       def __init__(self):
+               self._dirstack = []
+       
+       def _close(self):
+               while self._dirstack:
+                       self.back()
+       
+       def pwd(self):
+               return os.getcwd()
+       
+       def cd(self, name):
+               save = os.getcwd()
+               os.chdir(name)
+               self._dirstack.append(save)
+       
+       def back(self):
+               if not self._dirstack:
+                       raise os.error, "empty directory stack"
+               dir = self._dirstack[-1]
+               os.chdir(dir)
+               del self._dirstack[-1]
+       
+       def _filter(self, files, pat = None):
+               if pat:
+                       def keep(name, pat = pat):
+                               return fnmatch.fnmatch(name, pat)
+                       files = filter(keep, files)
+               files.sort()
+               return files
+
+       def isfile(self, name):
+               namev = name + ',v'
+               return os.path.isfile(namev) or \
+                      os.path.isfile(os.path.join('RCS', namev))
+       
+       def _unmangle(self, name):
+               if type(name) == type(''):
+                       rev = ''
+               else:
+                       name, rev = name
+               return name, rev
+       
+       def checkfile(self, name):
+               name, rev = self._unmangle(name)
+               if not self.isfile(name):
+                       raise os.error, 'not an rcs file %s' % `name`
+               for c in rev:
+                       if c not in okchars:
+                               raise ValueError, "bad char in rev"
+               return name, rev
+       
+       def listfiles(self, pat = None):
+               def isrcs(name): return name[-2:] == ',v'
+               def striprcs(name): return name[:-2]
+               files = os.listdir(os.curdir)
+               files = filter(isrcs, files)
+               if os.path.isdir('RCS'):
+                       files2 = os.listdir('RCS')
+                       files2 = filter(isrcs, files2)
+                       files = files + files2
+               files = map(striprcs, files)
+               return self._filter(files, pat)
+       
+       def listsubdirs(self, pat = None):
+               files = os.listdir(os.curdir)
+               files = filter(os.path.isdir, files)
+               return self._filter(files, pat)
+       
+       def isdir(self, name):
+               return os.path.isdir(name)
+
+       def _open(self, name, cmd = 'co -p'):
+               name, rev = self.checkfile(name)
+               namev = name + ',v'
+               if rev:
+                       cmd = cmd + ' -r' + rev
+               return os.popen('%s %s' %  (cmd, `namev`))
+
+       def _closepipe(self, f):
+               sts = f.close()
+               if sts:
+                       raise IOError, "Exit status %d" % sts
+       
+       def _remove(self, fn):
+               try:
+                       os.unlink(fn)
+               except os.error:
+                       pass
+       
+       def sum(self, name):
+               f = self._open(name)
+               BUFFERSIZE = 1024*8
+               sum = md5.new()
+               while 1:
+                       buffer = f.read(BUFFERSIZE)
+                       if not buffer:
+                               break
+                       sum.update(buffer)
+               self._closepipe(f)
+               return sum.digest()
+       
+       def _list(self, function, list):
+               if list is None:
+                       list = self.listfiles()
+               res = []
+               for name in list:
+                       try:
+                               res.append((name, function(name)))
+                       except (os.error, IOError):
+                               res.append((name, None))
+               return res
+       
+       def sumlist(self, list = None):
+               return self.list(self.sum, list)
+       
+       def _dict(self, function, list):
+               if list is None:
+                       list = self.listfiles()
+               dict = {}
+               for name in list:
+                       try:
+                               dict[name] = function(name)
+                       except (os.error, IOError):
+                               pass
+               return dict
+       
+       def sumdict(self, list = None):
+               return self.dict(self.sum, list)
+       
+       def get(self, name):
+               f = self._open(name)
+               data = f.read()
+               self._closepipe(f)
+               return data
+
+       def info(self, name):
+               f = self._open(name, 'rlog -h')
+               dict = {}
+               while 1:
+                       line = f.readline()
+                       if not line: break
+                       if line[0] == '\t':
+                               continue # XXX lock details, later
+                       i = string.find(line, ':')
+                       if i > 0:
+                               key, value = line[:i], string.strip(line[i+1:])
+                               dict[key] = value
+               self._closepipe(f)
+               return dict
+       
+       def head(self, name):
+               dict = self.info(name)
+               return dict['head']
+       
+       def log(self, name, flags = ''):
+               f = self._open(name, 'rlog %s 2>&1' % flags)
+               log = f.read()
+               self._closepipe(f)
+               return log
+
+       def put(self, fullname, data, message = ""):
+               if message and message[-1] != '\n':
+                       message = message + '\n'
+               name, rev = self._unmangle(fullname)
+               new = not self.isfile(name)
+               if new:
+                       for c in name:
+                               if c not in okchars:
+                                       raise ValueError, "bad char in name"
+               else:
+                       self._remove(name)
+               f = open(name, 'w')
+               f.write(data)
+               f.close()
+               tf = tempfile.mktemp()
+               try:
+                       if not new:
+                           cmd = "rcs -l%s %s >>%s 2>&1" % (rev, name, tf)
+                           sts = os.system(cmd)
+                           if sts:
+                               raise IOError, "rcs -l exit status %d" % sts
+                       cmd = "ci -r%s %s >>%s 2>&1" % (rev, name, tf)
+                       p = os.popen(cmd, 'w')
+                       p.write(message)
+                       sts = p.close()
+                       if sts:
+                               raise IOError, "ci exit status %d" % sts
+                       messages = open(tf).read()
+                       return messages or None
+               finally:
+                       self._remove(tf)
+       
+       def mkdir(self, name):
+               os.mkdir(name, 0777)
+       
+       def rmdir(self, name):
+               os.rmdir(name)
+
+
+class RCSProxyServer(RCSProxyLocal, server.Server):
+       
+       def __init__(self, address, verbose = server.VERBOSE):
+               RCSProxyLocal.__init__(self)
+               server.Server.__init__(self, address, verbose)
+       
+       def _close(self):
+               server.Server._close(self)
+               RCSProxyLocal._close(self)
+       
+       def _serve(self):
+               server.Server._serve(self)
+               # Retreat into start directory
+               while self._dirstack: self.back()
+
+
+class RCSProxyClient(client.Client):
+       
+       def __init__(self, address, verbose = client.VERBOSE):
+               client.Client.__init__(self, address, verbose)
+
+
+def test_server():
+       import string
+       import sys
+       if sys.argv[1:]:
+               port = string.atoi(sys.argv[1])
+       else:
+               port = 4127
+       proxy = RCSProxyServer(('', port))
+       proxy._serverloop()
+
+
+def test():
+       import sys
+       if not sys.argv[1:] or sys.argv[1] and sys.argv[1][0] in '0123456789':
+               test_server()
+               sys.exit(0)
+       proxy = RCSProxyLocal()
+       what = sys.argv[1]
+       if hasattr(proxy, what):
+               attr = getattr(proxy, what)
+               if callable(attr):
+                       print apply(attr, tuple(sys.argv[2:]))
+               else:
+                       print `attr`
+       else:
+               print "%s: no such attribute" % what
+               sys.exit(2)
+
+
+if __name__ == '__main__':
+       test()
diff --git a/Demo/pdist/README b/Demo/pdist/README
new file mode 100644 (file)
index 0000000..738126d
--- /dev/null
@@ -0,0 +1,2 @@
+This directory contains various modules and classes that support
+remote file system operations
diff --git a/Demo/pdist/cvslib.py b/Demo/pdist/cvslib.py
new file mode 100755 (executable)
index 0000000..c98f0ba
--- /dev/null
@@ -0,0 +1,186 @@
+"""Utilities to read and write CVS admin files (esp. CVS/Entries)"""
+
+import string
+import os
+import time
+
+
+class Entry:
+
+       """Class representing one (parsed) line from CVS/Entries"""
+       
+       def __init__(self, line):
+               words = string.splitfields(line, '/')
+               self.file = words[1]
+               self.rev = words[2]
+               dates = words[3] # ctime, mtime
+               if dates[:7] == 'Initial':
+                       self.ctime = None
+                       self.mtime = None
+                       self.new = 1
+               else:
+                       self.ctime = unctime(dates[:24])
+                       self.mtime = unctime(dates[25:])
+                       self.new = 0
+               self.extra = words[4]
+               self.sum = None
+       
+       def unparse(self):
+               if self.new:
+                       dates = "Initial %s" % self.file
+               else:
+                       dates = gmctime(self.ctime) + ' ' + gmctime(self.mtime)
+               return "/%s/%s/%s/%s/\n" % (
+                       self.file,
+                       self.rev,
+                       dates,
+                       self.extra)
+       
+       def setsum(self, sum):
+               self.sum = sum
+       
+       def getsum(self):
+               return self.sum
+       
+       def sethexsum(self, hexsum):
+               self.setsum(unhexify(hexsum))
+       
+       def gethexsum(self):
+               if self.sum:
+                       return hexify(self.sum)
+               else:
+                       return None
+
+
+class CVS:
+
+       """Class representing the contents of CVS/Entries (and CVS/Sums)"""
+       
+       def __init__(self):
+               self.readentries()
+       
+       def readentries(self):
+               self.entries = {}
+               f = self.cvsopen("Entries")
+               while 1:
+                       line = f.readline()
+                       if not line: break
+                       e = Entry(line)
+                       self.entries[e.file] = e
+               f.close()
+       
+       def readsums(self):
+               try:
+                       f = self.cvsopen("Sums")
+               except IOError:
+                       return
+               while 1:
+                       line = f.readline()
+                       if not line: break
+                       words = string.split(line)
+                       [file, rev, hexsum] = words
+                       e = self.entries[file]
+                       if e.rev == rev:
+                               e.sethexsum(hexsum)
+               f.close()
+       
+       def writeentries(self):
+               f = self.cvsopen("Entries", 'w')
+               for file in self.keys():
+                       f.write(self.entries[file].unparse())
+               f.close()
+       
+       def writesums(self):
+               if self.cvsexists("Sums"):
+                       f = self.cvsopen("Sums", 'w')
+               else:
+                       f = None
+               for file in self.keys():
+                       e = self.entries[file]
+                       hexsum = e.gethexsum()
+                       if hexsum:
+                               if not f:
+                                       f = self.cvsopen("Sums", 'w')
+                               f.write("%s %s %s\n" % (file, e.rev, hexsum))
+               if f:
+                       f.close()
+       
+       def keys(self):
+               keys = self.entries.keys()
+               keys.sort()
+               return keys
+
+       def cvsexists(self, file):
+               file = os.path.join("CVS", file)
+               return os.path.exists(file)
+       
+       def cvsopen(self, file, mode = 'r'):
+               file = os.path.join("CVS", file)
+               if 'r' not in mode:
+                       self.backup(file)
+               return open(file, mode)
+       
+       def backup(self, file):
+               if os.path.isfile(file):
+                       bfile = file + '~'
+                       os.rename(file, bfile)
+
+
+hexify_format = '%02x' * 16
+def hexify(sum):
+       "Return a hex representation of a 16-byte string (e.g. an MD5 digest)"
+       return hexify_format % tuple(map(ord, sum))
+
+def unhexify(hexsum):
+       "Return the original from a hexified string"
+       sum = ''
+       for i in range(0, len(hexsum), 2):
+               sum = sum + chr(string.atoi(hexsum[i:i+2], 16))
+       return sum
+
+
+unctime_monthmap = {}
+def unctime(date):
+       if not unctime_monthmap:
+               months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
+                         'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
+               i = 0
+               for m in months:
+                       i = i+1
+                       unctime_monthmap[m] = i
+       words = string.split(date) # Day Mon DD HH:MM:SS YEAR
+       year = string.atoi(words[4])
+       month = unctime_monthmap[words[1]]
+       day = string.atoi(words[2])
+       [hh, mm, ss] = map(string.atoi, string.splitfields(words[3], ':'))
+       ss = ss - time.timezone
+       return time.mktime((year, month, day, hh, mm, ss, 0, 0, 0))
+
+def gmctime(t):
+       return time.asctime(time.gmtime(t))
+
+def test_unctime():
+       now = int(time.time())
+       t = time.gmtime(now)
+       at = time.asctime(t)
+       print 'GMT', now, at
+       print 'timezone', time.timezone
+       print 'local', time.ctime(now)
+       u = unctime(at)
+       print 'unctime()', u
+       gu = time.gmtime(u)
+       print '->', gu
+       print time.asctime(gu)
+
+def test():
+       x = CVS()
+       keys = x.entries.keys()
+       keys.sort()
+       for file in keys:
+               e = x.entries[file]
+               print file, e.rev, gmctime(e.ctime), gmctime(e.mtime), e.extra,
+               print e.gethexsum()
+
+
+if __name__ == "__main__":
+       test()
diff --git a/Demo/pdist/rcvs.py b/Demo/pdist/rcvs.py
new file mode 100755 (executable)
index 0000000..eb43bb8
--- /dev/null
@@ -0,0 +1,192 @@
+from cvslib import CVS, Entry
+import RCSProxy
+import client
+import md5
+import os
+import string
+import sys
+import time
+import fnmatch
+
+
+ignored_patterns = ['*.pyc', '.*', '*~', '@*']
+def ignored(file):
+       if os.path.isdir(file): return 1
+       for pat in ignored_patterns:
+               if fnmatch.fnmatch(file, pat): return 1
+       return 0
+
+
+class PCVS(CVS):
+       
+       def __init__(self, proxy):
+               CVS.__init__(self)
+               self.proxy = proxy
+               self.readsums()
+               self.calcsums()
+       
+       def calcsums(self):
+               for file in self.keys():
+                       e = self.entries[file]
+                       if not e.new and e.sum is None:
+                               sum = self.proxy.sum((file, e.rev))
+                               e.setsum(sum)
+       
+       def fullcheck(self):
+               ok = 1
+               for file in self.keys():
+                       e = self.entries[file]
+                       if e.new:
+                               if self.proxy.isfile(file):
+                                       print "%s: created by someone else!"
+                                       ok = 0
+                               continue
+                       rrev = self.proxy.head(file)
+                       if rrev != e.rev:
+                               print "%s: out of date (%s vs. %s)" % \
+                                     (file, e.rev, rrev)
+                               ok = 0
+               return ok
+       
+       def update(self):
+               for file in self.keys():
+                       e = self.entries[file]
+                       if e.new:
+                               print 'A', file
+                               continue
+                       rrev = self.proxy.head(file)
+                       lsum = sumfile(file)
+                       if rrev == e.rev:
+                               if lsum == e.sum:
+                                       print '=', file
+                               else:
+                                       print 'M', file
+                               continue
+                       if e.sum != lsum:
+                               print "%s: conflict -- not updated" % file
+                               continue
+                       print "%s: getting ..." % file
+                       data = self.proxy.get(file)
+                       f = open(file, 'w')
+                       f.write(data)
+                       f.close()
+                       nsum = md5.new(data).digest()
+                       e.setsum(nsum)
+                       e.rev = rrev
+                       print 'U', file
+               self.writeentries()
+               self.writesums()
+       
+       def commit(self):
+               if not self.fullcheck():
+                       print "correct above errors first"
+                       return
+               needed = []
+               for file in self.keys():
+                       e = self.entries[file]
+                       if e.new:
+                               needed.append(file)
+                               continue
+                       lsum = sumfile(file)
+                       if lsum != e.sum:
+                               needed.append(file)
+                               continue
+               if not needed:
+                       print "no changes need committing"
+                       return
+               message = raw_input("One-liner: ")
+               for file in needed:
+                       print "%s: putting ..." % file
+                       e = self.entries[file]
+                       data = open(file).read()
+                       self.proxy.put(file, data, message)
+                       e.rev = self.proxy.head(file)
+                       e.setsum(self.proxy.sum(file))
+                       # XXX get it?
+                       mtime, ctime = os.stat(file)[-2:]
+                       e.mtime = mtime
+                       e.ctime = ctime
+               self.writeentries()
+               self.writesums()
+       
+       def report(self):
+               keys = self.keys()
+               files = os.listdir(os.curdir)
+               allfiles = files
+               for file in keys:
+                       if file not in allfiles:
+                               allfiles.append(file)
+               allfiles.sort()
+               for file in allfiles:
+                       if file not in keys:
+                               if not ignored(file):
+                                       print '?', file
+                               continue
+                       if file not in files:
+                               print file, ': lost'
+                               continue
+                       e = self.entries[file]
+                       if not os.path.exists(file):
+                               print "%s: lost" % file
+                               continue
+                       if e.new:
+                               print 'A', file
+                               continue
+                       lsum = sumfile(file)
+                       rrev = self.proxy.head(file)
+                       if rrev == e.rev:
+                               if lsum == e.sum:
+                                       print '=', file
+                               else:
+                                       print 'M', file
+                       else:
+                               if lsum == e.sum:
+                                       print 'U', file
+                               else:
+                                       print 'C', file
+       
+       def add(self, file):
+               if self.entries.has_key(file):
+                       print "%s: already known"
+               else:
+                       self.entries[file] = Entry('/%s/0/Initial %s//\n' %
+                                                  (file, file))
+
+
+def sumfile(file):
+       return md5.new(open(file).read()).digest()
+
+
+def test():
+       proxy = RCSProxy.RCSProxyClient(('voorn.cwi.nl', 4127))
+       proxy.cd('/ufs/guido/voorn/python-RCS/Demo/pdist')
+       x = PCVS(proxy)
+       args = sys.argv[1:]
+       if args:
+               cmd = args[0]
+               files = args[1:]
+               if cmd == 'add':
+                       if not files:
+                               print "add needs at least one file argument"
+                       else:
+                               for file in files:
+                                       x.add(file)
+                               x.writeentries()
+               elif cmd in ('update', 'up'):
+                       if files:
+                               print "updates wants no file arguments"
+                       else:
+                               x.update()
+               elif cmd in ('commit', 'com'):
+                       if files:
+                               print "commit wants no file arguments"
+                       else:
+                               x.commit()
+               else:
+                       print "Unknown command", cmd
+       else:
+               x.report()
+               if sys.argv[1:]: x.writesums()
+
+if __name__ == "__main__":
+       test()
diff --git a/Demo/pdist/rrcs.py b/Demo/pdist/rrcs.py
new file mode 100755 (executable)
index 0000000..74bce56
--- /dev/null
@@ -0,0 +1,174 @@
+#! /usr/local/bin/python
+
+import sys
+import os
+import getopt
+import string
+import md5
+import tempfile
+
+def main():
+       sys.stdout = sys.stderr
+       try:
+               opts, rest = getopt.getopt(sys.argv[1:], 'h:p:qv')
+               if not rest:
+                       raise getopt.error, "missing command"
+               cmd, rest = rest[0], rest[1:]
+               if not commands.has_key(cmd):
+                       raise getopt.error, "unknown command"
+               coptset, func = commands[cmd]
+               copts, files = getopt.getopt(rest, coptset)
+       except getopt.error, msg:
+               print msg
+               print "usage: rrcs [options] command [options] [file] ..."
+               print "where command can be:"
+               print "      ci|put      # checkin the given files"
+               print "      co|get      # checkout"
+               print "      info        # print header info"
+               print "      head        # print revision of head branch"
+               print "      list        # list filename if valid"
+               print "      log         # print full log"
+               print "      diff        # diff rcs file and work file"
+               print "if no files are given, all remote rcs files are assumed"
+               sys.exit(2)
+       x = openclient(opts)
+       if not files:
+               files = x.listfiles()
+       for fn in files:
+               try:
+                       func(x, copts, fn)
+               except (IOError, os.error), msg:
+                       print "%s: %s" % (fn, msg)
+
+def openclient(opts):
+       import client
+       import RCSProxy
+       host = 'spam'
+       port = 4127
+       verbose = client.VERBOSE
+       for o, a in opts:
+               if o == '-h':
+                       host = a
+                       if ':' in host:
+                               i = string.find(host, ':')
+                               host, p = host[:i], host[i+1:]
+                               if p:
+                                       port = string.atoi(p)
+               if o == '-p':
+                       port = string.atoi(a)
+               if o == '-v':
+                       verbose = verbose + 1
+               if o == '-q':
+                       verbose = 0
+       address = (host, port)
+       x = RCSProxy.RCSProxyClient(address, verbose)
+       return x
+
+def checkin(x, copts, fn):
+       f = open(fn)
+       data = f.read()
+       f.close()
+       new = not x.isfile(fn)
+       if not new and same(x, copts, fn, data):
+               print "%s: unchanged since last checkin" % fn
+               return
+       message = asklogmessage(new)
+       messages = x.put(fn, data, message)
+       if messages:
+               print messages
+
+def checkout(x, copts, fn):
+       data = x.get(fn)
+       f = open(fn, 'w')
+       f.write(data)
+       f.close()
+
+def info(x, copts, fn):
+       dict = x.info(fn)
+       keys = dict.keys()
+       keys.sort()
+       for key in keys:
+               print key + ':', dict[key]
+       print '='*70
+
+def head(x, copts, fn):
+       head = x.head(fn)
+       print fn, head
+
+def list(x, copts, fn):
+       if x.isfile(fn):
+               print fn
+
+def log(x, copts, fn):
+       flags = ''
+       for o, a in copts:
+               flags = flags + ' ' + o + a
+       flags = flags[1:]
+       messages = x.log(fn, flags)
+       print messages
+
+def diff(x, copts, fn):
+       if same(x, copts, fn):
+               return
+       flags = ''
+       for o, a in copts:
+               flags = flags + ' ' + o + a
+       flags = flags[1:]
+       data = x.get(fn)
+       tfn = tempfile.mktemp()
+       try:
+               tf = open(tfn, 'w')
+               tf.write(data)
+               tf.close()
+               print 'diff %s -r%s %s' % (flags, x.head(fn), fn)
+               sts = os.system('diff %s %s %s' % (flags, tfn, fn))
+               if sts:
+                       print '='*70
+       finally:
+               remove(tfn)
+
+def same(x, copts, fn, data = None):
+       if data is None:
+               f = open(fn)
+               data = f.read()
+               f.close()
+       lsum = md5.new(data).digest()
+       rsum = x.sum(fn)
+       return lsum == rsum
+
+def asklogmessage(new):
+       if new:
+               print "enter description,",
+       else:
+               print "enter log message,",
+       print "terminate with single '.' or end of file:"
+       if new:
+               print "NOTE: This is NOT the log message!"
+       message = ""
+       while 1:
+               sys.stderr.write(">> ")
+               sys.stderr.flush()
+               line = sys.stdin.readline()
+               if not line or line == '.\n': break
+               message = message + line
+       return message
+
+def remove(fn):
+       try:
+               os.unlink(fn)
+       except os.error:
+               pass
+
+commands = {
+       'ci': ('', checkin),
+       'put': ('', checkin),
+       'co': ('', checkout),
+       'get': ('', checkout),
+       'info': ('', info),
+       'head': ('', head),
+       'list': ('', list),
+       'log': ('bhLRtd:l:r:s:w:V:', log),
+       'diff': ('c', diff),
+       }
+
+main()