4#include "Stroika/Foundation/StroikaPreComp.h"
12#include "Stroika/Foundation/Linguistics/MessageUtilities.h"
13#include "Stroika/Foundation/Streams/MemoryStream.h"
18#include "Variant/XML/Writer.h"
19#include "VariantValue.h"
28using namespace Stroika::Foundation::Memory;
29using namespace Stroika::Foundation::Streams;
41OptionsFile::LoggerMessage::LoggerMessage (Msg msg,
const filesystem::path& fn,
const optional<String>& details)
48String OptionsFile::LoggerMessage::FormatMessage ()
const
53 sb <<
"; "sv << *fDetails;
54 details = Linguistics::MessageUtilities::Manager::sThe.RemoveTrailingSentencePunctuation (sb).first;
57 case Msg::eSuccessfullyReadFile:
58 return "Successfully read configuration file {}."_f(fFileName);
59 case Msg::eFailedToWriteFile:
60 return "Failed to write file {}: {}."_f(fFileName, details);
61 case Msg::eFailedToReadFile:
62 return "Failed to read file {}: {}."_f(fFileName, details);
63 case Msg::eFailedToParseReadFile:
64 return "Error analyzing configuration file {} - using defaults{}."_f(fFileName, details);
65 case Msg::eFailedToParseReadFileBadFormat:
66 return "Error analyzing configuration file (because bad format) {} - using defaults{}."_f(fFileName, details);
67 case Msg::eFailedToCompareReadFile:
68 return "Failed to compare configuration file: {}{}."_f(fFileName, details);
69 case Msg::eWritingConfigFile_SoDefaultsEditable:
70 return "Writing configuration file {} because not found (and so defaults are more easily seen and editable){}."_f(fFileName, details);
71 case Msg::eWritingConfigFile_BecauseUpgraded:
72 return "Writing configuration file {} in a new location because the software has been upgraded{}."_f(fFileName, details);
73 case Msg::eWritingConfigFile_BecauseSomethingChanged:
74 return "Writing configuration file {} because something changed (e.g. a default, or field added/removed){}."_f(fFileName, details);
75 case Msg::eFailedToWriteInUseValues:
76 return "Failed to write default (in use) values to file: {}{}."_f(fFileName, details);
89 [] (
const optional<Common::Version>& ,
const VariantValue& rawVariantValue) ->
VariantValue {
return rawVariantValue; };
93 Logger::Priority priority = Logger::eError;
94 using Msg = OptionsFile::LoggerMessage::Msg;
95 switch (message.fMsg) {
96 case Msg::eSuccessfullyReadFile:
97 priority = Logger::eInfo;
99 case Msg::eFailedToReadFile:
100 priority = Logger::eWarning;
102 case Msg::eWritingConfigFile_SoDefaultsEditable:
103 case Msg::eWritingConfigFile_BecauseUpgraded:
104 case Msg::eWritingConfigFile_BecauseSomethingChanged:
105 priority = Logger::eInfo;
108 case Msg::eFailedToParseReadFile:
109 case Msg::eFailedToParseReadFileBadFormat:
111 priority = Logger::eCriticalError;
114 Logger::sThe.
Log (priority,
"{}"_f, message.FormatMessage ());
117OptionsFile::ModuleNameToFileNameMapperType OptionsFile::mkFilenameMapper (
const String& appName)
119 return [appName] (
const String& moduleName,
const String& fileSuffix) -> filesystem::path {
121 (moduleName + fileSuffix).As<filesystem::path> ();
126 [] ([[maybe_unused]]
const String& ) -> optional<Common::Version> {
127 return optional<Common::Version> ();
134OptionsFile::OptionsFile (
const String& modName,
const ObjectVariantMapper& mapper, ModuleDataUpgraderType moduleUpgrader,
135 ModuleNameToFileNameMapperType moduleNameToFileNameMapper, ModuleNameToFileVersionMapperType moduleNameToReadFileVersion,
140 moduleNameToFileNameMapper,
141 moduleNameToFileNameMapper,
142 moduleNameToReadFileVersion,
146 String{reader.GetDefaultFileSuffix ().value_or (
""sv)}}
150OptionsFile::OptionsFile (
const String& modName,
const ObjectVariantMapper& mapper, ModuleDataUpgraderType moduleUpgrader,
151 ModuleNameToFileNameMapperType moduleNameToReadFileNameMapper, ModuleNameToFileNameMapperType moduleNameToWriteFileNameMapper,
156 moduleNameToReadFileNameMapper,
157 moduleNameToWriteFileNameMapper,
158 moduleNameToReadFileVersion,
162 String{reader.GetDefaultFileSuffix ().value_or (
""sv)}}
166OptionsFile::OptionsFile (
const String& modName,
const ObjectVariantMapper& mapper, ModuleDataUpgraderType moduleUpgrader,
167 ModuleNameToFileNameMapperType moduleNameToReadFileNameMapper, ModuleNameToFileNameMapperType moduleNameToWriteFileNameMapper,
168 ModuleNameToFileVersionMapperType moduleNameToReadFileVersion, LoggerType logger,
Variant::Reader reader,
170 : fModuleName_{modName}
172 , fModuleDataUpgrader_{moduleUpgrader}
173 , fModuleNameToReadFileNameMapper_{moduleNameToReadFileNameMapper}
174 , fModuleNameToWriteFileNameMapper_{moduleNameToWriteFileNameMapper}
175 , fModuleNameToFileVersionMapper_{moduleNameToReadFileVersion}
179 , fFileSuffix_{fileSuffix}
186 return IO::FileSystem::FileInputStream::New (GetReadFilePath_ ()).ReadAll ();
192 if (GetReadFilePath_ () == GetWriteFilePath_ ()) {
204 IO::FileSystem::FileOutputStream::Ptr outStream = IO::FileSystem::FileOutputStream::New (tmpFile.GetFilePath ());
205 outStream.Write (blob);
210 fLogger_ (LoggerMessage{LoggerMessage::Msg::eFailedToWriteFile, GetWriteFilePath_ (),
Characters::ToString (current_exception ())});
219 optional<VariantValue> r = fReader_.Read (MemoryStream::New<byte> (
ReadRaw ()));
220 if (r.has_value ()) {
221#if USE_NOISY_TRACE_IN_THIS_MODULE_
222 DbgTrace (
"present: upgrading module {}"_f, fModuleName_);
224 r = fModuleDataUpgrader_ (fModuleNameToFileVersionMapper_ (fModuleName_), *r);
226 fLogger_ (LoggerMessage{LoggerMessage::Msg::eSuccessfullyReadFile, GetReadFilePath_ ()});
230#if USE_NOISY_TRACE_IN_THIS_MODULE_
234 fLogger_ (LoggerMessage{LoggerMessage::Msg::eFailedToReadFile, GetReadFilePath_ (),
Characters::ToString (current_exception ())});
244 fWriter_.
Write (optionsObject, tmp);
248filesystem::path OptionsFile::GetReadFilePath_ ()
const
250 return fModuleNameToReadFileNameMapper_ (fModuleName_, fFileSuffix_);
253filesystem::path OptionsFile::GetWriteFilePath_ ()
const
255 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)