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
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
28
from bzrlib.trace import mutter
16
"""Implementation of Transport for the local filesystem.
29
19
from bzrlib.transport import Transport, register_transport, \
30
20
TransportError, NoSuchFile, FileExists
31
from bzrlib.osutils import abspath
33
23
class LocalTransportError(TransportError):
37
26
class LocalTransport(Transport):
38
27
"""This is the transport agent for local filesystem access."""
44
33
# realpath is incompatible with symlinks. When we traverse
45
34
# up we might be able to normpath stuff. RBC 20051003
46
35
super(LocalTransport, self).__init__(
47
os.path.normpath(abspath(base)))
36
os.path.normpath(os.path.abspath(base)))
49
38
def should_cache(self):
60
49
return LocalTransport(self.abspath(offset))
62
51
def abspath(self, relpath):
63
"""Return the full url to the given relative URL.
52
"""Return the full url to the given relative path.
64
53
This can be supplied with a string or a list
66
assert isinstance(relpath, basestring), (type(relpath), relpath)
67
return os.path.join(self.base, urllib.unquote(relpath))
55
if isinstance(relpath, basestring):
57
return os.path.join(self.base, *relpath)
69
59
def relpath(self, abspath):
70
60
"""Return the local path portion from a given absolute path.
72
from bzrlib.osutils import relpath
75
return relpath(self.base, abspath)
62
from bzrlib.branch import _relpath
63
return _relpath(self.base, abspath)
77
65
def has(self, relpath):
78
66
return os.access(self.abspath(relpath), os.F_OK)
86
74
path = self.abspath(relpath)
87
75
return open(path, 'rb')
89
if e.errno in (errno.ENOENT, errno.ENOTDIR):
90
raise NoSuchFile('File or directory %r does not exist' % path, orig_error=e)
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)
91
103
raise LocalTransportError(orig_error=e)
93
105
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(u'.'))
118
relpath = urllib.quote(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."""
184
184
for path in relpaths:
185
185
self._update_pb(pb, 'copy-to', count, total)
187
shutil.copy(self.abspath(path), other.abspath(path))
189
if e.errno in (errno.ENOENT, errno.ENOTDIR):
190
raise NoSuchFile('File or directory %r does not exist' % path, orig_error=e)
191
raise LocalTransportError(orig_error=e)
186
shutil.copy(self.abspath(path), other.abspath(path))
195
190
return super(LocalTransport, self).copy_to(relpaths, other, pb=pb)
198
"""See Transport.listable."""
201
193
def list_dir(self, relpath):
202
194
"""Return a list of all files at the given location.
232
224
from bzrlib.lock import WriteLock
233
225
return WriteLock(self.abspath(relpath))
236
class ScratchTransport(LocalTransport):
237
"""A transport that works in a temporary dir and cleans up after itself.
239
The dir only exists for the lifetime of the Python object.
240
Obviously you should not put anything precious in it.
243
def __init__(self, base=None):
245
base = tempfile.mkdtemp()
246
super(ScratchTransport, self).__init__(base)
249
shutil.rmtree(self.base, ignore_errors=True)
250
mutter("%r destroyed" % self)
227
# If nothing else matches, try the LocalTransport
228
register_transport(None, LocalTransport)
229
register_transport('file://', LocalTransport)