~bmerry/duplicity/pydrive-regular

335 by loafman
patch #6675: Add modelines
1
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
2
#
404 by loafman
Add/update copyright statements in all distribution source files
3
# Copyright 2002 Ben Escoto <ben@emerose.org>
4
# Copyright 2007 Kenneth Loafman <kenneth@loafman.com>
1 by bescoto
Initial checkin
5
#
6
# This file is part of duplicity.
7
#
2 by bescoto
Added full GPL statement in source files at request of Jaime Villate
8
# Duplicity is free software; you can redistribute it and/or modify it
9
# under the terms of the GNU General Public License as published by the
476 by loafman
After email voting among known duplicity contributors,
10
# Free Software Foundation; either version 2 of the License, or (at your
2 by bescoto
Added full GPL statement in source files at request of Jaime Villate
11
# option) any later version.
12
#
13
# Duplicity is distributed in the hope that it will be useful, but
14
# WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
# General Public License for more details.
17
#
18
# You should have received a copy of the GNU General Public License
19
# along with duplicity; if not, write to the Free Software Foundation,
20
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1 by bescoto
Initial checkin
21
22
"""Manage temporary files"""
23
1071 by Kenneth Loafman
* Misc fixes for the following PEP8 issues:
24
import os
25
import sys
1 by bescoto
Initial checkin
26
477 by loafman
Normalized include statements and tried to insure that all
27
from duplicity import log
773 by Kenneth Loafman
- Ignore ENOENT (file missing) errors where it is safe.
28
from duplicity import util
477 by loafman
Normalized include statements and tried to insure that all
29
from duplicity import path
30
from duplicity import file_naming
31
from duplicity import tempdir
521 by loafman
After merge of Checkpoint/Restart.
32
from duplicity import globals
33
from duplicity import gpg
1 by bescoto
Initial checkin
34
312 by loafman
Change to one statement per line.
35
1 by bescoto
Initial checkin
36
def new_temppath():
521 by loafman
After merge of Checkpoint/Restart.
37
    """
38
    Return a new TempPath
39
    """
304 by loafman
Untabify all files. To compare against previous
40
    filename = tempdir.default().mktemp()
41
    return TempPath(filename)
1 by bescoto
Initial checkin
42
312 by loafman
Change to one statement per line.
43
1 by bescoto
Initial checkin
44
class TempPath(path.Path):
521 by loafman
After merge of Checkpoint/Restart.
45
    """
46
    Path object used as a temporary file
47
    """
304 by loafman
Untabify all files. To compare against previous
48
    def delete(self):
521 by loafman
After merge of Checkpoint/Restart.
49
        """
50
        Forget and delete
51
        """
304 by loafman
Untabify all files. To compare against previous
52
        path.Path.delete(self)
53
        tempdir.default().forget(self.name)
1 by bescoto
Initial checkin
54
304 by loafman
Untabify all files. To compare against previous
55
    def open_with_delete(self, mode):
521 by loafman
After merge of Checkpoint/Restart.
56
        """
57
        Returns a fileobj.  When that is closed, delete file
58
        """
304 by loafman
Untabify all files. To compare against previous
59
        fh = FileobjHooked(path.Path.open(self, mode))
60
        fh.addhook(self.delete)
61
        return fh
1 by bescoto
Initial checkin
62
312 by loafman
Change to one statement per line.
63
864.5.1 by Michael Terry
gracefully handle multiple duplicate base dir entries in the sigtar; avoid writing such entries out
64
def get_fileobj_duppath(dirpath, partname, permname, remname, overwrite=False):
521 by loafman
After merge of Checkpoint/Restart.
65
    """
66
    Return a file object open for writing, will write to filename
304 by loafman
Untabify all files. To compare against previous
67
68
    Data will be processed and written to a temporary file.  When the
69
    return fileobject is closed, rename to final position.  filename
70
    must be a recognizable duplicity data file.
71
    """
521 by loafman
After merge of Checkpoint/Restart.
72
    if not globals.restart:
73
        td = tempdir.TemporaryDirectory(dirpath.name)
74
        tdpname = td.mktemp()
1033 by Kenneth Loafman
* Source formatted, using PyDev, all source files to fix some easily fixed
75
        tdp = TempDupPath(tdpname, parseresults=file_naming.parse(partname))
76
        fh = FileobjHooked(tdp.filtered_open("wb"), tdp=tdp, dirpath=dirpath,
77
                           partname=partname, permname=permname, remname=remname)
521 by loafman
After merge of Checkpoint/Restart.
78
    else:
1033 by Kenneth Loafman
* Source formatted, using PyDev, all source files to fix some easily fixed
79
        dp = path.DupPath(dirpath.name, index=(partname,))
864.5.1 by Michael Terry
gracefully handle multiple duplicate base dir entries in the sigtar; avoid writing such entries out
80
        mode = "ab"
81
        if overwrite:
82
            mode = "wb"
1033 by Kenneth Loafman
* Source formatted, using PyDev, all source files to fix some easily fixed
83
        fh = FileobjHooked(dp.filtered_open(mode), tdp=None, dirpath=dirpath,
84
                           partname=partname, permname=permname, remname=remname)
477 by loafman
Normalized include statements and tried to insure that all
85
304 by loafman
Untabify all files. To compare against previous
86
    def rename_and_forget():
521 by loafman
After merge of Checkpoint/Restart.
87
        tdp.rename(dirpath.append(partname))
304 by loafman
Untabify all files. To compare against previous
88
        td.forget(tdpname)
89
521 by loafman
After merge of Checkpoint/Restart.
90
    if not globals.restart:
91
        fh.addhook(rename_and_forget)
304 by loafman
Untabify all files. To compare against previous
92
93
    return fh
1 by bescoto
Initial checkin
94
312 by loafman
Change to one statement per line.
95
1 by bescoto
Initial checkin
96
def new_tempduppath(parseresults):
521 by loafman
After merge of Checkpoint/Restart.
97
    """
98
    Return a new TempDupPath, using settings from parseresults
99
    """
304 by loafman
Untabify all files. To compare against previous
100
    filename = tempdir.default().mktemp()
1033 by Kenneth Loafman
* Source formatted, using PyDev, all source files to fix some easily fixed
101
    return TempDupPath(filename, parseresults=parseresults)
1 by bescoto
Initial checkin
102
312 by loafman
Change to one statement per line.
103
1 by bescoto
Initial checkin
104
class TempDupPath(path.DupPath):
521 by loafman
After merge of Checkpoint/Restart.
105
    """
106
    Like TempPath, but build around DupPath
107
    """
304 by loafman
Untabify all files. To compare against previous
108
    def delete(self):
521 by loafman
After merge of Checkpoint/Restart.
109
        """
110
        Forget and delete
111
        """
304 by loafman
Untabify all files. To compare against previous
112
        path.DupPath.delete(self)
113
        tempdir.default().forget(self.name)
114
115
    def filtered_open_with_delete(self, mode):
521 by loafman
After merge of Checkpoint/Restart.
116
        """
117
        Returns a filtered fileobj.  When that is closed, delete file
118
        """
304 by loafman
Untabify all files. To compare against previous
119
        fh = FileobjHooked(path.DupPath.filtered_open(self, mode))
120
        fh.addhook(self.delete)
121
        return fh
122
1033 by Kenneth Loafman
* Source formatted, using PyDev, all source files to fix some easily fixed
123
    def open_with_delete(self, mode="rb"):
521 by loafman
After merge of Checkpoint/Restart.
124
        """
125
        Returns a fileobj.  When that is closed, delete file
126
        """
1033 by Kenneth Loafman
* Source formatted, using PyDev, all source files to fix some easily fixed
127
        assert mode == "rb"  # Why write a file and then close it immediately?
304 by loafman
Untabify all files. To compare against previous
128
        fh = FileobjHooked(path.DupPath.open(self, mode))
129
        fh.addhook(self.delete)
130
        return fh
1 by bescoto
Initial checkin
131
312 by loafman
Change to one statement per line.
132
1 by bescoto
Initial checkin
133
class FileobjHooked:
521 by loafman
After merge of Checkpoint/Restart.
134
    """
135
    Simulate a file, but add hook on close
136
    """
1033 by Kenneth Loafman
* Source formatted, using PyDev, all source files to fix some easily fixed
137
    def __init__(self, fileobj, tdp=None, dirpath=None,
138
                 partname=None, permname=None, remname=None):
521 by loafman
After merge of Checkpoint/Restart.
139
        """
140
        Initializer.  fileobj is the file object to simulate
141
        """
1033 by Kenneth Loafman
* Source formatted, using PyDev, all source files to fix some easily fixed
142
        self.fileobj = fileobj  # the actual file object
143
        self.closed = False  # True if closed
144
        self.hooklist = []  # filled later with thunks to run on close
145
        self.tdp = tdp  # TempDupPath object
146
        self.dirpath = dirpath  # path to directory
147
        self.partname = partname  # partial filename
148
        self.permname = permname  # permanent filename
149
        self.remname = remname  # remote filename
304 by loafman
Untabify all files. To compare against previous
150
151
    def write(self, buf):
521 by loafman
After merge of Checkpoint/Restart.
152
        """
153
        Write fileobj, return result of write()
154
        """
304 by loafman
Untabify all files. To compare against previous
155
        return self.fileobj.write(buf)
477 by loafman
Normalized include statements and tried to insure that all
156
521 by loafman
After merge of Checkpoint/Restart.
157
    def flush(self):
158
        """
159
        Flush fileobj and force sync.
160
        """
161
        self.fileobj.flush()
162
        os.fsync(self.fileobj.fileno())
163
164
    def to_partial(self):
165
        """
166
        We have achieved the first checkpoint, make file visible and permanent.
167
        """
168
        assert not globals.restart
169
        self.tdp.rename(self.dirpath.append(self.partname))
170
        self.fileobj.flush()
171
        del self.hooklist[0]
172
173
    def to_remote(self):
174
        """
175
        We have written the last checkpoint, now encrypt or compress
176
        and send a copy of it to the remote for final storage.
177
        """
178
        pr = file_naming.parse(self.remname)
179
        src = self.dirpath.append(self.partname)
180
        tgt = self.dirpath.append(self.remname)
181
        src_iter = SrcIter(src)
182
        if pr.compressed:
1033 by Kenneth Loafman
* Source formatted, using PyDev, all source files to fix some easily fixed
183
            gpg.GzipWriteFile(src_iter, tgt.name, size=sys.maxsize)
521 by loafman
After merge of Checkpoint/Restart.
184
        elif pr.encrypted:
1033 by Kenneth Loafman
* Source formatted, using PyDev, all source files to fix some easily fixed
185
            gpg.GPGWriteFile(src_iter, tgt.name, globals.gpg_profile, size=sys.maxsize)
521 by loafman
After merge of Checkpoint/Restart.
186
        else:
674.3.1 by ed
survive spaces in path on local copying with encryption enabled
187
            os.system("cp -p \"%s\" \"%s\"" % (src.name, tgt.name))
1033 by Kenneth Loafman
* Source formatted, using PyDev, all source files to fix some easily fixed
188
        globals.backend.move(tgt)  # @UndefinedVariable
521 by loafman
After merge of Checkpoint/Restart.
189
190
    def to_final(self):
191
        """
192
        We are finished, rename to final, gzip if needed.
193
        """
194
        src = self.dirpath.append(self.partname)
195
        tgt = self.dirpath.append(self.permname)
196
        src_iter = SrcIter(src)
197
        pr = file_naming.parse(self.permname)
198
        if pr.compressed:
1033 by Kenneth Loafman
* Source formatted, using PyDev, all source files to fix some easily fixed
199
            gpg.GzipWriteFile(src_iter, tgt.name, size=sys.maxsize)
521 by loafman
After merge of Checkpoint/Restart.
200
            os.unlink(src.name)
201
        else:
202
            os.rename(src.name, tgt.name)
203
1033 by Kenneth Loafman
* Source formatted, using PyDev, all source files to fix some easily fixed
204
    def read(self, length=-1):
521 by loafman
After merge of Checkpoint/Restart.
205
        """
206
        Read fileobj, return result of read()
207
        """
312 by loafman
Change to one statement per line.
208
        return self.fileobj.read(length)
304 by loafman
Untabify all files. To compare against previous
209
777.1.1 by Michael Terry
first pass at dropping tarfile
210
    def tell(self):
211
        """
212
        Returns current location of fileobj
213
        """
214
        return self.fileobj.tell()
215
216
    def seek(self, offset):
217
        """
218
        Seeks to a location of fileobj
219
        """
220
        return self.fileobj.seek(offset)
221
304 by loafman
Untabify all files. To compare against previous
222
    def close(self):
521 by loafman
After merge of Checkpoint/Restart.
223
        """
224
        Close fileobj, running hooks right afterwards
225
        """
304 by loafman
Untabify all files. To compare against previous
226
        assert not self.fileobj.close()
312 by loafman
Change to one statement per line.
227
        for hook in self.hooklist:
228
            hook()
304 by loafman
Untabify all files. To compare against previous
229
230
    def addhook(self, hook):
521 by loafman
After merge of Checkpoint/Restart.
231
        """
232
        Add hook (function taking no arguments) to run upon closing
233
        """
304 by loafman
Untabify all files. To compare against previous
234
        self.hooklist.append(hook)
235
721 by Kenneth Loafman
433591 AttributeError: FileobjHooked instance has no attribute 'name'
236
    def get_name(self):
237
        """
238
        Return the name of the file
239
        """
240
        return self.fileobj.name
241
242
    name = property(get_name)
243
244
521 by loafman
After merge of Checkpoint/Restart.
245
class Block:
246
    """
247
    Data block to return from SrcIter
248
    """
249
    def __init__(self, data):
250
        self.data = data
251
1070 by Kenneth Loafman
* Misc fixes for the following PEP8 issues:
252
521 by loafman
After merge of Checkpoint/Restart.
253
class SrcIter:
254
    """
255
    Iterate over source and return Block of data.
256
    """
257
    def __init__(self, src):
258
        self.src = src
259
        self.fp = src.open("rb")
1070 by Kenneth Loafman
* Misc fixes for the following PEP8 issues:
260
902.1.6 by Michael Terry
Fix block-loss when restarting inside a multi-block file due to block sizes being variable
261
    def next(self):
521 by loafman
After merge of Checkpoint/Restart.
262
        try:
902.1.6 by Michael Terry
Fix block-loss when restarting inside a multi-block file due to block sizes being variable
263
            res = Block(self.fp.read(self.get_read_size()))
747.1.1 by Michael Terry
always catch Exceptions, not BaseExceptions
264
        except Exception:
1065 by Kenneth Loafman
* Merged in lp:~angusgr/duplicity/exclude-older-than
265
            log.FatalError(_("Failed to read %s: %s") %
939.3.1 by Michael Terry
Promote filenames to unicode when printing to console and ensure that filenames from backend are bytes
266
                           (util.ufn(self.src.name), sys.exc_info()),
521 by loafman
After merge of Checkpoint/Restart.
267
                           log.ErrorCode.generic)
268
        if not res.data:
269
            self.fp.close()
270
            raise StopIteration
271
        return res
1070 by Kenneth Loafman
* Misc fixes for the following PEP8 issues:
272
902.1.6 by Michael Terry
Fix block-loss when restarting inside a multi-block file due to block sizes being variable
273
    def get_read_size(self):
274
        return 128 * 1024
1070 by Kenneth Loafman
* Misc fixes for the following PEP8 issues:
275
521 by loafman
After merge of Checkpoint/Restart.
276
    def get_footer(self):
277
        return ""