From a4000c3744e42fcbb638e742f3b63fa31a0dee15 Mon Sep 17 00:00:00 2001 From: Steven Bennetts Date: Fri, 8 May 2009 07:43:08 +0000 Subject: merge trunk@116587 skinning-7@119389 -> viewer-2.0.0-skinning-7 --- indra/newview/viewer_manifest.py | 1 + 1 file changed, 1 insertion(+) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 599882500c..583dba4fd9 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -84,6 +84,7 @@ class ViewerManifest(LLManifest): self.path("textures.xml") self.end_prefix("*/textures") self.path("*/xui/*/*.xml") + self.path("*/xui/*/widgets/*.xml") self.path("*/*.xml") # Local HTML files (e.g. loading screen) -- cgit v1.2.3 From 31cdebe2010a43d9158aec236cc3f5275819352c Mon Sep 17 00:00:00 2001 From: brad kittenbrink Date: Tue, 7 Jul 2009 16:04:23 -0700 Subject: Added copying and packaging of apr dlls and llcommon.dll. --- indra/newview/viewer_manifest.py | 1436 +++++++++++++++++++------------------- 1 file changed, 725 insertions(+), 711 deletions(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 2838ff6335..7edf0bad6b 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1,711 +1,725 @@ -#!/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. -# -# $LicenseInfo:firstyear=2006&license=viewergpl$ -# -# Copyright (c) 2006-2009, Linden Research, Inc. -# -# Second Life Viewer Source Code -# The source code in this file ("Source Code") is provided by Linden Lab -# to you under the terms of the GNU General Public License, version 2.0 -# ("GPL"), unless you have obtained a separate licensing agreement -# ("Other License"), formally executed by you and Linden Lab. Terms of -# the GPL can be found in doc/GPL-license.txt in this distribution, or -# online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 -# -# There are special exceptions to the terms and conditions of the GPL as -# it is applied to this Source Code. View the full text of the exception -# in the file doc/FLOSS-exception.txt in this software distribution, or -# online at -# http://secondlifegrid.net/programs/open_source/licensing/flossexception -# -# By copying, modifying or distributing this software, you acknowledge -# that you have read and understood your obligations described above, -# and agree to abide by those obligations. -# -# ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO -# WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -# COMPLETENESS OR PERFORMANCE. -# $/LicenseInfo$ -import sys -import os.path -import re -import tarfile -viewer_dir = os.path.dirname(__file__) -# add llmanifest library to our path so we don't have to muck with PYTHONPATH -sys.path.append(os.path.join(viewer_dir, '../lib/python/indra/util')) -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") - self.path(src="../../etc/message.xml", dst="app_settings/message.xml") - - 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("*.db2") - - # include the entire shaders directory recursively - self.path("shaders") - # ... and the entire windlight directory - self.path("windlight") - 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") - - # skins - if self.prefix(src="skins"): - self.path("paths.xml") - # include the entire textures directory recursively - if self.prefix(src="*/textures"): - self.path("*.tga") - self.path("*.j2c") - self.path("*.jpg") - self.path("*.png") - self.path("textures.xml") - self.end_prefix("*/textures") - self.path("*/xui/*/*.xml") - self.path("*/xui/*/widgets/*.xml") - self.path("*/*.xml") - - # Local HTML files (e.g. loading screen) - if self.prefix(src="*/html"): - self.path("*.png") - self.path("*/*/*.html") - self.path("*/*/*.gif") - self.end_prefix("*/html") - self.end_prefix("skins") - - # Files in the newview/ directory - self.path("gpu_table.txt") - - def login_channel(self): - """Channel reported for login and upgrade purposes ONLY; - used for A/B testing""" - # NOTE: Do not return the normal channel if login_channel - # is not specified, as some code may branch depending on - # whether or not this is present - return self.args.get('login_channel') - - def grid(self): - return self.args['grid'] - def channel(self): - return self.args['channel'] - def channel_unique(self): - return self.channel().replace("Second Life", "").strip() - def channel_oneword(self): - return "".join(self.channel_unique().split()) - def channel_lowerword(self): - return self.channel_oneword().lower() - - def flags_list(self): - """ Convenience function that returns the command-line flags - for the grid""" - - # Set command line flags relating to the target grid - grid_flags = '' - if not self.default_grid(): - grid_flags = "--grid %(grid)s "\ - "--helperuri http://preview-%(grid)s.secondlife.com/helpers/" %\ - {'grid':self.grid()} - - # set command line flags for channel - channel_flags = '' - if self.login_channel() and self.login_channel() != self.channel(): - # Report a special channel during login, but use default - channel_flags = '--channel "%s"' % (self.login_channel()) - elif not self.default_channel(): - channel_flags = '--channel "%s"' % self.channel() - - # Deal with settings - setting_flags = '' - if not self.default_channel() or not self.default_grid(): - if self.default_grid(): - setting_flags = '--settings settings_%s.xml'\ - % self.channel_lowerword() - else: - setting_flags = '--settings settings_%s_%s.xml'\ - % (self.grid(), self.channel_lowerword()) - - return " ".join((channel_flags, grid_flags, setting_flags)).strip() - - -class WindowsManifest(ViewerManifest): - def final_exe(self): - if self.default_channel(): - if self.default_grid(): - return "SecondLife.exe" - else: - return "SecondLifePreview.exe" - else: - return ''.join(self.channel().split()) + '.exe' - - - 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('debug/secondlife-bin.exe', 'release/secondlife-bin.exe', 'relwithdebinfo/secondlife-bin.exe'), dst=self.final_exe()) - # need to get the kdu dll from any of the build directories as well - try: - self.path(self.find_existing_file('../llkdu/%s/llkdu.dll' % self.args['configuration'], - '../../libraries/i686-win32/lib/release/llkdu.dll'), - dst='llkdu.dll') - pass - except: - print "Skipping llkdu.dll" - pass - self.path(src="licenses-win32.txt", dst="licenses.txt") - - self.path("featuretable.txt") - - # For use in crash reporting (generates minidumps) - self.path("dbghelp.dll") - - # For using FMOD for sound... DJS - self.path("fmod.dll") - - # For textures - if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): - self.path("openjpeg.dll") - self.end_prefix() - - # Mozilla appears to force a dependency on these files so we need to ship it (CP) - updated to vc8 versions (nyx) - # These need to be installed as a SxS assembly, currently a 'private' assembly. - # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx - if self.prefix(src=self.args['configuration'], dst=""): - if self.args['configuration'] == 'Debug': - self.path("msvcr80d.dll") - self.path("msvcp80d.dll") - self.path("Microsoft.VC80.DebugCRT.manifest") - else: - self.path("msvcr80.dll") - self.path("msvcp80.dll") - self.path("Microsoft.VC80.CRT.manifest") - self.end_prefix() - - # Mozilla runtime DLLs (CP) - if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): - self.path("freebl3.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() - - # Mozilla hack to get it to accept newer versions of msvc*80.dll than are listed in manifest - # necessary as llmozlib2-vc80.lib refers to an old version of msvc*80.dll - can be removed when new version of llmozlib is built - Nyx - # The config file name needs to match the exe's name. - self.path("SecondLife.exe.config", dst=self.final_exe() + ".config") - - # Vivox runtimes - if self.prefix(src="vivox-runtime/i686-win32", dst=""): - self.path("SLVoice.exe") - self.path("alut.dll") - self.path("vivoxsdk.dll") - self.path("ortp.dll") - self.path("wrap_oal.dll") - self.end_prefix() - - # pull in the crash logger and updater from other projects - self.path(src=self.find_existing_file( # tag:"crash-logger" here as a cue to the exporter - "../win_crash_logger/debug/windows-crash-logger.exe", - "../win_crash_logger/release/windows-crash-logger.exe", - "../win_crash_logger/relwithdebinfo/windows-crash-logger.exe"), - dst="win_crash_logger.exe") - self.path(src=self.find_existing_file( - "../win_updater/debug/windows-updater.exe", - "../win_updater/release/windows-updater.exe", - "../win_updater/relwithdebinfo/windows-updater.exe"), - dst="updater.exe") - - # For google-perftools tcmalloc allocator. - if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): - self.path("libtcmalloc_minimal.dll") - self.end_prefix() - - - 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): - # a standard map of strings for replacing in the templates - substitution_strings = { - 'version' : '.'.join(self.args['version']), - 'version_short' : '.'.join(self.args['version'][:-1]), - 'version_dashes' : '-'.join(self.args['version']), - 'final_exe' : self.final_exe(), - 'grid':self.args['grid'], - 'grid_caps':self.args['grid'].upper(), - # escape quotes becase NSIS doesn't handle them well - 'flags':self.flags_list().replace('"', '$\\"'), - 'channel':self.channel(), - 'channel_oneword':self.channel_oneword(), - 'channel_unique':self.channel_unique(), - } - - version_vars = """ - !define INSTEXE "%(final_exe)s" - !define VERSION "%(version_short)s" - !define VERSION_LONG "%(version)s" - !define VERSION_DASHES "%(version_dashes)s" - """ % substitution_strings - if self.default_channel(): - if self.default_grid(): - # release viewer - installer_file = "Second_Life_%(version_dashes)s_Setup.exe" - grid_vars_template = """ - OutFile "%(installer_file)s" - !define INSTFLAGS "%(flags)s" - !define INSTNAME "SecondLife" - !define SHORTCUT "Second Life" - !define URLNAME "secondlife" - Caption "Second Life ${VERSION}" - """ - else: - # beta grid viewer - installer_file = "Second_Life_%(version_dashes)s_(%(grid_caps)s)_Setup.exe" - grid_vars_template = """ - OutFile "%(installer_file)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}" - """ - else: - # some other channel on some grid - installer_file = "Second_Life_%(version_dashes)s_%(channel_oneword)s_Setup.exe" - grid_vars_template = """ - OutFile "%(installer_file)s" - !define INSTFLAGS "%(flags)s" - !define INSTNAME "SecondLife%(channel_oneword)s" - !define SHORTCUT "%(channel)s" - !define URLNAME "secondlife" - !define UNINSTALL_SETTINGS 1 - Caption "%(channel)s ${VERSION}" - """ - if 'installer_name' in self.args: - installer_file = self.args['installer_name'] - else: - installer_file = installer_file % substitution_strings - substitution_strings['installer_file'] = installer_file - - tempfile = "secondlife_setup_tmp.nsi" - # the following replaces strings in the nsi template - # it also does python-style % substitution - self.replace_in("installers/windows/installer_template.nsi", tempfile, { - "%%VERSION%%":version_vars, - "%%SOURCE%%":self.get_src_prefix(), - "%%GRID_VARS%%":grid_vars_template % substitution_strings, - "%%INSTALL_FILES%%":self.nsi_file_commands(True), - "%%DELETE_FILES%%":self.nsi_file_commands(False)}) - - # We use the Unicode version of NSIS, available from - # http://www.scratchpaper.com/ - NSIS_path = 'C:\\Program Files\\NSIS\\Unicode\\makensis.exe' - self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile)) - # self.remove(self.dst_path_of(tempfile)) - # If we're on a build machine, sign the code using our Authenticode certificate. JC - sign_py = 'C:\\buildscripts\\code-signing\\sign.py' - if os.path.exists(sign_py): - self.run_command(sign_py + ' ' + self.dst_path_of(installer_file)) - else: - print "Skipping code signing,", sign_py, "does not exist" - self.created_path(self.dst_path_of(installer_file)) - self.package_file = 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(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 - # /Contents/MacOS/ - self.contents_of_tar(self.args['source']+'/mozilla-universal-darwin.tgz', 'MacOS') - - self.path("Info-SecondLife.plist", dst="Info.plist") - - # copy additional libs in /Contents/MacOS/ - self.path("../../libraries/universal-darwin/lib_release/libndofdev.dylib", dst="MacOS/libndofdev.dylib") - - # 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() - - 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.nib") - - # If we are not using the default channel, use the 'Firstlook - # icon' to show that it isn't a stable release. - if self.default_channel() and self.default_grid(): - self.path("secondlife.icns") - else: - self.path("secondlife_firstlook.icns", "secondlife.icns") - self.path("SecondLife.nib") - - # Translations - self.path("English.lproj") - self.path("German.lproj") - self.path("Japanese.lproj") - self.path("Korean.lproj") - self.path("da.lproj") - self.path("es.lproj") - self.path("fr.lproj") - self.path("hu.lproj") - self.path("it.lproj") - self.path("nl.lproj") - self.path("pl.lproj") - self.path("pt.lproj") - self.path("ru.lproj") - self.path("tr.lproj") - self.path("uk.lproj") - self.path("zh-Hans.lproj") - - # SLVoice and vivox lols - self.path("vivox-runtime/universal-darwin/libalut.dylib", "libalut.dylib") - self.path("vivox-runtime/universal-darwin/libopenal.dylib", "libopenal.dylib") - self.path("vivox-runtime/universal-darwin/libortp.dylib", "libortp.dylib") - self.path("vivox-runtime/universal-darwin/libvivoxsdk.dylib", "libvivoxsdk.dylib") - self.path("vivox-runtime/universal-darwin/SLVoice", "SLVoice") - - # need to get the kdu dll from any of the build directories as well - try: - self.path(self.find_existing_file('../llkdu/%s/libllkdu.dylib' % self.args['configuration'], - "../../libraries/universal-darwin/lib_release/libllkdu.dylib"), - dst='libllkdu.dylib') - pass - except: - print "Skipping libllkdu.dylib" - pass - - #libfmodwrapper.dylib - self.path(self.args['configuration'] + "/libfmodwrapper.dylib", "libfmodwrapper.dylib") - - # our apps - self.path("../mac_crash_logger/" + self.args['configuration'] + "/mac-crash-logger.app", "mac-crash-logger.app") - self.path("../mac_updater/" + self.args['configuration'] + "/mac-updater.app", "mac-updater.app") - - # command line arguments for connecting to the proper grid - self.put_in_file(self.flags_list(), 'arguments.txt') - - self.end_prefix("Resources") - - self.end_prefix("Contents") - - # 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. - if ("package" in self.args['actions'] or - "unpacked" in self.args['actions']): - self.run_command('strip -S "%(viewer_binary)s"' % - { 'viewer_binary' : self.dst_path_of('Contents/MacOS/Second Life')}) - - - def package_finish(self): - channel_standin = 'Second Life' # hah, our default channel is not usable on its own - if not self.default_channel(): - channel_standin = self.channel() - - imagename="SecondLife_" + '_'.join(self.args['version']) - - # MBW -- If the mounted volume name changes, it breaks the .DS_Store's background image and icon positioning. - # If we really need differently named volumes, we'll need to create multiple DS_Store file images, or use some other trick. - - volname="Second Life Installer" # DO NOT CHANGE without understanding comment above - - if self.default_channel(): - if not self.default_grid(): - # beta case - imagename = imagename + '_' + self.args['grid'].upper() - else: - # first look, etc - imagename = imagename + '_' + self.channel_oneword().upper() - - 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 "%(vol)s" -fs HFS+ -type SPARSE -megabytes 300 -layout SPUD' % { - 'sparse':sparsename, - 'vol':volname}) - - # 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 - - if self.default_channel() and not self.default_grid(): - app_name = "Second Life " + self.args['grid'] - else: - app_name = channel_standin.strip() - - # Hack: - # Because there is no easy way to coerce the Finder into positioning - # the app bundle in the same place with different app names, we are - # adding multiple .DS_Store files to svn. There is one for release, - # one for release candidate and one for first look. Any other channels - # will use the release .DS_Store, and will look broken. - # - Ambroff 2008-08-20 - dmg_template = os.path.join( - 'installers', - 'darwin', - '%s-dmg' % "".join(self.channel_unique().split()).lower()) - - if not os.path.exists (self.src_path_of(dmg_template)): - dmg_template = os.path.join ('installers', 'darwin', 'release-dmg') - - for s,d in {self.get_dst_prefix():app_name + ".app", - os.path.join(dmg_template, "_VolumeIcon.icns"): ".VolumeIcon.icns", - os.path.join(dmg_template, "background.jpg"): "background.jpg", - os.path.join(dmg_template, "_DS_Store"): ".DS_Store"}.items(): - print "Copying to dmg", s, d - self.copy_action(self.src_path_of(s), os.path.join(volpath, d)) - - # Hide the background image, DS_Store file, and volume icon file (set their "visible" bit) - self.run_command('SetFile -a V "' + os.path.join(volpath, ".VolumeIcon.icns") + '"') - self.run_command('SetFile -a V "' + os.path.join(volpath, "background.jpg") + '"') - self.run_command('SetFile -a V "' + os.path.join(volpath, ".DS_Store") + '"') - - # Create the alias file (which is a resource file) from the .r - self.run_command('rez "' + self.src_path_of("installers/darwin/release-dmg/Applications-alias.r") + '" -o "' + os.path.join(volpath, "Applications") + '"') - - # Set the alias file's alias and custom icon bits - self.run_command('SetFile -a AC "' + os.path.join(volpath, "Applications") + '"') - - # Set the disk image root's custom icon bit - self.run_command('SetFile -a C "' + volpath + '"') - - # Unmount the image - self.run_command('hdiutil detach -force "' + 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.package_file = finalname - 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.png","secondlife_icon.png") - if self.prefix("linux_tools", dst=""): - self.path("client-readme.txt","README-linux.txt") - self.path("client-readme-voice.txt","README-linux-voice.txt") - self.path("client-readme-joystick.txt","README-linux-joystick.txt") - self.path("wrapper.sh","secondlife") - self.path("handle_secondlifeprotocol.sh") - self.path("register_secondlifeprotocol.sh") - 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') - - - def package_finish(self): - if 'installer_name' in self.args: - installer_name = self.args['installer_name'] - else: - installer_name_components = ['SecondLife_', self.args.get('arch')] - installer_name_components.extend(self.args['version']) - installer_name = "_".join(installer_name_components) - if self.default_channel(): - if not self.default_grid(): - installer_name += '_' + self.args['grid'].upper() - else: - installer_name += '_' + self.channel_oneword().upper() - - # Fix access permissions - self.run_command(""" - find %(dst)s -type d | xargs --no-run-if-empty chmod 755; - find %(dst)s -type f -perm 0700 | xargs --no-run-if-empty chmod 0755; - find %(dst)s -type f -perm 0500 | xargs --no-run-if-empty chmod 0555; - find %(dst)s -type f -perm 0600 | xargs --no-run-if-empty chmod 0644; - find %(dst)s -type f -perm 0400 | xargs --no-run-if-empty chmod 0444; - true""" % {'dst':self.get_dst_prefix() }) - self.package_file = installer_name + '.tar.bz2' - - # 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.build_path_of(installer_name)}) - try: - # --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_build_prefix(), - 'inst_name': installer_name, - 'inst_path':self.build_path_of(installer_name)}) - finally: - self.run_command("mv %(inst)s %(dst)s" % { - 'dst': self.get_dst_prefix(), - 'inst': self.build_path_of(installer_name)}) - -class Linux_i686Manifest(LinuxManifest): - def construct(self): - super(Linux_i686Manifest, self).construct() - - # install either the libllkdu we just built, or a prebuilt one, in - # decreasing order of preference. for linux package, this goes to bin/ - try: - self.path(self.find_existing_file('../llkdu/libllkdu.so', - '../../libraries/i686-linux/lib_release_client/libllkdu.so'), - dst='bin/libllkdu.so') - # keep this one to preserve syntax, open source mangling removes previous lines - pass - except: - print "Skipping libllkdu.so - not found" - pass - - self.path("secondlife-stripped","bin/do-not-directly-run-secondlife-bin") - self.path("../linux_crash_logger/linux-crash-logger-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("featuretable_linux.txt") - #self.path("secondlife-i686.supp") - - self.path("app_settings/mozilla-runtime-linux-i686") - - if self.prefix("../../libraries/i686-linux/lib_release_client", dst="lib"): - #self.path("libkdu_v42R.so", "libkdu.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("libcrypto.so.0.9.7") - self.path("libexpat.so.1") - self.path("libssl.so.0.9.7") - self.path("libuuid.so", "libuuid.so.1") - self.path("libSDL-1.2.so.0") - self.path("libELFIO.so") - self.path("libopenjpeg.so.1.3.0", "libopenjpeg.so.1.3") - self.path("libalut.so") - self.path("libopenal.so", "libopenal.so.1") - self.end_prefix("lib") - - # Vivox runtimes - if self.prefix(src="vivox-runtime/i686-linux", dst="bin"): - self.path("SLVoice") - self.end_prefix() - if self.prefix(src="vivox-runtime/i686-linux", dst="lib"): - self.path("libortp.so") - self.path("libvivoxsdk.so") - self.end_prefix("lib") - -class Linux_x86_64Manifest(LinuxManifest): - def construct(self): - super(Linux_x86_64Manifest, self).construct() - self.path("secondlife-stripped","bin/do-not-directly-run-secondlife-bin") - self.path("../linux_crash_logger/linux-crash-logger-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("featuretable_linux.txt") - self.path("secondlife-i686.supp") - -if __name__ == "__main__": - main() +#!/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. +# +# $LicenseInfo:firstyear=2006&license=viewergpl$ +# +# Copyright (c) 2006-2009, Linden Research, Inc. +# +# Second Life Viewer Source Code +# The source code in this file ("Source Code") is provided by Linden Lab +# to you under the terms of the GNU General Public License, version 2.0 +# ("GPL"), unless you have obtained a separate licensing agreement +# ("Other License"), formally executed by you and Linden Lab. Terms of +# the GPL can be found in doc/GPL-license.txt in this distribution, or +# online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +# +# There are special exceptions to the terms and conditions of the GPL as +# it is applied to this Source Code. View the full text of the exception +# in the file doc/FLOSS-exception.txt in this software distribution, or +# online at +# http://secondlifegrid.net/programs/open_source/licensing/flossexception +# +# By copying, modifying or distributing this software, you acknowledge +# that you have read and understood your obligations described above, +# and agree to abide by those obligations. +# +# ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +# WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +# COMPLETENESS OR PERFORMANCE. +# $/LicenseInfo$ +import sys +import os.path +import re +import tarfile +viewer_dir = os.path.dirname(__file__) +# add llmanifest library to our path so we don't have to muck with PYTHONPATH +sys.path.append(os.path.join(viewer_dir, '../lib/python/indra/util')) +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") + self.path(src="../../etc/message.xml", dst="app_settings/message.xml") + + 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("*.db2") + + # include the entire shaders directory recursively + self.path("shaders") + # ... and the entire windlight directory + self.path("windlight") + 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") + + # skins + if self.prefix(src="skins"): + self.path("paths.xml") + # include the entire textures directory recursively + if self.prefix(src="*/textures"): + self.path("*.tga") + self.path("*.j2c") + self.path("*.jpg") + self.path("*.png") + self.path("textures.xml") + self.end_prefix("*/textures") + self.path("*/xui/*/*.xml") + self.path("*/xui/*/widgets/*.xml") + self.path("*/*.xml") + + # Local HTML files (e.g. loading screen) + if self.prefix(src="*/html"): + self.path("*.png") + self.path("*/*/*.html") + self.path("*/*/*.gif") + self.end_prefix("*/html") + self.end_prefix("skins") + + # Files in the newview/ directory + self.path("gpu_table.txt") + + def login_channel(self): + """Channel reported for login and upgrade purposes ONLY; + used for A/B testing""" + # NOTE: Do not return the normal channel if login_channel + # is not specified, as some code may branch depending on + # whether or not this is present + return self.args.get('login_channel') + + def grid(self): + return self.args['grid'] + def channel(self): + return self.args['channel'] + def channel_unique(self): + return self.channel().replace("Second Life", "").strip() + def channel_oneword(self): + return "".join(self.channel_unique().split()) + def channel_lowerword(self): + return self.channel_oneword().lower() + + def flags_list(self): + """ Convenience function that returns the command-line flags + for the grid""" + + # Set command line flags relating to the target grid + grid_flags = '' + if not self.default_grid(): + grid_flags = "--grid %(grid)s "\ + "--helperuri http://preview-%(grid)s.secondlife.com/helpers/" %\ + {'grid':self.grid()} + + # set command line flags for channel + channel_flags = '' + if self.login_channel() and self.login_channel() != self.channel(): + # Report a special channel during login, but use default + channel_flags = '--channel "%s"' % (self.login_channel()) + elif not self.default_channel(): + channel_flags = '--channel "%s"' % self.channel() + + # Deal with settings + setting_flags = '' + if not self.default_channel() or not self.default_grid(): + if self.default_grid(): + setting_flags = '--settings settings_%s.xml'\ + % self.channel_lowerword() + else: + setting_flags = '--settings settings_%s_%s.xml'\ + % (self.grid(), self.channel_lowerword()) + + return " ".join((channel_flags, grid_flags, setting_flags)).strip() + + +class WindowsManifest(ViewerManifest): + def final_exe(self): + if self.default_channel(): + if self.default_grid(): + return "SecondLife.exe" + else: + return "SecondLifePreview.exe" + else: + return ''.join(self.channel().split()) + '.exe' + + + 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('debug/secondlife-bin.exe', 'release/secondlife-bin.exe', 'relwithdebinfo/secondlife-bin.exe'), dst=self.final_exe()) + + # need to get the llcommon.dll from any of the build directories as well + try: + self.path(self.find_existing_file('../llcommon/%s/llcommon.dll' % self.args['configuration']), + dst='llcommon.dll') + if self.prefix(src=self.args['configuration'], dst=""): + self.path('libapr-1.dll') + self.path('libaprutil-1.dll') + self.path('libapriconv-1.dll') + self.end_prefix() + except: + print "Skipping llcommon.dll (assuming llcommon was linked statically)" + pass + + # need to get the kdu dll from any of the build directories as well + try: + self.path(self.find_existing_file('../llkdu/%s/llkdu.dll' % self.args['configuration'], + '../../libraries/i686-win32/lib/release/llkdu.dll'), + dst='llkdu.dll') + pass + except: + print "Skipping llkdu.dll" + pass + self.path(src="licenses-win32.txt", dst="licenses.txt") + + self.path("featuretable.txt") + + # For use in crash reporting (generates minidumps) + self.path("dbghelp.dll") + + # For using FMOD for sound... DJS + self.path("fmod.dll") + + # For textures + if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): + self.path("openjpeg.dll") + self.end_prefix() + + # Mozilla appears to force a dependency on these files so we need to ship it (CP) - updated to vc8 versions (nyx) + # These need to be installed as a SxS assembly, currently a 'private' assembly. + # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx + if self.prefix(src=self.args['configuration'], dst=""): + if self.args['configuration'] == 'Debug': + self.path("msvcr80d.dll") + self.path("msvcp80d.dll") + self.path("Microsoft.VC80.DebugCRT.manifest") + else: + self.path("msvcr80.dll") + self.path("msvcp80.dll") + self.path("Microsoft.VC80.CRT.manifest") + self.end_prefix() + + # Mozilla runtime DLLs (CP) + if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): + self.path("freebl3.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() + + # Mozilla hack to get it to accept newer versions of msvc*80.dll than are listed in manifest + # necessary as llmozlib2-vc80.lib refers to an old version of msvc*80.dll - can be removed when new version of llmozlib is built - Nyx + # The config file name needs to match the exe's name. + self.path("SecondLife.exe.config", dst=self.final_exe() + ".config") + + # Vivox runtimes + if self.prefix(src="vivox-runtime/i686-win32", dst=""): + self.path("SLVoice.exe") + self.path("alut.dll") + self.path("vivoxsdk.dll") + self.path("ortp.dll") + self.path("wrap_oal.dll") + self.end_prefix() + + # pull in the crash logger and updater from other projects + self.path(src=self.find_existing_file( # tag:"crash-logger" here as a cue to the exporter + "../win_crash_logger/debug/windows-crash-logger.exe", + "../win_crash_logger/release/windows-crash-logger.exe", + "../win_crash_logger/relwithdebinfo/windows-crash-logger.exe"), + dst="win_crash_logger.exe") + self.path(src=self.find_existing_file( + "../win_updater/debug/windows-updater.exe", + "../win_updater/release/windows-updater.exe", + "../win_updater/relwithdebinfo/windows-updater.exe"), + dst="updater.exe") + + # For google-perftools tcmalloc allocator. + if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): + self.path("libtcmalloc_minimal.dll") + self.end_prefix() + + + 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): + # a standard map of strings for replacing in the templates + substitution_strings = { + 'version' : '.'.join(self.args['version']), + 'version_short' : '.'.join(self.args['version'][:-1]), + 'version_dashes' : '-'.join(self.args['version']), + 'final_exe' : self.final_exe(), + 'grid':self.args['grid'], + 'grid_caps':self.args['grid'].upper(), + # escape quotes becase NSIS doesn't handle them well + 'flags':self.flags_list().replace('"', '$\\"'), + 'channel':self.channel(), + 'channel_oneword':self.channel_oneword(), + 'channel_unique':self.channel_unique(), + } + + version_vars = """ + !define INSTEXE "%(final_exe)s" + !define VERSION "%(version_short)s" + !define VERSION_LONG "%(version)s" + !define VERSION_DASHES "%(version_dashes)s" + """ % substitution_strings + if self.default_channel(): + if self.default_grid(): + # release viewer + installer_file = "Second_Life_%(version_dashes)s_Setup.exe" + grid_vars_template = """ + OutFile "%(installer_file)s" + !define INSTFLAGS "%(flags)s" + !define INSTNAME "SecondLife" + !define SHORTCUT "Second Life" + !define URLNAME "secondlife" + Caption "Second Life ${VERSION}" + """ + else: + # beta grid viewer + installer_file = "Second_Life_%(version_dashes)s_(%(grid_caps)s)_Setup.exe" + grid_vars_template = """ + OutFile "%(installer_file)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}" + """ + else: + # some other channel on some grid + installer_file = "Second_Life_%(version_dashes)s_%(channel_oneword)s_Setup.exe" + grid_vars_template = """ + OutFile "%(installer_file)s" + !define INSTFLAGS "%(flags)s" + !define INSTNAME "SecondLife%(channel_oneword)s" + !define SHORTCUT "%(channel)s" + !define URLNAME "secondlife" + !define UNINSTALL_SETTINGS 1 + Caption "%(channel)s ${VERSION}" + """ + if 'installer_name' in self.args: + installer_file = self.args['installer_name'] + else: + installer_file = installer_file % substitution_strings + substitution_strings['installer_file'] = installer_file + + tempfile = "secondlife_setup_tmp.nsi" + # the following replaces strings in the nsi template + # it also does python-style % substitution + self.replace_in("installers/windows/installer_template.nsi", tempfile, { + "%%VERSION%%":version_vars, + "%%SOURCE%%":self.get_src_prefix(), + "%%GRID_VARS%%":grid_vars_template % substitution_strings, + "%%INSTALL_FILES%%":self.nsi_file_commands(True), + "%%DELETE_FILES%%":self.nsi_file_commands(False)}) + + # We use the Unicode version of NSIS, available from + # http://www.scratchpaper.com/ + NSIS_path = 'C:\\Program Files\\NSIS\\Unicode\\makensis.exe' + self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile)) + # self.remove(self.dst_path_of(tempfile)) + # If we're on a build machine, sign the code using our Authenticode certificate. JC + sign_py = 'C:\\buildscripts\\code-signing\\sign.py' + if os.path.exists(sign_py): + self.run_command(sign_py + ' ' + self.dst_path_of(installer_file)) + else: + print "Skipping code signing,", sign_py, "does not exist" + self.created_path(self.dst_path_of(installer_file)) + self.package_file = 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(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 + # /Contents/MacOS/ + self.contents_of_tar(self.args['source']+'/mozilla-universal-darwin.tgz', 'MacOS') + + self.path("Info-SecondLife.plist", dst="Info.plist") + + # copy additional libs in /Contents/MacOS/ + self.path("../../libraries/universal-darwin/lib_release/libndofdev.dylib", dst="MacOS/libndofdev.dylib") + + # 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() + + 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.nib") + + # If we are not using the default channel, use the 'Firstlook + # icon' to show that it isn't a stable release. + if self.default_channel() and self.default_grid(): + self.path("secondlife.icns") + else: + self.path("secondlife_firstlook.icns", "secondlife.icns") + self.path("SecondLife.nib") + + # Translations + self.path("English.lproj") + self.path("German.lproj") + self.path("Japanese.lproj") + self.path("Korean.lproj") + self.path("da.lproj") + self.path("es.lproj") + self.path("fr.lproj") + self.path("hu.lproj") + self.path("it.lproj") + self.path("nl.lproj") + self.path("pl.lproj") + self.path("pt.lproj") + self.path("ru.lproj") + self.path("tr.lproj") + self.path("uk.lproj") + self.path("zh-Hans.lproj") + + # SLVoice and vivox lols + self.path("vivox-runtime/universal-darwin/libalut.dylib", "libalut.dylib") + self.path("vivox-runtime/universal-darwin/libopenal.dylib", "libopenal.dylib") + self.path("vivox-runtime/universal-darwin/libortp.dylib", "libortp.dylib") + self.path("vivox-runtime/universal-darwin/libvivoxsdk.dylib", "libvivoxsdk.dylib") + self.path("vivox-runtime/universal-darwin/SLVoice", "SLVoice") + + # need to get the kdu dll from any of the build directories as well + try: + self.path(self.find_existing_file('../llkdu/%s/libllkdu.dylib' % self.args['configuration'], + "../../libraries/universal-darwin/lib_release/libllkdu.dylib"), + dst='libllkdu.dylib') + pass + except: + print "Skipping libllkdu.dylib" + pass + + #libfmodwrapper.dylib + self.path(self.args['configuration'] + "/libfmodwrapper.dylib", "libfmodwrapper.dylib") + + # our apps + self.path("../mac_crash_logger/" + self.args['configuration'] + "/mac-crash-logger.app", "mac-crash-logger.app") + self.path("../mac_updater/" + self.args['configuration'] + "/mac-updater.app", "mac-updater.app") + + # command line arguments for connecting to the proper grid + self.put_in_file(self.flags_list(), 'arguments.txt') + + self.end_prefix("Resources") + + self.end_prefix("Contents") + + # 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. + if ("package" in self.args['actions'] or + "unpacked" in self.args['actions']): + self.run_command('strip -S "%(viewer_binary)s"' % + { 'viewer_binary' : self.dst_path_of('Contents/MacOS/Second Life')}) + + + def package_finish(self): + channel_standin = 'Second Life' # hah, our default channel is not usable on its own + if not self.default_channel(): + channel_standin = self.channel() + + imagename="SecondLife_" + '_'.join(self.args['version']) + + # MBW -- If the mounted volume name changes, it breaks the .DS_Store's background image and icon positioning. + # If we really need differently named volumes, we'll need to create multiple DS_Store file images, or use some other trick. + + volname="Second Life Installer" # DO NOT CHANGE without understanding comment above + + if self.default_channel(): + if not self.default_grid(): + # beta case + imagename = imagename + '_' + self.args['grid'].upper() + else: + # first look, etc + imagename = imagename + '_' + self.channel_oneword().upper() + + 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 "%(vol)s" -fs HFS+ -type SPARSE -megabytes 300 -layout SPUD' % { + 'sparse':sparsename, + 'vol':volname}) + + # 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 + + if self.default_channel() and not self.default_grid(): + app_name = "Second Life " + self.args['grid'] + else: + app_name = channel_standin.strip() + + # Hack: + # Because there is no easy way to coerce the Finder into positioning + # the app bundle in the same place with different app names, we are + # adding multiple .DS_Store files to svn. There is one for release, + # one for release candidate and one for first look. Any other channels + # will use the release .DS_Store, and will look broken. + # - Ambroff 2008-08-20 + dmg_template = os.path.join( + 'installers', + 'darwin', + '%s-dmg' % "".join(self.channel_unique().split()).lower()) + + if not os.path.exists (self.src_path_of(dmg_template)): + dmg_template = os.path.join ('installers', 'darwin', 'release-dmg') + + for s,d in {self.get_dst_prefix():app_name + ".app", + os.path.join(dmg_template, "_VolumeIcon.icns"): ".VolumeIcon.icns", + os.path.join(dmg_template, "background.jpg"): "background.jpg", + os.path.join(dmg_template, "_DS_Store"): ".DS_Store"}.items(): + print "Copying to dmg", s, d + self.copy_action(self.src_path_of(s), os.path.join(volpath, d)) + + # Hide the background image, DS_Store file, and volume icon file (set their "visible" bit) + self.run_command('SetFile -a V "' + os.path.join(volpath, ".VolumeIcon.icns") + '"') + self.run_command('SetFile -a V "' + os.path.join(volpath, "background.jpg") + '"') + self.run_command('SetFile -a V "' + os.path.join(volpath, ".DS_Store") + '"') + + # Create the alias file (which is a resource file) from the .r + self.run_command('rez "' + self.src_path_of("installers/darwin/release-dmg/Applications-alias.r") + '" -o "' + os.path.join(volpath, "Applications") + '"') + + # Set the alias file's alias and custom icon bits + self.run_command('SetFile -a AC "' + os.path.join(volpath, "Applications") + '"') + + # Set the disk image root's custom icon bit + self.run_command('SetFile -a C "' + volpath + '"') + + # Unmount the image + self.run_command('hdiutil detach -force "' + 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.package_file = finalname + 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.png","secondlife_icon.png") + if self.prefix("linux_tools", dst=""): + self.path("client-readme.txt","README-linux.txt") + self.path("client-readme-voice.txt","README-linux-voice.txt") + self.path("client-readme-joystick.txt","README-linux-joystick.txt") + self.path("wrapper.sh","secondlife") + self.path("handle_secondlifeprotocol.sh") + self.path("register_secondlifeprotocol.sh") + 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') + + + def package_finish(self): + if 'installer_name' in self.args: + installer_name = self.args['installer_name'] + else: + installer_name_components = ['SecondLife_', self.args.get('arch')] + installer_name_components.extend(self.args['version']) + installer_name = "_".join(installer_name_components) + if self.default_channel(): + if not self.default_grid(): + installer_name += '_' + self.args['grid'].upper() + else: + installer_name += '_' + self.channel_oneword().upper() + + # Fix access permissions + self.run_command(""" + find %(dst)s -type d | xargs --no-run-if-empty chmod 755; + find %(dst)s -type f -perm 0700 | xargs --no-run-if-empty chmod 0755; + find %(dst)s -type f -perm 0500 | xargs --no-run-if-empty chmod 0555; + find %(dst)s -type f -perm 0600 | xargs --no-run-if-empty chmod 0644; + find %(dst)s -type f -perm 0400 | xargs --no-run-if-empty chmod 0444; + true""" % {'dst':self.get_dst_prefix() }) + self.package_file = installer_name + '.tar.bz2' + + # 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.build_path_of(installer_name)}) + try: + # --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_build_prefix(), + 'inst_name': installer_name, + 'inst_path':self.build_path_of(installer_name)}) + finally: + self.run_command("mv %(inst)s %(dst)s" % { + 'dst': self.get_dst_prefix(), + 'inst': self.build_path_of(installer_name)}) + +class Linux_i686Manifest(LinuxManifest): + def construct(self): + super(Linux_i686Manifest, self).construct() + + # install either the libllkdu we just built, or a prebuilt one, in + # decreasing order of preference. for linux package, this goes to bin/ + try: + self.path(self.find_existing_file('../llkdu/libllkdu.so', + '../../libraries/i686-linux/lib_release_client/libllkdu.so'), + dst='bin/libllkdu.so') + # keep this one to preserve syntax, open source mangling removes previous lines + pass + except: + print "Skipping libllkdu.so - not found" + pass + + self.path("secondlife-stripped","bin/do-not-directly-run-secondlife-bin") + self.path("../linux_crash_logger/linux-crash-logger-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("featuretable_linux.txt") + #self.path("secondlife-i686.supp") + + self.path("app_settings/mozilla-runtime-linux-i686") + + if self.prefix("../../libraries/i686-linux/lib_release_client", dst="lib"): + #self.path("libkdu_v42R.so", "libkdu.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("libcrypto.so.0.9.7") + self.path("libexpat.so.1") + self.path("libssl.so.0.9.7") + self.path("libuuid.so", "libuuid.so.1") + self.path("libSDL-1.2.so.0") + self.path("libELFIO.so") + self.path("libopenjpeg.so.1.3.0", "libopenjpeg.so.1.3") + self.path("libalut.so") + self.path("libopenal.so", "libopenal.so.1") + self.end_prefix("lib") + + # Vivox runtimes + if self.prefix(src="vivox-runtime/i686-linux", dst="bin"): + self.path("SLVoice") + self.end_prefix() + if self.prefix(src="vivox-runtime/i686-linux", dst="lib"): + self.path("libortp.so") + self.path("libvivoxsdk.so") + self.end_prefix("lib") + +class Linux_x86_64Manifest(LinuxManifest): + def construct(self): + super(Linux_x86_64Manifest, self).construct() + self.path("secondlife-stripped","bin/do-not-directly-run-secondlife-bin") + self.path("../linux_crash_logger/linux-crash-logger-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("featuretable_linux.txt") + self.path("secondlife-i686.supp") + +if __name__ == "__main__": + main() -- cgit v1.2.3 From b5fef75dad1c0992c63ede83b96da0b1db1f9a37 Mon Sep 17 00:00:00 2001 From: "Mark Palange (Mani)" Date: Thu, 9 Jul 2009 17:03:20 -0700 Subject: Moveing around DLL copying to support building llcommon.dll and using llcommon.dll while running unit tests. --- indra/newview/viewer_manifest.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 7edf0bad6b..0217c8f864 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -168,9 +168,8 @@ class WindowsManifest(ViewerManifest): # need to get the llcommon.dll from any of the build directories as well try: - self.path(self.find_existing_file('../llcommon/%s/llcommon.dll' % self.args['configuration']), - dst='llcommon.dll') if self.prefix(src=self.args['configuration'], dst=""): + self.path('llcommon.dll') self.path('libapr-1.dll') self.path('libaprutil-1.dll') self.path('libapriconv-1.dll') @@ -181,8 +180,7 @@ class WindowsManifest(ViewerManifest): # need to get the kdu dll from any of the build directories as well try: - self.path(self.find_existing_file('../llkdu/%s/llkdu.dll' % self.args['configuration'], - '../../libraries/i686-win32/lib/release/llkdu.dll'), + self.path(self.find_existing_file('%s/llkdu.dll' % self.args['configuration']), dst='llkdu.dll') pass except: @@ -394,7 +392,11 @@ class WindowsManifest(ViewerManifest): # We use the Unicode version of NSIS, available from # http://www.scratchpaper.com/ - NSIS_path = 'C:\\Program Files\\NSIS\\Unicode\\makensis.exe' + # Check two paths, one for Program Files, and one for Program Files (x86). + # Yay 64bit windows. + NSIS_path = os.path.expandvars('${ProgramFiles}\\NSIS\\Unicode\\makensis.exe') + if not os.path.exists(NSIS_path): + NSIS_path = os.path.expandvars('${ProgramFiles(x86)}\\NSIS\\Unicode\\makensis.exe') self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile)) # self.remove(self.dst_path_of(tempfile)) # If we're on a build machine, sign the code using our Authenticode certificate. JC -- cgit v1.2.3 From 4f32c076c81b8388e63ce002ec5a228bfe412843 Mon Sep 17 00:00:00 2001 From: "Mark Palange (Mani)" Date: Wed, 29 Jul 2009 16:46:05 -0700 Subject: DEV-35405 Viewer manifest needed some love for supporting the debug build, but its still broke on llmozlib --- indra/newview/viewer_manifest.py | 55 +++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 29 deletions(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 0217c8f864..f35c6f449e 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -162,26 +162,24 @@ class WindowsManifest(ViewerManifest): 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('debug/secondlife-bin.exe', 'release/secondlife-bin.exe', 'relwithdebinfo/secondlife-bin.exe'), dst=self.final_exe()) + # Find secondlife-bin.exe in the 'configuration' dir, then rename it to the result of final_exe. + self.path(src='%s/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe()) - # need to get the llcommon.dll from any of the build directories as well - try: - if self.prefix(src=self.args['configuration'], dst=""): + # need to get the llcommon.dll from the build directory as well + if self.prefix(src=self.args['configuration'], dst=""): + try: self.path('llcommon.dll') self.path('libapr-1.dll') self.path('libaprutil-1.dll') self.path('libapriconv-1.dll') - self.end_prefix() - except: - print "Skipping llcommon.dll (assuming llcommon was linked statically)" - pass + except: + print "Skipping llcommon.dll (assuming llcommon was linked statically)" + pass + self.end_prefix() - # need to get the kdu dll from any of the build directories as well + # need to get the kdu dll from the build directory as well try: - self.path(self.find_existing_file('%s/llkdu.dll' % self.args['configuration']), - dst='llkdu.dll') + self.path('%s/llkdu.dll' % self.args['configuration'], dst='llkdu.dll') pass except: print "Skipping llkdu.dll" @@ -197,8 +195,11 @@ class WindowsManifest(ViewerManifest): self.path("fmod.dll") # For textures - if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): - self.path("openjpeg.dll") + if self.prefix(src=self.args['configuration'], dst=""): + if(self.args['configuration'].lower() == 'debug'): + self.path("openjpegd.dll") + else: + self.path("openjpeg.dll") self.end_prefix() # Mozilla appears to force a dependency on these files so we need to ship it (CP) - updated to vc8 versions (nyx) @@ -216,7 +217,7 @@ class WindowsManifest(ViewerManifest): self.end_prefix() # Mozilla runtime DLLs (CP) - if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): + if self.prefix(src=self.args['configuration'], dst=""): self.path("freebl3.dll") self.path("js3250.dll") self.path("nspr4.dll") @@ -247,7 +248,7 @@ class WindowsManifest(ViewerManifest): self.path("SecondLife.exe.config", dst=self.final_exe() + ".config") # Vivox runtimes - if self.prefix(src="vivox-runtime/i686-win32", dst=""): + if self.prefix(src=self.args['configuration'], dst=""): self.path("SLVoice.exe") self.path("alut.dll") self.path("vivoxsdk.dll") @@ -256,22 +257,18 @@ class WindowsManifest(ViewerManifest): self.end_prefix() # pull in the crash logger and updater from other projects - self.path(src=self.find_existing_file( # tag:"crash-logger" here as a cue to the exporter - "../win_crash_logger/debug/windows-crash-logger.exe", - "../win_crash_logger/release/windows-crash-logger.exe", - "../win_crash_logger/relwithdebinfo/windows-crash-logger.exe"), + # tag:"crash-logger" here as a cue to the exporter + self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'], dst="win_crash_logger.exe") - self.path(src=self.find_existing_file( - "../win_updater/debug/windows-updater.exe", - "../win_updater/release/windows-updater.exe", - "../win_updater/relwithdebinfo/windows-updater.exe"), + self.path(src='../win_updater/%s/windows-updater.exe' % self.args['configuration'], dst="updater.exe") # For google-perftools tcmalloc allocator. - if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): - self.path("libtcmalloc_minimal.dll") - self.end_prefix() - + try: + self.path('%s/libtcmalloc_minimal.dll' % self.args['configuration']) + except: + print "Skipping libtcmalloc_minimal.dll" + pass def nsi_file_commands(self, install=True): def wpath(path): -- cgit v1.2.3 From 084983485f9e05ff9164fabe3244ffd6f33295cf Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 31 Jul 2009 13:26:24 -0400 Subject: DEV-34837: update Mac apr_suite package so that each of the .dylib files self-identifies as @executable_path/../Resources/filename. This allows the SL executable to find it at runtime in its official place in the app bundle. Change viewer_manifest.py to copy libllcommon.dylib, libapr*.dylib to app bundle's Resources subdir. --- indra/newview/viewer_manifest.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index f35c6f449e..7b8a64e3b4 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -472,16 +472,31 @@ class DarwinManifest(ViewerManifest): self.path("vivox-runtime/universal-darwin/libvivoxsdk.dylib", "libvivoxsdk.dylib") self.path("vivox-runtime/universal-darwin/SLVoice", "SLVoice") + libdir = "../../libraries/universal-darwin/lib_release" + + for libfile in ("libapr-1.0.3.7.dylib", "libaprutil-1.0.3.8.dylib"): + self.path(os.path.join(libdir, libfile), libfile) + # need to get the kdu dll from any of the build directories as well + lib = "llkdu" + libfile = "lib%s.dylib" % lib try: - self.path(self.find_existing_file('../llkdu/%s/libllkdu.dylib' % self.args['configuration'], - "../../libraries/universal-darwin/lib_release/libllkdu.dylib"), - dst='libllkdu.dylib') + self.path(self.find_existing_file('../%s/%s/%s' % + (lib, self.args['configuration'], libfile), + os.path.join(libdir, libfile)), + dst=libfile) pass except: - print "Skipping libllkdu.dylib" + print "Skipping %s" % libfile pass - + + lib = "llcommon" + libfile = "lib%s.dylib" % lib + self.path(self.find_existing_file('../%s/%s/%s' % + (lib, self.args['configuration'], libfile), + os.path.join(libdir, libfile)), + dst=libfile) + #libfmodwrapper.dylib self.path(self.args['configuration'] + "/libfmodwrapper.dylib", "libfmodwrapper.dylib") -- cgit v1.2.3 From 0ac96fd8e61e402840bf2788ed4f34487f780567 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 31 Jul 2009 16:13:46 -0400 Subject: DEV-34837: fix viewer_manifest.py to continue supporting static llcommon build --- indra/newview/viewer_manifest.py | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 7b8a64e3b4..c0a5ab5526 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -473,29 +473,25 @@ class DarwinManifest(ViewerManifest): self.path("vivox-runtime/universal-darwin/SLVoice", "SLVoice") libdir = "../../libraries/universal-darwin/lib_release" - - for libfile in ("libapr-1.0.3.7.dylib", "libaprutil-1.0.3.8.dylib"): - self.path(os.path.join(libdir, libfile), libfile) + dylibs = {} # need to get the kdu dll from any of the build directories as well - lib = "llkdu" - libfile = "lib%s.dylib" % lib - try: - self.path(self.find_existing_file('../%s/%s/%s' % - (lib, self.args['configuration'], libfile), - os.path.join(libdir, libfile)), - dst=libfile) - pass - except: - print "Skipping %s" % libfile - pass - - lib = "llcommon" - libfile = "lib%s.dylib" % lib - self.path(self.find_existing_file('../%s/%s/%s' % - (lib, self.args['configuration'], libfile), - os.path.join(libdir, libfile)), - dst=libfile) + for lib in "llkdu", "llcommon": + libfile = "lib%s.dylib" % lib + try: + self.path(self.find_existing_file('../%s/%s/%s' % + (lib, self.args['configuration'], libfile), + os.path.join(libdir, libfile)), + dst=libfile) + except RuntimeError: + print "Skipping %s" % libfile + dylibs[lib] = False + else: + dylibs[lib] = True + + if dylibs["llcommon"]: + for libfile in ("libapr-1.0.3.7.dylib", "libaprutil-1.0.3.8.dylib"): + self.path(os.path.join(libdir, libfile), libfile) #libfmodwrapper.dylib self.path(self.args['configuration'] + "/libfmodwrapper.dylib", "libfmodwrapper.dylib") -- cgit v1.2.3 From 03ebc43132331b9a8dcb3c418ec9c319a6beddda Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 5 Aug 2009 16:08:17 -0400 Subject: DEV-34837: Remove dependency on Leopard-only /usr/local/lib/libexpat.0.1.0.dylib. On Mac, add libexpat[.0.5.0].dylib to apr_suite package. Update libapr-1[.0.3.7].dylib and libaprutil-1[.0.3.8].dylib with versions that reference this expat. Make viewer_manifiest.py copy expat dylib to app bundle. --- indra/newview/viewer_manifest.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index c0a5ab5526..c2a9789ff1 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -490,7 +490,9 @@ class DarwinManifest(ViewerManifest): dylibs[lib] = True if dylibs["llcommon"]: - for libfile in ("libapr-1.0.3.7.dylib", "libaprutil-1.0.3.8.dylib"): + for libfile in ("libapr-1.0.3.7.dylib", + "libaprutil-1.0.3.8.dylib", + "libexpat.0.5.0.dylib"): self.path(os.path.join(libdir, libfile), libfile) #libfmodwrapper.dylib -- cgit v1.2.3 From 9695162dc20085c807363e562281271cec21cc1d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 11 Aug 2009 14:59:09 -0700 Subject: Add libllcommon.so to packaged/lib --- indra/newview/viewer_manifest.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index d198518ee3..432dafaf8f 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -483,8 +483,10 @@ class DarwinManifest(ViewerManifest): for lib in "llkdu", "llcommon": libfile = "lib%s.dylib" % lib try: - self.path(self.find_existing_file('../%s/%s/%s' % - (lib, self.args['configuration'], libfile), + self.path(self.find_existing_file(os.path.join(os.pardir, + lib, + self.args['configuration'], + libfile), os.path.join(libdir, libfile)), dst=libfile) except RuntimeError: @@ -674,15 +676,17 @@ class Linux_i686Manifest(LinuxManifest): # install either the libllkdu we just built, or a prebuilt one, in # decreasing order of preference. for linux package, this goes to bin/ - try: - self.path(self.find_existing_file('../llkdu/libllkdu.so', - '../../libraries/i686-linux/lib_release_client/libllkdu.so'), - dst='bin/libllkdu.so') - # keep this one to preserve syntax, open source mangling removes previous lines - pass - except: - print "Skipping libllkdu.so - not found" - pass + for lib, destdir in ("llkdu", "bin"), ("llcommon", "lib"): + libfile = "lib%s.so" % lib + try: + self.path(self.find_existing_file(os.path.join(os.pardir, lib, libfile), + '../../libraries/i686-linux/lib_release_client/%s' % libfile), + dst=os.path.join(destdir, libfile)) + # keep this one to preserve syntax, open source mangling removes previous lines + pass + except RuntimeError: + print "Skipping %s - not found" % libfile + pass self.path("secondlife-stripped","bin/do-not-directly-run-secondlife-bin") self.path("../linux_crash_logger/linux-crash-logger-stripped","linux-crash-logger.bin") -- cgit v1.2.3 From a15feff98c13cd693e60fc59345609c007de16db Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 12 Aug 2009 08:02:10 -0700 Subject: Add libgobject-2.0.so.0 to Linux package --- indra/newview/viewer_manifest.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 432dafaf8f..3270cba58c 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -701,6 +701,10 @@ class Linux_i686Manifest(LinuxManifest): self.path("app_settings/mozilla-runtime-linux-i686") + if self.prefix("../../libraries/i686-linux/lib_release", dst="lib"): + self.path("libgobject-2.0.so.0") + self.end_prefix("lib") + if self.prefix("../../libraries/i686-linux/lib_release_client", dst="lib"): #self.path("libkdu_v42R.so", "libkdu.so") self.path("libfmod-3.75.so") -- cgit v1.2.3 From 88f29fce3512ec03a01b875d1ae60c7af403d3a7 Mon Sep 17 00:00:00 2001 From: brad kittenbrink Date: Thu, 13 Aug 2009 11:55:40 -0400 Subject: Backed out changeset 75ab7d14eace. libgobject-2.0.so should not be being packaged on linux. --- indra/newview/viewer_manifest.py | 4 ---- 1 file changed, 4 deletions(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 3270cba58c..432dafaf8f 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -701,10 +701,6 @@ class Linux_i686Manifest(LinuxManifest): self.path("app_settings/mozilla-runtime-linux-i686") - if self.prefix("../../libraries/i686-linux/lib_release", dst="lib"): - self.path("libgobject-2.0.so.0") - self.end_prefix("lib") - if self.prefix("../../libraries/i686-linux/lib_release_client", dst="lib"): #self.path("libkdu_v42R.so", "libkdu.so") self.path("libfmod-3.75.so") -- cgit v1.2.3 From 2149be5df273e4b68bae3c797f26e507bb7951be Mon Sep 17 00:00:00 2001 From: CG Linden Date: Mon, 31 Aug 2009 17:16:02 -0700 Subject: Attempt to invoke the code signer differently --- indra/newview/viewer_manifest.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index ae3b1ba43e..6476e56681 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -395,9 +395,14 @@ class WindowsManifest(ViewerManifest): self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile)) # self.remove(self.dst_path_of(tempfile)) # If we're on a build machine, sign the code using our Authenticode certificate. JC - sign_py = 'C:\\buildscripts\\code-signing\\sign.py' + sign_py = os.path.expandvars("${SIGN}") + if not sign_py or sign_py == "${SIGN}": + sign_py = 'C:\\buildscripts\\code-signing\\sign.py' + python = os.path.expandvars("${PYTHON}") + if not python or python == "${PYTHON}": + python = 'python' if os.path.exists(sign_py): - self.run_command(sign_py + ' ' + self.dst_path_of(installer_file)) + self.run_command("%s %s %s" % (python, sign_py self.dst_path_of(installer_file))) else: print "Skipping code signing,", sign_py, "does not exist" self.created_path(self.dst_path_of(installer_file)) -- cgit v1.2.3 From 7eafa3209c6b8a7ef9b7d677943752f5345ff3f2 Mon Sep 17 00:00:00 2001 From: CG Linden Date: Mon, 31 Aug 2009 18:34:03 -0700 Subject: Fix syntax error in viewer_manifest.py --- indra/newview/viewer_manifest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 6476e56681..66ebd607c4 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -402,7 +402,7 @@ class WindowsManifest(ViewerManifest): if not python or python == "${PYTHON}": python = 'python' if os.path.exists(sign_py): - self.run_command("%s %s %s" % (python, sign_py self.dst_path_of(installer_file))) + self.run_command("%s %s %s" % (python, sign_py, self.dst_path_of(installer_file))) else: print "Skipping code signing,", sign_py, "does not exist" self.created_path(self.dst_path_of(installer_file)) -- cgit v1.2.3 From 1a6be4eb17372273b74fd9b849799372f23a15e9 Mon Sep 17 00:00:00 2001 From: CG Linden Date: Mon, 31 Aug 2009 20:09:56 -0700 Subject: Quote any backslashes so they get preserved when invoking python. --- indra/newview/viewer_manifest.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 66ebd607c4..024f2f655c 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -398,6 +398,8 @@ class WindowsManifest(ViewerManifest): sign_py = os.path.expandvars("${SIGN}") if not sign_py or sign_py == "${SIGN}": sign_py = 'C:\\buildscripts\\code-signing\\sign.py' + else: + sign_py = sign_py.replace('\\', '\\\\') python = os.path.expandvars("${PYTHON}") if not python or python == "${PYTHON}": python = 'python' -- cgit v1.2.3 From a6ff5974c36f8ea860b2065c549333d8cfc6a458 Mon Sep 17 00:00:00 2001 From: CG Linden Date: Tue, 1 Sep 2009 09:00:02 -0700 Subject: Also quite the backslashes in the argument for the sign command --- indra/newview/viewer_manifest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 024f2f655c..99c9abfddf 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -404,7 +404,7 @@ class WindowsManifest(ViewerManifest): if not python or python == "${PYTHON}": python = 'python' if os.path.exists(sign_py): - self.run_command("%s %s %s" % (python, sign_py, self.dst_path_of(installer_file))) + self.run_command("%s %s %s" % (python, sign_py, self.dst_path_of(installer_file).replace('\\', '\\\\'))) else: print "Skipping code signing,", sign_py, "does not exist" self.created_path(self.dst_path_of(installer_file)) -- cgit v1.2.3 From 40743eaf99c9cbfee08f0bb44bc7c614bc660f34 Mon Sep 17 00:00:00 2001 From: CG Linden Date: Tue, 1 Sep 2009 13:36:08 -0700 Subject: Try double-quoting backslashes --- indra/newview/viewer_manifest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 99c9abfddf..e85fddbc99 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -399,12 +399,12 @@ class WindowsManifest(ViewerManifest): if not sign_py or sign_py == "${SIGN}": sign_py = 'C:\\buildscripts\\code-signing\\sign.py' else: - sign_py = sign_py.replace('\\', '\\\\') + sign_py = sign_py.replace('\\', '\\\\\\\\') python = os.path.expandvars("${PYTHON}") if not python or python == "${PYTHON}": python = 'python' if os.path.exists(sign_py): - self.run_command("%s %s %s" % (python, sign_py, self.dst_path_of(installer_file).replace('\\', '\\\\'))) + self.run_command("%s %s %s" % (python, sign_py, self.dst_path_of(installer_file).replace('\\', '\\\\\\\\'))) else: print "Skipping code signing,", sign_py, "does not exist" self.created_path(self.dst_path_of(installer_file)) -- cgit v1.2.3 From afea10ebc94b8009b96b0b1771e6c0f614f406dd Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 2 Sep 2009 17:38:46 -0400 Subject: On Mac, move SLPlugin executable to the same directory as the viewer executable. Change LLDir_Mac::getLLPluginLauncher() to look in the viewer's executable dir instead of in the plugins dir. Change viewer_manifest.py's DarwinManifest.construct() to put SLPlugin in the new location. SLPlugin is being linked with our new libllcommon.dylib, which self-identifies as being findable via @executable_path/../Resources/libllcommon.dylib. This doesn't work from the Resources/llplugin subdir -- the above relative path ends up looking in the nonexistent Resources/Resources subdirectory. Putting SLPlugin in the Contents/MacOS directory with the viewer executable solves the problem. --- indra/newview/viewer_manifest.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 1b9acc7ac2..a27c4a7fb7 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -427,6 +427,9 @@ class DarwinManifest(ViewerManifest): # copy additional libs in /Contents/MacOS/ self.path("../../libraries/universal-darwin/lib_release/libndofdev.dylib", dst="MacOS/libndofdev.dylib") + self.path(os.path.join(os.pardir, "llplugin", "slplugin", self.args['configuration'], + "SLPlugin"), + os.path.join("MacOS", "SLPlugin")) # most everything goes in the Resources directory if self.prefix(src="", dst="Resources"): @@ -507,7 +510,6 @@ class DarwinManifest(ViewerManifest): # plugins if self.prefix(src="", dst="llplugin"): - self.path("../llplugin/slplugin/" + self.args['configuration'] + "/SLPlugin", "SLPlugin") self.path("../media_plugins/quicktime/" + self.args['configuration'] + "/media_plugin_quicktime.dylib", "media_plugin_quicktime.dylib") self.path("../media_plugins/webkit/" + self.args['configuration'] + "/media_plugin_webkit.dylib", "media_plugin_webkit.dylib") self.path("../../libraries/universal-darwin/lib_release/libllqtwebkit.dylib", "libllqtwebkit.dylib") -- cgit v1.2.3 From 2a446ab558f039db4a863f3d287f2ec2369ec8c3 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 10 Sep 2009 13:56:38 -0700 Subject: QAR-1619: move Linux SLPlugin executable to the viewer executable directory --- indra/newview/viewer_manifest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index a27c4a7fb7..91c091283a 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -702,6 +702,7 @@ class Linux_i686Manifest(LinuxManifest): self.path("secondlife-stripped","bin/do-not-directly-run-secondlife-bin") self.path("../linux_crash_logger/linux-crash-logger-stripped","bin/linux-crash-logger.bin") self.path("../linux_updater/linux-updater-stripped", "bin/linux-updater.bin") + self.path("../llplugin/slplugin/SLPlugin", "bin/SLPlugin") if self.prefix("res-sdl"): self.path("*") # recurse @@ -709,7 +710,6 @@ class Linux_i686Manifest(LinuxManifest): # plugins if self.prefix(src="", dst="bin/llplugin"): - self.path("../llplugin/slplugin/SLPlugin", "SLPlugin") self.path("../media_plugins/webkit/libmedia_plugin_webkit.so", "libmedia_plugin_webkit.so") self.path("../media_plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_quicktime.so") self.end_prefix("bin/llplugin") -- cgit v1.2.3 From 7dca49b0f238063b7396ead5dbd8206669a5934f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Mon, 14 Sep 2009 09:16:19 -0400 Subject: QAR-1619: At Sam's request, move SLPlugin to viewer executable dir, consistent with Mac and Linux. --- indra/newview/viewer_manifest.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index bb48e8e572..109c437730 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -169,6 +169,11 @@ class WindowsManifest(ViewerManifest): # Find secondlife-bin.exe in the 'configuration' dir, then rename it to the result of final_exe. self.path(src='%s/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe()) + # Plugin host application + self.path(os.path.join(os.pardir, + 'llplugin', 'slplugin', self.args['configuration'], "slplugin.exe"), + "slplugin.exe") + # need to get the llcommon.dll from the build directory as well if self.prefix(src=self.args['configuration'], dst=""): try: @@ -206,11 +211,6 @@ class WindowsManifest(ViewerManifest): self.path("openjpeg.dll") self.end_prefix() - # Plugin host application - if self.prefix(src='../llplugin/slplugin/%s' % self.args['configuration'], dst="llplugin"): - self.path("slplugin.exe") - self.end_prefix() - # Media plugins - QuickTime if self.prefix(src='../media_plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"): self.path("media_plugin_quicktime.dll") -- cgit v1.2.3 From 93869a8ef23bd07351309ed86e10a0acd66ae973 Mon Sep 17 00:00:00 2001 From: "Mark Palange (Mani)" Date: Tue, 15 Sep 2009 12:32:22 -0700 Subject: Fixed up CopyWinLibs.cmake post moap/viewer-2.0.0-3 merge. Added CRT assembly check to viewer_manifest.py. twiddled test_win32_manifest.py for ease of use. --- indra/newview/viewer_manifest.py | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index bb48e8e572..af7c474b03 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -164,11 +164,38 @@ class WindowsManifest(ViewerManifest): return ''.join(self.channel().split()) + '.exe' + def test_msvcrt_and_copy_action(self, src, dst): + # This can is used to test a dll manifest. + # It is used as a temporary override during the construct method + from test_win32_manifest import test_assembly_binding + if src and (os.path.exists(src) or os.path.islink(src)): + # ensure that destination path exists + self.cmakedirs(os.path.dirname(dst)) + self.created_paths.append(dst) + if not os.path.isdir(src): + if(self.args['configuration'].lower() == 'debug'): + test_assembly_binding(src, "Microsoft.VC80.DebugCRT", "8.0.50727.4053") + else: + test_assembly_binding(src, "Microsoft.VC80.CRT", "8.0.50727.4053") + self.ccopy(src,dst) + else: + raise Exception("Directories are not supported by test_CRT_and_copy_action()") + else: + print "Doesn't exist:", src + + def enable_crt_check(self): + WindowsManifest.copy_action = WindowsManifest.test_msvcrt_and_copy_action + + def disable_crt_check(self): + del WindowsManifest.copy_action + def construct(self): super(WindowsManifest, self).construct() # Find secondlife-bin.exe in the 'configuration' dir, then rename it to the result of final_exe. self.path(src='%s/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe()) + self.enable_crt_check() + # need to get the llcommon.dll from the build directory as well if self.prefix(src=self.args['configuration'], dst=""): try: @@ -178,18 +205,17 @@ class WindowsManifest(ViewerManifest): self.path('libapriconv-1.dll') except: print "Skipping llcommon.dll (assuming llcommon was linked statically)" - pass self.end_prefix() # need to get the kdu dll from the build directory as well try: self.path('%s/llkdu.dll' % self.args['configuration'], dst='llkdu.dll') - pass except: print "Skipping llkdu.dll" - pass - self.path(src="licenses-win32.txt", dst="licenses.txt") + self.disable_crt_check() + + self.path(src="licenses-win32.txt", dst="licenses.txt") self.path("featuretable.txt") # For use in crash reporting (generates minidumps) @@ -198,6 +224,8 @@ class WindowsManifest(ViewerManifest): # For using FMOD for sound... DJS self.path("fmod.dll") + self.enable_crt_check() + # For textures if self.prefix(src=self.args['configuration'], dst=""): if(self.args['configuration'].lower() == 'debug'): @@ -221,7 +249,6 @@ class WindowsManifest(ViewerManifest): self.path("media_plugin_webkit.dll") self.end_prefix() - # For WebKit/Qt plugin runtimes if self.prefix(src="../../libraries/i686-win32/lib/release", dst="llplugin"): self.path("libeay32.dll") self.path("qtcore4.dll") @@ -242,6 +269,8 @@ class WindowsManifest(ViewerManifest): self.path("qtiff4.dll") self.end_prefix() + self.disable_crt_check() + # These need to be installed as a SxS assembly, currently a 'private' assembly. # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx if self.prefix(src=self.args['configuration'], dst=""): -- cgit v1.2.3 From 8e7ba92eb9e0371385e3de9a76cc11355be8a974 Mon Sep 17 00:00:00 2001 From: "Mark Palange (Mani)" Date: Tue, 15 Sep 2009 16:33:00 -0700 Subject: More specific exepction handling to support correct crt_checking failures. --- indra/newview/viewer_manifest.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index d8f0e9f5d9..7084fca865 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -195,6 +195,7 @@ class WindowsManifest(ViewerManifest): self.path(src='%s/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe()) self.enable_crt_check() + # Plugin host application self.path(os.path.join(os.pardir, 'llplugin', 'slplugin', self.args['configuration'], "slplugin.exe"), @@ -207,14 +208,14 @@ class WindowsManifest(ViewerManifest): self.path('libapr-1.dll') self.path('libaprutil-1.dll') self.path('libapriconv-1.dll') - except: + except RuntimeError: print "Skipping llcommon.dll (assuming llcommon was linked statically)" self.end_prefix() # need to get the kdu dll from the build directory as well try: self.path('%s/llkdu.dll' % self.args['configuration'], dst='llkdu.dll') - except: + except RuntimeError: print "Skipping llkdu.dll" self.disable_crt_check() -- cgit v1.2.3 From 128c3dfc74fd02860f199359071b32ea5119033d Mon Sep 17 00:00:00 2001 From: "Mark Palange (Mani)" Date: Fri, 18 Sep 2009 11:29:28 -0700 Subject: Applied patch for SLPlugin location from: r133676 svn+ssh://svn.lindenlab.com/svn/linden/branches/media-on-a-prim/moap-6 --- indra/newview/viewer_manifest.py | 1592 +++++++++++++++++++------------------- 1 file changed, 796 insertions(+), 796 deletions(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 7084fca865..6ef905cca7 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1,796 +1,796 @@ -#!/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. -# -# $LicenseInfo:firstyear=2006&license=viewergpl$ -# -# Copyright (c) 2006-2009, Linden Research, Inc. -# -# Second Life Viewer Source Code -# The source code in this file ("Source Code") is provided by Linden Lab -# to you under the terms of the GNU General Public License, version 2.0 -# ("GPL"), unless you have obtained a separate licensing agreement -# ("Other License"), formally executed by you and Linden Lab. Terms of -# the GPL can be found in doc/GPL-license.txt in this distribution, or -# online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 -# -# There are special exceptions to the terms and conditions of the GPL as -# it is applied to this Source Code. View the full text of the exception -# in the file doc/FLOSS-exception.txt in this software distribution, or -# online at -# http://secondlifegrid.net/programs/open_source/licensing/flossexception -# -# By copying, modifying or distributing this software, you acknowledge -# that you have read and understood your obligations described above, -# and agree to abide by those obligations. -# -# ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO -# WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -# COMPLETENESS OR PERFORMANCE. -# $/LicenseInfo$ -import sys -import os.path -import re -import tarfile -viewer_dir = os.path.dirname(__file__) -# add llmanifest library to our path so we don't have to muck with PYTHONPATH -sys.path.append(os.path.join(viewer_dir, '../lib/python/indra/util')) -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") - self.path(src="../../etc/message.xml", dst="app_settings/message.xml") - - 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("*.db2") - - # include the entire shaders directory recursively - self.path("shaders") - # ... and the entire windlight directory - self.path("windlight") - 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") - - # skins - if self.prefix(src="skins"): - self.path("paths.xml") - # include the entire textures directory recursively - if self.prefix(src="*/textures"): - self.path("*/*.tga") - self.path("*/*.j2c") - self.path("*/*.jpg") - self.path("*/*.png") - self.path("*.tga") - self.path("*.j2c") - self.path("*.jpg") - self.path("*.png") - self.path("textures.xml") - self.end_prefix("*/textures") - self.path("*/xui/*/*.xml") - self.path("*/xui/*/widgets/*.xml") - self.path("*/*.xml") - - # Local HTML files (e.g. loading screen) - if self.prefix(src="*/html"): - self.path("*.png") - self.path("*/*/*.html") - self.path("*/*/*.gif") - self.end_prefix("*/html") - self.end_prefix("skins") - - # Files in the newview/ directory - self.path("gpu_table.txt") - - def login_channel(self): - """Channel reported for login and upgrade purposes ONLY; - used for A/B testing""" - # NOTE: Do not return the normal channel if login_channel - # is not specified, as some code may branch depending on - # whether or not this is present - return self.args.get('login_channel') - - def grid(self): - return self.args['grid'] - def channel(self): - return self.args['channel'] - def channel_unique(self): - return self.channel().replace("Second Life", "").strip() - def channel_oneword(self): - return "".join(self.channel_unique().split()) - def channel_lowerword(self): - return self.channel_oneword().lower() - - def flags_list(self): - """ Convenience function that returns the command-line flags - for the grid""" - - # Set command line flags relating to the target grid - grid_flags = '' - if not self.default_grid(): - grid_flags = "--grid %(grid)s "\ - "--helperuri http://preview-%(grid)s.secondlife.com/helpers/" %\ - {'grid':self.grid()} - - # set command line flags for channel - channel_flags = '' - if self.login_channel() and self.login_channel() != self.channel(): - # Report a special channel during login, but use default - channel_flags = '--channel "%s"' % (self.login_channel()) - elif not self.default_channel(): - channel_flags = '--channel "%s"' % self.channel() - - # Deal with settings - setting_flags = '' - if not self.default_channel() or not self.default_grid(): - if self.default_grid(): - setting_flags = '--settings settings_%s.xml'\ - % self.channel_lowerword() - else: - setting_flags = '--settings settings_%s_%s.xml'\ - % (self.grid(), self.channel_lowerword()) - - return " ".join((channel_flags, grid_flags, setting_flags)).strip() - - -class WindowsManifest(ViewerManifest): - def final_exe(self): - if self.default_channel(): - if self.default_grid(): - return "SecondLife.exe" - else: - return "SecondLifePreview.exe" - else: - return ''.join(self.channel().split()) + '.exe' - - - def test_msvcrt_and_copy_action(self, src, dst): - # This can is used to test a dll manifest. - # It is used as a temporary override during the construct method - from test_win32_manifest import test_assembly_binding - if src and (os.path.exists(src) or os.path.islink(src)): - # ensure that destination path exists - self.cmakedirs(os.path.dirname(dst)) - self.created_paths.append(dst) - if not os.path.isdir(src): - if(self.args['configuration'].lower() == 'debug'): - test_assembly_binding(src, "Microsoft.VC80.DebugCRT", "8.0.50727.4053") - else: - test_assembly_binding(src, "Microsoft.VC80.CRT", "8.0.50727.4053") - self.ccopy(src,dst) - else: - raise Exception("Directories are not supported by test_CRT_and_copy_action()") - else: - print "Doesn't exist:", src - - def enable_crt_check(self): - WindowsManifest.copy_action = WindowsManifest.test_msvcrt_and_copy_action - - def disable_crt_check(self): - del WindowsManifest.copy_action - - def construct(self): - super(WindowsManifest, self).construct() - # Find secondlife-bin.exe in the 'configuration' dir, then rename it to the result of final_exe. - self.path(src='%s/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe()) - - self.enable_crt_check() - - # Plugin host application - self.path(os.path.join(os.pardir, - 'llplugin', 'slplugin', self.args['configuration'], "slplugin.exe"), - "slplugin.exe") - - # need to get the llcommon.dll from the build directory as well - if self.prefix(src=self.args['configuration'], dst=""): - try: - self.path('llcommon.dll') - self.path('libapr-1.dll') - self.path('libaprutil-1.dll') - self.path('libapriconv-1.dll') - except RuntimeError: - print "Skipping llcommon.dll (assuming llcommon was linked statically)" - self.end_prefix() - - # need to get the kdu dll from the build directory as well - try: - self.path('%s/llkdu.dll' % self.args['configuration'], dst='llkdu.dll') - except RuntimeError: - print "Skipping llkdu.dll" - - self.disable_crt_check() - - self.path(src="licenses-win32.txt", dst="licenses.txt") - self.path("featuretable.txt") - - # For use in crash reporting (generates minidumps) - self.path("dbghelp.dll") - - # For using FMOD for sound... DJS - self.path("fmod.dll") - - self.enable_crt_check() - - # For textures - if self.prefix(src=self.args['configuration'], dst=""): - if(self.args['configuration'].lower() == 'debug'): - self.path("openjpegd.dll") - else: - self.path("openjpeg.dll") - self.end_prefix() - - # Media plugins - QuickTime - if self.prefix(src='../media_plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"): - self.path("media_plugin_quicktime.dll") - self.end_prefix() - - # Media plugins - WebKit/Qt - if self.prefix(src='../media_plugins/webkit/%s' % self.args['configuration'], dst="llplugin"): - self.path("media_plugin_webkit.dll") - self.end_prefix() - - if self.prefix(src="../../libraries/i686-win32/lib/release", dst="llplugin"): - self.path("libeay32.dll") - self.path("qtcore4.dll") - self.path("qtgui4.dll") - self.path("qtnetwork4.dll") - self.path("qtopengl4.dll") - self.path("qtwebkit4.dll") - self.path("ssleay32.dll") - self.end_prefix() - - # For WebKit/Qt plugin runtimes (image format plugins) - if self.prefix(src="../../libraries/i686-win32/lib/release/imageformats", dst="llplugin/imageformats"): - self.path("qgif4.dll") - self.path("qico4.dll") - self.path("qjpeg4.dll") - self.path("qmng4.dll") - self.path("qsvg4.dll") - self.path("qtiff4.dll") - self.end_prefix() - - self.disable_crt_check() - - # These need to be installed as a SxS assembly, currently a 'private' assembly. - # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx - if self.prefix(src=self.args['configuration'], dst=""): - if self.args['configuration'] == 'Debug': - self.path("msvcr80d.dll") - self.path("msvcp80d.dll") - self.path("Microsoft.VC80.DebugCRT.manifest") - else: - self.path("msvcr80.dll") - self.path("msvcp80.dll") - self.path("Microsoft.VC80.CRT.manifest") - self.end_prefix() - - # The config file name needs to match the exe's name. - self.path(src="%s/secondlife-bin.exe.config" % self.args['configuration'], dst=self.final_exe() + ".config") - - # Vivox runtimes - if self.prefix(src=self.args['configuration'], dst=""): - self.path("SLVoice.exe") - self.path("alut.dll") - self.path("vivoxsdk.dll") - self.path("ortp.dll") - self.path("wrap_oal.dll") - self.end_prefix() - - # pull in the crash logger and updater from other projects - # tag:"crash-logger" here as a cue to the exporter - self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'], - dst="win_crash_logger.exe") - self.path(src='../win_updater/%s/windows-updater.exe' % self.args['configuration'], - dst="updater.exe") - - # For google-perftools tcmalloc allocator. - try: - self.path('%s/libtcmalloc_minimal.dll' % self.args['configuration']) - except: - print "Skipping libtcmalloc_minimal.dll" - pass - - 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): - # a standard map of strings for replacing in the templates - substitution_strings = { - 'version' : '.'.join(self.args['version']), - 'version_short' : '.'.join(self.args['version'][:-1]), - 'version_dashes' : '-'.join(self.args['version']), - 'final_exe' : self.final_exe(), - 'grid':self.args['grid'], - 'grid_caps':self.args['grid'].upper(), - # escape quotes becase NSIS doesn't handle them well - 'flags':self.flags_list().replace('"', '$\\"'), - 'channel':self.channel(), - 'channel_oneword':self.channel_oneword(), - 'channel_unique':self.channel_unique(), - } - - version_vars = """ - !define INSTEXE "%(final_exe)s" - !define VERSION "%(version_short)s" - !define VERSION_LONG "%(version)s" - !define VERSION_DASHES "%(version_dashes)s" - """ % substitution_strings - if self.default_channel(): - if self.default_grid(): - # release viewer - installer_file = "Second_Life_%(version_dashes)s_Setup.exe" - grid_vars_template = """ - OutFile "%(installer_file)s" - !define INSTFLAGS "%(flags)s" - !define INSTNAME "SecondLife" - !define SHORTCUT "Second Life" - !define URLNAME "secondlife" - Caption "Second Life ${VERSION}" - """ - else: - # beta grid viewer - installer_file = "Second_Life_%(version_dashes)s_(%(grid_caps)s)_Setup.exe" - grid_vars_template = """ - OutFile "%(installer_file)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}" - """ - else: - # some other channel on some grid - installer_file = "Second_Life_%(version_dashes)s_%(channel_oneword)s_Setup.exe" - grid_vars_template = """ - OutFile "%(installer_file)s" - !define INSTFLAGS "%(flags)s" - !define INSTNAME "SecondLife%(channel_oneword)s" - !define SHORTCUT "%(channel)s" - !define URLNAME "secondlife" - !define UNINSTALL_SETTINGS 1 - Caption "%(channel)s ${VERSION}" - """ - if 'installer_name' in self.args: - installer_file = self.args['installer_name'] - else: - installer_file = installer_file % substitution_strings - substitution_strings['installer_file'] = installer_file - - tempfile = "secondlife_setup_tmp.nsi" - # the following replaces strings in the nsi template - # it also does python-style % substitution - self.replace_in("installers/windows/installer_template.nsi", tempfile, { - "%%VERSION%%":version_vars, - "%%SOURCE%%":self.get_src_prefix(), - "%%GRID_VARS%%":grid_vars_template % substitution_strings, - "%%INSTALL_FILES%%":self.nsi_file_commands(True), - "%%DELETE_FILES%%":self.nsi_file_commands(False)}) - - # We use the Unicode version of NSIS, available from - # http://www.scratchpaper.com/ - # Check two paths, one for Program Files, and one for Program Files (x86). - # Yay 64bit windows. - NSIS_path = os.path.expandvars('${ProgramFiles}\\NSIS\\Unicode\\makensis.exe') - if not os.path.exists(NSIS_path): - NSIS_path = os.path.expandvars('${ProgramFiles(x86)}\\NSIS\\Unicode\\makensis.exe') - self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile)) - # self.remove(self.dst_path_of(tempfile)) - # If we're on a build machine, sign the code using our Authenticode certificate. JC - sign_py = os.path.expandvars("${SIGN}") - if not sign_py or sign_py == "${SIGN}": - sign_py = 'C:\\buildscripts\\code-signing\\sign.py' - else: - sign_py = sign_py.replace('\\', '\\\\\\\\') - python = os.path.expandvars("${PYTHON}") - if not python or python == "${PYTHON}": - python = 'python' - if os.path.exists(sign_py): - self.run_command("%s %s %s" % (python, sign_py, self.dst_path_of(installer_file).replace('\\', '\\\\\\\\'))) - else: - print "Skipping code signing,", sign_py, "does not exist" - self.created_path(self.dst_path_of(installer_file)) - self.package_file = 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(self.args['configuration'] + "/Second Life.app", dst="") - - if self.prefix(src="", dst="Contents"): # everything goes in Contents - self.path("Info-SecondLife.plist", dst="Info.plist") - - # copy additional libs in /Contents/MacOS/ - self.path("../../libraries/universal-darwin/lib_release/libndofdev.dylib", dst="MacOS/libndofdev.dylib") - self.path(os.path.join(os.pardir, "llplugin", "slplugin", self.args['configuration'], - "SLPlugin"), - os.path.join("MacOS", "SLPlugin")) - - # most everything goes in the Resources directory - if self.prefix(src="", dst="Resources"): - super(DarwinManifest, self).construct() - - 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.nib") - - # If we are not using the default channel, use the 'Firstlook - # icon' to show that it isn't a stable release. - if self.default_channel() and self.default_grid(): - self.path("secondlife.icns") - else: - self.path("secondlife_firstlook.icns", "secondlife.icns") - self.path("SecondLife.nib") - - # Translations - self.path("English.lproj") - self.path("German.lproj") - self.path("Japanese.lproj") - self.path("Korean.lproj") - self.path("da.lproj") - self.path("es.lproj") - self.path("fr.lproj") - self.path("hu.lproj") - self.path("it.lproj") - self.path("nl.lproj") - self.path("pl.lproj") - self.path("pt.lproj") - self.path("ru.lproj") - self.path("tr.lproj") - self.path("uk.lproj") - self.path("zh-Hans.lproj") - - # SLVoice and vivox lols - self.path("vivox-runtime/universal-darwin/libalut.dylib", "libalut.dylib") - self.path("vivox-runtime/universal-darwin/libopenal.dylib", "libopenal.dylib") - self.path("vivox-runtime/universal-darwin/libortp.dylib", "libortp.dylib") - self.path("vivox-runtime/universal-darwin/libvivoxsdk.dylib", "libvivoxsdk.dylib") - self.path("vivox-runtime/universal-darwin/SLVoice", "SLVoice") - - libdir = "../../libraries/universal-darwin/lib_release" - dylibs = {} - - # need to get the kdu dll from any of the build directories as well - for lib in "llkdu", "llcommon": - libfile = "lib%s.dylib" % lib - try: - self.path(self.find_existing_file(os.path.join(os.pardir, - lib, - self.args['configuration'], - libfile), - os.path.join(libdir, libfile)), - dst=libfile) - except RuntimeError: - print "Skipping %s" % libfile - dylibs[lib] = False - else: - dylibs[lib] = True - - if dylibs["llcommon"]: - for libfile in ("libapr-1.0.3.7.dylib", - "libaprutil-1.0.3.8.dylib", - "libexpat.0.5.0.dylib"): - self.path(os.path.join(libdir, libfile), libfile) - - #libfmodwrapper.dylib - self.path(self.args['configuration'] + "/libfmodwrapper.dylib", "libfmodwrapper.dylib") - - # our apps - self.path("../mac_crash_logger/" + self.args['configuration'] + "/mac-crash-logger.app", "mac-crash-logger.app") - self.path("../mac_updater/" + self.args['configuration'] + "/mac-updater.app", "mac-updater.app") - - # plugins - if self.prefix(src="", dst="llplugin"): - self.path("../media_plugins/quicktime/" + self.args['configuration'] + "/media_plugin_quicktime.dylib", "media_plugin_quicktime.dylib") - self.path("../media_plugins/webkit/" + self.args['configuration'] + "/media_plugin_webkit.dylib", "media_plugin_webkit.dylib") - self.path("../../libraries/universal-darwin/lib_release/libllqtwebkit.dylib", "libllqtwebkit.dylib") - - self.end_prefix("llplugin") - - # command line arguments for connecting to the proper grid - self.put_in_file(self.flags_list(), 'arguments.txt') - - self.end_prefix("Resources") - - self.end_prefix("Contents") - - # 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. - if ("package" in self.args['actions'] or - "unpacked" in self.args['actions']): - self.run_command('strip -S "%(viewer_binary)s"' % - { 'viewer_binary' : self.dst_path_of('Contents/MacOS/Second Life')}) - - - def package_finish(self): - channel_standin = 'Second Life' # hah, our default channel is not usable on its own - if not self.default_channel(): - channel_standin = self.channel() - - imagename="SecondLife_" + '_'.join(self.args['version']) - - # MBW -- If the mounted volume name changes, it breaks the .DS_Store's background image and icon positioning. - # If we really need differently named volumes, we'll need to create multiple DS_Store file images, or use some other trick. - - volname="Second Life Installer" # DO NOT CHANGE without understanding comment above - - if self.default_channel(): - if not self.default_grid(): - # beta case - imagename = imagename + '_' + self.args['grid'].upper() - else: - # first look, etc - imagename = imagename + '_' + self.channel_oneword().upper() - - 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 "%(vol)s" -fs HFS+ -type SPARSE -megabytes 400 -layout SPUD' % { - 'sparse':sparsename, - 'vol':volname}) - - # 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 - - if self.default_channel() and not self.default_grid(): - app_name = "Second Life " + self.args['grid'] - else: - app_name = channel_standin.strip() - - # Hack: - # Because there is no easy way to coerce the Finder into positioning - # the app bundle in the same place with different app names, we are - # adding multiple .DS_Store files to svn. There is one for release, - # one for release candidate and one for first look. Any other channels - # will use the release .DS_Store, and will look broken. - # - Ambroff 2008-08-20 - dmg_template = os.path.join( - 'installers', - 'darwin', - '%s-dmg' % "".join(self.channel_unique().split()).lower()) - - if not os.path.exists (self.src_path_of(dmg_template)): - dmg_template = os.path.join ('installers', 'darwin', 'release-dmg') - - for s,d in {self.get_dst_prefix():app_name + ".app", - os.path.join(dmg_template, "_VolumeIcon.icns"): ".VolumeIcon.icns", - os.path.join(dmg_template, "background.jpg"): "background.jpg", - os.path.join(dmg_template, "_DS_Store"): ".DS_Store"}.items(): - print "Copying to dmg", s, d - self.copy_action(self.src_path_of(s), os.path.join(volpath, d)) - - # Hide the background image, DS_Store file, and volume icon file (set their "visible" bit) - self.run_command('SetFile -a V "' + os.path.join(volpath, ".VolumeIcon.icns") + '"') - self.run_command('SetFile -a V "' + os.path.join(volpath, "background.jpg") + '"') - self.run_command('SetFile -a V "' + os.path.join(volpath, ".DS_Store") + '"') - - # Create the alias file (which is a resource file) from the .r - self.run_command('rez "' + self.src_path_of("installers/darwin/release-dmg/Applications-alias.r") + '" -o "' + os.path.join(volpath, "Applications") + '"') - - # Set the alias file's alias and custom icon bits - self.run_command('SetFile -a AC "' + os.path.join(volpath, "Applications") + '"') - - # Set the disk image root's custom icon bit - self.run_command('SetFile -a C "' + volpath + '"') - - # Unmount the image - self.run_command('hdiutil detach -force "' + 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.package_file = finalname - 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.png","secondlife_icon.png") - if self.prefix("linux_tools", dst=""): - self.path("client-readme.txt","README-linux.txt") - self.path("client-readme-voice.txt","README-linux-voice.txt") - self.path("client-readme-joystick.txt","README-linux-joystick.txt") - self.path("wrapper.sh","secondlife") - self.path("handle_secondlifeprotocol.sh", "etc/handle_secondlifeprotocol.sh") - self.path("register_secondlifeprotocol.sh", "etc/register_secondlifeprotocol.sh") - self.path("refresh_desktop_app_entry.sh", "etc/refresh_desktop_app_entry.sh") - self.path("launch_url.sh","etc/launch_url.sh") - self.path("install.sh") - self.end_prefix("linux_tools") - - # Create an appropriate gridargs.dat for this package, denoting required grid. - self.put_in_file(self.flags_list(), 'etc/gridargs.dat') - - - def package_finish(self): - if 'installer_name' in self.args: - installer_name = self.args['installer_name'] - else: - installer_name_components = ['SecondLife_', self.args.get('arch')] - installer_name_components.extend(self.args['version']) - installer_name = "_".join(installer_name_components) - if self.default_channel(): - if not self.default_grid(): - installer_name += '_' + self.args['grid'].upper() - else: - installer_name += '_' + self.channel_oneword().upper() - - # Fix access permissions - self.run_command(""" - find %(dst)s -type d | xargs --no-run-if-empty chmod 755; - find %(dst)s -type f -perm 0700 | xargs --no-run-if-empty chmod 0755; - find %(dst)s -type f -perm 0500 | xargs --no-run-if-empty chmod 0555; - find %(dst)s -type f -perm 0600 | xargs --no-run-if-empty chmod 0644; - find %(dst)s -type f -perm 0400 | xargs --no-run-if-empty chmod 0444; - true""" % {'dst':self.get_dst_prefix() }) - self.package_file = installer_name + '.tar.bz2' - - # 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.build_path_of(installer_name)}) - try: - # --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_build_prefix(), - 'inst_name': installer_name, - 'inst_path':self.build_path_of(installer_name)}) - finally: - self.run_command("mv %(inst)s %(dst)s" % { - 'dst': self.get_dst_prefix(), - 'inst': self.build_path_of(installer_name)}) - -class Linux_i686Manifest(LinuxManifest): - def construct(self): - super(Linux_i686Manifest, self).construct() - - # install either the libllkdu we just built, or a prebuilt one, in - # decreasing order of preference. for linux package, this goes to bin/ - for lib, destdir in ("llkdu", "bin"), ("llcommon", "lib"): - libfile = "lib%s.so" % lib - try: - self.path(self.find_existing_file(os.path.join(os.pardir, lib, libfile), - '../../libraries/i686-linux/lib_release_client/%s' % libfile), - dst=os.path.join(destdir, libfile)) - # keep this one to preserve syntax, open source mangling removes previous lines - pass - except RuntimeError: - print "Skipping %s - not found" % libfile - pass - - self.path("secondlife-stripped","bin/do-not-directly-run-secondlife-bin") - self.path("../linux_crash_logger/linux-crash-logger-stripped","bin/linux-crash-logger.bin") - self.path("../linux_updater/linux-updater-stripped", "bin/linux-updater.bin") - self.path("../llplugin/slplugin/SLPlugin", "bin/SLPlugin") - if self.prefix("res-sdl"): - self.path("*") - # recurse - self.end_prefix("res-sdl") - - # plugins - if self.prefix(src="", dst="bin/llplugin"): - self.path("../media_plugins/webkit/libmedia_plugin_webkit.so", "libmedia_plugin_webkit.so") - self.path("../media_plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_quicktime.so") - self.end_prefix("bin/llplugin") - - self.path("featuretable_linux.txt") - #self.path("secondlife-i686.supp") - - if self.prefix("../../libraries/i686-linux/lib_release_client", dst="lib"): - #self.path("libkdu_v42R.so", "libkdu.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("libcrypto.so.0.9.7") - self.path("libexpat.so.1") - self.path("libssl.so.0.9.7") - self.path("libuuid.so", "libuuid.so.1") - self.path("libSDL-1.2.so.0") - self.path("libELFIO.so") - self.path("libopenjpeg.so.1.3.0", "libopenjpeg.so.1.3") - self.path("libalut.so") - self.path("libopenal.so", "libopenal.so.1") - self.end_prefix("lib") - - # Vivox runtimes - if self.prefix(src="vivox-runtime/i686-linux", dst="bin"): - self.path("SLVoice") - self.end_prefix() - if self.prefix(src="vivox-runtime/i686-linux", dst="lib"): - self.path("libortp.so") - self.path("libvivoxsdk.so") - self.end_prefix("lib") - -class Linux_x86_64Manifest(LinuxManifest): - def construct(self): - super(Linux_x86_64Manifest, self).construct() - self.path("secondlife-stripped","bin/do-not-directly-run-secondlife-bin") - self.path("../linux_crash_logger/linux-crash-logger-stripped","linux-crash-logger.bin") - if self.prefix("res-sdl"): - self.path("*") - # recurse - self.end_prefix("res-sdl") - - self.path("featuretable_linux.txt") - self.path("secondlife-i686.supp") - -if __name__ == "__main__": - main() +#!/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. +# +# $LicenseInfo:firstyear=2006&license=viewergpl$ +# +# Copyright (c) 2006-2009, Linden Research, Inc. +# +# Second Life Viewer Source Code +# The source code in this file ("Source Code") is provided by Linden Lab +# to you under the terms of the GNU General Public License, version 2.0 +# ("GPL"), unless you have obtained a separate licensing agreement +# ("Other License"), formally executed by you and Linden Lab. Terms of +# the GPL can be found in doc/GPL-license.txt in this distribution, or +# online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +# +# There are special exceptions to the terms and conditions of the GPL as +# it is applied to this Source Code. View the full text of the exception +# in the file doc/FLOSS-exception.txt in this software distribution, or +# online at +# http://secondlifegrid.net/programs/open_source/licensing/flossexception +# +# By copying, modifying or distributing this software, you acknowledge +# that you have read and understood your obligations described above, +# and agree to abide by those obligations. +# +# ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +# WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +# COMPLETENESS OR PERFORMANCE. +# $/LicenseInfo$ +import sys +import os.path +import re +import tarfile +viewer_dir = os.path.dirname(__file__) +# add llmanifest library to our path so we don't have to muck with PYTHONPATH +sys.path.append(os.path.join(viewer_dir, '../lib/python/indra/util')) +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") + self.path(src="../../etc/message.xml", dst="app_settings/message.xml") + + 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("*.db2") + + # include the entire shaders directory recursively + self.path("shaders") + # ... and the entire windlight directory + self.path("windlight") + 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") + + # skins + if self.prefix(src="skins"): + self.path("paths.xml") + # include the entire textures directory recursively + if self.prefix(src="*/textures"): + self.path("*/*.tga") + self.path("*/*.j2c") + self.path("*/*.jpg") + self.path("*/*.png") + self.path("*.tga") + self.path("*.j2c") + self.path("*.jpg") + self.path("*.png") + self.path("textures.xml") + self.end_prefix("*/textures") + self.path("*/xui/*/*.xml") + self.path("*/xui/*/widgets/*.xml") + self.path("*/*.xml") + + # Local HTML files (e.g. loading screen) + if self.prefix(src="*/html"): + self.path("*.png") + self.path("*/*/*.html") + self.path("*/*/*.gif") + self.end_prefix("*/html") + self.end_prefix("skins") + + # Files in the newview/ directory + self.path("gpu_table.txt") + + def login_channel(self): + """Channel reported for login and upgrade purposes ONLY; + used for A/B testing""" + # NOTE: Do not return the normal channel if login_channel + # is not specified, as some code may branch depending on + # whether or not this is present + return self.args.get('login_channel') + + def grid(self): + return self.args['grid'] + def channel(self): + return self.args['channel'] + def channel_unique(self): + return self.channel().replace("Second Life", "").strip() + def channel_oneword(self): + return "".join(self.channel_unique().split()) + def channel_lowerword(self): + return self.channel_oneword().lower() + + def flags_list(self): + """ Convenience function that returns the command-line flags + for the grid""" + + # Set command line flags relating to the target grid + grid_flags = '' + if not self.default_grid(): + grid_flags = "--grid %(grid)s "\ + "--helperuri http://preview-%(grid)s.secondlife.com/helpers/" %\ + {'grid':self.grid()} + + # set command line flags for channel + channel_flags = '' + if self.login_channel() and self.login_channel() != self.channel(): + # Report a special channel during login, but use default + channel_flags = '--channel "%s"' % (self.login_channel()) + elif not self.default_channel(): + channel_flags = '--channel "%s"' % self.channel() + + # Deal with settings + setting_flags = '' + if not self.default_channel() or not self.default_grid(): + if self.default_grid(): + setting_flags = '--settings settings_%s.xml'\ + % self.channel_lowerword() + else: + setting_flags = '--settings settings_%s_%s.xml'\ + % (self.grid(), self.channel_lowerword()) + + return " ".join((channel_flags, grid_flags, setting_flags)).strip() + + +class WindowsManifest(ViewerManifest): + def final_exe(self): + if self.default_channel(): + if self.default_grid(): + return "SecondLife.exe" + else: + return "SecondLifePreview.exe" + else: + return ''.join(self.channel().split()) + '.exe' + + + def test_msvcrt_and_copy_action(self, src, dst): + # This can is used to test a dll manifest. + # It is used as a temporary override during the construct method + from test_win32_manifest import test_assembly_binding + if src and (os.path.exists(src) or os.path.islink(src)): + # ensure that destination path exists + self.cmakedirs(os.path.dirname(dst)) + self.created_paths.append(dst) + if not os.path.isdir(src): + if(self.args['configuration'].lower() == 'debug'): + test_assembly_binding(src, "Microsoft.VC80.DebugCRT", "8.0.50727.4053") + else: + test_assembly_binding(src, "Microsoft.VC80.CRT", "8.0.50727.4053") + self.ccopy(src,dst) + else: + raise Exception("Directories are not supported by test_CRT_and_copy_action()") + else: + print "Doesn't exist:", src + + def enable_crt_check(self): + WindowsManifest.copy_action = WindowsManifest.test_msvcrt_and_copy_action + + def disable_crt_check(self): + del WindowsManifest.copy_action + + def construct(self): + super(WindowsManifest, self).construct() + # Find secondlife-bin.exe in the 'configuration' dir, then rename it to the result of final_exe. + self.path(src='%s/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe()) + + self.enable_crt_check() + + # Plugin host application + self.path(os.path.join(os.pardir, + 'llplugin', 'slplugin', self.args['configuration'], "slplugin.exe"), + "slplugin.exe") + + # need to get the llcommon.dll from the build directory as well + if self.prefix(src=self.args['configuration'], dst=""): + try: + self.path('llcommon.dll') + self.path('libapr-1.dll') + self.path('libaprutil-1.dll') + self.path('libapriconv-1.dll') + except RuntimeError: + print "Skipping llcommon.dll (assuming llcommon was linked statically)" + self.end_prefix() + + # need to get the kdu dll from the build directory as well + try: + self.path('%s/llkdu.dll' % self.args['configuration'], dst='llkdu.dll') + except RuntimeError: + print "Skipping llkdu.dll" + + self.disable_crt_check() + + self.path(src="licenses-win32.txt", dst="licenses.txt") + self.path("featuretable.txt") + + # For use in crash reporting (generates minidumps) + self.path("dbghelp.dll") + + # For using FMOD for sound... DJS + self.path("fmod.dll") + + self.enable_crt_check() + + # For textures + if self.prefix(src=self.args['configuration'], dst=""): + if(self.args['configuration'].lower() == 'debug'): + self.path("openjpegd.dll") + else: + self.path("openjpeg.dll") + self.end_prefix() + + # Media plugins - QuickTime + if self.prefix(src='../media_plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"): + self.path("media_plugin_quicktime.dll") + self.end_prefix() + + # Media plugins - WebKit/Qt + if self.prefix(src='../media_plugins/webkit/%s' % self.args['configuration'], dst="llplugin"): + self.path("media_plugin_webkit.dll") + self.end_prefix() + + if self.prefix(src="../../libraries/i686-win32/lib/release", dst="llplugin"): + self.path("libeay32.dll") + self.path("qtcore4.dll") + self.path("qtgui4.dll") + self.path("qtnetwork4.dll") + self.path("qtopengl4.dll") + self.path("qtwebkit4.dll") + self.path("ssleay32.dll") + self.end_prefix() + + # For WebKit/Qt plugin runtimes (image format plugins) + if self.prefix(src="../../libraries/i686-win32/lib/release/imageformats", dst="llplugin/imageformats"): + self.path("qgif4.dll") + self.path("qico4.dll") + self.path("qjpeg4.dll") + self.path("qmng4.dll") + self.path("qsvg4.dll") + self.path("qtiff4.dll") + self.end_prefix() + + self.disable_crt_check() + + # These need to be installed as a SxS assembly, currently a 'private' assembly. + # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx + if self.prefix(src=self.args['configuration'], dst=""): + if self.args['configuration'] == 'Debug': + self.path("msvcr80d.dll") + self.path("msvcp80d.dll") + self.path("Microsoft.VC80.DebugCRT.manifest") + else: + self.path("msvcr80.dll") + self.path("msvcp80.dll") + self.path("Microsoft.VC80.CRT.manifest") + self.end_prefix() + + # The config file name needs to match the exe's name. + self.path(src="%s/secondlife-bin.exe.config" % self.args['configuration'], dst=self.final_exe() + ".config") + + # Vivox runtimes + if self.prefix(src=self.args['configuration'], dst=""): + self.path("SLVoice.exe") + self.path("alut.dll") + self.path("vivoxsdk.dll") + self.path("ortp.dll") + self.path("wrap_oal.dll") + self.end_prefix() + + # pull in the crash logger and updater from other projects + # tag:"crash-logger" here as a cue to the exporter + self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'], + dst="win_crash_logger.exe") + self.path(src='../win_updater/%s/windows-updater.exe' % self.args['configuration'], + dst="updater.exe") + + # For google-perftools tcmalloc allocator. + try: + self.path('%s/libtcmalloc_minimal.dll' % self.args['configuration']) + except: + print "Skipping libtcmalloc_minimal.dll" + pass + + 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): + # a standard map of strings for replacing in the templates + substitution_strings = { + 'version' : '.'.join(self.args['version']), + 'version_short' : '.'.join(self.args['version'][:-1]), + 'version_dashes' : '-'.join(self.args['version']), + 'final_exe' : self.final_exe(), + 'grid':self.args['grid'], + 'grid_caps':self.args['grid'].upper(), + # escape quotes becase NSIS doesn't handle them well + 'flags':self.flags_list().replace('"', '$\\"'), + 'channel':self.channel(), + 'channel_oneword':self.channel_oneword(), + 'channel_unique':self.channel_unique(), + } + + version_vars = """ + !define INSTEXE "%(final_exe)s" + !define VERSION "%(version_short)s" + !define VERSION_LONG "%(version)s" + !define VERSION_DASHES "%(version_dashes)s" + """ % substitution_strings + if self.default_channel(): + if self.default_grid(): + # release viewer + installer_file = "Second_Life_%(version_dashes)s_Setup.exe" + grid_vars_template = """ + OutFile "%(installer_file)s" + !define INSTFLAGS "%(flags)s" + !define INSTNAME "SecondLife" + !define SHORTCUT "Second Life" + !define URLNAME "secondlife" + Caption "Second Life ${VERSION}" + """ + else: + # beta grid viewer + installer_file = "Second_Life_%(version_dashes)s_(%(grid_caps)s)_Setup.exe" + grid_vars_template = """ + OutFile "%(installer_file)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}" + """ + else: + # some other channel on some grid + installer_file = "Second_Life_%(version_dashes)s_%(channel_oneword)s_Setup.exe" + grid_vars_template = """ + OutFile "%(installer_file)s" + !define INSTFLAGS "%(flags)s" + !define INSTNAME "SecondLife%(channel_oneword)s" + !define SHORTCUT "%(channel)s" + !define URLNAME "secondlife" + !define UNINSTALL_SETTINGS 1 + Caption "%(channel)s ${VERSION}" + """ + if 'installer_name' in self.args: + installer_file = self.args['installer_name'] + else: + installer_file = installer_file % substitution_strings + substitution_strings['installer_file'] = installer_file + + tempfile = "secondlife_setup_tmp.nsi" + # the following replaces strings in the nsi template + # it also does python-style % substitution + self.replace_in("installers/windows/installer_template.nsi", tempfile, { + "%%VERSION%%":version_vars, + "%%SOURCE%%":self.get_src_prefix(), + "%%GRID_VARS%%":grid_vars_template % substitution_strings, + "%%INSTALL_FILES%%":self.nsi_file_commands(True), + "%%DELETE_FILES%%":self.nsi_file_commands(False)}) + + # We use the Unicode version of NSIS, available from + # http://www.scratchpaper.com/ + # Check two paths, one for Program Files, and one for Program Files (x86). + # Yay 64bit windows. + NSIS_path = os.path.expandvars('${ProgramFiles}\\NSIS\\Unicode\\makensis.exe') + if not os.path.exists(NSIS_path): + NSIS_path = os.path.expandvars('${ProgramFiles(x86)}\\NSIS\\Unicode\\makensis.exe') + self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile)) + # self.remove(self.dst_path_of(tempfile)) + # If we're on a build machine, sign the code using our Authenticode certificate. JC + sign_py = os.path.expandvars("${SIGN}") + if not sign_py or sign_py == "${SIGN}": + sign_py = 'C:\\buildscripts\\code-signing\\sign.py' + else: + sign_py = sign_py.replace('\\', '\\\\\\\\') + python = os.path.expandvars("${PYTHON}") + if not python or python == "${PYTHON}": + python = 'python' + if os.path.exists(sign_py): + self.run_command("%s %s %s" % (python, sign_py, self.dst_path_of(installer_file).replace('\\', '\\\\\\\\'))) + else: + print "Skipping code signing,", sign_py, "does not exist" + self.created_path(self.dst_path_of(installer_file)) + self.package_file = 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(self.args['configuration'] + "/Second Life.app", dst="") + + if self.prefix(src="", dst="Contents"): # everything goes in Contents + self.path("Info-SecondLife.plist", dst="Info.plist") + + # copy additional libs in /Contents/MacOS/ + self.path("../../libraries/universal-darwin/lib_release/libndofdev.dylib", dst="MacOS/libndofdev.dylib") + + # most everything goes in the Resources directory + if self.prefix(src="", dst="Resources"): + super(DarwinManifest, self).construct() + + 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.nib") + + # If we are not using the default channel, use the 'Firstlook + # icon' to show that it isn't a stable release. + if self.default_channel() and self.default_grid(): + self.path("secondlife.icns") + else: + self.path("secondlife_firstlook.icns", "secondlife.icns") + self.path("SecondLife.nib") + + # Translations + self.path("English.lproj") + self.path("German.lproj") + self.path("Japanese.lproj") + self.path("Korean.lproj") + self.path("da.lproj") + self.path("es.lproj") + self.path("fr.lproj") + self.path("hu.lproj") + self.path("it.lproj") + self.path("nl.lproj") + self.path("pl.lproj") + self.path("pt.lproj") + self.path("ru.lproj") + self.path("tr.lproj") + self.path("uk.lproj") + self.path("zh-Hans.lproj") + + # SLVoice and vivox lols + self.path("vivox-runtime/universal-darwin/libalut.dylib", "libalut.dylib") + self.path("vivox-runtime/universal-darwin/libopenal.dylib", "libopenal.dylib") + self.path("vivox-runtime/universal-darwin/libortp.dylib", "libortp.dylib") + self.path("vivox-runtime/universal-darwin/libvivoxsdk.dylib", "libvivoxsdk.dylib") + self.path("vivox-runtime/universal-darwin/SLVoice", "SLVoice") + + libdir = "../../libraries/universal-darwin/lib_release" + dylibs = {} + + # need to get the kdu dll from any of the build directories as well + for lib in "llkdu", "llcommon": + libfile = "lib%s.dylib" % lib + try: + self.path(self.find_existing_file(os.path.join(os.pardir, + lib, + self.args['configuration'], + libfile), + os.path.join(libdir, libfile)), + dst=libfile) + except RuntimeError: + print "Skipping %s" % libfile + dylibs[lib] = False + else: + dylibs[lib] = True + + if dylibs["llcommon"]: + for libfile in ("libapr-1.0.3.7.dylib", + "libaprutil-1.0.3.8.dylib", + "libexpat.0.5.0.dylib"): + self.path(os.path.join(libdir, libfile), libfile) + + #libfmodwrapper.dylib + self.path(self.args['configuration'] + "/libfmodwrapper.dylib", "libfmodwrapper.dylib") + + # our apps + self.path("../mac_crash_logger/" + self.args['configuration'] + "/mac-crash-logger.app", "mac-crash-logger.app") + self.path("../mac_updater/" + self.args['configuration'] + "/mac-updater.app", "mac-updater.app") + + # plugin launcher + self.path("../llplugin/slplugin/" + self.args['configuration'] + "/SLPlugin", "SLPlugin") + + # plugins + if self.prefix(src="", dst="llplugin"): + self.path("../media_plugins/quicktime/" + self.args['configuration'] + "/media_plugin_quicktime.dylib", "media_plugin_quicktime.dylib") + self.path("../media_plugins/webkit/" + self.args['configuration'] + "/media_plugin_webkit.dylib", "media_plugin_webkit.dylib") + self.path("../../libraries/universal-darwin/lib_release/libllqtwebkit.dylib", "libllqtwebkit.dylib") + + self.end_prefix("llplugin") + + # command line arguments for connecting to the proper grid + self.put_in_file(self.flags_list(), 'arguments.txt') + + self.end_prefix("Resources") + + self.end_prefix("Contents") + + # 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. + if ("package" in self.args['actions'] or + "unpacked" in self.args['actions']): + self.run_command('strip -S "%(viewer_binary)s"' % + { 'viewer_binary' : self.dst_path_of('Contents/MacOS/Second Life')}) + + + def package_finish(self): + channel_standin = 'Second Life' # hah, our default channel is not usable on its own + if not self.default_channel(): + channel_standin = self.channel() + + imagename="SecondLife_" + '_'.join(self.args['version']) + + # MBW -- If the mounted volume name changes, it breaks the .DS_Store's background image and icon positioning. + # If we really need differently named volumes, we'll need to create multiple DS_Store file images, or use some other trick. + + volname="Second Life Installer" # DO NOT CHANGE without understanding comment above + + if self.default_channel(): + if not self.default_grid(): + # beta case + imagename = imagename + '_' + self.args['grid'].upper() + else: + # first look, etc + imagename = imagename + '_' + self.channel_oneword().upper() + + 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 "%(vol)s" -fs HFS+ -type SPARSE -megabytes 400 -layout SPUD' % { + 'sparse':sparsename, + 'vol':volname}) + + # 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 + + if self.default_channel() and not self.default_grid(): + app_name = "Second Life " + self.args['grid'] + else: + app_name = channel_standin.strip() + + # Hack: + # Because there is no easy way to coerce the Finder into positioning + # the app bundle in the same place with different app names, we are + # adding multiple .DS_Store files to svn. There is one for release, + # one for release candidate and one for first look. Any other channels + # will use the release .DS_Store, and will look broken. + # - Ambroff 2008-08-20 + dmg_template = os.path.join( + 'installers', + 'darwin', + '%s-dmg' % "".join(self.channel_unique().split()).lower()) + + if not os.path.exists (self.src_path_of(dmg_template)): + dmg_template = os.path.join ('installers', 'darwin', 'release-dmg') + + for s,d in {self.get_dst_prefix():app_name + ".app", + os.path.join(dmg_template, "_VolumeIcon.icns"): ".VolumeIcon.icns", + os.path.join(dmg_template, "background.jpg"): "background.jpg", + os.path.join(dmg_template, "_DS_Store"): ".DS_Store"}.items(): + print "Copying to dmg", s, d + self.copy_action(self.src_path_of(s), os.path.join(volpath, d)) + + # Hide the background image, DS_Store file, and volume icon file (set their "visible" bit) + self.run_command('SetFile -a V "' + os.path.join(volpath, ".VolumeIcon.icns") + '"') + self.run_command('SetFile -a V "' + os.path.join(volpath, "background.jpg") + '"') + self.run_command('SetFile -a V "' + os.path.join(volpath, ".DS_Store") + '"') + + # Create the alias file (which is a resource file) from the .r + self.run_command('rez "' + self.src_path_of("installers/darwin/release-dmg/Applications-alias.r") + '" -o "' + os.path.join(volpath, "Applications") + '"') + + # Set the alias file's alias and custom icon bits + self.run_command('SetFile -a AC "' + os.path.join(volpath, "Applications") + '"') + + # Set the disk image root's custom icon bit + self.run_command('SetFile -a C "' + volpath + '"') + + # Unmount the image + self.run_command('hdiutil detach -force "' + 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.package_file = finalname + 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.png","secondlife_icon.png") + if self.prefix("linux_tools", dst=""): + self.path("client-readme.txt","README-linux.txt") + self.path("client-readme-voice.txt","README-linux-voice.txt") + self.path("client-readme-joystick.txt","README-linux-joystick.txt") + self.path("wrapper.sh","secondlife") + self.path("handle_secondlifeprotocol.sh", "etc/handle_secondlifeprotocol.sh") + self.path("register_secondlifeprotocol.sh", "etc/register_secondlifeprotocol.sh") + self.path("refresh_desktop_app_entry.sh", "etc/refresh_desktop_app_entry.sh") + self.path("launch_url.sh","etc/launch_url.sh") + self.path("install.sh") + self.end_prefix("linux_tools") + + # Create an appropriate gridargs.dat for this package, denoting required grid. + self.put_in_file(self.flags_list(), 'etc/gridargs.dat') + + + def package_finish(self): + if 'installer_name' in self.args: + installer_name = self.args['installer_name'] + else: + installer_name_components = ['SecondLife_', self.args.get('arch')] + installer_name_components.extend(self.args['version']) + installer_name = "_".join(installer_name_components) + if self.default_channel(): + if not self.default_grid(): + installer_name += '_' + self.args['grid'].upper() + else: + installer_name += '_' + self.channel_oneword().upper() + + # Fix access permissions + self.run_command(""" + find %(dst)s -type d | xargs --no-run-if-empty chmod 755; + find %(dst)s -type f -perm 0700 | xargs --no-run-if-empty chmod 0755; + find %(dst)s -type f -perm 0500 | xargs --no-run-if-empty chmod 0555; + find %(dst)s -type f -perm 0600 | xargs --no-run-if-empty chmod 0644; + find %(dst)s -type f -perm 0400 | xargs --no-run-if-empty chmod 0444; + true""" % {'dst':self.get_dst_prefix() }) + self.package_file = installer_name + '.tar.bz2' + + # 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.build_path_of(installer_name)}) + try: + # --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_build_prefix(), + 'inst_name': installer_name, + 'inst_path':self.build_path_of(installer_name)}) + finally: + self.run_command("mv %(inst)s %(dst)s" % { + 'dst': self.get_dst_prefix(), + 'inst': self.build_path_of(installer_name)}) + +class Linux_i686Manifest(LinuxManifest): + def construct(self): + super(Linux_i686Manifest, self).construct() + + # install either the libllkdu we just built, or a prebuilt one, in + # decreasing order of preference. for linux package, this goes to bin/ + for lib, destdir in ("llkdu", "bin"), ("llcommon", "lib"): + libfile = "lib%s.so" % lib + try: + self.path(self.find_existing_file(os.path.join(os.pardir, lib, libfile), + '../../libraries/i686-linux/lib_release_client/%s' % libfile), + dst=os.path.join(destdir, libfile)) + # keep this one to preserve syntax, open source mangling removes previous lines + pass + except RuntimeError: + print "Skipping %s - not found" % libfile + pass + + self.path("secondlife-stripped","bin/do-not-directly-run-secondlife-bin") + self.path("../linux_crash_logger/linux-crash-logger-stripped","bin/linux-crash-logger.bin") + self.path("../linux_updater/linux-updater-stripped", "bin/linux-updater.bin") + self.path("../llplugin/slplugin/SLPlugin", "bin/SLPlugin") + if self.prefix("res-sdl"): + self.path("*") + # recurse + self.end_prefix("res-sdl") + + # plugins + if self.prefix(src="", dst="bin/llplugin"): + self.path("../media_plugins/webkit/libmedia_plugin_webkit.so", "libmedia_plugin_webkit.so") + self.path("../media_plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_quicktime.so") + self.end_prefix("bin/llplugin") + + self.path("featuretable_linux.txt") + #self.path("secondlife-i686.supp") + + if self.prefix("../../libraries/i686-linux/lib_release_client", dst="lib"): + #self.path("libkdu_v42R.so", "libkdu.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("libcrypto.so.0.9.7") + self.path("libexpat.so.1") + self.path("libssl.so.0.9.7") + self.path("libuuid.so", "libuuid.so.1") + self.path("libSDL-1.2.so.0") + self.path("libELFIO.so") + self.path("libopenjpeg.so.1.3.0", "libopenjpeg.so.1.3") + self.path("libalut.so") + self.path("libopenal.so", "libopenal.so.1") + self.end_prefix("lib") + + # Vivox runtimes + if self.prefix(src="vivox-runtime/i686-linux", dst="bin"): + self.path("SLVoice") + self.end_prefix() + if self.prefix(src="vivox-runtime/i686-linux", dst="lib"): + self.path("libortp.so") + self.path("libvivoxsdk.so") + self.end_prefix("lib") + +class Linux_x86_64Manifest(LinuxManifest): + def construct(self): + super(Linux_x86_64Manifest, self).construct() + self.path("secondlife-stripped","bin/do-not-directly-run-secondlife-bin") + self.path("../linux_crash_logger/linux-crash-logger-stripped","linux-crash-logger.bin") + if self.prefix("res-sdl"): + self.path("*") + # recurse + self.end_prefix("res-sdl") + + self.path("featuretable_linux.txt") + self.path("secondlife-i686.supp") + +if __name__ == "__main__": + main() -- cgit v1.2.3 From 6f4b9d63f8eb97a7c4717a3160de358000b0981b Mon Sep 17 00:00:00 2001 From: "Mark Palange (Mani)" Date: Fri, 18 Sep 2009 19:29:18 -0700 Subject: Added dependcies to create_app_config_file. Further Clean up of dll copying merge mess. --- indra/newview/viewer_manifest.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 6ef905cca7..af3868394b 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -208,9 +208,11 @@ class WindowsManifest(ViewerManifest): self.path('libapr-1.dll') self.path('libaprutil-1.dll') self.path('libapriconv-1.dll') - except RuntimeError: + except RuntimeError, err: + print err.message print "Skipping llcommon.dll (assuming llcommon was linked statically)" - self.end_prefix() + + self.end_prefix() # need to get the kdu dll from the build directory as well try: -- cgit v1.2.3 From 0eedd1d9e8490ae771c8ea4af5c412d95385c800 Mon Sep 17 00:00:00 2001 From: brad kittenbrink Date: Wed, 23 Sep 2009 19:46:36 -0400 Subject: Oops libtcmalloc_minimal.dll was being packaged in a subdir it shouldn't have been. --- indra/newview/viewer_manifest.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index af3868394b..f62ed4b374 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -306,11 +306,15 @@ class WindowsManifest(ViewerManifest): dst="updater.exe") # For google-perftools tcmalloc allocator. - try: - self.path('%s/libtcmalloc_minimal.dll' % self.args['configuration']) - except: - print "Skipping libtcmalloc_minimal.dll" - pass + if self.prefix(src=self.args['configuration'], dst=""): + try: + if self.args['configuration'] == 'Debug': + self.path('libtcmalloc_minimal-debug.dll') + else: + self.path('libtcmalloc_minimal.dll') + except: + print "Skipping libtcmalloc_minimal.dll" + self.end_prefix() def nsi_file_commands(self, install=True): def wpath(path): -- cgit v1.2.3 From 17f9fd5f9653077b6059b34147a447310a30daec Mon Sep 17 00:00:00 2001 From: "Mark Palange (Mani)" Date: Fri, 25 Sep 2009 19:23:24 -0700 Subject: Changes force no crt manifest linking in windows plugin files. --- indra/newview/viewer_manifest.py | 58 +++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 15 deletions(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index af3868394b..d21e520974 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -165,7 +165,7 @@ class WindowsManifest(ViewerManifest): def test_msvcrt_and_copy_action(self, src, dst): - # This can is used to test a dll manifest. + # This is used to test a dll manifest. # It is used as a temporary override during the construct method from test_win32_manifest import test_assembly_binding if src and (os.path.exists(src) or os.path.islink(src)): @@ -183,10 +183,38 @@ class WindowsManifest(ViewerManifest): else: print "Doesn't exist:", src - def enable_crt_check(self): + def test_for_no_msvcrt_manifest_and_copy_action(self, src, dst): + # This is used to test that no manifest for the msvcrt exists. + # It is used as a temporary override during the construct method + from test_win32_manifest import test_assembly_binding + if src and (os.path.exists(src) or os.path.islink(src)): + # ensure that destination path exists + self.cmakedirs(os.path.dirname(dst)) + self.created_paths.append(dst) + if not os.path.isdir(src): + try: + if(self.args['configuration'].lower() == 'debug'): + test_assembly_binding(src, "Microsoft.VC80.DebugCRT", "") + else: + test_assembly_binding(src, "Microsoft.VC80.CRT", "") + raise Exception("Unknown condition") + except Exception, err: + if err.message != "No matching assembly" or err.message != "No manifest found": + raise Exception("Found unexpected MSVCRT manifest binding") + + self.ccopy(src,dst) + else: + raise Exception("Directories are not supported by test_CRT_and_copy_action()") + else: + print "Doesn't exist:", src + + def enable_crt_manifest_check(self): WindowsManifest.copy_action = WindowsManifest.test_msvcrt_and_copy_action - def disable_crt_check(self): + def enable_no_crt_manifest_check(self): + WindowsManifest.copy_action = WindowsManifest.test_for_no_msvcrt_manifest_and_copy_action + + def disable_manifest_check(self): del WindowsManifest.copy_action def construct(self): @@ -194,7 +222,7 @@ class WindowsManifest(ViewerManifest): # Find secondlife-bin.exe in the 'configuration' dir, then rename it to the result of final_exe. self.path(src='%s/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe()) - self.enable_crt_check() + self.enable_crt_manifest_check() # Plugin host application self.path(os.path.join(os.pardir, @@ -220,7 +248,15 @@ class WindowsManifest(ViewerManifest): except RuntimeError: print "Skipping llkdu.dll" - self.disable_crt_check() + self.disable_manifest_check() + + # For textures + if self.prefix(src=self.args['configuration'], dst=""): + if(self.args['configuration'].lower() == 'debug'): + self.path("openjpegd.dll") + else: + self.path("openjpeg.dll") + self.end_prefix() self.path(src="licenses-win32.txt", dst="licenses.txt") self.path("featuretable.txt") @@ -231,15 +267,7 @@ class WindowsManifest(ViewerManifest): # For using FMOD for sound... DJS self.path("fmod.dll") - self.enable_crt_check() - - # For textures - if self.prefix(src=self.args['configuration'], dst=""): - if(self.args['configuration'].lower() == 'debug'): - self.path("openjpegd.dll") - else: - self.path("openjpeg.dll") - self.end_prefix() + self.enable_no_crt_manifest_check() # Media plugins - QuickTime if self.prefix(src='../media_plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"): @@ -271,7 +299,7 @@ class WindowsManifest(ViewerManifest): self.path("qtiff4.dll") self.end_prefix() - self.disable_crt_check() + self.disable_manifest_check() # These need to be installed as a SxS assembly, currently a 'private' assembly. # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx -- cgit v1.2.3 From c4c537e957458650a2948ffbd3a787f007d87f7a Mon Sep 17 00:00:00 2001 From: "Mark Palange (Mani)" Date: Tue, 29 Sep 2009 10:02:17 -0700 Subject: Removing app.exe.config file creation. Should no longer be needed with rebuilt 3rd party libs. /me crosses fingers. --- indra/newview/viewer_manifest.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 8a3905633f..579bfaa4d9 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -314,9 +314,6 @@ class WindowsManifest(ViewerManifest): self.path("Microsoft.VC80.CRT.manifest") self.end_prefix() - # The config file name needs to match the exe's name. - self.path(src="%s/secondlife-bin.exe.config" % self.args['configuration'], dst=self.final_exe() + ".config") - # Vivox runtimes if self.prefix(src=self.args['configuration'], dst=""): self.path("SLVoice.exe") -- cgit v1.2.3 From 292aecbb3e14658c470978efeb7cd790ec156fd2 Mon Sep 17 00:00:00 2001 From: brad kittenbrink Date: Wed, 30 Sep 2009 18:57:00 -0700 Subject: Updated test_win32_manifest.py to throw custom exception objects, rather than relying on string comparison. --- indra/newview/viewer_manifest.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 579bfaa4d9..bda81a505d 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -187,6 +187,7 @@ class WindowsManifest(ViewerManifest): # This is used to test that no manifest for the msvcrt exists. # It is used as a temporary override during the construct method from test_win32_manifest import test_assembly_binding + from test_win32_manifest import NoManifestException, NoMatchingAssemblyException if src and (os.path.exists(src) or os.path.islink(src)): # ensure that destination path exists self.cmakedirs(os.path.dirname(dst)) @@ -198,9 +199,10 @@ class WindowsManifest(ViewerManifest): else: test_assembly_binding(src, "Microsoft.VC80.CRT", "") raise Exception("Unknown condition") - except Exception, err: - if err.message != "No matching assembly" or err.message != "No manifest found": - raise Exception("Found unexpected MSVCRT manifest binding") + except NoManifestException, err: + pass + except NoMatchingAssemblyException, err: + pass self.ccopy(src,dst) else: -- cgit v1.2.3 From 0f5bbec3747f3ff2b1d580506d35dc080fcd1a98 Mon Sep 17 00:00:00 2001 From: "Mark Palange (Mani)" Date: Mon, 5 Oct 2009 13:33:02 -0700 Subject: Minor tweaks to fix up viewer_manifest. -bad tcmalloc handling indentation -added nsis path for x64 windows --- indra/newview/viewer_manifest.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 036fa4923f..4ce7c953ed 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -271,8 +271,8 @@ class WindowsManifest(ViewerManifest): # For google-perftools tcmalloc allocator. if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): - self.path("libtcmalloc_minimal.dll") - self.end_prefix() + self.path("libtcmalloc_minimal.dll") + self.end_prefix() def nsi_file_commands(self, install=True): @@ -395,6 +395,8 @@ class WindowsManifest(ViewerManifest): # We use the Unicode version of NSIS, available from # http://www.scratchpaper.com/ NSIS_path = 'C:\\Program Files\\NSIS\\Unicode\\makensis.exe' + if not os.path.exists(NSIS_path): + NSIS_path = os.path.expandvars('${ProgramFiles(x86)}\\NSIS\\Unicode\\makensis.exe') self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile)) # self.remove(self.dst_path_of(tempfile)) # If we're on a build machine, sign the code using our Authenticode certificate. JC -- cgit v1.2.3 From d885db79f94ee3d6a2b4ed7febe7beb69d0c7d51 Mon Sep 17 00:00:00 2001 From: brad kittenbrink Date: Tue, 6 Oct 2009 16:59:45 -0700 Subject: Hmm, somehow we were getting away with packaging a broken libuuid.so.1 on linux. --- indra/newview/viewer_manifest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index e98ef4749b..ad6976c555 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -797,7 +797,7 @@ class Linux_i686Manifest(LinuxManifest): self.path("libcrypto.so.0.9.7") self.path("libexpat.so.1") self.path("libssl.so.0.9.7") - self.path("libuuid.so", "libuuid.so.1") + self.path("libuuid.so.1", "libuuid.so.1") self.path("libSDL-1.2.so.0") self.path("libELFIO.so") self.path("libopenjpeg.so.1.3.0", "libopenjpeg.so.1.3") -- cgit v1.2.3 From 47e02d13f7e6307d9eb507177b88bbf0ab496894 Mon Sep 17 00:00:00 2001 From: CG Linden Date: Wed, 14 Oct 2009 16:41:48 -0700 Subject: Increase the .dmg setup size from 500MB to 700MB --- indra/newview/viewer_manifest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 41aa13614e..f2e89ef062 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -626,7 +626,7 @@ class DarwinManifest(ViewerManifest): # make sure we don't have stale files laying about self.remove(sparsename, finalname) - self.run_command('hdiutil create "%(sparse)s" -volname "%(vol)s" -fs HFS+ -type SPARSE -megabytes 500 -layout SPUD' % { + self.run_command('hdiutil create "%(sparse)s" -volname "%(vol)s" -fs HFS+ -type SPARSE -megabytes 700 -layout SPUD' % { 'sparse':sparsename, 'vol':volname}) -- cgit v1.2.3 From 0f121ca6b8d2a8ad14d5f7f613e65aa4ce42a782 Mon Sep 17 00:00:00 2001 From: palange Date: Wed, 21 Oct 2009 17:59:35 -0700 Subject: DEV-41615 DEV-41615 Add symlinks to updater and crash logger app bundles to fix dylib refs.\nllcommon, apr and expat dylibs were missing from the crash logger and updater, instead of shipping extra copies were using relative pathed symlinks to the copies in the Second Life.app/Contents/Resources folder. --- indra/newview/viewer_manifest.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 06eb1e1265..7f3a56425c 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -573,6 +573,24 @@ class DarwinManifest(ViewerManifest): self.path("../mac_crash_logger/" + self.args['configuration'] + "/mac-crash-logger.app", "mac-crash-logger.app") self.path("../mac_updater/" + self.args['configuration'] + "/mac-updater.app", "mac-updater.app") + # our apps dependencies on shared libs + if dylibs["llcommon"]: + mac_crash_logger_res_path = self.dst_path_of("mac-crash-logger.app/Contents/Resources") + mac_updater_res_path = self.dst_path_of("mac-updater.app/Contents/Resources") + for libfile in ("libllcommon.dylib", + "libapr-1.0.3.7.dylib", + "libaprutil-1.0.3.8.dylib", + "libexpat.0.5.0.dylib"): + target_lib = os.path.join('../../..', libfile) + self.run_command("ln -s %(target)s '%(link)s'" % + {'target': target_lib, + 'link' : os.path.join(mac_crash_logger_res_path, libfile)} + ) + self.run_command("ln -s %(target)s '%(link)s'" % + {'target': target_lib, + 'link' : os.path.join(mac_updater_res_path, libfile)} + ) + # plugin launcher self.path("../llplugin/slplugin/" + self.args['configuration'] + "/SLPlugin", "SLPlugin") -- cgit v1.2.3 From f58857824e71edc39d98180e7750aee9ff1d780e Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 22 Oct 2009 10:40:27 -0400 Subject: Fixed Mac build breaker: failing ln -s command. viewer_manifest.py has acquired new 'ln -s' commands to avoid duplicating shared .dylib files between the main Second Life app bundle and the embedded mac-updater and mac-crash-logger app bundles. Unfortunately, the second time I ran with these new commands, they failed because the target already existed. Added -f switch to make that case benign. --- indra/newview/viewer_manifest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview/viewer_manifest.py') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 7f3a56425c..231a8e21a5 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -582,11 +582,11 @@ class DarwinManifest(ViewerManifest): "libaprutil-1.0.3.8.dylib", "libexpat.0.5.0.dylib"): target_lib = os.path.join('../../..', libfile) - self.run_command("ln -s %(target)s '%(link)s'" % + self.run_command("ln -sf %(target)s '%(link)s'" % {'target': target_lib, 'link' : os.path.join(mac_crash_logger_res_path, libfile)} ) - self.run_command("ln -s %(target)s '%(link)s'" % + self.run_command("ln -sf %(target)s '%(link)s'" % {'target': target_lib, 'link' : os.path.join(mac_updater_res_path, libfile)} ) -- cgit v1.2.3