~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/win32console.py

Close logging handler on disabling the test log. This will remove the
handler from the internal list inside python's logging module,
preventing shutdown from closing it twice.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007 Canonical Ltd
2
 
#
3
 
# This program is free software; you can redistribute it and/or modify
4
 
# it under the terms of the GNU General Public License as published by
5
 
# the Free Software Foundation; either version 2 of the License, or
6
 
# (at your option) any later version.
7
 
#
8
 
# This program is distributed in the hope that it will be useful,
9
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
# GNU General Public License for more details.
12
 
#
13
 
# You should have received a copy of the GNU General Public License
14
 
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
 
 
17
 
"""Win32-specific helper functions
18
 
 
19
 
Only one dependency: ctypes should be installed.
20
 
"""
21
 
 
22
 
import os
 
1
 
 
2
"""
 
3
Set of functions to work with console on Windows.
 
4
Author: Alexander Belchenko (e-mail: bialix AT ukr.net)
 
5
License: Public domain
 
6
"""
 
7
 
23
8
import struct
24
 
import sys
25
 
 
26
 
 
27
 
# Windows version
28
 
if sys.platform == 'win32':
29
 
    _major,_minor,_build,_platform,_text = sys.getwindowsversion()
30
 
    # from MSDN:
31
 
    # dwPlatformId
32
 
    #   The operating system platform.
33
 
    #   This member can be one of the following values.
34
 
    #   ==========================  ======================================
35
 
    #   Value                       Meaning
36
 
    #   --------------------------  --------------------------------------
37
 
    #   VER_PLATFORM_WIN32_NT       The operating system is Windows Vista,
38
 
    #   2                           Windows Server "Longhorn",
39
 
    #                               Windows Server 2003, Windows XP,
40
 
    #                               Windows 2000, or Windows NT.
41
 
    #
42
 
    #   VER_PLATFORM_WIN32_WINDOWS  The operating system is Windows Me,
43
 
    #   1                           Windows 98, or Windows 95.
44
 
    #   ==========================  ======================================
45
 
    if _platform == 2:
46
 
        winver = 'Windows NT'
47
 
    else:
48
 
        # don't care about real Windows name, just to force safe operations
49
 
        winver = 'Windows 98'
50
 
else:
51
 
    winver = None
52
 
 
53
 
 
54
 
# We can cope without it; use a separate variable to help pyflakes
55
 
try:
56
 
    import ctypes
57
 
    has_ctypes = True
58
 
except ImportError:
59
 
    has_ctypes = False
60
 
else:
61
 
    if winver == 'Windows 98':
62
 
        create_buffer = ctypes.create_string_buffer
63
 
        suffix = 'A'
64
 
    else:
65
 
        create_buffer = ctypes.create_unicode_buffer
66
 
        suffix = 'W'
67
 
try:
68
 
    import win32file
69
 
    has_win32file = True
70
 
except ImportError:
71
 
    has_win32file = False
72
 
 
73
 
 
74
 
# Special Win32 API constants
75
 
# Handles of std streams
76
 
WIN32_STDIN_HANDLE = -10
77
 
WIN32_STDOUT_HANDLE = -11
78
 
WIN32_STDERR_HANDLE = -12
79
 
 
80
 
# CSIDL constants (from MSDN 2003)
81
 
CSIDL_APPDATA = 0x001A      # Application Data folder
82
 
CSIDL_PERSONAL = 0x0005     # My Documents folder
83
 
 
84
 
# from winapi C headers
85
 
MAX_PATH = 260
86
 
UNLEN = 256
87
 
MAX_COMPUTERNAME_LENGTH = 31
 
9
 
 
10
try:
 
11
   import ctypes
 
12
except ImportError:
 
13
   ctypes = None
88
14
 
89
15
 
90
16
def get_console_size(defaultx=80, defaulty=25):
91
 
    """Return size of current console.
92
 
 
93
 
    This function try to determine actual size of current working
94
 
    console window and return tuple (sizex, sizey) if success,
95
 
    or default size (defaultx, defaulty) otherwise.
96
 
    """
97
 
    if not has_ctypes:
98
 
        # no ctypes is found
99
 
        return (defaultx, defaulty)
100
 
 
101
 
    # To avoid problem with redirecting output via pipe
102
 
    # need to use stderr instead of stdout
103
 
    h = ctypes.windll.kernel32.GetStdHandle(WIN32_STDERR_HANDLE)
104
 
    csbi = ctypes.create_string_buffer(22)
105
 
    res = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
106
 
 
107
 
    if res:
108
 
        (bufx, bufy, curx, cury, wattr,
 
17
   """ Return size of current console.
 
18
 
 
19
   This function try to determine actual size of current working
 
20
   console window and return tuple (sizex, sizey) if success,
 
21
   or default size (defaultx, defaulty) otherwise.
 
22
 
 
23
   Dependencies: ctypes should be installed.
 
24
   """
 
25
   if ctypes is None:
 
26
       # no ctypes is found
 
27
       return (defaultx, defaulty)
 
28
 
 
29
   h = ctypes.windll.kernel32.GetStdHandle(-11)
 
30
   csbi = ctypes.create_string_buffer(22)
 
31
   res = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
 
32
 
 
33
   if res:
 
34
       (bufx, bufy, curx, cury, wattr,
109
35
        left, top, right, bottom, maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
110
 
        sizex = right - left + 1
111
 
        sizey = bottom - top + 1
112
 
        return (sizex, sizey)
113
 
    else:
114
 
        return (defaultx, defaulty)
115
 
 
116
 
 
117
 
def get_appdata_location():
118
 
    """Return Application Data location.
119
 
    Return None if we cannot obtain location.
120
 
 
121
 
    Returned value can be unicode or plain sring.
122
 
    To convert plain string to unicode use
123
 
    s.decode(bzrlib.user_encoding)
124
 
    """
125
 
    if has_ctypes:
126
 
        try:
127
 
            SHGetSpecialFolderPath = \
128
 
                ctypes.windll.shell32.SHGetSpecialFolderPathW
129
 
        except AttributeError:
130
 
            pass
131
 
        else:
132
 
            buf = ctypes.create_unicode_buffer(MAX_PATH)
133
 
            if SHGetSpecialFolderPath(None,buf,CSIDL_APPDATA,0):
134
 
                return buf.value
135
 
    # from env variable
136
 
    appdata = os.environ.get('APPDATA')
137
 
    if appdata:
138
 
        return appdata
139
 
    # if we fall to this point we on win98
140
 
    # at least try C:/WINDOWS/Application Data
141
 
    windir = os.environ.get('windir')
142
 
    if windir:
143
 
        appdata = os.path.join(windir, 'Application Data')
144
 
        if os.path.isdir(appdata):
145
 
            return appdata
146
 
    # did not find anything
147
 
    return None
148
 
 
149
 
 
150
 
def get_home_location():
151
 
    """Return user's home location.
152
 
    Assume on win32 it's the <My Documents> folder.
153
 
    If location cannot be obtained return system drive root,
154
 
    i.e. C:\
155
 
 
156
 
    Returned value can be unicode or plain sring.
157
 
    To convert plain string to unicode use
158
 
    s.decode(bzrlib.user_encoding)
159
 
    """
160
 
    if has_ctypes:
161
 
        try:
162
 
            SHGetSpecialFolderPath = \
163
 
                ctypes.windll.shell32.SHGetSpecialFolderPathW
164
 
        except AttributeError:
165
 
            pass
166
 
        else:
167
 
            buf = ctypes.create_unicode_buffer(MAX_PATH)
168
 
            if SHGetSpecialFolderPath(None,buf,CSIDL_PERSONAL,0):
169
 
                return buf.value
170
 
    # try for HOME env variable
171
 
    home = os.path.expanduser('~')
172
 
    if home != '~':
173
 
        return home
174
 
    # at least return windows root directory
175
 
    windir = os.environ.get('windir')
176
 
    if windir:
177
 
        return os.path.splitdrive(windir)[0] + '/'
178
 
    # otherwise C:\ is good enough for 98% users
179
 
    return 'C:/'
180
 
 
181
 
 
182
 
def get_user_name():
183
 
    """Return user name as login name.
184
 
    If name cannot be obtained return None.
185
 
 
186
 
    Returned value can be unicode or plain sring.
187
 
    To convert plain string to unicode use
188
 
    s.decode(bzrlib.user_encoding)
189
 
    """
190
 
    if has_ctypes:
191
 
        try:
192
 
            advapi32 = ctypes.windll.advapi32
193
 
            GetUserName = getattr(advapi32, 'GetUserName'+suffix)
194
 
        except AttributeError:
195
 
            pass
196
 
        else:
197
 
            buf = create_buffer(UNLEN+1)
198
 
            n = ctypes.c_int(UNLEN+1)
199
 
            if GetUserName(buf, ctypes.byref(n)):
200
 
                return buf.value
201
 
    # otherwise try env variables
202
 
    return os.environ.get('USERNAME', None)
203
 
 
204
 
 
205
 
def get_host_name():
206
 
    """Return host machine name.
207
 
    If name cannot be obtained return None.
208
 
 
209
 
    Returned value can be unicode or plain sring.
210
 
    To convert plain string to unicode use
211
 
    s.decode(bzrlib.user_encoding)
212
 
    """
213
 
    if has_ctypes:
214
 
        try:
215
 
            kernel32 = ctypes.windll.kernel32
216
 
            GetComputerName = getattr(kernel32, 'GetComputerName'+suffix)
217
 
        except AttributeError:
218
 
            pass
219
 
        else:
220
 
            buf = create_buffer(MAX_COMPUTERNAME_LENGTH+1)
221
 
            n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1)
222
 
            if GetComputerName(buf, ctypes.byref(n)):
223
 
                return buf.value
224
 
    # otherwise try env variables
225
 
    return os.environ.get('COMPUTERNAME', None)
226
 
 
227
 
 
228
 
def _ensure_unicode(s):
229
 
    if s and type(s) != unicode:
230
 
        import bzrlib
231
 
        s = s.decode(bzrlib.user_encoding)
232
 
    return s
233
 
    
234
 
 
235
 
def get_appdata_location_unicode():
236
 
    return _ensure_unicode(get_appdata_location())
237
 
 
238
 
def get_home_location_unicode():
239
 
    return _ensure_unicode(get_home_location())
240
 
 
241
 
def get_user_name_unicode():
242
 
    return _ensure_unicode(get_user_name())
243
 
 
244
 
def get_host_name_unicode():
245
 
    return _ensure_unicode(get_host_name())
246
 
 
247
 
 
248
 
def _ensure_with_dir(path):
249
 
    if not os.path.split(path)[0] or path.startswith(u'*') or path.startswith(u'?'):
250
 
        return u'./' + path, True
251
 
    else:
252
 
        return path, False
253
 
    
254
 
def _undo_ensure_with_dir(path, corrected):
255
 
    if corrected:
256
 
        return path[2:]
257
 
    else:
258
 
        return path
259
 
 
260
 
 
261
 
 
262
 
def glob_expand(file_list):
263
 
    """Replacement for glob expansion by the shell.
264
 
 
265
 
    Win32's cmd.exe does not do glob expansion (eg ``*.py``), so we do our own
266
 
    here.
267
 
 
268
 
    :param file_list: A list of filenames which may include shell globs.
269
 
    :return: An expanded list of filenames.
270
 
 
271
 
    Introduced in bzrlib 0.18.
272
 
    """
273
 
    if not file_list:
274
 
        return []
275
 
    import glob
276
 
    expanded_file_list = []
277
 
    for possible_glob in file_list:
278
 
        
279
 
        # work around bugs in glob.glob()
280
 
        # - Python bug #1001604 ("glob doesn't return unicode with ...")
281
 
        # - failing expansion for */* with non-iso-8859-* chars
282
 
        possible_glob, corrected = _ensure_with_dir(possible_glob)
283
 
        glob_files = glob.glob(possible_glob)
284
 
 
285
 
        if glob_files == []:
286
 
            # special case to let the normal code path handle
287
 
            # files that do not exists
288
 
            expanded_file_list.append(
289
 
                _undo_ensure_with_dir(possible_glob, corrected))
290
 
        else:
291
 
            glob_files = [_undo_ensure_with_dir(elem, corrected) for elem in glob_files]
292
 
            expanded_file_list += glob_files
293
 
            
294
 
    return [elem.replace(u'\\', u'/') for elem in expanded_file_list] 
295
 
 
296
 
 
297
 
def get_app_path(appname):
298
 
    """Look up in Windows registry for full path to application executable.
299
 
    Typicaly, applications create subkey with their basename
300
 
    in HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\
301
 
 
302
 
    :param  appname:    name of application (if no filename extension
303
 
                        is specified, .exe used)
304
 
    :return:    full path to aplication executable from registry,
305
 
                or appname itself if nothing found.
306
 
    """
307
 
    import _winreg
308
 
    try:
309
 
        hkey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
310
 
                               r'SOFTWARE\Microsoft\Windows'
311
 
                               r'\CurrentVersion\App Paths')
312
 
    except EnvironmentError:
313
 
        return appname
314
 
 
315
 
    basename = appname
316
 
    if not os.path.splitext(basename)[1]:
317
 
        basename = appname + '.exe'
318
 
    try:
319
 
        try:
320
 
            fullpath = _winreg.QueryValue(hkey, basename)
321
 
        except WindowsError:
322
 
            fullpath = appname
323
 
    finally:
324
 
        _winreg.CloseKey(hkey)
325
 
 
326
 
    return fullpath
327
 
 
328
 
 
329
 
def set_file_attr_hidden(path):
330
 
    """Set file attributes to hidden if possible"""
331
 
    if has_win32file:
332
 
        win32file.SetFileAttributes(path, win32file.FILE_ATTRIBUTE_HIDDEN)
 
36
       sizex = right - left + 1
 
37
       sizey = bottom - top + 1
 
38
       return (sizex, sizey)
 
39
   else:
 
40
       return (defaultx, defaulty)