changeset 2854:97c5fba1c6ae

merged main
author Reimar Bauer <rb.proj AT googlemail DOT com>
date Thu, 20 Sep 2007 20:57:29 +0200
parents 40e50e27ee50 (current diff) 4825f1a252dc (diff)
children f003d451be90 e1ce3040fcd6
files
diffstat 7 files changed, 63 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Thu Sep 20 20:56:41 2007 +0200
+++ b/.hgignore	Thu Sep 20 20:57:29 2007 +0200
@@ -1,4 +1,5 @@
 .*\.py[co]
+.coverage
 tests/wiki
 wiki/underlay
 wiki/data/edit-log
--- a/MoinMoin/Page.py	Thu Sep 20 20:56:41 2007 +0200
+++ b/MoinMoin/Page.py	Thu Sep 20 20:57:29 2007 +0200
@@ -977,9 +977,11 @@
             text = self.encodeTextMimeType(self.body)
             request.setHttpHeader("Content-Length: %d" % len(text))
             if content_disposition:
-                file_name = "%s.txt" % self.page_name
+                # TODO: fix the encoding here, plain 8 bit is not allowed according to the RFCs
+                # There is no solution that is compatible to IE except stripping non-ascii chars
+                filename_enc = "%s.txt" % self.page_name.encode(config.charset)
                 request.setHttpHeader('Content-Disposition: %s; filename="%s"' % (
-                                      content_disposition, file_name))
+                                      content_disposition, filename_enc))
         else:
             request.setHttpHeader('Status: 404 NOTFOUND')
             text = u"Page %s not found." % self.page_name
--- a/MoinMoin/PageEditor.py	Thu Sep 20 20:56:41 2007 +0200
+++ b/MoinMoin/PageEditor.py	Thu Sep 20 20:57:29 2007 +0200
@@ -896,6 +896,7 @@
         revdir = os.path.join(pagedir, 'revisions')
         cfn = os.path.join(pagedir, 'current')
         clfn = os.path.join(pagedir, 'current-locked')
+        cltfn = os.path.join(pagedir, 'current-locked.tmp')
 
         # !!! these log objects MUST be created outside the locked area !!!
 
@@ -938,14 +939,33 @@
             f = file(clfn)
             revstr = f.read()
             f.close()
-            rev = int(revstr)
+            try:
+                rev = int(revstr)
+            except ValueError, err:
+                raise self.SaveError, _("Unable to determine current page revision from the 'current' file. The page %s is damaged and cannot be edited right now.") % self.page_name
+
             if not was_deprecated:
                 if self.do_revision_backup or rev == 0:
                     rev += 1
             revstr = '%08d' % rev
-            f = file(clfn, 'w')
-            f.write(revstr+'\n')
-            f.close()
+            # write the current page rev to a temporary file
+            try:
+                f = file(cltfn, 'w')
+                f.write(revstr+'\n')
+                f.close()
+            except IOError, err:
+                try:
+                    os.remove(cltfn)
+                except:
+                    pass # we don't care for errors in the os.remove
+                # throw a nicer exception
+                if err.errno == errno.ENOSPC:
+                    raise self.SaveError, _("Cannot save page %s, no storage space left.") % self.page_name
+                else:
+                    raise self.SaveError, _("An I/O error occurred while saving page %s (errno=%d)") % (self.page_name, err.errno)
+            # atomically put it in place (except on windows)
+            else:
+                filesys.rename(cltfn, clfn)
 
             if not deleted:
                 # save to page file
--- a/MoinMoin/action/AttachFile.py	Thu Sep 20 20:56:41 2007 +0200
+++ b/MoinMoin/action/AttachFile.py	Thu Sep 20 20:57:29 2007 +0200
@@ -26,7 +26,7 @@
     @license: GNU GPL, see COPYING for details.
 """
 
-import os, time, zipfile, mimetypes
+import os, time, zipfile, mimetypes, errno
 
 from MoinMoin import config, wikiutil, packages
 from MoinMoin.Page import Page
@@ -717,7 +717,11 @@
     savepath = os.path.join(attach_dir, basename + ext)
     if ext == '.map' and not filecontent.strip():
         # delete map file if it is empty
-        os.unlink(savepath)
+        try:
+            os.unlink(savepath)
+        except OSError, err:
+            if err.errno != errno.ENOENT: # no such file
+                raise
     else:
         stream = open(savepath, 'wb')
         try:
--- a/MoinMoin/action/__init__.py	Thu Sep 20 20:56:41 2007 +0200
+++ b/MoinMoin/action/__init__.py	Thu Sep 20 20:57:29 2007 +0200
@@ -140,10 +140,12 @@
 
         form_html = '''
 %(error_html)s
-<form method="post" action="" method="%(method)s" enctype="%(enctype)s">
+<form action="" method="%(method)s" enctype="%(enctype)s">
+<div>
 <input type="hidden" name="action" value="%(actionname)s">
 %(ticket_html)s
 %(user_html)s
+</div>
 </form>''' % d
 
         return Dialog(self.request, content=form_html)
--- a/MoinMoin/caching.py	Thu Sep 20 20:56:41 2007 +0200
+++ b/MoinMoin/caching.py	Thu Sep 20 20:57:29 2007 +0200
@@ -145,7 +145,7 @@
                         self.wlock.release()
             else:
                 self.request.log("Can't acquire write lock in %s" % self.lock_dir)
-        except (pickle.PicklingError, IOError, ValueError), err:
+        except (pickle.PicklingError, OSError, IOError, ValueError), err:
             raise CacheError(str(err))
 
     def remove(self):
--- a/MoinMoin/request/__init__.py	Thu Sep 20 20:56:41 2007 +0200
+++ b/MoinMoin/request/__init__.py	Thu Sep 20 20:57:29 2007 +0200
@@ -1307,36 +1307,40 @@
         #else:
         #    self.log("Notice: emit_http_headers called first time. Headers: %r" % all_headers)
 
-        content_type = None
-        status = None
-        headers = []
-        # assemble complete list of http headers
+        # assemble dict of http headers
+        headers = {}
         for header in all_headers:
             if isinstance(header, unicode):
                 header = header.encode('ascii')
             key, value = header.split(':', 1)
             lkey = key.lower()
             value = value.lstrip()
-            if content_type is None and lkey == "content-type":
-                content_type = value
-            elif status is None and lkey == "status":
-                status = value
+            if lkey in headers:
+                self.log("Duplicate http header: %r (ignored)" % header)
             else:
-                headers.append(header)
+                headers[lkey] = (key, value)
 
-        if content_type is None:
-            content_type = "text/html; charset=%s" % config.charset
-        ct_header = "Content-type: %s" % content_type
+        if 'content-type' not in headers:
+            headers['content-type'] = ('Content-type', 'text/html; charset=%s' % config.charset)
 
-        if status is None:
-            status = "200 OK"
-        try:
-            int(status.split(" ", 1)[0])
-        except:
-            self.log("emit_http_headers called with invalid header Status: %s" % status)
-            status = "500 Server Error - invalid status header"
-        st_header = "Status: %s" % status
+        if 'status' not in headers:
+            headers['status'] = ('Status', '200 OK')
+        else:
+            # check if we got a valid status
+            try:
+                status = headers['status'][1]
+                int(status.split(' ', 1)[0])
+            except:
+                self.log("emit_http_headers called with invalid header Status: %r" % status)
+                headers['status'] = ('Status', '500 Server Error - invalid status header')
 
+        header_format = '%s: %s'
+        st_header = header_format % headers['status']
+        del headers['status']
+        ct_header = header_format % headers['content-type']
+        del headers['content-type']
+
+        headers = [header_format % kv_tuple for kv_tuple in headers.values()] # make a list of strings
         headers = [st_header, ct_header] + headers # do NOT change order!
         self._emit_http_headers(headers)