From fca83b68dc2241587314c06b43d270169f9fe520 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Mon, 22 Jul 2024 09:58:14 +0100 Subject: [PATCH] General improvement to Environment Variables access - Concentrate the Environment Variables under a single API specified at ecflow/core/Environment.hpp - Replace all raw calls to ::getenv() Re ECFLOW-1957 --- libs/CMakeLists.txt | 2 + libs/base/src/ecflow/base/Openssl.cpp | 11 +- .../src/ecflow/base/cts/task/CtsWaitCmd.cpp | 3 +- .../base/src/ecflow/base/cts/task/TaskCmd.cpp | 3 +- .../src/ecflow/base/cts/user/AlterCmd.cpp | 5 +- .../src/ecflow/base/cts/user/CFileCmd.cpp | 17 +- libs/base/src/ecflow/base/cts/user/LogCmd.cpp | 6 +- libs/base/test/TestAlterCmd.cpp | 14 +- libs/base/test/TestArchiveAndRestoreCmd.cpp | 13 +- libs/base/test/TestCmd.cpp | 3 +- libs/base/test/TestLogCmd.cpp | 3 +- .../src/ecflow/client/ClientEnvironment.cpp | 96 ++++----- libs/client/test/InvokeServer.hpp | 4 +- libs/client/test/SCPort.cpp | 55 ++--- libs/client/test/TestJobGenOnly.cpp | 3 +- libs/client/test/TestServer.cpp | 24 ++- libs/client/test/TestSinglePerf.cpp | 12 +- libs/core/src/ecflow/core/EcfPortLock.hpp | 9 +- libs/core/src/ecflow/core/Environment.hpp | 193 ++++++++++++++++++ libs/core/src/ecflow/core/File.cpp | 15 +- libs/core/src/ecflow/core/Host.cpp | 5 +- libs/core/src/ecflow/core/Str.cpp | 102 --------- libs/core/src/ecflow/core/Str.hpp | 27 --- libs/core/test/TestFile.cpp | 4 +- libs/core/test/TestSanitizerAS.cpp | 3 +- libs/core/test/TestSanitizerUB.cpp | 3 +- libs/core/test/TestStringSplitPerf.cpp | 6 +- libs/node/src/ecflow/node/EcfFile.cpp | 29 +-- libs/node/src/ecflow/node/JobCreationCtrl.cpp | 19 +- libs/node/src/ecflow/node/Node.cpp | 13 +- libs/node/src/ecflow/node/NodeContainer.cpp | 7 +- libs/node/src/ecflow/node/ServerState.cpp | 13 +- libs/node/src/ecflow/node/Submittable.cpp | 37 ++-- libs/node/src/ecflow/node/Task.cpp | 7 +- .../src/ecflow/node/TaskScriptGenerator.cpp | 9 +- libs/node/test/TestAlias.cpp | 3 +- libs/node/test/TestEcfFile.cpp | 94 +++++---- libs/node/test/TestEcfFileLocator.cpp | 37 ++-- libs/node/test/TestEnviromentSubstitution.cpp | 3 +- libs/node/test/TestJobCreator.cpp | 5 +- libs/node/test/TestJobProfiler.cpp | 7 +- libs/node/test/TestPreProcessing.cpp | 7 +- libs/node/test/TestReplace.cpp | 5 +- libs/node/test/TestTaskScriptGenerator.cpp | 9 +- libs/node/test/TestVariableGeneration.cpp | 15 +- libs/node/test/TestVariableSubstitution.cpp | 11 +- libs/rest/src/ecflow/http/Client.cpp | 11 +- libs/rest/src/ecflow/http/HttpServer.cpp | 46 ++--- libs/rest/src/ecflow/http/Options.hpp | 1 + libs/rest/test/InvokeServer.hpp | 7 +- libs/rest/test/TestApiV1.cpp | 20 +- .../src/ecflow/server/ServerEnvironment.cpp | 82 +++----- libs/server/test/TestServer.cpp | 6 +- libs/server/test/TestServerEnvironment.cpp | 14 +- libs/simulator/test/TestAutoArchive.cpp | 17 +- libs/simulator/test/TestAutoRestore.cpp | 9 +- libs/test/TestClkSync.cpp | 11 +- libs/test/TestEvents.cpp | 3 +- libs/test/TestInitAddVariable.cpp | 3 +- libs/test/TestZombies.cpp | 3 +- libs/test/src/ServerTestHarness.cpp | 5 +- libs/test/src/TestFixture.cpp | 40 ++-- libs/test/src/ZombieUtill.cpp | 3 +- .../src/ecflow/udp/UDPServerEnvironment.cpp | 6 +- 64 files changed, 677 insertions(+), 581 deletions(-) create mode 100644 libs/core/src/ecflow/core/Environment.hpp diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index 57caa08c5..558e4ccea 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -241,6 +241,8 @@ set(srcs core/src/ecflow/core/DurationTimer.hpp core/src/ecflow/core/Ecf.hpp core/src/ecflow/core/EcfPortLock.hpp + core/src/ecflow/core/Enumerate.hpp + core/src/ecflow/core/Environment.hpp core/src/ecflow/core/Extract.hpp core/src/ecflow/core/File.hpp core/src/ecflow/core/File_r.hpp diff --git a/libs/base/src/ecflow/base/Openssl.cpp b/libs/base/src/ecflow/base/Openssl.cpp index b6c6e32b7..67d9c9cb6 100644 --- a/libs/base/src/ecflow/base/Openssl.cpp +++ b/libs/base/src/ecflow/base/Openssl.cpp @@ -11,9 +11,9 @@ #include "ecflow/base/Openssl.hpp" #include -#include // getenv #include +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Host.hpp" #include "ecflow/core/Str.hpp" @@ -80,9 +80,8 @@ void Openssl::enable(std::string host, const std::string& port) { } void Openssl::enable_if_defined(std::string host, const std::string& port) { - char* ecf_ssl = getenv("ECF_SSL"); - if (ecf_ssl) { - std::string ecf_ssl_env = ecf_ssl; + if (auto ecf_ssl = ecf::environment::fetch(ecf::environment::ECF_SSL); ecf_ssl) { + std::string ecf_ssl_env = ecf_ssl.value(); if (host == Str::LOCALHOST()) host = Host().name(); @@ -161,9 +160,7 @@ std::string Openssl::get_password() const { } std::string Openssl::certificates_dir() const { - std::string home_path = getenv("HOME"); - home_path += "/.ecflowrc/ssl/"; - return home_path; + return ecf::environment::get("HOME") + "/.ecflowrc/ssl/"; } std::string Openssl::pem() const { diff --git a/libs/base/src/ecflow/base/cts/task/CtsWaitCmd.cpp b/libs/base/src/ecflow/base/cts/task/CtsWaitCmd.cpp index 011e65a27..49c847b54 100644 --- a/libs/base/src/ecflow/base/cts/task/CtsWaitCmd.cpp +++ b/libs/base/src/ecflow/base/cts/task/CtsWaitCmd.cpp @@ -16,6 +16,7 @@ #include "ecflow/base/AbstractServer.hpp" #include "ecflow/base/cts/task/TaskApi.hpp" #include "ecflow/base/stc/PreAllocatedReply.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/Log.hpp" #include "ecflow/core/Str.hpp" #include "ecflow/node/Defs.hpp" @@ -128,7 +129,7 @@ bool TaskCmd::authenticate(AbstractServer* as, STC_Cmd_ptr& theReply) const { /// This can be done via AlterCmd by adding a variable on the task, ECF_PASS with value /// Submittable::FREE_JOBS_PASSWORD Note: this *does not* look for the variable up the node tree, only on the task. std::string ecf_pass_value; - if (submittable_->findVariableValue(Str::ECF_PASS(), ecf_pass_value)) { + if (submittable_->findVariableValue(ecf::environment::ECF_PASS, ecf_pass_value)) { if (ecf_pass_value == Submittable::FREE_JOBS_PASSWORD()) { submittable_->flag().clear(ecf::Flag::ZOMBIE); diff --git a/libs/base/src/ecflow/base/cts/task/TaskCmd.cpp b/libs/base/src/ecflow/base/cts/task/TaskCmd.cpp index 61c17dc44..c0a90fcee 100644 --- a/libs/base/src/ecflow/base/cts/task/TaskCmd.cpp +++ b/libs/base/src/ecflow/base/cts/task/TaskCmd.cpp @@ -12,6 +12,7 @@ #include "ecflow/base/AbstractServer.hpp" #include "ecflow/base/stc/PreAllocatedReply.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/Log.hpp" #include "ecflow/node/Defs.hpp" #include "ecflow/node/Submittable.hpp" @@ -123,7 +124,7 @@ bool TaskCmd::authenticate(AbstractServer* as, STC_Cmd_ptr& theReply) const { /// This can be done via AlterCmd by adding a variable on the task, ECF_PASS with value /// Submittable::FREE_JOBS_PASSWORD Note: this *does not* look for the variable up the node tree, only on the task. std::string ecf_pass_value; - if (submittable_->findVariableValue(Str::ECF_PASS(), ecf_pass_value)) { + if (submittable_->findVariableValue(ecf::environment::ECF_PASS, ecf_pass_value)) { if (ecf_pass_value == Submittable::FREE_JOBS_PASSWORD()) { submittable_->flag().clear(ecf::Flag::ZOMBIE); diff --git a/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp b/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp index 517c736cc..5e9d2f08e 100644 --- a/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp @@ -20,6 +20,7 @@ #include "ecflow/base/cts/user/CtsApi.hpp" #include "ecflow/core/Converter.hpp" #include "ecflow/core/Enumerate.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/Extract.hpp" #include "ecflow/core/Log.hpp" #include "ecflow/core/Message.hpp" @@ -296,8 +297,8 @@ STC_Cmd_ptr AlterCmd::alter_server_state(AbstractServer* as) const { else if (change_attr_type_ == AlterCmd::VARIABLE || add_attr_type_ == AlterCmd::ADD_VARIABLE) { // ECFLOW-380: Some variable should be read only - if (name_ == Str::ECF_HOST() || name_ == Str::ECF_PORT() || name_ == "ECF_PID" || name_ == "ECF_VERSION" || - name_ == "ECF_LISTS") { + if (name_ == ecf::environment::ECF_HOST || name_ == ecf::environment::ECF_PORT || name_ == "ECF_PID" || + name_ == "ECF_VERSION" || name_ == "ECF_LISTS") { std::stringstream ss; ss << "AlterCmd:: Cannot add or change read only server variable " << name_; throw std::runtime_error(ss.str()); diff --git a/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp b/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp index 47ca30231..569af519e 100644 --- a/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp @@ -18,6 +18,7 @@ #include "ecflow/base/cts/user/CtsApi.hpp" #include "ecflow/base/stc/PreAllocatedReply.hpp" #include "ecflow/core/Converter.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/node/EcfFile.hpp" #include "ecflow/node/Submittable.hpp" @@ -174,7 +175,7 @@ STC_Cmd_ptr CFileCmd::doHandleRequest(AbstractServer* as) const { case CFileCmd::JOB: { std::string ecf_job_file; - submittable->findParentVariableValue(Str::ECF_JOB(), ecf_job_file); + submittable->findParentVariableValue(ecf::environment::ECF_JOB, ecf_job_file); if (!File::open(ecf_job_file, fileContents)) { std::stringstream ss; ss << "CFileCmd::doHandleRequest: Failed to open the job file('" << ecf_job_file << "') for task " @@ -198,19 +199,19 @@ STC_Cmd_ptr CFileCmd::doHandleRequest(AbstractServer* as) const { // First try user variable, if defined this has priority ECFLOW-999 std::stringstream ss; std::string user_jobout; - if (submittable->findParentUserVariableValue(Str::ECF_JOBOUT(), user_jobout)) { + if (submittable->findParentUserVariableValue(ecf::environment::ECF_JOBOUT, user_jobout)) { if (File::open(user_jobout, fileContents)) break; ss << "Failed to open user specified job-out(ECF_JOBOUT='" << user_jobout << "') "; } - const Variable& ecf_jobout_gen_var = submittable->findGenVariable(Str::ECF_JOBOUT()); + const Variable& ecf_jobout_gen_var = submittable->findGenVariable(ecf::environment::ECF_JOBOUT); if (!File::open(ecf_jobout_gen_var.theValue(), fileContents)) { // If that fails as a backup, look under ECF_HOME/ECF_NAME.ECF_TRYNO, ECFLOW-177 preserve old SMS // behaviour std::string ecfhome_jobout; - submittable->findParentUserVariableValue(Str::ECF_HOME(), ecfhome_jobout); + submittable->findParentUserVariableValue(ecf::environment::ECF_HOME, ecfhome_jobout); ecfhome_jobout += submittable->absNodePath(); ecfhome_jobout += "."; ecfhome_jobout += submittable->tryNo(); @@ -239,7 +240,7 @@ STC_Cmd_ptr CFileCmd::doHandleRequest(AbstractServer* as) const { case CFileCmd::KILL: { std::string ecf_job_file; - submittable->findParentVariableValue(Str::ECF_JOB(), ecf_job_file); + submittable->findParentVariableValue(ecf::environment::ECF_JOB, ecf_job_file); std::string file = ecf_job_file + ".kill"; if (!File::open(file, fileContents)) { std::stringstream ss; @@ -252,7 +253,7 @@ STC_Cmd_ptr CFileCmd::doHandleRequest(AbstractServer* as) const { case CFileCmd::STAT: { std::string ecf_job_file; - submittable->findParentVariableValue(Str::ECF_JOB(), ecf_job_file); + submittable->findParentVariableValue(ecf::environment::ECF_JOB, ecf_job_file); std::string file = ecf_job_file + ".stat"; if (!File::open(file, fileContents)) { std::stringstream ss; @@ -275,7 +276,7 @@ STC_Cmd_ptr CFileCmd::doHandleRequest(AbstractServer* as) const { // First look for .man files in ECF_FILES and then ECF_HOME std::string ecf_files; - node->findParentUserVariableValue(Str::ECF_FILES(), ecf_files); + node->findParentUserVariableValue(ecf::environment::ECF_FILES, ecf_files); if (!ecf_files.empty() && fs::is_directory(ecf_files)) { std::string manFile = File::backwardSearch(ecf_files, node->absNodePath(), File::MAN_EXTN()); @@ -289,7 +290,7 @@ STC_Cmd_ptr CFileCmd::doHandleRequest(AbstractServer* as) const { if (fileContents.empty()) { // Try under ECF_HOME std::string ecf_home; - node->findParentUserVariableValue(Str::ECF_HOME(), ecf_home); + node->findParentUserVariableValue(ecf::environment::ECF_HOME, ecf_home); if (!ecf_home.empty() && fs::is_directory(ecf_home)) { std::string manFile = File::backwardSearch(ecf_home, node->absNodePath(), File::MAN_EXTN()); diff --git a/libs/base/src/ecflow/base/cts/user/LogCmd.cpp b/libs/base/src/ecflow/base/cts/user/LogCmd.cpp index b5d7a4fed..1918b77f6 100644 --- a/libs/base/src/ecflow/base/cts/user/LogCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/LogCmd.cpp @@ -17,6 +17,7 @@ #include "ecflow/base/cts/user/CtsApi.hpp" #include "ecflow/base/stc/PreAllocatedReply.hpp" #include "ecflow/core/Converter.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/Log.hpp" #include "ecflow/core/Str.hpp" #include "ecflow/node/Defs.hpp" @@ -145,12 +146,13 @@ STC_Cmd_ptr LogCmd::doHandleRequest(AbstractServer* as) const { // This is done adding it as a *USER* variable. This overloads the server variables // It also allows us to see the change in GUI. Note: Defs/server_variables are not synced // ECFLOW-376 - as->defs()->set_server().add_or_update_user_variables(Str::ECF_LOG(), Log::instance()->path()); + as->defs()->set_server().add_or_update_user_variables(ecf::environment::ECF_LOG, + Log::instance()->path()); } else { // User could have overridden ECF_LOG variable // *FIRST* look at user variables, then look at *server* variables. - std::string log_file_name = as->defs()->server().find_variable(Str::ECF_LOG()); + std::string log_file_name = as->defs()->server().find_variable(ecf::environment::ECF_LOG); // ECFLOW-377 should remove leading/trailing spaces from path ecf::algorithm::trim(log_file_name); diff --git a/libs/base/test/TestAlterCmd.cpp b/libs/base/test/TestAlterCmd.cpp index 088b42fb5..659a4b8eb 100644 --- a/libs/base/test/TestAlterCmd.cpp +++ b/libs/base/test/TestAlterCmd.cpp @@ -18,6 +18,7 @@ #include "ecflow/base/cts/user/PathsCmd.hpp" #include "ecflow/base/cts/user/RequeueNodeCmd.hpp" #include "ecflow/core/Ecf.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/Str.hpp" #include "ecflow/node/Defs.hpp" #include "ecflow/node/Family.hpp" @@ -959,15 +960,16 @@ BOOST_AUTO_TEST_CASE(test_alter_cmd) { { // free password TestStateChanged changed(s); std::string returnedValue; - BOOST_CHECK_MESSAGE(!task->findVariableValue(Str::ECF_PASS(), returnedValue), + BOOST_CHECK_MESSAGE(!task->findVariableValue(ecf::environment::ECF_PASS, returnedValue), "Expected no variable of name ECF_PASS"); - TestHelper::invokeRequest( - &defs, - Cmd_ptr(new AlterCmd( - task->absNodePath(), AlterCmd::ADD_VARIABLE, Str::ECF_PASS(), Submittable::FREE_JOBS_PASSWORD()))); + TestHelper::invokeRequest(&defs, + Cmd_ptr(new AlterCmd(task->absNodePath(), + AlterCmd::ADD_VARIABLE, + ecf::environment::ECF_PASS, + Submittable::FREE_JOBS_PASSWORD()))); - BOOST_CHECK_MESSAGE(task->findVariableValue(Str::ECF_PASS(), returnedValue), + BOOST_CHECK_MESSAGE(task->findVariableValue(ecf::environment::ECF_PASS, returnedValue), "Expected to find variable ECF_PASS on the task"); BOOST_CHECK_MESSAGE(returnedValue == Submittable::FREE_JOBS_PASSWORD(), "Expected variable value of name " << Submittable::FREE_JOBS_PASSWORD() << " but found " diff --git a/libs/base/test/TestArchiveAndRestoreCmd.cpp b/libs/base/test/TestArchiveAndRestoreCmd.cpp index 5603a62dd..5ba903719 100644 --- a/libs/base/test/TestArchiveAndRestoreCmd.cpp +++ b/libs/base/test/TestArchiveAndRestoreCmd.cpp @@ -16,6 +16,7 @@ #include "ecflow/base/cts/user/DeleteCmd.hpp" #include "ecflow/base/cts/user/PathsCmd.hpp" #include "ecflow/base/cts/user/RequeueNodeCmd.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Pid.hpp" #include "ecflow/core/Str.hpp" @@ -51,7 +52,7 @@ BOOST_AUTO_TEST_CASE(test_archive_and_restore_suite) { // We use Pid::unique_name, to allow multiple invocation of this test Defs theDefs; std::string ecf_home = File::test_data("libs/base/test", "libs/base"); - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); suite_ptr suite = theDefs.add_suite(Pid::unique_name("test_archive_and_restore_suite")); suite->add_family("f1")->add_task("t1"); // cout << theDefs << "\n"; @@ -97,7 +98,7 @@ BOOST_AUTO_TEST_CASE(test_archive_and_restore_family) { Defs theDefs; std::string ecf_home = File::test_data("libs/base/test", "libs/base"); - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); suite_ptr suite = theDefs.add_suite(Pid::unique_name("test_archive_and_restore_family")); family_ptr f3 = suite->add_family("f1")->add_family("f2")->add_family("f3"); f3->add_task("t1"); @@ -148,7 +149,7 @@ BOOST_AUTO_TEST_CASE(test_archive_and_restore_all) { Defs theDefs; { std::string ecf_home = File::test_data("libs/base/test", "libs/base"); - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); suite_ptr suite = theDefs.add_suite(Pid::unique_name("test_archive_and_restore_all")); family_ptr f1 = suite->add_family("f1"); f1->add_task("t1"); @@ -244,7 +245,7 @@ BOOST_AUTO_TEST_CASE(test_archive_and_restore_overlap) { Defs theDefs; std::string ecf_home = File::test_data("libs/base/test", "libs/base"); - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); suite_ptr suite = theDefs.add_suite(Pid::unique_name("test_archive_and_restore_overlap")); std::string f1_abs_node_path; { @@ -290,7 +291,7 @@ BOOST_AUTO_TEST_CASE(test_archive_and_delete_suite) { // We use Pid::unique_name, to allow multiple invocation of this test Defs theDefs; std::string ecf_home = File::test_data("libs/base/test", "libs/base"); - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); suite_ptr suite = theDefs.add_suite(Pid::unique_name("test_archive_and_delete_suite")); family_ptr family = suite->add_family("f1"); family->add_task("t1"); @@ -327,7 +328,7 @@ BOOST_AUTO_TEST_CASE(test_archive_and_restore_errors) { // We use Pid::unique_name, to allow multiple invocation of this test Defs theDefs; std::string ecf_home = File::test_data("libs/base/test", "libs/base"); - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); suite_ptr suite = theDefs.add_suite(Pid::unique_name("test_archive_and_restore_errors")); family_ptr f1 = suite->add_family("f1"); f1->add_task("t1"); diff --git a/libs/base/test/TestCmd.cpp b/libs/base/test/TestCmd.cpp index b3e330226..a3ef07655 100644 --- a/libs/base/test/TestCmd.cpp +++ b/libs/base/test/TestCmd.cpp @@ -19,6 +19,7 @@ #include "ecflow/base/cts/user/BeginCmd.hpp" #include "ecflow/base/cts/user/CtsCmd.hpp" #include "ecflow/core/Converter.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/Str.hpp" #include "ecflow/node/Defs.hpp" #include "ecflow/node/Family.hpp" @@ -82,7 +83,7 @@ BOOST_AUTO_TEST_CASE(test_simple_cmd) { // should be re-submitted, until the task try number > ECF_TRIES { std::string varValue; - if (t1->findParentUserVariableValue(Str::ECF_TRIES(), varValue)) { + if (t1->findParentUserVariableValue(ecf::environment::ECF_TRIES, varValue)) { auto ecf_tries = ecf::convert_to(varValue); while (true) { TestHelper::invokeRequest( diff --git a/libs/base/test/TestLogCmd.cpp b/libs/base/test/TestLogCmd.cpp index 0ca713645..a58426cea 100644 --- a/libs/base/test/TestLogCmd.cpp +++ b/libs/base/test/TestLogCmd.cpp @@ -13,6 +13,7 @@ #include "TestHelper.hpp" #include "TestNaming.hpp" #include "ecflow/base/cts/user/LogCmd.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Log.hpp" #include "ecflow/core/Str.hpp" @@ -83,7 +84,7 @@ BOOST_AUTO_TEST_CASE(test_log_cmd) { << defs.server().find_variable("ECF_LOG") << "'"); // Update ECF_LOG to have a *SPACE* at the end. ECFLOW-377 - defs.set_server().add_or_update_user_variables(Str::ECF_LOG(), new_log_file); + defs.set_server().add_or_update_user_variables(ecf::environment::ECF_LOG, new_log_file); BOOST_CHECK_MESSAGE(defs.server().find_variable("ECF_LOG") == new_log_file, "expected to find ECF_LOG with value '" << new_log_file << "' but found '" << defs.server().find_variable("ECF_LOG") << "'"); diff --git a/libs/client/src/ecflow/client/ClientEnvironment.cpp b/libs/client/src/ecflow/client/ClientEnvironment.cpp index 0511895bd..6fb705ed2 100644 --- a/libs/client/src/ecflow/client/ClientEnvironment.cpp +++ b/libs/client/src/ecflow/client/ClientEnvironment.cpp @@ -10,13 +10,13 @@ #include "ecflow/client/ClientEnvironment.hpp" -#include // for getenv() #include #include #include #include "ecflow/core/Converter.hpp" #include "ecflow/core/Ecf.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Host.hpp" #include "ecflow/core/PasswdFile.hpp" @@ -223,18 +223,15 @@ std::string ClientEnvironment::toString() const { } std::string ClientEnvironment::hostSpecified() { - char* the_host = getenv(Str::ECF_HOST().c_str()); - if (the_host) - return std::string(the_host); - return std::string(); + std::string specified_host; + ecf::environment::get(ecf::environment::ECF_HOST, specified_host); + return specified_host; } std::string ClientEnvironment::portSpecified() { - char* theEnv = getenv(Str::ECF_PORT().c_str()); - if (theEnv) { - return std::string(theEnv); - } - return Str::DEFAULT_PORT_NUMBER(); + std::string specified_port = Str::DEFAULT_PORT_NUMBER(); + ecf::environment::get(ecf::environment::ECF_PORT, specified_port); + return specified_port; } void ClientEnvironment::read_environment_variables() { @@ -242,47 +239,37 @@ void ClientEnvironment::read_environment_variables() { std::cout << "ClientEnvironment::read_environment_variables()\n"; #endif - if (getenv(Str::ECF_NAME().c_str())) - task_path_ = getenv(Str::ECF_NAME().c_str()); - if (getenv(Str::ECF_PASS().c_str())) - jobs_password_ = getenv(Str::ECF_PASS().c_str()); - if (getenv(Str::ECF_TRYNO().c_str())) - task_try_num_ = atoi(getenv(Str::ECF_TRYNO().c_str())); - if (getenv("ECF_HOSTFILE")) - host_file_ = getenv("ECF_HOSTFILE"); - if (getenv(Str::ECF_RID().c_str())) - remote_id_ = getenv(Str::ECF_RID().c_str()); - if (getenv("ECF_USER")) - user_name_ = getenv("ECF_USER"); - - if (getenv("ECF_TIMEOUT")) - timeout_ = atoi(getenv("ECF_TIMEOUT")); // host file timeout - if (timeout_ > MAX_TIMEOUT) - timeout_ = MAX_TIMEOUT; - if (timeout_ < MIN_TIMEOUT) - timeout_ = MIN_TIMEOUT; - - if (getenv("ECF_ZOMBIE_TIMEOUT")) - zombie_timeout_ = atoi(getenv("ECF_ZOMBIE_TIMEOUT")); // time out for zombies - if (zombie_timeout_ > MAX_TIMEOUT) - zombie_timeout_ = MAX_TIMEOUT; - if (zombie_timeout_ < MIN_TIMEOUT) - zombie_timeout_ = MIN_TIMEOUT; - - if (getenv("ECF_CONNECT_TIMEOUT")) - connect_timeout_ = atoi(getenv("ECF_CONNECT_TIMEOUT")); // for test only - - if (getenv("ECF_DENIED")) - denied_ = true; - if (getenv("NO_ECF")) - no_ecf_ = true; - if (getenv("ECF_DEBUG_CLIENT")) - debug_ = true; - - char* debug_level = getenv("ECF_DEBUG_LEVEL"); - if (debug_level) { + ecf::environment::get(ecf::environment::ECF_NAME, task_path_); + + ecf::environment::get(ecf::environment::ECF_PASS, jobs_password_); + + ecf::environment::get(ecf::environment::ECF_TRYNO, task_try_num_); + + ecf::environment::get("ECF_HOSTFILE", host_file_); + + ecf::environment::get(ecf::environment::ECF_RID, remote_id_); + + ecf::environment::get("ECF_USER", user_name_); + + ecf::environment::get("ECF_TIMEOUT", timeout_); + timeout_ = timeout_ > MAX_TIMEOUT ? MAX_TIMEOUT : timeout_; + timeout_ = timeout_ < MIN_TIMEOUT ? MIN_TIMEOUT : timeout_; + + ecf::environment::get("ECF_ZOMBIE_TIMEOUT", zombie_timeout_); + zombie_timeout_ = (zombie_timeout_ > MAX_TIMEOUT) ? MAX_TIMEOUT : zombie_timeout_; + zombie_timeout_ = (zombie_timeout_ < MIN_TIMEOUT) ? MIN_TIMEOUT : zombie_timeout_; + + ecf::environment::get("ECF_CONNECT_TIMEOUT", connect_timeout_); + + ecf::environment::get("ECF_DENIED", denied_); + + ecf::environment::get("NO_ECF", no_ecf_); + + ecf::environment::get("ECF_DEBUG_CLIENT", debug_); + + if (auto var = ecf::environment::fetch("ECF_DEBUG_LEVEL"); var) { try { - Ecf::set_debug_level(ecf::convert_to(debug_level)); + Ecf::set_debug_level(ecf::convert_to(var.value())); } catch (...) { throw std::runtime_error("The environment variable ECF_DEBUG_LEVEL must be an unsigned integer."); @@ -297,8 +284,8 @@ void ClientEnvironment::read_environment_variables() { port = host_vec_[0].second; // first entry is the config port } - if (getenv(Str::ECF_PORT().c_str())) { - port = getenv(Str::ECF_PORT().c_str()); + if (auto var = ecf::environment::fetch(ecf::environment::ECF_PORT); var) { + port = var.value(); host_vec_.clear(); // remove config settings, net effect is overriding host_vec_.emplace_back(host, port); } @@ -394,9 +381,8 @@ const std::string& ClientEnvironment::get_password(const char* env, const std::s return passwd_; } - char* file = getenv(env); - if (file) { - std::string user_passwd_file = file; + if (auto file = ecf::environment::fetch(env); file) { + std::string user_passwd_file = file.value(); // cout << " ClientEnvironment::get_password() ECF_CUSTOM_PASSWD " << user_passwd_file << "\n"; if (!user_passwd_file.empty() && fs::exists(user_passwd_file)) { // cout << " ClientEnvironment::get_password() LOADING password file\n"; diff --git a/libs/client/test/InvokeServer.hpp b/libs/client/test/InvokeServer.hpp index ba4890eb2..da9ea9f9a 100644 --- a/libs/client/test/InvokeServer.hpp +++ b/libs/client/test/InvokeServer.hpp @@ -18,6 +18,7 @@ #include "TestHelper.hpp" #include "ecflow/client/ClientInvoker.hpp" #include "ecflow/core/EcfPortLock.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/Host.hpp" #include "ecflow/core/Str.hpp" @@ -37,8 +38,9 @@ class InvokeServer { if (!msg.empty()) { std::cout << msg << " port(" << port_ << ")"; #ifdef ECF_OPENSSL - if (getenv("ECF_SSL")) + if (ecf::environment::has(ecf::environment::ECF_SSL)) { std::cout << " (ssl)"; + } #endif std::cout << std::endl; } diff --git a/libs/client/test/SCPort.cpp b/libs/client/test/SCPort.cpp index 1bdf5584a..796d25c60 100644 --- a/libs/client/test/SCPort.cpp +++ b/libs/client/test/SCPort.cpp @@ -15,6 +15,7 @@ #include "ecflow/client/ClientEnvironment.hpp" #include "ecflow/client/ClientInvoker.hpp" #include "ecflow/core/EcfPortLock.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/Str.hpp" namespace ecf { @@ -31,64 +32,70 @@ int SCPort::thePort_ = 3144; std::string SCPort::next() { bool debug = false; - if (getenv("ECF_DEBUG_TEST")) - debug = true; + ecf::environment::get("ECF_DEBUG_TEST", debug); - if (debug) + if (debug) { std::cout << "\nSCPort::next() : "; + } // Allow parallel tests - char* ECF_FREE_PORT = getenv("ECF_FREE_PORT"); - if (ECF_FREE_PORT) { - if (debug) - std::cout << " seed_port=ECF_FREE_PORT=(" << ECF_FREE_PORT << ")"; - std::string port = ECF_FREE_PORT; + + if (auto port = ecf::environment::fetch("ECF_FREE_PORT"); port) { + if (debug) { + std::cout << " seed_port=ECF_FREE_PORT=(" << port.value() << ")"; + } try { - thePort_ = ecf::convert_to(port); + thePort_ = ecf::convert_to(port.value()); } catch (...) { - std::cout << "SCPort::next() ECF_FREE_PORT(" << ECF_FREE_PORT << ") not convertible to an integer\n"; + std::cout << "SCPort::next() ECF_FREE_PORT(" << port.value() << ") not convertible to an integer\n"; } } // This is used to test remote servers(or legacy server with new client). Here ECF_HOST=localhost in the test // scripts std::string host = ClientEnvironment::hostSpecified(); - if (debug) + if (debug) { std::cout << " ECF_HOST('" << host << "')"; + } if (host == Str::LOCALHOST()) { - char* ecf_port = getenv("ECF_PORT"); - if (ecf_port) { - std::string port = ecf_port; - if (!port.empty()) { - if (debug) - std::cout << " ECF_PORT('" << ecf_port << "')\n"; - return port; + if (auto port = ecf::environment::fetch(ecf::environment::ECF_PORT); port) { + if (!port.value().empty()) { + if (debug) { + std::cout << " ECF_PORT('" << port.value() << "')\n"; + } + return port.value(); } } - if (debug) + if (debug) { std::cout << " !!!!!! ERROR when ECF_HOST=localhost EXPECTED ECF_PORT to be set !!!!!! "; + } } - if (debug) + if (debug) { std::cout << "\n"; + } std::string the_port = next_only(debug); - if (debug) + if (debug) { std::cout << " SCPort::next() returning free port=" << the_port << "\n"; + } return the_port; } std::string SCPort::next_only(bool debug) { - if (debug) + if (debug) { std::cout << " SCPort::next_only : starting seed_port(" << thePort_ << ")\n"; + } // Use a combination of local lock file, and pinging the server - while (!EcfPortLock::is_free(thePort_, debug)) + while (!EcfPortLock::is_free(thePort_, debug)) { thePort_++; + } - if (debug) + if (debug) { std::cout << " SCPort::next_only() seed_port(" << thePort_ << ")\n"; + } return ClientInvoker::find_free_port(thePort_, debug); } diff --git a/libs/client/test/TestJobGenOnly.cpp b/libs/client/test/TestJobGenOnly.cpp index 0fc4bfe42..a2a7fe932 100644 --- a/libs/client/test/TestJobGenOnly.cpp +++ b/libs/client/test/TestJobGenOnly.cpp @@ -13,6 +13,7 @@ #include // IWYU pragma: keep #include "TestNaming.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Str.hpp" #include "ecflow/node/Defs.hpp" @@ -67,7 +68,7 @@ BOOST_AUTO_TEST_CASE(test_jobgenonly) { BOOST_REQUIRE_MESSAGE(theDefs.restore(defsFile, errorMsg, warningMsg), errorMsg); // Override ECF_HOME. ECF_HOME is needed to locate to the .ecf files - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); // provide definition of ECF_CLIENT. This should replace smsinit, smscomplete, smsevent,etc // with path to the ecf client diff --git a/libs/client/test/TestServer.cpp b/libs/client/test/TestServer.cpp index 860a58824..4e067910e 100644 --- a/libs/client/test/TestServer.cpp +++ b/libs/client/test/TestServer.cpp @@ -18,6 +18,7 @@ #include "ecflow/client/ClientEnvironment.hpp" #include "ecflow/client/ClientInvoker.hpp" #include "ecflow/core/DurationTimer.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Str.hpp" #include "ecflow/core/Version.hpp" @@ -249,8 +250,9 @@ BOOST_AUTO_TEST_CASE(test_server_stress_test) { ClientInvoker theClient(invokeServer.host(), invokeServer.port()); int load = 125; #ifdef ECF_OPENSSL - if (getenv("ECF_SSL")) + if (ecf::environment::has(ecf::environment::ECF_SSL)) { load = 30; + } #endif { @@ -290,10 +292,9 @@ BOOST_AUTO_TEST_CASE(test_server_stress_test) { BOOST_REQUIRE_MESSAGE(theClient.defs()->suiteVec().size() >= 1, " no suite ?"); } cout << " Server handled " << load * 16 << " requests in boost_timer(" - << boost_timer.format(3, Str::cpu_timer_format()) << ")" - << " DurationTimer(" << to_simple_string(duration_timer.elapsed()) << ")" - << " Chrono_timer(" << std::chrono::duration(chrono_timer.elapsed()).count() - << " milli)" << endl; + << boost_timer.format(3, Str::cpu_timer_format()) << ")" << " DurationTimer(" + << to_simple_string(duration_timer.elapsed()) << ")" << " Chrono_timer(" + << std::chrono::duration(chrono_timer.elapsed()).count() << " milli)" << endl; } { theClient.set_auto_sync(true); @@ -326,10 +327,9 @@ BOOST_AUTO_TEST_CASE(test_server_stress_test) { BOOST_REQUIRE_MESSAGE(theClient.defs()->suiteVec().size() >= 1, " no suite ?"); } cout << " Server handled " << load * 8 << " requests in boost_timer(" - << boost_timer.format(3, Str::cpu_timer_format()) << ")" - << " DurationTimer(" << to_simple_string(duration_timer.elapsed()) << ")" - << " Chrono_timer(" << std::chrono::duration(chrono_timer.elapsed()).count() - << " milli)" + << boost_timer.format(3, Str::cpu_timer_format()) << ")" << " DurationTimer(" + << to_simple_string(duration_timer.elapsed()) << ")" << " Chrono_timer(" + << std::chrono::duration(chrono_timer.elapsed()).count() << " milli)" << " *with* AUTO SYNC" << endl; } } @@ -370,8 +370,9 @@ BOOST_AUTO_TEST_CASE(test_server_group_stress_test) { int load = 125; #ifdef ECF_OPENSSL - if (getenv("ECF_SSL")) + if (ecf::environment::has(ecf::environment::ECF_SSL)) { load = 30; + } #endif for (int i = 0; i < load; i++) { @@ -423,8 +424,9 @@ BOOST_AUTO_TEST_CASE(test_server_stress_test_2) { #endif #ifdef ECF_OPENSSL - if (getenv("ECF_SSL")) + if (ecf::environment::has(ecf::environment::ECF_SSL)) { load = 10; + } #endif boost::timer::cpu_timer diff --git a/libs/client/test/TestSinglePerf.cpp b/libs/client/test/TestSinglePerf.cpp index bee392cd7..508bcc17d 100644 --- a/libs/client/test/TestSinglePerf.cpp +++ b/libs/client/test/TestSinglePerf.cpp @@ -8,7 +8,7 @@ * nor does it submit to any jurisdiction. */ -#include // getenv +#include #include #include @@ -350,7 +350,7 @@ void time_load_and_downloads(ClientInvoker& theClient, BOOST_AUTO_TEST_CASE(test_perf_for_large_defs) { ECF_NAME_THIS_TEST(); - if (const char* ecf_ssl = getenv("ECF_SSL"); ecf_ssl) { + if (ecf::environment::has(ecf::environment::ECF_SSL)) { load_threshold_ms = 8000; // 4500; begin_threshold_ms = 800; // 400; sync_full_threshold_s = 4.5; // 2.6; @@ -362,11 +362,11 @@ BOOST_AUTO_TEST_CASE(test_perf_for_large_defs) { client_cmds_threshold_s = 950; // 8.5; } - if (const char* ecf_test_defs_dir = getenv("ECF_TEST_DEFS_DIR"); !ecf_test_defs_dir) { + if (auto ecf_test_defs_dir = ecf::environment::fetch("ECF_TEST_DEFS_DIR"); !ecf_test_defs_dir) { std::cout << "Ignoring test! Environment variable ECF_TEST_DEFS_DIR is not defined\n"; } - else if (!fs::exists(ecf_test_defs_dir)) { - std::cout << "Ignoring test! Test definitions directory " << ecf_test_defs_dir << " does not exist\n"; + else if (!fs::exists(ecf_test_defs_dir.value())) { + std::cout << "Ignoring test! Test definitions directory " << ecf_test_defs_dir.value() << " does not exist\n"; } else { /// This will remove checkpt and backup , to avoid server from loading it. (i.e from previous test) @@ -375,7 +375,7 @@ BOOST_AUTO_TEST_CASE(test_perf_for_large_defs) { "Server failed to start on " << invokeServer.host() << ":" << invokeServer.port()); ClientInvoker theClient(invokeServer.host(), invokeServer.port()); - time_load_and_downloads(theClient, invokeServer.host(), invokeServer.port(), ecf_test_defs_dir); + time_load_and_downloads(theClient, invokeServer.host(), invokeServer.port(), ecf_test_defs_dir.value()); } } diff --git a/libs/core/src/ecflow/core/EcfPortLock.hpp b/libs/core/src/ecflow/core/EcfPortLock.hpp index 6d96909e6..7a2f06ec7 100644 --- a/libs/core/src/ecflow/core/EcfPortLock.hpp +++ b/libs/core/src/ecflow/core/EcfPortLock.hpp @@ -22,6 +22,7 @@ #include #include "ecflow/core/Converter.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" namespace ecf { @@ -65,12 +66,8 @@ class EcfPortLock { static std::string port_file(const std::string& the_port) { // We need the *SAME* location so that different process find the same file. // When going across compiler the root_build_dir is not sufficient - char* ecf_port_lock_dir = getenv("ECF_PORT_LOCK_DIR"); - std::string path; - if (ecf_port_lock_dir) - path = ecf_port_lock_dir; - else - path = File::root_source_dir(); + std::string path = File::root_source_dir(); + ecf::environment::get("ECF_PORT_LOCK_DIR", path); path += "/"; path += the_port; diff --git a/libs/core/src/ecflow/core/Environment.hpp b/libs/core/src/ecflow/core/Environment.hpp new file mode 100644 index 000000000..ff9116f48 --- /dev/null +++ b/libs/core/src/ecflow/core/Environment.hpp @@ -0,0 +1,193 @@ +/* + * Copyright 2009- ECMWF. + * + * This software is licensed under the terms of the Apache Licence version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. + */ + +#ifndef ecflow_core_Environment_HPP +#define ecflow_core_Environment_HPP + +#include + +#include "ecflow/core/Message.hpp" + +namespace ecf { + +namespace environment { + +constexpr const char* ECF_PORT = "ECF_PORT"; +constexpr const char* ECF_RID = "ECF_RID"; +constexpr const char* ECF_TRYNO = "ECF_TRYNO"; +constexpr const char* ECF_TRIES = "ECF_TRIES"; +constexpr const char* ECF_NAME = "ECF_NAME"; +constexpr const char* ECF_HOST = "ECF_HOST"; +constexpr const char* ECF_HOST_PROTOCOL = "ECF_HOST_PROTOCOL"; +constexpr const char* ECF_PASS = "ECF_PASS"; +constexpr const char* ECF_JOB = "ECF_JOB"; +constexpr const char* ECF_JOBOUT = "ECF_JOBOUT"; +constexpr const char* ECF_SCRIPT = "ECF_SCRIPT"; +constexpr const char* ECF_DUMMY_TASK = "ECF_DUMMY_TASK"; +constexpr const char* ECF_NO_SCRIPT = "ECF_NO_SCRIPT"; +constexpr const char* ECF_MICRO = "ECF_MICRO"; +constexpr const char* ECF_FILES = "ECF_FILES"; +constexpr const char* ECF_FETCH = "ECF_FETCH"; +constexpr const char* ECF_KILL_CMD = "ECF_KILL_CMD"; +constexpr const char* ECF_STATUS_CMD = "ECF_STATUS_CMD"; +constexpr const char* ECF_HOME = "ECF_HOME"; +constexpr const char* ECF_INCLUDE = "ECF_INCLUDE"; +constexpr const char* ECF_JOB_CMD = "ECF_JOB_CMD"; +constexpr const char* ECF_OUT = "ECF_OUT"; +constexpr const char* ECF_EXTN = "ECF_EXTN"; +constexpr const char* ECF_LOG = "ECF_LOG"; +constexpr const char* ECF_PASSWD = "ECF_PASSWD"; +constexpr const char* ECF_CUSTOM_PASSWD = "ECF_CUSTOM_PASSWD"; + +constexpr const char* ECF_SSL = "ECF_SSL"; +constexpr const char* ECF_USER = "ECF_USER"; + +namespace /* anonymous */ { + +template +struct Wrapper +{ + static std::optional get(const char* name) { + if (auto var = std::getenv(name); var) { + return T{var}; + } + return std::nullopt; + } +}; + +template <> +struct Wrapper +{ + static std::optional get(const char* name) { + if (auto var = std::getenv(name); var) { + return std::make_optional(var); + } + return std::nullopt; + } +}; + +template <> +struct Wrapper +{ + static std::optional get(const char* name) { + if (auto var = std::getenv(name); var) { + return atoi(var); + } + return std::nullopt; + } +}; + +template <> +struct Wrapper +{ + static std::optional get(const char* name) { + if (auto var = std::getenv(name); var) { + return atoi(var); + } + return std::nullopt; + } +}; + +template <> +struct Wrapper +{ + static std::optional get(const char* name) { + if (auto var = std::getenv(name); var) { + return atol(var); + } + return std::nullopt; + } +}; + +template <> +struct Wrapper +{ + static std::optional get(const char* name) { + if (auto var = std::getenv(name); var) { + return true; + } + return std::nullopt; + } +}; + +} // namespace + +struct EnvVarNotFound : public std::runtime_error +{ + explicit EnvVarNotFound(std::basic_string what) : std::runtime_error(what) {} +}; + +/** + * @brief Retrieves the environment variable value and stores it in the given variable. + * If the environment variable is not found, the variable is left unchanged. + * + * In case of integral types, the environment variable is converted to the corresponding type. + * In case of bool type, if the environment variable is set, the variable is set to true. + * + * @tparam T + * @param name + * @param value + */ +template +void get(const char* name, T& value) { + if (auto found = Wrapper::get(name); found) { + value = found.value(); + } +} + +/** + * @brief Retrieves the environment variable value and returns it. + * If the environment variable is not found, an exception is thrown. + * + * In case of integral types, the environment variable is converted to the corresponding type. + * In case of bool type, if the environment variable is set, the result is true. + * + * @tparam T + * @param name + */ +template +T get(const char* name) { + if (auto found = Wrapper::get(name); found) { + return found.value(); + } + + throw EnvVarNotFound(Message(name).str()); +} + +/** + * @brief Retrieves the environment variable value and returns it (wrapped in an std::optional<>). + * If the environment variable is not found, std::nullopt is returned. + * + * In case of integral types, the environment variable is converted to the corresponding type. + * In case of bool type, if the environment variable is set, the result is true. + * + * @tparam T + * @param name + */ +template +std::optional fetch(const char* name) { + return Wrapper::get(name); +} + +/** + * @brief Checks if an environment variable is set. + * + * @tparam T + * @param name + */ +inline bool has(const char* name) { + return std::getenv(name) != nullptr; +} + +} // namespace environment + +} // namespace ecf + +#endif /* ecflow_core_Environment_HPP */ diff --git a/libs/core/src/ecflow/core/File.cpp b/libs/core/src/ecflow/core/File.cpp index e3a6aac11..3147cf1c6 100644 --- a/libs/core/src/ecflow/core/File.cpp +++ b/libs/core/src/ecflow/core/File.cpp @@ -16,6 +16,7 @@ #include #include "ecflow/core/Ecf.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/Log.hpp" #include "ecflow/core/NodePath.hpp" #include "ecflow/core/Str.hpp" @@ -54,7 +55,7 @@ const std::string& File::ECF_EXTN() { /// Search for the file, in $PATH return the first path that matches or an empty file, if not std::string File::which(const std::string& file) { - std::string env_paths = getenv("PATH"); + std::string env_paths = ecf::environment::get("PATH"); if (!env_paths.empty()) { std::string path; std::vector paths; @@ -839,12 +840,12 @@ static std::string bjam_workspace_dir() { stem = current_path.stem().string(); count++; if (count == 100) { - char* workspace = getenv("WK"); - if (workspace == NULL) { + auto workspace = ecf::environment::fetch("WK"); + if (!workspace) { throw std::runtime_error("File::bjam_workspace_dir() failed to find ecflow in a directory name, up the " "directory tree and WK undefined"); } - std::string the_workspace_dir = workspace; + std::string the_workspace_dir = workspace.value(); return the_workspace_dir; } } @@ -983,9 +984,9 @@ std::string File::find_ecf_client_path() { std::string File::test_data(const std::string& rel_path, const std::string& dir) { std::string test_file; - char* work_space = getenv("WK"); // for ecbuild - if (work_space != nullptr) { - test_file = std::string(work_space); + + if (auto workspace = ecf::environment::fetch("WK"); workspace) { + test_file = workspace.value(); if (!rel_path.empty() && rel_path[0] != '/') test_file += "/"; test_file += rel_path; diff --git a/libs/core/src/ecflow/core/Host.cpp b/libs/core/src/ecflow/core/Host.cpp index f2db501bd..4f75a8491 100644 --- a/libs/core/src/ecflow/core/Host.cpp +++ b/libs/core/src/ecflow/core/Host.cpp @@ -15,6 +15,7 @@ #include // for gethostname #include "ecflow/core/Ecf.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/Str.hpp" using namespace std; @@ -67,11 +68,11 @@ std::string Host::ecf_lists_file(const std::string& port) const { } std::string Host::ecf_passwd_file(const std::string& port) const { - return prefix_host_and_port(port, Str::ECF_PASSWD()); + return prefix_host_and_port(port, ecf::environment::ECF_PASSWD); } std::string Host::ecf_custom_passwd_file(const std::string& port) const { - return prefix_host_and_port(port, Str::ECF_CUSTOM_PASSWD()); + return prefix_host_and_port(port, ecf::environment::ECF_CUSTOM_PASSWD); } std::string Host::prefix_host_and_port(const std::string& port, const std::string& file_name) const { diff --git a/libs/core/src/ecflow/core/Str.cpp b/libs/core/src/ecflow/core/Str.cpp index 93b9e8d60..457afb362 100644 --- a/libs/core/src/ecflow/core/Str.cpp +++ b/libs/core/src/ecflow/core/Str.cpp @@ -79,112 +79,10 @@ const std::string& Str::LOCALHOST() { return localhost; } -const std::string& Str::ECF_PORT() { - static std::string ECF_PORT = "ECF_PORT"; - return ECF_PORT; -} -const std::string& Str::ECF_RID() { - static std::string ECF_RID = "ECF_RID"; - return ECF_RID; -} -const std::string& Str::ECF_TRYNO() { - static std::string ECF_TRYNO = "ECF_TRYNO"; - return ECF_TRYNO; -} -const std::string& Str::ECF_TRIES() { - static std::string ECF_TRIES = "ECF_TRIES"; - return ECF_TRIES; -} -const std::string& Str::ECF_NAME() { - static std::string ECF_NAME = "ECF_NAME"; - return ECF_NAME; -} -const std::string& Str::ECF_HOST() { - static std::string ECF_HOST = "ECF_HOST"; - return ECF_HOST; -} -const std::string& Str::ECF_PASS() { - static std::string ECF_PASS = "ECF_PASS"; - return ECF_PASS; -} -const std::string& Str::ECF_JOB() { - static std::string ECF_JOB = "ECF_JOB"; - return ECF_JOB; -} -const std::string& Str::ECF_JOBOUT() { - static std::string ECF_JOBOUT = "ECF_JOBOUT"; - return ECF_JOBOUT; -} -const std::string& Str::ECF_SCRIPT() { - static std::string ECF_SCRIPT = "ECF_SCRIPT"; - return ECF_SCRIPT; -} -const std::string& Str::ECF_DUMMY_TASK() { - static std::string ECF_DUMMY_TASK = "ECF_DUMMY_TASK"; - return ECF_DUMMY_TASK; -} -const std::string& Str::ECF_NO_SCRIPT() { - static std::string ECF_NO_SCRIPT = "ECF_NO_SCRIPT"; - return ECF_NO_SCRIPT; -} -const std::string& Str::ECF_MICRO() { - static std::string ECF_MICRO = "ECF_MICRO"; - return ECF_MICRO; -} -const std::string& Str::ECF_FILES() { - static std::string ECF_FILES = "ECF_FILES"; - return ECF_FILES; -} -const std::string& Str::ECF_FETCH() { - static std::string ECF_FETCH = "ECF_FETCH"; - return ECF_FETCH; -} -const std::string& Str::ECF_KILL_CMD() { - static std::string ECF_KILL_CMD = "ECF_KILL_CMD"; - return ECF_KILL_CMD; -} -const std::string& Str::ECF_STATUS_CMD() { - static std::string ECF_STATUS_CMD = "ECF_STATUS_CMD"; - return ECF_STATUS_CMD; -} - -const std::string& Str::ECF_HOME() { - static std::string ECF_HOME = "ECF_HOME"; - return ECF_HOME; -} -const std::string& Str::ECF_INCLUDE() { - static std::string ECF_INCLUDE = "ECF_INCLUDE"; - return ECF_INCLUDE; -} -const std::string& Str::ECF_JOB_CMD() { - static std::string ECF_JOB_CMD = "ECF_JOB_CMD"; - return ECF_JOB_CMD; -} -const std::string& Str::ECF_OUT() { - static std::string ECF_OUT = "ECF_OUT"; - return ECF_OUT; -} -const std::string& Str::ECF_EXTN() { - static std::string ECF_EXTN = "ECF_EXTN"; - return ECF_EXTN; -} -const std::string& Str::ECF_LOG() { - static std::string ECF_LOG = "ECF_LOG"; - return ECF_LOG; -} - const std::string& Str::WHITE_LIST_FILE() { static std::string WHITE_LIST_FILE = "ecf.lists"; return WHITE_LIST_FILE; } -const std::string& Str::ECF_PASSWD() { - static std::string ECF_PASSWD = "ecf.passwd"; - return ECF_PASSWD; -} -const std::string& Str::ECF_CUSTOM_PASSWD() { - static std::string ECF_CUSTOM_PASSWD = "ecf.custom_passwd"; - return ECF_CUSTOM_PASSWD; -} const std::string& Str::ALPHANUMERIC_UNDERSCORE() { static string ALPHANUMERIC_UNDERSCORE = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; diff --git a/libs/core/src/ecflow/core/Str.hpp b/libs/core/src/ecflow/core/Str.hpp index 2de926364..cb478c863 100644 --- a/libs/core/src/ecflow/core/Str.hpp +++ b/libs/core/src/ecflow/core/Str.hpp @@ -206,34 +206,7 @@ class Str { static const std::string& DEFAULT_PORT_NUMBER(); // "3141" static const std::string& LOCALHOST(); - static const std::string& ECF_PORT(); - static const std::string& ECF_RID(); - static const std::string& ECF_TRYNO(); - static const std::string& ECF_TRIES(); - static const std::string& ECF_NAME(); - static const std::string& ECF_HOST(); - static const std::string& ECF_PASS(); - static const std::string& ECF_JOB(); - static const std::string& ECF_JOBOUT(); - static const std::string& ECF_SCRIPT(); - static const std::string& ECF_DUMMY_TASK(); - static const std::string& ECF_NO_SCRIPT(); - static const std::string& ECF_MICRO(); - static const std::string& ECF_FILES(); - static const std::string& ECF_FETCH(); - static const std::string& ECF_KILL_CMD(); - static const std::string& ECF_STATUS_CMD(); - - static const std::string& ECF_HOME(); - static const std::string& ECF_INCLUDE(); - static const std::string& ECF_JOB_CMD(); - static const std::string& ECF_OUT(); - static const std::string& ECF_EXTN(); - static const std::string& ECF_LOG(); - static const std::string& WHITE_LIST_FILE(); - static const std::string& ECF_PASSWD(); - static const std::string& ECF_CUSTOM_PASSWD(); static const char* cpu_timer_format() { return "%ws wall, (%us user + %ss system = %ts) CPU (%p%)"; } }; diff --git a/libs/core/test/TestFile.cpp b/libs/core/test/TestFile.cpp index 73d470cb4..e5faaf2f9 100644 --- a/libs/core/test/TestFile.cpp +++ b/libs/core/test/TestFile.cpp @@ -8,7 +8,6 @@ * nor does it submit to any jurisdiction. */ -#include // for getenv() #include // for std::ofstream #include #include @@ -16,6 +15,7 @@ #include #include "ecflow/core/Converter.hpp" +#include "ecflow/core/Environment.hpp" // #define FILE_PERF_CHECK_IMPLEMENTATIONS 1; #ifdef FILE_PERF_CHECK_IMPLEMENTATIONS @@ -320,7 +320,7 @@ BOOST_AUTO_TEST_CASE(test_create_missing_directories) { ECF_NAME_THIS_TEST(); // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode. - if (getenv("ECFLOW_CRAY_BATCH")) { + if (ecf::environment::has("ECFLOW_CRAY_BATCH")) { ECF_TEST_DBG(<< "Test skipped until HPC team can fix File::createMissingDirectories.(like mkdir -p)"); return; } diff --git a/libs/core/test/TestSanitizerAS.cpp b/libs/core/test/TestSanitizerAS.cpp index 465eca956..57b5d5ada 100644 --- a/libs/core/test/TestSanitizerAS.cpp +++ b/libs/core/test/TestSanitizerAS.cpp @@ -13,6 +13,7 @@ #include #include "TestNaming.hpp" +#include "ecflow/core/Environment.hpp" using namespace boost; using namespace std; @@ -28,7 +29,7 @@ static bool is_sanitizer_available() { * Unfortunatelly this approach does not work when using Boost 1.66 @ Rocky 8.6. */ - bool is_available = ::getenv("ECF_TEST_SANITIZER_AS") != nullptr; + bool is_available = ecf::environment::has("ECF_TEST_SANITIZER_AS"); return is_available; } diff --git a/libs/core/test/TestSanitizerUB.cpp b/libs/core/test/TestSanitizerUB.cpp index e4f197822..911cb8298 100644 --- a/libs/core/test/TestSanitizerUB.cpp +++ b/libs/core/test/TestSanitizerUB.cpp @@ -13,6 +13,7 @@ #include #include "TestNaming.hpp" +#include "ecflow/core/Environment.hpp" using namespace boost; using namespace std; @@ -28,7 +29,7 @@ static bool is_sanitizer_available() { * Unfortunatelly this approach does not work when using Boost 1.66 @ Rocky 8.6. */ - bool is_available = ::getenv("ECF_TEST_SANITIZER_UB") != nullptr; + bool is_available = ecf::environment::has("ECF_TEST_SANITIZER_UB"); return is_available; } diff --git a/libs/core/test/TestStringSplitPerf.cpp b/libs/core/test/TestStringSplitPerf.cpp index 36d95c929..f80781e20 100644 --- a/libs/core/test/TestStringSplitPerf.cpp +++ b/libs/core/test/TestStringSplitPerf.cpp @@ -251,14 +251,14 @@ BOOST_AUTO_TEST_CASE(test_str_split_perf_with_file) { // Time for std::string_view(2) 2001774 times = 0.752472 // Now test performance of splitting with a big DEFS file - char* ecf_test_defs_dir = getenv("ECF_TEST_DEFS_DIR"); + auto ecf_test_defs_dir = ecf::environment::fetch("ECF_TEST_DEFS_DIR"); if (!ecf_test_defs_dir) { ECF_TEST_DBG(<< "Igoring test, since directory defined by environment variable(ECF_TEST_DEFS_DIR) is missing"); return; } - std::string path = std::string(ecf_test_defs_dir) + "/vsms2.31415.def"; + std::string path = ecf_test_defs_dir.value() + "/vsms2.31415.def"; if (!fs::exists(path)) { - std::cout << "Ingoring test, since file defined by environment variable(ECF_TEST_DEFS_DIR) " << path + std::cout << "Igoring test, since file defined by environment variable(ECF_TEST_DEFS_DIR) " << path << " is missing"; return; } diff --git a/libs/node/src/ecflow/node/EcfFile.cpp b/libs/node/src/ecflow/node/EcfFile.cpp index f3e20521c..953205289 100644 --- a/libs/node/src/ecflow/node/EcfFile.cpp +++ b/libs/node/src/ecflow/node/EcfFile.cpp @@ -20,6 +20,7 @@ #include "ecflow/core/Converter.hpp" #include "ecflow/core/Ecf.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Log.hpp" #include "ecflow/core/Str.hpp" @@ -99,7 +100,7 @@ EcfFile::EcfFile(Node* t, script_path_or_cmd_(pathToEcfFileOrCommand), script_origin_(script_origin), ecf_file_search_algorithm_(search_algo) { - node_->findParentUserVariableValue(Str::ECF_MICRO(), ecfMicroCache_); + node_->findParentUserVariableValue(ecf::environment::ECF_MICRO, ecfMicroCache_); if (ecfMicroCache_.empty() || ecfMicroCache_.size() != 1) { std::stringstream ss; ss << "EcfFile::EcfFile: Node " << t->absNodePath() << " is referencing a invalid ECF_MICRO variable(' " @@ -454,7 +455,7 @@ std::vector EcfFile::get_ecf_include_paths(const EcfFile& ecf) { const Node& node = *ecf.node_; std::string ecf_include; - node.findParentUserVariableValue(Str::ECF_INCLUDE(), ecf_include); + node.findParentUserVariableValue(ecf::environment::ECF_INCLUDE, ecf_include); std::vector paths; if (!ecf_include.empty()) { @@ -902,19 +903,19 @@ void EcfFile::get_used_variables(std::string& used_variables) const { // to modify. Hence, we have also excluded generated variables SUITE, FAMILY, TASK // **************************************************************************************** for (std::pair item : used_variables_map) { - if (item.first.find(Str::ECF_TRYNO()) != std::string::npos) + if (item.first.find(ecf::environment::ECF_TRYNO) != std::string::npos) continue; - if (item.first.find(Str::ECF_JOB()) != std::string::npos) + if (item.first.find(ecf::environment::ECF_JOB) != std::string::npos) continue; - if (item.first.find(Str::ECF_JOBOUT()) != std::string::npos) + if (item.first.find(ecf::environment::ECF_JOBOUT) != std::string::npos) continue; - if (item.first.find(Str::ECF_PASS()) != std::string::npos) + if (item.first.find(ecf::environment::ECF_PASS) != std::string::npos) continue; - if (item.first.find(Str::ECF_PORT()) != std::string::npos) + if (item.first.find(ecf::environment::ECF_PORT) != std::string::npos) continue; - if (item.first.find(Str::ECF_HOST()) != std::string::npos) + if (item.first.find(ecf::environment::ECF_HOST) != std::string::npos) continue; - if (item.first.find(Str::ECF_NAME()) != std::string::npos) + if (item.first.find(ecf::environment::ECF_NAME) != std::string::npos) continue; // We must use exact match, to avoid user variables like ESUITE,EFAMILY,ETASK @@ -1044,7 +1045,7 @@ const std::string& EcfFile::doCreateJobFile(JobsParam& jobsParam) const { // b/ The value of the user variable has a valid directory paths and job file name // c/ The user will lose the try number. std::string ecf_job; - if (!node_->findParentVariableValue(Str::ECF_JOB(), ecf_job)) { + if (!node_->findParentVariableValue(ecf::environment::ECF_JOB, ecf_job)) { LOG_ASSERT(!ecf_job.empty(), "EcfFile::doCreateJobFile: ECF_JOB should have been generated, program error"); } @@ -1123,7 +1124,7 @@ std::string EcfFile::script_or_job_path() const { // ECF_FETCH or ECF_SCRIPT_CMD std::string ecf_job; - (void)node_->findParentVariableValue(Str::ECF_JOB(), ecf_job); + (void)node_->findParentVariableValue(ecf::environment::ECF_JOB, ecf_job); return ecf_job; } @@ -1739,7 +1740,7 @@ std::string PreProcessor::getIncludedFilePath(const std::string& includedFile1, // WE get HERE *if* ECF_INCLUDE not specified, or if specified but file *not found* std::string ecf_include; - node->findParentVariableValue(Str::ECF_HOME(), ecf_include); + node->findParentVariableValue(ecf::environment::ECF_HOME, ecf_include); if (ecf_include.empty()) { std::stringstream ss; ss << "ECF_INCLUDE/ECF_HOME not specified, at : " << line; @@ -1778,7 +1779,7 @@ std::string PreProcessor::getIncludedFilePath(const std::string& includedFile1, } // include contents of %ECF_HOME%/%SUITE%/%FAMILY%/filename - node->findParentUserVariableValue(Str::ECF_HOME(), path); + node->findParentUserVariableValue(ecf::environment::ECF_HOME, path); if (path.empty()) { std::stringstream ss; ss << "ECF_HOME not specified, at : " << line; @@ -1867,7 +1868,7 @@ bool IncludeFileCache::lines(std::vector& lns) { string line; while (std::getline(fp_, line)) { lns.push_back(line); - } // c++11 + } // c++11 fp_.clear(); // eol fp_ will be in bad state reset. So we can re-use no_of_lines_ = lns.size(); // cache for next time diff --git a/libs/node/src/ecflow/node/JobCreationCtrl.cpp b/libs/node/src/ecflow/node/JobCreationCtrl.cpp index bd87bd01b..2ffb5b446 100644 --- a/libs/node/src/ecflow/node/JobCreationCtrl.cpp +++ b/libs/node/src/ecflow/node/JobCreationCtrl.cpp @@ -10,17 +10,22 @@ #include "ecflow/node/JobCreationCtrl.hpp" -#include // for getenv() #include #include +#include "ecflow/core/Environment.hpp" + void JobCreationCtrl::generate_temp_dir() { - if (!getenv("TMPDIR")) + if (auto tmpdir = ecf::environment::fetch("TMPDIR"); tmpdir) { + tempDirForJobGeneration_ = tmpdir.value(); + tempDirForJobGeneration_ += "/ecf_check_job_creation"; + if (fs::exists(tempDirForJobGeneration_)) { + fs::remove_all(tempDirForJobGeneration_); + } + std::cout << "JobCreationCtrl::generate_temp_dir() " << tempDirForJobGeneration_ << "\n"; + } + else { throw std::runtime_error( "JobCreationCtrl::generate_temp_dir(), The environment variable TMPDIR is not defined"); - tempDirForJobGeneration_ = getenv("TMPDIR"); - tempDirForJobGeneration_ += "/ecf_check_job_creation"; - if (fs::exists(tempDirForJobGeneration_)) - fs::remove_all(tempDirForJobGeneration_); - std::cout << "JobCreationCtrl::generate_temp_dir() " << tempDirForJobGeneration_ << "\n"; + } } diff --git a/libs/node/src/ecflow/node/Node.cpp b/libs/node/src/ecflow/node/Node.cpp index f73103b5c..ac304fde7 100644 --- a/libs/node/src/ecflow/node/Node.cpp +++ b/libs/node/src/ecflow/node/Node.cpp @@ -15,6 +15,7 @@ #include "ecflow/attribute/AutoCancelAttr.hpp" #include "ecflow/attribute/LateAttr.hpp" #include "ecflow/core/Ecf.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/Extract.hpp" #include "ecflow/core/Indentor.hpp" #include "ecflow/core/Log.hpp" @@ -1219,7 +1220,7 @@ search_user_edit_variables(const std::string& name, std::string& value, const Na bool Node::variableSubstitution(std::string& cmd) const { char micro = '%'; std::string micro_char; - findParentUserVariableValue(Str::ECF_MICRO(), micro_char); + findParentUserVariableValue(ecf::environment::ECF_MICRO, micro_char); if (!micro_char.empty() && micro_char.size() == 1) { micro = micro_char[0]; } @@ -1291,15 +1292,15 @@ bool Node::variable_substitution(std::string& cmd, const NameValueMap& user_edit // Leave ECF_JOB and ECF_JOBOUT out of this list: As user may legitimately override these. ECFLOW-999 bool generated_variable = false; if (percentVar.find("ECF_") == 0) { - if (percentVar.find(Str::ECF_HOST()) != std::string::npos) + if (percentVar.find(ecf::environment::ECF_HOST) != std::string::npos) generated_variable = true; - else if (percentVar.find(Str::ECF_PORT()) != std::string::npos) + else if (percentVar.find(ecf::environment::ECF_PORT) != std::string::npos) generated_variable = true; - else if (percentVar.find(Str::ECF_TRYNO()) != std::string::npos) + else if (percentVar.find(ecf::environment::ECF_TRYNO) != std::string::npos) generated_variable = true; - else if (percentVar.find(Str::ECF_NAME()) != std::string::npos) + else if (percentVar.find(ecf::environment::ECF_NAME) != std::string::npos) generated_variable = true; - else if (percentVar.find(Str::ECF_PASS()) != std::string::npos) + else if (percentVar.find(ecf::environment::ECF_PASS) != std::string::npos) generated_variable = true; } diff --git a/libs/node/src/ecflow/node/NodeContainer.cpp b/libs/node/src/ecflow/node/NodeContainer.cpp index 8363d3f3e..d10b4ecbc 100644 --- a/libs/node/src/ecflow/node/NodeContainer.cpp +++ b/libs/node/src/ecflow/node/NodeContainer.cpp @@ -19,6 +19,7 @@ #include "ecflow/core/Converter.hpp" #include "ecflow/core/Ecf.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Host.hpp" #include "ecflow/core/Log.hpp" @@ -1135,7 +1136,7 @@ void NodeContainer::update_limits() { std::string NodeContainer::archive_path() const { std::string the_archive_path; - if (!findParentUserVariableValue(Str::ECF_HOME(), the_archive_path)) { + if (!findParentUserVariableValue(ecf::environment::ECF_HOME, the_archive_path)) { std::stringstream ss; ss << "NodeContainer::archive_path: cannot find ECF_HOME from " << debugNodePath(); throw std::runtime_error(ss.str()); @@ -1148,7 +1149,7 @@ std::string NodeContainer::archive_path() const { std::string port = Str::DEFAULT_PORT_NUMBER(); Defs* the_defs = defs(); if (the_defs) { - port = the_defs->server().find_variable(Str::ECF_PORT()); + port = the_defs->server().find_variable(ecf::environment::ECF_PORT); if (port.empty()) port = Str::DEFAULT_PORT_NUMBER(); } @@ -1308,7 +1309,7 @@ void NodeContainer::remove_archived_files() { } std::string ecf_home; - if (!findParentUserVariableValue(Str::ECF_HOME(), ecf_home)) { + if (!findParentUserVariableValue(ecf::environment::ECF_HOME, ecf_home)) { return; } diff --git a/libs/node/src/ecflow/node/ServerState.cpp b/libs/node/src/ecflow/node/ServerState.cpp index b3068f42d..6fc99f0f0 100644 --- a/libs/node/src/ecflow/node/ServerState.cpp +++ b/libs/node/src/ecflow/node/ServerState.cpp @@ -11,6 +11,7 @@ #include "ecflow/node/ServerState.hpp" #include "ecflow/core/Ecf.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/Host.hpp" #include "ecflow/core/Log.hpp" #include "ecflow/core/Serialization.hpp" @@ -307,7 +308,7 @@ bool ServerState::variableSubsitution(std::string& cmd) const { // edit bill '%fred%' # should be 10 // To prevent this we will use a simple count char micro = '%'; - const Variable& micro_var = findVariable(Str::ECF_MICRO()); + const Variable& micro_var = findVariable(ecf::environment::ECF_MICRO); if (!micro_var.empty() && !micro_var.theValue().empty()) micro = micro_var.theValue()[0]; @@ -420,9 +421,9 @@ void ServerState::setup_default_env(const std::string& port) { void ServerState::setup_default_server_variables(std::vector& server_variables, const std::string& port) { Host host; - server_variables.emplace_back(Str::ECF_MICRO(), + server_variables.emplace_back(ecf::environment::ECF_MICRO, Ecf::MICRO()); // Preprocessor character for variable substitution and including files - server_variables.emplace_back(Str::ECF_HOME(), string(".")); + server_variables.emplace_back(ecf::environment::ECF_HOME, string(".")); server_variables.emplace_back(string("ECF_JOB_CMD"), Ecf::JOB_CMD()); // Command to be executed to submit a job server_variables.emplace_back(string("ECF_KILL_CMD"), Ecf::KILL_CMD()); // Command to be executed to kill a job server_variables.emplace_back(string("ECF_STATUS_CMD"), @@ -446,15 +447,15 @@ void ServerState::setup_default_server_variables(std::vector& server_v // job aborts, the job is automatically re-run. Useful when jobs are run in // an unreliable environments. For example using using commands like ftp(1) // in a job can fail easily, but re-running the job will often work - server_variables.emplace_back(Str::ECF_TRIES(), string("2")); + server_variables.emplace_back(ecf::environment::ECF_TRIES, string("2")); server_variables.emplace_back(string("ECF_VERSION"), Version::raw()); // server version // Needed to setup client environment. // The server sets these variable for use by the client. i.e when creating the jobs // The clients then uses them to communicate with the server. - server_variables.emplace_back(Str::ECF_PORT(), port); - server_variables.emplace_back(Str::ECF_HOST(), Str::LOCALHOST()); + server_variables.emplace_back(ecf::environment::ECF_PORT, port); + server_variables.emplace_back(ecf::environment::ECF_HOST, Str::LOCALHOST()); } /// determines why the node is not running. diff --git a/libs/node/src/ecflow/node/Submittable.cpp b/libs/node/src/ecflow/node/Submittable.cpp index 8f615b9db..8e878b4cf 100644 --- a/libs/node/src/ecflow/node/Submittable.cpp +++ b/libs/node/src/ecflow/node/Submittable.cpp @@ -15,6 +15,7 @@ #include "ecflow/core/Converter.hpp" #include "ecflow/core/Ecf.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/Extract.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Log.hpp" @@ -341,7 +342,7 @@ EcfFile Submittable::locatedEcfFile() const { std::string reasonEcfFileNotFound; std::string theAbsNodePath = absNodePath(); std::string ecf_home; - findParentUserVariableValue(Str::ECF_HOME(), ecf_home); + findParentUserVariableValue(ecf::environment::ECF_HOME, ecf_home); /// Update local ECF_SCRIPT variable, ECF_SCRIPT is a generated variable. IT *MUST* exist /// Likewise generated variable like TASK and ECF_NAME as they may occur in ECF_FETCH_CMD/ECF_SCRIPT_CMD @@ -368,7 +369,7 @@ EcfFile Submittable::locatedEcfFile() const { // Caution: This is not used in operations or research; equally it has not been tested. std::string ecf_fetch_cmd; - findParentVariableValue(Str::ECF_FETCH(), ecf_fetch_cmd); + findParentVariableValue(ecf::environment::ECF_FETCH, ecf_fetch_cmd); if (!ecf_fetch_cmd.empty()) { #ifdef DEBUG_TASK_LOCATION std::cout << "Submittable::locatedEcfFile() Submittable " << name() << " ECF_FETCH = '" << ecf_fetch_cmd @@ -417,7 +418,7 @@ EcfFile Submittable::locatedEcfFile() const { } std::string ecf_filesDirectory; - if (findParentUserVariableValue(Str::ECF_FILES(), ecf_filesDirectory)) { + if (findParentUserVariableValue(ecf::environment::ECF_FILES, ecf_filesDirectory)) { #ifdef DEBUG_TASK_LOCATION std::cout << "Submittable::locatedEcfFile() Submittable " << name() << " searching ECF_FILES = '" << ecf_filesDirectory << "' backwards\n"; @@ -570,7 +571,7 @@ bool Submittable::submit_job_only(JobsParam& jobsParam) { // If the task is a dummy task, return true std::string theValue; - if (findParentUserVariableValue(Str::ECF_DUMMY_TASK(), theValue)) { + if (findParentUserVariableValue(ecf::environment::ECF_DUMMY_TASK, theValue)) { return true; } @@ -585,7 +586,7 @@ bool Submittable::submit_job_only(JobsParam& jobsParam) { requeue_labels(); // ECFLOW-195, requeue no longer resets labels on tasks, hence we do it at task run time. theValue.clear(); - if (findParentUserVariableValue(Str::ECF_NO_SCRIPT(), theValue)) { + if (findParentUserVariableValue(ecf::environment::ECF_NO_SCRIPT, theValue)) { // The script is based on the ECF_JOB_CMD return non_script_based_job_submission(jobsParam); } @@ -795,7 +796,7 @@ void Submittable::kill(const std::string& zombie_pid) { throw std::runtime_error(ss.str()); } - if (!findParentUserVariableValue(Str::ECF_KILL_CMD(), ecf_kill_cmd) || ecf_kill_cmd.empty()) { + if (!findParentUserVariableValue(ecf::environment::ECF_KILL_CMD, ecf_kill_cmd) || ecf_kill_cmd.empty()) { flag().set(ecf::Flag::KILLCMD_FAILED); std::stringstream ss; ss << "Submittable::kill: ECF_KILL_CMD not defined, for task " << absNodePath() << "\n"; @@ -804,7 +805,7 @@ void Submittable::kill(const std::string& zombie_pid) { } else { // Use input - if (!findParentUserVariableValue(Str::ECF_KILL_CMD(), ecf_kill_cmd) || ecf_kill_cmd.empty()) { + if (!findParentUserVariableValue(ecf::environment::ECF_KILL_CMD, ecf_kill_cmd) || ecf_kill_cmd.empty()) { flag().set(ecf::Flag::KILLCMD_FAILED); std::stringstream ss; ss << "Submittable::kill: ECF_KILL_CMD not defined, for task " << absNodePath() << "\n"; @@ -870,7 +871,7 @@ void Submittable::status() { } std::string ecf_status_cmd; - if (!findParentUserVariableValue(Str::ECF_STATUS_CMD(), ecf_status_cmd) || ecf_status_cmd.empty()) { + if (!findParentUserVariableValue(ecf::environment::ECF_STATUS_CMD, ecf_status_cmd) || ecf_status_cmd.empty()) { flag().set(ecf::Flag::STATUSCMD_FAILED); std::stringstream ss; ss << "Submittable::status: ECF_STATUS_CMD not defined, for task " << absNodePath() << "\n"; @@ -901,7 +902,7 @@ bool Submittable::createChildProcess(JobsParam& jobsParam) { cout << "Submittable::createChildProcess for task " << name() << endl; #endif std::string ecf_job_cmd; - findParentUserVariableValue(Str::ECF_JOB_CMD(), ecf_job_cmd); + findParentUserVariableValue(ecf::environment::ECF_JOB_CMD, ecf_job_cmd); if (ecf_job_cmd.empty()) { jobsParam.errorMsg() += "Submittable::createChildProcess: Could not find ECF_JOB_CMD : "; return false; @@ -1070,21 +1071,21 @@ void Submittable::set_genvar_ecfrid(const std::string& value) { // Check the variable names. i.e. we know they are valid SubGenVariables::SubGenVariables(const Submittable* sub) : submittable_(sub), - genvar_ecfjob_(Str::ECF_JOB(), "", false), - genvar_ecfjobout_(Str::ECF_JOBOUT(), "", false), - genvar_ecftryno_(Str::ECF_TRYNO(), "", false), + genvar_ecfjob_(ecf::environment::ECF_JOB, "", false), + genvar_ecfjobout_(ecf::environment::ECF_JOBOUT, "", false), + genvar_ecftryno_(ecf::environment::ECF_TRYNO, "", false), genvar_task_("TASK", "", false), - genvar_ecfpass_(Str::ECF_PASS(), "", false), - genvar_ecfscript_(Str::ECF_SCRIPT(), "", false), - genvar_ecfname_(Str::ECF_NAME(), "", false), - genvar_ecfrid_(Str::ECF_RID(), "", false) { + genvar_ecfpass_(ecf::environment::ECF_PASS, "", false), + genvar_ecfscript_(ecf::environment::ECF_SCRIPT, "", false), + genvar_ecfname_(ecf::environment::ECF_NAME, "", false), + genvar_ecfrid_(ecf::environment::ECF_RID, "", false) { } void SubGenVariables::update_generated_variables() const { // cache strings that are used in many variables std::string theAbsNodePath = submittable_->absNodePath(); std::string ecf_home; - submittable_->findParentUserVariableValue(Str::ECF_HOME(), ecf_home); + submittable_->findParentUserVariableValue(ecf::environment::ECF_HOME, ecf_home); update_static_generated_variables(ecf_home, theAbsNodePath); update_dynamic_generated_variables(ecf_home, theAbsNodePath); } @@ -1129,7 +1130,7 @@ void SubGenVariables::update_dynamic_generated_variables(const std::string& ecf_ /// associated with Suites/Families nodes. /// Bottom up. Can be expensive when we have thousands of tasks. std::string ecf_out; - submittable_->findParentUserVariableValue(Str::ECF_OUT(), ecf_out); + submittable_->findParentUserVariableValue(ecf::environment::ECF_OUT, ecf_out); if (ecf_out.empty()) { genvar_ecfjobout_.value_by_ref().reserve(ecf_home.size() + theAbsNodePath.size() + 1 + the_try_no.size()); diff --git a/libs/node/src/ecflow/node/Task.cpp b/libs/node/src/ecflow/node/Task.cpp index ff15d6d2f..3797492d0 100644 --- a/libs/node/src/ecflow/node/Task.cpp +++ b/libs/node/src/ecflow/node/Task.cpp @@ -15,6 +15,7 @@ #include "ecflow/core/Converter.hpp" #include "ecflow/core/Ecf.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/Extract.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Indentor.hpp" @@ -214,7 +215,7 @@ alias_ptr Task::add_alias(std::vector& user_file_contents, throw std::runtime_error(ss.str()); } - findParentUserVariableValue(Str::ECF_HOME(), dir_to_create); + findParentUserVariableValue(ecf::environment::ECF_HOME, dir_to_create); dir_to_create += absNodePath(); if (!File::createDirectories(dir_to_create)) { throw std::runtime_error("Task::add_alias: could not create directory " + dir_to_create); @@ -519,7 +520,7 @@ bool Task::resolveDependencies(JobsParam& jobsParam) { // If the task was aborted, and we have not exceeded ECF_TRIES, then resubmit // otherwise ONLY in state QUEUED can we submit jobs std::string varValue; - if (findParentUserVariableValue(Str::ECF_TRIES(), varValue)) { + if (findParentUserVariableValue(ecf::environment::ECF_TRIES, varValue)) { // std::cout << "tryNo_ = " << tryNo_ << " ECF_TRIES = " << varValue << "\n"; try { auto ecf_tries = ecf::convert_to(varValue); @@ -816,7 +817,7 @@ const std::string& Task::script_extension() const { // Migration support, allow user to specify extension. This allows users to use '.sms' // Note: This should be removed in the future since there is performance hit. // searching up the node tree, when most of the time we are using .ecf - const std::string& ecf_extn = find_parent_user_variable_value(Str::ECF_EXTN()); + const std::string& ecf_extn = find_parent_user_variable_value(ecf::environment::ECF_EXTN); if (!ecf_extn.empty()) return ecf_extn; return File::ECF_EXTN(); // ".ecf" diff --git a/libs/node/src/ecflow/node/TaskScriptGenerator.cpp b/libs/node/src/ecflow/node/TaskScriptGenerator.cpp index 6199a0d5a..eeb012f70 100644 --- a/libs/node/src/ecflow/node/TaskScriptGenerator.cpp +++ b/libs/node/src/ecflow/node/TaskScriptGenerator.cpp @@ -15,6 +15,7 @@ #include "ecflow/attribute/QueueAttr.hpp" #include "ecflow/core/Converter.hpp" #include "ecflow/core/Ecf.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Str.hpp" #include "ecflow/node/Task.hpp" @@ -27,12 +28,12 @@ namespace ecf { TaskScriptGenerator::TaskScriptGenerator(const Task* task) : task_(task), is_dummy_task_(false) { /// if ECF_DUMMY_TASK specified ignore std::string theValue; - is_dummy_task_ = task_->findParentUserVariableValue(Str::ECF_DUMMY_TASK(), theValue); + is_dummy_task_ = task_->findParentUserVariableValue(ecf::environment::ECF_DUMMY_TASK, theValue); if (is_dummy_task_) return; /// if ECF_FILES specified use this before ECF_HOME - if (task_->findParentUserVariableValue(Str::ECF_FILES(), ecf_files_)) { + if (task_->findParentUserVariableValue(ecf::environment::ECF_FILES, ecf_files_)) { // Create any missing directories if ECF_FILES is specified try { fs::create_directories(ecf_files_); @@ -45,13 +46,13 @@ TaskScriptGenerator::TaskScriptGenerator(const Task* task) : task_(task), is_dum } /// Find ECF_HOME and ECF_INCLUDE - if (!task_->findParentUserVariableValue(Str::ECF_HOME(), ecf_home_)) { + if (!task_->findParentUserVariableValue(ecf::environment::ECF_HOME, ecf_home_)) { std::stringstream ss; ss << "TaskScriptGenerator: Could not generate scripts for task " << task_->absNodePath() << " no ECF_HOME specified\n"; throw std::runtime_error(ss.str()); } - if (!task_->findParentUserVariableValue(Str::ECF_INCLUDE(), ecf_include_)) { + if (!task_->findParentUserVariableValue(ecf::environment::ECF_INCLUDE, ecf_include_)) { std::stringstream ss; ss << "TaskScriptGenerator: Could not generate scripts for task " << task_->absNodePath() << " no ECF_INCLUDE specified\n"; diff --git a/libs/node/test/TestAlias.cpp b/libs/node/test/TestAlias.cpp index b7d0f2eba..c604bb690 100644 --- a/libs/node/test/TestAlias.cpp +++ b/libs/node/test/TestAlias.cpp @@ -13,6 +13,7 @@ #include #include "TestNaming.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Str.hpp" #include "ecflow/node/Alias.hpp" @@ -58,7 +59,7 @@ BOOST_AUTO_TEST_CASE(test_alias_create) { t->addEvent(event2); t->addLabel(label1); t->addLabel(label2); - s->add_variable(Str::ECF_HOME(), ecf_home); + s->add_variable(ecf::environment::ECF_HOME, ecf_home); } // Create .usr file content diff --git a/libs/node/test/TestEcfFile.cpp b/libs/node/test/TestEcfFile.cpp index 2118541db..e44b7f8e0 100644 --- a/libs/node/test/TestEcfFile.cpp +++ b/libs/node/test/TestEcfFile.cpp @@ -8,7 +8,6 @@ * nor does it submit to any jurisdiction. */ -#include // for getenv #include #include @@ -16,6 +15,7 @@ #include "TestNaming.hpp" #include "ecflow/core/Ecf.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Pid.hpp" #include "ecflow/core/Str.hpp" @@ -30,6 +30,10 @@ using namespace std; using namespace ecf; +boost::test_tools::assertion_result is_testing_on_cray([[maybe_unused]] boost::unit_test::test_unit_id id) { + return ecf::environment::has("ECFLOW_CRAY_BATCH"); +} + BOOST_AUTO_TEST_SUITE(U_Node) BOOST_AUTO_TEST_SUITE(T_EcfFile) @@ -70,7 +74,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_simple_include_file) { // is not found in ECF_INCLUDE we then look at ECF_HOME // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode. - if (getenv("ECFLOW_CRAY_BATCH")) { + if (ecf::environment::has("ECFLOW_CRAY_BATCH")) { cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n"; return; } @@ -86,7 +90,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_simple_include_file) { suite_ptr suite = Suite::create(Pid::unique_name("test_ecf_simple_include_file")); Defs theDefs; { - suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/includes")); + suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/includes")); suite->addTask(task_t1); theDefs.addSuite(suite); } @@ -94,7 +98,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_simple_include_file) { // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified // or when file does not exist in ECF_INCLUDE std::string ecf_home = File::test_data("libs/node/test/data", "libs/node"); - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); /// begin , will cause creation of generated variables. The generated variables /// are use in client scripts and used to locate the sms files @@ -153,7 +157,7 @@ BOOST_AUTO_TEST_CASE(test_ECFLOW_495) { ECF_NAME_THIS_TEST(); // This tests for a regression where, *NOT* all the include file were processed. - if (getenv("ECFLOW_CRAY_BATCH")) { + if (ecf::environment::has("ECFLOW_CRAY_BATCH")) { cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n"; return; } @@ -165,7 +169,7 @@ BOOST_AUTO_TEST_CASE(test_ECFLOW_495) { // endsuite Defs theDefs; suite_ptr suite = theDefs.add_suite(Pid::unique_name("test_ECFLOW_495")); - suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/includes")); + suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/includes")); task_ptr task_t1 = suite->add_task("t1"); // PrintStyle style(PrintStyle::STATE); @@ -174,7 +178,7 @@ BOOST_AUTO_TEST_CASE(test_ECFLOW_495) { // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified // or when file does not exist in ECF_INCLUDE std::string ecf_home = File::test_data("libs/node/test/data", "libs/node"); - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); /// begin , will cause creation of generated variables. The generated variables /// are use in client scripts and used to locate the ecf files @@ -226,7 +230,7 @@ BOOST_AUTO_TEST_CASE(test_ECFLOW_495) { BOOST_AUTO_TEST_CASE(test_ECF_SCRIPT_CMD_ECFLOW_427) { ECF_NAME_THIS_TEST(); - if (getenv("ECFLOW_CRAY_BATCH")) { + if (ecf::environment::has("ECFLOW_CRAY_BATCH")) { cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n"; return; } @@ -242,7 +246,7 @@ BOOST_AUTO_TEST_CASE(test_ECF_SCRIPT_CMD_ECFLOW_427) { suite_ptr suite = Suite::create(Pid::unique_name("test_ECF_SCRIPT_CMD_ECFLOW_427")); Defs theDefs; { - suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/includes")); + suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/includes")); suite->addVariable(Variable("body", "body")); suite->addTask(task_t1); theDefs.addSuite(suite); @@ -251,7 +255,7 @@ BOOST_AUTO_TEST_CASE(test_ECF_SCRIPT_CMD_ECFLOW_427) { // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified // or when file does not exist in ECF_INCLUDE std::string ecf_home = File::test_data("libs/node/test/data", "libs/node"); - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); /// begin , will cause creation of generated variables. The generated variables /// are use in client scripts and used to locate the sms files @@ -373,7 +377,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_include_file) { // is not found in ECF_INCLUDE we then look at ECF_HOME // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode. - if (getenv("ECFLOW_CRAY_BATCH")) { + if (ecf::environment::has("ECFLOW_CRAY_BATCH")) { cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n"; return; } @@ -393,7 +397,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_include_file) { suite_ptr suite = Suite::create(Pid::unique_name("test_ecf_include_file")); Defs theDefs; { - suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/includes")); + suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/includes")); suite->addVariable(Variable("SLEEPTIME", "1")); suite->addVariable(Variable("ECF_CLIENT_EXE_PATH", "a/made/up/path")); suite->addTask(task_t1); @@ -402,7 +406,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_include_file) { // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified // or when file does not exist in ECF_INCLUDE - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); /// begin , will cause creation of generated variables. The generated variables /// are use in client scripts and used to locate the sms files @@ -456,7 +460,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_include_multi_paths_ECFLOW_261) { // The specific files are specified in ECF_INCLUDE with multiple paths // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode. - if (getenv("ECFLOW_CRAY_BATCH")) { + if (ecf::environment::has("ECFLOW_CRAY_BATCH")) { cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n"; return; } @@ -476,7 +480,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_include_multi_paths_ECFLOW_261) { Defs theDefs; { suite->addVariable( - Variable(Str::ECF_INCLUDE(), + Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/empty_include1:$ECF_HOME/empty_include2:$ECF_HOME/includes:$ECF_HOME/includes2")); suite->addTask(task_t1); theDefs.addSuite(suite); @@ -484,7 +488,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_include_multi_paths_ECFLOW_261) { // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified // or when file does not exist in ECF_INCLUDE - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); /// begin , will cause creation of generated variables. The generated variables /// are use in client scripts and used to locate the sms files @@ -539,7 +543,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_include_ECFLOW_274) { // In this case we expect to find bill.h in the same directory as the script // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode. - if (getenv("ECFLOW_CRAY_BATCH")) { + if (ecf::environment::has("ECFLOW_CRAY_BATCH")) { cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n"; return; } @@ -558,14 +562,14 @@ BOOST_AUTO_TEST_CASE(test_ecf_include_ECFLOW_274) { suite_ptr suite = Suite::create(Pid::unique_name("test_ecf_include_ECFLOW_274")); Defs theDefs; { - suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/includes")); + suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/includes")); suite->addTask(task_t1); theDefs.addSuite(suite); } // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified // or when file does not exist in ECF_INCLUDE - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); /// begin , will cause creation of generated variables. The generated variables /// are use in client scripts and used to locate the sms files @@ -634,7 +638,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_simple_used_variables) { // See File: libs/node/test/data/includes/used_variables.h // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode. - if (getenv("ECFLOW_CRAY_BATCH")) { + if (ecf::environment::has("ECFLOW_CRAY_BATCH")) { cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n"; return; } @@ -651,7 +655,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_simple_used_variables) { Defs theDefs; { suite = theDefs.add_suite(Pid::unique_name("test_ecf_simple_used_variables")); - suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/includes")); + suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/includes")); suite->add_variable("ESUITE", "suite"); task_t1 = suite->add_family("f1")->add_task("t1"); } @@ -659,7 +663,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_simple_used_variables) { // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified // or when file does not exist in ECF_INCLUDE std::string ecf_home = File::test_data("libs/node/test/data", "libs/node"); - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); /// begin , will cause creation of generated variables. The generated variables /// are use in client scripts and used to locate the sms files @@ -706,7 +710,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_simple_used_variables_with_comments) { // Those variable defined within comments and manuals that are not defined should be ignored // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode. - if (getenv("ECFLOW_CRAY_BATCH")) { + if (ecf::environment::has("ECFLOW_CRAY_BATCH")) { cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n"; return; } @@ -726,7 +730,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_simple_used_variables_with_comments) { Defs theDefs; { suite = theDefs.add_suite(Pid::unique_name("test_ecf_simple_used_variables_with_comments")); - suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/includes")); + suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/includes")); suite->add_variable("ETASK", "suite"); suite->add_variable("FRED", "fred"); task_t1 = suite->add_family("f1")->add_task("t1"); @@ -734,7 +738,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_simple_used_variables_with_comments) { // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified // or when file does not exist in ECF_INCLUDE - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); /// begin , will cause creation of generated variables. The generated variables /// are use in client scripts and used to locate the sms files @@ -777,7 +781,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_simple_used_variables_errors) { // BUT we DO NOT define variable FRED, hence we expect failure // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode. - if (getenv("ECFLOW_CRAY_BATCH")) { + if (ecf::environment::has("ECFLOW_CRAY_BATCH")) { cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n"; return; } @@ -797,14 +801,14 @@ BOOST_AUTO_TEST_CASE(test_ecf_simple_used_variables_errors) { Defs theDefs; { suite = theDefs.add_suite(Pid::unique_name("test_ecf_simple_used_variables_errors")); - suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/includes")); + suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/includes")); suite->add_variable("ETASK", "suite"); task_t1 = suite->add_family("f1")->add_task("t1"); } // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified // or when file does not exist in ECF_INCLUDE - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); /// begin , will cause creation of generated variables. The generated variables /// are use in client scripts and used to locate the sms files @@ -838,7 +842,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_file) { ECF_NAME_THIS_TEST(); // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode. - if (getenv("ECFLOW_CRAY_BATCH")) { + if (ecf::environment::has("ECFLOW_CRAY_BATCH")) { cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n"; return; } @@ -866,7 +870,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_file) { suite_ptr suite = Suite::create(Pid::unique_name("test_ecf_file")); Defs theDefs; { - suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/includes")); + suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/includes")); suite->addVariable(Variable("SLEEPTIME", "1")); suite->addVariable(Variable("ECF_CLIENT_EXE_PATH", "a/made/up/path")); for (const NameValueMap::value_type& p : expected_used_variables) { @@ -877,7 +881,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_file) { } // Override ECF_HOME. ECF_HOME is need to locate to the .ecf files - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); /// begin , will cause creation of generated variables. The generated variables /// are use in client scripts and used to locate the sms files @@ -1033,7 +1037,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_file_includenoop) { ECF_NAME_THIS_TEST(); // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode. - if (getenv("ECFLOW_CRAY_BATCH")) { + if (ecf::environment::has("ECFLOW_CRAY_BATCH")) { cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n"; return; } @@ -1049,7 +1053,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_file_includenoop) { suite_ptr suite = Suite::create(Pid::unique_name("test_ecf_file_includenoop")); Defs theDefs; { - suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/includes")); + suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/includes")); suite->addVariable(Variable("SLEEPTIME", "1")); suite->addVariable(Variable("ECF_CLIENT_EXE_PATH", "a/made/up/path")); suite->addTask(task_t1); @@ -1058,7 +1062,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_file_includenoop) { // cout << theDefs << "\n"; // Override ECF_HOME. ECF_HOME is need to locate to the .ecf files - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); /// begin , will cause creation of generated variables. The generated variables /// are use in client scripts and used to locate the ecf files @@ -1126,7 +1130,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_file_override_ECF_JOB) { ECF_NAME_THIS_TEST(); // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode. - if (getenv("ECFLOW_CRAY_BATCH")) { + if (ecf::environment::has("ECFLOW_CRAY_BATCH")) { cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n"; return; } @@ -1146,7 +1150,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_file_override_ECF_JOB) { suite_ptr suite = Suite::create(Pid::unique_name("test_ecf_file_override_ECF_JOB")); Defs theDefs; { - suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/includes")); + suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/includes")); suite->addVariable(Variable("SLEEPTIME", "1")); suite->addVariable(Variable("ECF_CLIENT_EXE_PATH", "a/made/up/path")); suite->addTask(task_t1); @@ -1155,7 +1159,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_file_override_ECF_JOB) { // cout << theDefs << "\n"; // Override ECF_HOME. ECF_HOME is need to locate to the .ecf files - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); /// begin , will cause creation of generated variables. The generated variables /// are use in client scripts and used to locate the ecf files @@ -1223,13 +1227,13 @@ BOOST_AUTO_TEST_CASE(test_manual_files) { // Create a defs file, where the task name mirrors the ecf files in the given directory Defs theDefs; suite_ptr suite = theDefs.add_suite("suite"); // ** relies on name of suite, in SMSHOME/suite - suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/../includes")); + suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/../includes")); family_ptr family = suite->add_family("family"); task_ptr task_t1 = family->add_task("t1"); // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified // or when file does not exist in ECF_INCLUDE - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); /// begin , will cause creation of generated variables. The generated variables /// are use in client scripts and used to locate the sms files @@ -1299,7 +1303,7 @@ BOOST_AUTO_TEST_CASE(test_ECFLOW_672) { // test for recursive includes that are not recursive - if (getenv("ECFLOW_CRAY_BATCH")) { + if (ecf::environment::has("ECFLOW_CRAY_BATCH")) { cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n"; return; } @@ -1311,13 +1315,13 @@ BOOST_AUTO_TEST_CASE(test_ECFLOW_672) { // endsuite Defs theDefs; suite_ptr suite = theDefs.add_suite("ECFLOW_672"); - suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/ECFLOW_672")); + suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/ECFLOW_672")); task_ptr task_t1 = suite->add_task("t"); // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified // or when file does not exist in ECF_INCLUDE std::string ecf_home = File::test_data("libs/node/test/data", "libs/node"); - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); /// begin , will cause creation of generated variables. The generated variables /// are use in client scripts and used to locate the ecf files @@ -1353,7 +1357,7 @@ static void basic_test_template(const std::string& test_name, const std::string& ecf_micro = "", bool expect_success = true) { // This test FAIL's randomly on the cray in BATCH mode, but passes in interactive mode. - if (getenv("ECFLOW_CRAY_BATCH")) { + if (ecf::environment::has("ECFLOW_CRAY_BATCH")) { cout << " **** SKIPPING test, until HPC team can fix File::createMissingDirectories.(like mkdir -p) *****\n"; return; } @@ -1369,7 +1373,7 @@ static void basic_test_template(const std::string& test_name, suite_ptr suite = Suite::create(Pid::unique_name(test_name)); Defs theDefs; { - suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/includes")); + suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/includes")); suite->add_variable("simple", "simple"); suite->add_variable("tail", "tail"); if (!ecf_micro.empty()) @@ -1381,7 +1385,7 @@ static void basic_test_template(const std::string& test_name, // Override ECF_HOME. ECF_HOME is as default location for .ecf files, when ECF_INCLUDE not specified // or when file does not exist in ECF_INCLUDE std::string ecf_home = File::test_data("libs/node/test/data", "libs/node"); - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); /// begin , will cause creation of generated variables. The generated variables /// are use in client scripts and used to locate the sms files diff --git a/libs/node/test/TestEcfFileLocator.cpp b/libs/node/test/TestEcfFileLocator.cpp index 8a904e7e0..f41f25a9b 100644 --- a/libs/node/test/TestEcfFileLocator.cpp +++ b/libs/node/test/TestEcfFileLocator.cpp @@ -13,6 +13,7 @@ #include #include "TestNaming.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Pid.hpp" #include "ecflow/core/Str.hpp" @@ -113,7 +114,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_file_search) { // task task Defs theDefs; suite_ptr suite = theDefs.add_suite(Pid::unique_name("test_ecf_file_search")); - suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/includes")); + suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/includes")); family_ptr f1 = suite->add_family("f1"); family_ptr f2 = f1->add_family("f2"); family_ptr f3 = f2->add_family("f3"); @@ -123,7 +124,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_file_search) { // or when file does not exist in ECF_INCLUDE std::string ecf_home = File::test_data("libs/node/test/data", "libs/node"); std::string ecf_lists = File::test_data("libs/node/test/data", "libs/node"); - suite->add_variable(Str::ECF_HOME(), ecf_home); + suite->add_variable(ecf::environment::ECF_HOME, ecf_home); // cerr << theDefs << "\n"; /// begin , will cause creation of generated variables. The generated variables @@ -144,7 +145,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_file_search) { suite->deleteVariable("ECF_FILES_LOOKUP"); // cleanup - suite->add_variable(Str::ECF_FILES(), ecf_lists); + suite->add_variable(ecf::environment::ECF_FILES, ecf_lists); located_ecf_file(task, EcfFile::ECF_SCRIPT, EcfFile::PRUNE_ROOT, @@ -170,7 +171,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_file_search) { suite->deleteVariable("ECF_FILES_LOOKUP"); // cleanup - suite->add_variable(Str::ECF_FILES(), ecf_lists); + suite->add_variable(ecf::environment::ECF_FILES, ecf_lists); located_ecf_file(task, EcfFile::ECF_FILES, EcfFile::PRUNE_ROOT, __LINE__); suite->add_variable("ECF_FILES_LOOKUP", "prune_leaf"); // change look up method located_ecf_file(task, EcfFile::ECF_FILES, EcfFile::PRUNE_LEAF, __LINE__); @@ -209,7 +210,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_file_search) { } { // cout << "Test ECF_FILES at intermediate location, by prune_leaf\n"; - suite->add_variable(Str::ECF_FILES(), ecf_lists); + suite->add_variable(ecf::environment::ECF_FILES, ecf_lists); Node* node = task.get(); node = node->parent(); node = node->parent(); @@ -283,7 +284,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_file_locator) { Defs theDefs; { suite_ptr suite = theDefs.add_suite("suite"); - suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/includes")); + suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/includes")); suite->addVariable(Variable("SLEEPTIME", "10")); family_ptr fam = suite->add_family("family"); fam->add_task("t1"); @@ -299,16 +300,16 @@ BOOST_AUTO_TEST_CASE(test_ecf_file_locator) { } { suite_ptr suite2 = theDefs.add_suite("suite2"); - suite2->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/includes")); - suite2->addVariable(Variable(Str::ECF_FILES(), "$ECF_HOME")); + suite2->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/includes")); + suite2->addVariable(Variable(ecf::environment::ECF_FILES, "$ECF_HOME")); family_ptr fam = suite2->add_family("family"); - fam->addVariable(Variable(Str::ECF_FETCH(), "smsfetch -F %ECF_FILES% -I %ECF_INCLUDE%")); + fam->addVariable(Variable(ecf::environment::ECF_FETCH, "smsfetch -F %ECF_FILES% -I %ECF_INCLUDE%")); fam->add_task("t2"); } { suite_ptr suite = theDefs.add_suite("suite3"); - suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/includes")); - suite->addVariable(Variable(Str::ECF_FILES(), "$ECF_HOME")); + suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/includes")); + suite->addVariable(Variable(ecf::environment::ECF_FILES, "$ECF_HOME")); family_ptr fam = suite->add_family("family"); fam->addVariable(Variable("ECF_SCRIPT_CMD", "script_cmd -F %ECF_FILES% -I %ECF_INCLUDE%")); fam->add_task("t2"); @@ -321,7 +322,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_file_locator) { BOOST_REQUIRE_MESSAGE(theTasks.size() == 8, "Expected 8 tasks but found, " << theTasks.size()); // Override ECF_HOME. ECF_HOME is need to locate to the ecf files - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), smshome); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, smshome); /// begin , will cause creation of generated variables. The generated variables /// are use in client scripts and used to locate the sms files @@ -383,7 +384,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_file_locator_using_ECF_FILES) { Defs theDefs; { suite_ptr suite = theDefs.add_suite("suite"); - suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/includes")); + suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/includes")); suite->addVariable(Variable("SLEEPTIME", "10")); family_ptr fam = suite->add_family("family"); fam->add_task("t1"); @@ -397,8 +398,8 @@ BOOST_AUTO_TEST_CASE(test_ecf_file_locator_using_ECF_FILES) { BOOST_REQUIRE_MESSAGE(theTasks.size() == 3, "Expected 3 tasks but found, " << theTasks.size()); // ECF_HOME, a directory with no .ecf files - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), smshome); - theDefs.set_server().add_or_update_user_variables(Str::ECF_FILES(), ecf_files); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, smshome); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_FILES, ecf_files); // cerr << theDefs << "\n"; @@ -450,7 +451,7 @@ BOOST_AUTO_TEST_CASE(test_ecf_file_locator_using_ECF_FILES_variable_substitution Defs theDefs; { suite_ptr suite = theDefs.add_suite("suite"); - suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/includes")); + suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/includes")); suite->addVariable(Variable("SLEEPTIME", "10")); family_ptr fam = suite->add_family("family"); fam->addVariable(Variable("FAMILY", "family")); @@ -465,8 +466,8 @@ BOOST_AUTO_TEST_CASE(test_ecf_file_locator_using_ECF_FILES_variable_substitution BOOST_REQUIRE_MESSAGE(theTasks.size() == 3, "Expected 3 tasks but found, " << theTasks.size()); // ECF_HOME, a directory with no .ecf files - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), smshome); - theDefs.set_server().add_or_update_user_variables(Str::ECF_FILES(), ecf_files); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, smshome); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_FILES, ecf_files); // cerr << theDefs << "\n"; diff --git a/libs/node/test/TestEnviromentSubstitution.cpp b/libs/node/test/TestEnviromentSubstitution.cpp index 6f2599d4c..d1960c2d9 100644 --- a/libs/node/test/TestEnviromentSubstitution.cpp +++ b/libs/node/test/TestEnviromentSubstitution.cpp @@ -14,6 +14,7 @@ #include #include "TestNaming.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/Str.hpp" #include "ecflow/node/Defs.hpp" #include "ecflow/node/Suite.hpp" @@ -36,7 +37,7 @@ BOOST_AUTO_TEST_CASE(test_environment_substitution) { suite->addVariable(Variable("AVI", "avi")); std::vector> env; - env.emplace_back(Str::ECF_HOME(), string("/home/smshome")); + env.emplace_back(ecf::environment::ECF_HOME, string("/home/smshome")); env.emplace_back(string("FRED"), string("/home/fred")); env.emplace_back(string("BILL"), string("/home/bill")); env.emplace_back(string("JANE"), string("/home/jane")); diff --git a/libs/node/test/TestJobCreator.cpp b/libs/node/test/TestJobCreator.cpp index 31756f8ec..d654e6547 100644 --- a/libs/node/test/TestJobCreator.cpp +++ b/libs/node/test/TestJobCreator.cpp @@ -13,6 +13,7 @@ #include #include "TestNaming.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Str.hpp" #include "ecflow/node/Defs.hpp" @@ -64,7 +65,7 @@ BOOST_AUTO_TEST_CASE(test_job_creator) { { suite_ptr suite = Suite::create("suite"); family_ptr fam = Family::create("family"); - suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/../includes")); + suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/../includes")); suite->addVariable(Variable("SLEEPTIME", "1")); suite->addVariable(Variable("ECF_CLIENT_EXE_PATH", "a/made/up/path")); fam->addTask(Task::create("t1")); @@ -90,7 +91,7 @@ BOOST_AUTO_TEST_CASE(test_job_creator) { BOOST_REQUIRE_MESSAGE(theTasks.size() == 6, "Expected 6 tasks but found, " << theTasks.size()); // Override ECF_HOME. ECF_HOME is need to locate to the .ecf files - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); /// begin , will cause creation of generated variables. The generated variables /// are use in client scripts and used to locate the ecf files diff --git a/libs/node/test/TestJobProfiler.cpp b/libs/node/test/TestJobProfiler.cpp index 1082f1da8..6da823204 100644 --- a/libs/node/test/TestJobProfiler.cpp +++ b/libs/node/test/TestJobProfiler.cpp @@ -13,6 +13,7 @@ #include #include "TestNaming.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Log.hpp" #include "ecflow/core/Str.hpp" @@ -46,8 +47,10 @@ BOOST_AUTO_TEST_CASE(test_job_profiler) { Defs theDefs; { suite_ptr suite = theDefs.add_suite("suite"); - suite->addVariable(Variable(Str::ECF_INCLUDE(), File::test_data("libs/node/test/data/includes", "libs/node"))); - suite->addVariable(Variable("ECF_HOME", File::test_data("libs/node/test/data/SMSHOME", "libs/node"))); + suite->addVariable( + Variable(ecf::environment::ECF_INCLUDE, File::test_data("libs/node/test/data/includes", "libs/node"))); + suite->addVariable( + Variable(ecf::environment::ECF_HOME, File::test_data("libs/node/test/data/SMSHOME", "libs/node"))); suite->addVariable(Variable("SLEEPTIME", "10")); family_ptr fam = suite->add_family("family"); fam->add_task("t1"); diff --git a/libs/node/test/TestPreProcessing.cpp b/libs/node/test/TestPreProcessing.cpp index 7543a7b6d..3221f39e3 100644 --- a/libs/node/test/TestPreProcessing.cpp +++ b/libs/node/test/TestPreProcessing.cpp @@ -15,6 +15,7 @@ #include "TestNaming.hpp" #include "ecflow/core/Ecf.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Str.hpp" #include "ecflow/node/Defs.hpp" @@ -120,8 +121,8 @@ void test_sms_preprocessing(const std::string& directory, bool pass) { Defs theDefs; { suite_ptr suite = theDefs.add_suite("suite"); - suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/includes")); - suite->addVariable(Variable(Str::ECF_OUT(), "$ECF_HOME")); + suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/includes")); + suite->addVariable(Variable(ecf::environment::ECF_OUT, "$ECF_HOME")); suite->addVariable(Variable("SLEEPTIME", "10")); family_ptr fam = suite->add_family("family"); @@ -164,7 +165,7 @@ void test_sms_preprocessing(const std::string& directory, bool pass) { theDefs.getAllTasks(theTasks); // Override ECF_HOME. ECF_HOME is need to locate the ecf files - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + theDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); /// begin , will cause creation of generated variables. The generated variables /// are used in client scripts(sms) and used to locate the sms files diff --git a/libs/node/test/TestReplace.cpp b/libs/node/test/TestReplace.cpp index f40b4825a..3dba61c5b 100644 --- a/libs/node/test/TestReplace.cpp +++ b/libs/node/test/TestReplace.cpp @@ -12,6 +12,7 @@ #include "TestNaming.hpp" #include "ecflow/core/Ecf.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Str.hpp" #include "ecflow/node/Defs.hpp" @@ -982,7 +983,7 @@ BOOST_AUTO_TEST_CASE(test_trigger_references_during_replace) { suite_ptr server_suite; { server_suite = serverDefs.add_suite("suite"); - server_suite->addVariable(Variable(Str::ECF_INCLUDE(), "$ECF_HOME/../includes")); + server_suite->addVariable(Variable(ecf::environment::ECF_INCLUDE, "$ECF_HOME/../includes")); server_suite->addVariable(Variable("SLEEPTIME", "1")); server_suite->addVariable(Variable("ECF_CLIENT_EXE_PATH", "a/made/up/path")); family_ptr fam = server_suite->add_family("family"); @@ -1001,7 +1002,7 @@ BOOST_AUTO_TEST_CASE(test_trigger_references_during_replace) { // Override ECF_HOME. ECF_HOME is need to locate to the .ecf files std::string ecf_home = File::test_data("libs/node/test/data/SMSHOME", "libs/node"); - serverDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), ecf_home); + serverDefs.set_server().add_or_update_user_variables(ecf::environment::ECF_HOME, ecf_home); /// begin , will cause creation of generated variables. The generated variables /// are use in client scripts and used to locate the ecf files diff --git a/libs/node/test/TestTaskScriptGenerator.cpp b/libs/node/test/TestTaskScriptGenerator.cpp index 804da7302..b250aecd9 100644 --- a/libs/node/test/TestTaskScriptGenerator.cpp +++ b/libs/node/test/TestTaskScriptGenerator.cpp @@ -16,6 +16,7 @@ #include "MyDefsFixture.hpp" #include "TestNaming.hpp" #include "ecflow/core/Ecf.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Str.hpp" #include "ecflow/node/Defs.hpp" @@ -94,8 +95,8 @@ BOOST_AUTO_TEST_CASE(test_task_script_generator) { Defs theDefs; { suite_ptr suite = theDefs.add_suite("suite"); - suite->add_variable(Str::ECF_INCLUDE(), ecf_home); - suite->add_variable(Str::ECF_HOME(), ecf_home); + suite->add_variable(ecf::environment::ECF_INCLUDE, ecf_home); + suite->add_variable(ecf::environment::ECF_HOME, ecf_home); suite->add_variable("SLEEP", "10"); task_ptr t1 = suite->add_task("t1"); t1->addEvent(Event("event1")); @@ -186,8 +187,8 @@ BOOST_AUTO_TEST_CASE(test_task_script_generator_with_dummy_tasks) { Defs theDefs; { suite_ptr suite = theDefs.add_suite("suite"); - suite->add_variable(Str::ECF_INCLUDE(), ecf_home); - suite->add_variable(Str::ECF_HOME(), ecf_home); + suite->add_variable(ecf::environment::ECF_INCLUDE, ecf_home); + suite->add_variable(ecf::environment::ECF_HOME, ecf_home); suite->add_variable("SLEEP", "10"); family_ptr f1 = suite->add_family("f1"); tasks_with_scripts.push_back(f1->add_task("t1")); diff --git a/libs/node/test/TestVariableGeneration.cpp b/libs/node/test/TestVariableGeneration.cpp index ef69a0eb2..f42b279fa 100644 --- a/libs/node/test/TestVariableGeneration.cpp +++ b/libs/node/test/TestVariableGeneration.cpp @@ -15,6 +15,7 @@ #include "TestNaming.hpp" #include "ecflow/core/Cal.hpp" #include "ecflow/core/Converter.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/Str.hpp" #include "ecflow/node/Defs.hpp" #include "ecflow/node/Family.hpp" @@ -67,13 +68,13 @@ BOOST_AUTO_TEST_CASE(test_generated_variables) { // Check Submittable generated variables findParentVariableValue(t, "TASK", "t"); - findParentVariableValue(t, Str::ECF_RID(), ""); - findParentVariableValue(t, Str::ECF_TRYNO(), "0"); - findParentVariableValue(t, Str::ECF_NAME(), "/suite/f/f2/t"); - findParentVariableValue(t, Str::ECF_PASS(), ""); - findParentVariableValue(t, Str::ECF_JOB(), "./suite/f/f2/t.job0"); - findParentVariableValue(t, Str::ECF_JOBOUT(), "./suite/f/f2/t.0"); - findParentVariableValue(t, Str::ECF_SCRIPT(), "./suite/f/f2/t.ecf"); + findParentVariableValue(t, ecf::environment::ECF_RID, ""); + findParentVariableValue(t, ecf::environment::ECF_TRYNO, "0"); + findParentVariableValue(t, ecf::environment::ECF_NAME, "/suite/f/f2/t"); + findParentVariableValue(t, ecf::environment::ECF_PASS, ""); + findParentVariableValue(t, ecf::environment::ECF_JOB, "./suite/f/f2/t.job0"); + findParentVariableValue(t, ecf::environment::ECF_JOBOUT, "./suite/f/f2/t.0"); + findParentVariableValue(t, ecf::environment::ECF_SCRIPT, "./suite/f/f2/t.ecf"); // Check Family generated variables findParentVariableValue(t, "FAMILY", "f/f2"); diff --git a/libs/node/test/TestVariableSubstitution.cpp b/libs/node/test/TestVariableSubstitution.cpp index 4ddf206b2..6cc710b33 100644 --- a/libs/node/test/TestVariableSubstitution.cpp +++ b/libs/node/test/TestVariableSubstitution.cpp @@ -15,6 +15,7 @@ #include "TestNaming.hpp" #include "ecflow/core/Ecf.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/Str.hpp" #include "ecflow/core/Version.hpp" #include "ecflow/node/Defs.hpp" @@ -380,10 +381,10 @@ BOOST_AUTO_TEST_CASE(test_user_variable_substitution_1) { static std::vector required_server_variables() { std::vector required_server_variables; - required_server_variables.push_back(Str::ECF_PORT()); - required_server_variables.push_back(Str::ECF_HOST()); + required_server_variables.push_back(ecf::environment::ECF_PORT); + required_server_variables.push_back(ecf::environment::ECF_HOST); - required_server_variables.push_back(Str::ECF_HOME()); + required_server_variables.push_back(ecf::environment::ECF_HOME); required_server_variables.emplace_back("ECF_LOG"); required_server_variables.emplace_back("ECF_CHECK"); required_server_variables.emplace_back("ECF_CHECKOLD"); @@ -473,12 +474,12 @@ BOOST_AUTO_TEST_CASE(test_generated_variable_substitution) { string value; value.clear(); - t->findParentVariableValue(Str::ECF_JOBOUT(), value); + t->findParentVariableValue(ecf::environment::ECF_JOBOUT, value); BOOST_CHECK_MESSAGE(value == "/fred/bill/joe/suite/f/t.0", "ECF_JOBOUT expected /fred/bill/joe/suite/f/t.0, but found " << value); value.clear(); - t1->findParentVariableValue(Str::ECF_JOBOUT(), value); + t1->findParentVariableValue(ecf::environment::ECF_JOBOUT, value); BOOST_CHECK_MESSAGE(value == "/fred/bill/joe2/suite/f1/t1.0", "ECF_JOBOUT expected /fred/bill/joe/suite/f/t.0, but found " << value); diff --git a/libs/rest/src/ecflow/http/Client.cpp b/libs/rest/src/ecflow/http/Client.cpp index cd7661bb1..73fb592e9 100644 --- a/libs/rest/src/ecflow/http/Client.cpp +++ b/libs/rest/src/ecflow/http/Client.cpp @@ -13,6 +13,7 @@ #include #include "ecflow/core/Child.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/Str.hpp" #include "ecflow/http/BasicAuth.hpp" #include "ecflow/http/HttpServerException.hpp" @@ -26,17 +27,17 @@ namespace ecf::http { -const char* const ECF_USER = getenv("ECF_USER"); -const char* const ECF_PASS = getenv("ECF_PASS"); +const auto ECF_USER = ecf::environment::fetch(ecf::environment::ECF_USER); +const auto ECF_PASS = ecf::environment::fetch(ecf::environment::ECF_PASS); bool authenticate(const httplib::Request& request, ClientInvoker* ci) { #ifdef ECF_OPENSSL auto auth_with_token = [&](const std::string& token) { if (TokenStorage::instance().verify(token)) { - if (ECF_USER != nullptr && ECF_PASS != nullptr) { - ci->set_user_name(std::string(ECF_USER)); - ci->set_password(std::string(ECF_PASS)); + if (ECF_USER && ECF_PASS) { + ci->set_user_name(ECF_USER.value()); + ci->set_password(ECF_PASS.value()); } return true; } diff --git a/libs/rest/src/ecflow/http/HttpServer.cpp b/libs/rest/src/ecflow/http/HttpServer.cpp index ef3e9ed32..2aaf7ed9f 100644 --- a/libs/rest/src/ecflow/http/HttpServer.cpp +++ b/libs/rest/src/ecflow/http/HttpServer.cpp @@ -13,6 +13,7 @@ #include #include "ecflow/core/Converter.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/Filesystem.hpp" #include "ecflow/http/Api.hpp" #include "ecflow/http/JSON.hpp" @@ -25,33 +26,16 @@ HttpServer::HttpServer(int argc, char** argv) { } void read_environment() { - if (getenv("ECF_RESTAPI_VERBOSE") != nullptr) { - opts.verbose = true; - } - if (getenv("ECF_RESTAPI_NOSSL") != nullptr) { - opts.no_ssl = true; - } - if (getenv("ECF_RESTAPI_POLLING_INTERVAL") != nullptr) { - opts.polling_interval = atoi(getenv("ECF_RESTAPI_POLLING_INTERVAL")); - } - if (getenv("ECF_RESTAPI_PORT") != nullptr) { - opts.port = atoi(getenv("ECF_RESTAPI_PORT")); - } - if (getenv("ECF_HOST") != nullptr) { - opts.ecflow_host = std::string(getenv("ECF_HOST")); - } - if (getenv("ECF_PORT") != nullptr) { - opts.ecflow_port = atoi(getenv("ECF_PORT")); - } - if (getenv("ECF_RESTAPI_TOKENS_FILE") != nullptr) { - opts.tokens_file = std::string(getenv("ECF_RESTAPI_TOKENS_FILE")); - } - if (getenv("ECF_RESTAPI_CERT_DIRECTORY") != nullptr) { - opts.cert_directory = std::string(getenv("ECF_RESTAPI_CERT_DIRECTORY")); - } - if (getenv("ECF_RESTAPI_MAX_UPDATE_INTERVAL") != nullptr) { - opts.max_polling_interval = atoi(getenv("ECF_RESTAPI_MAX_UPDATE_INTERVAL")); - } + ecf::environment::get("ECF_RESTAPI_VERBOSE", opts.verbose); + ecf::environment::get("ECF_RESTAPI_NOSSL", opts.no_ssl); + ecf::environment::get("ECF_RESTAPI_POLLING_INTERVAL", opts.polling_interval); + ecf::environment::get("ECF_RESTAPI_PORT", opts.port); + ecf::environment::get("ECF_HOST", opts.ecflow_host); + ecf::environment::get("ECF_PORT", opts.ecflow_port); + ecf::environment::get("ECF_RESTAPI_TOKENS_FILE", opts.tokens_file); + ecf::environment::get("ECF_RESTAPI_CERT_DIRECTORY", opts.cert_directory); + ecf::environment::get("ECF_RESTAPI_MAX_UPDATE_INTERVAL", opts.max_polling_interval); + ecf::environment::get("ECF_HOST_PROTOCOL", opts.host_protocol); } void HttpServer::parse_args(int argc, char** argv) const { @@ -68,6 +52,7 @@ void HttpServer::parse_args(int argc, char** argv) const { bool verbose = false; bool no_ssl = false; + bool backend_http = false; desc.add_options() ("cert_directory", po::value(&opts.cert_directory), "directory where certificates are found (default: $HOME/.ecflowrc/ssl)") @@ -79,7 +64,8 @@ void HttpServer::parse_args(int argc, char** argv) const { ("port,p", po::value(&opts.port), "port to listen (default: 8080)") ("polling_interval", po::value(&opts.polling_interval), "interval in seconds to poll ecflow server for updates (default: 10)") ("tokens_file", po::value(&opts.tokens_file), "location of api tokens file (default: api-tokens.json)") - ("verbose,v", po::bool_switch(&verbose), "enable verbose mode"); + ("verbose,v", po::bool_switch(&verbose), "enable verbose mode") + ("http", po::bool_switch(&backend_http), "use http as protocol to communicate with server (default: false)"); // clang-format on @@ -97,9 +83,13 @@ void HttpServer::parse_args(int argc, char** argv) const { if (no_ssl) { opts.no_ssl = true; } + if (backend_http) { + opts.host_protocol = "http"; + } setenv("ECF_HOST", opts.ecflow_host.c_str(), 1); setenv("ECF_PORT", ecf::convert_to(opts.ecflow_port).c_str(), 1); + setenv("ECF_HOST_PROTOCOL", opts.host_protocol.c_str(), 1); // Unset these, otherwise ClientInvoker will automatically // try to use them unsetenv("ECF_PASSWD"); diff --git a/libs/rest/src/ecflow/http/Options.hpp b/libs/rest/src/ecflow/http/Options.hpp index 57e3f4bfe..3e03353a1 100644 --- a/libs/rest/src/ecflow/http/Options.hpp +++ b/libs/rest/src/ecflow/http/Options.hpp @@ -23,6 +23,7 @@ struct Options int port{8080}; // ECF_RESTAPI_PORT std::string ecflow_host{"localhost"}; // ECF_HOST int ecflow_port{3141}; // ECF_PORT + std::string host_protocol{""}; // ECF_HOST_PROTOCOL std::string tokens_file{"api-tokens.json"}; // ECF_RESTAPI_TOKENS_FILE std::string cert_directory{std::string(getenv("HOME")) + "/.ecflowrc/ssl"}; // ECF_RESTAPI_CERT_DIRECTORY int max_polling_interval{300}; // ECF_RESTAPI_MAX_POLLING_INTERVAL diff --git a/libs/rest/test/InvokeServer.hpp b/libs/rest/test/InvokeServer.hpp index c5e3a683d..572c6ff3b 100644 --- a/libs/rest/test/InvokeServer.hpp +++ b/libs/rest/test/InvokeServer.hpp @@ -19,6 +19,7 @@ #include "TestHelper.hpp" #include "ecflow/client/ClientInvoker.hpp" #include "ecflow/core/EcfPortLock.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/Host.hpp" #include "ecflow/core/Str.hpp" #include "ecflow/server/Server.hpp" @@ -27,7 +28,8 @@ class InvokeServer { public: InvokeServer() { - std::string port(getenv("ECF_PORT")); + std::string port; + ecf::environment::get(ecf::environment::ECF_PORT, port); /// Remove check pt and backup check pt file, else server will load it & remove log file ecf::Host h; fs::remove(h.ecf_checkpt_file(port)); @@ -58,7 +60,8 @@ class InvokeServer { } ~InvokeServer() { - std::string port(getenv("ECF_PORT")); + std::string port; + ecf::environment::get(ecf::environment::ECF_PORT, port); BOOST_TEST_MESSAGE("*****InvokeServer:: Closing server on port " << port); { diff --git a/libs/rest/test/TestApiV1.cpp b/libs/rest/test/TestApiV1.cpp index 0c259b244..f2e925ac8 100644 --- a/libs/rest/test/TestApiV1.cpp +++ b/libs/rest/test/TestApiV1.cpp @@ -36,9 +36,9 @@ const std::string API_HOST("localhost"); const std::string API_KEY("3a8c3f7ac204d9c6370b5916bd8b86166c208e10776285edcbc741d56b5b4c1e"); std::unique_ptr create_certificate() { - const char* cert_dir = getenv("ECF_API_CERT_DIRECTORY"); - const std::string path_to_cert = - (cert_dir == nullptr) ? std::string(getenv("HOME")) + "/.ecflowrc/ssl/" : std::string(cert_dir); + auto cert_dir = ecf::environment::fetch("ECF_API_CERT_DIRECTORY"); + + const std::string path_to_cert = (cert_dir) ? cert_dir.value() : ecf::environment::get("HOME") + "/.ecflowrc/ssl/"; std::unique_ptr cert; @@ -67,9 +67,10 @@ std::unique_ptr create_token_file() { } void start_api_server() { + if (ecf::environment::has("NO_API_SERVER")) { + return; // terminate early, for debugging purposes + } - if (getenv("NO_API_SERVER") != nullptr) - return; // for debugging std::thread t([] { int argc = 3; char* argv[] = {(char*)"ecflow_http", (char*)"--polling_interval", (char*)"1", NULL}; @@ -83,13 +84,16 @@ void start_api_server() { } std::unique_ptr start_ecflow_server() { - if (getenv("NO_ECFLOW_SERVER") != nullptr) + if (ecf::environment::has("NO_ECFLOW_SERVER")) { return nullptr; + } auto srv = std::make_unique(); - BOOST_REQUIRE_MESSAGE(srv->server_started, "Server failed to start on port " << getenv("ECF_PORT")); - BOOST_TEST_MESSAGE("ecflow server at localhost:" << getenv("ECF_PORT")); + auto port = ecf::environment::get("ECF_PORT"); + BOOST_REQUIRE_MESSAGE(srv->server_started, "Server failed to start on port " << port); + BOOST_TEST_MESSAGE("ecflow server at localhost:" << port); + return srv; } diff --git a/libs/server/src/ecflow/server/ServerEnvironment.cpp b/libs/server/src/ecflow/server/ServerEnvironment.cpp index 1e97b4ad7..92920a6e4 100644 --- a/libs/server/src/ecflow/server/ServerEnvironment.cpp +++ b/libs/server/src/ecflow/server/ServerEnvironment.cpp @@ -10,7 +10,6 @@ #include "ecflow/server/ServerEnvironment.hpp" -#include // for getenv() #include #include @@ -18,6 +17,7 @@ #include "ecflow/core/Calendar.hpp" #include "ecflow/core/Converter.hpp" #include "ecflow/core/Ecf.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/Filesystem.hpp" #include "ecflow/core/Log.hpp" #include "ecflow/core/Pid.hpp" @@ -170,10 +170,10 @@ void ServerEnvironment::init(int argc, char* argv[], const std::string& path_to_ if (ecf_white_list_file_ == Str::WHITE_LIST_FILE()) ecf_white_list_file_ = host_name_.prefix_host_and_port(port, ecf_white_list_file_); - if (ecf_passwd_file_ == Str::ECF_PASSWD()) + if (ecf_passwd_file_ == ecf::environment::ECF_PASSWD) ecf_passwd_file_ = host_name_.prefix_host_and_port(port, ecf_passwd_file_); - if (ecf_passwd_custom_file_ == Str::ECF_CUSTOM_PASSWD()) + if (ecf_passwd_custom_file_ == ecf::environment::ECF_CUSTOM_PASSWD) ecf_passwd_custom_file_ = host_name_.prefix_host_and_port(port, ecf_passwd_custom_file_); // Change directory to ECF_HOME and check thats its accessible @@ -367,10 +367,10 @@ void ServerEnvironment::variables(std::vectorpath()); theRetVec.emplace_back(std::string("ECF_CHECK"), ecf_checkpt_file_); theRetVec.emplace_back(std::string("ECF_CHECKOLD"), ecf_backup_checkpt_file_); @@ -604,10 +604,10 @@ void ServerEnvironment::read_config_file(std::string& log_file_name, const std:: po::value(&ecf_white_list_file_)->default_value(Str::WHITE_LIST_FILE()), "Path name to file the list valid users and their access rights")( "ECF_PASSWD", - po::value(&ecf_passwd_file_)->default_value(Str::ECF_PASSWD()), + po::value(&ecf_passwd_file_)->default_value(ecf::environment::ECF_PASSWD), "Path name to passwd file")( "ECF_CUSTOM_PASSWD", - po::value(&ecf_passwd_custom_file_)->default_value(Str::ECF_CUSTOM_PASSWD()), + po::value(&ecf_passwd_custom_file_)->default_value(ecf::environment::ECF_CUSTOM_PASSWD), "Path name to custom passwd file, for user who don't use login name")( "ECF_TASK_THRESHOLD", po::value(&the_task_threshold)->default_value(JobProfiler::task_threshold_default()), @@ -648,9 +648,8 @@ void ServerEnvironment::read_environment_variables(std::string& log_file_name) { if (debug()) cout << "ServerEnvironment::read_environment_variables()\n"; - char* serverPort = getenv(Str::ECF_PORT().c_str()); - if (serverPort) { - std::string port = serverPort; + if (auto var = ecf::environment::fetch(ecf::environment::ECF_PORT); var) { + std::string port = var.value(); try { serverPort_ = ecf::convert_to(port); } @@ -661,9 +660,9 @@ void ServerEnvironment::read_environment_variables(std::string& log_file_name) { throw ServerEnvironmentException(ss.str()); } } - char* checkPtInterval = getenv("ECF_CHECKINTERVAL"); - if (checkPtInterval) { - std::string interval = checkPtInterval; + + if (auto var = ecf::environment::fetch("ECF_CHECKINTERVAL"); var) { + std::string interval = var.value(); try { checkPtInterval_ = ecf::convert_to(interval); } @@ -675,54 +674,37 @@ void ServerEnvironment::read_environment_variables(std::string& log_file_name) { } } - char* ecfHome = getenv(Str::ECF_HOME().c_str()); - if (ecfHome) - ecfHome_ = ecfHome; + ecf::environment::get(ecf::environment::ECF_HOME, ecfHome_); if (ecfHome_ == ".") { // expand to absolute paths ecfHome_ = fs::current_path().string(); } - char* logFileName = getenv("ECF_LOG"); - if (logFileName) - log_file_name = logFileName; + ecf::environment::get(ecf::environment::ECF_LOG, log_file_name); - char* checkPtFileName = getenv("ECF_CHECK"); - if (checkPtFileName) - ecf_checkpt_file_ = checkPtFileName; + ecf::environment::get("ECF_CHECK", ecf_checkpt_file_); - char* oldCheckPtFileName = getenv("ECF_CHECKOLD"); - if (oldCheckPtFileName) - ecf_backup_checkpt_file_ = oldCheckPtFileName; + ecf::environment::get("ECF_CHECKOLD", ecf_backup_checkpt_file_); - char* smsWhiteListFile = getenv("ECF_LISTS"); - if (smsWhiteListFile) - ecf_white_list_file_ = smsWhiteListFile; + ecf::environment::get("ECF_LISTS", ecf_white_list_file_); - char* passwd = getenv("ECF_PASSWD"); - if (passwd) - ecf_passwd_file_ = passwd; + ecf::environment::get(ecf::environment::ECF_PASSWD, ecf_passwd_file_); - char* custom_passwd = getenv("ECF_CUSTOM_PASSWD"); - if (custom_passwd) - ecf_passwd_custom_file_ = custom_passwd; + ecf::environment::get(ecf::environment::ECF_CUSTOM_PASSWD, ecf_passwd_custom_file_); - char* ecf_prune_node_log = getenv("ECF_PRUNE_NODE_LOG"); - if (ecf_prune_node_log) { + if (auto var = ecf::environment::fetch("ECF_PRUNE_NODE_LOG"); var) { try { - ecf_prune_node_log_ = ecf::convert_to(ecf_prune_node_log); + ecf_prune_node_log_ = ecf::convert_to(var.value()); } catch (const ecf::bad_conversion&) { std::stringstream ss; ss << "ServerEnviroment::read_environment_variables: ECF_PRUNE_NODE_LOG must be convertible to an integer, " "But found: " - << ecf_prune_node_log; + << var.value(); throw ServerEnvironmentException(ss.str()); } } - if (getenv("ECF_DEBUG_SERVER")) { - debug_ = true; // can also be enabled via --debug option - } + ecf::environment::get("ECF_DEBUG_SERVER", debug_); #ifdef ECF_OPENSSL // IF ECF_SSL= 1 search server.crt @@ -730,15 +712,14 @@ void ServerEnvironment::read_environment_variables(std::string& log_file_name) { ssl_.enable_if_defined(serverHost_, the_port()); #endif - char* threshold = getenv("ECF_TASK_THRESHOLD"); - if (threshold) { - std::string task_threshold = threshold; + if (auto var = ecf::environment::fetch("ECF_TASK_THRESHOLD"); var) { + std::string task_threshold = var.value(); try { JobProfiler::set_task_threshold(ecf::convert_to(task_threshold)); } catch (...) { std::stringstream ss; - ss << "ServerEnvironment::read_environment_variables(): ECF_TASK_THRESHOLD is defined(" << threshold + ss << "ServerEnvironment::read_environment_variables(): ECF_TASK_THRESHOLD is defined(" << var.value() << ") but value is *not* convertible to an integer\n"; throw ServerEnvironmentException(ss.str()); } @@ -805,7 +786,7 @@ std::string ServerEnvironment::dump() const { std::vector ServerEnvironment::expected_variables() { std::vector expected_variables; - expected_variables.push_back(Str::ECF_HOME()); + expected_variables.push_back(ecf::environment::ECF_HOME); expected_variables.emplace_back("ECF_LOG"); expected_variables.emplace_back("ECF_CHECK"); expected_variables.emplace_back("ECF_CHECKOLD"); @@ -820,14 +801,15 @@ std::vector ServerEnvironment::expected_variables() { expected_variables.emplace_back("ECF_PID"); expected_variables.emplace_back("ECF_VERSION"); expected_variables.emplace_back("ECF_LISTS"); - expected_variables.push_back(Str::ECF_PORT()); - expected_variables.push_back(Str::ECF_HOST()); + expected_variables.push_back(ecf::environment::ECF_PORT); + expected_variables.push_back(ecf::environment::ECF_HOST); expected_variables.emplace_back("ECF_INTERVAL"); expected_variables.emplace_back("ECF_PASSWD"); expected_variables.emplace_back("ECF_CUSTOM_PASSWD"); #ifdef ECF_OPENSSL - if (getenv("ECF_SSL")) + if (ecf::environment::has("ECF_SSL")) { expected_variables.emplace_back("ECF_SSL"); + } #endif return expected_variables; } diff --git a/libs/server/test/TestServer.cpp b/libs/server/test/TestServer.cpp index 4b4214e0e..32e5d659f 100644 --- a/libs/server/test/TestServer.cpp +++ b/libs/server/test/TestServer.cpp @@ -156,9 +156,9 @@ BOOST_AUTO_TEST_CASE(test_server) { // Hence the lock file is not always sufficient. // ECF_FREE_PORT should be unique among gnu,clang,intel, etc std::string the_port1 = "3144"; - char* test_ecf_port = getenv("ECF_FREE_PORT"); // from metabuilder, allow parallel tests - if (test_ecf_port) - the_port1 = test_ecf_port; + if (auto port = ecf::environment::fetch("ECF_FREE_PORT"); port) { // from metabuilder, allow parallel tests + the_port1 = port.value(); + } cout << " Find free port to start server, starting with port " << the_port1 << "\n"; auto the_port = ecf::convert_to(the_port1); diff --git a/libs/server/test/TestServerEnvironment.cpp b/libs/server/test/TestServerEnvironment.cpp index d781f5763..eb5e36706 100644 --- a/libs/server/test/TestServerEnvironment.cpp +++ b/libs/server/test/TestServerEnvironment.cpp @@ -18,6 +18,7 @@ #include "ecflow/core/CheckPt.hpp" #include "ecflow/core/Converter.hpp" #include "ecflow/core/Ecf.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Host.hpp" #include "ecflow/core/Log.hpp" @@ -122,7 +123,7 @@ BOOST_AUTO_TEST_CASE(test_server_environment_log_file) { bool found_var = false; typedef std::pair mpair; for (const mpair& p : server_vars) { - if (Str::ECF_LOG() == p.first) { + if (ecf::environment::ECF_LOG == p.first) { BOOST_CHECK_MESSAGE(p.second == Log::instance()->path(), "Expected " << Log::instance()->path() << " but found " << p.second); found_var = true; @@ -192,12 +193,12 @@ BOOST_AUTO_TEST_CASE(test_server_config_file) { typedef std::pair mpair; for (const mpair& p : server_vars) { // std::cout << "server variables " << p.first << " " << p.second << "\n"; - if (Str::ECF_HOME() == p.first) { + if (ecf::environment::ECF_HOME == p.first) { BOOST_CHECK_MESSAGE(p.second == fs::current_path().string(), "for ECF_HOME expected " << fs::current_path().string() << " but found " << p.second); continue; } - if (string("ECF_PORT") == p.first && !getenv("ECF_PORT")) { + if (string("ECF_PORT") == p.first && !ecf::environment::has("ECF_PORT")) { BOOST_CHECK_MESSAGE(p.second == Str::DEFAULT_PORT_NUMBER(), "for ECF_PORT expected " << Str::DEFAULT_PORT_NUMBER() << " but found " << p.second); continue; @@ -267,9 +268,10 @@ BOOST_AUTO_TEST_CASE(test_server_config_file) { Host host; std::string port = Str::DEFAULT_PORT_NUMBER(); - if (getenv("ECF_PORT")) - port = getenv("ECF_PORT"); - std::string expected = host.prefix_host_and_port(port, Str::ECF_PASSWD()); + if (ecf::environment::has("ECF_PORT")) { + port = ecf::environment::has("ECF_PORT"); + } + std::string expected = host.prefix_host_and_port(port, ecf::environment::ECF_PASSWD); BOOST_CHECK_MESSAGE(p.second == expected, "for ECF_PASSWD expected " << expected << " but found " << p.second); diff --git a/libs/simulator/test/TestAutoArchive.cpp b/libs/simulator/test/TestAutoArchive.cpp index 040c14102..df06db9d6 100644 --- a/libs/simulator/test/TestAutoArchive.cpp +++ b/libs/simulator/test/TestAutoArchive.cpp @@ -15,6 +15,7 @@ #include "TestUtil.hpp" #include "ecflow/attribute/AutoArchiveAttr.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Str.hpp" #include "ecflow/node/Defs.hpp" @@ -40,8 +41,8 @@ BOOST_AUTO_TEST_CASE(test_autoarchive_suite) { // ****: Since we have no time dependencies the simulator calendar increment // ****: is in hours. Hence autoarchive at hour resolution Defs theDefs; - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), - File::test_data("libs/simulator/test", "libs/simulator")); // required for archive + theDefs.set_server().add_or_update_user_variables( + ecf::environment::ECF_HOME, File::test_data("libs/simulator/test", "libs/simulator")); // required for archive suite_ptr s1, s2, s3; { ClockAttr clockAttr(true); @@ -125,8 +126,8 @@ BOOST_AUTO_TEST_CASE(test_autoarchive_ast_node_reset) { // ****: Since we have no time dependencies the simulator calendar increment // ****: is in hours. Hence autoarchive at hour resolution Defs theDefs; - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), - File::test_data("libs/simulator/test", "libs/simulator")); // required for archive + theDefs.set_server().add_or_update_user_variables( + ecf::environment::ECF_HOME, File::test_data("libs/simulator/test", "libs/simulator")); // required for archive suite_ptr suite_s2; suite_ptr suite_s3; @@ -200,8 +201,8 @@ BOOST_AUTO_TEST_CASE(test_autoarchive_ast_node_reset) { BOOST_AUTO_TEST_CASE(test_autoarchive_family) { cout << "Simulator:: ...test_autoarchive_family\n"; Defs theDefs; - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), - File::test_data("libs/simulator/test", "libs/simulator")); // required for archive + theDefs.set_server().add_or_update_user_variables( + ecf::environment::ECF_HOME, File::test_data("libs/simulator/test", "libs/simulator")); // required for archive { ClockAttr clockAttr(true); @@ -270,8 +271,8 @@ BOOST_AUTO_TEST_CASE(test_autoarchive_family) { BOOST_AUTO_TEST_CASE(test_two_autoarchive_in_hierarchy) { cout << "Simulator:: ...test_two_autoarchive_in_hierarchy\n"; Defs theDefs; - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), - File::test_data("libs/simulator/test", "libs/simulator")); // required for archive + theDefs.set_server().add_or_update_user_variables( + ecf::environment::ECF_HOME, File::test_data("libs/simulator/test", "libs/simulator")); // required for archive suite_ptr suite; { diff --git a/libs/simulator/test/TestAutoRestore.cpp b/libs/simulator/test/TestAutoRestore.cpp index 90442a013..6ba3313bf 100644 --- a/libs/simulator/test/TestAutoRestore.cpp +++ b/libs/simulator/test/TestAutoRestore.cpp @@ -15,6 +15,7 @@ #include "TestUtil.hpp" #include "ecflow/attribute/AutoArchiveAttr.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Str.hpp" #include "ecflow/node/AutoRestoreAttr.hpp" @@ -41,8 +42,8 @@ BOOST_AUTO_TEST_CASE(test_autorestore_suite) { // ****: Since we have no time dependencies the simulator calendar increment // ****: is in hours. Hence autoarchive at hour resolution Defs theDefs; - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), - File::test_data("libs/simulator/test", "libs/simulator")); // required for archive + theDefs.set_server().add_or_update_user_variables( + ecf::environment::ECF_HOME, File::test_data("libs/simulator/test", "libs/simulator")); // required for archive string s1_path; { ClockAttr clockAttr(true); @@ -96,8 +97,8 @@ BOOST_AUTO_TEST_CASE(test_autorestore_family) { // before // *** autorestore Defs theDefs; - theDefs.set_server().add_or_update_user_variables(Str::ECF_HOME(), - File::test_data("libs/simulator/test", "libs/simulator")); // required for archive + theDefs.set_server().add_or_update_user_variables( + ecf::environment::ECF_HOME, File::test_data("libs/simulator/test", "libs/simulator")); // required for archive std::vector vec; { diff --git a/libs/test/TestClkSync.cpp b/libs/test/TestClkSync.cpp index cf1f59c99..9ce8e97c4 100644 --- a/libs/test/TestClkSync.cpp +++ b/libs/test/TestClkSync.cpp @@ -20,6 +20,7 @@ #include "TestNaming.hpp" #include "ecflow/attribute/VerifyAttr.hpp" #include "ecflow/core/DurationTimer.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/PrintStyle.hpp" #include "ecflow/node/Defs.hpp" #include "ecflow/node/Family.hpp" @@ -88,7 +89,7 @@ BOOST_AUTO_TEST_CASE(test_suite_calendar_sync) { TestClean clean_at_start_and_end; // When using ECF_SSL sync is to slow. - if (getenv("ECF_SSL")) { + if (ecf::environment::has(ecf::environment::ECF_SSL)) { cout << " ignore test undel ECF_SSL\n"; return; } @@ -142,8 +143,8 @@ BOOST_AUTO_TEST_CASE(test_suite_calendar_sync) { boost::posix_time::ptime sync_clock_suiteTime = TestFixture::client().defs()->suiteVec()[0]->calendar().suiteTime(); ss << " Sync clock suite time:" << to_simple_string(sync_clock_suiteTime) << " full_sync(" - << TestFixture::client().server_reply().full_sync() << ")" - << " in_sync(" << TestFixture::client().server_reply().in_sync() << ") cal_count(" + << TestFixture::client().server_reply().full_sync() << ")" << " in_sync(" + << TestFixture::client().server_reply().in_sync() << ") cal_count(" << TestFixture::client().defs()->updateCalendarCount() << ")\n"; // suiteVec is now invalidated @@ -152,8 +153,8 @@ BOOST_AUTO_TEST_CASE(test_suite_calendar_sync) { boost::posix_time::ptime sync_full_suiteTime = TestFixture::client().defs()->suiteVec()[0]->calendar().suiteTime(); ss << " Sync full suite time :" << to_simple_string(sync_full_suiteTime) << " full_sync(" - << TestFixture::client().server_reply().full_sync() << ")" - << " in_sync(" << TestFixture::client().server_reply().in_sync() << ") cal_count(" + << TestFixture::client().server_reply().full_sync() << ")" << " in_sync(" + << TestFixture::client().server_reply().in_sync() << ") cal_count(" << TestFixture::client().defs()->updateCalendarCount() << ")\n"; BOOST_REQUIRE_MESSAGE(sync_clock_suiteTime == sync_full_suiteTime, diff --git a/libs/test/TestEvents.cpp b/libs/test/TestEvents.cpp index 4505f401f..ca36b5ac9 100644 --- a/libs/test/TestEvents.cpp +++ b/libs/test/TestEvents.cpp @@ -19,6 +19,7 @@ #include "TestNaming.hpp" #include "ecflow/attribute/VerifyAttr.hpp" #include "ecflow/core/DurationTimer.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/node/Defs.hpp" #include "ecflow/node/Family.hpp" #include "ecflow/node/Limit.hpp" @@ -152,7 +153,7 @@ BOOST_AUTO_TEST_CASE(test_event_and_query) { << TestFixture::client().get_string()); // Added since in 5.2.0 (only 5.2.0 server supports this behaviour) - if (!getenv("ECF_DISABLE_TEST_FOR_OLD_SERVERS")) { + if (!ecf::environment::has("ECF_DISABLE_TEST_FOR_OLD_SERVERS")) { BOOST_CHECK_MESSAGE(TestFixture::client().query("limit", suite->absNodePath(), "limit_x") == 0, "query command failed " << TestFixture::client().errorMsg()); BOOST_CHECK_MESSAGE(TestFixture::client().get_string() == "0", diff --git a/libs/test/TestInitAddVariable.cpp b/libs/test/TestInitAddVariable.cpp index 5921b7747..ccc576a42 100644 --- a/libs/test/TestInitAddVariable.cpp +++ b/libs/test/TestInitAddVariable.cpp @@ -20,6 +20,7 @@ #include "ecflow/attribute/VerifyAttr.hpp" #include "ecflow/core/Converter.hpp" #include "ecflow/core/DurationTimer.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/node/Defs.hpp" #include "ecflow/node/Family.hpp" #include "ecflow/node/Suite.hpp" @@ -39,7 +40,7 @@ BOOST_AUTO_TEST_CASE(test_init_add_variable) { ECF_NAME_THIS_TEST(); // Added since in 5.2.0 (only 5.2.0 server supports this behaviour) - if (getenv("ECF_DISABLE_TEST_FOR_OLD_SERVERS")) { + if (ecf::environment::has("ECF_DISABLE_TEST_FOR_OLD_SERVERS")) { std::cout << "\n Disable test_init_add_variable for old server , re-enable when 5.2.0 is minimum version\n"; return; } diff --git a/libs/test/TestZombies.cpp b/libs/test/TestZombies.cpp index f1c694e74..273a2ca9f 100644 --- a/libs/test/TestZombies.cpp +++ b/libs/test/TestZombies.cpp @@ -22,6 +22,7 @@ #include "ecflow/core/Child.hpp" #include "ecflow/core/Converter.hpp" #include "ecflow/core/DurationTimer.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/node/Defs.hpp" #include "ecflow/node/Family.hpp" #include "ecflow/node/Suite.hpp" @@ -642,7 +643,7 @@ static void create_and_start_test(const std::string& suite_name, BOOST_AUTO_TEST_CASE(enable_debug_for_ECF_TRY_NO_Greater_than_one) { BOOST_CHECK_MESSAGE(true, "dummy test"); - if (getenv("ECF_DEBUG_ZOMBIES")) { + if (ecf::environment::has("ECF_DEBUG_ZOMBIES")) { ecf_debug_enabled = true; ECF_NAME_THIS_TEST(); } diff --git a/libs/test/src/ServerTestHarness.cpp b/libs/test/src/ServerTestHarness.cpp index 5d273a552..ff053a837 100644 --- a/libs/test/src/ServerTestHarness.cpp +++ b/libs/test/src/ServerTestHarness.cpp @@ -21,6 +21,7 @@ #include "ecflow/core/Converter.hpp" #include "ecflow/core/DurationTimer.hpp" #include "ecflow/core/Ecf.hpp" +#include "ecflow/core/Environment.hpp" #include "ecflow/core/File.hpp" #include "ecflow/core/Str.hpp" #include "ecflow/node/Defs.hpp" @@ -95,9 +96,9 @@ defs_ptr ServerTestHarness::doRun(Defs& theClientDefs, for (suite_ptr s : theClientDefs.suiteVec()) { // Always override these to correctly locate files. - s->addVariable(Variable(Str::ECF_HOME(), ecf_home)); + s->addVariable(Variable(ecf::environment::ECF_HOME, ecf_home)); s->addVariable(Variable("ECF_CLIENT_EXE_PATH", theClientExePath)); - s->addVariable(Variable(Str::ECF_INCLUDE(), TestFixture::includes())); + s->addVariable(Variable(ecf::environment::ECF_INCLUDE, TestFixture::includes())); if (s->findVariable("SLEEPTIME").empty()) s->addVariable(Variable("SLEEPTIME", "1")); diff --git a/libs/test/src/TestFixture.cpp b/libs/test/src/TestFixture.cpp index 5d2f132eb..0dd430719 100644 --- a/libs/test/src/TestFixture.cpp +++ b/libs/test/src/TestFixture.cpp @@ -10,7 +10,6 @@ #include "TestFixture.hpp" -#include // for getenv() #include // for ofstream #include @@ -99,8 +98,9 @@ void TestFixture::init(const std::string& project_test_dir) { host_ = ClientEnvironment::hostSpecified(); port_ = ClientEnvironment::portSpecified(); // returns ECF_PORT, otherwise Str::DEFAULT_PORT_NUMBER #ifdef ECF_OPENSSL - if (getenv("ECF_SSL")) + if (ecf::environment::has("ECF_SSL")) { std::cout << " Openssl enabled\n"; + } #endif if (!host_.empty() && host_ != Str::LOCALHOST()) { @@ -110,9 +110,9 @@ void TestFixture::init(const std::string& project_test_dir) { // Must use a file system accessible from the server. Use $SCRATCH // Duplicate test data, required to scratch area and reset ECF_HOME - char* scratchEnv = getenv("SCRATCH"); - assert(scratchEnv != NULL); - std::string theSCRATCHArea(scratchEnv); + auto scratchEnv = ecf::environment::fetch("SCRATCH"); + assert(scratchEnv); + std::string theSCRATCHArea(scratchEnv.value()); assert(!theSCRATCHArea.empty()); theSCRATCHArea += "/test_dir"; @@ -301,8 +301,9 @@ int TestFixture::job_submission_interval() { } std::string TestFixture::smshome() { - if (serverOnLocalMachine()) + if (serverOnLocalMachine()) { return local_ecf_home(); + } return scratchSmsHome_; } @@ -311,22 +312,25 @@ bool TestFixture::serverOnLocalMachine() { } std::string TestFixture::theClientExePath() { - if (serverOnLocalMachine()) + if (serverOnLocalMachine()) { return File::find_ecf_client_path(); + } - char* client_path_p = getenv("ECF_CLIENT_EXE_PATH"); - if (client_path_p == nullptr) { - + if (auto client_path_p = ecf::environment::fetch("ECF_CLIENT_EXE_PATH"); client_path_p) { + return client_path_p.value(); + } + else { // Try this before complaining std::string path = "/usr/local/apps/ecflow/current/bin/ecflow_client"; - if (fs::exists(path)) + if (fs::exists(path)) { return path; + } cout << "Please set ECF_CLIENT_EXE_PATH. This needs to be set to path to the client executable\n"; cout << "The client must be the one that was built on the same platform as the server\n"; assert(false); + return string(); // This is needed to silence compiler warnings about no return } - return string(client_path_p); } void TestFixture::clearLog() { @@ -341,14 +345,16 @@ std::string TestFixture::pathToLogFile() { return host.ecf_log_file(port_); } - char* pathToRemoteLog_p = getenv("ECF_LOG"); - if (pathToRemoteLog_p == nullptr) { + if (auto var = ecf::environment::fetch("ECF_LOG"); var) { + return var.value(); + } + else { cout << "TestFixture::pathToLogFile(): assert failed\n"; cout << "Please set ECF_LOG. This needs to be set to path to the log file\n"; cout << "that can be seen by the client and server\n"; assert(false); + return string(); // This is needed to silence compiler warnings about no return } - return std::string(pathToRemoteLog_p); } std::string TestFixture::local_ecf_home() { @@ -379,8 +385,8 @@ std::string TestFixture::local_ecf_home() { std::string rel_path = "data/ECF_HOME_" + build_type + "_" + compiler; // Allow post-fix to be added, to allow test to run in parallel - if (const char* custom_postfix = getenv("TEST_ECF_HOME_POSTFIX"); custom_postfix) { - rel_path += custom_postfix; + if (auto custom_postfix = ecf::environment::fetch("TEST_ECF_HOME_POSTFIX"); custom_postfix) { + rel_path += custom_postfix.value(); } std::string absolute_path = File::test_data_in_current_dir(rel_path); diff --git a/libs/test/src/ZombieUtill.cpp b/libs/test/src/ZombieUtill.cpp index 8373151fc..8b6f1b118 100644 --- a/libs/test/src/ZombieUtill.cpp +++ b/libs/test/src/ZombieUtill.cpp @@ -16,6 +16,7 @@ #include "ZombieUtil.hpp" #include "ecflow/attribute/Zombie.hpp" #include "ecflow/core/AssertTimer.hpp" +#include "ecflow/core/Environment.hpp" using namespace std; using namespace ecf; @@ -53,7 +54,7 @@ int ZombieUtil::do_zombie_user_action(User::Action uc, bool fail_if_to_long) { /// return the number of zombies set to user action; bool ecf_debug_zombies = false; - if (getenv("ECF_DEBUG_ZOMBIES")) { + if (ecf::environment::has("ECF_DEBUG_ZOMBIES")) { ecf_debug_zombies = true; cout << "\n do_zombie_user_action " << User::to_string(uc) << " expected_action_cnt " << expected_action_cnt << "\n"; diff --git a/libs/udp/src/ecflow/udp/UDPServerEnvironment.cpp b/libs/udp/src/ecflow/udp/UDPServerEnvironment.cpp index 044c6f257..406ccc3dd 100644 --- a/libs/udp/src/ecflow/udp/UDPServerEnvironment.cpp +++ b/libs/udp/src/ecflow/udp/UDPServerEnvironment.cpp @@ -10,7 +10,7 @@ #include "ecflow/udp/UDPServerEnvironment.hpp" -#include +#include "ecflow/core/Environment.hpp" namespace ecf { @@ -32,9 +32,7 @@ const std::unordered_map options_map = {{UDPServerEnvi UDPServerEnvironment::UDPServerEnvironment() : environment_{} { for (auto variable : variables) { - if (const char* value = ::getenv(variable); value) { - environment_[variable] = value; - } + ecf::environment::get(variable, environment_[variable]); } }