/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

Support user.signingkey configuration variable in .git/config.

Merged from https://code.launchpad.net/~jelmer/brz/local-git-key/+merge/381000

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