]>
git.proxmox.com Git - mirror_edk2.git/blob - AppPkg/Applications/Python/Python-2.7.2/Lib/distutils/command/bdist_msi.py
1 # -*- coding: iso-8859-1 -*-
2 # Copyright (C) 2005, 2006 Martin von Löwis
3 # Licensed to PSF under a Contributor Agreement.
4 # The bdist_wininst command proper
5 # based on bdist_wininst
7 Implements the bdist_msi command.
10 from sysconfig
import get_python_version
12 from distutils
. core
import Command
13 from distutils
. dir_util
import remove_tree
14 from distutils
. version
import StrictVersion
15 from distutils
. errors
import DistutilsOptionError
16 from distutils
import log
17 from distutils
. util
import get_platform
20 from msilib
import schema
, sequence
, text
21 from msilib
import Directory
, Feature
, Dialog
, add_data
23 class PyDialog ( Dialog
):
24 """Dialog class with a fixed layout: controls at the top, then a ruler,
25 then a list of buttons: back, next, cancel. Optionally a bitmap at the
27 def __init__ ( self
, * args
, ** kw
):
28 """Dialog(database, name, x, y, w, h, attributes, title, first,
29 default, cancel, bitmap=true)"""
30 Dialog
.__ init
__ ( self
, * args
)
32 #if kw.get("bitmap", True):
33 # self.bitmap("Bitmap", 0, 0, bmwidth, ruler, "PythonWin")
34 self
. line ( "BottomLine" , 0 , ruler
, self
. w
, 0 )
36 def title ( self
, title
):
37 "Set the title text of the dialog at the top."
38 # name, x, y, w, h, flags=Visible|Enabled|Transparent|NoPrefix,
39 # text, in VerdanaBold10
40 self
. text ( "Title" , 15 , 10 , 320 , 60 , 0x30003 ,
41 r
"{\VerdanaBold10} %s " % title
)
43 def back ( self
, title
, next
, name
= "Back" , active
= 1 ):
44 """Add a back button with a given title, the tab-next button,
45 its name in the Control table, possibly initially disabled.
47 Return the button, so that events can be associated"""
49 flags
= 3 # Visible|Enabled
52 return self
. pushbutton ( name
, 180 , self
. h
- 27 , 56 , 17 , flags
, title
, next
)
54 def cancel ( self
, title
, next
, name
= "Cancel" , active
= 1 ):
55 """Add a cancel button with a given title, the tab-next button,
56 its name in the Control table, possibly initially disabled.
58 Return the button, so that events can be associated"""
60 flags
= 3 # Visible|Enabled
63 return self
. pushbutton ( name
, 304 , self
. h
- 27 , 56 , 17 , flags
, title
, next
)
65 def next ( self
, title
, next
, name
= "Next" , active
= 1 ):
66 """Add a Next button with a given title, the tab-next button,
67 its name in the Control table, possibly initially disabled.
69 Return the button, so that events can be associated"""
71 flags
= 3 # Visible|Enabled
74 return self
. pushbutton ( name
, 236 , self
. h
- 27 , 56 , 17 , flags
, title
, next
)
76 def xbutton ( self
, name
, title
, next
, xpos
):
77 """Add a button with a given title, the tab-next button,
78 its name in the Control table, giving its x position; the
79 y-position is aligned with the other buttons.
81 Return the button, so that events can be associated"""
82 return self
. pushbutton ( name
, int ( self
. w
* xpos
- 28 ), self
. h
- 27 , 56 , 17 , 3 , title
, next
)
84 class bdist_msi ( Command
):
86 description
= "create a Microsoft Installer (.msi) binary distribution"
88 user_options
= [( 'bdist-dir=' , None ,
89 "temporary directory for creating the distribution" ),
91 "platform name to embed in generated filenames "
92 "(default: %s )" % get_platform ()),
94 "keep the pseudo-installation tree around after " +
95 "creating the distribution archive" ),
96 ( 'target-version=' , None ,
97 "require a specific python version" +
98 " on the target system" ),
99 ( 'no-target-compile' , 'c' ,
100 "do not compile .py to .pyc on the target system" ),
101 ( 'no-target-optimize' , 'o' ,
102 "do not compile .py to .pyo (optimized)"
103 "on the target system" ),
105 "directory to put final built distributions in" ),
107 "skip rebuilding everything (for testing/debugging)" ),
108 ( 'install-script=' , None ,
109 "basename of installation script to be run after"
110 "installation or before deinstallation" ),
111 ( 'pre-install-script=' , None ,
112 "Fully qualified filename of a script to be run before "
113 "any files are installed. This script need not be in the "
117 boolean_options
= [ 'keep-temp' , 'no-target-compile' , 'no-target-optimize' ,
120 all_versions
= [ '2.0' , '2.1' , '2.2' , '2.3' , '2.4' ,
121 '2.5' , '2.6' , '2.7' , '2.8' , '2.9' ,
122 '3.0' , '3.1' , '3.2' , '3.3' , '3.4' ,
123 '3.5' , '3.6' , '3.7' , '3.8' , '3.9' ]
126 def initialize_options ( self
):
127 self
. bdist_dir
= None
128 self
. plat_name
= None
130 self
. no_target_compile
= 0
131 self
. no_target_optimize
= 0
132 self
. target_version
= None
135 self
. install_script
= None
136 self
. pre_install_script
= None
139 def finalize_options ( self
):
140 if self
. bdist_dir
is None :
141 bdist_base
= self
. get_finalized_command ( 'bdist' ). bdist_base
142 self
. bdist_dir
= os
. path
. join ( bdist_base
, 'msi' )
143 short_version
= get_python_version ()
144 if ( not self
. target_version
) and self
. distribution
. has_ext_modules ():
145 self
. target_version
= short_version
146 if self
. target_version
:
147 self
. versions
= [ self
. target_version
]
148 if not self
. skip_build
and self
. distribution
. has_ext_modules () \
149 and self
. target_version
!= short_version
:
150 raise DistutilsOptionError
, \
151 "target version can only be %s , or the '--skip-build'" \
152 " option must be specified" % ( short_version
,)
154 self
. versions
= list ( self
. all_versions
)
156 self
. set_undefined_options ( 'bdist' ,
157 ( 'dist_dir' , 'dist_dir' ),
158 ( 'plat_name' , 'plat_name' ),
161 if self
. pre_install_script
:
162 raise DistutilsOptionError
, "the pre-install-script feature is not yet implemented"
164 if self
. install_script
:
165 for script
in self
. distribution
. scripts
:
166 if self
. install_script
== os
. path
. basename ( script
):
169 raise DistutilsOptionError
, \
170 "install_script ' %s ' not found in scripts" % \
172 self
. install_script_key
= None
177 if not self
. skip_build
:
178 self
. run_command ( 'build' )
180 install
= self
. reinitialize_command ( 'install' , reinit_subcommands
= 1 )
181 install
. prefix
= self
. bdist_dir
182 install
. skip_build
= self
. skip_build
185 install_lib
= self
. reinitialize_command ( 'install_lib' )
186 # we do not want to include pyc or pyo files
187 install_lib
. compile = 0
188 install_lib
. optimize
= 0
190 if self
. distribution
. has_ext_modules ():
191 # If we are building an installer for a Python version other
192 # than the one we are currently running, then we need to ensure
193 # our build_lib reflects the other Python version rather than ours.
194 # Note that for target_version!=sys.version, we must have skipped the
195 # build step, so there is no issue with enforcing the build of this
197 target_version
= self
. target_version
198 if not target_version
:
199 assert self
. skip_build
, "Should have already checked this"
200 target_version
= sys
. version
[ 0 : 3 ]
201 plat_specifier
= ". %s-%s " % ( self
. plat_name
, target_version
)
202 build
= self
. get_finalized_command ( 'build' )
203 build
. build_lib
= os
. path
. join ( build
. build_base
,
204 'lib' + plat_specifier
)
206 log
. info ( "installing to %s " , self
. bdist_dir
)
207 install
. ensure_finalized ()
209 # avoid warning of 'install_lib' about installing
210 # into a directory not in sys.path
211 sys
. path
. insert ( 0 , os
. path
. join ( self
. bdist_dir
, 'PURELIB' ))
217 self
. mkpath ( self
. dist_dir
)
218 fullname
= self
. distribution
. get_fullname ()
219 installer_name
= self
. get_installer_filename ( fullname
)
220 installer_name
= os
. path
. abspath ( installer_name
)
221 if os
. path
. exists ( installer_name
): os
. unlink ( installer_name
)
223 metadata
= self
. distribution
. metadata
224 author
= metadata
. author
226 author
= metadata
. maintainer
229 version
= metadata
. get_version ()
230 # ProductVersion must be strictly numeric
231 # XXX need to deal with prerelease versions
232 sversion
= " %d . %d . %d " % StrictVersion ( version
). version
233 # Prefix ProductName with Python x.y, so that
234 # it sorts together with the other Python packages
235 # in Add-Remove-Programs (APR)
236 fullname
= self
. distribution
. get_fullname ()
237 if self
. target_version
:
238 product_name
= "Python %s %s " % ( self
. target_version
, fullname
)
240 product_name
= "Python %s " % ( fullname
)
241 self
. db
= msilib
. init_database ( installer_name
, schema
,
242 product_name
, msilib
. gen_uuid (),
244 msilib
. add_tables ( self
. db
, sequence
)
245 props
= [( 'DistVersion' , version
)]
246 email
= metadata
. author_email
or metadata
. maintainer_email
248 props
. append (( "ARPCONTACT" , email
))
250 props
. append (( "ARPURLINFOABOUT" , metadata
. url
))
252 add_data ( self
. db
, 'Property' , props
)
254 self
. add_find_python ()
260 if hasattr ( self
. distribution
, 'dist_files' ):
261 tup
= 'bdist_msi' , self
. target_version
or 'any' , fullname
262 self
. distribution
. dist_files
. append ( tup
)
264 if not self
. keep_temp
:
265 remove_tree ( self
. bdist_dir
, dry_run
= self
. dry_run
)
269 cab
= msilib
. CAB ( "distfiles" )
270 rootdir
= os
. path
. abspath ( self
. bdist_dir
)
272 root
= Directory ( db
, cab
, None , rootdir
, "TARGETDIR" , "SourceDir" )
273 f
= Feature ( db
, "Python" , "Python" , "Everything" ,
274 0 , 1 , directory
= "TARGETDIR" )
276 items
= [( f
, root
, '' )]
277 for version
in self
. versions
+ [ self
. other_version
]:
278 target
= "TARGETDIR" + version
279 name
= default
= "Python" + version
281 if version
is self
. other_version
:
282 title
= "Python from another location"
285 title
= "Python %s from registry" % version
287 f
= Feature ( db
, name
, title
, desc
, 1 , level
, directory
= target
)
288 dir = Directory ( db
, cab
, root
, rootdir
, target
, default
)
289 items
. append (( f
, dir , version
))
293 for feature
, dir , version
in items
:
297 for file in os
. listdir ( dir . absolute
):
298 afile
= os
. path
. join ( dir . absolute
, file )
299 if os
. path
. isdir ( afile
):
300 short
= " %s | %s " % ( dir . make_short ( file ), file )
301 default
= file + version
302 newdir
= Directory ( db
, cab
, dir , file , default
, short
)
305 if not dir . component
:
306 dir . start_component ( dir . logical
, feature
, 0 )
307 if afile
not in seen
:
308 key
= seen
[ afile
] = dir . add_file ( file )
309 if file == self
. install_script
:
310 if self
. install_script_key
:
311 raise DistutilsOptionError (
312 "Multiple files with name %s " % file )
313 self
. install_script_key
= '[# %s ]' % key
316 add_data ( self
. db
, "DuplicateFile" ,
317 [( key
+ version
, dir . component
, key
, None , dir . logical
)])
321 def add_find_python ( self
):
322 """Adds code to the installer to compute the location of Python.
324 Properties PYTHON.MACHINE.X.Y and PYTHON.USER.X.Y will be set from the
325 registry for each version of Python.
327 Properties TARGETDIRX.Y will be set from PYTHON.USER.X.Y if defined,
328 else from PYTHON.MACHINE.X.Y.
330 Properties PYTHONX.Y will be set to TARGETDIRX.Y \\ python.exe"""
333 for ver
in self
. versions
:
334 install_path
= r
"SOFTWARE\Python\PythonCore\ %s \InstallPath" % ver
335 machine_reg
= "python.machine." + ver
336 user_reg
= "python.user." + ver
337 machine_prop
= "PYTHON.MACHINE." + ver
338 user_prop
= "PYTHON.USER." + ver
339 machine_action
= "PythonFromMachine" + ver
340 user_action
= "PythonFromUser" + ver
341 exe_action
= "PythonExe" + ver
342 target_dir_prop
= "TARGETDIR" + ver
343 exe_prop
= "PYTHON" + ver
345 # type: msidbLocatorTypeRawValue + msidbLocatorType64bit
349 add_data ( self
. db
, "RegLocator" ,
350 [( machine_reg
, 2 , install_path
, None , Type
),
351 ( user_reg
, 1 , install_path
, None , Type
)])
352 add_data ( self
. db
, "AppSearch" ,
353 [( machine_prop
, machine_reg
),
354 ( user_prop
, user_reg
)])
355 add_data ( self
. db
, "CustomAction" ,
356 [( machine_action
, 51 + 256 , target_dir_prop
, "[" + machine_prop
+ "]" ),
357 ( user_action
, 51 + 256 , target_dir_prop
, "[" + user_prop
+ "]" ),
358 ( exe_action
, 51 + 256 , exe_prop
, "[" + target_dir_prop
+ "] \\ python.exe" ),
360 add_data ( self
. db
, "InstallExecuteSequence" ,
361 [( machine_action
, machine_prop
, start
),
362 ( user_action
, user_prop
, start
+ 1 ),
363 ( exe_action
, None , start
+ 2 ),
365 add_data ( self
. db
, "InstallUISequence" ,
366 [( machine_action
, machine_prop
, start
),
367 ( user_action
, user_prop
, start
+ 1 ),
368 ( exe_action
, None , start
+ 2 ),
370 add_data ( self
. db
, "Condition" ,
371 [( "Python" + ver
, 0 , "NOT TARGETDIR" + ver
)])
375 def add_scripts ( self
):
376 if self
. install_script
:
378 for ver
in self
. versions
+ [ self
. other_version
]:
379 install_action
= "install_script." + ver
380 exe_prop
= "PYTHON" + ver
381 add_data ( self
. db
, "CustomAction" ,
382 [( install_action
, 50 , exe_prop
, self
. install_script_key
)])
383 add_data ( self
. db
, "InstallExecuteSequence" ,
384 [( install_action
, "&Python %s =3" % ver
, start
)])
386 # XXX pre-install scripts are currently refused in finalize_options()
387 # but if this feature is completed, it will also need to add
388 # entries for each version as the above code does
389 if self
. pre_install_script
:
390 scriptfn
= os
. path
. join ( self
. bdist_dir
, "preinstall.bat" )
391 f
= open ( scriptfn
, "w" )
392 # The batch file will be executed with [PYTHON], so that %1
393 # is the path to the Python interpreter; %0 will be the path
400 f
. write ( 'rem =""" \n %1 %0 \n exit \n """ \n ' )
401 f
. write ( open ( self
. pre_install_script
). read ())
403 add_data ( self
. db
, "Binary" ,
404 [( "PreInstall" , msilib
. Binary ( scriptfn
))
406 add_data ( self
. db
, "CustomAction" ,
407 [( "PreInstall" , 2 , "PreInstall" , None )
409 add_data ( self
. db
, "InstallExecuteSequence" ,
410 [( "PreInstall" , "NOT Installed" , 450 )])
418 title
= "[ProductName] Setup"
420 # see "Dialog Style Bits"
421 modal
= 3 # visible | modal
422 modeless
= 1 # visible
424 # UI customization properties
425 add_data ( db
, "Property" ,
426 # See "DefaultUIFont Property"
427 [( "DefaultUIFont" , "DlgFont8" ),
428 # See "ErrorDialog Style Bit"
429 ( "ErrorDialog" , "ErrorDlg" ),
430 ( "Progress1" , "Install" ), # modified in maintenance type dlg
431 ( "Progress2" , "installs" ),
432 ( "MaintenanceForm_Action" , "Repair" ),
433 # possible values: ALL, JUSTME
434 ( "WhichUsers" , "ALL" )
437 # Fonts, see "TextStyle Table"
438 add_data ( db
, "TextStyle" ,
439 [( "DlgFont8" , "Tahoma" , 9 , None , 0 ),
440 ( "DlgFontBold8" , "Tahoma" , 8 , None , 1 ), #bold
441 ( "VerdanaBold10" , "Verdana" , 10 , None , 1 ),
442 ( "VerdanaRed9" , "Verdana" , 9 , 255 , 0 ),
445 # UI Sequences, see "InstallUISequence Table", "Using a Sequence Table"
446 # Numbers indicate sequence; see sequence.py for how these action integrate
447 add_data ( db
, "InstallUISequence" ,
448 [( "PrepareDlg" , "Not Privileged or Windows9x or Installed" , 140 ),
449 ( "WhichUsersDlg" , "Privileged and not Windows9x and not Installed" , 141 ),
450 # In the user interface, assume all-users installation if privileged.
451 ( "SelectFeaturesDlg" , "Not Installed" , 1230 ),
452 # XXX no support for resume installations yet
453 #("ResumeDlg", "Installed AND (RESUME OR Preselected)", 1240),
454 ( "MaintenanceTypeDlg" , "Installed AND NOT RESUME AND NOT Preselected" , 1250 ),
455 ( "ProgressDlg" , None , 1280 )])
457 add_data ( db
, 'ActionText' , text
. ActionText
)
458 add_data ( db
, 'UIText' , text
. UIText
)
459 #####################################################################
460 # Standard dialogs: FatalError, UserExit, ExitDialog
461 fatal
= PyDialog ( db
, "FatalError" , x
, y
, w
, h
, modal
, title
,
462 "Finish" , "Finish" , "Finish" )
463 fatal
. title ( "[ProductName] Installer ended prematurely" )
464 fatal
. back ( "< Back" , "Finish" , active
= 0 )
465 fatal
. cancel ( "Cancel" , "Back" , active
= 0 )
466 fatal
. text ( "Description1" , 15 , 70 , 320 , 80 , 0x30003 ,
467 "[ProductName] setup ended prematurely because of an error. Your system has not been modified. To install this program at a later time, please run the installation again." )
468 fatal
. text ( "Description2" , 15 , 155 , 320 , 20 , 0x30003 ,
469 "Click the Finish button to exit the Installer." )
470 c
= fatal
. next ( "Finish" , "Cancel" , name
= "Finish" )
471 c
. event ( "EndDialog" , "Exit" )
473 user_exit
= PyDialog ( db
, "UserExit" , x
, y
, w
, h
, modal
, title
,
474 "Finish" , "Finish" , "Finish" )
475 user_exit
. title ( "[ProductName] Installer was interrupted" )
476 user_exit
. back ( "< Back" , "Finish" , active
= 0 )
477 user_exit
. cancel ( "Cancel" , "Back" , active
= 0 )
478 user_exit
. text ( "Description1" , 15 , 70 , 320 , 80 , 0x30003 ,
479 "[ProductName] setup was interrupted. Your system has not been modified. "
480 "To install this program at a later time, please run the installation again." )
481 user_exit
. text ( "Description2" , 15 , 155 , 320 , 20 , 0x30003 ,
482 "Click the Finish button to exit the Installer." )
483 c
= user_exit
. next ( "Finish" , "Cancel" , name
= "Finish" )
484 c
. event ( "EndDialog" , "Exit" )
486 exit_dialog
= PyDialog ( db
, "ExitDialog" , x
, y
, w
, h
, modal
, title
,
487 "Finish" , "Finish" , "Finish" )
488 exit_dialog
. title ( "Completing the [ProductName] Installer" )
489 exit_dialog
. back ( "< Back" , "Finish" , active
= 0 )
490 exit_dialog
. cancel ( "Cancel" , "Back" , active
= 0 )
491 exit_dialog
. text ( "Description" , 15 , 235 , 320 , 20 , 0x30003 ,
492 "Click the Finish button to exit the Installer." )
493 c
= exit_dialog
. next ( "Finish" , "Cancel" , name
= "Finish" )
494 c
. event ( "EndDialog" , "Return" )
496 #####################################################################
497 # Required dialog: FilesInUse, ErrorDlg
498 inuse
= PyDialog ( db
, "FilesInUse" ,
500 19 , # KeepModeless|Modal|Visible
502 "Retry" , "Retry" , "Retry" , bitmap
= False )
503 inuse
. text ( "Title" , 15 , 6 , 200 , 15 , 0x30003 ,
504 r
"{\DlgFontBold8}Files in Use" )
505 inuse
. text ( "Description" , 20 , 23 , 280 , 20 , 0x30003 ,
506 "Some files that need to be updated are currently in use." )
507 inuse
. text ( "Text" , 20 , 55 , 330 , 50 , 3 ,
508 "The following applications are using files that need to be updated by this setup. Close these applications and then click Retry to continue the installation or Cancel to exit it." )
509 inuse
. control ( "List" , "ListBox" , 20 , 107 , 330 , 130 , 7 , "FileInUseProcess" ,
511 c
= inuse
. back ( "Exit" , "Ignore" , name
= "Exit" )
512 c
. event ( "EndDialog" , "Exit" )
513 c
= inuse
. next ( "Ignore" , "Retry" , name
= "Ignore" )
514 c
. event ( "EndDialog" , "Ignore" )
515 c
= inuse
. cancel ( "Retry" , "Exit" , name
= "Retry" )
516 c
. event ( "EndDialog" , "Retry" )
518 # See "Error Dialog". See "ICE20" for the required names of the controls.
519 error
= Dialog ( db
, "ErrorDlg" ,
521 65543 , # Error|Minimize|Modal|Visible
523 "ErrorText" , None , None )
524 error
. text ( "ErrorText" , 50 , 9 , 280 , 48 , 3 , "" )
525 #error.control("ErrorIcon", "Icon", 15, 9, 24, 24, 5242881, None, "py.ico", None, None)
526 error
. pushbutton ( "N" , 120 , 72 , 81 , 21 , 3 , "No" , None ). event ( "EndDialog" , "ErrorNo" )
527 error
. pushbutton ( "Y" , 240 , 72 , 81 , 21 , 3 , "Yes" , None ). event ( "EndDialog" , "ErrorYes" )
528 error
. pushbutton ( "A" , 0 , 72 , 81 , 21 , 3 , "Abort" , None ). event ( "EndDialog" , "ErrorAbort" )
529 error
. pushbutton ( "C" , 42 , 72 , 81 , 21 , 3 , "Cancel" , None ). event ( "EndDialog" , "ErrorCancel" )
530 error
. pushbutton ( "I" , 81 , 72 , 81 , 21 , 3 , "Ignore" , None ). event ( "EndDialog" , "ErrorIgnore" )
531 error
. pushbutton ( "O" , 159 , 72 , 81 , 21 , 3 , "Ok" , None ). event ( "EndDialog" , "ErrorOk" )
532 error
. pushbutton ( "R" , 198 , 72 , 81 , 21 , 3 , "Retry" , None ). event ( "EndDialog" , "ErrorRetry" )
534 #####################################################################
535 # Global "Query Cancel" dialog
536 cancel
= Dialog ( db
, "CancelDlg" , 50 , 10 , 260 , 85 , 3 , title
,
538 cancel
. text ( "Text" , 48 , 15 , 194 , 30 , 3 ,
539 "Are you sure you want to cancel [ProductName] installation?" )
540 #cancel.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None,
541 # "py.ico", None, None)
542 c
= cancel
. pushbutton ( "Yes" , 72 , 57 , 56 , 17 , 3 , "Yes" , "No" )
543 c
. event ( "EndDialog" , "Exit" )
545 c
= cancel
. pushbutton ( "No" , 132 , 57 , 56 , 17 , 3 , "No" , "Yes" )
546 c
. event ( "EndDialog" , "Return" )
548 #####################################################################
549 # Global "Wait for costing" dialog
550 costing
= Dialog ( db
, "WaitForCostingDlg" , 50 , 10 , 260 , 85 , modal
, title
,
551 "Return" , "Return" , "Return" )
552 costing
. text ( "Text" , 48 , 15 , 194 , 30 , 3 ,
553 "Please wait while the installer finishes determining your disk space requirements." )
554 c
= costing
. pushbutton ( "Return" , 102 , 57 , 56 , 17 , 3 , "Return" , None )
555 c
. event ( "EndDialog" , "Exit" )
557 #####################################################################
558 # Preparation dialog: no user input except cancellation
559 prep
= PyDialog ( db
, "PrepareDlg" , x
, y
, w
, h
, modeless
, title
,
560 "Cancel" , "Cancel" , "Cancel" )
561 prep
. text ( "Description" , 15 , 70 , 320 , 40 , 0x30003 ,
562 "Please wait while the Installer prepares to guide you through the installation." )
563 prep
. title ( "Welcome to the [ProductName] Installer" )
564 c
= prep
. text ( "ActionText" , 15 , 110 , 320 , 20 , 0x30003 , "Pondering..." )
565 c
. mapping ( "ActionText" , "Text" )
566 c
= prep
. text ( "ActionData" , 15 , 135 , 320 , 30 , 0x30003 , None )
567 c
. mapping ( "ActionData" , "Text" )
568 prep
. back ( "Back" , None , active
= 0 )
569 prep
. next ( "Next" , None , active
= 0 )
570 c
= prep
. cancel ( "Cancel" , None )
571 c
. event ( "SpawnDialog" , "CancelDlg" )
573 #####################################################################
574 # Feature (Python directory) selection
575 seldlg
= PyDialog ( db
, "SelectFeaturesDlg" , x
, y
, w
, h
, modal
, title
,
576 "Next" , "Next" , "Cancel" )
577 seldlg
. title ( "Select Python Installations" )
579 seldlg
. text ( "Hint" , 15 , 30 , 300 , 20 , 3 ,
580 "Select the Python locations where %s should be installed."
581 % self
. distribution
. get_fullname ())
583 seldlg
. back ( "< Back" , None , active
= 0 )
584 c
= seldlg
. next ( "Next >" , "Cancel" )
586 c
. event ( "[TARGETDIR]" , "[SourceDir]" , ordering
= order
)
587 for version
in self
. versions
+ [ self
. other_version
]:
589 c
. event ( "[TARGETDIR]" , "[TARGETDIR %s ]" % version
,
590 "FEATURE_SELECTED AND &Python %s =3" % version
,
592 c
. event ( "SpawnWaitDialog" , "WaitForCostingDlg" , ordering
= order
+ 1 )
593 c
. event ( "EndDialog" , "Return" , ordering
= order
+ 2 )
594 c
= seldlg
. cancel ( "Cancel" , "Features" )
595 c
. event ( "SpawnDialog" , "CancelDlg" )
597 c
= seldlg
. control ( "Features" , "SelectionTree" , 15 , 60 , 300 , 120 , 3 ,
598 "FEATURE" , None , "PathEdit" , None )
599 c
. event ( "[FEATURE_SELECTED]" , "1" )
600 ver
= self
. other_version
601 install_other_cond
= "FEATURE_SELECTED AND &Python %s =3" % ver
602 dont_install_other_cond
= "FEATURE_SELECTED AND &Python %s <>3" % ver
604 c
= seldlg
. text ( "Other" , 15 , 200 , 300 , 15 , 3 ,
605 "Provide an alternate Python location" )
606 c
. condition ( "Enable" , install_other_cond
)
607 c
. condition ( "Show" , install_other_cond
)
608 c
. condition ( "Disable" , dont_install_other_cond
)
609 c
. condition ( "Hide" , dont_install_other_cond
)
611 c
= seldlg
. control ( "PathEdit" , "PathEdit" , 15 , 215 , 300 , 16 , 1 ,
612 "TARGETDIR" + ver
, None , "Next" , None )
613 c
. condition ( "Enable" , install_other_cond
)
614 c
. condition ( "Show" , install_other_cond
)
615 c
. condition ( "Disable" , dont_install_other_cond
)
616 c
. condition ( "Hide" , dont_install_other_cond
)
618 #####################################################################
620 cost
= PyDialog ( db
, "DiskCostDlg" , x
, y
, w
, h
, modal
, title
,
621 "OK" , "OK" , "OK" , bitmap
= False )
622 cost
. text ( "Title" , 15 , 6 , 200 , 15 , 0x30003 ,
623 "{\DlgFontBold8}Disk Space Requirements" )
624 cost
. text ( "Description" , 20 , 20 , 280 , 20 , 0x30003 ,
625 "The disk space required for the installation of the selected features." )
626 cost
. text ( "Text" , 20 , 53 , 330 , 60 , 3 ,
627 "The highlighted volumes (if any) do not have enough disk space "
628 "available for the currently selected features. You can either "
629 "remove some files from the highlighted volumes, or choose to "
630 "install less features onto local drive(s), or select different "
631 "destination drive(s)." )
632 cost
. control ( "VolumeList" , "VolumeCostList" , 20 , 100 , 330 , 150 , 393223 ,
633 None , " {120}{70}{70}{70}{70} " , None , None )
634 cost
. xbutton ( "OK" , "Ok" , None , 0.5 ). event ( "EndDialog" , "Return" )
636 #####################################################################
637 # WhichUsers Dialog. Only available on NT, and for privileged users.
638 # This must be run before FindRelatedProducts, because that will
639 # take into account whether the previous installation was per-user
640 # or per-machine. We currently don't support going back to this
641 # dialog after "Next" was selected; to support this, we would need to
642 # find how to reset the ALLUSERS property, and how to re-run
643 # FindRelatedProducts.
644 # On Windows9x, the ALLUSERS property is ignored on the command line
645 # and in the Property table, but installer fails according to the documentation
646 # if a dialog attempts to set ALLUSERS.
647 whichusers
= PyDialog ( db
, "WhichUsersDlg" , x
, y
, w
, h
, modal
, title
,
648 "AdminInstall" , "Next" , "Cancel" )
649 whichusers
. title ( "Select whether to install [ProductName] for all users of this computer." )
650 # A radio group with two options: allusers, justme
651 g
= whichusers
. radiogroup ( "AdminInstall" , 15 , 60 , 260 , 50 , 3 ,
652 "WhichUsers" , "" , "Next" )
653 g
. add ( "ALL" , 0 , 5 , 150 , 20 , "Install for all users" )
654 g
. add ( "JUSTME" , 0 , 25 , 150 , 20 , "Install just for me" )
656 whichusers
. back ( "Back" , None , active
= 0 )
658 c
= whichusers
. next ( "Next >" , "Cancel" )
659 c
. event ( "[ALLUSERS]" , "1" , 'WhichUsers="ALL"' , 1 )
660 c
. event ( "EndDialog" , "Return" , ordering
= 2 )
662 c
= whichusers
. cancel ( "Cancel" , "AdminInstall" )
663 c
. event ( "SpawnDialog" , "CancelDlg" )
665 #####################################################################
666 # Installation Progress dialog (modeless)
667 progress
= PyDialog ( db
, "ProgressDlg" , x
, y
, w
, h
, modeless
, title
,
668 "Cancel" , "Cancel" , "Cancel" , bitmap
= False )
669 progress
. text ( "Title" , 20 , 15 , 200 , 15 , 0x30003 ,
670 "{\DlgFontBold8}[Progress1] [ProductName]" )
671 progress
. text ( "Text" , 35 , 65 , 300 , 30 , 3 ,
672 "Please wait while the Installer [Progress2] [ProductName]. "
673 "This may take several minutes." )
674 progress
. text ( "StatusLabel" , 35 , 100 , 35 , 20 , 3 , "Status:" )
676 c
= progress
. text ( "ActionText" , 70 , 100 , w
- 70 , 20 , 3 , "Pondering..." )
677 c
. mapping ( "ActionText" , "Text" )
679 #c=progress.text("ActionData", 35, 140, 300, 20, 3, None)
680 #c.mapping("ActionData", "Text")
682 c
= progress
. control ( "ProgressBar" , "ProgressBar" , 35 , 120 , 300 , 10 , 65537 ,
683 None , "Progress done" , None , None )
684 c
. mapping ( "SetProgress" , "Progress" )
686 progress
. back ( "< Back" , "Next" , active
= False )
687 progress
. next ( "Next >" , "Cancel" , active
= False )
688 progress
. cancel ( "Cancel" , "Back" ). event ( "SpawnDialog" , "CancelDlg" )
690 ###################################################################
691 # Maintenance type: repair/uninstall
692 maint
= PyDialog ( db
, "MaintenanceTypeDlg" , x
, y
, w
, h
, modal
, title
,
693 "Next" , "Next" , "Cancel" )
694 maint
. title ( "Welcome to the [ProductName] Setup Wizard" )
695 maint
. text ( "BodyText" , 15 , 63 , 330 , 42 , 3 ,
696 "Select whether you want to repair or remove [ProductName]." )
697 g
= maint
. radiogroup ( "RepairRadioGroup" , 15 , 108 , 330 , 60 , 3 ,
698 "MaintenanceForm_Action" , "" , "Next" )
699 #g.add("Change", 0, 0, 200, 17, "&Change [ProductName]")
700 g
. add ( "Repair" , 0 , 18 , 200 , 17 , "&Repair [ProductName]" )
701 g
. add ( "Remove" , 0 , 36 , 200 , 17 , "Re&move [ProductName]" )
703 maint
. back ( "< Back" , None , active
= False )
704 c
= maint
. next ( "Finish" , "Cancel" )
705 # Change installation: Change progress dialog to "Change", then ask
706 # for feature selection
707 #c.event("[Progress1]", "Change", 'MaintenanceForm_Action="Change"', 1)
708 #c.event("[Progress2]", "changes", 'MaintenanceForm_Action="Change"', 2)
710 # Reinstall: Change progress dialog to "Repair", then invoke reinstall
711 # Also set list of reinstalled features to "ALL"
712 c
. event ( "[REINSTALL]" , "ALL" , 'MaintenanceForm_Action="Repair"' , 5 )
713 c
. event ( "[Progress1]" , "Repairing" , 'MaintenanceForm_Action="Repair"' , 6 )
714 c
. event ( "[Progress2]" , "repairs" , 'MaintenanceForm_Action="Repair"' , 7 )
715 c
. event ( "Reinstall" , "ALL" , 'MaintenanceForm_Action="Repair"' , 8 )
717 # Uninstall: Change progress to "Remove", then invoke uninstall
718 # Also set list of removed features to "ALL"
719 c
. event ( "[REMOVE]" , "ALL" , 'MaintenanceForm_Action="Remove"' , 11 )
720 c
. event ( "[Progress1]" , "Removing" , 'MaintenanceForm_Action="Remove"' , 12 )
721 c
. event ( "[Progress2]" , "removes" , 'MaintenanceForm_Action="Remove"' , 13 )
722 c
. event ( "Remove" , "ALL" , 'MaintenanceForm_Action="Remove"' , 14 )
724 # Close dialog when maintenance action scheduled
725 c
. event ( "EndDialog" , "Return" , 'MaintenanceForm_Action<>"Change"' , 20 )
726 #c.event("NewDialog", "SelectFeaturesDlg", 'MaintenanceForm_Action="Change"', 21)
728 maint
. cancel ( "Cancel" , "RepairRadioGroup" ). event ( "SpawnDialog" , "CancelDlg" )
730 def get_installer_filename ( self
, fullname
):
731 # Factored out to allow overriding in subclasses
732 if self
. target_version
:
733 base_name
= " %s . %s- py %s .msi" % ( fullname
, self
. plat_name
,
736 base_name
= " %s . %s .msi" % ( fullname
, self
. plat_name
)
737 installer_name
= os
. path
. join ( self
. dist_dir
, base_name
)
738 return installer_name