~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/win32utils.py

  • Committer: Ian Clatworthy
  • Date: 2007-08-13 14:33:10 UTC
  • mto: (2733.1.1 ianc-integration)
  • mto: This revision was merged to the branch mainline in revision 2734.
  • Revision ID: ian.clatworthy@internode.on.net-20070813143310-twhj4la0qnupvze8
Added Quick Start Summary

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
 
 
68
 
 
69
# Special Win32 API constants
 
70
# Handles of std streams
 
71
WIN32_STDIN_HANDLE = -10
 
72
WIN32_STDOUT_HANDLE = -11
 
73
WIN32_STDERR_HANDLE = -12
 
74
 
 
75
# CSIDL constants (from MSDN 2003)
 
76
CSIDL_APPDATA = 0x001A      # Application Data folder
 
77
CSIDL_PERSONAL = 0x0005     # My Documents folder
 
78
 
 
79
# from winapi C headers
 
80
MAX_PATH = 260
 
81
UNLEN = 256
 
82
MAX_COMPUTERNAME_LENGTH = 31
 
83
 
 
84
 
 
85
def get_console_size(defaultx=80, defaulty=25):
 
86
    """Return size of current console.
 
87
 
 
88
    This function try to determine actual size of current working
 
89
    console window and return tuple (sizex, sizey) if success,
 
90
    or default size (defaultx, defaulty) otherwise.
 
91
    """
 
92
    if not has_ctypes:
 
93
        # no ctypes is found
 
94
        return (defaultx, defaulty)
 
95
 
 
96
    # To avoid problem with redirecting output via pipe
 
97
    # need to use stderr instead of stdout
 
98
    h = ctypes.windll.kernel32.GetStdHandle(WIN32_STDERR_HANDLE)
 
99
    csbi = ctypes.create_string_buffer(22)
 
100
    res = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
 
101
 
 
102
    if res:
 
103
        (bufx, bufy, curx, cury, wattr,
 
104
        left, top, right, bottom, maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
 
105
        sizex = right - left + 1
 
106
        sizey = bottom - top + 1
 
107
        return (sizex, sizey)
 
108
    else:
 
109
        return (defaultx, defaulty)
 
110
 
 
111
 
 
112
def get_appdata_location():
 
113
    """Return Application Data location.
 
114
    Return None if we cannot obtain location.
 
115
 
 
116
    Returned value can be unicode or plain sring.
 
117
    To convert plain string to unicode use
 
118
    s.decode(bzrlib.user_encoding)
 
119
    """
 
120
    if has_ctypes:
 
121
        try:
 
122
            SHGetSpecialFolderPath = \
 
123
                ctypes.windll.shell32.SHGetSpecialFolderPathW
 
124
        except AttributeError:
 
125
            pass
 
126
        else:
 
127
            buf = ctypes.create_unicode_buffer(MAX_PATH)
 
128
            if SHGetSpecialFolderPath(None,buf,CSIDL_APPDATA,0):
 
129
                return buf.value
 
130
    # from env variable
 
131
    appdata = os.environ.get('APPDATA')
 
132
    if appdata:
 
133
        return appdata
 
134
    # if we fall to this point we on win98
 
135
    # at least try C:/WINDOWS/Application Data
 
136
    windir = os.environ.get('windir')
 
137
    if windir:
 
138
        appdata = os.path.join(windir, 'Application Data')
 
139
        if os.path.isdir(appdata):
 
140
            return appdata
 
141
    # did not find anything
 
142
    return None
 
143
 
 
144
 
 
145
def get_home_location():
 
146
    """Return user's home location.
 
147
    Assume on win32 it's the <My Documents> folder.
 
148
    If location cannot be obtained return system drive root,
 
149
    i.e. C:\
 
150
 
 
151
    Returned value can be unicode or plain sring.
 
152
    To convert plain string to unicode use
 
153
    s.decode(bzrlib.user_encoding)
 
154
    """
 
155
    if has_ctypes:
 
156
        try:
 
157
            SHGetSpecialFolderPath = \
 
158
                ctypes.windll.shell32.SHGetSpecialFolderPathW
 
159
        except AttributeError:
 
160
            pass
 
161
        else:
 
162
            buf = ctypes.create_unicode_buffer(MAX_PATH)
 
163
            if SHGetSpecialFolderPath(None,buf,CSIDL_PERSONAL,0):
 
164
                return buf.value
 
165
    # try for HOME env variable
 
166
    home = os.path.expanduser('~')
 
167
    if home != '~':
 
168
        return home
 
169
    # at least return windows root directory
 
170
    windir = os.environ.get('windir')
 
171
    if windir:
 
172
        return os.path.splitdrive(windir)[0] + '/'
 
173
    # otherwise C:\ is good enough for 98% users
 
174
    return 'C:/'
 
175
 
 
176
 
 
177
def get_user_name():
 
178
    """Return user name as login name.
 
179
    If name cannot be obtained return None.
 
180
 
 
181
    Returned value can be unicode or plain sring.
 
182
    To convert plain string to unicode use
 
183
    s.decode(bzrlib.user_encoding)
 
184
    """
 
185
    if has_ctypes:
 
186
        try:
 
187
            advapi32 = ctypes.windll.advapi32
 
188
            GetUserName = getattr(advapi32, 'GetUserName'+suffix)
 
189
        except AttributeError:
 
190
            pass
 
191
        else:
 
192
            buf = create_buffer(UNLEN+1)
 
193
            n = ctypes.c_int(UNLEN+1)
 
194
            if GetUserName(buf, ctypes.byref(n)):
 
195
                return buf.value
 
196
    # otherwise try env variables
 
197
    return os.environ.get('USERNAME', None)
 
198
 
 
199
 
 
200
def get_host_name():
 
201
    """Return host machine name.
 
202
    If name cannot be obtained return None.
 
203
 
 
204
    Returned value can be unicode or plain sring.
 
205
    To convert plain string to unicode use
 
206
    s.decode(bzrlib.user_encoding)
 
207
    """
 
208
    if has_ctypes:
 
209
        try:
 
210
            kernel32 = ctypes.windll.kernel32
 
211
            GetComputerName = getattr(kernel32, 'GetComputerName'+suffix)
 
212
        except AttributeError:
 
213
            pass
 
214
        else:
 
215
            buf = create_buffer(MAX_COMPUTERNAME_LENGTH+1)
 
216
            n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1)
 
217
            if GetComputerName(buf, ctypes.byref(n)):
 
218
                return buf.value
 
219
    # otherwise try env variables
 
220
    return os.environ.get('COMPUTERNAME', None)
 
221
 
 
222
 
 
223
def _ensure_unicode(s):
 
224
    if s and type(s) != unicode:
 
225
        import bzrlib
 
226
        s = s.decode(bzrlib.user_encoding)
 
227
    return s
 
228
    
 
229
 
 
230
def get_appdata_location_unicode():
 
231
    return _ensure_unicode(get_appdata_location())
 
232
 
 
233
def get_home_location_unicode():
 
234
    return _ensure_unicode(get_home_location())
 
235
 
 
236
def get_user_name_unicode():
 
237
    return _ensure_unicode(get_user_name())
 
238
 
 
239
def get_host_name_unicode():
 
240
    return _ensure_unicode(get_host_name())
 
241
 
 
242
 
 
243
def _ensure_with_dir(path):
 
244
    if not os.path.split(path)[0] or path.startswith(u'*') or path.startswith(u'?'):
 
245
        return u'./' + path, True
 
246
    else:
 
247
        return path, False
 
248
    
 
249
def _undo_ensure_with_dir(path, corrected):
 
250
    if corrected:
 
251
        return path[2:]
 
252
    else:
 
253
        return path
 
254
 
 
255
 
 
256
 
 
257
def glob_expand(file_list):
 
258
    """Replacement for glob expansion by the shell.
 
259
 
 
260
    Win32's cmd.exe does not do glob expansion (eg ``*.py``), so we do our own
 
261
    here.
 
262
 
 
263
    :param file_list: A list of filenames which may include shell globs.
 
264
    :return: An expanded list of filenames.
 
265
 
 
266
    Introduced in bzrlib 0.18.
 
267
    """
 
268
    if not file_list:
 
269
        return []
 
270
    import glob
 
271
    expanded_file_list = []
 
272
    for possible_glob in file_list:
 
273
        
 
274
        # work around bugs in glob.glob()
 
275
        # - Python bug #1001604 ("glob doesn't return unicode with ...")
 
276
        # - failing expansion for */* with non-iso-8859-* chars
 
277
        possible_glob, corrected = _ensure_with_dir(possible_glob)
 
278
        glob_files = glob.glob(possible_glob)
 
279
 
 
280
        if glob_files == []:
 
281
            # special case to let the normal code path handle
 
282
            # files that do not exists
 
283
            expanded_file_list.append(
 
284
                _undo_ensure_with_dir(possible_glob, corrected))
 
285
        else:
 
286
            glob_files = [_undo_ensure_with_dir(elem, corrected) for elem in glob_files]
 
287
            expanded_file_list += glob_files
 
288
            
 
289
    return [elem.replace(u'\\', u'/') for elem in expanded_file_list]