1
# -*- coding: UTF-8 -*-
8
from popen2 import Popen3
9
from IStorageWrapper import IStorageWrapper
11
## Wraps rdiff-backup application.
13
# @author Salvador de la Puente González
14
# @contact neo.salvador@gmail.com
15
class RdiffBackupWrapper(IStorageWrapper):
16
## rdiff-backup command
18
__rdiffCommand = "rdiff-backup"
20
## rdiff-backup command prototype to check backup directory
22
__cmdCheckBackupDirectory = __rdiffCommand + " --check-destination-dir \"$snapshotPath$\""
24
## rdiff-backup command prototype to setup backup directory
26
__cmdSetupBackupDirectory = __rdiffCommand + " --create-full-path --exclude-regexp '.' / \"$snapshotPath$\""
28
## rdiff-backup command prototype to backup a new file or directory
30
__cmdBackupNewPath = __rdiffCommand + " $pathsIncluded$ --exclude-regexp '.' / \"$snapshotPath$\""
32
## rdiff-backup command prototype to recover a snapshot
34
__cmdRecoverAtTime = __rdiffCommand + " -r '$time$' --force \"$snapshotPath$\" \"$targetPath$\""
36
## rdiff-backup command prototype to recover a given path at given time to given target path
38
__cmdRecoverPathAtTime = __rdiffCommand + " -r '$time$' --force --include \"$sourcePath$\" --exclude-regexp '.' \"$snapshotPath$\" \"$targetPath$\""
40
## rdiff-backup command prototype to list all snapshots performed
42
__cmdListSnapshots = __rdiffCommand + " -l \"$snapshotPath$\""
44
## rdiff-backup command prototype to list content from a directory at given time
46
__cmdListAtTime = __rdiffCommand + " --list-at-time '$time$' \"$snapshotPath$$dirPath$\""
48
## rdiff-backup command prototype to list content from a directory at given time
49
# TODO: falta este, va a dar problemas porque es una opción inexistente en rdiff-backup
51
## Default constructor setups object properly
54
# FIXME: preguntar a config manager
55
snapshotDirectory = os.path.normpath(os.getenv("HOME") + "/.hdlorean/snapshots")
56
self._IStorageWrapper__snapshotsDirectory = snapshotDirectory
58
# Setup cmd private attributes
59
self.__cmdCheckBackupDirectory = string.replace(self.__cmdCheckBackupDirectory, "$snapshotPath$", snapshotDirectory)
60
self.__cmdSetupBackupDirectory = string.replace(self.__cmdSetupBackupDirectory, "$snapshotPath$", snapshotDirectory)
61
self.__cmdBackupNewPath = string.replace(self.__cmdBackupNewPath, "$snapshotPath$", snapshotDirectory)
62
self.__cmdRecoverAtTime = string.replace(self.__cmdRecoverAtTime, "$snapshotPath$", snapshotDirectory)
63
self.__cmdRecoverPathAtTime = string.replace(self.__cmdRecoverPathAtTime, "$snapshotPath$", snapshotDirectory)
64
self.__cmdListAtTime = string.replace(self.__cmdListAtTime, "$snapshotPath$", snapshotDirectory)
65
self.__cmdListSnapshots = string.replace(self.__cmdListSnapshots, "$snapshotPath$", snapshotDirectory)
67
# FIXME: Mejorar el sistema de comprobación, quizá pedir externamente
68
command = self.__cmdCheckBackupDirectory
69
print >> sys.stderr, "EXEC>" + command
70
result = Popen3(command)
71
status = result.wait()
74
command = self.__cmdSetupBackupDirectory
75
print >> sys.stderr, "EXEC>" + command
76
result = Popen3(command)
77
status = result.wait()
79
# TODO: Añadir control de errores
80
print >> sys.stderr, "Backup directory was created succesfully"
82
print >> sys.stderr, "Backup directory already exists"
84
# REMEMBER: rdiff-backup tiene una resolución máxima de segundos
88
## Backups a set of files
90
# @param setFileSet a set with absolute paths to files to be backupped
91
def backupSet(self, setFileSet):
93
for filePath in setFileSet:
94
pathsIncluded = pathsIncluded + " --include \"" + filePath + "\""
96
command = string.replace(self.__cmdBackupNewPath, "$pathsIncluded$", pathsIncluded)
97
print >> sys.stderr, "EXEC>" + command
98
result = Popen3(command)
99
status = result.wait()
101
# TODO: Añadir control de errores y devolver el log
103
# REMEMBER: rdiff-backup tiene una resolución máxima de segundos
107
## Recovers a snapshot at given time to a given target directory
109
# @param strTime time of the backup to be recovered
110
# @param strTargetPath target directory to copy recovered snapshot
111
def recoverSnapshotAtTime(self, strTime, strTargetPath):
112
# Make target path if it does not exist
113
if(not os.path.exists(strTargetPath)):
114
os.makedirs(strTargetPath)
116
command = string.replace(self.__cmdRecoverAtTime, "$time$", strTime)
117
command = string.replace(command, "$targetPath$", strTargetPath)
118
print >> sys.stderr, "EXEC>" + command
119
result = Popen3(command)
120
status = result.wait()
122
# TODO: Añadir control de errores y devolver el log
125
## Recovers a given path at given time to a given target directory
127
# @param strSourcePath path to recover
128
# @param strTime time of the snapshot to be recovered
129
# @param strTargetPath target directory to copy recovered snapshot
130
def recoverPathAtTime(self, strSourcePath, strTime, strTargetPath):
132
strTmpPath = "/tmp/hdlorean/"
134
if(not os.path.exists(strTmpPath)):
135
os.makedirs(strTmpPath)
137
# Make target path if it does not exist
138
if(not os.path.exists(strTargetPath)):
139
os.makedirs(strTargetPath)
141
# During restoration, rdiff-backup, overwrite permissions and automatically fix the type of the path. Its an util trick.
142
fixedSource = os.path.normpath(strTmpPath + "/" + strSourcePath)
143
if(not os.path.exists(fixedSource)):
144
os.makedirs(fixedSource)
146
command = string.replace(self.__cmdRecoverPathAtTime, "$sourcePath$", fixedSource)
147
command = string.replace(command, "$time$", strTime)
148
command = string.replace(command, "$targetPath$", strTmpPath)
149
print >> sys.stderr, "EXEC>" + command
150
result = Popen3(command)
151
status = result.wait()
153
# TODO: Añadir control de errores y devolver el log
155
# Move files to target path
156
shutil.move(fixedSource, strTargetPath)
159
shutil.rmtree(strTmpPath, True)
162
## Deletes an specified snapshot at given time
164
# @param strTime time of the snapshot to be deleted
165
def deleteAtTime(self, strTime):
166
# TODO: Diseñar el comando apañando convenientemente el contenido de la carpeta de backups de rdiff
167
raise "Not implemented yet"
169
## Gets a list of the content of the given directory at given time
171
# @param strDir directory path to list it content
172
# @param strTime specify when list operation is performed
173
# @param boolRecursive if true, then it returns the content of folder and its subfolders. Otherwise, just returns content of folder
174
# @return an array with the content of the folder and some important metadata
175
def getDirList(self, strDir, strTime, boolRecursive):
176
command = string.replace(self.__cmdListAtTime, "$time$", strTime)
177
command = string.replace(command, "$dirPath$", strDir)
178
print >> sys.stderr, "EXEC>" + command
179
result = Popen3(command)
180
status = result.wait()
181
content = result.fromchild.readlines()
184
# Filter content if recursive option is disabled
185
# TODO: Añadir metadata de interés como son los permisos, tamaño...
186
if not boolRecursive:
187
for filePath in content:
188
head, tail = os.path.split(filePath)
190
# REMEMBER: Cuando rdiff lista, no mete la barra inicial, hay que añadirla, para asegurarnos, comparamos después de normalizar
191
if os.path.normpath(head) == os.path.normpath(strDir):
192
filteredContent = filteredContent + [filePath]
194
filteredContent = content
197
# TODO: Añadir control de errores
199
return filteredContent
201
## Gets a list of all snapshot performed by now
203
# @return an array with all snapshots available
204
def getAllSnapshots(self):
205
command = self.__cmdListSnapshots
206
print >> sys.stderr, "EXEC>" + command
207
result = Popen3(command)
208
status = result.wait()
209
snapshots = result.fromchild.readlines()
210
# TODO: traducir a un mejor formato
212
# TODO: Añadir control de errores