~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/local.py

Exclude more files from dumb-rsync upload

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
 
"""Implementation of Transport for the local filesystem.
17
 
"""
18
 
 
 
16
 
 
17
"""Transport for the local filesystem.
 
18
 
 
19
This is a fairly thin wrapper on regular file IO."""
 
20
 
 
21
import os
 
22
import errno
 
23
import shutil
 
24
from stat import ST_MODE, S_ISDIR, ST_SIZE
 
25
import tempfile
 
26
import urllib
 
27
 
 
28
from bzrlib.trace import mutter
19
29
from bzrlib.transport import Transport, register_transport, \
20
30
    TransportError, NoSuchFile, FileExists
21
 
import os, errno
 
31
from bzrlib.osutils import abspath
22
32
 
23
33
class LocalTransportError(TransportError):
24
34
    pass
25
35
 
 
36
 
26
37
class LocalTransport(Transport):
27
38
    """This is the transport agent for local filesystem access."""
28
39
 
33
44
        # realpath is incompatible with symlinks. When we traverse
34
45
        # up we might be able to normpath stuff. RBC 20051003
35
46
        super(LocalTransport, self).__init__(
36
 
            os.path.normpath(os.path.abspath(base)))
 
47
            os.path.normpath(abspath(base)))
37
48
 
38
49
    def should_cache(self):
39
50
        return False
49
60
            return LocalTransport(self.abspath(offset))
50
61
 
51
62
    def abspath(self, relpath):
52
 
        """Return the full url to the given relative path.
 
63
        """Return the full url to the given relative URL.
53
64
        This can be supplied with a string or a list
54
65
        """
55
 
        if isinstance(relpath, basestring):
56
 
            relpath = [relpath]
57
 
        return os.path.join(self.base, *relpath)
 
66
        assert isinstance(relpath, basestring), (type(relpath), relpath)
 
67
        return os.path.join(self.base, urllib.unquote(relpath))
58
68
 
59
69
    def relpath(self, abspath):
60
70
        """Return the local path portion from a given absolute path.
61
71
        """
62
 
        from bzrlib.branch import _relpath
63
 
        return _relpath(self.base, abspath)
 
72
        from bzrlib.osutils import relpath
 
73
        if abspath is None:
 
74
            abspath = '.'
 
75
        return relpath(self.base, abspath)
64
76
 
65
77
    def has(self, relpath):
66
78
        return os.access(self.abspath(relpath), os.F_OK)
74
86
            path = self.abspath(relpath)
75
87
            return open(path, 'rb')
76
88
        except IOError,e:
77
 
            if e.errno == errno.ENOENT:
78
 
                raise NoSuchFile('File %r does not exist' % path, orig_error=e)
79
 
            raise LocalTransportError(orig_error=e)
80
 
 
81
 
    def get_partial(self, relpath, start, length=None):
82
 
        """Get just part of a file.
83
 
 
84
 
        :param relpath: Path to the file, relative to base
85
 
        :param start: The starting position to read from
86
 
        :param length: The length to read. A length of None indicates
87
 
                       read to the end of the file.
88
 
        :return: A file-like object containing at least the specified bytes.
89
 
                 Some implementations may return objects which can be read
90
 
                 past this length, but this is not guaranteed.
91
 
        """
92
 
        # LocalTransport.get_partial() doesn't care about the length
93
 
        # argument, because it is using a local file, and thus just
94
 
        # returns the file seek'ed to the appropriate location.
95
 
        try:
96
 
            path = self.abspath(relpath)
97
 
            f = open(path, 'rb')
98
 
            f.seek(start, 0)
99
 
            return f
100
 
        except IOError,e:
101
 
            if e.errno == errno.ENOENT:
102
 
                raise NoSuchFile('File %r does not exist' % path, orig_error=e)
 
89
            if e.errno in (errno.ENOENT, errno.ENOTDIR):
 
90
                raise NoSuchFile('File or directory %r does not exist' % path, orig_error=e)
103
91
            raise LocalTransportError(orig_error=e)
104
92
 
105
93
    def put(self, relpath, f):
123
111
        finally:
124
112
            fp.close()
125
113
 
 
114
    def iter_files_recursive(self):
 
115
        """Iter the relative paths of files in the transports sub-tree."""
 
116
        queue = list(self.list_dir('.'))
 
117
        while queue:
 
118
            relpath = urllib.quote(queue.pop(0))
 
119
            st = self.stat(relpath)
 
120
            if S_ISDIR(st[ST_MODE]):
 
121
                for i, basename in enumerate(self.list_dir(relpath)):
 
122
                    queue.insert(i, relpath+'/'+basename)
 
123
            else:
 
124
                yield relpath
 
125
 
126
126
    def mkdir(self, relpath):
127
127
        """Create a directory at the given path."""
128
128
        try:
183
183
            count = 0
184
184
            for path in relpaths:
185
185
                self._update_pb(pb, 'copy-to', count, total)
186
 
                shutil.copy(self.abspath(path), other.abspath(path))
 
186
                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)
187
192
                count += 1
188
193
            return count
189
194
        else:
190
195
            return super(LocalTransport, self).copy_to(relpaths, other, pb=pb)
191
196
 
 
197
    def listable(self):
 
198
        """See Transport.listable."""
 
199
        return True
192
200
 
193
201
    def list_dir(self, relpath):
194
202
        """Return a list of all files at the given location.
224
232
        from bzrlib.lock import WriteLock
225
233
        return WriteLock(self.abspath(relpath))
226
234
 
227
 
# If nothing else matches, try the LocalTransport
228
 
register_transport(None, LocalTransport)
229
 
register_transport('file://', LocalTransport)
 
235
 
 
236
class ScratchTransport(LocalTransport):
 
237
    """A transport that works in a temporary dir and cleans up after itself.
 
238
    
 
239
    The dir only exists for the lifetime of the Python object.
 
240
    Obviously you should not put anything precious in it.
 
241
    """
 
242
 
 
243
    def __init__(self, base=None):
 
244
        if base is None:
 
245
            base = tempfile.mkdtemp()
 
246
        super(ScratchTransport, self).__init__(base)
 
247
 
 
248
    def __del__(self):
 
249
        shutil.rmtree(self.base, ignore_errors=True)
 
250
        mutter("%r destroyed" % self)