diff --git a/autobuild.xml b/autobuild.xml index a0877de17a..a8bdc51034 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3524,9 +3524,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - fc3291e515f11e8324407949fb53cb53 + 92235fabdca2d3865014f7ec630e2688 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11161/62517/viewer_manager-1.0.511006-darwin64-511006.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11444/64857/viewer_manager-1.0.511221-darwin64-511221.tar.bz2 name darwin64 @@ -3548,9 +3548,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 93421dfd7486517350c434cf568d0914 + bfea9c61d0b29d741081c0c8a315d364 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11163/62529/viewer_manager-1.0.511006-windows-511006.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11446/64863/viewer_manager-1.0.511221-windows-511221.tar.bz2 name windows @@ -3561,7 +3561,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 1.0.511006 + 1.0.511221 vlc-bin diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py index 842744bb29..7c9c9df297 100755 --- a/indra/lib/python/indra/util/llmanifest.py +++ b/indra/lib/python/indra/util/llmanifest.py @@ -527,6 +527,20 @@ class LLManifest(object): return path def run_command(self, command): + """ + Runs an external command. + Raises ManifestError exception if the command returns a nonzero status. + """ + print "Running command:", command + sys.stdout.flush() + try: + subprocess.check_call(command) + except subprocess.CalledProcessError as err: + raise ManifestError( "Command %s returned non-zero status (%s)" + % (command, err.returncode) ) + + # Added for compatibility reasons + def run_command_shell(self, command): """ Runs an external command. Raises ManifestError exception if the command returns a nonzero status. @@ -538,6 +552,7 @@ class LLManifest(object): except subprocess.CalledProcessError as err: raise ManifestError( "Command %s returned non-zero status (%s)" % (command, err.returncode) ) + # def created_path(self, path): """ Declare that you've created a path in order to @@ -550,6 +565,7 @@ class LLManifest(object): def put_in_file(self, contents, dst, src=None): # write contents as dst dst_path = self.dst_path_of(dst) + self.cmakedirs(os.path.dirname(dst_path)) f = open(dst_path, "wb") try: f.write(contents) diff --git a/indra/newview/fs_viewer_manifest.py b/indra/newview/fs_viewer_manifest.py index dd7c10c48b..a1ee0ccc50 100644 --- a/indra/newview/fs_viewer_manifest.py +++ b/indra/newview/fs_viewer_manifest.py @@ -96,12 +96,12 @@ class FSViewerManifest: if not os.path.exists( debugDir ): os.makedirs( debugDir ) - self.run_command( "objcopy %s %s" % (fileSource, debugFile) ) + self.run_command_shell( "objcopy %s %s" % (fileSource, debugFile) ) - self.run_command( "gdb -batch -ex \"save gdb-index %s\" %s" % (debugDir, debugFile ) ) - self.run_command( "objcopy --add-section .gdb_index=%s --set-section-flags .gdb_index=readonly %s %s" % (debugIndexFile, debugFile, debugFile) ) + self.run_command_shell( "gdb -batch -ex \"save gdb-index %s\" %s" % (debugDir, debugFile ) ) + self.run_command_shell( "objcopy --add-section .gdb_index=%s --set-section-flags .gdb_index=readonly %s %s" % (debugIndexFile, debugFile, debugFile) ) - self.run_command( "cd %s && objcopy --add-gnu-debuglink=%s %s" % (debugDir, debugName, fileBin) ) + self.run_command_shell( "cd %s && objcopy --add-gnu-debuglink=%s %s" % (debugDir, debugName, fileBin) ) if( os.path.exists( "%s/firestorm-symbols-linux.tar.bz2" % self.args['configuration'].lower()) ): symName = "%s/Phoenix_%s_%s_%s_symbols-linux.tar.bz2" % ( self.args['configuration'].lower(), self.fs_channel_legacy_oneword(), @@ -174,7 +174,7 @@ class FSViewerManifest: def fs_setuid_chromesandbox( self ): filename = os.path.join( self.get_dst_prefix(), "bin", "chrome-sandbox" ) - self.run_command( "chmod 755 %s" % ( filename) ) # Strip sticky bit that might be set (in case the following two commands fail) - self.run_command( "sudo -n chown root:root %s || exit 0" % ( filename) ) - self.run_command( "sudo -n chmod 4755 %s || exit 0" % ( filename) ) + self.run_command_shell( "chmod 755 %s" % ( filename) ) # Strip sticky bit that might be set (in case the following two commands fail) + self.run_command_shell( "sudo -n chown root:root %s || exit 0" % ( filename) ) + self.run_command_shell( "sudo -n chmod 4755 %s || exit 0" % ( filename) ) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 65ad83d189..1b4c407803 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -32,11 +32,13 @@ import os.path import shutil import errno import json +import plistlib +import random import re +import stat +import subprocess import tarfile import time -import random -import subprocess # import shlex @@ -341,6 +343,129 @@ class ViewerManifest(LLManifest,FSViewerManifest): random.shuffle(names) return ', '.join(names) + def relsymlinkf(self, src, dst=None, catch=True): + """ + relsymlinkf() is just like symlinkf(), but instead of requiring the + caller to pass 'src' as a relative pathname, this method expects 'src' + to be absolute, and creates a symlink whose target is the relative + path from 'src' to dirname(dst). + """ + dstdir, dst = self._symlinkf_prep_dst(src, dst) + + # Determine the relative path starting from the directory containing + # dst to the intended src. + src = self.relpath(src, dstdir) + + self._symlinkf(src, dst, catch) + return dst + + def symlinkf(self, src, dst=None, catch=True): + """ + Like ln -sf, but uses os.symlink() instead of running ln. This creates + a symlink at 'dst' that points to 'src' -- see: + https://docs.python.org/2/library/os.html#os.symlink + + If you omit 'dst', this creates a symlink with basename(src) at + get_dst_prefix() -- in other words: put a symlink to this pathname + here at the current dst prefix. + + 'src' must specifically be a *relative* symlink. It makes no sense to + create an absolute symlink pointing to some path on the build machine! + + Also: + - We prepend 'dst' with the current get_dst_prefix(), so it has similar + meaning to associated self.path() calls. + - We ensure that the containing directory os.path.dirname(dst) exists + before attempting the symlink. + + If you pass catch=False, exceptions will be propagated instead of + caught. + """ + dstdir, dst = self._symlinkf_prep_dst(src, dst) + self._symlinkf(src, dst, catch) + return dst + + def _symlinkf_prep_dst(self, src, dst): + # helper for relsymlinkf() and symlinkf() + if dst is None: + dst = os.path.basename(src) + dst = os.path.join(self.get_dst_prefix(), dst) + # Seems silly to prepend get_dst_prefix() to dst only to call + # os.path.dirname() on it again, but this works even when the passed + # 'dst' is itself a pathname. + dstdir = os.path.dirname(dst) + self.cmakedirs(dstdir) + return (dstdir, dst) + + def _symlinkf(self, src, dst, catch): + # helper for relsymlinkf() and symlinkf() + # the passed src must be relative + if os.path.isabs(src): + raise ManifestError("Do not symlinkf(absolute %r, asis=True)" % src) + + # The outer catch is the one that reports failure even after attempted + # recovery. + try: + # At the inner layer, recovery may be possible. + try: + os.symlink(src, dst) + except OSError as 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. + elif os.path.islink(dst): + if os.readlink(dst) == src: + # the requested link already exists + pass + else: + # dst is the wrong symlink; attempt to remove and recreate it + os.remove(dst) + os.symlink(src, dst) + elif os.path.isdir(dst): + print "Requested symlink (%s) exists but is a directory; replacing" % dst + shutil.rmtree(dst) + os.symlink(src, dst) + elif os.path.exists(dst): + print "Requested symlink (%s) exists but is a file; replacing" % dst + os.remove(dst) + os.symlink(src, dst) + else: + # out of ideas + raise + except Exception as err: + # report + print "Can't symlink %r -> %r: %s: %s" % \ + (dst, src, err.__class__.__name__, err) + # if caller asked us not to catch, re-raise this exception + if not catch: + raise + + def relpath(self, path, base=None, symlink=False): + """ + Return the relative path from 'base' to the passed 'path'. If base is + omitted, self.get_dst_prefix() is assumed. In other words: make a + same-name symlink to this path right here in the current dest prefix. + + Normally we resolve symlinks. To retain symlinks, pass symlink=True. + """ + if base is None: + base = self.get_dst_prefix() + + # Since we use os.path.relpath() for this, which is purely textual, we + # must ensure that both pathnames are absolute. + if symlink: + # symlink=True means: we know path is (or indirects through) a + # symlink, don't resolve, we want to use the symlink. + abspath = os.path.abspath + else: + # symlink=False means to resolve any symlinks we may find + abspath = os.path.realpath + + return os.path.relpath(abspath(path), abspath(base)) + class WindowsManifest(ViewerManifest): # We want the platform, per se, for every Windows build to be 'win'. The @@ -359,6 +484,8 @@ class WindowsManifest(ViewerManifest): # 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 + # TODO: This is redundant with LLManifest.copy_action(). Why aren't we + # calling copy_action() in conjunction with 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)) @@ -379,6 +506,8 @@ class WindowsManifest(ViewerManifest): # 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 + # TODO: This is redundant with LLManifest.copy_action(). Why aren't we + # calling copy_action() in conjunction with 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)) @@ -407,19 +536,17 @@ class WindowsManifest(ViewerManifest): pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') relpkgdir = os.path.join(pkgdir, "lib", "release") debpkgdir = os.path.join(pkgdir, "lib", "debug") - vmpdir = os.path.join(pkgdir, "VMP") - llbasedir = os.path.join(pkgdir, "lib", "python", "llbase") if self.is_packaging_viewer(): # Find secondlife-bin.exe in the 'configuration' dir, then rename it to the result of final_exe. self.path(src='%s/firestorm-bin.exe' % self.args['configuration'], dst=self.final_exe()) # Remove VMP - # include the compiled launcher scripts so that it gets included in the file_list - #self.path(src='%s/SL_Launcher.exe' % vmpdir, dst="SL_Launcher.exe") - - #IUM is not normally executed directly, just imported. No exe needed. - #self.path2basename(vmpdir,"InstallerUserMessage.py") + #with self.prefix(src=os.path.join(pkgdir, "VMP"), dst=""): + # include the compiled launcher scripts so that it gets included in the file_list + # self.path('SL_Launcher.exe') + #IUM is not normally executed directly, just imported. No exe needed. + # self.path("InstallerUserMessage.py") #with self.prefix(src=self.icon_path(), dst="vmp_icons"): # self.path("secondlife.ico") @@ -430,12 +557,9 @@ class WindowsManifest(ViewerManifest): # self.path("*.gif") #before, we only needed llbase at build time. With VMP, we need it at run time. - #llbase_path = os.path.join(self.get_dst_prefix(),'llbase') - #if not os.path.exists(llbase_path): - # os.makedirs(llbase_path) - #with self.prefix(dst="llbase"): - # self.path2basename(llbasedir,"*.py") - # self.path2basename(llbasedir,"_cllsd.so") + #with self.prefix(src=os.path.join(pkgdir, "lib", "python", "llbase"), dst="llbase"): + # self.path("*.py") + # self.path("_cllsd.so") # Remove VMP # Plugin host application @@ -550,31 +674,19 @@ class WindowsManifest(ViewerManifest): self.path("media_plugin_gstreamer10.dll") # CEF runtime files - debug - if self.args['configuration'].lower() == 'debug': - with self.prefix(src=os.path.join(os.pardir, 'packages', 'bin', 'debug'), dst="llplugin"): - self.path("chrome_elf.dll") - self.path("d3dcompiler_43.dll") - self.path("d3dcompiler_47.dll") - self.path("libcef.dll") - self.path("libEGL.dll") - self.path("libGLESv2.dll") - self.path("dullahan_host.exe") - self.path("natives_blob.bin") - self.path("snapshot_blob.bin") - self.path("widevinecdmadapter.dll") - else: # CEF runtime files - not debug (release, relwithdebinfo etc.) - with self.prefix(src=os.path.join(os.pardir, 'packages', 'bin', 'release'), dst="llplugin"): - self.path("chrome_elf.dll") - self.path("d3dcompiler_43.dll") - self.path("d3dcompiler_47.dll") - self.path("libcef.dll") - self.path("libEGL.dll") - self.path("libGLESv2.dll") - self.path("dullahan_host.exe") - self.path("natives_blob.bin") - self.path("snapshot_blob.bin") - self.path("widevinecdmadapter.dll") + config = 'debug' if self.args['configuration'].lower() == 'debug' else 'release' + with self.prefix(src=os.path.join(pkgdir, 'bin', config), dst="llplugin"): + self.path("chrome_elf.dll") + self.path("d3dcompiler_43.dll") + self.path("d3dcompiler_47.dll") + self.path("libcef.dll") + self.path("libEGL.dll") + self.path("libGLESv2.dll") + self.path("dullahan_host.exe") + self.path("natives_blob.bin") + self.path("snapshot_blob.bin") + self.path("widevinecdmadapter.dll") # MSVC DLLs needed for CEF and have to be in same directory as plugin with self.prefix(src=os.path.join(os.pardir, 'sharedlibs', 'Release'), dst="llplugin"): @@ -582,7 +694,7 @@ class WindowsManifest(ViewerManifest): self.path("msvcr120.dll") # CEF files common to all configurations - with self.prefix(src=os.path.join(os.pardir, 'packages', 'resources'), dst="llplugin"): + with self.prefix(src=os.path.join(pkgdir, 'resources'), dst="llplugin"): self.path("cef.pak") self.path("cef_100_percent.pak") self.path("cef_200_percent.pak") @@ -590,7 +702,7 @@ class WindowsManifest(ViewerManifest): self.path("devtools_resources.pak") self.path("icudtl.dat") - with self.prefix(src=os.path.join(os.pardir, 'packages', 'resources', 'locales'), dst=os.path.join('llplugin', 'locales')): + with self.prefix(src=os.path.join(pkgdir, 'resources', 'locales'), dst=os.path.join('llplugin', 'locales')): self.path("am.pak") self.path("ar.pak") self.path("bg.pak") @@ -645,7 +757,7 @@ class WindowsManifest(ViewerManifest): self.path("zh-CN.pak") self.path("zh-TW.pak") - with self.prefix(src=os.path.join(os.pardir, 'packages', 'bin', 'release'), dst="llplugin"): + with self.prefix(src=os.path.join(pkgdir, 'bin', 'release'), dst="llplugin"): self.path("libvlc.dll") self.path("libvlccore.dll") self.path("plugins/") @@ -803,7 +915,7 @@ class WindowsManifest(ViewerManifest): nsis_retry_wait=15 for attempt in xrange(nsis_attempts): try: - self.run_command('"' + NSIS_path + '" /V2 ' + self.dst_path_of(tempfile)) + self.run_command([NSIS_path, '/V2', self.dst_path_of(tempfile)]) except ManifestError as err: if attempt+1 < nsis_attempts: print >> sys.stderr, "nsis failed, waiting %d seconds before retrying" % nsis_retry_wait @@ -828,8 +940,7 @@ class WindowsManifest(ViewerManifest): if os.path.exists(sign_py): dst_path = self.dst_path_of(exe) print "about to run signing of: ", dst_path - self.run_command(' '.join((python, self.escape_slashes(sign_py), - self.escape_slashes(dst_path)))) + self.run_command([python, sign_py, dst_path]) else: print "Skipping code signing of %s: %s not found" % (exe, sign_py) @@ -856,15 +967,401 @@ class DarwinManifest(ViewerManifest): # darwin requires full app bundle packaging even for debugging. return True +# construct method VMP trampoline crazy VMP launcher juggling shamelessly replaced with old version + # def construct(self): + # # These are the names of the top-level application and the embedded + # # applications for the VMP and for the actual viewer, respectively. + # # These names, without the .app suffix, determine the flyover text for + # # their corresponding Dock icons. + # toplevel_app, toplevel_icon = "Second Life.app", "secondlife.icns" + # launcher_app, launcher_icon = "Launcher.app", "secondlife.icns" + # viewer_app, viewer_icon = "Viewer.app", "secondlife.icns" + + # # copy over the build result (this is a no-op if run within the xcode script) + # self.path(os.path.join(self.args['configuration'], toplevel_app), dst="") + + # pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') + # relpkgdir = os.path.join(pkgdir, "lib", "release") + # debpkgdir = os.path.join(pkgdir, "lib", "debug") + + # # -------------------- top-level Second Life.app --------------------- + # # top-level Second Life application is only a container + # with self.prefix(src="", dst="Contents"): # everything goes in Contents + # # top-level Info.plist is as generated by CMake + # Info_plist = "Info.plist" + # ## This self.path() call reports 0 files... skip? + # self.path(Info_plist) + # Info_plist = self.dst_path_of(Info_plist) + + # # the one file in top-level MacOS directory is the trampoline to + # # our nested launcher_app + # with self.prefix(dst="MacOS"): + # toplevel_MacOS = self.get_dst_prefix() + # trampoline = self.put_in_file("""\ +# #!/bin/bash +# open "%s" +# """ % + # # up one directory from MacOS to its sibling Resources directory + # os.path.join('$(dirname "$0")', os.pardir, 'Resources', launcher_app), + # "SL_Launcher", # write this file + # "trampoline") # flag to add to list of copied files + # # Script must be executable + # self.run_command(["chmod", "+x", trampoline]) + + # # Make a symlink to a nested app Frameworks directory that doesn't + # # yet exist. We shouldn't need this; the only things that need + # # Frameworks are nested apps under viewer_app, and they should + # # simply find its Contents/Frameworks by relative pathnames. But + # # empirically, we do: if we omit this symlink, CEF doesn't work -- + # # the login splash screen doesn't even display. SIIIIGH. + # # We're passing a path that's already relative, hence symlinkf() + # # rather than relsymlinkf(). + # self.symlinkf(os.path.join("Resources", viewer_app, "Contents", "Frameworks")) + + # with self.prefix(src="", dst="Resources"): + # # top-level Resources directory should be pretty sparse + # # need .icns file referenced by top-level Info.plist + # with self.prefix(src=self.icon_path(), dst="") : + # self.path(toplevel_icon) + + # # ------------------- nested launcher_app -------------------- + # with self.prefix(dst=os.path.join(launcher_app, "Contents")): + # # Info.plist is just like top-level one... + # Info = plistlib.readPlist(Info_plist) + # # except for these replacements: + # Info["CFBundleExecutable"] = "SL_Launcher" + # Info["CFBundleIconFile"] = launcher_icon + # self.put_in_file( + # plistlib.writePlistToString(Info), + # os.path.basename(Info_plist), + # "Info.plist") + + # # copy VMP libs to MacOS + # with self.prefix(dst="MacOS"): + # #this copies over the python wrapper script, + # #associated utilities and required libraries, see + # #SL-321, SL-322, SL-323 + # with self.prefix(src=os.path.join(pkgdir, "VMP"), dst=""): + # self.path("SL_Launcher") + # self.path("*.py") + # # certifi will be imported by requests; this is + # # our custom version to get our ca-bundle.crt + # self.path("certifi") + # with self.prefix(src=os.path.join(pkgdir, "lib", "python"), dst=""): + # # llbase provides our llrest service layer and llsd decoding + # with self.prefix("llbase"): + # # (Why is llbase treated specially here? What + # # DON'T we want to copy out of lib/python/llbase?) + # self.path("*.py") + # self.path("_cllsd.so") + # #requests module needed by llbase/llrest.py + # #this is only needed on POSIX, because in Windows + # #we compile it into the EXE + # for pypkg in "chardet", "idna", "requests", "urllib3": + # self.path(pypkg) + + # # launcher_app/Contents/Resources + # with self.prefix(dst="Resources"): + # with self.prefix(src=self.icon_path(), dst="") : + # self.path(launcher_icon) + # with self.prefix(dst="vmp_icons"): + # self.path("secondlife.ico") + # #VMP Tkinter icons + # with self.prefix("vmp_icons"): + # self.path("*.png") + # self.path("*.gif") + + # # -------------------- nested viewer_app --------------------- + # with self.prefix(dst=os.path.join(viewer_app, "Contents")): + # # Info.plist is just like top-level one... + # Info = plistlib.readPlist(Info_plist) + # # except for these replacements: + # # (CFBundleExecutable may be moot: SL_Launcher directly + # # runs the executable, instead of launching the app) + # Info["CFBundleExecutable"] = "Second Life" + # Info["CFBundleIconFile"] = viewer_icon + # self.put_in_file( + # plistlib.writePlistToString(Info), + # os.path.basename(Info_plist), + # "Info.plist") + + # # CEF framework goes inside viewer_app/Contents/Frameworks. + # # Remember where we parked this car. + # with self.prefix(src="", dst="Frameworks"): + # CEF_framework = "Chromium Embedded Framework.framework" + # self.path2basename(relpkgdir, CEF_framework) + # CEF_framework = self.dst_path_of(CEF_framework) + + # with self.prefix(dst="MacOS"): + # # CMake constructs the Second Life executable in the + # # MacOS directory belonging to the top-level Second + # # Life.app. Move it here. + # here = self.get_dst_prefix() + # relbase = os.path.realpath(os.path.dirname(Info_plist)) + # self.cmakedirs(here) + # for f in os.listdir(toplevel_MacOS): + # if f == os.path.basename(trampoline): + # # don't move the trampoline script we just made! + # continue + # fromwhere = os.path.join(toplevel_MacOS, f) + # towhere = os.path.join(here, f) + # print "Moving %s => %s" % \ + # (self.relpath(fromwhere, relbase), + # self.relpath(towhere, relbase)) + # # now do it, only without relativizing paths + # os.rename(fromwhere, towhere) + + # # 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', self.dst_path_of('Second Life')]) + + # with self.prefix(dst="Resources"): + # # defer cross-platform file copies until we're in the right + # # nested Resources directory + # super(DarwinManifest, self).construct() + + # with self.prefix(src=self.icon_path(), dst="") : + # self.path(viewer_icon) + + # with self.prefix(src=relpkgdir, dst=""): + # self.path("libndofdev.dylib") + # self.path("libhunspell-1.3.0.dylib") + + # with self.prefix("cursors_mac"): + # self.path("*.tif") + + # self.path("licenses-mac.txt", dst="licenses.txt") + # self.path("featuretable_mac.txt") + # self.path("SecondLife.nib") + # self.path("ca-bundle.crt") + + # self.path("SecondLife.nib") + + # # Translations + # self.path("English.lproj/language.txt") + # self.replace_in(src="English.lproj/InfoPlist.strings", + # dst="English.lproj/InfoPlist.strings", + # searchdict={'%%VERSION%%':'.'.join(self.args['version'])} + # ) + # 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") + + # 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. + # """ + # # This was simple before we started needing to pass + # # wildcards. Fortunately, self.path() ends up appending a + # # (source, dest) pair to self.file_list for every expanded + # # file processed. Remember its size before the call. + # oldlen = len(self.file_list) + # self.path(src, dst) + # # The dest appended to self.file_list has been prepended + # # with self.get_dst_prefix(). Strip it off again. + # added = [os.path.relpath(d, self.get_dst_prefix()) + # for s, d in self.file_list[oldlen:]] + # if not added: + # print "Skipping %s" % dst + # return added + + # # 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_parent = self.get_dst_prefix() + # libfile = "libllcommon.dylib" + # dylibs = path_optional(self.find_existing_file(os.path.join(os.pardir, + # "llcommon", + # self.args['configuration'], + # libfile), + # os.path.join(relpkgdir, libfile)), + # dst=libfile) + + # for libfile in ( + # "libapr-1.0.dylib", + # "libaprutil-1.0.dylib", + # "libcollada14dom.dylib", + # "libexpat.1.dylib", + # "libexception_handler.dylib", + # "libGLOD.dylib", + # # libnghttp2.dylib is a symlink to + # # libnghttp2.major.dylib, which is a symlink to + # # libnghttp2.version.dylib. Get all of them. + # "libnghttp2.*dylib", + # ): + # dylibs += path_optional(os.path.join(relpkgdir, 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(relpkgdir, libfile) + + # # dylibs that vary based on configuration + # if self.args['configuration'].lower() == 'debug': + # for libfile in ( + # "libfmodexL.dylib", + # ): + # dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile) + # else: + # for libfile in ( + # "libfmodex.dylib", + # ): + # dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile) + + # # our apps + # executable_path = {} + # for app_bld_dir, app in (("mac_crash_logger", "mac-crash-logger.app"), + # # plugin launcher + # (os.path.join("llplugin", "slplugin"), "SLPlugin.app"), + # ): + # self.path2basename(os.path.join(os.pardir, + # app_bld_dir, self.args['configuration']), + # app) + # executable_path[app] = \ + # self.dst_path_of(os.path.join(app, "Contents", "MacOS")) + + # # 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. + # with self.prefix(dst=os.path.join(app, "Contents", "Resources")): + # for libfile in dylibs: + # self.relsymlinkf(os.path.join(libfile_parent, libfile)) + + # # Dullahan helper apps go inside SLPlugin.app + # with self.prefix(dst=os.path.join( + # "SLPlugin.app", "Contents", "Frameworks")): + + # frameworkname = 'Chromium Embedded Framework' + + # # This code constructs a relative symlink from the + # # target framework folder back to the real CEF framework. + # # It needs to be relative so that the symlink still works when + # # (as is normal) the user moves the app bundle out of the DMG + # # and into the /Applications folder. Note we pass catch=False, + # # letting the uncaught exception terminate the process, since + # # without this symlink, Second Life web media can't possibly work. + + # # It might seem simpler just to symlink Frameworks back to + # # the parent of Chromimum Embedded Framework.framework. But + # # that would create a symlink cycle, which breaks our + # # packaging step. So make a symlink from Chromium Embedded + # # Framework.framework to the directory of the same name, which + # # is NOT an ancestor of the symlink. + + # # from SLPlugin.app/Contents/Frameworks/Chromium Embedded + # # Framework.framework back to + # # $viewer_app/Contents/Frameworks/Chromium Embedded Framework.framework + # SLPlugin_framework = self.relsymlinkf(CEF_framework, catch=False) + + # # copy DullahanHelper.app + # self.path2basename(relpkgdir, 'DullahanHelper.app') + + # # and fix that up with a Frameworks/CEF symlink too + # with self.prefix(dst=os.path.join( + # 'DullahanHelper.app', 'Contents', 'Frameworks')): + # # from Dullahan Helper.app/Contents/Frameworks/Chromium Embedded + # # Framework.framework back to + # # SLPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework + # # Since SLPlugin_framework is itself a + # # symlink, don't let relsymlinkf() resolve -- + # # explicitly call relpath(symlink=True) and + # # create that symlink here. + # DullahanHelper_framework = \ + # self.symlinkf(self.relpath(SLPlugin_framework, symlink=True), + # catch=False) + + # # change_command includes install_name_tool, the + # # -change subcommand and the old framework rpath + # # stamped into the executable. To use it with + # # run_command(), we must still append the new + # # framework path and the pathname of the + # # executable to change. + # change_command = [ + # 'install_name_tool', '-change', + # '@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework'] + + # with self.prefix(dst=os.path.join( + # 'DullahanHelper.app', 'Contents', 'MacOS')): + # # Now self.get_dst_prefix() is, at runtime, + # # @executable_path. Locate the helper app + # # framework (which is a symlink) from here. + # newpath = os.path.join( + # '@executable_path', + # self.relpath(DullahanHelper_framework, symlink=True), + # frameworkname) + # # and restamp the DullahanHelper executable + # self.run_command( + # change_command + + # [newpath, self.dst_path_of('DullahanHelper')]) + + # # SLPlugin plugins + # with self.prefix(dst="llplugin"): + # dylibexecutable = 'media_plugin_cef.dylib' + # self.path2basename("../media_plugins/cef/" + self.args['configuration'], + # dylibexecutable) + + # # Do this install_name_tool *after* media plugin is copied over. + # # Locate the framework lib executable -- relative to + # # SLPlugin.app/Contents/MacOS, which will be our + # # @executable_path at runtime! + # newpath = os.path.join( + # '@executable_path', + # self.relpath(SLPlugin_framework, executable_path["SLPlugin.app"], + # symlink=True), + # frameworkname) + # # restamp media_plugin_cef.dylib + # self.run_command( + # change_command + + # [newpath, self.dst_path_of(dylibexecutable)]) + + # # copy LibVLC plugin itself + # self.path2basename("../media_plugins/libvlc/" + self.args['configuration'], + # "media_plugin_libvlc.dylib") + + # # copy LibVLC dynamic libraries + # with self.prefix(src=relpkgdir, dst="lib"): + # self.path( "libvlc*.dylib*" ) + # # copy LibVLC plugins folder + # with self.prefix(src='plugins', dst=""): + # self.path( "*.dylib" ) + # self.path( "plugins.dat" ) 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="") + self.path(self.args['configuration'] + "/Firestorm.app", dst="") pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') relpkgdir = os.path.join(pkgdir, "lib", "release") debpkgdir = os.path.join(pkgdir, "lib", "debug") - vmpdir = os.path.join(pkgdir, "VMP") - llbasedir = os.path.join(pkgdir, "lib", "python", "llbase") requestsdir = os.path.join(pkgdir, "lib", "python", "requests") urllib3dir = os.path.join(pkgdir, "lib", "python", "urllib3") chardetdir = os.path.join(pkgdir, "lib", "python", "chardet") @@ -877,45 +1374,8 @@ class DarwinManifest(ViewerManifest): self.path(os.path.join(relpkgdir, "libndofdev.dylib"), dst="Resources/libndofdev.dylib") self.path(os.path.join(relpkgdir, "libhunspell-1.3.0.dylib"), dst="Resources/libhunspell-1.3.0.dylib") - with self.prefix(dst="MacOS"): - #this copies over the python wrapper script, associated utilities and required libraries, see SL-321, SL-322, SL-323 - self.path2basename(vmpdir,"SL_Launcher") - self.path2basename(vmpdir,"*.py") - # certifi will be imported by requests; this is our custom version to get our ca-bundle.crt - certifi_path = os.path.join(self.get_dst_prefix(),'certifi') - if not os.path.exists(certifi_path): - os.makedirs(certifi_path) - with self.prefix(dst="certifi"): - self.path2basename(os.path.join(vmpdir,"certifi"),"*") - # llbase provides our llrest service layer and llsd decoding - llbase_path = os.path.join(self.get_dst_prefix(),'llbase') - if not os.path.exists(llbase_path): - os.makedirs(llbase_path) - with self.prefix(dst="llbase"): - self.path2basename(llbasedir,"*.py") - self.path2basename(llbasedir,"_cllsd.so") - #requests module needed by llbase/llrest.py - #this is only needed on POSIX, because in Windows we compile it into the EXE - requests_path = os.path.join(self.get_dst_prefix(),'requests') - if not os.path.exists(requests_path): - os.makedirs(requests_path) - with self.prefix(dst="requests"): - self.path2basename(requestsdir,"*") - urllib3_path = os.path.join(self.get_dst_prefix(),'urllib3') - if not os.path.exists(urllib3_path): - os.makedirs(urllib3_path) - with self.prefix(dst="urllib3"): - self.path2basename(urllib3dir,"*") - chardet_path = os.path.join(self.get_dst_prefix(),'chardet') - if not os.path.exists(chardet_path): - os.makedirs(chardet_path) - with self.prefix(dst="chardet"): - self.path2basename(chardetdir,"*") - idna_path = os.path.join(self.get_dst_prefix(),'idna') - if not os.path.exists(idna_path): - os.makedirs(idna_path) - with self.prefix(dst="idna"): - self.path2basename(idnadir,"*") + # Growl Frameworks + self.path("../packages/Frameworks/Growl", dst="Frameworks/Growl") # most everything goes in the Resources directory with self.prefix(src="", dst="Resources"): @@ -926,22 +1386,14 @@ class DarwinManifest(ViewerManifest): self.path("licenses-mac.txt", dst="licenses.txt") self.path("featuretable_mac.txt") - self.path("SecondLife.nib") + self.path("VivoxAUP.txt") self.path("ca-bundle.crt") icon_path = self.icon_path() with self.prefix(src=icon_path, dst="") : - self.path("secondlife.icns") + self.path("firestorm_icon.icns") - with self.prefix(src=icon_path, dst="vmp_icons"): - self.path("secondlife.ico") - - #VMP Tkinter icons - with self.prefix("vmp_icons"): - self.path("*.png") - self.path("*.gif") - - self.path("SecondLife.nib") + self.path("Firestorm.nib") # Translations self.path("English.lproj/language.txt") @@ -1010,11 +1462,16 @@ class DarwinManifest(ViewerManifest): # libnghttp2.major.dylib, which is a symlink # to libnghttp2.version.dylib. Get all of them. "libnghttp2.*dylib", + "libgrowl.dylib", + "libgrowl++.dylib", + "libLeap.dylib", ): dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile) # SLVoice and vivox lols, no symlinks needed for libfile in ( + 'libalut.dylib', + 'libopenal.dylib', 'libortp.dylib', 'libsndfile.dylib', 'libvivoxoal.dylib', @@ -1057,6 +1514,15 @@ class DarwinManifest(ViewerManifest): except OSError as err: print "Can't symlink %s -> %s: %s" % (src, dst, err) + # Moved from the x86_64 specific version because code + # below that does symlinking and path fixup depends on it. + with self.prefix(src="../packages/bin_x86", dst=""): + self.path("SLPlugin.app", "SLPlugin.app") + + with self.prefix(src = "llplugin", dst="llplugin"): + self.path("media_plugin_quicktime.dylib", "media_plugin_quicktime.dylib") + self.path("media_plugin_cef.dylib", "media_plugin_cef.dylib") + # Dullahan helper apps go inside SLPlugin.app with self.prefix(src="", dst="SLPlugin.app/Contents/Frameworks"): helperappfile = 'DullahanHelper.app' @@ -1076,7 +1542,7 @@ class DarwinManifest(ViewerManifest): helperexecutablepath = self.dst_path_of('SLPlugin.app/Contents/Frameworks/DullahanHelper.app/Contents/MacOS/DullahanHelper') - self.run_command('install_name_tool -change ' + self.run_command_shell('install_name_tool -change ' '"@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework" ' '"@executable_path/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework" "%s"' % helperexecutablepath) @@ -1101,11 +1567,15 @@ class DarwinManifest(ViewerManifest): # do this install_name_tool *after* media plugin is copied over dylibexecutablepath = self.dst_path_of('llplugin/media_plugin_cef.dylib') - self.run_command('install_name_tool -change ' + self.run_command_shell('install_name_tool -change ' '"@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework" ' '"@executable_path/../Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework" "%s"' % dylibexecutablepath) + # Copy in prebuilt framework if it's there + with self.prefix(src="../packages/bin_x86/Frameworks", dst="Frameworks"): + self.path("Chromium Embedded Framework.framework") + # CEF framework goes inside Second Life.app/Contents/Frameworks with self.prefix(src="", dst="Frameworks"): frameworkfile="Chromium Embedded Framework.framework" @@ -1159,8 +1629,9 @@ class DarwinManifest(ViewerManifest): # 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)r' % - { 'viewer_binary' : self.dst_path_of('Contents/MacOS/Second Life')}) + self.run_command_shell('strip -S %(viewer_binary)r' % + { 'viewer_binary' : self.dst_path_of('Contents/MacOS/Firestorm')}) +# construct method VMP trampoline crazy VMP launcher juggling shamelessly replaced with old version def package_finish(self): global CHANNEL_VENDOR_BASE @@ -1176,9 +1647,10 @@ class DarwinManifest(ViewerManifest): # 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 1300 -layout SPUD' % { - 'sparse':sparsename, - 'vol':volname}) + self.run_command(['hdiutil', 'create', sparsename, + '-volname', volname, '-fs', 'HFS+', + '-type', 'SPARSE', '-megabytes', '1300', + '-layout', 'SPUD']) # mount the image and get the name of the mount point and device node try: @@ -1237,18 +1709,18 @@ class DarwinManifest(ViewerManifest): # well, possibly we've mistaken the nature of the problem. In any # case, don't hang up the whole build looping indefinitely, let # the original problem manifest by executing the desired command. - self.run_command('SetFile -a V %r' % pathname) + self.run_command(['SetFile', '-a', 'V', pathname]) # Create the alias file (which is a resource file) from the .r - self.run_command('Rez %r -o %r' % - (self.src_path_of("installers/darwin/release-dmg/Applications-alias.r"), - os.path.join(volpath, "Applications"))) + 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 %r' % os.path.join(volpath, "Applications")) + 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 %r' % volpath) + self.run_command(['SetFile', '-a', 'C', volpath]) # Sign the app if requested; # do this in the copy that's in the .dmg so that the extended attributes used by @@ -1284,7 +1756,10 @@ class DarwinManifest(ViewerManifest): # and that it contains the correct cert/key. If a build host is set up with a clean version of macOS Sierra (or later) # then you will need to change this line (and the one for 'codesign' command below) to point to right place or else # pull in the cert/key into the default viewer keychain 'viewer.keychain-db' and export it to 'viewer.keychain' - self.run_command('security unlock-keychain -p "%s" "%s/Library/Keychains/viewer.keychain"' % ( keychain_pwd, home_path ) ) + viewer_keychain = os.path.join(home_path, 'Library', + 'Keychains', 'viewer.keychain') + self.run_command(['security', 'unlock-keychain', + '-p', keychain_pwd, viewer_keychain]) signed=False sign_attempts=3 sign_retry_wait=15 @@ -1293,11 +1768,9 @@ class DarwinManifest(ViewerManifest): sign_attempts-=1; self.run_command( # Note: See blurb above about names of keychains - 'codesign --verbose --deep --force --keychain "%(home_path)s/Library/Keychains/viewer.keychain" --sign %(identity)r %(bundle)r' % { - 'home_path' : home_path, - 'identity': identity, - 'bundle': app_in_dmg - }) + ['codesign', '--verbose', '--deep', '--force', + '--keychain', viewer_keychain, '--sign', identity, + app_in_dmg]) signed=True # if no exception was raised, the codesign worked except ManifestError as err: if sign_attempts: @@ -1307,18 +1780,19 @@ class DarwinManifest(ViewerManifest): else: print >> sys.stderr, "Maximum codesign attempts exceeded; giving up" raise - self.run_command('spctl -a -texec -vv %(bundle)r' % { 'bundle': app_in_dmg }) + self.run_command(['spctl', '-a', '-texec', '-vv', app_in_dmg]) imagename="SecondLife_" + '_'.join(self.args['version']) finally: # Unmount the image even if exceptions from any of the above - self.run_command('hdiutil detach -force %r' % devfile) + self.run_command(['hdiutil', 'detach', '-force', devfile]) 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}) + self.run_command(['hdiutil', 'convert', sparsename, '-format', 'UDZO', + '-imagekey', 'zlib-level=9', '-o', finalname]) + self.run_command(['hdiutil', 'internet-enable', '-yes', finalname]) # get rid of the temp file self.package_file = finalname self.remove(sparsename) @@ -1369,19 +1843,16 @@ class LinuxManifest(ViewerManifest): self.path2basename("../llplugin/slplugin", "SLPlugin") #this copies over the python wrapper script, associated utilities and required libraries, see SL-321, SL-322 and SL-323 # Remove VMP - #self.path2basename("../viewer_components/manager","SL_Launcher") - #self.path2basename("../viewer_components/manager","*.py") - #llbase_path = os.path.join(self.get_dst_prefix(),'llbase') - #if not os.path.exists(llbase_path): - # os.makedirs(llbase_path) - #with self.prefix(dst="llbase"): - # self.path2basename("../packages/lib/python/llbase","*.py") - # self.path2basename("../packages/lib/python/llbase","_cllsd.so") + #with self.prefix(src="../viewer_components/manager", dst=""): + # self.path("SL_Launcher") + # self.path("*.py") + #with self.prefix(src=os.path.join("lib", "python", "llbase"), dst="llbase"): + # self.path("*.py") + # self.path("_cllsd.so") # Remove VMP - with self.prefix("res-sdl"): - self.path("*") - # recurse + # recurses, packaged again + self.path("res-sdl") # Get the icons based on the channel type icon_path = self.icon_path() @@ -1392,11 +1863,12 @@ class LinuxManifest(ViewerManifest): self.path("firestorm_256.BMP","ll_icon.BMP") # plugins - with self.prefix(src="", dst="bin/llplugin"): - self.path("../media_plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_gstreamer.so") - self.path("../media_plugins/cef/libmedia_plugin_cef.so", "libmedia_plugin_cef.so" ) - self.path("../media_plugins/libvlc/libmedia_plugin_libvlc.so", "libmedia_plugin_libvlc.so") - self.path("../media_plugins/gstreamer10/libmedia_plugin_gstreamer10.so", "libmedia_plugin_gstreamer10.so") + with self.prefix(src="../media_plugins", dst="bin/llplugin"): + self.path("gstreamer010/libmedia_plugin_gstreamer010.so", + "libmedia_plugin_gstreamer.so") + self.path2basename("libvlc", "libmedia_plugin_libvlc.so") + self.path("cef/libmedia_plugin_cef.so", "libmedia_plugin_cef.so" ) + with self.prefix(src=os.path.join(os.pardir, 'packages', 'lib', 'vlc', 'plugins'), dst="bin/llplugin/vlc/plugins"): self.path( "plugins.dat" ) @@ -1405,11 +1877,11 @@ class LinuxManifest(ViewerManifest): with self.prefix(src=os.path.join(os.pardir, 'packages', 'lib' ), dst="lib"): self.path( "libvlc*.so*" ) - with self.prefix(src=os.path.join(os.pardir, 'packages', 'lib', 'vlc', 'plugins'), dst="bin/llplugin/vlc/plugins"): + with self.prefix(src=os.path.join(pkgdir, 'lib', 'vlc', 'plugins'), dst="bin/llplugin/vlc/plugins"): self.path( "plugins.dat" ) self.path( "*/*.so" ) - with self.prefix(src=os.path.join(os.pardir, 'packages', 'lib' ), dst="lib"): + with self.prefix(src=os.path.join(pkgdir, 'lib' ), dst="lib"): self.path( "libvlc*.so*" ) # CEF files @@ -1582,48 +2054,45 @@ class LinuxManifest(ViewerManifest): self.fs_setuid_chromesandbox() # Chown chrome-sandbox to root:root and set the setuid bit # 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.run_command(['find', self.get_dst_prefix(), + '-type', 'd', '-exec', 'chmod', '755', '{}', ';']) + for old, new in ('0700', '0755'), ('0500', '0555'), ('0600', '0644'), ('0400', '0444'): + self.run_command(['find', self.get_dst_prefix(), + '-type', 'f', '-perm', old, + '-exec', 'chmod', new, '{}', ';']) self.package_file = installer_name + '.tar.xz' # 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)}) + realname = self.get_dst_prefix() + tempname = self.build_path_of(installer_name) + self.run_command(["mv", realname, tempname]) try: # only create tarball if it's a release build. if self.args['buildtype'].lower() == 'release': # --numeric-owner hides the username of the builder for # security etc. - self.run_command('tar -C %(dir)s --numeric-owner %(fs_excludes)s -cJf ' - '%(inst_path)s.tar.xz %(inst_name)s' % { - 'dir': self.get_build_prefix(), - 'inst_name': installer_name, - 'inst_path':self.build_path_of(installer_name), - 'fs_excludes':self.fs_linux_tar_excludes() - }) + self.run_command(['tar', '-C', self.get_build_prefix(), + '--numeric-owner', self.fs_linux_tar_excludes(), '-cjf', + tempname + '.tar.bz2', installer_name]) else: print "Skipping %s.tar.xz for non-Release build (%s)" % \ (installer_name, self.args['buildtype']) finally: - self.run_command("mv %(inst)s %(dst)s" % { - 'dst': self.get_dst_prefix(), - 'inst': self.build_path_of(installer_name)}) + self.run_command(["mv", tempname, realname]) def strip_binaries(self): if self.args['buildtype'].lower() == 'release' and self.is_packaging_viewer(): print "* Going strip-crazy on the packaged binaries, since this is a RELEASE build" # makes some small assumptions about our packaged dir structure - # Remove VMP - #self.run_command(r"find %(d)r/bin %(d)r/lib -type f \! -name \*.py \! -name SL_Launcher \! -name update_install | xargs --no-run-if-empty strip -S" % {'d': self.get_dst_prefix()} ) - self.run_command(r"find %(d)r/bin %(d)r/lib -type f \! -name update_install \! -name *.pak \! -name *.dat \! -name *.bin \! -name core \! -path '*win32*' | xargs --no-run-if-empty strip -S" % {'d': self.get_dst_prefix()} ) # makes some small assumptions about our packaged dir structure - # Remove VMP + self.run_command( + ["find"] + + [os.path.join(self.get_dst_prefix(), dir) for dir in ('bin', 'lib')] + + # Remove VMP + #['-type', 'f', '!', '-name', '*.py', '!', '-name', 'SL_Launcher', + ['-type', 'f', '!', + # Remove VMP + '!', '-name', 'update_install', '-exec', 'strip', '-S', '{}', ';']) class Linux_i686_Manifest(LinuxManifest): address_size = 32 @@ -1755,7 +2224,7 @@ class Linux_x86_64_Manifest(LinuxManifest): self.path("secondlife-i686.supp") ################################################################ - +# Added back for Mac compatibility reason def symlinkf(src, dst): """ Like ln -sf, but uses os.symlink() instead of running ln. @@ -1796,6 +2265,7 @@ def symlinkf(src, dst): % os.path.join(parent, tail)) else: raise +# Added back for Mac compatibility reason if __name__ == "__main__": main()