~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to tools/win32/bzr_postinstall.py

  • Committer: John Arbash Meinel
  • Date: 2007-04-12 21:18:29 UTC
  • mto: This revision was merged to the branch mainline in revision 2415.
  • Revision ID: john@arbash-meinel.com-20070412211829-dduwktk8in0e6zpl
Clean up test ordering

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005 by 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
"""bzr postinstall helper for win32 installation
 
18
Written by Alexander Belchenko
 
19
 
 
20
Dependency: ctypes
 
21
"""
 
22
 
 
23
import os
 
24
import shutil
 
25
import sys
 
26
 
 
27
 
 
28
##
 
29
# CONSTANTS
 
30
 
 
31
VERSION = "1.5.20070131"
 
32
 
 
33
USAGE = """Bzr postinstall helper for win32 installation
 
34
Usage: %s [options]
 
35
 
 
36
OPTIONS:
 
37
    -h, --help                  - help message
 
38
    -v, --version               - version info
 
39
 
 
40
    -n, --dry-run               - print actions rather than execute them
 
41
    -q, --silent                - no messages for user
 
42
 
 
43
    --start-bzr                 - update start_bzr.bat
 
44
    --add-path                  - add bzr directory to environment PATH
 
45
    --delete-path               - delete bzr directory to environment PATH
 
46
    --add-shell-menu            - add shell context menu to start bzr session
 
47
    --delete-shell-menu         - delete context menu from shell
 
48
    --check-mfc71               - check if MFC71.DLL present in system
 
49
""" % os.path.basename(sys.argv[0])
 
50
 
 
51
# Windows version
 
52
_major,_minor,_build,_platform,_text = sys.getwindowsversion()
 
53
# from MSDN:
 
54
# dwPlatformId
 
55
#   The operating system platform.
 
56
#   This member can be one of the following values.
 
57
#   ==========================  ======================================
 
58
#   Value                       Meaning
 
59
#   --------------------------  --------------------------------------
 
60
#   VER_PLATFORM_WIN32_NT       The operating system is Windows Vista,
 
61
#   2                           Windows Server "Longhorn",
 
62
#                               Windows Server 2003, Windows XP,
 
63
#                               Windows 2000, or Windows NT.
 
64
#
 
65
#   VER_PLATFORM_WIN32_WINDOWS  The operating system is Windows Me,
 
66
#   1                           Windows 98, or Windows 95.
 
67
#   ==========================  ======================================
 
68
if _platform == 2:
 
69
    winver = 'Windows NT'
 
70
else:
 
71
    # don't care about real Windows name, just to force safe operations
 
72
    winver = 'Windows 98'
 
73
 
 
74
 
 
75
##
 
76
# INTERNAL VARIABLES
 
77
 
 
78
(OK, ERROR) = range(2)
 
79
VERSION_FORMAT = "%-50s%s"
 
80
 
 
81
 
 
82
def main():
 
83
    import ctypes
 
84
    import getopt
 
85
    import re
 
86
    import _winreg
 
87
 
 
88
    import locale
 
89
    user_encoding = locale.getpreferredencoding() or 'ascii'
 
90
 
 
91
    import ctypes
 
92
 
 
93
    hkey_str = {_winreg.HKEY_LOCAL_MACHINE: 'HKEY_LOCAL_MACHINE',
 
94
                _winreg.HKEY_CURRENT_USER: 'HKEY_CURRENT_USER',
 
95
                _winreg.HKEY_CLASSES_ROOT: 'HKEY_CLASSES_ROOT',
 
96
               }
 
97
 
 
98
    dry_run = False
 
99
    silent = False
 
100
    start_bzr = False
 
101
    add_path = False
 
102
    delete_path = False
 
103
    add_shell_menu = False
 
104
    delete_shell_menu = False
 
105
    check_mfc71 = False
 
106
 
 
107
    try:
 
108
        opts, args = getopt.getopt(sys.argv[1:], "hvnq",
 
109
                                   ["help", "version",
 
110
                                    "dry-run",
 
111
                                    "silent",
 
112
                                    "start-bzr",
 
113
                                    "add-path",
 
114
                                    "delete-path",
 
115
                                    "add-shell-menu",
 
116
                                    "delete-shell-menu",
 
117
                                    "check-mfc71",
 
118
                                   ])
 
119
 
 
120
        for o, a in opts:
 
121
            if o in ("-h", "--help"):
 
122
                print USAGE
 
123
                return OK
 
124
            elif o in ("-v", "--version"):
 
125
                print VERSION_FORMAT % (USAGE.splitlines()[0], VERSION)
 
126
                return OK
 
127
 
 
128
            elif o in ('-n', "--dry-run"):
 
129
                dry_run = True
 
130
            elif o in ('-q', '--silent'):
 
131
                silent = True
 
132
 
 
133
            elif o == "--start-bzr":
 
134
                start_bzr = True
 
135
            elif o == "--add-path":
 
136
                add_path = True
 
137
            elif o == "--delete-path":
 
138
                delete_path = True
 
139
            elif o == "--add-shell-menu":
 
140
                add_shell_menu = True
 
141
            elif o == "--delete-shell-menu":
 
142
                delete_shell_menu = True
 
143
            elif o == "--check-mfc71":
 
144
                check_mfc71 = True
 
145
 
 
146
    except getopt.GetoptError, msg:
 
147
        print str(msg)
 
148
        print USAGE
 
149
        return ERROR
 
150
 
 
151
    # message box from Win32API
 
152
    MessageBoxA = ctypes.windll.user32.MessageBoxA
 
153
    MB_OK = 0
 
154
    MB_ICONERROR = 16
 
155
    MB_ICONEXCLAMATION = 48
 
156
 
 
157
    bzr_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
 
158
 
 
159
    if start_bzr:
 
160
        fname = os.path.join(bzr_dir, "start_bzr.bat")
 
161
        if os.path.isfile(fname):
 
162
            f = file(fname, "r")
 
163
            content = f.readlines()
 
164
            f.close()
 
165
        else:
 
166
            content = ["bzr.exe help\n"]
 
167
 
 
168
        for ix in xrange(len(content)):
 
169
            s = content[ix]
 
170
            if re.match(r'.*(?<!\\)bzr\.exe([ "].*)?$',
 
171
                        s.rstrip('\r\n'),
 
172
                        re.IGNORECASE):
 
173
                content[ix] = s.replace('bzr.exe',
 
174
                                        '"%s"' % os.path.join(bzr_dir,
 
175
                                                              'bzr.exe'))
 
176
 
 
177
        if dry_run:
 
178
            print "*** Write file: start_bzr.bat"
 
179
            print "*** File content:"
 
180
            print ''.join(content)
 
181
        else:
 
182
            f = file(fname, 'w')
 
183
            f.write(''.join(content))
 
184
            f.close()
 
185
 
 
186
    if (add_path or delete_path) and winver == 'Windows NT':
 
187
        # find appropriate registry key:
 
188
        # 1. HKLM\System\CurrentControlSet\Control\SessionManager\Environment
 
189
        # 2. HKCU\Environment
 
190
        keys = ((_winreg.HKEY_LOCAL_MACHINE, (r'System\CurrentControlSet\Control'
 
191
                                              r'\Session Manager\Environment')),
 
192
                (_winreg.HKEY_CURRENT_USER, r'Environment'),
 
193
               )
 
194
 
 
195
        hkey = None
 
196
        for key, subkey in keys:
 
197
            try:
 
198
                hkey = _winreg.OpenKey(key, subkey, 0, _winreg.KEY_ALL_ACCESS)
 
199
                try:
 
200
                    path_u, type_ = _winreg.QueryValueEx(hkey, 'Path')
 
201
                except WindowsError:
 
202
                    if key != _winreg.HKEY_CURRENT_USER:
 
203
                        _winreg.CloseKey(hkey)
 
204
                        hkey = None
 
205
                        continue
 
206
                    else:
 
207
                        path_u = u''
 
208
                        type_ = _winreg.REG_SZ
 
209
            except EnvironmentError:
 
210
                continue
 
211
            break
 
212
 
 
213
        if hkey is None:
 
214
            print "Cannot find appropriate registry key for PATH"
 
215
        else:
 
216
            path_list = [i for i in path_u.split(os.pathsep) if i != '']
 
217
            f_change = False
 
218
            for ix, item in enumerate(path_list[:]):
 
219
                if item == bzr_dir:
 
220
                    if delete_path:
 
221
                        del path_list[ix]
 
222
                        f_change = True
 
223
                    elif add_path:
 
224
                        print "*** Bzr already in PATH"
 
225
                    break
 
226
            else:
 
227
                if add_path and not delete_path:
 
228
                    path_list.append(bzr_dir.decode(user_encoding))
 
229
                    f_change = True
 
230
 
 
231
            if f_change:
 
232
                path_u = os.pathsep.join(path_list)
 
233
                if dry_run:
 
234
                    print "*** Registry key %s\\%s" % (hkey_str[key], subkey)
 
235
                    print "*** Modify PATH variable. New value:"
 
236
                    print path_u
 
237
                else:
 
238
                    _winreg.SetValueEx(hkey, 'Path', 0, type_, path_u)
 
239
                    _winreg.FlushKey(hkey)
 
240
 
 
241
        if not hkey is None:
 
242
            _winreg.CloseKey(hkey)
 
243
 
 
244
    if (add_path or delete_path) and winver == 'Windows 98':
 
245
        # mutating autoexec.bat
 
246
        # adding or delete string:
 
247
        # SET PATH=%PATH%;C:\PROGRA~1\Bazaar
 
248
        abat = 'C:\\autoexec.bat'
 
249
        abak = 'C:\\autoexec.bak'
 
250
 
 
251
        def backup_autoexec_bat(name, backupname, dry_run):
 
252
            # backup autoexec.bat
 
253
            if os.path.isfile(name):
 
254
                if not dry_run:
 
255
                    shutil.copyfile(name, backupname)
 
256
                else:
 
257
                    print '*** backup copy of autoexec.bat created'
 
258
 
 
259
        GetShortPathName = ctypes.windll.kernel32.GetShortPathNameA
 
260
        buf = ctypes.create_string_buffer(260)
 
261
        if GetShortPathName(bzr_dir, buf, 260):
 
262
            bzr_dir_8_3 = buf.value
 
263
        else:
 
264
            bzr_dir_8_3 = bzr_dir
 
265
        pattern = 'SET PATH=%PATH%;' + bzr_dir_8_3
 
266
 
 
267
        # search pattern
 
268
        f = file(abat, 'r')
 
269
        lines = f.readlines()
 
270
        f.close()
 
271
        found = False
 
272
        for i in lines:
 
273
            if i.rstrip('\r\n') == pattern:
 
274
                found = True
 
275
                break
 
276
 
 
277
        if delete_path and found:
 
278
            backup_autoexec_bat(abat, abak, dry_run)
 
279
            if not dry_run:
 
280
                f = file(abat, 'w')
 
281
                for i in lines:
 
282
                    if i.rstrip('\r\n') != pattern:
 
283
                        f.write(i)
 
284
                f.close()
 
285
            else:
 
286
                print '*** Remove line <%s> from autoexec.bat' % pattern
 
287
                    
 
288
        elif add_path and not found:
 
289
            backup_autoexec_bat(abat, abak, dry_run)
 
290
            if not dry_run:
 
291
                f = file(abat, 'a')
 
292
                f.write(pattern)
 
293
                f.write('\n')
 
294
                f.close()
 
295
            else:
 
296
                print '*** Add line <%s> to autoexec.bat' % pattern
 
297
 
 
298
    if add_shell_menu and not delete_shell_menu:
 
299
        hkey = None
 
300
        try:
 
301
            hkey = _winreg.CreateKey(_winreg.HKEY_CLASSES_ROOT,
 
302
                                     r'Folder\shell\bzr')
 
303
        except EnvironmentError:
 
304
            if not silent:
 
305
                MessageBoxA(None,
 
306
                            'Unable to create registry key for context menu',
 
307
                            'EnvironmentError',
 
308
                            MB_OK | MB_ICONERROR)
 
309
 
 
310
        if not hkey is None:
 
311
            _winreg.SetValue(hkey, '', _winreg.REG_SZ, 'Bzr Here')
 
312
            hkey2 = _winreg.CreateKey(hkey, 'command')
 
313
            _winreg.SetValue(hkey2, '', _winreg.REG_SZ,
 
314
                             '%s /K "%s"' % (
 
315
                                    os.environ.get('COMSPEC', '%COMSPEC%'),
 
316
                                    os.path.join(bzr_dir, 'start_bzr.bat')))
 
317
            _winreg.CloseKey(hkey2)
 
318
            _winreg.CloseKey(hkey)
 
319
 
 
320
    if delete_shell_menu:
 
321
        try:
 
322
            _winreg.DeleteKey(_winreg.HKEY_CLASSES_ROOT,
 
323
                              r'Folder\shell\bzr\command')
 
324
        except EnvironmentError:
 
325
            pass
 
326
 
 
327
        try:
 
328
            _winreg.DeleteKey(_winreg.HKEY_CLASSES_ROOT,
 
329
                              r'Folder\shell\bzr')
 
330
        except EnvironmentError:
 
331
            pass
 
332
 
 
333
    if check_mfc71:
 
334
        try:
 
335
            ctypes.windll.LoadLibrary('mfc71.dll')
 
336
        except WindowsError:
 
337
            MessageBoxA(None,
 
338
                        ("Library MFC71.DLL is not found on your system.\n"
 
339
                         "This library needed for SFTP transport.\n"
 
340
                         "If you need to work via SFTP you should download\n"
 
341
                         "this library manually and put it to directory\n"
 
342
                         "where Bzr installed.\n"
 
343
                         "For detailed instructions see:\n"
 
344
                         "http://bazaar-vcs.org/BzrOnPureWindows"
 
345
                        ),
 
346
                        "Warning",
 
347
                        MB_OK | MB_ICONEXCLAMATION)
 
348
 
 
349
    return OK
 
350
 
 
351
 
 
352
if __name__ == "__main__":
 
353
    sys.exit(main())