[Zope3-checkins] CVS: Zope3/src/zope/app/browser/content - configure.zcml:1.23.2.1 file.py:1.2.28.1 folder.py:1.2.28.1 fssync.py:1.12.2.1 i18n.py:1.2.28.1 i18nimage.py:1.3.12.1 sql.py:1.5.24.1 sqltest.pt:1.2.28.1

Grégoire Weber zope@i-con.ch
Sun, 22 Jun 2003 10:24:09 -0400


Update of /cvs-repository/Zope3/src/zope/app/browser/content
In directory cvs.zope.org:/tmp/cvs-serv24874/src/zope/app/browser/content

Modified Files:
      Tag: cw-mail-branch
	configure.zcml file.py folder.py fssync.py i18n.py 
	i18nimage.py sql.py sqltest.pt 
Log Message:
Synced up with HEAD

=== Zope3/src/zope/app/browser/content/configure.zcml 1.23 => 1.23.2.1 ===
--- Zope3/src/zope/app/browser/content/configure.zcml:1.23	Tue May 20 15:09:53 2003
+++ Zope3/src/zope/app/browser/content/configure.zcml	Sun Jun 22 10:22:38 2003
@@ -248,45 +248,28 @@
       file="folder_icon.gif" 
       />
 
-  <browser:menuItems menu="zmi_views"
-      for="zope.app.interfaces.content.folder.IFolder">
-
-    <browser:menuItem title="Contents" 
-        action="@@contents.html"
-        />
-
-  </browser:menuItems>
-
   <browser:menuItem menu="add_content"
       for="zope.app.interfaces.container.IAdding"
       title="Folder" action="Folder"
       description="A simple Folder." 
       />
 
-  <browser:pages
+  <browser:page
+      name="contents.html" 
+      menu="zmi_views" title="Contents"
       for="zope.app.interfaces.content.folder.IFolder"
       permission="zope.ManageContent" 
       class="zope.app.browser.container.contents.Contents"
-      >
-
-    <browser:page name="contents.html" attribute="contents" />
-    <browser:page name="removeObjects.html" attribute="removeObjects" />
-    <browser:page name="cutObjects.html" attribute="cutObjects" />
-    <browser:page name="copyObjects.html" attribute="copyObjects" />
-    <browser:page name="pasteObjects.html" attribute="pasteObjects" />
-    <browser:page name="renameObjects.html" attribute="renameObjects" />
-    <browser:page name="rename.html" attribute="rename" />
-
-  </browser:pages>
+      attribute="contents"
+      />
 
-  <browser:pages
+  <browser:page
+      name="index.html" 
       for="zope.app.interfaces.content.folder.IFolder"
       permission="zope.View" 
-      class="zope.app.browser.container.contents.Contents">
-
-    <browser:page name="index.html" attribute="index" />
-
-  </browser:pages>
+      class="zope.app.browser.container.contents.Contents"
+      attribute="index" 
+      />
 
   <browser:page
       for="zope.app.interfaces.content.folder.IFolder"
@@ -340,13 +323,6 @@
       />
 
   <browser:menuItem
-      menu="zmi_views"
-      for="zope.app.interfaces.content.sql.ISQLScript"
-      title="Cache"
-      action="Caching.html"
-      />
-
-  <browser:menuItem
       menu="add_content"
       for="zope.app.interfaces.container.IAdding"
       title="SQLScript"
@@ -440,6 +416,14 @@
       permission="zope.ManageServices"
       class="zope.app.browser.content.fssync.SnarfCommit"
       attribute="commit"
+      />
+
+  <browser:page
+      for="zope.interface.Interface"
+      name="checkin.snarf"
+      permission="zope.ManageServices"
+      class="zope.app.browser.content.fssync.SnarfCommit"
+      attribute="checkin"
       />
 
 </zopeConfigure>


=== Zope3/src/zope/app/browser/content/file.py 1.2 => 1.2.28.1 ===
--- Zope3/src/zope/app/browser/content/file.py:1.2	Wed Dec 25 09:12:30 2002
+++ Zope3/src/zope/app/browser/content/file.py	Sun Jun 22 10:22:38 2003
@@ -46,7 +46,7 @@
     """File editing mix-in that uses a file-upload widget.
     """
 
-    data = CustomWidget(FileWidget)
+    data_widget = CustomWidget(FileWidget)
 
 
 


=== Zope3/src/zope/app/browser/content/folder.py 1.2 => 1.2.28.1 ===
--- Zope3/src/zope/app/browser/content/folder.py:1.2	Wed Dec 25 09:12:30 2002
+++ Zope3/src/zope/app/browser/content/folder.py	Sun Jun 22 10:22:38 2003
@@ -15,10 +15,10 @@
 
 $Id$
 """
-
+from zope.interface import implements
 from zope.app.browser.container.adding import Adding
 from zope.app.interfaces.content.folder import IFolderAdding
 
 class FolderAdding(Adding):
 
-    __implements__ = IFolderAdding
+    implements(IFolderAdding)


=== Zope3/src/zope/app/browser/content/fssync.py 1.12 => 1.12.2.1 ===
--- Zope3/src/zope/app/browser/content/fssync.py:1.12	Tue May 20 15:09:54 2003
+++ Zope3/src/zope/app/browser/content/fssync.py	Sun Jun 22 10:22:38 2003
@@ -18,18 +18,27 @@
 """
 
 import os
+import cgi
 import shutil
 import tempfile
 
 from transaction import get_transaction
 
-from zope.fssync.compare import checkUptodate
-
 from zope.publisher.browser import BrowserView
-from zope.app.fssync.syncer import toFS, fromFS
-from zope.app.traversing import objectName, getParent, getRoot
+from zope.app.traversing import getName, getParent, getRoot
 from zope.app.interfaces.exceptions import UserError
 from zope.fssync.snarf import Snarfer, Unsnarfer
+from zope.app.fssync.syncer import toFS
+from zope.app.fssync.committer import Committer, Checker
+from zope.fssync.metadata import Metadata
+
+def snarf_dir(response, dirname):
+    """Helper to snarf a directory to the response."""
+    response.setStatus(200)
+    response.setHeader("Content-Type", "application/x-snarf")
+    snf = Snarfer(response)
+    snf.addtree(dirname)
+    return ""
 
 class SnarfFile(BrowserView):
 
@@ -40,85 +49,174 @@
 
     def show(self):
         """Return the snarfed response."""
-        response = self.request.response
-        response.setStatus(200)
-        response.setHeader("Content-Type", "application/x-snarf")
         dirname = tempfile.mktemp()
         try:
             os.mkdir(dirname)
-            toFS(self.context, objectName(self.context) or "root", dirname)
-            snf = Snarfer(response)
-            snf.addtree(dirname)
+            toFS(self.context, getName(self.context) or "root", dirname)
+            return snarf_dir(self.request.response, dirname)
         finally:
             if os.path.isdir(dirname):
                 shutil.rmtree(dirname)
-        return ""
 
-# And here is the inverse operation, fromFS.snarf.
+class NewMetadata(Metadata):
+    """Subclass of Metadata that sets the 'added' flag in all entries."""
 
-class SnarfCommit(SnarfFile):
+    def getentry(self, file):
+        entry = Metadata.getentry(self, file)
+        if entry:
+            entry["flag"] = "added"
+        return entry
+
+class SnarfCommit(BrowserView):
+
+    """View for committing and checking in changes.
+
+    The input to commit() should be a POST request whose data is a
+    snarf archive.  It returns an updated snarf archive, or a text
+    document with errors.
+
+    The alternate entry point checkin() is for checking in a new
+    archive.  It is similar to commit() but creates a brand new tree
+    and doesn't return anything.
+    """
 
-    """View for committing changes."""
+    # XXX Maybe split into two classes with a common base instead?
 
     def commit(self):
+        self.check_content_type()
+        self.set_transaction()
+        self.parse_args()
+        self.set_note()
+        try:
+            self.make_tempdir()
+            self.set_commit_arguments()
+            self.make_commit_metadata()
+            self.unsnarf_body()
+            self.call_checker()
+            if self.errors:
+                return self.send_errors()
+            else:
+                self.call_committer()
+                self.write_to_filesystem()
+                return self.send_archive()
+        finally:
+            self.remove_tempdir()
+
+    def checkin(self):
+        self.check_content_type()
+        self.set_transaction()
+        self.parse_args()
+        self.set_note()
+        try:
+            self.make_tempdir()
+            self.set_checkin_arguments()
+            self.make_checkin_metadata()
+            self.unsnarf_body()
+            self.call_committer()
+            return ""
+        finally:
+            self.remove_tempdir()
+
+    def check_content_type(self):
         if not self.request.getHeader("Content-Type") == "application/x-snarf":
-            self.request.response.setHeader("Content-Type", "text/plain")
-            return "ERROR: Content-Type is not application/x-snarf\n"
-        istr = self.request.bodyFile
-        istr.seek(0)
-        errors = self.do_commit(istr)
-        if not errors:
-            return self.show() # Return the snarfed tree!
+            raise ValueError("Content-Type is not application/x-snarf")
+
+    def set_transaction(self):
+        self.txn = get_transaction()
+
+    def parse_args(self):
+        # The query string in the URL didn't get parsed, because we're
+        # getting a POST request with an unrecognized content-type
+        qs = self.request._environ.get("QUERY_STRING")
+        if qs:
+            self.args = cgi.parse_qs(qs)
         else:
-            self.request.response.setHeader("Content-Type", "text/plain")
-            errors.insert(0, "Up-to-date check failed:")
-            errors.append("")
-            return "\n".join(errors)
-
-    def do_commit(self, istr):
-        # 000) Set transaction note
-        note = self.request.get("note")
-        if not note:
-            # XXX Hack because cgi doesn't parse the query string
-            qs = self.request._environ.get("QUERY_STRING")
-            if qs and qs.startswith("note="):
-                note = qs[5:]
-                import urllib
-                note = urllib.unquote(note)
+            self.args = {}
+
+    def get_arg(self, key):
+        value = self.request.get(key)
+        if value is None:
+            values = self.args.get(key)
+            if values is not None:
+                value = " ".join(values)
+        return value
+
+    def set_note(self):
+        note = self.get_arg("note")
         if note:
-            get_transaction().note(note)
-        # 0) Allocate temporary names
-        topdir = tempfile.mktemp()
-        working = os.path.join(topdir, "working")
-        current = os.path.join(topdir, "current")
-        try:
-            # 1) Create the top directory
-            os.mkdir(topdir)
-            # 2) Unsnarf into a working directory
-            os.mkdir(working)
-            uns = Unsnarfer(istr)
-            uns.unsnarf(working)
-            # 3) Save the current state of the object to disk
-            os.mkdir(current)
-            toFS(self.context, objectName(self.context) or "root", current)
-            # 4) Check that the working originals are up-to-date
-            errors = checkUptodate(working, current)
-            if errors:
-                # Make the messages nicer by editing out topdir
-                errors = [x.replace(os.path.join(topdir, ""), "")
-                          for x in errors]
-                return errors
-            # 5) Now call fromFS()
-            name = objectName(self.context)
-            container = getParent(self.context)
-            if container is None and name == "":
-                # Hack to get loading the root to work; see top of fromFS().
-                container = getRoot(self.context)
-            fromFS(container, name, working)
-            # 6) Return success
-            return []
-        finally:
-            try:
-                shutil.rmtree(topdir)
-            except os.error:
-                pass
+            self.txn.note(note)
+
+    def set_commit_arguments(self):
+        # Compute self.{name, container, fspath} for commit()
+        self.name = getName(self.context)
+        self.container = getParent(self.context)
+        if self.container is None and self.name == "":
+            # Hack to get loading the root to work
+            self.container = getRoot(self.context)
+            self.fspath = os.path.join(self.tempdir, "root")
+        else:
+            self.fspath = os.path.join(self.tempdir, self.name)
+
+    def set_checkin_arguments(self):
+        # Compute self.{name, container, fspath} for checkin()
+        name = self.get_arg("name")
+        if not name:
+            raise ValueError("required argument 'name' missing")
+        src = self.get_arg("src")
+        if not src:
+            src = name
+        self.container = self.context
+        self.name = name
+        self.fspath = os.path.join(self.tempdir, src)
+
+    def make_commit_metadata(self):
+        self.metadata = Metadata()
+
+    def make_checkin_metadata(self):
+        self.metadata = NewMetadata()
+
+    tempdir = None
+
+    def make_tempdir(self):
+        self.tempdir = tempfile.mktemp()
+        os.mkdir(self.tempdir)
+
+    def remove_tempdir(self):
+        if self.tempdir and os.path.exists(self.tempdir):
+            shutil.rmtree(self.tempdir)
+
+    def unsnarf_body(self):
+        fp = self.request.bodyFile
+        fp.seek(0)
+        uns = Unsnarfer(fp)
+        uns.unsnarf(self.tempdir)
+
+    def call_checker(self):
+        if self.get_arg("raise"):
+            c = Checker(self.metadata, True)
+        else:
+            c = Checker(self.metadata)
+        c.check(self.container, self.name, self.fspath)
+        self.errors = c.errors()
+
+    def send_errors(self):
+        self.txn.abort()
+        lines = ["Up-to-date check failed:"]
+        tempdir_sep = os.path.join(self.tempdir, "") # E.g. foo -> foo/
+        for e in self.errors:
+            lines.append(e.replace(tempdir_sep, ""))
+        lines.append("")
+        self.request.response.setHeader("Content-Type", "text/plain")
+        return "\n".join(lines)
+
+    def call_committer(self):
+        c = Committer(self.metadata)
+        c.synch(self.container, self.name, self.fspath)
+
+    def write_to_filesystem(self):
+        shutil.rmtree(self.tempdir) # Start with clean slate
+        os.mkdir(self.tempdir)
+        toFS(self.context, getName(self.context) or "root", self.tempdir)
+
+    def send_archive(self):
+        return snarf_dir(self.request.response, self.tempdir)


=== Zope3/src/zope/app/browser/content/i18n.py 1.2 => 1.2.28.1 ===
--- Zope3/src/zope/app/browser/content/i18n.py:1.2	Wed Dec 25 09:12:30 2002
+++ Zope3/src/zope/app/browser/content/i18n.py	Sun Jun 22 10:22:38 2003
@@ -41,8 +41,6 @@
 
 class I18nFileEdit(BrowserView):
 
-    __implements__ = BrowserView.__implements__
-
     name = 'editForm'
     title = 'Edit Form'
     description = ('This edit form allows you to make changes to the ' +


=== Zope3/src/zope/app/browser/content/i18nimage.py 1.3 => 1.3.12.1 ===
--- Zope3/src/zope/app/browser/content/i18nimage.py:1.3	Wed Apr 30 19:37:51 2003
+++ Zope3/src/zope/app/browser/content/i18nimage.py	Sun Jun 22 10:22:38 2003
@@ -25,8 +25,6 @@
 
 class I18nImageEdit(BrowserView):
 
-    __implements__ = BrowserView.__implements__
-
     name = 'editForm'
     title = 'Edit Form'
     description = ('This edit form allows you to make changes to the ' +


=== Zope3/src/zope/app/browser/content/sql.py 1.5 => 1.5.24.1 ===
--- Zope3/src/zope/app/browser/content/sql.py:1.5	Thu Feb 20 11:46:04 2003
+++ Zope3/src/zope/app/browser/content/sql.py	Sun Jun 22 10:22:38 2003
@@ -17,21 +17,11 @@
 from zope.publisher.browser import BrowserView
 from zope.app.interfaces.content.sql import ISQLScript
 from zope.app.interfaces.rdb import DatabaseException
-from zope.proxy.context import ContextMethod
+from zope.context import ContextMethod
 
 class SQLScriptTest(BrowserView):
     """Edit View for SQL Scripts"""
 
-    # XXX: if the following line is uncommented, @@test.html stops working
-    # __implements__ = BrowserView.__implements__
-    #
-    # Just found the reason: if you specify __implements__ here, it overrides
-    # the one defined in zope.app.pagetemplate.simpeviewclass.simple,
-    # and IBrowserPublisher disappears from the interface list.  Instead,
-    # __implements__ of the newly created class (see SimpleViewClass in the
-    # same module) ought to be a union of __implements__ of all the base
-    # classes.  Or perhaps it should be done by zope.app.browser.form.editview?
-
     __used_for__ = ISQLScript
 
     error = None
@@ -39,20 +29,19 @@
     def getArguments(self):
         form = self.request.form
         arguments = {}
-        # XXX does anyone know what arg[0] and arg[1] are supposed to be?
-        for arg in self.context.getArguments().items():
-            value = form.get(arg[0])
+
+        for argname, argvalue in self.context.getArguments().items():
+            value = form.get(argname)
             if value is None:
-                value = arg[1].get('default')
+                value = argvalue.get('default')
             if value is not None:
-                arguments[arg[0].encode('UTF-8')] = value
+                arguments[argname.encode('UTF-8')] = value
         return arguments
 
     def getTestResults(self):
-        self.context.getConnection()
         try:
             return self.context(**self.getArguments())
-        except (DatabaseException, AttributeError), error:
+        except (DatabaseException, AttributeError, Exception), error:
             self.error = error
             return []
 


=== Zope3/src/zope/app/browser/content/sqltest.pt 1.2 => 1.2.28.1 ===
--- Zope3/src/zope/app/browser/content/sqltest.pt:1.2	Wed Dec 25 09:12:30 2002
+++ Zope3/src/zope/app/browser/content/sqltest.pt	Sun Jun 22 10:22:38 2003
@@ -7,7 +7,7 @@
   <div metal:fill-slot="body">
   <form action="." method="post">
 
-    <pre tal:content="context/getSource" />
+    <pre tal:content="context/source" />
 
     <table border="1"
         tal:define="args context/getArguments"