~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/local.py

Merge from integration.

Show diffs side-by-side

added added

removed removed

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