summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 0f59079)
raw | patch | inline | side by side (parent: 0f59079)
author | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Mon, 17 Dec 2001 03:52:48 +0000 (03:52 +0000) | ||
committer | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Mon, 17 Dec 2001 03:52:48 +0000 (03:52 +0000) |
storing more than one file per node - if a property name is supplied,
the file is called designator.property.
I decided not to migrate the existing files stored over to the new naming
scheme - the FileClass just doesn't specify the property name.
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@473 57a73879-2fb5-44c3-a270-3262357dd7e2
the file is called designator.property.
I decided not to migrate the existing files stored over to the new naming
scheme - the FileClass just doesn't specify the property name.
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@473 57a73879-2fb5-44c3-a270-3262357dd7e2
diff --git a/CHANGES.txt b/CHANGES.txt
index 7d44745c06f6471c2f8c3c8d5797a7c37be48683..e2478978327590755da6e959588e553ad675ea62 100644 (file)
--- a/CHANGES.txt
+++ b/CHANGES.txt
This file contains the changes to the Roundup system over time. The entries
are given with the most recent entry first.
This file contains the changes to the Roundup system over time. The entries
are given with the most recent entry first.
-2001-11-?? - 0.3.1
+2001-12-?? - 0.3.1b1
Feature:
. Added INSTANCE_NAME to configuration - used in web and email to identify
the instance.
Feature:
. Added INSTANCE_NAME to configuration - used in web and email to identify
the instance.
diff --git a/doc/announcement.txt b/doc/announcement.txt
index f1ca352e1275dd8ebb720d422362eb007707e593..cdba40605b5220c517128612d8ccb839d52170f8 100644 (file)
--- a/doc/announcement.txt
+++ b/doc/announcement.txt
- Roundup 0.3.0 - an issue tracking system
+ Roundup 0.3.1b1 - an issue tracking system
-This release contains several new features which will require migration, so
-please read MIGRATION.txt!
+If you are upgrading from pre-0.3.0, please read MIGRATION.txt.
+
+Roundup requires python 2.1.1 for correct operation. Support for dumbdbm has
+been disabled until python 2.1.2 and 2.2 are released.
Big stuff in this release:
Big stuff in this release:
- - lots of bug fixes, thanks to all users for their great feedback!
- - much more flexible administration tool
- - much better handling of errors
- - more configuration options
- - CGI login uses cookies instead of basic auth
- - passwords are encoded in the database
- - much, much more: see the CHANGES file for details.
+ - Use of transactions to prevent partial data commits
+ - Zope Product front-end
+ - Nicer, more consistent change message generation
+ - Several bug fixes
+ - Much, much more: see the CHANGES file for details.
Source and documentation is available at the website:
http://roundup.sourceforge.net/
Source and documentation is available at the website:
http://roundup.sourceforge.net/
diff --git a/doc/index.html b/doc/index.html
index 59d2f35b4e46eea683fb7c7415607944933f14ea..b53b2b6659ce9485e3c59c85cce5fd5d4d0150a6 100644 (file)
--- a/doc/index.html
+++ b/doc/index.html
<title>Roundup: an Issue-Tracking System for Knowledge Workers</title>
</head><body>
<title>Roundup: an Issue-Tracking System for Knowledge Workers</title>
</head><body>
-<h1 align=center>Roundup (0.3.0)</h1>
+<h1 align=center>Roundup (0.3.1)</h1>
<h3 align=center>An Issue-Tracking System for Knowledge Workers</h2>
<h1>Contents</h1>
<h3 align=center>An Issue-Tracking System for Knowledge Workers</h2>
<h1>Contents</h1>
<h2><a name="requires">Prerequisites</a></h2>
<h2><a name="requires">Prerequisites</a></h2>
-<dl>
- <dd>Python 2.1.1 is required for the correct operation of roundup
-</dl>
+<p>
+Python 2.1.1 is required for the correct operation of roundup.
+</p>
+<p>
Download the latest version from
<a href="http://www.python.org/">http://www.python.org/</a>.
Download the latest version from
<a href="http://www.python.org/">http://www.python.org/</a>.
+</p>
</table>
<p>
</table>
<p>
-<table border=1 cellspacing=0>
+<table width=100% border=1 cellspacing=0>
<tr><th colspan=2>Command Help</th></tr>
<tr><th colspan=2>Command Help</th></tr>
-<tr><td valign=top><strong>history</strong></td>
- <td><tt>history designator</tt><p>
- Lists the journal entries for the node identified by the designator.
-</td></tr>
-
+
+
+<tr><td valign=top><strong>commit</strong></td>
+ <td><tt>Usage: commit</tt><p>
+<pre>
+The changes made during an interactive session are not
+automatically written to the database - they must be committed
+using this command.
+
+One-off commands on the command-line are automatically committed if
+they are successful.
+
+</pre></td></tr>
+
+
+<tr><td valign=top><strong>create</strong></td>
+ <td><tt>Usage: create classname property=value ...</tt><p>
+<pre>
+This creates a new entry of the given class using the property
+name=value arguments provided on the command line after the "create"
+command.
+
+</pre></td></tr>
+
+
+<tr><td valign=top><strong>display</strong></td>
+ <td><tt>Usage: display designator</tt><p>
+<pre>
+This lists the properties and their associated values for the given
+node.
+
+</pre></td></tr>
+
+
+<tr><td valign=top><strong>export</strong></td>
+ <td><tt>Usage: export class[,class] destination_dir</tt><p>
+<pre>
+This action exports the current data from the database into
+tab-separated-value files that are placed in the nominated destination
+directory. The journals are not exported.
+
+</pre></td></tr>
+
+
<tr><td valign=top><strong>find</strong></td>
<tr><td valign=top><strong>find</strong></td>
- <td><tt>find classname propname=value ...</tt><p>
- Find the nodes of the given class with a given property value. The
- value may be either the nodeid of the linked node, or its key value.
-</td></tr>
-
+ <td><tt>Usage: find classname propname=value ...</tt><p>
+<pre>
+Find the nodes of the given class with a given link property value. The
+value may be either the nodeid of the linked node, or its key value.
+
+</pre></td></tr>
+
+
+<tr><td valign=top><strong>get</strong></td>
+ <td><tt>Usage: get property designator[,designator]*</tt><p>
+<pre>
+Retrieves the property value of the nodes specified by the designators.
+
+</pre></td></tr>
+
+
+<tr><td valign=top><strong>help</strong></td>
+ <td><tt>Usage: help topic</tt><p>
+<pre>
+commands -- list commands
+<command> -- help specific to a command
+initopts -- init command options
+all -- all available help
+
+</pre></td></tr>
+
+
+<tr><td valign=top><strong>history</strong></td>
+ <td><tt>Usage: history designator</tt><p>
+<pre>
+Lists the journal entries for the node identified by the designator.
+
+</pre></td></tr>
+
+
+<tr><td valign=top><strong>import</strong></td>
+ <td><tt>Usage: import class file</tt><p>
+<pre>
+The file must define the same properties as the class (including having
+a "header" line with those property names.) The new nodes are added to
+the existing database - if you want to create a new database using the
+imported data, then create a new database (or, tediously, retire all
+the old data.)
+
+</pre></td></tr>
+
+
+<tr><td valign=top><strong>initialise</strong></td>
+ <td><tt>Usage: initialise [template [backend [admin password]]]</tt><p>
+<pre>
+The command will prompt for the instance home directory (if not supplied
+through INSTANCE_HOME or the -i option. The template, backend and admin
+password may be specified on the command-line as arguments, in that
+order.
+
+See also initopts help.
+
+</pre></td></tr>
+
+
<tr><td valign=top><strong>list</strong></td>
<tr><td valign=top><strong>list</strong></td>
- <td><tt>list classname [property]</tt><p>
- Lists all instances of the given class along. If the property is not
- specified, the "label" property is used. The label property is tried
- in order: the key, "name", "title" and then the first property,
- alphabetically.
-</td></tr>
-
+ <td><tt>Usage: list classname [property]</tt><p>
+<pre>
+Lists all instances of the given class. If the property is not
+specified, the "label" property is used. The label property is tried
+in order: the key, "name", "title" and then the first property,
+alphabetically.
+
+</pre></td></tr>
+
+
<tr><td valign=top><strong>retire</strong></td>
<tr><td valign=top><strong>retire</strong></td>
- <td><tt>retire designator[,designator]*</tt><p>
- This action indicates that a particular node is not to be retrieved by
- the list or find commands, and its key value may be re-used.
-</td></tr>
-
-<tr><td valign=top><strong>create</strong></td>
- <td><tt>create classname property=value ...</tt><p>
- This creates a new entry of the given class using the property
- name=value arguments provided on the command line after the "create"
- command.
-</td></tr>
-
-<tr><td valign=top><strong>get</strong></td>
- <td><tt>get property designator[,designator]*</tt><p>
- Retrieves the property value of the nodes specified by the designators.
-</td></tr>
-
-<tr><td valign=top><strong>spec</strong></td>
- <td><tt>spec classname</tt><p>
- This lists the properties for a given class.
-</td></tr>
-
+ <td><tt>Usage: retire designator[,designator]*</tt><p>
+<pre>
+This action indicates that a particular node is not to be retrieved by
+the list or find commands, and its key value may be re-used.
+
+</pre></td></tr>
+
+
+<tr><td valign=top><strong>rollback</strong></td>
+ <td><tt>Usage: rollback</tt><p>
+<pre>
+The changes made during an interactive session are not
+automatically written to the database - they must be committed
+manually. This command undoes all those changes, so a commit
+immediately after would make no changes to the database.
+
+</pre></td></tr>
+
+
<tr><td valign=top><strong>set</strong></td>
<tr><td valign=top><strong>set</strong></td>
- <td><tt>set designator[,designator]* propname=value ...</tt><p>
- Sets the property to the value for all designators given.
-</td></tr>
+ <td><tt>Usage: set designator[,designator]* propname=value ...</tt><p>
+<pre>
+Sets the property to the value for all designators given.
-<tr><td valign=top><strong>init</strong></td>
- <td><tt>init [template [backend [admin password]]]</tt><p>
- The command will prompt for the instance home directory (if not supplied
- through INSTANCE_HOME or the -i option. The template, backend and admin
- password may be specified on the command-line as arguments, in that order.
-</td></tr>
+</pre></td></tr>
-<tr><td valign=top><strong>export</strong></td>
- <td><tt>export class[,class] destination_dir</tt><p>
- This action exports the current data from the database into
- comma-separated files that are placed in the nominated destination
- directory. The journals are not exported.
-</td></tr>
-<tr><td valign=top><strong>import</strong></td>
- <td><tt>import class file</tt><p>
- The file must define the same properties as the class (including having
- a "header" line with those property names.)
-</td></tr>
-
-<tr><td valign=top><strong>freshen</strong></td>
- <td><tt>freshen</tt><p>
- <strong>**DO NOT USE**</strong>
- <p>
- This currently kills databases!!!!
- <p>
- This action should generally not be used. It reads in an instance
- database and writes it again. In the future, is may also update
- instance code to account for changes in templates. It's probably wise
- not to use it anyway. Until we're sure it won't break things...
-</td></tr>
+<tr><td valign=top><strong>specification</strong></td>
+ <td><tt>Usage: specification classname</tt><p>
+<pre>
+This lists the properties for a given class.
-<tr><td><strong>help</strong></td>
- <td><tt>help [command]</tt><p>
- Short help about roundup-admin or the specific command.
- </td></tr>
+</pre></td></tr>
+
+
+<tr><td valign=top><strong>table</strong></td>
+ <td><tt>Usage: table classname [property[,property]*]</tt><p>
+<pre>
+Lists all instances of the given class. If the properties are not
+specified, all properties are displayed. By default, the column widths
+are the width of the property names. The width may be explicitly defined
+by defining the property as "name:width". For example::
+ roundup> table priority id,name:10
+ Id Name
+ 1 fatal-bug
+ 2 bug
+ 3 usability
+ 4 feature
+
+</pre></td></tr>
-<tr><td><strong>morehelp</strong></td>
- <td><tt>morehelp</tt><p>
- All available help from the roundup-admin tool.
- </td></tr>
</table>
<p>
</table>
<p>
<p> </p>
<hr>
<p> </p>
<hr>
-$Id: index.html,v 1.21 2001-12-13 00:20:01 richard Exp $
+$Id: index.html,v 1.22 2001-12-17 03:52:47 richard Exp $
<p> </p>
</body></html>
<p> </p>
</body></html>
diff --git a/roundup-admin b/roundup-admin
index 2a4162e98565976e44e6abcc33b148dd980c62fc..6a1d5c078efa1716ccc4a5e9e17d209857a4a983 100755 (executable)
--- a/roundup-admin
+++ b/roundup-admin
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: roundup-admin,v 1.54 2001-12-15 23:09:23 richard Exp $
+# $Id: roundup-admin,v 1.55 2001-12-17 03:52:47 richard Exp $
# python version check
from roundup import version_check
# python version check
from roundup import version_check
print '\n'.join(commands)
print
print '\n'.join(commands)
print
+ def help_commands_html(self, indent_re=re.compile(r'^(\s+)\S+')):
+ commands = self.commands.values()
+ def sortfun(a, b):
+ return cmp(a.__name__, b.__name__)
+ commands.sort(sortfun)
+ for command in commands:
+ h = command.__doc__.split('\n')
+ name = command.__name__[3:]
+ usage = h[0]
+ print '''
+<tr><td valign=top><strong>%(name)s</strong></td>
+ <td><tt>%(usage)s</tt><p>
+<pre>'''%locals()
+ indent = indent_re.match(h[3])
+ if indent: indent = len(indent.group(1))
+ for line in h[3:]:
+ if indent:
+ print line[indent:]
+ else:
+ print line
+ print '</pre></td></tr>\n'
+
def help_all(self):
print '''
All commands (except help) require an instance specifier. This is just the path
def help_all(self):
print '''
All commands (except help) require an instance specifier. This is just the path
#
# $Log: not supported by cvs2svn $
#
# $Log: not supported by cvs2svn $
+# Revision 1.54 2001/12/15 23:09:23 richard
+# Some cleanups in roundup-admin, also made it work again...
+#
# Revision 1.53 2001/12/13 00:20:00 richard
# . Centralised the python version check code, bumped version to 2.1.1 (really
# needs to be 2.1.2, but that isn't released yet :)
# Revision 1.53 2001/12/13 00:20:00 richard
# . Centralised the python version check code, bumped version to 2.1.1 (really
# needs to be 2.1.2, but that isn't released yet :)
index b11a461513e5fe6a29b1a9dd89a674f4e0164038..0d52750cf605106f40fe1de70129962023924575 100644 (file)
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-#$Id: back_anydbm.py,v 1.18 2001-12-16 10:53:38 richard Exp $
+#$Id: back_anydbm.py,v 1.19 2001-12-17 03:52:48 richard Exp $
'''
This module defines a backend that saves the hyperdatabase in a database
chosen by anydbm. It is guaranteed to always be available in python
'''
This module defines a backend that saves the hyperdatabase in a database
chosen by anydbm. It is guaranteed to always be available in python
res = res + db.keys()
return res
res = res + db.keys()
return res
+
+ #
+ # Files - special node properties
+ #
+ def filename(self, classname, nodeid, property=None):
+ '''Determine what the filename for the given node and optionally property is.
+ '''
+ # TODO: split into multiple files directories
+ if property:
+ return os.path.join(self.dir, 'files', '%s%s.%s'%(classname,
+ nodeid, property))
+ else:
+ # roundupdb.FileClass never specified the property name, so don't include it
+ return os.path.join(self.dir, 'files', '%s%s'%(classname,
+ nodeid))
+
+ def storefile(self, classname, nodeid, property, content):
+ '''Store the content of the file in the database. The property may be None, in
+ which case the filename does not indicate which property is being saved.
+ '''
+ name = self.filename(classname, nodeid, property)
+ open(name + '.tmp', 'wb').write(content)
+ self.transactions.append((self._doStoreFile, (name, )))
+
+ def getfile(self, classname, nodeid, property):
+ '''Store the content of the file in the database.
+ '''
+ return open(self.filename(classname, nodeid, property), 'rb').read()
+
+
#
# Journal
#
#
# Journal
#
'''
if DEBUG:
print 'commit', (self,)
'''
if DEBUG:
print 'commit', (self,)
- # lock the DB
+ # TODO: lock the DB
+
+ # keep a handle to all the database files opened
+ self.databases = {}
+
+ # now, do all the transactions
for method, args in self.transactions:
for method, args in self.transactions:
- # TODO: optimise this, duh!
method(*args)
method(*args)
- # unlock the DB
+
+ # now close all the database files
+ for db in self.databases.values():
+ db.close()
+ del self.databases
+ # TODO: unlock the DB
# all transactions committed, back to normal
self.cache = {}
# all transactions committed, back to normal
self.cache = {}
def _doSaveNode(self, classname, nodeid, node):
if DEBUG:
print '_doSaveNode', (self, classname, nodeid, node)
def _doSaveNode(self, classname, nodeid, node):
if DEBUG:
print '_doSaveNode', (self, classname, nodeid, node)
- db = self.getclassdb(classname, 'c')
+
+ # get the database handle
+ db_name = 'nodes.%s'%classname
+ if self.databases.has_key(db_name):
+ db = self.databases[db_name]
+ else:
+ db = self.databases[db_name] = self.getclassdb(classname, 'c')
+
# now save the marshalled data
db[nodeid] = marshal.dumps(node)
# now save the marshalled data
db[nodeid] = marshal.dumps(node)
- db.close()
def _doSaveJournal(self, classname, nodeid, action, params):
if DEBUG:
print '_doSaveJournal', (self, classname, nodeid, action, params)
entry = (nodeid, date.Date().get_tuple(), self.journaltag, action,
params)
def _doSaveJournal(self, classname, nodeid, action, params):
if DEBUG:
print '_doSaveJournal', (self, classname, nodeid, action, params)
entry = (nodeid, date.Date().get_tuple(), self.journaltag, action,
params)
- db = self._opendb('journals.%s'%classname, 'c')
+
+ # get the database handle
+ db_name = 'journals.%s'%classname
+ if self.databases.has_key(db_name):
+ db = self.databases[db_name]
+ else:
+ db = self.databases[db_name] = self._opendb(db_name, 'c')
+
+ # now insert the journal entry
if db.has_key(nodeid):
s = db[nodeid]
l = marshal.loads(db[nodeid])
if db.has_key(nodeid):
s = db[nodeid]
l = marshal.loads(db[nodeid])
else:
l = [entry]
db[nodeid] = marshal.dumps(l)
else:
l = [entry]
db[nodeid] = marshal.dumps(l)
- db.close()
+
+ def _doStoreFile(self, name, **databases):
+ # the file is currently ".tmp" - move it to its real name to commit
+ os.rename(name+".tmp", name)
def rollback(self):
''' Reverse all actions from the current transaction.
'''
if DEBUG:
print 'rollback', (self, )
def rollback(self):
''' Reverse all actions from the current transaction.
'''
if DEBUG:
print 'rollback', (self, )
+ for method, args in self.transactions:
+ # delete temporary files
+ if method == self._doStoreFile:
+ os.remove(args[0]+".tmp")
self.cache = {}
self.dirtynodes = {}
self.newnodes = {}
self.cache = {}
self.dirtynodes = {}
self.newnodes = {}
#
#$Log: not supported by cvs2svn $
#
#$Log: not supported by cvs2svn $
+#Revision 1.18 2001/12/16 10:53:38 richard
+#take a copy of the node dict so that the subsequent set
+#operation doesn't modify the oldvalues structure
+#
#Revision 1.17 2001/12/14 23:42:57 richard
#yuck, a gdbm instance tests false :(
#I've left the debugging code in - it should be removed one day if we're ever
#Revision 1.17 2001/12/14 23:42:57 richard
#yuck, a gdbm instance tests false :(
#I've left the debugging code in - it should be removed one day if we're ever
diff --git a/roundup/roundupdb.py b/roundup/roundupdb.py
index f57139ed49d33716f6779915d051773325dc5a58..50cd90c4dcca11d9a69076be33364dba63e56d3a 100644 (file)
--- a/roundup/roundupdb.py
+++ b/roundup/roundupdb.py
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: roundupdb.py,v 1.33 2001-12-16 10:53:37 richard Exp $
+# $Id: roundupdb.py,v 1.34 2001-12-17 03:52:48 richard Exp $
__doc__ = """
Extending hyperdb with types specific to issue-tracking.
__doc__ = """
Extending hyperdb with types specific to issue-tracking.
content = propvalues['content']
del propvalues['content']
newid = Class.create(self, **propvalues)
content = propvalues['content']
del propvalues['content']
newid = Class.create(self, **propvalues)
- self.setcontent(self.classname, newid, content)
+ self.db.storefile(self.classname, newid, None, content)
return newid
return newid
- def filename(self, classname, nodeid):
- # TODO: split into multiple files directories
- return os.path.join(self.db.dir, 'files', '%s%s'%(classname, nodeid))
-
- def setcontent(self, classname, nodeid, content):
- ''' set the content file for this file
- '''
- open(self.filename(classname, nodeid), 'wb').write(content)
-
- def getcontent(self, classname, nodeid):
- ''' get the content file for this file
- '''
- return open(self.filename(classname, nodeid), 'rb').read()
-
def get(self, nodeid, propname, default=_marker):
''' trap the content propname and get it from the file
'''
if propname == 'content':
def get(self, nodeid, propname, default=_marker):
''' trap the content propname and get it from the file
'''
if propname == 'content':
- return self.getcontent(self.classname, nodeid)
+ return self.db.getfile(self.classname, nodeid, None)
if default is not _marker:
return Class.get(self, nodeid, propname, default)
else:
if default is not _marker:
return Class.get(self, nodeid, propname, default)
else:
#
# $Log: not supported by cvs2svn $
#
# $Log: not supported by cvs2svn $
+# Revision 1.33 2001/12/16 10:53:37 richard
+# take a copy of the node dict so that the subsequent set
+# operation doesn't modify the oldvalues structure
+#
# Revision 1.32 2001/12/15 23:48:35 richard
# Added ROUNDUPDBSENDMAILDEBUG so one can test the sendmail method without
# actually sending mail :)
# Revision 1.32 2001/12/15 23:48:35 richard
# Added ROUNDUPDBSENDMAILDEBUG so one can test the sendmail method without
# actually sending mail :)
diff --git a/test/test_db.py b/test/test_db.py
index 08b918adebc927eff22b37d4f5f6b738fbf7dd50..c0919f569337b9f11da1467c0857dc3929ae4cb0 100644 (file)
--- a/test/test_db.py
+++ b/test/test_db.py
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: test_db.py,v 1.11 2001-12-10 23:17:20 richard Exp $
+# $Id: test_db.py,v 1.12 2001-12-17 03:52:48 richard Exp $
import unittest, os, shutil
from roundup.hyperdb import String, Password, Link, Multilink, Date, \
Interval, Class, DatabaseError
import unittest, os, shutil
from roundup.hyperdb import String, Password, Link, Multilink, Date, \
Interval, Class, DatabaseError
+from roundup.roundupdb import FileClass
def setupSchema(db, create):
status = Class(db, "status", name=String())
def setupSchema(db, create):
status = Class(db, "status", name=String())
Class(db, "user", username=String(), password=Password())
Class(db, "issue", title=String(), status=Link("status"),
nosy=Multilink("user"))
Class(db, "user", username=String(), password=Password())
Class(db, "issue", title=String(), status=Link("status"),
nosy=Multilink("user"))
+ FileClass(db, "file", name=String(), type=String())
db.commit()
class MyTestCase(unittest.TestCase):
db.commit()
class MyTestCase(unittest.TestCase):
# remove previous test, ignore errors
if os.path.exists('_test_dir'):
shutil.rmtree('_test_dir')
# remove previous test, ignore errors
if os.path.exists('_test_dir'):
shutil.rmtree('_test_dir')
- os.mkdir('_test_dir')
+ os.makedirs('_test_dir/files')
self.db = anydbm.Database('_test_dir', 'test')
setupSchema(self.db, 1)
self.db = anydbm.Database('_test_dir', 'test')
setupSchema(self.db, 1)
def testTransactions(self):
num_issues = len(self.db.issue.list())
def testTransactions(self):
num_issues = len(self.db.issue.list())
+ files_dir = os.path.join('_test_dir', 'files')
+ if os.path.exists(files_dir):
+ num_files = len(os.listdir(files_dir))
+ else:
+ num_files = 0
self.db.issue.create(title="don't commit me!", status='1')
self.assertNotEqual(num_issues, len(self.db.issue.list()))
self.db.rollback()
self.db.issue.create(title="don't commit me!", status='1')
self.assertNotEqual(num_issues, len(self.db.issue.list()))
self.db.rollback()
self.assertNotEqual(num_issues, len(self.db.issue.list()))
self.db.rollback()
self.assertNotEqual(num_issues, len(self.db.issue.list()))
self.assertNotEqual(num_issues, len(self.db.issue.list()))
self.db.rollback()
self.assertNotEqual(num_issues, len(self.db.issue.list()))
+ self.db.file.create(name="test", type="text/plain", content="hi")
+ self.db.rollback()
+ self.assertEqual(num_files, len(os.listdir(files_dir)))
+ self.db.file.create(name="test", type="text/plain", content="hi")
+ self.db.commit()
+ self.assertNotEqual(num_files, len(os.listdir(files_dir)))
+ num_files2 = len(os.listdir(files_dir))
+ self.db.file.create(name="test", type="text/plain", content="hi")
+ self.db.rollback()
+ self.assertNotEqual(num_files, len(os.listdir(files_dir)))
+ self.assertEqual(num_files2, len(os.listdir(files_dir)))
+
def testExceptions(self):
# this tests the exceptions that should be raised
def testExceptions(self):
# this tests the exceptions that should be raised
# remove previous test, ignore errors
if os.path.exists('_test_dir'):
shutil.rmtree('_test_dir')
# remove previous test, ignore errors
if os.path.exists('_test_dir'):
shutil.rmtree('_test_dir')
- os.mkdir('_test_dir')
+ os.makedirs('_test_dir/files')
db = anydbm.Database('_test_dir', 'test')
setupSchema(db, 1)
self.db = anydbm.Database('_test_dir')
db = anydbm.Database('_test_dir', 'test')
setupSchema(db, 1)
self.db = anydbm.Database('_test_dir')
# remove previous test, ignore errors
if os.path.exists('_test_dir'):
shutil.rmtree('_test_dir')
# remove previous test, ignore errors
if os.path.exists('_test_dir'):
shutil.rmtree('_test_dir')
- os.mkdir('_test_dir')
+ os.makedirs('_test_dir/files')
self.db = bsddb.Database('_test_dir', 'test')
setupSchema(self.db, 1)
self.db = bsddb.Database('_test_dir', 'test')
setupSchema(self.db, 1)
# remove previous test, ignore errors
if os.path.exists('_test_dir'):
shutil.rmtree('_test_dir')
# remove previous test, ignore errors
if os.path.exists('_test_dir'):
shutil.rmtree('_test_dir')
- os.mkdir('_test_dir')
+ os.makedirs('_test_dir/files')
db = bsddb.Database('_test_dir', 'test')
setupSchema(db, 1)
self.db = bsddb.Database('_test_dir')
db = bsddb.Database('_test_dir', 'test')
setupSchema(db, 1)
self.db = bsddb.Database('_test_dir')
# remove previous test, ignore errors
if os.path.exists('_test_dir'):
shutil.rmtree('_test_dir')
# remove previous test, ignore errors
if os.path.exists('_test_dir'):
shutil.rmtree('_test_dir')
- os.mkdir('_test_dir')
+ os.makedirs('_test_dir/files')
self.db = bsddb3.Database('_test_dir', 'test')
setupSchema(self.db, 1)
self.db = bsddb3.Database('_test_dir', 'test')
setupSchema(self.db, 1)
# remove previous test, ignore errors
if os.path.exists('_test_dir'):
shutil.rmtree('_test_dir')
# remove previous test, ignore errors
if os.path.exists('_test_dir'):
shutil.rmtree('_test_dir')
- os.mkdir('_test_dir')
+ os.makedirs('_test_dir/files')
db = bsddb3.Database('_test_dir', 'test')
setupSchema(db, 1)
self.db = bsddb3.Database('_test_dir')
db = bsddb3.Database('_test_dir', 'test')
setupSchema(db, 1)
self.db = bsddb3.Database('_test_dir')
#
# $Log: not supported by cvs2svn $
#
# $Log: not supported by cvs2svn $
+# Revision 1.11 2001/12/10 23:17:20 richard
+# Added transaction tests to test_db
+#
# Revision 1.10 2001/12/03 21:33:39 richard
# Fixes so the tests use commit and not close
#
# Revision 1.10 2001/12/03 21:33:39 richard
# Fixes so the tests use commit and not close
#