123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- /*##############################################################################
- HPCC SYSTEMS software Copyright (C) 2017 HPCC Systems®.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- ############################################################################## */
- #include <stdio.h>
- #include <iostream>
- #include <string>
- #include <vector>
- #include "platform.h"
- #include <exception>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include "EnvironmentMgr.hpp"
- #include "Exceptions.hpp"
- #include "Status.hpp"
- #include "jutil.hpp"
- //
- // Inputs file format (json)
- //
- // {
- // "input-name" : [ <array of values> ],
- // ...
- // }
- bool processOptions(int argc, char *argv[]);
- bool validate();
- std::string getNextArg(int argc, char *argv[], int idx);
- bool dirExists(const std::string &dirName);
- bool fileExists(const std::string &fileName);
- std::vector<std::string> splitString(const std::string &input, const std::string &delim);
- void outputStatus(Status &status, enum statusMsg::msgLevel);
- // Default configuration directories
- EnvironmentType envType = XML;
- std::string masterSchemaFile = "environment.xsd";
- std::string configSchemaRelativeDir = ".." PATHSEPSTR "componentfiles" PATHSEPSTR "configschema" PATHSEPSTR "xsd" PATHSEPSTR;
- std::string configSchemaDir = "";
- std::string configSchemaPluginsDir = "";
- std::string envFile;
- enum statusMsg::msgLevel outputLevel = statusMsg::warning;
- bool verbose = false;
- bool validateHiddenNodes = false;
- EnvironmentMgr *pEnvMgr = nullptr;
- class CliException : public std::exception
- {
- public:
- explicit CliException(std::string reason) : m_reason(std::move(reason)) { }
- virtual const char *what() const noexcept override
- {
- return m_reason.c_str();
- }
- private:
- std::string m_reason;
- };
- void usage()
- {
- //
- // usage below documents options
- std::cout << std::endl;
- std::cout << "envchk <options> envfile" << std::endl;
- std::cout << std::endl;
- std::cout << " -d --schema-dir <path> : path to schema files. default (" << configSchemaDir << ")" << std::endl;
- std::cout << " -p --schema-plugins-dir <path> : path to plugin files, default (" << configSchemaPluginsDir << ")" << std::endl;
- std::cout << " -m --master-config <filename> : name of master schema file, default (" << masterSchemaFile << ")" << std::endl;
- std::cout << " -l --level <level> : output level (and above), e=error, w=warning, i=informational" << std::endl;
- std::cout << " -v --verbose : verbose output" << std::endl;
- std::cout << std::endl;
- }
- int main(int argc, char *argv[])
- {
- int rc = 0;
- //
- // Build the default directory for the schema files
- std::string processPath(queryCurrentProcessPath());
- configSchemaDir = processPath.substr(0, processPath.find_last_of(PATHSEPSTR)) + PATHSEPSTR + configSchemaRelativeDir;
- //
- // Print usage?
- if (argc == 1)
- {
- usage();
- return 0;
- }
- //
- // Read options and validate
- if (!processOptions(argc, argv))
- {
- return 1; // get out now
- }
- if (!validate())
- {
- usage();
- return 1;
- }
- //
- // Create an environment manager reference and load the schema
- try
- {
- pEnvMgr = getEnvironmentMgrInstance(envType);
- if (verbose)
- std::cout << "Loading schema defined by " << masterSchemaFile << std::endl;
- // note that these are hardcoded for HPCC at this time, but could be made into options
- std::map<std::string, std::string> cfgParms;
- cfgParms["buildset"] = "buildset.xml"; // Not used right now, and probably never will be
- std::string pluginsPath = configSchemaPluginsDir;
- if (!pEnvMgr->loadSchema(configSchemaDir, masterSchemaFile, cfgParms))
- {
- throw CliException(pEnvMgr->getLastSchemaMessage());
- }
- }
- catch (const ParseException &pe)
- {
- std::cerr << "There was a problem creating the environment manager instance: " << pe.what() << std::endl;
- }
- catch(const CliException &e)
- {
- std::cerr << "There was a problem loading the schema: " << e.what() << std::endl;
- }
- //
- // If there is an environment, load it and apply
- if (!envFile.empty())
- {
- if (pEnvMgr->loadEnvironment(envFile))
- {
- Status status;
- pEnvMgr->validate(status, validateHiddenNodes);
- outputStatus(status, outputLevel);
- }
- else
- {
- std::cerr << "There was a problem loading the environment: " << std::endl << pEnvMgr->getLastEnvironmentMessage() << std::endl;
- rc = 1;
- }
- }
- return rc;
- }
- void outputStatus(Status &status, enum statusMsg::msgLevel lvl)
- {
- for (int curLevel=lvl; curLevel <= statusMsg::fatal; ++curLevel)
- {
- std::vector<statusMsg> msgs = status.getMessages(static_cast<enum statusMsg::msgLevel>(curLevel), false);
- for (auto &msg: msgs)
- {
- std::string path;
- if (!msg.nodeId.empty())
- {
- auto pNode = pEnvMgr->findEnvironmentNodeById(msg.nodeId);
- if (pNode)
- {
- pNode->getPath(path);
- }
- }
- std::cerr << status.getStatusTypeString(msg.msgLevel) << " : Path=" << path;
- if (!msg.attribute.empty())
- std::cerr << "[" << msg.attribute << "]";
- std::cerr << " Message=" << msg.msg << std::endl;
- }
- }
- }
- bool processOptions(int argc, char *argv[])
- {
- bool rc = true;
- int idx = 1;
- std::string optName, optVal;
- bool checkDir = false;
- try
- {
- while (idx < argc)
- {
- optName = getNextArg(argc, argv, idx++);
- if (optName == "-d" || optName == "--schema-dir")
- {
- configSchemaDir = getNextArg(argc, argv, idx++) += PATHSEPSTR;
- }
- else if (optName == "-p" || optName == "--schema-plugins-dir")
- {
- configSchemaPluginsDir = getNextArg(argc, argv, idx++) += PATHSEPSTR;
- }
- else if (optName == "-m" || optName == "--master-config")
- {
- masterSchemaFile = getNextArg(argc, argv, idx++);
- }
- else if (optName == "-l" || optName == "--level")
- {
- std::string lvl = getNextArg(argc, argv, idx++);
- {
- if (lvl == "e")
- {
- outputLevel = statusMsg::error;
- }
- else if (lvl == "w")
- {
- outputLevel = statusMsg::warning;
- }
- else if (lvl == "i")
- {
- outputLevel = statusMsg::info;
- }
- else
- {
- throw CliException("Output level is not valid");
- }
- }
- }
- else if (optName == "-v" || optName == "--verbose")
- {
- verbose = true;
- }
- else if (idx == argc)
- {
- envFile = optName;
- }
- else
- {
- throw CliException("Parameters are incorrect");
- }
- }
- }
- catch(const CliException &e)
- {
- std::cerr << "There was an issue processing options: " << e.what() << std::endl;
- rc = false;
- }
- return rc;
- }
- bool validate()
- {
- if (!dirExists(configSchemaDir))
- {
- std::cerr << "Schema directory " << configSchemaDir << " does not exist" << std::endl;
- return false;
- }
- if (!configSchemaPluginsDir.empty() && !dirExists(configSchemaPluginsDir))
- {
- std::cerr << "Schema plugins directory " << configSchemaPluginsDir << " does not exist" << std::endl;
- return false;
- }
- if (!fileExists(configSchemaDir + masterSchemaFile))
- {
- std::cerr << "The master config file " << masterSchemaFile << " does not exist" << std::endl;
- return false;
- }
- if (!envFile.empty())
- {
- if (!fileExists(envFile))
- {
- std::cerr << "The environment file " << envFile << " does not exist" << std::endl;
- return false;
- }
- }
- return true;
- }
- std::string getNextArg(int argc, char *argv[], int idx)
- {
- if (idx < argc)
- {
- return std::string(argv[idx]);
- }
- throw CliException("Arguments exhausted when more expected");
- }
- bool dirExists(const std::string &dirName)
- {
- bool rc = true;
- struct stat info;
- if (stat(dirName.c_str(), &info) != 0)
- {
- rc = false;
- }
- rc = ((info.st_mode&S_IFMT)==S_IFDIR);
- return rc;
- }
- bool fileExists(const std::string &fileName)
- {
- struct stat info;
- return stat(fileName.c_str(), &info) == 0;
- }
- std::vector<std::string> splitString(const std::string &input, const std::string &delim)
- {
- size_t start = 0, end = 0, delimLen = delim.length();
- std::vector<std::string> list;
- while (end != std::string::npos)
- {
- end = input.find(delim, start);
- std::string item = input.substr(start, (end == std::string::npos) ? std::string::npos : end - start);
- if (!item.empty())
- list.push_back(item);
- if (end != std::string::npos)
- {
- start = end + delimLen;
- if (start >= input.length())
- end = std::string::npos;
- }
- }
- return list;
- }
|