~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/local.py

  • Committer: Martin Pool
  • Date: 2005-04-28 10:01:44 UTC
  • Revision ID: mbp@sourcefrog.net-20050428100144-e9d4ccfe5fb236df
- new 'bzr ignored' command!

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/env python
2
 
"""\
3
 
An implementation of the Transport object for local
4
 
filesystem access.
5
 
"""
6
 
 
7
 
from bzrlib.transport import Transport, register_transport, \
8
 
    TransportError, NoSuchFile, FileExists
9
 
import os, errno
10
 
 
11
 
class LocalTransportError(TransportError):
12
 
    pass
13
 
 
14
 
class LocalTransport(Transport):
15
 
    """This is the transport agent for local filesystem access."""
16
 
 
17
 
    def __init__(self, base):
18
 
        """Set the base path where files will be stored."""
19
 
        if base.startswith('file://'):
20
 
            base = base[7:]
21
 
        super(LocalTransport, self).__init__(os.path.realpath(base))
22
 
 
23
 
    def should_cache(self):
24
 
        return False
25
 
 
26
 
    def clone(self, offset=None):
27
 
        """Return a new LocalTransport with root at self.base + offset
28
 
        Because the local filesystem does not require a connection, 
29
 
        we can just return a new object.
30
 
        """
31
 
        if offset is None:
32
 
            return LocalTransport(self.base)
33
 
        else:
34
 
            return LocalTransport(self.abspath(offset))
35
 
 
36
 
    def abspath(self, relpath):
37
 
        """Return the full url to the given relative path.
38
 
        This can be supplied with a string or a list
39
 
        """
40
 
        if isinstance(relpath, basestring):
41
 
            relpath = [relpath]
42
 
        return os.path.join(self.base, *relpath)
43
 
 
44
 
    def relpath(self, abspath):
45
 
        """Return the local path portion from a given absolute path.
46
 
        """
47
 
        from branch import _relpath
48
 
        return _relpath(self.base, abspath)
49
 
 
50
 
    def has(self, relpath):
51
 
        return os.access(self.abspath(relpath), os.F_OK)
52
 
 
53
 
    def get(self, relpath):
54
 
        """Get the file at the given relative path.
55
 
 
56
 
        :param relpath: The relative path to the file
57
 
        """
58
 
        try:
59
 
            path = self.abspath(relpath)
60
 
            return open(path, 'rb')
61
 
        except IOError,e:
62
 
            if e.errno == errno.ENOENT:
63
 
                raise NoSuchFile('File %r does not exist' % path, orig_error=e)
64
 
            raise LocalTransportError(orig_error=e)
65
 
 
66
 
    def put(self, relpath, f):
67
 
        """Copy the file-like or string object into the location.
68
 
 
69
 
        :param relpath: Location to put the contents, relative to base.
70
 
        :param f:       File-like or string object.
71
 
        """
72
 
        from bzrlib.atomicfile import AtomicFile
73
 
 
74
 
        try:
75
 
            path = self.abspath(relpath)
76
 
            fp = AtomicFile(path, 'wb')
77
 
        except IOError, e:
78
 
            if e.errno == errno.ENOENT:
79
 
                raise NoSuchFile('File %r does not exist' % path, orig_error=e)
80
 
            raise LocalTransportError(orig_error=e)
81
 
        try:
82
 
            self._pump(f, fp)
83
 
            fp.commit()
84
 
        finally:
85
 
            fp.close()
86
 
 
87
 
    def mkdir(self, relpath):
88
 
        """Create a directory at the given path."""
89
 
        try:
90
 
            os.mkdir(self.abspath(relpath))
91
 
        except OSError,e:
92
 
            if e.errno == errno.EEXIST:
93
 
                raise FileExists(orig_error=e)
94
 
            elif e.errno == errno.ENOENT:
95
 
                raise NoSuchFile(orig_error=e)
96
 
            raise LocalTransportError(orig_error=e)
97
 
 
98
 
    def append(self, relpath, f):
99
 
        """Append the text in the file-like object into the final
100
 
        location.
101
 
        """
102
 
        fp = open(self.abspath(relpath), 'ab')
103
 
        self._pump(f, fp)
104
 
 
105
 
    def copy(self, rel_from, rel_to):
106
 
        """Copy the item at rel_from to the location at rel_to"""
107
 
        import shutil
108
 
        path_from = self.abspath(rel_from)
109
 
        path_to = self.abspath(rel_to)
110
 
        try:
111
 
            shutil.copy(path_from, path_to)
112
 
        except OSError,e:
113
 
            raise LocalTransportError(orig_error=e)
114
 
 
115
 
    def move(self, rel_from, rel_to):
116
 
        """Move the item at rel_from to the location at rel_to"""
117
 
        path_from = self.abspath(rel_from)
118
 
        path_to = self.abspath(rel_to)
119
 
 
120
 
        try:
121
 
            os.rename(path_from, path_to)
122
 
        except OSError,e:
123
 
            raise LocalTransportError(orig_error=e)
124
 
 
125
 
    def delete(self, relpath):
126
 
        """Delete the item at relpath"""
127
 
        try:
128
 
            os.remove(self.abspath(relpath))
129
 
        except OSError,e:
130
 
            raise LocalTransportError(orig_error=e)
131
 
 
132
 
    def copy_to(self, relpaths, other, pb=None):
133
 
        """Copy a set of entries from self into another Transport.
134
 
 
135
 
        :param relpaths: A list/generator of entries to be copied.
136
 
        """
137
 
        if isinstance(other, LocalTransport):
138
 
            # Both from & to are on the local filesystem
139
 
            # Unfortunately, I can't think of anything faster than just
140
 
            # copying them across, one by one :(
141
 
            import shutil
142
 
 
143
 
            total = self._get_total(relpaths)
144
 
            count = 0
145
 
            for path in relpaths:
146
 
                self._update_pb(pb, 'copy-to', count, total)
147
 
                shutil.copy(self.abspath(path), other.abspath(path))
148
 
                count += 1
149
 
            return count
150
 
        else:
151
 
            return super(LocalTransport, self).copy_to(relpaths, other, pb=pb)
152
 
 
153
 
 
154
 
    def async_get(self, relpath):
155
 
        """Make a request for an file at the given location, but
156
 
        don't worry about actually getting it yet.
157
 
 
158
 
        :rtype: AsyncFile
159
 
        """
160
 
        raise NotImplementedError
161
 
 
162
 
    def list_dir(self, relpath):
163
 
        """Return a list of all files at the given location.
164
 
        WARNING: many transports do not support this, so trying avoid using
165
 
        it if at all possible.
166
 
        """
167
 
        try:
168
 
            return os.listdir(self.abspath(relpath))
169
 
        except OSError,e:
170
 
            raise LocalTransportError(orig_error=e)
171
 
 
172
 
    def stat(self, relpath):
173
 
        """Return the stat information for a file.
174
 
        """
175
 
        try:
176
 
            return os.stat(self.abspath(relpath))
177
 
        except OSError,e:
178
 
            raise LocalTransportError(orig_error=e)
179
 
 
180
 
    def lock_read(self, relpath):
181
 
        """Lock the given file for shared (read) access.
182
 
        :return: A lock object, which should be passed to Transport.unlock()
183
 
        """
184
 
        from bzrlib.lock import ReadLock
185
 
        return ReadLock(self.abspath(relpath))
186
 
 
187
 
    def lock_write(self, relpath):
188
 
        """Lock the given file for exclusive (write) access.
189
 
        WARNING: many transports do not support this, so trying avoid using it
190
 
 
191
 
        :return: A lock object, which should be passed to Transport.unlock()
192
 
        """
193
 
        from bzrlib.lock import WriteLock
194
 
        return WriteLock(self.abspath(relpath))
195
 
 
196
 
# If nothing else matches, try the LocalTransport
197
 
register_transport(None, LocalTransport)
198
 
register_transport('file://', LocalTransport)