/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/win32utils.py

  • Committer: Gustav Hartvigsson
  • Date: 2021-01-09 21:36:27 UTC
  • Revision ID: gustav.hartvigsson@gmail.com-20210109213627-h1xwcutzy9m7a99b
Added 'Case Preserving Working Tree Use Cases' from Canonical Wiki

* Addod a page from the Canonical Bazaar wiki
  with information on the scmeatics of case
  perserving filesystems an a case insensitive
  filesystem works.
  
  * Needs re-work, but this will do as it is the
    same inforamoton as what was on the linked
    page in the currint documentation.

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
import struct
25
25
import sys
26
26
 
27
 
from bzrlib import cmdline
28
 
 
29
 
# Windows version
30
 
if sys.platform == 'win32':
31
 
    _major,_minor,_build,_platform,_text = sys.getwindowsversion()
32
 
    # from MSDN:
33
 
    # dwPlatformId
34
 
    #   The operating system platform.
35
 
    #   This member can be one of the following values.
36
 
    #   ==========================  ======================================
37
 
    #   Value                       Meaning
38
 
    #   --------------------------  --------------------------------------
39
 
    #   VER_PLATFORM_WIN32_NT       The operating system is Windows Vista,
40
 
    #   2                           Windows Server "Longhorn",
41
 
    #                               Windows Server 2003, Windows XP,
42
 
    #                               Windows 2000, or Windows NT.
43
 
    #
44
 
    #   VER_PLATFORM_WIN32_WINDOWS  The operating system is Windows Me,
45
 
    #   1                           Windows 98, or Windows 95.
46
 
    #   ==========================  ======================================
47
 
    if _platform == 2:
48
 
        winver = 'Windows NT'
49
 
    else:
50
 
        # don't care about real Windows name, just to force safe operations
51
 
        winver = 'Windows 98'
52
 
else:
53
 
    winver = None
54
 
 
55
 
 
56
 
# We can cope without it; use a separate variable to help pyflakes
57
 
try:
58
 
    import ctypes
59
 
    has_ctypes = True
60
 
except ImportError:
61
 
    has_ctypes = False
62
 
else:
63
 
    if winver == 'Windows 98':
64
 
        create_buffer = ctypes.create_string_buffer
65
 
        suffix = 'A'
66
 
    else:
67
 
        create_buffer = ctypes.create_unicode_buffer
68
 
        suffix = 'W'
69
 
try:
70
 
    import win32file
71
 
    import pywintypes
72
 
    has_win32file = True
73
 
except ImportError:
74
 
    has_win32file = False
75
 
try:
76
 
    import win32api
77
 
    has_win32api = True
78
 
except ImportError:
79
 
    has_win32api = False
80
 
 
81
 
# pulling in win32com.shell is a bit of overhead, and normally we don't need
82
 
# it as ctypes is preferred and common.  lazy_imports and "optional"
83
 
# modules don't work well, so we do our own lazy thing...
84
 
has_win32com_shell = None # Set to True or False once we know for sure...
 
27
from breezy import (
 
28
    cmdline,
 
29
    )
 
30
from breezy.i18n import gettext
 
31
 
85
32
 
86
33
# Special Win32 API constants
87
34
# Handles of std streams
91
38
 
92
39
# CSIDL constants (from MSDN 2003)
93
40
CSIDL_APPDATA = 0x001A      # Application Data folder
94
 
CSIDL_LOCAL_APPDATA = 0x001c# <user name>\Local Settings\Application Data (non roaming)
 
41
# <user name>\Local Settings\Application Data (non roaming)
 
42
CSIDL_LOCAL_APPDATA = 0x001c
95
43
CSIDL_PERSONAL = 0x0005     # My Documents folder
96
44
 
97
45
# from winapi C headers
106
54
 
107
55
def debug_memory_win32api(message='', short=True):
108
56
    """Use trace.note() to dump the running memory info."""
109
 
    from bzrlib import trace
110
 
    if has_ctypes:
111
 
        class PROCESS_MEMORY_COUNTERS_EX(ctypes.Structure):
112
 
            """Used by GetProcessMemoryInfo"""
113
 
            _fields_ = [('cb', ctypes.c_ulong),
114
 
                        ('PageFaultCount', ctypes.c_ulong),
115
 
                        ('PeakWorkingSetSize', ctypes.c_size_t),
116
 
                        ('WorkingSetSize', ctypes.c_size_t),
117
 
                        ('QuotaPeakPagedPoolUsage', ctypes.c_size_t),
118
 
                        ('QuotaPagedPoolUsage', ctypes.c_size_t),
119
 
                        ('QuotaPeakNonPagedPoolUsage', ctypes.c_size_t),
120
 
                        ('QuotaNonPagedPoolUsage', ctypes.c_size_t),
121
 
                        ('PagefileUsage', ctypes.c_size_t),
122
 
                        ('PeakPagefileUsage', ctypes.c_size_t),
123
 
                        ('PrivateUsage', ctypes.c_size_t),
124
 
                       ]
125
 
        cur_process = ctypes.windll.kernel32.GetCurrentProcess()
126
 
        mem_struct = PROCESS_MEMORY_COUNTERS_EX()
127
 
        ret = ctypes.windll.psapi.GetProcessMemoryInfo(cur_process,
128
 
            ctypes.byref(mem_struct),
129
 
            ctypes.sizeof(mem_struct))
130
 
        if not ret:
131
 
            trace.note('Failed to GetProcessMemoryInfo()')
132
 
            return
133
 
        info = {'PageFaultCount': mem_struct.PageFaultCount,
134
 
                'PeakWorkingSetSize': mem_struct.PeakWorkingSetSize,
135
 
                'WorkingSetSize': mem_struct.WorkingSetSize,
136
 
                'QuotaPeakPagedPoolUsage': mem_struct.QuotaPeakPagedPoolUsage,
137
 
                'QuotaPagedPoolUsage': mem_struct.QuotaPagedPoolUsage,
138
 
                'QuotaPeakNonPagedPoolUsage':
139
 
                    mem_struct.QuotaPeakNonPagedPoolUsage,
140
 
                'QuotaNonPagedPoolUsage': mem_struct.QuotaNonPagedPoolUsage,
141
 
                'PagefileUsage': mem_struct.PagefileUsage,
142
 
                'PeakPagefileUsage': mem_struct.PeakPagefileUsage,
143
 
                'PrivateUsage': mem_struct.PrivateUsage,
144
 
               }
145
 
    elif has_win32api:
146
 
        import win32process
147
 
        # win32process does not return PrivateUsage, because it doesn't use
148
 
        # PROCESS_MEMORY_COUNTERS_EX (it uses the one without _EX).
149
 
        proc = win32process.GetCurrentProcess()
150
 
        info = win32process.GetProcessMemoryInfo(proc)
151
 
    else:
152
 
        trace.note('Cannot debug memory on win32 without ctypes'
153
 
                   ' or win32process')
 
57
    import ctypes
 
58
    from breezy import trace
 
59
    class PROCESS_MEMORY_COUNTERS_EX(ctypes.Structure):
 
60
        """Used by GetProcessMemoryInfo"""
 
61
        _fields_ = [('cb', ctypes.c_ulong),
 
62
                    ('PageFaultCount', ctypes.c_ulong),
 
63
                    ('PeakWorkingSetSize', ctypes.c_size_t),
 
64
                    ('WorkingSetSize', ctypes.c_size_t),
 
65
                    ('QuotaPeakPagedPoolUsage', ctypes.c_size_t),
 
66
                    ('QuotaPagedPoolUsage', ctypes.c_size_t),
 
67
                    ('QuotaPeakNonPagedPoolUsage', ctypes.c_size_t),
 
68
                    ('QuotaNonPagedPoolUsage', ctypes.c_size_t),
 
69
                    ('PagefileUsage', ctypes.c_size_t),
 
70
                    ('PeakPagefileUsage', ctypes.c_size_t),
 
71
                    ('PrivateUsage', ctypes.c_size_t),
 
72
                    ]
 
73
    cur_process = ctypes.windll.kernel32.GetCurrentProcess()
 
74
    mem_struct = PROCESS_MEMORY_COUNTERS_EX()
 
75
    ret = ctypes.windll.psapi.GetProcessMemoryInfo(
 
76
        cur_process, ctypes.byref(mem_struct), ctypes.sizeof(mem_struct))
 
77
    if not ret:
 
78
        trace.note(gettext('Failed to GetProcessMemoryInfo()'))
154
79
        return
 
80
    info = {'PageFaultCount': mem_struct.PageFaultCount,
 
81
            'PeakWorkingSetSize': mem_struct.PeakWorkingSetSize,
 
82
            'WorkingSetSize': mem_struct.WorkingSetSize,
 
83
            'QuotaPeakPagedPoolUsage': mem_struct.QuotaPeakPagedPoolUsage,
 
84
            'QuotaPagedPoolUsage': mem_struct.QuotaPagedPoolUsage,
 
85
            'QuotaPeakNonPagedPoolUsage':
 
86
                mem_struct.QuotaPeakNonPagedPoolUsage,
 
87
            'QuotaNonPagedPoolUsage': mem_struct.QuotaNonPagedPoolUsage,
 
88
            'PagefileUsage': mem_struct.PagefileUsage,
 
89
            'PeakPagefileUsage': mem_struct.PeakPagefileUsage,
 
90
            'PrivateUsage': mem_struct.PrivateUsage,
 
91
            }
155
92
    if short:
156
93
        # using base-2 units (see HACKING.txt).
157
 
        trace.note('WorkingSize %7dKiB'
158
 
                   '\tPeakWorking %7dKiB\t%s',
 
94
        trace.note(gettext('WorkingSize {0:>7}KiB'
 
95
                           '\tPeakWorking {1:>7}KiB\t{2}').format(
159
96
                   info['WorkingSetSize'] / 1024,
160
97
                   info['PeakWorkingSetSize'] / 1024,
161
 
                   message)
 
98
                   message))
162
99
        return
163
100
    if message:
164
101
        trace.note('%s', message)
165
 
    trace.note('WorkingSize       %8d KiB', info['WorkingSetSize'] / 1024)
166
 
    trace.note('PeakWorking       %8d KiB', info['PeakWorkingSetSize'] / 1024)
167
 
    trace.note('PagefileUsage     %8d KiB', info.get('PagefileUsage', 0) / 1024)
168
 
    trace.note('PeakPagefileUsage %8d KiB',
 
102
    trace.note(gettext('WorkingSize       %8d KiB'),
 
103
               info['WorkingSetSize'] / 1024)
 
104
    trace.note(gettext('PeakWorking       %8d KiB'),
 
105
               info['PeakWorkingSetSize'] / 1024)
 
106
    trace.note(gettext('PagefileUsage     %8d KiB'),
 
107
               info.get('PagefileUsage', 0) / 1024)
 
108
    trace.note(gettext('PeakPagefileUsage %8d KiB'),
169
109
               info.get('PeakPagefileUsage', 0) / 1024)
170
 
    trace.note('PrivateUsage      %8d KiB', info.get('PrivateUsage', 0) / 1024)
171
 
    trace.note('PageFaultCount    %8d', info.get('PageFaultCount', 0))
 
110
    trace.note(gettext('PrivateUsage      %8d KiB'),
 
111
               info.get('PrivateUsage', 0) / 1024)
 
112
    trace.note(gettext('PageFaultCount    %8d'), info.get('PageFaultCount', 0))
172
113
 
173
114
 
174
115
def get_console_size(defaultx=80, defaulty=25):
178
119
    console window and return tuple (sizex, sizey) if success,
179
120
    or default size (defaultx, defaulty) otherwise.
180
121
    """
181
 
    if not has_ctypes:
182
 
        # no ctypes is found
183
 
        return (defaultx, defaulty)
184
 
 
 
122
    import ctypes
185
123
    # To avoid problem with redirecting output via pipe
186
124
    # we need to use stderr instead of stdout
187
125
    h = ctypes.windll.kernel32.GetStdHandle(WIN32_STDERR_HANDLE)
190
128
 
191
129
    if res:
192
130
        (bufx, bufy, curx, cury, wattr,
193
 
        left, top, right, bottom, maxx, maxy) = struct.unpack(
 
131
         left, top, right, bottom, maxx, maxy) = struct.unpack(
194
132
            "hhhhHhhhhhh", csbi.raw)
195
133
        sizex = right - left + 1
196
134
        sizey = bottom - top + 1
204
142
 
205
143
    Result is always unicode (or None).
206
144
    """
207
 
    if has_ctypes:
208
 
        try:
209
 
            SHGetSpecialFolderPath = \
210
 
                ctypes.windll.shell32.SHGetSpecialFolderPathW
211
 
        except AttributeError:
212
 
            pass
213
 
        else:
214
 
            buf = ctypes.create_unicode_buffer(MAX_PATH)
215
 
            if SHGetSpecialFolderPath(None,buf,csidl,0):
216
 
                return buf.value
217
 
 
218
 
    global has_win32com_shell
219
 
    if has_win32com_shell is None:
220
 
        try:
221
 
            from win32com.shell import shell
222
 
            has_win32com_shell = True
223
 
        except ImportError:
224
 
            has_win32com_shell = False
225
 
    if has_win32com_shell:
226
 
        # still need to bind the name locally, but this is fast.
227
 
        from win32com.shell import shell
228
 
        try:
229
 
            return shell.SHGetSpecialFolderPath(0, csidl, 0)
230
 
        except shell.error:
231
 
            # possibly E_NOTIMPL meaning we can't load the function pointer,
232
 
            # or E_FAIL meaning the function failed - regardless, just ignore it
233
 
            pass
234
 
    return None
 
145
    import ctypes
 
146
    try:
 
147
        SHGetSpecialFolderPath = \
 
148
            ctypes.windll.shell32.SHGetSpecialFolderPathW
 
149
    except AttributeError:
 
150
        pass
 
151
    else:
 
152
        buf = ctypes.create_unicode_buffer(MAX_PATH)
 
153
        if SHGetSpecialFolderPath(None, buf, csidl, 0):
 
154
            return buf.value
235
155
 
236
156
 
237
157
def get_appdata_location():
242
162
    one that moves with the user as they logon to different machines, and
243
163
    a 'local' one that stays local to the machine.  This returns the 'roaming'
244
164
    directory, and thus is suitable for storing user-preferences, etc.
245
 
 
246
 
    Returned value can be unicode or plain string.
247
 
    To convert plain string to unicode use
248
 
    s.decode(osutils.get_user_encoding())
249
 
    (XXX - but see bug 262874, which asserts the correct encoding is 'mbcs')
250
165
    """
251
166
    appdata = _get_sh_special_folder_path(CSIDL_APPDATA)
252
167
    if appdata:
253
168
        return appdata
254
 
    # from env variable
255
 
    appdata = os.environ.get('APPDATA')
256
 
    if appdata:
257
 
        return appdata
258
 
    # if we fall to this point we on win98
259
 
    # at least try C:/WINDOWS/Application Data
260
 
    windir = os.environ.get('windir')
261
 
    if windir:
262
 
        appdata = os.path.join(windir, 'Application Data')
263
 
        if os.path.isdir(appdata):
264
 
            return appdata
265
 
    # did not find anything
266
 
    return None
 
169
    # Use APPDATA if defined, will return None if not
 
170
    return os.environ.get('APPDATA')
267
171
 
268
172
 
269
173
def get_local_appdata_location():
275
179
    a 'local' one that stays local to the machine.  This returns the 'local'
276
180
    directory, and thus is suitable for caches, temp files and other things
277
181
    which don't need to move with the user.
278
 
 
279
 
    Returned value can be unicode or plain string.
280
 
    To convert plain string to unicode use
281
 
    s.decode(osutils.get_user_encoding())
282
 
    (XXX - but see bug 262874, which asserts the correct encoding is 'mbcs')
283
182
    """
284
183
    local = _get_sh_special_folder_path(CSIDL_LOCAL_APPDATA)
285
184
    if local:
296
195
    Assume on win32 it's the <My Documents> folder.
297
196
    If location cannot be obtained return system drive root,
298
197
    i.e. C:\
299
 
 
300
 
    Returned value can be unicode or plain string.
301
 
    To convert plain string to unicode use
302
 
    s.decode(osutils.get_user_encoding())
303
198
    """
304
199
    home = _get_sh_special_folder_path(CSIDL_PERSONAL)
305
200
    if home:
306
201
        return home
307
 
    # try for HOME env variable
308
 
    home = os.path.expanduser('~')
309
 
    if home != '~':
 
202
    home = os.environ.get('HOME')
 
203
    if home is not None:
310
204
        return home
 
205
    homepath = os.environ.get('HOMEPATH')
 
206
    if homepath is not None:
 
207
        return os.path.join(os.environ.get('HOMEDIR', ''), home)
311
208
    # at least return windows root directory
312
 
    windir = os.environ.get('windir')
 
209
    windir = os.environ.get('WINDIR')
313
210
    if windir:
314
211
        return os.path.splitdrive(windir)[0] + '/'
315
212
    # otherwise C:\ is good enough for 98% users
316
 
    return 'C:/'
 
213
    return u'C:/'
317
214
 
318
215
 
319
216
def get_user_name():
320
217
    """Return user name as login name.
321
218
    If name cannot be obtained return None.
322
 
 
323
 
    Returned value can be unicode or plain string.
324
 
    To convert plain string to unicode use
325
 
    s.decode(osutils.get_user_encoding())
326
219
    """
327
 
    if has_ctypes:
328
 
        try:
329
 
            advapi32 = ctypes.windll.advapi32
330
 
            GetUserName = getattr(advapi32, 'GetUserName'+suffix)
331
 
        except AttributeError:
332
 
            pass
333
 
        else:
334
 
            buf = create_buffer(UNLEN+1)
335
 
            n = ctypes.c_int(UNLEN+1)
336
 
            if GetUserName(buf, ctypes.byref(n)):
337
 
                return buf.value
 
220
    try:
 
221
        advapi32 = ctypes.windll.advapi32
 
222
        GetUserName = getattr(advapi32, 'GetUserNameW')
 
223
    except AttributeError:
 
224
        pass
 
225
    else:
 
226
        buf = ctypes.create_unicode_buffer(UNLEN + 1)
 
227
        n = ctypes.c_int(UNLEN + 1)
 
228
        if GetUserName(buf, ctypes.byref(n)):
 
229
            return buf.value
338
230
    # otherwise try env variables
339
 
    return os.environ.get('USERNAME', None)
 
231
    return os.environ.get('USERNAME')
340
232
 
341
233
 
342
234
# 1 == ComputerNameDnsHostname, which returns "The DNS host name of the local
343
235
# computer or the cluster associated with the local computer."
344
236
_WIN32_ComputerNameDnsHostname = 1
345
237
 
 
238
 
346
239
def get_host_name():
347
240
    """Return host machine name.
348
241
    If name cannot be obtained return None.
349
242
 
350
 
    :return: A unicode string representing the host name. On win98, this may be
351
 
        a plain string as win32 api doesn't support unicode.
 
243
    :return: A unicode string representing the host name.
352
244
    """
353
 
    if has_win32api:
354
 
        try:
355
 
            return win32api.GetComputerNameEx(_WIN32_ComputerNameDnsHostname)
356
 
        except (NotImplementedError, win32api.error):
357
 
            # NotImplemented will happen on win9x...
358
 
            pass
359
 
    if has_ctypes:
360
 
        try:
361
 
            kernel32 = ctypes.windll.kernel32
362
 
        except AttributeError:
363
 
            pass # Missing the module we need
364
 
        else:
365
 
            buf = create_buffer(MAX_COMPUTERNAME_LENGTH+1)
366
 
            n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1)
367
 
 
368
 
            # Try GetComputerNameEx which gives a proper Unicode hostname
369
 
            GetComputerNameEx = getattr(kernel32, 'GetComputerNameEx'+suffix,
370
 
                                        None)
371
 
            if (GetComputerNameEx is not None
372
 
                and GetComputerNameEx(_WIN32_ComputerNameDnsHostname,
373
 
                                      buf, ctypes.byref(n))):
374
 
                return buf.value
375
 
 
376
 
            # Try GetComputerName in case GetComputerNameEx wasn't found
377
 
            # It returns the NETBIOS name, which isn't as good, but still ok.
378
 
            # The first GetComputerNameEx might have changed 'n', so reset it
379
 
            n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1)
380
 
            GetComputerName = getattr(kernel32, 'GetComputerName'+suffix,
381
 
                                      None)
382
 
            if (GetComputerName is not None
383
 
                and GetComputerName(buf, ctypes.byref(n))):
384
 
                return buf.value
385
 
    # otherwise try env variables, which will be 'mbcs' encoded
386
 
    # on Windows (Python doesn't expose the native win32 unicode environment)
387
 
    # According to this:
388
 
    # http://msdn.microsoft.com/en-us/library/aa246807.aspx
389
 
    # environment variables should always be encoded in 'mbcs'.
390
 
    try:
391
 
        return os.environ['COMPUTERNAME'].decode("mbcs")
392
 
    except KeyError:
393
 
        return None
394
 
 
395
 
 
396
 
def _ensure_unicode(s):
397
 
    if s and type(s) != unicode:
398
 
        from bzrlib import osutils
399
 
        s = s.decode(osutils.get_user_encoding())
400
 
    return s
401
 
 
402
 
 
403
 
def get_appdata_location_unicode():
404
 
    return _ensure_unicode(get_appdata_location())
405
 
 
406
 
def get_home_location_unicode():
407
 
    return _ensure_unicode(get_home_location())
408
 
 
409
 
def get_user_name_unicode():
410
 
    return _ensure_unicode(get_user_name())
411
 
 
412
 
def get_host_name_unicode():
413
 
    return _ensure_unicode(get_host_name())
 
245
    import ctypes
 
246
    buf = ctypes.create_unicode_buffer(MAX_COMPUTERNAME_LENGTH + 1)
 
247
    n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH + 1)
 
248
 
 
249
    # Try GetComputerNameEx which gives a proper Unicode hostname
 
250
    GetComputerNameEx = getattr(
 
251
        ctypes.windll.kernel32, 'GetComputerNameExW', None)
 
252
    if (GetComputerNameEx is not None
 
253
        and GetComputerNameEx(_WIN32_ComputerNameDnsHostname,
 
254
                              buf, ctypes.byref(n))):
 
255
        return buf.value
 
256
    return os.environ.get('COMPUTERNAME')
414
257
 
415
258
 
416
259
def _ensure_with_dir(path):
417
260
    if (not os.path.split(path)[0] or path.startswith(u'*')
418
 
        or path.startswith(u'?')):
 
261
            or path.startswith(u'?')):
419
262
        return u'./' + path, True
420
263
    else:
421
264
        return path, False
422
265
 
 
266
 
423
267
def _undo_ensure_with_dir(path, corrected):
424
268
    if corrected:
425
269
        return path[2:]
427
271
        return path
428
272
 
429
273
 
430
 
 
431
274
def glob_one(possible_glob):
432
275
    """Same as glob.glob().
433
276
 
457
300
    :param file_list: A list of filenames which may include shell globs.
458
301
    :return: An expanded list of filenames.
459
302
 
460
 
    Introduced in bzrlib 0.18.
 
303
    Introduced in breezy 0.18.
461
304
    """
462
305
    if not file_list:
463
306
        return []
468
311
 
469
312
 
470
313
def get_app_path(appname):
471
 
    """Look up in Windows registry for full path to application executable.
 
314
    r"""Look up in Windows registry for full path to application executable.
472
315
    Typically, applications create subkey with their basename
473
316
    in HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\
474
317
 
485
328
 
486
329
    try:
487
330
        hkey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
488
 
            'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\' +
489
 
            basename)
 
331
                               'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\' +
 
332
                               basename)
490
333
    except EnvironmentError:
491
334
        return appname
492
335
 
500
343
 
501
344
    if type_id == REG_SZ:
502
345
        return path
503
 
    if type_id == REG_EXPAND_SZ and has_win32api:
504
 
        fullpath = win32api.ExpandEnvironmentStrings(path)
505
 
        if len(fullpath) > 1 and fullpath[0] == '"' and fullpath[-1] == '"':
506
 
            fullpath = fullpath[1:-1]   # remove quotes around value
507
 
        return fullpath
508
346
    return appname
509
347
 
510
348
 
511
349
def set_file_attr_hidden(path):
512
350
    """Set file attributes to hidden if possible"""
513
 
    if has_win32file:
514
 
        if winver != 'Windows 98':
515
 
            SetFileAttributes = win32file.SetFileAttributesW
516
 
        else:
517
 
            SetFileAttributes = win32file.SetFileAttributes
518
 
        try:
519
 
            SetFileAttributes(path, win32file.FILE_ATTRIBUTE_HIDDEN)
520
 
        except pywintypes.error, e:
521
 
            from bzrlib import trace
522
 
            trace.mutter('Unable to set hidden attribute on %r: %s', path, e)
523
 
 
524
 
 
525
 
def _command_line_to_argv(command_line, single_quotes_allowed=False):
 
351
    from ctypes.wintypes import BOOL, DWORD, LPWSTR
 
352
    import ctypes
 
353
    # <https://docs.microsoft.com/windows/desktop/api/fileapi/nf-fileapi-setfileattributesw>
 
354
    SetFileAttributes = ctypes.windll.kernel32.SetFileAttributesW
 
355
    SetFileAttributes.argtypes = LPWSTR, DWORD
 
356
    SetFileAttributes.restype = BOOL
 
357
    FILE_ATTRIBUTE_HIDDEN = 2
 
358
    if not SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN):
 
359
        e = ctypes.WinError()
 
360
        from . import trace
 
361
        trace.mutter('Unable to set hidden attribute on %r: %s', path, e)
 
362
 
 
363
 
 
364
def _command_line_to_argv(command_line, argv, single_quotes_allowed=False):
526
365
    """Convert a Unicode command line into a list of argv arguments.
527
366
 
528
367
    It performs wildcard expansion to make wildcards act closer to how they
535
374
                                  default.
536
375
    :return: A list of unicode strings.
537
376
    """
538
 
    s = cmdline.Splitter(command_line, single_quotes_allowed=single_quotes_allowed)
539
 
    # Now that we've split the content, expand globs if necessary
 
377
    # First, split the command line
 
378
    s = cmdline.Splitter(
 
379
        command_line, single_quotes_allowed=single_quotes_allowed)
 
380
 
 
381
    # Bug #587868 Now make sure that the length of s agrees with sys.argv
 
382
    # we do this by simply counting the number of arguments in each. The counts should
 
383
    # agree no matter what encoding sys.argv is in (AFAIK)
 
384
    # len(arguments) < len(sys.argv) should be an impossibility since python gets
 
385
    # args from the very same PEB as does GetCommandLineW
 
386
    arguments = list(s)
 
387
 
 
388
    # Now shorten the command line we get from GetCommandLineW to match sys.argv
 
389
    if len(arguments) < len(argv):
 
390
        raise AssertionError("Split command line can't be shorter than argv")
 
391
    arguments = arguments[len(arguments) - len(argv):]
 
392
 
 
393
    # Carry on to process globs (metachars) in the command line
 
394
    # expand globs if necessary
540
395
    # TODO: Use 'globbing' instead of 'glob.glob', this gives us stuff like
541
396
    #       '**/' style globs
542
397
    args = []
543
 
    for is_quoted, arg in s:
 
398
    for is_quoted, arg in arguments:
544
399
        if is_quoted or not glob.has_magic(arg):
545
400
            args.append(arg)
546
401
        else:
548
403
    return args
549
404
 
550
405
 
551
 
if has_ctypes and winver != 'Windows 98':
552
 
    def get_unicode_argv():
553
 
        prototype = ctypes.WINFUNCTYPE(ctypes.c_wchar_p)
554
 
        GetCommandLineW = prototype(("GetCommandLineW",
555
 
                                     ctypes.windll.kernel32))
556
 
        command_line = GetCommandLineW()
557
 
        if command_line is None:
558
 
            raise ctypes.WinError()
559
 
        # Skip the first argument, since we only care about parameters
560
 
        argv = _command_line_to_argv(command_line)[1:]
561
 
        if getattr(sys, 'frozen', None) is None:
562
 
            # Invoked via 'python.exe' which takes the form:
563
 
            #   python.exe [PYTHON_OPTIONS] C:\Path\bzr [BZR_OPTIONS]
564
 
            # we need to get only BZR_OPTIONS part,
565
 
            # We already removed 'python.exe' so we remove everything up to and
566
 
            # including the first non-option ('-') argument.
567
 
            for idx in xrange(len(argv)):
568
 
                if argv[idx][:1] != '-':
569
 
                    break
570
 
            argv = argv[idx+1:]
571
 
        return argv
572
 
else:
573
 
    get_unicode_argv = None
 
406
def _ctypes_is_local_pid_dead(pid):
 
407
    import ctypes
 
408
    kernel32 = ctypes.wintypes.windll.kernel32
 
409
    """True if pid doesn't correspond to live process on this machine"""
 
410
    handle = kernel32.OpenProcess(1, False, pid)
 
411
    if not handle:
 
412
        errorcode = ctypes.GetLastError()
 
413
        if errorcode == 5:  # ERROR_ACCESS_DENIED
 
414
            # Probably something alive we're not allowed to kill
 
415
            return False
 
416
        elif errorcode == 87:  # ERROR_INVALID_PARAMETER
 
417
            return True
 
418
        raise ctypes.WinError(errorcode)
 
419
    Kernel32.CloseHandle(handle)
 
420
    return False
 
421
 
 
422
is_local_pid_dead = _ctypes_is_local_pid_dead