4#include "Stroika/Foundation/StroikaPreComp.h"
10#include "Stroika/Foundation/DataExchange/Variant/XML/Writer.h"
17#include "Stroika/Foundation/Linguistics/MessageUtilities.h"
18#include "Stroika/Foundation/Streams/MemoryStream.h"
27using namespace Stroika::Foundation::Memory;
28using namespace Stroika::Foundation::Streams;
40OptionsFile::LoggerMessage::LoggerMessage (Msg msg,
const filesystem::path& fn,
const optional<String>& details)
47String OptionsFile::LoggerMessage::FormatMessage ()
const
52 sb <<
"; "sv << *fDetails;
53 details = Linguistics::MessageUtilities::Manager::sThe.RemoveTrailingSentencePunctuation (sb).first;
56 case Msg::eSuccessfullyReadFile:
57 return "Successfully read configuration file '{}'."_f(fFileName);
58 case Msg::eFailedToWriteFile:
59 return "Failed to write file '{}': {}."_f(fFileName, details);
60 case Msg::eFailedToReadFile:
61 return "Failed to read file '{}': {}."_f(fFileName, details);
62 case Msg::eFailedToParseReadFile:
63 return "Error analyzing configuration file '{}' - using defaults{}."_f(fFileName, details);
64 case Msg::eFailedToParseReadFileBadFormat:
65 return "Error analyzing configuration file (because bad format) '{}' - using defaults{}."_f(fFileName, details);
66 case Msg::eFailedToCompareReadFile:
67 return "Failed to compare configuration file: '{}'{}."_f(fFileName, details);
68 case Msg::eWritingConfigFile_SoDefaultsEditable:
69 return "Writing configuration file '{}' because not found (and so defaults are more easily seen and editable){}."_f(fFileName, details);
70 case Msg::eWritingConfigFile_BecauseUpgraded:
71 return "Writing configuration file '{}' in a new location because the software has been upgraded{}."_f(fFileName, details);
72 case Msg::eWritingConfigFile_BecauseSomethingChanged:
73 return "Writing configuration file '{}' because something changed (e.g. a default, or field added/removed){}."_f(fFileName, details);
74 case Msg::eFailedToWriteInUseValues:
75 return "Failed to write default (in use) values to file: '{}'{}."_f(fFileName, details);
88 [] (
const optional<Common::Version>& ,
const VariantValue& rawVariantValue) ->
VariantValue {
return rawVariantValue; };
92 Logger::Priority priority = Logger::eError;
93 using Msg = OptionsFile::LoggerMessage::Msg;
94 switch (message.fMsg) {
95 case Msg::eSuccessfullyReadFile:
96 priority = Logger::eInfo;
98 case Msg::eFailedToReadFile:
99 priority = Logger::eWarning;
101 case Msg::eWritingConfigFile_SoDefaultsEditable:
102 case Msg::eWritingConfigFile_BecauseUpgraded:
103 case Msg::eWritingConfigFile_BecauseSomethingChanged:
104 priority = Logger::eInfo;
107 case Msg::eFailedToParseReadFile:
108 case Msg::eFailedToParseReadFileBadFormat:
110 priority = Logger::eCriticalError;
113 Logger::sThe.
Log (priority,
"{}"_f, message.FormatMessage ());
116OptionsFile::ModuleNameToFileNameMapperType OptionsFile::mkFilenameMapper (
const String& appName)
118 return [appName] (
const String& moduleName,
const String& fileSuffix) -> filesystem::path {
120 (moduleName + fileSuffix).As<filesystem::path> ();
125 [] ([[maybe_unused]]
const String& ) -> optional<Common::Version> {
126 return optional<Common::Version> ();
133OptionsFile::OptionsFile (
const String& modName,
const ObjectVariantMapper& mapper, ModuleDataUpgraderType moduleUpgrader,
134 ModuleNameToFileNameMapperType moduleNameToFileNameMapper, ModuleNameToFileVersionMapperType moduleNameToReadFileVersion,
139 moduleNameToFileNameMapper,
140 moduleNameToFileNameMapper,
141 moduleNameToReadFileVersion,
145 String{reader.GetDefaultFileSuffix ().value_or (
""sv)}}
149OptionsFile::OptionsFile (
const String& modName,
const ObjectVariantMapper& mapper, ModuleDataUpgraderType moduleUpgrader,
150 ModuleNameToFileNameMapperType moduleNameToReadFileNameMapper, ModuleNameToFileNameMapperType moduleNameToWriteFileNameMapper,
155 moduleNameToReadFileNameMapper,
156 moduleNameToWriteFileNameMapper,
157 moduleNameToReadFileVersion,
161 String{reader.GetDefaultFileSuffix ().value_or (
""sv)}}
165OptionsFile::OptionsFile (
const String& modName,
const ObjectVariantMapper& mapper, ModuleDataUpgraderType moduleUpgrader,
166 ModuleNameToFileNameMapperType moduleNameToReadFileNameMapper, ModuleNameToFileNameMapperType moduleNameToWriteFileNameMapper,
167 ModuleNameToFileVersionMapperType moduleNameToReadFileVersion, LoggerType logger,
Variant::Reader reader,
169 : fModuleName_{modName}
171 , fModuleDataUpgrader_{moduleUpgrader}
172 , fModuleNameToReadFileNameMapper_{moduleNameToReadFileNameMapper}
173 , fModuleNameToWriteFileNameMapper_{moduleNameToWriteFileNameMapper}
174 , fModuleNameToFileVersionMapper_{moduleNameToReadFileVersion}
178 , fFileSuffix_{fileSuffix}
185 return IO::FileSystem::FileInputStream::New (GetReadFilePath_ ()).ReadAll ();
191 if (GetReadFilePath_ () == GetWriteFilePath_ ()) {
203 IO::FileSystem::FileOutputStream::Ptr outStream = IO::FileSystem::FileOutputStream::New (tmpFile.GetFilePath ());
204 outStream.Write (blob);
209 fLogger_ (LoggerMessage{LoggerMessage::Msg::eFailedToWriteFile, GetWriteFilePath_ (),
Characters::ToString (current_exception ())});
218 optional<VariantValue> r = fReader_.Read (MemoryStream::New<byte> (
ReadRaw ()));
219 if (r.has_value ()) {
220#if USE_NOISY_TRACE_IN_THIS_MODULE_
221 DbgTrace (
"present: upgrading module {}"_f, fModuleName_);
223 r = fModuleDataUpgrader_ (fModuleNameToFileVersionMapper_ (fModuleName_), *r);
225 fLogger_ (LoggerMessage{LoggerMessage::Msg::eSuccessfullyReadFile, GetReadFilePath_ ()});
229#if USE_NOISY_TRACE_IN_THIS_MODULE_
233 fLogger_ (LoggerMessage{LoggerMessage::Msg::eFailedToReadFile, GetReadFilePath_ (),
Characters::ToString (current_exception ())});
243 fWriter_.
Write (optionsObject, tmp);
247filesystem::path OptionsFile::GetReadFilePath_ ()
const
249 return fModuleNameToReadFileNameMapper_ (fModuleName_, fFileSuffix_);
252filesystem::path OptionsFile::GetWriteFilePath_ ()
const
254 return fModuleNameToWriteFileNameMapper_ (fModuleName_, fFileSuffix_);
#define RequireNotReached()
#define Stroika_Foundation_Debug_OptionalizeTraceArgs(...)
Similar to String, but intended to more efficiently construct a String. Mutable type (String is large...
String is like std::u32string, except it is much easier to use, often much more space efficient,...
ObjectVariantMapper can be used to map C++ types to and from variant-union types, which can be transp...
nonvirtual void WriteRaw(const BLOB &blob)
static const Variant::Writer kDefaultWriter
function< optional< Common::Version >(const String &moduleName)> ModuleNameToFileVersionMapperType
nonvirtual void Write(const T &optionsObject)
static const ModuleDataUpgraderType kDefaultUpgrader
static const LoggerType kDefaultLogger
function< VariantValue(const optional< Common::Version > &version, const VariantValue &rawVariantValue)> ModuleDataUpgraderType
nonvirtual BLOB ReadRaw() const
static const Variant::Reader kDefaultReader
nonvirtual optional< T > Read()
abstract class specifying interface for readers that map a source like XML or JSON to a VariantValue ...
abstract class specifying interface for writers VariantValue objects to serialized formats like JSON,...
nonvirtual void Write(const VariantValue &v, const Streams::OutputStream::Ptr< byte > &out) const
Simple variant-value (case variant union) object, with (variant) basic types analogous to a value in ...
A simple/portable wrapper on syslog/log4j/WindowsEventlog, with features like throttling,...
void Log(Priority logLevel, const wchar_t *format,...)
utility to atomically update/write a file.
String ToString(T &&t, ARGS... args)
Return a debug-friendly, display version of the argument: not guaranteed parsable or usable except fo...
filesystem::path GetApplicationData(bool createIfNotPresent=true)