summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorThomas Nelson <rider@lindenlab.com>2018-01-23 08:55:58 -0800
committerThomas Nelson <rider@lindenlab.com>2018-01-23 08:55:58 -0800
commit6489598d57571d5b984cb37eec4dd4421ce86c2a (patch)
tree87584ba45f81e0f6877f8eaafce53e821bf924a8 /indra
parent1b8c2b5ebbe0d42f147730bc9b6528fa8c6796ce (diff)
parentd97d7c52068b71bd99b10db046c6a0688b61a254 (diff)
Merged lindenlab/viewer64 into default
Diffstat (limited to 'indra')
-rwxr-xr-xindra/lib/python/indra/util/llmanifest.py3
-rw-r--r--indra/llcommon/llfile.cpp9
-rw-r--r--indra/llcommon/llfile.h1
-rw-r--r--indra/llui/llspellcheck.cpp5
-rw-r--r--indra/llvfs/lldir.cpp11
-rw-r--r--indra/llvfs/lldir.h25
-rw-r--r--indra/llvfs/lldir_linux.cpp28
-rw-r--r--indra/llvfs/lldir_solaris.cpp28
-rw-r--r--indra/llvfs/lldir_win32.cpp109
-rw-r--r--indra/media_plugins/libvlc/media_plugin_libvlc.cpp55
-rw-r--r--indra/newview/app_settings/settings.xml2
-rw-r--r--indra/newview/llappviewer.cpp10
-rw-r--r--indra/newview/llpresetsmanager.cpp10
-rw-r--r--indra/newview/lltexturecache.cpp8
-rw-r--r--indra/newview/skins/default/xui/en/mime_types.xml2
-rwxr-xr-xindra/newview/viewer_manifest.py1028
16 files changed, 764 insertions, 570 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/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 <typename... NAMES>
+ 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 <typename... NAMES>
+ 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 ebc8fdca33..5485349c83 100644
--- a/indra/llvfs/lldir_win32.cpp
+++ b/indra/llvfs/lldir_win32.cpp
@@ -31,7 +31,8 @@
#include "lldir_win32.h"
#include "llerror.h"
#include "llrand.h" // for gLindenLabRandomNumber
-#include "shlobj.h"
+#include <shlobj.h>
+#include <fstream>
#include <direct.h>
#include <errno.h>
@@ -44,28 +45,25 @@ DWORD GetDllVersion(LPCTSTR lpszDllName);
LLDir_Win32::LLDir_Win32()
{
+ // set this first: used by append() and add() methods
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));
+ // 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".
//
- // 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 = ll_safe_string(getenv("LOCALAPPDATA"));
+ WCHAR w_str[MAX_PATH];
if (GetTempPath(MAX_PATH, w_str))
{
if (wcslen(w_str)) /* Flawfinder: ignore */
@@ -73,12 +71,54 @@ 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
{
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()
@@ -124,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.
@@ -133,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();
@@ -142,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()
@@ -164,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/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 <mmsystem.h>
+#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,30 +401,60 @@ 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)
{
LLPluginMessage message_in;
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 @@
<key>UpdaterMaximumBandwidth</key>
<map>
<key>Comment</key>
- <string>Maximum allowable downstream bandwidth for updater service (kilo bits per second)</string>
+ <string>Obsolete: this parameter is no longer used.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 225ade2957..95e5cbe09e 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -4134,10 +4134,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();
@@ -4151,10 +4148,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/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
</widgettype>
<impl>
- media_plugin_cef
+ media_plugin_libvlc
</impl>
</mimetype>
</mimetypes>
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 57539077fa..e0c332681e 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -32,11 +32,13 @@ import os.path
import shutil
import errno
import json
+import plistlib
+import random
import re
+import stat
+import subprocess
import tarfile
import time
-import random
-import subprocess
viewer_dir = os.path.dirname(__file__)
# Add indra/lib/python to our path so we don't have to muck with PYTHONPATH.
@@ -290,6 +292,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
@@ -308,6 +433,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 +455,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))
@@ -356,18 +485,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")
@@ -378,12 +505,9 @@ class WindowsManifest(ViewerManifest):
self.path("*.gif")
#before, we only needed llbase at build time. With VMP, we need it at run time.
- llbase_path = os.path.join(self.get_dst_prefix(),'llbase')
- if not os.path.exists(llbase_path):
- os.makedirs(llbase_path)
- with self.prefix(dst="llbase"):
- self.path2basename(llbasedir,"*.py")
- self.path2basename(llbasedir,"_cllsd.so")
+ with self.prefix(src=os.path.join(pkgdir, "lib", "python", "llbase"), dst="llbase"):
+ self.path("*.py")
+ self.path("_cllsd.so")
# Plugin host application
self.path2basename(os.path.join(os.pardir,
@@ -482,31 +606,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"):
@@ -514,7 +626,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")
@@ -522,7 +634,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")
@@ -577,10 +689,10 @@ 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"):
- 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
@@ -713,7 +825,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
@@ -736,8 +848,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)
@@ -765,310 +876,392 @@ class DarwinManifest(ViewerManifest):
return True
def construct(self):
+ # These are the names of the top-level application and the embedded
+ # applications for the VMP and for the actual viewer, respectively.
+ # These names, without the .app suffix, determine the flyover text for
+ # their corresponding Dock icons.
+ toplevel_app, toplevel_icon = "Second Life.app", "secondlife.icns"
+ launcher_app, launcher_icon = "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(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")
- 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")
+ # -------------------- 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", dst="Info.plist")
-
- # copy additional libs in <bundle>/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(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,"*")
-
- # 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")
-
- with self.prefix(src=icon_path, dst="vmp_icons"):
- self.path("secondlife.ico")
+ # top-level Info.plist is as generated by CMake
+ Info_plist = "Info.plist"
+ ## This self.path() call reports 0 files... skip?
+ self.path(Info_plist)
+ Info_plist = self.dst_path_of(Info_plist)
+
+ # the one file in top-level MacOS directory is the trampoline to
+ # our nested launcher_app
+ with self.prefix(dst="MacOS"):
+ toplevel_MacOS = self.get_dst_prefix()
+ trampoline = self.put_in_file("""\
+#!/bin/bash
+open "%s" --args "$@"
+""" %
+ # up one directory from MacOS to its sibling Resources directory
+ os.path.join('$(dirname "$0")', os.pardir, 'Resources', launcher_app),
+ "SL_Launcher", # write this file
+ "trampoline") # flag to add to list of copied files
+ # Script must be executable
+ self.run_command(["chmod", "+x", trampoline])
+
+ # Make a symlink to a nested app Frameworks directory that doesn't
+ # yet exist. We shouldn't need this; the only things that need
+ # Frameworks are nested apps under viewer_app, and they should
+ # simply find its Contents/Frameworks by relative pathnames. But
+ # empirically, we do: if we omit this symlink, CEF doesn't work --
+ # the login splash screen doesn't even display. SIIIIGH.
+ # We're passing a path that's already relative, hence symlinkf()
+ # rather than relsymlinkf().
+ self.symlinkf(os.path.join("Resources", viewer_app, "Contents", "Frameworks"))
- #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)
- # <top level>.app/Contents/Frameworks/Chromium Embedded Framework.framework/
- # <top level>.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
@@ -1084,9 +1277,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:
@@ -1145,18 +1339,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
@@ -1192,7 +1386,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
@@ -1201,11 +1398,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:
@@ -1215,18 +1410,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)
@@ -1273,18 +1469,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")
- llbase_path = os.path.join(self.get_dst_prefix(),'llbase')
- if not os.path.exists(llbase_path):
- os.makedirs(llbase_path)
- with self.prefix(dst="llbase"):
- self.path2basename("../packages/lib/python/llbase","*.py")
- self.path2basename("../packages/lib/python/llbase","_cllsd.so")
-
- with self.prefix("res-sdl"):
- self.path("*")
- # recurse
+ 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")
+
+ # recurses, packaged again
+ self.path("res-sdl")
# Get the icons based on the channel type
icon_path = self.icon_path()
@@ -1295,15 +1488,16 @@ 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"):
+ 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
@@ -1319,43 +1513,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
@@ -1452,46 +1645,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()