Remove obsolete pdist demo.

This commit is contained in:
Georg Brandl 2010-08-02 23:17:21 +00:00
parent 2db2b8a17d
commit 68642f5ed0
21 changed files with 0 additions and 3196 deletions

View File

@ -35,9 +35,6 @@ newmetaclasses Demonstration of metaclasses.
parser Example using the parser module.
pdist Old, unfinished code messing with CVS, RCS and remote
files.
pysvr An example of embedding Python in a threaded
application.

View File

@ -1,301 +0,0 @@
"""File System Proxy.
Provide an OS-neutral view on a file system, locally or remotely.
The functionality is geared towards implementing some sort of
rdist-like utility between a Mac and a UNIX system.
The module defines three classes:
FSProxyLocal -- used for local access
FSProxyServer -- used on the server side of remote access
FSProxyClient -- 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
from stat import *
import time
import fnmatch
maxnamelen = 255
skipnames = (os.curdir, os.pardir)
class FSProxyLocal:
def __init__(self):
self._dirstack = []
self._ignore = ['*.pyc'] + self._readignore()
def _close(self):
while self._dirstack:
self.back()
def _readignore(self):
file = self._hide('ignore')
try:
f = open(file)
except IOError:
file = self._hide('synctree.ignorefiles')
try:
f = open(file)
except IOError:
return []
ignore = []
while 1:
line = f.readline()
if not line: break
if line[-1] == '\n': line = line[:-1]
ignore.append(line)
f.close()
return ignore
def _hidden(self, name):
return name[0] == '.'
def _hide(self, name):
return '.%s' % name
def visible(self, name):
if len(name) > maxnamelen: return 0
if name[-1] == '~': return 0
if name in skipnames: return 0
if self._hidden(name): return 0
head, tail = os.path.split(name)
if head or not tail: return 0
if os.path.islink(name): return 0
if '\0' in open(name, 'rb').read(512): return 0
for ign in self._ignore:
if fnmatch.fnmatch(name, ign): return 0
return 1
def check(self, name):
if not self.visible(name):
raise os.error("protected name %s" % repr(name))
def checkfile(self, name):
self.check(name)
if not os.path.isfile(name):
raise os.error("not a plain file %s" % repr(name))
def pwd(self):
return os.getcwd()
def cd(self, name):
self.check(name)
save = os.getcwd(), self._ignore
os.chdir(name)
self._dirstack.append(save)
self._ignore = self._ignore + self._readignore()
def back(self):
if not self._dirstack:
raise os.error("empty directory stack")
dir, ignore = self._dirstack[-1]
os.chdir(dir)
del self._dirstack[-1]
self._ignore = ignore
def _filter(self, files, pat = None):
if pat:
def keep(name, pat = pat):
return fnmatch.fnmatch(name, pat)
files = list(filter(keep, files))
files = list(filter(self.visible, files))
files.sort()
return files
def list(self, pat = None):
files = os.listdir(os.curdir)
return self._filter(files, pat)
def listfiles(self, pat = None):
files = os.listdir(os.curdir)
files = list(filter(os.path.isfile, files))
return self._filter(files, pat)
def listsubdirs(self, pat = None):
files = os.listdir(os.curdir)
files = list(filter(os.path.isdir, files))
return self._filter(files, pat)
def exists(self, name):
return self.visible(name) and os.path.exists(name)
def isdir(self, name):
return self.visible(name) and os.path.isdir(name)
def islink(self, name):
return self.visible(name) and os.path.islink(name)
def isfile(self, name):
return self.visible(name) and os.path.isfile(name)
def sum(self, name):
self.checkfile(name)
BUFFERSIZE = 1024*8
f = open(name)
sum = md5.new()
while 1:
buffer = f.read(BUFFERSIZE)
if not buffer:
break
sum.update(buffer)
return sum.digest()
def size(self, name):
self.checkfile(name)
return os.stat(name)[ST_SIZE]
def mtime(self, name):
self.checkfile(name)
return time.localtime(os.stat(name)[ST_MTIME])
def stat(self, name):
self.checkfile(name)
size = os.stat(name)[ST_SIZE]
mtime = time.localtime(os.stat(name)[ST_MTIME])
return size, mtime
def info(self, name):
sum = self.sum(name)
size = os.stat(name)[ST_SIZE]
mtime = time.localtime(os.stat(name)[ST_MTIME])
return sum, size, mtime
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 statlist(self, list = None):
return self._list(self.stat, list)
def mtimelist(self, list = None):
return self._list(self.mtime, list)
def sizelist(self, list = None):
return self._list(self.size, list)
def infolist(self, list = None):
return self._list(self.info, 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 sizedict(self, list = None):
return self.dict(self.size, list)
def mtimedict(self, list = None):
return self.dict(self.mtime, list)
def statdict(self, list = None):
return self.dict(self.stat, list)
def infodict(self, list = None):
return self._dict(self.info, list)
def read(self, name, offset = 0, length = -1):
self.checkfile(name)
f = open(name)
f.seek(offset)
if length == 0:
data = ''
elif length < 0:
data = f.read()
else:
data = f.read(length)
f.close()
return data
def create(self, name):
self.check(name)
if os.path.exists(name):
self.checkfile(name)
bname = name + '~'
try:
os.unlink(bname)
except os.error:
pass
os.rename(name, bname)
f = open(name, 'w')
f.close()
def write(self, name, data, offset = 0):
self.checkfile(name)
f = open(name, 'r+')
f.seek(offset)
f.write(data)
f.close()
def mkdir(self, name):
self.check(name)
os.mkdir(name, 0o777)
def rmdir(self, name):
self.check(name)
os.rmdir(name)
class FSProxyServer(FSProxyLocal, server.Server):
def __init__(self, address, verbose = server.VERBOSE):
FSProxyLocal.__init__(self)
server.Server.__init__(self, address, verbose)
def _close(self):
server.Server._close(self)
FSProxyLocal._close(self)
def _serve(self):
server.Server._serve(self)
# Retreat into start directory
while self._dirstack: self.back()
class FSProxyClient(client.Client):
def __init__(self, address, verbose = client.VERBOSE):
client.Client.__init__(self, address, verbose)
def test():
import string
import sys
if sys.argv[1:]:
port = string.atoi(sys.argv[1])
else:
port = 4127
proxy = FSProxyServer(('', port))
proxy._serverloop()
if __name__ == '__main__':
test()

View File

@ -1,198 +0,0 @@
#! /usr/bin/env python3
"""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 two classes:
RCSProxyLocal -- used for local access
RCSProxyServer -- used on the server side of remote access
The corresponding client class, RCSProxyClient, is defined in module
rcsclient.
The remote classes are instantiated with an IP address and an optional
verbosity flag.
"""
import server
import md5
import os
import fnmatch
import string
import tempfile
import rcslib
class DirSupport:
def __init__(self):
self._dirstack = []
def __del__(self):
self._close()
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 listsubdirs(self, pat = None):
files = os.listdir(os.curdir)
files = list(filter(os.path.isdir, files))
return self._filter(files, pat)
def isdir(self, name):
return os.path.isdir(name)
def mkdir(self, name):
os.mkdir(name, 0o777)
def rmdir(self, name):
os.rmdir(name)
class RCSProxyLocal(rcslib.RCS, DirSupport):
def __init__(self):
rcslib.RCS.__init__(self)
DirSupport.__init__(self)
def __del__(self):
DirSupport.__del__(self)
rcslib.RCS.__del__(self)
def sumlist(self, list = None):
return self._list(self.sum, list)
def sumdict(self, list = None):
return self._dict(self.sum, list)
def sum(self, name_rev):
f = self._open(name_rev)
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 get(self, name_rev):
f = self._open(name_rev)
data = f.read()
self._closepipe(f)
return data
def put(self, name_rev, data, message=None):
name, rev = self._unmangle(name_rev)
f = open(name, 'w')
f.write(data)
f.close()
self.checkin(name_rev, message)
self._remove(name)
def _list(self, function, list = None):
"""INTERNAL: apply FUNCTION to all files in LIST.
Return a list of the results.
The list defaults to all files in the directory if None.
"""
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 _dict(self, function, list = None):
"""INTERNAL: apply FUNCTION to all files in LIST.
Return a dictionary mapping files to results.
The list defaults to all files in the directory if None.
"""
if list is None:
list = self.listfiles()
dict = {}
for name in list:
try:
dict[name] = function(name)
except (os.error, IOError):
pass
return dict
class RCSProxyServer(RCSProxyLocal, server.SecureServer):
def __init__(self, address, verbose = server.VERBOSE):
RCSProxyLocal.__init__(self)
server.SecureServer.__init__(self, address, verbose)
def _close(self):
server.SecureServer._close(self)
RCSProxyLocal._close(self)
def _serve(self):
server.SecureServer._serve(self)
# Retreat into start directory
while self._dirstack: self.back()
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 hasattr(attr, '__call__'):
print(attr(*sys.argv[2:]))
else:
print(repr(attr))
else:
print("%s: no such attribute" % what)
sys.exit(2)
if __name__ == '__main__':
test()

View File

@ -1,121 +0,0 @@
Filesystem, RCS and CVS client and server classes
=================================================
*** See the security warning at the end of this file! ***
This directory contains various modules and classes that support
remote file system operations.
CVS stuff
---------
rcvs Script to put in your bin directory
rcvs.py Remote CVS client command line interface
cvslib.py CVS admin files classes (used by rrcs)
cvslock.py CVS locking algorithms
RCS stuff
---------
rrcs Script to put in your bin directory
rrcs.py Remote RCS client command line interface
rcsclient.py Return an RCSProxyClient instance
(has reasonable default server/port/directory)
RCSProxy.py RCS proxy and server classes (on top of rcslib.py)
rcslib.py Local-only RCS base class (affects stdout &
local work files)
FSProxy stuff
-------------
sumtree.py Old demo for FSProxy
cmptree.py First FSProxy client (used to sync from the Mac)
FSProxy.py Filesystem interface classes
Generic client/server stuff
---------------------------
client.py Client class
server.py Server class
security.py Security mix-in class (not very secure I think)
Other generic stuff
-------------------
cmdfw.py CommandFrameWork class
(used by rcvs, should be used by rrcs as well)
Client/Server operation
-----------------------
The Client and Server classes implement a simple-minded RPC protocol,
using Python's pickle module to transfer arguments, return values and
exceptions with the most generality. The Server class is instantiated
with a port number on which it should listen for requests; the Client
class is instantiated with a host name and a port number where it
should connect to. Once a client is connected, a TCP connection is
maintained between client and server.
The Server class currently handles only one connection at a time;
however it could be rewritten to allow various modes of operations,
using multiple threads or processes or the select() system call as
desired to serve multiple clients simultaneously (when using select(),
still handling one request at a time). This would not require
rewriting of the Client class. It may also be possible to adapt the
code to use UDP instead of TCP, but then both classes will have to be
rewritten (and unless extensive acknowlegements and request serial
numbers are used, the server should handle duplicate requests, so its
semantics should be idempotent -- shrudder).
Even though the FSProxy and RCSProxy modules define client classes,
the client class is fully generic -- what methods it supports is
determined entirely by the server. The server class, however, must be
derived from. This is generally done as follows:
from server import Server
from client import Client
# Define a class that performs the operations locally
class MyClassLocal:
def __init__(self): ...
def _close(self): ...
# Derive a server class using multiple inheritance
class MyClassServer(MyClassLocal, Server):
def __init__(self, address):
# Must initialize MyClassLocal as well as Server
MyClassLocal.__init__(self)
Server.__init__(self, address)
def _close(self):
Server._close()
MyClassLocal._close()
# A dummy client class
class MyClassClient(Client): pass
Note that because MyClassLocal isn't used in the definition of
MyClassClient, it would actually be better to place it in a separate
module so the definition of MyClassLocal isn't executed when we only
instantiate a client.
The modules client and server should probably be renamed to Client and
Server in order to match the class names.
*** Security warning: this version requires that you have a file
$HOME/.python_keyfile at the server and client side containing two
comma- separated numbers. The security system at the moment makes no
guarantees of actuallng being secure -- however it requires that the
key file exists and contains the same numbers at both ends for this to
work. (You can specify an alternative keyfile in $PYTHON_KEYFILE).
Have a look at the Security class in security.py for details;
basically, if the key file contains (x, y), then the security server
class chooses a random number z (the challenge) in the range
10..100000 and the client must be able to produce pow(z, x, y)
(i.e. z**x mod y).

View File

@ -1,156 +0,0 @@
"""RPC Client module."""
import sys
import socket
import pickle
import builtins
import os
# Default verbosity (0 = silent, 1 = print connections, 2 = print requests too)
VERBOSE = 1
class Client:
"""RPC Client class. No need to derive a class -- it's fully generic."""
def __init__(self, address, verbose = VERBOSE):
self._pre_init(address, verbose)
self._post_init()
def _pre_init(self, address, verbose = VERBOSE):
if type(address) == type(0):
address = ('', address)
self._address = address
self._verbose = verbose
if self._verbose: print("Connecting to %s ..." % repr(address))
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._socket.connect(address)
if self._verbose: print("Connected.")
self._lastid = 0 # Last id for which a reply has been received
self._nextid = 1 # Id of next request
self._replies = {} # Unprocessed replies
self._rf = self._socket.makefile('r')
self._wf = self._socket.makefile('w')
def _post_init(self):
self._methods = self._call('.methods')
def __del__(self):
self._close()
def _close(self):
if self._rf: self._rf.close()
self._rf = None
if self._wf: self._wf.close()
self._wf = None
if self._socket: self._socket.close()
self._socket = None
def __getattr__(self, name):
if name in self._methods:
method = _stub(self, name)
setattr(self, name, method) # XXX circular reference
return method
raise AttributeError(name)
def _setverbose(self, verbose):
self._verbose = verbose
def _call(self, name, *args):
return self._vcall(name, args)
def _vcall(self, name, args):
return self._recv(self._vsend(name, args))
def _send(self, name, *args):
return self._vsend(name, args)
def _send_noreply(self, name, *args):
return self._vsend(name, args, 0)
def _vsend_noreply(self, name, args):
return self._vsend(name, args, 0)
def _vsend(self, name, args, wantreply = 1):
id = self._nextid
self._nextid = id+1
if not wantreply: id = -id
request = (name, args, id)
if self._verbose > 1: print("sending request: %s" % repr(request))
wp = pickle.Pickler(self._wf)
wp.dump(request)
return id
def _recv(self, id):
exception, value, rid = self._vrecv(id)
if rid != id:
raise RuntimeError("request/reply id mismatch: %d/%d" % (id, rid))
if exception is None:
return value
x = exception
if hasattr(builtins, exception):
x = getattr(builtins, exception)
elif exception in ('posix.error', 'mac.error'):
x = os.error
if x == exception:
exception = x
raise exception(value)
def _vrecv(self, id):
self._flush()
if id in self._replies:
if self._verbose > 1: print("retrieving previous reply, id = %d" % id)
reply = self._replies[id]
del self._replies[id]
return reply
aid = abs(id)
while 1:
if self._verbose > 1: print("waiting for reply, id = %d" % id)
rp = pickle.Unpickler(self._rf)
reply = rp.load()
del rp
if self._verbose > 1: print("got reply: %s" % repr(reply))
rid = reply[2]
arid = abs(rid)
if arid == aid:
if self._verbose > 1: print("got it")
return reply
self._replies[rid] = reply
if arid > aid:
if self._verbose > 1: print("got higher id, assume all ok")
return (None, None, id)
def _flush(self):
self._wf.flush()
from security import Security
class SecureClient(Client, Security):
def __init__(self, *args):
self._pre_init(*args)
Security.__init__(self)
self._wf.flush()
line = self._rf.readline()
challenge = int(line.strip())
response = self._encode_challenge(challenge)
line = repr(int(response))
if line[-1] in 'Ll': line = line[:-1]
self._wf.write(line + '\n')
self._wf.flush()
self._post_init()
class _stub:
"""Helper class for Client -- each instance serves as a method of the client."""
def __init__(self, client, name):
self._client = client
self._name = name
def __call__(self, *args):
return self._client._vcall(self._name, args)

View File

@ -1,142 +0,0 @@
"Framework for command line interfaces like CVS. See class CmdFrameWork."
class CommandFrameWork:
"""Framework class for command line interfaces like CVS.
The general command line structure is
command [flags] subcommand [subflags] [argument] ...
There's a class variable GlobalFlags which specifies the
global flags options. Subcommands are defined by defining
methods named do_<subcommand>. Flags for the subcommand are
defined by defining class or instance variables named
flags_<subcommand>. If there's no command, method default()
is called. The __doc__ strings for the do_ methods are used
for the usage message, printed after the general usage message
which is the class variable UsageMessage. The class variable
PostUsageMessage is printed after all the do_ methods' __doc__
strings. The method's return value can be a suggested exit
status. [XXX Need to rewrite this to clarify it.]
Common usage is to derive a class, instantiate it, and then call its
run() method; by default this takes its arguments from sys.argv[1:].
"""
UsageMessage = \
"usage: (name)s [flags] subcommand [subflags] [argument] ..."
PostUsageMessage = None
GlobalFlags = ''
def __init__(self):
"""Constructor, present for completeness."""
pass
def run(self, args = None):
"""Process flags, subcommand and options, then run it."""
import getopt, sys
if args is None: args = sys.argv[1:]
try:
opts, args = getopt.getopt(args, self.GlobalFlags)
except getopt.error as msg:
return self.usage(msg)
self.options(opts)
if not args:
self.ready()
return self.default()
else:
cmd = args[0]
mname = 'do_' + cmd
fname = 'flags_' + cmd
try:
method = getattr(self, mname)
except AttributeError:
return self.usage("command %r unknown" % (cmd,))
try:
flags = getattr(self, fname)
except AttributeError:
flags = ''
try:
opts, args = getopt.getopt(args[1:], flags)
except getopt.error as msg:
return self.usage(
"subcommand %s: " % cmd + str(msg))
self.ready()
return method(opts, args)
def options(self, opts):
"""Process the options retrieved by getopt.
Override this if you have any options."""
if opts:
print("-"*40)
print("Options:")
for o, a in opts:
print('option', o, 'value', repr(a))
print("-"*40)
def ready(self):
"""Called just before calling the subcommand."""
pass
def usage(self, msg = None):
"""Print usage message. Return suitable exit code (2)."""
if msg: print(msg)
print(self.UsageMessage % {'name': self.__class__.__name__})
docstrings = {}
c = self.__class__
while 1:
for name in dir(c):
if name[:3] == 'do_':
if name in docstrings:
continue
try:
doc = getattr(c, name).__doc__
except:
doc = None
if doc:
docstrings[name] = doc
if not c.__bases__:
break
c = c.__bases__[0]
if docstrings:
print("where subcommand can be:")
for name in sorted(docstrings.keys()):
print(docstrings[name])
if self.PostUsageMessage:
print(self.PostUsageMessage)
return 2
def default(self):
"""Default method, called when no subcommand is given.
You should always override this."""
print("Nobody expects the Spanish Inquisition!")
def test():
"""Test script -- called when this module is run as a script."""
import sys
class Hello(CommandFrameWork):
def do_hello(self, opts, args):
"hello -- print 'hello world', needs no arguments"
print("Hello, world")
x = Hello()
tests = [
[],
['hello'],
['spam'],
['-x'],
['hello', '-x'],
None,
]
for t in tests:
print('-'*10, t, '-'*10)
sts = x.run(t)
print("Exit status:", repr(sts))
if __name__ == '__main__':
test()

View File

@ -1,213 +0,0 @@
"""Compare local and remote dictionaries and transfer differing files -- like rdist."""
import sys
from reprlib import repr
import FSProxy
import time
import os
def raw_input(prompt):
sys.stdout.write(prompt)
sys.stdout.flush()
return sys.stdin.readline()
def main():
pwd = os.getcwd()
s = input("chdir [%s] " % pwd)
if s:
os.chdir(s)
pwd = os.getcwd()
host = ask("host", 'voorn.cwi.nl')
port = 4127
verbose = 1
mode = ''
print("""\
Mode should be a string of characters, indicating what to do with differences.
r - read different files to local file system
w - write different files to remote file system
c - create new files, either remote or local
d - delete disappearing files, either remote or local
""")
s = input("mode [%s] " % mode)
if s: mode = s
address = (host, port)
t1 = time.time()
local = FSProxy.FSProxyLocal()
remote = FSProxy.FSProxyClient(address, verbose)
compare(local, remote, mode)
remote._close()
local._close()
t2 = time.time()
dt = t2-t1
mins, secs = divmod(dt, 60)
print(mins, "minutes and", round(secs), "seconds")
input("[Return to exit] ")
def ask(prompt, default):
s = input("%s [%s] " % (prompt, default))
return s or default
def askint(prompt, default):
s = input("%s [%s] " % (prompt, str(default)))
if s: return string.atoi(s)
return default
def compare(local, remote, mode):
print()
print("PWD =", repr(os.getcwd()))
sums_id = remote._send('sumlist')
subdirs_id = remote._send('listsubdirs')
remote._flush()
print("calculating local sums ...")
lsumdict = {}
for name, info in local.sumlist():
lsumdict[name] = info
print("getting remote sums ...")
sums = remote._recv(sums_id)
print("got", len(sums))
rsumdict = {}
for name, rsum in sums:
rsumdict[name] = rsum
if name not in lsumdict:
print(repr(name), "only remote")
if 'r' in mode and 'c' in mode:
recvfile(local, remote, name)
else:
lsum = lsumdict[name]
if lsum != rsum:
print(repr(name), end=' ')
rmtime = remote.mtime(name)
lmtime = local.mtime(name)
if rmtime > lmtime:
print("remote newer", end=' ')
if 'r' in mode:
recvfile(local, remote, name)
elif lmtime > rmtime:
print("local newer", end=' ')
if 'w' in mode:
sendfile(local, remote, name)
else:
print("same mtime but different sum?!?!", end=' ')
print()
for name in lsumdict.keys():
if not list(rsumdict.keys()):
print(repr(name), "only locally", end=' ')
fl()
if 'w' in mode and 'c' in mode:
sendfile(local, remote, name)
elif 'r' in mode and 'd' in mode:
os.unlink(name)
print("removed.")
print()
print("gettin subdirs ...")
subdirs = remote._recv(subdirs_id)
common = []
for name in subdirs:
if local.isdir(name):
print("Common subdirectory", repr(name))
common.append(name)
else:
print("Remote subdirectory", repr(name), "not found locally")
if 'r' in mode and 'c' in mode:
pr = "Create local subdirectory %s? [y] " % \
repr(name)
if 'y' in mode:
ok = 'y'
else:
ok = ask(pr, "y")
if ok[:1] in ('y', 'Y'):
local.mkdir(name)
print("Subdirectory %s made" % \
repr(name))
common.append(name)
lsubdirs = local.listsubdirs()
for name in lsubdirs:
if name not in subdirs:
print("Local subdirectory", repr(name), "not found remotely")
for name in common:
print("Entering subdirectory", repr(name))
local.cd(name)
remote.cd(name)
compare(local, remote, mode)
remote.back()
local.back()
def sendfile(local, remote, name):
try:
remote.create(name)
except (IOError, os.error) as msg:
print("cannot create:", msg)
return
print("sending ...", end=' ')
fl()
data = open(name).read()
t1 = time.time()
remote._send_noreply('write', name, data)
remote._flush()
t2 = time.time()
dt = t2-t1
print(len(data), "bytes in", round(dt), "seconds", end=' ')
if dt:
print("i.e.", round(len(data)/dt), "bytes/sec", end=' ')
print()
def recvfile(local, remote, name):
ok = 0
try:
rv = recvfile_real(local, remote, name)
ok = 1
return rv
finally:
if not ok:
print("*** recvfile of %r failed, deleting" % (name,))
local.delete(name)
def recvfile_real(local, remote, name):
try:
local.create(name)
except (IOError, os.error) as msg:
print("cannot create:", msg)
return
print("receiving ...", end=' ')
fl()
f = open(name, 'w')
t1 = time.time()
length = 4*1024
offset = 0
id = remote._send('read', name, offset, length)
remote._flush()
while 1:
newoffset = offset + length
newid = remote._send('read', name, newoffset, length)
data = remote._recv(id)
id = newid
if not data: break
f.seek(offset)
f.write(data)
offset = newoffset
size = f.tell()
t2 = time.time()
f.close()
dt = t2-t1
print(size, "bytes in", round(dt), "seconds", end=' ')
if dt:
print("i.e.", int(size//dt), "bytes/sec", end=' ')
print()
remote._recv(id) # ignored
def fl():
sys.stdout.flush()
if __name__ == '__main__':
main()

View File

@ -1,359 +0,0 @@
"""Utilities for CVS administration."""
import string
import os
import time
import md5
import fnmatch
if not hasattr(time, 'timezone'):
time.timezone = 0
class File:
"""Represent a file's status.
Instance variables:
file -- the filename (no slashes), None if uninitialized
lseen -- true if the data for the local file is up to date
eseen -- true if the data from the CVS/Entries entry is up to date
(this implies that the entry must be written back)
rseen -- true if the data for the remote file is up to date
proxy -- RCSProxy instance used to contact the server, or None
Note that lseen and rseen don't necessary mean that a local
or remote file *exists* -- they indicate that we've checked it.
However, eseen means that this instance corresponds to an
entry in the CVS/Entries file.
If lseen is true:
lsum -- checksum of the local file, None if no local file
lctime -- ctime of the local file, None if no local file
lmtime -- mtime of the local file, None if no local file
If eseen is true:
erev -- revision, None if this is a no revision (not '0')
enew -- true if this is an uncommitted added file
edeleted -- true if this is an uncommitted removed file
ectime -- ctime of last local file corresponding to erev
emtime -- mtime of last local file corresponding to erev
extra -- 5th string from CVS/Entries file
If rseen is true:
rrev -- revision of head, None if non-existent
rsum -- checksum of that revision, Non if non-existent
If eseen and rseen are both true:
esum -- checksum of revision erev, None if no revision
Note
"""
def __init__(self, file = None):
if file and '/' in file:
raise ValueError("no slash allowed in file")
self.file = file
self.lseen = self.eseen = self.rseen = 0
self.proxy = None
def __cmp__(self, other):
return cmp(self.file, other.file)
def getlocal(self):
try:
self.lmtime, self.lctime = os.stat(self.file)[-2:]
except os.error:
self.lmtime = self.lctime = self.lsum = None
else:
self.lsum = md5.new(open(self.file).read()).digest()
self.lseen = 1
def getentry(self, line):
words = string.splitfields(line, '/')
if self.file and words[1] != self.file:
raise ValueError("file name mismatch")
self.file = words[1]
self.erev = words[2]
self.edeleted = 0
self.enew = 0
self.ectime = self.emtime = None
if self.erev[:1] == '-':
self.edeleted = 1
self.erev = self.erev[1:]
if self.erev == '0':
self.erev = None
self.enew = 1
else:
dates = words[3]
self.ectime = unctime(dates[:24])
self.emtime = unctime(dates[25:])
self.extra = words[4]
if self.rseen:
self.getesum()
self.eseen = 1
def getremote(self, proxy = None):
if proxy:
self.proxy = proxy
try:
self.rrev = self.proxy.head(self.file)
except (os.error, IOError):
self.rrev = None
if self.rrev:
self.rsum = self.proxy.sum(self.file)
else:
self.rsum = None
if self.eseen:
self.getesum()
self.rseen = 1
def getesum(self):
if self.erev == self.rrev:
self.esum = self.rsum
elif self.erev:
name = (self.file, self.erev)
self.esum = self.proxy.sum(name)
else:
self.esum = None
def putentry(self):
"""Return a line suitable for inclusion in CVS/Entries.
The returned line is terminated by a newline.
If no entry should be written for this file,
return "".
"""
if not self.eseen:
return ""
rev = self.erev or '0'
if self.edeleted:
rev = '-' + rev
if self.enew:
dates = 'Initial ' + self.file
else:
dates = gmctime(self.ectime) + ' ' + \
gmctime(self.emtime)
return "/%s/%s/%s/%s/\n" % (
self.file,
rev,
dates,
self.extra)
def report(self):
print('-'*50)
def r(key, repr=repr, self=self):
try:
value = repr(getattr(self, key))
except AttributeError:
value = "?"
print("%-15s:" % key, value)
r("file")
if self.lseen:
r("lsum", hexify)
r("lctime", gmctime)
r("lmtime", gmctime)
if self.eseen:
r("erev")
r("enew")
r("edeleted")
r("ectime", gmctime)
r("emtime", gmctime)
if self.rseen:
r("rrev")
r("rsum", hexify)
if self.eseen:
r("esum", hexify)
class CVS:
"""Represent the contents of a CVS admin file (and more).
Class variables:
FileClass -- the class to be instantiated for entries
(this should be derived from class File above)
IgnoreList -- shell patterns for local files to be ignored
Instance variables:
entries -- a dictionary containing File instances keyed by
their file name
proxy -- an RCSProxy instance, or None
"""
FileClass = File
IgnoreList = ['.*', '@*', ',*', '*~', '*.o', '*.a', '*.so', '*.pyc']
def __init__(self):
self.entries = {}
self.proxy = None
def setproxy(self, proxy):
if proxy is self.proxy:
return
self.proxy = proxy
for e in list(self.entries.values()):
e.rseen = 0
def getentries(self):
"""Read the contents of CVS/Entries"""
self.entries = {}
f = self.cvsopen("Entries")
while 1:
line = f.readline()
if not line: break
e = self.FileClass()
e.getentry(line)
self.entries[e.file] = e
f.close()
def putentries(self):
"""Write CVS/Entries back"""
f = self.cvsopen("Entries", 'w')
for e in list(self.values()):
f.write(e.putentry())
f.close()
def getlocalfiles(self):
entries_keys = set(self.entries.keys())
addlist = os.listdir(os.curdir)
for name in addlist:
if not self.ignored(name):
entries_keys.add(name)
for file in sorted(entries_keys):
try:
e = self.entries[file]
except KeyError:
e = self.entries[file] = self.FileClass(file)
e.getlocal()
def getremotefiles(self, proxy = None):
if proxy:
self.proxy = proxy
if not self.proxy:
raise RuntimeError("no RCS proxy")
addlist = self.proxy.listfiles()
for file in addlist:
try:
e = self.entries[file]
except KeyError:
e = self.entries[file] = self.FileClass(file)
e.getremote(self.proxy)
def report(self):
for e in list(self.values()):
e.report()
print('-'*50)
def keys(self):
return sorted(self.entries.keys())
def values(self):
def value(key, self=self):
return self.entries[key]
return [value(k) for k in self.keys()]
def items(self):
def item(key, self=self):
return (key, self.entries[key])
return [item(k) for k in self.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 + '~'
try: os.unlink(bfile)
except os.error: pass
os.rename(file, bfile)
def ignored(self, file):
if os.path.isdir(file): return True
for pat in self.IgnoreList:
if fnmatch.fnmatch(file, pat): return True
return False
# hexify and unhexify are useful to print MD5 checksums in hex format
hexify_format = '%02x' * 16
def hexify(sum):
"Return a hex representation of a 16-byte string (e.g. an MD5 digest)"
if sum is None:
return "None"
return hexify_format % tuple(map(ord, sum))
def unhexify(hexsum):
"Return the original from a hexified string"
if hexsum == "None":
return None
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 date == "None": return None
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] = list(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):
if t is None: return "None"
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()
x.getentries()
x.getlocalfiles()
## x.report()
import rcsclient
proxy = rcsclient.openrcsclient()
x.getremotefiles(proxy)
x.report()
if __name__ == "__main__":
test()

View File

@ -1,279 +0,0 @@
"""CVS locking algorithm.
CVS locking strategy
====================
As reverse engineered from the CVS 1.3 sources (file lock.c):
- Locking is done on a per repository basis (but a process can hold
write locks for multiple directories); all lock files are placed in
the repository and have names beginning with "#cvs.".
- Before even attempting to lock, a file "#cvs.tfl.<pid>" is created
(and removed again), to test that we can write the repository. [The
algorithm can still be fooled (1) if the repository's mode is changed
while attempting to lock; (2) if this file exists and is writable but
the directory is not.]
- While creating the actual read/write lock files (which may exist for
a long time), a "meta-lock" is held. The meta-lock is a directory
named "#cvs.lock" in the repository. The meta-lock is also held while
a write lock is held.
- To set a read lock:
- acquire the meta-lock
- create the file "#cvs.rfl.<pid>"
- release the meta-lock
- To set a write lock:
- acquire the meta-lock
- check that there are no files called "#cvs.rfl.*"
- if there are, release the meta-lock, sleep, try again
- create the file "#cvs.wfl.<pid>"
- To release a write lock:
- remove the file "#cvs.wfl.<pid>"
- rmdir the meta-lock
- To release a read lock:
- remove the file "#cvs.rfl.<pid>"
Additional notes
----------------
- A process should read-lock at most one repository at a time.
- A process may write-lock as many repositories as it wishes (to avoid
deadlocks, I presume it should always lock them top-down in the
directory hierarchy).
- A process should make sure it removes all its lock files and
directories when it crashes.
- Limitation: one user id should not be committing files into the same
repository at the same time.
Turn this into Python code
--------------------------
rl = ReadLock(repository, waittime)
wl = WriteLock(repository, waittime)
list = MultipleWriteLock([repository1, repository2, ...], waittime)
"""
import os
import time
import stat
import pwd
# Default wait time
DELAY = 10
# XXX This should be the same on all Unix versions
EEXIST = 17
# Files used for locking (must match cvs.h in the CVS sources)
CVSLCK = "#cvs.lck"
CVSRFL = "#cvs.rfl."
CVSWFL = "#cvs.wfl."
class Error:
def __init__(self, msg):
self.msg = msg
def __repr__(self):
return repr(self.msg)
def __str__(self):
return str(self.msg)
class Locked(Error):
pass
class Lock:
def __init__(self, repository = ".", delay = DELAY):
self.repository = repository
self.delay = delay
self.lockdir = None
self.lockfile = None
pid = repr(os.getpid())
self.cvslck = self.join(CVSLCK)
self.cvsrfl = self.join(CVSRFL + pid)
self.cvswfl = self.join(CVSWFL + pid)
def __del__(self):
print("__del__")
self.unlock()
def setlockdir(self):
while 1:
try:
self.lockdir = self.cvslck
os.mkdir(self.cvslck, 0o777)
return
except os.error as msg:
self.lockdir = None
if msg.args[0] == EEXIST:
try:
st = os.stat(self.cvslck)
except os.error:
continue
self.sleep(st)
continue
raise Error("failed to lock %s: %s" % (
self.repository, msg))
def unlock(self):
self.unlockfile()
self.unlockdir()
def unlockfile(self):
if self.lockfile:
print("unlink", self.lockfile)
try:
os.unlink(self.lockfile)
except os.error:
pass
self.lockfile = None
def unlockdir(self):
if self.lockdir:
print("rmdir", self.lockdir)
try:
os.rmdir(self.lockdir)
except os.error:
pass
self.lockdir = None
def sleep(self, st):
sleep(st, self.repository, self.delay)
def join(self, name):
return os.path.join(self.repository, name)
def sleep(st, repository, delay):
if delay <= 0:
raise Locked(st)
uid = st[stat.ST_UID]
try:
pwent = pwd.getpwuid(uid)
user = pwent[0]
except KeyError:
user = "uid %d" % uid
print("[%s]" % time.ctime(time.time())[11:19], end=' ')
print("Waiting for %s's lock in" % user, repository)
time.sleep(delay)
class ReadLock(Lock):
def __init__(self, repository, delay = DELAY):
Lock.__init__(self, repository, delay)
ok = 0
try:
self.setlockdir()
self.lockfile = self.cvsrfl
fp = open(self.lockfile, 'w')
fp.close()
ok = 1
finally:
if not ok:
self.unlockfile()
self.unlockdir()
class WriteLock(Lock):
def __init__(self, repository, delay = DELAY):
Lock.__init__(self, repository, delay)
self.setlockdir()
while 1:
uid = self.readers_exist()
if not uid:
break
self.unlockdir()
self.sleep(uid)
self.lockfile = self.cvswfl
fp = open(self.lockfile, 'w')
fp.close()
def readers_exist(self):
n = len(CVSRFL)
for name in os.listdir(self.repository):
if name[:n] == CVSRFL:
try:
st = os.stat(self.join(name))
except os.error:
continue
return st
return None
def MultipleWriteLock(repositories, delay = DELAY):
while 1:
locks = []
for r in repositories:
try:
locks.append(WriteLock(r, 0))
except Locked as instance:
del locks
break
else:
break
sleep(instance.msg, r, delay)
return list
def test():
import sys
if sys.argv[1:]:
repository = sys.argv[1]
else:
repository = "."
rl = None
wl = None
try:
print("attempting write lock ...")
wl = WriteLock(repository)
print("got it.")
wl.unlock()
print("attempting read lock ...")
rl = ReadLock(repository)
print("got it.")
rl.unlock()
finally:
print([1])
print([2])
if rl:
rl.unlock()
print([3])
if wl:
wl.unlock()
print([4])
rl = None
print([5])
wl = None
print([6])
if __name__ == '__main__':
test()

View File

@ -1,24 +0,0 @@
import sys
import rcvs
def raw_input(prompt):
sys.stdout.write(prompt)
sys.stdout.flush()
return sys.stdin.readline()
def main():
while 1:
try:
line = input('$ ')
except EOFError:
break
words = line.split()
if not words:
continue
if words[0] != 'rcvs':
words.insert(0, 'rcvs')
sys.argv = words
rcvs.main()
if __name__ == '__main__':
main()

View File

@ -1,109 +0,0 @@
#! /usr/bin/env python3
"""Turn a pile of RCS log output into ChangeLog file entries.
"""
import sys
import string
import re
import getopt
import time
def main():
args = sys.argv[1:]
opts, args = getopt.getopt(args, 'p:')
prefix = ''
for o, a in opts:
if p == '-p': prefix = a
f = sys.stdin
allrevs = []
while 1:
file = getnextfile(f)
if not file: break
revs = []
while 1:
rev = getnextrev(f, file)
if not rev:
break
revs.append(rev)
if revs:
allrevs[len(allrevs):] = revs
allrevs.sort()
allrevs.reverse()
for rev in allrevs:
formatrev(rev, prefix)
parsedateprog = re.compile(
'^date: ([0-9]+)/([0-9]+)/([0-9]+) ' +
'([0-9]+):([0-9]+):([0-9]+); author: ([^ ;]+)')
authormap = {
'guido': 'Guido van Rossum <guido@cnri.reston.va.us>',
'jack': 'Jack Jansen <jack@cwi.nl>',
'sjoerd': 'Sjoerd Mullender <sjoerd@cwi.nl>',
}
def formatrev(rev, prefix):
dateline, file, revline, log = rev
if parsedateprog.match(dateline) >= 0:
fields = parsedateprog.group(1, 2, 3, 4, 5, 6)
author = parsedateprog.group(7)
if author in authormap: author = authormap[author]
tfields = list(map(string.atoi, fields)) + [0, 0, 0]
tfields[5] = tfields[5] - time.timezone
t = time.mktime(tuple(tfields))
print(time.ctime(t), '', author)
words = string.split(log)
words[:0] = ['*', prefix + file + ':']
maxcol = 72-8
col = maxcol
for word in words:
if col > 0 and col + len(word) >= maxcol:
print()
print('\t' + word, end=' ')
col = -1
else:
print(word, end=' ')
col = col + 1 + len(word)
print()
print()
startprog = re.compile("^Working file: (.*)$")
def getnextfile(f):
while 1:
line = f.readline()
if not line: return None
if startprog.match(line) >= 0:
file = startprog.group(1)
# Skip until first revision
while 1:
line = f.readline()
if not line: return None
if line[:10] == '='*10: return None
if line[:10] == '-'*10: break
## print "Skipped", line,
return file
## else:
## print "Ignored", line,
def getnextrev(f, file):
# This is called when we are positioned just after a '---' separator
revline = f.readline()
dateline = f.readline()
log = ''
while 1:
line = f.readline()
if not line: break
if line[:10] == '='*10:
# Ignore the *last* log entry for each file since it
# is the revision since which we are logging.
return None
if line[:10] == '-'*10: break
log = log + line
return dateline, file, revline, log
if __name__ == '__main__':
main()

View File

@ -1,33 +0,0 @@
#!/usr/bin/env python
# -*- python -*-
#
# guido's version, from rcsbump,v 1.2 1995/06/22 21:27:27 bwarsaw Exp
#
# Python script for bumping up an RCS major revision number.
import sys
import re
import rcslib
import string
WITHLOCK = 1
majorrev_re = re.compile('^[0-9]+')
dir = rcslib.RCS()
if sys.argv[1:]:
files = sys.argv[1:]
else:
files = dir.listfiles()
for file in files:
# get the major revnumber of the file
headbranch = dir.info(file)['head']
majorrev_re.match(headbranch)
majorrev = string.atoi(majorrev_re.group(0)) + 1
if not dir.islocked(file):
dir.checkout(file, WITHLOCK)
msg = "Bumping major revision number (to %d)" % majorrev
dir.checkin((file, "%s.0" % majorrev), msg, "-f")

View File

@ -1,71 +0,0 @@
"""Customize this file to change the default client etc.
(In general, it is probably be better to make local operation the
default and to require something like an RCSSERVER environment
variable to enable remote operation.)
"""
import string
import os
# These defaults don't belong here -- they should be taken from the
# environment or from a hidden file in the current directory
HOST = 'voorn.cwi.nl'
PORT = 4127
VERBOSE = 1
LOCAL = 0
import client
class RCSProxyClient(client.SecureClient):
def __init__(self, address, verbose = client.VERBOSE):
client.SecureClient.__init__(self, address, verbose)
def openrcsclient(opts = []):
"open an RCSProxy client based on a list of options returned by getopt"
import RCSProxy
host = HOST
port = PORT
verbose = VERBOSE
local = LOCAL
directory = None
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 == '-d':
directory = a
if o == '-v':
verbose = verbose + 1
if o == '-q':
verbose = 0
if o == '-L':
local = 1
if local:
import RCSProxy
x = RCSProxy.RCSProxyLocal()
else:
address = (host, port)
x = RCSProxyClient(address, verbose)
if not directory:
try:
directory = open(os.path.join("CVS", "Repository")).readline()
except IOError:
pass
else:
if directory[-1] == '\n':
directory = directory[:-1]
if directory:
x.cd(directory)
return x

View File

@ -1,334 +0,0 @@
"""RCS interface module.
Defines the class RCS, which represents a directory with rcs version
files and (possibly) corresponding work files.
"""
import fnmatch
import os
import re
import string
import tempfile
class RCS:
"""RCS interface class (local filesystem version).
An instance of this class represents a directory with rcs version
files and (possible) corresponding work files.
Methods provide access to most rcs operations such as
checkin/checkout, access to the rcs metadata (revisions, logs,
branches etc.) as well as some filesystem operations such as
listing all rcs version files.
XXX BUGS / PROBLEMS
- The instance always represents the current directory so it's not
very useful to have more than one instance around simultaneously
"""
# Characters allowed in work file names
okchars = string.ascii_letters + string.digits + '-_=+'
def __init__(self):
"""Constructor."""
pass
def __del__(self):
"""Destructor."""
pass
# --- Informational methods about a single file/revision ---
def log(self, name_rev, otherflags = ''):
"""Return the full log text for NAME_REV as a string.
Optional OTHERFLAGS are passed to rlog.
"""
f = self._open(name_rev, 'rlog ' + otherflags)
data = f.read()
status = self._closepipe(f)
if status:
data = data + "%s: %s" % status
elif data[-1] == '\n':
data = data[:-1]
return data
def head(self, name_rev):
"""Return the head revision for NAME_REV"""
dict = self.info(name_rev)
return dict['head']
def info(self, name_rev):
"""Return a dictionary of info (from rlog -h) for NAME_REV
The dictionary's keys are the keywords that rlog prints
(e.g. 'head' and its values are the corresponding data
(e.g. '1.3').
XXX symbolic names and locks are not returned
"""
f = self._open(name_rev, 'rlog -h')
dict = {}
while 1:
line = f.readline()
if not line: break
if line[0] == '\t':
# XXX could be a lock or symbolic name
# Anything else?
continue
i = string.find(line, ':')
if i > 0:
key, value = line[:i], string.strip(line[i+1:])
dict[key] = value
status = self._closepipe(f)
if status:
raise IOError(status)
return dict
# --- Methods that change files ---
def lock(self, name_rev):
"""Set an rcs lock on NAME_REV."""
name, rev = self.checkfile(name_rev)
cmd = "rcs -l%s %s" % (rev, name)
return self._system(cmd)
def unlock(self, name_rev):
"""Clear an rcs lock on NAME_REV."""
name, rev = self.checkfile(name_rev)
cmd = "rcs -u%s %s" % (rev, name)
return self._system(cmd)
def checkout(self, name_rev, withlock=0, otherflags=""):
"""Check out NAME_REV to its work file.
If optional WITHLOCK is set, check out locked, else unlocked.
The optional OTHERFLAGS is passed to co without
interpretation.
Any output from co goes to directly to stdout.
"""
name, rev = self.checkfile(name_rev)
if withlock: lockflag = "-l"
else: lockflag = "-u"
cmd = 'co %s%s %s %s' % (lockflag, rev, otherflags, name)
return self._system(cmd)
def checkin(self, name_rev, message=None, otherflags=""):
"""Check in NAME_REV from its work file.
The optional MESSAGE argument becomes the checkin message
(default "<none>" if None); or the file description if this is
a new file.
The optional OTHERFLAGS argument is passed to ci without
interpretation.
Any output from ci goes to directly to stdout.
"""
name, rev = self._unmangle(name_rev)
new = not self.isvalid(name)
if not message: message = "<none>"
if message and message[-1] != '\n':
message = message + '\n'
lockflag = "-u"
if new:
f = tempfile.NamedTemporaryFile()
f.write(message)
f.flush()
cmd = 'ci %s%s -t%s %s %s' % \
(lockflag, rev, f.name, otherflags, name)
else:
message = re.sub(r'([\"$`])', r'\\\1', message)
cmd = 'ci %s%s -m"%s" %s %s' % \
(lockflag, rev, message, otherflags, name)
return self._system(cmd)
# --- Exported support methods ---
def listfiles(self, pat = None):
"""Return a list of all version files matching optional PATTERN."""
files = os.listdir(os.curdir)
files = list(filter(self._isrcs, files))
if os.path.isdir('RCS'):
files2 = os.listdir('RCS')
files2 = list(filter(self._isrcs, files2))
files = files + files2
files = list(map(self.realname, files))
return self._filter(files, pat)
def isvalid(self, name):
"""Test whether NAME has a version file associated."""
namev = self.rcsname(name)
return (os.path.isfile(namev) or
os.path.isfile(os.path.join('RCS', namev)))
def rcsname(self, name):
"""Return the pathname of the version file for NAME.
The argument can be a work file name or a version file name.
If the version file does not exist, the name of the version
file that would be created by "ci" is returned.
"""
if self._isrcs(name): namev = name
else: namev = name + ',v'
if os.path.isfile(namev): return namev
namev = os.path.join('RCS', os.path.basename(namev))
if os.path.isfile(namev): return namev
if os.path.isdir('RCS'):
return os.path.join('RCS', namev)
else:
return namev
def realname(self, namev):
"""Return the pathname of the work file for NAME.
The argument can be a work file name or a version file name.
If the work file does not exist, the name of the work file
that would be created by "co" is returned.
"""
if self._isrcs(namev): name = namev[:-2]
else: name = namev
if os.path.isfile(name): return name
name = os.path.basename(name)
return name
def islocked(self, name_rev):
"""Test whether FILE (which must have a version file) is locked.
XXX This does not tell you which revision number is locked and
ignores any revision you may pass in (by virtue of using rlog
-L -R).
"""
f = self._open(name_rev, 'rlog -L -R')
line = f.readline()
status = self._closepipe(f)
if status:
raise IOError(status)
if not line: return None
if line[-1] == '\n':
line = line[:-1]
return self.realname(name_rev) == self.realname(line)
def checkfile(self, name_rev):
"""Normalize NAME_REV into a (NAME, REV) tuple.
Raise an exception if there is no corresponding version file.
"""
name, rev = self._unmangle(name_rev)
if not self.isvalid(name):
raise os.error('not an rcs file %r' % (name,))
return name, rev
# --- Internal methods ---
def _open(self, name_rev, cmd = 'co -p', rflag = '-r'):
"""INTERNAL: open a read pipe to NAME_REV using optional COMMAND.
Optional FLAG is used to indicate the revision (default -r).
Default COMMAND is "co -p".
Return a file object connected by a pipe to the command's
output.
"""
name, rev = self.checkfile(name_rev)
namev = self.rcsname(name)
if rev:
cmd = cmd + ' ' + rflag + rev
return os.popen("%s %r" % (cmd, namev))
def _unmangle(self, name_rev):
"""INTERNAL: Normalize NAME_REV argument to (NAME, REV) tuple.
Raise an exception if NAME contains invalid characters.
A NAME_REV argument is either NAME string (implying REV='') or
a tuple of the form (NAME, REV).
"""
if type(name_rev) == type(''):
name_rev = name, rev = name_rev, ''
else:
name, rev = name_rev
for c in rev:
if c not in self.okchars:
raise ValueError("bad char in rev")
return name_rev
def _closepipe(self, f):
"""INTERNAL: Close PIPE and print its exit status if nonzero."""
sts = f.close()
if not sts: return None
detail, reason = divmod(sts, 256)
if reason == 0: return 'exit', detail # Exit status
signal = reason&0x7F
if signal == 0x7F:
code = 'stopped'
signal = detail
else:
code = 'killed'
if reason&0x80:
code = code + '(coredump)'
return code, signal
def _system(self, cmd):
"""INTERNAL: run COMMAND in a subshell.
Standard input for the command is taken from /dev/null.
Raise IOError when the exit status is not zero.
Return whatever the calling method should return; normally
None.
A derived class may override this method and redefine it to
capture stdout/stderr of the command and return it.
"""
cmd = cmd + " </dev/null"
sts = os.system(cmd)
if sts: raise IOError("command exit status %d" % sts)
def _filter(self, files, pat = None):
"""INTERNAL: Return a sorted copy of the given list of FILES.
If a second PATTERN argument is given, only files matching it
are kept. No check for valid filenames is made.
"""
if pat:
def keep(name, pat = pat):
return fnmatch.fnmatch(name, pat)
files = list(filter(keep, files))
else:
files = files[:]
files.sort()
return files
def _remove(self, fn):
"""INTERNAL: remove FILE without complaints."""
try:
os.unlink(fn)
except os.error:
pass
def _isrcs(self, name):
"""INTERNAL: Test whether NAME ends in ',v'."""
return name[-2:] == ',v'

View File

@ -1,8 +0,0 @@
#!/usr/bin/env python
import addpack
addpack.addpack('/home/guido/src/python/Demo/pdist')
import rcvs
rcvs.main()

View File

@ -1,476 +0,0 @@
#! /usr/bin/env python3
"""Remote CVS -- command line interface"""
# XXX To do:
#
# Bugs:
# - if the remote file is deleted, "rcvs update" will fail
#
# Functionality:
# - cvs rm
# - descend into directories (alraedy done for update)
# - conflict resolution
# - other relevant commands?
# - branches
#
# - Finesses:
# - retain file mode's x bits
# - complain when "nothing known about filename"
# - edit log message the way CVS lets you edit it
# - cvs diff -rREVA -rREVB
# - send mail the way CVS sends it
#
# Performance:
# - cache remote checksums (for every revision ever seen!)
# - translate symbolic revisions to numeric revisions
#
# Reliability:
# - remote locking
#
# Security:
# - Authenticated RPC?
from cvslib import CVS, File
import md5
import os
import sys
from cmdfw import CommandFrameWork
DEF_LOCAL = 1 # Default -l
class MyFile(File):
def action(self):
"""Return a code indicating the update status of this file.
The possible return values are:
'=' -- everything's fine
'0' -- file doesn't exist anywhere
'?' -- exists locally only
'A' -- new locally
'R' -- deleted locally
'U' -- changed remotely, no changes locally
(includes new remotely or deleted remotely)
'M' -- changed locally, no changes remotely
'C' -- conflict: changed locally as well as remotely
(includes cases where the file has been added
or removed locally and remotely)
'D' -- deleted remotely
'N' -- new remotely
'r' -- get rid of entry
'c' -- create entry
'u' -- update entry
(and probably others :-)
"""
if not self.lseen:
self.getlocal()
if not self.rseen:
self.getremote()
if not self.eseen:
if not self.lsum:
if not self.rsum: return '0' # Never heard of
else:
return 'N' # New remotely
else: # self.lsum
if not self.rsum: return '?' # Local only
# Local and remote, but no entry
if self.lsum == self.rsum:
return 'c' # Restore entry only
else: return 'C' # Real conflict
else: # self.eseen
if not self.lsum:
if self.edeleted:
if self.rsum: return 'R' # Removed
else: return 'r' # Get rid of entry
else: # not self.edeleted
if self.rsum:
print("warning:", end=' ')
print(self.file, end=' ')
print("was lost")
return 'U'
else: return 'r' # Get rid of entry
else: # self.lsum
if not self.rsum:
if self.enew: return 'A' # New locally
else: return 'D' # Deleted remotely
else: # self.rsum
if self.enew:
if self.lsum == self.rsum:
return 'u'
else:
return 'C'
if self.lsum == self.esum:
if self.esum == self.rsum:
return '='
else:
return 'U'
elif self.esum == self.rsum:
return 'M'
elif self.lsum == self.rsum:
return 'u'
else:
return 'C'
def update(self):
code = self.action()
if code == '=': return
print(code, self.file)
if code in ('U', 'N'):
self.get()
elif code == 'C':
print("%s: conflict resolution not yet implemented" % \
self.file)
elif code == 'D':
remove(self.file)
self.eseen = 0
elif code == 'r':
self.eseen = 0
elif code in ('c', 'u'):
self.eseen = 1
self.erev = self.rrev
self.enew = 0
self.edeleted = 0
self.esum = self.rsum
self.emtime, self.ectime = os.stat(self.file)[-2:]
self.extra = ''
def commit(self, message = ""):
code = self.action()
if code in ('A', 'M'):
self.put(message)
return 1
elif code == 'R':
print("%s: committing removes not yet implemented" % \
self.file)
elif code == 'C':
print("%s: conflict resolution not yet implemented" % \
self.file)
def diff(self, opts = []):
self.action() # To update lseen, rseen
flags = ''
rev = self.rrev
# XXX should support two rev options too!
for o, a in opts:
if o == '-r':
rev = a
else:
flags = flags + ' ' + o + a
if rev == self.rrev and self.lsum == self.rsum:
return
flags = flags[1:]
fn = self.file
data = self.proxy.get((fn, rev))
sum = md5.new(data).digest()
if self.lsum == sum:
return
import tempfile
tf = tempfile.NamedTemporaryFile()
tf.write(data)
tf.flush()
print('diff %s -r%s %s' % (flags, rev, fn))
sts = os.system('diff %s %s %s' % (flags, tf.name, fn))
if sts:
print('='*70)
def commitcheck(self):
return self.action() != 'C'
def put(self, message = ""):
print("Checking in", self.file, "...")
data = open(self.file).read()
if not self.enew:
self.proxy.lock(self.file)
messages = self.proxy.put(self.file, data, message)
if messages:
print(messages)
self.setentry(self.proxy.head(self.file), self.lsum)
def get(self):
data = self.proxy.get(self.file)
f = open(self.file, 'w')
f.write(data)
f.close()
self.setentry(self.rrev, self.rsum)
def log(self, otherflags):
print(self.proxy.log(self.file, otherflags))
def add(self):
self.eseen = 0 # While we're hacking...
self.esum = self.lsum
self.emtime, self.ectime = 0, 0
self.erev = ''
self.enew = 1
self.edeleted = 0
self.eseen = 1 # Done
self.extra = ''
def setentry(self, erev, esum):
self.eseen = 0 # While we're hacking...
self.esum = esum
self.emtime, self.ectime = os.stat(self.file)[-2:]
self.erev = erev
self.enew = 0
self.edeleted = 0
self.eseen = 1 # Done
self.extra = ''
SENDMAIL = "/usr/lib/sendmail -t"
MAILFORM = """To: %s
Subject: CVS changes: %s
...Message from rcvs...
Committed files:
%s
Log message:
%s
"""
class RCVS(CVS):
FileClass = MyFile
def __init__(self):
CVS.__init__(self)
def update(self, files):
for e in self.whichentries(files, 1):
e.update()
def commit(self, files, message = ""):
list = self.whichentries(files)
if not list: return
ok = 1
for e in list:
if not e.commitcheck():
ok = 0
if not ok:
print("correct above errors first")
return
if not message:
message = input("One-liner: ")
committed = []
for e in list:
if e.commit(message):
committed.append(e.file)
self.mailinfo(committed, message)
def mailinfo(self, files, message = ""):
towhom = "sjoerd@cwi.nl, jack@cwi.nl" # XXX
mailtext = MAILFORM % (towhom, ' '.join(files),
' '.join(files), message)
print('-'*70)
print(mailtext)
print('-'*70)
ok = input("OK to mail to %s? " % towhom)
if ok.lower().strip() in ('y', 'ye', 'yes'):
p = os.popen(SENDMAIL, "w")
p.write(mailtext)
sts = p.close()
if sts:
print("Sendmail exit status %s" % str(sts))
else:
print("Mail sent.")
else:
print("No mail sent.")
def report(self, files):
for e in self.whichentries(files):
e.report()
def diff(self, files, opts):
for e in self.whichentries(files):
e.diff(opts)
def add(self, files):
if not files:
raise RuntimeError("'cvs add' needs at least one file")
list = []
for e in self.whichentries(files, 1):
e.add()
def rm(self, files):
if not files:
raise RuntimeError("'cvs rm' needs at least one file")
raise RuntimeError("'cvs rm' not yet imlemented")
def log(self, files, opts):
flags = ''
for o, a in opts:
flags = flags + ' ' + o + a
for e in self.whichentries(files):
e.log(flags)
def whichentries(self, files, localfilestoo = 0):
if files:
list = []
for file in files:
if file in self.entries:
e = self.entries[file]
else:
e = self.FileClass(file)
self.entries[file] = e
list.append(e)
else:
list = list(self.entries.values())
for file in self.proxy.listfiles():
if file in self.entries:
continue
e = self.FileClass(file)
self.entries[file] = e
list.append(e)
if localfilestoo:
for file in os.listdir(os.curdir):
if file not in self.entries \
and not self.ignored(file):
e = self.FileClass(file)
self.entries[file] = e
list.append(e)
list.sort()
if self.proxy:
for e in list:
if e.proxy is None:
e.proxy = self.proxy
return list
class rcvs(CommandFrameWork):
GlobalFlags = 'd:h:p:qvL'
UsageMessage = \
"usage: rcvs [-d directory] [-h host] [-p port] [-q] [-v] [subcommand arg ...]"
PostUsageMessage = \
"If no subcommand is given, the status of all files is listed"
def __init__(self):
"""Constructor."""
CommandFrameWork.__init__(self)
self.proxy = None
self.cvs = RCVS()
def close(self):
if self.proxy:
self.proxy._close()
self.proxy = None
def recurse(self):
self.close()
names = os.listdir(os.curdir)
for name in names:
if name == os.curdir or name == os.pardir:
continue
if name == "CVS":
continue
if not os.path.isdir(name):
continue
if os.path.islink(name):
continue
print("--- entering subdirectory", name, "---")
os.chdir(name)
try:
if os.path.isdir("CVS"):
self.__class__().run()
else:
self.recurse()
finally:
os.chdir(os.pardir)
print("--- left subdirectory", name, "---")
def options(self, opts):
self.opts = opts
def ready(self):
import rcsclient
self.proxy = rcsclient.openrcsclient(self.opts)
self.cvs.setproxy(self.proxy)
self.cvs.getentries()
def default(self):
self.cvs.report([])
def do_report(self, opts, files):
self.cvs.report(files)
def do_update(self, opts, files):
"""update [-l] [-R] [file] ..."""
local = DEF_LOCAL
for o, a in opts:
if o == '-l': local = 1
if o == '-R': local = 0
self.cvs.update(files)
self.cvs.putentries()
if not local and not files:
self.recurse()
flags_update = '-lR'
do_up = do_update
flags_up = flags_update
def do_commit(self, opts, files):
"""commit [-m message] [file] ..."""
message = ""
for o, a in opts:
if o == '-m': message = a
self.cvs.commit(files, message)
self.cvs.putentries()
flags_commit = 'm:'
do_com = do_commit
flags_com = flags_commit
def do_diff(self, opts, files):
"""diff [difflags] [file] ..."""
self.cvs.diff(files, opts)
flags_diff = 'cbitwcefhnlr:sD:S:'
do_dif = do_diff
flags_dif = flags_diff
def do_add(self, opts, files):
"""add file ..."""
if not files:
print("'rcvs add' requires at least one file")
return
self.cvs.add(files)
self.cvs.putentries()
def do_remove(self, opts, files):
"""remove file ..."""
if not files:
print("'rcvs remove' requires at least one file")
return
self.cvs.remove(files)
self.cvs.putentries()
do_rm = do_remove
def do_log(self, opts, files):
"""log [rlog-options] [file] ..."""
self.cvs.log(files, opts)
flags_log = 'bhLNRtd:s:V:r:'
def remove(fn):
try:
os.unlink(fn)
except os.error:
pass
def main():
r = rcvs()
try:
r.run()
finally:
r.close()
if __name__ == "__main__":
main()

View File

@ -1,8 +0,0 @@
#!/usr/bin/env python
import addpack
addpack.addpack('/home/guido/src/python/Demo/pdist')
import rrcs
rrcs.main()

View File

@ -1,158 +0,0 @@
#! /usr/bin/env python3
"Remote RCS -- command line interface"
import sys
import os
import getopt
import string
import md5
import tempfile
from rcsclient import openrcsclient
def main():
sys.stdout = sys.stderr
try:
opts, rest = getopt.getopt(sys.argv[1:], 'h:p:d:qvL')
if not rest:
cmd = 'head'
else:
cmd, rest = rest[0], rest[1:]
if cmd not in commands:
raise getopt.error("unknown command")
coptset, func = commands[cmd]
copts, files = getopt.getopt(rest, coptset)
except getopt.error as 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 = openrcsclient(opts)
if not files:
files = x.listfiles()
for fn in files:
try:
func(x, copts, fn)
except (IOError, os.error) as msg:
print("%s: %s" % (fn, msg))
def checkin(x, copts, fn):
f = open(fn)
data = f.read()
f.close()
new = not x.isvalid(fn)
if not new and same(x, copts, fn, data):
print("%s: unchanged since last checkin" % fn)
return
print("Checking in", fn, "...")
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 lock(x, copts, fn):
x.lock(fn)
def unlock(x, copts, fn):
x.unlock(fn)
def info(x, copts, fn):
info_dict = x.info(fn)
for key in sorted(info_dict.keys()):
print(key + ':', info_dict[key])
print('='*70)
def head(x, copts, fn):
head = x.head(fn)
print(fn, head)
def list(x, copts, fn):
if x.isvalid(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)
tf = tempfile.NamedTemporaryFile()
tf.write(data)
tf.flush()
print('diff %s -r%s %s' % (flags, x.head(fn), fn))
sts = os.system('diff %s %s %s' % (flags, tf.name, fn))
if sts:
print('='*70)
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,", end=' ')
else:
print("enter log message,", end=' ')
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),
'lock': ('', lock),
'unlock': ('', unlock),
'log': ('bhLRtd:l:r:s:w:V:', log),
'diff': ('c', diff),
}
if __name__ == '__main__':
main()

View File

@ -1,33 +0,0 @@
class Security:
def __init__(self):
import os
env = os.environ
if 'PYTHON_KEYFILE' in env:
keyfile = env['PYTHON_KEYFILE']
else:
keyfile = '.python_keyfile'
if 'HOME' in env:
keyfile = os.path.join(env['HOME'], keyfile)
if not os.path.exists(keyfile):
import sys
for dir in sys.path:
kf = os.path.join(dir, keyfile)
if os.path.exists(kf):
keyfile = kf
break
try:
self._key = eval(open(keyfile).readline())
except IOError:
raise IOError("python keyfile %s: cannot open" % keyfile)
def _generate_challenge(self):
import random
return random.randint(100, 100000)
def _compare_challenge_response(self, challenge, response):
return self._encode_challenge(challenge) == response
def _encode_challenge(self, challenge):
p, m = self._key
return pow(int(challenge), p, m)

View File

@ -1,143 +0,0 @@
"""RPC Server module."""
import sys
import socket
import pickle
from fnmatch import fnmatch
from reprlib import repr
# Default verbosity (0 = silent, 1 = print connections, 2 = print requests too)
VERBOSE = 1
class Server:
"""RPC Server class. Derive a class to implement a particular service."""
def __init__(self, address, verbose = VERBOSE):
if type(address) == type(0):
address = ('', address)
self._address = address
self._verbose = verbose
self._socket = None
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._socket.bind(address)
self._socket.listen(1)
self._listening = 1
def _setverbose(self, verbose):
self._verbose = verbose
def __del__(self):
self._close()
def _close(self):
self._listening = 0
if self._socket:
self._socket.close()
self._socket = None
def _serverloop(self):
while self._listening:
self._serve()
def _serve(self):
if self._verbose: print("Wait for connection ...")
conn, address = self._socket.accept()
if self._verbose: print("Accepted connection from %s" % repr(address))
if not self._verify(conn, address):
print("*** Connection from %s refused" % repr(address))
conn.close()
return
rf = conn.makefile('r')
wf = conn.makefile('w')
ok = 1
while ok:
wf.flush()
if self._verbose > 1: print("Wait for next request ...")
ok = self._dorequest(rf, wf)
_valid = ['192.16.201.*', '192.16.197.*', '132.151.1.*', '129.6.64.*']
def _verify(self, conn, address):
host, port = address
for pat in self._valid:
if fnmatch(host, pat): return 1
return 0
def _dorequest(self, rf, wf):
rp = pickle.Unpickler(rf)
try:
request = rp.load()
except EOFError:
return 0
if self._verbose > 1: print("Got request: %s" % repr(request))
try:
methodname, args, id = request
if '.' in methodname:
reply = (None, self._special(methodname, args), id)
elif methodname[0] == '_':
raise NameError("illegal method name %s" % repr(methodname))
else:
method = getattr(self, methodname)
reply = (None, method(*args), id)
except:
reply = (sys.exc_info()[:2], id)
if id < 0 and reply[:2] == (None, None):
if self._verbose > 1: print("Suppress reply")
return 1
if self._verbose > 1: print("Send reply: %s" % repr(reply))
wp = pickle.Pickler(wf)
wp.dump(reply)
return 1
def _special(self, methodname, args):
if methodname == '.methods':
if not hasattr(self, '_methods'):
self._methods = tuple(self._listmethods())
return self._methods
raise NameError("unrecognized special method name %s" % repr(methodname))
def _listmethods(self, cl=None):
if not cl: cl = self.__class__
names = sorted([x for x in cl.__dict__.keys() if x[0] != '_'])
for base in cl.__bases__:
basenames = self._listmethods(base)
basenames = list(filter(lambda x, names=names: x not in names, basenames))
names[len(names):] = basenames
return names
from security import Security
class SecureServer(Server, Security):
def __init__(self, *args):
Server.__init__(self, *args)
Security.__init__(self)
def _verify(self, conn, address):
import string
challenge = self._generate_challenge()
conn.send("%d\n" % challenge)
response = ""
while "\n" not in response and len(response) < 100:
data = conn.recv(100)
if not data:
break
response = response + data
try:
response = string.atol(string.strip(response))
except string.atol_error:
if self._verbose > 0:
print("Invalid response syntax", repr(response))
return 0
if not self._compare_challenge_response(challenge, response):
if self._verbose > 0:
print("Invalid response value", repr(response))
return 0
if self._verbose > 1:
print("Response matches challenge. Go ahead!")
return 1

View File

@ -1,27 +0,0 @@
import time
import sys
import FSProxy
def main():
t1 = time.time()
#proxy = FSProxy.FSProxyClient(('voorn.cwi.nl', 4127))
proxy = FSProxy.FSProxyLocal()
sumtree(proxy)
proxy._close()
t2 = time.time()
print(t2-t1, "seconds")
sys.stdout.write("[Return to exit] ")
sys.stdout.flush()
sys.stdin.readline()
def sumtree(proxy):
print("PWD =", proxy.pwd())
files = proxy.listfiles()
proxy.infolist(files)
subdirs = proxy.listsubdirs()
for name in subdirs:
proxy.cd(name)
sumtree(proxy)
proxy.back()
main()