|
/
Zope
/
gocept svn checkins
/
Archive
/
2007
/
2007-02
/
SVN: r4442 - gocept.js.dojo/trunk/src/gocept/js/dojo/resources
[
SVN: r4438 - in buildout-recipes/gocept.cmmi: . ... ]
[
Re: [gocept svn checkins] SVN: r4444 - ... ]
SVN: r4442 - gocept.js.dojo/trunk/src/gocept/js/dojo/resources
Roman Joost <rj(at)gocept.com> |
2007-02-14 11:52:36 |
[ FULL ]
|
Author: roman
Date: Wed Feb 14 11:52:35 2007
New Revision: 4442
Modified:
gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js
Log:
handle the substring search better
Modified: gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js
==============================================================================
---
gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js (original)
+++ gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js Wed Feb
14 11:52:35 2007
(at)(at) -15,15 +15,10 (at)(at)
title = title.toLowerCase();
if (!value)
return true;
-
- switch(title.search(value)) {
- case -1: // not found
- return false;
- case 0: // found
- return true;
- default:
- break
- }
-
- return true
+
+ var r = title.indexOf(value)
+ if (r >= 0)
+ return true;
+
+ return false
}
|
SVN: r4443 - gocept.js.dojo/trunk/src/gocept/js/dojo
Christian Zagrodnick <cz(at)gocept.com> |
2007-02-14 14:10:18 |
[ FULL ]
|
Author: zagy
Date: Wed Feb 14 14:10:17 2007
New Revision: 4443
Modified:
gocept.js.dojo/trunk/src/gocept/js/dojo/table.py
Log:
whitespace
Modified: gocept.js.dojo/trunk/src/gocept/js/dojo/table.py
==============================================================================
--- gocept.js.dojo/trunk/src/gocept/js/dojo/table.py (original)
+++ gocept.js.dojo/trunk/src/gocept/js/dojo/table.py Wed Feb 14 14:10:17 2007
(at)(at) -1,6 +1,7 (at)(at)
# Copyright (c) 2007 gocept gmbh & co. kg
# See also LICENSE.txt
# $Id$
+
import zc.table.table
import zc.table.column
import zc.resourcelibrary
(at)(at) -11,7 +12,7 (at)(at)
def __call__(self, attrs):
"""renders the table"""
zc.resourcelibrary.need('tableHandlers')
-
+
return "\n<table%s>\n%s</table>\n%s" % (
self._getTableAttributes(attrs), self.renderContents(),
self.renderExtra())
(at)(at) -20,7 +21,6 (at)(at)
"""returns given attributes as string incl. CSS class"""
return "%s %s" %(self._getCSSClass('table'), attrs)
-
def renderHeader(self, column):
return ' <th%s %s>\n %s\n </th>\n' % (
self._getCSSClass('th'), column.attrs, self.getHeader(column))
(at)(at) -29,27 +29,27 (at)(at)
"""renders cell without any whitespace"""
return ' <td%s>%s</td>\n' % (
self._getCSSClass('td'), self.getCell(item, column),)
-
+
def renderRows(self):
return ''.join([self.renderRow(item, id) for id, item in enumerate(
self.getItems())])
-
+
def renderRow(self, item, id):
return ' <tr%s value="%s">\n%s </tr>\n' % (
self._getCSSClass('tr'), id, self.renderCells(item))
+
class DojoTableColumn(zc.table.column.Column):
-
+
def __init__(self, title=None, getter=None, attrs=""):
if getter is not None:
self.getter = getter
-
+
if title is not None:
self.title = title
self.name = title
self.attrs = attrs
-
+
def renderCell(self, item, formatter):
value = self.getter(item, formatter)
return unicode(value)
-
|
SVN: r4445 - gocept.js.dojo/trunk/src/gocept/js/dojo/resources
Roman Joost <rj(at)gocept.com> |
2007-02-15 10:39:54 |
[ FULL ]
|
Author: roman
Date: Thu Feb 15 10:39:53 2007
New Revision: 4445
Modified:
gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js
Log:
added code to select rows and receive metadata preview html snippet
Modified: gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js
==============================================================================
---
gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js (original)
+++ gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js Thu Feb
15 10:39:53 2007
(at)(at) -1,5 +1,6 (at)(at)
// imports
dojo.require("dojo.widget.FilteringTable");
+dojo.require("dojo.io.*");
function updateFilter(tableId, input) {
var table = dojo.widget.byId(tableId);
(at)(at) -7,6 +8,7 (at)(at)
return False;
table.setFilter("Titel", titleFilter);
+ // put a filter on every column
}
function titleFilter(title) {
(at)(at) -22,3 +24,36 (at)(at)
return false
}
+
+function onDataSelect(e) {
+ if (e.rangeParent.nodeType == 3)
+ var doc_title = e.rangeParent.nodeValue;
+ else
+ return false;
+
+ dojo.io.bind({
+ url: doc_title + "/metadata_preview",
+ load: onMetadataReceived,
+ mimetype: "text/xml",
+ content: {}
+ })
+}
+
+function onMetadataReceived(type, data, evt) {
+ // don't do anything if the server returns no valid XML doc
+ if (data.nodeType != 9)
+ return false
+
+ var container = document.getElementById('previewcontainer');
+ if (container.childNodes.length > 0)
+ container.removeChild(container.firstChild)
+
+ container.appendChild( data.firstChild )
+}
+
+function tableInit() {
+ var table = dojo.widget.byId('contentListing');
+ dojo.event.connect(table, 'onSelect', 'onDataSelect');
+}
+
+dojo.addOnLoad(tableInit)
|
SVN: r4446 - gocept.js.dojo/trunk/src/gocept/js/dojo/resources
Roman Joost <rj(at)gocept.com> |
2007-02-15 11:44:36 |
[ FULL ]
|
Author: roman
Date: Thu Feb 15 11:44:35 2007
New Revision: 4446
Modified:
gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js
Log:
added code to make the previewcontainer visible
Modified: gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js
==============================================================================
---
gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js (original)
+++ gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js Thu Feb
15 11:44:35 2007
(at)(at) -45,6 +45,9 (at)(at)
return false
var container = document.getElementById('previewcontainer');
+ var preview = document.getElementById('preview')
+ preview.setAttribute('class', 'visible')
+
if (container.childNodes.length > 0)
container.removeChild(container.firstChild)
|
SVN: r4454 - in gocept.js.dojo/trunk/src/gocept/js/dojo: . resources
Roman Joost <rj(at)gocept.com> |
2007-02-20 10:06:35 |
[ FULL ]
|
Author: roman
Date: Tue Feb 20 10:06:33 2007
New Revision: 4454
Modified:
gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js
gocept.js.dojo/trunk/src/gocept/js/dojo/table.py
gocept.js.dojo/trunk/src/gocept/js/dojo/table.txt
gocept.js.dojo/trunk/src/gocept/js/dojo/test.py
Log:
- DojoTableFormatter now sets the table row value by using a callable
Modified: gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js
==============================================================================
---
gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js (original)
+++ gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js Tue Feb
20 10:06:33 2007
(at)(at) -25,14 +25,20 (at)(at)
return false
}
+// handler fired, when the user selected a table cell
function onDataSelect(e) {
- if (e.rangeParent.nodeType == 3)
- var doc_title = e.rangeParent.nodeValue;
- else
+ if (e.rangeParent.nodeType == 3) {
+ var url = e.target.parentNode.getAttribute('value');
+ } else {
return false;
+ }
+ loadMetadataHTML(url)
+}
+
+function loadMetadataHTML(url) {
dojo.io.bind({
- url: doc_title + "/metadata_preview",
+ url: url,
load: onMetadataReceived,
mimetype: "text/xml",
content: {}
Modified: gocept.js.dojo/trunk/src/gocept/js/dojo/table.py
==============================================================================
--- gocept.js.dojo/trunk/src/gocept/js/dojo/table.py (original)
+++ gocept.js.dojo/trunk/src/gocept/js/dojo/table.py Tue Feb 20 10:06:33 2007
(at)(at) -2,6 +2,9 (at)(at)
# See also LICENSE.txt
# $Id$
+import zope.traversing.browser
+import zope.component.interfaces
+
import zc.table.table
import zc.table.column
import zc.resourcelibrary
(at)(at) -9,6 +12,16 (at)(at)
class DojoTableFormatter(zc.table.table.Formatter):
+ def __init__(self, context, request, items, row_value=None, **kwargs):
+ if row_value is None:
+ row_value = lambda id, item, request: id
+
+ if not callable(row_value):
+ raise TypeError("row_value must be callable.")
+
+ self.row_value = row_value
+ super(DojoTableFormatter, self).__init__(context, request, items,
**kwargs)
+
def __call__(self, attrs):
"""renders the table"""
zc.resourcelibrary.need('tableHandlers')
(at)(at) -35,8 +48,9 (at)(at)
self.getItems())])
def renderRow(self, item, id):
+ value = self.row_value(id, item, self.request)
return ' <tr%s value="%s">\n%s </tr>\n' % (
- self._getCSSClass('tr'), id, self.renderCells(item))
+ self._getCSSClass('tr'), value, self.renderCells(item))
class DojoTableColumn(zc.table.column.Column):
Modified: gocept.js.dojo/trunk/src/gocept/js/dojo/table.txt
==============================================================================
--- gocept.js.dojo/trunk/src/gocept/js/dojo/table.txt (original)
+++ gocept.js.dojo/trunk/src/gocept/js/dojo/table.txt Tue Feb 20 10:06:33 2007
(at)(at) -5,10 +5,18 (at)(at)
specific attributes. Please keep in mind, that you have to use at least
the DojoTableColumn. The zc.table default columns won't work (and it
wouldn't make sense to use them, because dojo needs additional
-attributes in the head). Provide the attributes as a string parameter::
+attributes in the head).
+
+We need to set the site since we're a functional test::
+
+ >>> import zope.app.component.hooks
+ >>> old_site = zope.app.component.hooks.getSite()
+ >>> zope.app.component.hooks.setSite(getRootFolder())
+
+Provide the attributes as a string parameter::
>>> import gocept.js.dojo.table
- >>>
+ >>>
>>>
>>> class Test(object):
...
(at)(at) -39,10 +47,11 (at)(at)
...<th field="Titel" dataType="String">...
...</th>...
+
DojoTableColumn
===============
-You can pass additional attributes as a string to render dojo
+You can pass itional attributes as a string to render dojo
attributes. I'll reuse the above example::
>>> print table
(at)(at) -66,3 +75,49 (at)(at)
<td>20.02.2007</td>
</tr>
<tr value="1">...
+
+Distinctive table row values
+============================
+
+Now we test, if our Formatter handles the row_value callable correctly.
+Define a row_value callable, provide it to the Formatter. The Formatter
+calls for the row_value method during the rendering of every row. The
+row_value is used by Dojo to create distinctive table rows::
+
+ >>> class Test(object):
+ ...
+ ... nameattrs = 'field="Titel" dataType="String"'
+ ... dateattrs = 'field="Erstellt" dataType="Date"'
+ ... columns = (
+ ... gocept.js.dojo.table.DojoTableColumn('Titel',
+ ... lambda t, c: t[0],
+ ... nameattrs),
+ ... gocept.js.dojo.table.DojoTableColumn('Erstellt',
+ ... lambda t, c: t[1],
+ ... dateattrs),
+ ... )
+ ...
+ ... content = [('A', '20.02.2007'), ('B', '20.03.2007')]
+ ...
+ ... def row_value(self, id, item, request):
+ ... return item[0]
+ ...
+ ... def contentTable(self, attrs):
+ ... return gocept.js.dojo.table.DojoTableFormatter(
+ ... self, self, self.content,
+ ... columns=self.columns, row_value=self.row_value)(attrs)
+ >>>
+ >>> attrs = 'dojoType="FilteringTable" enableMultiselect="true"'
+ >>> table = Test().contentTable(attrs)
+ >>> print table
+ <table...
+ ...<tr value="A">...
+ ...<tr value="B">...
+
+
+Cleanup
+=======
+
+After tests we clean up::
+
+ >>> zope.app.component.hooks.setSite(old_site)
Modified: gocept.js.dojo/trunk/src/gocept/js/dojo/test.py
==============================================================================
--- gocept.js.dojo/trunk/src/gocept/js/dojo/test.py (original)
+++ gocept.js.dojo/trunk/src/gocept/js/dojo/test.py Tue Feb 20 10:06:33 2007
(at)(at) -1,12 +1,17 (at)(at)
# Copyright (c) 2007 gocept gmbh & co. kg
# See also LICENSE.txt
# $Id: test.py 7986 2007-02-09 15:04:26Z zagy $
+import unittest
from zope.testing import doctest
+import zeit.cms.testing
+
def test_suite():
- return doctest.DocFileSuite(
+ suite = unittest.TestSuite()
+ suite.addTest(zeit.cms.testing.FunctionalDocFileSuite(
'table.txt',
optionflags=(doctest.REPORT_NDIFF + doctest.NORMALIZE_WHITESPACE +
- doctest.ELLIPSIS))
+ doctest.ELLIPSIS)))
+ return suite
|
SVN: r4455 - gocept.js.dojo/trunk/src/gocept/js/dojo/resources
Roman Joost <rj(at)gocept.com> |
2007-02-20 15:48:37 |
[ FULL ]
|
Author: roman
Date: Tue Feb 20 15:48:35 2007
New Revision: 4455
Modified:
gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js
Log:
assign the metadata_preview to the containers innerHTML
Modified: gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js
==============================================================================
---
gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js (original)
+++ gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js Tue Feb
20 15:48:35 2007
(at)(at) -40,24 +40,16 (at)(at)
dojo.io.bind({
url: url,
load: onMetadataReceived,
- mimetype: "text/xml",
+ mimetype: "text/plain",
content: {}
})
}
function onMetadataReceived(type, data, evt) {
- // don't do anything if the server returns no valid XML doc
- if (data.nodeType != 9)
- return false
-
- var container = document.getElementById('previewcontainer');
- var preview = document.getElementById('preview')
- preview.setAttribute('class', 'visible')
-
- if (container.childNodes.length > 0)
- container.removeChild(container.firstChild)
+ var container = document.getElementById('bottomcontent');
+ container.setAttribute('class', 'visible')
- container.appendChild( data.firstChild )
+ container.innerHTML = data
}
function tableInit() {
|
SVN: r4456 - gocept.js.dojo/trunk/src/gocept/js/dojo/resources
Christian Zagrodnick <cz(at)gocept.com> |
2007-02-20 16:14:09 |
[ FULL ]
|
Author: zagy
Date: Tue Feb 20 16:14:07 2007
New Revision: 4456
Modified:
gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js
Log:
only loading url if it actually is a url
Modified: gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js
==============================================================================
---
gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js (original)
+++ gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js Tue Feb
20 16:14:07 2007
(at)(at) -27,11 +27,14 (at)(at)
// handler fired, when the user selected a table cell
function onDataSelect(e) {
- if (e.rangeParent.nodeType == 3) {
- var url = e.target.parentNode.getAttribute('value');
- } else {
+ if (e.rangeParent.nodeType != 3) {
return false;
}
+
+ var url = e.target.parentNode.getAttribute('value');
+ if (url.indexOf('http') == -1) {
+ return false;
+ }
loadMetadataHTML(url)
}
|
SVN: r4457 - gocept.js.dojo/trunk/src/gocept/js/dojo
Christian Zagrodnick <cz(at)gocept.com> |
2007-02-20 16:15:05 |
[ FULL ]
|
Author: zagy
Date: Tue Feb 20 16:15:03 2007
New Revision: 4457
Added:
gocept.js.dojo/trunk/src/gocept/js/dojo/interfaces.py (contents, props
changed)
Modified:
gocept.js.dojo/trunk/src/gocept/js/dojo/table.py
gocept.js.dojo/trunk/src/gocept/js/dojo/table.txt
gocept.js.dojo/trunk/src/gocept/js/dojo/test.py
Log:
refactored dojotable to work together with normal columns.
changed formatter so the __call__ does not get any arguments. This is at it
should be now.
using zope functional test layer
Added: gocept.js.dojo/trunk/src/gocept/js/dojo/interfaces.py
==============================================================================
--- (empty file)
+++ gocept.js.dojo/trunk/src/gocept/js/dojo/interfaces.py Tue Feb 20 16:15:03
2007
(at)(at) -0,0 +1,15 (at)(at)
+# Copyright (c) 2007 gocept gmbh & co. kg
+# See also LICENSE.txt
+# $Id$
+
+import zope.schema
+
+import zc.table.interfaces
+
+
+class IDojoColumn(zc.table.interfaces.IColumn):
+
+ extra_attributes = zope.schema.TextLine(
+ title=u'Extra Attributes added to <td>',
+ required=False,
+ default=u'')
Modified: gocept.js.dojo/trunk/src/gocept/js/dojo/table.py
==============================================================================
--- gocept.js.dojo/trunk/src/gocept/js/dojo/table.py (original)
+++ gocept.js.dojo/trunk/src/gocept/js/dojo/table.py Tue Feb 20 16:15:03 2007
(at)(at) -2,6 +2,7 (at)(at)
# See also LICENSE.txt
# $Id$
+import zope.interface
import zope.traversing.browser
import zope.component.interfaces
(at)(at) -9,34 +10,40 (at)(at)
import zc.table.column
import zc.resourcelibrary
+import gocept.js.dojo.interfaces
+
class DojoTableFormatter(zc.table.table.Formatter):
- def __init__(self, context, request, items, row_value=None, **kwargs):
+ def __init__(self, context, request, items,
+ table_attributes=u'', row_value=None, **kwargs):
if row_value is None:
row_value = lambda id, item, request: id
-
if not callable(row_value):
raise TypeError("row_value must be callable.")
-
self.row_value = row_value
- super(DojoTableFormatter, self).__init__(context, request, items,
**kwargs)
+ self.table_attributes = table_attributes
+ super(DojoTableFormatter, self).__init__(context, request, items,
+ **kwargs)
- def __call__(self, attrs):
+ def __call__(self):
"""renders the table"""
zc.resourcelibrary.need('tableHandlers')
return "\n<table%s>\n%s</table>\n%s" % (
- self._getTableAttributes(attrs), self.renderContents(),
+ self._getTableAttributes(), self.renderContents(),
self.renderExtra())
- def _getTableAttributes(self, attrs):
+ def _getTableAttributes(self):
"""returns given attributes as string incl. CSS class"""
- return "%s %s" %(self._getCSSClass('table'), attrs)
+ return "%s %s" %(self._getCSSClass('table'), self.table_attributes)
def renderHeader(self, column):
+ attrs = u'dojotype="html"'
+ if gocept.js.dojo.interfaces.IDojoColumn.providedBy(column):
+ attrs = column.extra_attributes
return ' <th%s %s>\n %s\n </th>\n' % (
- self._getCSSClass('th'), column.attrs, self.getHeader(column))
+ self._getCSSClass('th'), attrs, self.getHeader(column))
def renderCell(self, item, column):
"""renders cell without any whitespace"""
(at)(at) -55,14 +62,16 (at)(at)
class DojoTableColumn(zc.table.column.Column):
- def __init__(self, title=None, getter=None, attrs=""):
+ zope.interface.implements(gocept.js.dojo.interfaces.IDojoColumn)
+
+ def __init__(self, title=None, getter=None, extra_attributes=u''):
if getter is not None:
self.getter = getter
if title is not None:
self.title = title
self.name = title
- self.attrs = attrs
+ self.extra_attributes = extra_attributes
def renderCell(self, item, formatter):
value = self.getter(item, formatter)
Modified: gocept.js.dojo/trunk/src/gocept/js/dojo/table.txt
==============================================================================
--- gocept.js.dojo/trunk/src/gocept/js/dojo/table.txt (original)
+++ gocept.js.dojo/trunk/src/gocept/js/dojo/table.txt Tue Feb 20 16:15:03 2007
(at)(at) -33,14 +33,15 (at)(at)
...
... content = [('A', '20.02.2007'), ('B', '20.03.2007')]
...
- ... def contentTable(self, attrs):
+ ... (at)property
+ ... def contentTable(self):
+ ... attrs = 'dojoType="FilteringTable" enableMultiselect="true"'
... return gocept.js.dojo.table.DojoTableFormatter(
... self, self, self.content,
- ... columns=self.columns)(attrs)
+ ... columns=self.columns, table_attributes=attrs)
>>>
>>>
- >>> attrs = 'dojoType="FilteringTable" enableMultiselect="true"'
- >>> table = Test().contentTable(attrs)
+ >>> table = Test().contentTable()
>>> print table
<BLANKLINE>
<table dojoType="FilteringTable" enableMultiselect="true">
(at)(at) -51,7 +52,7 (at)(at)
DojoTableColumn
===============
-You can pass itional attributes as a string to render dojo
+You can pass optional attributes as a string to render dojo
attributes. I'll reuse the above example::
>>> print table
(at)(at) -102,13 +103,15 (at)(at)
... def row_value(self, id, item, request):
... return item[0]
...
- ... def contentTable(self, attrs):
+ ... (at)property
+ ... def contentTable(self):
+ ... attrs = 'dojoType="FilteringTable" enableMultiselect="true"'
... return gocept.js.dojo.table.DojoTableFormatter(
... self, self, self.content,
- ... columns=self.columns, row_value=self.row_value)(attrs)
+ ... columns=self.columns, row_value=self.row_value,
+ ... table_attributes=attrs)
>>>
- >>> attrs = 'dojoType="FilteringTable" enableMultiselect="true"'
- >>> table = Test().contentTable(attrs)
+ >>> table = Test().contentTable()
>>> print table
<table...
...<tr value="A">...
Modified: gocept.js.dojo/trunk/src/gocept/js/dojo/test.py
==============================================================================
--- gocept.js.dojo/trunk/src/gocept/js/dojo/test.py (original)
+++ gocept.js.dojo/trunk/src/gocept/js/dojo/test.py Tue Feb 20 16:15:03 2007
(at)(at) -5,12 +5,12 (at)(at)
from zope.testing import doctest
-import zeit.cms.testing
+import zope.app.testing.functional
def test_suite():
suite = unittest.TestSuite()
- suite.addTest(zeit.cms.testing.FunctionalDocFileSuite(
+ suite.addTest(zope.app.testing.functional.FunctionalDocFileSuite(
'table.txt',
optionflags=(doctest.REPORT_NDIFF + doctest.NORMALIZE_WHITESPACE +
doctest.ELLIPSIS)))
|
SVN: r4458 - gocept.js.dojo/trunk/src/gocept/js/dojo/resources
Roman Joost <rj(at)gocept.com> |
2007-02-21 16:25:39 |
[ FULL ]
|
Author: roman
Date: Wed Feb 21 16:25:38 2007
New Revision: 4458
Modified:
gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js
Log:
resize the topcontent box, so that the metadata screen doesn't overflow the
entire content box
Modified: gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js
==============================================================================
---
gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js (original)
+++ gocept.js.dojo/trunk/src/gocept/js/dojo/resources/tableHandlers.js Wed Feb
21 16:25:38 2007
(at)(at) -50,8 +50,13 (at)(at)
function onMetadataReceived(type, data, evt) {
var container = document.getElementById('bottomcontent');
+ var topcontent = document.getElementById('topcontent')
+ // reduce the height of the topcontent box
+ if (!topcontent.style.height)
+ topcontent.style.height = '60%';
+
+ // make the metadata preview box visible and show the HTML
container.setAttribute('class', 'visible')
-
container.innerHTML = data
}
|
SVN: r4462 - gocept.js.dojo/trunk/src/gocept/js/dojo
Roman Joost <rj(at)gocept.com> |
2007-02-22 16:13:43 |
[ FULL ]
|
Author: roman
Date: Thu Feb 22 16:13:41 2007
New Revision: 4462
Modified:
gocept.js.dojo/trunk/src/gocept/js/dojo/ (props changed)
Log:
changed external to dojo/trunk
|
SVN: r4467 - gocept.zeoraid/trunk/src/gocept/zeoraid
Christian Theune <ct(at)gocept.com> |
2007-02-24 16:49:40 |
[ FULL ]
|
Author: ctheune
Date: Sat Feb 24 16:49:38 2007
New Revision: 4467
Modified:
gocept.zeoraid/trunk/src/gocept/zeoraid/TODO.txt
gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py
Log:
- fix up recovery to:
- work asynchronously
- support busy sites that get commits while recovering
Modified: gocept.zeoraid/trunk/src/gocept/zeoraid/TODO.txt
==============================================================================
--- gocept.zeoraid/trunk/src/gocept/zeoraid/TODO.txt (original)
+++ gocept.zeoraid/trunk/src/gocept/zeoraid/TODO.txt Sat Feb 24 16:49:38 2007
(at)(at) -28,6 +28,9 (at)(at)
Features
========
+ - Rebuild a whole storage including undo data (requires a transaction
+ iterator from the storage.)
+
- Think about how to / whether to make packing work.
- Think about how to do recover with the whole database and not just the
Modified: gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py
==============================================================================
--- gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py (original)
+++ gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py Sat Feb 24 16:49:38 2007
(at)(at) -16,6 +16,7 (at)(at)
get_serial = storage.getSerial
return get_serial(oid)
+
def get_last_transaction(storage):
if hasattr(storage, '_zeoraid_lastTransaction'):
last_transaction = storage._zeoraid_lastTransaction()
(at)(at) -23,9 +24,11 (at)(at)
last_transaction = storage.lastTransaction()
return last_transaction
+
class RAIDError(Exception):
pass
+
class RAIDStorage(object):
"""The RAID storage is a drop-in replacement for the client storages that
are configured.
(at)(at) -75,7 +78,7 (at)(at)
s = tids.setdefault(tid, [])
s.append(name)
- self._unrecovered_oids = []
+ self._unrecovered_transactions = {}
self._last_tid = None
print "Storages", repr(tids)
(at)(at) -181,7 +184,8 (at)(at)
self._apply_all_storages('store', oid, oldserial, data, version,
transaction)
if self._log_stores:
- self._unrecovered_oids.append(oid)
+ oids = self._unrecovered_transactions.setdefault(self._tid, [])
+ oids.append(oid)
return self._tid
def lastTransaction(self):
(at)(at) -223,6 +227,11 (at)(at)
if transaction is not self._transaction:
return
try:
+ if self._log_stores:
+ # We may have logged some stores within that transaction
+ # which we have to remove again because we aborted it.
+ if self._tid in self._unrecovered_transactions:
+ del self._unrecovered_transactions[self._tid]
self._apply_all_storages('tpc_abort', transaction)
finally:
self._transaction = None
(at)(at) -343,43 +352,73 (at)(at)
# *something* went wrong. Put the storage back to degraded.
self._degrade_storage(name)
raise
- else:
- # Reactivate storage if nothing failed
- self.storages_recovering.remove(name)
- self.storages_optimal.append(name)
self._print_status()
def _recover_second(self, name):
storage = self.storages[name]
reference_storage = self.storages[self.storages_optimal[0]]
- tm = transaction.TransactionManager()
- t = tm.get()
- last_transaction = get_last_transaction(storage)
- reference_storage.tpc_begin(t)
- # We can stop logging stores now as we have the lock
- self._log_stores = False
- try:
- tm2 = transaction.TransactionManager()
- t2 = tm2.get()
- for oid in self._unrecovered_oids:
- data, tid = reference_storage.load(oid, '')
- oldserial = get_serial(storage, oid)
-
- if tid <= last_transaction:
- try:
- old_data = storage.loadSerial(oid, tid)
- except ZODB.POSException.POSKeyError:
- pass
- else:
- if old_data == data:
+ # Start a transation on the reference storage to acquire the
+ # commit log # and prevent other people from committing in the second
phase.
+ # XXX This needs to be optimized in a way that the second phase
+ # gets re-run as long as possible, only holding the commit lock if
+ # no transactions remain that need to be replayed and putting the
+ # recovered storage back into the array of optimal storages.
+ while 1:
+ tm = transaction.TransactionManager()
+ t = tm.get()
+ last_transaction = get_last_transaction(storage)
+ reference_storage.tpc_begin(t)
+ unrecovered_transactions = self._unrecovered_transactions
+ if unrecovered_transactions:
+ # We acquired the commit lock and there are transactions that
+ # have been committed and were not yet transferred to the
+ # recovering storage. We have to try to replay those and then
+ # check again. We can remove the commit lock for now.
+ self._unrecovered_transactions = {}
+ reference_storage.tpc_abort(t)
+
+ # RRR: Refactor into its own method?
+ tm2 = transaction.TransactionManager()
+ t2 = tm2.get()
+
+ # Get the unrecovered transactions in the order they were
+ # recorded.
+ tids = sorted(unrecovered_transactions.keys())
+ for tid in tids:
+ oids = unrecovered_transactions[tid]
+ # We create one transaction for all oids that belong to
one
+ # transaction.
+ storage.tpc_begin(t2, tid=tid)
+ for oid in oids:
+ data, tid_ = reference_storage.load(oid, '')
+ if tid_ > tid:
+ # If the current tid of the object is newer
+ # than the one we logged, we can ignore it,
because
+ # there will be another entry for this oid in a
+ # later transaction.
continue
-
- storage.tpc_begin(t2, tid=tid)
- storage.store(oid, oldserial, data, '', t2)
- storage.tpc_vote(t2)
- storage.tpc_finish(t2)
- finally:
- reference_storage.tpc_abort(t)
+ try:
+ oldserial = get_serial(storage, oid)
+ except ZODB.POSException.POSKeyError:
+ # This means that the object is new and didn't
have an
+ # old transaction yet.
+ # XXX Might this also happen with non-undoable
storages?
+ oldserial = ZODB.utils.z64
+ storage.store(oid, oldserial, data, '', t2)
+ storage.tpc_vote(t2)
+ storage.tpc_finish(t2)
+ # /RRR
+ else:
+ # We acquired the commit lock and no committed transactions
+ # are waiting in the log. This means the recovering storage
+ # has caught up by now and we can put it into optimal state
+ # again.
+ self.storages_recovering.remove(name)
+ self.storages_optimal.append(name)
+ # We can also stop logging stores now.
+ self._log_stores = False
+ reference_storage.tpc_abort(t)
+ break
def _recover_first(self, name):
"""The inner loop of the recovery code. Does the actual work."""
(at)(at) -401,7 +440,8 (at)(at)
last_transaction = get_last_transaction(storage)
# This flag starts logging all succcessfull stores and updates those
oids
# in the second pass again.
- self._unrecovered_oids = []
+ max_transaction =
get_last_transaction(self.storages[self.storages_optimal[0]])
+ self._unrecovered_transactions = {}
self._log_stores = True
# The init flag allows us to phrase the break condition of the
# following loop a little bit more elegantly.
(at)(at) -413,6 +453,9 (at)(at)
init = False
oid, tid, data, next_oid =
self._apply_single_storage('record_iternext', next_oid)
+ if tid > max_transaction:
+ continue
+
if tid <= last_transaction:
try:
old_data = storage.loadSerial(oid, tid)
|
SVN: r4472 - in gocept.zeoraid/trunk/src/gocept/zeoraid: . tests
Christian Theune <ct(at)gocept.com> |
2007-02-25 23:18:15 |
[ FULL ]
|
Author: ctheune
Date: Sun Feb 25 23:18:12 2007
New Revision: 4472
Added:
gocept.zeoraid/trunk/src/gocept/zeoraid/tests/
gocept.zeoraid/trunk/src/gocept/zeoraid/tests/__init__.py (contents, props
changed)
gocept.zeoraid/trunk/src/gocept/zeoraid/tests/test_basics.py (contents,
props changed)
Modified:
gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py
Log:
- added tests and locking
Modified: gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py
==============================================================================
--- gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py (original)
+++ gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py Sun Feb 25 23:18:12 2007
(at)(at) -37,24 +37,28 (at)(at)
storages, coordinate the transactions between the storages and alert the
RAID controller if a storage fails.
- TODO
-
- - make store and tpc_* methods work against all storages
- - make load methods work against a hashed selection of the storages
-
"""
_transaction = None
- def __init__(self, name, storages):
+ def __init__(self, name, storages, read_only=False):
self.__name__ = name
+ self.read_only = read_only
self.storages = {}
self._log_stores = False
+
+ # Allocate locks
+ l = threading.RLock()
+ self._lock_acquire = l.acquire
+ self._lock_release = l.release
+ l = threading.Lock()
+ self._commit_lock_acquire = l.acquire
+ self._commit_lock_release = l.release
+
# Remember the openers to for recovering a storage later
self.openers = {}
# Open the storages
for opener in storages:
- print "Activating", opener.name
self.storages[opener.name] = opener.open()
self.openers[opener.name] = opener
(at)(at) -64,7 +68,6 (at)(at)
tids = {}
for name, storage in self.storages.items():
- print "Validating", name, storage
try:
tid = get_last_transaction(storage)
except ZEO.ClientStorage.ClientDisconnected:
(at)(at) -81,14 +84,11 (at)(at)
self._unrecovered_transactions = {}
self._last_tid = None
- print "Storages", repr(tids)
# Activate all optimal storages
if tids:
self._last_tid = max(tids.keys())
- print "Valid tid %r" % self._last_tid
self.storages_optimal.extend(tids[self._last_tid])
del tids[self._last_tid]
- print "Invalid tids %r" % tids.keys()
# Deactive all degraded storages
for degraded_storages in tids.values():
(at)(at) -97,13 +97,10 (at)(at)
t = time.time()
self.ts = persistent.TimeStamp.TimeStamp(*(time.gmtime(t)[:5] +
(t%60,)))
- print 'Optimal storages: %r' % self.storages_optimal
- print 'Degraded storages: %r' % self.storages_degraded
if not self.storages_optimal:
raise RAIDError("Can't start without at least one optimal
storage.")
def _degrade_storage(self, name, fail=True):
- print "Eliminating storage ..."
if name in self.storages_optimal:
self.storages_optimal.remove(name)
self.storages_degraded.append(name)
(at)(at) -111,14 +108,9 (at)(at)
t = threading.Thread(target=storage.close)
t.start()
del self.storages[name]
- self._print_status()
if not self.storages_optimal and fail:
raise RAIDError("No storages remain.")
- def _print_status(self):
- print 'Optimal storages: %r' % self.storages_optimal
- print 'Degraded storages: %r' % self.storages_degraded
-
def _apply_single_storage(self, method_name, *args, **kw):
while len(self.storages_optimal):
name = self.storages_optimal[0]
(at)(at) -133,14 +125,13 (at)(at)
def _apply_all_storages(self, method_name, *args, **kw):
results = []
for name in self.storages_optimal:
- print "%s to storage %s" % (method_name, name)
+ time.sleep(0.01)
storage = self.storages[name]
try:
method = getattr(storage, method_name)
results.append(method(*args, **kw))
except ZEO.ClientStorage.ClientDisconnected:
self._degrade_storage(name)
- print "Testing results ..."
res = results[:]
while res:
test = res.pop()
(at)(at) -154,7 +145,7 (at)(at)
XXX Revisit this approach?
"""
- return False
+ return self.read_only
def getName(self):
return self.__name__
(at)(at) -180,13 +171,16 (at)(at)
if transaction is not self._transaction:
raise ZODB.POSException.StorageTransactionError(self, transaction)
- # Do we need a lock?
- self._apply_all_storages('store', oid, oldserial, data, version,
- transaction)
- if self._log_stores:
- oids = self._unrecovered_transactions.setdefault(self._tid, [])
- oids.append(oid)
- return self._tid
+ self._lock_acquire()
+ try:
+ self._apply_all_storages('store', oid, oldserial, data, version,
+ transaction)
+ if self._log_stores:
+ oids = self._unrecovered_transactions.setdefault(self._tid,
[])
+ oids.append(oid)
+ return self._tid
+ finally:
+ self._lock_release()
def lastTransaction(self):
return self._apply_single_storage('lastTransaction')
(at)(at) -205,7 +199,13 (at)(at)
def new_oid(self):
# XXX This is not exactly a read operation, but we only need an answer
from one storage
- return self._apply_single_storage('new_oid')
+ if self.isReadOnly():
+ raise ZODB.POSException.ReadOnlyError()
+ self._lock_acquire()
+ try:
+ return self._apply_single_storage('new_oid')
+ finally:
+ self._lock_release()
def registerDB(self, db, limit):
# XXX Is it safe to register a DB with multiple storages or do we need
some kind
(at)(at) -216,82 +216,144 (at)(at)
# XXX lets say no for now
return False
+ def undoLog(self, first=0, last=-20, filter=None):
+ return self._apply_single_storage('undoLog', first, last, filter)
+
+ def undoInfo(self, first=0, last=-20, specification=None):
+ return self._apply_all_storages('undoInfo', first, last,
+ specification)
+
+ def undo(self, transaction_id, transaction):
+ self._lock_acquire()
+ try:
+ return self._apply_all_storages('undo', transaction_id,
transaction)
+ finally:
+ self._lock_release()
+
def supportsTransactionalUndo(self):
return False
+ def pack(self, t, referencesf):
+ if self.isReadOnly():
+ raise ZODB.POSException.ReadOnlyError()
+ self._apply_all_storages('pack', t, referencesf)
+
def supportsVersions(self):
- # XXX lets say no for now
- return False
+ return True
- def tpc_abort(self, transaction):
- if transaction is not self._transaction:
- return
+ def commitVersion(self, src, dest, transaction, abort=False):
+ if self.isReadOnly():
+ raise ZODB.POSException.ReadOnlyError()
+ self._lock_acquire()
try:
- if self._log_stores:
- # We may have logged some stores within that transaction
- # which we have to remove again because we aborted it.
- if self._tid in self._unrecovered_transactions:
- del self._unrecovered_transactions[self._tid]
- self._apply_all_storages('tpc_abort', transaction)
+ return self._apply_all_storages('commitVersion', src, dest,
transaction,
+ abort)
finally:
- self._transaction = None
+ self._lock_release()
- def tpc_begin(self, transaction, tid=None, status=' '):
+ def abortVersion(self, src, transaction):
if self.isReadOnly():
raise ZODB.POSException.ReadOnlyError()
- if self._transaction is transaction:
- return
+ self._lock_acquire()
+ try:
+ return self._apply_all_storages('abortVersion', src, transaction)
+ finally:
+ self._lock_release()
- # I don't understand the lock that protects _transaction. The commit
- # log and status will be deduced by the underlying storages.
+ def tpc_abort(self, transaction):
+ self._lock_acquire()
+ try:
+ if transaction is not self._transaction:
+ return
+ try:
+ if self._log_stores:
+ # We may have logged some stores within that transaction
+ # which we have to remove again because we aborted it.
+ if self._tid in self._unrecovered_transactions:
+ del self._unrecovered_transactions[self._tid]
+ self._apply_all_storages('tpc_abort', transaction)
+ self._transaction = None
+ finally:
+ self._commit_lock_release()
+ finally:
+ self._lock_release()
- self._transaction = transaction
- # Remove storages that aren't on the same last tid anymore (this
happens
- # if a storage disconnects
- for name in self.storages_optimal:
- storage = self.storages[name]
- try:
- last_tid = get_last_transaction(storage)
- except ZEO.ClientStorage.ClientDisconnected:
- self._degrade_storage(name, fail=False)
- continue
- if last_tid != self._last_tid:
- self._degrade_storage(name)
+ def tpc_begin(self, transaction, tid=None, status=' '):
+ if self.isReadOnly():
+ raise ZODB.POSException.ReadOnlyError()
- # Create a common tid for all storages if we don't have one yet.
- if tid is None:
- now = time.time()
- t = persistent.TimeStamp.TimeStamp(*(time.gmtime(now)[:5] + (now %
60,)))
- self.ts = t.laterThan(self.ts)
- self._tid = repr(self.ts)
- else:
- self._ts = persistent.TimeStamp.TimeStamp(tid)
- self._tid = tid
+ self._lock_acquire()
+ try:
+ if self._transaction is transaction:
+ return
+ self._lock_release()
+ self._commit_lock_acquire()
+ self._lock_acquire()
+
+ # I don't understand the lock that protects _transaction. The
commit
+ # lock and status will be deduced by the underlying storages.
+
+ self._transaction = transaction
+
+ # Remove storages that aren't on the same last tid anymore (this
happens
+ # if a storage disconnects
+ for name in self.storages_optimal:
+ storage = self.storages[name]
+ try:
+ last_tid = get_last_transaction(storage)
+ except ZEO.ClientStorage.ClientDisconnected:
+ self._degrade_storage(name, fail=False)
+ continue
+ if last_tid != self._last_tid:
+ self._degrade_storage(name)
+
+ # Create a common tid for all storages if we don't have one yet.
+ if tid is None:
+ now = time.time()
+ t = persistent.TimeStamp.TimeStamp(*(time.gmtime(now)[:5] +
(now % 60,)))
+ self.ts = t.laterThan(self.ts)
+ self._tid = repr(self.ts)
+ else:
+ self._ts = persistent.TimeStamp.TimeStamp(tid)
+ self._tid = tid
- self._apply_all_storages('tpc_begin', transaction, self._tid, status)
+ self._apply_all_storages('tpc_begin', transaction, self._tid,
status)
+ finally:
+ self._lock_release()
def tpc_vote(self, transaction):
- if transaction is not self._transaction:
- return
- res = self._apply_all_storages('tpc_vote', transaction)
- # XXX result consistency check?
- return res[0]
+ self._lock_acquire()
+ try:
+ if transaction is not self._transaction:
+ return
+ self._apply_all_storages('tpc_vote', transaction)
+ finally:
+ self._lock_release()
def tpc_finish(self, transaction, callback=None):
- if transaction is not self._transaction:
- return
+ self._lock_acquire()
try:
- if callback is not None:
- callback(self._tid)
- self._apply_all_storages('tpc_finish', transaction)
- self._last_tid = self._tid
- return self._tid
+ if transaction is not self._transaction:
+ return
+ try:
+ if callback is not None:
+ callback(self._tid)
+ self._apply_all_storages('tpc_finish', transaction)
+ self._last_tid = self._tid
+ return self._tid
+ finally:
+ self._transaction = None
+ self._commit_lock_release()
finally:
- self._transaction = None
+ self._lock_release()
def getSerial(self, oid):
- return self._apply_single_storage('getSerial', oid)
+ self._lock_acquire()
+ try:
+ return self._apply_single_storage('getSerial', oid)
+ finally:
+ self._lock_release()
def getExtensionMethods(self):
# XXX This is very awkward right now.
(at)(at) -309,13 +371,13 (at)(at)
return self._apply_single_storage('__len__')
def versionEmpty(self, version):
- return 1
+ return self._apply_single_storage('versionEmpty', version)
def versions(self, max=None):
- return ()
+ return self._apply_single_storage('versions', max)
def modifiedInVersion(self, oid):
- return ''
+ return self._apply_single_storage('modifiedInVersion', oid)
def getTid(self, oid):
# This is an ugly hack because ClientStorage doesn't implement getTid
(at)(at) -323,8 +385,6 (at)(at)
# Extension methods for RAIDStorage
def raid_recover(self, name):
- print "Recovering storage %r" % name
- # XXX locking
if name not in self.storages_degraded:
return
self.storages_degraded.remove(name)
(at)(at) -339,7 +399,6 (at)(at)
begin = time.time()
self._recover_first(name)
end = time.time()
- print "RECOVERY: First pass in %s seconds." % (end-begin)
# Second pass: Start the TPC on a reference storage to block other
# transactions so we can catch up. The second pass should be
(at)(at) -347,12 +406,10 (at)(at)
begin = time.time()
self._recover_second(name)
end = time.time()
- print "RECOVERY: Second pass in %s seconds." % (end-begin)
except:
# *something* went wrong. Put the storage back to degraded.
self._degrade_storage(name)
raise
- self._print_status()
def _recover_second(self, name):
storage = self.storages[name]
(at)(at) -473,7 +530,6 (at)(at)
oldserial = ZODB.utils.z64
- print "Recovering (oid=%r,tid=%r,old_tid=%r,lastTransaction=%r)" %
(oid, tid, oldserial, last_transaction)
assert oldserial <= tid, "last_transaction and oldserial are
not in-sync"
storage.tpc_begin(t, tid=tid)
Added: gocept.zeoraid/trunk/src/gocept/zeoraid/tests/__init__.py
==============================================================================
--- (empty file)
+++ gocept.zeoraid/trunk/src/gocept/zeoraid/tests/__init__.py Sun Feb 25
23:18:12 2007
(at)(at) -0,0 +1 (at)(at)
+#make this a package
Added: gocept.zeoraid/trunk/src/gocept/zeoraid/tests/test_basics.py
==============================================================================
--- (empty file)
+++ gocept.zeoraid/trunk/src/gocept/zeoraid/tests/test_basics.py Sun Feb 25
23:18:12 2007
(at)(at) -0,0 +1,65 (at)(at)
+import unittest
+
+from ZODB.tests import StorageTestBase, BasicStorage, \
+ TransactionalUndoStorage, VersionStorage, \
+ TransactionalUndoVersionStorage, PackableStorage, \
+ Synchronization, ConflictResolution, HistoryStorage, \
+ Corruption, RevisionStorage, PersistentStorage, \
+ MTStorage, ReadOnlyStorage, RecoveryStorage
+
+import gocept.zeoraid.storage
+
+from ZODB.FileStorage.FileStorage import FileStorage
+
+class DemoOpener(object):
+
+ def __init__(self, name, *kwargs):
+ self.name = name
+ self.kwargs = kwargs or {}
+
+ def open(self, **kwargs):
+ return FileStorage(self.name, **self.kwargs)
+
+class BaseReplicationStorageTests(StorageTestBase.StorageTestBase):
+
+ def open(self, **kwargs):
+ # A RAIDStorage requires openers, not storages.
+ s1 = DemoOpener('s1.fs')
+ s2 = DemoOpener('s2.fs')
+
+ self._storage = gocept.zeoraid.storage.RAIDStorage('teststorage',
+ [s1, s2], **kwargs)
+
+ def setUp(self):
+ self.open()
+
+ def tearDown(self):
+ self._storage.close()
+ self._storage.cleanup()
+
+class ReplicationStorageTests(BaseReplicationStorageTests,
+ BasicStorage.BasicStorage,
+ TransactionalUndoStorage.TransactionalUndoStorage,
+ RevisionStorage.RevisionStorage,
+ VersionStorage.VersionStorage,
+ TransactionalUndoVersionStorage.TransactionalUndoVersionStorage,
+ PackableStorage.PackableStorage,
+ PackableStorage.PackableUndoStorage,
+ Synchronization.SynchronizedStorage,
+ ConflictResolution.ConflictResolvingStorage,
+ ConflictResolution.ConflictResolvingTransUndoStorage,
+ HistoryStorage.HistoryStorage,
+ PersistentStorage.PersistentStorage,
+ MTStorage.MTStorage,
+ ReadOnlyStorage.ReadOnlyStorage
+ ):
+ pass
+
+
+def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTest(unittest.makeSuite(ReplicationStorageTests, "check"))
+ return suite
+
+if __name__=='__main__':
+ unittest.main()
|
SVN: r4476 - gocept.zeoraid/trunk/src/gocept/zeoraid
Christian Theune <ct(at)gocept.com> |
2007-02-26 17:10:26 |
[ FULL ]
|
Author: ctheune
Date: Mon Feb 26 17:10:24 2007
New Revision: 4476
Modified:
gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py
Log:
- fix support for read-only on undo()
Modified: gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py
==============================================================================
--- gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py (original)
+++ gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py Mon Feb 26 17:10:24 2007
(at)(at) -222,6 +222,8 (at)(at)
specification)
def undo(self, transaction_id, transaction):
+ if self.isReadOnly():
+ raise ZODB.POSException.ReadOnlyError()
self._lock_acquire()
try:
return self._apply_all_storages('undo', transaction_id,
transaction)
|
SVN: r4477 - gocept.js.dojo/trunk/src/gocept/js/dojo
Christian Zagrodnick <cz(at)gocept.com> |
2007-02-27 13:37:15 |
[ FULL ]
|
Author: zagy
Date: Tue Feb 27 13:37:11 2007
New Revision: 4477
Modified:
gocept.js.dojo/trunk/src/gocept/js/dojo/table.py
Log:
added a very simple selection column which is able to tell the order of the
submitted entries. important for sorting a table via drag and drop.
Modified: gocept.js.dojo/trunk/src/gocept/js/dojo/table.py
==============================================================================
--- gocept.js.dojo/trunk/src/gocept/js/dojo/table.py (original)
+++ gocept.js.dojo/trunk/src/gocept/js/dojo/table.py Tue Feb 27 13:37:11 2007
(at)(at) -76,3 +76,44 (at)(at)
def renderCell(self, item, formatter):
value = self.getter(item, formatter)
return unicode(value)
+
+
+class SelectionColumn(zc.table.column.SelectionColumn):
+
+ def getItems(self, items, request):
+ used_ids = request.get(self.prefix + '.used')
+ id_map = dict((self.makeId(item), item) for item in items)
+ ordered = []
+ for id in used_ids:
+ ordered.append(id_map[id])
+ return ordered
+
+ def getSelected(self, items, request):
+ selected_ids = request.get(self.prefix)
+ if not selected_ids:
+ return []
+ id_map = dict((self.makeId(item), item) for item in items)
+ result = []
+ for id in selected_ids:
+ result.append(id_map[id])
+ return result
+
+ def renderCell(self, item, formatter):
+ value = self.makeId(item)
+ name = '%s:list' % self.prefix
+ used_name = '%s.used:list' % self.prefix
+ checked = self.get(item)
+ checked_html = ''
+ if checked:
+ checked_html = 'checked="checked"'
+ return (
+ u'<input type="hidden" name="%s" value="%s" />'
+ u'<input type="checkbox" name="%s" value="%s" %s /> ') % (
+ used_name, value, name, value, checked_html)
+
+ def input(self, items, request):
+ raise NotImplementedError()
+
+ def update(self, items, data):
+ raise NotImplementedError()
+
|
SVN: r4478 - in gocept.zeoraid/trunk/src/gocept/zeoraid: . tests
Christian Theune <ct(at)gocept.com> |
2007-02-28 00:34:28 |
[ FULL ]
|
Author: ctheune
Date: Wed Feb 28 00:34:25 2007
New Revision: 4478
Modified:
gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py
gocept.zeoraid/trunk/src/gocept/zeoraid/tests/test_basics.py
Log:
- added ZEO tests (still breaking)
- fixed some API methods that FileStorage implemented in a weird way
Modified: gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py
==============================================================================
--- gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py (original)
+++ gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py Wed Feb 28 00:34:25 2007
(at)(at) -192,8 +192,8 (at)(at)
#def iterator(self):
# XXX Dunno
- def history(self, oid, version=None, size=1, filter=None):
- return self._apply_single_storage('history', oid, version, size,
filter)
+ def history(self, oid, version=None, size=1):
+ return self._apply_single_storage('history', oid, version, size)
def new_oid(self):
# XXX This is not exactly a read operation, but we only need an answer
from one storage
(at)(at) -241,13 +241,12 (at)(at)
def supportsVersions(self):
return True
- def commitVersion(self, src, dest, transaction, abort=False):
+ def commitVersion(self, src, dest, transaction):
if self.isReadOnly():
raise ZODB.POSException.ReadOnlyError()
self._lock_acquire()
try:
- return self._apply_all_storages('commitVersion', src, dest,
transaction,
- abort)
+ return self._apply_all_storages('commitVersion', src, dest,
transaction)
finally:
self._lock_release()
Modified: gocept.zeoraid/trunk/src/gocept/zeoraid/tests/test_basics.py
==============================================================================
--- gocept.zeoraid/trunk/src/gocept/zeoraid/tests/test_basics.py (original)
+++ gocept.zeoraid/trunk/src/gocept/zeoraid/tests/test_basics.py Wed Feb 28
00:34:25 2007
(at)(at) -1,4 +1,5 (at)(at)
import unittest
+import tempfile
from ZODB.tests import StorageTestBase, BasicStorage, \
TransactionalUndoStorage, VersionStorage, \
(at)(at) -11,16 +12,29 (at)(at)
from ZODB.FileStorage.FileStorage import FileStorage
+from ZEO.ClientStorage import ClientStorage
+from ZEO.tests import forker, CommitLockTests, ThreadTests
+from ZEO.tests.testZEO import get_port
+
+
class DemoOpener(object):
- def __init__(self, name, *kwargs):
+ class_ = FileStorage
+
+ def __init__(self, name, **kwargs):
self.name = name
self.kwargs = kwargs or {}
def open(self, **kwargs):
- return FileStorage(self.name, **self.kwargs)
+ return self.class_(self.name, **self.kwargs)
+
+
+class ZEOOpener(DemoOpener):
+
+ class_ = ClientStorage
+
-class BaseReplicationStorageTests(StorageTestBase.StorageTestBase):
+class FileStorageBackendTests(StorageTestBase.StorageTestBase):
def open(self, **kwargs):
# A RAIDStorage requires openers, not storages.
(at)(at) -37,8 +51,47 (at)(at)
self._storage.close()
self._storage.cleanup()
-class ReplicationStorageTests(BaseReplicationStorageTests,
- BasicStorage.BasicStorage,
+
+class ZEOStorageBackendTests(StorageTestBase.StorageTestBase):
+
+ def open(self, **kwargs):
+ self._storage = gocept.zeoraid.storage.RAIDStorage('teststorage',
+ self._storages,
**kwargs)
+
+ def setUp(self):
+ self._server_storage_files = []
+ self._servers = []
+ self._storages = []
+ for i in xrange(5):
+ port = get_port()
+ zconf = forker.ZEOConfig(('', port))
+ zport, adminaddr, pid, path =
forker.start_zeo_server(self.getConfig(),
+ zconf, port)
+
+ self._servers.append(adminaddr)
+ self._storages.append(ZEOOpener(zport, storage='1',
+ cache_size=2000000,
+ min_disconnect_poll=0.5, wait=1,
+ wait_timeout=60))
+ self.open()
+
+ def getConfig(self):
+ filename = self.__fs_base = tempfile.mktemp()
+ self._server_storage_files.append(filename)
+ return """\
+ <filestorage 1>
+ path %s
+ </filestorage>
+ """ % filename
+
+ def tearDown(self):
+ self._storage.close()
+ for server in self._servers:
+ forker.shutdown_zeo_server(server)
+ # XXX wait for servers to come down
+ # XXX delete filestorage files
+
+class ReplicationStorageTests(BasicStorage.BasicStorage,
TransactionalUndoStorage.TransactionalUndoStorage,
RevisionStorage.RevisionStorage,
VersionStorage.VersionStorage,
(at)(at) -51,14 +104,26 (at)(at)
HistoryStorage.HistoryStorage,
PersistentStorage.PersistentStorage,
MTStorage.MTStorage,
- ReadOnlyStorage.ReadOnlyStorage
+ ReadOnlyStorage.ReadOnlyStorage,
):
pass
+class FSReplicationStorageTests(FileStorageBackendTests,
+ ReplicationStorageTests):
+ pass
+
+
+class ZEOReplicationStorageTests(ZEOStorageBackendTests,
+ ReplicationStorageTests,
+ ThreadTests.ThreadTests):
+ pass
+
+
def test_suite():
suite = unittest.TestSuite()
- suite.addTest(unittest.makeSuite(ReplicationStorageTests, "check"))
+ suite.addTest(unittest.makeSuite(FSReplicationStorageTests, "check"))
+ suite.addTest(unittest.makeSuite(ZEOReplicationStorageTests, "check"))
return suite
if __name__=='__main__':
|
|