~bzr-pqm/bzr/bzr.dev

1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
1
# Copyright (C) 2005, 2006 Canonical Ltd
1185.11.19 by John Arbash Meinel
Testing put and append, also testing agaist file-like objects as well as strings.
2
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1185.16.72 by Martin Pool
[merge] from robert and fix up tests
16
17
"""Transport for the local filesystem.
18
19
This is a fairly thin wrapper on regular file IO."""
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
20
1442.1.42 by Robert Collins
rebuild ScratchBranch on top of ScratchTransport
21
import os
22
import shutil
1608.2.5 by Martin Pool
Add Transport.supports_unix_modebits, so tests can
23
import sys
1442.1.44 by Robert Collins
Many transport related tweaks:
24
from stat import ST_MODE, S_ISDIR, ST_SIZE
1442.1.42 by Robert Collins
rebuild ScratchBranch on top of ScratchTransport
25
import tempfile
26
1551.2.56 by Aaron Bentley
Better illegal pathname check for Windows
27
from bzrlib.osutils import (abspath, realpath, normpath, pathjoin, rename, 
1685.1.52 by John Arbash Meinel
[merge] bzr.dev 1704
28
                            check_legal_path, rmtree)
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
29
from bzrlib.symbol_versioning import warn
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
30
from bzrlib.trace import mutter
31
from bzrlib.transport import Transport, Server
32
import bzrlib.urlutils as urlutils
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
33
1442.1.42 by Robert Collins
rebuild ScratchBranch on top of ScratchTransport
34
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
35
class LocalTransport(Transport):
36
    """This is the transport agent for local filesystem access."""
37
38
    def __init__(self, base):
39
        """Set the base path where files will be stored."""
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
40
        if not base.startswith('file://'):
41
            warn("Instantiating LocalTransport with a filesystem path"
42
                " is deprecated as of bzr 0.8."
43
                " Please use bzrlib.transport.get_transport()"
44
                " or pass in a file:// url.",
45
                 DeprecationWarning,
46
                 stacklevel=2
47
                 )
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
48
            base = urlutils.local_path_to_url(base)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
49
        if base[-1] != '/':
50
            base = base + '/'
51
        super(LocalTransport, self).__init__(base)
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
52
        self._local_base = urlutils.local_path_from_url(base)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
53
907.1.32 by John Arbash Meinel
Renaming is_remote to should_cache as it is more appropriate.
54
    def should_cache(self):
907.1.22 by John Arbash Meinel
Fixed some encoding issues, added is_remote function for Transport objects.
55
        return False
56
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
57
    def clone(self, offset=None):
58
        """Return a new LocalTransport with root at self.base + offset
59
        Because the local filesystem does not require a connection, 
60
        we can just return a new object.
61
        """
62
        if offset is None:
63
            return LocalTransport(self.base)
64
        else:
65
            return LocalTransport(self.abspath(offset))
66
907.1.8 by John Arbash Meinel
Changed the format for abspath. Updated branch to use a hidden _transport
67
    def abspath(self, relpath):
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
68
        """Return the full url to the given relative URL."""
1185.12.70 by Aaron Bentley
Removed b
69
        assert isinstance(relpath, basestring), (type(relpath), relpath)
1685.1.12 by John Arbash Meinel
Some more work to get LocalTransport to only support URLs
70
        # jam 20060426 Using normpath on the real path, because that ensures
71
        #       proper handling of stuff like
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
72
        path = normpath(pathjoin(self._local_base, urlutils.unescape(relpath)))
73
        return urlutils.local_path_to_url(path)
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
74
75
    def local_abspath(self, relpath):
76
        """Transform the given relative path URL into the actual path on disk
77
78
        This function only exists for the LocalTransport, since it is
79
        the only one that has direct local access.
80
        This is mostly for stuff like WorkingTree which needs to know
81
        the local working directory.
82
        """
83
        absurl = self.abspath(relpath)
84
        # mutter(u'relpath %s => base: %s, absurl %s', relpath, self.base, absurl)
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
85
        return urlutils.local_path_from_url(absurl)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
86
907.1.24 by John Arbash Meinel
Remote functionality work.
87
    def relpath(self, abspath):
88
        """Return the local path portion from a given absolute path.
89
        """
1442.1.64 by Robert Collins
Branch.open_containing now returns a tuple (Branch, relative-path).
90
        if abspath is None:
1185.33.66 by Martin Pool
[patch] use unicode literals for all hardcoded paths (Alexander Belchenko)
91
            abspath = u'.'
1551.2.53 by abentley
Strip trailing slashes in a platform-sensible way
92
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
93
        return urlutils.file_relpath(
94
            urlutils.strip_trailing_slash(self.base), 
95
            urlutils.strip_trailing_slash(abspath))
907.1.24 by John Arbash Meinel
Remote functionality work.
96
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
97
    def has(self, relpath):
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
98
        return os.access(self.local_abspath(relpath), os.F_OK)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
99
907.1.50 by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown.
100
    def get(self, relpath):
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
101
        """Get the file at the given relative path.
907.1.20 by John Arbash Meinel
Removed Transport.open(), making get + put encode/decode to utf-8
102
103
        :param relpath: The relative path to the file
104
        """
907.1.48 by John Arbash Meinel
Updated LocalTransport by passing it through the transport_test suite, and got it to pass.
105
        try:
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
106
            path = self.local_abspath(relpath)
107
            # mutter('LocalTransport.get(%r) => %r', relpath, path)
907.1.50 by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown.
108
            return open(path, 'rb')
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
109
        except (IOError, OSError),e:
110
            self._translate_error(e, path)
907.1.20 by John Arbash Meinel
Removed Transport.open(), making get + put encode/decode to utf-8
111
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
112
    def put(self, relpath, f, mode=None):
907.1.20 by John Arbash Meinel
Removed Transport.open(), making get + put encode/decode to utf-8
113
        """Copy the file-like or string object into the location.
114
115
        :param relpath: Location to put the contents, relative to base.
116
        :param f:       File-like or string object.
117
        """
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
118
        from bzrlib.atomicfile import AtomicFile
119
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
120
        path = relpath
907.1.48 by John Arbash Meinel
Updated LocalTransport by passing it through the transport_test suite, and got it to pass.
121
        try:
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
122
            path = self.local_abspath(relpath)
1551.2.56 by Aaron Bentley
Better illegal pathname check for Windows
123
            check_legal_path(path)
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
124
            fp = AtomicFile(path, 'wb', new_mode=mode)
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
125
        except (IOError, OSError),e:
126
            self._translate_error(e, path)
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
127
        try:
128
            self._pump(f, fp)
129
            fp.commit()
130
        finally:
131
            fp.close()
132
1442.1.44 by Robert Collins
Many transport related tweaks:
133
    def iter_files_recursive(self):
134
        """Iter the relative paths of files in the transports sub-tree."""
1185.33.66 by Martin Pool
[patch] use unicode literals for all hardcoded paths (Alexander Belchenko)
135
        queue = list(self.list_dir(u'.'))
1442.1.44 by Robert Collins
Many transport related tweaks:
136
        while queue:
1608.1.1 by Martin Pool
[patch] LocalTransport.list_dir should return url-quoted strings (ddaa)
137
            relpath = queue.pop(0)
1442.1.44 by Robert Collins
Many transport related tweaks:
138
            st = self.stat(relpath)
139
            if S_ISDIR(st[ST_MODE]):
140
                for i, basename in enumerate(self.list_dir(relpath)):
141
                    queue.insert(i, relpath+'/'+basename)
142
            else:
143
                yield relpath
144
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
145
    def mkdir(self, relpath, mode=None):
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
146
        """Create a directory at the given path."""
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
147
        path = relpath
907.1.48 by John Arbash Meinel
Updated LocalTransport by passing it through the transport_test suite, and got it to pass.
148
        try:
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
149
            path = self.local_abspath(relpath)
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
150
            os.mkdir(path)
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
151
            if mode is not None:
152
                os.chmod(path, mode)
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
153
        except (IOError, OSError),e:
154
            self._translate_error(e, path)
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
155
1666.1.6 by Robert Collins
Make knit the default format.
156
    def append(self, relpath, f, mode=None):
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
157
        """Append the text in the file-like object into the final
158
        location.
159
        """
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
160
        try:
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
161
            fp = open(self.local_abspath(relpath), 'ab')
1666.1.6 by Robert Collins
Make knit the default format.
162
            if mode is not None:
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
163
                os.chmod(self.local_abspath(relpath), mode)
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
164
        except (IOError, OSError),e:
165
            self._translate_error(e, relpath)
1551.2.38 by abentley
Fixed win32 bug with tell
166
        # win32 workaround (tell on an unwritten file returns 0)
167
        fp.seek(0, 2)
1563.2.3 by Robert Collins
Change the return signature of transport.append and append_multi to return the length of the pre-append content.
168
        result = fp.tell()
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
169
        self._pump(f, fp)
1563.2.3 by Robert Collins
Change the return signature of transport.append and append_multi to return the length of the pre-append content.
170
        return result
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
171
172
    def copy(self, rel_from, rel_to):
173
        """Copy the item at rel_from to the location at rel_to"""
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
174
        path_from = self.local_abspath(rel_from)
175
        path_to = self.local_abspath(rel_to)
907.1.48 by John Arbash Meinel
Updated LocalTransport by passing it through the transport_test suite, and got it to pass.
176
        try:
177
            shutil.copy(path_from, path_to)
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
178
        except (IOError, OSError),e:
179
            # TODO: What about path_to?
180
            self._translate_error(e, path_from)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
181
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
182
    def rename(self, rel_from, rel_to):
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
183
        path_from = self.local_abspath(rel_from)
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
184
        try:
185
            # *don't* call bzrlib.osutils.rename, because we want to 
186
            # detect errors on rename
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
187
            os.rename(path_from, self.local_abspath(rel_to))
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
188
        except (IOError, OSError),e:
189
            # TODO: What about path_to?
190
            self._translate_error(e, path_from)
191
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
192
    def move(self, rel_from, rel_to):
193
        """Move the item at rel_from to the location at rel_to"""
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
194
        path_from = self.local_abspath(rel_from)
195
        path_to = self.local_abspath(rel_to)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
196
907.1.48 by John Arbash Meinel
Updated LocalTransport by passing it through the transport_test suite, and got it to pass.
197
        try:
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
198
            # this version will delete the destination if necessary
1185.31.58 by John Arbash Meinel
Updating for new transport tests so that they pass on win32
199
            rename(path_from, path_to)
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
200
        except (IOError, OSError),e:
201
            # TODO: What about path_to?
202
            self._translate_error(e, path_from)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
203
204
    def delete(self, relpath):
205
        """Delete the item at relpath"""
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
206
        path = relpath
907.1.48 by John Arbash Meinel
Updated LocalTransport by passing it through the transport_test suite, and got it to pass.
207
        try:
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
208
            path = self.local_abspath(relpath)
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
209
            os.remove(path)
210
        except (IOError, OSError),e:
211
            # TODO: What about path_to?
212
            self._translate_error(e, path)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
213
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
214
    def copy_to(self, relpaths, other, mode=None, pb=None):
907.1.28 by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function.
215
        """Copy a set of entries from self into another Transport.
216
217
        :param relpaths: A list/generator of entries to be copied.
218
        """
219
        if isinstance(other, LocalTransport):
220
            # Both from & to are on the local filesystem
221
            # Unfortunately, I can't think of anything faster than just
222
            # copying them across, one by one :(
223
            total = self._get_total(relpaths)
224
            count = 0
225
            for path in relpaths:
226
                self._update_pb(pb, 'copy-to', count, total)
1185.16.158 by John Arbash Meinel
Added a test that copy_to raises NoSuchFile when a directory is missing (not IOError)
227
                try:
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
228
                    mypath = self.local_abspath(path)
229
                    otherpath = other.local_abspath(path)
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
230
                    shutil.copy(mypath, otherpath)
231
                    if mode is not None:
232
                        os.chmod(otherpath, mode)
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
233
                except (IOError, OSError),e:
234
                    self._translate_error(e, path)
907.1.28 by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function.
235
                count += 1
236
            return count
237
        else:
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
238
            return super(LocalTransport, self).copy_to(relpaths, other, mode=mode, pb=pb)
907.1.28 by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function.
239
1400.1.1 by Robert Collins
implement a basic test for the ui branch command from http servers
240
    def listable(self):
241
        """See Transport.listable."""
242
        return True
907.1.28 by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function.
243
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
244
    def list_dir(self, relpath):
245
        """Return a list of all files at the given location.
246
        WARNING: many transports do not support this, so trying avoid using
247
        it if at all possible.
248
        """
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
249
        path = self.local_abspath(relpath)
907.1.48 by John Arbash Meinel
Updated LocalTransport by passing it through the transport_test suite, and got it to pass.
250
        try:
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
251
            return [urlutils.escape(entry) for entry in os.listdir(path)]
1607.1.3 by Robert Collins
Apply David Allouches list_dir quoting fix.
252
        except (IOError, OSError), e:
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
253
            self._translate_error(e, path)
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
254
255
    def stat(self, relpath):
256
        """Return the stat information for a file.
257
        """
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
258
        path = relpath
907.1.48 by John Arbash Meinel
Updated LocalTransport by passing it through the transport_test suite, and got it to pass.
259
        try:
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
260
            path = self.local_abspath(relpath)
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
261
            return os.stat(path)
262
        except (IOError, OSError),e:
263
            self._translate_error(e, path)
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
264
907.1.24 by John Arbash Meinel
Remote functionality work.
265
    def lock_read(self, relpath):
266
        """Lock the given file for shared (read) access.
267
        :return: A lock object, which should be passed to Transport.unlock()
268
        """
269
        from bzrlib.lock import ReadLock
1185.65.29 by Robert Collins
Implement final review suggestions.
270
        path = relpath
271
        try:
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
272
            path = self.local_abspath(relpath)
1185.65.29 by Robert Collins
Implement final review suggestions.
273
            return ReadLock(path)
274
        except (IOError, OSError), e:
275
            self._translate_error(e, path)
907.1.24 by John Arbash Meinel
Remote functionality work.
276
277
    def lock_write(self, relpath):
278
        """Lock the given file for exclusive (write) access.
279
        WARNING: many transports do not support this, so trying avoid using it
280
281
        :return: A lock object, which should be passed to Transport.unlock()
282
        """
283
        from bzrlib.lock import WriteLock
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
284
        return WriteLock(self.local_abspath(relpath))
907.1.24 by John Arbash Meinel
Remote functionality work.
285
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
286
    def rmdir(self, relpath):
287
        """See Transport.rmdir."""
288
        path = relpath
289
        try:
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
290
            path = self.local_abspath(relpath)
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
291
            os.rmdir(path)
292
        except (IOError, OSError),e:
293
            self._translate_error(e, path)
1442.1.41 by Robert Collins
move duplicate scratch logic into a scratch transport
294
1608.2.7 by Martin Pool
Rename supports_unix_modebits to _can_roundtrip_unix_modebits for clarity
295
    def _can_roundtrip_unix_modebits(self):
1608.2.5 by Martin Pool
Add Transport.supports_unix_modebits, so tests can
296
        if sys.platform == 'win32':
297
            # anyone else?
298
            return False
299
        else:
300
            return True
301
302
1442.1.41 by Robert Collins
move duplicate scratch logic into a scratch transport
303
class ScratchTransport(LocalTransport):
304
    """A transport that works in a temporary dir and cleans up after itself.
305
    
306
    The dir only exists for the lifetime of the Python object.
307
    Obviously you should not put anything precious in it.
308
    """
309
1442.1.42 by Robert Collins
rebuild ScratchBranch on top of ScratchTransport
310
    def __init__(self, base=None):
311
        if base is None:
312
            base = tempfile.mkdtemp()
1442.1.41 by Robert Collins
move duplicate scratch logic into a scratch transport
313
        super(ScratchTransport, self).__init__(base)
314
315
    def __del__(self):
1692.7.6 by Martin Pool
[patch] force deletion of trees containing readonly files (alexander)
316
        rmtree(self.base, ignore_errors=True)
1442.1.41 by Robert Collins
move duplicate scratch logic into a scratch transport
317
        mutter("%r destroyed" % self)
1530.1.1 by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter.
318
319
1530.1.3 by Robert Collins
transport implementations now tested consistently.
320
class LocalRelpathServer(Server):
1530.1.1 by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter.
321
    """A pretend server for local transports, using relpaths."""
322
1530.1.3 by Robert Collins
transport implementations now tested consistently.
323
    def get_url(self):
324
        """See Transport.Server.get_url."""
325
        return "."
326
327
328
class LocalAbspathServer(Server):
1530.1.1 by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter.
329
    """A pretend server for local transports, using absolute paths."""
330
1530.1.3 by Robert Collins
transport implementations now tested consistently.
331
    def get_url(self):
332
        """See Transport.Server.get_url."""
333
        return os.path.abspath("")
334
335
336
class LocalURLServer(Server):
1530.1.1 by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter.
337
    """A pretend server for local transports, using file:// urls."""
1530.1.3 by Robert Collins
transport implementations now tested consistently.
338
339
    def get_url(self):
340
        """See Transport.Server.get_url."""
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
341
        return urlutils.local_path_to_url('')
1530.1.11 by Robert Collins
Push the transport permutations list into each transport module allowing for automatic testing of new modules that are registered as transports.
342
343
344
def get_test_permutations():
345
    """Return the permutations to be used in testing."""
346
    return [(LocalTransport, LocalRelpathServer),
347
            (LocalTransport, LocalAbspathServer),
348
            (LocalTransport, LocalURLServer),
349
            ]