# Copyright 2002 Ben Escoto
#
# This file is part of duplicity.
#
# Duplicity is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3 of the License, or (at your
# option) any later version.
#
# Duplicity is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with duplicity; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Manage temporary files"""
import tempfile
import log, path, file_naming
import duplicity.tempdir as tempdir
def new_temppath():
"""Return a new TempPath"""
filename = tempdir.default().mktemp()
return TempPath(filename)
class TempPath(path.Path):
"""Path object used as a temporary file"""
def delete(self):
"""Forget and delete"""
path.Path.delete(self)
tempdir.default().forget(self.name)
def open_with_delete(self, mode):
"""Returns a fileobj. When that is closed, delete file"""
fh = FileobjHooked(path.Path.open(self, mode))
fh.addhook(self.delete)
return fh
def get_fileobj_duppath(dirpath, filename):
"""Return a file object open for writing, will write to filename
Data will be processed and written to a temporary file. When the
return fileobject is closed, rename to final position. filename
must be a recognizable duplicity data file.
"""
td = tempdir.TemporaryDirectory(dirpath.name)
tdpname = td.mktemp()
tdp = TempDupPath(tdpname, parseresults = file_naming.parse(filename))
fh = FileobjHooked(tdp.filtered_open("wb"))
def rename_and_forget():
tdp.rename(dirpath.append(filename))
td.forget(tdpname)
fh.addhook(rename_and_forget)
return fh
def new_tempduppath(parseresults):
"""Return a new TempDupPath, using settings from parseresults"""
filename = tempdir.default().mktemp()
return TempDupPath(filename, parseresults = parseresults)
class TempDupPath(path.DupPath):
"""Like TempPath, but build around DupPath"""
def delete(self):
"""Forget and delete"""
path.DupPath.delete(self)
tempdir.default().forget(self.name)
def filtered_open_with_delete(self, mode):
"""Returns a filtered fileobj. When that is closed, delete file"""
fh = FileobjHooked(path.DupPath.filtered_open(self, mode))
fh.addhook(self.delete)
return fh
def open_with_delete(self, mode = "rb"):
"""Returns a fileobj. When that is closed, delete file"""
assert mode == "rb" # Why write a file and then close it immediately?
fh = FileobjHooked(path.DupPath.open(self, mode))
fh.addhook(self.delete)
return fh
class FileobjHooked:
"""Simulate a file, but add hook on close"""
def __init__(self, fileobj):
"""Initializer. fileobj is the file object to simulate"""
self.fileobj = fileobj
self.closed = None
self.hooklist = [] # fill later with thunks to run on close
# self.second by MDR. Will be filled by addfilehandle -- poor mans tee
self.second = None
def write(self, buf):
if self.second: self.second.write(buf) # by MDR. actual tee
return self.fileobj.write(buf)
def read(self, length = -1): return self.fileobj.read(length)
def close(self):
"""Close fileobj, running hooks right afterwards"""
assert not self.fileobj.close()
if self.second: assert not self.second.close()
for hook in self.hooklist: hook()
def addhook(self, hook):
"""Add hook (function taking no arguments) to run upon closing"""
self.hooklist.append(hook)
def addfilehandle(self, fh): # by MDR
"""Add a second filehandle for listening to the input
This only works properly for two write handles"""
assert not self.second
self.second = fh
syntax highlighted by Code2HTML, v. 0.9.1