27
from bzrlib import cmdline
30
if sys.platform == 'win32':
31
_major,_minor,_build,_platform,_text = sys.getwindowsversion()
34
# The operating system platform.
35
# This member can be one of the following values.
36
# ========================== ======================================
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.
44
# VER_PLATFORM_WIN32_WINDOWS The operating system is Windows Me,
45
# 1 Windows 98, or Windows 95.
46
# ========================== ======================================
50
# don't care about real Windows name, just to force safe operations
56
# We can cope without it; use a separate variable to help pyflakes
63
if winver == 'Windows 98':
64
create_buffer = ctypes.create_string_buffer
67
create_buffer = ctypes.create_unicode_buffer
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...
30
from breezy.i18n import gettext
86
33
# Special Win32 API constants
87
34
# Handles of std streams
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
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),
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))
131
trace.note('Failed to GetProcessMemoryInfo()')
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,
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)
152
trace.note('Cannot debug memory on win32 without 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),
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))
78
trace.note(gettext('Failed to GetProcessMemoryInfo()'))
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,
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,
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))
174
115
def get_console_size(defaultx=80, defaulty=25):
205
143
Result is always unicode (or None).
209
SHGetSpecialFolderPath = \
210
ctypes.windll.shell32.SHGetSpecialFolderPathW
211
except AttributeError:
214
buf = ctypes.create_unicode_buffer(MAX_PATH)
215
if SHGetSpecialFolderPath(None,buf,csidl,0):
218
global has_win32com_shell
219
if has_win32com_shell is None:
221
from win32com.shell import shell
222
has_win32com_shell = True
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
229
return shell.SHGetSpecialFolderPath(0, csidl, 0)
231
# possibly E_NOTIMPL meaning we can't load the function pointer,
232
# or E_FAIL meaning the function failed - regardless, just ignore it
147
SHGetSpecialFolderPath = \
148
ctypes.windll.shell32.SHGetSpecialFolderPathW
149
except AttributeError:
152
buf = ctypes.create_unicode_buffer(MAX_PATH)
153
if SHGetSpecialFolderPath(None, buf, csidl, 0):
237
157
def get_appdata_location():
296
195
Assume on win32 it's the <My Documents> folder.
297
196
If location cannot be obtained return system drive root,
300
Returned value can be unicode or plain string.
301
To convert plain string to unicode use
302
s.decode(osutils.get_user_encoding())
304
199
home = _get_sh_special_folder_path(CSIDL_PERSONAL)
307
# try for HOME env variable
308
home = os.path.expanduser('~')
202
home = os.environ.get('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')
314
211
return os.path.splitdrive(windir)[0] + '/'
315
212
# otherwise C:\ is good enough for 98% users
319
216
def get_user_name():
320
217
"""Return user name as login name.
321
218
If name cannot be obtained return None.
323
Returned value can be unicode or plain string.
324
To convert plain string to unicode use
325
s.decode(osutils.get_user_encoding())
329
advapi32 = ctypes.windll.advapi32
330
GetUserName = getattr(advapi32, 'GetUserName'+suffix)
331
except AttributeError:
334
buf = create_buffer(UNLEN+1)
335
n = ctypes.c_int(UNLEN+1)
336
if GetUserName(buf, ctypes.byref(n)):
221
advapi32 = ctypes.windll.advapi32
222
GetUserName = getattr(advapi32, 'GetUserNameW')
223
except AttributeError:
226
buf = ctypes.create_unicode_buffer(UNLEN + 1)
227
n = ctypes.c_int(UNLEN + 1)
228
if GetUserName(buf, ctypes.byref(n)):
338
230
# otherwise try env variables
339
return os.environ.get('USERNAME', None)
231
return os.environ.get('USERNAME')
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
346
239
def get_host_name():
347
240
"""Return host machine name.
348
241
If name cannot be obtained return None.
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.
355
return win32api.GetComputerNameEx(_WIN32_ComputerNameDnsHostname)
356
except (NotImplementedError, win32api.error):
357
# NotImplemented will happen on win9x...
361
kernel32 = ctypes.windll.kernel32
362
except AttributeError:
363
pass # Missing the module we need
365
buf = create_buffer(MAX_COMPUTERNAME_LENGTH+1)
366
n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1)
368
# Try GetComputerNameEx which gives a proper Unicode hostname
369
GetComputerNameEx = getattr(kernel32, 'GetComputerNameEx'+suffix,
371
if (GetComputerNameEx is not None
372
and GetComputerNameEx(_WIN32_ComputerNameDnsHostname,
373
buf, ctypes.byref(n))):
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,
382
if (GetComputerName is not None
383
and GetComputerName(buf, ctypes.byref(n))):
385
# otherwise try env variables, which will be 'mbcs' encoded
386
# on Windows (Python doesn't expose the native win32 unicode environment)
388
# http://msdn.microsoft.com/en-us/library/aa246807.aspx
389
# environment variables should always be encoded in 'mbcs'.
391
return os.environ['COMPUTERNAME'].decode("mbcs")
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())
403
def get_appdata_location_unicode():
404
return _ensure_unicode(get_appdata_location())
406
def get_home_location_unicode():
407
return _ensure_unicode(get_home_location())
409
def get_user_name_unicode():
410
return _ensure_unicode(get_user_name())
412
def get_host_name_unicode():
413
return _ensure_unicode(get_host_name())
246
buf = ctypes.create_unicode_buffer(MAX_COMPUTERNAME_LENGTH + 1)
247
n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH + 1)
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))):
256
return os.environ.get('COMPUTERNAME')
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
421
264
return path, False
423
267
def _undo_ensure_with_dir(path, corrected):
501
344
if type_id == REG_SZ:
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
511
349
def set_file_attr_hidden(path):
512
350
"""Set file attributes to hidden if possible"""
514
if winver != 'Windows 98':
515
SetFileAttributes = win32file.SetFileAttributesW
517
SetFileAttributes = win32file.SetFileAttributes
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)
525
def _command_line_to_argv(command_line, single_quotes_allowed=False):
351
from ctypes.wintypes import BOOL, DWORD, LPWSTR
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()
361
trace.mutter('Unable to set hidden attribute on %r: %s', path, e)
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.
528
367
It performs wildcard expansion to make wildcards act closer to how they
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] != '-':
573
get_unicode_argv = None
406
def _ctypes_is_local_pid_dead(pid):
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)
412
errorcode = ctypes.GetLastError()
413
if errorcode == 5: # ERROR_ACCESS_DENIED
414
# Probably something alive we're not allowed to kill
416
elif errorcode == 87: # ERROR_INVALID_PARAMETER
418
raise ctypes.WinError(errorcode)
419
Kernel32.CloseHandle(handle)
422
is_local_pid_dead = _ctypes_is_local_pid_dead