~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/win32utils.py

  • Committer: Mark Hammond
  • Date: 2008-08-23 03:58:23 UTC
  • mto: This revision was merged to the branch mainline in revision 3728.
  • Revision ID: mhammond@skippinet.com.au-20080823035823-1anntol029n0il6r
Add win32utils.get_local_appdata_location() so bzr and plugins can 
differentiate between the 'local' and 'roaming' locations offered by
windows.  Includes support for falling back to pywin32 if ctypes isn't
available and introduces new tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
70
70
except ImportError:
71
71
    has_win32file = False
72
72
 
 
73
# pulling in win32com.shell is a bit of overhead, and normally we don't need
 
74
# it as ctypes is preferred and common.  lazy_imports and "optional"
 
75
# modules don't work well, so we do our own lazy thing...
 
76
has_win32com_shell = None # Set to True or False once we know for sure...
73
77
 
74
78
# Special Win32 API constants
75
79
# Handles of std streams
79
83
 
80
84
# CSIDL constants (from MSDN 2003)
81
85
CSIDL_APPDATA = 0x001A      # Application Data folder
 
86
CSIDL_LOCAL_APPDATA = 0x001c# <user name>\Local Settings\Applicaiton Data (non roaming)
82
87
CSIDL_PERSONAL = 0x0005     # My Documents folder
83
88
 
84
89
# from winapi C headers
114
119
        return (defaultx, defaulty)
115
120
 
116
121
 
 
122
def _get_sh_special_folder_path(csidl):
 
123
    """Call SHGetSpecialFolderPathW if available, or return None.
 
124
    
 
125
    Result is always unicode (or None).
 
126
    """
 
127
    if has_ctypes:
 
128
        try:
 
129
            SHGetSpecialFolderPath = \
 
130
                ctypes.windll.shell32.SHGetSpecialFolderPathW
 
131
        except AttributeError:
 
132
            pass
 
133
        else:
 
134
            buf = ctypes.create_unicode_buffer(MAX_PATH)
 
135
            if SHGetSpecialFolderPath(None,buf,csidl,0):
 
136
                return buf.value
 
137
 
 
138
    global has_win32com_shell
 
139
    if has_win32com_shell is None:
 
140
        try:
 
141
            from win32com.shell import shell
 
142
            has_win32com_shell = True
 
143
        except ImportError:
 
144
            has_win32com_shell = False
 
145
    if has_win32com_shell:
 
146
        # still need to bind the name locally, but this is fast.
 
147
        from win32com.shell import shell
 
148
        try:
 
149
            return shell.SHGetSpecialFolderPath(0, csidl, 0)
 
150
        except shell.error:
 
151
            # possibly E_NOTIMPL meaning we can't load the function pointer,
 
152
            # or E_FAIL meaning the function failed - regardless, just ignore it
 
153
            pass
 
154
    return None
 
155
 
 
156
 
117
157
def get_appdata_location():
118
158
    """Return Application Data location.
119
159
    Return None if we cannot obtain location.
120
160
 
121
 
    Returned value can be unicode or plain sring.
 
161
    Windows defines two 'Application Data' folders per user - a 'roaming'
 
162
    one that moves with the user as they logon to different machines, and
 
163
    a 'local' one that stays local to the machine.  This returns the 'roaming'
 
164
    directory, and thus is suitable for storing user-preferences, etc.
 
165
 
 
166
    Returned value can be unicode or plain string.
122
167
    To convert plain string to unicode use
123
168
    s.decode(bzrlib.user_encoding)
124
169
    """
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
 
170
    appdata = _get_sh_special_folder_path(CSIDL_APPDATA)
 
171
    if appdata:
 
172
        return appdata
135
173
    # from env variable
136
174
    appdata = os.environ.get('APPDATA')
137
175
    if appdata:
147
185
    return None
148
186
 
149
187
 
 
188
def get_local_appdata_location():
 
189
    """Return Local Application Data location.
 
190
    Return the same as get_appdata_location() if we cannot obtain location.
 
191
 
 
192
    Windows defines two 'Application Data' folders per user - a 'roaming'
 
193
    one that moves with the user as they logon to different machines, and
 
194
    a 'local' one that stays local to the machine.  This returns the 'local'
 
195
    directory, and thus is suitable for caches, temp files and other things
 
196
    which don't need to move with the user.
 
197
 
 
198
    Returned value can be unicode or plain string.
 
199
    To convert plain string to unicode use
 
200
    s.decode(bzrlib.user_encoding)
 
201
    """
 
202
    local = _get_sh_special_folder_path(CSIDL_LOCAL_APPDATA)
 
203
    if local:
 
204
        return local
 
205
    # Vista supplies LOCALAPPDATA, but XP and earlier do not.
 
206
    local = os.environ.get('LOCALAPPDATA')
 
207
    if local:
 
208
        return local
 
209
    return get_appdata_location()
 
210
 
 
211
 
150
212
def get_home_location():
151
213
    """Return user's home location.
152
214
    Assume on win32 it's the <My Documents> folder.
157
219
    To convert plain string to unicode use
158
220
    s.decode(bzrlib.user_encoding)
159
221
    """
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
 
222
    home = _get_sh_special_folder_path(CSIDL_PERSONAL)
 
223
    if home:
 
224
        return home
170
225
    # try for HOME env variable
171
226
    home = os.path.expanduser('~')
172
227
    if home != '~':