This repository has been archived by the owner on Nov 15, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
WebdavMirror.py
106 lines (93 loc) · 4.22 KB
/
WebdavMirror.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
"""A simple Webdav mirror based on https://launchpad.net/python-webdav-lib
@author Markus Tacker <[email protected]>"""
from webdav import *
from webdav.WebdavClient import *
import logging
import os
from urllib import unquote
from time import mktime
import sys
class WebdavMirror(object):
def __init__(self, url, basedir, username = None, password = None, targetdir = './'):
"""Mirror the ressources found at url to the local targetdir.
basedir is the webdav folder name to start from.
If username and password are given they're used for authentication."""
if url[-1] == '/':
url = url[0:-1]
self._url = url
if basedir[-1] != '/':
basedir = basedir + '/'
if basedir[0] != '/':
basedir = '/' + basedir
self._basedir = basedir
self._username = username
self._password = password
if not os.path.isdir(targetdir):
raise Exception('Not a directory %s' % targetdir)
self._targetdir = os.path.realpath(targetdir) + os.sep
self.localFileList = []
self.listDir(self._targetdir)
self.fileList = []
self.mirrorContents()
self.cleanUp()
def mirrorContents(self, url = None):
"Recursive mirror the contents of the given url"
if url is None:
url = self._url + self._basedir
webdavConnection = CollectionStorer(url, validateResourceNames=False)
webdavConnection.connection.logger.setLevel(logging.WARN)
authFailures = 0
while authFailures < 2:
try:
for resource, properties in webdavConnection.getCollectionContents():
if properties.getResourceType() == 'collection':
newurl = self._url + str(properties.properties['displayname'])
if newurl == url:
# Recursion
continue
self.mirrorContents(newurl)
else:
target = self._targetdir + unquote(str(properties.properties['displayname'])).replace(self._basedir, '')
self.fileList.append(target)
mtime = mktime(properties.getLastModified())
if not os.path.isdir(os.path.dirname(target)):
os.makedirs(os.path.dirname(target))
if os.path.isfile(target):
stats = os.stat(target)
if stats.st_size == properties.getContentLength() and stats.st_mtime == mtime:
continue
resource.downloadFile(target)
os.utime(target, (mtime, mtime))
break # break out of the authorization failure counter
except AuthorizationError, e:
if e.authType == "Basic":
webdavConnection.connection.addBasicAuthorization(self._username, self._password)
elif e.authType == "Digest":
info = parseDigestAuthInfo(e.authInfo)
webdavConnection.connection.addDigestAuthorization(self._username, self._password, realm=info["realm"], qop=info["qop"], nonce=info["nonce"])
else:
raise
authFailures += 1
def listDir(self, dir):
"Create a recursive directory listing"
for _ in os.listdir(dir):
path = dir + _
if os.path.isdir(path):
self.listDir(path + os.sep)
else:
self.localFileList.append(path)
def cleanUp(self):
"Remove local files which are no longer in the repo"
for localFile in self.localFileList:
if not localFile in self.fileList:
sys.stdout.write("Deleting %s\n" % localFile)
os.remove(localFile)
if __name__ == "__main__":
import sys
webdavUrl = sys.argv[1]
basedir = sys.argv[2]
username = sys.argv[3]
password = sys.argv[4]
targetdir = sys.argv[5]
WebdavMirror(webdavUrl, basedir, username, password, targetdir)