~jelmer/brz/colocated-spec

« back to all changes in this revision

Viewing changes to breezy/osutils.py

  • Committer: Jelmer Vernooij
  • Date: 2017-05-22 00:56:52 UTC
  • mfrom: (6621.2.26 py3_pokes)
  • Revision ID: jelmer@jelmer.uk-20170522005652-yjahcr9hwmjkno7n
Merge Python3 porting work ('py3 pokes')

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
import time
25
25
import codecs
26
26
 
27
 
from breezy.lazy_import import lazy_import
 
27
from .lazy_import import lazy_import
28
28
lazy_import(globals(), """
29
29
from datetime import datetime
30
30
from datetime import timedelta
55
55
from breezy.i18n import gettext
56
56
""")
57
57
 
58
 
from breezy.symbol_versioning import (
 
58
from .sixish import (
 
59
    PY3,
 
60
    text_type,
 
61
    )
 
62
from .symbol_versioning import (
59
63
    DEPRECATED_PARAMETER,
60
64
    deprecated_function,
61
65
    deprecated_in,
70
74
 
71
75
 
72
76
import breezy
73
 
from breezy import symbol_versioning, _fs_enc
 
77
from . import symbol_versioning, _fs_enc
74
78
 
75
79
 
76
80
# Cross platform wall-clock time functionality with decent resolution.
94
98
 
95
99
 
96
100
def get_unicode_argv():
 
101
    if PY3:
 
102
        return sys.argv[1:]
97
103
    try:
98
104
        user_encoding = get_user_encoding()
99
105
        return [a.decode(user_encoding) for a in sys.argv[1:]]
106
112
    """Make a filename read-only."""
107
113
    mod = os.lstat(filename).st_mode
108
114
    if not stat.S_ISLNK(mod):
109
 
        mod = mod & 0777555
 
115
        mod = mod & 0o777555
110
116
        chmod_if_possible(filename, mod)
111
117
 
112
118
 
113
119
def make_writable(filename):
114
120
    mod = os.lstat(filename).st_mode
115
121
    if not stat.S_ISLNK(mod):
116
 
        mod = mod | 0200
 
122
        mod = mod | 0o200
117
123
        chmod_if_possible(filename, mod)
118
124
 
119
125
 
125
131
        # It is probably faster to just do the chmod, rather than
126
132
        # doing a stat, and then trying to compare
127
133
        os.chmod(filename, mode)
128
 
    except (IOError, OSError),e:
 
134
    except (IOError, OSError) as e:
129
135
        # Permission/access denied seems to commonly happen on smbfs; there's
130
136
        # probably no point warning about it.
131
137
        # <https://bugs.launchpad.net/bzr/+bug/606537>
214
220
            stat = getattr(os, 'lstat', os.stat)
215
221
            stat(f)
216
222
            return True
217
 
        except OSError, e:
 
223
        except OSError as e:
218
224
            if e.errno == errno.ENOENT:
219
225
                return False;
220
226
            else:
248
254
    file_existed = False
249
255
    try:
250
256
        rename_func(new, tmp_name)
251
 
    except (errors.NoSuchFile,), e:
 
257
    except (errors.NoSuchFile,) as e:
252
258
        pass
253
 
    except IOError, e:
 
259
    except IOError as e:
254
260
        # RBC 20060103 abstraction leakage: the paramiko SFTP clients rename
255
261
        # function raises an IOError with errno is None when a rename fails.
256
262
        # This then gets caught here.
257
263
        if e.errno not in (None, errno.ENOENT, errno.ENOTDIR):
258
264
            raise
259
 
    except Exception, e:
 
265
    except Exception as e:
260
266
        if (getattr(e, 'errno', None) is None
261
267
            or e.errno not in (errno.ENOENT, errno.ENOTDIR)):
262
268
            raise
263
269
    else:
264
270
        file_existed = True
265
271
 
266
 
    failure_exc = None
267
272
    success = False
268
273
    try:
269
 
        try:
270
 
            # This may throw an exception, in which case success will
271
 
            # not be set.
272
 
            rename_func(old, new)
273
 
            success = True
274
 
        except (IOError, OSError), e:
275
 
            # source and target may be aliases of each other (e.g. on a
276
 
            # case-insensitive filesystem), so we may have accidentally renamed
277
 
            # source by when we tried to rename target
278
 
            failure_exc = sys.exc_info()
279
 
            if (file_existed and e.errno in (None, errno.ENOENT)
280
 
                and old.lower() == new.lower()):
281
 
                # source and target are the same file on a case-insensitive
282
 
                # filesystem, so we don't generate an exception
283
 
                failure_exc = None
 
274
        # This may throw an exception, in which case success will
 
275
        # not be set.
 
276
        rename_func(old, new)
 
277
        success = True
 
278
    except (IOError, OSError) as e:
 
279
        # source and target may be aliases of each other (e.g. on a
 
280
        # case-insensitive filesystem), so we may have accidentally renamed
 
281
        # source by when we tried to rename target
 
282
        if (file_existed and e.errno in (None, errno.ENOENT)
 
283
            and old.lower() == new.lower()):
 
284
            # source and target are the same file on a case-insensitive
 
285
            # filesystem, so we don't generate an exception
 
286
            pass
 
287
        else:
 
288
            raise
284
289
    finally:
285
290
        if file_existed:
286
291
            # If the file used to exist, rename it back into place
289
294
                unlink_func(tmp_name)
290
295
            else:
291
296
                rename_func(tmp_name, new)
292
 
    if failure_exc is not None:
293
 
        try:
294
 
            raise failure_exc[0], failure_exc[1], failure_exc[2]
295
 
        finally:
296
 
            del failure_exc
297
297
 
298
298
 
299
299
# In Python 2.4.2 and older, os.path.abspath and os.path.realpath
348
348
    path = posixpath.expanduser("~")
349
349
    try:
350
350
        return path.decode(_fs_enc)
 
351
    except AttributeError:
 
352
        return path
351
353
    except UnicodeDecodeError:
352
354
        raise errors.BadFilenameEncoding(path, _fs_enc)
353
355
 
397
399
    # check for absolute path
398
400
    drive = ntpath.splitdrive(path)[0]
399
401
    if drive == '' and path[:2] not in('//','\\\\'):
400
 
        cwd = os.getcwdu()
 
402
        cwd = _getcwd()
401
403
        # we cannot simply os.path.join cwd and path
402
404
        # because os.path.join('C:','/path') produce '/path'
403
405
        # and this is incorrect
422
424
 
423
425
 
424
426
def _win32_getcwd():
425
 
    return _win32_fixdrive(os.getcwdu().replace('\\', '/'))
 
427
    return _win32_fixdrive(_getcwd().replace('\\', '/'))
426
428
 
427
429
 
428
430
def _win32_mkdtemp(*args, **kwargs):
437
439
    """
438
440
    try:
439
441
        fancy_rename(old, new, rename_func=os.rename, unlink_func=os.unlink)
440
 
    except OSError, e:
 
442
    except OSError as e:
441
443
        if e.errno in (errno.EPERM, errno.EACCES, errno.EBUSY, errno.EINVAL):
442
444
            # If we try to rename a non-existant file onto cwd, we get
443
445
            # EPERM or EACCES instead of ENOENT, this will raise ENOENT
448
450
 
449
451
 
450
452
def _mac_getcwd():
451
 
    return unicodedata.normalize('NFC', os.getcwdu())
 
453
    return unicodedata.normalize('NFC', _getcwd())
452
454
 
453
455
 
454
456
def _rename_wrap_exception(rename_func):
461
463
    def _rename_wrapper(old, new):
462
464
        try:
463
465
            rename_func(old, new)
464
 
        except OSError, e:
 
466
        except OSError as e:
465
467
            detailed_error = OSError(e.errno, e.strerror +
466
468
                                " [occurred when renaming '%s' to '%s']" %
467
469
                                (old, new))
471
473
 
472
474
    return _rename_wrapper
473
475
 
 
476
 
 
477
if sys.version_info > (3,):
 
478
    _getcwd = os.getcwd
 
479
else:
 
480
    _getcwd = os.getcwdu
 
481
 
 
482
 
474
483
# Default rename wraps os.rename()
475
484
rename = _rename_wrap_exception(os.rename)
476
485
 
483
492
path_from_environ = _posix_path_from_environ
484
493
_get_home_dir = _posix_get_home_dir
485
494
getuser_unicode = _posix_getuser_unicode
486
 
getcwd = os.getcwdu
 
495
getcwd = _getcwd
487
496
dirname = os.path.dirname
488
497
basename = os.path.basename
489
498
split = os.path.split
513
522
    mkdtemp = _win32_mkdtemp
514
523
    rename = _rename_wrap_exception(_win32_rename)
515
524
    try:
516
 
        from breezy import _walkdirs_win32
 
525
        from . import _walkdirs_win32
517
526
    except ImportError:
518
527
        pass
519
528
    else:
566
575
 
567
576
    :param trace: If True trace the selected encoding via mutter().
568
577
    """
569
 
    from breezy.trace import mutter
 
578
    from .trace import mutter
570
579
    output_encoding = getattr(sys.stdout, 'encoding', None)
571
580
    if not output_encoding:
572
581
        input_encoding = getattr(sys.stdin, 'encoding', None)
908
917
    (date_fmt, tt, offset_str) = \
909
918
               _format_date(t, offset, timezone, date_fmt, show_offset)
910
919
    date_str = time.strftime(date_fmt, tt)
911
 
    if not isinstance(date_str, unicode):
 
920
    if not isinstance(date_str, text_type):
912
921
        date_str = date_str.decode(get_user_encoding(), 'replace')
913
922
    return date_str + offset_str
914
923
 
1102
1111
    if config.GlobalStack().get('ignore_missing_extensions'):
1103
1112
        return
1104
1113
    # the warnings framework should by default show this only once
1105
 
    from breezy.trace import warning
 
1114
    from .trace import warning
1106
1115
    warning(
1107
1116
        "brz: warning: some compiled extensions could not be loaded; "
1108
1117
        "see <https://answers.launchpad.net/bzr/+faq/703>")
1112
1121
 
1113
1122
 
1114
1123
try:
1115
 
    from breezy._chunks_to_lines_pyx import chunks_to_lines
1116
 
except ImportError, e:
 
1124
    from ._chunks_to_lines_pyx import chunks_to_lines
 
1125
except ImportError as e:
1117
1126
    failed_to_load_extension(e)
1118
 
    from breezy._chunks_to_lines_py import chunks_to_lines
 
1127
    from ._chunks_to_lines_py import chunks_to_lines
1119
1128
 
1120
1129
 
1121
1130
def split_lines(s):
1152
1161
        return
1153
1162
    try:
1154
1163
        os.link(src, dest)
1155
 
    except (OSError, IOError), e:
 
1164
    except (OSError, IOError) as e:
1156
1165
        if e.errno != errno.EXDEV:
1157
1166
            raise
1158
1167
        shutil.copyfile(src, dest)
1165
1174
    """
1166
1175
    try:
1167
1176
       _delete_file_or_dir(path)
1168
 
    except (OSError, IOError), e:
 
1177
    except (OSError, IOError) as e:
1169
1178
        if e.errno in (errno.EPERM, errno.EACCES):
1170
1179
            # make writable and try again
1171
1180
            try:
1363
1372
    Otherwise it is decoded from the the filesystem's encoding. If decoding
1364
1373
    fails, a errors.BadFilenameEncoding exception is raised.
1365
1374
    """
1366
 
    if type(filename) is unicode:
 
1375
    if isinstance(filename, text_type):
1367
1376
        return filename
1368
1377
    try:
1369
1378
        return filename.decode(_fs_enc)
1378
1387
    Otherwise it is decoded from utf-8. If decoding fails, the exception is
1379
1388
    wrapped in a BzrBadParameterNotUnicode exception.
1380
1389
    """
1381
 
    if isinstance(unicode_or_utf8_string, unicode):
 
1390
    if isinstance(unicode_or_utf8_string, text_type):
1382
1391
        return unicode_or_utf8_string
1383
1392
    try:
1384
1393
        return unicode_or_utf8_string.decode('utf8')
1690
1699
        if orig_val is not None:
1691
1700
            del os.environ[env_variable]
1692
1701
    else:
1693
 
        if isinstance(value, unicode):
 
1702
        if not PY3 and isinstance(value, text_type):
1694
1703
            value = value.encode(get_user_encoding())
1695
1704
        os.environ[env_variable] = value
1696
1705
    return orig_val
1789
1798
        append = dirblock.append
1790
1799
        try:
1791
1800
            names = sorted(map(decode_filename, _listdir(top)))
1792
 
        except OSError, e:
 
1801
        except OSError as e:
1793
1802
            if not _is_error_enotdir(e):
1794
1803
                raise
1795
1804
        else:
1855
1864
            #       but that gets a bit tricky, and requires custom compiling
1856
1865
            #       for win98 anyway.
1857
1866
            try:
1858
 
                from breezy._walkdirs_win32 import Win32ReadDir
 
1867
                from ._walkdirs_win32 import Win32ReadDir
1859
1868
                _selected_dir_reader = Win32ReadDir()
1860
1869
            except ImportError:
1861
1870
                pass
1862
1871
        elif _fs_enc in ('utf-8', 'ascii'):
1863
1872
            try:
1864
 
                from breezy._readdir_pyx import UTF8DirReader
 
1873
                from ._readdir_pyx import UTF8DirReader
1865
1874
                _selected_dir_reader = UTF8DirReader()
1866
 
            except ImportError, e:
 
1875
            except ImportError as e:
1867
1876
                failed_to_load_extension(e)
1868
1877
                pass
1869
1878
 
1999
2008
    try:
2000
2009
        s = os.stat(src)
2001
2010
        chown(dst, s.st_uid, s.st_gid)
2002
 
    except OSError, e:
 
2011
    except OSError as e:
2003
2012
        trace.warning(
2004
2013
            'Unable to copy ownership from "%s" to "%s". '
2005
2014
            'You may want to set it manually.', src, dst)
2113
2122
    empty string rather than raise an error), and repeats the recv if
2114
2123
    interrupted by a signal.
2115
2124
    """
2116
 
    while 1:
 
2125
    while True:
2117
2126
        try:
2118
2127
            bytes = sock.recv(max_read_size)
2119
 
        except socket.error, e:
 
2128
        except socket.error as e:
2120
2129
            eno = e.args[0]
2121
2130
            if eno in _end_of_stream_errors:
2122
2131
                # The connection was closed by the other side.  Callers expect
2169
2178
    while sent_total < byte_count:
2170
2179
        try:
2171
2180
            sent = sock.send(buffer(bytes, sent_total, MAX_SOCKET_CHUNK))
2172
 
        except (socket.error, IOError), e:
 
2181
        except (socket.error, IOError) as e:
2173
2182
            if e.args[0] in _end_of_stream_errors:
2174
2183
                raise errors.ConnectionReset(
2175
2184
                    "Error trying to write to socket", e)
2200
2209
            sock.connect(sa)
2201
2210
            return sock
2202
2211
 
2203
 
        except socket.error, err:
 
2212
        except socket.error as err:
2204
2213
            # 'err' is now the most recent error
2205
2214
            if sock is not None:
2206
2215
                sock.close()
2261
2270
    global file_kind_from_stat_mode
2262
2271
    if file_kind_from_stat_mode is file_kind_from_stat_mode_thunk:
2263
2272
        try:
2264
 
            from breezy._readdir_pyx import UTF8DirReader
 
2273
            from ._readdir_pyx import UTF8DirReader
2265
2274
            file_kind_from_stat_mode = UTF8DirReader().kind_from_mode
2266
 
        except ImportError, e:
 
2275
        except ImportError as e:
2267
2276
            # This is one time where we won't warn that an extension failed to
2268
2277
            # load. The extension is never available on Windows anyway.
2269
 
            from breezy._readdir_py import (
 
2278
            from ._readdir_py import (
2270
2279
                _kind_from_mode as file_kind_from_stat_mode
2271
2280
                )
2272
2281
    return file_kind_from_stat_mode(mode)
2276
2285
    try:
2277
2286
        # XXX cache?
2278
2287
        return _lstat(f)
2279
 
    except OSError, e:
 
2288
    except OSError as e:
2280
2289
        if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
2281
2290
            raise errors.NoSuchFile(f)
2282
2291
        raise
2302
2311
    while True:
2303
2312
        try:
2304
2313
            return f(*a, **kw)
2305
 
        except (IOError, OSError), e:
 
2314
        except (IOError, OSError) as e:
2306
2315
            if e.errno == errno.EINTR:
2307
2316
                continue
2308
2317
            raise
2324
2333
        re_obj = re.compile(re_string, flags)
2325
2334
        re_obj.search("")
2326
2335
        return re_obj
2327
 
    except errors.InvalidPattern, e:
 
2336
    except errors.InvalidPattern as e:
2328
2337
        if where:
2329
2338
            where = ' in ' + where
2330
2339
        # despite the name 'error' is a type
2420
2429
        self.encode = encode
2421
2430
 
2422
2431
    def write(self, object):
2423
 
        if type(object) is str:
 
2432
        if isinstance(object, str):
2424
2433
            self.stream.write(object)
2425
2434
        else:
2426
2435
            data, _ = self.encode(object, self.errors)
2544
2553
    try:
2545
2554
        # Special meaning of unix kill: just check if it's there.
2546
2555
        os.kill(pid, 0)
2547
 
    except OSError, e:
 
2556
    except OSError as e:
2548
2557
        if e.errno == errno.ESRCH:
2549
2558
            # On this machine, and really not found: as sure as we can be
2550
2559
            # that it's dead.
2580
2589
    if fn is not None:
2581
2590
        try:
2582
2591
            fn(fileno)
2583
 
        except IOError, e:
 
2592
        except IOError as e:
2584
2593
            # See bug #1075108, on some platforms fdatasync exists, but can
2585
2594
            # raise ENOTSUP. However, we are calling fdatasync to be helpful
2586
2595
            # and reduce the chance of corruption-on-powerloss situations. It
2598
2607
    """
2599
2608
    try:
2600
2609
        os.mkdir(path)
2601
 
    except OSError, e:
 
2610
    except OSError as e:
2602
2611
        if e.errno != errno.EEXIST:
2603
2612
            raise
2604
2613
        if os.listdir(path) != []: