Merge viewer-bugsplat

master
Ansariel 2018-10-27 00:50:58 +02:00
commit ee34ea1f4b
32 changed files with 885 additions and 889 deletions

View File

@ -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

View File

@ -448,9 +448,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>7a7bd828233e8a2b0e9c022f6219e6e7</string>
<string>c3b5e8c57bd1c92bc9e0956586908b99</string>
<key>url</key>
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/23730/182106/bugsplat-1.0.6.519145-darwin64-519145.tar.bz2</string>
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/26330/207568/bugsplat-1.0.7.520791-darwin64-520791.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -460,9 +460,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>a3938332a11215e6909d67d1b9be5259</string>
<string>766dfde65a5b42ea5691d41df79c43e0</string>
<key>url</key>
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/23732/182120/bugsplat-3.6.0.4.519145-windows-519145.tar.bz2</string>
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/26332/207582/bugsplat-3.6.0.4.520791-windows-520791.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>
@ -472,46 +472,16 @@
<key>archive</key>
<map>
<key>hash</key>
<string>453d624d87a80779f59cfb1880613d90</string>
<string>afd01285e22f27d473fac6f88fac9a3b</string>
<key>url</key>
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/23731/182115/bugsplat-3.6.0.4.519145-windows64-519145.tar.bz2</string>
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/26331/207576/bugsplat-3.6.0.4.520791-windows64-520791.tar.bz2</string>
</map>
<key>name</key>
<string>windows64</string>
</map>
</map>
<key>version</key>
<string>1.0.6.519145</string>
</map>
<key>chardet</key>
<map>
<key>copyright</key>
<string>Contributors to charset (see https://github.com/chardet/chardet)</string>
<key>description</key>
<string>Python Character Encoding Library</string>
<key>license</key>
<string>LGPL</string>
<key>license_file</key>
<string>LICENSES/chardet.txt</string>
<key>name</key>
<string>chardet</string>
<key>platforms</key>
<map>
<key>darwin64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>0124862b6a1b88455c78a68f8b823d21</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6662/23578/chardet-3.0.4-darwin64-506651.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
</map>
</map>
<key>version</key>
<string>3.0.4</string>
<string>1.0.7.520791</string>
</map>
<key>colladadom</key>
<map>
@ -1801,36 +1771,6 @@
<key>version</key>
<string>2012.1-2</string>
</map>
<key>idna</key>
<map>
<key>copyright</key>
<string>Copyright (c) 2013-2017, Kim Davies. All rights reserved.</string>
<key>description</key>
<string>Python Internationalized Domain Names in Applications (IDNA) Library</string>
<key>license</key>
<string>see idna.rst</string>
<key>license_file</key>
<string>LICENSES/idna.rst</string>
<key>name</key>
<string>idna</string>
<key>platforms</key>
<map>
<key>darwin64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>7dfe9fc4023d7d4f511dd9fac7258266</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6663/23584/idna-2.5-darwin64-506652.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
</map>
</map>
<key>version</key>
<string>2.5</string>
</map>
<key>jpeglib</key>
<map>
<key>copyright</key>
@ -2509,46 +2449,6 @@
<key>version</key>
<string>0.0.1</string>
</map>
<key>llbase</key>
<map>
<key>copyright</key>
<string>Copyright (c) 2010, Linden Research, Inc.</string>
<key>license</key>
<string>mit</string>
<key>license_file</key>
<string>LICENSES/llbase-license.txt</string>
<key>name</key>
<string>llbase</string>
<key>platforms</key>
<map>
<key>darwin64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>e18eeb0691af053b83bd46b76c6ee86a</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6299/21982/llbase-0.9.3.506286-darwin64-506286.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
</map>
<key>windows</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>e6865670f9bca1c82fb8b91db3ea515c</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6301/21994/llbase-0.9.3.506286-windows-506286.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>
</map>
</map>
<key>version</key>
<string>0.9.3.506286</string>
</map>
<key>llca</key>
<map>
<key>copyright</key>
@ -3315,52 +3215,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>version</key>
<string>8.35.500898</string>
</map>
<key>requests</key>
<map>
<key>copyright</key>
<string>Copyright 2016 Kenneth Reitz</string>
<key>description</key>
<string>Python HTTP Library</string>
<key>license</key>
<string>Apache</string>
<key>license_file</key>
<string>LICENSES/requests.txt</string>
<key>name</key>
<string>requests</string>
<key>platforms</key>
<map>
<key>darwin64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>b8d134a970261b445a3f376ba4e05ff7</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6693/23788/requests-2.18.1-darwin64-506681.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
</map>
<key>linux64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>9fe44ba82ee05363fdfa4c1b9f2ec360</string>
<key>url</key>
<string>http://downloads.phoenixviewer.com/requests-2.18.1-linux64-180841555.tar.bz2</string>
</map>
<key>name</key>
<string>linux64</string>
</map>
</map>
<key>source</key>
<string>https://bitbucket.org/lindenlab/p64_python-requests</string>
<key>source_type</key>
<string>hg</string>
<key>version</key>
<string>2.18.1</string>
</map>
<key>slvoice</key>
<map>
<key>copyright</key>
@ -3571,36 +3425,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>version</key>
<string>0.8.0.1</string>
</map>
<key>urllib3</key>
<map>
<key>copyright</key>
<string>Copyright 2008-2016 Andrey Petrov and contributors (see CONTRIBUTORS.txt)</string>
<key>description</key>
<string>Python HTTP Library</string>
<key>license</key>
<string>MIT</string>
<key>license_file</key>
<string>LICENSES/urllib3.txt</string>
<key>name</key>
<string>urllib3</string>
<key>platforms</key>
<map>
<key>darwin64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>22f64c7fbb6704d2e9519fd1cca8e49b</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6659/23560/urllib3-1.21.1-darwin64-506648.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
</map>
</map>
<key>version</key>
<string>1.21.1</string>
</map>
<key>viewer-manager</key>
<map>
<key>copyright</key>
@ -3608,7 +3432,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>description</key>
<string>Linden Lab Viewer Management Process suite.</string>
<key>license</key>
<string>Proprietary</string>
<string>viewerlgpl</string>
<key>license_file</key>
<string>LICENSE</string>
<key>name</key>
@ -3620,9 +3444,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>ce95944fb842849108102263a25fc794</string>
<string>1d801a03cb87a248b6573f8550603286</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/23237/178332/viewer_manager-1.0.518840-darwin64-518840.tar.bz2</string>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/26264/206909/viewer_manager-2.0.520750-darwin64-520750.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -3656,9 +3480,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>642f847a9ac45551af65a55826974334</string>
<string>65e20bc630033178f3f7e4890c0b85f7</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/23236/178338/viewer_manager-1.0.518840-windows-518840.tar.bz2</string>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/26265/206915/viewer_manager-2.0.520750-windows-520750.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>
@ -3669,7 +3493,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>source_type</key>
<string>hg</string>
<key>version</key>
<string>1.0.518840</string>
<string>2.0.520750</string>
</map>
<key>vlc-bin</key>
<map>

View File

@ -1,4 +0,0 @@
# -*- cmake -*-
include(Prebuilt)
use_prebuilt_binary(llbase)

View File

@ -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)

View File

@ -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()]

View File

@ -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

View File

@ -119,13 +119,14 @@ namespace {
public:
RecordToFile(const std::string& filename)
{
// <FS:Ansariel> 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>(recordToFile)->okay())
{
s->mFileRecorderFileName = file_name;
s->mFileRecorder = recordToFile;
addRecorder(recordToFile);
RecorderPtr recordToFile(new RecordToFile(file_name));
if (boost::dynamic_pointer_cast<RecordToFile>(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
{
/* <FS:LO> 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);
}
} </FS:LO> */
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<std::string, unsigned int>::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();
}
// <FS:Ansriel> Fix log output - we don't need an escaped output
//addEscapedMessage(message_stream, message);
message_stream << message;
// </FS:Ansariel>
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)
}

View File

@ -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<Recorder> RecorderPtr;

View File

@ -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);
}

View File

@ -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.
*/

View File

@ -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)
{}

View File

@ -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<std::string>& 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<std::string>::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<LLLeapListener> 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<std::string>& 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<std::string>&
}
}
LLLeap* LLLeap::create(const std::string& desc, const std::vector<std::string>& plugin, bool exc)
{
LLProcess::Params params;
params.desc = desc;
std::vector<std::string>::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

View File

@ -14,6 +14,7 @@
#include "llinstancetracker.h"
#include "llexception.h"
#include "llprocess.h"
#include <string>
#include <vector>
@ -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

View File

@ -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<TestRecorder>(mRecorder)->setWantsTime(t);
}
{
boost::dynamic_pointer_cast<TestRecorder>(mRecorder)->showTime(t);
}
void setWantsMultiline(bool t)
{
boost::dynamic_pointer_cast<TestRecorder>(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<TestRecorder>(anotherRecorder)->setWantsTime(true);
boost::dynamic_pointer_cast<TestRecorder>(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<>

View File

@ -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

View File

@ -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");
}
//<FS:TS> Used by LGG's selection beams

View File

@ -1446,12 +1446,10 @@ static CursorRef gCursors[UI_CURSOR_COUNT];
static void initPixmapCursor(int cursorid, int hotspotX, int hotspotY)
{
// cursors are in <Application Bundle>/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);
}

View File

@ -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}")

View File

@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${MACOSX_WRAPPER_EXECUTABLE_NAME}</string>
<string>${MACOSX_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>

View File

@ -6366,6 +6366,17 @@
<key>Value</key>
<real>96.0</real>
</map>
<key>ForceAddressSize</key>
<map>
<key>Comment</key>
<string>Force Windows update to 32-bit or 64-bit viewer.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>ForceAssetFail</key>
<map>
<key>Comment</key>
@ -17210,19 +17221,6 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<real>1.0</real>
</map>
<key>VerboseLogs</key>
<map>
<key>Comment</key>
<string>Display source file and line number for each log item for debugging purposes</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
<key>Backup</key>
<integer>0</integer>
</map>
<key>VertexShaderEnable</key>
<map>
<key>Comment</key>
@ -21080,7 +21078,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<string>if true, disables running the GPU benchmark at startup
(default to class 1)</string>
<key>Persist</key>
<integer>0</integer>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>

View File

@ -341,7 +341,7 @@ SetOutPath "$INSTDIR"
CreateShortCut "$SMPROGRAMS\$INSTSHORTCUT\$INSTSHORTCUT.lnk" \
"$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM"
# <FS:Ansariel> 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"
# <FS:Ansariel> 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"
# <FS:Ansariel> 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
# <FS:Ansariel> Remove VMP
#WriteRegStr HKEY_CLASSES_ROOT "Applications\$INSTEXE" "IsHostApp" ""
#WriteRegStr HKEY_CLASSES_ROOT "Applications\${VIEWER_EXE}" "NoStartPage" ""
# </FS:Ansariel> Remove VMP
WriteRegStr HKEY_CLASSES_ROOT "Applications\$VIEWER_EXE" "IsHostApp" ""
##WriteRegStr HKEY_CLASSES_ROOT "Applications\${VIEWER_EXE}" "NoStartPage" ""
# <FS:CR> 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}" # <FS:Ansariel> 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
# <FS:Ansariel> 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"
# <FS:Ansariel> Remove VMP
#DeleteRegKey HKEY_CLASSES_ROOT "Applications\$INSTEXE"
#DeleteRegKey HKEY_CLASSES_ROOT "Applications\${VIEWER_EXE}"
# </FS:Ansariel> 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.
# <FS:Ansariel> 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.
# <FS:Ansariel> 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

View File

@ -26,6 +26,8 @@
#import "llappdelegate-objc.h"
#if defined(LL_BUGSPLAT)
#include <boost/filesystem.hpp>
#include <vector>
@import BugsplatMac;
// derived from BugsplatMac's BugsplatTester/AppDelegate.m
@interface LLAppDelegate () <BugsplatStartupManagerDelegate>
@ -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<BugsplatAttachment *> *)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<AttachmentInfo> 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

View File

@ -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
// <FS:Ansariel> 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");
// }
//}
// </FS:Ansariel>
#endif
#if LL_WINDOWS
if (gGLManager.mGLVersion < LLFeatureManager::getInstance()->getExpectedGLVersion())
{
@ -1356,6 +1329,38 @@ bool LLAppViewer::init()
gGLActive = FALSE;
// <FS:Ansariel> 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);
// </FS:Ansariel>
// 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.
// <FS:Ansariel> LL merge error
//if (!gDisconnected && isAgentAvatarValid())
//{
// gAgentAvatarp->updateAvatarRezMetrics(true); // force a last packet to be sent.
//}
// </FS:Ansariel>
LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
effectp->setPositionGlobal(gAgent.getPositionGlobal());
effectp->setColor(LLColor4U(gAgent.getEffectColor()));

View File

@ -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<LLEventAPI::Response>
(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;

View File

@ -28,8 +28,10 @@
#define LL_LLLOGININSTANCE_H
#include "lleventdispatcher.h"
#include "lleventapi.h"
#include <boost/scoped_ptr.hpp>
#include <boost/function.hpp>
#include <memory> // 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<LLEventAPI::Response> ResponsePtr;
void constructAuthParams(LLPointer<LLCredential> 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);

View File

@ -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 */
}

View File

@ -332,6 +332,9 @@ private:
RecordToChatConsole::RecordToChatConsole():
mRecorder(new RecordToChatConsoleRecorder())
{
mRecorder->showTags(false);
mRecorder->showLocation(false);
mRecorder->showMultiline(true);
}
////////////////////////////////////////////////////////////////////////////

View File

@ -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
// <FS:Ansariel> 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
// </FS:Ansariel>
exe_path += "SLVoice.exe";
gDirUtilp->append(exe_path, "SLVoice.exe");
#elif LL_DARWIN
// <FS:Ansariel/TS> 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
// </FS:Ansariel/TS>
#else
// <FS:ND> 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
// </FS:ND>
#endif
// See if the vivox executable exists

View File

@ -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/
<tag>confirm</tag>
<usetemplate
@ -3958,6 +3957,44 @@ Please download from https://secondlife.com/support/downloads/
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="PauseForUpdate"
type="alertmodal">
Version [VERSION] is required for login.
Click OK to download and install.
<tag>confirm</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="OptionalUpdateReady"
type="alertmodal">
Version [VERSION] has been downloaded and is ready to install.
Click OK to install.
<tag>confirm</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="PromptOptionalUpdate"
type="alertmodal">
Version [VERSION] has been downloaded and is ready to install.
Proceed?
<tag>confirm</tag>
<usetemplate
canceltext="Not Now"
name="yesnocancelbuttons"
notext="Skip"
yestext="Install"/>
</notification>
<notification
icon="alertmodal.tga"
name="LoginFailedUnknown"

View File

@ -539,7 +539,7 @@ class WindowsManifest(ViewerManifest):
pass
except NoMatchingAssemblyException as err:
pass
self.ccopy(src,dst)
else:
raise Exception("Directories are not supported by test_CRT_and_copy_action()")
@ -560,7 +560,7 @@ class WindowsManifest(ViewerManifest):
# <FS:Ansariel> 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")
# </FS:Ansariel> 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
# <FS:Ansariel> 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")
# </FS:Ansariel> 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')] +
# <FS:Ansariel> Remove VMP
#['-type', 'f', '!', '-name', '*.py', '!', '-name', 'SL_Launcher',
# ['-type', 'f', '!', '-name', '*.py',
['-type', 'f', "!", "-name", "*.dat", "!", "-name", "*.pak", "!", "-name", "*.bin",
# </FS:Ansariel> Remove VMP
'!', '-name', 'update_install', '-exec', 'strip', '-S', '{}', ';'])

View File

@ -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);

View File

@ -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.
// <FS:Ansariel> 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"]);
// </FS:Ansariel>
}
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"];