Commit 68642f5e authored by Georg Brandl's avatar Georg Brandl

Remove obsolete pdist demo.

parent 2db2b8a1
......@@ -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.
......
"""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()
#! /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()
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).
"""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)
"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()
"""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()
This diff is collapsed.
"""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()
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()
#! /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()
#!/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")
"""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
This diff is collapsed.
#!/usr/bin/env python
import addpack
addpack.addpack('/home/guido/src/python/Demo/pdist')
import rcvs
rcvs.main()
This diff is collapsed.
#!/usr/bin/env python
import addpack
addpack.addpack('/home/guido/src/python/Demo/pdist')
import rrcs
rrcs.main()
#! /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()
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)
"""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
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()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment