Precommit (#1)

* first commit

* cleanup
This commit is contained in:
tompzf
2025-11-04 13:28:06 +01:00
committed by GitHub
parent dba45dc636
commit 6ed4b1534e
898 changed files with 256340 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
# Define project
project(sdv_packager VERSION 1.0 LANGUAGES CXX)
# build test application
add_executable(sdv_packager
"main.cpp"
"../../sdv_services/core/installation_manifest.h"
"../../sdv_services/core/installation_manifest.cpp"
"../../sdv_services/core/installation_composer.h"
"../../sdv_services/core/installation_composer.cpp"
"../../sdv_services/core/toml_parser/parser_toml.h"
"../../sdv_services/core/toml_parser/parser_toml.cpp"
"../../sdv_services/core/toml_parser/lexer_toml.h"
"../../sdv_services/core/toml_parser/lexer_toml.cpp"
"../../sdv_services/core/toml_parser/parser_node_toml.h"
"../../sdv_services/core/toml_parser/parser_node_toml.cpp"
"../../sdv_services/core/toml_parser/character_reader_utf_8.h"
"../../sdv_services/core/toml_parser/character_reader_utf_8.cpp"
"../../sdv_services/core/toml_parser/exception.h"
"environment.cpp"
"environment.h"
"packager.cpp"
"packager.h"
)
if (WIN32)
target_link_libraries(sdv_packager ${CMAKE_THREAD_LIBS_INIT} Ws2_32 Winmm Rpcrt4.lib)
else()
target_link_libraries(sdv_packager ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT} rt)
endif()
# Build dependencies
add_dependencies(sdv_packager core_services)
# Execute the installation packager utility to create an installation manifest for the core files.
# TODO EVE
add_custom_command(
OUTPUT install_manifest.toml
COMMAND "$<TARGET_FILE:sdv_packager>" PACK core -O. ./*.sdv --create_manifest_only --verbose
DEPENDS sdv_packager dependency_sdv_services
WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
VERBATIM
)
add_custom_target(
install_manifest
DEPENDS install_manifest.toml
)
# Appending the executable to the service list
set(SDV_Executable_List ${SDV_Executable_List} sdv_packager PARENT_SCOPE)
set(SDV_Executable_List ${SDV_Executable_List} install_manifest PARENT_SCOPE)

View File

@@ -0,0 +1,971 @@
#include "environment.h"
#include <string_view>
#include "../../global/cmdlnparser/cmdlnparser.cpp"
CSdvPackagerEnvironment::CSdvPackagerEnvironment() : m_cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character)) {}
CSdvPackagerEnvironment::CSdvPackagerEnvironment(const std::vector<std::string>& rvecArgs) :
m_cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character))
{
// Create a classic argument array
std::vector<const char*> vecArgPtrs;
for (const std::string& rssArg : rvecArgs)
vecArgPtrs.push_back(rssArg.c_str());
// Call the constructor
*this = CSdvPackagerEnvironment(vecArgPtrs.size(), &vecArgPtrs.front());
}
bool CSdvPackagerEnvironment::Help() const
{
return m_bHelp;
}
void CSdvPackagerEnvironment::ShowHelp() const
{
size_t nArgumentGroup = 0;
std::stringstream sstreamText;
// Show default information:
sstreamText << "Component installation package utility. This utility can be used to pack, install and uninstall "
"SDV component installations on the current machine."
<< std::endl
<< std::endl;
// Show information based on the command.
switch (m_eOperatingMode)
{
case EOperatingMode::pack:
nArgumentGroup = 1;
sstreamText << "PACK command usage:" << std::endl
<< " sdv_package PACK <name> <files> [options]" << std::endl
<< std::endl;
sstreamText
<< "Provide one or more files to add to the installation onto the command line. Wildcards (**, *, ?) are "
"supported, allowing multiple files and directories to be added automatically. Instead regular expressions can also "
"be used by prefixing the paths by \"regex:\". If a specific target location (relative to the installation "
"directory) is required, this can be added by \"=<directory>\"."
<< std::endl
<< std::endl
<< "Examples:" << std::endl
<< " *.sdv - This will pack all SDV files from the input directory." << std::endl
<< " **/*.* - This will pack all files from all directories." << std::endl
<< " abc.sdv=mysub - This will pack \"abc.sdv\" into target \"mysub\"." << std::endl
<< " regex:[^/].sdv - This will pack all SDV files from the input directory." << std::endl
<< std::endl
<< "REMARKS: To create updatable components, use the '--set_version' option to set a version." << std::endl;
break;
case EOperatingMode::install:
nArgumentGroup = 2;
sstreamText << "INSTALL command usage:" << std::endl
<< " sdv_package INSTALL <package> [options]" << std::endl
<< std::endl;
sstreamText
<< "Install an installation package and update the configuration if applicable." << std::endl
<< std::endl
<< "The configuration uses an optional string following the option to define what to configure. The string is "
"separated "
"by the '+' separator followed by a list of components (separated by a comma ',' or a '+') to include in the "
"configuration. For example to update a local configuration ('--local' option) use:"
<< std::endl
<< " --config_fileabc.toml+my_component1,my_component2" << std::endl
<< "and a server configuration:" << std::endl
<< " --user_config+my_component1+my_component2" << std::endl
<< "If the configuration file is not existing, it will be created automatically." << std::endl
<< std::endl
<< "REMARKS: The server based installation can only take place when the system is offline. Use \"sdv_control\" "
"to install on a running server instance."
<< std::endl;
break;
case EOperatingMode::direct_install:
nArgumentGroup = 3;
sstreamText << "DIRECT_INSTALL command usage:" << std::endl
<< " sdv_package DIRECT_INSTALL <name> <files> [options]" << std::endl
<< std::endl;
sstreamText
<< "Provide one or more files to add to the installation onto the command line. Wildcards (**, *, ?) are "
"supported, allowing multiple files and directories to be added automatically. Instead regular expressions can also "
"used by prefixing the paths by \"regex:\". If a specific target location (relative to the installation "
"directory) is required, this can be added by \"=<directory>\"."
<< std::endl
<< std::endl
<< "Examples:" << std::endl
<< " *.sdv - This will install all SDV files from the input directory." << std::endl
<< " **/*.* - This will install all files from the input directory and sub-directories." << std::endl
<< " abc.sdv=mysub - This will install \"abc.sdv\" into target \"mysub\"." << std::endl
<< " regex:[^/].sdv - This will install all SDV files from the input directory." << std::endl
<< std::endl
<< "The configuration uses an optional string following the option to define what to configure. The string is "
"separated "
"by the '+' separator followed by a list of components (separated by a comma ',' or a '+') to include in the "
"configuration. For example to update a local configuration ('--local' option) use:"
<< std::endl
<< " --config_fileabc.toml+my_component1,my_component2" << std::endl
<< "and a server configuration:" << std::endl
<< " --user_config+my_component1+my_component2" << std::endl
<< "If the configuration file is not existing, it will be created automatically." << std::endl
<< std::endl
<< "REMARKS: The server based installation can only take place when the system is offline. Use \"sdv_control\" to "
"install "
"on a running server instance."
<< std::endl
<< std::endl
<< "REMARKS: To create updatable components, use the '--set_version' option to set a version." << std::endl;
break;
case EOperatingMode::uninstall:
nArgumentGroup = 4;
sstreamText << "UNINSTALL command usage:" << std::endl
<< " sdv_package UNINSTALL <name> <files> [options]" << std::endl
<< std::endl;
sstreamText
<< "Uninstall a previously installed package with the supplied name. Update the configuration files where "
"applicable."
<< std::endl
<< std::endl
<< "REMARKS: The server based unistallation can only take place when the system is offline. Use \"sdv_control\" to "
"install on a running server instance."
<< std::endl;
break;
case EOperatingMode::verify:
nArgumentGroup = 5;
sstreamText << "VERIFY command usage:" << std::endl
<< " sdv_package VERIFY <package> [options]" << std::endl
<< std::endl;
sstreamText << "Verify the package for corruption and/or tampering." << std::endl;
break;
case EOperatingMode::show:
nArgumentGroup = 6;
sstreamText << "SHOW command usage:" << std::endl
<< " sdv_package SHOW [ALL|INFO|MODULES|COMPONENTS] <package> [options]" << std::endl
<< std::endl;
sstreamText << "Show package information. The following information can be selected (multiple selections are possible):"
<< std::endl
<< " ALL Show all information about the package content." << std::endl
<< " INFO Show package information." << std::endl
<< " MODULES Show the modules contained in the package." << std::endl
<< " COMPONENTS Show the components contained in the package." << std::endl;
break;
default:
sstreamText << "Usage: sdv_package <command> [options]" << std::endl << std::endl;
sstreamText << "The following commands are available:" << std::endl
<< " PACK Create an installation package." << std::endl
<< " INSTALL Install an installation package." << std::endl
<< " DIRECT_INSTALL Install the components directly without creating an installation package."
<< std::endl
<< " UNINSTALL Uninstall a previously installed installation package." << std::endl
<< " VERIFY Verify the integrity of the installation package." << std::endl
<< " SHOW Show information about the installation package." << std::endl
<< std::endl
<< "For information about the options of each command, provide the '--help' option following the command."
<< std::endl;
break;
}
m_cmdln.PrintHelp(std::cout, sstreamText.str(), nArgumentGroup);
}
void CSdvPackagerEnvironment::ReportInfo() const
{
// Do not report anything
if (m_bSilent) return;
// Dependable on the verbose and the silent settings, select the output stream for information.
std::stringstream sstreamDummy;
std::ostream& rstreamVerbose = !m_bHelp && m_bVerbose ? std::cout : sstreamDummy;
std::ostream& rstreamNormal = m_bHelp || m_bSilent ? sstreamDummy : std::cout;
// Assign additional paths and report information...
switch (m_eOperatingMode)
{
case EOperatingMode::pack:
if (m_bCreateManifestOnly)
rstreamNormal << "Creating an installation manifest..." << std::endl;
else
rstreamNormal << "Creating an installation package..." << std::endl;
rstreamVerbose << "Source location: " << m_pathSourceLocation.generic_u8string() << std::endl;
rstreamVerbose << "Output location: " << m_pathOutputLocation.generic_u8string() << std::endl;
rstreamVerbose << "Installation name: " << m_ssInstallName << std::endl;
rstreamVerbose << "Product name: " << m_ssProductName << std::endl;
rstreamVerbose << "Package description: " << m_ssDescription << std::endl;
rstreamVerbose << "Author: " << m_ssAuthor << std::endl;
rstreamVerbose << "Address: " << m_ssAddress << std::endl;
rstreamVerbose << "Copyright: " << m_ssCopyrights << std::endl;
rstreamVerbose << "Version: " << m_ssPackageVersion << std::endl;
rstreamVerbose << "Keep directory structure: " << (m_bKeepStructure ? "true" : "false") << std::endl;
break;
case EOperatingMode::install:
rstreamNormal << "Installing a package..." << std::endl;
if (m_bCreateManifestOnly)
rstreamVerbose << "No file copy, creating manifest only..." << std::endl;
if (m_bLocal)
rstreamVerbose << "Local installation..." << std::endl;
else
rstreamVerbose << "Instance ID: " << m_uiInstanceID << std::endl;
rstreamVerbose << "Target base location: " << m_pathTargetLocation.generic_u8string() << std::endl;
rstreamVerbose << "Installation root location: " << m_pathRootLocation.generic_u8string() << std::endl;
rstreamVerbose << "Install location: " << m_pathInstallLocation.generic_u8string() << std::endl;
rstreamVerbose << "Update: " << (m_bUpdate ? "true" : "false") << std::endl;
rstreamVerbose << "Overwrite: " << (m_bOverwrite ? "true" : "false") << std::endl;
if (m_bLocal)
{
if (!m_pathConfigLocal.empty())
{
bool bInitial = true;
for (const auto& rpathConfigDir : m_vecLocalConfigDirs)
{
if (bInitial)
rstreamVerbose << "Config location: ";
else
rstreamVerbose << " ";
bInitial = false;
rstreamVerbose << rpathConfigDir.generic_u8string() << std::endl;
}
rstreamVerbose << "Config file: " << m_pathConfigLocal.generic_u8string() << std::endl;
}
}
else
{
bool bInitial = true;
for (const auto& rssComponent : m_vecUserConfigComponents)
{
if (bInitial)
rstreamVerbose << "User config components: ";
else
rstreamVerbose << " ";
bInitial = false;
rstreamVerbose << rssComponent << std::endl;
}
bInitial = true;
for (const auto& rssComponent : m_vecPlatformConfigComponents)
{
if (bInitial)
rstreamVerbose << "Platform config components: ";
else
rstreamVerbose << " ";
bInitial = false;
rstreamVerbose << rssComponent << std::endl;
}
bInitial = true;
for (const auto& rssComponent : m_vecVehIfcConfigComponents)
{
if (bInitial)
rstreamVerbose << "Vehicle interface config components: ";
else
rstreamVerbose << " ";
bInitial = false;
rstreamVerbose << rssComponent << std::endl;
}
bInitial = true;
for (const auto& rssComponent : m_vecVehAbstrConfigComponents)
{
if (bInitial)
rstreamVerbose << "Vehicle abstraction config components: ";
else
rstreamVerbose << " ";
bInitial = false;
rstreamVerbose << rssComponent << std::endl;
}
}
break;
case EOperatingMode::direct_install:
rstreamNormal << "Direct installation of modules..." << std::endl;
rstreamVerbose << "Source location: " << m_pathSourceLocation.generic_u8string() << std::endl;
if (m_bLocal)
rstreamVerbose << "Local installation..." << std::endl;
else
std::cout << "Instance ID: " << m_uiInstanceID << std::endl;
rstreamVerbose << "Target base location: " << m_pathTargetLocation.generic_u8string() << std::endl;
rstreamVerbose << "Installation root location: " << m_pathRootLocation.generic_u8string() << std::endl;
rstreamVerbose << "Install location: " << m_pathInstallLocation.generic_u8string() << std::endl;
rstreamVerbose << "Installation name: " << m_ssInstallName << std::endl;
rstreamVerbose << "Product name: " << m_ssProductName << std::endl;
rstreamVerbose << "Package description: " << m_ssDescription << std::endl;
rstreamVerbose << "Author: " << m_ssAuthor << std::endl;
rstreamVerbose << "Address: " << m_ssAddress << std::endl;
rstreamVerbose << "Copyright: " << m_ssCopyrights << std::endl;
rstreamVerbose << "Version: " << m_ssPackageVersion << std::endl;
rstreamVerbose << "Keep directory structure: " << (m_bKeepStructure ? "true" : "false") << std::endl;
rstreamVerbose << "Update: " << (m_bUpdate ? "true" : "false") << std::endl;
rstreamVerbose << "Overwrite: " << (m_bOverwrite ? "true" : "false") << std::endl;
if (!m_pathPackage.empty())
rstreamVerbose << "Package: " << m_pathPackage.generic_u8string() << std::endl;
if (m_bLocal)
{
if (!m_pathConfigLocal.empty())
{
bool bInitial = true;
for (const auto& rpathConfigDir : m_vecLocalConfigDirs)
{
if (bInitial)
rstreamVerbose << "Config location: ";
else
rstreamVerbose << " ";
bInitial = false;
rstreamVerbose << rpathConfigDir.generic_u8string() << std::endl;
}
rstreamVerbose << "Config file: " << m_pathConfigLocal.generic_u8string() << std::endl;
}
}
else
{
bool bInitial = true;
for (const auto& rssComponent : m_vecUserConfigComponents)
{
if (bInitial)
rstreamVerbose << "User config components: ";
else
rstreamVerbose << " ";
bInitial = false;
rstreamVerbose << rssComponent << std::endl;
}
bInitial = true;
for (const auto& rssComponent : m_vecPlatformConfigComponents)
{
if (bInitial)
rstreamVerbose << "Platform config components: ";
else
rstreamVerbose << " ";
bInitial = false;
rstreamVerbose << rssComponent << std::endl;
}
bInitial = true;
for (const auto& rssComponent : m_vecVehIfcConfigComponents)
{
if (bInitial)
rstreamVerbose << "Vehicle interface config components: ";
else
rstreamVerbose << " ";
bInitial = false;
rstreamVerbose << rssComponent << std::endl;
}
bInitial = true;
for (const auto& rssComponent : m_vecVehAbstrConfigComponents)
{
if (bInitial)
rstreamVerbose << "Vehicle abstraction config components: ";
else
rstreamVerbose << " ";
bInitial = false;
rstreamVerbose << rssComponent << std::endl;
}
}
break;
case EOperatingMode::uninstall:
rstreamNormal << "Uninstall installation..." << std::endl;
rstreamVerbose << "Target base location: " << m_pathTargetLocation.generic_u8string() << std::endl;
rstreamVerbose << "Installation root location: " << m_pathRootLocation.generic_u8string() << std::endl;
rstreamVerbose << "Install location: " << m_pathInstallLocation.generic_u8string() << std::endl;
rstreamVerbose << "Installation name: " << m_ssInstallName << std::endl;
if (m_bLocal)
{
bool bInitial = true;
for (const auto& rpathConfigDir : m_vecLocalConfigDirs)
{
if (bInitial)
rstreamVerbose << "Config location: ";
else
rstreamVerbose << " ";
bInitial = false;
rstreamVerbose << rpathConfigDir.generic_u8string() << std::endl;
}
}
break;
case EOperatingMode::verify:
rstreamNormal << "Verify package integrity..." << std::endl;
if (!m_pathPackage.empty())
rstreamVerbose << "Package: " << m_pathPackage.generic_u8string() << std::endl;
break;
case EOperatingMode::show:
rstreamNormal << "Show package information..." << std::endl;
rstreamVerbose << "Information: ";
if (m_uiShowFlags & static_cast<uint32_t>(EShowMask::info))
rstreamVerbose << "package ";
if (m_uiShowFlags & static_cast<uint32_t>(EShowMask::modules))
rstreamVerbose << "modules ";
if (m_uiShowFlags & static_cast<uint32_t>(EShowMask::components))
rstreamVerbose << "components";
rstreamVerbose << std::endl;
rstreamVerbose << "Output: ";
if (m_uiShowFlags & static_cast<uint32_t>(EShowMask::console))
rstreamVerbose << "console ";
if (m_uiShowFlags & static_cast<uint32_t>(EShowMask::xml))
rstreamVerbose << "xml ";
if (m_uiShowFlags & static_cast<uint32_t>(EShowMask::json))
rstreamVerbose << "json";
rstreamVerbose << std::endl;
if (!m_pathPackage.empty())
rstreamVerbose << "Package: " << m_pathPackage.generic_u8string() << std::endl;
break;
default:
rstreamNormal << "Nothing to do..." << std::endl;
break;
}
}
bool CSdvPackagerEnvironment::Silent() const
{
return m_bSilent;
}
bool CSdvPackagerEnvironment::Verbose() const
{
return m_bVerbose;
}
bool CSdvPackagerEnvironment::Version() const
{
return m_bVersion;
}
bool CSdvPackagerEnvironment::CreateManifestOnly() const
{
return m_bCreateManifestOnly;
}
CSdvPackagerEnvironment::EOperatingMode CSdvPackagerEnvironment::OperatingMode() const
{
return m_eOperatingMode;
}
bool CSdvPackagerEnvironment::KeepStructure() const
{
return m_bKeepStructure;
}
const std::vector<CSdvPackagerEnvironment::SModule>& CSdvPackagerEnvironment::ModuleList() const
{
return m_vecModules;
}
const std::filesystem::path& CSdvPackagerEnvironment::PackagePath() const
{
return m_pathPackage;
}
const std::filesystem::path& CSdvPackagerEnvironment::SourceLocation() const
{
return m_pathSourceLocation;
}
const std::filesystem::path& CSdvPackagerEnvironment::OutputLocation() const
{
return m_pathOutputLocation;
}
const std::filesystem::path& CSdvPackagerEnvironment::TargetLocation() const
{
return m_pathTargetLocation;
}
const std::filesystem::path& CSdvPackagerEnvironment::RootLocation() const
{
return m_pathRootLocation;
}
const std::filesystem::path& CSdvPackagerEnvironment::InstallLocation() const
{
return m_pathInstallLocation;
}
bool CSdvPackagerEnvironment::Local() const
{
return m_bLocal;
}
uint32_t CSdvPackagerEnvironment::InstanceID() const
{
return m_uiInstanceID;
}
bool CSdvPackagerEnvironment::Update() const
{
return m_bUpdate;
}
bool CSdvPackagerEnvironment::Overwrite() const
{
return m_bOverwrite;
}
const std::filesystem::path& CSdvPackagerEnvironment::LocalConfigFile(std::vector<std::string>& rvecComponents) const
{
rvecComponents = m_vecConfigLocalComponents;
return m_pathConfigLocal;
}
const std::vector<std::filesystem::path>& CSdvPackagerEnvironment::LocalConfigLocations() const
{
return m_vecLocalConfigDirs;
}
bool CSdvPackagerEnvironment::ActivateLocalConfig() const
{
return m_bActivateLocalConfig;
}
bool CSdvPackagerEnvironment::InsertIntoUserConfig(std::vector<std::string>& rvecComponents) const
{
rvecComponents = m_vecUserConfigComponents;
return m_bInsertIntoUserConfig;
}
bool CSdvPackagerEnvironment::InsertIntoPlatformConfig(std::vector<std::string>& rvecComponents) const
{
rvecComponents = m_vecPlatformConfigComponents;
return m_bInsertIntoPlatformConfig;
}
bool CSdvPackagerEnvironment::InsertIntoVehicleInterfaceConfig(std::vector<std::string>& rvecComponents) const
{
rvecComponents = m_vecVehIfcConfigComponents;
return m_bInsertIntoVehIfcConfig;
}
bool CSdvPackagerEnvironment::InsertIntoVehicleAbstractionConfig(std::vector<std::string>& rvecComponents) const
{
rvecComponents = m_vecVehAbstrConfigComponents;
return m_bInsertIntoVehAbstrConfig;
}
const std::string& CSdvPackagerEnvironment::InstallName() const
{
return m_ssInstallName;
}
const std::string& CSdvPackagerEnvironment::ProductName() const
{
return m_ssProductName;
}
const std::string& CSdvPackagerEnvironment::Description() const
{
return m_ssDescription;
}
const std::string& CSdvPackagerEnvironment::Author() const
{
return m_ssAuthor;
}
const std::string& CSdvPackagerEnvironment::Address() const
{
return m_ssAddress;
}
const std::string& CSdvPackagerEnvironment::Copyrights() const
{
return m_ssCopyrights;
}
const std::string& CSdvPackagerEnvironment::PackageVersion() const
{
return m_ssPackageVersion;
}
uint32_t CSdvPackagerEnvironment::ShowFlags() const
{
return m_uiShowFlags;
}
bool CSdvPackagerEnvironment::CheckShowFlag(EShowMask eMask) const
{
return (m_uiShowFlags & static_cast<uint32_t>(eMask)) == static_cast<uint32_t>(eMask);
}
int CSdvPackagerEnvironment::Error() const
{
return m_nError;
}
const std::string& CSdvPackagerEnvironment::ArgError() const
{
return m_ssArgError;
}
void CSdvPackagerEnvironment::SplitConfigString(const std::string& rssInput,
std::filesystem::path& rpath,
std::vector<std::string>& rvecComponents)
{
size_t nPos = rssInput.find('+');
rpath = std::filesystem::u8path(rssInput.substr(0, nPos));
while (nPos != std::string::npos)
{
size_t nNextPos = rssInput.find_first_of("+,", nPos + 1);
std::string ss = rssInput.substr(nPos + 1, nNextPos);
if (!ss.empty())
rvecComponents.push_back(ss);
nPos = nNextPos;
}
}
bool CSdvPackagerEnvironment::ProcessCommandLine(const std::vector<std::string>& rvecCommands)
{
// Make upper case string
auto fnMakeUpper = [](const std::string& rss)
{
std::string rssTemp;
rssTemp.reserve(rss.size());
for (char c : rss)
rssTemp += static_cast<char>(std::toupper(c));
return rssTemp;
};
// Process the first command...
size_t nOptionGroup = 0;
if (rvecCommands.empty())
{
m_eOperatingMode = EOperatingMode::none;
}
else if (iequals(rvecCommands[0], "PACK"))
{
m_eOperatingMode = EOperatingMode::pack;
nOptionGroup = 1;
}
else if (iequals(rvecCommands[0], "INSTALL"))
{
m_eOperatingMode = EOperatingMode::install;
nOptionGroup = 2;
}
else if (iequals(rvecCommands[0], "DIRECT_INSTALL"))
{
m_eOperatingMode = EOperatingMode::direct_install;
nOptionGroup = 3;
}
else if (iequals(rvecCommands[0], "UNINSTALL"))
{
m_eOperatingMode = EOperatingMode::uninstall;
nOptionGroup = 4;
}
else if (iequals(rvecCommands[0], "VERIFY"))
{
m_eOperatingMode = EOperatingMode::verify;
nOptionGroup = 5;
}
else if (iequals(rvecCommands[0], "SHOW"))
{
m_eOperatingMode = EOperatingMode::show;
nOptionGroup = 6;
}
else
{
m_nError = CMDLN_ARG_ERR;
m_ssArgError = "Invalid command \"" + rvecCommands[0] + "\" supplied at the command line.";
return false;
}
size_t nCommandPos = 1; // Start iteration at the second command argument
// Help requested? Do not continue parsing
if (m_bHelp)
return false;
// Check for silent and verbose flags.
if (m_bSilent && m_bVerbose)
{
m_nError = CMDLN_SILENT_VERBOSE;
m_ssArgError = CMDLN_SILENT_VERBOSE_MSG;
return false;
}
// Get the installation name
auto fnGetInstallName = [rvecCommands, &nCommandPos, this]() -> bool
{
// Expecting the installation name
if (nCommandPos >= rvecCommands.size())
{
m_nError = CMDLN_INSTALL_NAME_MISSING;
m_ssArgError = CMDLN_INSTALL_NAME_MISSING_MSG;
return false;
}
m_ssInstallName = rvecCommands[nCommandPos];
nCommandPos++;
return true;
};
// Get the modules to pack/install
auto fnGetModules = [rvecCommands, &nCommandPos, this]() -> bool
{
// Expecting at least one source
if (nCommandPos >= rvecCommands.size())
{
m_nError = CMDLN_SOURCE_FILE_MISSING;
m_ssArgError = CMDLN_SOURCE_FILE_MISSING_MSG;
return false;
}
for (;nCommandPos < rvecCommands.size(); nCommandPos++)
{
const std::string& rssCommand = rvecCommands[nCommandPos];
size_t nPos = rssCommand.find('=');
SModule sModule;
sModule.ssSearchString = rssCommand.substr(0, nPos);
if (nPos != std::string::npos)
sModule.pathRelTarget = std::filesystem::u8path(rssCommand.substr(nPos + 1));
m_vecModules.push_back(std::move(sModule));
}
return true;
};
// Cneck for no more commands
auto fnCheckForNoMoreCommands = [rvecCommands, &nCommandPos, this]() -> bool
{
if (nCommandPos != rvecCommands.size())
{
m_nError = CMDLN_TOO_MANY_SOURCE_FILES;
m_ssArgError = CMDLN_TOO_MANY_SOURCE_FILES_MSG;
return false;
}
return true;
};
// Get exactly one installation package
auto fnGetPackage = [rvecCommands, &nCommandPos, this]() -> bool
{
// Expecting exactly one installation package
if (nCommandPos >= rvecCommands.size())
{
m_nError = CMDLN_SOURCE_FILE_MISSING;
m_ssArgError = CMDLN_SOURCE_FILE_MISSING_MSG;
return false;
}
m_pathPackage = std::filesystem::u8path(rvecCommands[nCommandPos]);
nCommandPos++;
// Check for the correct ending and its existence
if (m_pathPackage.extension() != ".sdv_package" || !std::filesystem::exists(m_pathPackage)
|| !std::filesystem::is_regular_file(m_pathPackage))
{
m_nError = CMDLN_SOURCE_FILE_ERROR;
m_ssArgError = CMDLN_SOURCE_FILE_ERROR_MSG;
return false;
}
// Any commands left... then too many source files were supplied
if (nCommandPos != rvecCommands.size())
{
m_nError = CMDLN_TOO_MANY_SOURCE_FILES;
m_ssArgError = CMDLN_TOO_MANY_SOURCE_FILES_MSG;
}
return true;
};
// Check the source location
auto fnCheckSourceLocation = [this]() -> bool
{
// Check for the source location
if (m_pathSourceLocation.empty())
m_pathSourceLocation = std::filesystem::current_path();
if (!std::filesystem::is_directory(m_pathSourceLocation))
{
m_nError = CMDLN_SOURCE_LOCATION_ERROR;
m_ssArgError =
std::string(CMDLN_SOURCE_LOCATION_ERROR_MSG) + "\n Source location: " + m_pathSourceLocation.generic_u8string();
return false;
}
return true;
};
// Check the output location
auto fnCheckOutputLocation = [this]() -> bool
{
// Check for the output location (and create directory if needed)
if (m_pathOutputLocation.empty())
m_pathOutputLocation = std::filesystem::current_path();
try
{
if (!std::filesystem::is_directory(m_pathOutputLocation))
std::filesystem::create_directories(m_pathOutputLocation);
if (!std::filesystem::is_directory(m_pathOutputLocation))
{
m_nError = CMDLN_OUTPUT_LOCATION_ERROR;
m_ssArgError = std::string(CMDLN_OUTPUT_LOCATION_ERROR_MSG)
+ "\n Output location: " + m_pathOutputLocation.generic_u8string();
return false;
}
}
catch (const std::filesystem::filesystem_error&)
{
m_nError = CMDLN_OUTPUT_LOCATION_ERROR;
m_ssArgError =
std::string(CMDLN_OUTPUT_LOCATION_ERROR_MSG) + "\n Output location: " + m_pathOutputLocation.generic_u8string();
return false;
}
return true;
};
// Check the target location
auto fnCheckTargetLocation = [this]() -> bool
{
// Check for the target location (and create directory if needed)
try
{
// If not locally, get the target from the environment variable
if (!m_bLocal)
{
#ifdef _WIN32
const wchar_t* szInstallDir = _wgetenv(L"SDV_COMPONENT_INSTALL");
if (szInstallDir) m_pathTargetLocation = szInstallDir;
#elif defined __unix__
const char* szInstallDir = getenv("SDV_COMPONENT_INSTALL");
if (szInstallDir) m_pathTargetLocation = std::filesystem::u8path(szInstallDir);
#else
#error OS not supported!
#endif
}
// Is the directory existing? If not, creat ethe directory
if (!m_pathTargetLocation.empty() && !std::filesystem::is_directory(m_pathTargetLocation))
std::filesystem::create_directories(m_pathTargetLocation);
// The directory should exist; otherwise error.
if (m_pathTargetLocation.empty() || !std::filesystem::is_directory(m_pathTargetLocation))
{
m_nError = CMDLN_TARGET_LOCATION_ERROR;
m_ssArgError = std::string(CMDLN_TARGET_LOCATION_ERROR_MSG) + "\n Target location: " +
m_pathTargetLocation.generic_u8string();
return false;
}
}
catch (const std::filesystem::filesystem_error&)
{
m_nError = CMDLN_TARGET_LOCATION_ERROR;
m_ssArgError =
std::string(CMDLN_TARGET_LOCATION_ERROR_MSG) + "\n Target location: " + m_pathTargetLocation.generic_u8string();
return false;
}
return true;
};
// Get product
auto fnGetProduct = [this]()
{
if (m_ssProductName.empty())
m_ssProductName = m_ssInstallName;
};
// Following the initial command, several additional information must be supplied.
switch (m_eOperatingMode)
{
case EOperatingMode::pack:
if (!fnGetInstallName())
return false;
if (!fnGetModules())
return false;
if (!fnCheckSourceLocation())
return false;
if (!fnCheckOutputLocation())
return false;
fnGetProduct();
if (m_pathOutputLocation.empty())
m_pathPackage = std::filesystem::u8path(m_ssInstallName + ".sdv_package");
else
m_pathPackage = m_pathOutputLocation / std::filesystem::u8path(m_ssInstallName + ".sdv_package");
break;
case EOperatingMode::direct_install:
if (!fnGetInstallName())
return false;
if (!fnGetModules())
return false;
if (!fnCheckSourceLocation())
return false;
if (!fnCheckTargetLocation())
return false;
fnGetProduct();
break;
case EOperatingMode::install:
if (!fnGetPackage())
return false;
if (!fnCheckForNoMoreCommands())
return false;
if (!fnCheckTargetLocation())
return false;
break;
case EOperatingMode::uninstall:
if (!fnGetInstallName())
return false;
if (!fnCheckForNoMoreCommands())
return false;
if (!fnCheckTargetLocation())
return false;
break;
case EOperatingMode::verify:
if (!fnGetPackage())
return false;
if (!fnCheckForNoMoreCommands())
return false;
break;
case EOperatingMode::show:
// Expecting one or more show commands followed by one installation package
while (nCommandPos != rvecCommands.size())
{
if (!m_vecModules.empty())
{
m_nError = CMDLN_TOO_MANY_SOURCE_FILES;
m_ssArgError = CMDLN_TOO_MANY_SOURCE_FILES_MSG;
return false;
}
if (iequals(rvecCommands[nCommandPos], "ALL"))
{
m_uiShowFlags |= static_cast<uint32_t>(EShowMask::all);
nCommandPos++;
}
else if (iequals(rvecCommands[nCommandPos], "INFO"))
{
m_uiShowFlags |= static_cast<uint32_t>(EShowMask::info);
nCommandPos++;
}
else if (iequals(rvecCommands[nCommandPos], "MODULES"))
{
m_uiShowFlags |= static_cast<uint32_t>(EShowMask::modules);
nCommandPos++;
}
else if (iequals(rvecCommands[nCommandPos], "COMPONENTS"))
{
m_uiShowFlags |= static_cast<uint32_t>(EShowMask::components);
nCommandPos++;
}
else
{
// Check whether preceeded by at least one command
if (!(m_uiShowFlags & 0x00ff))
{
m_nError = CMDLN_MISSING_SHOW_COMMAND;
m_ssArgError = CMDLN_MISSING_SHOW_COMMAND_MSG;
return false;
}
if (!fnGetPackage())
return false;
}
}
if (m_pathPackage.empty())
{
m_nError = CMDLN_SOURCE_FILE_MISSING;
m_ssArgError = CMDLN_SOURCE_FILE_MISSING_MSG;
return false;
}
break;
default:
break;
}
// Check for incompatible options
auto vecIncompatibleOptions = m_cmdln.IncompatibleArguments(nOptionGroup, false);
if (!vecIncompatibleOptions.empty() && m_eOperatingMode != EOperatingMode::none)
{
m_nError = CMDLN_INCOMPATIBLE_ARGUMENTS;
m_ssArgError = std::string("The option '" + vecIncompatibleOptions[0] + "' cannot be used with the " +
fnMakeUpper(rvecCommands[0]) + " command.");
return false;
}
// Assign root and installation locations
m_pathRootLocation = m_pathTargetLocation;
if (!m_bLocal)
m_pathRootLocation /= std::to_string(m_uiInstanceID);
m_pathInstallLocation = m_pathRootLocation;
return true;
}

View File

@@ -0,0 +1,724 @@
#ifndef ENVIRONMENT_H
#define ENVIRONMENT_H
#include <string>
#include <vector>
#include <filesystem>
#include <cstdint>
#include "../../global/cmdlnparser/cmdlnparser.h"
#include "../error_msg.h"
#include <interfaces/config.h>
/**
* @brief Compare whether two characters are identical when both are converted to lower case.
* @remarks Cannot deal with Unicode letters comprising of more than one characters.
* @param[in] cLeft First character
* @param[in] cRight Second character
* @return The case independent equality of the characters.
*/
inline bool ichar_equals(char cLeft, char cRight)
{
return std::tolower(static_cast<unsigned char>(cLeft)) ==
std::tolower(static_cast<unsigned char>(cRight));
}
/**
* @brief Compare for case-independent equality.
* @param[in] rssLeft Reference to the left string.
* @param[in] rssRight Reference to the right string.
* @return The case-independent equality of the strings.
*/
inline bool iequals(const std::string& rssLeft, const std::string& rssRight)
{
return std::equal(rssLeft.begin(), rssLeft.end(), rssRight.begin(), rssRight.end(), ichar_equals);
}
class CSdvPackagerEnvironment
{
public:
/**
* @brief Environment exception triggered on error during command line processing.
*/
struct SEnvironmentException : std::exception
{
/**
* @brief Constructor
* @param[in] nCodeParam Exception code
* @param[in] rssDescriptionParam Reference to the exception description text.
*/
SEnvironmentException(int nCodeParam, const std::string& rssDescriptionParam) :
nCode(nCodeParam), ssDescription(rssDescriptionParam)
{}
/**
* @brief Returns the explanatory string.
* @return Pointer to the explanatory string as C-string.
*/
virtual const char* what() const noexcept
{
return ssDescription.c_str();
}
int nCode = 0; ///< Exception code
std::string ssDescription; ///< Exception description
};
/**
* @brief Operation mode the packager utility is running in.
*/
enum class EOperatingMode
{
none, ///< No mode selected
pack, ///< Packing operation (default)
direct_install, ///< Direct installation.
install, ///< Installation
uninstall, ///< Remove an installed package.
verify, ///< Verify integrity
show, ///< Show content
};
/**
* @brief Show information mask (multiple can be combined).
*/
enum class EShowMask
{
all = 0x00ff, ///< Show all information
info = 0x0001, ///< Show package information
modules = 0x0010, ///< Show modules
components = 0x0020, ///< Show components
console = 0x01000000, ///< Show as console output (extended form)
console_simple = 0x03000000, ///< Show as console output (simple form)
xml = 0x10000000, ///< Provide as XML
json = 0x20000000, ///< Provide as JSON
};
/**
* @brief Product version structure
*/
struct SVersion
{
size_t nMajor = 0; ///< Major version number
size_t nMinor = 0; ///< Minor version number
size_t nPatch = 0; ///< Patch level
};
/**
* @brief Module structure containing the module search string and relative target path.
* @details The module structure is used for module selection during packing and direct installation - hence the search string
* and potential target directory.
*/
struct SModule
{
std::string ssSearchString; ///< Module path; can contain wildcards and regular expression (therefore of
///< type std::string).
std::filesystem::path pathRelTarget; ///< Relative target path. Default is empty.
};
/**
* @brief Default constructor
*/
CSdvPackagerEnvironment();
/**
* @brief Constructor with program arguments.
* @param[in] rvecArgs Reference to the vector with program arguments
*/
CSdvPackagerEnvironment(const std::vector<std::string>& rvecArgs);
/**
* @brief Constructor with program arguments.
* @tparam TCharType Character type.
* @param[in] nArgs The amount of arguments.
* @param[in] rgszArgs Array of arguments.
*/
template <typename TCharType>
CSdvPackagerEnvironment(size_t nArgs, const TCharType** rgszArgs);
/**
* @brief Help was requested on the command line.
* @return Returns 'true' when help was requested. Otherwise returns 'false'.
*/
bool Help() const;
/**
* @brief Show command line help.
*/
void ShowHelp() const;
/**
* @brief Report information about the command and the settings dependable on the reporting flag.
*/
void ReportInfo() const;
/**
* @brief Return whether silent mode was requested for the console output.
* @return Returns whether the silent mode is switched on.
*/
bool Silent() const;
/**
* @brief Return whether verbose mode was requested for the console output.
* @return Returns whether the verbose mode is switched on.
*/
bool Verbose() const;
/**
* @brief Version information was requested on the command line.
* @return Returns 'true' when version info was requested. Otherwise returns 'false'.
*/
bool Version() const;
/**
* @brief Create a manifest during the creation phase.
* @return Returns whether a manifest should be the only output of the creation.
*/
bool CreateManifestOnly() const;
/**
* @brief The operating mode the packager is running in.
* @return Returns the current operating mode based on the command line settings.
*/
EOperatingMode OperatingMode() const;
/**
* @brief Keep the current structure during the installation. This requires a source input directory to be set.
* @return Returns whether a structure should be kept relative to the source directory.
*/
bool KeepStructure() const;
/**
* @brief List of modules or packages to create or install respectively.
* @return Returns a reference to the variable containing the list of modules or packages. Could contain wildcards and regular
* expression strings.
*/
const std::vector<SModule>& ModuleList() const;
/**
* @brief Get the package path. Available for installation, uninstallation, verification and content showing commands.
* @return Returns a reference to the variable containing the package path.
*/
const std::filesystem::path& PackagePath() const;
/**
* @brief During package creation, the source location of the modules and files to create the package for (or directly install).
* During package installation, source location of the package.
* @return Returns a reference to the variable containing the source location.
*/
const std::filesystem::path& SourceLocation() const;
/**
* @brief During package creation, the output location of the package file.
* @return Returns a reference to the variable containing the output location.
*/
const std::filesystem::path& OutputLocation() const;
/**
* @brief During package installation, base path to the package target location.
* @return Returns a reference to the variable containing the target location.
*/
const std::filesystem::path& TargetLocation() const;
/**
* @brief During package installation, base path to the package root location (including instance).
* @return Returns a reference to the variable containing the root location.
*/
const std::filesystem::path& RootLocation() const;
/**
* @brief During package installation, base path to the package installation location (including package name).
* @return Returns a reference to the variable containing the installation location.
*/
const std::filesystem::path& InstallLocation() const;
/**
* @brief Set when the local flag has been supplied on the command line.
* @return Returns whether local system operation is enabled.
*/
bool Local() const;
/**
* @brief The instance to use to install the package to.
* @return The instance ID.
*/
uint32_t InstanceID() const;
/**
* @brief Update if an older version has been found.
* @return Returns whether the update flag was specified.
*/
bool Update() const;
/**
* @brief Overwrite any version that might be installed before.
* @return Returns whether the overwrite flags was specified.
*/
bool Overwrite() const;
/**
* @brief Return the configuration file to create or update during the installation.
* @param[out] rvecComponents Reference to a list of component names to add to the configuration. If no components are listed, all components
* are to be added (if a configuration file was supplied).
* @return Returns a reference to the variable containing the path to the configuration file or empty when no file was supplied.
*/
const std::filesystem::path& LocalConfigFile(std::vector<std::string>& rvecComponents) const;
/**
* @brief During package installation, the configuration file locations during local operation.
* @return Returns a reference to the variable containing the vector with configuration locations.
*/
const std::vector<std::filesystem::path>& LocalConfigLocations() const;
/**
* @brief Activate the local configuration in the settings file of the system.
* @return Returns whether a configuration is requested.
*/
bool ActivateLocalConfig() const;
/**
* @brief Add the components to the user configuration.
* @remarks Only complex services will be inserted.
* @param[out] rvecComponents Reference to a list of component names to add to the configuration. If no components are listed, all components
* are to be added (if a the function returns true).
* @return Returns true if a configuration update is requested; false otherwise.
*/
bool InsertIntoUserConfig(std::vector<std::string>& rvecComponents) const;
/**
* @brief Add the components to the platform configuration.
* @param[out] rvecComponents Reference to a list of component names to add to the configuration. If no components are listed, all components
* are to be added (if a the function returns true).
* @return Returns true if a configuration update is requested; false otherwise.
*/
bool InsertIntoPlatformConfig(std::vector<std::string>& rvecComponents) const;
/**
* @brief Add the components to the vehicle interface configuration.
* @param[out] rvecComponents Reference to a list of component names to add to the configuration. If no components are listed, all components
* are to be added (if a the function returns true).
* @return Returns true if a configuration update is requested; false otherwise.
*/
bool InsertIntoVehicleInterfaceConfig(std::vector<std::string>& rvecComponents) const;
/**
* @brief Add the components to the vehicle abstraction configuration.
* @param[out] rvecComponents Reference to a list of component names to add to the configuration. If no components are listed, all components
* are to be added (if a the function returns true).
* @return Returns true if a configuration update is requested; false otherwise.
*/
bool InsertIntoVehicleAbstractionConfig(std::vector<std::string>& rvecComponents) const;
/**
* @brief The installation name for the package creation.
* @return Returns a reference to the variable containing the installation name.
*/
const std::string& InstallName() const;
/**
* @brief Get the product name. If not explicitly provided, this will be the installation name.
* @return Returns a reference to the variable containing the product name.
*/
const std::string& ProductName() const;
/**
* @brief Get the product description.
* @return Returns a reference to the variable containing the product description or empty if no description was provided.
*/
const std::string& Description() const;
/**
* @brief Get the product author.
* @return Returns a reference to the variable containing the product author or empty if no author was provided.
*/
const std::string& Author() const;
/**
* @brief Get the product author's address.
* @return Returns a reference to the variable containing the product author's address or empty if no address was provided.
*/
const std::string& Address() const;
/**
* @brief Get the product copyrights.
* @return Returns a reference to the variable containing the product copyrights or empty if no copyrights were provided.
*/
const std::string& Copyrights() const;
/**
* @brief Get the package version string (format: major.minor.patch).
* @return Returns a reference to the variable containing the package version string or empty if no version string was provided.
*/
const std::string& PackageVersion() const;
/**
* @brief Get the show flags.
* @return The shhow flags.
*/
uint32_t ShowFlags() const;
/**
* @brief Check whether the show flags contain certain flags.
* @param[in] eMask Show flag mask to check for.
* @return Returns true when the flags contaion exactly the provided mask.
*/
bool CheckShowFlag(EShowMask eMask) const;
/**
* @brief Was a commandline parse error or a logical error with command line arguments detected?
* @return Returns the result of the command line parsing. If no error occurs, NO_ERROR is returned.
*/
int Error() const;
/**
* @brief Parse error that might have occurred.
* @return Returns a reference to the variable containing the error text.
*/
const std::string& ArgError() const;
private:
/**
* @brief Split a configuration string in path and components.
* @details A configuration string can consist of &lt;path&gt;+component,component,component... The path might be optional. If
* missing, the string starts with '+'. The components might also be optional. If missing, the '+' is also not needed.
* @param[in] rssInput Reference to the configuration string.
* @param[out] rpath Reference to the path to be returned.
* @param[out] rvecComponents Reference to the vector containing the component names.
*/
void SplitConfigString(const std::string& rssInput, std::filesystem::path& rpath, std::vector<std::string>& rvecComponents);
/**
* @brief Process the parsed environment settings.
* @param[in] rvecCommands Commands list from the command line.
* @return Returns true on successful processing, false when an error has occurred.
*/
bool ProcessCommandLine(const std::vector<std::string>& rvecCommands);
CCommandLine m_cmdln; ///< Command line parsing class.
bool m_bHelp = false; ///< Set when help was requested on the command line.
bool m_bSilent = false; ///< Set when silent mode is enabled.
bool m_bVerbose = false; ///< Set when verbose reporting mode is enabled.
bool m_bVersion = false; ///< Set when version information was requested.
bool m_bKeepStructure = false; ///< When set, keep the source directory structure.
bool m_bCreateManifestOnly = false; ///< Create a manifest only.
bool m_bLocal = false; ///< When set, the installation is on a local instance only.
bool m_bUpdate = false; ///< Update an existing installation.
bool m_bOverwrite = false; ///< Overwrite an existing installation.
EOperatingMode m_eOperatingMode = EOperatingMode::none; ///< Operating mode of the packager utility.
std::vector<SModule> m_vecModules; ///< List of modules (module search string).
std::filesystem::path m_pathSourceLocation; ///< Path to the input location.
std::filesystem::path m_pathOutputLocation; ///< Path to the output location.
std::filesystem::path m_pathTargetLocation; ///< Path to the target location (at installation).
std::filesystem::path m_pathRootLocation; ///< Target root location (includes the instance for server location).
std::filesystem::path m_pathInstallLocation; ///< Target install location (root location with installation name).
std::filesystem::path m_pathPackage; ///< Path to the package during installation, uninstallation, integrity checking and
///< content showing.
uint32_t m_uiInstanceID = 1000u; ///< Instance number (optional).
std::string m_ssInstallName; ///< Installation name.
std::string m_ssProductName; ///< Product name (default is package name).
std::string m_ssDescription; ///< Product description
std::string m_ssAuthor; ///< Author
std::string m_ssAddress; ///< Company address
std::string m_ssCopyrights; ///< Copyright
std::string m_ssPackageVersion; ///< Package version string
std::filesystem::path m_pathConfigLocal; ///< Configuration file path (local only).
std::vector<std::string> m_vecConfigLocalComponents; ///< List of components to add to the configuration file.
bool m_bActivateLocalConfig = false; ///< Activate the local config in the settings file.
std::vector<std::filesystem::path> m_vecLocalConfigDirs; ///< List of directories to scan for the component to uninstall.
std::vector<std::string> m_vecUserConfigComponents; ///< User configuration (server only).
std::vector<std::string> m_vecPlatformConfigComponents; ///< Platform configuration (server only).
std::vector<std::string> m_vecVehIfcConfigComponents; ///< Vehicle interface configuration (server only).
std::vector<std::string> m_vecVehAbstrConfigComponents; ///< Vehicle abstraction configuration (server only).
bool m_bInsertIntoUserConfig = false; ///< When set, insert the components into the user config (server only).
bool m_bInsertIntoPlatformConfig = false;///< When set, insert the components into the platform config (server only).
bool m_bInsertIntoVehIfcConfig = false; ///< When set, insert the components into the vehicle interface config (server only).
bool m_bInsertIntoVehAbstrConfig = false;///< When set, insert the components into the vehicle abstraction config (server only).
uint32_t m_uiShowFlags = 0; ///< Show package information bitmask.
int m_nError = NO_ERROR; ///< Error code after processing the command line.
std::string m_ssArgError; ///< Error text after processing the command line.
};
template <typename TCharType>
CSdvPackagerEnvironment::CSdvPackagerEnvironment(size_t nArgs, const TCharType** rgszArgs) :
m_cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character))
{
m_cmdln.PrintMaxWidth(80);
m_cmdln.PrintSyntax(false);
try
{
std::vector<std::string> vecCommands;
// COMMANDS (selective argument groups 1-6):
// PACK Pack modules and files into an installation package
// Usage: sdv_packager PACK <package name> <files> <options>
// INSTALL Install a package into the system
// Usage: sdv_packager INSTALL <package path> <options>
// DIRECT_INSTALL Directly install modules and files into the system (without the creation of a package)
// Usage: sdv_packager DIRECT_INSTALL <package name> <files> <options>
// UNINSTALL Remove an installation from the system
// Usage: sdv_packager UNINSTALL <package name> <options>
// VERIFY Verify the consistency and the integrity of an installation package.
// Usage: sdv_packager VERIFY <package path> <options>
// SHOW Show package information
// Usage: sdv_packager SHOW <ALL|INFO|MODULES|COMPONENTS> <package path> <options>
m_cmdln.DefineDefaultArgument(vecCommands, "COMMAND <...> <options>");
// ARGUMENT SELECTION GROUP #0 - General options:
// -?, --help Show help
// -s, --silent Silent mode
// -v, --verbose Verbose mode
// --version Show version
auto& rArgHelpDef = m_cmdln.DefineOption("?", m_bHelp, "Show help", true, 0, 1, 2, 3, 4, 5, 6);
rArgHelpDef.AddSubOptionName("help");
auto& rArgSilentDef = m_cmdln.DefineOption("s", m_bSilent, "Do not show any information on STDOUT. Not compatible with "
"'--verbose'.");
rArgSilentDef.AddSubOptionName("silent");
auto& rArgVerboseDef = m_cmdln.DefineOption("v", m_bVerbose, "Provide verbose information. Not compatible with "
"'--silent'.");
rArgVerboseDef.AddSubOptionName("verbose");
m_cmdln.DefineSubOption("version", m_bVersion, "Show version information.");
// ARGUMENT SELECTION GROUP #2 & #3 & #4: General options during installation/uninstallation
// -L, --local Local installation
// --instance<id> Instance ID to use for installation
auto& rLocalArgDef = m_cmdln.DefineOption("L", m_bLocal, "Target the local system.", true, 2, 3, 4);
rLocalArgDef.AddSubOptionName("local");
auto& rInstance = m_cmdln.DefineSubOption("instance", m_uiInstanceID, "The instance ID of the SDV server instance when not "
"targeting the local system (default ID is 1000).", true, 2, 3, 4);
// ARGUMENT SELECTION GROUP #1 - Packing:
// -O<path> Optional destination location
// --signature<path> Path to the file to use to sign the package (not implemented yet)
m_cmdln.DefineGroup("Package creation");
m_cmdln.DefineOption("O", m_pathOutputLocation, "The output location (optional, default is current directory).", true, 1);
// ARGUMENT SECLECTION GROUP #1 & #3 - Packing and direct installation:
// -I<path> Optional source location
// --keep_structure Maintain original directory structure
// --create_manifest_only Create a manifest file only
// --set_product<string> Set the product name (if not identical to installation name).
// --set_description<string> Set the package description
// --set_author<string> Set author string
// --set_address<string> Set address string (multi-line)
// --set_copyright<string> Set copyright string
// --set_version<string> Set product version string (also use for updates).
m_cmdln.DefineOption("I", m_pathSourceLocation, "The source location (optional, default is current directory).", true,
1, 3);
m_cmdln.DefineSubOption("keep_structure", m_bKeepStructure, "Maintain the directory structure within the package. In "
"combination with the source location (current directory or directory provided by '-I' option).", true, 1, 3);
m_cmdln.DefineSubOption("create_manifest_only", m_bCreateManifestOnly, "Create manifest, but does not copy module files "
"from specified location. If provided, the manifest will be stored in the output directory (current directory or "
"directory provided by '-O' option).", true, 1);
m_cmdln.DefineSubOption("set_product", m_ssProductName, "Set the product name (default is package name).", true, 1, 3);
m_cmdln.DefineSubOption("set_description", m_ssDescription, "Set the package description.", true, 1, 3);
m_cmdln.DefineSubOption("set_author", m_ssAuthor, "Set author name.", true, 1, 3);
m_cmdln.DefineSubOption("set_address", m_ssAddress, "Set author address information.", true, 1, 3);
m_cmdln.DefineSubOption("set_copyright", m_ssCopyrights, "Set copyright information.", true, 1, 3);
m_cmdln.DefineSubOption("set_version", m_ssPackageVersion, "Set package version (needed to allow updates).", true, 1, 3);
// ARGUMENT SELECTION GROUP #2 & #3 & #4- Installation from package and direct installation:
// -T<path> Optional target location
// -P, --update Use update if a previous package with older version has been found
// -W, --overwrite Use overwrite if a previous package has been found
// --verify_signed Verify whether the package is signed and if not return an error (not implemented)
m_cmdln.DefineGroup("Installation / uninstallation");
auto& rTargetLoc = m_cmdln.DefineOption("T", m_pathTargetLocation, "The target location for package installation. Required "
"when targeting a local system ('--local' option).", true, 2, 3, 4);
auto& rArgDefUpdate = m_cmdln.DefineOption("P", m_bUpdate, "Update the installation if an older version is existing.",
true, 2, 3);
rArgDefUpdate.AddSubOptionName("update");
auto& rArgDefOverwrite = m_cmdln.DefineOption("W", m_bOverwrite, "Overwrite the installation if an installation is "
"existing (regardless of the installed version).", true, 2, 3);
rArgDefOverwrite.AddSubOptionName("overwrite");
// Configuration
// ARGUMENT SELECTION GROUP #2 & #3 & #4 - Update from package and directly and uninstallation:
// --config_dir<paths...> Local instance only; directory to configuration files to update.
m_cmdln.DefineGroup("Configuration update");
auto& rConfigDir = m_cmdln.DefineSubOption("config_dir", m_vecLocalConfigDirs, "One or more configuration directories "
"to scan for components being updated. Use with local systems only ('--local' option).", true, 2, 3, 4);
// --config_file<path>[=<x,>[all,-component,-...]|[+component,+....]] Local instance only; configuration file.
// --activate_config Local instance only; select config into settings.
// --user_config[=<x,>[all,-component,-...]|[+component,+....]] Server instance only; user configuration.
// --platform_config[=<x,>[all,-component,-...]|[+component,+....]] Server instance only; platform config.
// --vehifc_config[=<x,>[all,-component,-...]|[+component,+....]] Server instance only; vehicle interface config.
// --vehabstr_config[=<x,>[all,-component,-...]|[+component,+....]] Server instance only; vehicle abstraction config.
std::string ssConfigFileLocal;
auto& rConfigFile = m_cmdln.DefineSubOption("config_file", ssConfigFileLocal, "Update a user configuration file. For "
"usage, see explanatory text above. Use with local systems only ('--local' option).", true, 2, 3);
auto& rActivateConfig = m_cmdln.DefineSubOption("activate_config", m_bActivateLocalConfig, "Update the settings file to "
"automatically activate the provided configuration file. Use with local system only ('--local' option).", true, 2, 3);
std::string ssUserConfigServer, ssPlatformConfigServer, ssInterfaceConfigServer, ssAbstrConfigServer;
auto& rPlatformConfig = m_cmdln.DefineSubOption("platform_config", ssPlatformConfigServer, "Update the platform "
"configuration defining which components of this installation are used to interact with the hardware platform. For "
"usage, see explanatory text above. Use on server only.", true, 2, 3);
auto& rInterfaceConfig = m_cmdln.DefineSubOption("interface_config", ssInterfaceConfigServer, "Update the vehicle "
"interface configuration defining which components of this installation represent the vehicle interface. For usage, "
"see explanatory text above. Use on server only.", true, 2, 3);
auto& rAbstrConfig = m_cmdln.DefineSubOption("abstract_config", ssAbstrConfigServer, "Update the vehicle abstraction "
"configuration defining which components of this installation represent an abstracted vehicle to the application "
"components. For usage, see explanatory text above. Use on server only.", true, 2, 3);
auto& rUserConfig = m_cmdln.DefineSubOption("user_config", ssUserConfigServer, "Update the user configuration defining "
"which components of this installation need to be instantiated automatically. User configuration can only contain "
"complex services. For usage, see explanatory text above. Use on server only.", true, 2, 3);
// ARGUMENT SELECTION GROUP #5 - Package verififcation
m_cmdln.DefineGroup("Verification options");
// --verify_signed Verify whether the package is signed and if not return an error (not implemented)
// ARGUMENT SELECTION GROUP #6 - Show package information
// --show_simple
// --xml (not implemented)
// --json (not implemented)
m_cmdln.DefineGroup("Show options");
bool bShowSimple = false;
m_cmdln.DefineSubOption("show_simple", bShowSimple, "Show package information in simple format.", true, 6);
m_cmdln.Parse(static_cast<size_t>(nArgs), rgszArgs);
// Process the command line
if (!ProcessCommandLine(vecCommands)) return;
// Update show mask
if (bShowSimple)
m_uiShowFlags |= static_cast<uint32_t>(EShowMask::console_simple);
else // TODO: if not XML and JSON, add console
m_uiShowFlags |= static_cast<uint32_t>(EShowMask::console);
// Split the configuration strings
if (!ssConfigFileLocal.empty())
SplitConfigString(ssConfigFileLocal, m_pathConfigLocal, m_vecConfigLocalComponents);
if (rUserConfig.OptionAvailableOnCommandLine())
{
m_bInsertIntoUserConfig = true;
std::filesystem::path rpathTemp;
SplitConfigString(ssUserConfigServer, rpathTemp, m_vecUserConfigComponents);
if (!rpathTemp.empty())
{
m_nError = CMDLN_INVALID_CONFIG_STRING;
m_ssArgError = CMDLN_INVALID_CONFIG_STRING_MSG;
return;
}
}
if (rPlatformConfig.OptionAvailableOnCommandLine())
{
m_bInsertIntoPlatformConfig = true;
std::filesystem::path rpathTemp;
SplitConfigString(ssPlatformConfigServer, rpathTemp, m_vecPlatformConfigComponents);
if (!rpathTemp.empty())
{
m_nError = CMDLN_INVALID_CONFIG_STRING;
m_ssArgError = CMDLN_INVALID_CONFIG_STRING_MSG;
return;
}
}
if (rInterfaceConfig.OptionAvailableOnCommandLine())
{
m_bInsertIntoVehIfcConfig = true;
std::filesystem::path rpathTemp;
SplitConfigString(ssInterfaceConfigServer, rpathTemp, m_vecVehIfcConfigComponents);
if (!rpathTemp.empty())
{
m_nError = CMDLN_INVALID_CONFIG_STRING;
m_ssArgError = CMDLN_INVALID_CONFIG_STRING_MSG;
return;
}
}
if (rAbstrConfig.OptionAvailableOnCommandLine())
{
m_bInsertIntoVehAbstrConfig = true;
std::filesystem::path rpathTemp;
SplitConfigString(ssAbstrConfigServer, rpathTemp, m_vecVehAbstrConfigComponents);
if (!rpathTemp.empty())
{
m_nError = CMDLN_INVALID_CONFIG_STRING;
m_ssArgError = CMDLN_INVALID_CONFIG_STRING_MSG;
return;
}
}
// Check for the local flag and if set, this is not compatible to server options.
// Also if not set, local options are not allowed.
if (m_bLocal)
{
if (rInstance.OptionAvailableOnCommandLine())
{
m_nError = CMDLN_INCOMPATIBLE_ARGUMENTS;
m_ssArgError = "The option '--instance' cannot be used with with local installations ('--local' option).";
return;
}
if (rUserConfig.OptionAvailableOnCommandLine() || rPlatformConfig.OptionAvailableOnCommandLine() ||
rInterfaceConfig.OptionAvailableOnCommandLine() || rAbstrConfig.OptionAvailableOnCommandLine())
{
m_nError = CMDLN_INCOMPATIBLE_ARGUMENTS;
m_ssArgError = "The configuration options '--user_config', '--platform_config', '--vehifc_config' and "
"'--vehabstr_config' cannot be used with with local installations ('--local' option).";
return;
}
if (!rTargetLoc.OptionAvailableOnCommandLine())
{
m_nError = CMDLN_TARGET_LOCATION_ERROR;
m_ssArgError = "The target location option '-T' must be used when specifying local installations ('--local' "
"option).";
return;
}
if (rActivateConfig.OptionAvailableOnCommandLine() && !rConfigFile.OptionAvailableOnCommandLine())
{
m_nError = CMDLN_INCOMPATIBLE_ARGUMENTS;
m_ssArgError = "Activating a configuration file using the option '--activate_config' can only be used with when a "
"configuration file is provided using the option '--config_file'.";
return;
}
} else
{
if (rConfigFile.OptionAvailableOnCommandLine())
{
m_nError = CMDLN_INCOMPATIBLE_ARGUMENTS;
m_ssArgError = "The configuration file option '--config_path' can only be used with with local installations "
"('--local' option).";
return;
}
if (rActivateConfig.OptionAvailableOnCommandLine())
{
m_nError = CMDLN_INCOMPATIBLE_ARGUMENTS;
m_ssArgError = "The configuration file option '--activate_config' can only be used with with local "
"installations ('--local' option).";
return;
}
if (rConfigDir.OptionAvailableOnCommandLine())
{
m_nError = CMDLN_INCOMPATIBLE_ARGUMENTS;
m_ssArgError = "The configuration file option '--config_dir' can only be used with with local installations "
"('--local' option).";
return;
}
if (rTargetLoc.OptionAvailableOnCommandLine())
{
m_nError = CMDLN_INCOMPATIBLE_ARGUMENTS;
m_ssArgError = "The target location option '-T' can only be used with with local installations ('--local' option).";
return;
}
}
// Check update and overwrite
if (m_bUpdate && m_bOverwrite)
{
m_nError = CMDLN_UPDATE_OVERWRITE_ERROR;
m_ssArgError = CMDLN_UPDATE_OVERWRITE_ERROR_MSG;
return;
}
} catch (const SArgumentParseException& rsExcept)
{
// If not all fits, but help is requested, this is okay...
// Otherwise throw an environment exception.
if (!m_bHelp)
{
m_nError = CMDLN_ARG_ERR;
m_ssArgError = rsExcept.what();
return;
}
}
}
#endif // !defined ENVIRONMENT_H

View File

@@ -0,0 +1,514 @@
#include "../../global/process_watchdog.h"
#include <support/mem_access.h>
#include <support/sdv_core.h>
#include <support/app_control.h>
#include <support/toml.h>
#include "../../global/exec_dir_helper.h"
#include "../../global/filesystem_helper.h"
#include "../../sdv_services/core/installation_manifest.h"
#include <filesystem>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <set>
#include "packager.h"
#if defined(_WIN32) && defined(_UNICODE)
extern "C" int wmain(int iArgc, const wchar_t* rgszArgv[])
#else
extern "C" int main(int iArgc, const char* rgszArgv[])
#endif
{
// Workaround for GCC to make certain that POSIX thread library is loaded before the components are loaded.
// REASON: If the first call to a thread is done in a dynamic library, the application is already classified as single
// threaded and a termination is initiated.
// See: https://stackoverflow.com/questions/51209268/using-stdthread-in-a-library-loaded-with-dlopen-leads-to-a-sigsev
// NOTE EVE 27.05.2025: This task has been taken over by the process watchdog.
CProcessWatchdog watchdog;
// If not set, set the runtime location to the EXE directory.
if (sdv::app::CAppControl::GetFrameworkRuntimeDirectory().empty())
sdv::app::CAppControl::SetFrameworkRuntimeDirectory(GetExecDirectory());
if (sdv::app::CAppControl::GetComponentInstallDirectory().empty())
sdv::app::CAppControl::SetComponentInstallDirectory(GetExecDirectory());
// Process the command line.
CSdvPackagerEnvironment environment(iArgc, rgszArgv);
// Print tool title
if (!environment.Silent())
{
std::cout << "SDV Component Installation Package Utility" << std::endl;
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
std::cout << "Author: Erik Verhoeven" << std::endl << std::endl;
}
// Version requested?
if (environment.Version() || environment.Verbose())
std::cout << "Version: " << (SDVFrameworkBuildVersion / 100) << "." << (SDVFrameworkBuildVersion % 100) << " build " <<
SDVFrameworkSubbuildVersion << " interface " << SDVFrameworkInterfaceVersion << std::endl << std::endl;
if (!environment.ArgError().empty() && !environment.Silent())
std::cerr << "ERROR: " << environment.ArgError() << std::endl;
if (environment.Help())
{
if (!environment.Silent())
{
if (environment.Error() != NO_ERROR)
std::cout << std::endl;
environment.ShowHelp();
}
return environment.Error();
}
if (environment.Error()) return CMDLN_ARG_ERR;
// Report information about the settings
environment.ReportInfo();
// Anything to do?
if (environment.OperatingMode() == CSdvPackagerEnvironment::EOperatingMode::none) return NO_ERROR;
CPackager packager(environment);
packager.Execute();
if (!packager.ArgError().empty() && !environment.Silent())
std::cerr << "ERROR: " << packager.ArgError() << std::endl;
return packager.Error();
#if 0
if (environment.CreateManifestOnly() && environment.Verbose())
std::cout << "No file copy, creating manifest only..." << std::endl;
if (!environment.Silent())
std::cout << "Installation name: " << environment.InstallName() << std::endl;
if (!environment.CreateManifestOnly())
{
if (environment.Verbose())
std::cout << "Instance ID: " << environment.InstanceID() << std::endl;
}
std::filesystem::path pathTargetRoot = environment.TargetLocation();
pathTargetRoot /= std::to_string(environment.InstanceID());
if (environment.Verbose())
std::cout << "Target root location: " << pathTargetRoot.generic_u8string() << std::endl;
if (environment.Verbose())
{
if (environment.OperatingMode() == CSdvPackagerEnvironment::EOperatingMode::pack)
std::cout << "Installing a package..." << std::endl;
else
{
if (environment.OperatingMode() == CSdvPackagerEnvironment::EOperatingMode::direct_install)
std::cout << "Direct installation of modules..." << std::endl;
else if (environment.CreateManifestOnly())
std::cout << "Creating an installation manifest..." << std::endl;
else
std::cout << "Creating an installation package..." << std::endl;
}
}
std::filesystem::path pathInstallLocation = environment.TargetLocation();
if (!environment.CreateManifestOnly())
{
pathInstallLocation /= std::to_string(environment.InstanceID());
pathInstallLocation /= environment.InstallName();
if (environment.Verbose())
std::cout << "Install location: " << pathInstallLocation.generic_u8string() << std::endl;
}
if (!environment.ConfigPath().empty())
{
if (environment.ConfigPath().is_relative()) environment.ConfigPath() = pathTargetRoot / environment.ConfigPath();
if (environment.Verbose())
std::cout << "Config location: " << environment.ConfigPath().parent_path().generic_u8string() << std::endl;
}
if (environment.CreateManifestOnly())
environment.InputLocation() = environment.TargetLocation();
if (environment.Verbose())
std::cout << "Source location: "
<< (environment.InputLocation().empty() ? "not provided" : environment.InputLocation().generic_u8string()) << std::endl;
// ================= START OF OPERATION =================
// Start the application control
sdv::app::CAppControl appcontrol;
std::string ssAppConfigTOML = R"code(
[Application]
Mode="Essential"
)code";
ssAppConfigTOML += "Instance=" + std::to_string(environment.InstanceID());
// Start the appcontrol
if (!appcontrol.Startup(ssAppConfigTOML))
{
if (!environment.Silent())
std::cerr << "ERROR: " << APP_CONTROL_STARTUP_ERROR_MSG << std::endl;
return APP_CONTROL_STARTUP_ERROR;
}
// Create the target directory
try
{
std::filesystem::create_directories(environment.TargetLocation());
}
catch (const std::filesystem::filesystem_error& /*rexcept*/)
{
if (!environment.Silent())
std::cerr << "ERROR: " << CREATE_TARGET_DIR_ERROR_MSG << std::endl;
return CREATE_TARGET_DIR_ERROR;
}
if (!environment.CreateManifestOnly())
{
// Remove existing installation directory
try
{
if (std::filesystem::exists(pathInstallLocation))
std::filesystem::remove_all(pathInstallLocation);
}
catch (const std::filesystem::filesystem_error& /*rexcept*/)
{
if (!environment.Silent())
std::cerr << "ERROR: " << CANNOT_REMOVE_INSTALL_DIR_MSG << std::endl;
return CANNOT_REMOVE_INSTALL_DIR;
}
// Create the installation directory
try
{
std::filesystem::create_directories(pathInstallLocation);
}
catch (const std::filesystem::filesystem_error& /*rexcept*/)
{
if (!environment.Silent())
std::cerr << "ERROR: " << CREATE_INSTALL_DIR_ERROR_MSG << std::endl;
return CREATE_INSTALL_DIR_ERROR;
}
}
// Create the config directory
if (!environment.ConfigPath().empty())
{
try
{
std::filesystem::create_directories(environment.ConfigPath().parent_path());
}
catch (const std::filesystem::filesystem_error& /*rexcept*/)
{
if (!environment.Silent())
std::cerr << "ERROR: " << CREATE_CONFIG_DIR_ERROR_MSG << std::endl;
return CREATE_CONFIG_DIR_ERROR;
}
}
// Add the installation manifest
CInstallManifest manifest;
manifest.Create(environment.InstallName());
// Process all modules
std::set<std::filesystem::path> setModules;
for (std::filesystem::path& rpathSearchModule : environment.ModuleList())
{
if (environment.Verbose())
std::cout << "Supplied module: " << rpathSearchModule.generic_u8string() << std::endl;
if (rpathSearchModule.is_relative()) rpathSearchModule = environment.InputLocation() / rpathSearchModule;
// Does the path have wildcards?
bool bHasWildcards = rpathSearchModule.generic_u8string().find_first_of("*?") != std::string::npos;
// Get a list of modules based on the module search criteria
std::vector<std::filesystem::path> vecSearchedModules = FindFilesWithWildcards(rpathSearchModule);
if (vecSearchedModules.empty() && !bHasWildcards)
{
if (!environment.Silent())
std::cerr << "ERROR: " << CMDLN_SOURCE_FILE_ERROR_MSG << " (" << rpathSearchModule.generic_u8string() << ")" <<
std::endl;
return CMDLN_SOURCE_FILE_ERROR;
}
// Process each module...
for (std::filesystem::path& rpathModule : vecSearchedModules)
{
// Processed already?
if (setModules.find(rpathModule) != setModules.end()) continue;
setModules.insert(rpathModule);
// Determine the relative path to from source location
std::filesystem::path pathRelSource;
try
{
pathRelSource = environment.InputLocation().empty() ?
rpathModule.filename() : std::filesystem::proximate(rpathModule, environment.InputLocation());
} catch (std::filesystem::filesystem_error& /*rexcept*/)
{}
if (pathRelSource.empty() || pathRelSource.begin()->string() == "..")
{
if (!environment.Silent())
std::cerr << "ERROR: The source directory must be a parent of the module! The module will not be installed." <<
std::endl;
continue;
}
if (!environment.Silent())
std::cout << "Processing module: " << pathRelSource.generic_u8string() << std::endl;
if (!std::filesystem::exists(rpathModule) || !std::filesystem::is_regular_file(rpathModule))
{
if (!environment.Silent())
std::cerr << "ERROR: Module cannot be found or is invalid!" << std::endl;
continue;
}
if (!environment.CreateManifestOnly())
{
// Create target module path
std::filesystem::path pathPargetModule = pathInstallLocation / pathRelSource;
// Create the target directory if not existing
try
{
std::filesystem::create_directories(pathPargetModule.parent_path());
}
catch (std::filesystem::filesystem_error& /*rexcept*/)
{
if (!environment.Silent())
std::cerr << "ERROR: Cannot create the module target directory!" << std::endl;
continue;
}
// Copy the file to there
std::filesystem::copy(rpathModule, pathPargetModule);
if (environment.Verbose())
std::cout << "Target module: " << pathPargetModule.generic_u8string() << std::endl;
}
// Add the installation manifest
if (!manifest.AddModule(rpathModule))
{
if (!environment.Silent())
std::cerr << "ERROR: Cannot store the component manifest!" << std::endl;
continue;
}
}
}
if (!manifest.Save(pathInstallLocation))
{
if (!environment.Silent())
std::cerr << "ERROR: " << SAVE_INSTALL_MANIFEST_ERROR_MSG << std::endl;
return SAVE_INSTALL_MANIFEST_ERROR;
}
if (environment.Verbose())
std::cout << "Saved installation manifest: " << (pathInstallLocation / "install_manifest.toml").generic_u8string() <<
std::endl;
// Write config file
if (!environment.ConfigPath().empty())
{
std::ofstream fstream(environment.ConfigPath());
if (!fstream.is_open())
{
if (!environment.Silent())
std::cerr << "ERROR: " << SAVE_CONFIG_FILE_ERROR_MSG << std::endl;
return SAVE_CONFIG_FILE_ERROR;
}
fstream << "[Configuration]" << std::endl;
fstream << "Version = " << SDVFrameworkInterfaceVersion << std::endl << std::endl;
// Add each component that is a system object, device, basic service, complex service or an app...
// Also add the modules that contain one of the other component types (utility, proxy or stub).
std::map<std::filesystem::path, bool> mapModules;
for (const auto& rsComponent : manifest.ComponentList())
{
//// Exclude the class from the configuration?
//if (std::find(environment.ExcludeConfigClassList().begin(), environment.ExcludeConfigClassList().end(), rsComponent.ssClassName) !=
// environment.ExcludeConfigClassList().end()) continue;
// Get or insert the module in the map
auto itModule = mapModules.find(rsComponent.pathRelModule);
if (itModule == mapModules.end())
{
auto prInsert = mapModules.insert(std::make_pair(rsComponent.pathRelModule, false));
if (!prInsert.second) continue;
itModule = prInsert.first;
}
// Add the component if it is a system object, device, basic service, complex service or an app.
switch (rsComponent.eType)
{
case sdv::EObjectType::SystemObject:
case sdv::EObjectType::Device:
case sdv::EObjectType::BasicService:
case sdv::EObjectType::ComplexService:
fstream << "[[Component]]" << std::endl;
fstream << "Path = \"" << rsComponent.pathRelModule.generic_u8string() << "\"" << std::endl;
fstream << "Class = \"" << rsComponent.ssClassName << "\"" << std::endl;
if (rsComponent.ssDefaultObjectName.empty())
fstream << "Name = \"" << rsComponent.ssClassName << "\"" << std::endl;
else
fstream << "Name = \"" << rsComponent.ssDefaultObjectName << "\"" << std::endl;
fstream << std::endl;
itModule->second = true; // Module was added through component.
break;
default:
break;
}
}
// Add all modules that were not added through a component already
for (const auto& rvtModule : mapModules)
{
if (rvtModule.second) continue; // Module added already
fstream << "[[Module]]" << std::endl;
fstream << "Path = \"" << rvtModule.first.generic_u8string() << "\"" << std::endl << std::endl;
}
fstream.close();
if (environment.Verbose())
std::cout << "Saved configuration file: " << environment.ConfigPath().generic_u8string() << std::endl;
}
// Write settings file
if (environment.Settings())
{
// Read the existing settings
std::filesystem::path pathSettings = pathTargetRoot / "settings.toml";
std::list<std::string> lstSystemConfigs;
std::string ssAppConfig;
if (std::filesystem::exists(pathSettings))
{
std::ifstream fstream(pathSettings);
if (fstream.is_open())
{
if (environment.Verbose())
std::cout << "Reading existing settings file..." << std::endl;
std::string ssContent((std::istreambuf_iterator<char>(fstream)), std::istreambuf_iterator<char>());
sdv::toml::CTOMLParser parser(ssContent);
sdv::toml::CNode nodeVersion = parser.GetDirect("Settings.Version");
if (nodeVersion.GetValue() != SDVFrameworkInterfaceVersion)
{
if (!environment.Silent())
std::cout << "ERROR: " << SETTING_FILE_VERSION_INVALID_MSG << " No update taken place. (version " <<
static_cast<uint32_t>(nodeVersion.GetValue()) << " detected; version " <<
SDVFrameworkInterfaceVersion << " needed)." << std::endl;
return SETTING_FILE_VERSION_INVALID;
}
// Read the system configurations
sdv::toml::CNodeCollection nodeSysConfigs = parser.GetDirect("Settings.SystemConfig");
for (size_t nIndex = 0; nIndex < nodeSysConfigs.GetCount(); nIndex++)
{
sdv::toml::CNode nodeSysConfig = nodeSysConfigs[nIndex];
if (nodeSysConfig)
{
lstSystemConfigs.push_back(nodeSysConfig.GetValue());
if (environment.Verbose())
std::cout << "Detected existing SystemConfig entry: " <<
static_cast<std::string>(nodeSysConfig.GetValue()) << std::endl;
}
}
// Read the app config
sdv::toml::CNode nodeAppConfig = parser.GetDirect("Settings.AppConfig");
if (nodeAppConfig)
{
ssAppConfig = static_cast<std::string>(nodeAppConfig.GetValue());
if (environment.Verbose())
std::cout << "Detected existing AppConfig entry: " << ssAppConfig << std::endl;
}
}
}
// (Over)write existing settings file
std::ofstream fstream(pathSettings);
if (!fstream.is_open())
{
std::cerr << "ERROR: " << SAVE_SETTINGS_FILE_ERROR_MSG << std::endl;
return SAVE_SETTINGS_FILE_ERROR;
}
// TODO... allow partial update of TOML file. Needs parser-updates first to be able to do this. See:
// https://dev.azure.com/SW4ZF/AZP-074_DivDI_SofDCarResearch/_workitems/edit/580309
const char* szSettingsTemplatePart1 = R"code(# Settings file
[Settings]
Version = 100
# The system config array can contain zero or more configurations that are loaded at the time
# the system ist started. It is advisable to split the configurations in:
# platform config - containing all the components needed to interact with the OS,
# middleware, vehicle bus, Ethernet.
# vehicle interface - containing the vehicle bus interpretation components like data link
# based on DBC and devices for their abstraction.
# vehicle abstraction - containing the basic services
# Load the system configurations by providing the "SystemConfig" keyword as an array of strings.
# A relative path is relative to the installation directory (being "exe_location/instance_id").
#
# Example:
# SystemConfig = [ "platform.toml", "vehicle_ifc.toml", "vehicle_abstract.toml" ]
#
)code";
fstream << szSettingsTemplatePart1;
if (!lstSystemConfigs.empty())
fstream << "SystemConfig = [ ";
for (auto it = lstSystemConfigs.begin(); it != lstSystemConfigs.end(); ++it)
{
if (environment.Verbose())
std::cout << "Storing system config " << *it << " to the settings file." << std::endl;
fstream << "\"" << *it << "\"";
if (std::next(it) != lstSystemConfigs.end())
{
fstream << ", ";
}
}
if (!lstSystemConfigs.empty())
fstream << " ]" << std::endl;
const char* szSettingsTemplatePart2 = R"code(
# The application config contains the configuration file that can be updated when services and
# apps are being added to the system (or being removed from the system). Load the application
# config by providing the "AppConfig" keyword as a string value. A relative path is relative to
# the installation directory (being "exe_location/instance_id").
#
# Example
# AppConfig = "app_config.toml"
#
)code";
fstream << szSettingsTemplatePart2;
if (!environment.ConfigPath().empty())
{
if (!ssAppConfig.empty() && ssAppConfig != environment.ConfigPath().filename().generic_u8string())
{
if (!environment.Silent())
std::cout << "WARNING: The application config file in the settings is being updated from " <<
environment.ConfigPath().filename().generic_u8string() << " to " << ssAppConfig << std::endl;
}
ssAppConfig = environment.ConfigPath().filename().generic_u8string();
}
if (!ssAppConfig.empty())
{
if (environment.Verbose())
std::cout << "Storing application config " << ssAppConfig << " to the settings file." << std::endl;
fstream << "AppConfig = \"" << ssAppConfig << "\"" << std::endl;
}
fstream.close();
if (environment.Verbose())
std::cout << "Saved settings file: " << pathSettings.generic_u8string() << std::endl;
}
appcontrol.Shutdown();
if (!environment.Silent())
std::cout << std::endl << "Done..." << std::endl;
return NO_ERROR;
#endif
return NOT_IMPLEMENTED;
}

View File

@@ -0,0 +1,607 @@
#include "packager.h"
#include "../../sdv_services/core/installation_composer.h"
CPackager::CPackager(CSdvPackagerEnvironment& renv) : m_env(renv)
{}
bool CPackager::Execute()
{
switch (m_env.OperatingMode())
{
case CSdvPackagerEnvironment::EOperatingMode::pack:
if (!Pack()) return false;
break;
case CSdvPackagerEnvironment::EOperatingMode::install:
if (!Unpack()) return false;
break;
case CSdvPackagerEnvironment::EOperatingMode::direct_install:
if (!Copy()) return false;
break;
case CSdvPackagerEnvironment::EOperatingMode::uninstall:
if (!Remove()) return false;
break;
case CSdvPackagerEnvironment::EOperatingMode::verify:
if (!CheckIntegrity()) return false;
break;
case CSdvPackagerEnvironment::EOperatingMode::show:
if (!ShowContent()) return false;
break;
default:
return false;
break;
}
return true;
}
int CPackager::Error() const
{
return m_nError;
}
const std::string& CPackager::ArgError() const
{
return m_ssArgError;
}
bool CPackager::Pack()
{
try
{
CInstallComposer composer;
size_t nCount = 0;
for (const CSdvPackagerEnvironment::SModule& rsModule : m_env.ModuleList())
{
// Check for regular expression or wildcard search string
std::string ssSearchString;
uint32_t uiFlags = 0;
bool bExpectFile = true; // When set, expect at least one file for the addition
if (rsModule.ssSearchString.substr(0, 6) == "regex:")
{
ssSearchString = rsModule.ssSearchString.substr(6);
uiFlags = static_cast<uint32_t>(CInstallComposer::EAddModuleFlags::regex);
bExpectFile = false;
}
else
{
ssSearchString = rsModule.ssSearchString;
// Check for a wildcard character
bExpectFile = ssSearchString.find_first_of("*?") != std::string::npos;
// Wildcards are default...
uiFlags = static_cast<uint32_t>(CInstallComposer::EAddModuleFlags::wildcards);
}
// Should the directory structure be maintained
if (m_env.KeepStructure())
uiFlags |= static_cast<uint32_t>(CInstallComposer::EAddModuleFlags::keep_structure);
// Add the module
auto vecFiles = composer.AddModule(m_env.SourceLocation(), ssSearchString, rsModule.pathRelTarget, uiFlags);
if (bExpectFile && !vecFiles.size())
{
m_nError = CMDLN_SOURCE_FILE_ERROR;
m_ssArgError = CMDLN_SOURCE_FILE_ERROR_MSG;
return false;
}
// Report the files if requested
if (m_env.Verbose())
{
for (const auto& rpathFile : vecFiles)
std::cout << "Adding " << rpathFile.generic_u8string() << "..." << std::endl;
}
nCount += vecFiles.size();
}
if (!nCount)
{
m_nError = NO_SOURCE_FILES;
m_ssArgError = NO_SOURCE_FILES_MSG;
return false;
}
// Add additional information as properties
if (!m_env.ProductName().empty())
composer.AddProperty("Product", m_env.ProductName());
if (!m_env.Description().empty())
composer.AddProperty("Description", m_env.Description());
if (!m_env.Author().empty())
composer.AddProperty("Author", m_env.Author());
if (!m_env.Address().empty())
composer.AddProperty("Address", m_env.Address());
if (!m_env.Copyrights().empty())
composer.AddProperty("Copyrights", m_env.Copyrights());
if (!m_env.PackageVersion().empty())
composer.AddProperty("Version", m_env.PackageVersion());
// Report count if requested
if (!m_env.Silent())
std::cout << "Added " << nCount << " files..." << std::endl;
// Create manifest only? Or compose package.
if (m_env.CreateManifestOnly())
{
if (m_env.Verbose())
std::cout << "Create installation manifest..." << std::endl;
CInstallManifest manifest = composer.ComposeInstallManifest(m_env.InstallName());
std::filesystem::path pathOutputLocation = m_env.OutputLocation().empty() ? "." : m_env.OutputLocation();
return manifest.Save(pathOutputLocation);
}
else
{
if (m_env.Verbose())
std::cout << "Compose package..." << std::endl;
return composer.Compose(m_env.PackagePath(), m_env.InstallName());
}
}
catch (const sdv::XSysExcept& rexception)
{
m_nError = PACKAGE_CREATION_ERROR;
m_ssArgError = rexception.what();
return false;
}
}
bool CPackager::Unpack()
{
CInstallManifest manifest;
try
{
if (m_env.Verbose())
std::cout << "Read package..." << std::endl;
CInstallComposer extractor;
CInstallComposer::EUpdateRules eUpdateRule = CInstallComposer::EUpdateRules::not_allowed;
if (m_env.Overwrite())
eUpdateRule = CInstallComposer::EUpdateRules::overwrite;
if (m_env.Update())
eUpdateRule = CInstallComposer::EUpdateRules::update_when_new;
manifest = extractor.Extract(m_env.PackagePath(), m_env.InstallLocation(), eUpdateRule);
if (m_env.Verbose())
{
auto vecFiles = manifest.ModuleList();
for (const auto& rpathFile : vecFiles)
std::cout << "Extracting " << rpathFile.generic_u8string() << "..." << std::endl;
std::cout << "Product name: " << *manifest.Property("Product") << std::endl;
std::cout << "Package description: " << *manifest.Property("Description") << std::endl;
std::cout << "Author: " << *manifest.Property("Author") << std::endl;
std::cout << "Address: " << *manifest.Property("Address") << std::endl;
std::cout << "Copyright: " << *manifest.Property("Copyrights") << std::endl;
std::cout << "Version: " << *manifest.Property("Version") << std::endl;
}
}
catch (const sdv::XSysExcept& rexception)
{
m_nError = PACKAGE_READ_ERROR;
m_ssArgError = rexception.what();
return false;
}
return true;
}
bool CPackager::Copy()
{
CInstallManifest manifest;
try
{
CInstallComposer composer;
size_t nCount = 0;
for (const CSdvPackagerEnvironment::SModule& rsModule : m_env.ModuleList())
{
// Check for regular expression or wildcard search string
std::string ssSearchString;
uint32_t uiFlags = 0;
bool bExpectFile = true; // When set, expect at least one file for the addition
if (rsModule.ssSearchString.substr(0, 6) == "regex:")
{
ssSearchString = rsModule.ssSearchString.substr(6);
uiFlags = static_cast<uint32_t>(CInstallComposer::EAddModuleFlags::regex);
bExpectFile = false;
}
else
{
ssSearchString = rsModule.ssSearchString;
// Check for a wildcard character
bExpectFile = ssSearchString.find_first_of("*?") != std::string::npos;
// Wildcards are default...
uiFlags = static_cast<uint32_t>(CInstallComposer::EAddModuleFlags::wildcards);
}
// Should the directory structure be maintained
if (m_env.KeepStructure())
uiFlags |= static_cast<uint32_t>(CInstallComposer::EAddModuleFlags::keep_structure);
// Add the module
auto vecFiles = composer.AddModule(m_env.SourceLocation(), ssSearchString, rsModule.pathRelTarget, uiFlags);
if (bExpectFile && !vecFiles.size())
{
m_nError = CMDLN_SOURCE_FILE_ERROR;
m_ssArgError = CMDLN_SOURCE_FILE_ERROR_MSG;
return false;
}
// Report the files if requested
if (m_env.Verbose())
{
for (const auto& rpathFile : vecFiles)
std::cout << "Adding " << rpathFile.generic_u8string() << "..." << std::endl;
}
nCount += vecFiles.size();
}
if (!nCount)
{
m_nError = NO_SOURCE_FILES;
m_ssArgError = NO_SOURCE_FILES_MSG;
return false;
}
// Add additional information as properties
if (!m_env.ProductName().empty())
composer.AddProperty("Product", m_env.ProductName());
if (!m_env.Description().empty())
composer.AddProperty("Description", m_env.Description());
if (!m_env.Author().empty())
composer.AddProperty("Author", m_env.Author());
if (!m_env.Address().empty())
composer.AddProperty("Address", m_env.Address());
if (!m_env.Copyrights().empty())
composer.AddProperty("Copyrights", m_env.Copyrights());
if (!m_env.PackageVersion().empty())
composer.AddProperty("Version", m_env.PackageVersion());
// Report count if requested
if (!m_env.Silent())
std::cout << "Added " << nCount << " files..." << std::endl;
CInstallComposer::EUpdateRules eUpdateRule = CInstallComposer::EUpdateRules::not_allowed;
if (m_env.Overwrite())
eUpdateRule = CInstallComposer::EUpdateRules::overwrite;
if (m_env.Update())
eUpdateRule = CInstallComposer::EUpdateRules::update_when_new;
manifest = composer.ComposeDirect(m_env.InstallName(), m_env.InstallLocation(), eUpdateRule);
// Report count if requested
if (!m_env.Silent())
std::cout << "Copied " << manifest.ModuleList().size() << " files..." << std::endl;
}
catch (const sdv::XSysExcept& rexception)
{
m_nError = PACKAGE_READ_ERROR;
m_ssArgError = rexception.what();
return false;
}
return true;
}
bool CPackager::Remove()
{
CInstallManifest manifest;
try
{
if (m_env.Verbose())
std::cout << "Remove installation..." << std::endl;
CInstallComposer composer;
manifest = composer.Remove(m_env.InstallName(), m_env.InstallLocation());
// Report the files if requested
if (m_env.Verbose())
{
auto vecFiles = manifest.ModuleList();
for (const auto& rpathFile : vecFiles)
std::cout << "Removing " << rpathFile.generic_u8string() << "..." << std::endl;
}
// Report count if requested
if (!m_env.Silent())
std::cout << "Removed " << manifest.ModuleList().size() << " files..." << std::endl;
}
catch (const sdv::XSysExcept& rexception)
{
m_nError = PACKAGE_READ_ERROR;
m_ssArgError = rexception.what();
return false;
}
return manifest.IsValid();
}
bool CPackager::CheckIntegrity()
{
CInstallManifest manifest;
try
{
if (m_env.Verbose())
std::cout << "Verify package..." << std::endl;
CInstallComposer verifier;
bool bRet = verifier.Verify(m_env.PackagePath());
// Report count if requested
if (!m_env.Silent())
std::cout << "Verification of package " << (bRet ? "was successful..." : "has failed...") << std::endl;
}
catch (const sdv::XSysExcept& rexception)
{
m_nError = PACKAGE_READ_ERROR;
m_ssArgError = rexception.what();
return false;
}
return true;
}
void DrawTable(const std::vector<std::vector<std::string>>& rvecInfoTable, bool bSimple)
{
if (rvecInfoTable.empty()) return; // No columns
// Simple? One column only
if (bSimple)
{
for (const auto& rvecLine : rvecInfoTable)
{
if (!rvecLine.empty())
std::cout << rvecLine[0] << std::endl;
}
return;
}
// Measure the sizes of each column.
std::vector<size_t> vecSizes;
for (const auto& rvecLine : rvecInfoTable)
{
if (vecSizes.size() < rvecLine.size())
vecSizes.resize(rvecLine.size());
for (size_t nIndex = 0; nIndex < rvecLine.size(); nIndex++)
{
if (rvecLine[nIndex].size() > vecSizes[nIndex])
vecSizes[nIndex] = rvecLine[nIndex].size();
}
}
auto fnPrintValue = [](std::stringstream& rsstream, const std::string& rssValue, size_t nLength)
{
rsstream << rssValue;
if (rssValue.size() < nLength)
rsstream << std::string(nLength - rssValue.size(), ' ');
};
// Print first line
bool bInitialLine = true;
std::stringstream sstream;
for (const auto& rvecLine : rvecInfoTable)
{
// Print values
bool bInitialCol = true;
for (size_t nIndex = 0; nIndex < rvecLine.size(); nIndex++)
{
// Add apace or separator
if (bInitialCol)
sstream << " ";
else
sstream << " | ";
bInitialCol = false;
// Print the value
bool bLast = nIndex == vecSizes.size() - 1;
fnPrintValue(sstream, rvecLine[nIndex], bLast ? 0 : vecSizes[nIndex]);
}
// Less values than sizes... then print additional space
for (size_t nIndex = rvecLine.size(); nIndex < vecSizes.size(); nIndex++)
{
// Add apace or separator
if (bInitialCol)
sstream << " ";
else
sstream << " | ";
bInitialCol = false;
// Print the empty space
bool bLast = nIndex == vecSizes.size() - 1;
fnPrintValue(sstream, "", bLast ? 0 : vecSizes[nIndex]);
}
// End of line
sstream << std::endl;
// Initial line... then print dashes
if (bInitialLine)
{
bool bInitialCol1stLine = true;
for (size_t nSize : vecSizes)
{
// Add apace or separator
if (bInitialCol1stLine)
sstream << "-";
else
sstream << "-+-";
bInitialCol1stLine = false;
// Print dashes
sstream << std::string(nSize, '-');
}
// End of line
sstream << "-" << std::endl;
bInitialLine = false;
}
}
// Stream the table
std::cout << sstream.str();
}
bool CPackager::ShowContent()
{
CInstallManifest manifest;
try
{
if (m_env.Verbose())
std::cout << "Show package information..." << std::endl;
CInstallComposer extractor;
manifest = extractor.ExtractInstallManifest(m_env.PackagePath());
bool bConsole = m_env.CheckShowFlag(CSdvPackagerEnvironment::EShowMask::console);
bool bSimple = m_env.CheckShowFlag(CSdvPackagerEnvironment::EShowMask::console_simple);
// Currently no support for XML and JSON.
if (bConsole)
{
// Information
if (m_env.CheckShowFlag(CSdvPackagerEnvironment::EShowMask::info))
{
// Show information about the package
std::cout << std::endl;
if (!bSimple && !m_env.Silent())
std::cout << "Information:" << std::endl;
std::vector<std::vector<std::string>> vecTable;
auto vecProperties = manifest.PropertyList();
if (bSimple)
{
// No header, one column
std::vector<std::string> vecInitial = {std::string("Installation=") + manifest.InstallName()};
vecTable.push_back(vecInitial);
for (const auto& prProperty : vecProperties)
{
std::vector<std::string> vecLine = {prProperty.first + "=" + prProperty.second};
vecTable.push_back(vecLine);
}
} else
{
// Header and multiple columns
std::vector<std::string> vecHeader = {"Name", "Value"};
vecTable.push_back(vecHeader);
std::vector<std::string> vecInitial = {"Installation", manifest.InstallName()};
vecTable.push_back(vecInitial);
for (const auto& prProperty : vecProperties)
{
std::vector<std::string> vecLine = {prProperty.first, prProperty.second};
vecTable.push_back(vecLine);
}
}
DrawTable(vecTable, bSimple);
}
// Modules
if (m_env.CheckShowFlag(CSdvPackagerEnvironment::EShowMask::modules))
{
// Show module information
std::cout << std::endl;
if (!bSimple && !m_env.Silent())
std::cout << "Modules:" << std::endl;
std::vector<std::vector<std::string>> vecTable;
if (!bSimple)
{
// Header only when not simple
std::vector<std::string> vecHeader = {"Filename"};
vecTable.push_back(vecHeader);
}
auto vecModules = manifest.ModuleList();
for (const auto& pathModule : vecModules)
{
std::vector<std::string> vecLine = {pathModule.generic_u8string()};
vecTable.push_back(vecLine);
}
DrawTable(vecTable, bSimple);
}
// Components
if (m_env.CheckShowFlag(CSdvPackagerEnvironment::EShowMask::components))
{
// Show component information
std::cout << std::endl;
if (!bSimple && !m_env.Silent())
std::cout << "Components:" << std::endl;
std::vector<std::vector<std::string>> vecTable;
if (!bSimple)
{
// Header only when not simple
std::vector<std::string> vecHeader = {"Class", "Alias", "Type", "Dependency"};
vecTable.push_back(vecHeader);
}
auto vecComponents = manifest.ComponentList();
for (const auto& sComponent : vecComponents)
{
if (bSimple)
{
// Simple - no header and onle column containing all classes and associated aliases.
vecTable.push_back(std::vector<std::string>{sComponent.ssClassName});
for (const auto& rssAlias : sComponent.seqAliases)
vecTable.push_back(std::vector<std::string>{rssAlias});
}
else
{
// Not simple - header and multiple columns allowed
// Components can have a list of aliases and a list of dependencies. Add extra lines for each additional
// alias and dependcy.
size_t nIndex = 0;
std::vector<std::string> vecLine;
bool bAliasEnd = sComponent.seqAliases.empty(), bDependencyEnd = sComponent.seqDependencies.empty();
do
{
vecLine.push_back(nIndex ? "" : sComponent.ssClassName);
vecLine.push_back(bAliasEnd ? "" : sComponent.seqAliases[nIndex]);
if (!nIndex)
{
switch (sComponent.eType)
{
case sdv::EObjectType::SystemObject:
vecLine.push_back("System object");
break;
case sdv::EObjectType::Device:
vecLine.push_back("Device");
break;
case sdv::EObjectType::BasicService:
vecLine.push_back("Basic service");
break;
case sdv::EObjectType::ComplexService:
vecLine.push_back("Complex service");
break;
case sdv::EObjectType::Application:
vecLine.push_back("Application");
break;
case sdv::EObjectType::Proxy:
vecLine.push_back("Proxy object");
break;
case sdv::EObjectType::Stub:
vecLine.push_back("Stub object");
break;
case sdv::EObjectType::Utility:
vecLine.push_back("Utility");
break;
default:
vecLine.push_back("Unknown object");
break;
}
}
else
vecLine.push_back("");
vecLine.push_back(bDependencyEnd ? "" : sComponent.seqDependencies[nIndex]);
vecTable.push_back(vecLine);
nIndex++;
bAliasEnd = nIndex >= sComponent.seqAliases.size();
bDependencyEnd = nIndex >= sComponent.seqDependencies.size();
} while (!bAliasEnd && !bDependencyEnd);
}
}
DrawTable(vecTable, bSimple);
}
}
}
catch (const sdv::XSysExcept& rexception)
{
m_nError = PACKAGE_READ_ERROR;
m_ssArgError = rexception.what();
return false;
}
return manifest.IsValid();
}

View File

@@ -0,0 +1,80 @@
#ifndef PACKAGER_H
#define PACKAGER_H
#include "environment.h"
/**
* @brief Packager class.
*/
class CPackager
{
public:
/**
* @brief Constructor
* @param[in] renv Reference to the environment object.
*/
CPackager(CSdvPackagerEnvironment& renv);
/**
* @brief Execute the packager dependable on the environment settings.
* @return Returns whether the execution was successful.
*/
bool Execute();
/**
* @brief Was a commandline parse error or a logical error with command line arguments detected?
* @return Returns the result of the command line parsing. If no error occurs, NO_ERROR is returned.
*/
int Error() const;
/**
* @brief Parse error that might have occurred.
* @return Returns a reference to the member variable containing the error text.
*/
const std::string& ArgError() const;
private:
/**
* @brief Pack files into a package. Uses the environment settings to create the package.
* @return Returns whether the packing operation was successful.
*/
bool Pack();
/**
* @brief Unpack an installation package into the target location. Uses the environment settings to unpack the package.
* @return Returns whether the packing opereration was successful.
*/
bool Unpack();
/**
* @brief Copy files from the source location to the target location (direct installation). Uses the environment settings to
* copy the files.
* @return Returns whether the copy operation was successful.
*/
bool Copy();
/**
* @brief Remove an installation from the target location. Uses the environment settings to remove the files.
* @return Returns whether the removal operation was successful.
*/
bool Remove();
/**
* @brief Check package integrity. Uses the environment settings to check the package.
* @return Returns whether the integrity operation was successful.
*/
bool CheckIntegrity();
/**
* @brief Show package content. Uses the environment settings to show the package content.
* @return Returns whether the show operation was successful.
*/
bool ShowContent();
CSdvPackagerEnvironment m_env; ///< The packager environment
int m_nError = NO_ERROR; ///< Error code after processing the command line.
std::string m_ssArgError; ///< Error text after processing the command line.
};
#endif // !defined PACKAGER_H