~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/win32utils.py

  • Committer: Aaron Bentley
  • Date: 2008-03-29 21:16:20 UTC
  • mto: (3298.2.13 revision_id_to_revno)
  • mto: This revision was merged to the branch mainline in revision 3328.
  • Revision ID: aaron@aaronbentley.com-20080329211620-1a91xrjinusqxudy
Update tests for null:, clea up slightly

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
 
23
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
 
88
 
 
89
 
 
90
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,
 
109
        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)