/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/transport/local.py

  • Committer: Jelmer Vernooij
  • Date: 2020-08-22 22:46:24 UTC
  • mfrom: (7490.40.105 work)
  • mto: This revision was merged to the branch mainline in revision 7521.
  • Revision ID: jelmer@jelmer.uk-20200822224624-om4a4idsr7cn8jew
merge lp:brz/3.1.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005-2012, 2016 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
20
20
"""
21
21
 
22
22
import os
23
 
from stat import ST_MODE, S_ISDIR, ST_SIZE, S_IMODE
 
23
from stat import ST_MODE, S_ISDIR, S_IMODE
24
24
import sys
25
25
 
26
 
from bzrlib.lazy_import import lazy_import
 
26
from ..lazy_import import lazy_import
27
27
lazy_import(globals(), """
28
28
import errno
29
29
import shutil
30
30
 
31
 
from bzrlib import (
 
31
from breezy import (
32
32
    atomicfile,
33
33
    osutils,
34
34
    urlutils,
35
 
    symbol_versioning,
36
 
    transport,
37
35
    )
38
 
from bzrlib.trace import mutter
39
 
from bzrlib.transport import LateReadError
 
36
from breezy.transport import LateReadError
40
37
""")
41
38
 
42
 
from bzrlib import transport
 
39
from .. import transport
43
40
 
44
41
 
45
42
_append_flags = os.O_CREAT | os.O_APPEND | os.O_WRONLY | osutils.O_BINARY | osutils.O_NOINHERIT
52
49
    def __init__(self, base):
53
50
        """Set the base path where files will be stored."""
54
51
        if not base.startswith('file://'):
55
 
            symbol_versioning.warn(
56
 
                "Instantiating LocalTransport with a filesystem path"
57
 
                " is deprecated as of bzr 0.8."
58
 
                " Please use bzrlib.transport.get_transport()"
59
 
                " or pass in a file:// url.",
60
 
                 DeprecationWarning,
61
 
                 stacklevel=2
62
 
                 )
63
 
            base = urlutils.local_path_to_url(base)
 
52
            raise AssertionError("not a file:// url: %r" % base)
64
53
        if base[-1] != '/':
65
54
            base = base + '/'
66
55
 
74
63
 
75
64
        super(LocalTransport, self).__init__(base)
76
65
        self._local_base = urlutils.local_path_from_url(base)
 
66
        if self._local_base[-1] != '/':
 
67
            self._local_base = self._local_base + '/'
77
68
 
78
69
    def clone(self, offset=None):
79
70
        """Return a new LocalTransport with root at self.base + offset
99
90
         - relative_reference is url escaped.
100
91
        """
101
92
        if relative_reference in ('.', ''):
102
 
            return self._local_base
 
93
            # _local_base normally has a trailing slash; strip it so that stat
 
94
            # on a transport pointing to a symlink reads the link not the
 
95
            # referent but be careful of / and c:\
 
96
            return osutils.split(self._local_base)[0]
103
97
        return self._local_base + urlutils.unescape(relative_reference)
104
98
 
105
99
    def abspath(self, relpath):
108
102
        # jam 20060426 Using normpath on the real path, because that ensures
109
103
        #       proper handling of stuff like
110
104
        path = osutils.normpath(osutils.pathjoin(
111
 
                    self._local_base, urlutils.unescape(relpath)))
 
105
            self._local_base, urlutils.unescape(relpath)))
112
106
        # on windows, our _local_base may or may not have a drive specified
113
107
        # (ie, it may be "/" or "c:/foo").
114
108
        # If 'relpath' is '/' we *always* get back an abspath without
116
110
        # we want our abspaths to have a drive letter too - so handle that
117
111
        # here.
118
112
        if (sys.platform == "win32" and self._local_base[1:2] == ":"
119
 
            and path == '/'):
 
113
                and path == '/'):
120
114
            path = self._local_base[:3]
121
115
 
122
116
        return urlutils.local_path_to_url(path)
143
137
        if abspath is None:
144
138
            abspath = u'.'
145
139
 
146
 
        return urlutils.file_relpath(
147
 
            urlutils.strip_trailing_slash(self.base),
148
 
            urlutils.strip_trailing_slash(abspath))
 
140
        return urlutils.file_relpath(self.base, abspath)
149
141
 
150
142
    def has(self, relpath):
151
143
        return os.access(self._abspath(relpath), os.F_OK)
161
153
        try:
162
154
            path = self._abspath(relpath)
163
155
            return osutils.open_file(path, 'rb')
164
 
        except (IOError, OSError),e:
 
156
        except (IOError, OSError) as e:
165
157
            if e.errno == errno.EISDIR:
166
158
                return LateReadError(relpath)
167
159
            self._translate_error(e, path)
180
172
            path = self._abspath(relpath)
181
173
            osutils.check_legal_path(path)
182
174
            fp = atomicfile.AtomicFile(path, 'wb', new_mode=mode)
183
 
        except (IOError, OSError),e:
 
175
        except (IOError, OSError) as e:
184
176
            self._translate_error(e, path)
185
177
        try:
186
178
            length = self._pump(f, fp)
189
181
            fp.close()
190
182
        return length
191
183
 
192
 
    def put_bytes(self, relpath, bytes, mode=None):
 
184
    def put_bytes(self, relpath, raw_bytes, mode=None):
193
185
        """Copy the string into the location.
194
186
 
195
187
        :param relpath: Location to put the contents, relative to base.
196
 
        :param bytes:   String
 
188
        :param raw_bytes:   String
197
189
        """
198
 
 
 
190
        if not isinstance(raw_bytes, bytes):
 
191
            raise TypeError(
 
192
                'raw_bytes must be bytes, not %s' % type(raw_bytes))
199
193
        path = relpath
200
194
        try:
201
195
            path = self._abspath(relpath)
202
196
            osutils.check_legal_path(path)
203
197
            fp = atomicfile.AtomicFile(path, 'wb', new_mode=mode)
204
 
        except (IOError, OSError),e:
 
198
        except (IOError, OSError) as e:
205
199
            self._translate_error(e, path)
206
200
        try:
207
201
            if bytes:
208
 
                fp.write(bytes)
 
202
                fp.write(raw_bytes)
209
203
            fp.commit()
210
204
        finally:
211
205
            fp.close()
228
222
        abspath = self._abspath(relpath)
229
223
        if mode is None:
230
224
            # os.open() will automatically use the umask
231
 
            local_mode = 0666
 
225
            local_mode = 0o666
232
226
        else:
233
227
            local_mode = mode
234
228
        try:
235
229
            fd = os.open(abspath, _put_non_atomic_flags, local_mode)
236
 
        except (IOError, OSError),e:
 
230
        except (IOError, OSError) as e:
237
231
            # We couldn't create the file, maybe we need to create
238
232
            # the parent directory, and try again
239
233
            if (not create_parent_dir
240
 
                or e.errno not in (errno.ENOENT,errno.ENOTDIR)):
 
234
                    or e.errno not in (errno.ENOENT, errno.ENOTDIR)):
241
235
                self._translate_error(e, relpath)
242
236
            parent_dir = os.path.dirname(abspath)
243
237
            if not parent_dir:
247
241
            # file again
248
242
            try:
249
243
                fd = os.open(abspath, _put_non_atomic_flags, local_mode)
250
 
            except (IOError, OSError), e:
 
244
            except (IOError, OSError) as e:
251
245
                self._translate_error(e, relpath)
252
246
        try:
253
247
            st = os.fstat(fd)
254
248
            if mode is not None and mode != S_IMODE(st.st_mode):
255
249
                # Because of umask, we may still need to chmod the file.
256
250
                # But in the general case, we won't have to
257
 
                os.chmod(abspath, mode)
 
251
                osutils.chmod_if_possible(abspath, mode)
258
252
            writer(fd)
259
253
        finally:
260
254
            os.close(fd)
300
294
            st = self.stat(relpath)
301
295
            if S_ISDIR(st[ST_MODE]):
302
296
                for i, basename in enumerate(self.list_dir(relpath)):
303
 
                    queue.insert(i, relpath+'/'+basename)
 
297
                    queue.insert(i, relpath + '/' + basename)
304
298
            else:
305
299
                yield relpath
306
300
 
308
302
        """Create a real directory, filtering through mode"""
309
303
        if mode is None:
310
304
            # os.mkdir() will filter through umask
311
 
            local_mode = 0777
 
305
            local_mode = 0o777
312
306
        else:
313
307
            local_mode = mode
314
308
        try:
315
309
            os.mkdir(abspath, local_mode)
316
 
            if mode is not None:
317
 
                # It is probably faster to just do the chmod, rather than
318
 
                # doing a stat, and then trying to compare
319
 
                os.chmod(abspath, mode)
320
 
        except (IOError, OSError),e:
 
310
        except (IOError, OSError) as e:
321
311
            self._translate_error(e, abspath)
 
312
        if mode is not None:
 
313
            try:
 
314
                osutils.chmod_if_possible(abspath, mode)
 
315
            except (IOError, OSError) as e:
 
316
                self._translate_error(e, abspath)
322
317
 
323
318
    def mkdir(self, relpath, mode=None):
324
319
        """Create a directory at the given path."""
326
321
 
327
322
    def open_write_stream(self, relpath, mode=None):
328
323
        """See Transport.open_write_stream."""
329
 
        # initialise the file
330
 
        self.put_bytes_non_atomic(relpath, "", mode=mode)
331
324
        abspath = self._abspath(relpath)
332
 
        handle = osutils.open_file(abspath, 'wb')
 
325
        try:
 
326
            handle = osutils.open_file(abspath, 'wb')
 
327
        except (IOError, OSError) as e:
 
328
            self._translate_error(e, abspath)
 
329
        handle.truncate()
333
330
        if mode is not None:
334
331
            self._check_mode_and_size(abspath, handle.fileno(), mode)
335
332
        transport._file_streams[self.abspath(relpath)] = handle
340
337
        file_abspath = self._abspath(relpath)
341
338
        if mode is None:
342
339
            # os.open() will automatically use the umask
343
 
            local_mode = 0666
 
340
            local_mode = 0o666
344
341
        else:
345
342
            local_mode = mode
346
343
        try:
347
344
            return file_abspath, os.open(file_abspath, _append_flags, local_mode)
348
 
        except (IOError, OSError),e:
 
345
        except (IOError, OSError) as e:
349
346
            self._translate_error(e, relpath)
350
347
 
351
348
    def _check_mode_and_size(self, file_abspath, fd, mode=None):
354
351
        if mode is not None and mode != S_IMODE(st.st_mode):
355
352
            # Because of umask, we may still need to chmod the file.
356
353
            # But in the general case, we won't have to
357
 
            os.chmod(file_abspath, mode)
 
354
            osutils.chmod_if_possible(file_abspath, mode)
358
355
        return st.st_size
359
356
 
360
357
    def append_file(self, relpath, f, mode=None):
393
390
        path_to = self._abspath(rel_to)
394
391
        try:
395
392
            shutil.copy(path_from, path_to)
396
 
        except (IOError, OSError),e:
 
393
        except (IOError, OSError) as e:
397
394
            # TODO: What about path_to?
398
395
            self._translate_error(e, path_from)
399
396
 
401
398
        path_from = self._abspath(rel_from)
402
399
        path_to = self._abspath(rel_to)
403
400
        try:
404
 
            # *don't* call bzrlib.osutils.rename, because we want to
 
401
            # *don't* call breezy.osutils.rename, because we want to
405
402
            # detect conflicting names on rename, and osutils.rename tries to
406
 
            # mask cross-platform differences there; however we do update the
407
 
            # exception to include the filenames
 
403
            # mask cross-platform differences there
408
404
            os.rename(path_from, path_to)
409
 
        except (IOError, OSError),e:
 
405
        except (IOError, OSError) as e:
410
406
            # TODO: What about path_to?
411
 
            self._translate_error(
412
 
                osutils._add_rename_error_details(e, path_from, path_to),
413
 
                path_from)
 
407
            self._translate_error(e, path_from)
414
408
 
415
409
    def move(self, rel_from, rel_to):
416
410
        """Move the item at rel_from to the location at rel_to"""
420
414
        try:
421
415
            # this version will delete the destination if necessary
422
416
            osutils.rename(path_from, path_to)
423
 
        except (IOError, OSError),e:
 
417
        except (IOError, OSError) as e:
424
418
            # TODO: What about path_to?
425
419
            self._translate_error(e, path_from)
426
420
 
430
424
        try:
431
425
            path = self._abspath(relpath)
432
426
            os.remove(path)
433
 
        except (IOError, OSError),e:
 
427
        except (IOError, OSError) as e:
434
428
            self._translate_error(e, path)
435
429
 
436
430
    def external_url(self):
437
 
        """See bzrlib.transport.Transport.external_url."""
 
431
        """See breezy.transport.Transport.external_url."""
438
432
        # File URL's are externally usable.
439
433
        return self.base
440
434
 
456
450
                    otherpath = other._abspath(path)
457
451
                    shutil.copy(mypath, otherpath)
458
452
                    if mode is not None:
459
 
                        os.chmod(otherpath, mode)
460
 
                except (IOError, OSError),e:
 
453
                        osutils.chmod_if_possible(otherpath, mode)
 
454
                except (IOError, OSError) as e:
461
455
                    self._translate_error(e, path)
462
456
                count += 1
463
457
            return count
476
470
        path = self._abspath(relpath)
477
471
        try:
478
472
            entries = os.listdir(path)
479
 
        except (IOError, OSError), e:
 
473
        except (IOError, OSError) as e:
480
474
            self._translate_error(e, path)
481
475
        return [urlutils.escape(entry) for entry in entries]
482
476
 
487
481
        try:
488
482
            path = self._abspath(relpath)
489
483
            return os.lstat(path)
490
 
        except (IOError, OSError),e:
 
484
        except (IOError, OSError) as e:
491
485
            self._translate_error(e, path)
492
486
 
493
487
    def lock_read(self, relpath):
494
488
        """Lock the given file for shared (read) access.
495
489
        :return: A lock object, which should be passed to Transport.unlock()
496
490
        """
497
 
        from bzrlib.lock import ReadLock
 
491
        from breezy.lock import ReadLock
498
492
        path = relpath
499
493
        try:
500
494
            path = self._abspath(relpath)
501
495
            return ReadLock(path)
502
 
        except (IOError, OSError), e:
 
496
        except (IOError, OSError) as e:
503
497
            self._translate_error(e, path)
504
498
 
505
499
    def lock_write(self, relpath):
508
502
 
509
503
        :return: A lock object, which should be passed to Transport.unlock()
510
504
        """
511
 
        from bzrlib.lock import WriteLock
 
505
        from breezy.lock import WriteLock
512
506
        return WriteLock(self._abspath(relpath))
513
507
 
514
508
    def rmdir(self, relpath):
517
511
        try:
518
512
            path = self._abspath(relpath)
519
513
            os.rmdir(path)
520
 
        except (IOError, OSError),e:
 
514
        except (IOError, OSError) as e:
521
515
            self._translate_error(e, path)
522
516
 
523
517
    if osutils.host_os_dereferences_symlinks():
524
518
        def readlink(self, relpath):
525
519
            """See Transport.readlink."""
526
 
            return osutils.readlink(self._abspath(relpath))
 
520
            try:
 
521
                return osutils.readlink(self._abspath(relpath))
 
522
            except (IOError, OSError) as e:
 
523
                self._translate_error(e, relpath)
527
524
 
528
525
    if osutils.hardlinks_good():
529
526
        def hardlink(self, source, link_name):
530
527
            """See Transport.link."""
531
528
            try:
532
529
                os.link(self._abspath(source), self._abspath(link_name))
533
 
            except (IOError, OSError), e:
 
530
            except (IOError, OSError) as e:
534
531
                self._translate_error(e, source)
535
532
 
536
 
    if osutils.has_symlinks():
 
533
    if getattr(os, 'symlink', None) is not None:
537
534
        def symlink(self, source, link_name):
538
535
            """See Transport.symlink."""
539
536
            abs_link_dirpath = urlutils.dirname(self.abspath(link_name))
540
537
            source_rel = urlutils.file_relpath(
541
 
                urlutils.strip_trailing_slash(abs_link_dirpath),
542
 
                urlutils.strip_trailing_slash(self.abspath(source))
543
 
            )
 
538
                abs_link_dirpath, self.abspath(source))
544
539
 
545
540
            try:
546
541
                os.symlink(source_rel, self._abspath(link_name))
547
 
            except (IOError, OSError), e:
 
542
            except (IOError, OSError) as e:
548
543
                self._translate_error(e, source_rel)
549
544
 
550
545
    def _can_roundtrip_unix_modebits(self):
565
560
        self._local_base = urlutils._win32_local_path_from_url(base)
566
561
 
567
562
    def abspath(self, relpath):
568
 
        path = osutils.normpath(osutils.pathjoin(
569
 
                    self._local_base, urlutils.unescape(relpath)))
 
563
        path = osutils._win32_normpath(osutils.pathjoin(
 
564
            self._local_base, urlutils.unescape(relpath)))
570
565
        return urlutils._win32_local_path_to_url(path)
571
566
 
572
567
    def clone(self, offset=None):
588
583
 
589
584
def get_test_permutations():
590
585
    """Return the permutations to be used in testing."""
591
 
    from bzrlib.tests import test_server
592
 
    return [(LocalTransport, test_server.LocalURLServer),]
 
586
    from ..tests import test_server
 
587
    return [(LocalTransport, test_server.LocalURLServer), ]