[Zope3-checkins] CVS: Zope3/src/zope/app/browser/services - bundle.pt:1.7 bundle.py:1.7
Guido van Rossum
guido@python.org
Thu, 19 Jun 2003 17:33:32 -0400
Update of /cvs-repository/Zope3/src/zope/app/browser/services
In directory cvs.zope.org:/tmp/cvs-serv14524/zope/app/browser/services
Modified Files:
bundle.pt bundle.py
Log Message:
The bundle code now supports version overrides.
The bundle UI looks a little cleaner, with fewer lines per item.
=== Zope3/src/zope/app/browser/services/bundle.pt 1.6 => 1.7 ===
--- Zope3/src/zope/app/browser/services/bundle.pt:1.6 Mon Jun 16 22:22:23 2003
+++ Zope3/src/zope/app/browser/services/bundle.pt Thu Jun 19 17:33:01 2003
@@ -46,32 +46,35 @@
<ul>
<tal:block tal:repeat="cnf view/listConfigurations">
- <li tal:condition="python: cnf['service'] == svc['service']">
- <a tal:content="cnf/path" tal:attributes="href cnf/path">path</a>
- (current status: <span tal:replace="cnf/status">Active</span>)
- <br>
- <i tal:content="cnf/usage">Usage summary</i>
- implemented by
- <i tal:content="cnf/implementation">Implementation summary</i>
+ <li tal:condition="python: cnf['service'] == svc['service']"
+ tal:define="activate python:cnf['advice'] == 'Active'">
+ <a tal:attributes="href cnf/path">
+ <i tal:content="cnf/usage">Usage summary</i>
+ implemented by
+ <i tal:content="cnf/implementation">Implementation summary</i>
+ </a>
+ <span tal:condition="cnf/conflict">
+ <br>
+ <font color="red" tal:condition="not:activate">Conflicts
+ with</font>
+ <font color="green" tal:condition="activate">Overrides</font>
+ <a tal:content="cnf/conflict"
+ tal:attributes="href cnf/conflict">path</a>
+ </span>
<br>
- <span tal:condition="not:cnf/conflict">
- Action:
- <b><input type="radio" tal:attributes="name cnf/path"
- value="Registered" />Register only</b>
+ <span tal:condition="python: cnf['advice'] == 'Active'">
+ <input type="radio" tal:attributes="name cnf/path"
+ value="Registered" />Register only
<b><input type="radio" tal:attributes="name cnf/path"
value="Active" checked />Register and activate</b>
- </span>
- <span tal:condition="cnf/conflict">
- <font color="red">
- Conflicts with <a tal:content="cnf/conflict"
- tal:attributes="href cnf/conflict">path</a>
- </font>
- <br>Action:
+ </span>
+ <span tal:condition="python: cnf['advice'] == 'Registered'">
<b><input type="radio" tal:attributes="name cnf/path"
value="Registered" checked />Register only</b>
- <b><input type="radio" tal:attributes="name cnf/path"
- value="Active" />Register and activate</b>
+ <input type="radio" tal:attributes="name cnf/path"
+ value="Active" />Register and activate
</span>
+ (is: <span tal:replace="cnf/status">Active</span>)
</li>
</tal:block>
</ul>
=== Zope3/src/zope/app/browser/services/bundle.py 1.6 => 1.7 ===
--- Zope3/src/zope/app/browser/services/bundle.py:1.6 Mon Jun 16 22:04:47 2003
+++ Zope3/src/zope/app/browser/services/bundle.py Thu Jun 19 17:33:01 2003
@@ -31,6 +31,7 @@
$Id$
"""
+import re
from transaction import get_transaction
from zope.app import zapi
from zope.app.interfaces.container import IReadContainer
@@ -48,7 +49,18 @@
def __init__(self, context, request):
BrowserView.__init__(self, context, request)
- self.sitepath = zapi.getPath(zapi.getParent(self.context))
+ self.mypath = zapi.getPath(self.context)
+ self.myversion = self.parseVersion(self.mypath)
+ # Compute sitepath as the parent of mypath
+ sitepath = zapi.getPath(self.context)
+ i = sitepath.rfind("/")
+ if i > 0:
+ sitepath = sitepath[:i]
+ elif i == 0:
+ sitepath = "/"
+ else:
+ sitepath = ""
+ self.sitepath = sitepath
self.configurations = self.findConfigurations(self.context, "")
self.configurations.sort(self.compareConfigurations)
self.services = self.findServices()
@@ -151,23 +163,86 @@
def getAdvice(self, obj):
name = self.getServiceName(obj)
+ advice = Active
conflict = ""
sm = zapi.getServiceManager(obj)
service = sm.queryLocalService(name)
- if not service:
- advice = Active
- else:
+ if service:
registry = service.queryConfigurationsFor(obj)
- if not registry:
- advice = Active
- else:
+ if registry:
active = registry.active()
- if not active or active == obj:
- advice = Active
- else:
- advice = Registered
+ if active and active != obj:
conflict = zapi.getPath(active)
+ if not self.inOlderVersion(active):
+ advice = Registered
return name, advice, conflict
+
+ def inOlderVersion(self, obj):
+ # Return whether obj (an active component) belongs to an older
+ # version of the same bundle we're proposing to activate here.
+ # XXX This assumes sites are named with ++etc++site; there is
+ # no support for the older ++etc++Services.
+ path = zapi.getPath(obj)
+ prefix = "/++etc++site/"
+ i = path.rfind(prefix) # (can the prefix occur twice?)
+ if i < 0:
+ return False
+ i += len(prefix) # points just after the second "/"
+ i = path.find("/", i) # finds next slash after that
+ if i >= 0:
+ path = path[:i]
+ # Now path is of the form ".../++etc++site/name-version"
+ version = self.parseVersion(path)
+ if not version:
+ return False
+ i = path.rfind("-") + 1
+ return self.mypath[:i] == path[:i] and self.myversion > version
+
+ nineDigits = re.compile(r"^\d{1,9}$")
+
+ def parseVersion(self, path):
+ # Return a list containing the version numbers, suitably
+ # modified for sane version comparison. If there is no
+ # version number, return None. A version number is any number
+ # of dot-separated integers of at most 9 digits, optionally
+ # followed by another dot and something like "a1" or "b1"
+ # indicating an alpha or beta version. If no alpha or beta
+ # version is present, "f" is assumed (indicating "final").
+ # ("f" is chosen to compare higher than "a1", "b1" or "c1" but
+ # lower than "p1"; "p1" is sometimes used to indicate a patch
+ # release.) Examples:
+ #
+ # "/foo/bar-boo" -> None
+ # "/foo/bar-boo-1.0" -> ["f000000001", "f000000000", "f"]
+ # "/foo/bar-boo-1.0.f" -> ["f000000001", "f000000000", "f"]
+ # "/foo/bar-boo-1.0.a1" -> ["f000000001", "f000000000", "a1"]
+ #
+ # Note that we do a string compare on the alpha/beta version
+ # number; "a10" will compare less than "a2". OTOH, the
+ # integers are padded with leading zeros, so "10" will compare
+ # higher than "2".
+ i = path.rfind("/") + 1
+ base = path[i:]
+ i = base.rfind("-") + 1
+ if not i:
+ return None # No version
+ version = base[i:]
+ parts = version.split(".")
+ last = parts[-1]
+ if self.nineDigits.match(last):
+ last = "f"
+ else:
+ last = last.lower()
+ del parts[-1]
+ if not parts:
+ return None
+ for i in range(len(parts)):
+ p = parts[i]
+ if not self.nineDigits.match(p):
+ return None
+ parts[i] = "f" + "0"*(9-len(p)) + p
+ parts.append(last)
+ return parts
def findServiceConfiguration(self, name):
for path, obj in self.configurations: