~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to tools/win32/bzr_postinstall.py

  • Committer: abentley
  • Date: 2005-10-14 03:50:50 UTC
  • mto: (1185.25.1)
  • mto: This revision was merged to the branch mainline in revision 1460.
  • Revision ID: abentley@lappy-20051014035050-d779472ccb599a51
semi-broke merge

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())