~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/local.py

Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
"""Transport for the local filesystem.
18
18
 
19
 
This is a fairly thin wrapper on regular file IO."""
 
19
This is a fairly thin wrapper on regular file IO.
 
20
"""
20
21
 
21
22
import os
22
23
import shutil
64
65
        else:
65
66
            return LocalTransport(self.abspath(offset))
66
67
 
 
68
    def _abspath(self, relative_reference):
 
69
        """Return a path for use in os calls.
 
70
 
 
71
        Several assumptions are made:
 
72
         - relative_reference does not contain '..'
 
73
         - relative_reference is url escaped.
 
74
        """
 
75
        if relative_reference in ('.', ''):
 
76
            return self._local_base
 
77
        return self._local_base + urlutils.unescape(relative_reference)
 
78
 
67
79
    def abspath(self, relpath):
68
80
        """Return the full url to the given relative URL."""
 
81
        # TODO: url escape the result. RBC 20060523.
69
82
        assert isinstance(relpath, basestring), (type(relpath), relpath)
70
83
        # jam 20060426 Using normpath on the real path, because that ensures
71
84
        #       proper handling of stuff like
79
92
        the only one that has direct local access.
80
93
        This is mostly for stuff like WorkingTree which needs to know
81
94
        the local working directory.
 
95
        
 
96
        This function is quite expensive: it calls realpath which resolves
 
97
        symlinks.
82
98
        """
83
99
        absurl = self.abspath(relpath)
84
100
        # mutter(u'relpath %s => base: %s, absurl %s', relpath, self.base, absurl)
95
111
            urlutils.strip_trailing_slash(abspath))
96
112
 
97
113
    def has(self, relpath):
98
 
        return os.access(self.local_abspath(relpath), os.F_OK)
 
114
        return os.access(self._abspath(relpath), os.F_OK)
99
115
 
100
116
    def get(self, relpath):
101
117
        """Get the file at the given relative path.
103
119
        :param relpath: The relative path to the file
104
120
        """
105
121
        try:
106
 
            path = self.local_abspath(relpath)
107
 
            # mutter('LocalTransport.get(%r) => %r', relpath, path)
 
122
            path = self._abspath(relpath)
108
123
            return open(path, 'rb')
109
124
        except (IOError, OSError),e:
110
125
            self._translate_error(e, path)
119
134
 
120
135
        path = relpath
121
136
        try:
122
 
            path = self.local_abspath(relpath)
 
137
            path = self._abspath(relpath)
123
138
            check_legal_path(path)
124
139
            fp = AtomicFile(path, 'wb', new_mode=mode)
125
140
        except (IOError, OSError),e:
146
161
        """Create a directory at the given path."""
147
162
        path = relpath
148
163
        try:
149
 
            path = self.local_abspath(relpath)
 
164
            path = self._abspath(relpath)
150
165
            os.mkdir(path)
151
166
            if mode is not None:
152
167
                os.chmod(path, mode)
154
169
            self._translate_error(e, path)
155
170
 
156
171
    def append(self, relpath, f, mode=None):
157
 
        """Append the text in the file-like object into the final
158
 
        location.
159
 
        """
 
172
        """Append the text in the file-like object into the final location."""
 
173
        abspath = self._abspath(relpath)
160
174
        try:
161
 
            fp = open(self.local_abspath(relpath), 'ab')
 
175
            fp = open(abspath, 'ab')
 
176
            # FIXME should we really be chmodding every time ? RBC 20060523
162
177
            if mode is not None:
163
 
                os.chmod(self.local_abspath(relpath), mode)
 
178
                os.chmod(abspath, mode)
164
179
        except (IOError, OSError),e:
165
180
            self._translate_error(e, relpath)
166
181
        # win32 workaround (tell on an unwritten file returns 0)
171
186
 
172
187
    def copy(self, rel_from, rel_to):
173
188
        """Copy the item at rel_from to the location at rel_to"""
174
 
        path_from = self.local_abspath(rel_from)
175
 
        path_to = self.local_abspath(rel_to)
 
189
        path_from = self._abspath(rel_from)
 
190
        path_to = self._abspath(rel_to)
176
191
        try:
177
192
            shutil.copy(path_from, path_to)
178
193
        except (IOError, OSError),e:
180
195
            self._translate_error(e, path_from)
181
196
 
182
197
    def rename(self, rel_from, rel_to):
183
 
        path_from = self.local_abspath(rel_from)
 
198
        path_from = self._abspath(rel_from)
184
199
        try:
185
200
            # *don't* call bzrlib.osutils.rename, because we want to 
186
201
            # detect errors on rename
187
 
            os.rename(path_from, self.local_abspath(rel_to))
 
202
            os.rename(path_from, self._abspath(rel_to))
188
203
        except (IOError, OSError),e:
189
204
            # TODO: What about path_to?
190
205
            self._translate_error(e, path_from)
191
206
 
192
207
    def move(self, rel_from, rel_to):
193
208
        """Move the item at rel_from to the location at rel_to"""
194
 
        path_from = self.local_abspath(rel_from)
195
 
        path_to = self.local_abspath(rel_to)
 
209
        path_from = self._abspath(rel_from)
 
210
        path_to = self._abspath(rel_to)
196
211
 
197
212
        try:
198
213
            # this version will delete the destination if necessary
205
220
        """Delete the item at relpath"""
206
221
        path = relpath
207
222
        try:
208
 
            path = self.local_abspath(relpath)
 
223
            path = self._abspath(relpath)
209
224
            os.remove(path)
210
225
        except (IOError, OSError),e:
211
 
            # TODO: What about path_to?
212
226
            self._translate_error(e, path)
213
227
 
214
228
    def copy_to(self, relpaths, other, mode=None, pb=None):
225
239
            for path in relpaths:
226
240
                self._update_pb(pb, 'copy-to', count, total)
227
241
                try:
228
 
                    mypath = self.local_abspath(path)
229
 
                    otherpath = other.local_abspath(path)
 
242
                    mypath = self._abspath(path)
 
243
                    otherpath = other._abspath(path)
230
244
                    shutil.copy(mypath, otherpath)
231
245
                    if mode is not None:
232
246
                        os.chmod(otherpath, mode)
246
260
        WARNING: many transports do not support this, so trying avoid using
247
261
        it if at all possible.
248
262
        """
249
 
        path = self.local_abspath(relpath)
 
263
        path = self._abspath(relpath)
250
264
        try:
251
265
            return [urlutils.escape(entry) for entry in os.listdir(path)]
252
266
        except (IOError, OSError), e:
257
271
        """
258
272
        path = relpath
259
273
        try:
260
 
            path = self.local_abspath(relpath)
 
274
            path = self._abspath(relpath)
261
275
            return os.stat(path)
262
276
        except (IOError, OSError),e:
263
277
            self._translate_error(e, path)
269
283
        from bzrlib.lock import ReadLock
270
284
        path = relpath
271
285
        try:
272
 
            path = self.local_abspath(relpath)
 
286
            path = self._abspath(relpath)
273
287
            return ReadLock(path)
274
288
        except (IOError, OSError), e:
275
289
            self._translate_error(e, path)
281
295
        :return: A lock object, which should be passed to Transport.unlock()
282
296
        """
283
297
        from bzrlib.lock import WriteLock
284
 
        return WriteLock(self.local_abspath(relpath))
 
298
        return WriteLock(self._abspath(relpath))
285
299
 
286
300
    def rmdir(self, relpath):
287
301
        """See Transport.rmdir."""
288
302
        path = relpath
289
303
        try:
290
 
            path = self.local_abspath(relpath)
 
304
            path = self._abspath(relpath)
291
305
            os.rmdir(path)
292
306
        except (IOError, OSError),e:
293
307
            self._translate_error(e, path)