");
@@ -160,12 +161,12 @@ void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, LLSD
LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
- std::string user_agent = llformat("%s %d.%d.%d (%d)",
- LLVersionInfo::instance().getChannel().c_str(),
- LLVersionInfo::instance().getMajor(),
- LLVersionInfo::instance().getMinor(),
- LLVersionInfo::instance().getPatch(),
- LLVersionInfo::instance().getBuild());
+ std::string user_agent = stringize(
+ LLVersionInfo::instance().getChannel(), ' ',
+ LLVersionInfo::instance().getMajor(), '.',
+ LLVersionInfo::instance().getMinor(), '.',
+ LLVersionInfo::instance().getPatch(), " (",
+ LLVersionInfo::instance().getBuild(), ')');
initHttpHeader(httpHeaders, user_agent, key);
@@ -215,12 +216,12 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s
LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
- std::string user_agent = llformat("%s %d.%d.%d (%d)",
- LLVersionInfo::instance().getChannel().c_str(),
- LLVersionInfo::instance().getMajor(),
- LLVersionInfo::instance().getMinor(),
- LLVersionInfo::instance().getPatch(),
- LLVersionInfo::instance().getBuild());
+ std::string user_agent = stringize(
+ LLVersionInfo::instance().getChannel(), ' ',
+ LLVersionInfo::instance().getMajor(), '.',
+ LLVersionInfo::instance().getMinor(), '.',
+ LLVersionInfo::instance().getPatch(), " (",
+ LLVersionInfo::instance().getBuild(), ')');
initHttpHeader(httpHeaders, user_agent);
httpOpts->setSSLVerifyPeer(false);
diff --git a/indra/newview/llversioninfo.cpp b/indra/newview/llversioninfo.cpp
index adc7d8f960..bb1e0e26a9 100644
--- a/indra/newview/llversioninfo.cpp
+++ b/indra/newview/llversioninfo.cpp
@@ -73,7 +73,7 @@ void LLVersionInfo::initSingleton()
// fully constructed; such calls don't really belong in the constructor.
// cache the version string
- version = STRINGIZE(getShortVersion() << "." << getBuild());
+ version = stringize(getShortVersion(), ".", getBuild());
}
LLVersionInfo::~LLVersionInfo()
@@ -95,7 +95,7 @@ S32 LLVersionInfo::getPatch()
return LL_VIEWER_VERSION_PATCH;
}
-S32 LLVersionInfo::getBuild()
+U64 LLVersionInfo::getBuild()
{
return LL_VIEWER_VERSION_BUILD;
}
diff --git a/indra/newview/llversioninfo.h b/indra/newview/llversioninfo.h
index a67577b020..6a42649851 100644
--- a/indra/newview/llversioninfo.h
+++ b/indra/newview/llversioninfo.h
@@ -61,7 +61,7 @@ public:
S32 getPatch();
/// return the build number as an integer
- S32 getBuild();
+ U64 getBuild();
/// return the full viewer version as a string like "2.0.0.200030"
std::string getVersion();
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index ca5fa49ef6..3b1a1025b8 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -221,6 +221,7 @@
#include "llfloaterscriptrecover.h"
#include "llfloatersearchreplace.h"
#include "llpanelgroup.h"
+#include "llsidepanelinventory.h"
#include "NACLfloaterexploresounds.h"
#include "particleeditor.h"
#include "quickprefs.h"
@@ -633,10 +634,10 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("quickprefs", "floater_quickprefs.xml", (LLFloaterBuildFunc)&LLFloaterReg::build
);
LLFloaterReg::add("region_tracker", "floater_region_tracker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build);
LLFloaterReg::add("search_replace", "floater_search_replace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build);
- LLFloaterReg::add("secondary_inventory", "floater_my_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build);
+ LLFloaterReg::add("secondary_inventory", "floater_my_inventory.xml", (LLFloaterBuildFunc)&LLSidepanelInventory::createSecondaryInventoryWindow);
LLFloaterReg::add("script_recover", "floater_script_recover.xml", (LLFloaterBuildFunc)&LLFloaterReg::build);
LLFloaterReg::add("sound_explorer", "floater_NACL_explore_sounds.xml", (LLFloaterBuildFunc)&LLFloaterReg::build);
- LLFloaterReg::add("vram_usage", "floater_fs_vram_usage.xml", static_cast( &LLFloaterReg::build< FSFloaterVRAMUsage >) );
+ LLFloaterReg::add("vram_usage", "floater_fs_vram_usage.xml", static_cast(&LLFloaterReg::build));
LLFloaterReg::add("local_mesh_floater", "floater_vj_local_mesh.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); // local mesh
LLFloaterReg::registerControlVariables(); // Make sure visibility and rect controls get preserved when saving
diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp
index de2527e497..0e295a4b3f 100644
--- a/indra/newview/llweb.cpp
+++ b/indra/newview/llweb.cpp
@@ -160,7 +160,7 @@ std::string LLWeb::expandURLSubstitutions(const std::string &url,
substitution["VERSION_MAJOR"] = LLVersionInfo::instance().getMajor();
substitution["VERSION_MINOR"] = LLVersionInfo::instance().getMinor();
substitution["VERSION_PATCH"] = LLVersionInfo::instance().getPatch();
- substitution["VERSION_BUILD"] = LLVersionInfo::instance().getBuild();
+ substitution["VERSION_BUILD"] = std::to_string(LLVersionInfo::instance().getBuild());
substitution["CHANNEL"] = LLVersionInfo::instance().getChannel();
substitution["GRID"] = LLGridManager::getInstance()->getGridId();
substitution["GRID_LOWERCASE"] = utf8str_tolower(LLGridManager::getInstance()->getGridId());
diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp
index f65447f830..57ba768aa0 100644
--- a/indra/newview/llxmlrpctransaction.cpp
+++ b/indra/newview/llxmlrpctransaction.cpp
@@ -42,6 +42,7 @@
#include "bufferarray.h"
#include "llversioninfo.h"
#include "llviewercontrol.h"
+#include "stringize.h"
// Have to include these last to avoid queue redefinition!
@@ -399,14 +400,14 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip, const
httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML);
- std::string user_agent = llformat("%s %d.%d.%d (%d)",
- LLVersionInfo::instance().getChannel().c_str(),
- LLVersionInfo::instance().getMajor(),
- LLVersionInfo::instance().getMinor(),
- LLVersionInfo::instance().getPatch(),
- LLVersionInfo::instance().getBuild());
+ std::string user_agent = stringize(
+ LLVersionInfo::instance().getChannel(), ' ',
+ LLVersionInfo::instance().getMajor(), '.',
+ LLVersionInfo::instance().getMinor(), '.',
+ LLVersionInfo::instance().getPatch(), " (",
+ LLVersionInfo::instance().getBuild(), ')');
- httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
+ httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
///* Setting the DNS cache timeout to -1 disables it completely.
//This might help with bug #503 */
diff --git a/indra/newview/skins/starlight/xui/en/panel_main_inventory.xml b/indra/newview/skins/starlight/xui/en/panel_main_inventory.xml
index 2520428234..425d93a530 100644
--- a/indra/newview/skins/starlight/xui/en/panel_main_inventory.xml
+++ b/indra/newview/skins/starlight/xui/en/panel_main_inventory.xml
@@ -1,14 +1,12 @@
+ name="main inventory panel">
@@ -24,150 +22,336 @@
name="ItemcountUnknown">
Fetched [ITEM_COUNT] Elements [FILTER]
-
- Elements:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Inventory
+ Multi_Folder_Mode
+ Single_Folder_Mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+ left="4"
+ name="combination_view_inventory"
+ top_delta="0"
+ visible="false">
+
+
+
+
+
+
+
+
+
+
+
+
+
+ right="-4">
-
-
+ width="31"/>
+
-
+
-
+ right="-1"
+ name="dummy_icon" />
+ width="32">
-
-
+
+
diff --git a/indra/newview/skins/starlight/xui/en/sidepanel_inventory.xml b/indra/newview/skins/starlight/xui/en/sidepanel_inventory.xml
new file mode 100644
index 0000000000..31e7055359
--- /dev/null
+++ b/indra/newview/skins/starlight/xui/en/sidepanel_inventory.xml
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+ Received items ([NUM])
+ Received items
+
+
+
+ [NUM] new
+
+
+
+ Purchases from the marketplace will be delivered here.
+
+
+
+
+
+
+
diff --git a/indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml b/indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml
index 440e0d7af2..27eb1dc6c4 100644
--- a/indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml
+++ b/indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml
@@ -1,16 +1,14 @@
+ name="main inventory panel">
+ bg_opaque_color="Transparent"
+ bg_alpha_color="Transparent"
@@ -26,120 +24,234 @@
name="ItemcountUnknown">
Fetched [ITEM_COUNT] Elements [FILTER]
-
- Elements:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Inventory
+ Multi_Folder_Mode
+ Single_Folder_Mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ right="-4">
-
-
+
-
+ width="31"/>
+
-
+
-
+ right="-1"
+ name="dummy_icon" />
+ width="32">
-
-
+
+
diff --git a/indra/newview/skins/starlightcui/xui/en/sidepanel_inventory.xml b/indra/newview/skins/starlightcui/xui/en/sidepanel_inventory.xml
index 5990a42ecf..ed2233580b 100644
--- a/indra/newview/skins/starlightcui/xui/en/sidepanel_inventory.xml
+++ b/indra/newview/skins/starlightcui/xui/en/sidepanel_inventory.xml
@@ -50,8 +50,7 @@
height="300"
width="330" />
-
+ height="235">
Received items ([NUM])
Received items
+ left="5"
+ right="-43" />
+ top_pad="0">
[NUM] new
-
- Purchases from the marketplace will be delivered here.
-
+
+ Purchases from the marketplace will be delivered here.
+
diff --git a/indra/newview/skins/vintage/xui/en/panel_main_inventory.xml b/indra/newview/skins/vintage/xui/en/panel_main_inventory.xml
index 9bcd920d21..b5e5698f59 100644
--- a/indra/newview/skins/vintage/xui/en/panel_main_inventory.xml
+++ b/indra/newview/skins/vintage/xui/en/panel_main_inventory.xml
@@ -23,7 +23,12 @@
Fetched [ITEM_COUNT] Elements [FILTER]
-
+
+
+
+ Inventory
+ Multi_Folder_Mode
+ Single_Folder_Mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -501,6 +560,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -577,6 +725,8 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Prevents creating __pycache__ directory
@@ -494,11 +494,30 @@ class ViewerManifest(LLManifest,FSViewerManifest):
return os.path.relpath(abspath(path), abspath(base))
+ # Undo Github-Build stuff - I don't think we need this
+ #def set_github_output_path(self, variable, path):
+ # self.set_github_output(variable,
+ # os.path.normpath(os.path.join(self.get_dst_prefix(), path)))
-class WindowsManifest(ViewerManifest):
+ #def set_github_output(self, variable, *values):
+ # GITHUB_OUTPUT = os.getenv('GITHUB_OUTPUT')
+ # if GITHUB_OUTPUT and values:
+ # with open(GITHUB_OUTPUT, 'a') as outf:
+ # if len(values) == 1:
+ # print('='.join((variable, values[0])), file=outf)
+ # else:
+ # delim = secrets.token_hex(8)
+ # print('<<'.join((variable, delim)), file=outf)
+ # for value in values:
+ # print(value, file=outf)
+ # print(delim, file=outf)
+ #
+
+class Windows_x86_64_Manifest(ViewerManifest):
# We want the platform, per se, for every Windows build to be 'win'. The
# VMP will concatenate that with the address_size.
build_data_json_platform = 'win'
+ address_size = 64
def final_exe(self):
return self.exec_name()+".exe"
@@ -559,7 +578,7 @@ class WindowsManifest(ViewerManifest):
print("Doesn't exist:", src)
def construct(self):
- super(WindowsManifest, self).construct()
+ super().construct()
pkgdir = os.path.join(self.args['build'], os.pardir, 'packages')
relpkgdir = os.path.join(pkgdir, "lib", "release")
@@ -568,6 +587,32 @@ class WindowsManifest(ViewerManifest):
if self.is_packaging_viewer():
# Find firestorm-bin.exe in the 'configuration' dir, then rename it to the result of final_exe.
self.path(src='%s/firestorm-bin.exe' % self.args['configuration'], dst=self.final_exe())
+ # Emit the whole app image as one of the GitHub step outputs. We
+ # want the whole app -- but NOT the extraneous build products that
+ # get tossed into the same directory, such as the installer and
+ # the symbols tarball, so add exclusions. When we feed
+ # upload-artifact multiple absolute pathnames, even just for
+ # exclusion, it ends up creating several extraneous directory
+ # levels within the artifact -- so try using only relative paths.
+ # One problem: as of right now, our current directory os.getcwd()
+ # is not the same as the initial working directory for this job
+ # step, meaning paths relative to our os.getcwd() won't work for
+ # the subsequent upload-artifact step. We're a couple directory
+ # levels down. Try adjusting for those when specifying the base
+ # for self.relpath().
+ # Undo Github-Build stuff - I don't think we need this
+ #appbase = self.relpath(
+ # self.get_dst_prefix(),
+ # base=os.path.join(os.getcwd(), os.pardir, os.pardir))
+ #self.set_github_output('viewer_app', appbase,
+ # # except for this stuff
+ # *(('!' + os.path.join(appbase, pattern))
+ # for pattern in (
+ # 'secondlife-bin.*',
+ # '*_Setup.exe',
+ # '*.bat',
+ # '*.tar.bz2')))
+ #
# Remove VMP
#with self.prefix(src=os.path.join(pkgdir, "VMP")):
@@ -631,20 +676,12 @@ class WindowsManifest(ViewerManifest):
self.path("SLVoice.exe")
# Vivox libraries
- if (self.address_size == 64):
- self.path("vivoxsdk_x64.dll")
- self.path("ortp_x64.dll")
- else:
- self.path("vivoxsdk.dll")
- self.path("ortp.dll")
+ self.path("vivoxsdk_x64.dll")
+ self.path("ortp_x64.dll")
# OpenSSL
- if (self.address_size == 64):
- self.path("libcrypto-1_1-x64.dll")
- self.path("libssl-1_1-x64.dll")
- else:
- self.path("libcrypto-1_1.dll")
- self.path("libssl-1_1.dll")
+ self.path("libcrypto-1_1-x64.dll")
+ self.path("libssl-1_1-x64.dll")
# HTTP/2
self.path("nghttp2.dll")
@@ -654,14 +691,9 @@ class WindowsManifest(ViewerManifest):
# 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")
+ self.path("BsSndRpt64.exe")
+ self.path("BugSplat64.dll")
+ self.path("BugSplatRc64.dll")
# Growl
self.path("growl.dll")
@@ -793,6 +825,48 @@ class WindowsManifest(ViewerManifest):
self.fs_copy_windows_manifest( )
def nsi_file_commands(self, install=True):
+ # Undo Github-Build stuff - I don't think we need this
+ #def INSTDIR(path):
+ # # Note that '$INSTDIR' is purely textual here: we write
+ # # exactly that into the .nsi file for NSIS to interpret.
+ # # Pass the result through normpath() to handle the case in which
+ # # path is the empty string. On Windows, that produces "$INSTDIR\".
+ # # Unfortunately, if that's the last item on a line, NSIS takes
+ # # that as line continuation and misinterprets the following line.
+ # # Ensure we don't emit a trailing backslash.
+ # return os.path.normpath(os.path.join('$INSTDIR', path))
+
+ #result = []
+ #dest_files = [pair[1] for pair in self.file_list if pair[0] and os.path.isfile(pair[1])]
+ ## sort deepest hierarchy first
+ #dest_files.sort(key=lambda f: (f.count(os.path.sep), f), reverse=True)
+ #out_path = None
+ #for pkg_file in dest_files:
+ # pkg_file = os.path.normpath(pkg_file)
+ # rel_file = self.relpath(pkg_file)
+ # installed_dir = INSTDIR(os.path.dirname(rel_file))
+ # if install and installed_dir != out_path:
+ # out_path = installed_dir
+ # # emit SetOutPath every time it changes
+ # result.append('SetOutPath ' + out_path)
+ # if install:
+ # result.append('File ' + rel_file)
+ # else:
+ # result.append('Delete ' + INSTDIR(rel_file))
+
+ ## at the end of a delete, just rmdir all the directories
+ #if not install:
+ # deleted_file_dirs = [os.path.dirname(self.relpath(f)) for f in dest_files]
+ # # find all ancestors so that we don't skip any dirs that happened
+ # # to have no non-dir children
+ # deleted_dirs = set(itertools.chain.from_iterable(path_ancestors(d)
+ # for d in deleted_file_dirs))
+ # # sort deepest hierarchy first
+ # for d in sorted(deleted_dirs, key=lambda f: (f.count(os.path.sep), f), reverse=True):
+ # result.append('RMDir ' + INSTDIR(d))
+
+ #return '\n'.join(result)
+
def wpath(path):
if path.endswith('/') or path.endswith(os.path.sep):
path = path[:-1]
@@ -833,6 +907,7 @@ class WindowsManifest(ViewerManifest):
prev = d
return result
+ #
def package_finish(self):
# a standard map of strings for replacing in the templates
@@ -840,8 +915,7 @@ class WindowsManifest(ViewerManifest):
'version' : '.'.join(self.args['version']),
'version_short' : '.'.join(self.args['version'][:-1]),
'version_dashes' : '-'.join(self.args['version']),
- 'version_registry' : '%s(%s)' %
- ('.'.join(self.args['version']), self.address_size),
+ 'version_registry' : '%s(64)' % '.'.join(self.args['version']),
'final_exe' : self.final_exe(),
'flags':'',
'app_name':self.app_name(),
@@ -887,12 +961,18 @@ class WindowsManifest(ViewerManifest):
Caption "%(caption)s"
"""
- if(self.address_size == 64):
- engage_registry="SetRegView 64"
- program_files="!define MULTIUSER_USE_PROGRAMFILES64"
- else:
- engage_registry="SetRegView 32"
- program_files=""
+ engage_registry="SetRegView 64"
+ program_files="!define MULTIUSER_USE_PROGRAMFILES64"
+
+ # Dump the installers/windows directory into the raw app image tree
+ # because NSIS needs those files. But don't use path() because we
+ # don't want them installed with the viewer - they're only for use by
+ # the installer itself.
+ # Undo Github-Build stuff - I don't think we need this
+ #shutil.copytree(os.path.join(self.get_src_prefix(), 'installers', 'windows'),
+ # os.path.join(self.get_dst_prefix(), 'installers', 'windows'),
+ # dirs_exist_ok=True)
+ #
tempfile = "firestorm_setup_tmp.nsi"
@@ -902,6 +982,10 @@ class WindowsManifest(ViewerManifest):
# it also does python-style % substitution
self.replace_in("installers/windows/installer_template.nsi", tempfile, {
"%%VERSION%%":version_vars,
+ # The template references "%%SOURCE%%\installers\windows\...".
+ # Now that we've copied that directory into the app image
+ # tree, we can just replace %%SOURCE%% with '.'.
+ #"%%SOURCE%%":'.', Undo Github-Build stuff
"%%SOURCE%%":self.get_src_prefix(),
"%%INST_VARS%%":inst_vars_template % substitution_strings,
"%%INSTALL_FILES%%":self.nsi_file_commands(True),
@@ -909,16 +993,7 @@ class WindowsManifest(ViewerManifest):
"%%ENGAGEREGISTRY%%":engage_registry,
"%%DELETE_FILES%%":self.nsi_file_commands(False)})
- # If we're on a build machine, sign the code using our Authenticode certificate. JC
- # 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 (
- # self.final_exe(),
- # "SLVersionChecker.exe",
- # "llplugin/dullahan_host.exe",
- # ):
- # self.sign(exe)
-
+ # Undo Github-Build stuff
# Check two paths, one for Program Files, and one for Program Files (x86).
# Yay 64bit windows.
nsis_path = "makensis.exe"
@@ -936,6 +1011,7 @@ class WindowsManifest(ViewerManifest):
self.created_path(self.dst_path_of(installer_file))
self.package_file = installer_file
+ #
def sign(self, exe):
sign_py = os.environ.get('SIGN', r'C:\buildscripts\code-signing\sign.py')
@@ -950,17 +1026,9 @@ class WindowsManifest(ViewerManifest):
def escape_slashes(self, path):
return path.replace('\\', '\\\\\\\\')
-class Windows_i686_Manifest(WindowsManifest):
- # Although we aren't literally passed ADDRESS_SIZE, we can infer it from
- # the passed 'arch', which is used to select the specific subclass.
- address_size = 32
-
-class Windows_x86_64_Manifest(WindowsManifest):
- address_size = 64
-
-
-class DarwinManifest(ViewerManifest):
+class Darwin_x86_64_Manifest(ViewerManifest):
build_data_json_platform = 'mac'
+ address_size = 64
def finish_build_data_dict(self, build_data_dict):
build_data_dict.update({'Bundle Id':self.args['bundleid']})
@@ -1311,8 +1379,9 @@ class DarwinManifest(ViewerManifest):
# self.path( "plugins.dat" )
def construct(self):
- # copy over the build result (this is a no-op if run within the xcode script)
- # self.path(os.path.join(self.args['configuration'], self.channel()+".app"), dst="")
+ # copy over the build result (this is a no-op if run within the xcode
+ # script)
+ #self.path(os.path.join(self.args['configuration'], self.channel() + ".app"), dst="")
self.path(os.path.join(self.args['configuration'], "Firestorm.app"), dst="")
pkgdir = os.path.join(self.args['build'], os.pardir, 'packages')
@@ -1358,7 +1427,7 @@ class DarwinManifest(ViewerManifest):
# most everything goes in the Resources directory
with self.prefix(dst="Resources"):
- super(DarwinManifest, self).construct()
+ super().construct()
with self.prefix(src_dst="cursors_mac"):
self.path("*.tif")
@@ -1838,18 +1907,6 @@ class DarwinManifest(ViewerManifest):
self.remove(sparsename)
self.fs_save_osx_symbols()
-class Darwin_i386_Manifest(DarwinManifest):
- address_size = 32
-
-
-class Darwin_i686_Manifest(DarwinManifest):
- """alias in case arch is passed as i686 instead of i386"""
- pass
-
-
-class Darwin_x86_64_Manifest(DarwinManifest):
- address_size = 64
-
class LinuxManifest(ViewerManifest):
build_data_json_platform = 'lnx'
diff --git a/indra/test/hexdump.h b/indra/test/hexdump.h
new file mode 100644
index 0000000000..dd7cbaaa3c
--- /dev/null
+++ b/indra/test/hexdump.h
@@ -0,0 +1,97 @@
+/**
+ * @file hexdump.h
+ * @author Nat Goodspeed
+ * @date 2023-09-08
+ * @brief Provide hexdump() and hexmix() ostream formatters
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Copyright (c) 2023, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_HEXDUMP_H)
+#define LL_HEXDUMP_H
+
+#include
+#include
+#include
+#include
+
+// Format a given byte string as 2-digit hex values, no separators
+// Usage: std::cout << hexdump(somestring) << ...
+class hexdump
+{
+public:
+ hexdump(const std::string_view& data):
+ hexdump(data.data(), data.length())
+ {}
+
+ hexdump(const char* data, size_t len):
+ hexdump(reinterpret_cast(data), len)
+ {}
+
+ hexdump(const unsigned char* data, size_t len):
+ mData(data, data + len)
+ {}
+
+ friend std::ostream& operator<<(std::ostream& out, const hexdump& self)
+ {
+ auto oldfmt{ out.flags() };
+ auto oldfill{ out.fill() };
+ out.setf(std::ios_base::hex, std::ios_base::basefield);
+ out.fill('0');
+ for (auto c : self.mData)
+ {
+ out << std::setw(2) << unsigned(c);
+ }
+ out.setf(oldfmt, std::ios_base::basefield);
+ out.fill(oldfill);
+ return out;
+ }
+
+private:
+ std::vector mData;
+};
+
+// Format a given byte string as a mix of printable characters and, for each
+// non-printable character, "\xnn"
+// Usage: std::cout << hexmix(somestring) << ...
+class hexmix
+{
+public:
+ hexmix(const std::string_view& data):
+ mData(data)
+ {}
+
+ hexmix(const char* data, size_t len):
+ mData(data, len)
+ {}
+
+ friend std::ostream& operator<<(std::ostream& out, const hexmix& self)
+ {
+ auto oldfmt{ out.flags() };
+ auto oldfill{ out.fill() };
+ out.setf(std::ios_base::hex, std::ios_base::basefield);
+ out.fill('0');
+ for (auto c : self.mData)
+ {
+ // std::isprint() must be passed an unsigned char!
+ if (std::isprint(static_cast(c)))
+ {
+ out << c;
+ }
+ else
+ {
+ out << "\\x" << std::setw(2) << unsigned(c);
+ }
+ }
+ out.setf(oldfmt, std::ios_base::basefield);
+ out.fill(oldfill);
+ return out;
+ }
+
+private:
+ std::string mData;
+};
+
+#endif /* ! defined(LL_HEXDUMP_H) */
diff --git a/indra/test/namedtempfile.h b/indra/test/namedtempfile.h
index 02917aeca8..ad14cebbd1 100644
--- a/indra/test/namedtempfile.h
+++ b/indra/test/namedtempfile.h
@@ -13,15 +13,16 @@
#define LL_NAMEDTEMPFILE_H
#include "llerror.h"
-#include "llapr.h"
-#include "apr_file_io.h"
+#include "llstring.h"
+#include "stringize.h"
#include
-#include
-#include
-#include
+#include
+#include
#include
+#include
#include
#include
+#include
/**
* Create a text file with specified content "somewhere in the
@@ -31,134 +32,123 @@ class NamedTempFile: public boost::noncopyable
{
LOG_CLASS(NamedTempFile);
public:
- NamedTempFile(const std::string& pfx, const std::string& content, apr_pool_t* pool=gAPRPoolp):
- mPool(pool)
+ NamedTempFile(const std::string_view& pfx,
+ const std::string_view& content,
+ const std::string_view& sfx=std::string_view(""))
{
- createFile(pfx, boost::phoenix::placeholders::arg1 << content);
+ createFile(pfx, [&content](std::ostream& out){ out << content; }, sfx);
}
- // Disambiguate when passing string literal
- NamedTempFile(const std::string& pfx, const char* content, apr_pool_t* pool=gAPRPoolp):
- mPool(pool)
+ // Disambiguate when passing string literal -- unclear why a string
+ // literal should be ambiguous wrt std::string_view and Streamer
+ NamedTempFile(const std::string_view& pfx,
+ const char* content,
+ const std::string_view& sfx=std::string_view(""))
{
- createFile(pfx, boost::phoenix::placeholders::arg1 << content);
+ createFile(pfx, [&content](std::ostream& out){ out << content; }, sfx);
}
// Function that accepts an ostream ref and (presumably) writes stuff to
// it, e.g.:
// (boost::phoenix::placeholders::arg1 << "the value is " << 17 << '\n')
- typedef boost::function Streamer;
+ typedef std::function Streamer;
- NamedTempFile(const std::string& pfx, const Streamer& func, apr_pool_t* pool=gAPRPoolp):
- mPool(pool)
+ NamedTempFile(const std::string_view& pfx,
+ const Streamer& func,
+ const std::string_view& sfx=std::string_view(""))
{
- createFile(pfx, func);
+ createFile(pfx, func, sfx);
}
virtual ~NamedTempFile()
{
- ll_apr_assert_status(apr_file_remove(mPath.c_str(), mPool));
+ boost::filesystem::remove(mPath);
}
- virtual std::string getName() const { return mPath; }
+ std::string getName() const { return mPath.string(); }
- void peep()
+ template
+ void peep_via(CALLABLE&& callable) const
{
- std::cout << "File '" << mPath << "' contains:\n";
- std::ifstream reader(mPath.c_str());
+ std::forward(callable)(stringize("File '", mPath, "' contains:"));
+ boost::filesystem::ifstream reader(mPath, std::ios::binary);
std::string line;
while (std::getline(reader, line))
- std::cout << line << '\n';
- std::cout << "---\n";
+ std::forward(callable)(line);
+ std::forward(callable)("---");
+ }
+
+ void peep_log() const
+ {
+ peep_via([](const std::string& line){ LL_DEBUGS() << line << LL_ENDL; });
+ }
+
+ void peep(std::ostream& out=std::cout) const
+ {
+ peep_via([&out](const std::string& line){ out << line << '\n'; });
+ }
+
+ friend std::ostream& operator<<(std::ostream& out, const NamedTempFile& self)
+ {
+ self.peep(out);
+ return out;
+ }
+
+ static boost::filesystem::path temp_path(const std::string_view& pfx="",
+ const std::string_view& sfx="")
+ {
+ // This variable is set by GitHub actions and is the recommended place
+ // to put temp files belonging to an actions job.
+ const char* RUNNER_TEMP = getenv("RUNNER_TEMP");
+ boost::filesystem::path tempdir{
+ // if RUNNER_TEMP is set and not empty
+ (RUNNER_TEMP && *RUNNER_TEMP)?
+ boost::filesystem::path(RUNNER_TEMP) : // use RUNNER_TEMP if available
+ boost::filesystem::temp_directory_path()}; // else canonical temp dir
+ boost::filesystem::path tempname{
+ // use filename template recommended by unique_path() doc, but
+ // with underscores instead of hyphens: some use cases involve
+ // temporary Python scripts
+ tempdir / stringize(pfx, "%%%%_%%%%_%%%%_%%%%", sfx) };
+ return boost::filesystem::unique_path(tempname);
}
protected:
- void createFile(const std::string& pfx, const Streamer& func)
+ void createFile(const std::string_view& pfx,
+ const Streamer& func,
+ const std::string_view& sfx)
{
// Create file in a temporary place.
- const char* tempdir = NULL;
- ll_apr_assert_status(apr_temp_dir_get(&tempdir, mPool));
-
- // Construct a temp filename template in that directory.
- char *tempname = NULL;
- ll_apr_assert_status(apr_filepath_merge(&tempname,
- tempdir,
- (pfx + "XXXXXX").c_str(),
- 0,
- mPool));
-
- // Create a temp file from that template.
- apr_file_t* fp = NULL;
- ll_apr_assert_status(apr_file_mktemp(&fp,
- tempname,
- APR_CREATE | APR_WRITE | APR_EXCL,
- mPool));
- // apr_file_mktemp() alters tempname with the actual name. Not until
- // now is it valid to capture as our mPath.
- mPath = tempname;
-
+ mPath = temp_path(pfx, sfx);
+ boost::filesystem::ofstream out{ mPath, std::ios::binary };
// Write desired content.
- std::ostringstream out;
- // Stream stuff to it.
func(out);
-
- std::string data(out.str());
- apr_size_t writelen(data.length());
- ll_apr_assert_status(apr_file_write(fp, data.c_str(), &writelen));
- ll_apr_assert_status(apr_file_close(fp));
- llassert_always(writelen == data.length());
}
- std::string mPath;
- apr_pool_t* mPool;
+ boost::filesystem::path mPath;
};
/**
* Create a NamedTempFile with a specified filename extension. This is useful
* when, for instance, you must be able to use the file in a Python import
* statement.
- *
- * A NamedExtTempFile actually has two different names. We retain the original
- * no-extension name as a placeholder in the temp directory to ensure
- * uniqueness; to that we link the name plus the desired extension. Naturally,
- * both must be removed on destruction.
*/
class NamedExtTempFile: public NamedTempFile
{
LOG_CLASS(NamedExtTempFile);
public:
- NamedExtTempFile(const std::string& ext, const std::string& content, apr_pool_t* pool=gAPRPoolp):
- NamedTempFile(remove_dot(ext), content, pool),
- mLink(mPath + ensure_dot(ext))
- {
- linkto(mLink);
- }
+ NamedExtTempFile(const std::string& ext, const std::string_view& content):
+ NamedTempFile(remove_dot(ext), content, ensure_dot(ext))
+ {}
// Disambiguate when passing string literal
- NamedExtTempFile(const std::string& ext, const char* content, apr_pool_t* pool=gAPRPoolp):
- NamedTempFile(remove_dot(ext), content, pool),
- mLink(mPath + ensure_dot(ext))
- {
- linkto(mLink);
- }
+ NamedExtTempFile(const std::string& ext, const char* content):
+ NamedTempFile(remove_dot(ext), content, ensure_dot(ext))
+ {}
- NamedExtTempFile(const std::string& ext, const Streamer& func, apr_pool_t* pool=gAPRPoolp):
- NamedTempFile(remove_dot(ext), func, pool),
- mLink(mPath + ensure_dot(ext))
- {
- linkto(mLink);
- }
-
- virtual ~NamedExtTempFile()
- {
- ll_apr_assert_status(apr_file_remove(mLink.c_str(), mPool));
- }
-
- // Since the caller has gone to the trouble to create the name with the
- // extension, that should be the name we return. In this class, mPath is
- // just a placeholder to ensure that future createFile() calls won't
- // collide.
- virtual std::string getName() const { return mLink; }
+ NamedExtTempFile(const std::string& ext, const Streamer& func):
+ NamedTempFile(remove_dot(ext), func, ensure_dot(ext))
+ {}
static std::string ensure_dot(const std::string& ext)
{
@@ -175,7 +165,7 @@ public:
{
return ext;
}
- return std::string(".") + ext;
+ return "." + ext;
}
static std::string remove_dot(const std::string& ext)
@@ -187,19 +177,6 @@ public:
}
return ext.substr(found);
}
-
-private:
- void linkto(const std::string& path)
- {
- // This method assumes that since mPath (without extension) is
- // guaranteed by apr_file_mktemp() to be unique, then (mPath + any
- // extension) is also unique. This is likely, though not guaranteed:
- // files could be created in the same temp directory other than by
- // this class.
- //ll_apr_assert_status(apr_file_link(mPath.c_str(), path.c_str()));
- }
-
- std::string mLink;
};
#endif /* ! defined(LL_NAMEDTEMPFILE_H) */
diff --git a/indra/test/test.cpp b/indra/test/test.cpp
index f099037411..5a0d950f6f 100644
--- a/indra/test/test.cpp
+++ b/indra/test/test.cpp
@@ -102,10 +102,10 @@ public:
class RecordToTempFile : public LLError::Recorder, public boost::noncopyable
{
public:
- RecordToTempFile(apr_pool_t* pPool)
+ RecordToTempFile()
: LLError::Recorder(),
boost::noncopyable(),
- mTempFile("log", "", pPool),
+ mTempFile("log", ""),
mFile(mTempFile.getName().c_str())
{
}
@@ -146,11 +146,11 @@ private:
class LLReplayLogReal: public LLReplayLog, public boost::noncopyable
{
public:
- LLReplayLogReal(LLError::ELevel level, apr_pool_t* pool)
+ LLReplayLogReal(LLError::ELevel level)
: LLReplayLog(),
boost::noncopyable(),
mOldSettings(LLError::saveAndResetSettings()),
- mRecorder(new RecordToTempFile(pool))
+ mRecorder(new RecordToTempFile())
{
LLError::setFatalFunction(wouldHaveCrashed);
LLError::setDefaultLevel(level);
@@ -636,7 +636,7 @@ int main(int argc, char **argv)
if (LOGFAIL && *LOGFAIL)
{
LLError::ELevel level = LLError::decodeLevel(LOGFAIL);
- replayer.reset(new LLReplayLogReal(level, gAPRPoolp));
+ replayer.reset(new LLReplayLogReal(level));
}
}
LLError::setFatalFunction(wouldHaveCrashed);