diff --git a/.hgtags b/.hgtags
index 41d279f17d..8719b0d8c7 100755
--- a/.hgtags
+++ b/.hgtags
@@ -580,3 +580,4 @@ ad0e15543836d64d6399d28b32852510435e344a 5.1.0-release
ac3b1332ad4f55b7182a8cbcc1254535a0069f75 5.1.7-release
23ea0fe36fadf009a60c080392ce80e4bf8af8d9 5.1.8-release
52422540bfe54b71155aa455360bee6e3ef1fd96 5.1.9-release
+1cfa567caf5088ae299271be08cc2d9f0801ff6a pre-Poseidon
diff --git a/autobuild.xml b/autobuild.xml
index a602fede00..02a43a2404 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -448,9 +448,9 @@
archive
name
darwin64
@@ -460,9 +460,9 @@
archive
name
windows
@@ -472,46 +472,16 @@
archive
name
windows64
version
- 1.0.6.519145
-
- chardet
-
colladadom
@@ -1801,36 +1771,6 @@
version
2012.1-2
- idna
-
- copyright
- Copyright (c) 2013-2017, Kim Davies. All rights reserved.
- description
- Python Internationalized Domain Names in Applications (IDNA) Library
- license
- see idna.rst
- license_file
- LICENSES/idna.rst
- name
- idna
- platforms
-
- darwin64
-
- archive
-
- hash
- 7dfe9fc4023d7d4f511dd9fac7258266
- url
- http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6663/23584/idna-2.5-darwin64-506652.tar.bz2
-
- name
- darwin64
-
-
- version
- 2.5
-
jpeglib
copyright
@@ -2509,46 +2449,6 @@
version
0.0.1
- llbase
-
- copyright
- Copyright (c) 2010, Linden Research, Inc.
- license
- mit
- license_file
- LICENSES/llbase-license.txt
- name
- llbase
- platforms
-
- darwin64
-
- archive
-
- hash
- e18eeb0691af053b83bd46b76c6ee86a
- url
- http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6299/21982/llbase-0.9.3.506286-darwin64-506286.tar.bz2
-
- name
- darwin64
-
- windows
-
- archive
-
- hash
- e6865670f9bca1c82fb8b91db3ea515c
- url
- http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6301/21994/llbase-0.9.3.506286-windows-506286.tar.bz2
-
- name
- windows
-
-
- version
- 0.9.3.506286
-
llca
copyright
@@ -3315,52 +3215,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
version
8.35.500898
- requests
-
- copyright
- Copyright 2016 Kenneth Reitz
- description
- Python HTTP Library
- license
- Apache
- license_file
- LICENSES/requests.txt
- name
- requests
- platforms
-
- darwin64
-
- archive
-
- hash
- b8d134a970261b445a3f376ba4e05ff7
- url
- http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6693/23788/requests-2.18.1-darwin64-506681.tar.bz2
-
- name
- darwin64
-
- linux64
-
- archive
-
- hash
- 9fe44ba82ee05363fdfa4c1b9f2ec360
- url
- http://downloads.phoenixviewer.com/requests-2.18.1-linux64-180841555.tar.bz2
-
- name
- linux64
-
-
- source
- https://bitbucket.org/lindenlab/p64_python-requests
- source_type
- hg
- version
- 2.18.1
-
slvoice
copyright
@@ -3571,36 +3425,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
version
0.8.0.1
- urllib3
-
- copyright
- Copyright 2008-2016 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
- description
- Python HTTP Library
- license
- MIT
- license_file
- LICENSES/urllib3.txt
- name
- urllib3
- platforms
-
- darwin64
-
- archive
-
- hash
- 22f64c7fbb6704d2e9519fd1cca8e49b
- url
- http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6659/23560/urllib3-1.21.1-darwin64-506648.tar.bz2
-
- name
- darwin64
-
-
- version
- 1.21.1
-
viewer-manager
copyright
@@ -3608,7 +3432,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
description
Linden Lab Viewer Management Process suite.
license
- Proprietary
+ viewerlgpl
license_file
LICENSE
name
@@ -3620,9 +3444,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- ce95944fb842849108102263a25fc794
+ 1d801a03cb87a248b6573f8550603286
url
- http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/23237/178332/viewer_manager-1.0.518840-darwin64-518840.tar.bz2
+ http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/26264/206909/viewer_manager-2.0.520750-darwin64-520750.tar.bz2
name
darwin64
@@ -3656,9 +3480,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- 642f847a9ac45551af65a55826974334
+ 65e20bc630033178f3f7e4890c0b85f7
url
- http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/23236/178338/viewer_manager-1.0.518840-windows-518840.tar.bz2
+ http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/26265/206915/viewer_manager-2.0.520750-windows-520750.tar.bz2
name
windows
@@ -3669,7 +3493,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
source_type
hg
version
- 1.0.518840
+ 2.0.520750
vlc-bin
diff --git a/indra/cmake/LLBase.cmake b/indra/cmake/LLBase.cmake
deleted file mode 100644
index 76e3c688a3..0000000000
--- a/indra/cmake/LLBase.cmake
+++ /dev/null
@@ -1,4 +0,0 @@
-# -*- cmake -*-
-include(Prebuilt)
-
-use_prebuilt_binary(llbase)
diff --git a/indra/cmake/Requests.cmake b/indra/cmake/Requests.cmake
deleted file mode 100644
index b9c729d697..0000000000
--- a/indra/cmake/Requests.cmake
+++ /dev/null
@@ -1,7 +0,0 @@
-if (DARWIN)
- include (Prebuilt)
- use_prebuilt_binary(requests)
- use_prebuilt_binary(urllib3)
- use_prebuilt_binary(chardet)
- use_prebuilt_binary(idna)
-endif (DARWIN)
diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py
index 0bfc4d11dc..054633d780 100755
--- a/indra/lib/python/indra/util/llmanifest.py
+++ b/indra/lib/python/indra/util/llmanifest.py
@@ -634,6 +634,14 @@ class LLManifest(object):
# *TODO is this gonna be useful?
print "Cleaning up " + c
+ def process_either(self, src, dst):
+ # If it's a real directory, recurse through it --
+ # but not a symlink! Handle those like files.
+ if os.path.isdir(src) and not os.path.islink(src):
+ return self.process_directory(src, dst)
+ else:
+ return self.process_file(src, dst)
+
def process_file(self, src, dst):
if self.includes(src, dst):
for action in self.actions:
@@ -660,10 +668,7 @@ class LLManifest(object):
for name in names:
srcname = os.path.join(src, name)
dstname = os.path.join(dst, name)
- if os.path.isdir(srcname):
- count += self.process_directory(srcname, dstname)
- else:
- count += self.process_file(srcname, dstname)
+ count += self.process_either(srcname, dstname)
return count
def includes(self, src, dst):
@@ -835,11 +840,7 @@ class LLManifest(object):
# if we're specifying a single path (not a glob),
# we should error out if it doesn't exist
self.check_file_exists(src)
- # if it's a directory, recurse through it
- if os.path.isdir(src):
- count += self.process_directory(src, dst)
- else:
- count += self.process_file(src, dst)
+ count += self.process_either(src, dst)
return count
try_prefixes = [self.get_src_prefix(), self.get_artwork_prefix(), self.get_build_prefix()]
diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h
index 8fb27af6a4..c551413811 100644
--- a/indra/llcommon/llcoros.h
+++ b/indra/llcommon/llcoros.h
@@ -169,6 +169,26 @@ public:
static void set_consuming(bool consuming);
static bool get_consuming();
+ /**
+ * RAII control of the consuming flag
+ */
+ class OverrideConsuming
+ {
+ public:
+ OverrideConsuming(bool consuming):
+ mPrevConsuming(get_consuming())
+ {
+ set_consuming(consuming);
+ }
+ ~OverrideConsuming()
+ {
+ set_consuming(mPrevConsuming);
+ }
+
+ private:
+ bool mPrevConsuming;
+ };
+
/**
* Please do NOT directly use boost::dcoroutines::future! It is essential
* to maintain the "current" coroutine at every context switch. This
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index b9961040ee..63143a2ea6 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -119,13 +119,14 @@ namespace {
public:
RecordToFile(const std::string& filename)
{
+ // Don't screw up log file output
+ this->showMultiline(true);
+
mFile.open(filename.c_str(), std::ios_base::out | std::ios_base::app);
if (!mFile)
{
LL_INFOS() << "Error setting log file to " << filename << LL_ENDL;
}
- mWantsTime = true;
- mWantsTags = true;
}
~RecordToFile()
@@ -151,7 +152,7 @@ namespace {
public:
RecordToStderr(bool timestamp) : mUseANSI(ANSI_PROBE)
{
- mWantsTime = timestamp;
+ this->showMultiline(true);
}
virtual void recordMessage(LLError::ELevel level,
@@ -215,7 +216,13 @@ namespace {
class RecordToFixedBuffer : public LLError::Recorder
{
public:
- RecordToFixedBuffer(LLLineBuffer* buffer) : mBuffer(buffer) { }
+ RecordToFixedBuffer(LLLineBuffer* buffer)
+ : mBuffer(buffer)
+ {
+ this->showMultiline(true);
+ this->showTags(false);
+ this->showLocation(false);
+ }
virtual void recordMessage(LLError::ELevel level,
const std::string& message)
@@ -232,7 +239,11 @@ namespace {
{
public:
RecordToWinDebug()
- {}
+ {
+ this->showMultiline(true);
+ this->showTags(false);
+ this->showLocation(false);
+ }
virtual void recordMessage(LLError::ELevel level,
const std::string& message)
@@ -419,8 +430,6 @@ namespace LLError
public:
virtual ~SettingsConfig();
- bool mPrintLocation;
-
LLError::ELevel mDefaultLevel;
LevelMap mFunctionLevelMap;
@@ -461,7 +470,6 @@ namespace LLError
SettingsConfig::SettingsConfig()
: LLRefCount(),
- mPrintLocation(false),
mDefaultLevel(LLError::LEVEL_DEBUG),
mFunctionLevelMap(),
mClassLevelMap(),
@@ -694,12 +702,6 @@ namespace LLError
commonInit(user_dir, app_dir, log_to_stderr);
}
- void setPrintLocation(bool print)
- {
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
- s->mPrintLocation = print;
- }
-
void setFatalFunction(const FatalFunction& f)
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
@@ -814,7 +816,6 @@ namespace LLError
s->mTagLevelMap.clear();
s->mUniqueLogMessages.clear();
- setPrintLocation(config["print-location"]);
setDefaultLevel(decodeLevel(config["default-level"]));
LLSD sets = config["settings"];
@@ -837,11 +838,12 @@ namespace LLError
namespace LLError
{
Recorder::Recorder()
- : mWantsTime(false),
- mWantsTags(false),
- mWantsLevel(true),
- mWantsLocation(false),
- mWantsFunctionName(true)
+ : mWantsTime(true)
+ , mWantsTags(true)
+ , mWantsLevel(true)
+ , mWantsLocation(true)
+ , mWantsFunctionName(true)
+ , mWantsMultiline(false)
{
}
@@ -878,6 +880,42 @@ namespace LLError
return mWantsFunctionName;
}
+ // virtual
+ bool Recorder::wantsMultiline()
+ {
+ return mWantsMultiline;
+ }
+
+ void Recorder::showTime(bool show)
+ {
+ mWantsTime = show;
+ }
+
+ void Recorder::showTags(bool show)
+ {
+ mWantsTags = show;
+ }
+
+ void Recorder::showLevel(bool show)
+ {
+ mWantsLevel = show;
+ }
+
+ void Recorder::showLocation(bool show)
+ {
+ mWantsLocation = show;
+ }
+
+ void Recorder::showFunctionName(bool show)
+ {
+ mWantsFunctionName = show;
+ }
+
+ void Recorder::showMultiline(bool show)
+ {
+ mWantsMultiline = show;
+ }
+
void addRecorder(RecorderPtr recorder)
{
if (!recorder)
@@ -910,17 +948,15 @@ namespace LLError
s->mFileRecorder.reset();
s->mFileRecorderFileName.clear();
- if (file_name.empty())
+ if (!file_name.empty())
{
- return;
- }
-
- RecorderPtr recordToFile(new RecordToFile(file_name));
- if (boost::dynamic_pointer_cast(recordToFile)->okay())
- {
- s->mFileRecorderFileName = file_name;
- s->mFileRecorder = recordToFile;
- addRecorder(recordToFile);
+ RecorderPtr recordToFile(new RecordToFile(file_name));
+ if (boost::dynamic_pointer_cast(recordToFile)->okay())
+ {
+ s->mFileRecorderFileName = file_name;
+ s->mFileRecorder = recordToFile;
+ addRecorder(recordToFile);
+ }
}
}
@@ -931,14 +967,12 @@ namespace LLError
removeRecorder(s->mFixedBufferRecorder);
s->mFixedBufferRecorder.reset();
- if (!fixedBuffer)
+ if (fixedBuffer)
{
- return;
- }
-
- RecorderPtr recordToFixedBuffer(new RecordToFixedBuffer(fixedBuffer));
- s->mFixedBufferRecorder = recordToFixedBuffer;
- addRecorder(recordToFixedBuffer);
+ RecorderPtr recordToFixedBuffer(new RecordToFixedBuffer(fixedBuffer));
+ s->mFixedBufferRecorder = recordToFixedBuffer;
+ addRecorder(recordToFixedBuffer);
+ }
}
std::string logFileName()
@@ -950,9 +984,9 @@ namespace LLError
namespace
{
- /* Hide the log sanitize function so gcc doesnt complain.
- void addEscapedMessage(std::ostream& out, const std::string& message)
+ std::string escapedMessageLines(const std::string& message)
{
+ std::ostringstream out;
size_t written_out = 0;
size_t all_content = message.length();
size_t escape_char_index; // always relative to start of message
@@ -988,13 +1022,16 @@ namespace
// write whatever was left
out << message.substr(written_out, std::string::npos);
}
- } */
+ return out.str();
+ }
- void writeToRecorders(const LLError::CallSite& site, const std::string& escaped_message, bool show_location = true, bool show_time = true, bool show_tags = true, bool show_level = true, bool show_function = true)
+ void writeToRecorders(const LLError::CallSite& site, const std::string& message)
{
LLError::ELevel level = site.mLevel;
LLError::SettingsConfigPtr s = LLError::Settings::getInstance()->getSettingsConfig();
-
+
+ std::string escaped_message;
+
for (Recorders::const_iterator i = s->mRecorders.begin();
i != s->mRecorders.end();
++i)
@@ -1009,7 +1046,7 @@ namespace
}
message_stream << " ";
- if (show_level && r->wantsLevel())
+ if (r->wantsLevel())
{
message_stream << site.mLevelString;
}
@@ -1021,19 +1058,30 @@ namespace
}
message_stream << " ";
- if (r->wantsLocation() || level == LLError::LEVEL_ERROR || s->mPrintLocation)
+ if (r->wantsLocation() || level == LLError::LEVEL_ERROR)
{
message_stream << site.mLocationString;
}
message_stream << " ";
- if (show_function && r->wantsFunctionName())
+ if (r->wantsFunctionName())
{
message_stream << site.mFunctionString;
}
message_stream << " : ";
- message_stream << escaped_message;
+ if (r->wantsMultiline())
+ {
+ message_stream << message;
+ }
+ else
+ {
+ if (escaped_message.empty())
+ {
+ escaped_message = escapedMessageLines(message);
+ }
+ message_stream << escaped_message;
+ }
r->recordMessage(level, message_stream.str());
}
@@ -1235,10 +1283,11 @@ namespace LLError
std::ostringstream prefix;
if( nd::logging::throttle( site.mFile, site.mLine, &prefix ) )
return;
- std::ostringstream message_stream;
if (site.mPrintOnce)
{
+ std::ostringstream message_stream;
+
std::map::iterator messageIter = s->mUniqueLogMessages.find(message);
if (messageIter != s->mUniqueLogMessages.end())
{
@@ -1258,22 +1307,18 @@ namespace LLError
message_stream << "ONCE: ";
s->mUniqueLogMessages[message] = 1;
}
+ message_stream << message;
+ message = message_stream.str();
}
- // Fix log output - we don't need an escaped output
- //addEscapedMessage(message_stream, message);
- message_stream << message;
- //
- std::string message_line(message_stream.str());
-
- writeToRecorders(site, message_line);
+ writeToRecorders(site, message);
if (site.mLevel == LEVEL_ERROR)
{
- g->mFatalMessage = message_line;
+ g->mFatalMessage = message;
if (s->mCrashFunction)
{
- s->mCrashFunction(message_line);
+ s->mCrashFunction(message);
}
}
}
@@ -1581,3 +1626,4 @@ bool debugLoggingEnabled(const std::string& tag)
}
+
diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h
index ddbcdc94a0..a6278b3e50 100644
--- a/indra/llcommon/llerrorcontrol.h
+++ b/indra/llcommon/llerrorcontrol.h
@@ -148,13 +148,22 @@ namespace LLError
bool wantsLevel();
bool wantsLocation();
bool wantsFunctionName();
+ bool wantsMultiline();
+
+ void showTime(bool show);
+ void showTags(bool show);
+ void showLevel(bool show);
+ void showLocation(bool show);
+ void showFunctionName(bool show);
+ void showMultiline(bool show);
protected:
- bool mWantsTime,
- mWantsTags,
- mWantsLevel,
- mWantsLocation,
- mWantsFunctionName;
+ bool mWantsTime;
+ bool mWantsTags;
+ bool mWantsLevel;
+ bool mWantsLocation;
+ bool mWantsFunctionName;
+ bool mWantsMultiline;
};
typedef boost::shared_ptr RecorderPtr;
diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp
index a828a354b6..95aaaeb58b 100644
--- a/indra/llcommon/llevents.cpp
+++ b/indra/llcommon/llevents.cpp
@@ -554,10 +554,8 @@ bool LLEventStream::post(const LLSD& event)
*****************************************************************************/
bool LLEventMailDrop::post(const LLSD& event)
{
- bool posted = false;
-
- if (!mSignal->empty())
- posted = LLEventStream::post(event);
+ // forward the call to our base class
+ bool posted = LLEventStream::post(event);
if (!posted)
{ // if the event was not handled we will save it for later so that it can
@@ -573,16 +571,25 @@ LLBoundListener LLEventMailDrop::listen_impl(const std::string& name,
const NameList& after,
const NameList& before)
{
- if (!mEventHistory.empty())
+ // Before actually connecting this listener for subsequent post() calls,
+ // first feed each of the saved events, in order, to the new listener.
+ // Remove any that this listener consumes -- Effective STL, Item 9.
+ for (auto hi(mEventHistory.begin()), hend(mEventHistory.end()); hi != hend; )
{
- if (listener(mEventHistory.front()))
+ if (listener(*hi))
{
- mEventHistory.pop_front();
+ // new listener consumed this event, erase it
+ hi = mEventHistory.erase(hi);
+ }
+ else
+ {
+ // listener did not consume this event, just move along
+ ++hi;
}
}
+ // let base class perform the actual connection
return LLEventStream::listen_impl(name, listener, after, before);
-
}
diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h
index 1d51c660ed..5d60c63810 100644
--- a/indra/llcommon/llevents.h
+++ b/indra/llcommon/llevents.h
@@ -650,15 +650,21 @@ public:
* LLEventMailDrop
*****************************************************************************/
/**
- * LLEventMailDrop is a specialization of LLEventStream. Events are posted normally,
- * however if no listeners return that they have handled the event it is placed in
- * a queue. Subsequent attaching listeners will receive stored events from the queue
- * until a listener indicates that the event has been handled. In order to receive
- * multiple events from a mail drop the listener must disconnect and reconnect.
+ * LLEventMailDrop is a specialization of LLEventStream. Events are posted
+ * normally, however if no listener returns that it has handled the event
+ * (returns true), it is placed in a queue. Subsequent attaching listeners
+ * will receive stored events from the queue until some listener indicates
+ * that the event has been handled.
+ *
+ * LLEventMailDrop completely decouples the timing of post() calls from
+ * listen() calls: every event posted to an LLEventMailDrop is eventually seen
+ * by all listeners, until some listener consumes it. The caveat is that each
+ * event *must* eventually reach a listener that will consume it, else the
+ * queue will grow to arbitrary length.
*
* @NOTE: When using an LLEventMailDrop (or LLEventQueue) with a LLEventTimeout or
- * LLEventFilter attaching the filter downstream using Timeout's constructor will
- * cause the MailDrop to discharge any of it's stored events. The timeout should
+ * LLEventFilter attaching the filter downstream, using Timeout's constructor will
+ * cause the MailDrop to discharge any of its stored events. The timeout should
* instead be connected upstream using its listen() method.
* See llcoro::suspendUntilEventOnWithTimeout() for an example.
*/
diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h
index f1f4226c40..7f5b9b4ac2 100644
--- a/indra/llcommon/llinitparam.h
+++ b/indra/llcommon/llinitparam.h
@@ -2115,6 +2115,9 @@ namespace LLInitParam
typedef typename super_t::iterator iterator;
typedef typename super_t::const_iterator const_iterator;
+ using super_t::operator();
+ using super_t::operator const container_t&;
+
explicit Multiple(const char* name = "")
: super_t(DERIVED_BLOCK::getBlockDescriptor(), name, container_t(), &validate, RANGE::minCount, RANGE::maxCount)
{}
diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp
index c87d2a3e58..cf8f8cc6a5 100644
--- a/indra/llcommon/llleap.cpp
+++ b/indra/llcommon/llleap.cpp
@@ -47,9 +47,9 @@ class LLLeapImpl: public LLLeap
LOG_CLASS(LLLeap);
public:
// Called only by LLLeap::create()
- LLLeapImpl(const std::string& desc, const std::vector& plugin):
+ LLLeapImpl(const LLProcess::Params& cparams):
// We might reassign mDesc in the constructor body if it's empty here.
- mDesc(desc),
+ mDesc(cparams.desc),
// We expect multiple LLLeapImpl instances. Definitely tweak
// mDonePump's name for uniqueness.
mDonePump("LLLeap", true),
@@ -67,17 +67,17 @@ public:
// this class or method name.
mListener(new LLLeapListener(boost::bind(&LLLeapImpl::connect, this, _1, _2)))
{
- // Rule out empty vector
- if (plugin.empty())
+ // Rule out unpopulated Params block
+ if (! cparams.executable.isProvided())
{
LLTHROW(Error("no plugin command"));
}
// Don't leave desc empty either, but in this case, if we weren't
// given one, we'll fake one.
- if (desc.empty())
+ if (mDesc.empty())
{
- mDesc = LLProcess::basename(plugin[0]);
+ mDesc = LLProcess::basename(cparams.executable);
// how about a toLower() variant that returns the transformed string?!
std::string desclower(mDesc);
LLStringUtil::toLower(desclower);
@@ -87,9 +87,9 @@ public:
// notice Python specially: we provide Python LLSD serialization
// support, so there's a pretty good reason to implement plugins
// in that language.
- if (plugin.size() >= 2 && (desclower == "python" || desclower == "python.exe"))
+ if (cparams.args.size() && (desclower == "python" || desclower == "python.exe"))
{
- mDesc = LLProcess::basename(plugin[1]);
+ mDesc = LLProcess::basename(cparams.args()[0]);
}
}
@@ -97,14 +97,10 @@ public:
mDonePump.listen("LLLeap", boost::bind(&LLLeapImpl::bad_launch, this, _1));
// Okay, launch child.
- LLProcess::Params params;
+ // Get a modifiable copy of params block to set files and postend.
+ LLProcess::Params params(cparams);
+ // copy our deduced mDesc back into the params block
params.desc = mDesc;
- std::vector::const_iterator pi(plugin.begin()), pend(plugin.end());
- params.executable = *pi++;
- for ( ; pi != pend; ++pi)
- {
- params.args.add(*pi);
- }
params.files.add(LLProcess::FileParam("pipe")); // stdin
params.files.add(LLProcess::FileParam("pipe")); // stdout
params.files.add(LLProcess::FileParam("pipe")); // stderr
@@ -429,17 +425,17 @@ private:
boost::scoped_ptr mListener;
};
-// This must follow the declaration of LLLeapImpl, so it may as well be last.
-LLLeap* LLLeap::create(const std::string& desc, const std::vector& plugin, bool exc)
+// These must follow the declaration of LLLeapImpl, so they may as well be last.
+LLLeap* LLLeap::create(const LLProcess::Params& params, bool exc)
{
// If caller is willing to permit exceptions, just instantiate.
if (exc)
- return new LLLeapImpl(desc, plugin);
+ return new LLLeapImpl(params);
// Caller insists on suppressing LLLeap::Error. Very well, catch it.
try
{
- return new LLLeapImpl(desc, plugin);
+ return new LLLeapImpl(params);
}
catch (const LLLeap::Error&)
{
@@ -447,6 +443,23 @@ LLLeap* LLLeap::create(const std::string& desc, const std::vector&
}
}
+LLLeap* LLLeap::create(const std::string& desc, const std::vector& plugin, bool exc)
+{
+ LLProcess::Params params;
+ params.desc = desc;
+ std::vector::const_iterator pi(plugin.begin()), pend(plugin.end());
+ // could validate here, but let's rely on LLLeapImpl's constructor
+ if (pi != pend)
+ {
+ params.executable = *pi++;
+ }
+ for ( ; pi != pend; ++pi)
+ {
+ params.args.add(*pi);
+ }
+ return create(params, exc);
+}
+
LLLeap* LLLeap::create(const std::string& desc, const std::string& plugin, bool exc)
{
// Use LLStringUtil::getTokens() to parse the command line
diff --git a/indra/llcommon/llleap.h b/indra/llcommon/llleap.h
index 8aac8a64c5..7cecdf2f8f 100644
--- a/indra/llcommon/llleap.h
+++ b/indra/llcommon/llleap.h
@@ -14,6 +14,7 @@
#include "llinstancetracker.h"
#include "llexception.h"
+#include "llprocess.h"
#include
#include
@@ -61,6 +62,19 @@ public:
static LLLeap* create(const std::string& desc, const std::string& plugin,
bool exc=true);
+ /**
+ * Pass an LLProcess::Params instance to specify desc, executable, args et al.
+ *
+ * Note that files and postend are set implicitly; any values you set in
+ * those fields will be disregarded.
+ *
+ * Pass exc=false to suppress LLLeap::Error exception. Obviously in that
+ * case the caller cannot discover the nature of the error, merely that an
+ * error of some kind occurred (because create() returned NULL). Either
+ * way, the error is logged.
+ */
+ static LLLeap* create(const LLProcess::Params& params, bool exc=true);
+
/**
* Exception thrown for invalid create() arguments, e.g. no plugin
* program. This is more resiliant than an LL_ERRS failure, because the
diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp
index ce0dbce075..8e1f4c14ac 100644
--- a/indra/llcommon/tests/llerror_test.cpp
+++ b/indra/llcommon/tests/llerror_test.cpp
@@ -78,8 +78,12 @@ namespace tut
class TestRecorder : public LLError::Recorder
{
public:
- TestRecorder() { mWantsTime = false; mWantsTags = true; }
- virtual ~TestRecorder() { }
+ TestRecorder()
+ {
+ showTime(false);
+ }
+ virtual ~TestRecorder()
+ {}
virtual void recordMessage(LLError::ELevel level,
const std::string& message)
@@ -90,8 +94,6 @@ namespace tut
int countMessages() { return (int) mMessages.size(); }
void clearMessages() { mMessages.clear(); }
- void setWantsTime(bool t) { mWantsTime = t; }
-
std::string message(int n)
{
std::ostringstream test_name;
@@ -139,9 +141,14 @@ namespace tut
}
void setWantsTime(bool t)
- {
- boost::dynamic_pointer_cast(mRecorder)->setWantsTime(t);
- }
+ {
+ boost::dynamic_pointer_cast(mRecorder)->showTime(t);
+ }
+
+ void setWantsMultiline(bool t)
+ {
+ boost::dynamic_pointer_cast(mRecorder)->showMultiline(t);
+ }
std::string message(int n)
{
@@ -378,27 +385,6 @@ namespace
}
}
-namespace tut
-{
- template<> template<>
- void ErrorTestObject::test<5>()
- // file and line information in log messages
- {
- std::string location = writeReturningLocation();
- // expecting default to not print location information
-
- LLError::setPrintLocation(true);
- writeReturningLocation();
-
- LLError::setPrintLocation(false);
- writeReturningLocation();
-
- ensure_message_does_not_contain(0, location);
- ensure_message_field_equals(1, LOCATION_FIELD, location);
- ensure_message_does_not_contain(2, location);
- }
-}
-
/* The following helper functions and class members all log a simple message
from some particular function scope. Each function takes a bool argument
that indicates if it should log its own name or not (in the manner that
@@ -512,6 +498,39 @@ namespace
}
}
+namespace
+{
+ void writeMsgNeedsEscaping()
+ {
+ LL_DEBUGS("WriteTag") << "backslash\\" << LL_ENDL;
+ LL_INFOS("WriteTag") << "newline\nafternewline" << LL_ENDL;
+ LL_WARNS("WriteTag") << "return\rafterreturn" << LL_ENDL;
+
+ LL_DEBUGS("WriteTag") << "backslash\\backslash\\" << LL_ENDL;
+ LL_INFOS("WriteTag") << "backslash\\newline\nanothernewline\nafternewline" << LL_ENDL;
+ LL_WARNS("WriteTag") << "backslash\\returnnewline\r\n\\afterbackslash" << LL_ENDL;
+ }
+};
+
+namespace tut
+{
+ template<> template<>
+ void ErrorTestObject::test<5>()
+ // backslash, return, and newline are not escaped with backslashes
+ {
+ LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
+ setWantsMultiline(true);
+ writeMsgNeedsEscaping(); // but should not be now
+ ensure_message_field_equals(0, MSG_FIELD, "backslash\\");
+ ensure_message_field_equals(1, MSG_FIELD, "newline\nafternewline");
+ ensure_message_field_equals(2, MSG_FIELD, "return\rafterreturn");
+ ensure_message_field_equals(3, MSG_FIELD, "backslash\\backslash\\");
+ ensure_message_field_equals(4, MSG_FIELD, "backslash\\newline\nanothernewline\nafternewline");
+ ensure_message_field_equals(5, MSG_FIELD, "backslash\\returnnewline\r\n\\afterbackslash");
+ ensure_message_count(6);
+ }
+}
+
namespace tut
{
template<> template<>
@@ -583,7 +602,6 @@ namespace tut
// special handling of LL_ERRS() calls
void ErrorTestObject::test<8>()
{
- LLError::setPrintLocation(false);
std::string location = errorReturningLocation();
ensure_message_field_equals(0, LOCATION_FIELD, location);
@@ -630,15 +648,15 @@ namespace tut
// output order
void ErrorTestObject::test<10>()
{
- LLError::setPrintLocation(true);
LLError::setTimeFunction(roswell);
setWantsTime(true);
+
std::string location,
function;
writeReturningLocationAndFunction(location, function);
ensure_equals("order is time level tags location function message",
- message(0),
+ message(0),
roswell() + " INFO " + "# " /* no tag */ + location + " " + function + " : " + "apple");
}
@@ -658,7 +676,7 @@ namespace tut
LLError::setTimeFunction(roswell);
LLError::RecorderPtr anotherRecorder(new TestRecorder());
- boost::dynamic_pointer_cast(anotherRecorder)->setWantsTime(true);
+ boost::dynamic_pointer_cast(anotherRecorder)->showTime(true);
LLError::addRecorder(anotherRecorder);
LL_INFOS() << "baz" << LL_ENDL;
@@ -835,20 +853,6 @@ namespace tut
}
}
-namespace
-{
- void writeMsgNeedsEscaping()
- {
- LL_DEBUGS("WriteTag") << "backslash\\" << LL_ENDL;
- LL_INFOS("WriteTag") << "newline\nafternewline" << LL_ENDL;
- LL_WARNS("WriteTag") << "return\rafterreturn" << LL_ENDL;
-
- LL_DEBUGS("WriteTag") << "backslash\\backslash\\" << LL_ENDL;
- LL_INFOS("WriteTag") << "backslash\\newline\nanothernewline\nafternewline" << LL_ENDL;
- LL_WARNS("WriteTag") << "backslash\\returnnewline\r\n\\afterbackslash" << LL_ENDL;
- }
-};
-
namespace tut
{
template<> template<>
diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp
index b6a32a0e78..be26416cbb 100644
--- a/indra/llui/llnotificationslistener.cpp
+++ b/indra/llui/llnotificationslistener.cpp
@@ -90,9 +90,12 @@ void LLNotificationsListener::requestAdd(const LLSD& event_data) const
{
if(event_data.has("reply"))
{
+ LLSD payload(event_data["payload"]);
+ // copy reqid, if provided, to link response with request
+ payload["reqid"] = event_data["reqid"];
mNotifications.add(event_data["name"],
event_data["substitutions"],
- event_data["payload"],
+ payload,
boost::bind(&LLNotificationsListener::NotificationResponder,
this,
event_data["reply"].asString(),
@@ -112,10 +115,12 @@ void LLNotificationsListener::NotificationResponder(const std::string& reply_pum
const LLSD& notification,
const LLSD& response) const
{
- LLSD reponse_event;
- reponse_event["notification"] = notification;
- reponse_event["response"] = response;
- LLEventPumps::getInstance()->obtain(reply_pump).post(reponse_event);
+ LLSD response_event;
+ response_event["notification"] = notification;
+ response_event["response"] = response;
+ // surface reqid at top level of response for request/response protocol
+ response_event["reqid"] = notification["payload"]["reqid"];
+ LLEventPumps::getInstance()->obtain(reply_pump).post(response_event);
}
void LLNotificationsListener::listChannels(const LLSD& params) const
diff --git a/indra/llvfs/lldir_mac.cpp b/indra/llvfs/lldir_mac.cpp
index fc27e11e35..0b1fc3b6a5 100644
--- a/indra/llvfs/lldir_mac.cpp
+++ b/indra/llvfs/lldir_mac.cpp
@@ -187,9 +187,9 @@ void LLDir_Mac::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");
}
- mCAFile = getExpandedFilename(LL_PATH_EXECUTABLE, "../Resources", "ca-bundle.crt");
+ mCAFile = add(mAppRODataDir, "ca-bundle.crt");
}
// Used by LGG's selection beams
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index b09551ddc1..74ccbb280b 100644
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -1446,12 +1446,10 @@ static CursorRef gCursors[UI_CURSOR_COUNT];
static void initPixmapCursor(int cursorid, int hotspotX, int hotspotY)
{
// cursors are in /Contents/Resources/cursors_mac/UI_CURSOR_FOO.tif
- std::string fullpath = gDirUtilp->getAppRODataDir();
- fullpath += gDirUtilp->getDirDelimiter();
- fullpath += "cursors_mac";
- fullpath += gDirUtilp->getDirDelimiter();
- fullpath += cursorIDToName(cursorid);
- fullpath += ".tif";
+ std::string fullpath = gDirUtilp->add(
+ gDirUtilp->getAppRODataDir(),
+ "cursors_mac",
+ cursorIDToName(cursorid) + std::string(".tif"));
gCursors[cursorid] = createImageCursor(fullpath.c_str(), hotspotX, hotspotY);
}
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 5db837f4b2..6cfe73e57f 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -24,7 +24,6 @@ include(GLOD)
include(Hunspell)
include(JsonCpp)
include(LLAppearance)
-include(LLBase)
include(LLAudio)
include(LLCA)
include(LLCharacter)
@@ -51,7 +50,6 @@ include(OPENAL)
include(OpenGL)
include(OpenSSL)
include(PNG)
-include(Requests)
include(TemplateCheck)
include(UI)
include(UnixInstall)
@@ -2536,8 +2534,7 @@ if (DARWIN)
# magically known to CMake -- it's that these names are referenced in the
# Info-SecondLife.plist file in the configure_file() directive below.
set(product "${VIEWER_CHANNEL}")
- # this is the setting for the Python wrapper, see SL-322 and WRAPPER line in Info-SecondLife.plist
- set(MACOSX_WRAPPER_EXECUTABLE_NAME "SL_Launcher")
+ set(MACOSX_EXECUTABLE_NAME "${VIEWER_CHANNEL}")
set(MACOSX_BUNDLE_INFO_STRING "${VIEWER_CHANNEL}")
set(MACOSX_BUNDLE_ICON_FILE "firestorm_icon.icns")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.phoenixviewer.firestorm.viewer-${ND_VIEWER_FLAVOR}")
diff --git a/indra/newview/Info-SecondLife.plist b/indra/newview/Info-SecondLife.plist
index 8aabd6818b..9482f07524 100644
--- a/indra/newview/Info-SecondLife.plist
+++ b/indra/newview/Info-SecondLife.plist
@@ -5,7 +5,7 @@
CFBundleDevelopmentRegion
English
CFBundleExecutable
- ${MACOSX_WRAPPER_EXECUTABLE_NAME}
+ ${MACOSX_EXECUTABLE_NAME}
CFBundleGetInfoString
${MACOSX_BUNDLE_INFO_STRING}
CFBundleIconFile
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index e19701e9bb..7d32bf9838 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -6366,6 +6366,17 @@
Value
96.0
+ ForceAddressSize
+
+ Comment
+ Force Windows update to 32-bit or 64-bit viewer.
+ Persist
+ 1
+ Type
+ U32
+ Value
+ 0
+
ForceAssetFail
Comment
@@ -17210,19 +17221,6 @@ Change of this parameter will affect the layout of buttons in notification toast
Value
1.0
- VerboseLogs
-
- Comment
- Display source file and line number for each log item for debugging purposes
- Persist
- 1
- Type
- Boolean
- Value
- 0
- Backup
- 0
-
VertexShaderEnable
Comment
@@ -21080,7 +21078,7 @@ Change of this parameter will affect the layout of buttons in notification toast
if true, disables running the GPU benchmark at startup
(default to class 1)
Persist
- 0
+ 1
Type
Boolean
Value
diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi
index bc66c9053d..050bd3bd13 100644
--- a/indra/newview/installers/windows/installer_template.nsi
+++ b/indra/newview/installers/windows/installer_template.nsi
@@ -341,7 +341,7 @@ SetOutPath "$INSTDIR"
CreateShortCut "$SMPROGRAMS\$INSTSHORTCUT\$INSTSHORTCUT.lnk" \
"$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM"
# Remove VMP
- #"$INSTDIR\$INSTEXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
+ #"$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
WriteINIStr "$SMPROGRAMS\$INSTSHORTCUT\SL Create Account.url" \
@@ -365,11 +365,11 @@ SetOutPath "$INSTDIR"
CreateShortCut "$DESKTOP\$INSTSHORTCUT.lnk" \
"$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM"
# Remove VMP
- #"$INSTDIR\$INSTEXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
+ #"$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
CreateShortCut "$INSTDIR\$INSTSHORTCUT.lnk" \
"$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM"
# Remove VMP
- #"$INSTDIR\$INSTEXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
+ #"$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
CreateShortCut "$INSTDIR\Uninstall $INSTSHORTCUT.lnk" \
'"$INSTDIR\uninst.exe"' ''
@@ -377,7 +377,6 @@ CreateShortCut "$INSTDIR\Uninstall $INSTSHORTCUT.lnk" \
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\The Phoenix Firestorm Project\$INSTPROG" "" "$INSTDIR"
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\The Phoenix Firestorm Project\$INSTPROG" "Version" "${VERSION_LONG}"
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\The Phoenix Firestorm Project\$INSTPROG" "Shortcut" "$INSTSHORTCUT"
-#WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\The Phoenix Firestorm Project\$INSTPROG" "Exe" "$INSTEXE"
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\The Phoenix Firestorm Project\$INSTPROG" "Exe" "$VIEWER_EXE"
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "Publisher" "The Phoenix Firestorm Project, Inc."
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "URLInfoAbout" "http://www.firestormviewer.org"
@@ -395,11 +394,9 @@ ${Else}
${EndIf}
# from FS:Ansariel
-#WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "DisplayIcon" '"$INSTDIR\$INSTEXE"'
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "DisplayIcon" '"$INSTDIR\$VIEWER_EXE"'
# BUG-2707 Disable SEHOP for installed viewer.
-#WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\$INSTEXE" "DisableExceptionChainValidation" 1
WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\$VIEWER_EXE" "DisableExceptionChainValidation" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "NoRepair" 1
@@ -419,11 +416,8 @@ WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\DefaultIcon" "" '"$INSTDIR\$
# URL param must be last item passed to viewer, it ignores subsequent params to avoid parameter injection attacks.
WriteRegExpandStr HKEY_CLASSES_ROOT "x-grid-location-info\shell\open\command" "" '"$INSTDIR\$VIEWER_EXE" -url "%1"'
-# Only allow Launcher to be the icon
-# Remove VMP
-#WriteRegStr HKEY_CLASSES_ROOT "Applications\$INSTEXE" "IsHostApp" ""
-#WriteRegStr HKEY_CLASSES_ROOT "Applications\${VIEWER_EXE}" "NoStartPage" ""
-# Remove VMP
+WriteRegStr HKEY_CLASSES_ROOT "Applications\$VIEWER_EXE" "IsHostApp" ""
+##WriteRegStr HKEY_CLASSES_ROOT "Applications\${VIEWER_EXE}" "NoStartPage" ""
# Register hop:// protocol registry info
WriteRegStr HKEY_CLASSES_ROOT "hop" "(default)" "URL:Second Life"
@@ -453,7 +447,6 @@ Section Uninstall
# Start with some default values.
StrCpy $INSTPROG "${INSTNAME}"
StrCpy $INSTEXE "${INSTEXE}"
-StrCpy $VIEWER_EXE "${VIEWER_EXE}" # Disable VMP
StrCpy $INSTSHORTCUT "${SHORTCUT}"
# Make sure the user can install/uninstall
@@ -469,13 +462,9 @@ Call un.CloseSecondLife
DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\The Phoenix Firestorm Project\$INSTPROG"
DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG"
# BUG-2707 Remove entry that disabled SEHOP
-# Disable VMP
-#DeleteRegKey HKEY_LOCAL_MACHINE "Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\$INSTEXE"
-DeleteRegKey HKEY_LOCAL_MACHINE "Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\$VIEWER_EXE"
-# Remove VMP
-#DeleteRegKey HKEY_CLASSES_ROOT "Applications\$INSTEXE"
-#DeleteRegKey HKEY_CLASSES_ROOT "Applications\${VIEWER_EXE}"
-# Remove VMP
+DeleteRegKey HKEY_LOCAL_MACHINE "Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\${VIEWER_EXE}"
+##DeleteRegKey HKEY_CLASSES_ROOT "Applications\$INSTEXE"
+DeleteRegKey HKEY_CLASSES_ROOT "Applications\${VIEWER_EXE}"
# Clean up shortcuts
Delete "$SMPROGRAMS\$INSTSHORTCUT\*.*"
@@ -754,7 +743,7 @@ FunctionEnd
;; After install completes, launch app
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Function .onInstSuccess
-Call CheckWindowsServPack # Warn if not on the latest SP before asking to launch.
+ Call CheckWindowsServPack # Warn if not on the latest SP before asking to launch.
# Disable VMP
#Push $R0
#Push $0
@@ -797,7 +786,22 @@ label_ask_launch:
IDYES label_launch IDNO label_no_launch
label_launch:
- # Assumes SetOutPath $INSTDIR
+ # Assumes SetOutPath $INSTDIR
+ # Run INSTEXE (our updater), passing VIEWER_EXE plus the command-line
+ # arguments built into our shortcuts. This gives the updater a chance
+ # to verify that the viewer we just installed is appropriate for the
+ # running system -- or, if not, to download and install a different
+ # viewer. For instance, if a user running 32-bit Windows installs a
+ # 64-bit viewer, it cannot run on this system. But since the updater
+ # is a 32-bit executable even in the 64-bit viewer package, the
+ # updater can detect the problem and adapt accordingly.
+ # Once everything is in order, the updater will run the specified
+ # viewer with the specified params.
+ # Quote the updater executable and the viewer executable because each
+ # must be a distinct command-line token, but DO NOT quote the language
+ # string because it must decompose into separate command-line tokens.
+ # No updater, thanks!
+ # Exec '"$INSTDIR\$INSTEXE" precheck "$INSTDIR\$VIEWER_EXE" $SHORTCUT_LANG_PARAM'
Exec '"$WINDIR\explorer.exe" "$INSTDIR\$INSTSHORTCUT.lnk"'
label_no_launch:
Pop $R0
diff --git a/indra/newview/llappdelegate-objc.mm b/indra/newview/llappdelegate-objc.mm
index 72cc4f3fc3..bac60eb084 100644
--- a/indra/newview/llappdelegate-objc.mm
+++ b/indra/newview/llappdelegate-objc.mm
@@ -26,6 +26,8 @@
#import "llappdelegate-objc.h"
#if defined(LL_BUGSPLAT)
+#include
+#include
@import BugsplatMac;
// derived from BugsplatMac's BugsplatTester/AppDelegate.m
@interface LLAppDelegate ()
@@ -288,25 +290,59 @@
infos("bugsplatStartupManagerWillSendCrashReport");
}
-- (BugsplatAttachment *)attachmentForBugsplatStartupManager:(BugsplatStartupManager *)bugsplatStartupManager {
- std::string logfile = CrashMetadata_instance().logFilePathname;
- // Still to do:
- // userSettingsPathname
- // staticDebugPathname
- // but the BugsplatMac version 1.0.5 BugsplatStartupManagerDelegate API
- // doesn't yet provide a way to attach more than one file.
- NSString *ns_logfile = [NSString stringWithCString:logfile.c_str()
- encoding:NSUTF8StringEncoding];
- NSData *data = [NSData dataWithContentsOfFile:ns_logfile];
+struct AttachmentInfo
+{
+ AttachmentInfo(const std::string& path, const std::string& type):
+ pathname(path),
+ basename(boost::filesystem::path(path).filename().string()),
+ mimetype(type)
+ {}
- // Apologies for the hard-coded log-file basename, but I do not know the
- // incantation for "$(basename "$logfile")" in this language.
- BugsplatAttachment *attachment =
- [[BugsplatAttachment alloc] initWithFilename:@"SecondLife.log"
- attachmentData:data
- contentType:@"text/plain"];
- infos("attachmentForBugsplatStartupManager attaching " + logfile);
- return attachment;
+ std::string pathname, basename, mimetype;
+};
+
+- (NSArray *)attachmentsForBugsplatStartupManager:(BugsplatStartupManager *)bugsplatStartupManager
+{
+ const CrashMetadata& metadata(CrashMetadata_instance());
+
+ // Since we must do very similar processing for each of several file
+ // pathnames, start by collecting them into a vector so we can iterate
+ // instead of spelling out the logic for each.
+ std::vector info{
+ AttachmentInfo(metadata.logFilePathname, "text/plain"),
+ AttachmentInfo(metadata.userSettingsPathname, "text/xml"),
+ AttachmentInfo(metadata.staticDebugPathname, "text/xml")
+ };
+
+ // We "happen to know" that info[0].basename is "SecondLife.old" -- due to
+ // the fact that BugsplatMac only notices a crash during the viewer run
+ // following the crash. Replace .old with .log to reduce confusion.
+ info[0].basename =
+ boost::filesystem::path(info[0].pathname).stem().string() + ".log";
+
+ NSMutableArray *attachments = [[NSMutableArray alloc] init];
+
+ // Iterate over each AttachmentInfo in info vector
+ for (const AttachmentInfo& attach : info)
+ {
+ NSString *nspathname = [NSString stringWithCString:attach.pathname.c_str()
+ encoding:NSUTF8StringEncoding];
+ NSString *nsbasename = [NSString stringWithCString:attach.basename.c_str()
+ encoding:NSUTF8StringEncoding];
+ NSString *nsmimetype = [NSString stringWithCString:attach.mimetype.c_str()
+ encoding:NSUTF8StringEncoding];
+ NSData *nsdata = [NSData dataWithContentsOfFile:nspathname];
+
+ BugsplatAttachment *attachment =
+ [[BugsplatAttachment alloc] initWithFilename:nsbasename
+ attachmentData:nsdata
+ contentType:nsmimetype];
+
+ [attachments addObject:attachment];
+ infos("attachmentsForBugsplatStartupManager attaching " + attach.pathname);
+ }
+
+ return attachments;
}
- (void)bugsplatStartupManagerDidFinishSendingCrashReport:(BugsplatStartupManager *)bugsplatStartupManager
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 2da5396914..f9eb8ecfd5 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1070,11 +1070,6 @@ bool LLAppViewer::init()
mNumSessions++;
gSavedSettings.setS32("NumSessions", mNumSessions);
- if (gSavedSettings.getBOOL("VerboseLogs"))
- {
- LLError::setPrintLocation(true);
- }
-
// LLKeyboard relies on LLUI to know what some accelerator keys are called.
LLKeyboard::setStringTranslatorFunc( LLTrans::getKeyboardString );
@@ -1285,28 +1280,6 @@ bool LLAppViewer::init()
}
}
-// don't nag developers who need to run the executable directly
-#if LL_RELEASE_FOR_DOWNLOAD
- // Disable VMP
- // MAINT-8305: If we're processing a SLURL, skip the launcher check.
- //if (gSavedSettings.getString("CmdLineLoginLocation").empty())
- //{
- // const char* PARENT = getenv("PARENT");
- // if (! (PARENT && std::string(PARENT) == "SL_Launcher"))
- // {
- // // Don't directly run this executable. Please run the launcher, which
- // // will run the viewer itself.
- // // Naturally we do not consider this bulletproof. The point is to
- // // gently remind a user who *inadvertently* finds him/herself in this
- // // situation to do things the Right Way. Anyone who intentionally
- // // bypasses this mechanism needs no reminder that s/he's shooting
- // // him/herself in the foot.
- // LLNotificationsUtil::add("RunLauncher");
- // }
- //}
- //
-#endif
-
#if LL_WINDOWS
if (gGLManager.mGLVersion < LLFeatureManager::getInstance()->getExpectedGLVersion())
{
@@ -1356,6 +1329,38 @@ bool LLAppViewer::init()
gGLActive = FALSE;
+ // Disable updater
+// LLProcess::Params updater;
+// updater.desc = "updater process";
+// // Because it's the updater, it MUST persist beyond the lifespan of the
+// // viewer itself.
+// updater.autokill = false;
+//#if LL_WINDOWS
+// updater.executable = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "updater.exe");
+//#elif LL_DARWIN
+// // explicitly run the system Python interpreter on updater.py
+// updater.executable = "python";
+// updater.args.add(gDirUtilp->add(gDirUtilp->getAppRODataDir(), "updater", "updater.py"));
+//#else
+// updater.executable = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "updater");
+//#endif
+// // add LEAP mode command-line argument to whichever of these we selected
+// updater.args.add("leap");
+// // UpdaterServiceSettings
+// updater.args.add(stringize(gSavedSettings.getU32("UpdaterServiceSetting")));
+// // channel
+// updater.args.add(LLVersionInfo::getChannel());
+// // testok
+// updater.args.add(stringize(gSavedSettings.getBOOL("UpdaterWillingToTest")));
+// // UpdaterServiceURL
+// updater.args.add(gSavedSettings.getString("UpdaterServiceURL"));
+// // ForceAddressSize
+// updater.args.add(stringize(gSavedSettings.getU32("ForceAddressSize")));
+//
+// // Run the updater. An exception from launching the updater should bother us.
+// LLLeap::create(updater, true);
+ //
+
// Iterate over --leap command-line options. But this is a bit tricky: if
// there's only one, it won't be an array at all.
LLSD LeapCommand(gSavedSettings.getLLSD("LeapCommand"));
@@ -1991,7 +1996,7 @@ bool LLAppViewer::cleanup()
release_start_screen(); // just in case
- LLError::logToFixedBuffer(NULL);
+ LLError::logToFixedBuffer(NULL); // stop the fixed buffer recorder
LL_INFOS() << "Cleaning Up" << LL_ENDL;
@@ -4706,14 +4711,6 @@ void LLAppViewer::requestQuit()
gAgentAvatarp->updateAvatarRezMetrics(true); // force a last packet to be sent.
}
- // Try to send last batch of avatar rez metrics.
- // LL merge error
- //if (!gDisconnected && isAgentAvatarValid())
- //{
- // gAgentAvatarp->updateAvatarRezMetrics(true); // force a last packet to be sent.
- //}
- //
-
LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
effectp->setPositionGlobal(gAgent.getPositionGlobal());
effectp->setColor(LLColor4U(gAgent.getEffectColor()));
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 947666a89b..0b35c80a54 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -268,14 +268,12 @@ bool LLLoginInstance::handleLoginEvent(const LLSD& event)
mLoginState = event["state"].asString();
mResponseData = event["data"];
-
+
if(event.has("transfer_rate"))
{
mTransferRate = event["transfer_rate"].asReal();
}
-
-
// Call the method registered in constructor, if any, for more specific
// handling
mDispatcher.try_call(event);
@@ -291,6 +289,14 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
// Login has failed.
// Figure out why and respond...
LLSD response = event["data"];
+ LLSD updater = response["updater"];
+
+ // Always provide a response to the updater, if in fact the updater
+ // contacted us, if in fact the ping contains a 'reply' key. Most code
+ // paths tell it not to proceed with updating.
+ ResponsePtr resp(std::make_shared
+ (LLSDMap("update", false), updater));
+
std::string reason_response = response["reason"].asString();
std::string message_response = response["message"].asString();
LL_DEBUGS("LLLogin") << "reason " << reason_response
@@ -342,17 +348,44 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
}
else if(reason_response == "update")
{
- // This shouldn't happen - the viewer manager should have forced an update;
- // possibly the user ran the viewer directly and bypassed the update check
+ // This can happen if the user clicked Login quickly, before we heard
+ // back from the Viewer Version Manager, but login failed because
+ // login.cgi is insisting on a required update. We were called with an
+ // event that bundles both the login.cgi 'response' and the
+ // synchronization event from the 'updater'.
std::string required_version = response["message_args"]["VERSION"];
LL_WARNS("LLLogin") << "Login failed because an update to version " << required_version << " is required." << LL_ENDL;
if (gViewerWindow)
gViewerWindow->setShowProgress(FALSE, FALSE);
- LLSD data(LLSD::emptyMap());
- data["VERSION"] = required_version;
- LLNotificationsUtil::add("RequiredUpdate", data, LLSD::emptyMap(), boost::bind(&LLLoginInstance::handleLoginDisallowed, this, _1, _2));
+ LLSD args(LLSDMap("VERSION", required_version));
+ if (updater.isUndefined())
+ {
+ // If the updater failed to shake hands, better advise the user to
+ // download the update him/herself.
+ LLNotificationsUtil::add(
+ "RequiredUpdate",
+ args,
+ updater,
+ boost::bind(&LLLoginInstance::handleLoginDisallowed, this, _1, _2));
+ }
+ else
+ {
+ // If we've heard from the updater that an update is required,
+ // then display the prompt that assures the user we'll take care
+ // of it. This is the one case in which we bind 'resp':
+ // instead of destroying our Response object (and thus sending a
+ // negative reply to the updater) as soon as we exit this
+ // function, bind our shared_ptr so it gets passed into
+ // syncWithUpdater. That ensures that the response is delayed
+ // until the user has responded to the notification.
+ LLNotificationsUtil::add(
+ "PauseForUpdate",
+ args,
+ updater,
+ boost::bind(&LLLoginInstance::syncWithUpdater, this, resp, _1, _2));
+ }
}
else if( reason_response == "key"
|| reason_response == "presence"
@@ -375,6 +408,19 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
}
}
+void LLLoginInstance::syncWithUpdater(ResponsePtr resp, const LLSD& notification, const LLSD& response)
+{
+ LL_INFOS("LLLogin") << "LLLoginInstance::syncWithUpdater" << LL_ENDL;
+ // 'resp' points to an instance of LLEventAPI::Response that will be
+ // destroyed as soon as we return and the notification response functor is
+ // unregistered. Modify it so that it tells the updater to go ahead and
+ // perform the update. Naturally, if we allowed the user a choice as to
+ // whether to proceed or not, this assignment would reflect the user's
+ // selection.
+ (*resp)["update"] = true;
+ attemptComplete();
+}
+
void LLLoginInstance::handleLoginDisallowed(const LLSD& notification, const LLSD& response)
{
attemptComplete();
@@ -434,7 +480,6 @@ bool LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key)
return true;
}
-
std::string construct_start_string()
{
std::string start;
diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h
index c5f2f6a60d..c486773465 100644
--- a/indra/newview/lllogininstance.h
+++ b/indra/newview/lllogininstance.h
@@ -28,8 +28,10 @@
#define LL_LLLOGININSTANCE_H
#include "lleventdispatcher.h"
+#include "lleventapi.h"
#include
#include
+#include // std::shared_ptr
#include "llsecapi.h"
class LLLogin;
class LLEventStream;
@@ -71,6 +73,7 @@ public:
LLNotificationsInterface& getNotificationsInterface() const { return *mNotifications; }
private:
+ typedef std::shared_ptr ResponsePtr;
void constructAuthParams(LLPointer user_credentials);
void updateApp(bool mandatory, const std::string& message);
bool updateDialogCallback(const LLSD& notification, const LLSD& response);
@@ -80,7 +83,8 @@ private:
void handleLoginSuccess(const LLSD& event);
void handleDisconnect(const LLSD& event);
void handleIndeterminate(const LLSD& event);
- void handleLoginDisallowed(const LLSD& notification, const LLSD& response);
+ void handleLoginDisallowed(const LLSD& notification, const LLSD& response);
+ void syncWithUpdater(ResponsePtr resp, const LLSD& notification, const LLSD& response);
bool handleTOSResponse(bool v, const std::string& key);
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index cd3adf262d..0be253a820 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -758,8 +758,7 @@ bool idle_startup()
if (!found_template)
{
message_template_path =
- gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE,
- "../Resources/app_settings",
+ gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,
"message_template.msg");
found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */
}
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 9b82eeda11..726e1b6a6b 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -332,6 +332,9 @@ private:
RecordToChatConsole::RecordToChatConsole():
mRecorder(new RecordToChatConsoleRecorder())
{
+ mRecorder->showTags(false);
+ mRecorder->showLocation(false);
+ mRecorder->showMultiline(true);
}
////////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index 6ea661d6c6..ebf7802d2d 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -824,41 +824,41 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon()
{
#ifndef VIVOXDAEMON_REMOTEHOST
// Launch the voice daemon
- std::string exe_path = gDirUtilp->getExecutableDir();
- exe_path += gDirUtilp->getDirDelimiter();
+ std::string exe_path = gDirUtilp->getAppRODataDir();
#if LL_WINDOWS
// FIRE-22709: Local voice not working in OpenSim
#ifdef OPENSIM
if (!LLGridManager::instance().isInSecondLife())
{
- exe_path += "voice_os" + gDirUtilp->getDirDelimiter();
+ gDirUtilp->append(exe_path, "voice_os" + gDirUtilp->getDirDelimiter() + "SLVoice.exe");
}
+ else
#endif
//
- exe_path += "SLVoice.exe";
+ gDirUtilp->append(exe_path, "SLVoice.exe");
#elif LL_DARWIN
// FIRE-22709: Local voice not working in OpenSim
- //exe_path += "../Resources/SLVoice";
+ //gDirUtilp->append(exe_path, "SLVoice");
#ifdef OPENSIM
if (LLGridManager::instance().isInSecondLife())
{
#endif
- exe_path += "../Resources/SLVoice";
+ gDirUtilp->append(exe_path, "SLVoice");
#ifdef OPENSIM
}
else
{
- exe_path += "../Resources/voice_os/SLVoice";
+ gDirUtilp->append(exe_path, "voice_os/SLVoice");
}
#endif
//
#else
// On Linux the viewer can run SLVoice.exe through wine (https://www.winehq.org/)
- // exe_path += "SLVoice";
+ //gDirUtilp->append(exe_path, "SLVoice");
if( !viewerUsesWineForVoice() )
- exe_path += "SLVoice"; // native version
+ gDirUtilp->append(exe_path, "SLVoice"); // native version
else
- exe_path += "win32/SLVoice.exe"; // use bundled win32 version
+ gDirUtilp->append(exe_path, "win32/SLVoice"); // use bundled win32 version
//
#endif
// See if the vivox executable exists
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index e47c53b75f..1386903efa 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -3950,7 +3950,6 @@ Finished download of raw terrain file to:
name="RequiredUpdate"
type="alertmodal">
Version [VERSION] is required for login.
-This should have been updated for you but apparently was not.
Please download from https://secondlife.com/support/downloads/
confirm
+
+Version [VERSION] is required for login.
+Click OK to download and install.
+ confirm
+
+
+
+
+Version [VERSION] has been downloaded and is ready to install.
+Click OK to install.
+ confirm
+
+
+
+
+Version [VERSION] has been downloaded and is ready to install.
+Proceed?
+ confirm
+
+
+
Remove VMP
#with self.prefix(src=os.path.join(pkgdir, "VMP")):
# include the compiled launcher scripts so that it gets included in the file_list
- # self.path('SL_Launcher.exe')
+ # self.path('updater.exe')
#IUM is not normally executed directly, just imported. No exe needed.
# self.path("InstallerUserMessage.py")
@@ -572,12 +572,7 @@ class WindowsManifest(ViewerManifest):
# self.path("*.png")
# self.path("*.gif")
- #before, we only needed llbase at build time. With VMP, we need it at run time.
- #with self.prefix(src=os.path.join(pkgdir, "lib", "python", "llbase"), dst="llbase"):
- # self.path("*.py")
- # self.path("_cllsd.so")
# Remove VMP
-
# Plugin host application
self.path2basename(os.path.join(os.pardir,
'llplugin', 'slplugin', self.args['configuration']),
@@ -910,7 +905,7 @@ class WindowsManifest(ViewerManifest):
substitution_strings['is64bit'] = (1 if (self.address_size == 64) else 0)
version_vars = """
- !define INSTEXE "SL_Launcher.exe"
+ !define INSTEXE "updater.exe"
!define VERSION "%(version_short)s"
!define VERSION_LONG "%(version)s"
!define VERSION_DASHES "%(version_dashes)s"
@@ -958,7 +953,8 @@ class WindowsManifest(ViewerManifest):
# note that the enclosing setup exe is signed later, after the makensis makes it.
# Unlike the viewer binary, the VMP filenames are invariant with respect to version, os, etc.
#for exe in (
- # "SL_Launcher.exe",
+ # self.final_exe(),
+ # "updater.exe",
# ):
# self.sign(exe)
@@ -1035,425 +1031,321 @@ class DarwinManifest(ViewerManifest):
# return bool(set(["package", "unpacked"]).intersection(self.args['actions']))
# 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 = self.channel()+".app"
- # toplevel_icon = "secondlife.icns"
- # launcher_app, launcher_icon = "Second Life Launcher.app", "secondlife.icns"
- # viewer_app, viewer_icon = "Second Life Viewer.app", "secondlife.icns"
-
- # # capture the path to the directory containing toplevel_app
- # parentdir = os.path.join(self.get_dst_prefix(), os.pardir)
-
# # 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="")
+ # self.path(os.path.join(self.args['configuration'], self.channel()+".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(dst="Contents"): # everything goes in Contents
- # # top-level Info.plist is as generated by CMake
- # Info_plist = self.dst_path_of("Info.plist")
+ # with self.prefix(src="", dst="Contents"): # everything goes in Contents
+ # bugsplat_db = self.args.get('bugsplat')
+ # if bugsplat_db:
+ # # Inject BugsplatServerURL into Info.plist if provided.
+ # Info_plist = self.dst_path_of("Info.plist")
+ # Info = plistlib.readPlist(Info_plist)
+ # # https://www.bugsplat.com/docs/platforms/os-x#configuration
+ # Info["BugsplatServerURL"] = \
+ # "https://{}.bugsplat.com/".format(bugsplat_db)
+ # self.put_in_file(
+ # plistlib.writePlistToString(Info),
+ # os.path.basename(Info_plist),
+ # "Info.plist")
+
+ # # CEF framework goes inside 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)
+
+ # if self.args.get('bugsplat'):
+ # self.path2basename(relpkgdir, "BugsplatMac.framework")
- # toplevel_MacOS = self.dst_path_of("MacOS")
- # # the one file in top-level MacOS directory is the trampoline to
- # # our nested launcher_app
# with self.prefix(dst="MacOS"):
- # if not self.is_rearranging():
- # trampoline = ""
- # else:
- # with self.prefix(dst="MacOS"):
- # 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])
+ # executable = self.dst_path_of(self.channel())
+ # if self.args.get('bugsplat'):
+ # # According to Apple Technical Note TN2206:
+ # # https://developer.apple.com/library/archive/technotes/tn2206/_index.html#//apple_ref/doc/uid/DTS40007919-CH1-TNTAG207
+ # # "If an app uses @rpath or an absolute path to link to a
+ # # dynamic library outside of the app, the app will be
+ # # rejected by Gatekeeper. ... Neither the codesign nor the
+ # # spctl tool will show the error."
+ # # (Thanks, Apple. Maybe fix spctl to warn?)
+ # # The BugsplatMac framework embeds @rpath, which is
+ # # causing scary Gatekeeper popups at viewer start. Work
+ # # around this by changing the reference baked into our
+ # # viewer. The install_name_tool -change option needs the
+ # # previous value. Instead of guessing -- which might
+ # # silently be defeated by a BugSplat SDK update that
+ # # changes their baked-in @rpath -- ask for the path
+ # # stamped into the framework.
+ # # Let exception, if any, propagate -- if this doesn't
+ # # work, we need the build to noisily fail!
+ # oldpath = subprocess.check_output(
+ # ['objdump', '-macho', '-dylib-id', '-non-verbose',
+ # os.path.join(relpkgdir, "BugsplatMac.framework", "BugsplatMac")]
+ # ).splitlines()[-1] # take the last line of output
+ # self.run_command(
+ # ['install_name_tool', '-change', oldpath,
+ # '@executable_path/../Frameworks/BugsplatMac.framework/BugsplatMac',
+ # executable])
- # # 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"))
+ # # 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', executable])
# with self.prefix(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()) :
- # self.path(toplevel_icon)
+ # # defer cross-platform file copies until we're in the
+ # # nested Resources directory
+ # super(DarwinManifest, self).construct()
- # # ------------------- 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")
+ # # need .icns file referenced by Info.plist
+ # with self.prefix(src=self.icon_path(), dst="") :
+ # self.path("secondlife.icns")
- # # 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")):
- # 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")):
- # # llbase provides our llrest service layer and llsd decoding
- # with self.prefix(src="llbase", dst="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)
+ # # Copy in the updater script and helper modules
+ # self.path(src=os.path.join(pkgdir, 'VMP'), dst="updater")
- # # launcher_app/Contents/Resources
- # with self.prefix(dst="Resources"):
- # with self.prefix(src=self.icon_path()) :
- # self.path(launcher_icon)
- # with self.prefix(dst="vmp_icons"):
- # self.path("secondlife.ico")
- # #VMP Tkinter icons
- # with self.prefix(src_dst="vmp_icons"):
- # self.path("*.png")
- # self.path("*.gif")
+ # with self.prefix(src="", dst=os.path.join("updater", "icons")):
+ # self.path2basename(self.icon_path(), "secondlife.ico")
+ # with self.prefix(src="vmp_icons", dst=""):
+ # self.path("*.png")
+ # self.path("*.gif")
- # # -------------------- nested viewer_app ---------------------
- # with self.prefix(dst=os.path.join(viewer_app, "Contents")):
- # defer Info.plist until after MacOS
- # 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 = self.dst_path_of(f)
- # fromrel = self.relpath(fromwhere, relbase)
- # torel = self.relpath(towhere, relbase)
- # if not self.is_rearranging():
- # print "Not yet moving {} => {}".format(fromrel, torel)
- # else:
- # print "Moving {} => {}".format(fromrel, torel)
- # # now do it, only without relativizing paths
- # os.rename(fromwhere, towhere)
+ # with self.prefix(src=relpkgdir, dst=""):
+ # self.path("libndofdev.dylib")
+ # self.path("libhunspell-1.3.0.dylib")
- # # If we haven't yet moved executables, find our viewer
- # # executable where it was linked, in toplevel_MacOS.
- # # If we have, find it here.
- # whichdir = here if self.is_rearranging() else toplevel_MacOS
- # # Pick the biggest of the executables as the real viewer.
- # # Make (basename, fullpath) pairs; for each pair,
- # # expand to (size, basename, fullpath) triples; sort
- # # by size; pick the last triple; take the basename and
- # # fullpath from that.
- # # _, exename, exepath = \
- # # sorted((os.path.getsize(path), name, path)
- # # for name, path in
- # # ((name, os.path.join(whichdir, name))
- # # for name in os.listdir(whichdir)))[-1]
+ # with self.prefix("cursors_mac"):
+ # self.path("*.tif")
- # if self.is_rearranging():
- # # 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.
- # self.run_command(['strip', '-S', exepath])
+ # self.path("licenses-mac.txt", dst="licenses.txt")
+ # self.path("featuretable_mac.txt")
+ # self.path("SecondLife.nib")
- # # 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"] = exename
- # Info["CFBundleIconFile"] = viewer_icon
- # bugsplat_db = self.args.get('bugsplat')
- # if bugsplat_db:
- # # https://www.bugsplat.com/docs/platforms/os-x#configuration
- # Info["BugsplatServerURL"] = \
- # "https://{}.bugsplat.com/".format(bugsplat_db)
- # self.put_in_file(
- # plistlib.writePlistToString(Info),
- # os.path.basename(Info_plist),
- # "Info.plist")
+ # with self.prefix(src=pkgdir,dst=""):
+ # self.path("ca-bundle.crt")
- # with self.prefix(dst="Frameworks"):
- # # CEF framework goes inside viewer_app/Contents/Frameworks.
- # CEF_framework = "Chromium Embedded Framework.framework"
- # self.path2basename(relpkgdir, CEF_framework)
- # # Remember where we parked this car.
- # CEF_framework = self.dst_path_of(CEF_framework)
+ # # 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")
- # if self.args.get('bugsplat'):
- # self.path2basename(relpkgdir, "BugsplatMac.framework")
+ # 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
- # with self.prefix(dst="Resources"):
- # # defer cross-platform file copies until we're in the right
- # # nested Resources directory
- # super(DarwinManifest, self).construct()
+ # # 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)
- # with self.prefix(src=self.icon_path()) :
- # self.path(viewer_icon)
+ # 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)
- # with self.prefix(src=relpkgdir):
- # self.path("libndofdev.dylib")
- # self.path("libhunspell-1.3.0.dylib")
+ # # 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)
- # with self.prefix("cursors_mac"):
- # self.path("*.tif")
+ # # 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)
- # self.path("licenses-mac.txt", dst="licenses.txt")
- # self.path("featuretable_mac.txt")
- # self.path("SecondLife.nib")
+ # # 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"))
- # with self.prefix(src=pkgdir,dst=""):
- # self.path("ca-bundle.crt")
+ # # 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))
- # self.path("SecondLife.nib")
+ # # Dullahan helper apps go inside SLPlugin.app
+ # with self.prefix(dst=os.path.join(
+ # "SLPlugin.app", "Contents", "Frameworks")):
- # # 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")
+ # frameworkname = 'Chromium Embedded Framework'
- # 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
+ # # 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.
- # # 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)
+ # # 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.
- # 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)
+ # # 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)
- # # 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)
+ # # copy DullahanHelper.app
+ # self.path2basename(relpkgdir, 'DullahanHelper.app')
- # # 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)
+ # # 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)
- # # 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"))
+ # # 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']
- # # 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))
+ # 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')])
- # # Dullahan helper apps go inside SLPlugin.app
- # with self.prefix(dst=os.path.join(
- # "SLPlugin.app", "Contents", "Frameworks")):
+ # # SLPlugin plugins
+ # with self.prefix(dst="llplugin"):
+ # dylibexecutable = 'media_plugin_cef.dylib'
+ # self.path2basename("../media_plugins/cef/" + self.args['configuration'],
+ # dylibexecutable)
- # frameworkname = 'Chromium Embedded Framework'
+ # # 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)])
- # # 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.
+ # # copy LibVLC plugin itself
+ # self.path2basename("../media_plugins/libvlc/" + self.args['configuration'],
+ # "media_plugin_libvlc.dylib")
- # # 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.
+ # # 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" )
- # # from SLPlugin.app/Contents/Frameworks/Chromium Embedded
- # # Framework.framework back to
- # # $viewer_app/Contents/Frameworks/Chromium Embedded Framework.framework
- # SLPlugin_framework = self.relsymlinkf(CEF_framework, catch=False)
-
- # # copy DullahanHelper.app
- # self.path2basename(relpkgdir, 'DullahanHelper.app')
-
- # # and fix that up with a Frameworks/CEF symlink too
- # with self.prefix(dst=os.path.join(
- # 'DullahanHelper.app', 'Contents', 'Frameworks')):
- # # from Dullahan Helper.app/Contents/Frameworks/Chromium Embedded
- # # Framework.framework back to
- # # SLPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework
- # # Since SLPlugin_framework is itself a
- # # symlink, don't let relsymlinkf() resolve --
- # # explicitly call relpath(symlink=True) and
- # # create that symlink here.
- # DullahanHelper_framework = \
- # self.symlinkf(self.relpath(SLPlugin_framework, symlink=True),
- # catch=False)
-
- # # change_command includes install_name_tool, the
- # # -change subcommand and the old framework rpath
- # # stamped into the executable. To use it with
- # # run_command(), we must still append the new
- # # framework path and the pathname of the
- # # executable to change.
- # change_command = [
- # 'install_name_tool', '-change',
- # '@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework']
-
- # with self.prefix(dst=os.path.join(
- # 'DullahanHelper.app', 'Contents', 'MacOS')):
- # # Now self.get_dst_prefix() is, at runtime,
- # # @executable_path. Locate the helper app
- # # framework (which is a symlink) from here.
- # newpath = os.path.join(
- # '@executable_path',
- # self.relpath(DullahanHelper_framework, symlink=True),
- # frameworkname)
- # # and restamp the DullahanHelper executable
- # self.run_command(
- # change_command +
- # [newpath, self.dst_path_of('DullahanHelper')])
-
- # # SLPlugin plugins
- # with self.prefix(dst="llplugin"):
- # dylibexecutable = 'media_plugin_cef.dylib'
- # self.path2basename("../media_plugins/cef/" + self.args['configuration'],
- # dylibexecutable)
-
- # # Do this install_name_tool *after* media plugin is copied over.
- # # Locate the framework lib executable -- relative to
- # # SLPlugin.app/Contents/MacOS, which will be our
- # # @executable_path at runtime!
- # newpath = os.path.join(
- # '@executable_path',
- # self.relpath(SLPlugin_framework, executable_path["SLPlugin.app"],
- # symlink=True),
- # frameworkname)
- # # restamp media_plugin_cef.dylib
- # self.run_command(
- # change_command +
- # [newpath, self.dst_path_of(dylibexecutable)])
-
- # # copy LibVLC plugin itself
- # self.path2basename("../media_plugins/libvlc/" + self.args['configuration'],
- # "media_plugin_libvlc.dylib")
-
- # # copy LibVLC dynamic libraries
- # with self.prefix(src=relpkgdir, dst="lib"):
- # self.path( "libvlc*.dylib*" )
- # # copy LibVLC plugins folder
- # with self.prefix(src='plugins', dst=""):
- # self.path( "*.dylib" )
- # self.path( "plugins.dat" )
def construct(self):
# copy over the build result (this is a no-op if run within the xcode script)
self.path(self.args['configuration'] + "/Firestorm.app", dst="")
@@ -1480,14 +1372,14 @@ class DarwinManifest(ViewerManifest):
with self.prefix(dst="Resources"):
super(DarwinManifest, self).construct()
- with self.prefix(src_dst="cursors_mac"):
+ with self.prefix("cursors_mac"):
self.path("*.tif")
self.path("licenses-mac.txt", dst="licenses.txt")
self.path("featuretable_mac.txt")
self.path("VivoxAUP.txt")
- with self.prefix(src=pkgdir):
+ with self.prefix(src=pkgdir,dst=""):
self.path("ca-bundle.crt")
icon_path = self.icon_path()
@@ -1495,7 +1387,6 @@ class DarwinManifest(ViewerManifest):
self.path("firestorm_icon.icns")
self.path("Firestorm.nib")
-
# Translations
self.path("English.lproj/language.txt")
self.replace_in(src="English.lproj/InfoPlist.strings",
@@ -1622,6 +1513,7 @@ class DarwinManifest(ViewerManifest):
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"),
@@ -1629,6 +1521,8 @@ class DarwinManifest(ViewerManifest):
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,
@@ -1675,8 +1569,9 @@ class DarwinManifest(ViewerManifest):
# SLPlugin plugins
with self.prefix(dst="llplugin"):
+ dylibexecutable = 'media_plugin_cef.dylib'
self.path2basename("../media_plugins/cef/" + self.args['configuration'],
- "media_plugin_cef.dylib")
+ dylibexecutable)
# copy LibVLC plugin itself
self.path2basename("../media_plugins/libvlc/" + self.args['configuration'],
@@ -1684,7 +1579,7 @@ class DarwinManifest(ViewerManifest):
# copy LibVLC dynamic libraries
with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'packages', 'lib', 'release' ), dst="lib"):
- self.path("libvlc*.dylib*")
+ self.path( "libvlc*.dylib*" )
# copy LibVLC plugins folder
with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'packages', 'lib', 'release', 'plugins' ), dst="lib"):
@@ -1931,10 +1826,7 @@ class DarwinManifest(ViewerManifest):
else:
print >> sys.stderr, "Maximum codesign attempts exceeded; giving up"
raise
- self.run_command(['spctl', '-a', '-texec', '-vv', app_in_dmg])
-
- imagename="SecondLife_" + '_'.join(self.args['version'])
-
+ self.run_command(['spctl', '-a', '-texec', '-vvvv', app_in_dmg])
finally:
# Unmount the image even if exceptions from any of the above
@@ -1994,12 +1886,8 @@ class LinuxManifest(ViewerManifest):
self.path2basename("../llplugin/slplugin", "SLPlugin")
#this copies over the python wrapper script, associated utilities and required libraries, see SL-321, SL-322 and SL-323
# Remove VMP
- #with self.prefix(src="../viewer_components/manager"):
- # 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(src="../viewer_components/manager", dst=""):
+ # self.path("*.py")
# Remove VMP
# recurses, packaged again
@@ -2246,7 +2134,7 @@ class LinuxManifest(ViewerManifest):
["find"] +
[os.path.join(self.get_dst_prefix(), dir) for dir in ('bin', 'lib')] +
# Remove VMP
- #['-type', 'f', '!', '-name', '*.py', '!', '-name', 'SL_Launcher',
+ # ['-type', 'f', '!', '-name', '*.py',
['-type', 'f', "!", "-name", "*.dat", "!", "-name", "*.pak", "!", "-name", "*.bin",
# Remove VMP
'!', '-name', 'update_install', '-exec', 'strip', '-S', '{}', ';'])
diff --git a/indra/test/test.cpp b/indra/test/test.cpp
index b426a5d1f6..28644fb52e 100644
--- a/indra/test/test.cpp
+++ b/indra/test/test.cpp
@@ -548,7 +548,6 @@ int main(int argc, char **argv)
LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
}
LLError::setFatalFunction(wouldHaveCrashed);
- LLError::setPrintLocation(true);
std::string test_app_name(argv[0]);
std::string test_log = test_app_name + ".log";
LLFile::remove(test_log);
diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp
index c767d52c7b..e3390f33c6 100644
--- a/indra/viewer_components/login/lllogin.cpp
+++ b/indra/viewer_components/login/lllogin.cpp
@@ -128,6 +128,15 @@ void LLLogin::Impl::connect(const std::string& uri, const LLSD& login_params)
LL_DEBUGS("LLLogin") << " connected with uri '" << uri << "', login_params " << login_params << LL_ENDL;
}
+namespace {
+// Instantiate this rendezvous point at namespace scope so it's already
+// present no matter how early the updater might post to it.
+// Use an LLEventMailDrop, which has future-like semantics: regardless of the
+// relative order in which post() or listen() are called, it delivers each
+// post() event to its listener(s) until one of them consumes that event.
+static LLEventMailDrop sSyncPoint("LoginSync");
+}
+
void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
{
LLSD printable_params = login_params;
@@ -219,7 +228,47 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
}
else
{
+ // Synchronize here with the updater. We synchronize here rather
+ // than in the fail.login handler, which actually examines the
+ // response from login.cgi, because here we are definitely in a
+ // coroutine and can definitely use suspendUntilBlah(). Whoever's
+ // listening for fail.login might not be.
+
+ // If the reason for login failure is that we must install a
+ // required update, we definitely want to pass control to the
+ // updater to manage that for us. We'll handle any other login
+ // failure ourselves, as usual. We figure that no matter where you
+ // are in the world, or what kind of network you're on, we can
+ // reasonably expect the Viewer Version Manager to respond more or
+ // less as quickly as login.cgi. This synchronization is only
+ // intended to smooth out minor races between the two services.
+ // But what if the updater crashes? Use a timeout so that
+ // eventually we'll tire of waiting for it and carry on as usual.
+ // Given the above, it can be a fairly short timeout, at least
+ // from a human point of view.
+
+ // Since sSyncPoint is an LLEventMailDrop, we DEFINITELY want to
+ // consume the posted event.
+ // Disable updater
+ //LLCoros::OverrideConsuming oc(true);
+ //// Timeout should produce the isUndefined() object passed here.
+ //LL_DEBUGS("LLLogin") << "Login failure, waiting for sync from updater" << LL_ENDL;
+ //LLSD updater = llcoro::suspendUntilEventOnWithTimeout(sSyncPoint, 10, LLSD());
+ //if (updater.isUndefined())
+ //{
+ // LL_WARNS("LLLogin") << "Failed to hear from updater, proceeding with fail.login"
+ // << LL_ENDL;
+ //}
+ //else
+ //{
+ // LL_DEBUGS("LLLogin") << "Got responses from updater and login.cgi" << LL_ENDL;
+ //}
+ //// Let the fail.login handler deal with empty updater response.
+ //LLSD responses(mAuthResponse["responses"]);
+ //responses["updater"] = updater;
+ //sendProgressEvent("offline", "fail.login", responses);
sendProgressEvent("offline", "fail.login", mAuthResponse["responses"]);
+ //
}
return; // Done!
}
@@ -249,10 +298,10 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
// *NOTE: The response from LLXMLRPCListener's Poller::poll method returns an
// llsd with no "responses" node. To make the output from an incomplete login symmetrical
// to success, add a data/message and data/reason fields.
- LLSD error_response;
- error_response["reason"] = mAuthResponse["status"];
- error_response["errorcode"] = mAuthResponse["errorcode"];
- error_response["message"] = mAuthResponse["error"];
+ LLSD error_response(LLSDMap
+ ("reason", mAuthResponse["status"])
+ ("errorcode", mAuthResponse["errorcode"])
+ ("message", mAuthResponse["error"]));
if(mAuthResponse.has("certificate"))
{
error_response["certificate"] = mAuthResponse["certificate"];