From a507df6e284ca11badaceda43effcd101ea09bac Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 18 Sep 2012 11:40:45 -0400 Subject: SWAT-711: Create Mac app bundle symlinks only for .dylib files that exist. Previous viewer_manifest.py unconditionally created Mac symlinks for all expected .dylib files. Recent change to revert to statically linking llcommon means we no longer build libllcommon.dylib, therefore we no longer copy it, therefore any symlink to that library will be broken by definition. Change to create symlinks for .dylib files that were successfully copied. --- indra/lib/python/indra/util/llmanifest.py | 21 +++ indra/newview/viewer_manifest.py | 241 +++++++++++++++--------------- 2 files changed, 144 insertions(+), 118 deletions(-) diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py index a4fb77357c..8feb6b97a9 100644 --- a/indra/lib/python/indra/util/llmanifest.py +++ b/indra/lib/python/indra/util/llmanifest.py @@ -621,6 +621,23 @@ class LLManifest(object): d = src_re.sub(d_template, s.replace('\\', '/')) yield os.path.normpath(s), os.path.normpath(d) + def path2basename(self, path, file): + """ + It is a common idiom to write: + self.path(os.path.join(somedir, somefile), somefile) + + So instead you can write: + self.path2basename(somedir, somefile) + + Note that this is NOT the same as: + self.path(os.path.join(somedir, somefile)) + + which is the same as: + temppath = os.path.join(somedir, somefile) + self.path(temppath, temppath) + """ + return self.path(os.path.join(path, file), file) + def path(self, src, dst=None): sys.stdout.write("Processing %s => %s ... " % (src, dst)) sys.stdout.flush() @@ -666,6 +683,10 @@ class LLManifest(object): print "%d files" % count + # Let caller check whether we processed as many files as expected. In + # particular, let caller notice 0. + return count + def do(self, *actions): self.actions = actions self.construct() diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index d1c952ac3b..8b1c278cb3 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -28,6 +28,7 @@ $/LicenseInfo$ """ import sys import os.path +import errno import re import tarfile import time @@ -74,20 +75,20 @@ class ViewerManifest(LLManifest): # include the list of Lindens (if any) # see https://wiki.lindenlab.com/wiki/Generated_Linden_Credits linden_names_path = os.getenv("LINDEN_CREDITS") - if linden_names_path : + if not linden_names_path : + print "No 'LINDEN_CREDITS' specified in environment, using built-in list" + else: try: linden_file = open(linden_names_path,'r') + except IOError: + print "No Linden names found at '%s', using built-in list" % linden_names_path + else: # all names should be one line, but the join below also converts to a string linden_names = ', '.join(linden_file.readlines()) self.put_in_file(linden_names, "lindens.txt") linden_file.close() print "Linden names extracted from '%s'" % linden_names_path self.file_list.append([linden_names_path,self.dst_path_of("lindens.txt")]) - except IOError: - print "No Linden names found at '%s', using built-in list" % linden_names_path - pass - else : - print "No 'LINDEN_CREDITS' specified in environment, using built-in list" # ... and the entire windlight directory self.path("windlight") @@ -149,14 +150,9 @@ class ViewerManifest(LLManifest): self.path("gpu_table.txt") # The summary.json file gets left in the base checkout dir by - # build.sh. It's only created for a build.sh build, therefore we - # have to check whether it exists. :-P - summary_json = "summary.json" - summary_json_path = os.path.join(os.pardir, os.pardir, summary_json) - if os.path.exists(os.path.join(self.get_src_prefix(), summary_json_path)): - self.path(summary_json_path, summary_json) - else: - print "No %s" % os.path.join(self.get_src_prefix(), summary_json_path) + # build.sh. It's only created for a build.sh build. + if not self.path2basename(os.path.join(os.pardir, os.pardir), "summary.json"): + print "No summary.json file" def login_channel(self): """Channel reported for login and upgrade purposes ONLY; @@ -327,13 +323,13 @@ class WindowsManifest(ViewerManifest): 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") + self.path2basename(os.path.join(os.pardir, + 'llplugin', 'slplugin', self.args['configuration']), + "slplugin.exe") #self.disable_manifest_check() - self.path(src="../viewer_components/updater/scripts/windows/update_install.bat", dst="update_install.bat") + self.path2basename("../viewer_components/updater/scripts/windows", "update_install.bat") # Get shared libs from the shared libs staging directory if self.prefix(src=os.path.join(os.pardir, 'sharedlibs', self.args['configuration']), dst=""): @@ -367,9 +363,7 @@ class WindowsManifest(ViewerManifest): # Get fmod dll, continue if missing - try: - self.path("fmod.dll") - except: + if not self.path("fmod.dll"): print "Skipping fmod.dll" # For textures @@ -710,85 +704,82 @@ class DarwinManifest(ViewerManifest): self.path("uk.lproj") self.path("zh-Hans.lproj") - libdir = "../packages/lib/release" - dylibs = {} + def path_optional(src, dst): + """ + For a number of our self.path() calls, not only do we want + to deal with the absence of src, we also want to remember + which were present. Return either an empty list (absent) + or a list containing dst (present). Concatenate these + return values to get a list of all libs that are present. + """ + if self.path(src, dst): + return [dst] + print "Skipping %s" % dst + return [] - # Need to get the llcommon dll from any of the build directories as well - lib = "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.dylib", - "libaprutil-1.0.dylib", - "libexpat.1.5.2.dylib", - "libexception_handler.dylib", - "libGLOD.dylib", - "libcollada14dom.dylib" - ): - self.path(os.path.join(libdir, libfile), libfile) - - # SLVoice and vivox lols - for libfile in ('libsndfile.dylib', 'libvivoxoal.dylib', 'libortp.dylib', \ - 'libvivoxsdk.dylib', 'libvivoxplatform.dylib', 'SLVoice') : - self.path(os.path.join(libdir, libfile), libfile) + libdir = "../packages/lib/release" + # dylibs is a list of all the .dylib files we expect to need + # in our bundled sub-apps. For each of these we'll create a + # symlink from sub-app/Contents/Resources to the real .dylib. + # Need to get the llcommon dll from any of the build directories as well. + libfile = "libllcommon.dylib" + dylibs = path_optional(self.find_existing_file(os.path.join(os.pardir, + "llcommon", + self.args['configuration'], + libfile), + os.path.join(libdir, libfile)), + dst=libfile) + + for libfile in ( + "libapr-1.0.dylib", + "libaprutil-1.0.dylib", + "libcollada14dom.dylib", + "libexpat.1.5.2.dylib", + "libexception_handler.dylib", + "libGLOD.dylib", + ): + dylibs += path_optional(os.path.join(libdir, libfile), libfile) + + # SLVoice and vivox lols, no symlinks needed + for libfile in ( + 'libortp.dylib', + 'libsndfile.dylib', + 'libvivoxoal.dylib', + 'libvivoxsdk.dylib', + 'libvivoxplatform.dylib', + 'SLVoice', + ): + self.path2basename(libdir, libfile) - try: - # FMOD for sound - self.path(self.args['configuration'] + "/libfmodwrapper.dylib", "libfmodwrapper.dylib") - except: - print "Skipping FMOD - not found" + # FMOD for sound + libfile = "libfmodwrapper.dylib" + path_optional(os.path.join(self.args['configuration'], libfile), libfile) # 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.app", "SLPlugin.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") - slplugin_res_path = self.dst_path_of("SLPlugin.app/Contents/Resources") - for libfile in ("libllcommon.dylib", - "libapr-1.0.dylib", - "libaprutil-1.0.dylib", - "libexpat.1.5.2.dylib", - "libexception_handler.dylib", - "libGLOD.dylib", - "libcollada14dom.dylib" - ): - target_lib = os.path.join('../../..', libfile) - self.run_command("ln -sf %(target)r %(link)r" % - {'target': target_lib, - 'link' : os.path.join(mac_crash_logger_res_path, libfile)} - ) - self.run_command("ln -sf %(target)r %(link)r" % - {'target': target_lib, - 'link' : os.path.join(mac_updater_res_path, libfile)} - ) - self.run_command("ln -sf %(target)r %(link)r" % - {'target': target_lib, - 'link' : os.path.join(slplugin_res_path, libfile)} - ) + for app_bld_dir, app in (("mac_crash_logger", "mac-crash-logger.app"), + ("mac_updater", "mac-updater.app"), + # plugin launcher + (os.path.join("llplugin", "slplugin"), "SLPlugin.app"), + ): + self.path2basename(os.path.join(os.pardir, + app_bld_dir, self.args['configuration']), + app) + + # our apps dependencies on shared libs + # for each app, for each dylib we collected in dylibs, + # create a symlink to the real copy of the dylib. + resource_path = self.dst_path_of(os.path.join(app, "Contents", "Resources")) + for libfile in dylibs: + symlinkf(os.path.join(os.pardir, os.pardir, os.pardir, libfile), + os.path.join(resource_path, libfile)) # 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("../packages/lib/release/libllqtwebkit.dylib", "libllqtwebkit.dylib") + self.path2basename("../media_plugins/quicktime/" + self.args['configuration'], + "media_plugin_quicktime.dylib") + self.path2basename("../media_plugins/webkit/" + self.args['configuration'], + "media_plugin_webkit.dylib") + self.path2basename("../packages/lib/release", "libllqtwebkit.dylib") self.end_prefix("llplugin") @@ -931,20 +922,25 @@ class LinuxManifest(ViewerManifest): 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") + if self.prefix(src="", dst="etc"): + self.path("handle_secondlifeprotocol.sh") + self.path("register_secondlifeprotocol.sh") + self.path("refresh_desktop_app_entry.sh") + self.path("launch_url.sh") + self.end_prefix("etc") 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') - self.path("secondlife-bin","bin/do-not-directly-run-secondlife-bin") - self.path("../linux_crash_logger/linux-crash-logger","bin/linux-crash-logger.bin") - self.path("../linux_updater/linux-updater", "bin/linux-updater.bin") - self.path("../llplugin/slplugin/SLPlugin", "bin/SLPlugin") + if self.prefix(src="", dst="bin"): + self.path("secondlife-bin","do-not-directly-run-secondlife-bin") + self.path("../linux_crash_logger/linux-crash-logger","linux-crash-logger.bin") + self.path("../linux_updater/linux-updater", "linux-updater.bin") + self.path2basename("../llplugin/slplugin", "SLPlugin") + self.path2basename("../viewer_components/updater/scripts/linux", "update_install") + self.end_prefix("bin") if self.prefix("res-sdl"): self.path("*") @@ -960,17 +956,13 @@ class LinuxManifest(ViewerManifest): self.end_prefix("res-sdl") self.end_prefix(icon_path) - self.path("../viewer_components/updater/scripts/linux/update_install", "bin/update_install") - # plugins if self.prefix(src="", dst="bin/llplugin"): - self.path("../media_plugins/webkit/libmedia_plugin_webkit.so", "libmedia_plugin_webkit.so") + self.path2basename("../media_plugins/webkit", "libmedia_plugin_webkit.so") self.path("../media_plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_gstreamer.so") self.end_prefix("bin/llplugin") - try: - self.path("../llcommon/libllcommon.so", "lib/libllcommon.so") - except: + if not self.path("../llcommon/libllcommon.so", "lib/libllcommon.so"): print "Skipping llcommon.so (assuming llcommon was linked statically)" self.path("featuretable_linux.txt") @@ -1054,11 +1046,8 @@ class Linux_i686Manifest(LinuxManifest): self.path("libopenjpeg.so*") self.path("libdirectfb-1.4.so.5") self.path("libfusion-1.4.so.5") - self.path("libdirect-1.4.so.5.0.4") - self.path("libdirect-1.4.so.5") - self.path("libhunspell-1.3.so") - self.path("libhunspell-1.3.so.0") - self.path("libhunspell-1.3.so.0.0.0") + self.path("libdirect-1.4.so.5*") + self.path("libhunspell-1.3.so*") self.path("libalut.so") self.path("libopenal.so", "libopenal.so.1") self.path("libopenal.so", "libvivoxoal.so.1") # vivox's sdk expects this soname @@ -1082,12 +1071,8 @@ class Linux_i686Manifest(LinuxManifest): # version number. self.path("libfontconfig.so.*.*") self.path("libtcmalloc.so*") #formerly called google perf tools - try: - self.path("libfmod-3.75.so") - pass - except: - print "Skipping libfmod-3.75.so - not found" - pass + if not self.path("libfmod-3.75.so"): + print "Skipping libfmod-3.75.so - not found" self.end_prefix("lib") # Vivox runtimes @@ -1116,5 +1101,25 @@ class Linux_x86_64Manifest(LinuxManifest): ################################################################ +def symlinkf(src, dst): + """ + Like ln -sf, but uses os.symlink() instead of running ln. + """ + try: + os.symlink(src, dst) + except OSError, err: + if err.errno != errno.EEXIST: + raise + # We could just blithely attempt to remove and recreate the target + # file, but that strategy doesn't work so well if we don't have + # permissions to remove it. Check to see if it's already the + # symlink we want, which is the usual reason for EEXIST. + if not (os.path.islink(dst) and os.readlink(dst) == src): + # Here either dst isn't a symlink or it's the wrong symlink. + # Remove and recreate. Caller will just have to deal with any + # exceptions at this stage. + os.remove(dst) + os.symlink(src, dst) + if __name__ == "__main__": main() -- cgit v1.2.3 From ca76f9aaf89b4a57c38d81ab6d2d91e91b2fd8a0 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Tue, 6 Nov 2012 14:51:04 -0500 Subject: tag merge of DRTVWR-223 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 6d9234d3e8..9b10cf59b8 100644 --- a/.hgtags +++ b/.hgtags @@ -309,3 +309,4 @@ ceed0b65a69f1eac20d523e0203320a32f9a3f3c DRTVWR-215 733ceac77583874f3626ef7a15c105b83ef0f5bb 3.4.0-beta7 d02759655d6b36d60f4a927e4bfce82844a82ef5 3.4.0-release 97977c67245f52db20eb15f1918cc0f24778cabc 3.4.0-release +e497dcde7a3653e384eb223a8a460030e89c294c DRTVWR-223 -- cgit v1.2.3