diff options
24 files changed, 885 insertions, 1208 deletions
diff --git a/autobuild.xml b/autobuild.xml index 160f1d7d59..f0358eb8ba 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -225,90 +225,6 @@ <key>version</key> <string>1.57</string> </map> - <key>bugsplat</key> - <map> - <key>copyright</key> - <string>Copyright 2003-2017, BugSplat</string> - <key>description</key> - <string>Bugsplat crash reporting package</string> - <key>license</key> - <string>Proprietary</string> - <key>license_file</key> - <string>LICENSES/BUGSPLAT_LICENSE.txt</string> - <key>name</key> - <string>bugsplat</string> - <key>platforms</key> - <map> - <key>darwin64</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>436b124bce8cf57b18dbf10f5e6ebcd4</string> - <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/26151/206132/bugsplat-1.0.7.520674-darwin64-520674.tar.bz2</string> - </map> - <key>name</key> - <string>darwin64</string> - </map> - <key>windows</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>5d19acddc51ee7c802297dd176194362</string> - <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/26153/206145/bugsplat-3.6.0.4.520674-windows-520674.tar.bz2</string> - </map> - <key>name</key> - <string>windows</string> - </map> - <key>windows64</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>78f5688b694e04c052fb0a1165c98bb5</string> - <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/26152/206142/bugsplat-3.6.0.4.520674-windows64-520674.tar.bz2</string> - </map> - <key>name</key> - <string>windows64</string> - </map> - </map> - <key>version</key> - <string>1.0.7.520674</string> - </map> - <key>chardet</key> - <map> - <key>copyright</key> - <string>Contributors to charset (see https://github.com/chardet/chardet)</string> - <key>description</key> - <string>Python Character Encoding Library</string> - <key>license</key> - <string>LGPL</string> - <key>license_file</key> - <string>LICENSES/chardet.txt</string> - <key>name</key> - <string>chardet</string> - <key>platforms</key> - <map> - <key>darwin64</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>0124862b6a1b88455c78a68f8b823d21</string> - <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6662/23578/chardet-3.0.4-darwin64-506651.tar.bz2</string> - </map> - <key>name</key> - <string>darwin64</string> - </map> - </map> - <key>version</key> - <string>3.0.4</string> - </map> <key>colladadom</key> <map> <key>copyright</key> @@ -1519,36 +1435,6 @@ <key>version</key> <string>2012.1-2</string> </map> - <key>idna</key> - <map> - <key>copyright</key> - <string>Copyright (c) 2013-2017, Kim Davies. All rights reserved.</string> - <key>description</key> - <string>Python Internationalized Domain Names in Applications (IDNA) Library</string> - <key>license</key> - <string>see idna.rst</string> - <key>license_file</key> - <string>LICENSES/idna.rst</string> - <key>name</key> - <string>idna</string> - <key>platforms</key> - <map> - <key>darwin64</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>7dfe9fc4023d7d4f511dd9fac7258266</string> - <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6663/23584/idna-2.5-darwin64-506652.tar.bz2</string> - </map> - <key>name</key> - <string>darwin64</string> - </map> - </map> - <key>version</key> - <string>2.5</string> - </map> <key>jpeglib</key> <map> <key>copyright</key> @@ -2227,46 +2113,6 @@ <key>version</key> <string>0.0.1</string> </map> - <key>llbase</key> - <map> - <key>copyright</key> - <string>Copyright (c) 2010, Linden Research, Inc.</string> - <key>license</key> - <string>mit</string> - <key>license_file</key> - <string>LICENSES/llbase-license.txt</string> - <key>name</key> - <string>llbase</string> - <key>platforms</key> - <map> - <key>darwin64</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>e18eeb0691af053b83bd46b76c6ee86a</string> - <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6299/21982/llbase-0.9.3.506286-darwin64-506286.tar.bz2</string> - </map> - <key>name</key> - <string>darwin64</string> - </map> - <key>windows</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>e6865670f9bca1c82fb8b91db3ea515c</string> - <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6301/21994/llbase-0.9.3.506286-windows-506286.tar.bz2</string> - </map> - <key>name</key> - <string>windows</string> - </map> - </map> - <key>version</key> - <string>0.9.3.506286</string> - </map> <key>llca</key> <map> <key>copyright</key> @@ -3009,52 +2855,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>version</key> <string>8.35.500898</string> </map> - <key>requests</key> - <map> - <key>copyright</key> - <string>Copyright 2016 Kenneth Reitz</string> - <key>description</key> - <string>Python HTTP Library</string> - <key>license</key> - <string>Apache</string> - <key>license_file</key> - <string>LICENSES/requests.txt</string> - <key>name</key> - <string>requests</string> - <key>platforms</key> - <map> - <key>darwin64</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>b8d134a970261b445a3f376ba4e05ff7</string> - <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6693/23788/requests-2.18.1-darwin64-506681.tar.bz2</string> - </map> - <key>name</key> - <string>darwin64</string> - </map> - <key>linux64</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>a92f2235991871c3d601a73cfef9b2af</string> - <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/4105/11530/requests-1.0-linux64-504094.tar.bz2</string> - </map> - <key>name</key> - <string>linux64</string> - </map> - </map> - <key>source</key> - <string>https://bitbucket.org/lindenlab/p64_python-requests</string> - <key>source_type</key> - <string>hg</string> - <key>version</key> - <string>2.18.1</string> - </map> <key>slvoice</key> <map> <key>copyright</key> @@ -3265,36 +3065,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>version</key> <string>0.8.0.1</string> </map> - <key>urllib3</key> - <map> - <key>copyright</key> - <string>Copyright 2008-2016 Andrey Petrov and contributors (see CONTRIBUTORS.txt)</string> - <key>description</key> - <string>Python HTTP Library</string> - <key>license</key> - <string>MIT</string> - <key>license_file</key> - <string>LICENSES/urllib3.txt</string> - <key>name</key> - <string>urllib3</string> - <key>platforms</key> - <map> - <key>darwin64</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>22f64c7fbb6704d2e9519fd1cca8e49b</string> - <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6659/23560/urllib3-1.21.1-darwin64-506648.tar.bz2</string> - </map> - <key>name</key> - <string>darwin64</string> - </map> - </map> - <key>version</key> - <string>1.21.1</string> - </map> <key>viewer-manager</key> <map> <key>copyright</key> @@ -3302,7 +3072,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>description</key> <string>Linden Lab Viewer Management Process suite.</string> <key>license</key> - <string>Proprietary</string> + <string>viewerlgpl</string> <key>license_file</key> <string>LICENSE</string> <key>name</key> @@ -3314,9 +3084,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>4785e25bde1503e99cb4c2fe344b3d4e</string> + <string>eeeb18f7396de3147c6d958dfbc1a2e5</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/25165/197744/viewer_manager-1.0.520046-darwin64-520046.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/26016/204885/viewer_manager-2.0.520576-darwin64-520576.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -3338,9 +3108,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>b03866283b2cf3d8a79a93a07cbec9d6</string> + <string>2832c40449a8a8230e9072ceac5120af</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/25166/197758/viewer_manager-1.0.520046-windows-520046.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/26017/204891/viewer_manager-2.0.520576-windows-520576.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -3351,7 +3121,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>source_type</key> <string>hg</string> <key>version</key> - <string>1.0.520046</string> + <string>2.0.520576</string> </map> <key>vlc-bin</key> <map> 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/llcommon/llcoros.h b/indra/llcommon/llcoros.h index 8fb27af6a4..c551413811 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -170,6 +170,26 @@ public: 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 * Future wraps the essential boost::dcoroutines::future functionality diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index dce97b5411..eedd8c92b5 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -545,10 +545,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 @@ -564,16 +562,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<std::string>& plugin): + LLLeapImpl(const LLProcess::Params& cparams): // We might reassign mDesc in the constructor body if it's empty here. - mDesc(desc), + mDesc(cparams.desc), // We expect multiple LLLeapImpl instances. Definitely tweak // mDonePump's name for uniqueness. mDonePump("LLLeap", true), @@ -67,17 +67,17 @@ public: // this class or method name. mListener(new LLLeapListener(boost::bind(&LLLeapImpl::connect, this, _1, _2))) { - // Rule out empty vector - if (plugin.empty()) + // Rule out unpopulated Params block + if (! cparams.executable.isProvided()) { LLTHROW(Error("no plugin command")); } // Don't leave desc empty either, but in this case, if we weren't // given one, we'll fake one. - if (desc.empty()) + if (mDesc.empty()) { - mDesc = LLProcess::basename(plugin[0]); + mDesc = LLProcess::basename(cparams.executable); // how about a toLower() variant that returns the transformed string?! std::string desclower(mDesc); LLStringUtil::toLower(desclower); @@ -87,9 +87,9 @@ public: // notice Python specially: we provide Python LLSD serialization // support, so there's a pretty good reason to implement plugins // in that language. - if (plugin.size() >= 2 && (desclower == "python" || desclower == "python.exe")) + if (cparams.args.size() && (desclower == "python" || desclower == "python.exe")) { - mDesc = LLProcess::basename(plugin[1]); + mDesc = LLProcess::basename(cparams.args()[0]); } } @@ -97,14 +97,10 @@ public: mDonePump.listen("LLLeap", boost::bind(&LLLeapImpl::bad_launch, this, _1)); // Okay, launch child. - LLProcess::Params params; + // Get a modifiable copy of params block to set files and postend. + LLProcess::Params params(cparams); + // copy our deduced mDesc back into the params block params.desc = mDesc; - std::vector<std::string>::const_iterator pi(plugin.begin()), pend(plugin.end()); - params.executable = *pi++; - for ( ; pi != pend; ++pi) - { - params.args.add(*pi); - } params.files.add(LLProcess::FileParam("pipe")); // stdin params.files.add(LLProcess::FileParam("pipe")); // stdout params.files.add(LLProcess::FileParam("pipe")); // stderr @@ -429,17 +425,17 @@ private: boost::scoped_ptr<LLLeapListener> mListener; }; -// This must follow the declaration of LLLeapImpl, so it may as well be last. -LLLeap* LLLeap::create(const std::string& desc, const std::vector<std::string>& plugin, bool exc) +// These must follow the declaration of LLLeapImpl, so they may as well be last. +LLLeap* LLLeap::create(const LLProcess::Params& params, bool exc) { // If caller is willing to permit exceptions, just instantiate. if (exc) - return new LLLeapImpl(desc, plugin); + return new LLLeapImpl(params); // Caller insists on suppressing LLLeap::Error. Very well, catch it. try { - return new LLLeapImpl(desc, plugin); + return new LLLeapImpl(params); } catch (const LLLeap::Error&) { @@ -447,6 +443,23 @@ LLLeap* LLLeap::create(const std::string& desc, const std::vector<std::string>& } } +LLLeap* LLLeap::create(const std::string& desc, const std::vector<std::string>& plugin, bool exc) +{ + LLProcess::Params params; + params.desc = desc; + std::vector<std::string>::const_iterator pi(plugin.begin()), pend(plugin.end()); + // could validate here, but let's rely on LLLeapImpl's constructor + if (pi != pend) + { + params.executable = *pi++; + } + for ( ; pi != pend; ++pi) + { + params.args.add(*pi); + } + return create(params, exc); +} + LLLeap* LLLeap::create(const std::string& desc, const std::string& plugin, bool exc) { // Use LLStringUtil::getTokens() to parse the command line 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 <string> #include <vector> @@ -62,6 +63,19 @@ public: 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 * string(s) passed to create() might come from an external source. This 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 79c4362747..87dc1b9795 100644 --- a/indra/llvfs/lldir_mac.cpp +++ b/indra/llvfs/lldir_mac.cpp @@ -171,9 +171,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"); } std::string LLDir_Mac::getCurPath() diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 843294c239..d4afbb15df 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -1429,12 +1429,10 @@ static CursorRef gCursors[UI_CURSOR_COUNT]; static void initPixmapCursor(int cursorid, int hotspotX, int hotspotY) { // cursors are in <Application Bundle>/Contents/Resources/cursors_mac/UI_CURSOR_FOO.tif - std::string fullpath = gDirUtilp->getAppRODataDir(); - fullpath += gDirUtilp->getDirDelimiter(); - fullpath += "cursors_mac"; - fullpath += gDirUtilp->getDirDelimiter(); - fullpath += cursorIDToName(cursorid); - fullpath += ".tif"; + std::string fullpath = gDirUtilp->add( + gDirUtilp->getAppRODataDir(), + "cursors_mac", + cursorIDToName(cursorid) + std::string(".tif")); gCursors[cursorid] = createImageCursor(fullpath.c_str(), hotspotX, hotspotY); } diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index e573b927d7..e7111ebe54 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -3,14 +3,7 @@ project(viewer) include(00-Common) -# DON'T move Linking.cmake to its place in the alphabetized list below: it -# sets variables on which the 3p .cmake files depend. -include(Linking) - include(Boost) -if (BUGSPLAT_DB) - include(bugsplat) -endif (BUGSPLAT_DB) include(BuildPackagesInfo) include(BuildVersion) include(CMakeCopyIfDifferent) @@ -23,7 +16,6 @@ include(GLOD) include(Hunspell) include(JsonCpp) include(LLAppearance) -include(LLBase) include(LLAudio) include(LLCA) include(LLCharacter) @@ -44,13 +36,13 @@ include(LLUI) include(LLVFS) include(LLWindow) include(LLXML) +include(Linking) include(NDOF) include(NVAPI) include(OPENAL) include(OpenGL) include(OpenSSL) include(PNG) -include(Requests) include(TemplateCheck) include(UI) include(UnixInstall) @@ -99,12 +91,6 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ) -if (BUGSPLAT_DB) - include_directories( - ${BUGSPLAT_INCLUDE_DIR} - ) -endif (BUGSPLAT_DB) - include_directories(SYSTEM ${LLCOMMON_SYSTEM_INCLUDE_DIRS} ${LLXML_SYSTEM_INCLUDE_DIRS} @@ -1368,14 +1354,6 @@ if (DARWIN) # This should be compiled with the viewer. LIST(APPEND viewer_SOURCE_FILES llappdelegate-objc.mm) - set_source_files_properties( - llappdelegate-objc.mm - PROPERTIES - COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}" - # BugsplatMac is a module, imported with @import. That language feature - # demands these switches. - COMPILE_FLAGS "-fmodules -fcxx-modules" - ) find_library(AGL_LIBRARY AGL) find_library(APPKIT_LIBRARY AppKit) @@ -1390,12 +1368,6 @@ if (DARWIN) ${COREAUDIO_LIBRARY} ) - if (BUGSPLAT_DB) - list(APPEND viewer_LIBRARIES - ${BUGSPLAT_LIBRARIES} - ) - endif (BUGSPLAT_DB) - # Add resource files to the project. set(viewer_RESOURCE_FILES secondlife.icns @@ -1421,11 +1393,6 @@ endif (DARWIN) if (LINUX) LIST(APPEND viewer_SOURCE_FILES llappviewerlinux.cpp) - set_source_files_properties( - llappviewerlinux.cpp - PROPERTIES - COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}" - ) LIST(APPEND viewer_SOURCE_FILES llappviewerlinux_api_dbus.cpp) SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed") @@ -1442,11 +1409,6 @@ if (WINDOWS) llappviewerwin32.cpp llwindebug.cpp ) - set_source_files_properties( - llappviewerwin32.cpp - PROPERTIES - COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}" - ) list(APPEND viewer_HEADER_FILES llappviewerwin32.h @@ -1729,11 +1691,6 @@ if (SDL_FOUND) ) endif (SDL_FOUND) -if (BUGSPLAT_DB) - set_property(TARGET ${VIEWER_BINARY_NAME} - PROPERTY COMPILE_DEFINITIONS "LL_BUGSPLAT") -endif (BUGSPLAT_DB) - # add package files file(GLOB EVENT_HOST_SCRIPT_GLOB_LIST ${CMAKE_CURRENT_SOURCE_DIR}/../viewer_components/*.py) @@ -1832,7 +1789,7 @@ if (WINDOWS) ${SHARED_LIB_STAGING_DIR}/Debug/fmodexL.dll ) endif (FMODEX) - + add_custom_command( OUTPUT ${CMAKE_CFG_INTDIR}/copy_touched.bat COMMAND ${PYTHON_EXECUTABLE} @@ -1841,16 +1798,15 @@ if (WINDOWS) --actions=copy --arch=${ARCH} --artwork=${ARTWORK_DIR} - "--bugsplat=${BUGSPLAT_DB}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} - "--channel=${VIEWER_CHANNEL}" --configuration=${CMAKE_CFG_INTDIR} --dest=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} --grid=${GRID} + "--channel=${VIEWER_CHANNEL}" + --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt --source=${CMAKE_CURRENT_SOURCE_DIR} --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/copy_touched.bat - --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py stage_third_party_libs @@ -1868,9 +1824,24 @@ if (WINDOWS) add_dependencies(${VIEWER_BINARY_NAME} SLPlugin - windows-crash-logger + windows-crash-logger ) + # sets the 'working directory' for debugging from visual studio. + if (NOT UNATTENDED) + add_custom_command( + TARGET ${VIEWER_BINARY_NAME} POST_BUILD + COMMAND ${CMAKE_SOURCE_DIR}/tools/vstool/vstool.exe + ARGS + --solution + ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.sln + --workingdir + ${VIEWER_BINARY_NAME} + "${CMAKE_CURRENT_SOURCE_DIR}" + COMMENT "Setting the ${VIEWER_BINARY_NAME} working directory for debugging." + ) + endif (NOT UNATTENDED) + if (PACKAGE) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.bz2 @@ -1893,16 +1864,15 @@ if (WINDOWS) ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py --arch=${ARCH} --artwork=${ARTWORK_DIR} - "--bugsplat=${BUGSPLAT_DB}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} "--channel=${VIEWER_CHANNEL}" + --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt --configuration=${CMAKE_CFG_INTDIR} --dest=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} --grid=${GRID} --source=${CMAKE_CURRENT_SOURCE_DIR} --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/touched.bat - --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt DEPENDS ${VIEWER_BINARY_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py @@ -1933,8 +1903,8 @@ else (WINDOWS) endif (WINDOWS) # *NOTE: - this list is very sensitive to ordering, test carefully on all -# platforms if you change the relative order of the entries here. -# In particular, cmake 2.6.4 (when building with linux/makefile generators) +# platforms if you change the releative order of the entries here. +# In particular, cmake 2.6.4 (when buidling with linux/makefile generators) # appears to sometimes de-duplicate redundantly listed dependencies improperly. # To work around this, higher level modules should be listed before the modules # that they depend upon. -brad @@ -2009,12 +1979,6 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${LLAPPEARANCE_LIBRARIES} ) -if (BUGSPLAT_DB) - target_link_libraries(${VIEWER_BINARY_NAME} - ${BUGSPLAT_LIBRARIES} - ) -endif (BUGSPLAT_DB) - set(ARTWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH "Path to artwork files.") @@ -2038,16 +2002,15 @@ if (LINUX) ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py --arch=${ARCH} --artwork=${ARTWORK_DIR} - "--bugsplat=${BUGSPLAT_DB}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} "--channel=${VIEWER_CHANNEL}" + --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt --configuration=${CMAKE_CFG_INTDIR} --dest=${CMAKE_CURRENT_BINARY_DIR}/packaged --grid=${GRID} --source=${CMAKE_CURRENT_SOURCE_DIR} --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.touched - --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py ${COPY_INPUT_DEPENDENCIES} @@ -2061,18 +2024,17 @@ if (LINUX) COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py - --actions=copy --arch=${ARCH} + --actions=copy --artwork=${ARTWORK_DIR} - "--bugsplat=${BUGSPLAT_DB}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} - "--channel=${VIEWER_CHANNEL}" --configuration=${CMAKE_CFG_INTDIR} --dest=${CMAKE_CURRENT_BINARY_DIR}/packaged --grid=${GRID} - --source=${CMAKE_CURRENT_SOURCE_DIR} + "--channel=${VIEWER_CHANNEL}" --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt + --source=${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py ${COPY_INPUT_DEPENDENCIES} @@ -2090,52 +2052,31 @@ if (LINUX) endif (LINUX) if (DARWIN) - # These all get set with PROPERTIES. It's not that the property names are - # 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 - if (PACKAGE) - set(MACOSX_WRAPPER_EXECUTABLE_NAME "SL_Launcher") - else (PACKAGE) - # force the name of the actual executable to allow running it within Xcode for debugging - set(MACOSX_WRAPPER_EXECUTABLE_NAME "../Resources/Second Life Viewer.app/Contents/MacOS/Second Life") - endif (PACKAGE) - set(MACOSX_BUNDLE_INFO_STRING "${VIEWER_CHANNEL}") + # These all get set with PROPERTIES + set(product "Second Life") + set(MACOSX_EXECUTABLE_NAME "Second Life") + set(MACOSX_BUNDLE_INFO_STRING "Second Life Viewer") set(MACOSX_BUNDLE_ICON_FILE "secondlife.icns") set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.secondlife.indra.viewer") set(MACOSX_BUNDLE_LONG_VERSION_STRING "${VIEWER_CHANNEL} ${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}") set(MACOSX_BUNDLE_BUNDLE_NAME "SecondLife") - set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}") + set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${VIEWER_SHORT_VERSION}") set(MACOSX_BUNDLE_BUNDLE_VERSION "${VIEWER_SHORT_VERSION}${VIEWER_MACOSX_PHASE}${VIEWER_REVISION}") set(MACOSX_BUNDLE_COPYRIGHT "Copyright © Linden Research, Inc. 2007") set(MACOSX_BUNDLE_NSMAIN_NIB_FILE "SecondLife.nib") set(MACOSX_BUNDLE_NSPRINCIPAL_CLASS "NSApplication") - - # https://blog.kitware.com/upcoming-in-cmake-2-8-12-osx-rpath-support/ - set(CMAKE_MACOSX_RPATH 1) set_target_properties( ${VIEWER_BINARY_NAME} PROPERTIES OUTPUT_NAME "${product}" - # From Contents/MacOS/SecondLife, look in Contents/Frameworks - INSTALL_RPATH "@loader_path/../Frameworks" - # SIGH, as of 2018-05-24 (cmake 3.11.1) the INSTALL_RPATH property simply - # does not work. Try this: - LINK_FLAGS "-rpath @loader_path/../Frameworks" MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info-SecondLife.plist" ) - set(VIEWER_APP_BUNDLE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app") - set(VIEWER_APP_EXE "${VIEWER_APP_BUNDLE}/Contents/MacOS/${product}") - set(VIEWER_APP_DSYM "${VIEWER_APP_EXE}.dSYM") - set(VIEWER_APP_XCARCHIVE "${VIEWER_APP_BUNDLE}/../${product}.xcarchive.zip") - configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/Info-SecondLife.plist" - "${VIEWER_APP_BUNDLE}/Contents/Info.plist" + "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app/Contents/Info.plist" ) add_custom_command( @@ -2146,16 +2087,15 @@ if (DARWIN) --actions=copy --arch=${ARCH} --artwork=${ARTWORK_DIR} - "--bugsplat=${BUGSPLAT_DB}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} - --bundleid=${MACOSX_BUNDLE_GUI_IDENTIFIER} - "--channel=${VIEWER_CHANNEL}" --configuration=${CMAKE_CFG_INTDIR} - --dest=${VIEWER_APP_BUNDLE} + --dest=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app --grid=${GRID} - --source=${CMAKE_CURRENT_SOURCE_DIR} + "--channel=${VIEWER_CHANNEL}" --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt + --bundleid=${MACOSX_BUNDLE_GUI_IDENTIFIER} + --source=${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${VIEWER_BINARY_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py @@ -2180,16 +2120,15 @@ if (DARWIN) ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py --arch=${ARCH} --artwork=${ARTWORK_DIR} - "--bugsplat=${BUGSPLAT_DB}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} - "--channel=${VIEWER_CHANNEL}" --configuration=${CMAKE_CFG_INTDIR} - --dest=${VIEWER_APP_BUNDLE} + --dest=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app --grid=${GRID} + "--channel=${VIEWER_CHANNEL}" + --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt --source=${CMAKE_CURRENT_SOURCE_DIR} --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.touched - --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt ${SIGNING_SETTING} DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py @@ -2201,152 +2140,67 @@ if (INSTALL) include(${CMAKE_CURRENT_SOURCE_DIR}/ViewerInstall.cmake) endif (INSTALL) -# Note that the conventional VIEWER_SYMBOL_FILE is set by ../../build.sh -if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIEWER_SYMBOL_FILE) - if (NOT BUGSPLAT_DB) - # Breakpad symbol-file generation - set(SYMBOL_SEARCH_DIRS "") - if (WINDOWS) - list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") - # slplugin.exe failing symbols dump - need to debug, might have to do with updated version of google breakpad - # set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX} slplugin.exe") - set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX}") - set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}") - set(VIEWER_COPY_MANIFEST copy_w_viewer_manifest) - endif (WINDOWS) - if (DARWIN) - list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") - # *TODO: Generate these search dirs in the cmake files related to each binary. - list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/llplugin/slplugin/${CMAKE_CFG_INTDIR}") - list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/mac_crash_logger/${CMAKE_CFG_INTDIR}") - list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/gstreamer010/${CMAKE_CFG_INTDIR}") - set(VIEWER_EXE_GLOBS "'${product}' SLPlugin mac-crash-logger") - set(VIEWER_EXE_GLOBS "'${product}' mac-crash-logger") - set(VIEWER_LIB_GLOB "*.dylib") - endif (DARWIN) - if (LINUX) - list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/packaged") - set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin SLPlugin") - set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin") - set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}*") - set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest) - endif (LINUX) - - if(CMAKE_CFG_INTDIR STREQUAL ".") - set(LLBUILD_CONFIG ${CMAKE_BUILD_TYPE}) - else(CMAKE_CFG_INTDIR STREQUAL ".") - # set LLBUILD_CONFIG to be a shell variable evaluated at build time - # reflecting the configuration we are currently building. - set(LLBUILD_CONFIG ${CMAKE_CFG_INTDIR}) - endif(CMAKE_CFG_INTDIR STREQUAL ".") - add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}" - COMMAND "${PYTHON_EXECUTABLE}" - ARGS - "${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py" - "${LLBUILD_CONFIG}" - "${SYMBOL_SEARCH_DIRS}" - "${VIEWER_EXE_GLOBS}" - "${VIEWER_LIB_GLOB}" - "${AUTOBUILD_INSTALL_DIR}/bin/dump_syms" - "${VIEWER_SYMBOL_FILE}" - DEPENDS generate_breakpad_symbols.py - VERBATIM) - - add_custom_target(generate_symbols DEPENDS "${VIEWER_SYMBOL_FILE}" ${VIEWER_BINARY_NAME} "${VIEWER_COPY_MANIFEST}") - add_dependencies(generate_symbols ${VIEWER_BINARY_NAME}) - if (WINDOWS OR LINUX) - add_dependencies(generate_symbols "${VIEWER_COPY_MANIFEST}") - endif (WINDOWS OR LINUX) - - else (NOT BUGSPLAT_DB) - # BugSplat symbol-file generation - if (WINDOWS) - # Just pack up a tarball containing only the .pdb file for the - # executable. Because we intend to use cygwin tar, we must render - # VIEWER_SYMBOL_FILE in cygwin path syntax. - execute_process(COMMAND "cygpath" "-u" "${VIEWER_SYMBOL_FILE}" - OUTPUT_VARIABLE VIEWER_SYMBOL_FILE_CYGWIN - OUTPUT_STRIP_TRAILING_WHITESPACE) - execute_process(COMMAND "cygpath" "-u" "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" - OUTPUT_VARIABLE PARENT_DIRECTORY_CYGWIN - OUTPUT_STRIP_TRAILING_WHITESPACE) - add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}" - # Use of 'tar ...j' here assumes VIEWER_SYMBOL_FILE endswith .tar.bz2; - # testing a string suffix is painful enough in CMake language that - # we'll continue assuming it until forced to generalize. - COMMAND "tar" - ARGS - "cjf" - "${VIEWER_SYMBOL_FILE_CYGWIN}" - "-C" - "${PARENT_DIRECTORY_CYGWIN}" - "secondlife-bin.pdb" - DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-bin.pdb" - COMMENT "Packing viewer PDB into ${VIEWER_SYMBOL_FILE_CYGWIN}" - ) - add_custom_target(generate_symbols DEPENDS "${VIEWER_SYMBOL_FILE}" ${VIEWER_BINARY_NAME}) - add_dependencies(generate_symbols ${VIEWER_BINARY_NAME}) - endif (WINDOWS) - if (DARWIN) - # Have to run dsymutil first, then pack up the resulting .dSYM directory - add_custom_command(OUTPUT "${VIEWER_APP_DSYM}" - COMMAND "dsymutil" - ARGS - ${VIEWER_APP_EXE} - COMMENT "Generating ${VIEWER_APP_DSYM}" - ) - add_custom_target(dsym_generate DEPENDS "${VIEWER_APP_DSYM}") - add_dependencies(dsym_generate ${VIEWER_BINARY_NAME}) - add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}" - # See above comments about "tar ...j" - COMMAND "tar" - ARGS - "cjf" - "${VIEWER_SYMBOL_FILE}" - "-C" - "${VIEWER_APP_DSYM}/.." - "${product}.dSYM" - DEPENDS "${VIEWER_APP_DSYM}" - COMMENT "Packing dSYM into ${VIEWER_SYMBOL_FILE}" - ) - add_custom_target(dsym_tarball DEPENDS "${VIEWER_SYMBOL_FILE}") - add_dependencies(dsym_tarball dsym_generate) - add_custom_command(OUTPUT "${VIEWER_APP_XCARCHIVE}" - COMMAND "zip" - ARGS - "-r" - "${VIEWER_APP_XCARCHIVE}" - "." - WORKING_DIRECTORY "${VIEWER_APP_DSYM}/.." - DEPENDS "${VIEWER_APP_DSYM}" - COMMENT "Generating xcarchive.zip for upload to BugSplat" - ) - add_custom_target(dsym_xcarchive DEPENDS "${VIEWER_APP_XCARCHIVE}") - add_dependencies(dsym_xcarchive dsym_generate) - # Have to create a stamp file, and depend on it, to force CMake to run - # the cleanup step. - add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/dsym.stamp" - COMMAND rm -rf "${VIEWER_APP_DSYM}" - COMMAND touch "${CMAKE_CURRENT_BINARY_DIR}/dsym.stamp" - DEPENDS "${VIEWER_SYMBOL_FILE}" "${VIEWER_APP_XCARCHIVE}" - COMMENT "Cleaning up dSYM" - ) - add_custom_target(generate_symbols DEPENDS - "${VIEWER_APP_DSYM}" - "${VIEWER_SYMBOL_FILE}" - "${VIEWER_APP_XCARCHIVE}" - "${CMAKE_CURRENT_BINARY_DIR}/dsym.stamp" - ) - add_dependencies(generate_symbols dsym_tarball dsym_xcarchive) - endif (DARWIN) - if (LINUX) - # TBD - endif (LINUX) - endif (NOT BUGSPLAT_DB) - - # for both BUGSPLAT_DB and Breakpad - add_dependencies(llpackage generate_symbols) -endif () +if (PACKAGE) + set(SYMBOL_SEARCH_DIRS "") + # Note that the path to VIEWER_SYMBOL_FILE must match that in ../../build.sh + if (WINDOWS) + list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") + set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-windows-$ENV{AUTOBUILD_ADDRSIZE}.tar.bz2") + # slplugin.exe failing symbols dump - need to debug, might have to do with updated version of google breakpad + # set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX} slplugin.exe") + set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX}") + set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}") + set(VIEWER_COPY_MANIFEST copy_w_viewer_manifest) + endif (WINDOWS) + if (DARWIN) + list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") + # *TODO: Generate these search dirs in the cmake files related to each binary. + list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/llplugin/slplugin/${CMAKE_CFG_INTDIR}") + list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/mac_crash_logger/${CMAKE_CFG_INTDIR}") + list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/gstreamer010/${CMAKE_CFG_INTDIR}") + set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-darwin-$ENV{AUTOBUILD_ADDRSIZE}.tar.bz2") + set(VIEWER_EXE_GLOBS "'Second Life' SLPlugin mac-crash-logger") + set(VIEWER_EXE_GLOBS "'Second Life' mac-crash-logger") + set(VIEWER_LIB_GLOB "*.dylib") + endif (DARWIN) + if (LINUX) + list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/packaged") + set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-linux-$ENV{AUTOBUILD_ADDRSIZE}.tar.bz2") + set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin SLPlugin") + set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin") + set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}*") + set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest) + endif (LINUX) + + if(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) + if(CMAKE_CFG_INTDIR STREQUAL ".") + set(LLBUILD_CONFIG ${CMAKE_BUILD_TYPE}) + else(CMAKE_CFG_INTDIR STREQUAL ".") + # set LLBUILD_CONFIG to be a shell variable evaluated at build time + # reflecting the configuration we are currently building. + set(LLBUILD_CONFIG ${CMAKE_CFG_INTDIR}) + endif(CMAKE_CFG_INTDIR STREQUAL ".") + add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}" + COMMAND "${PYTHON_EXECUTABLE}" + ARGS + "${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py" + "${LLBUILD_CONFIG}" + "${SYMBOL_SEARCH_DIRS}" + "${VIEWER_EXE_GLOBS}" + "${VIEWER_LIB_GLOB}" + "${AUTOBUILD_INSTALL_DIR}/bin/dump_syms" + "${VIEWER_SYMBOL_FILE}" + DEPENDS generate_breakpad_symbols.py + VERBATIM) + + add_custom_target(generate_breakpad_symbols DEPENDS "${VIEWER_SYMBOL_FILE}" "${VIEWER_BINARY_NAME}" "${VIEWER_COPY_MANIFEST}") + add_dependencies(generate_breakpad_symbols "${VIEWER_BINARY_NAME}") + if (WINDOWS OR LINUX) + add_dependencies(generate_breakpad_symbols "${VIEWER_COPY_MANIFEST}") + endif (WINDOWS OR LINUX) + add_dependencies(llpackage generate_breakpad_symbols) + endif(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) +endif (PACKAGE) if (LL_TESTS) # To add a viewer unit test, just add the test .cpp file below 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 @@ <key>CFBundleDevelopmentRegion</key> <string>English</string> <key>CFBundleExecutable</key> - <string>${MACOSX_WRAPPER_EXECUTABLE_NAME}</string> + <string>${MACOSX_EXECUTABLE_NAME}</string> <key>CFBundleGetInfoString</key> <string>${MACOSX_BUNDLE_INFO_STRING}</string> <key>CFBundleIconFile</key> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 8e8cce5787..ca13c60768 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -4316,6 +4316,17 @@ <key>Value</key> <real>96.0</real> </map> + <key>ForceAddressSize</key> + <map> + <key>Comment</key> + <string>Force Windows update to 32-bit or 64-bit viewer.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>0</integer> + </map> <key>ForceAssetFail</key> <map> <key>Comment</key> @@ -16172,7 +16183,7 @@ <string>if true, disables running the GPU benchmark at startup (default to class 1)</string> <key>Persist</key> - <integer>0</integer> + <integer>1</integer> <key>Type</key> <string>Boolean</string> <key>Value</key> diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index 14c8dba39f..76187b49a5 100644 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -299,7 +299,7 @@ StrCpy $SHORTCUT_LANG_PARAM "--set InstallLanguage $(LanguageCode)" CreateDirectory "$SMPROGRAMS\$INSTSHORTCUT"
SetOutPath "$INSTDIR"
CreateShortCut "$SMPROGRAMS\$INSTSHORTCUT\$INSTSHORTCUT.lnk" \
- "$INSTDIR\$INSTEXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
+ "$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
WriteINIStr "$SMPROGRAMS\$INSTSHORTCUT\SL Create Account.url" \
@@ -317,9 +317,9 @@ CreateShortCut "$SMPROGRAMS\$INSTSHORTCUT\Uninstall $INSTSHORTCUT.lnk" \ # Other shortcuts
SetOutPath "$INSTDIR"
CreateShortCut "$DESKTOP\$INSTSHORTCUT.lnk" \
- "$INSTDIR\$INSTEXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
+ "$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
CreateShortCut "$INSTDIR\$INSTSHORTCUT.lnk" \
- "$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"' ''
@@ -327,7 +327,7 @@ CreateShortCut "$INSTDIR\Uninstall $INSTSHORTCUT.lnk" \ WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "" "$INSTDIR"
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Version" "${VERSION_LONG}"
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Shortcut" "$INSTSHORTCUT"
-WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Exe" "$INSTEXE"
+WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Exe" "$VIEWER_EXE"
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "Publisher" "Linden Research, Inc."
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "URLInfoAbout" "http://secondlife.com/whatis/"
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "URLUpdateInfo" "http://secondlife.com/support/downloads/"
@@ -338,10 +338,10 @@ WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninst WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "EstimatedSize" "0x0001D500" # ~117 MB
# 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
# Write URL registry info
WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}" "(default)" "URL:Second Life"
@@ -358,9 +358,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
-WriteRegStr HKEY_CLASSES_ROOT "Applications\$INSTEXE" "IsHostApp" ""
-WriteRegStr HKEY_CLASSES_ROOT "Applications\${VIEWER_EXE}" "NoStartPage" ""
+WriteRegStr HKEY_CLASSES_ROOT "Applications\$VIEWER_EXE" "IsHostApp" ""
+##WriteRegStr HKEY_CLASSES_ROOT "Applications\${VIEWER_EXE}" "NoStartPage" ""
# Write out uninstaller
WriteUninstaller "$INSTDIR\uninst.exe"
@@ -398,8 +397,8 @@ Call un.CloseSecondLife DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG"
DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG"
# BUG-2707 Remove entry that disabled SEHOP
-DeleteRegKey HKEY_LOCAL_MACHINE "Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\$INSTEXE"
-DeleteRegKey HKEY_CLASSES_ROOT "Applications\$INSTEXE"
+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
@@ -537,6 +536,7 @@ Function RemoveProgFilesOnInst # Remove old SecondLife.exe to invalidate any old shortcuts to it that may be in non-standard locations. See MAINT-3575
Delete "$INSTDIR\$INSTEXE"
+Delete "$INSTDIR\$VIEWER_EXE"
# Remove old shader files first so fallbacks will work. See DEV-5663
RMDir /r "$INSTDIR\app_settings\shaders"
@@ -673,7 +673,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.
Push $R0
Push $0
;; MAINT-7812: Only write nsis.winstall file with /marker switch
@@ -694,8 +694,21 @@ Call CheckWindowsServPack # Warn if not on the latest SP before asking to launc Pop $R0
Push $R0 # Option value, unused#
StrCmp $SKIP_AUTORUN "true" +2;
-# Assumes SetOutPath $INSTDIR
- Exec '"$WINDIR\explorer.exe" "$INSTDIR\$INSTSHORTCUT.lnk"'
+ # 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.
+ Exec '"$INSTDIR\$INSTEXE" precheck "$INSTDIR\$VIEWER_EXE" $SHORTCUT_LANG_PARAM'
Pop $R0
#
FunctionEnd
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index dd82aa735f..56e79bed74 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1092,26 +1092,6 @@ bool LLAppViewer::init() } } -// don't nag developers who need to run the executable directly -#if LL_RELEASE_FOR_DOWNLOAD - // 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()) { @@ -1159,6 +1139,36 @@ bool LLAppViewer::init() gGLActive = FALSE; + 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")); @@ -3930,12 +3940,6 @@ void LLAppViewer::requestQuit() gAgentAvatarp->updateAvatarRezMetrics(true); // force a last packet to be sent. } - // Try to send last batch of avatar rez metrics. - 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 bc93fa2c20..126c6be388 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -253,14 +253,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); @@ -276,6 +274,14 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event) // Login has failed. // Figure out why and respond... LLSD response = event["data"]; + LLSD updater = response["updater"]; + + // Always provide a response to the updater, if in fact the updater + // contacted us, if in fact the ping contains a 'reply' key. Most code + // paths tell it not to proceed with updating. + ResponsePtr resp(std::make_shared<LLEventAPI::Response> + (LLSDMap("update", false), updater)); + std::string reason_response = response["reason"].asString(); std::string message_response = response["message"].asString(); LL_DEBUGS("LLLogin") << "reason " << reason_response @@ -328,17 +334,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); - 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" @@ -361,6 +394,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(); @@ -420,7 +466,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 651ad10afb..b759b43474 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 <boost/scoped_ptr.hpp> #include <boost/function.hpp> +#include <memory> // std::shared_ptr #include "llsecapi.h" class LLLogin; class LLEventStream; @@ -68,6 +70,7 @@ public: LLNotificationsInterface& getNotificationsInterface() const { return *mNotifications; } private: + typedef std::shared_ptr<LLEventAPI::Response> ResponsePtr; void constructAuthParams(LLPointer<LLCredential> user_credentials); void updateApp(bool mandatory, const std::string& message); bool updateDialogCallback(const LLSD& notification, const LLSD& response); @@ -77,7 +80,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 cc02642203..b44d996558 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -480,8 +480,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/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index b039afa734..dd35ed4c71 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -770,14 +770,13 @@ 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 - exe_path += "SLVoice.exe"; + gDirUtilp->append(exe_path, "SLVoice.exe"); #elif LL_DARWIN - exe_path += "../Resources/SLVoice"; + gDirUtilp->append(exe_path, "SLVoice"); #else - exe_path += "SLVoice"; + gDirUtilp->append(exe_path, "SLVoice"); #endif // See if the vivox executable exists llstat s; diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 9eaa5330c3..e2859603e0 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -3841,7 +3841,6 @@ Finished download of raw terrain file to: name="RequiredUpdate" type="alertmodal"> Version [VERSION] is required for login. -This should have been updated for you but apparently was not. Please download from https://secondlife.com/support/downloads/ <tag>confirm</tag> <usetemplate @@ -3851,6 +3850,44 @@ Please download from https://secondlife.com/support/downloads/ <notification icon="alertmodal.tga" + name="PauseForUpdate" + type="alertmodal"> +Version [VERSION] is required for login. +Click OK to download and install. + <tag>confirm</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="OptionalUpdateReady" + type="alertmodal"> +Version [VERSION] has been downloaded and is ready to install. +Click OK to install. + <tag>confirm</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="PromptOptionalUpdate" + type="alertmodal"> +Version [VERSION] has been downloaded and is ready to install. +Proceed? + <tag>confirm</tag> + <usetemplate + canceltext="Not Now" + name="yesnocancelbuttons" + notext="Skip" + yestext="Install"/> + </notification> + + <notification + icon="alertmodal.tga" name="LoginFailedUnknown" type="alertmodal"> Sorry, login failed for an unrecognized reason. diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 464f7aa3e9..57da87a3ee 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -26,20 +26,19 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA $/LicenseInfo$ """ -import errno -import json +import sys import os import os.path +import shutil +import errno +import json import plistlib import random import re -import shutil import stat import subprocess -import sys import tarfile import time -import zipfile viewer_dir = os.path.dirname(__file__) # Add indra/lib/python to our path so we don't have to muck with PYTHONPATH. @@ -64,7 +63,7 @@ class ViewerManifest(LLManifest): self.path(src="../../etc/message.xml", dst="app_settings/message.xml") if self.is_packaging_viewer(): - with self.prefix(src_dst="app_settings"): + with self.prefix(src="app_settings"): self.exclude("logcontrol.xml") self.exclude("logcontrol-dev.xml") self.path("*.ini") @@ -86,7 +85,7 @@ class ViewerManifest(LLManifest): # ... and the included spell checking dictionaries pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') - with self.prefix(src=pkgdir): + with self.prefix(src=pkgdir,dst=""): self.path("dictionaries") # include the extracted packages information (see BuildPackagesInfo.cmake) @@ -108,18 +107,17 @@ class ViewerManifest(LLManifest): Type='String', Value='')) settings_install = {} - sourceid = self.args.get('sourceid') - if sourceid: + if 'sourceid' in self.args and self.args['sourceid']: settings_install['sourceid'] = settings_template['sourceid'].copy() - settings_install['sourceid']['Value'] = sourceid - print "Set sourceid in settings_install.xml to '%s'" % sourceid + settings_install['sourceid']['Value'] = self.args['sourceid'] + print "Set sourceid in settings_install.xml to '%s'" % self.args['sourceid'] - if self.args.get('channel_suffix'): + if 'channel_suffix' in self.args and self.args['channel_suffix']: settings_install['CmdLineChannel'] = settings_template['CmdLineChannel'].copy() settings_install['CmdLineChannel']['Value'] = self.channel_with_pkg_suffix() print "Set CmdLineChannel in settings_install.xml to '%s'" % self.channel_with_pkg_suffix() - if self.args.get('grid'): + if 'grid' in self.args and self.args['grid']: settings_install['CmdLineGridChoice'] = settings_template['CmdLineGridChoice'].copy() settings_install['CmdLineGridChoice']['Value'] = self.grid() print "Set CmdLineGridChoice in settings_install.xml to '%s'" % self.grid() @@ -131,20 +129,20 @@ class ViewerManifest(LLManifest): src="environment") - with self.prefix(src_dst="character"): + with self.prefix(src="character"): self.path("*.llm") self.path("*.xml") self.path("*.tga") # Include our fonts - with self.prefix(src_dst="fonts"): + with self.prefix(src="fonts"): self.path("*.ttf") self.path("*.txt") # skins - with self.prefix(src_dst="skins"): + with self.prefix(src="skins"): # include the entire textures directory recursively - with self.prefix(src_dst="*/textures"): + with self.prefix(src="*/textures"): self.path("*/*.tga") self.path("*/*.j2c") self.path("*/*.jpg") @@ -172,7 +170,7 @@ class ViewerManifest(LLManifest): # local_assets dir (for pre-cached textures) - with self.prefix(src_dst="local_assets"): + with self.prefix(src="local_assets"): self.path("*.j2c") self.path("*.tga") @@ -188,10 +186,6 @@ class ViewerManifest(LLManifest): "Address Size":self.address_size, "Update Service":"https://update.secondlife.com/update", } - # Only store this if it's both present and non-empty - bugsplat_db = self.args.get('bugsplat') - if bugsplat_db: - build_data_dict["BugSplat DB"] = bugsplat_db build_data_dict = self.finish_build_data_dict(build_data_dict) with open(os.path.join(os.pardir,'build_data.json'), 'w') as build_data_handle: json.dump(build_data_dict,build_data_handle) @@ -212,9 +206,8 @@ class ViewerManifest(LLManifest): def channel_with_pkg_suffix(self): fullchannel=self.channel() - channel_suffix = self.args.get('channel_suffix') - if channel_suffix: - fullchannel+=' '+channel_suffix + if 'channel_suffix' in self.args and self.args['channel_suffix']: + fullchannel+=' '+self.args['channel_suffix'] return fullchannel def channel_variant(self): @@ -222,7 +215,8 @@ class ViewerManifest(LLManifest): return self.channel().replace(CHANNEL_VENDOR_BASE, "").strip() def channel_type(self): # returns 'release', 'beta', 'project', or 'test' - channel_qualifier=self.channel_variant().lower() + global CHANNEL_VENDOR_BASE + channel_qualifier=self.channel().replace(CHANNEL_VENDOR_BASE, "").lower().strip() if channel_qualifier.startswith('release'): channel_type='release' elif channel_qualifier.startswith('beta'): @@ -240,12 +234,11 @@ class ViewerManifest(LLManifest): if self.channel_type() == 'release': suffix=suffix.replace('Release', '').strip() # for the base release viewer, suffix will now be null - for any other, append what remains - if suffix: - suffix = "_".join([''] + suffix.split()) + if len(suffix) > 0: + suffix = "_"+ ("_".join(suffix.split())) # the additional_packages mechanism adds more to the installer name (but not to the app name itself) - # ''.split() produces empty list, so suffix only changes if - # channel_suffix is non-empty - suffix = "_".join([suffix] + self.args.get('channel_suffix', '').split()) + if 'channel_suffix' in self.args and self.args['channel_suffix']: + suffix+='_'+("_".join(self.args['channel_suffix'].split())) return suffix def installer_base_name(self): @@ -477,7 +470,7 @@ class WindowsManifest(ViewerManifest): pass except NoMatchingAssemblyException as err: pass - + self.ccopy(src,dst) else: raise Exception("Directories are not supported by test_CRT_and_copy_action()") @@ -495,24 +488,19 @@ class WindowsManifest(ViewerManifest): # Find secondlife-bin.exe in the 'configuration' dir, then rename it to the result of final_exe. self.path(src='%s/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe()) - with self.prefix(src=os.path.join(pkgdir, "VMP")): + with self.prefix(src=os.path.join(pkgdir, "VMP"), dst=""): # include the compiled launcher scripts so that it gets included in the file_list - self.path('SL_Launcher.exe') + self.path('updater.exe') #IUM is not normally executed directly, just imported. No exe needed. self.path("InstallerUserMessage.py") - with self.prefix(dst="vmp_icons"): - with self.prefix(src=self.icon_path()): - self.path("secondlife.ico") - #VMP Tkinter icons - with self.prefix(src="vmp_icons"): - self.path("*.png") - self.path("*.gif") + with self.prefix(src=self.icon_path(), dst="vmp_icons"): + self.path("secondlife.ico") - #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") + #VMP Tkinter icons + with self.prefix("vmp_icons"): + self.path("*.png") + self.path("*.gif") # Plugin host application self.path2basename(os.path.join(os.pardir, @@ -520,8 +508,8 @@ class WindowsManifest(ViewerManifest): "slplugin.exe") # Get shared libs from the shared libs staging directory - with self.prefix(src=os.path.join(self.args['build'], os.pardir, - 'sharedlibs', self.args['configuration'])): + with self.prefix(src=os.path.join(os.pardir, 'sharedlibs', self.args['configuration']), + dst=""): # Get llcommon and deps. If missing assume static linkage and continue. try: @@ -587,17 +575,6 @@ class WindowsManifest(ViewerManifest): # Hunspell self.path("libhunspell.dll") - # BugSplat - if self.args.get('bugsplat'): - if(self.address_size == 64): - self.path("BsSndRpt64.exe") - self.path("BugSplat64.dll") - self.path("BugSplatRc64.dll") - else: - self.path("BsSndRpt.exe") - self.path("BugSplat.dll") - self.path("BugSplatRc.dll") - # For google-perftools tcmalloc allocator. try: if self.args['configuration'].lower() == 'debug': @@ -607,116 +584,114 @@ class WindowsManifest(ViewerManifest): except: print "Skipping libtcmalloc_minimal.dll" + self.path(src="licenses-win32.txt", dst="licenses.txt") self.path("featuretable.txt") - with self.prefix(src=pkgdir): + with self.prefix(src=pkgdir,dst=""): self.path("ca-bundle.crt") # Media plugins - CEF - with self.prefix(dst="llplugin"): - with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'media_plugins')): - with self.prefix(src=os.path.join('cef', self.args['configuration'])): - self.path("media_plugin_cef.dll") - - # Media plugins - LibVLC - with self.prefix(src=os.path.join('libvlc', self.args['configuration'])): - self.path("media_plugin_libvlc.dll") - - # Media plugins - Example (useful for debugging - not shipped with release viewer) - if self.channel_type() != 'release': - with self.prefix(src=os.path.join('example', self.args['configuration'])): - self.path("media_plugin_example.dll") - - # CEF runtime files - debug - # CEF runtime files - not debug (release, relwithdebinfo etc.) - config = 'debug' if self.args['configuration'].lower() == 'debug' else 'release' - with self.prefix(src=os.path.join(pkgdir, 'bin', config)): - self.path("chrome_elf.dll") - self.path("d3dcompiler_43.dll") - self.path("d3dcompiler_47.dll") - self.path("libcef.dll") - self.path("libEGL.dll") - self.path("libGLESv2.dll") - self.path("dullahan_host.exe") - self.path("natives_blob.bin") - self.path("snapshot_blob.bin") - self.path("widevinecdmadapter.dll") - - # MSVC DLLs needed for CEF and have to be in same directory as plugin - with self.prefix(src=os.path.join(self.args['build'], os.pardir, - 'sharedlibs', 'Release')): - self.path("msvcp120.dll") - self.path("msvcr120.dll") - - # CEF files common to all configurations - with self.prefix(src=os.path.join(pkgdir, 'resources')): - self.path("cef.pak") - self.path("cef_100_percent.pak") - self.path("cef_200_percent.pak") - self.path("cef_extensions.pak") - self.path("devtools_resources.pak") - self.path("icudtl.dat") - - with self.prefix(src=os.path.join(pkgdir, 'resources', 'locales'), dst='locales'): - self.path("am.pak") - self.path("ar.pak") - self.path("bg.pak") - self.path("bn.pak") - self.path("ca.pak") - self.path("cs.pak") - self.path("da.pak") - self.path("de.pak") - self.path("el.pak") - self.path("en-GB.pak") - self.path("en-US.pak") - self.path("es-419.pak") - self.path("es.pak") - self.path("et.pak") - self.path("fa.pak") - self.path("fi.pak") - self.path("fil.pak") - self.path("fr.pak") - self.path("gu.pak") - self.path("he.pak") - self.path("hi.pak") - self.path("hr.pak") - self.path("hu.pak") - self.path("id.pak") - self.path("it.pak") - self.path("ja.pak") - self.path("kn.pak") - self.path("ko.pak") - self.path("lt.pak") - self.path("lv.pak") - self.path("ml.pak") - self.path("mr.pak") - self.path("ms.pak") - self.path("nb.pak") - self.path("nl.pak") - self.path("pl.pak") - self.path("pt-BR.pak") - self.path("pt-PT.pak") - self.path("ro.pak") - self.path("ru.pak") - self.path("sk.pak") - self.path("sl.pak") - self.path("sr.pak") - self.path("sv.pak") - self.path("sw.pak") - self.path("ta.pak") - self.path("te.pak") - self.path("th.pak") - self.path("tr.pak") - self.path("uk.pak") - self.path("vi.pak") - self.path("zh-CN.pak") - self.path("zh-TW.pak") - - with self.prefix(src=os.path.join(pkgdir, 'bin', 'release')): - self.path("libvlc.dll") - self.path("libvlccore.dll") - self.path("plugins/") + with self.prefix(src='../media_plugins/cef/%s' % self.args['configuration'], dst="llplugin"): + self.path("media_plugin_cef.dll") + + # Media plugins - LibVLC + with self.prefix(src='../media_plugins/libvlc/%s' % self.args['configuration'], dst="llplugin"): + self.path("media_plugin_libvlc.dll") + + # Media plugins - Example (useful for debugging - not shipped with release viewer) + if self.channel_type() != 'release': + with self.prefix(src='../media_plugins/example/%s' % self.args['configuration'], dst="llplugin"): + self.path("media_plugin_example.dll") + + # CEF runtime files - debug + # CEF runtime files - not debug (release, relwithdebinfo etc.) + config = 'debug' if self.args['configuration'].lower() == 'debug' else 'release' + with self.prefix(src=os.path.join(pkgdir, 'bin', config), dst="llplugin"): + self.path("chrome_elf.dll") + self.path("d3dcompiler_43.dll") + self.path("d3dcompiler_47.dll") + self.path("libcef.dll") + self.path("libEGL.dll") + self.path("libGLESv2.dll") + self.path("dullahan_host.exe") + self.path("natives_blob.bin") + self.path("snapshot_blob.bin") + self.path("widevinecdmadapter.dll") + + # MSVC DLLs needed for CEF and have to be in same directory as plugin + with self.prefix(src=os.path.join(os.pardir, 'sharedlibs', 'Release'), dst="llplugin"): + self.path("msvcp120.dll") + self.path("msvcr120.dll") + + # CEF files common to all configurations + with self.prefix(src=os.path.join(pkgdir, 'resources'), dst="llplugin"): + self.path("cef.pak") + self.path("cef_100_percent.pak") + self.path("cef_200_percent.pak") + self.path("cef_extensions.pak") + self.path("devtools_resources.pak") + self.path("icudtl.dat") + + with self.prefix(src=os.path.join(pkgdir, 'resources', 'locales'), dst=os.path.join('llplugin', 'locales')): + self.path("am.pak") + self.path("ar.pak") + self.path("bg.pak") + self.path("bn.pak") + self.path("ca.pak") + self.path("cs.pak") + self.path("da.pak") + self.path("de.pak") + self.path("el.pak") + self.path("en-GB.pak") + self.path("en-US.pak") + self.path("es-419.pak") + self.path("es.pak") + self.path("et.pak") + self.path("fa.pak") + self.path("fi.pak") + self.path("fil.pak") + self.path("fr.pak") + self.path("gu.pak") + self.path("he.pak") + self.path("hi.pak") + self.path("hr.pak") + self.path("hu.pak") + self.path("id.pak") + self.path("it.pak") + self.path("ja.pak") + self.path("kn.pak") + self.path("ko.pak") + self.path("lt.pak") + self.path("lv.pak") + self.path("ml.pak") + self.path("mr.pak") + self.path("ms.pak") + self.path("nb.pak") + self.path("nl.pak") + self.path("pl.pak") + self.path("pt-BR.pak") + self.path("pt-PT.pak") + self.path("ro.pak") + self.path("ru.pak") + self.path("sk.pak") + self.path("sl.pak") + self.path("sr.pak") + self.path("sv.pak") + self.path("sw.pak") + self.path("ta.pak") + self.path("te.pak") + self.path("th.pak") + self.path("tr.pak") + self.path("uk.pak") + self.path("vi.pak") + self.path("zh-CN.pak") + self.path("zh-TW.pak") + + with self.prefix(src=os.path.join(pkgdir, 'bin', 'release'), dst="llplugin"): + self.path("libvlc.dll") + self.path("libvlccore.dll") + self.path("plugins/") # pull in the crash logger and updater from other projects # tag:"crash-logger" here as a cue to the exporter @@ -788,7 +763,7 @@ class WindowsManifest(ViewerManifest): substitution_strings['installer_file'] = installer_file 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" @@ -832,7 +807,7 @@ 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", + "updater.exe", ): self.sign(exe) @@ -899,431 +874,279 @@ class DarwinManifest(ViewerManifest): # darwin requires full app bundle packaging even for debugging. return True - def is_rearranging(self): - # That said, some stuff should still only be performed once. - # Are either of these actions in 'actions'? Is the set intersection - # non-empty? - 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'], "Second Life.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") - - toplevel_MacOS = self.dst_path_of("MacOS") - # the one file in top-level MacOS directory is the trampoline to - # our nested launcher_app - 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]) - - # Make a symlink to a nested app Frameworks directory that doesn't - # yet exist. We shouldn't need this; the only things that need - # Frameworks are nested apps under viewer_app, and they should - # simply find its Contents/Frameworks by relative pathnames. But - # empirically, we do: if we omit this symlink, CEF doesn't work -- - # the login splash screen doesn't even display. SIIIIGH. - # We're passing a path that's already relative, hence symlinkf() - # rather than relsymlinkf(). - self.symlinkf(os.path.join("Resources", viewer_app, "Contents", "Frameworks")) + with self.prefix(src="", dst="Contents"): # everything goes in Contents + # 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) + + with self.prefix(dst="MacOS"): + # NOTE: the -S argument to strip causes it to keep + # enough info for annotated backtraces (i.e. function + # names in the crash log). 'strip' with no arguments + # yields a slightly smaller binary but makes crash + # logs mostly useless. This may be desirable for the + # final release. Or not. + if ("package" in self.args['actions'] or + "unpacked" in self.args['actions']): + self.run_command( + ['strip', '-S', self.dst_path_of('Second Life')]) with self.prefix(dst="Resources"): - # 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) - - # ------------------- nested launcher_app -------------------- - with self.prefix(dst=os.path.join(launcher_app, "Contents")): - # Info.plist is just like top-level one... - Info = plistlib.readPlist(Info_plist) - # except for these replacements: - Info["CFBundleExecutable"] = "SL_Launcher" - Info["CFBundleIconFile"] = launcher_icon - self.put_in_file( - plistlib.writePlistToString(Info), - os.path.basename(Info_plist), - "Info.plist") - - # copy VMP libs to MacOS - with self.prefix(dst="MacOS"): - #this copies over the python wrapper script, - #associated utilities and required libraries, see - #SL-321, SL-322, SL-323 - with self.prefix(src=os.path.join(pkgdir, "VMP")): - 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) - - # 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") - - # -------------------- 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) - - # 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] - - 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]) - - # 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(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) - - if self.args.get('bugsplat'): - self.path2basename(relpkgdir, "BugsplatMac.framework") - - with self.prefix(dst="Resources"): - # defer cross-platform file copies until we're in the right - # nested Resources directory - super(DarwinManifest, self).construct() - - with self.prefix(src=self.icon_path()) : - self.path(viewer_icon) - - with self.prefix(src=relpkgdir): - self.path("libndofdev.dylib") - self.path("libhunspell-1.3.0.dylib") - - with self.prefix(src_dst="cursors_mac"): - self.path("*.tif") - - self.path("licenses-mac.txt", dst="licenses.txt") - self.path("featuretable_mac.txt") - self.path("SecondLife.nib") - - with self.prefix(src=pkgdir): - self.path("ca-bundle.crt") - - self.path("SecondLife.nib") - - # Translations - self.path("English.lproj/language.txt") - self.replace_in(src="English.lproj/InfoPlist.strings", - dst="English.lproj/InfoPlist.strings", - searchdict={'%%VERSION%%':'.'.join(self.args['version'])} - ) - self.path("German.lproj") - self.path("Japanese.lproj") - self.path("Korean.lproj") - self.path("da.lproj") - self.path("es.lproj") - self.path("fr.lproj") - self.path("hu.lproj") - self.path("it.lproj") - self.path("nl.lproj") - self.path("pl.lproj") - self.path("pt.lproj") - self.path("ru.lproj") - self.path("tr.lproj") - self.path("uk.lproj") - self.path("zh-Hans.lproj") - - def path_optional(src, dst): - """ - For a number of our self.path() calls, not only do we want - to deal with the absence of src, we also want to remember - which were present. Return either an empty list (absent) - or a list containing dst (present). Concatenate these - return values to get a list of all libs that are present. - """ - # This was simple before we started needing to pass - # wildcards. Fortunately, self.path() ends up appending a - # (source, dest) pair to self.file_list for every expanded - # file processed. Remember its size before the call. - oldlen = len(self.file_list) - self.path(src, dst) - # The dest appended to self.file_list has been prepended - # with self.get_dst_prefix(). Strip it off again. - added = [os.path.relpath(d, self.get_dst_prefix()) - for s, d in self.file_list[oldlen:]] - if not added: - print "Skipping %s" % dst - return added - - # dylibs is a list of all the .dylib files we expect to need - # in our bundled sub-apps. For each of these we'll create a - # symlink from sub-app/Contents/Resources to the real .dylib. - # Need to get the llcommon dll from any of the build directories as well. - libfile_parent = self.get_dst_prefix() - libfile = "libllcommon.dylib" - dylibs = path_optional(self.find_existing_file(os.path.join(os.pardir, - "llcommon", - self.args['configuration'], - libfile), - os.path.join(relpkgdir, libfile)), - dst=libfile) - - for libfile in ( - "libapr-1.0.dylib", - "libaprutil-1.0.dylib", - "libcollada14dom.dylib", - "libexpat.1.dylib", - "libexception_handler.dylib", - "libGLOD.dylib", - # libnghttp2.dylib is a symlink to - # libnghttp2.major.dylib, which is a symlink to - # libnghttp2.version.dylib. Get all of them. - "libnghttp2.*dylib", - ): - dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile) - - # SLVoice and vivox lols, no symlinks needed - for libfile in ( - 'libortp.dylib', - 'libsndfile.dylib', - 'libvivoxoal.dylib', - 'libvivoxsdk.dylib', - 'libvivoxplatform.dylib', - 'SLVoice', - ): - self.path2basename(relpkgdir, libfile) - - # dylibs that vary based on configuration - if self.args['configuration'].lower() == 'debug': - for libfile in ( - "libfmodexL.dylib", - ): - dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile) - else: - for libfile in ( - "libfmodex.dylib", - ): - dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile) - - # our apps - executable_path = {} - for app_bld_dir, app in ( - ("mac_crash_logger", "mac-crash-logger.app"), - # plugin launcher - (os.path.join("llplugin", "slplugin"), "SLPlugin.app"), - ): - self.path2basename( - os.path.join(os.pardir, app_bld_dir, self.args['configuration']), - app) - executable_path[app] = \ - self.dst_path_of(os.path.join(app, "Contents", "MacOS")) - - # our apps dependencies on shared libs - # for each app, for each dylib we collected in dylibs, - # create a symlink to the real copy of the dylib. - with self.prefix(dst=os.path.join(app, "Contents", "Resources")): - for libfile in dylibs: - self.relsymlinkf(os.path.join(libfile_parent, libfile)) - - # Dullahan helper apps go inside SLPlugin.app - with self.prefix(dst=os.path.join( - "SLPlugin.app", "Contents", "Frameworks")): - - frameworkname = 'Chromium Embedded Framework' - - # This code constructs a relative symlink from the - # target framework folder back to the real CEF framework. - # It needs to be relative so that the symlink still works when - # (as is normal) the user moves the app bundle out of the DMG - # and into the /Applications folder. Note we pass catch=False, - # letting the uncaught exception terminate the process, since - # without this symlink, Second Life web media can't possibly work. - - # It might seem simpler just to symlink Frameworks back to - # the parent of Chromimum Embedded Framework.framework. But - # that would create a symlink cycle, which breaks our - # packaging step. So make a symlink from Chromium Embedded - # Framework.framework to the directory of the same name, which - # is NOT an ancestor of the symlink. - - # from SLPlugin.app/Contents/Frameworks/Chromium Embedded - # Framework.framework back to - # $viewer_app/Contents/Frameworks/Chromium Embedded Framework.framework - SLPlugin_framework = self.relsymlinkf(CEF_framework, catch=False) - - # copy DullahanHelper.app - self.path2basename(relpkgdir, 'DullahanHelper.app') - - # and fix that up with a Frameworks/CEF symlink too - with self.prefix(dst=os.path.join( - 'DullahanHelper.app', 'Contents', 'Frameworks')): - # from Dullahan Helper.app/Contents/Frameworks/Chromium Embedded - # Framework.framework back to - # SLPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework - # Since SLPlugin_framework is itself a - # symlink, don't let relsymlinkf() resolve -- - # explicitly call relpath(symlink=True) and - # create that symlink here. - DullahanHelper_framework = \ - self.symlinkf(self.relpath(SLPlugin_framework, symlink=True), - catch=False) - - # change_command includes install_name_tool, the - # -change subcommand and the old framework rpath - # stamped into the executable. To use it with - # run_command(), we must still append the new - # framework path and the pathname of the - # executable to change. - change_command = [ - 'install_name_tool', '-change', - '@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework'] - - with self.prefix(dst=os.path.join( - 'DullahanHelper.app', 'Contents', 'MacOS')): - # Now self.get_dst_prefix() is, at runtime, - # @executable_path. Locate the helper app - # framework (which is a symlink) from here. - newpath = os.path.join( - '@executable_path', - self.relpath(DullahanHelper_framework, symlink=True), - frameworkname) - # and restamp the DullahanHelper executable - self.run_command( - change_command + - [newpath, self.dst_path_of('DullahanHelper')]) - - # SLPlugin plugins - with self.prefix(dst="llplugin"): - dylibexecutable = 'media_plugin_cef.dylib' - self.path2basename("../media_plugins/cef/" + self.args['configuration'], - dylibexecutable) - - # Do this install_name_tool *after* media plugin is copied over. - # Locate the framework lib executable -- relative to - # SLPlugin.app/Contents/MacOS, which will be our - # @executable_path at runtime! - newpath = os.path.join( - '@executable_path', - self.relpath(SLPlugin_framework, executable_path["SLPlugin.app"], - symlink=True), - frameworkname) - # restamp media_plugin_cef.dylib - self.run_command( - change_command + - [newpath, self.dst_path_of(dylibexecutable)]) - - # copy LibVLC plugin itself - self.path2basename("../media_plugins/libvlc/" + self.args['configuration'], - "media_plugin_libvlc.dylib") - - # copy LibVLC dynamic libraries - with self.prefix(src=relpkgdir, dst="lib"): - self.path( "libvlc*.dylib*" ) - # copy LibVLC plugins folder - with self.prefix(src='plugins'): - self.path( "*.dylib" ) - self.path( "plugins.dat" ) + # defer cross-platform file copies until we're in the + # nested Resources directory + super(DarwinManifest, self).construct() + + # need .icns file referenced by Info.plist + with self.prefix(src=self.icon_path(), dst="") : + self.path("secondlife.icns") + + # Copy in the updater script and helper modules + self.path(src=os.path.join(pkgdir, 'VMP'), dst="updater") + + 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") + + with self.prefix(src=relpkgdir, dst=""): + self.path("libndofdev.dylib") + self.path("libhunspell-1.3.0.dylib") + + with self.prefix("cursors_mac"): + self.path("*.tif") + + self.path("licenses-mac.txt", dst="licenses.txt") + self.path("featuretable_mac.txt") + self.path("SecondLife.nib") + + with self.prefix(src=pkgdir,dst=""): + self.path("ca-bundle.crt") + + self.path("SecondLife.nib") + + # Translations + self.path("English.lproj/language.txt") + self.replace_in(src="English.lproj/InfoPlist.strings", + dst="English.lproj/InfoPlist.strings", + searchdict={'%%VERSION%%':'.'.join(self.args['version'])} + ) + self.path("German.lproj") + self.path("Japanese.lproj") + self.path("Korean.lproj") + self.path("da.lproj") + self.path("es.lproj") + self.path("fr.lproj") + self.path("hu.lproj") + self.path("it.lproj") + self.path("nl.lproj") + self.path("pl.lproj") + self.path("pt.lproj") + self.path("ru.lproj") + self.path("tr.lproj") + self.path("uk.lproj") + self.path("zh-Hans.lproj") + + def path_optional(src, dst): + """ + For a number of our self.path() calls, not only do we want + to deal with the absence of src, we also want to remember + which were present. Return either an empty list (absent) + or a list containing dst (present). Concatenate these + return values to get a list of all libs that are present. + """ + # This was simple before we started needing to pass + # wildcards. Fortunately, self.path() ends up appending a + # (source, dest) pair to self.file_list for every expanded + # file processed. Remember its size before the call. + oldlen = len(self.file_list) + self.path(src, dst) + # The dest appended to self.file_list has been prepended + # with self.get_dst_prefix(). Strip it off again. + added = [os.path.relpath(d, self.get_dst_prefix()) + for s, d in self.file_list[oldlen:]] + if not added: + print "Skipping %s" % dst + return added + + # dylibs is a list of all the .dylib files we expect to need + # in our bundled sub-apps. For each of these we'll create a + # symlink from sub-app/Contents/Resources to the real .dylib. + # Need to get the llcommon dll from any of the build directories as well. + libfile_parent = self.get_dst_prefix() + libfile = "libllcommon.dylib" + dylibs = path_optional(self.find_existing_file(os.path.join(os.pardir, + "llcommon", + self.args['configuration'], + libfile), + os.path.join(relpkgdir, libfile)), + dst=libfile) + + for libfile in ( + "libapr-1.0.dylib", + "libaprutil-1.0.dylib", + "libcollada14dom.dylib", + "libexpat.1.dylib", + "libexception_handler.dylib", + "libGLOD.dylib", + # libnghttp2.dylib is a symlink to + # libnghttp2.major.dylib, which is a symlink to + # libnghttp2.version.dylib. Get all of them. + "libnghttp2.*dylib", + ): + dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile) + + # SLVoice and vivox lols, no symlinks needed + for libfile in ( + 'libortp.dylib', + 'libsndfile.dylib', + 'libvivoxoal.dylib', + 'libvivoxsdk.dylib', + 'libvivoxplatform.dylib', + 'SLVoice', + ): + self.path2basename(relpkgdir, libfile) + + # dylibs that vary based on configuration + if self.args['configuration'].lower() == 'debug': + for libfile in ( + "libfmodexL.dylib", + ): + dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile) + else: + for libfile in ( + "libfmodex.dylib", + ): + dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile) + + # our apps + executable_path = {} + for app_bld_dir, app in (("mac_crash_logger", "mac-crash-logger.app"), + # plugin launcher + (os.path.join("llplugin", "slplugin"), "SLPlugin.app"), + ): + self.path2basename(os.path.join(os.pardir, + app_bld_dir, self.args['configuration']), + app) + executable_path[app] = \ + self.dst_path_of(os.path.join(app, "Contents", "MacOS")) + + # our apps dependencies on shared libs + # for each app, for each dylib we collected in dylibs, + # create a symlink to the real copy of the dylib. + with self.prefix(dst=os.path.join(app, "Contents", "Resources")): + for libfile in dylibs: + self.relsymlinkf(os.path.join(libfile_parent, libfile)) + + # Dullahan helper apps go inside SLPlugin.app + with self.prefix(dst=os.path.join( + "SLPlugin.app", "Contents", "Frameworks")): + + frameworkname = 'Chromium Embedded Framework' + + # This code constructs a relative symlink from the + # target framework folder back to the real CEF framework. + # It needs to be relative so that the symlink still works when + # (as is normal) the user moves the app bundle out of the DMG + # and into the /Applications folder. Note we pass catch=False, + # letting the uncaught exception terminate the process, since + # without this symlink, Second Life web media can't possibly work. + + # It might seem simpler just to symlink Frameworks back to + # the parent of Chromimum Embedded Framework.framework. But + # that would create a symlink cycle, which breaks our + # packaging step. So make a symlink from Chromium Embedded + # Framework.framework to the directory of the same name, which + # is NOT an ancestor of the symlink. + + # from SLPlugin.app/Contents/Frameworks/Chromium Embedded + # Framework.framework back to + # $viewer_app/Contents/Frameworks/Chromium Embedded Framework.framework + SLPlugin_framework = self.relsymlinkf(CEF_framework, catch=False) + + # copy DullahanHelper.app + self.path2basename(relpkgdir, 'DullahanHelper.app') + + # and fix that up with a Frameworks/CEF symlink too + with self.prefix(dst=os.path.join( + 'DullahanHelper.app', 'Contents', 'Frameworks')): + # from Dullahan Helper.app/Contents/Frameworks/Chromium Embedded + # Framework.framework back to + # SLPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework + # Since SLPlugin_framework is itself a + # symlink, don't let relsymlinkf() resolve -- + # explicitly call relpath(symlink=True) and + # create that symlink here. + DullahanHelper_framework = \ + self.symlinkf(self.relpath(SLPlugin_framework, symlink=True), + catch=False) + + # change_command includes install_name_tool, the + # -change subcommand and the old framework rpath + # stamped into the executable. To use it with + # run_command(), we must still append the new + # framework path and the pathname of the + # executable to change. + change_command = [ + 'install_name_tool', '-change', + '@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework'] + + with self.prefix(dst=os.path.join( + 'DullahanHelper.app', 'Contents', 'MacOS')): + # Now self.get_dst_prefix() is, at runtime, + # @executable_path. Locate the helper app + # framework (which is a symlink) from here. + newpath = os.path.join( + '@executable_path', + self.relpath(DullahanHelper_framework, symlink=True), + frameworkname) + # and restamp the DullahanHelper executable + self.run_command( + change_command + + [newpath, self.dst_path_of('DullahanHelper')]) + + # SLPlugin plugins + with self.prefix(dst="llplugin"): + dylibexecutable = 'media_plugin_cef.dylib' + self.path2basename("../media_plugins/cef/" + self.args['configuration'], + dylibexecutable) + + # Do this install_name_tool *after* media plugin is copied over. + # Locate the framework lib executable -- relative to + # SLPlugin.app/Contents/MacOS, which will be our + # @executable_path at runtime! + newpath = os.path.join( + '@executable_path', + self.relpath(SLPlugin_framework, executable_path["SLPlugin.app"], + symlink=True), + frameworkname) + # restamp media_plugin_cef.dylib + self.run_command( + change_command + + [newpath, self.dst_path_of(dylibexecutable)]) + + # copy LibVLC plugin itself + self.path2basename("../media_plugins/libvlc/" + self.args['configuration'], + "media_plugin_libvlc.dylib") + + # copy LibVLC dynamic libraries + with self.prefix(src=relpkgdir, dst="lib"): + self.path( "libvlc*.dylib*" ) + # copy LibVLC plugins folder + with self.prefix(src='plugins', dst=""): + self.path( "*.dylib" ) + self.path( "plugins.dat" ) def package_finish(self): global CHANNEL_VENDOR_BASE @@ -1472,10 +1295,35 @@ open "%s" --args "$@" 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']) - + print 72*'=' + import stat + print app_in_dmg + # Second Life.app + for sub0 in os.listdir(app_in_dmg): + print '--{}'.format(sub0) + path0 = os.path.join(app_in_dmg, sub0) + if os.path.isfile(path0): + # shouldn't be any file here + with open(path0) as inf: + for line in inf: + print ' {}'.format(line.rstrip()) + elif os.path.isdir(path0): + # Contents + for sub1 in os.listdir(path0): + print '----{}'.format(sub1) + path1 = os.path.join(path0, sub1) + if os.path.isfile(path1): + # Info.plist, PkgInfo + with open(path1) as inf: + for line in inf: + print ' {}'.format(line.rstrip()) + elif os.path.isdir(path1): + # Frameworks, MacOS, Resources + for sub2 in os.listdir(path1): + path2 = os.path.join(path1, sub2) + print ' {:04o} {}'.format(stat.S_IMODE(os.stat(path2).st_mode), sub2) + print 72*'=' + self.run_command(['spctl', '-a', '-texec', '-vvvv', app_in_dmg]) finally: # Unmount the image even if exceptions from any of the above @@ -1514,29 +1362,25 @@ class LinuxManifest(ViewerManifest): debpkgdir = os.path.join(pkgdir, "lib", "debug") self.path("licenses-linux.txt","licenses.txt") - with self.prefix("linux_tools"): + with self.prefix("linux_tools", dst=""): self.path("client-readme.txt","README-linux.txt") self.path("client-readme-voice.txt","README-linux-voice.txt") self.path("client-readme-joystick.txt","README-linux-joystick.txt") self.path("wrapper.sh","secondlife") - with self.prefix(dst="etc"): + with self.prefix(src="", dst="etc"): self.path("handle_secondlifeprotocol.sh") self.path("register_secondlifeprotocol.sh") self.path("refresh_desktop_app_entry.sh") self.path("launch_url.sh") self.path("install.sh") - with self.prefix(dst="bin"): + with self.prefix(src="", dst="bin"): self.path("secondlife-bin","do-not-directly-run-secondlife-bin") self.path("../linux_crash_logger/linux-crash-logger","linux-crash-logger.bin") self.path2basename("../llplugin/slplugin", "SLPlugin") #this copies over the python wrapper script, associated utilities and required libraries, see SL-321, SL-322 and SL-323 - with self.prefix(src="../viewer_components/manager"): - self.path("SL_Launcher") + with self.prefix(src="../viewer_components/manager", dst=""): self.path("*.py") - with self.prefix(src=os.path.join("lib", "python", "llbase"), dst="llbase"): - self.path("*.py") - self.path("_cllsd.so") # recurses, packaged again self.path("res-sdl") @@ -1544,9 +1388,9 @@ class LinuxManifest(ViewerManifest): # Get the icons based on the channel type icon_path = self.icon_path() print "DEBUG: icon_path '%s'" % icon_path - with self.prefix(src=icon_path) : + with self.prefix(src=icon_path, dst="") : self.path("secondlife_256.png","secondlife_icon.png") - with self.prefix(dst="res-sdl") : + with self.prefix(src="",dst="res-sdl") : self.path("secondlife_256.BMP","ll_icon.BMP") # plugins @@ -1568,7 +1412,7 @@ class LinuxManifest(ViewerManifest): self.path("featuretable_linux.txt") - with self.prefix(src=pkgdir): + with self.prefix(src=pkgdir,dst=""): self.path("ca-bundle.crt") def package_finish(self): @@ -1611,7 +1455,7 @@ class LinuxManifest(ViewerManifest): self.run_command( ["find"] + [os.path.join(self.get_dst_prefix(), dir) for dir in ('bin', 'lib')] + - ['-type', 'f', '!', '-name', '*.py', '!', '-name', 'SL_Launcher', + ['-type', 'f', '!', '-name', '*.py', '!', '-name', 'update_install', '-exec', 'strip', '-S', '{}', ';']) class Linux_i686_Manifest(LinuxManifest): @@ -1624,7 +1468,7 @@ class Linux_i686_Manifest(LinuxManifest): relpkgdir = os.path.join(pkgdir, "lib", "release") debpkgdir = os.path.join(pkgdir, "lib", "debug") - with self.prefix(src=relpkgdir, dst="lib"): + with self.prefix(relpkgdir, dst="lib"): self.path("libapr-1.so") self.path("libapr-1.so.0") self.path("libapr-1.so.0.4.5") @@ -1710,8 +1554,4 @@ class Linux_x86_64_Manifest(LinuxManifest): ################################################################ if __name__ == "__main__": - extra_arguments = [ - dict(name='bugsplat', description="""BugSplat database to which to post crashes, - if BugSplat crash reporting is desired""", default=''), - ] - main(extra=extra_arguments) + main() diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp index c767d52c7b..9193d32b49 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,44 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params) } else { - sendProgressEvent("offline", "fail.login", mAuthResponse["responses"]); + // 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. + 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); } return; // Done! } @@ -249,10 +295,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"]; |