1# 2# A NSIS installer script for scOrange Windows application 3# 4 5# Required definitions need to be passed to the makensis call 6# - BASEDIR base location of all required files, ... (see below) 7# - PYARCH python architecture identifier (win32 or amd64) 8# - PY{MAJOR,MINOR,MICRO} Python version of the included installer 9# - APPNAME Application (short) name 10# - VER{MAJOR,MINOR,MICRO} Application version 11# - PYINSTALLER basename of the python installer 12# - INSTALL_REGISTRY_KEY reg subkey name to use for storing install infomation 13# (details will be stored under Software/${INSTALL_REGISTRY_KEY}) 14 15 16# Required data layout at compile time 17# (by default BASEDIR is the directory where this .nsi script is located; 18# use -NOCD parameter when invoking makensis to preserve invoker cwd) 19 20# ${BASEDIR}/ 21# wheelhouse/ 22# requirements.txt 23 24 25## InstallationTypes: 26## - Normal 27## - Private 28 29 30# Python installation type: Normal | Private (Env | Private) 31# - Normal: 32# If a compatible Python installation is found it is used, otherwise an 33# Python installer is executed (this installer must register the 34# appropriate keys in the Windows registry). 35# - Private: 36# A private copy of the Python interpreter is installed for use by the 37# application 38 39#!include InstallConfig.nsh 40 41!ifndef PYINSTALL_TYPE 42 !error "PYINSTALL_TYPE must be defined" 43!endif 44 45!ifndef APPNAME 46 !error "APPNAME must be defined" 47!endif 48 49!ifndef APPLICATIONNAME 50 !define APPLICATIONNAME ${APPNAME} 51!endif 52 53!ifdef VERMAJOR & VERMINOR 54 !ifdef VERMICRO 55 !define APPVERSION ${VERMAJOR}.${VERMINOR}.${VERMICRO} 56 !else 57 !define APPVERSION ${VERMAJOR}.${VERMINOR} 58 !endif 59!else 60 !error "VERMAJOR and VERMINOR are no defiend" 61!endif 62 63!define PYTHON_VERSION ${PYMAJOR}.${PYMINOR}.${PYMICRO} 64!define PYTAG ${PYMAJOR}${PYMINOR} 65 66!if ${PYARCH} == win32 67 !define BITS 32 68!else if ${PYARCH} == win_amd64 69 !define BITS 64 70!else 71 !error "Invalid PYARCH ${PYARCH}" 72!endif 73 74 75!ifndef OUTFILENAME 76 !define OUTFILENAME \ 77 ${APPNAME}-${APPVERSION}-python-${PYMAJOR}.${PYMINOR}-${PYARCH}-setup.exe 78!endif 79 80 81OutFile ${OUTFILENAME} 82Name ${APPLICATIONNAME}-${VERSION} 83 84!ifndef DEFAULT_INSTALL_FOLDER 85 !define DEFAULT_INSTALL_FOLDER ${APPNAME} 86!endif 87 88# Wheel packages which are already compressed. 89SetCompress "off" 90 91!ifdef INSTALLERICON 92 Icon "${INSTALLERICON}" 93 UninstallIcon "${INSTALLERICON}" 94 95 !define MUI_ICON ${INSTALLERICON} 96 !define MUI_UNICON ${INSTALLERICON} 97!endif 98 99!ifndef BASEDIR 100 !define BASEDIR . 101!endif 102 103# Application launcher shortcut name (in start menu or on the desktop) 104!ifndef LAUNCHER_SHORTCUT_NAME 105 !define LAUNCHER_SHORTCUT_NAME "${APPNAME}" 106!endif 107 108!ifndef INSTALL_REGISTRY_KEY 109 !error 'INSTALL_REGISTRY_KEY must be defined' 110!endif 111 112# Registry key/values where the installation layout is saved 113!define INSTALL_SETTINGS_KEY Software\${INSTALL_REGISTRY_KEY} 114!define INSTALL_SETTINGS_INSTDIR InstallDir 115!define INSTALL_SETTINGS_INSTMODE InstallMode 116 117# Support for both current or all users installation layout 118# (see MultiUser/Readme.html) 119!define MULTIUSER_EXECUTIONLEVEL Highest 120# By default select current user mode 121!define MULTIUSER_INSTALLMODE_DEFAULT_CURRENTUSER 122 123!if ${BITS} == 64 124 # Use correct program files folder. 125 # NSIS >= 3.02 (currently still unreleased) 126 !define MULTIUSER_USE_PROGRAMFILES64 127!endif 128 129# Enable the Current/All Users selection page. 130!define MULTIUSER_MUI 131 132# Enable /AllUsers or /CurrentUser command line switch 133# (see MultiUser/Readme.html) 134!define MULTIUSER_INSTALLMODE_COMMANDLINE 135 136# the default folder name where the application will be installed 137!define MULTIUSER_INSTALLMODE_INSTDIR ${DEFAULT_INSTALL_FOLDER} 138 139!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_KEY ${INSTALL_SETTINGS_KEY} 140!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME ${INSTALL_SETTINGS_INSTDIR} 141 142!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY ${INSTALL_SETTINGS_KEY} 143!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME ${INSTALL_SETTINGS_INSTMODE} 144 145# A function which will restore the install dir passed on the command 146# line (/D=DIR) if running in silent mode (MultiUser.nsh will not respect 147# the default $InstDir). 148!define MULTIUSER_INSTALLMODE_FUNCTION RestoreSilentInstallDir 149 150!include Sections.nsh 151!include MultiUser.nsh 152!include MUI2.nsh 153!include LogicLib.nsh 154!include FileFunc.nsh 155 156# Installer Pages Definitions 157# --------------------------- 158 159!insertmacro MUI_PAGE_WELCOME 160 161!ifdef LICENSE_FILE 162 !insertmacro MUI_PAGE_LICENSE "${LICENSE_FILE}" 163!endif 164 165!define MUI_STARTMENUPAGE_DEFAULTFOLDER ${APPNAME} 166# Stay on InstFiles page to allow log view inspection 167!define MUI_FINISHPAGE_NOAUTOCLOSE 168 169Var StartMenuFolder 170 171# All/Current user install selection selection page: 172!insertmacro MULTIUSER_PAGE_INSTALLMODE 173 174# Components Selection Page: 175# - put the component description box at the bottom of the list (more 176# compact GUI) 177!define MUI_COMPONENTSPAGE_SMALLDESC 178!insertmacro MUI_PAGE_COMPONENTS 179 180# Install Directory selection page: 181# Custom function to call on leaving the Directory Page (validation) 182!define MUI_PAGE_CUSTOMFUNCTION_LEAVE "DirectoryLeave" 183!insertmacro MUI_PAGE_DIRECTORY 184 185# Start Menu Directory selection page: 186# - custom start menu page pre callback function to skip the page if 187# Start Menu section is unselected 188!define MUI_PAGE_CUSTOMFUNCTION_PRE "StartMenuPre" 189# - no check box to enable/disable start menu creation 190# (is controled by the Components Page) 191!define MUI_STARTMENUPAGE_NODISABLE 192!insertmacro MUI_PAGE_STARTMENU StartMenuPageID $StartMenuFolder 193 194# Install Files page: 195!insertmacro MUI_PAGE_INSTFILES 196 197# Finish Page: 198# - run the application from the finish page 199!define MUI_FINISHPAGE_RUN 200!define MUI_FINISHPAGE_RUN_FUNCTION "LaunchApplication" 201!define MUI_FINISHPAGE_RUN_TEXT "Start ${APPLICATIONNAME}" 202# - add link at the bottom 203!define MUI_FINISHPAGE_LINK "singlecell.biolab.si" 204!define MUI_FINISHPAGE_LINK_LOCATION "http://singlecell.biolab.si" 205 206!insertmacro MUI_PAGE_FINISH 207 208# Uninstaller Page Definitions 209# ---------------------------- 210!insertmacro MUI_UNPAGE_CONFIRM 211!insertmacro MUI_UNPAGE_INSTFILES 212!insertmacro MUI_UNPAGE_FINISH 213 214!insertmacro MUI_LANGUAGE English 215 216# Temporary folder where temp data will be extracted 217# ($PLUGINSDIR is the (supposedly) recommend place for this; deleted on exit) 218!define TEMPDIR "$PLUGINSDIR\${APPNAME}-installer-data" 219 220!include "PythonHelpers.nsh" 221 222# 223# ${ExtractTemp} Resource TargetLocation 224# 225# Extract a Resource (available at compile time) to TargetLocation 226# (available at install time) 227# 228!macro _EXTRACT_TEMP_MACRO RESOURCE LOCATION 229 SetOutPath ${LOCATION} 230 File ${RESOURCE} 231!macroend 232!define ExtractTemp "!insertmacro _EXTRACT_TEMP_MACRO" 233 234# 235# ${ExtractTempRec} Resource TargetLocation 236# 237# Extract a Resource (available at compile time) recursively to 238# TargetLocation (available at install time) 239# 240!macro _EXTRACT_TEMP_MACRO_REC RESOURCE LOCATION 241 SetOutPath ${LOCATION} 242 File /r ${RESOURCE} 243!macroend 244!define ExtractTempRec "!insertmacro _EXTRACT_TEMP_MACRO_REC" 245 246 247# Key prefix where "Add/Remove Programs" entries are registerd 248!define WINDOWS_UNINSTALL_REGKEY \ 249 "Software\Microsoft\Windows\CurrentVersion\Uninstall" 250 251# Full key path for the application uninstall entry in Add/Remove Programs 252!define APPLICATION_UNINSTALL_REGKEY "${WINDOWS_UNINSTALL_REGKEY}\${APPNAME}" 253 254# Uninstaller base name 255!ifndef UNINSTALL_EXEFILE 256 !define UNINSTALL_EXEFILE "${APPLICATIONNAME}-Uninstall.exe" 257!endif 258 259# Preserved $InstDir as present in .onInit (i.e from /D=... command line 260# switch) 261Var SilentInstallDir 262 263# The (env) base Python prefix 264Var BasePythonPrefix 265 266# The created env Python installation layout 267Var PythonPrefix 268Var PythonExecPrefix 269Var PythonScriptsPrefix 270 271# Python installaion mode (1 if installed for all users; 0 if installed for 272# current user only 273Var PythonInstallMode 274 275Var LogFile 276!macro __LOG_INIT 277 !ifdef __UNINSTALL__ 278 FileOpen $LogFile "$TEMP\${UNINSTALL_EXEFILE}-uninstall-log.txt" "w" 279 !else 280 FileOpen $LogFile "$TEMP\$EXEFILE-install-log.txt" "w" 281 !endif 282 FileWrite $LogFile "------------------------$\r$\n" 283 !ifdef __UNINSTALL__ 284 FileWrite $LogFile "${APPLICATIONNAME} ${VERSION} Uninstall Log$\r$\n" 285 !else 286 FileWrite $LogFile "${APPLICATIONNAME} ${VERSION} Install Log$\r$\n" 287 !endif 288 FileWrite $LogFile "------------------------$\r$\n" 289!macroend 290 291!define LogInit "!insertmacro __LOG_INIT" 292 293# ${LogWrite} STR 294# ---------------- 295# Write a STR to $LogFile. The $LogFile file must already be open 296# (by ${LogInit}) 297!macro __LOG_WRITE TEXT 298 FileWrite $LogFile '${TEXT}$\r$\n' 299!macroend 300!define LogWrite "!insertmacro __LOG_WRITE" 301 302 303# ${ExecToLog} COMMAND 304# -------------------- 305# Log the COMMAND using ${LogWrite} and execute it using nsExec::ExecToLog 306!macro __EXEC_TO_LOG COMMAND 307 ${LogWrite} 'nsExec::ExecToLog: ${COMMAND}' 308 SetDetailsPrint listonly 309 DetailPrint 'Executing: ${COMMAND}' 310 SetDetailsPrint both 311 nsExec::ExecToLog '${COMMAND}' 312!macroend 313!define ExecToLog "!insertmacro __EXEC_TO_LOG" 314 315 316# Validate the selected installation directory. Show a message and Abort 317# if it is not suitable for installation. 318Function DirectoryLeave 319 ${LogWrite} "DirectoryLeave" 320 ${LogWrite} "InstDir: $InstDir" 321 Push $R0 322 Push $R1 323 Push $R2 324 Push $R3 325 ${DirState} "$InstDir" $R0 326 ${LogWrite} "InstDir state: $R0" 327 # Check if this looks like a location of an existing install 328 ${If} $R0 == 1 329 # Directory exists and is not empty 330 ${If} ${FileExists} "$InstDir\${UNINSTALL_EXEFILE}" 331!if ${PYINSTALL_TYPE} == Private 332 ${AndIf} ${FileExists} "$InstDir\Python${PYTAG}-${BITS}\*.*" 333!else if ${PYINSTALL_TYPE} == Normal 334 ${AndIf} ${FileExists} "$InstDir\pyvenv.cfg" 335 ${AndIfNot} ${FileExists} "$InstDir\python.exe" 336 # Check that the existing env is binary compatible 337 ${GetPythonVersion} "$InstDir\Scripts\python.exe" $R1 $R2 338 ${GetPythonArch} "$InstDir\Scripts\python.exe" $R1 $R3 339 ${If} $R1 != 0 340 ${OrIf} "$R2/$R3" != "${PYMAJOR}.${PYMINOR}/${PYARCH}" 341 ${LogWrite} 'Python version/architecture mismatch \ 342 ($R2/$R3 != ${PYMAJOR}.${PYMINOR}/${PYARCH})' 343 MessageBox MB_OK '\ 344 "$InstDir" contains a pre-existing environment \ 345 that is not binary compatible with this installer.$\r$\n\ 346 Please choose another destination folder.' 347 Abort '$R1 $R2 != "${PYMAJOR}.${PYMINOR} ${PYARCH}"' 348 ${EndIf} 349 ${LogWrite} 'Found existing python in $InstDir: $R2 - $R3' 350!endif 351 MessageBox MB_YESNO|MB_ICONQUESTION \ 352 '"$InstDir" looks like an existing ${APPLICATIONNAME} \ 353 installation. Do you want to overwrite it?' \ 354 /SD IDYES IDYES continue_ IDNO abort_ 355 abort_: 356 ${LogWrite} "Overwrite of an existing installation cancelled \ 357 by user (InstDir: $InstDir)" 358 Abort "Aborting" 359 continue_: 360 ${LogWrite} "Reusing an existing installation directory: \ 361 $InstDir" 362 ${Else} 363 ${LogWrite} "$InstDir is not empty, aborting" 364 MessageBox MB_OK '"$InstDir" exists and is not empty.$\r$\n \ 365 Please choose annother destination folder.' 366 Abort '"$InstDir" exists an is not empty' 367 ${EndIf} 368 ${EndIf} 369 Pop $R2 370 Pop $R1 371 Pop $R0 372FunctionEnd 373 374 375Function RestoreSilentInstallDir 376 ${If} $SilentInstallDir != "" 377 ${AndIf} ${Silent} 378 StrCpy $InstDir $SilentInstallDir 379 ${LogWrite} "Restored InstDir to: $SilentInstallDir" 380 ${EndIf} 381FunctionEnd 382 383 384# Section Python 385# -------------- 386# Install Official Python distribution 387 388!if ${PYINSTALL_TYPE} == Private 389# Install/layout a Python installation inside the 390# $InstDir\Python${PYTAG}-${BITS} folder. 391Section "-Python ${PYTHON_VERSION} (${BITS} bit)" SectionPython 392 ${If} $InstDir == "" 393 Abort "Invalid installation prefix" 394 ${EndIf} 395 ${LogWrite} "Installing a private python installation" 396 ${ExtractTemp} "${BASEDIR}\${PYINSTALLER}" "${TEMPDIR}" 397 DetailPrint 'Installing a private Python ${PYTHON_VERSION} (${BITS} bit) \ 398 in "$InstDir\Python${PYTAG}-${BITS}"' 399 400 ${PyInstallNoRegister} "${TEMPDIR}\${PYINSTALLER}" \ 401 "$InstDir\Python${PYTAG}-${BITS}" $0 402 # msvcredist? 403 ${If} $0 != 0 404 Abort "Python installation failed (error value: $0)" 405 ${EndIf} 406 ${IfNot} ${FileExists} "$InstDir\Python${PYTAG}-${BITS}\python.exe" 407 ${LogWrite} "Failed to install Python in $InstDir$\r$\n\ 408 Python executable not found in: \ 409 $InstDir\Python${PYTAG}-${BITS}" 410 Abort "Failed to install Python in $InstDir" 411 ${EndIf} 412 ${GetPythonVersion} "$InstDir\Python${PYTAG}-${BITS}\python.exe" $0 $1 413 ${If} $0 != 0 414 Abort "Python installation failed (simple command returned an error: $0)" 415 ${EndIf} 416 StrCpy $BasePythonPrefix "$InstDir\Python${PYTAG}-${BITS}" 417SectionEnd 418 419Function un.Python 420 # Uninstall a private copy of python 421 ${If} $InstDir != "" 422 ${AndIf} ${FileExists} "$InstDir\Python${PYTAG}-${BITS}\*.*" 423 # Delete entire dir 424 RMDir /R /REBOOTOK "$InstDir\Python${PYTAG}-${BITS}" 425 ${EndIf} 426FunctionEnd 427 428!else if ${PYINSTALL_TYPE} == Normal 429# Run the embeded Python installer to install the official python distribution, 430# if one is not already installed. After the installation completes the 431# location of the installation is queried from the windows registry. 432Section "Python ${PYTHON_VERSION} (${BITS} bit)" SectionPython 433 SectionIn RO 434 ${If} $BasePythonPrefix != "" 435 # The section should heve been unselected (disabled) in .onInit 436 Abort "Installer logic error" 437 ${EndIf} 438 439 ${LogWrite} "Installing Python ${PYTHON_VERSION} (${BITS} bit)" 440 ${ExtractTemp} "${BASEDIR}\${PYINSTALLER}" "${TEMPDIR}" 441 DetailPrint "Executing external installer for Python \ 442 ${PYTHON_VERSION} (${BITS} bit)" 443 # TODO: Ask for confirmation again? 444 ${PyInstall} "${TEMPDIR}\${PYINSTALLER}" $MultiUser.InstallMode $0 445 ${If} $0 != 0 446 Abort "Python installation failed (error value: $0)" 447 ${EndIf} 448 ${GetPythonInstall} \ 449 "${PYMAJOR}.${PYMINOR}" $BasePythonPrefix $PythonInstallMode 450 ${If} $BasePythonPrefix == "" 451 Abort "Python installation failed (cannot determine Python \ 452 installation prefix)." 453 ${EndIf} 454SectionEnd 455 456Function un.Python 457 # Nothing to do 458FunctionEnd 459!endif 460 461Section "-Python env setup" SectionEnvSetup 462 ${If} $BasePythonPrefix == "" 463 Abort "No base python configured. Cannot proceed." 464 ${EndIf} 465 ${LogWrite} "Setup effective python prefix" 466!if ${PYINSTALL_TYPE} == Private 467 ${LogWrite} "Using Python installed in $BasePythonPrefix" 468 StrCpy $PythonPrefix "$BasePythonPrefix" 469 StrCpy $PythonExecPrefix "$PythonPrefix" 470 StrCpy $PythonScriptsPrefix "$PythonPrefix\Scripts" 471!else if ${PYINSTALL_TYPE} == Normal 472 ${IfNot} ${FileExists} "$InstDir\pyvenv.cfg" 473 DetailPrint "Creating virtual env in $InstDir \ 474 (using base $BasePythonPrefix)" 475 ${LogWrite} "Creating virtaul env in $InstDir \ 476 (using base $BasePythonPrefix)" 477 ${ExecToLog} '"$BasePythonPrefix\python" -m venv "$InstDir"' 478 ${EndIf} 479 StrCpy $PythonPrefix "$InstDir" 480 StrCpy $PythonExecPrefix "$PythonPrefix\Scripts" 481 StrCpy $PythonScriptsPrefix "$PythonPrefix\Scripts" 482!endif 483 ${LogWrite} "Target environment layout:" 484 ${LogWrite} " PythonPrefix: $PythonPrefix" 485 ${LogWrite} " PythonExecPrefix: $PythonExecPrefix" 486 ${LogWrite} " PythonScriptsPrefix: $PythonScriptsPrefix" 487SectionEnd 488 489Function un.Environment 490!if ${PYINSTALL_TYPE} == Normal 491 ${If} $InstDir != "" 492 ${AndIf} ${FileExists} "$InstDir\pyvenv.cfg" 493 ${AndIf} ${FileExists} "$InstDir\${UNINSTALL_EXEFILE}" 494 ${LogWrite} "Removing $InstDir" 495 # TODO: Need a more specific marker 496 RMDir /R /REBOOTOK "$InstDir" 497 ${EndIf} 498!endif 499FunctionEnd 500 501 502# Instal into the python environment in $PythonPrefix all the required packages 503Section "Install required pacakges" InstallPackages 504 SectionIn RO 505 ${If} $PythonExecPrefix == "" 506 Abort "No python executable configured. Cannot proceed." 507 ${EndIf} 508 ${ExtractTemp} "${BASEDIR}\requirements.txt" "${TEMPDIR}" 509 ${ExtractTempRec} "${BASEDIR}\wheelhouse\*.*" "${TEMPDIR}\wheelhouse" 510 511 # Install into PythonPrefix 512 ${LogWrite} "Installing packages into $PythonPrefix" 513 DetailPrint "Installing required packages" 514 ${ExecToLog} '"$PythonExecPrefix\python" -m ensurepip' 515 # First update pip to at least the bundled version (>=9) 516 ${ExecToLog} '\ 517 "$PythonExecPrefix\python" -m pip install --upgrade \ 518 --isolated --no-cache-dir --no-index \ 519 --find-links "${TEMPDIR}\wheelhouse" \ 520 pip>=9 \ 521 ' 522 Pop $0 523 ${If} $0 != 0 524 ${LogWrite} "pip install exited with: $0)" 525 Abort "Failed to install required packages (exit status $0)" 526 ${EndIf} 527 528 ${ExecToLog} '\ 529 "$PythonExecPrefix\python" -m pip install \ 530 --isolated --no-cache-dir --no-index \ 531 --find-links "${TEMPDIR}\wheelhouse" \ 532 -r "${TEMPDIR}\requirements.txt" \ 533 ' 534 Pop $0 535 ${If} $0 != 0 536 ${LogWrite} "pip install exited with: $0)" 537 Abort "Failed to install required packages (exit status $0)" 538 ${EndIf} 539SectionEnd 540 541 542Function un.InstallPackages 543FunctionEnd 544 545 546Section -Icons 547 # Layout icons if necessary (are not present) 548 ${IfNot} ${FileExists} $PythonPrefix\share\scorange\icons\*.ico" 549 ${ExtractTempRec} "${BASEDIR}\icons\*.ico" "${TEMPDIR}\icons" 550 CreateDirectory "$PythonPrefix\share\scorange\icons" 551 CopyFiles /SILENT "${TEMPDIR}\icons\*.ico" \ 552 "$PythonPrefix\share\scorange\icons" 553 ${EndIf} 554SectionEnd 555 556 557# Create utility shortcut launchers in the $InstDir 558Section -Launchers 559 SetOutPath "$InstDir" 560 DetailPrint "Creating launcher shortcuts" 561 # Startup shortcut 562 CreateShortCut \ 563 "$InstDir\${LAUNCHER_SHORTCUT_NAME}.lnk" \ 564 "$PythonExecPrefix\pythonw.exe" "-m orangecontrib.single_cell" \ 565 "$PythonPrefix\share\scorange\icons\scOrange.ico" 0 566 # Utility shortcut to launch the application with max log level attached 567 # to the console that remains visible after exit 568 CreateShortCut \ 569 "$InstDir\${LAUNCHER_SHORTCUT_NAME} Debug.lnk" \ 570 "%COMSPEC%" '/K "$PythonExecPrefix\python.exe" -m orangecontrib.single_cell -l4' \ 571 "$PythonPrefix\share\scorange\icons\scOrange.ico" 0 572!if ${PYINSTALL_TYPE} == Normal 573 # A utility shortcut for activating the environment 574 CreateShortCut \ 575 "$InstDir\${APPNAME} Command Prompt.lnk" \ 576 "%COMSPEC%" '/K "$PythonScriptsPrefix\activate.bat"' 577!endif 578 579SectionEnd 580 581 582Function un.Launchers 583 Delete "$InstDir\${LAUNCHER_SHORTCUT_NAME}.lnk" 584 Delete "$InstDir\${LAUNCHER_SHORTCUT_NAME} Debug.lnk" 585!if ${PYINSTALL_TYPE} == Normal 586 Delete "$InstDir\${APPNAME} Command Prompt.lnk" 587!endif 588FunctionEnd 589 590 591SectionGroup "Shortcuts" SectionShortcuts 592Section "Start Menu Shortcuts" SectionStartMenu 593 !insertmacro MUI_STARTMENU_WRITE_BEGIN StartMenuPageID 594 DetailPrint "Creating Start Menu Shortcuts" 595 ${If} $StartMenuFolder != "" 596 ${LogWrite} "Creating shortcuts in $SMPROGRAMS\$StartMenuFolder" 597 # Output path is used as the default CWD for the created shortcuts 598 SetDetailsPrint none 599 SetOutPath "%HOMEDRIVE%\%HOMEPATH%" 600 SetDetailsPrint both 601 CreateDirectory "$SMPROGRAMS\$StartMenuFolder" 602 CreateShortCut \ 603 "$SMPROGRAMS\$StartMenuFolder\${LAUNCHER_SHORTCUT_NAME}.lnk" \ 604 "$PythonExecPrefix\pythonw.exe" "-m orangecontrib.single_cell" \ 605 "$PythonPrefix\share\scorange\icons\scOrange.ico" 0 606!if ${PYINSTALL_TYPE} == Normal 607 # A utility shortcut for activating the environment 608 CreateShortCut \ 609 "$SMPROGRAMS\$StartMenuFolder\${APPNAME} Command Prompt.lnk" \ 610 "%COMSPEC%" '/K "$PythonScriptsPrefix\activate.bat"' 611!endif 612 ${EndIf} 613 !insertmacro MUI_STARTMENU_WRITE_END 614SectionEnd 615 616# StartMenuPage 'pre' callback. Skip Start Menu directory selection if 617# the SectionStarMenu is not selected on the Components page 618Function StartMenuPre 619 ${IfNot} ${SectionIsSelected} ${SectionStartMenu} 620 ${LogWrite} "Skiping start menu page because it is not selected" 621 Abort 622 ${EndIf} 623FunctionEnd 624 625Section "Desktop Shortcuts" SectionDesktop 626 DetailPrint "Installing Desktop shortcurt" 627 CreateShortCut \ 628 "$DESKTOP\${LAUNCHER_SHORTCUT_NAME}.lnk" \ 629 "$PythonExecPrefix\pythonw.exe" "-m orangecontrib.single_cell" \ 630 "$PythonPrefix\share\scorange\icons\scOrange.ico" 0 631SectionEnd 632 633SectionGroupEnd 634 635Function un.Shortcuts 636 !insertmacro MUI_STARTMENU_GETFOLDER StartMenuPageID $0 637 ${If} $0 != "" 638 ${AndIf} ${FileExists} "$SMPROGRAMS\$0" 639 ${LogWrite} "Removing Start Menu Shortcuts (from $SMPROGRAMS\$0)" 640 DetailPrint "Removing Start Menu shortcuts" 641 Delete "$SMPROGRAMS\$0\${LAUNCHER_SHORTCUT_NAME}.lnk" 642 RMDir "$SMPROGRAMS\$0" 643 ${EndIf} 644 ${LogWrite} "Removing Desktop shortcurt" 645 DetailPrint "Removing Desktop shortcurt" 646 Delete "$DESKTOP\${LAUNCHER_SHORTCUT_NAME}.lnk" 647FunctionEnd 648 649 650# Should this section be made selectable by the user. Would allow multiple 651# installations. 652Section -Register SectionRegister 653 DetailPrint "Writing to registry" 654 ${LogWrite} 'Register installation layout (${INSTALL_SETTINGS_KEY})' 655 ${LogWrite} ' BasePythonPrefix "$BasePythonPrefix"' 656 WriteRegStr SHELL_CONTEXT \ 657 ${INSTALL_SETTINGS_KEY} BasePythonPrefix "$BasePythonPrefix" 658 ${LogWrite} ' PythonPrefix "$PythonPrefix"' 659 WriteRegStr SHELL_CONTEXT \ 660 ${INSTALL_SETTINGS_KEY} PythonPrefix "$PythonPrefix" 661 ${LogWrite} ' ${INSTALL_SETTINGS_INSTDIR} "$InstDir"' 662 WriteRegStr SHELL_CONTEXT \ 663 ${INSTALL_SETTINGS_KEY} ${INSTALL_SETTINGS_INSTDIR} \ 664 "$InstDir" 665 666 WriteRegStr SHELL_CONTEXT \ 667 ${INSTALL_SETTINGS_KEY} ${INSTALL_SETTINGS_INSTMODE} \ 668 $MultiUser.InstallMode 669 ${LogWrite} ' InstallType "${PYINSTALL_TYPE}"' 670 WriteRegStr SHELL_CONTEXT \ 671 ${INSTALL_SETTINGS_KEY} InstallType ${PYINSTALL_TYPE} 672 673 ${LogWrite} "Register .ows filetype" 674 WriteRegStr SHELL_CONTEXT \ 675 "Software\Classes\.ows" "" "scOrange" 676 WriteRegStr SHELL_CONTEXT \ 677 "Software\Classes\scOrange" "" "Orange Workflow" 678 WriteRegStr SHELL_CONTEXT \ 679 "Software\Classes\scOrange\DefaultIcon" "" \ 680 "$PythonPrefix\share\scorange\icons\OrangeOWS.ico" 681 WriteRegStr SHELL_CONTEXT \ 682 "Software\Classes\scOrange\Shell\Open\Command\" "" \ 683 '"$PythonExecPrefix\pythonw.exe" -m orangecontrib.single_cell "%1"' 684 685 WriteUninstaller "$InstDir\${UNINSTALL_EXEFILE}" 686 687 # Register uninstaller in Add/Remove Programs 688 689 ${LogWrite} "Register uninstaller (${WINDOWS_UNINSTALL_REGKEY}\${APPNAME})" 690 691 WriteRegStr SHELL_CONTEXT \ 692 "${WINDOWS_UNINSTALL_REGKEY}\${APPNAME}" \ 693 DisplayName "${APPNAME} ${APPVERSION} (${BITS} bit)" 694 WriteRegStr SHELL_CONTEXT \ 695 "${WINDOWS_UNINSTALL_REGKEY}\${APPNAME}" \ 696 DisplayVersion "${APPVERSION}" 697 WriteRegStr SHELL_CONTEXT \ 698 "${WINDOWS_UNINSTALL_REGKEY}\${APPNAME}" \ 699 DisplayIcon "$InstDir\${UNINSTALL_EXEFILE}" 700 WriteRegStr SHELL_CONTEXT \ 701 "${WINDOWS_UNINSTALL_REGKEY}\${APPNAME}" \ 702 "UninstallString" \ 703 '"$InstDir\${UNINSTALL_EXEFILE}" /$MultiUser.InstallMode' 704 WriteRegStr SHELL_CONTEXT \ 705 "${WINDOWS_UNINSTALL_REGKEY}\${APPNAME}" \ 706 "QuietUninstallString" \ 707 '"$InstDir\${UNINSTALL_EXEFILE}" /$MultiUser.InstallMode /S' 708 WriteRegStr SHELL_CONTEXT \ 709 "${WINDOWS_UNINSTALL_REGKEY}\${APPNAME}" \ 710 InstallLocation "$InstDir" 711 WriteRegStr SHELL_CONTEXT \ 712 "${WINDOWS_UNINSTALL_REGKEY}\${APPNAME}" \ 713 URLInfoAbout http://singlecell.biolab.si 714 715 WriteRegDWORD SHELL_CONTEXT \ 716 "${WINDOWS_UNINSTALL_REGKEY}\${APPNAME}" \ 717 NoModify 1 718 WriteRegDWORD SHELL_CONTEXT \ 719 "${WINDOWS_UNINSTALL_REGKEY}\${APPNAME}" \ 720 NoRepair 1 721SectionEnd 722 723 724Var un.InstallDir 725 726Function un.Register 727 DetailPrint "Unregister" 728 ReadRegStr $un.InstallDir SHCTX ${INSTALL_SETTINGS_KEY} InstallDir 729 ${If} $un.InstallDir != "" 730 ${AndIf} $un.InstallDir == $InstDir 731 ${LogWrite} "Deleting reg key: ${INSTALL_SETTINGS_KEY}" 732 DeleteRegKey SHCTX "${INSTALL_SETTINGS_KEY}" 733 ${LogWrite} "Deleting reg key: Software\Classes\scOrange" 734 DeleteRegKey SHCTX Software\Classes\scOrange 735 ${Else} 736 ${LogWrite} "InstallDir from ${INSTALL_SETTINGS_KEY} does not match \ 737 InstDir ($un.InstallDir != $InstDir). Leaving it." 738 ${EndIf} 739 740 ReadRegStr $un.InstallDir SHCTX \ 741 "${WINDOWS_UNINSTALL_REGKEY}\${APPNAME}" InstallLocation 742 ${If} $un.InstallDir != "" 743 ${AndIf} $un.InstallDir == $InstDir 744 ${LogWrite} "Deleting reg key: ${WINDOWS_UNINSTALL_REGKEY}\${APPNAME}" 745 DeleteRegKey SHCTX "${WINDOWS_UNINSTALL_REGKEY}\${APPNAME}" 746 ${Else} 747 ${LogWrite} "InstallLocation from \ 748 ${WINDOWS_UNINSTALL_REGKEY}\${APPNAME} does not match \ 749 InstDir ($0 != $InstDir). Leaving it." 750 ${EndIf} 751FunctionEnd 752 753Function LaunchApplication 754 ExecShell "open" "$PythonExecPrefix\pythonw.exe" "-m orangecontrib.single_cell" 755FunctionEnd 756 757 758!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN 759 760!insertmacro MUI_DESCRIPTION_TEXT ${SectionPython} \ 761 "Install Python ${PYTHON_VERSION} (${BITS} bit)" 762!insertmacro MUI_DESCRIPTION_TEXT ${InstallPackages} \ 763 "Install required packages into the destination environment" 764!insertmacro MUI_DESCRIPTION_TEXT ${SectionStartMenu} \ 765 "Install Start Menu shortcuts" 766!insertmacro MUI_DESCRIPTION_TEXT ${SectionDesktop} \ 767 "Install Desktop shortcuts" 768 769!insertmacro MUI_FUNCTION_DESCRIPTION_END 770 771 772Section Uninstall 773 ReadRegStr $BasePythonPrefix SHCTX ${INSTALL_SETTINGS_KEY} BasePythonPrefix 774 ReadRegStr $PythonPrefix SHCTX ${INSTALL_SETTINGS_KEY} PythonPrefix 775 ReadRegStr $un.InstallDir SHCTX ${INSTALL_SETTINGS_KEY} InstallDir 776 777 ${LogWrite} "InstDir: $InstDir" 778 ${LogWrite} "Layout from registry:" 779 ${LogWrite} " InstallDir: $un.InstallDir" 780 ${LogWrite} " PythonPrefix: $PythonPrefix" 781 ${LogWrite} " BasePythonPrefix: $BasePythonPrefix" 782 783 Call un.Register 784 Call un.Shortcuts 785 Call un.Launchers 786 Call un.InstallPackages 787 Call un.Environment 788 Call un.Python 789 790 ${If} ${FileExists} "$InstDir\${UNINSTALL_EXEFILE}" 791 Delete "$InstDir\${UNINSTALL_EXEFILE}" 792 ${EndIf} 793SectionEnd 794 795 796Function .onInit 797 ${LogInit} 798 InitPluginsDir 799 # $InstDir is not empty if specified by the /D command line switch. 800 # Store it because MultiUser.nsh will override it with its own either 801 # in MULTIUSER_INIT or MULTIUSER_PAGE_INSTALLMODE. 802 ${If} $InstDir != "" 803 ${AndIf} ${Silent} 804 StrCpy $SilentInstallDir $InstDir 805 ${LogWrite} "SilentInstallDir: $SilentInstallDir" 806 ${EndIf} 807 ${LogWrite} "Setting ${BITS} bit registry view." 808 SetRegView ${BITS} 809 810 # Initialize MultiUser.nsh 811 !insertmacro MULTIUSER_INIT 812 813!if ${PYINSTALL_TYPE} == Normal 814 ${GetPythonInstall} ${PYMAJOR}.${PYMINOR} $BasePythonPrefix $PythonInstallMode 815 ${LogWrite} "Python Prefix: $BasePythonPrefix" 816 ${LogWrite} "Python Install Type: $PythonInstallMode" 817 ${If} $BasePythonPrefix != "" 818 ${GetPythonVersion} "$BasePythonPrefix\python.exe" $0 $1 819 ${LogWrite} "Python Version: $1" 820 ${GetPythonArch} "$BasePythonPrefix\python.exe" $0 $1 821 ${LogWrite} "Python platform: $1" 822 823 # Found an appropriate python installation and can reuse it 824 # Change the SectionPython to Unselected 825 SectionGetText ${SectionPython} $0 826 SectionSetText ${SectionPython} "$0 - Already installed" 827 !insertmacro UnselectSection ${SectionPython} 828 !insertmacro SetSectionFlag ${SectionPython} ${SF_RO} 829 ${Else} 830 !insertmacro SelectSection ${SectionPython} 831 !insertmacro SetSectionFlag ${SectionPython} ${SF_RO} 832 ${EndIf} 833!endif 834FunctionEnd 835 836 837Function un.onInit 838 ${LogInit} 839 ${LogWrite} "Setting ${BITS} bit registry view." 840 SetRegView ${BITS} 841 !insertmacro MULTIUSER_UNINIT 842FunctionEnd 843