~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/local.py

Merged mailine

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
import urllib
26
26
 
27
27
from bzrlib.trace import mutter
28
 
from bzrlib.transport import Transport
29
 
from bzrlib.osutils import abspath
 
28
from bzrlib.transport import Transport, Server
 
29
from bzrlib.osutils import abspath, realpath, normpath, pathjoin, rename
30
30
 
31
31
 
32
32
class LocalTransport(Transport):
38
38
            base = base[7:]
39
39
        # realpath is incompatible with symlinks. When we traverse
40
40
        # up we might be able to normpath stuff. RBC 20051003
41
 
        super(LocalTransport, self).__init__(
42
 
            os.path.normpath(abspath(base)))
 
41
        base = normpath(abspath(base))
 
42
        if base[-1] != '/':
 
43
            base = base + '/'
 
44
        super(LocalTransport, self).__init__(base)
43
45
 
44
46
    def should_cache(self):
45
47
        return False
59
61
        This can be supplied with a string or a list
60
62
        """
61
63
        assert isinstance(relpath, basestring), (type(relpath), relpath)
62
 
        return os.path.join(self.base, urllib.unquote(relpath))
 
64
        return pathjoin(self.base, urllib.unquote(relpath))
63
65
 
64
66
    def relpath(self, abspath):
65
67
        """Return the local path portion from a given absolute path.
67
69
        from bzrlib.osutils import relpath
68
70
        if abspath is None:
69
71
            abspath = u'.'
70
 
        return relpath(self.base, abspath)
 
72
        if abspath.endswith('/'):
 
73
            abspath = abspath[:-1]
 
74
        return relpath(self.base[:-1], abspath)
71
75
 
72
76
    def has(self, relpath):
73
77
        return os.access(self.abspath(relpath), os.F_OK)
83
87
        except (IOError, OSError),e:
84
88
            self._translate_error(e, path)
85
89
 
86
 
    def put(self, relpath, f):
 
90
    def put(self, relpath, f, mode=None):
87
91
        """Copy the file-like or string object into the location.
88
92
 
89
93
        :param relpath: Location to put the contents, relative to base.
94
98
        path = relpath
95
99
        try:
96
100
            path = self.abspath(relpath)
97
 
            fp = AtomicFile(path, 'wb')
 
101
            fp = AtomicFile(path, 'wb', new_mode=mode)
98
102
        except (IOError, OSError),e:
99
103
            self._translate_error(e, path)
100
104
        try:
115
119
            else:
116
120
                yield relpath
117
121
 
118
 
    def mkdir(self, relpath):
 
122
    def mkdir(self, relpath, mode=None):
119
123
        """Create a directory at the given path."""
120
124
        path = relpath
121
125
        try:
122
126
            path = self.abspath(relpath)
123
127
            os.mkdir(path)
 
128
            if mode is not None:
 
129
                os.chmod(path, mode)
124
130
        except (IOError, OSError),e:
125
131
            self._translate_error(e, path)
126
132
 
128
134
        """Append the text in the file-like object into the final
129
135
        location.
130
136
        """
131
 
        fp = open(self.abspath(relpath), 'ab')
 
137
        try:
 
138
            fp = open(self.abspath(relpath), 'ab')
 
139
        except (IOError, OSError),e:
 
140
            self._translate_error(e, relpath)
132
141
        self._pump(f, fp)
133
142
 
134
143
    def copy(self, rel_from, rel_to):
148
157
        path_to = self.abspath(rel_to)
149
158
 
150
159
        try:
151
 
            os.rename(path_from, path_to)
 
160
            rename(path_from, path_to)
152
161
        except (IOError, OSError),e:
153
162
            # TODO: What about path_to?
154
163
            self._translate_error(e, path_from)
163
172
            # TODO: What about path_to?
164
173
            self._translate_error(e, path)
165
174
 
166
 
    def copy_to(self, relpaths, other, pb=None):
 
175
    def copy_to(self, relpaths, other, mode=None, pb=None):
167
176
        """Copy a set of entries from self into another Transport.
168
177
 
169
178
        :param relpaths: A list/generator of entries to be copied.
179
188
            for path in relpaths:
180
189
                self._update_pb(pb, 'copy-to', count, total)
181
190
                try:
182
 
                    shutil.copy(self.abspath(path), other.abspath(path))
 
191
                    mypath = self.abspath(path)
 
192
                    otherpath = other.abspath(path)
 
193
                    shutil.copy(mypath, otherpath)
 
194
                    if mode is not None:
 
195
                        os.chmod(otherpath, mode)
183
196
                except (IOError, OSError),e:
184
197
                    self._translate_error(e, path)
185
198
                count += 1
186
199
            return count
187
200
        else:
188
 
            return super(LocalTransport, self).copy_to(relpaths, other, pb=pb)
 
201
            return super(LocalTransport, self).copy_to(relpaths, other, mode=mode, pb=pb)
189
202
 
190
203
    def listable(self):
191
204
        """See Transport.listable."""
245
258
    def __del__(self):
246
259
        shutil.rmtree(self.base, ignore_errors=True)
247
260
        mutter("%r destroyed" % self)
 
261
 
 
262
 
 
263
class LocalRelpathServer(Server):
 
264
    """A pretend server for local transports, using relpaths."""
 
265
 
 
266
    def get_url(self):
 
267
        """See Transport.Server.get_url."""
 
268
        return "."
 
269
 
 
270
 
 
271
class LocalAbspathServer(Server):
 
272
    """A pretend server for local transports, using absolute paths."""
 
273
 
 
274
    def get_url(self):
 
275
        """See Transport.Server.get_url."""
 
276
        return os.path.abspath("")
 
277
 
 
278
 
 
279
class LocalURLServer(Server):
 
280
    """A pretend server for local transports, using file:// urls."""
 
281
 
 
282
    def get_url(self):
 
283
        """See Transport.Server.get_url."""
 
284
        # FIXME: \ to / on windows
 
285
        return "file://%s" % os.path.abspath("")
 
286
 
 
287
 
 
288
def get_test_permutations():
 
289
    """Return the permutations to be used in testing."""
 
290
    return [(LocalTransport, LocalRelpathServer),
 
291
            (LocalTransport, LocalAbspathServer),
 
292
            (LocalTransport, LocalURLServer),
 
293
            ]