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