diff options
| author | Ryan Williams <rdw@lindenlab.com> | 2007-02-21 23:57:35 +0000 | 
|---|---|---|
| committer | Ryan Williams <rdw@lindenlab.com> | 2007-02-21 23:57:35 +0000 | 
| commit | b7b4135e5507fd7be5aab24d5de64675dd28caca (patch) | |
| tree | c198c0c3bebe31cec9deb8229330cafd5a9acbfd | |
| parent | 5bdbc85a14447c9839f300072c4a3e3146f51585 (diff) | |
SL-33966: Viewer installed files are not described in a centralized source
This introduces the viewer_manifest.py and associated libraries.  Check out https://osiris.lindenlab.com/mediawiki/index.php/Installer_Manifest for some more information.
The gist of it is that all files to be included in the viewer installations are described in viewer_manifest.py.  viewer_manifest.py also acts as a packager, if you give it the right options.  All of the old methods of packaging (Makefile_Mac, scons, and the various .bat files) still work, but they are mostly just shells for calls to viewer_manifest.py.
You're now required to have python 2.3 or later on your machine to be able to package up an installer, but thankfully most people already have this.
| -rw-r--r-- | indra/newview/installers/windows/installer_template.nsi | 858 | ||||
| -rwxr-xr-x | indra/newview/viewer_manifest.py | 437 | ||||
| -rw-r--r-- | indra/test/test_llmanifest.py | 109 | 
3 files changed, 1404 insertions, 0 deletions
| diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi new file mode 100644 index 0000000000..6178cfbc96 --- /dev/null +++ b/indra/newview/installers/windows/installer_template.nsi @@ -0,0 +1,858 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +;;; secondlife setup.nsi
 +;;; Copyright 2004-2006, Linden Research, Inc.
 +;;; For info, see http://www.nullsoft.com/free/nsis/
 +;;;
 +;;; NSIS 2.02 or higher required
 +;;; Author: James Cook, Don Kjer
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +;;; Compiler flags
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +
 +;;; Detect NSIS compiler version
 +!define "NSIS${NSIS_VERSION}"
 +!ifdef "NSISv2.02" | "NSISv2.03" | "NSISv2.04" | "NSISv2.05" | "NSISv2.06"
 +    ;;; before 2.07 defaulted lzma to solid (whole file)
 +    SetCompressor lzma
 +!else
 +    ;;; after 2.07 required /solid for whole file compression
 +    SetCompressor /solid lzma
 +!endif
 +
 +SetOverwrite on				; overwrite files
 +SetCompress auto			; compress iff saves space
 +SetDatablockOptimize off		; only saves us 0.1%, not worth it
 +XPStyle on                              ; add an XP manifest to the installer
 +
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +;;; Project flags
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +
 +%%VERSION%%
 +
 +;;; Tweak for different servers/builds (this placeholder is replaced by viewer_manifest.py)
 +%%GRID_VARS%%
 +
 +Name ${INSTNAME}
 +
 +SubCaption 0 " Setup"			; override "license agreement" text
 +
 +BrandingText " "				; bottom of window text
 +Icon res\install_icon.ico		; our custom icon
 +UninstallIcon res\uninstall_icon.ico    ; our custom icon
 +WindowIcon on					; show our icon in left corner
 +BGGradient off					; no big background window
 +CRCCheck on						; make sure CRC is OK
 +InstProgressFlags smooth colored		; new colored smooth look
 +ShowInstDetails nevershow		; no details, no "show" button
 +SetOverwrite on					; stomp files by default
 +AutoCloseWindow true			; after all files install, close window
 +
 +!ifdef UPDATE
 +LicenseText "This package will update Second Life to version ${VERSION_LONG}." "Next >"
 +!else
 +LicenseText "This package will install Second Life on your computer." "Next >"
 +!endif
 +
 +LicenseData "releasenotes.txt"
 +
 +InstallDir "$PROGRAMFILES\${INSTNAME}"
 +InstallDirRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" ""
 +!ifdef UPDATE
 +DirText "Installation Directory" "Select the Second Life directory to update:"
 +!else
 +DirText "Installation Directory" "Select the directory to install Second Life in:"
 +!endif
 +
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +;;; Variables
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +Var INSTPROG
 +Var INSTEXE
 +Var INSTFLAGS
 +Var INSTSHORTCUT
 +
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +;;; Sections
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +
 +Section ""						; (default section)
 +
 +SetShellVarContext all			; install for all users (if you change this, change it in the uninstall as well)
 +
 +
 +; Start with some default values.
 +StrCpy $INSTFLAGS "${INSTFLAGS}"
 +StrCpy $INSTPROG "${INSTNAME}"
 +StrCpy $INSTEXE "${INSTEXE}"
 +StrCpy $INSTSHORTCUT "${SHORTCUT}"
 +
 +IfSilent +2
 +Goto NOT_SILENT
 +  Call CheckStartupParams                 ; Figure out where, what and how to install.
 +NOT_SILENT:
 +Call CheckWindowsVersion		; warn if on Windows 98/ME
 +Call CheckIfAdministrator		; Make sure the user can install/uninstall
 +Call CheckIfAlreadyCurrent		; Make sure that we haven't already installed this version
 +Call CloseSecondLife			; Make sure we're not running
 +Call RemoveNSIS					; Check for old NSIS install to remove
 +
 +;;; Don't remove cache files during a regular install, removing the inventory cache on upgrades results in lots of damage to the servers.
 +;Call RemoveCacheFiles			; Installing over removes potentially corrupted
 +								; VFS and cache files.
 +
 +
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +;;; Files
 +;;;
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +;; This placeholder is replaced by the complete list of all the files in the installer, by viewer_manifest.py
 +%%INSTALL_FILES%%
 +
 +; If this is a silent update, we don't need to re-create these shortcuts or registry entries.
 +IfSilent POST_INSTALL
 +
 +; Shortcuts in start menu
 +CreateDirectory	"$SMPROGRAMS\$INSTSHORTCUT"
 +SetOutPath "$INSTDIR"
 +CreateShortCut	"$SMPROGRAMS\$INSTSHORTCUT\$INSTSHORTCUT.lnk" \
 +				"$INSTDIR\$INSTEXE" "$INSTFLAGS"
 +
 +!ifdef MUSEUM
 +CreateShortCut	"$SMPROGRAMS\$INSTSHORTCUT\$INSTSHORTCUT Museum.lnk" \
 +
 +				"$INSTDIR\$INSTEXE" "$INSTFLAGS -simple"
 +CreateShortCut	"$SMPROGRAMS\$INSTSHORTCUT\$INSTSHORTCUT Museum Spanish.lnk" \
 +
 +				"$INSTDIR\$INSTEXE" "$INSTFLAGS -simple -spanish"
 +!endif
 +
 +WriteINIStr		"$SMPROGRAMS\$INSTSHORTCUT\SL Create Trial Account.url" \
 +				"InternetShortcut" "URL" \
 +				"http://www.secondlife.com/registration/"
 +WriteINIStr		"$SMPROGRAMS\$INSTSHORTCUT\SL Your Account.url" \
 +				"InternetShortcut" "URL" \
 +				"http://www.secondlife.com/account/"
 +CreateShortCut	"$SMPROGRAMS\$INSTSHORTCUT\SL Release Notes.lnk" \
 +				"$INSTDIR\releasenotes.txt"
 +CreateShortCut	"$SMPROGRAMS\$INSTSHORTCUT\SL Scripting Language Help.lnk" \
 +				"$INSTDIR\lsl_guide.html"
 +CreateShortCut	"$SMPROGRAMS\$INSTSHORTCUT\Uninstall $INSTSHORTCUT.lnk" \
 +				'"$INSTDIR\uninst.exe"' '/P="$INSTPROG"'
 +
 +; Other shortcuts
 +SetOutPath "$INSTDIR"
 +CreateShortCut "$DESKTOP\$INSTSHORTCUT.lnk" "$INSTDIR\$INSTEXE" "$INSTFLAGS"
 +CreateShortCut "$INSTDIR\$INSTSHORTCUT.lnk" "$INSTDIR\$INSTEXE" "$INSTFLAGS"
 +CreateShortCut "$INSTDIR\Uninstall $INSTSHORTCUT.lnk" \
 +				'"$INSTDIR\uninst.exe"' '/P="$INSTPROG"'
 +
 +!ifdef MUSEUM
 +CreateShortCut "$DESKTOP\$INSTSHORTCUT Museum.lnk" "$INSTDIR\$INSTEXE" "$INSTFLAGS -simple"
 +
 +CreateShortCut "$DESKTOP\$INSTSHORTCUT Museum Spanish.lnk" "$INSTDIR\$INSTEXE" "$INSTFLAGS -simple -spanish"
 +
 +CreateShortCut "$INSTDIR\$INSTSHORTCUT Museum.lnk" "$INSTDIR\$INSTEXE" "$INSTFLAGS -simple"
 +
 +CreateShortCut "$INSTDIR\$INSTSHORTCUT Museum Spanish.lnk" "$INSTDIR\$INSTEXE" "$INSTFLAGS -simple -spanish"
 +
 +!endif
 +
 +; Write registry
 +WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "" "$INSTDIR"
 +WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Version" "${VERSION_LONG}"
 +WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Flags" "$INSTFLAGS"
 +WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Shortcut" "$INSTSHORTCUT"
 +WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Exe" "$INSTEXE"
 +WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "DisplayName" "$INSTPROG (remove only)"
 +WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "UninstallString" '"$INSTDIR\uninst.exe" /P="$INSTPROG"'
 +
 +; Write URL registry info
 +WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}" "(default)" "URL:Second Life"
 +WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}" "URL Protocol" ""
 +WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\DefaultIcon" "" '"$INSTDIR\$INSTEXE"'
 +WriteRegExpandStr HKEY_CLASSES_ROOT "${URLNAME}\shell\open\command" "" '"$INSTDIR\$INSTEXE" $INSTFLAGS -url "%1"'
 +
 +Goto WRITE_UNINST
 +
 +POST_INSTALL:
 +; Run a post-executable script if necessary.
 +Call PostInstallExe
 +
 +WRITE_UNINST:
 +; write out uninstaller
 +WriteUninstaller "$INSTDIR\uninst.exe"
 +
 +; end of default section
 +SectionEnd
 +
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +; PostInstallExe
 +; This just runs any post installation scripts.
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +Function PostInstallExe
 +push $0
 +  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "PostInstallExe"
 +  ;MessageBox MB_OK '$0'
 +  ExecWait '$0'
 +pop $0
 +FunctionEnd
 +
 +
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +; CheckStartupParameters
 +; Sets INSTFLAGS, INSTPROG, and INSTEXE.
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +Function CheckStartupParams
 +push $0
 +push $R0
 +
 +  ; Look for a registry entry with info about where to update.
 +  Call GetProgramName
 +  pop $R0
 +  StrCpy $INSTPROG "$R0"
 +  StrCpy $INSTEXE "$R0.exe"
 +
 +  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" ""
 +  ; If key doesn't exist, skip install
 +  IfErrors ABORT
 +  StrCpy $INSTDIR "$0"
 +
 +  ; We now have a directory to install to.  Get the startup parameters and shortcut as well.
 +  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Flags"
 +  IfErrors +2
 +  StrCpy $INSTFLAGS "$0"
 +  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Shortcut"
 +  IfErrors +2
 +  StrCpy $INSTSHORTCUT "$0"
 +  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Exe"
 +  IfErrors +2
 +  StrCpy $INSTEXE "$0"
 +  Goto FINISHED
 +
 +ABORT:
 +  MessageBox MB_OK "Could not find the program '$INSTPROG'. Silent update failed."
 +  Quit
 +
 +FINISHED:
 +  ;MessageBox MB_OK "INSTPROG: $INSTPROG, INSTEXE: $INSTEXE, INSTFLAGS: $INSTFLAGS"
 +pop $R0
 +pop $0
 +FunctionEnd
 +
 +Function un.CheckStartupParams
 +push $0
 +push $R0
 +
 +  ; Look for a registry entry with info about where to update.
 +  Call un.GetProgramName
 +  pop $R0
 +  StrCpy $INSTPROG "$R0"
 +  StrCpy $INSTEXE "$R0.exe"
 +
 +  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" ""
 +  ; If key doesn't exist, skip install
 +  IfErrors ABORT
 +  StrCpy $INSTDIR "$0"
 +
 +  ; We now have a directory to install to.  Get the startup parameters and shortcut as well.
 +  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Flags"
 +  IfErrors +2
 +  StrCpy $INSTFLAGS "$0"
 +  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Shortcut"
 +  IfErrors +2
 +  StrCpy $INSTSHORTCUT "$0"
 +  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Exe"
 +  IfErrors +2
 +  StrCpy $INSTEXE "$0"
 +  Goto FINISHED
 +
 +ABORT:
 +  MessageBox MB_OK "Could not find the program '$INSTPROG'. Silent update failed."
 +  Quit
 +
 +FINISHED:
 +  ;MessageBox MB_OK "INSTPROG: $INSTPROG, INSTEXE: $INSTEXE, INSTFLAGS: $INSTFLAGS"
 +pop $R0
 +pop $0
 +FunctionEnd
 +
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +;;; After install completes, offer readme file
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +Function .onInstSuccess
 +	MessageBox MB_YESNO \
 +	"Start Second Life now?" /SD IDYES IDNO NoReadme
 +		; Assumes SetOutPath $INSTDIR
 +		Exec '"$INSTDIR\$INSTEXE" $INSTFLAGS'
 +	NoReadme:
 +FunctionEnd
 +
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +; Remove old NSIS version. Modifies no variables.
 +; Does NOT delete the LindenWorld directory, or any
 +; user files in that directory.
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +Function RemoveNSIS
 +  Push $0
 +  ; Grab the installation directory of the old version
 +  DetailPrint "Checking for old version..."
 +  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" ""
 +
 +  ; If key doesn't exist, skip uninstall
 +  IfErrors NO_NSIS
 +
 +  ; Clean up legacy beta shortcuts
 +  Delete "$SMPROGRAMS\Second Life Beta.lnk"
 +  Delete "$DESKTOP\Second Life Beta.lnk"
 +  Delete "$SMPROGRAMS\Second Life.lnk"
 +  
 +  ; Clean up old newview.exe file
 +  Delete "$INSTDIR\newview.exe"
 +
 +  ; Intentionally don't delete the stuff in
 +  ; Documents and Settings, so we keep the user's settings
 +
 +  NO_NSIS:
 +  Pop $0
 +FunctionEnd
 +
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +; Make sure we're not on Windows 98 / ME
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +Function CheckWindowsVersion
 +	DetailPrint "Checking Windows version..."
 +	Call GetWindowsVersion
 +	Pop $R0
 +	; Just get first two characters, ignore 4.0 part of "NT 4.0"
 +	StrCpy $R0 $R0 2
 +	; Blacklist certain OS versions
 +	StrCmp $R0 "95" win_ver_bad
 +	StrCmp $R0 "98" win_ver_bad
 +	StrCmp $R0 "ME" win_ver_bad
 +	StrCmp $R0 "NT" win_ver_bad
 +	Return
 +win_ver_bad:
 +	MessageBox MB_YESNO 'Second Life only supports Windows XP, Windows 2000, and Mac OS X.$\n$\nAttempting to install on Windows $R0 can result in crashes and data loss.$\n$\nInstall anyway?' IDNO win_ver_abort
 +	Return
 +win_ver_abort:
 +	Quit
 +FunctionEnd
 +
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +; Make sure the user can install/uninstall
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +Function CheckIfAdministrator
 +		DetailPrint "Checking for permission to install..."
 +         UserInfo::GetAccountType
 +         Pop $R0
 +         StrCmp $R0 "Admin" is_admin
 +         MessageBox MB_OK 'You appear to be using a "limited" account.$\nYou must be an "administrator" to install Second Life.'
 +         Quit
 +is_admin:
 +         Return
 +FunctionEnd
 +
 +Function un.CheckIfAdministrator
 +		DetailPrint "Checking for permission to uninstall..."
 +         UserInfo::GetAccountType
 +         Pop $R0
 +         StrCmp $R0 "Admin" is_admin
 +         MessageBox MB_OK 'You appear to be using a "limited" account.$\nYou must be an "administrator" to uninstall Second Life.'
 +         Quit
 +is_admin:
 +         Return
 +FunctionEnd
 +
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +; Checks to see if the current version has already been installed (according to the registry).
 +; If it has, allow user to bail out of install process.
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +Function CheckIfAlreadyCurrent
 +  Push $0
 +	ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Version"
 +    StrCmp $0 ${VERSION_LONG} 0 DONE
 +	MessageBox MB_OKCANCEL "It appears that Second Life ${VERSION_LONG} is already installed.$\n$\nWould you like to install it again?" /SD IDOK IDOK DONE
 +    Quit
 +
 +  DONE:
 +    Pop $0
 +    Return
 +FunctionEnd
 +	
 +
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +; Close the program, if running. Modifies no variables.
 +; Allows user to bail out of install process.
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +Function CloseSecondLife
 +  Push $0
 +  FindWindow $0 "Second Life" ""
 +  IntCmp $0 0 DONE
 +  MessageBox MB_OKCANCEL "Second Life can't be installed while it is already running.$\n$\nFinish what you're doing then select OK to close Second Life and continue.$\nSelect CANCEL to cancel installation." IDOK CLOSE IDCANCEL CANCEL_INSTALL
 +
 +  CANCEL_INSTALL:
 +    Quit
 +
 +  CLOSE:
 +    DetailPrint "Waiting for Second Life to shut down..."
 +    SendMessage $0 16 0 0
 +
 +  LOOP:
 +	  FindWindow $0 "Second Life" ""
 +	  IntCmp $0 0 DONE
 +	  Sleep 500
 +	  Goto LOOP
 +
 +  DONE:
 +    Pop $0
 +    Return
 +FunctionEnd
 +
 +
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +; Delete files in Documents and Settings\<user>\SecondLife\cache
 +; Delete files in Documents and Settings\All Users\SecondLife\cache
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +Function RemoveCacheFiles
 +
 +; Delete files in Documents and Settings\<user>\SecondLife
 +Push $0
 +Push $1
 +Push $2
 +  DetailPrint "Deleting cache files in Documents and Settings folder"
 +
 +  StrCpy $0 0 ; Index number used to iterate via EnumRegKey
 +
 +  LOOP:
 +    EnumRegKey $1 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" $0
 +    StrCmp $1 "" DONE               ; no more users
 +
 +    ReadRegStr $2 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$1" "ProfileImagePath" 
 +    StrCmp $2 "" CONTINUE 0         ; "ProfileImagePath" value is missing
 +
 +    ; Required since ProfileImagePath is of type REG_EXPAND_SZ
 +    ExpandEnvStrings $2 $2
 +
 +	; When explicitly uninstalling, everything goes away
 +    RMDir /r "$2\Application Data\SecondLife\cache"
 +
 +  CONTINUE:
 +    IntOp $0 $0 + 1
 +    Goto LOOP
 +  DONE:
 +Pop $2
 +Pop $1
 +Pop $0
 +
 +; Delete files in Documents and Settings\All Users\SecondLife
 +Push $0
 +  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" "Common AppData"
 +  StrCmp $0 "" +2
 +  RMDir /r "$0\SecondLife\cache"
 +Pop $0
 +
 +; Delete filse in C:\Windows\Application Data\SecondLife
 +; If the user is running on a pre-NT system, Application Data lives here instead of
 +; in Documents and Settings.
 +RMDir /r "$WINDIR\Application Data\SecondLife\cache"
 +
 +FunctionEnd
 +
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +; Delete files in Documents and Settings\<user>\SecondLife
 +; Delete files in Documents and Settings\All Users\SecondLife
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +Function un.DocumentsAndSettingsFolder
 +
 +; Delete files in Documents and Settings\<user>\SecondLife
 +Push $0
 +Push $1
 +Push $2
 +
 +  DetailPrint "Deleting files in Documents and Settings folder"
 +
 +  StrCpy $0 0 ; Index number used to iterate via EnumRegKey
 +
 +  LOOP:
 +    EnumRegKey $1 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" $0
 +    StrCmp $1 "" DONE               ; no more users
 +
 +    ReadRegStr $2 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$1" "ProfileImagePath" 
 +    StrCmp $2 "" CONTINUE 0         ; "ProfileImagePath" value is missing
 +
 +    ; Required since ProfileImagePath is of type REG_EXPAND_SZ
 +    ExpandEnvStrings $2 $2
 +
 +	; If uninstalling a normal install remove everything
 +	; Otherwise (preview/dmz etc) just remove cache
 +    StrCmp $INSTFLAGS "" RM_ALL RM_CACHE
 +      RM_ALL:
 +        RMDir /r "$2\Application Data\SecondLife"
 +        GoTo CONTINUE
 +      RM_CACHE:
 +        RMDir /r "$2\Application Data\SecondLife\Cache"
 +
 +  CONTINUE:
 +    IntOp $0 $0 + 1
 +    Goto LOOP
 +  DONE:
 +
 +Pop $2
 +Pop $1
 +Pop $0
 +
 +; Delete files in Documents and Settings\All Users\SecondLife
 +Push $0
 +  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" "Common AppData"
 +  StrCmp $0 "" +2
 +  RMDir /r "$0\SecondLife"
 +Pop $0
 +
 +; Delete filse in C:\Windows\Application Data\SecondLife
 +; If the user is running on a pre-NT system, Application Data lives here instead of
 +; in Documents and Settings.
 +RMDir /r "$WINDIR\Application Data\SecondLife"
 +
 +FunctionEnd
 +
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +; Close the program, if running. Modifies no variables.
 +; Allows user to bail out of uninstall process.
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +Function un.CloseSecondLife
 +  Push $0
 +  FindWindow $0 "Second Life" ""
 +  IntCmp $0 0 DONE
 +  MessageBox MB_OKCANCEL "Second Life can't be uninstalled while it is already running.$\n$\nFinish what you're doing then select OK to close Second Life and continue.$\nSelect CANCEL to cancel installation." IDOK CLOSE IDCANCEL CANCEL_UNINSTALL
 +
 +  CANCEL_UNINSTALL:
 +    Quit
 +
 +  CLOSE:
 +    DetailPrint "Waiting for Second Life to shut down..."
 +    SendMessage $0 16 0 0
 +
 +  LOOP:
 +	  FindWindow $0 "Second Life" ""
 +	  IntCmp $0 0 DONE
 +	  Sleep 500
 +	  Goto LOOP
 +
 +  DONE:
 +    Pop $0
 +    Return
 +FunctionEnd
 +
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +;;; Delete the installed files
 +;;; This deletes the uninstall executable, but it works 
 +;;; because it is copied to temp directory before running
 +;;;
 +;;; Note:  You must list all files here, because we only
 +;;; want to delete our files, not things users left in the
 +;;; application directories.
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +Function un.ProgramFiles
 +
 +;; Remove mozilla file first so recursive directory deletion doesn't get hung up
 +Delete "$INSTDIR\app_settings\mozilla\components"
 +
 +;; This placeholder is replaced by the complete list of files to uninstall by viewer_manifest.py
 +%%DELETE_FILES%%
 +
 +;; Optional/obsolete files.  Delete won't fail if they don't exist.
 +Delete "$INSTDIR\dronesettings.ini"
 +Delete "$INSTDIR\message_template.msg"
 +Delete "$INSTDIR\newview.pdb"
 +Delete "$INSTDIR\newview.map"
 +Delete "$INSTDIR\SecondLife.pdb"
 +Delete "$INSTDIR\SecondLife.map"
 +Delete "$INSTDIR\comm.dat"
 +Delete "$INSTDIR\*.glsl"
 +Delete "$INSTDIR\motions\*.lla"
 +Delete "$INSTDIR\trial\*.html"
 +Delete "$INSTDIR\newview.exe"
 +;; Remove entire help directory
 +Delete "$INSTDIR\help\Advanced\*"
 +RMDir  "$INSTDIR\help\Advanced"
 +Delete "$INSTDIR\help\basics\*"
 +RMDir  "$INSTDIR\help\basics"
 +Delete "$INSTDIR\help\Concepts\*"
 +RMDir  "$INSTDIR\help\Concepts"
 +Delete "$INSTDIR\help\welcome\*"
 +RMDir  "$INSTDIR\help\welcome"
 +Delete "$INSTDIR\help\*"
 +RMDir  "$INSTDIR\help"
 +
 +Delete "$INSTDIR\uninst.exe"
 +RMDir "$INSTDIR"
 +
 +IfFileExists "$INSTDIR" FOLDERFOUND NOFOLDER
 +
 +FOLDERFOUND:
 +  MessageBox MB_YESNO "There are still files in your SecondLife program directory.$\n$\nThese are possibly files you created or moved to:$\n$INSTDIR$\n$\nDo you want to remove them?" IDNO NOFOLDER
 +  RMDir /r "$INSTDIR"
 +
 +NOFOLDER:
 +
 +FunctionEnd
 +
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +;;; Uninstall settings
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +UninstallText "This will uninstall Second Life ${VERSION_LONG} from your system."
 +ShowUninstDetails show
 +
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +;;; Uninstall section
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +Section Uninstall
 +
 +; Start with some default values.
 +StrCpy $INSTFLAGS "${FARMFLAG}"
 +StrCpy $INSTPROG "${INSTNAME}"
 +StrCpy $INSTEXE "${INSTEXE}"
 +StrCpy $INSTSHORTCUT "${SHORTCUT}"
 +Call un.CheckStartupParams              ; Figure out where, what and how to uninstall.
 +Call un.CheckIfAdministrator		; Make sure the user can install/uninstall
 +
 +; uninstall for all users (if you change this, change it in the install as well)
 +SetShellVarContext all			
 +
 +; Make sure we're not running
 +Call un.CloseSecondLife
 +
 +; Clean up registry keys
 +DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG"
 +DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG"
 +
 +; Clean up shortcuts
 +Delete "$SMPROGRAMS\$INSTSHORTCUT\*.*"
 +RMDir  "$SMPROGRAMS\$INSTSHORTCUT"
 +
 +Delete "$DESKTOP\$INSTSHORTCUT.lnk"
 +Delete "$INSTDIR\$INSTSHORTCUT.lnk"
 +Delete "$INSTDIR\Uninstall $INSTSHORTCUT.lnk"
 +
 +; Clean up cache and log files.
 +; Leave them in-place for non AGNI installs.
 +
 +!ifdef UNINSTALL_SETTINGS
 +Call un.DocumentsAndSettingsFolder
 +!endif
 +
 +Call un.ProgramFiles
 +
 +SectionEnd 				; end of uninstall section
 +
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +; (From the NSIS wiki, DK)
 +; GetParameterValue
 +;
 +; Usage:
 +; !insertmacro GetParameterValue "/L=" "1033"
 +; pop $R0
 +;
 +; Returns on top of stack
 +;
 +; Example command lines:
 +; foo.exe /S /L=1033 /D=C:\Program Files\Foo
 +; or:
 +; foo.exe /S "/L=1033" /D="C:\Program Files\Foo"
 +; gpv "/L=" "1033"
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +
 + !macro GetParameterValue SWITCH DEFAULT
 +   Push $0
 +   Push $1
 +   Push $2
 +   Push $3
 +   Push $4
 +
 + ;$CMDLINE='"My Setup\Setup.exe" /L=1033 /S'
 +   Push "$CMDLINE"
 +   Push '${SWITCH}"'
 +   !insertmacro StrStr
 +   Pop $0
 +   StrCmp "$0" "" gpv_notquoted
 + ;$0='/L="1033" /S'
 +   StrLen $2 "$0"
 +   Strlen $1 "${SWITCH}"
 +   IntOp $1 $1 + 1
 +   StrCpy $0 "$0" $2 $1
 + ;$0='1033" /S'
 +   Push "$0"
 +   Push '"'
 +   !insertmacro StrStr
 +   Pop $1
 +   StrLen $2 "$0"
 +   StrLen $3 "$1"
 +   IntOp $4 $2 - $3
 +   StrCpy $0 $0 $4 0
 +   Goto gpv_done
 +
 +   gpv_notquoted:
 +   Push "$CMDLINE"
 +   Push "${SWITCH}"
 +   !insertmacro StrStr
 +   Pop $0
 +   StrCmp "$0" "" gpv_done
 + ;$0='/L="1033" /S'
 +   StrLen $2 "$0"
 +   Strlen $1 "${SWITCH}"
 +   StrCpy $0 "$0" $2 $1
 + ;$0=1033 /S'
 +   Push "$0"
 +   Push ' '
 +   !insertmacro StrStr
 +   Pop $1
 +   StrLen $2 "$0"
 +   StrLen $3 "$1"
 +   IntOp $4 $2 - $3
 +   StrCpy $0 $0 $4 0
 +   Goto gpv_done
 +
 +   gpv_done:
 +   StrCmp "$0" "" 0 +2
 +   StrCpy $0 "${DEFAULT}"
 +
 +   Pop $4
 +   Pop $3
 +   Pop $2
 +   Pop $1
 +   Exch $0
 + !macroend
 +
 +; And I had to modify StrStr a tiny bit.
 +; Possible upgrade switch the goto's to use ${__LINE__}
 +
 +!macro STRSTR
 +  Exch $R1 ; st=haystack,old$R1, $R1=needle
 +  Exch    ; st=old$R1,haystack
 +  Exch $R2 ; st=old$R1,old$R2, $R2=haystack
 +  Push $R3
 +  Push $R4
 +  Push $R5
 +  StrLen $R3 $R1
 +  StrCpy $R4 0
 +  ; $R1=needle
 +  ; $R2=haystack
 +  ; $R3=len(needle)
 +  ; $R4=cnt
 +  ; $R5=tmp
 + ;  loop;
 +    StrCpy $R5 $R2 $R3 $R4
 +    StrCmp $R5 $R1 +4
 +    StrCmp $R5 "" +3
 +    IntOp $R4 $R4 + 1
 +    Goto -4
 + ;  done;
 +  StrCpy $R1 $R2 "" $R4
 +  Pop $R5
 +  Pop $R4
 +  Pop $R3
 +  Pop $R2
 +  Exch $R1
 +!macroend
 +
 +Function GetProgramName
 +  !insertmacro GetParameterValue "/P=" "SecondLife"
 +FunctionEnd
 +
 +Function un.GetProgramName
 +  !insertmacro GetParameterValue "/P=" "SecondLife"
 +FunctionEnd
 +
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 +; (From the NSIS documentation, JC)
 +; GetWindowsVersion
 +;
 +; Based on Yazno's function, http://yazno.tripod.com/powerpimpit/
 +; Updated by Joost Verburg
 +;
 +; Returns on top of stack
 +;
 +; Windows Version (95, 98, ME, NT x.x, 2000, XP, 2003)
 +; or
 +; '' (Unknown Windows Version)
 +;
 +; Usage:
 +;   Call GetWindowsVersion
 +;   Pop $R0
 +;   ; at this point $R0 is "NT 4.0" or whatnot
 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 + 
 +Function GetWindowsVersion
 + 
 +   Push $R0
 +   Push $R1
 + 
 +   ReadRegStr $R0 HKLM \
 +   "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
 +
 +   IfErrors 0 lbl_winnt
 +   
 +   ; we are not NT
 +   ReadRegStr $R0 HKLM \
 +   "SOFTWARE\Microsoft\Windows\CurrentVersion" VersionNumber
 + 
 +   StrCpy $R1 $R0 1
 +   StrCmp $R1 '4' 0 lbl_error
 + 
 +   StrCpy $R1 $R0 3
 + 
 +   StrCmp $R1 '4.0' lbl_win32_95
 +   StrCmp $R1 '4.9' lbl_win32_ME lbl_win32_98
 + 
 +   lbl_win32_95:
 +     StrCpy $R0 '95'
 +   Goto lbl_done
 + 
 +   lbl_win32_98:
 +     StrCpy $R0 '98'
 +   Goto lbl_done
 + 
 +   lbl_win32_ME:
 +     StrCpy $R0 'ME'
 +   Goto lbl_done
 + 
 +   lbl_winnt:
 + 
 +   StrCpy $R1 $R0 1
 + 
 +   StrCmp $R1 '3' lbl_winnt_x
 +   StrCmp $R1 '4' lbl_winnt_x
 + 
 +   StrCpy $R1 $R0 3
 + 
 +   StrCmp $R1 '5.0' lbl_winnt_2000
 +   StrCmp $R1 '5.1' lbl_winnt_XP
 +   StrCmp $R1 '5.2' lbl_winnt_2003 lbl_error
 + 
 +   lbl_winnt_x:
 +     StrCpy $R0 "NT $R0" 6
 +   Goto lbl_done
 + 
 +   lbl_winnt_2000:
 +     Strcpy $R0 '2000'
 +   Goto lbl_done
 + 
 +   lbl_winnt_XP:
 +     Strcpy $R0 'XP'
 +   Goto lbl_done
 + 
 +   lbl_winnt_2003:
 +     Strcpy $R0 '2003'
 +   Goto lbl_done
 + 
 +   lbl_error:
 +     Strcpy $R0 ''
 +   lbl_done:
 + 
 +   Pop $R1
 +   Exch $R0
 + 
 +FunctionEnd
 diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py new file mode 100755 index 0000000000..104d860c87 --- /dev/null +++ b/indra/newview/viewer_manifest.py @@ -0,0 +1,437 @@ +#!/usr/bin/python +# @file viewer_manifest.py +# @author Ryan Williams +# @brief Description of all installer viewer files, and methods for packaging +#        them into installers for all supported platforms. +# +# Copyright (c) 2006-$CurrentYear$, Linden Research, Inc. +# $License$ +import sys +import os.path +import re +import tarfile +viewer_dir = os.path.dirname(__file__) +# add llmanifest library to our path so you don't have to muck with PYTHONPATH +sys.path.append(os.path.join(viewer_dir, '../lib/python/indra')) +from llmanifest import LLManifest, main, proper_windows_path, path_ancestors + +class ViewerManifest(LLManifest): +        def construct(self): +                super(ViewerManifest, self).construct() +                self.exclude("*.svn*") +                self.path(src="../../scripts/messages/message_template.msg", dst="app_settings/message_template.msg") + +                if self.prefix(src="app_settings"): +                        self.exclude("logcontrol.xml") +                        self.exclude("logcontrol-dev.xml") +                        self.path("*.pem") +                        self.path("*.ini") +                        self.path("*.xml") +                        self.path("*.vp") +                        self.path("*.db2") + +                        # include the entire shaders directory recursively +                        self.path("shaders") +                        self.end_prefix("app_settings") + +                if self.prefix(src="character"): +                        self.path("*.llm") +                        self.path("*.xml") +                        self.path("*.tga") +                        self.end_prefix("character") + + +                # Include our fonts +                if self.prefix(src="fonts"): +                        self.path("*.ttf") +                        self.path("*.txt") +                        self.end_prefix("fonts") + +                # XUI +                if self.prefix(src="skins"): +                        self.path("paths.xml") +                        self.path("xui/*/*.xml") +                        self.path('words.*.txt') + +                        # Local HTML files (e.g. loading screen) +                        if self.prefix("html/*"): +                                self.path("*.html") +                                self.path("*.gif") +                                self.path("*.jpg") +                                self.path("*.css") +                                self.end_prefix("html/*") +                        self.end_prefix("skins") + +                self.path("featuretable.txt") +                self.path("releasenotes.txt") +                self.path("lsl_guide.html") +                self.path("gpu_table.txt") + +        def flags_list(self): +                """ Convenience function that returns the command-line flags for the grid""" +                if(self.args['grid'] == ''): +                        return "" +                elif(self.args['grid'] == 'firstlook'): +                        return '-settings settings_firstlook.xml' +                else: +			return ("-settings settings_beta.xml --%(grid)s -helperuri http://preview-%(grid)s.secondlife.com/helpers/" % {'grid':self.args['grid']}) + +        def login_url(self): +                """ Convenience function that returns the appropriate login url for the grid""" +                if(self.args.get('login_url')): +                        return self.args['login_url'] +                else: +                        if(self.args['grid'] == ''): +                                return 'http://secondlife.com/app/login/' +                        elif(self.args['grid'] == 'firstlook'): +                                return 'http://secondlife.com/app/login/firstlook/' +                        else: +                                return 'http://secondlife.com/app/login/beta/' + +        def replace_login_url(self): +                # set the login page to point to a url appropriate for the type of client +                self.replace_in("skins/xui/en-us/panel_login.xml", searchdict={'http://secondlife.com/app/login/':self.login_url()}) + +        def create_unpacked(self): +                unpacked_file_name = "unpacked_%(plat)s_%(vers)s.tar" % { +                        'plat':self.args['platform'], +                        'vers':'_'.join(self.args['version'])} +                print "Creating unpacked file:", unpacked_file_name +                # could add a gz here but that doubles the time it takes to do this step +                tf = tarfile.open(self.src_path_of(unpacked_file_name), 'w:') +                # add the entire installation package, at the very top level +                tf.add(self.get_dst_prefix(), "") +                tf.close() + +class WindowsManifest(ViewerManifest): +        def final_exe(self): +                # *NOTE: these are the only two executable names that the crash reporter recognizes +                if self.args['grid'] == '': +                        return "SecondLife.exe" +                else: +                        return "SecondLifePreview.exe" +                        # return "SecondLifePreview%s.exe" % (self.args['grid'], ) + +        def construct(self): +                super(WindowsManifest, self).construct() +                # the final exe is complicated because we're not sure where it's coming from, +                # nor do we have a fixed name for the executable +                self.path(self.find_existing_file('ReleaseForDownload/Secondlife.exe', 'Secondlife.exe', 'ReleaseNoOpt/newview_noopt.exe'), dst=self.final_exe()) +                # need to get the kdu dll from any of the build directories as well +                self.path(self.find_existing_file('ReleaseForDownload/llkdu.dll', 'llkdu.dll', '../../libraries/i686-win32/lib_release/llkdu.dll'), dst='llkdu.dll') +                self.path(src="licenses-win32.txt", dst="licenses.txt") + +                # For use in crash reporting (generates minidumps) +                self.path("dbghelp.dll") + +                # For using FMOD for sound... DJS +                self.path("fmod.dll") + +                # Mozilla appears to force a dependency on these files so we need to ship it (CP) +                self.path("msvcr71.dll") +                self.path("msvcp71.dll") + +                # Mozilla runtime DLLs (CP) +                if self.prefix(src="../../libraries/i686-win32/lib_release", dst=""): +                        self.path("gksvggdiplus.dll") +                        self.path("js3250.dll") +                        self.path("nspr4.dll") +                        self.path("nss3.dll") +                        self.path("nssckbi.dll") +                        self.path("plc4.dll") +                        self.path("plds4.dll") +                        self.path("smime3.dll") +                        self.path("softokn3.dll") +                        self.path("ssl3.dll") +                        self.path("xpcom.dll") +                        self.path("xul.dll") +                        self.end_prefix() + +                # Mozilla runtime misc files (CP) +                if self.prefix(src="app_settings/mozilla"): +                        self.path("chrome/*.*") +                        self.path("components/*.*") +                        self.path("greprefs/*.*") +                        self.path("plugins/*.*") +                        self.path("res/*.*") +                        self.path("res/*/*") +                        self.end_prefix() + +                # pull in the crash logger and updater from other projects +                self.path(src="../win_crash_logger/win_crash_logger.exe", dst="win_crash_logger.exe") +                self.path(src="../win_updater/updater.exe", dst="updater.exe") +                self.replace_login_url() + +        def nsi_file_commands(self, install=True): +                def wpath(path): +                        if(path.endswith('/') or path.endswith(os.path.sep)): +                                path = path[:-1] +                        path = path.replace('/', '\\') +                        return path + +                result = "" +                dest_files = [pair[1] for pair in self.file_list if pair[0] and os.path.isfile(pair[1])] +                # sort deepest hierarchy first +                dest_files.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b)) +                dest_files.reverse() +                out_path = None +                for pkg_file in dest_files: +                        rel_file = os.path.normpath(pkg_file.replace(self.get_dst_prefix()+os.path.sep,'')) +                        installed_dir = wpath(os.path.join('$INSTDIR', os.path.dirname(rel_file))) +                        pkg_file = wpath(os.path.normpath(pkg_file)) +                        if installed_dir != out_path: +                                if(install): +                                        out_path = installed_dir +                                        result += 'SetOutPath ' + out_path + '\n' +                        if(install): +                                result += 'File ' + pkg_file + '\n' +                        else: +                                result += 'Delete ' + wpath(os.path.join('$INSTDIR', rel_file)) + '\n' +		# at the end of a delete, just rmdir all the directories +		if(not install): +			deleted_file_dirs = [os.path.dirname(pair[1].replace(self.get_dst_prefix()+os.path.sep,'')) for pair in self.file_list] +			# find all ancestors so that we don't skip any dirs that happened to have no non-dir children +			deleted_dirs = [] +			for d in deleted_file_dirs: +				deleted_dirs.extend(path_ancestors(d)) +			# sort deepest hierarchy first +			deleted_dirs.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b)) +			deleted_dirs.reverse() +			prev = None +			for d in deleted_dirs: +				if d != prev:   # skip duplicates +					result += 'RMDir ' + wpath(os.path.join('$INSTDIR', os.path.normpath(d))) + '\n' +				prev = d + +                return result + +        def package_finish(self): +                self.create_unpacked() +                version_vars_template = """ +                !define INSTEXE  "%(final_exe)s" +                !define VERSION "%(version_short)s" +                !define VERSION_LONG "%(version)s" +                !define VERSION_DASHES "%(version_dashes)s" +                """ +                if(self.args['grid'] == ''): +                        installer_file = "Second Life %(version_dashes)s Setup.exe" +                        grid_vars_template = """ +                        OutFile "%(outfile)s" +                        !define INSTFLAGS "%(flags)s" +                        !define INSTNAME   "SecondLife" +                        !define SHORTCUT   "Second Life" +                        !define URLNAME   "secondlife" +                        Caption "Second Life ${VERSION}" +                        """ +                else: +                        installer_file = "Second Life %(version_dashes)s (%(grid_caps)s) Setup.exe" +                        grid_vars_template = """ +                        OutFile "%(outfile)s" +			!define INSTFLAGS "%(flags)s" +                        !define INSTNAME   "SecondLife%(grid_caps)s" +                        !define SHORTCUT   "Second Life (%(grid_caps)s)" +                        !define URLNAME   "secondlife%(grid)s" +                        !define UNINSTALL_SETTINGS 1 +                        Caption "Second Life %(grid)s ${VERSION}" +                        """ +                if(self.args.has_key('installer_name')): +                        installer_file = self.args['installer_name'] +                else: +                        installer_file = installer_file % {'version_dashes' : '-'.join(self.args['version']), +                                                                                           'grid_caps' : self.args['grid'].upper()} +                tempfile = "../secondlife_setup.nsi" +                # the following is an odd sort of double-string replacement +                self.replace_in("installers/windows/installer_template.nsi", tempfile, { +                        "%%VERSION%%":version_vars_template%{'version_short' : '.'.join(self.args['version'][:-1]), +                                                                                                 'version' : '.'.join(self.args['version']), +                                                                                                 'version_dashes' : '-'.join(self.args['version']), +                                                                                                 'final_exe' : self.final_exe()}, +                        "%%GRID_VARS%%":grid_vars_template%{'grid':self.args['grid'], +                                                                                                'grid_caps':self.args['grid'].upper(), +                                                                                                'outfile':installer_file, +                                                                                                'flags':self.flags_list()}, +                        "%%INSTALL_FILES%%":self.nsi_file_commands(True), +                        "%%DELETE_FILES%%":self.nsi_file_commands(False)}) + +                NSIS_path = 'C:\\Program Files\\NSIS\\makensis.exe' +                self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile)) +#                self.remove(self.dst_path_of(tempfile)) +                self.created_path(installer_file) + + +class DarwinManifest(ViewerManifest): +        def construct(self): +                # copy over the build result (this is a no-op if run within the xcode script) +                self.path("build/" + self.args['configuration'] + "/Second Life.app", dst="") + +                if self.prefix(src="", dst="Contents"):  # everything goes in Contents +                        # Expand the tar file containing the assorted mozilla bits into +                        #  <bundle>/Contents/MacOS/ +                        self.contents_of_tar('mozilla-universal-darwin.tgz', 'MacOS') +#                       self.run_command('tar -zx -C "%(macos)s" -f "%(tarfile)s"' % +#                                                        {'macos':self.ensure_dst_dir("MacOS"), +#                                                         'tarfile':self.src_path_of("mozilla-universal-darwin.tgz")}) + +                        # replace the default theme with our custom theme (so scrollbars work). +                        if self.prefix(src="mozilla-theme", dst="MacOS/chrome"): +                                self.path("classic.jar") +                                self.path("classic.manifest") +                                self.end_prefix("MacOS/chrome") + +                        # most everything goes in the Resources directory +                        if self.prefix(src="", dst="Resources"): +                                super(DarwinManifest, self).construct() + +                                # the trial directory seems to be not used [rdw] +                                self.path('trial') + +                                if self.prefix("cursors_mac"): +                                        self.path("*.tif") +                                        self.end_prefix("cursors_mac") + +                                self.path("licenses-mac.txt", dst="licenses.txt") +                                self.path("featuretable_mac.txt") +                                self.path("secondlife.icns") + +                                # llkdu dynamic library +                                self.path("../../libraries/universal-darwin/lib_release/libllkdu.dylib", "libllkdu.dylib") + +                                # command line arguments for connecting to the proper grid +                                self.put_in_file(self.flags_list(), 'arguments.txt') + +                                # set the proper login url +                                self.replace_login_url() + +                                self.end_prefix("Resources") + +                        self.end_prefix("Contents") + + +        def package_finish(self): +                # NOTE: the -S argument to strip causes it to keep enough info for +                # annotated backtraces (i.e. function names in the crash log).  'strip' with no +                # arguments yields a slightly smaller binary but makes crash logs mostly useless. +                # This may be desirable for the final release.  Or not. +                self.run_command('strip -S "%(viewer_binary)s"' % +                                                 { 'viewer_binary' : self.dst_path_of('Contents/MacOS/Second Life')}) + +                self.create_unpacked() + +                imagename="SecondLife_" + '_'.join(self.args['version']) +                if(self.args['grid'] != ''): +                        imagename = imagename + '_' + self.args['grid'] + +                sparsename = imagename + ".sparseimage" +                finalname = imagename + ".dmg" +                # make sure we don't have stale files laying about +                self.remove(sparsename, finalname) + +                self.run_command('hdiutil create "%(sparse)s" -volname "Second Life" -fs HFS+ -type SPARSE -megabytes 200' % {'sparse':sparsename}) + +                # mount the image and get the name of the mount point and device node +                hdi_output = self.run_command('hdiutil attach -private "' + sparsename + '"') +                devfile = re.search("/dev/disk([0-9]+)[^s]", hdi_output).group(0).strip() +                volpath = re.search('HFS\s+(.+)', hdi_output).group(1).strip() + +                # Copy everything in to the mounted .dmg +                for s,d in {self.get_dst_prefix():("Second Life " + self.args['grid']).strip()+ ".app", +                                        "lsl_guide.html":"Linden Scripting Language Guide.html", +                                        "releasenotes.txt":"Release Notes.txt", +                                        "installers/darwin/mac_image_hidden":".hidden", +                                        "installers/darwin/mac_image_background.tga":"background.tga", +                                        "installers/darwin/mac_image_DS_Store":".DS_Store"}.items(): +                        print "Copying to dmg", s, d +                        self.copy_action(self.src_path_of(s), os.path.join(volpath, d)) + +                # Unmount the image +                self.run_command('hdiutil detach "' + devfile + '"') + +                print "Converting temp disk image to final disk image" +                self.run_command('hdiutil convert "%(sparse)s" -format UDZO -imagekey zlib-level=9 -o "%(final)s"' % {'sparse':sparsename, 'final':finalname}) +                # get rid of the temp file +                self.remove(sparsename) + +class LinuxManifest(ViewerManifest): +        def construct(self): +                super(LinuxManifest, self).construct() +                self.path("licenses-linux.txt","licenses.txt") +                self.path("res/ll_icon.ico","secondlife.ico") +                if self.prefix("linux_tools", ""): +                        self.path("client-readme.txt","README-linux.txt") +                        self.path("wrapper.sh","secondlife") +                        self.path("unicode.ttf","unicode.ttf") +                        self.end_prefix("linux_tools") + +                # Create an appropriate gridargs.dat for this package, denoting required grid. +                self.put_in_file(self.flags_list(), 'gridargs.dat') +                # set proper login url +                self.replace_login_url() + +        def package_finish(self): +                if(self.args.has_key('installer_name')): +                        installer_name = self.args['installer_name'] +                else: +                        installer_name = '_'.join('SecondLife_', self.args.get('arch'), *self.args['version']) +                        if grid != '': +                                installer_name += "_" + grid.upper() + +                # stripping all the libs removes a few megabytes from the end-user package +                for s,d in self.file_list: +                        if re.search("lib/lib.+\.so.*", d): +                                self.run_command('strip -S %s' % d) +                self.create_unpacked() +                # temporarily move directory tree so that it has the right name in the tarfile +                self.run_command("mv %(dst)s %(inst)s" % {'dst':self.get_dst_prefix(),'inst':self.src_path_of(installer_name)}) +                # --numeric-owner hides the username of the builder for security etc. +                self.run_command('tar -C %(dir)s --numeric-owner -cjf %(inst_path)s.tar.bz2 %(inst_name)s' % {'dir':self.get_src_prefix(), 'inst_name': installer_name, 'inst_path':self.src_path_of(installer_name)}) +                self.run_command("mv %(inst)s %(dst)s" % {'dst':self.get_dst_prefix(),'inst':self.src_path_of(installer_name)}) + +class Linux_i686Manifest(LinuxManifest): +        def construct(self): +                super(Linux_i686Manifest, self).construct() +                self.path("secondlife-i686-bin-stripped","bin/do-not-directly-run-secondlife-bin") +                self.path("../linux_crash_logger/linux-crash-logger-i686-bin-stripped","linux-crash-logger.bin") +                self.path("linux_tools/launch_url.sh","launch_url.sh") +                if self.prefix("res-sdl"): +                        self.path("*") +                        # recurse +                        self.end_prefix("res-sdl") + +                self.path("app_settings/mozilla-runtime-linux-i686", "app_settings/mozilla") + +                if self.prefix("../../libraries/i686-linux/lib_release_client", "lib"): +                        self.path("libkdu_v42R.so") +                        self.path("libfmod-3.75.so") +                        self.path("libapr-1.so.0") +                        self.path("libaprutil-1.so.0") +                        self.path("libdb-4.2.so") +                        self.path("libogg.so.0") +                        self.path("libvorbis.so.0") +                        self.path("libvorbisfile.so.0") +                        self.path("libvorbisenc.so.0") +                        self.path("libcurl.so.3") +                        self.path("libcrypto.so.0.9.7") +                        self.path("libssl.so.0.9.7") +                        self.path("libexpat.so.1") +                        self.path("libstdc++.so.6") +                        self.path("libelfio.so") +                        self.path("libuuid.so", "libuuid.so.1") +                        self.path("libSDL-1.2.so.0") +                        self.path("libllkdu.so", "../bin/libllkdu.so") # llkdu goes in bin for some reason +                        self.end_prefix("lib") + + +class Linux_x86_64Manifest(LinuxManifest): +        def construct(self): +                super(Linux_x86_64Manifest, self).construct() +                self.path("secondlife-x86_64-bin-stripped","bin/secondlife-bin") +                # TODO: I get the sense that this isn't fully fleshed out +                if self.prefix("../../libraries/x86_64-linux/lib_release_client", "lib"): +                        self.path("libkdu_v42R.so") +                        self.path("libxmlrpc.so.0") +                        # self.path("libllkdu.so", "../bin/libllkdu.so") # llkdu goes in bin for some reason +                        self.end_prefix("lib") + + +if __name__ == "__main__": +        main(srctree=viewer_dir, dsttree=os.path.join(viewer_dir, "packaged")) diff --git a/indra/test/test_llmanifest.py b/indra/test/test_llmanifest.py new file mode 100644 index 0000000000..cc464237a2 --- /dev/null +++ b/indra/test/test_llmanifest.py @@ -0,0 +1,109 @@ +#!/usr/bin/python +# @file test_llmanifest.py +# @author Ryan Williams +# @brief Test cases for LLManifest library. +# +# Copyright (c) 2006-$CurrentYear$, Linden Research, Inc. +# $License$ + +from indra import llmanifest +import os.path +import os +import unittest + +class DemoManifest(llmanifest.LLManifest): +    def construct(self): +        super(DemoManifest, self).construct() +        if self.prefix("dir_1"): +            self.path("test_a") +            self.path(src="test_b", dst="test_dst_b") +            self.path("*.test") +            self.path("*.tex", "*.jpg") +            if self.prefix("nested", dst=""): +                self.path("deep") +                self.end_prefix() +            self.end_prefix("dir_1") + + +class Demo_ArchManifest(llmanifest.LLManifest): +        pass + +class TestLLManifest(unittest.TestCase): +    mode='static' +    def setUp(self): +        self.m = llmanifest.LLManifest("src", "dst", {'grid':'default', 'platform':'darwin', 'version':(1,2,3,4)}) + +    def testproperwindowspath(self): +        self.assertEqual(llmanifest.proper_windows_path("C:\Program Files", "cygwin"),"/cygdrive/c/Program Files") +        self.assertEqual(llmanifest.proper_windows_path("C:\Program Files", "windows"), "C:\Program Files") +        self.assertEqual(llmanifest.proper_windows_path("/cygdrive/c/Program Files/NSIS", "windows"), "C:\Program Files\NSIS") +        self.assertEqual(llmanifest.proper_windows_path("/cygdrive/c/Program Files/NSIS", "cygwin"), "/cygdrive/c/Program Files/NSIS") + +    def testpathancestors(self): +        self.assertEqual(["dir"], [p for p in llmanifest.path_ancestors("dir")]) +        self.assertEqual(["dir/sub", "dir"], [p for p in llmanifest.path_ancestors("dir/sub")]) +        self.assertEqual(["dir/sub", "dir"], [p for p in llmanifest.path_ancestors("dir/sub/")]) +        self.assertEqual(["dir/sub/two", "dir/sub", "dir"], [p for p in llmanifest.path_ancestors("dir/sub/two")]) + + +    def testforplatform(self): +        self.assertEqual(llmanifest.LLManifest.for_platform('demo'), DemoManifest) +        def tmp_test(): +            return llmanifest.LLManifest.for_platform('extant') +        self.assertRaises(KeyError, tmp_test) +        ExtantManifest = llmanifest.LLManifestRegistry('ExtantManifest', (llmanifest.LLManifest,), {}) +        self.assertEqual(llmanifest.LLManifest.for_platform('extant'), ExtantManifest) +        self.assertEqual(llmanifest.LLManifest.for_platform('demo', 'Arch'), Demo_ArchManifest) + + +    def testprefix(self): +        self.assertEqual(self.m.get_src_prefix(), "src") +        self.assertEqual(self.m.get_dst_prefix(), "dst") +        self.m.prefix("level1") +        self.assertEqual(self.m.get_src_prefix(), "src/level1") +        self.assertEqual(self.m.get_dst_prefix(), "dst/level1") +        self.m.end_prefix() +        self.m.prefix(src="src", dst="dst") +        self.assertEqual(self.m.get_src_prefix(), "src/src") +        self.assertEqual(self.m.get_dst_prefix(), "dst/dst") +        self.m.end_prefix() + +    def testendprefix(self): +        self.assertEqual(self.m.get_src_prefix(), "src") +        self.assertEqual(self.m.get_dst_prefix(), "dst") +        self.m.prefix("levela") +        self.m.end_prefix() +        self.assertEqual(self.m.get_src_prefix(), "src") +        self.assertEqual(self.m.get_dst_prefix(), "dst") +        self.m.prefix("level1") +        self.m.end_prefix("level1") +        self.assertEqual(self.m.get_src_prefix(), "src") +        self.assertEqual(self.m.get_dst_prefix(), "dst") +        self.m.prefix("level1") +        def tmp_test(): +            self.m.end_prefix("mismatch") +        self.assertRaises(ValueError, tmp_test) + +    def testruncommand(self): +        self.assertEqual("Hello\n", self.m.run_command("echo Hello")) +        def tmp_test(): +            self.m.run_command("fff_garbage") +        self.assertRaises(RuntimeError, tmp_test) + +    def testpathof(self): +        self.assertEqual(self.m.src_path_of("a"), "src/a") +        self.assertEqual(self.m.dst_path_of("a"), "dst/a") +        self.m.prefix("tmp") +        self.assertEqual(self.m.src_path_of("b/c"), "src/tmp/b/c") +        self.assertEqual(self.m.dst_path_of("b/c"), "dst/tmp/b/c") + +    def testcmakedirs(self): +        self.m.cmakedirs("test_dir_DELETE/nested/dir") +        self.assert_(os.path.exists("test_dir_DELETE/nested/dir")) +        self.assert_(os.path.isdir("test_dir_DELETE")) +        self.assert_(os.path.isdir("test_dir_DELETE/nested")) +        self.assert_(os.path.isdir("test_dir_DELETE/nested/dir")) +        os.removedirs("test_dir_DELETE/nested/dir") + +if __name__ == '__main__': +    unittest.main() | 
