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 StringIO import StringIO
|
||||||
from mimetypes import guess_type
|
from mimetypes import guess_type
|
||||||
from base64 import encodestring
|
from base64 import encodestring
|
||||||
|
from appy.shared.utils import copyData
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
urlRex = re.compile(r'http://([^:/]+)(:[0-9]+)?(/.+)?', re.I)
|
urlRex = re.compile(r'http://([^:/]+)(:[0-9]+)?(/.+)?', re.I)
|
||||||
|
binaryRex = re.compile(r'[\000-\006\177-\277]')
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
class Resource:
|
class Resource:
|
||||||
|
@ -26,6 +28,11 @@ class Resource:
|
||||||
self.uri = uri or '/'
|
self.uri = uri or '/'
|
||||||
else: raise 'Wrong URL: %s' % str(url)
|
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):
|
def updateHeaders(self, headers):
|
||||||
# Add credentials if present
|
# Add credentials if present
|
||||||
if not (self.username and self.password): return
|
if not (self.username and self.password): return
|
||||||
|
@ -39,7 +46,7 @@ class Resource:
|
||||||
headers['Accept'] = '*/*'
|
headers['Accept'] = '*/*'
|
||||||
return headers
|
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.'''
|
'''Sends a HTTP request with p_method, for p_uri.'''
|
||||||
conn = httplib.HTTP()
|
conn = httplib.HTTP()
|
||||||
conn.connect(self.host, self.port)
|
conn.connect(self.host, self.port)
|
||||||
|
@ -48,7 +55,7 @@ class Resource:
|
||||||
self.updateHeaders(headers)
|
self.updateHeaders(headers)
|
||||||
for n, v in headers.items(): conn.putheader(n, v)
|
for n, v in headers.items(): conn.putheader(n, v)
|
||||||
conn.endheaders()
|
conn.endheaders()
|
||||||
if body: conn.send(body)
|
if body: copyData(body, conn, 'send', type=bodyType)
|
||||||
ver, code, msg = conn.getreply()
|
ver, code, msg = conn.getreply()
|
||||||
data = conn.getfile().read()
|
data = conn.getfile().read()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
@ -78,30 +85,24 @@ class Resource:
|
||||||
'''
|
'''
|
||||||
if type == 'fileName':
|
if type == 'fileName':
|
||||||
# p_content is the name of a file on disk
|
# p_content is the name of a file on disk
|
||||||
f = file(content, 'rb')
|
size = os.stat(content)[stat.ST_SIZE]
|
||||||
body = f.read()
|
body = file(content, 'rb')
|
||||||
f.close()
|
name = os.path.basename(content)
|
||||||
fileName = os.path.basename(content)
|
fileType, encoding = guess_type(content)
|
||||||
fileType, encoding = guess_type(fileName)
|
bodyType = 'file'
|
||||||
elif type == 'zope':
|
elif type == 'zope':
|
||||||
# p_content is a "Zope" file, ie a OFS.Image.File instance
|
# p_content is a "Zope" file, ie a OFS.Image.File instance
|
||||||
fileName = name
|
# p_name is given
|
||||||
fileType = content.content_type
|
fileType = content.content_type
|
||||||
encoding = None
|
encoding = None
|
||||||
if isinstance(content.data, basestring):
|
size = content.size
|
||||||
# The file content is here, in one piece
|
body = content
|
||||||
body = content.data
|
bodyType = 'zope'
|
||||||
else:
|
fileUri = self.uri + '/' + name
|
||||||
# There are several parts to this file.
|
headers = {'Content-Length': str(size)}
|
||||||
body = ''
|
|
||||||
data = content.data
|
|
||||||
while data is not None:
|
|
||||||
body += data.data
|
|
||||||
data = data.next
|
|
||||||
fileUri = self.uri + '/' + fileName
|
|
||||||
headers = {}
|
|
||||||
if fileType: headers['Content-Type'] = fileType
|
if fileType: headers['Content-Type'] = fileType
|
||||||
if encoding: headers['Content-Encoding'] = encoding
|
if encoding: headers['Content-Encoding'] = encoding
|
||||||
headers['Content-Length'] = str(len(body))
|
res = self.sendRequest('PUT', fileUri, body, headers, bodyType=bodyType)
|
||||||
return self.sendRequest('PUT', fileUri, body, headers)
|
# 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
|
if verbose: print 'Removing %s...' % fileToRemove
|
||||||
os.remove(fileToRemove)
|
os.remove(fileToRemove)
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
def copyFolder(source, dest, cleanDest=False):
|
def copyFolder(source, dest, cleanDest=False):
|
||||||
'''Copies the content of folder p_source to folder p_dest. p_dest is
|
'''Copies the content of folder p_source to folder p_dest. p_dest is
|
||||||
created, with intermediary subfolders if required. If p_cleanDest 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)
|
# Copy a subfolder (recursively)
|
||||||
copyFolder(sourceName, destName)
|
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:
|
class Traceback:
|
||||||
'''Dumps the last traceback into a string.'''
|
'''Dumps the last traceback into a string.'''
|
||||||
|
@ -229,6 +271,7 @@ class CodeAnalysis:
|
||||||
print '%s: %d files, %d lines (%.0f%% comments, %.0f%% blank)' % \
|
print '%s: %d files, %d lines (%.0f%% comments, %.0f%% blank)' % \
|
||||||
(self.name, self.numberOfFiles, lines, commentRate, blankRate)
|
(self.name, self.numberOfFiles, lines, commentRate, blankRate)
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
class LinesCounter:
|
class LinesCounter:
|
||||||
'''Counts and classifies the lines of code within a folder hierarchy.'''
|
'''Counts and classifies the lines of code within a folder hierarchy.'''
|
||||||
def __init__(self, folderOrModule):
|
def __init__(self, folderOrModule):
|
||||||
|
|
Loading…
Reference in a new issue