From ec13121def29405788c1eeb37bb714c5d39e3a4c Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 28 Nov 2017 16:42:24 -0500 Subject: MAINT-7751: Remove redundant viewer_manifest.py directory creation. The LLManifest.copy_action() method ensures that the destination directory for any file copy exists before trying to copy the file, specifically so we don't have to clutter the business logic with tests and explicit directory creation. Remove redundant os.makedirs() stanzas. --- indra/newview/viewer_manifest.py | 37 +++++++++---------------------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 5cee88ca32..e55020f689 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -308,6 +308,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)) @@ -328,6 +330,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)) @@ -379,9 +383,6 @@ 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") @@ -781,49 +782,32 @@ class DarwinManifest(ViewerManifest): idnadir = os.path.join(pkgdir, "lib", "python", "idna") with self.prefix(src="", dst="Contents"): # everything goes in Contents - self.path("Info.plist", dst="Info.plist") + self.path("Info.plist") - # copy additional libs in /Contents/MacOS/ - 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(src=relpkgdir, dst="Resources"): + self.path("libndofdev.dylib") + self.path("libhunspell-1.3.0.dylib") + # copy additional libs in /Contents/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 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,"*") @@ -1277,9 +1261,6 @@ class LinuxManifest(ViewerManifest): #this copies over the python wrapper script, associated utilities and required libraries, see SL-321, SL-322 and SL-323 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") -- cgit v1.2.3 From 662013f146feee5e5403c91ddc43e8d9ea07a8b2 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 29 Nov 2017 09:58:12 -0500 Subject: MAINT-7751: Tidying up viewer_manifest.py a little --- indra/newview/viewer_manifest.py | 80 +++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 46 deletions(-) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 89bea10c95..8048f4eb2f 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -360,18 +360,16 @@ 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/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe()) - # 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") @@ -382,9 +380,9 @@ class WindowsManifest(ViewerManifest): self.path("*.gif") #before, we only needed llbase at build time. With VMP, we need it at run time. - 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") # Plugin host application self.path2basename(os.path.join(os.pardir, @@ -772,12 +770,6 @@ class DarwinManifest(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") - requestsdir = os.path.join(pkgdir, "lib", "python", "requests") - urllib3dir = os.path.join(pkgdir, "lib", "python", "urllib3") - chardetdir = os.path.join(pkgdir, "lib", "python", "chardet") - idnadir = os.path.join(pkgdir, "lib", "python", "idna") with self.prefix(src="", dst="Contents"): # everything goes in Contents self.path("Info.plist") @@ -789,25 +781,20 @@ class DarwinManifest(ViewerManifest): # copy additional libs in /Contents/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 - 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 - with self.prefix(dst="certifi"): - self.path2basename(os.path.join(vmpdir,"certifi"),"*") - # llbase provides our llrest service layer and llsd decoding - 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 - with self.prefix(dst="requests"): - self.path2basename(requestsdir,"*") - with self.prefix(dst="urllib3"): - self.path2basename(urllib3dir,"*") - with self.prefix(dst="chardet"): - self.path2basename(chardetdir,"*") - with self.prefix(dst="idna"): - self.path2basename(idnadir,"*") + 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"): + 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) # most everything goes in the Resources directory with self.prefix(src="", dst="Resources"): @@ -1257,15 +1244,15 @@ class LinuxManifest(ViewerManifest): self.path("../linux_crash_logger/linux-crash-logger","linux-crash-logger.bin") 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 - self.path2basename("../viewer_components/manager","SL_Launcher") - self.path2basename("../viewer_components/manager","*.py") - 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") - 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() @@ -1276,9 +1263,10 @@ class LinuxManifest(ViewerManifest): self.path("secondlife_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/libvlc/libmedia_plugin_libvlc.so", "libmedia_plugin_libvlc.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") with self.prefix(src=os.path.join(os.pardir, 'packages', 'lib', 'vlc', 'plugins'), dst="bin/llplugin/vlc/plugins"): self.path( "plugins.dat" ) -- cgit v1.2.3 From 488d165895db3c2ae2aebbb3b727e95b8a3de6bf Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Mon, 4 Dec 2017 17:15:47 -0500 Subject: MAINT-7751: Rework DarwinManifest to produce new app bundle structure. Specifically, Second Life.app is now mostly just a wrapper. Its Contents/ Resources contains nested Launcher.app (the VMP) and Viewer.app (the viewer itself). Most of what used to be in the top-level Second Life.app has been relocated to the embedded Viewer.app. VMP stuff has of course been extracted to Launcher.app. The top-level Second Life.app executable is now a tiny script that runs Launcher.app. This structure permits different icons and different Dock flyover text for the launcher and the viewer, hopefully ameliorating a certain amount of user confusion about the dual icons. This requires a corresponding VMP change: on macOS, the VMP must now find both its resources and the viewer executable by walking up from Launcher.app and down again into its sibling Viewer.app. Since Dock flyover text is determined by the embedded app names, allow Product to change these at will. That means we should be able to tweak exactly one variable assignment to change either of those embedded app names, without having to chase down other references scattered throughout the source repo. For that reason, create top-level trampoline SL_Launcher script dynamically: it must reference the launcher app by name. That means we must also perform (the equivalent of) chmod +x on that generated script. The one mystery surrounding this restructuring is that without a top-level Frameworks symlink pointing to the embedded Viewer.app's Frameworks directory (where CEF lives), CEF refuses to start: no splash screen, no MoP. Perhaps we can fix that someday. Use Python's bundled plistlib to generate Info.plist files for the embedded applications. Reorganize stray code stanzas to try to help the structure of the code more or less resemble the structure of the desired result. Add ViewerManifest.relpath() method to determine the relative path from a specified base to the target path. If base omitted, assumes get_dst_prefix() -- handy for creating symlinks. Determining exactly the right number of os.pardir instances to concatenate into the relative pathname for a symlink (or an install_name_tool stamp) was tedious, fragile and unobvious, difficult to desk-check. Using relpath() should make all that more robust. Migrate symlinkf() from free function to ViewerManifest method, refactoring into _symlinkf_prep_dst() and _symlinkf(), adding relsymlinkf(). This lets us add convenience features such as prepending get_dst_prefix() to the dest (the place where we want to create the symlink), defaulting dest to the basename of target and ensuring that the parent of that dest already exists -- as with LLManifest.path(). Moreover, since it makes no sense whatsoever to create an absolute symlink to some path on the build machine, relsymlinkf() creates every symlink relative to dirname(dest). That, in turn, lets us eliminate a certain amount of boilerplate around existing calls. (Also, since we now ensure the parent directory exists, scrap the logic to diagnose "nonexistent parent directory.") Make llmanifest.LLManifest.run_command() not pass shell=True to subprocess, thereby permitting (requiring) the list form rather than the string form. Change all existing calls to list form. This makes calls more readable, for two reasons. First, many of the arguments are taken from script variables; these can simply be dropped into the list instead of indirecting through string interpolation. Second, it eliminates the need to manually escape individual arguments, since subprocess promises to honor the distinction between list elements. Also fix LLManifest.put_in_file() to ensure the containing directory exists. Consolidate some viewer_manifest.py redundancy, e.g. copying the same set of ten DLLs from either of two directories depending on Release vs. Debug. --- indra/lib/python/indra/util/llmanifest.py | 3 +- indra/newview/viewer_manifest.py | 945 ++++++++++++++++++------------ 2 files changed, 568 insertions(+), 380 deletions(-) diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py index 7050ce43b7..598261e3d7 100755 --- a/indra/lib/python/indra/util/llmanifest.py +++ b/indra/lib/python/indra/util/llmanifest.py @@ -529,7 +529,7 @@ class LLManifest(object): print "Running command:", command sys.stdout.flush() try: - subprocess.check_call(command, shell=True) + subprocess.check_call(command) except subprocess.CalledProcessError as err: raise ManifestError( "Command %s returned non-zero status (%s)" % (command, err.returncode) ) @@ -545,6 +545,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/viewer_manifest.py b/indra/newview/viewer_manifest.py index 8048f4eb2f..cb5503eee0 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -32,11 +32,12 @@ import os.path import shutil import errno import json +import random import re +import stat +import subprocess import tarfile import time -import random -import subprocess viewer_dir = os.path.dirname(__file__) # Add indra/lib/python to our path so we don't have to muck with PYTHONPATH. @@ -290,6 +291,129 @@ class ViewerManifest(LLManifest): 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 @@ -481,31 +605,19 @@ class WindowsManifest(ViewerManifest): self.path("media_plugin_example.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"): @@ -513,7 +625,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") @@ -521,7 +633,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") @@ -576,7 +688,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/") @@ -712,7 +824,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 @@ -735,8 +847,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) @@ -764,282 +875,397 @@ class DarwinManifest(ViewerManifest): return True def construct(self): + global plistlib + import plistlib # only import for Darwin + + # 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(self.args['configuration'] + "/Second Life.app", dst="") + 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 - self.path("Info.plist") - - with self.prefix(src=relpkgdir, dst="Resources"): - self.path("libndofdev.dylib") - self.path("libhunspell-1.3.0.dylib") - - # copy additional libs in /Contents/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"): - 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) - - # most everything goes in the Resources directory - with self.prefix(src="", dst="Resources"): - super(DarwinManifest, self).construct() - - 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") - - icon_path = self.icon_path() - with self.prefix(src=icon_path, dst="") : - self.path("secondlife.icns") + # 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( + 'open "%s"\n' % + # 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 -- but os.chmod() is pretty low-level: + # if we just chmod(stat.S_IEXEC), we end up with NOTHING BUT x! + # Have to read the existing permissions bits, then supplement with + # x for (user, group, other). + os.chmod(trampoline, stat.S_IMODE(os.stat(trampoline).st_mode) + | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) + + # 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=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") - - # 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 = "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 - 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) - - # 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: - src = os.path.join(os.pardir, os.pardir, os.pardir, libfile) - dst = os.path.join(resource_path, libfile) - try: - symlinkf(src, dst) - except OSError as err: - print "Can't symlink %s -> %s: %s" % (src, dst, err) - - # Dullahan helper apps go inside SLPlugin.app - with self.prefix(src="", dst="SLPlugin.app/Contents/Frameworks"): - helperappfile = 'DullahanHelper.app' - self.path2basename(relpkgdir, helperappfile) - - pluginframeworkpath = self.dst_path_of('Chromium Embedded Framework.framework'); - # Putting a Frameworks directory under Contents/MacOS - # isn't canonical, but the path baked into Dullahan - # Helper.app/Contents/MacOS/DullahanHelper is: - # @executable_path/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework - # (notice, not @executable_path/../Frameworks/etc.) - # So we'll create a symlink (below) from there back to the - # Frameworks directory nested under SLPlugin.app. - helperframeworkpath = \ - self.dst_path_of('DullahanHelper.app/Contents/MacOS/' - 'Frameworks/Chromium Embedded Framework.framework') - - - helperexecutablepath = self.dst_path_of('SLPlugin.app/Contents/Frameworks/DullahanHelper.app/Contents/MacOS/DullahanHelper') - self.run_command('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) - - # SLPlugin plugins - with self.prefix(src="", dst="llplugin"): - self.path2basename("../media_plugins/cef/" + self.args['configuration'], - "media_plugin_cef.dylib") - - # copy LibVLC plugin itself - self.path2basename("../media_plugins/libvlc/" + self.args['configuration'], - "media_plugin_libvlc.dylib") - - # copy LibVLC dynamic libraries - with self.prefix(src=os.path.join(os.pardir, 'packages', 'lib', 'release' ), dst="lib"): - self.path( "libvlc*.dylib*" ) - - # copy LibVLC plugins folder - with self.prefix(src=os.path.join(os.pardir, 'packages', 'lib', 'release', 'plugins' ), dst="lib"): - self.path( "*.dylib" ) - self.path( "plugins.dat" ) - - - # 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 ' - '"@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework" ' - '"@executable_path/../Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework" "%s"' % dylibexecutablepath) - - - # CEF framework goes inside Second Life.app/Contents/Frameworks - with self.prefix(src="", dst="Frameworks"): - frameworkfile="Chromium Embedded Framework.framework" - self.path2basename(relpkgdir, frameworkfile) - - # This code constructs a relative path from the - # target framework folder back to the location of the symlink. - # 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 also call 'raise' - # to terminate the process if we get an error since without - # this symlink, Second Life web media can't possibly work. - # Real Framework folder: - # Second Life.app/Contents/Frameworks/Chromium Embedded Framework.framework/ - # Location of symlink and why it's relative - # Second Life.app/Contents/Resources/SLPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework/ - # Real Frameworks folder, with the symlink inside the bundled SLPlugin.app (and why it's relative) - # .app/Contents/Frameworks/Chromium Embedded Framework.framework/ - # .app/Contents/Resources/SLPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework -> - # It might seem simpler just to create a symlink Frameworks 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. - frameworkpath = os.path.join(os.pardir, os.pardir, os.pardir, - os.pardir, "Frameworks", - "Chromium Embedded Framework.framework") - try: - # from SLPlugin.app/Contents/Frameworks/Chromium Embedded - # Framework.framework back to Second - # Life.app/Contents/Frameworks/Chromium Embedded Framework.framework - origin, target = pluginframeworkpath, frameworkpath - symlinkf(target, origin) - # from SLPlugin.app/Contents/Frameworks/Dullahan - # Helper.app/Contents/MacOS/Frameworks/Chromium Embedded - # Framework.framework back to - # SLPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework - self.cmakedirs(os.path.dirname(helperframeworkpath)) - origin = helperframeworkpath - target = os.path.join(os.pardir, frameworkpath) - symlinkf(target, origin) - except OSError as err: - print "Can't symlink %s -> %s: %s" % (origin, target, err) - raise + 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") - # 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)r' % - { 'viewer_binary' : self.dst_path_of('Contents/MacOS/Second Life')}) + # 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 package_finish(self): global CHANNEL_VENDOR_BASE @@ -1055,9 +1281,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: @@ -1116,18 +1343,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 @@ -1163,7 +1390,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 @@ -1172,11 +1402,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: @@ -1186,18 +1414,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) @@ -1268,11 +1497,11 @@ class LinuxManifest(ViewerManifest): "libmedia_plugin_gstreamer.so") self.path2basename("libvlc", "libmedia_plugin_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*" ) # llcommon @@ -1288,43 +1517,42 @@ class LinuxManifest(ViewerManifest): self.strip_binaries() # 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.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)}) + 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 -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)}) + self.run_command(['tar', '-C', self.get_build_prefix(), + '--numeric-owner', '-cjf', + tempname + '.tar.bz2', installer_name]) else: print "Skipping %s.tar.bz2 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 - 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( + ["find"] + + [os.path.join(self.get_dst_prefix(), dir) for dir in ('bin', 'lib')] + + ['-type', 'f', '!', '-name', '*.py', '!', '-name', 'SL_Launcher', + '!', '-name', 'update_install', '-exec', 'strip', '-S', '{}', ';']) class Linux_i686_Manifest(LinuxManifest): address_size = 32 @@ -1421,46 +1649,5 @@ class Linux_x86_64_Manifest(LinuxManifest): ################################################################ -def symlinkf(src, dst): - """ - Like ln -sf, but uses os.symlink() instead of running ln. - """ - 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: - # see if the problem is that the parent directory does not exist - # and try to explain what is missing - (parent, tail) = os.path.split(dst) - while not os.path.exists(parent): - (parent, tail) = os.path.split(parent) - if tail: - raise Exception("Requested symlink (%s) cannot be created because %s does not exist" - % os.path.join(parent, tail)) - else: - raise - if __name__ == "__main__": main() -- cgit v1.2.3 From 00b60e51c8e24eb563d0bbd41c9edb8ff58707f3 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 5 Dec 2017 12:03:15 -0500 Subject: MAINT-7751: Update to viewer-manager build 511174 --- autobuild.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 10895b34d2..16d6bc6124 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3231,9 +3231,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - fc3291e515f11e8324407949fb53cb53 + e8eb88e13ec90de4d1107e3d309eb7e1 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/11374/64282/viewer_manager-1.0.511174-darwin64-511174.tar.bz2 name darwin64 @@ -3255,9 +3255,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 93421dfd7486517350c434cf568d0914 + 09bb68cc312811287b850ba7a77437ca 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/11375/64288/viewer_manager-1.0.511174-windows-511174.tar.bz2 name windows @@ -3268,7 +3268,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 1.0.511006 + 1.0.511174 vlc-bin -- cgit v1.2.3 From 54eb04ee901611666ce5016eec2cc8ae9efde50e Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 5 Dec 2017 17:08:58 -0500 Subject: MAINT-7751: Update to viewer-manager build 511199 --- autobuild.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 16d6bc6124..cace3da265 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3231,9 +3231,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - e8eb88e13ec90de4d1107e3d309eb7e1 + 66a67d3be4a5307102b37fc47e67ebfc url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11374/64282/viewer_manager-1.0.511174-darwin64-511174.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11408/64513/viewer_manager-1.0.511199-darwin64-511199.tar.bz2 name darwin64 @@ -3255,9 +3255,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 09bb68cc312811287b850ba7a77437ca + 596ddb0aaf7ba6d2a83541e94f4a7013 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11375/64288/viewer_manager-1.0.511174-windows-511174.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11411/64525/viewer_manager-1.0.511199-windows-511199.tar.bz2 name windows @@ -3268,7 +3268,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 1.0.511174 + 1.0.511199 vlc-bin -- cgit v1.2.3 From 6bba46effa13549988031d58ea8c4c60a97cfe3b Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 6 Dec 2017 05:17:14 -0500 Subject: MAINT-7751: Add shbang line to macOS trampoline script. This evidently makes all the difference as to whether the app is considered launchable. --- indra/newview/viewer_manifest.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index cb5503eee0..5456c264d3 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -906,8 +906,10 @@ class DarwinManifest(ViewerManifest): # our nested launcher_app with self.prefix(dst="MacOS"): toplevel_MacOS = self.get_dst_prefix() - trampoline = self.put_in_file( - 'open "%s"\n' % + 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 -- cgit v1.2.3 From 64df1bd80e8b5e11ac49b51cc7cbe1e5d59fed9b Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 6 Dec 2017 09:58:47 -0500 Subject: MAINT-7751: Update to viewer-manager build 511211 --- autobuild.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 16d6bc6124..5d67a394da 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3231,9 +3231,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - e8eb88e13ec90de4d1107e3d309eb7e1 + 659bee64b69f5a08c5d24c8566845be6 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11374/64282/viewer_manager-1.0.511174-darwin64-511174.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11431/64648/viewer_manager-1.0.511211-darwin64-511211.tar.bz2 name darwin64 @@ -3255,9 +3255,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 09bb68cc312811287b850ba7a77437ca + 4f8ef531768db8811b238e00dfc8373c url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11375/64288/viewer_manager-1.0.511174-windows-511174.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11432/64654/viewer_manager-1.0.511211-windows-511211.tar.bz2 name windows @@ -3268,7 +3268,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 1.0.511174 + 1.0.511211 vlc-bin -- cgit v1.2.3 From d79846a779ed6a819a390eb653e78c6f1e25b0e3 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 6 Dec 2017 17:09:06 -0500 Subject: MAINT-7751: Respond to Coyot's code-review suggestions. --- indra/newview/viewer_manifest.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 5456c264d3..73631631e0 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -32,6 +32,7 @@ import os.path import shutil import errno import json +import plistlib import random import re import stat @@ -343,7 +344,7 @@ class ViewerManifest(LLManifest): # 'dst' is itself a pathname. dstdir = os.path.dirname(dst) self.cmakedirs(dstdir) - return dstdir, dst + return (dstdir, dst) def _symlinkf(self, src, dst, catch): # helper for relsymlinkf() and symlinkf() @@ -875,9 +876,6 @@ class DarwinManifest(ViewerManifest): return True def construct(self): - global plistlib - import plistlib # only import for Darwin - # 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 @@ -914,12 +912,8 @@ open "%s" 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 -- but os.chmod() is pretty low-level: - # if we just chmod(stat.S_IEXEC), we end up with NOTHING BUT x! - # Have to read the existing permissions bits, then supplement with - # x for (user, group, other). - os.chmod(trampoline, stat.S_IMODE(os.stat(trampoline).st_mode) - | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) + # 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 -- cgit v1.2.3 From 12fbe63e657cb64cf5f7044acb4f999a5d1f2670 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 6 Dec 2017 17:53:21 -0500 Subject: MAINT-7751: Update to viewer-manager build 511221 --- autobuild.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 5d67a394da..30e92ab783 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3231,9 +3231,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 659bee64b69f5a08c5d24c8566845be6 + 92235fabdca2d3865014f7ec630e2688 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11431/64648/viewer_manager-1.0.511211-darwin64-511211.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11444/64857/viewer_manager-1.0.511221-darwin64-511221.tar.bz2 name darwin64 @@ -3255,9 +3255,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 4f8ef531768db8811b238e00dfc8373c + bfea9c61d0b29d741081c0c8a315d364 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11432/64654/viewer_manager-1.0.511211-windows-511211.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11446/64863/viewer_manager-1.0.511221-windows-511221.tar.bz2 name windows @@ -3268,7 +3268,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 1.0.511211 + 1.0.511221 vlc-bin -- cgit v1.2.3 From 0e73aec0a25091b010812b878676c24dfb140af4 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 7 Dec 2017 14:03:47 -0500 Subject: MAINT-8070: Tweak macOS embedded app names (flyover text) per Product --- indra/newview/viewer_manifest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 73631631e0..9fc113ff72 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -880,9 +880,9 @@ class DarwinManifest(ViewerManifest): # 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" + toplevel_app, toplevel_icon = "Second Life.app", "secondlife.icns" + launcher_app, launcher_icon = "Second Life Launcher.app", "secondlife.icns" + viewer_app, viewer_icon = "Second Life 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="") -- cgit v1.2.3 From c565c62745ec37484118888f8f45dbde34d42e46 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 7 Dec 2017 16:43:04 -0500 Subject: MAINT-8069: Pass any command-line arguments through to SL_Launcher. --- indra/newview/viewer_manifest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 9fc113ff72..f930e8b2ce 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -906,7 +906,7 @@ class DarwinManifest(ViewerManifest): toplevel_MacOS = self.get_dst_prefix() trampoline = self.put_in_file("""\ #!/bin/bash -open "%s" +open "%s" --args "$@" """ % # up one directory from MacOS to its sibling Resources directory os.path.join('$(dirname "$0")', os.pardir, 'Resources', launcher_app), -- cgit v1.2.3 From c5abe29e9bbc3e90089d6aa7e638be8ca028644c Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 12 Dec 2017 19:44:18 -0500 Subject: MAINT-8082: Make UpdaterMaximumBandwidth comment admit uselessness. --- indra/newview/app_settings/settings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index c0e963c228..4a4f4bfc61 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -12332,7 +12332,7 @@ UpdaterMaximumBandwidth Comment - Maximum allowable downstream bandwidth for updater service (kilo bits per second) + Obsolete: this parameter is no longer used. Persist 1 Type -- cgit v1.2.3 From e94adafe71f3e4425f1856596d303a518f98e859 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 12 Dec 2017 19:54:14 -0500 Subject: MAINT-8082: Update to viewer-manager build 511350 --- autobuild.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 30e92ab783..cc981a9771 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3231,9 +3231,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 92235fabdca2d3865014f7ec630e2688 + 530283012fd76b21e98fc525a4c46342 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11444/64857/viewer_manager-1.0.511221-darwin64-511221.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11611/66908/viewer_manager-1.0.511350-darwin64-511350.tar.bz2 name darwin64 @@ -3255,9 +3255,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - bfea9c61d0b29d741081c0c8a315d364 + 3f0f245fee120d72bb6c468472013c20 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11446/64863/viewer_manager-1.0.511221-windows-511221.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11612/66914/viewer_manager-1.0.511350-windows-511350.tar.bz2 name windows @@ -3268,7 +3268,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 1.0.511221 + 1.0.511350 vlc-bin -- cgit v1.2.3 From df21b99723cf9e215160ef6601b2ba42e23b786d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 13 Dec 2017 08:27:41 -0500 Subject: MAINT-8082: Update to viewer-manager build 511355 --- autobuild.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index cc981a9771..4ccc4c5784 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3231,9 +3231,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 530283012fd76b21e98fc525a4c46342 + 8bb2754bb078713f875e7374c95294fc url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11611/66908/viewer_manager-1.0.511350-darwin64-511350.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11619/66949/viewer_manager-1.0.511355-darwin64-511355.tar.bz2 name darwin64 @@ -3255,9 +3255,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 3f0f245fee120d72bb6c468472013c20 + cc406ba4d9250e4c959c99b64877248f url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11612/66914/viewer_manager-1.0.511350-windows-511350.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11620/66955/viewer_manager-1.0.511355-windows-511355.tar.bz2 name windows @@ -3268,7 +3268,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 1.0.511350 + 1.0.511355 vlc-bin -- cgit v1.2.3 From 0d1c5958fb9a70721df26151686f070f8486667f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 13 Dec 2017 21:37:46 -0500 Subject: MAINT-8087: Update to viewer-manager build 511391 --- autobuild.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 4ccc4c5784..f96517baad 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3231,9 +3231,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 8bb2754bb078713f875e7374c95294fc + 69a42a95bc4442972f3d9ff933a77441 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11619/66949/viewer_manager-1.0.511355-darwin64-511355.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11666/67316/viewer_manager-1.0.511391-darwin64-511391.tar.bz2 name darwin64 @@ -3255,9 +3255,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - cc406ba4d9250e4c959c99b64877248f + e6a9b1b35fdea7d2c72e9280484741a7 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11620/66955/viewer_manager-1.0.511355-windows-511355.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11667/67322/viewer_manager-1.0.511391-windows-511391.tar.bz2 name windows @@ -3268,7 +3268,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 1.0.511355 + 1.0.511391 vlc-bin -- cgit v1.2.3 From bdea97399b12a1e9ede23b1fe4e8c4e28f25210e Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 14 Dec 2017 17:54:06 -0500 Subject: MAINT-8087: Use SHGetKnownFolderPath(), not SHGetSpecialFolderPath(). SHGetSpecialFolderPath() is deprecated, and empirically it appears to be failing when the user name contains non-ASCII characters. The relevant Microsoft documentation pages recommend calling SHGetKnownFolderPath() instead. Also, the SHGetSpecialFolderPath() calls had no error checking or reporting, which is why we can only say it "appears to be" failing. Make sure that if SHGetKnownFolderPath() fails, at least we try to tell somebody about it. --- indra/llvfs/lldir_win32.cpp | 62 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp index ebc8fdca33..55f0a6338d 100644 --- a/indra/llvfs/lldir_win32.cpp +++ b/indra/llvfs/lldir_win32.cpp @@ -31,7 +31,10 @@ #include "lldir_win32.h" #include "llerror.h" #include "llrand.h" // for gLindenLabRandomNumber -#include "shlobj.h" +#include +#include +#include +#include #include #include @@ -42,30 +45,59 @@ #define PACKVERSION(major,minor) MAKELONG(minor,major) DWORD GetDllVersion(LPCTSTR lpszDllName); +namespace { + +std::string getKnownFolderPath(const std::string& desc, REFKNOWNFOLDERID folderid) +{ + // https://msdn.microsoft.com/en-us/library/windows/desktop/bb762188(v=vs.85).aspx + PWSTR wstrptr = 0; + HRESULT result = SHGetKnownFolderPath( + folderid, + KF_FLAG_DEFAULT, // no flags + NULL, // current user, no impersonation + &wstrptr); + if (result == S_OK) + { + std::string utf8 = utf16str_to_utf8str(llutf16string(wstrptr)); + // have to free the returned pointer after copying its data + CoTaskMemFree(wstrptr); + return utf8; + } + + // gack, no logging yet! + // at least say something to a developer trying to debug this... + static std::map codes + { + { E_FAIL, "E_FAIL; known folder does not have a path?" }, + { E_INVALIDARG, "E_INVALIDARG; not present on system?" } + }; + auto found = codes.find(result); + const char* text = (found == codes.end())? "unknown" : found->second; + std::cout << "*** SHGetKnownFolderPath(" << desc << ") failed with " + << result << " (" << text << ")\n"; + return {}; +} + +} // anonymous namespace + LLDir_Win32::LLDir_Win32() { mDirDelimiter = "\\"; - WCHAR w_str[MAX_PATH]; - // Application Data is where user settings go - SHGetSpecialFolderPath(NULL, w_str, CSIDL_APPDATA, TRUE); - - mOSUserDir = utf16str_to_utf8str(llutf16string(w_str)); + mOSUserDir = getKnownFolderPath("RoamingAppData", FOLDERID_RoamingAppData); // We want cache files to go on the local disk, even if the // user is on a network with a "roaming profile". // - // On XP this is: - // C:\Docments and Settings\James\Local Settings\Application Data // On Vista this is: // C:\Users\James\AppData\Local // // We used to store the cache in AppData\Roaming, and the installer // cleans up that version on upgrade. JC - SHGetSpecialFolderPath(NULL, w_str, CSIDL_LOCAL_APPDATA, TRUE); - mOSCacheDir = utf16str_to_utf8str(llutf16string(w_str)); + mOSCacheDir = getKnownFolderPath("LocalAppData", FOLDERID_LocalAppData); + WCHAR w_str[MAX_PATH]; if (GetTempPath(MAX_PATH, w_str)) { if (wcslen(w_str)) /* Flawfinder: ignore */ @@ -73,6 +105,16 @@ LLDir_Win32::LLDir_Win32() w_str[wcslen(w_str)-1] = '\0'; /* Flawfinder: ignore */ // remove trailing slash } mTempDir = utf16str_to_utf8str(llutf16string(w_str)); + + if (mOSUserDir.empty()) + { + mOSUserDir = mTempDir; + } + + if (mOSCacheDir.empty()) + { + mOSCacheDir = mTempDir; + } } else { -- cgit v1.2.3 From 867b5f5a904366810c614d7b3327f253e46e59ae Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 14 Dec 2017 18:47:15 -0500 Subject: MAINT-8087: #include header for CoTaskMemFree() function which is required to free the pointer returned by SHGetKnownFolderPath(). --- indra/llvfs/lldir_win32.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp index 55f0a6338d..4d8aa0e189 100644 --- a/indra/llvfs/lldir_win32.cpp +++ b/indra/llvfs/lldir_win32.cpp @@ -35,6 +35,7 @@ #include #include #include +#include // CoTaskMemFree() #include #include -- cgit v1.2.3 From 870008f15b60399af6971ea746bcf7a05a8ea1db Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 14 Dec 2017 19:33:10 -0500 Subject: MAINT-8087: New LLDir_Win32 code requires ole32 in a few more places. --- indra/test/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt index 8344cead57..3f12431acc 100644 --- a/indra/test/CMakeLists.txt +++ b/indra/test/CMakeLists.txt @@ -73,6 +73,9 @@ if (NOT WINDOWS) list(APPEND test_SOURCE_FILES llmessagetemplateparser_tut.cpp ) + set(EXTRA_WINDOWS_LIBRARIES "") +else (NOT WINDOWS) + set(EXTRA_WINDOWS_LIBRARIES ole32) endif (NOT WINDOWS) set_source_files_properties(${test_HEADER_FILES} @@ -96,6 +99,7 @@ target_link_libraries(lltest ${GOOGLEMOCK_LIBRARIES} ${PTHREAD_LIBRARY} ${WINDOWS_LIBRARIES} + ${EXTRA_WINDOWS_LIBRARIES} ${BOOST_PROGRAM_OPTIONS_LIBRARY} ${BOOST_REGEX_LIBRARY} ${BOOST_COROUTINE_LIBRARY} -- cgit v1.2.3 From 18bf0eae3ba88733bed43224f32373a26d80630b Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 14 Dec 2017 21:16:08 -0500 Subject: MAINT-8087: Update to viewer-manager build 511437 --- autobuild.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index f96517baad..cdb2a2c841 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3231,9 +3231,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 69a42a95bc4442972f3d9ff933a77441 + 9baddc9bf684124c1b782c27f9bdf68d url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11666/67316/viewer_manager-1.0.511391-darwin64-511391.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11733/67685/viewer_manager-1.0.511437-darwin64-511437.tar.bz2 name darwin64 @@ -3255,9 +3255,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - e6a9b1b35fdea7d2c72e9280484741a7 + cc189c4e0394cb9b3a82452990895a34 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11667/67322/viewer_manager-1.0.511391-windows-511391.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11734/67691/viewer_manager-1.0.511437-windows-511437.tar.bz2 name windows @@ -3268,7 +3268,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 1.0.511391 + 1.0.511437 vlc-bin -- cgit v1.2.3 From 30c2f108badb7699715f95206b6a853c88569096 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 15 Dec 2017 15:28:10 -0500 Subject: MAINT-8087: Update to viewer-manager build 511460 --- autobuild.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index cdb2a2c841..099946d47e 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3231,9 +3231,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 9baddc9bf684124c1b782c27f9bdf68d + d06ba26bf4502659a4e1d3d00fa65a57 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11733/67685/viewer_manager-1.0.511437-darwin64-511437.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11769/68035/viewer_manager-1.0.511460-darwin64-511460.tar.bz2 name darwin64 @@ -3255,9 +3255,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - cc189c4e0394cb9b3a82452990895a34 + ec8f71ccf7cc729ee470c15fcb6cea55 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11734/67691/viewer_manager-1.0.511437-windows-511437.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11770/68045/viewer_manager-1.0.511460-windows-511460.tar.bz2 name windows @@ -3268,7 +3268,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 1.0.511437 + 1.0.511460 vlc-bin -- cgit v1.2.3 From 34a9de7270efc4aa45504eb70ec7367cf7162603 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 15 Dec 2017 17:07:37 -0500 Subject: MAINT-8087: Update to viewer-manager build 511462 --- autobuild.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 099946d47e..5ea349e55d 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3231,9 +3231,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - d06ba26bf4502659a4e1d3d00fa65a57 + a1cc313f9238316a514b8d3056f86b31 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11769/68035/viewer_manager-1.0.511460-darwin64-511460.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11774/68078/viewer_manager-1.0.511462-darwin64-511462.tar.bz2 name darwin64 @@ -3255,9 +3255,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - ec8f71ccf7cc729ee470c15fcb6cea55 + 73894a49bd63e06adc0e365efae6e03e url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11770/68045/viewer_manager-1.0.511460-windows-511460.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11775/68084/viewer_manager-1.0.511462-windows-511462.tar.bz2 name windows @@ -3268,7 +3268,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 1.0.511460 + 1.0.511462 vlc-bin -- cgit v1.2.3 From 7c3638e09718557ca03f263b08d45c4b7face547 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 20 Dec 2017 17:27:43 -0500 Subject: MAINT-8087: Update to viewer-manager build 511531 --- autobuild.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 5ea349e55d..45e83901e0 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3231,9 +3231,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - a1cc313f9238316a514b8d3056f86b31 + e16cfcbef21c04ca51f2c6aa178d1f72 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11774/68078/viewer_manager-1.0.511462-darwin64-511462.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11874/69202/viewer_manager-1.0.511531-darwin64-511531.tar.bz2 name darwin64 @@ -3255,9 +3255,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 73894a49bd63e06adc0e365efae6e03e + 8f53d1b01fb7d62e497da5d0d5026857 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11775/68084/viewer_manager-1.0.511462-windows-511462.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11875/69208/viewer_manager-1.0.511531-windows-511531.tar.bz2 name windows @@ -3268,7 +3268,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 1.0.511462 + 1.0.511531 vlc-bin -- cgit v1.2.3 From 36e5f543ced86ce1d976c0740fe04bc36475fbaf Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 20 Dec 2017 22:33:28 -0500 Subject: MAINT-8087: Update to viewer-manager build 511535 --- autobuild.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 45e83901e0..532fecb815 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3231,9 +3231,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - e16cfcbef21c04ca51f2c6aa178d1f72 + 401b86c884995974220ac570e0a84ff1 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11874/69202/viewer_manager-1.0.511531-darwin64-511531.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11883/69273/viewer_manager-1.0.511535-darwin64-511535.tar.bz2 name darwin64 @@ -3255,9 +3255,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 8f53d1b01fb7d62e497da5d0d5026857 + 6e0ab85a8b19a575c56f52af3b871b2e url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11875/69208/viewer_manager-1.0.511531-windows-511531.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11884/69279/viewer_manager-1.0.511535-windows-511535.tar.bz2 name windows @@ -3268,7 +3268,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 1.0.511531 + 1.0.511535 vlc-bin -- cgit v1.2.3 From 5002bf5660f41685fc0549880994f4b35440d535 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 20 Dec 2017 22:51:26 -0500 Subject: MAINT-8087: Use env vars from VMP for AppData\Roaming and Local. On Windows, when logged in with a non-ASCII username, every one of the three documented APIs -- SHGetSpecialFolderPath(), SHGetFolderPath() and SHGetKnownFolderPath() -- fails to retrieve any pathname at all. We cannot account for the fact that the oldest of these continues to work with the release viewer and within a Python script (though not, curiously, from a Python interactive session). With a non-ASCII username, they consistently fail when called from an Alex Ivy viewer build: "The filename, directory name, or volume label syntax is incorrect." Empirically, with a non-ASCII username, the preset APPDATA and LOCALAPPDATA environment variables are also useless, e.g. c:\Users\??????\AppData\Roaming where those are, yup, actual question marks. Empirically, the VMP is able to successfully call SHGetFolderPath() to retrieve both AppData\Roaming and AppData\Local. Therefore, we make the VMP set the APPDATA and LOCALAPPDATA environment variables to the UTF-8 encoded correct pathnames. Instead of calling SHGetSomethingFolderPath() at all, make LLDir_Win32 retrieve those environment variables. Make LLFile::mkdir() treat "directory already exists" as a success case. Every single call fell into one of two categories: either it didn't check success at all, or it tested specially to exempt errno == EEXIST. Migrate that test into mkdir(); eliminate it from call sites. Make LLDir::append() and add() convenience functions accept variadic arguments. Replace add(add()...) constructs, as well as clumsy concatenations of directory names and getDirDelimiter(), with simple variadic add() calls. --- indra/llcommon/llfile.cpp | 9 ++- indra/llcommon/llfile.h | 1 + indra/llui/llspellcheck.cpp | 5 +- indra/llvfs/lldir.cpp | 11 +--- indra/llvfs/lldir.h | 25 +++++++- indra/llvfs/lldir_linux.cpp | 28 +++----- indra/llvfs/lldir_solaris.cpp | 28 +++----- indra/llvfs/lldir_win32.cpp | 128 ++++++++++++++++--------------------- indra/newview/llappviewer.cpp | 10 +-- indra/newview/llpresetsmanager.cpp | 10 +-- indra/newview/lltexturecache.cpp | 8 +-- indra/test/CMakeLists.txt | 4 -- 12 files changed, 112 insertions(+), 155 deletions(-) diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index 7b559861bb..8aa41035b9 100644 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -182,7 +182,14 @@ int LLFile::mkdir(const std::string& dirname, int perms) int rc = ::mkdir(dirname.c_str(), (mode_t)perms); #endif // We often use mkdir() to ensure the existence of a directory that might - // already exist. Don't spam the log if it does. + // already exist. There is no known case in which we want to call out as + // an error the requested directory already existing. + if (rc < 0 && errno == EEXIST) + { + // this is not the error you want, move along + return 0; + } + // anything else might be a problem return warnif("mkdir", dirname, rc, EEXIST); } diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h index 37eb75881c..ba935b8714 100644 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -69,6 +69,7 @@ public: // perms is a permissions mask like 0777 or 0700. In most cases it will // be overridden by the user's umask. It is ignored on Windows. + // mkdir() considers "directory already exists" to be SUCCESS. static int mkdir(const std::string& filename, int perms = 0700); static int rmdir(const std::string& filename); diff --git a/indra/llui/llspellcheck.cpp b/indra/llui/llspellcheck.cpp index 5a52600337..7f64743e99 100644 --- a/indra/llui/llspellcheck.cpp +++ b/indra/llui/llspellcheck.cpp @@ -406,10 +406,7 @@ const std::string LLSpellChecker::getDictionaryAppPath() const std::string LLSpellChecker::getDictionaryUserPath() { std::string dict_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, DICT_DIR, ""); - if (!gDirUtilp->fileExists(dict_path)) - { - LLFile::mkdir(dict_path); - } + LLFile::mkdir(dict_path); return dict_path; } diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index b845de71fa..2069888774 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -597,7 +597,7 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd << "': prefix is empty, possible bad filename" << LL_ENDL; } - std::string expanded_filename = add(add(prefix, subdir1), subdir2); + std::string expanded_filename = add(prefix, subdir1, subdir2); if (expanded_filename.empty() && in_filename.empty()) { return ""; @@ -693,7 +693,7 @@ void LLDir::walkSearchSkinDirs(const std::string& subdir, std::string subdir_path(add(skindir, subdir)); BOOST_FOREACH(std::string subsubdir, subsubdirs) { - std::string full_path(add(add(subdir_path, subsubdir), filename)); + std::string full_path(add(subdir_path, subsubdir, filename)); if (fileExists(full_path)) { function(subsubdir, full_path); @@ -1052,13 +1052,6 @@ void LLDir::dumpCurrentDirectories() LL_DEBUGS("AppInit","Directories") << " SkinDir: " << getSkinDir() << LL_ENDL; } -std::string LLDir::add(const std::string& path, const std::string& name) const -{ - std::string destpath(path); - append(destpath, name); - return destpath; -} - void LLDir::append(std::string& destpath, const std::string& name) const { // Delegate question of whether we need a separator to helper method. diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h index b219c6e29f..e233413a7f 100644 --- a/indra/llvfs/lldir.h +++ b/indra/llvfs/lldir.h @@ -202,9 +202,28 @@ class LLDir /// Append specified @a name to @a destpath, separated by getDirDelimiter() /// if both are non-empty. void append(std::string& destpath, const std::string& name) const; - /// Append specified @a name to @a path, separated by getDirDelimiter() - /// if both are non-empty. Return result, leaving @a path unmodified. - std::string add(const std::string& path, const std::string& name) const; + /// Variadic form: append @a name0 and @a name1 and arbitrary other @a + /// names to @a destpath, separated by getDirDelimiter() as needed. + template + void append(std::string& destpath, const std::string& name0, const std::string& name1, + const NAMES& ... names) const + { + // In a typical recursion case, we'd accept (destpath, name0, names). + // We accept (destpath, name0, name1, names) because it's important to + // delegate the two-argument case to the non-template implementation. + append(destpath, name0); + append(destpath, name1, names...); + } + + /// Append specified @a names to @a path, separated by getDirDelimiter() + /// as needed. Return result, leaving @a path unmodified. + template + std::string add(const std::string& path, const NAMES& ... names) const + { + std::string destpath(path); + append(destpath, names...); + return destpath; + } protected: // Does an add() or append() call need a directory delimiter? diff --git a/indra/llvfs/lldir_linux.cpp b/indra/llvfs/lldir_linux.cpp index 7a4034c228..a9f3166d41 100644 --- a/indra/llvfs/lldir_linux.cpp +++ b/indra/llvfs/lldir_linux.cpp @@ -185,41 +185,29 @@ void LLDir_Linux::initAppDirs(const std::string &app_name, int res = LLFile::mkdir(mOSUserAppDir); if (res == -1) { - if (errno != EEXIST) - { - LL_WARNS() << "Couldn't create app user dir " << mOSUserAppDir << LL_ENDL; - LL_WARNS() << "Default to base dir" << mOSUserDir << LL_ENDL; - mOSUserAppDir = mOSUserDir; - } + LL_WARNS() << "Couldn't create app user dir " << mOSUserAppDir << LL_ENDL; + LL_WARNS() << "Default to base dir" << mOSUserDir << LL_ENDL; + mOSUserAppDir = mOSUserDir; } res = LLFile::mkdir(getExpandedFilename(LL_PATH_LOGS,"")); if (res == -1) { - if (errno != EEXIST) - { - LL_WARNS() << "Couldn't create LL_PATH_LOGS dir " << getExpandedFilename(LL_PATH_LOGS,"") << LL_ENDL; - } + LL_WARNS() << "Couldn't create LL_PATH_LOGS dir " << getExpandedFilename(LL_PATH_LOGS,"") << LL_ENDL; } res = LLFile::mkdir(getExpandedFilename(LL_PATH_USER_SETTINGS,"")); if (res == -1) { - if (errno != EEXIST) - { - LL_WARNS() << "Couldn't create LL_PATH_USER_SETTINGS dir " << getExpandedFilename(LL_PATH_USER_SETTINGS,"") << LL_ENDL; - } + LL_WARNS() << "Couldn't create LL_PATH_USER_SETTINGS dir " << getExpandedFilename(LL_PATH_USER_SETTINGS,"") << LL_ENDL; } - + res = LLFile::mkdir(getExpandedFilename(LL_PATH_CACHE,"")); if (res == -1) { - if (errno != EEXIST) - { - LL_WARNS() << "Couldn't create LL_PATH_CACHE dir " << getExpandedFilename(LL_PATH_CACHE,"") << LL_ENDL; - } + LL_WARNS() << "Couldn't create LL_PATH_CACHE dir " << getExpandedFilename(LL_PATH_CACHE,"") << LL_ENDL; } - + mCAFile = getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem"); } diff --git a/indra/llvfs/lldir_solaris.cpp b/indra/llvfs/lldir_solaris.cpp index b43b2f27ce..d60237bacc 100644 --- a/indra/llvfs/lldir_solaris.cpp +++ b/indra/llvfs/lldir_solaris.cpp @@ -203,41 +203,29 @@ void LLDir_Solaris::initAppDirs(const std::string &app_name, int res = LLFile::mkdir(mOSUserAppDir); if (res == -1) { - if (errno != EEXIST) - { - LL_WARNS() << "Couldn't create app user dir " << mOSUserAppDir << LL_ENDL; - LL_WARNS() << "Default to base dir" << mOSUserDir << LL_ENDL; - mOSUserAppDir = mOSUserDir; - } + LL_WARNS() << "Couldn't create app user dir " << mOSUserAppDir << LL_ENDL; + LL_WARNS() << "Default to base dir" << mOSUserDir << LL_ENDL; + mOSUserAppDir = mOSUserDir; } res = LLFile::mkdir(getExpandedFilename(LL_PATH_LOGS,"")); if (res == -1) { - if (errno != EEXIST) - { - LL_WARNS() << "Couldn't create LL_PATH_LOGS dir " << getExpandedFilename(LL_PATH_LOGS,"") << LL_ENDL; - } + LL_WARNS() << "Couldn't create LL_PATH_LOGS dir " << getExpandedFilename(LL_PATH_LOGS,"") << LL_ENDL; } res = LLFile::mkdir(getExpandedFilename(LL_PATH_USER_SETTINGS,"")); if (res == -1) { - if (errno != EEXIST) - { - LL_WARNS() << "Couldn't create LL_PATH_USER_SETTINGS dir " << getExpandedFilename(LL_PATH_USER_SETTINGS,"") << LL_ENDL; - } + LL_WARNS() << "Couldn't create LL_PATH_USER_SETTINGS dir " << getExpandedFilename(LL_PATH_USER_SETTINGS,"") << LL_ENDL; } - + res = LLFile::mkdir(getExpandedFilename(LL_PATH_CACHE,"")); if (res == -1) { - if (errno != EEXIST) - { - LL_WARNS() << "Couldn't create LL_PATH_CACHE dir " << getExpandedFilename(LL_PATH_CACHE,"") << LL_ENDL; - } + LL_WARNS() << "Couldn't create LL_PATH_CACHE dir " << getExpandedFilename(LL_PATH_CACHE,"") << LL_ENDL; } - + mCAFile = getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem"); } diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp index 4d8aa0e189..5485349c83 100644 --- a/indra/llvfs/lldir_win32.cpp +++ b/indra/llvfs/lldir_win32.cpp @@ -32,10 +32,7 @@ #include "llerror.h" #include "llrand.h" // for gLindenLabRandomNumber #include -#include -#include -#include -#include // CoTaskMemFree() +#include #include #include @@ -46,47 +43,15 @@ #define PACKVERSION(major,minor) MAKELONG(minor,major) DWORD GetDllVersion(LPCTSTR lpszDllName); -namespace { - -std::string getKnownFolderPath(const std::string& desc, REFKNOWNFOLDERID folderid) -{ - // https://msdn.microsoft.com/en-us/library/windows/desktop/bb762188(v=vs.85).aspx - PWSTR wstrptr = 0; - HRESULT result = SHGetKnownFolderPath( - folderid, - KF_FLAG_DEFAULT, // no flags - NULL, // current user, no impersonation - &wstrptr); - if (result == S_OK) - { - std::string utf8 = utf16str_to_utf8str(llutf16string(wstrptr)); - // have to free the returned pointer after copying its data - CoTaskMemFree(wstrptr); - return utf8; - } - - // gack, no logging yet! - // at least say something to a developer trying to debug this... - static std::map codes - { - { E_FAIL, "E_FAIL; known folder does not have a path?" }, - { E_INVALIDARG, "E_INVALIDARG; not present on system?" } - }; - auto found = codes.find(result); - const char* text = (found == codes.end())? "unknown" : found->second; - std::cout << "*** SHGetKnownFolderPath(" << desc << ") failed with " - << result << " (" << text << ")\n"; - return {}; -} - -} // anonymous namespace - LLDir_Win32::LLDir_Win32() { + // set this first: used by append() and add() methods mDirDelimiter = "\\"; - // Application Data is where user settings go - mOSUserDir = getKnownFolderPath("RoamingAppData", FOLDERID_RoamingAppData); + // Application Data is where user settings go. We rely on $APPDATA being + // correct; in fact the VMP makes a point of setting it properly, since + // Windows itself botches the job for non-ASCII usernames (MAINT-8087). + mOSUserDir = ll_safe_string(getenv("APPDATA")); // We want cache files to go on the local disk, even if the // user is on a network with a "roaming profile". @@ -96,7 +61,7 @@ LLDir_Win32::LLDir_Win32() // // We used to store the cache in AppData\Roaming, and the installer // cleans up that version on upgrade. JC - mOSCacheDir = getKnownFolderPath("LocalAppData", FOLDERID_LocalAppData); + mOSCacheDir = ll_safe_string(getenv("LOCALAPPDATA")); WCHAR w_str[MAX_PATH]; if (GetTempPath(MAX_PATH, w_str)) @@ -122,6 +87,38 @@ LLDir_Win32::LLDir_Win32() mTempDir = mOSUserDir; } +/*==========================================================================*| + // Now that we've got mOSUserDir, one way or another, let's see how we did + // with our environment variables. + { + auto report = [this](std::ostream& out){ + out << "mOSUserDir = '" << mOSUserDir << "'\n" + << "mOSCacheDir = '" << mOSCacheDir << "'\n" + << "mTempDir = '" << mTempDir << "'" << std::endl; + }; + int res = LLFile::mkdir(mOSUserDir); + if (res == -1) + { + // If we couldn't even create the directory, just blurt to stderr + report(std::cerr); + } + else + { + // successfully created logdir, plunk a log file there + std::string logfilename(add(mOSUserDir, "lldir.log")); + std::ofstream logfile(logfilename.c_str()); + if (! logfile.is_open()) + { + report(std::cerr); + } + else + { + report(logfile); + } + } + } +|*==========================================================================*/ + // fprintf(stderr, "mTempDir = <%s>",mTempDir); // Set working directory, for LLDir::getWorkingDir() @@ -167,7 +164,7 @@ LLDir_Win32::LLDir_Win32() // 'llplugin' need to go somewhere else. // alas... this also gets called during static initialization // time due to the construction of gDirUtil in lldir.cpp. - if(! LLFile::isdir(mAppRODataDir + mDirDelimiter + "skins")) + if(! LLFile::isdir(add(mAppRODataDir, "skins"))) { // What? No skins in the working dir? // Try the executable's directory. @@ -176,7 +173,7 @@ LLDir_Win32::LLDir_Win32() // LL_INFOS() << "mAppRODataDir = " << mAppRODataDir << LL_ENDL; - mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins"; + mSkinBaseDir = add(mAppRODataDir, "skins"); // Build the default cache directory mDefaultCacheDir = buildSLOSCacheDir(); @@ -185,13 +182,10 @@ LLDir_Win32::LLDir_Win32() int res = LLFile::mkdir(mDefaultCacheDir); if (res == -1) { - if (errno != EEXIST) - { - LL_WARNS() << "Couldn't create LL_PATH_CACHE dir " << mDefaultCacheDir << LL_ENDL; - } + LL_WARNS() << "Couldn't create LL_PATH_CACHE dir " << mDefaultCacheDir << LL_ENDL; } - mLLPluginDir = mExecutableDir + mDirDelimiter + "llplugin"; + mLLPluginDir = add(mExecutableDir, "llplugin"); } LLDir_Win32::~LLDir_Win32() @@ -207,52 +201,38 @@ void LLDir_Win32::initAppDirs(const std::string &app_name, if (!app_read_only_data_dir.empty()) { mAppRODataDir = app_read_only_data_dir; - mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins"; + mSkinBaseDir = add(mAppRODataDir, "skins"); } mAppName = app_name; - mOSUserAppDir = mOSUserDir; - mOSUserAppDir += "\\"; - mOSUserAppDir += app_name; + mOSUserAppDir = add(mOSUserDir, app_name); int res = LLFile::mkdir(mOSUserAppDir); if (res == -1) { - if (errno != EEXIST) - { - LL_WARNS() << "Couldn't create app user dir " << mOSUserAppDir << LL_ENDL; - LL_WARNS() << "Default to base dir" << mOSUserDir << LL_ENDL; - mOSUserAppDir = mOSUserDir; - } + LL_WARNS() << "Couldn't create app user dir " << mOSUserAppDir << LL_ENDL; + LL_WARNS() << "Default to base dir" << mOSUserDir << LL_ENDL; + mOSUserAppDir = mOSUserDir; } //dumpCurrentDirectories(); res = LLFile::mkdir(getExpandedFilename(LL_PATH_LOGS,"")); if (res == -1) { - if (errno != EEXIST) - { - LL_WARNS() << "Couldn't create LL_PATH_LOGS dir " << getExpandedFilename(LL_PATH_LOGS,"") << LL_ENDL; - } + LL_WARNS() << "Couldn't create LL_PATH_LOGS dir " << getExpandedFilename(LL_PATH_LOGS,"") << LL_ENDL; } - + res = LLFile::mkdir(getExpandedFilename(LL_PATH_USER_SETTINGS,"")); if (res == -1) { - if (errno != EEXIST) - { - LL_WARNS() << "Couldn't create LL_PATH_USER_SETTINGS dir " << getExpandedFilename(LL_PATH_USER_SETTINGS,"") << LL_ENDL; - } + LL_WARNS() << "Couldn't create LL_PATH_USER_SETTINGS dir " << getExpandedFilename(LL_PATH_USER_SETTINGS,"") << LL_ENDL; } - + res = LLFile::mkdir(getExpandedFilename(LL_PATH_CACHE,"")); if (res == -1) { - if (errno != EEXIST) - { - LL_WARNS() << "Couldn't create LL_PATH_CACHE dir " << getExpandedFilename(LL_PATH_CACHE,"") << LL_ENDL; - } + LL_WARNS() << "Couldn't create LL_PATH_CACHE dir " << getExpandedFilename(LL_PATH_CACHE,"") << LL_ENDL; } - + mCAFile = getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem"); } diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 087a672d69..b33b3a6410 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4136,10 +4136,7 @@ void dumpVFSCaches() S32 res = LLFile::mkdir("StaticVFSDump"); if (res == -1) { - if (errno != EEXIST) - { - LL_WARNS() << "Couldn't create dir StaticVFSDump" << LL_ENDL; - } + LL_WARNS() << "Couldn't create dir StaticVFSDump" << LL_ENDL; } SetCurrentDirectory(utf8str_to_utf16str("StaticVFSDump").c_str()); gStaticVFS->dumpFiles(); @@ -4153,10 +4150,7 @@ void dumpVFSCaches() res = LLFile::mkdir("VFSDump"); if (res == -1) { - if (errno != EEXIST) - { - LL_WARNS() << "Couldn't create dir VFSDump" << LL_ENDL; - } + LL_WARNS() << "Couldn't create dir VFSDump" << LL_ENDL; } SetCurrentDirectory(utf8str_to_utf16str("VFSDump").c_str()); gVFS->dumpFiles(); diff --git a/indra/newview/llpresetsmanager.cpp b/indra/newview/llpresetsmanager.cpp index 76d721ecdc..96818d5a21 100644 --- a/indra/newview/llpresetsmanager.cpp +++ b/indra/newview/llpresetsmanager.cpp @@ -78,16 +78,10 @@ std::string LLPresetsManager::getPresetsDir(const std::string& subdirectory) std::string presets_path = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PRESETS_DIR); std::string full_path; - if (!gDirUtilp->fileExists(presets_path)) - { - LLFile::mkdir(presets_path); - } + LLFile::mkdir(presets_path); full_path = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PRESETS_DIR, subdirectory); - if (!gDirUtilp->fileExists(full_path)) - { - LLFile::mkdir(full_path); - } + LLFile::mkdir(full_path); return full_path; } diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 435d833345..371da5d0a2 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -1054,11 +1054,11 @@ S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL texture_cache return max_size ; } } - + if (!mReadOnly) { LLFile::mkdir(mTexturesDirName); - + const char* subdirs = "0123456789abcdef"; for (S32 i=0; i<16; i++) { @@ -1602,11 +1602,11 @@ void LLTextureCache::clearCorruptedCache() closeHeaderEntriesFile();//close possible file handler purgeAllTextures(false) ; //clear the cache. - + if (!mReadOnly) //regenerate the directory tree if not exists. { LLFile::mkdir(mTexturesDirName); - + const char* subdirs = "0123456789abcdef"; for (S32 i=0; i<16; i++) { diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt index 3f12431acc..8344cead57 100644 --- a/indra/test/CMakeLists.txt +++ b/indra/test/CMakeLists.txt @@ -73,9 +73,6 @@ if (NOT WINDOWS) list(APPEND test_SOURCE_FILES llmessagetemplateparser_tut.cpp ) - set(EXTRA_WINDOWS_LIBRARIES "") -else (NOT WINDOWS) - set(EXTRA_WINDOWS_LIBRARIES ole32) endif (NOT WINDOWS) set_source_files_properties(${test_HEADER_FILES} @@ -99,7 +96,6 @@ target_link_libraries(lltest ${GOOGLEMOCK_LIBRARIES} ${PTHREAD_LIBRARY} ${WINDOWS_LIBRARIES} - ${EXTRA_WINDOWS_LIBRARIES} ${BOOST_PROGRAM_OPTIONS_LIBRARY} ${BOOST_REGEX_LIBRARY} ${BOOST_COROUTINE_LIBRARY} -- cgit v1.2.3 From dfd62c56d3b2da9e17c17f8e5ee0c09b3333a970 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 21 Dec 2017 09:27:36 -0500 Subject: MAINT-8087: Update to viewer-manager build 511542 --- autobuild.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 532fecb815..b7371893f9 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3231,9 +3231,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 401b86c884995974220ac570e0a84ff1 + 75e29dcb5b326eddd473a841436cf226 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11883/69273/viewer_manager-1.0.511535-darwin64-511535.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11895/69299/viewer_manager-1.0.511542-darwin64-511542.tar.bz2 name darwin64 @@ -3255,9 +3255,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 6e0ab85a8b19a575c56f52af3b871b2e + e27bdc13c25d68aeb65238752e8d067e url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11884/69279/viewer_manager-1.0.511535-windows-511535.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11897/69334/viewer_manager-1.0.511542-windows-511542.tar.bz2 name windows @@ -3268,7 +3268,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 1.0.511535 + 1.0.511542 vlc-bin -- cgit v1.2.3 From 6b3ac6823d7d2eb1566b70c69109ffd57faa4e97 Mon Sep 17 00:00:00 2001 From: callum_linden Date: Thu, 21 Dec 2017 13:08:32 -0800 Subject: A change elsewhere in the viewer_manifest.py script that copies files into the right place after a build impacted the fragment of code that copies over the VLC runtime files (Libvlc.dll, libvlccore.dll and the VLC plugins dir) and they never made it to the right place. This change restores that copy --- indra/newview/viewer_manifest.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index f930e8b2ce..e0c332681e 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -689,10 +689,10 @@ class WindowsManifest(ViewerManifest): self.path("zh-CN.pak") self.path("zh-TW.pak") - with self.prefix(src=os.path.join(pkgdir, 'bin', 'release'), dst="llplugin"): - self.path("libvlc.dll") - self.path("libvlccore.dll") - self.path("plugins/") + with self.prefix(src=os.path.join(pkgdir, 'bin', 'release'), dst="llplugin"): + self.path("libvlc.dll") + self.path("libvlccore.dll") + self.path("plugins/") # pull in the crash logger and updater from other projects # tag:"crash-logger" here as a cue to the exporter -- cgit v1.2.3 From 7ac3a755e713d0a34747660b3d48d0a7f6978c3e Mon Sep 17 00:00:00 2001 From: callum_linden Date: Thu, 21 Dec 2017 14:36:50 -0800 Subject: MAINT-8119 Fix. A change elsewhere in the viewer_manifest.py script that copies files into the right place after a build impacted the fragment of code that copies over the VLC runtime files (Libvlc.dll, libvlccore.dll and the VLC plugins dir) and they never made it to the right place. This change restores that copy --- indra/newview/viewer_manifest.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index f930e8b2ce..e0c332681e 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -689,10 +689,10 @@ class WindowsManifest(ViewerManifest): self.path("zh-CN.pak") self.path("zh-TW.pak") - with self.prefix(src=os.path.join(pkgdir, 'bin', 'release'), dst="llplugin"): - self.path("libvlc.dll") - self.path("libvlccore.dll") - self.path("plugins/") + with self.prefix(src=os.path.join(pkgdir, 'bin', 'release'), dst="llplugin"): + self.path("libvlc.dll") + self.path("libvlccore.dll") + self.path("plugins/") # pull in the crash logger and updater from other projects # tag:"crash-logger" here as a cue to the exporter -- cgit v1.2.3 From 2e388c92a4400a0a61b05b7f7aaae49abe878a25 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 2 Jan 2018 20:49:21 -0500 Subject: MAINT-8078: Update to viewer-manager build 511634 --- autobuild.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index b7371893f9..c747f67a17 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3231,9 +3231,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 75e29dcb5b326eddd473a841436cf226 + 8c0816f7b4e48ae6232f731f26b97c32 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11895/69299/viewer_manager-1.0.511542-darwin64-511542.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12019/70060/viewer_manager-1.0.511634-darwin64-511634.tar.bz2 name darwin64 @@ -3255,9 +3255,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - e27bdc13c25d68aeb65238752e8d067e + d0d72cc42f2b1a93a6ffd75999ac5014 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/11897/69334/viewer_manager-1.0.511542-windows-511542.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12020/70066/viewer_manager-1.0.511634-windows-511634.tar.bz2 name windows @@ -3268,7 +3268,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 1.0.511542 + 1.0.511634 vlc-bin -- cgit v1.2.3 From 17891cfcda13ef990d7ac000395396a6a6ee78d6 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 3 Jan 2018 15:32:21 -0500 Subject: MAINT-8078: Update to viewer-manager build 511658 --- autobuild.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index c747f67a17..0b827f2080 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3231,9 +3231,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 8c0816f7b4e48ae6232f731f26b97c32 + a8071b247d78e5555340f83e3491e7df url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12019/70060/viewer_manager-1.0.511634-darwin64-511634.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12055/70540/viewer_manager-1.0.511658-darwin64-511658.tar.bz2 name darwin64 @@ -3255,9 +3255,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - d0d72cc42f2b1a93a6ffd75999ac5014 + a9597ba92618b2616e058dee8f56c80c url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12020/70066/viewer_manager-1.0.511634-windows-511634.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12056/70546/viewer_manager-1.0.511658-windows-511658.tar.bz2 name windows @@ -3268,7 +3268,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 1.0.511634 + 1.0.511658 vlc-bin -- cgit v1.2.3 From 26161cf57778c8b554768e16b6b1111c1b2a7b33 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 4 Jan 2018 14:43:21 -0500 Subject: MAINT-8123: Update to viewer-manager build 511679 --- autobuild.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 0b827f2080..a6b0a1d652 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3231,9 +3231,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - a8071b247d78e5555340f83e3491e7df + 4f205b14f712cbef8035a527ae2305c8 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12055/70540/viewer_manager-1.0.511658-darwin64-511658.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12093/71064/viewer_manager-1.0.511679-darwin64-511679.tar.bz2 name darwin64 @@ -3255,9 +3255,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - a9597ba92618b2616e058dee8f56c80c + e89fd2ec532b707fa93155ec25533be2 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12056/70546/viewer_manager-1.0.511658-windows-511658.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12094/71070/viewer_manager-1.0.511679-windows-511679.tar.bz2 name windows @@ -3268,7 +3268,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 1.0.511658 + 1.0.511679 vlc-bin -- cgit v1.2.3 From 37e699bede72f711afc3391f751fac5a8d4ccf2a Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 4 Jan 2018 16:57:40 -0500 Subject: MAINT-8135: Update to viewer-manager build 511688 --- autobuild.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index a6b0a1d652..c90ffe493c 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3231,9 +3231,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 4f205b14f712cbef8035a527ae2305c8 + c4d56d3e942169661a598035a9fbd533 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12093/71064/viewer_manager-1.0.511679-darwin64-511679.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12112/71187/viewer_manager-1.0.511688-darwin64-511688.tar.bz2 name darwin64 @@ -3255,9 +3255,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - e89fd2ec532b707fa93155ec25533be2 + 61f324d880eaa303669b99e28e6cf64c url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12094/71070/viewer_manager-1.0.511679-windows-511679.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12113/71193/viewer_manager-1.0.511688-windows-511688.tar.bz2 name windows @@ -3268,7 +3268,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 1.0.511679 + 1.0.511688 vlc-bin -- cgit v1.2.3 From 6659192a351f61a1c2476a6d34cc5fd6c8d6123f Mon Sep 17 00:00:00 2001 From: callum_linden Date: Fri, 5 Jan 2018 12:29:38 -0800 Subject: Fix for MAINT-8148 - AVI fails to play. For Windows, the x-msvideo MIME type was pointed at CEF which is unable to play it. Switching that to LibVLC made it work as expected. It was already switched on macOS --- indra/newview/skins/default/xui/en/mime_types.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/skins/default/xui/en/mime_types.xml b/indra/newview/skins/default/xui/en/mime_types.xml index 8a810f32a6..de9ac4247f 100644 --- a/indra/newview/skins/default/xui/en/mime_types.xml +++ b/indra/newview/skins/default/xui/en/mime_types.xml @@ -526,7 +526,7 @@ movie - media_plugin_cef + media_plugin_libvlc -- cgit v1.2.3 From d97d7c52068b71bd99b10db046c6a0688b61a254 Mon Sep 17 00:00:00 2001 From: callum_linden Date: Fri, 5 Jan 2018 13:19:08 -0800 Subject: Fix for MAINT-8119 - this bug morphed from a packaging issue to being all about audio not playing when a media stream started. There is some as yet, unknown interaction between the volume catcher code in the CEF plugin and the VLC volume controls. The fix for now is to add a Windows call to the VLC code that sets the process volume explicitly. Later we will address the volume catcher code, move it to a common spot so both CEF and LibVLC can use the same bytes --- indra/media_plugins/libvlc/media_plugin_libvlc.cpp | 55 ++++++++++++++++++---- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp index 048e7675f8..80702a1079 100644 --- a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp +++ b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp @@ -37,6 +37,11 @@ #include "vlc/vlc.h" #include "vlc/libvlc_version.h" +#if LL_WINDOWS +// needed for waveOut call - see below for description +#include +#endif + //////////////////////////////////////////////////////////////////////////////// // class MediaPluginLibVLC : @@ -55,6 +60,7 @@ private: void playMedia(); void resetVLC(); void setVolume(const F64 volume); + void setVolumeVLC(); void updateTitle(const char* title); static void* lock(void* data, void** p_pixels); @@ -221,6 +227,7 @@ void MediaPluginLibVLC::eventCallbacks(const libvlc_event_t* event, void* ptr) case libvlc_MediaPlayerPlaying: parent->mDuration = (float)(libvlc_media_get_duration(parent->mLibVLCMedia)) / 1000.0f; parent->mVlcStatus = STATUS_PLAYING; + parent->setVolumeVLC(); break; case libvlc_MediaPlayerPaused: @@ -394,28 +401,58 @@ void MediaPluginLibVLC::updateTitle(const char* title) sendMessage(message); } -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginLibVLC::setVolume(const F64 volume) +void MediaPluginLibVLC::setVolumeVLC() { - mCurVolume = volume; - if (mLibVLCMediaPlayer) { - int result = libvlc_audio_set_volume(mLibVLCMediaPlayer, (int)(volume * 100)); - if (result != 0) + int vlc_vol = (int)(mCurVolume * 100); + + int result = libvlc_audio_set_volume(mLibVLCMediaPlayer, vlc_vol); + if (result == 0) + { + // volume change was accepted by LibVLC + } + else { - // volume wasn't set but not much to be done here + // volume change was NOT accepted by LibVLC and not actioned } + +#if LL_WINDOWS + // https ://jira.secondlife.com/browse/MAINT-8119 + // CEF media plugin uses code in media_plugins/cef/windows_volume_catcher.cpp to + // set the actual output volume of the plugin process since there is no API in + // CEF to otherwise do this. + // There are explicit calls to change the volume in LibVLC but sometimes they + // are ignored SLPlugin.exe process volume is set to 0 so you never heard audio + // from the VLC media stream. + // The right way to solve this is to move the volume catcher stuff out of + // the CEF plugin and into it's own folder under media_plugins and have it referenced + // by both CEF and VLC. That's for later. The code there boils down to this so for + // now, as we approach a release, the less risky option is to do it directly vs + // calls to volume catcher code. + DWORD left_channel = (DWORD)(mCurVolume * 65535.0f); + DWORD right_channel = (DWORD)(mCurVolume * 65535.0f); + DWORD hw_volume = left_channel << 16 | right_channel; + waveOutSetVolume(NULL, hw_volume); +#endif } else { // volume change was requested but VLC wasn't ready. - // that's okay thought because we saved the value in mCurVolume and + // that's okay though because we saved the value in mCurVolume and // the next volume change after the VLC system is initilzied will set it } } +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginLibVLC::setVolume(const F64 volume) +{ + mCurVolume = volume; + + setVolumeVLC(); +} + //////////////////////////////////////////////////////////////////////////////// // void MediaPluginLibVLC::receiveMessage(const char* message_string) -- cgit v1.2.3