diff options
Diffstat (limited to 'indra/newview/viewer_manifest.py')
-rwxr-xr-x | indra/newview/viewer_manifest.py | 343 |
1 files changed, 183 insertions, 160 deletions
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 19863dd845..f7b3a45e8d 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -7,7 +7,7 @@ $LicenseInfo:firstyear=2006&license=viewerlgpl$ Second Life Viewer Source Code -Copyright (C) 2006-2011, Linden Research, Inc. +Copyright (C) 2006-2014, Linden Research, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -38,7 +38,7 @@ viewer_dir = os.path.dirname(__file__) # Put it FIRST because some of our build hosts have an ancient install of # indra.util.llmanifest under their system Python! sys.path.insert(0, os.path.join(viewer_dir, os.pardir, "lib", "python")) -from indra.util.llmanifest import LLManifest, main, proper_windows_path, path_ancestors +from indra.util.llmanifest import LLManifest, main, proper_windows_path, path_ancestors, CHANNEL_VENDOR_BASE, RELEASE_CHANNEL, ManifestError try: from llbase import llsd except ImportError: @@ -104,26 +104,43 @@ class ViewerManifest(LLManifest): self.path("dictionaries") self.end_prefix(pkgdir) - # CHOP-955: If we have "sourceid" in the build process - # environment, generate it into settings_install.xml. - try: - sourceid = os.environ["sourceid"] - except KeyError: - # no sourceid, no settings_install.xml file - pass - else: - if sourceid: - # Single-entry subset of the LLSD content of settings.xml - content = dict(sourceid=dict(Comment='Identify referring agency to Linden web servers', - Persist=1, - Type='String', - Value=sourceid)) - # put_in_file(src=) need not be an actual pathname; it - # only needs to be non-empty - settings_install = self.put_in_file(llsd.format_pretty_xml(content), - "settings_install.xml", - src="environment") - print "Put sourceid '%s' in %s" % (sourceid, settings_install) + # CHOP-955: If we have "sourceid" or "viewer_channel" in the + # build process environment, generate it into + # settings_install.xml. + settings_template = dict( + sourceid=dict(Comment='Identify referring agency to Linden web servers', + Persist=1, + Type='String', + Value=''), + CmdLineGridChoice=dict(Comment='Default grid', + Persist=0, + Type='String', + Value=''), + CmdLineChannel=dict(Comment='Command line specified channel name', + Persist=0, + Type='String', + Value='')) + settings_install = {} + if 'sourceid' in self.args and self.args['sourceid']: + settings_install['sourceid'] = settings_template['sourceid'].copy() + settings_install['sourceid']['Value'] = self.args['sourceid'] + print "Set sourceid in settings_install.xml to '%s'" % self.args['sourceid'] + + if 'channel_suffix' in self.args and self.args['channel_suffix']: + settings_install['CmdLineChannel'] = settings_template['CmdLineChannel'].copy() + settings_install['CmdLineChannel']['Value'] = self.channel_with_pkg_suffix() + print "Set CmdLineChannel in settings_install.xml to '%s'" % self.channel_with_pkg_suffix() + + if 'grid' in self.args and self.args['grid']: + settings_install['CmdLineGridChoice'] = settings_template['CmdLineGridChoice'].copy() + settings_install['CmdLineGridChoice']['Value'] = self.grid() + print "Set CmdLineGridChoice in settings_install.xml to '%s'" % self.grid() + + # put_in_file(src=) need not be an actual pathname; it + # only needs to be non-empty + self.put_in_file(llsd.format_pretty_xml(settings_install), + "settings_install.xml", + src="environment") self.end_prefix("app_settings") @@ -186,62 +203,72 @@ class ViewerManifest(LLManifest): 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 channel_with_pkg_suffix(self): + fullchannel=self.channel() + if 'channel_suffix' in self.args and self.args['channel_suffix']: + fullchannel+=' '+self.args['channel_suffix'] + return fullchannel + + def channel_variant(self): + global CHANNEL_VENDOR_BASE + return self.channel().replace(CHANNEL_VENDOR_BASE, "").strip() + + def channel_type(self): # returns 'release', 'beta', 'project', or 'test' + global CHANNEL_VENDOR_BASE + channel_qualifier=self.channel().replace(CHANNEL_VENDOR_BASE, "").lower().strip() + if channel_qualifier.startswith('release'): + channel_type='release' + elif channel_qualifier.startswith('beta'): + channel_type='beta' + elif channel_qualifier.startswith('project'): + channel_type='project' + else: + channel_type='test' + return channel_type + + def channel_variant_app_suffix(self): + # get any part of the compiled channel name after the CHANNEL_VENDOR_BASE + suffix=self.channel_variant() + # by ancient convention, we don't use Release in the app name + if self.channel_type() == 'release': + suffix=suffix.replace('Release', '').strip() + # for the base release viewer, suffix will now be null - for any other, append what remains + if len(suffix) > 0: + suffix = "_"+ ("_".join(suffix.split())) + # the additional_packages mechanism adds more to the installer name (but not to the app name itself) + if 'channel_suffix' in self.args and self.args['channel_suffix']: + suffix+='_'+("_".join(self.args['channel_suffix'].split())) + return suffix + + def installer_base_name(self): + global CHANNEL_VENDOR_BASE + # a standard map of strings for replacing in the templates + substitution_strings = { + 'channel_vendor_base' : '_'.join(CHANNEL_VENDOR_BASE.split()), + 'channel_variant_underscores':self.channel_variant_app_suffix(), + 'version_underscores' : '_'.join(self.args['version']), + 'arch':self.args['arch'] + } + return "%(channel_vendor_base)s%(channel_variant_underscores)s_%(version_underscores)s_%(arch)s" % substitution_strings def app_name(self): - app_suffix='Test' - channel_type=self.channel_lowerword() - if channel_type.startswith('release') : + global CHANNEL_VENDOR_BASE + channel_type=self.channel_type() + if channel_type == 'release': app_suffix='Viewer' - elif re.match('^(beta|project).*',channel_type) : - app_suffix=self.channel_unique() - return "Second Life "+app_suffix - + else: + app_suffix=self.channel_variant() + return CHANNEL_VENDOR_BASE + ' ' + app_suffix + + def app_name_oneword(self): + return ''.join(self.app_name().split()) + def icon_path(self): - icon_path="icons/" - channel_type=self.channel_lowerword() - print "Icon channel type '%s'" % channel_type - if channel_type.startswith('release') : - icon_path += 'release' - elif re.match('^beta.*',channel_type) : - icon_path += 'beta' - elif re.match('^project.*',channel_type) : - icon_path += 'project' - else : - icon_path += 'test' - return icon_path - - def flags_list(self): - """ Convenience function that returns the command-line flags - for the grid""" - - # The original role of this method seems to have been to build a - # grid-specific viewer: one that would, on launch, preselect a - # particular grid. (Apparently that dates back to when the protocol - # between viewer and simulator required them to be updated in - # lockstep, so that "the beta grid" required "a beta viewer.") But - # those viewer command-line switches no longer work without tweaking - # user_settings/grids.xml. In fact, going forward, it's unclear what - # use case that would address. - - # This method also set a channel-specific (or grid-and-channel- - # specific) user_settings/settings_something.xml file. It has become - # clear that saving user settings in a channel-specific file causes - # more problems (confusion) than it solves, so we've discontinued that. - - # In fact we now avoid forcing viewer command-line switches at all, - # instead introducing a settings_install.xml file. Command-line - # switches don't aggregate well; for instance the generated --channel - # switch actually prevented the user specifying --channel on the - # command line. Settings files have well-defined override semantics. - return None + return "icons/" + self.channel_type() def extract_names(self,src): try: @@ -266,15 +293,9 @@ class ViewerManifest(LLManifest): random.shuffle(names) return ', '.join(names) -class WindowsManifest(ViewerManifest): +class Windows_i686_Manifest(ViewerManifest): def final_exe(self): - app_suffix="Test" - channel_type=self.channel_lowerword() - if channel_type.startswith('release') : - app_suffix='' - elif re.match('^(beta|project).*',channel_type) : - app_suffix=''.join(self.channel_unique().split()) - return "SecondLife"+app_suffix+".exe" + return self.app_name_oneword()+".exe" def test_msvcrt_and_copy_action(self, src, dst): # This is used to test a dll manifest. @@ -323,7 +344,7 @@ class WindowsManifest(ViewerManifest): print "Doesn't exist:", src def construct(self): - super(WindowsManifest, self).construct() + super(Windows_i686_Manifest, self).construct() if self.is_packaging_viewer(): # Find secondlife-bin.exe in the 'configuration' dir, then rename it to the result of final_exe. @@ -556,62 +577,33 @@ class WindowsManifest(ViewerManifest): '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(), 'flags':'', - 'channel':self.channel(), - 'channel_oneword':self.channel_oneword(), - 'channel_unique':self.channel_unique(), - 'subchannel_underscores':'_'.join(self.channel_unique().split()) + 'app_name':self.app_name(), + 'app_name_oneword':self.app_name_oneword() } + installer_file = self.installer_base_name() + '_Setup.exe' + substitution_strings['installer_file'] = installer_file + 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 "SecondLifeViewer" - !define SHORTCUT "Second Life Viewer" - !define URLNAME "secondlife" - Caption "Second Life" - """ - else: - # alternate 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}" - """ + + if self.channel_type() == 'release': + substitution_strings['caption'] = CHANNEL_VENDOR_BASE else: - # some other channel (grid name not used) - installer_file = "Second_Life_%(version_dashes)s_%(subchannel_underscores)s_Setup.exe" - grid_vars_template = """ + substitution_strings['caption'] = self.app_name() + ' ${VERSION}' + + inst_vars_template = """ OutFile "%(installer_file)s" - !define INSTFLAGS "%(flags)s" - !define INSTNAME "SecondLife%(channel_oneword)s" - !define SHORTCUT "%(channel)s" + !define INSTNAME "%(app_name_oneword)s" + !define SHORTCUT "%(app_name)s" !define URLNAME "secondlife" - !define UNINSTALL_SETTINGS 1 - Caption "%(channel)s ${VERSION}" + Caption "%(caption)s" """ - 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 @@ -619,7 +611,7 @@ class WindowsManifest(ViewerManifest): self.replace_in("installers/windows/installer_template.nsi", tempfile, { "%%VERSION%%":version_vars, "%%SOURCE%%":self.get_src_prefix(), - "%%GRID_VARS%%":grid_vars_template % substitution_strings, + "%%INST_VARS%%":inst_vars_template % substitution_strings, "%%INSTALL_FILES%%":self.nsi_file_commands(True), "%%DELETE_FILES%%":self.nsi_file_commands(False)}) @@ -630,7 +622,22 @@ class WindowsManifest(ViewerManifest): 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)) + installer_created=False + nsis_attempts=3 + nsis_retry_wait=15 + while (not installer_created) and (nsis_attempts > 0): + try: + nsis_attempts-=1; + self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile)) + installer_created=True # if no exception was raised, the codesign worked + except ManifestError, err: + if nsis_attempts: + print >> sys.stderr, "nsis failed, waiting %d seconds before retrying" % nsis_retry_wait + time.sleep(nsis_retry_wait) + nsis_retry_wait*=2 + else: + print >> sys.stderr, "Maximum nsis attempts exceeded; giving up" + raise # 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}") @@ -649,7 +656,7 @@ class WindowsManifest(ViewerManifest): self.package_file = installer_file -class DarwinManifest(ViewerManifest): +class Darwin_i386_Manifest(ViewerManifest): def is_packaging_viewer(self): # darwin requires full app bundle packaging even for debugging. return True @@ -671,7 +678,7 @@ class DarwinManifest(ViewerManifest): # most everything goes in the Resources directory if self.prefix(src="", dst="Resources"): - super(DarwinManifest, self).construct() + super(Darwin_i386_Manifest, self).construct() if self.prefix("cursors_mac"): self.path("*.tif") @@ -742,7 +749,6 @@ class DarwinManifest(ViewerManifest): "libcollada14dom.dylib", "libexpat.1.5.2.dylib", "libexception_handler.dylib", - "libfmodex.dylib", "libGLOD.dylib", ): dylibs += path_optional(os.path.join(libdir, libfile), libfile) @@ -758,6 +764,20 @@ class DarwinManifest(ViewerManifest): 'SLVoice', ): self.path2basename(libdir, libfile) + + # dylibs that vary based on configuration + if self.args['configuration'].lower() == 'debug': + for libfile in ( + "libfmodexL.dylib", + ): + dylibs += path_optional(os.path.join("../packages/lib/debug", + libfile), libfile) + else: + for libfile in ( + "libfmodex.dylib", + ): + dylibs += path_optional(os.path.join("../packages/lib/release", + libfile), libfile) # our apps for app_bld_dir, app in (("mac_crash_logger", "mac-crash-logger.app"), @@ -807,6 +827,7 @@ class DarwinManifest(ViewerManifest): self.run_command("chmod +x %r" % os.path.join(self.get_dst_prefix(), script)) def package_finish(self): + global CHANNEL_VENDOR_BASE # Sign the app if requested. if 'signature' in self.args: identity = self.args['signature'] @@ -825,33 +846,43 @@ class DarwinManifest(ViewerManifest): keychain_pwd = open(keychain_pwd_path).read().rstrip() self.run_command('security unlock-keychain -p "%s" "%s/Library/Keychains/viewer.keychain"' % ( keychain_pwd, home_path ) ) - self.run_command('codesign --verbose --force --keychain "%(home_path)s/Library/Keychains/viewer.keychain" --sign %(identity)r %(bundle)r' % { - 'home_path' : home_path, - 'identity': identity, - 'bundle': self.get_dst_prefix() - }) + signed=False + sign_attempts=3 + sign_retry_wait=15 + while (not signed) and (sign_attempts > 0): + try: + sign_attempts-=1; + self.run_command( + 'codesign --verbose --force --keychain "%(home_path)s/Library/Keychains/viewer.keychain" --sign %(identity)r %(bundle)r' % { + 'home_path' : home_path, + 'identity': identity, + 'bundle': self.get_dst_prefix() + }) + signed=True # if no exception was raised, the codesign worked + except ManifestError, err: + if sign_attempts: + print >> sys.stderr, "codesign failed, waiting %d seconds before retrying" % sign_retry_wait + time.sleep(sign_retry_wait) + sign_retry_wait*=2 + else: + print >> sys.stderr, "Maximum codesign attempts exceeded; giving up" + raise 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 + volname=CHANNEL_VENDOR_BASE+" 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() + imagename = self.installer_base_name() 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)r -volname %(vol)r -fs HFS+ -type SPARSE -megabytes 700 -layout SPUD' % { + self.run_command('hdiutil create %(sparse)r -volname %(vol)r -fs HFS+ -type SPARSE -megabytes 1000 -layout SPUD' % { 'sparse':sparsename, 'vol':volname}) @@ -878,7 +909,7 @@ class DarwinManifest(ViewerManifest): # will use the release .DS_Store, and will look broken. # - Ambroff 2008-08-20 dmg_template = os.path.join( - 'installers', 'darwin', '%s-dmg' % self.channel_lowerword()) + 'installers', 'darwin', '%s-dmg' % self.channel_type()) if not os.path.exists (self.src_path_of(dmg_template)): dmg_template = os.path.join ('installers', 'darwin', 'release-dmg') @@ -926,6 +957,7 @@ class DarwinManifest(ViewerManifest): print "Converting temp disk image to final disk image" self.run_command('hdiutil convert %(sparse)r -format UDZO -imagekey zlib-level=9 -o %(final)r' % {'sparse':sparsename, 'final':finalname}) + self.run_command('hdiutil internet-enable -yes %(final)r' % {'final':finalname}) # get rid of the temp file self.package_file = finalname self.remove(sparsename) @@ -960,8 +992,9 @@ class LinuxManifest(ViewerManifest): # recurse self.end_prefix("res-sdl") - # Get the icons based on the channel + # Get the icons based on the channel type icon_path = self.icon_path() + print "DEBUG: icon_path '%s'" % icon_path if self.prefix(src=icon_path, dst="") : self.path("secondlife_256.png","secondlife_icon.png") if self.prefix(src="",dst="res-sdl") : @@ -987,17 +1020,7 @@ class LinuxManifest(ViewerManifest): self.run_command("chmod +x %r" % os.path.join(self.get_dst_prefix(), script)) 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() + installer_name = self.installer_base_name() self.strip_binaries() @@ -1039,9 +1062,9 @@ class LinuxManifest(ViewerManifest): print "* Going strip-crazy on the packaged binaries, since this is a RELEASE build" self.run_command(r"find %(d)r/bin %(d)r/lib -type f \! -name update_install | xargs --no-run-if-empty strip -S" % {'d': self.get_dst_prefix()} ) # makes some small assumptions about our packaged dir structure -class Linux_i686Manifest(LinuxManifest): +class Linux_i686_Manifest(LinuxManifest): def construct(self): - super(Linux_i686Manifest, self).construct() + super(Linux_i686_Manifest, self).construct() if self.prefix("../packages/lib/release", dst="lib"): self.path("libapr-1.so") @@ -1127,9 +1150,9 @@ class Linux_i686Manifest(LinuxManifest): self.strip_binaries() -class Linux_x86_64Manifest(LinuxManifest): +class Linux_x86_64_Manifest(LinuxManifest): def construct(self): - super(Linux_x86_64Manifest, self).construct() + super(Linux_x86_64_Manifest, self).construct() # support file for valgrind debug tool self.path("secondlife-i686.supp") |