13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
"""Implementation of Transport for the local filesystem.
17
"""Transport for the local filesystem.
19
This is a fairly thin wrapper on regular file IO."""
24
from stat import ST_MODE, S_ISDIR, ST_SIZE
27
from bzrlib.trace import mutter
19
28
from bzrlib.transport import Transport, register_transport, \
20
29
TransportError, NoSuchFile, FileExists
30
from bzrlib.osutils import abspath
23
32
class LocalTransportError(TransportError):
26
36
class LocalTransport(Transport):
27
37
"""This is the transport agent for local filesystem access."""
33
43
# realpath is incompatible with symlinks. When we traverse
34
44
# up we might be able to normpath stuff. RBC 20051003
35
45
super(LocalTransport, self).__init__(
36
os.path.normpath(os.path.abspath(base)))
46
os.path.normpath(abspath(base)))
38
48
def should_cache(self):
59
69
def relpath(self, abspath):
60
70
"""Return the local path portion from a given absolute path.
62
from bzrlib.branch import _relpath
63
return _relpath(self.base, abspath)
72
from bzrlib.osutils import relpath
75
return relpath(self.base, abspath)
65
77
def has(self, relpath):
66
78
return os.access(self.abspath(relpath), os.F_OK)
74
86
path = self.abspath(relpath)
75
87
return open(path, 'rb')
77
if e.errno == errno.ENOENT:
78
raise NoSuchFile('File %r does not exist' % path, orig_error=e)
79
raise LocalTransportError(orig_error=e)
81
def get_partial(self, relpath, start, length=None):
82
"""Get just part of a file.
84
:param relpath: Path to the file, relative to base
85
:param start: The starting position to read from
86
:param length: The length to read. A length of None indicates
87
read to the end of the file.
88
:return: A file-like object containing at least the specified bytes.
89
Some implementations may return objects which can be read
90
past this length, but this is not guaranteed.
92
# LocalTransport.get_partial() doesn't care about the length
93
# argument, because it is using a local file, and thus just
94
# returns the file seek'ed to the appropriate location.
96
path = self.abspath(relpath)
101
if e.errno == errno.ENOENT:
102
raise NoSuchFile('File %r does not exist' % path, orig_error=e)
89
if e.errno in (errno.ENOENT, errno.ENOTDIR):
90
raise NoSuchFile('File or directory %r does not exist' % path, orig_error=e)
103
91
raise LocalTransportError(orig_error=e)
105
93
def put(self, relpath, f):
114
def iter_files_recursive(self):
115
"""Iter the relative paths of files in the transports sub-tree."""
116
queue = list(self.list_dir('.'))
118
relpath = queue.pop(0)
119
st = self.stat(relpath)
120
if S_ISDIR(st[ST_MODE]):
121
for i, basename in enumerate(self.list_dir(relpath)):
122
queue.insert(i, relpath+'/'+basename)
126
126
def mkdir(self, relpath):
127
127
"""Create a directory at the given path."""
227
227
from bzrlib.lock import WriteLock
228
228
return WriteLock(self.abspath(relpath))
231
class ScratchTransport(LocalTransport):
232
"""A transport that works in a temporary dir and cleans up after itself.
234
The dir only exists for the lifetime of the Python object.
235
Obviously you should not put anything precious in it.
238
def __init__(self, base=None):
240
base = tempfile.mkdtemp()
241
super(ScratchTransport, self).__init__(base)
244
shutil.rmtree(self.base, ignore_errors=True)
245
mutter("%r destroyed" % self)
230
247
# If nothing else matches, try the LocalTransport
231
248
register_transport(None, LocalTransport)
232
249
register_transport('file://', LocalTransport)