~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/local.py

  • Committer: Robert Collins
  • Date: 2005-10-17 11:56:54 UTC
  • mfrom: (1185.16.59)
  • Revision ID: robertc@robertcollins.net-20051017115654-662239e1587524a8
mergeĀ fromĀ martin.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
 
17
 
"""Transport for the local filesystem.
18
 
 
19
 
This is a fairly thin wrapper on regular file IO."""
 
16
"""Implementation of Transport for the local filesystem.
 
17
"""
20
18
 
21
19
import os
 
20
import errno
22
21
import shutil
23
22
from stat import ST_MODE, S_ISDIR, ST_SIZE
24
23
import tempfile
25
 
import urllib
26
24
 
27
25
from bzrlib.trace import mutter
28
 
from bzrlib.transport import Transport
29
 
from bzrlib.osutils import abspath
 
26
from bzrlib.transport import Transport, register_transport, \
 
27
    TransportError, NoSuchFile, FileExists
 
28
 
 
29
 
 
30
class LocalTransportError(TransportError):
 
31
    pass
30
32
 
31
33
 
32
34
class LocalTransport(Transport):
39
41
        # realpath is incompatible with symlinks. When we traverse
40
42
        # up we might be able to normpath stuff. RBC 20051003
41
43
        super(LocalTransport, self).__init__(
42
 
            os.path.normpath(abspath(base)))
 
44
            os.path.normpath(os.path.abspath(base)))
43
45
 
44
46
    def should_cache(self):
45
47
        return False
55
57
            return LocalTransport(self.abspath(offset))
56
58
 
57
59
    def abspath(self, relpath):
58
 
        """Return the full url to the given relative URL.
 
60
        """Return the full url to the given relative path.
59
61
        This can be supplied with a string or a list
60
62
        """
61
 
        assert isinstance(relpath, basestring), (type(relpath), relpath)
62
 
        return os.path.join(self.base, urllib.unquote(relpath))
 
63
        if isinstance(relpath, basestring):
 
64
            relpath = [relpath]
 
65
        return os.path.join(self.base, *relpath)
63
66
 
64
67
    def relpath(self, abspath):
65
68
        """Return the local path portion from a given absolute path.
66
69
        """
67
70
        from bzrlib.osutils import relpath
68
 
        if abspath is None:
69
 
            abspath = u'.'
70
71
        return relpath(self.base, abspath)
71
72
 
72
73
    def has(self, relpath):
80
81
        try:
81
82
            path = self.abspath(relpath)
82
83
            return open(path, 'rb')
83
 
        except (IOError, OSError),e:
84
 
            self._translate_error(e, path)
 
84
        except IOError,e:
 
85
            if e.errno in (errno.ENOENT, errno.ENOTDIR):
 
86
                raise NoSuchFile('File or directory %r does not exist' % path, orig_error=e)
 
87
            raise LocalTransportError(orig_error=e)
85
88
 
86
89
    def put(self, relpath, f):
87
90
        """Copy the file-like or string object into the location.
91
94
        """
92
95
        from bzrlib.atomicfile import AtomicFile
93
96
 
94
 
        path = relpath
95
97
        try:
96
98
            path = self.abspath(relpath)
97
99
            fp = AtomicFile(path, 'wb')
98
 
        except (IOError, OSError),e:
99
 
            self._translate_error(e, path)
 
100
        except IOError, e:
 
101
            if e.errno == errno.ENOENT:
 
102
                raise NoSuchFile('File %r does not exist' % path, orig_error=e)
 
103
            raise LocalTransportError(orig_error=e)
100
104
        try:
101
105
            self._pump(f, fp)
102
106
            fp.commit()
105
109
 
106
110
    def iter_files_recursive(self):
107
111
        """Iter the relative paths of files in the transports sub-tree."""
108
 
        queue = list(self.list_dir(u'.'))
 
112
        queue = list(self.list_dir('.'))
109
113
        while queue:
110
 
            relpath = urllib.quote(queue.pop(0))
 
114
            relpath = queue.pop(0)
111
115
            st = self.stat(relpath)
112
116
            if S_ISDIR(st[ST_MODE]):
113
117
                for i, basename in enumerate(self.list_dir(relpath)):
117
121
 
118
122
    def mkdir(self, relpath):
119
123
        """Create a directory at the given path."""
120
 
        path = relpath
121
124
        try:
122
 
            path = self.abspath(relpath)
123
 
            os.mkdir(path)
124
 
        except (IOError, OSError),e:
125
 
            self._translate_error(e, path)
 
125
            os.mkdir(self.abspath(relpath))
 
126
        except OSError,e:
 
127
            if e.errno == errno.EEXIST:
 
128
                raise FileExists(orig_error=e)
 
129
            elif e.errno == errno.ENOENT:
 
130
                raise NoSuchFile(orig_error=e)
 
131
            raise LocalTransportError(orig_error=e)
126
132
 
127
133
    def append(self, relpath, f):
128
134
        """Append the text in the file-like object into the final
138
144
        path_to = self.abspath(rel_to)
139
145
        try:
140
146
            shutil.copy(path_from, path_to)
141
 
        except (IOError, OSError),e:
142
 
            # TODO: What about path_to?
143
 
            self._translate_error(e, path_from)
 
147
        except OSError,e:
 
148
            raise LocalTransportError(orig_error=e)
144
149
 
145
150
    def move(self, rel_from, rel_to):
146
151
        """Move the item at rel_from to the location at rel_to"""
149
154
 
150
155
        try:
151
156
            os.rename(path_from, path_to)
152
 
        except (IOError, OSError),e:
153
 
            # TODO: What about path_to?
154
 
            self._translate_error(e, path_from)
 
157
        except OSError,e:
 
158
            raise LocalTransportError(orig_error=e)
155
159
 
156
160
    def delete(self, relpath):
157
161
        """Delete the item at relpath"""
158
 
        path = relpath
159
162
        try:
160
 
            path = self.abspath(relpath)
161
 
            os.remove(path)
162
 
        except (IOError, OSError),e:
163
 
            # TODO: What about path_to?
164
 
            self._translate_error(e, path)
 
163
            os.remove(self.abspath(relpath))
 
164
        except OSError,e:
 
165
            raise LocalTransportError(orig_error=e)
165
166
 
166
167
    def copy_to(self, relpaths, other, pb=None):
167
168
        """Copy a set of entries from self into another Transport.
178
179
            count = 0
179
180
            for path in relpaths:
180
181
                self._update_pb(pb, 'copy-to', count, total)
181
 
                try:
182
 
                    shutil.copy(self.abspath(path), other.abspath(path))
183
 
                except (IOError, OSError),e:
184
 
                    self._translate_error(e, path)
 
182
                shutil.copy(self.abspath(path), other.abspath(path))
185
183
                count += 1
186
184
            return count
187
185
        else:
196
194
        WARNING: many transports do not support this, so trying avoid using
197
195
        it if at all possible.
198
196
        """
199
 
        path = relpath
200
197
        try:
201
 
            path = self.abspath(relpath)
202
 
            return os.listdir(path)
203
 
        except (IOError, OSError),e:
204
 
            self._translate_error(e, path)
 
198
            return os.listdir(self.abspath(relpath))
 
199
        except OSError,e:
 
200
            raise LocalTransportError(orig_error=e)
205
201
 
206
202
    def stat(self, relpath):
207
203
        """Return the stat information for a file.
208
204
        """
209
 
        path = relpath
210
205
        try:
211
 
            path = self.abspath(relpath)
212
 
            return os.stat(path)
213
 
        except (IOError, OSError),e:
214
 
            self._translate_error(e, path)
 
206
            return os.stat(self.abspath(relpath))
 
207
        except OSError,e:
 
208
            raise LocalTransportError(orig_error=e)
215
209
 
216
210
    def lock_read(self, relpath):
217
211
        """Lock the given file for shared (read) access.
245
239
    def __del__(self):
246
240
        shutil.rmtree(self.base, ignore_errors=True)
247
241
        mutter("%r destroyed" % self)
 
242
 
 
243
# If nothing else matches, try the LocalTransport
 
244
register_transport(None, LocalTransport)
 
245
register_transport('file://', LocalTransport)