[Zope-Checkins] CVS: Products/AdaptableStorage/gateway_fs - FSUserList.py:1.1 FSConnection.py:1.7 public.py:1.4
Shane Hathaway
shane@zope.com
Mon, 6 Jan 2003 18:18:14 -0500
Update of /cvs-repository/Products/AdaptableStorage/gateway_fs
In directory cvs.zope.org:/tmp/cvs-serv1755/gateway_fs
Modified Files:
FSConnection.py public.py
Added Files:
FSUserList.py
Log Message:
- Added a user folder mapper for the filesystem. SQL version coming
soon. (SQL tests fail at the moment.)
- Added unwriteData() to FSConnection. I may remove it later, since it turned
out I didn't need it.
- Made configuration errors easier to read.
- Added null implementations of certain interfaces.
- Added a default for FixedClassifier.
=== Added File Products/AdaptableStorage/gateway_fs/FSUserList.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""User list gateway, where the user list is stored in a flat file.
$Id: FSUserList.py,v 1.1 2003/01/06 23:17:41 shane Exp $
"""
from mapper_public import IGateway, RowSequenceSchema
class FSUserList:
__implements__ = IGateway
schema = RowSequenceSchema()
schema.addField('id', 'string', 1)
schema.addField('password', 'string')
schema.addField('roles', 'string:list')
schema.addField('domains', 'string:list')
def __init__(self, fs_conn):
self.fs_conn = fs_conn
def getSchema(self):
return self.schema
def load(self, event):
c = self.fs_conn
p = event.getKeychain()[-1]
assert c.readNodeType(p) == 'f'
text = c.readData(p)
res = []
for line in text.split('\n'):
L = line.strip()
if ':' in L:
id, password, rolelist, domainlist = L.split(':', 3)
roles = self._splitList(rolelist)
domains = self._splitList(domainlist)
res.append((id, password, roles, domains))
res.sort()
return res, text
def _splitList(self, s):
return tuple([item.strip() for item in s.split(',') if item])
def _joinList(self, items):
for item in items:
if item.strip() != item:
raise MappingError(
"Leading and trailing whitespace are not allowed in %s"
% repr(item))
item = item.strip()
if ',' in item or ':' in item or '\n' in item:
raise MappingError(
"Commas, colons, and newlines are not allowed in %s"
% repr(item))
return ','.join(items)
def store(self, event, state):
replace_lines = {}
for id, password, roles, domains in state:
if ':' in id or '\n' in id:
raise MappingError('User IDs cannot have colons or newlines')
if ':' in password or '\n' in password:
raise MappingError('Passwords cannot have colons or newlines')
rolelist = self._joinList(roles)
domainlist = self._joinList(domains)
to_write = '%s:%s:%s:%s' % (id, password, rolelist, domainlist)
replace_lines[id] = to_write
p = event.getKeychain()[-1]
self.fs_conn.writeNodeType(p, 'f')
text = self.fs_conn.readData(p, allow_missing=1)
if text is None:
text = ''
new_lines = []
# Replace / remove users
for line in text.split('\n'):
L = line.strip()
if ':' in L:
name, stuff = L.split(':', 1)
replace = replace_lines.get(name, '')
if replace and replace != L:
new_lines.append(replace)
del replace_lines[name]
# else remove the line
else:
new_lines.append(line)
# Append new users
for line in replace_lines.values():
new_lines.append(line)
# Write it
text = '\n'.join(new_lines)
self.fs_conn.writeData(p, text)
serial = list(state)
serial.sort()
return text
=== Products/AdaptableStorage/gateway_fs/FSConnection.py 1.6 => 1.7 ===
--- Products/AdaptableStorage/gateway_fs/FSConnection.py:1.6 Tue Dec 31 16:47:44 2002
+++ Products/AdaptableStorage/gateway_fs/FSConnection.py Mon Jan 6 18:17:41 2003
@@ -26,14 +26,14 @@
from mapper_public import ITPCConnection
-# Try to decipher this one ;-)
+# Try to decipher this regular expression ;-)
# It basically matches "\n[sectionname]...\n", where len(sectionname) > 0.
section_re = re.compile(r'^\[([^\[\]\n]+)\][^\r\n]*(?:\r\n|\r|\n)',
re.MULTILINE)
-NODE_TYPE_SECTION = '@node_type'
-DATA_SECTION = '@data'
+NODE_TYPE_SECTION = '@node_type' # Data is 'f' (file) or 'd' (directory)
+DATA_SECTION = '@data' # Data is a string (file) or list of names (directory)
# Write modes
@@ -73,7 +73,7 @@
self._preserve = {}
- def expandPath(self, subpath, check_exists=0):
+ def expandPath(self, subpath):
if self.basepath:
while subpath.startswith('/') or subpath.startswith('\\'):
subpath = subpath[1:]
@@ -81,8 +81,6 @@
else:
# unchanged.
path = subpath
- if check_exists:
- assert os.path.exists(path), '%s does not exist' % path
return path
@@ -128,20 +126,32 @@
self._write(subpath, DATA_SECTION, data)
+ def unwriteData(self, subpath):
+ m = self._pending
+ sections = m.get(subpath)
+ if sections is not None:
+ if sections.has_key(DATA_SECTION):
+ res = sections[DATA_SECTION]
+ del sections[DATA_SECTION]
+ return res
+ # Nothing was written.
+ return None
+
+
def readSection(self, subpath, section_name, default=None):
self.checkSectionName(section_name)
- path = self.expandPath(subpath, 1)
+ path = self.expandPath(subpath)
sections = self.getPropertiesFromFile(path)
return sections.get(section_name, default)
def readNodeType(self, subpath):
- path = self.expandPath(subpath, 1)
+ path = self.expandPath(subpath)
return os.path.isdir(path) and 'd' or 'f'
- def readData(self, subpath):
- path = self.expandPath(subpath, 1)
+ def readData(self, subpath, allow_missing=0):
+ path = self.expandPath(subpath)
isdir = os.path.isdir(path)
# Read either the directory listing or the file contents.
if isdir:
@@ -153,7 +163,12 @@
# Return a sequence instead of a string.
return names
else:
- f = open(path, 'rb')
+ try:
+ f = open(path, 'rb')
+ except IOError:
+ if allow_missing:
+ return None
+ raise
try:
return f.read()
finally:
@@ -175,9 +190,11 @@
"""Read a properties file next to path."""
props_fn = self.getPropertiesPath(path)
- if not os.path.exists(props_fn):
+ try:
+ f = open(props_fn, 'rb')
+ except IOError:
+ # The file is presumably nonexistent
return {}
- f = open(props_fn, 'rb')
try:
data = f.read()
finally:
@@ -287,6 +304,7 @@
'Data for a directory must be a list or tuple at %s'
% subpath)
+
def queue(self, subpath, section_name, data, mode=WRITE_UNCONDITIONAL):
"""Queues data to be written at commit time"""
if mode == WRITE_UNCONDITIONAL:
@@ -310,6 +328,7 @@
(subpath, section_name))
else:
sections[section_name] = data
+
#
# ITPCConnection implementation
=== Products/AdaptableStorage/gateway_fs/public.py 1.3 => 1.4 ===
--- Products/AdaptableStorage/gateway_fs/public.py:1.3 Fri Jan 3 17:04:17 2003
+++ Products/AdaptableStorage/gateway_fs/public.py Mon Jan 6 18:17:41 2003
@@ -25,4 +25,4 @@
from FSFileData import FSFileData
from FSProperties import FSProperties
from FSSectionData import FSSectionData
-
+from FSUserList import FSUserList