~ubuntu-branches/ubuntu/precise/pybackpack/precise

« back to all changes in this revision

Viewing changes to src/pybackpack/rdiff_interface.py

  • Committer: Bazaar Package Importer
  • Author(s): Andy Price, Andy Price, Piotr Ożarowski, Marco Rodrigues
  • Date: 2007-12-23 15:07:21 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20071223150721-16ur0rbpnlppmbz3
Tags: 0.5.4-1
[ Andy Price ]
* New upstream release
* Update debian/docs - TODO file has been removed
* Depend on genisoimage which upstream now uses
* Remove debian/dirs - distutils creates usr/bin
* Fix section in debian/menu to follow menu guidelines

[ Piotr Ożarowski ]
* Homepage field added
* Rename XS-Vcs-* fields to Vcs-* (dpkg supports them now)

[ Marco Rodrigues ]
* Update Standards-Version to 3.7.3.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
import rdiff_backup.Main
2
 
import os
3
 
import sys
4
 
import shutil
5
 
import gtk
6
 
import gobject
7
 
import time
8
 
import subprocess
9
 
 
10
 
import version
11
 
from LogHandler import LogHandler
12
 
from ConfigParser import SafeConfigParser, NoOptionError
13
 
 
14
 
base = os.environ['HOME']
15
 
setspath = "%s/.%s/sets/" % (base, version.APPPATH)
16
 
 
17
 
class RdiffError(Exception):
18
 
        """Called when running rdiff-backup fails."""
19
 
        def __init__(self, status):
20
 
                self.status = status
21
 
 
22
 
        def __str__(self):
23
 
                return "rdiff-backup exit with status %d\n" % self.status
24
 
 
25
 
 
26
 
def Refresh():
27
 
        reload(rdiff_backup.Main)
28
 
 
29
 
def FindSets():
30
 
        """Finds all backup sets in the user's home directory"""
31
 
        global backupsets
32
 
        backupsets = []
33
 
        if os.path.exists(setspath):
34
 
                sets = [x for x in os.listdir(setspath) if os.path.isdir(setspath+x)]
35
 
                sets.sort()
36
 
                for set in sets:
37
 
                        setopts = {'path': set}
38
 
                        if not os.path.exists(os.path.join(setspath, set, "filelist")):
39
 
                                print _("No 'filelist' for %s") % set
40
 
                                continue
41
 
                        setopts['filelist_inc'] = []
42
 
                        setopts['filelist_exc'] = []
43
 
                        filelist = open(os.path.join(setspath, set, "filelist")).readlines()
44
 
                        for l in filelist:
45
 
                                if l[0] == "#":
46
 
                                        continue
47
 
                                elif l[0] == "-":
48
 
                                        setopts['filelist_exc'].append(l[2:].strip())
49
 
                                elif l[0] == "+":
50
 
                                        setopts['filelist_inc'].append(l[2:].strip())
51
 
                                else:
52
 
                                        continue
53
 
                        cp = SafeConfigParser()
54
 
                        if cp.read(setspath+set+"/set.ini") == []:
55
 
                                print _("Couldn't read in description file: %s") % setspath+set+"/set.ini"
56
 
                                continue
57
 
                        try:
58
 
                                setopts['name'] = cp.get('Set', 'name')
59
 
                                setopts['desc'] = cp.get('Set', 'desc')
60
 
                                for key, val in cp.items('Set'):
61
 
                                        setopts[key] = val
62
 
                                backupsets.append(setopts)
63
 
                        except NoOptionError, e:
64
 
                                print _("Couldn't parse %(filename)s fully: %(error)s") % {'filename':setspath+set+"/set.ini", 'error':e}
65
 
 
66
 
def CheckDestination(path, ignore_rdiff_data=True):
67
 
        """Checks if the path is writeable, and if it's got something in it"""
68
 
        if not os.access(path, os.R_OK|os.W_OK|os.X_OK):
69
 
                return (False, 'no_permission')
70
 
        if os.path.abspath(path) == os.path.abspath(os.environ['HOME']):
71
 
                return (False, 'is_home_dir')
72
 
        if len(os.listdir(path)) != 0:
73
 
                if os.listdir(path).count('rdiff-backup-data') == 1 and ignore_rdiff_data:
74
 
                        return (True, '')
75
 
                else:
76
 
                        return (False, 'not_empty')
77
 
        # OK to write to this path
78
 
        return (True, '')
79
 
 
80
 
def ParseRestoreSrc(path):
81
 
        if len(path) == 0:
82
 
                return None
83
 
        try:
84
 
                contents = os.listdir(path)
85
 
        except OSError, e:
86
 
                return None
87
 
        if contents == []:
88
 
                return None
89
 
        if contents.count('%s.set' % version.APPPATH) == 1:
90
 
                cp = SafeConfigParser()
91
 
                cp.read(os.path.join(path, '%s.set' % version.APPPATH))
92
 
                ret = {}
93
 
                for key, val in cp.items('Set'):
94
 
                        ret[key] = val
95
 
                ret['increments'] = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
96
 
                log = LogHandler()
97
 
                sys.stdout = log
98
 
                args = ['--list-increments', '--parsable-output', '--terminal-verbosity', '0', path.replace("rdiff-backup-data", "")]
99
 
                Refresh()
100
 
                try:
101
 
                        Run_rdiff(args)
102
 
                except OSError, e:
103
 
                        """rdiff-backup <= 1.1.9 has a bug where it can't restore from a read-only 
104
 
                           location unless it's run as root. Unfortunately there's not much we can
105
 
                           do until 1.2.0(?) becomes mainstream. We deal with that bug here."""
106
 
                        sys.stdout = sys.__stdout__
107
 
                        for f in os.listdir(path):
108
 
                                if f[:15] == "current_mirror." or f[:11] == "increments.":
109
 
                                        rawtime = f.replace("current_mirror.", "").replace("increments.", "").replace(".data", "")
110
 
                                        try:
111
 
                                                ret['increments'].insert_before(ret['increments'][0].iter, (rawtime, rawtime))
112
 
                                        except IndexError, e:
113
 
                                                ret['increments'].append((rawtime, rawtime))
114
 
                        ret['readonly'] = True
115
 
                        return ret
116
 
                sys.stdout = sys.__stdout__
117
 
                for inc in str(log).splitlines():
118
 
                        timestamp = inc.split()[0]
119
 
                        try:
120
 
                                ret['increments'].insert_before(ret['increments'][0].iter, (time.ctime(float(timestamp)), timestamp))
121
 
                        except IndexError, e:
122
 
                                ret['increments'].append((time.ctime(float(timestamp)), timestamp))
123
 
                return ret
124
 
        elif contents.count('rdiff-backup-data') == 1:
125
 
                return ParseRestoreSrc(os.path.join(path, 'rdiff-backup-data'))
126
 
        else:
127
 
                return None
128
 
        """don't really need to recurse all the way down the tree :)
129
 
        else:
130
 
                for d in [os.path.join(path, x) for x in contents if os.path.isdir(os.path.join(path, x))]:
131
 
                        ret = ParseRestoreSrc(d)
132
 
                        if ret == None:
133
 
                                continue
134
 
                        else:
135
 
                                return ret"""
136
 
        return None
137
 
 
138
 
def ParseRestoreSSHSrc(user, host, path):
139
 
        path = path.replace("/rdiff-backup-data", "")
140
 
        if len(path) == 0:
141
 
                return None
142
 
        args = ['scp',
143
 
                '%s@%s:%s/rdiff-backup-data/%s.set' % (user, host, path, version.APPPATH),
144
 
                '/tmp/%s.ssh.set' % version.APPPATH]
145
 
        scp = subprocess.Popen(args, shell=False)
146
 
        while scp.poll() is None:
147
 
                gtk.main_iteration()
148
 
        cp = SafeConfigParser()
149
 
        if cp.read('/tmp/%s.ssh.set' % version.APPPATH) == []:
150
 
                return None
151
 
        ret = {}
152
 
        for key, val in cp.items('Set'):
153
 
                ret[key] = val
154
 
        ret['increments'] = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
155
 
        log = LogHandler()
156
 
        sys.stdout = log
157
 
        sshpath = "%s@%s::%s" % (user, host, path)
158
 
        args = ['--list-increments', '--parsable-output', '--terminal-verbosity', '0', sshpath]
159
 
        Refresh()
160
 
        try:
161
 
                Run_rdiff(args)
162
 
        except OSError, e:
163
 
                return None
164
 
        sys.stdout = sys.__stdout__
165
 
        for inc in str(log).splitlines():
166
 
                timestamp = inc.split()[0]
167
 
                try:
168
 
                        ret['increments'].insert_before(ret['increments'][0].iter, (time.ctime(float(timestamp)), timestamp))
169
 
                except IndexError, e:
170
 
                        ret['increments'].append((time.ctime(float(timestamp)), timestamp))
171
 
        return ret
172
 
        
173
 
def SetExists(name):
174
 
        return os.path.exists(setspath+name)
175
 
 
176
 
def ListSets():
177
 
        """Prints a list of all backup sets"""
178
 
        for name,extra in backupsets.items():
179
 
                print _("name:") + (" %s" % name) + "\n"\
180
 
                        + _("title:") + (" %s" % extra['info'][0]) + "\n"\
181
 
                        + _("description:") + (" %s" % extra['info'][1]) + "\n"\
182
 
                        + _("default destination:") + (" %s" % extra['default_dest'])\
183
 
                        + "\n======\n\n"
184
 
 
185
 
def WriteSet(name, desc, filelist, overwrite=False, extrakeys=None):
186
 
        """Writes set.ini and filelist to a new or existing set directory"""
187
 
        try:
188
 
                os.makedirs(setspath+name)
189
 
        except OSError, e:
190
 
                if overwrite and str(e)[7:9]=="17":
191
 
                        pass
192
 
                else:
193
 
                        raise OSError(e)
194
 
        
195
 
        cp = SafeConfigParser()
196
 
        cp.add_section("Set")
197
 
        cp.set("Set", "name", str(name))
198
 
        cp.set("Set", "desc", str(desc))
199
 
        if extrakeys is not None:
200
 
                for key,val in extrakeys.items():
201
 
                        cp.set("Set", key, str(val))
202
 
        inifile = open(setspath+name+"/set.ini", "w")
203
 
        cp.write(inifile)
204
 
        inifile.close()
205
 
        
206
 
        flist = open(setspath+name+"/filelist", "w")
207
 
        includefiles = ""
208
 
        for path, include in filelist:
209
 
                if include:
210
 
                        includefiles += "+ %s\n" % path # add these to the end of the file
211
 
                else:
212
 
                        flist.write("- %s\n" % path)
213
 
        flist.write(includefiles)
214
 
        flist.write("- **\n")
215
 
        flist.close()
216
 
        
217
 
def DeleteSet(name):
218
 
        if not SetExists(name):
219
 
                print _("The set '%s' does not exist.") % name
220
 
                return
221
 
        try:
222
 
                os.remove(setspath+name+"/set.ini")
223
 
                os.remove(setspath+name+"/filelist")
224
 
                os.rmdir(setspath+name)
225
 
        except OSError, e:
226
 
                print e
227
 
        
228
 
def SysExit(status=0):
229
 
        raise RdiffError(status)
230
 
 
231
 
def BackupSet(set, dest, output=sys.__stdout__, err_output=sys.__stderr__,\
232
 
        copy_set_file=True, is_ssh=False):
233
 
        """Performs a backup of the specified set to the path dest"""
234
 
        if not SetExists(set['path']):
235
 
                print _("Backup set %s not found.") % set
236
 
                return
237
 
        exitfunction = sys.exit
238
 
        sys.exit = SysExit
239
 
        arglist = ['--terminal-verbosity', '5', '--verbosity', '9']
240
 
        if not is_ssh:
241
 
                arglist.extend(['--exclude', dest])
242
 
        arglist.extend(['--include-globbing-filelist', setspath+set['path']+"/filelist", "/", dest])
243
 
        sys.stdout = output
244
 
        sys.stderr = err_output
245
 
        Run_rdiff(arglist)
246
 
        if copy_set_file:
247
 
                shutil.copyfile(os.path.join(setspath, set['path'], "set.ini"), os.path.join(dest, "rdiff-backup-data", "%s.set" % version.APPPATH))
248
 
        sys.stderr = sys.__stderr__
249
 
        sys.stdout = sys.__stdout__
250
 
        sys.exit = exitfunction
251
 
 
252
 
 
253
 
def Run_rdiff(arglist):
254
 
        print >>sys.__stdout__, arglist
255
 
        rdiff_backup.Main.parse_cmdlineoptions(arglist)
256
 
        if rdiff_backup.Main.Globals.version > "0.13":
257
 
                rdiff_backup.Main.check_action()
258
 
        if rdiff_backup.Main.Globals.version < "0.13":
259
 
                rdiff_backup.Main.set_action()
260
 
        cmdpairs = rdiff_backup.Main.SetConnections.get_cmd_pairs(rdiff_backup.Main.args, rdiff_backup.Main.remote_schema, rdiff_backup.Main.remote_cmd)
261
 
        rdiff_backup.Main.Security.initialize(rdiff_backup.Main.action or "mirror", cmdpairs)
262
 
        rps = map(rdiff_backup.Main.SetConnections.cmdpair2rp, cmdpairs)
263
 
        if rdiff_backup.Main.Globals.version > "0.13":
264
 
                rdiff_backup.Main.final_set_action(rps)
265
 
        rdiff_backup.Main.misc_setup(rps)
266
 
        rdiff_backup.Main.take_action(rps)
267
 
        rdiff_backup.Main.cleanup()
268
 
        
269
 
 
270
 
def RestoreSet(src_path, dst_path, output=sys.__stdout__, err_output=sys.__stderr__, increment="now"):
271
 
        """Restores the rdiff-backup backup from src to dst_path"""
272
 
        exitfunction = sys.exit
273
 
        sys.exit = SysExit
274
 
        arglist = ['--force', '--terminal-verbosity', '5', '--verbosity', '9', '-r', increment, src_path, dst_path]
275
 
        sys.stdout = output
276
 
        sys.stderr = err_output
277
 
        try:
278
 
                Run_rdiff(arglist)
279
 
        except Exception, e:
280
 
                sys.stderr.write(_("Error:") + (" %s\n" % e)
281
 
                        + _("rdiff-backup version: ") + "%s\n%s " % (rdiff_backup.Main.Globals.version, version.APPNAME)
282
 
                        + _("version:") + " %s\n" % version.VERSION
283
 
                        + _("Please e-mail the contents of this text box to:") 
284
 
                        + "andy@andrewprice.me.uk")
285
 
                raise AssertionError(e)
286
 
        logfile = sys.stdout
287
 
        sys.stdout = sys.__stdout__
288
 
        sys.stderr = sys.__stderr__
289
 
        sys.exit = exitfunction