Improvements in the WebDAV client. Transmission of binary files seems to have bugs.
This commit is contained in:
parent
990e16c6e7
commit
3cfc24fe02
|
@ -1,11 +1,13 @@
|
|||
# ------------------------------------------------------------------------------
|
||||
import os, re, httplib, sys
|
||||
import os, re, httplib, sys, stat
|
||||
from StringIO import StringIO
|
||||
from mimetypes import guess_type
|
||||
from base64 import encodestring
|
||||
from appy.shared.utils import copyData
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
urlRex = re.compile(r'http://([^:/]+)(:[0-9]+)?(/.+)?', re.I)
|
||||
binaryRex = re.compile(r'[\000-\006\177-\277]')
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
class Resource:
|
||||
|
@ -26,6 +28,11 @@ class Resource:
|
|||
self.uri = uri or '/'
|
||||
else: raise 'Wrong URL: %s' % str(url)
|
||||
|
||||
def __repr__(self):
|
||||
port = ':' + str(self.port)
|
||||
if self.port == 80: port = ''
|
||||
return '<Dav resource at %s%s/%s>' % (self.url, port, self.uri)
|
||||
|
||||
def updateHeaders(self, headers):
|
||||
# Add credentials if present
|
||||
if not (self.username and self.password): return
|
||||
|
@ -39,7 +46,7 @@ class Resource:
|
|||
headers['Accept'] = '*/*'
|
||||
return headers
|
||||
|
||||
def sendRequest(self, method, uri, body=None, headers={}):
|
||||
def sendRequest(self, method, uri, body=None, headers={}, bodyType=None):
|
||||
'''Sends a HTTP request with p_method, for p_uri.'''
|
||||
conn = httplib.HTTP()
|
||||
conn.connect(self.host, self.port)
|
||||
|
@ -48,7 +55,7 @@ class Resource:
|
|||
self.updateHeaders(headers)
|
||||
for n, v in headers.items(): conn.putheader(n, v)
|
||||
conn.endheaders()
|
||||
if body: conn.send(body)
|
||||
if body: copyData(body, conn, 'send', type=bodyType)
|
||||
ver, code, msg = conn.getreply()
|
||||
data = conn.getfile().read()
|
||||
conn.close()
|
||||
|
@ -78,30 +85,24 @@ class Resource:
|
|||
'''
|
||||
if type == 'fileName':
|
||||
# p_content is the name of a file on disk
|
||||
f = file(content, 'rb')
|
||||
body = f.read()
|
||||
f.close()
|
||||
fileName = os.path.basename(content)
|
||||
fileType, encoding = guess_type(fileName)
|
||||
size = os.stat(content)[stat.ST_SIZE]
|
||||
body = file(content, 'rb')
|
||||
name = os.path.basename(content)
|
||||
fileType, encoding = guess_type(content)
|
||||
bodyType = 'file'
|
||||
elif type == 'zope':
|
||||
# p_content is a "Zope" file, ie a OFS.Image.File instance
|
||||
fileName = name
|
||||
# p_name is given
|
||||
fileType = content.content_type
|
||||
encoding = None
|
||||
if isinstance(content.data, basestring):
|
||||
# The file content is here, in one piece
|
||||
body = content.data
|
||||
else:
|
||||
# There are several parts to this file.
|
||||
body = ''
|
||||
data = content.data
|
||||
while data is not None:
|
||||
body += data.data
|
||||
data = data.next
|
||||
fileUri = self.uri + '/' + fileName
|
||||
headers = {}
|
||||
size = content.size
|
||||
body = content
|
||||
bodyType = 'zope'
|
||||
fileUri = self.uri + '/' + name
|
||||
headers = {'Content-Length': str(size)}
|
||||
if fileType: headers['Content-Type'] = fileType
|
||||
if encoding: headers['Content-Encoding'] = encoding
|
||||
headers['Content-Length'] = str(len(body))
|
||||
return self.sendRequest('PUT', fileUri, body, headers)
|
||||
res = self.sendRequest('PUT', fileUri, body, headers, bodyType=bodyType)
|
||||
# Close the file when relevant
|
||||
if type =='fileName': body.close()
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
|
@ -47,7 +47,7 @@ def cleanFolder(folder, exts=extsToClean, verbose=False):
|
|||
if verbose: print 'Removing %s...' % fileToRemove
|
||||
os.remove(fileToRemove)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
def copyFolder(source, dest, cleanDest=False):
|
||||
'''Copies the content of folder p_source to folder p_dest. p_dest is
|
||||
created, with intermediary subfolders if required. If p_cleanDest is
|
||||
|
@ -70,6 +70,48 @@ def copyFolder(source, dest, cleanDest=False):
|
|||
# Copy a subfolder (recursively)
|
||||
copyFolder(sourceName, destName)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
def encodeData(data, encoding=None):
|
||||
'''Applies some p_encoding to string p_data, but only if an p_encoding is
|
||||
specified.'''
|
||||
if not encoding: return data
|
||||
return data.encode(encoding)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
def copyData(data, target, targetMethod, type='string', encoding=None,
|
||||
chunkSize=1024):
|
||||
'''Copies p_data to a p_target, using p_targetMethod. For example, it copies
|
||||
p_data which is a string containing the binary content of a file, to
|
||||
p_target, which can be a HTTP connection or a file object.
|
||||
|
||||
p_targetMethod can be "write" (files) or "send" (HTTP connections) or ...
|
||||
p_type can be "string", "file" or "zope". In the latter case it is an
|
||||
instance of OFS.Image.File. If p_type is "file", one may, in p_chunkSize,
|
||||
specify the amount of bytes transmitted at a time.
|
||||
|
||||
If an p_encoding is specified, it is applied on p_data before copying.
|
||||
|
||||
Note that if the p_target is a Python file, it must be opened in a way
|
||||
that is compatible with the content of p_data, ie file('myFile.doc','wb')
|
||||
if content is binary.'''
|
||||
dump = getattr(target, targetMethod)
|
||||
if type == 'string': dump(encodeData(data, encoding))
|
||||
elif type == 'file':
|
||||
while True:
|
||||
chunk = data.read(chunkSize)
|
||||
if not chunk: break
|
||||
dump(encodeData(chunk, encoding))
|
||||
elif type == 'zope':
|
||||
# A OFS.Image.File instance can be split into several chunks
|
||||
if isinstance(data.data, basestring): # One chunk
|
||||
dump(encodeData(data.data, encoding))
|
||||
else:
|
||||
# Several chunks
|
||||
data = data.data
|
||||
while data is not None:
|
||||
dump(encodeData(data.data, encoding))
|
||||
data = data.next
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
class Traceback:
|
||||
'''Dumps the last traceback into a string.'''
|
||||
|
@ -229,6 +271,7 @@ class CodeAnalysis:
|
|||
print '%s: %d files, %d lines (%.0f%% comments, %.0f%% blank)' % \
|
||||
(self.name, self.numberOfFiles, lines, commentRate, blankRate)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
class LinesCounter:
|
||||
'''Counts and classifies the lines of code within a folder hierarchy.'''
|
||||
def __init__(self, folderOrModule):
|
||||
|
|
Loading…
Reference in a new issue