mercurial/windows.py
branchstable
changeset 49366 288de6f5d724
parent 49319 a75b530cfc29
child 49518 805419729e11
equal deleted inserted replaced
49364:e8ea403b1c46 49366:288de6f5d724
     3 #  Copyright 2005-2009 Olivia Mackall <olivia@selenic.com> and others
     3 #  Copyright 2005-2009 Olivia Mackall <olivia@selenic.com> and others
     4 #
     4 #
     5 # This software may be used and distributed according to the terms of the
     5 # This software may be used and distributed according to the terms of the
     6 # GNU General Public License version 2 or any later version.
     6 # GNU General Public License version 2 or any later version.
     7 
     7 
     8 from __future__ import absolute_import
       
     9 
     8 
    10 import errno
     9 import errno
    11 import getpass
    10 import getpass
    12 import msvcrt
    11 import msvcrt  # pytype: disable=import-error
    13 import os
    12 import os
    14 import re
    13 import re
    15 import stat
    14 import stat
    16 import string
    15 import string
    17 import sys
    16 import sys
       
    17 import winreg  # pytype: disable=import-error
    18 
    18 
    19 from .i18n import _
    19 from .i18n import _
    20 from .pycompat import getattr
    20 from .pycompat import getattr
    21 from . import (
    21 from . import (
    22     encoding,
    22     encoding,
    24     policy,
    24     policy,
    25     pycompat,
    25     pycompat,
    26     win32,
    26     win32,
    27 )
    27 )
    28 
    28 
    29 try:
       
    30     import _winreg as winreg  # pytype: disable=import-error
       
    31 
       
    32     winreg.CloseKey
       
    33 except ImportError:
       
    34     # py2 only
       
    35     import winreg  # pytype: disable=import-error
       
    36 
    29 
    37 osutil = policy.importmod('osutil')
    30 osutil = policy.importmod('osutil')
    38 
    31 
    39 getfsmountpoint = win32.getvolumename
    32 getfsmountpoint = win32.getvolumename
    40 getfstype = win32.getfstype
    33 getfstype = win32.getfstype
    52 unlink = win32.unlink
    45 unlink = win32.unlink
    53 
    46 
    54 umask = 0o022
    47 umask = 0o022
    55 
    48 
    56 
    49 
    57 class mixedfilemodewrapper(object):
    50 class mixedfilemodewrapper:
    58     """Wraps a file handle when it is opened in read/write mode.
    51     """Wraps a file handle when it is opened in read/write mode.
    59 
    52 
    60     fopen() and fdopen() on Windows have a specific-to-Windows requirement
    53     fopen() and fdopen() on Windows have a specific-to-Windows requirement
    61     that files opened with mode r+, w+, or a+ make a call to a file positioning
    54     that files opened with mode r+, w+, or a+ make a call to a file positioning
    62     function when switching between reads and writes. Without this extra call,
    55     function when switching between reads and writes. Without this extra call,
   129 
   122 
   130         object.__setattr__(self, '_lastop', self.OPREAD)
   123         object.__setattr__(self, '_lastop', self.OPREAD)
   131         return self._fp.readlines(*args, **kwargs)
   124         return self._fp.readlines(*args, **kwargs)
   132 
   125 
   133 
   126 
   134 class fdproxy(object):
   127 class fdproxy:
   135     """Wraps osutil.posixfile() to override the name attribute to reflect the
   128     """Wraps osutil.posixfile() to override the name attribute to reflect the
   136     underlying file name.
   129     underlying file name.
   137     """
   130     """
   138 
   131 
   139     def __init__(self, name, fp):
   132     def __init__(self, name, fp):
   161     try:
   154     try:
   162         fp = osutil.posixfile(name, mode, buffering)  # may raise WindowsError
   155         fp = osutil.posixfile(name, mode, buffering)  # may raise WindowsError
   163 
   156 
   164         # PyFile_FromFd() ignores the name, and seems to report fp.name as the
   157         # PyFile_FromFd() ignores the name, and seems to report fp.name as the
   165         # underlying file descriptor.
   158         # underlying file descriptor.
   166         if pycompat.ispy3:
   159         fp = fdproxy(name, fp)
   167             fp = fdproxy(name, fp)
       
   168 
   160 
   169         # The position when opening in append mode is implementation defined, so
   161         # The position when opening in append mode is implementation defined, so
   170         # make it consistent with other platforms, which position at EOF.
   162         # make it consistent with other platforms, which position at EOF.
   171         if b'a' in mode:
   163         if b'a' in mode:
   172             fp.seek(0, os.SEEK_END)
   164             fp.seek(0, os.SEEK_END)
   214     msvcrt.putwch(u'\r')  # pytype: disable=module-attr
   206     msvcrt.putwch(u'\r')  # pytype: disable=module-attr
   215     msvcrt.putwch(u'\n')  # pytype: disable=module-attr
   207     msvcrt.putwch(u'\n')  # pytype: disable=module-attr
   216     return encoding.unitolocal(pw)
   208     return encoding.unitolocal(pw)
   217 
   209 
   218 
   210 
   219 class winstdout(object):
   211 class winstdout:
   220     """Some files on Windows misbehave.
   212     """Some files on Windows misbehave.
   221 
   213 
   222     When writing to a broken pipe, EINVAL instead of EPIPE may be raised.
   214     When writing to a broken pipe, EINVAL instead of EPIPE may be raised.
   223 
   215 
   224     When writing too many bytes to a console at the same, a "Not enough space"
   216     When writing too many bytes to a console at the same, a "Not enough space"
   225     error may happen. Python 3 already works around that.
   217     error may happen. Python 3 already works around that.
   226     """
   218     """
   227 
   219 
   228     def __init__(self, fp):
   220     def __init__(self, fp):
   229         self.fp = fp
   221         self.fp = fp
   230         self.throttle = not pycompat.ispy3 and _isatty(fp)
       
   231 
   222 
   232     def __getattr__(self, key):
   223     def __getattr__(self, key):
   233         return getattr(self.fp, key)
   224         return getattr(self.fp, key)
   234 
   225 
   235     def close(self):
   226     def close(self):
   238         except IOError:
   229         except IOError:
   239             pass
   230             pass
   240 
   231 
   241     def write(self, s):
   232     def write(self, s):
   242         try:
   233         try:
   243             if not self.throttle:
   234             return self.fp.write(s)
   244                 return self.fp.write(s)
       
   245             # This is workaround for "Not enough space" error on
       
   246             # writing large size of data to console.
       
   247             limit = 16000
       
   248             l = len(s)
       
   249             start = 0
       
   250             while start < l:
       
   251                 end = start + limit
       
   252                 self.fp.write(s[start:end])
       
   253                 start = end
       
   254         except IOError as inst:
   235         except IOError as inst:
   255             if inst.errno != 0 and not win32.lasterrorwaspipeerror(inst):
   236             if inst.errno != 0 and not win32.lasterrorwaspipeerror(inst):
   256                 raise
   237                 raise
   257             self.close()
   238             self.close()
   258             raise IOError(errno.EPIPE, 'Broken pipe')
   239             raise IOError(errno.EPIPE, 'Broken pipe')
   587                 dmap = {
   568                 dmap = {
   588                     normcase(n): s
   569                     normcase(n): s
   589                     for n, k, s in listdir(dir, True)
   570                     for n, k, s in listdir(dir, True)
   590                     if getkind(s.st_mode) in _wantedkinds
   571                     if getkind(s.st_mode) in _wantedkinds
   591                 }
   572                 }
   592             except OSError as err:
   573             except (FileNotFoundError, NotADirectoryError):
   593                 # Python >= 2.5 returns ENOENT and adds winerror field
       
   594                 # EINVAL is raised if dir is not a directory.
       
   595                 if err.errno not in (errno.ENOENT, errno.EINVAL, errno.ENOTDIR):
       
   596                     raise
       
   597                 dmap = {}
   574                 dmap = {}
   598             cache = dircache.setdefault(dir, dmap)
   575             cache = dircache.setdefault(dir, dmap)
   599         yield cache.get(base, None)
   576         yield cache.get(base, None)
   600 
   577 
   601 
   578 
   649 
   626 
   650 def rename(src, dst):
   627 def rename(src, dst):
   651     '''atomically rename file src to dst, replacing dst if it exists'''
   628     '''atomically rename file src to dst, replacing dst if it exists'''
   652     try:
   629     try:
   653         os.rename(src, dst)
   630         os.rename(src, dst)
   654     except OSError as e:
   631     except FileExistsError:
   655         if e.errno != errno.EEXIST:
       
   656             raise
       
   657         unlink(dst)
   632         unlink(dst)
   658         os.rename(src, dst)
   633         os.rename(src, dst)
   659 
   634 
   660 
   635 
   661 def gethgcmd():
   636 def gethgcmd():
   669 
   644 
   670 def isexec(f):
   645 def isexec(f):
   671     return False
   646     return False
   672 
   647 
   673 
   648 
   674 class cachestat(object):
   649 class cachestat:
   675     def __init__(self, path):
   650     def __init__(self, path):
   676         pass
   651         pass
   677 
   652 
   678     def cacheable(self):
   653     def cacheable(self):
   679         return False
   654         return False
   687     scope: optionally specify scope for registry lookup, this can be
   662     scope: optionally specify scope for registry lookup, this can be
   688     a sequence of scopes to look up in order. Default (CURRENT_USER,
   663     a sequence of scopes to look up in order. Default (CURRENT_USER,
   689     LOCAL_MACHINE).
   664     LOCAL_MACHINE).
   690     """
   665     """
   691     if scope is None:
   666     if scope is None:
       
   667         # pytype: disable=module-attr
   692         scope = (winreg.HKEY_CURRENT_USER, winreg.HKEY_LOCAL_MACHINE)
   668         scope = (winreg.HKEY_CURRENT_USER, winreg.HKEY_LOCAL_MACHINE)
       
   669         # pytype: enable=module-attr
   693     elif not isinstance(scope, (list, tuple)):
   670     elif not isinstance(scope, (list, tuple)):
   694         scope = (scope,)
   671         scope = (scope,)
   695     for s in scope:
   672     for s in scope:
   696         try:
   673         try:
       
   674             # pytype: disable=module-attr
   697             with winreg.OpenKey(s, encoding.strfromlocal(key)) as hkey:
   675             with winreg.OpenKey(s, encoding.strfromlocal(key)) as hkey:
   698                 name = valname and encoding.strfromlocal(valname) or valname
   676                 # pytype: enable=module-attr
       
   677                 name = None
       
   678                 if valname is not None:
       
   679                     name = encoding.strfromlocal(valname)
       
   680                 # pytype: disable=module-attr
   699                 val = winreg.QueryValueEx(hkey, name)[0]
   681                 val = winreg.QueryValueEx(hkey, name)[0]
       
   682                 # pytype: enable=module-attr
       
   683 
   700                 # never let a Unicode string escape into the wild
   684                 # never let a Unicode string escape into the wild
   701                 return encoding.unitolocal(val)
   685                 return encoding.unitolocal(val)
   702         except EnvironmentError:
   686         except EnvironmentError:
   703             pass
   687             pass
   704 
   688