mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #12118 from ethereum/separate-input-modes-for-help-license-version
Separate input modes for `--help`, `--license` and `--version`
This commit is contained in:
commit
2d45099a87
@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
#include <solc/CommandLineInterface.h>
|
#include <solc/CommandLineInterface.h>
|
||||||
|
|
||||||
|
#include "license.h"
|
||||||
#include "solidity/BuildInfo.h"
|
#include "solidity/BuildInfo.h"
|
||||||
|
|
||||||
#include <libsolidity/interface/Version.h>
|
#include <libsolidity/interface/Version.h>
|
||||||
@ -405,6 +406,13 @@ bool CommandLineInterface::readInputFiles()
|
|||||||
{
|
{
|
||||||
solAssert(!m_standardJsonInput.has_value(), "");
|
solAssert(!m_standardJsonInput.has_value(), "");
|
||||||
|
|
||||||
|
if (
|
||||||
|
m_options.input.mode == InputMode::Help ||
|
||||||
|
m_options.input.mode == InputMode::License ||
|
||||||
|
m_options.input.mode == InputMode::Version
|
||||||
|
)
|
||||||
|
return true;
|
||||||
|
|
||||||
m_fileReader.setBasePath(m_options.input.basePath);
|
m_fileReader.setBasePath(m_options.input.basePath);
|
||||||
|
|
||||||
if (m_fileReader.basePath() != "")
|
if (m_fileReader.basePath() != "")
|
||||||
@ -573,8 +581,18 @@ void CommandLineInterface::createJson(string const& _fileName, string const& _js
|
|||||||
|
|
||||||
bool CommandLineInterface::parseArguments(int _argc, char const* const* _argv)
|
bool CommandLineInterface::parseArguments(int _argc, char const* const* _argv)
|
||||||
{
|
{
|
||||||
CommandLineParser parser(sout(/* _markAsUsed */ false), serr(/* _markAsUsed */ false));
|
CommandLineParser parser(serr(/* _markAsUsed */ false));
|
||||||
bool success = parser.parse(_argc, _argv, isatty(fileno(stdin)));
|
|
||||||
|
if (isatty(fileno(stdin)) && _argc == 1)
|
||||||
|
{
|
||||||
|
// If the terminal is taking input from the user, provide more user-friendly output.
|
||||||
|
CommandLineParser::printHelp(sout());
|
||||||
|
|
||||||
|
// In this case we want to exit with an error but not display any error message.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = parser.parse(_argc, _argv);
|
||||||
if (!success)
|
if (!success)
|
||||||
return false;
|
return false;
|
||||||
m_hasOutput = m_hasOutput || parser.hasOutput();
|
m_hasOutput = m_hasOutput || parser.hasOutput();
|
||||||
@ -587,6 +605,15 @@ bool CommandLineInterface::processInput()
|
|||||||
{
|
{
|
||||||
switch (m_options.input.mode)
|
switch (m_options.input.mode)
|
||||||
{
|
{
|
||||||
|
case InputMode::Help:
|
||||||
|
CommandLineParser::printHelp(sout());
|
||||||
|
break;
|
||||||
|
case InputMode::License:
|
||||||
|
printLicense();
|
||||||
|
break;
|
||||||
|
case InputMode::Version:
|
||||||
|
printVersion();
|
||||||
|
break;
|
||||||
case InputMode::StandardJson:
|
case InputMode::StandardJson:
|
||||||
{
|
{
|
||||||
solAssert(m_standardJsonInput.has_value(), "");
|
solAssert(m_standardJsonInput.has_value(), "");
|
||||||
@ -594,21 +621,38 @@ bool CommandLineInterface::processInput()
|
|||||||
StandardCompiler compiler(m_fileReader.reader(), m_options.formatting.json);
|
StandardCompiler compiler(m_fileReader.reader(), m_options.formatting.json);
|
||||||
sout() << compiler.compile(move(m_standardJsonInput.value())) << endl;
|
sout() << compiler.compile(move(m_standardJsonInput.value())) << endl;
|
||||||
m_standardJsonInput.reset();
|
m_standardJsonInput.reset();
|
||||||
return true;
|
break;
|
||||||
}
|
}
|
||||||
case InputMode::Assembler:
|
case InputMode::Assembler:
|
||||||
{
|
if (!assemble(m_options.assembly.inputLanguage, m_options.assembly.targetMachine))
|
||||||
return assemble(m_options.assembly.inputLanguage, m_options.assembly.targetMachine);
|
return false;
|
||||||
}
|
break;
|
||||||
case InputMode::Linker:
|
case InputMode::Linker:
|
||||||
return link();
|
if (!link())
|
||||||
|
return false;
|
||||||
|
writeLinkedFiles();
|
||||||
|
break;
|
||||||
case InputMode::Compiler:
|
case InputMode::Compiler:
|
||||||
case InputMode::CompilerWithASTImport:
|
case InputMode::CompilerWithASTImport:
|
||||||
return compile();
|
if (!compile())
|
||||||
|
return false;
|
||||||
|
outputCompilationResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
solAssert(false, "");
|
return !m_outputFailed;
|
||||||
return false;
|
}
|
||||||
|
|
||||||
|
void CommandLineInterface::printVersion()
|
||||||
|
{
|
||||||
|
sout() << "solc, the solidity compiler commandline interface" << endl;
|
||||||
|
sout() << "Version: " << solidity::frontend::VersionString << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandLineInterface::printLicense()
|
||||||
|
{
|
||||||
|
sout() << otherLicenses << endl;
|
||||||
|
// This is a static variable generated by cmake from LICENSE.txt
|
||||||
|
sout() << licenseText << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandLineInterface::compile()
|
bool CommandLineInterface::compile()
|
||||||
@ -843,21 +887,6 @@ void CommandLineInterface::handleAst()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandLineInterface::actOnInput()
|
|
||||||
{
|
|
||||||
if (m_options.input.mode == InputMode::StandardJson || m_options.input.mode == InputMode::Assembler)
|
|
||||||
// Already done in "processInput" phase.
|
|
||||||
return true;
|
|
||||||
else if (m_options.input.mode == InputMode::Linker)
|
|
||||||
writeLinkedFiles();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, "");
|
|
||||||
outputCompilationResults();
|
|
||||||
}
|
|
||||||
return !m_outputFailed;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CommandLineInterface::link()
|
bool CommandLineInterface::link()
|
||||||
{
|
{
|
||||||
solAssert(m_options.input.mode == InputMode::Linker, "");
|
solAssert(m_options.input.mode == InputMode::Linker, "");
|
||||||
|
@ -55,17 +55,16 @@ public:
|
|||||||
bool parseArguments(int _argc, char const* const* _argv);
|
bool parseArguments(int _argc, char const* const* _argv);
|
||||||
/// Read the content of all input files and initialize the file reader.
|
/// Read the content of all input files and initialize the file reader.
|
||||||
bool readInputFiles();
|
bool readInputFiles();
|
||||||
/// Parse the files and create source code objects
|
/// Parse the files, create source code objects, print the output.
|
||||||
bool processInput();
|
bool processInput();
|
||||||
/// Perform actions on the input depending on provided compiler arguments
|
|
||||||
/// @returns true on success.
|
|
||||||
bool actOnInput();
|
|
||||||
|
|
||||||
CommandLineOptions const& options() const { return m_options; }
|
CommandLineOptions const& options() const { return m_options; }
|
||||||
FileReader const& fileReader() const { return m_fileReader; }
|
FileReader const& fileReader() const { return m_fileReader; }
|
||||||
std::optional<std::string> const& standardJsonInput() const { return m_standardJsonInput; }
|
std::optional<std::string> const& standardJsonInput() const { return m_standardJsonInput; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void printVersion();
|
||||||
|
void printLicense();
|
||||||
bool compile();
|
bool compile();
|
||||||
bool link();
|
bool link();
|
||||||
void writeLinkedFiles();
|
void writeLinkedFiles();
|
||||||
|
@ -16,8 +16,6 @@
|
|||||||
*/
|
*/
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
|
||||||
#include "license.h"
|
|
||||||
|
|
||||||
#include <solc/CommandLineParser.h>
|
#include <solc/CommandLineParser.h>
|
||||||
#include <libyul/optimiser/Suite.h>
|
#include <libyul/optimiser/Suite.h>
|
||||||
#include <liblangutil/EVMVersion.h>
|
#include <liblangutil/EVMVersion.h>
|
||||||
@ -36,19 +34,12 @@ namespace po = boost::program_options;
|
|||||||
namespace solidity::frontend
|
namespace solidity::frontend
|
||||||
{
|
{
|
||||||
|
|
||||||
ostream& CommandLineParser::sout()
|
|
||||||
{
|
|
||||||
m_hasOutput = true;
|
|
||||||
return m_sout;
|
|
||||||
}
|
|
||||||
|
|
||||||
ostream& CommandLineParser::serr()
|
ostream& CommandLineParser::serr()
|
||||||
{
|
{
|
||||||
m_hasOutput = true;
|
m_hasOutput = true;
|
||||||
return m_serr;
|
return m_serr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define cout
|
|
||||||
#define cerr
|
#define cerr
|
||||||
|
|
||||||
static string const g_strAllowPaths = "allow-paths";
|
static string const g_strAllowPaths = "allow-paths";
|
||||||
@ -147,26 +138,6 @@ static map<InputMode, string> const g_inputModeName = {
|
|||||||
{InputMode::Linker, "linker"},
|
{InputMode::Linker, "linker"},
|
||||||
};
|
};
|
||||||
|
|
||||||
void CommandLineParser::printVersionAndExit()
|
|
||||||
{
|
|
||||||
sout() <<
|
|
||||||
"solc, the solidity compiler commandline interface" <<
|
|
||||||
endl <<
|
|
||||||
"Version: " <<
|
|
||||||
solidity::frontend::VersionString <<
|
|
||||||
endl;
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommandLineParser::printLicenseAndExit()
|
|
||||||
{
|
|
||||||
sout() << otherLicenses << endl;
|
|
||||||
// This is a static variable generated by cmake from LICENSE.txt
|
|
||||||
sout() << licenseText << endl;
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool CommandLineParser::checkMutuallyExclusive(vector<string> const& _optionNames)
|
bool CommandLineParser::checkMutuallyExclusive(vector<string> const& _optionNames)
|
||||||
{
|
{
|
||||||
if (countEnabledOptions(_optionNames) > 1)
|
if (countEnabledOptions(_optionNames) > 1)
|
||||||
@ -297,11 +268,11 @@ OptimiserSettings CommandLineOptions::optimiserSettings() const
|
|||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandLineParser::parse(int _argc, char const* const* _argv, bool _interactiveTerminal)
|
bool CommandLineParser::parse(int _argc, char const* const* _argv)
|
||||||
{
|
{
|
||||||
m_hasOutput = false;
|
m_hasOutput = false;
|
||||||
|
|
||||||
if (!parseArgs(_argc, _argv, _interactiveTerminal))
|
if (!parseArgs(_argc, _argv))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return processArgs();
|
return processArgs();
|
||||||
@ -482,6 +453,10 @@ bool CommandLineParser::parseOutputSelection()
|
|||||||
|
|
||||||
switch (_mode)
|
switch (_mode)
|
||||||
{
|
{
|
||||||
|
case InputMode::Help:
|
||||||
|
case InputMode::License:
|
||||||
|
case InputMode::Version:
|
||||||
|
solAssert(false);
|
||||||
case InputMode::Compiler:
|
case InputMode::Compiler:
|
||||||
case InputMode::CompilerWithASTImport:
|
case InputMode::CompilerWithASTImport:
|
||||||
return contains(compilerModeOutputs, _outputName);
|
return contains(compilerModeOutputs, _outputName);
|
||||||
@ -847,7 +822,7 @@ po::positional_options_description CommandLineParser::positionalOptionsDescripti
|
|||||||
return filesPositions;
|
return filesPositions;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandLineParser::parseArgs(int _argc, char const* const* _argv, bool _interactiveTerminal)
|
bool CommandLineParser::parseArgs(int _argc, char const* const* _argv)
|
||||||
{
|
{
|
||||||
po::options_description allOptions = optionsDescription();
|
po::options_description allOptions = optionsDescription();
|
||||||
po::positional_options_description filesPositions = positionalOptionsDescription();
|
po::positional_options_description filesPositions = positionalOptionsDescription();
|
||||||
@ -866,18 +841,6 @@ bool CommandLineParser::parseArgs(int _argc, char const* const* _argv, bool _int
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_args.count(g_strHelp) || (_interactiveTerminal && _argc == 1))
|
|
||||||
{
|
|
||||||
sout() << allOptions;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_args.count(g_strVersion))
|
|
||||||
printVersionAndExit();
|
|
||||||
|
|
||||||
if (m_args.count(g_strLicense))
|
|
||||||
printLicenseAndExit();
|
|
||||||
|
|
||||||
po::notify(m_args);
|
po::notify(m_args);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -886,6 +849,9 @@ bool CommandLineParser::parseArgs(int _argc, char const* const* _argv, bool _int
|
|||||||
bool CommandLineParser::processArgs()
|
bool CommandLineParser::processArgs()
|
||||||
{
|
{
|
||||||
if (!checkMutuallyExclusive({
|
if (!checkMutuallyExclusive({
|
||||||
|
g_strHelp,
|
||||||
|
g_strLicense,
|
||||||
|
g_strVersion,
|
||||||
g_strStandardJSON,
|
g_strStandardJSON,
|
||||||
g_strLink,
|
g_strLink,
|
||||||
g_strAssemble,
|
g_strAssemble,
|
||||||
@ -895,7 +861,13 @@ bool CommandLineParser::processArgs()
|
|||||||
}))
|
}))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (m_args.count(g_strStandardJSON) > 0)
|
if (m_args.count(g_strHelp) > 0)
|
||||||
|
m_options.input.mode = InputMode::Help;
|
||||||
|
else if (m_args.count(g_strLicense) > 0)
|
||||||
|
m_options.input.mode = InputMode::License;
|
||||||
|
else if (m_args.count(g_strVersion) > 0)
|
||||||
|
m_options.input.mode = InputMode::Version;
|
||||||
|
else if (m_args.count(g_strStandardJSON) > 0)
|
||||||
m_options.input.mode = InputMode::StandardJson;
|
m_options.input.mode = InputMode::StandardJson;
|
||||||
else if (m_args.count(g_strAssemble) > 0 || m_args.count(g_strStrictAssembly) > 0 || m_args.count(g_strYul) > 0)
|
else if (m_args.count(g_strAssemble) > 0 || m_args.count(g_strStrictAssembly) > 0 || m_args.count(g_strYul) > 0)
|
||||||
m_options.input.mode = InputMode::Assembler;
|
m_options.input.mode = InputMode::Assembler;
|
||||||
@ -906,6 +878,13 @@ bool CommandLineParser::processArgs()
|
|||||||
else
|
else
|
||||||
m_options.input.mode = InputMode::Compiler;
|
m_options.input.mode = InputMode::Compiler;
|
||||||
|
|
||||||
|
if (
|
||||||
|
m_options.input.mode == InputMode::Help ||
|
||||||
|
m_options.input.mode == InputMode::License ||
|
||||||
|
m_options.input.mode == InputMode::Version
|
||||||
|
)
|
||||||
|
return true;
|
||||||
|
|
||||||
map<string, set<InputMode>> validOptionInputModeCombinations = {
|
map<string, set<InputMode>> validOptionInputModeCombinations = {
|
||||||
// TODO: This should eventually contain all options.
|
// TODO: This should eventually contain all options.
|
||||||
{g_strErrorRecovery, {InputMode::Compiler, InputMode::CompilerWithASTImport}},
|
{g_strErrorRecovery, {InputMode::Compiler, InputMode::CompilerWithASTImport}},
|
||||||
|
@ -48,6 +48,9 @@ namespace solidity::frontend
|
|||||||
|
|
||||||
enum class InputMode
|
enum class InputMode
|
||||||
{
|
{
|
||||||
|
Help,
|
||||||
|
License,
|
||||||
|
Version,
|
||||||
Compiler,
|
Compiler,
|
||||||
CompilerWithASTImport,
|
CompilerWithASTImport,
|
||||||
StandardJson,
|
StandardJson,
|
||||||
@ -230,34 +233,28 @@ struct CommandLineOptions
|
|||||||
|
|
||||||
/// Parses the command-line arguments and produces a filled-out CommandLineOptions structure.
|
/// Parses the command-line arguments and produces a filled-out CommandLineOptions structure.
|
||||||
/// Validates provided values and prints error messages in case of errors.
|
/// Validates provided values and prints error messages in case of errors.
|
||||||
///
|
|
||||||
/// The class is also responsible for handling options that only result in printing informational
|
|
||||||
/// text, without the need to invoke the compiler - printing usage banner, version or license.
|
|
||||||
class CommandLineParser
|
class CommandLineParser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit CommandLineParser(std::ostream& _sout, std::ostream& _serr):
|
explicit CommandLineParser(std::ostream& _serr):
|
||||||
m_sout(_sout),
|
|
||||||
m_serr(_serr)
|
m_serr(_serr)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/// Parses the command-line arguments and fills out the internal CommandLineOptions structure.
|
/// Parses the command-line arguments and fills out the internal CommandLineOptions structure.
|
||||||
/// Performs validation and prints error messages. If requested, prints usage banner, version
|
/// Performs validation and prints error messages.
|
||||||
/// or license.
|
|
||||||
/// @param interactiveTerminal specifies whether the terminal is taking input from the user.
|
|
||||||
/// This is used to determine whether to provide more user-friendly output in some situations.
|
|
||||||
/// E.g. whether to print help text when no arguments are provided.
|
|
||||||
/// @return true if there were no validation errors when parsing options and the
|
/// @return true if there were no validation errors when parsing options and the
|
||||||
/// CommandLineOptions structure has been fully initialized. false if there were errors - in
|
/// CommandLineOptions structure has been fully initialized. false if there were errors - in
|
||||||
/// this case CommandLineOptions may be only partially filled out. May also return false if
|
/// this case CommandLineOptions may be only partially filled out. May also return false if
|
||||||
/// there is not further processing necessary and the program should just exit.
|
/// there is not further processing necessary and the program should just exit.
|
||||||
bool parse(int _argc, char const* const* _argv, bool _interactiveTerminal);
|
bool parse(int _argc, char const* const* _argv);
|
||||||
|
|
||||||
CommandLineOptions const& options() const { return m_options; }
|
CommandLineOptions const& options() const { return m_options; }
|
||||||
|
|
||||||
/// Returns true if the parser has written anything to any of its output streams.
|
/// Returns true if the parser has written anything to any of its output streams.
|
||||||
bool hasOutput() const { return m_hasOutput; }
|
bool hasOutput() const { return m_hasOutput; }
|
||||||
|
|
||||||
|
static void printHelp(std::ostream& _out) { _out << optionsDescription(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// @returns a specification of all named command-line options accepted by the compiler.
|
/// @returns a specification of all named command-line options accepted by the compiler.
|
||||||
/// The object can be used to parse command-line arguments or to generate the help screen.
|
/// The object can be used to parse command-line arguments or to generate the help screen.
|
||||||
@ -270,7 +267,7 @@ private:
|
|||||||
/// Uses boost::program_options to parse the command-line arguments and leaves the result in @a m_args.
|
/// Uses boost::program_options to parse the command-line arguments and leaves the result in @a m_args.
|
||||||
/// Also handles the arguments that result in information being printed followed by immediate exit.
|
/// Also handles the arguments that result in information being printed followed by immediate exit.
|
||||||
/// @returns false if parsing fails due to syntactical errors or the arguments not matching the description.
|
/// @returns false if parsing fails due to syntactical errors or the arguments not matching the description.
|
||||||
bool parseArgs(int _argc, char const* const* _argv, bool _interactiveTerminal);
|
bool parseArgs(int _argc, char const* const* _argv);
|
||||||
|
|
||||||
/// Validates parsed arguments stored in @a m_args and fills out the internal CommandLineOptions
|
/// Validates parsed arguments stored in @a m_args and fills out the internal CommandLineOptions
|
||||||
/// structure.
|
/// structure.
|
||||||
@ -294,20 +291,13 @@ private:
|
|||||||
bool parseOutputSelection();
|
bool parseOutputSelection();
|
||||||
|
|
||||||
bool checkMutuallyExclusive(std::vector<std::string> const& _optionNames);
|
bool checkMutuallyExclusive(std::vector<std::string> const& _optionNames);
|
||||||
[[noreturn]] void printVersionAndExit();
|
|
||||||
[[noreturn]] void printLicenseAndExit();
|
|
||||||
size_t countEnabledOptions(std::vector<std::string> const& _optionNames) const;
|
size_t countEnabledOptions(std::vector<std::string> const& _optionNames) const;
|
||||||
static std::string joinOptionNames(std::vector<std::string> const& _optionNames, std::string _separator = ", ");
|
static std::string joinOptionNames(std::vector<std::string> const& _optionNames, std::string _separator = ", ");
|
||||||
|
|
||||||
/// Returns the stream that should receive normal output. Sets m_hasOutput to true if the
|
|
||||||
/// stream has ever been used.
|
|
||||||
std::ostream& sout();
|
|
||||||
|
|
||||||
/// Returns the stream that should receive error output. Sets m_hasOutput to true if the
|
/// Returns the stream that should receive error output. Sets m_hasOutput to true if the
|
||||||
/// stream has ever been used.
|
/// stream has ever been used.
|
||||||
std::ostream& serr();
|
std::ostream& serr();
|
||||||
|
|
||||||
std::ostream& m_sout;
|
|
||||||
std::ostream& m_serr;
|
std::ostream& m_serr;
|
||||||
bool m_hasOutput = false;
|
bool m_hasOutput = false;
|
||||||
|
|
||||||
|
@ -65,8 +65,7 @@ int main(int argc, char** argv)
|
|||||||
bool success =
|
bool success =
|
||||||
cli.parseArguments(argc, argv) &&
|
cli.parseArguments(argc, argv) &&
|
||||||
cli.readInputFiles() &&
|
cli.readInputFiles() &&
|
||||||
cli.processInput() &&
|
cli.processInput();
|
||||||
cli.actOnInput();
|
|
||||||
|
|
||||||
return success ? 0 : 1;
|
return success ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,8 @@
|
|||||||
|
|
||||||
#include <libsolutil/JSON.h>
|
#include <libsolutil/JSON.h>
|
||||||
|
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
#include <range/v3/view/transform.hpp>
|
#include <range/v3/view/transform.hpp>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -110,9 +112,42 @@ namespace solidity::frontend::test
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(CommandLineInterfaceTest)
|
BOOST_AUTO_TEST_SUITE(CommandLineInterfaceTest)
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(help)
|
||||||
|
{
|
||||||
|
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles({"solc", "--help"}, "", /* _processInput */ true);
|
||||||
|
|
||||||
|
BOOST_TEST(result.success);
|
||||||
|
BOOST_TEST(boost::starts_with(result.stdoutContent, "solc, the Solidity commandline compiler."));
|
||||||
|
BOOST_TEST(result.stderrContent == "");
|
||||||
|
BOOST_TEST(result.options.input.mode == InputMode::Help);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(license)
|
||||||
|
{
|
||||||
|
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles({"solc", "--license"}, "", /* _processInput */ true);
|
||||||
|
|
||||||
|
BOOST_TEST(result.success);
|
||||||
|
BOOST_TEST(boost::starts_with(result.stdoutContent, "Most of the code is licensed under GPLv3"));
|
||||||
|
BOOST_TEST(result.stderrContent == "");
|
||||||
|
BOOST_TEST(result.options.input.mode == InputMode::License);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(version)
|
||||||
|
{
|
||||||
|
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles({"solc", "--version"}, "", /* _processInput */ true);
|
||||||
|
|
||||||
|
BOOST_TEST(result.success);
|
||||||
|
BOOST_TEST(boost::ends_with(result.stdoutContent, "Version: " + solidity::frontend::VersionString + "\n"));
|
||||||
|
BOOST_TEST(result.stderrContent == "");
|
||||||
|
BOOST_TEST(result.options.input.mode == InputMode::Version);
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(multiple_input_modes)
|
BOOST_AUTO_TEST_CASE(multiple_input_modes)
|
||||||
{
|
{
|
||||||
array<string, 6> inputModeOptions = {
|
array<string, 9> inputModeOptions = {
|
||||||
|
"--help",
|
||||||
|
"--license",
|
||||||
|
"--version",
|
||||||
"--standard-json",
|
"--standard-json",
|
||||||
"--link",
|
"--link",
|
||||||
"--assemble",
|
"--assemble",
|
||||||
@ -122,7 +157,7 @@ BOOST_AUTO_TEST_CASE(multiple_input_modes)
|
|||||||
};
|
};
|
||||||
string expectedMessage =
|
string expectedMessage =
|
||||||
"The following options are mutually exclusive: "
|
"The following options are mutually exclusive: "
|
||||||
"--standard-json, --link, --assemble, --strict-assembly, --yul, --import-ast. "
|
"--help, --license, --version, --standard-json, --link, --assemble, --strict-assembly, --yul, --import-ast. "
|
||||||
"Select at most one.\n";
|
"Select at most one.\n";
|
||||||
|
|
||||||
for (string const& mode1: inputModeOptions)
|
for (string const& mode1: inputModeOptions)
|
||||||
|
@ -30,8 +30,6 @@
|
|||||||
#include <libsmtutil/SolverInterface.h>
|
#include <libsmtutil/SolverInterface.h>
|
||||||
#include <libsolidity/interface/Version.h>
|
#include <libsolidity/interface/Version.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
@ -48,16 +46,12 @@ using namespace solidity::yul;
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
optional<CommandLineOptions> parseCommandLine(vector<string> const& _commandLine, ostream& _stdout, ostream& _stderr)
|
optional<CommandLineOptions> parseCommandLine(vector<string> const& _commandLine, ostream& _stderr)
|
||||||
{
|
{
|
||||||
vector<char const*> argv = test::makeArgv(_commandLine);
|
vector<char const*> argv = test::makeArgv(_commandLine);
|
||||||
|
|
||||||
CommandLineParser cliParser(_stdout, _stderr);
|
CommandLineParser cliParser(_stderr);
|
||||||
bool success = cliParser.parse(
|
bool success = cliParser.parse(static_cast<int>(_commandLine.size()), argv.data());
|
||||||
static_cast<int>(_commandLine.size()),
|
|
||||||
argv.data(),
|
|
||||||
false // interactiveTerminal
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
return nullopt;
|
return nullopt;
|
||||||
@ -81,24 +75,34 @@ BOOST_AUTO_TEST_CASE(no_options)
|
|||||||
expectedOptions.modelChecker.initialize = true;
|
expectedOptions.modelChecker.initialize = true;
|
||||||
expectedOptions.modelChecker.settings = {};
|
expectedOptions.modelChecker.settings = {};
|
||||||
|
|
||||||
stringstream sout, serr;
|
stringstream serr;
|
||||||
optional<CommandLineOptions> parsedOptions = parseCommandLine(commandLine, sout, serr);
|
optional<CommandLineOptions> parsedOptions = parseCommandLine(commandLine, serr);
|
||||||
|
|
||||||
BOOST_TEST(sout.str() == "");
|
|
||||||
BOOST_TEST(serr.str() == "");
|
BOOST_TEST(serr.str() == "");
|
||||||
BOOST_REQUIRE(parsedOptions.has_value());
|
BOOST_REQUIRE(parsedOptions.has_value());
|
||||||
BOOST_TEST(parsedOptions.value() == expectedOptions);
|
BOOST_TEST(parsedOptions.value() == expectedOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(help)
|
BOOST_AUTO_TEST_CASE(help_license_version)
|
||||||
{
|
{
|
||||||
stringstream sout, serr;
|
map<string, InputMode> expectedModePerOption = {
|
||||||
optional<CommandLineOptions> parsedOptions = parseCommandLine({"solc", "--help"}, sout, serr);
|
{"--help", InputMode::Help},
|
||||||
|
{"--license", InputMode::License},
|
||||||
|
{"--version", InputMode::Version},
|
||||||
|
};
|
||||||
|
|
||||||
BOOST_TEST(serr.str() == "");
|
for (auto const& [option, expectedMode]: expectedModePerOption)
|
||||||
BOOST_TEST(boost::starts_with(sout.str(), "solc, the Solidity commandline compiler."));
|
{
|
||||||
BOOST_TEST(sout.str().find("Usage: solc [options] [input_file...]") != string::npos);
|
stringstream serr;
|
||||||
BOOST_TEST(!parsedOptions.has_value());
|
optional<CommandLineOptions> parsedOptions = parseCommandLine({"solc", option}, serr);
|
||||||
|
|
||||||
|
CommandLineOptions expectedOptions;
|
||||||
|
expectedOptions.input.mode = expectedMode;
|
||||||
|
|
||||||
|
BOOST_TEST(serr.str() == "");
|
||||||
|
BOOST_REQUIRE(parsedOptions.has_value());
|
||||||
|
BOOST_TEST(parsedOptions.value() == expectedOptions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(cli_mode_options)
|
BOOST_AUTO_TEST_CASE(cli_mode_options)
|
||||||
@ -220,10 +224,9 @@ BOOST_AUTO_TEST_CASE(cli_mode_options)
|
|||||||
5,
|
5,
|
||||||
};
|
};
|
||||||
|
|
||||||
stringstream sout, serr;
|
stringstream serr;
|
||||||
optional<CommandLineOptions> parsedOptions = parseCommandLine(commandLine, sout, serr);
|
optional<CommandLineOptions> parsedOptions = parseCommandLine(commandLine, serr);
|
||||||
|
|
||||||
BOOST_TEST(sout.str() == "");
|
|
||||||
BOOST_TEST(serr.str() == "");
|
BOOST_TEST(serr.str() == "");
|
||||||
BOOST_REQUIRE(parsedOptions.has_value());
|
BOOST_REQUIRE(parsedOptions.has_value());
|
||||||
BOOST_TEST(parsedOptions.value() == expectedOptions);
|
BOOST_TEST(parsedOptions.value() == expectedOptions);
|
||||||
@ -337,10 +340,9 @@ BOOST_AUTO_TEST_CASE(assembly_mode_options)
|
|||||||
expectedOptions.optimizer.expectedExecutionsPerDeployment = 1000;
|
expectedOptions.optimizer.expectedExecutionsPerDeployment = 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
stringstream sout, serr;
|
stringstream serr;
|
||||||
optional<CommandLineOptions> parsedOptions = parseCommandLine(commandLine, sout, serr);
|
optional<CommandLineOptions> parsedOptions = parseCommandLine(commandLine, serr);
|
||||||
|
|
||||||
BOOST_TEST(sout.str() == "");
|
|
||||||
BOOST_TEST(serr.str() == "Warning: Yul is still experimental. Please use the output with care.\n");
|
BOOST_TEST(serr.str() == "Warning: Yul is still experimental. Please use the output with care.\n");
|
||||||
BOOST_REQUIRE(parsedOptions.has_value());
|
BOOST_REQUIRE(parsedOptions.has_value());
|
||||||
BOOST_TEST(parsedOptions.value() == expectedOptions);
|
BOOST_TEST(parsedOptions.value() == expectedOptions);
|
||||||
@ -406,10 +408,9 @@ BOOST_AUTO_TEST_CASE(standard_json_mode_options)
|
|||||||
expectedOptions.compiler.combinedJsonRequests->abi = true;
|
expectedOptions.compiler.combinedJsonRequests->abi = true;
|
||||||
expectedOptions.compiler.combinedJsonRequests->binary = true;
|
expectedOptions.compiler.combinedJsonRequests->binary = true;
|
||||||
|
|
||||||
stringstream sout, serr;
|
stringstream serr;
|
||||||
optional<CommandLineOptions> parsedOptions = parseCommandLine(commandLine, sout, serr);
|
optional<CommandLineOptions> parsedOptions = parseCommandLine(commandLine, serr);
|
||||||
|
|
||||||
BOOST_TEST(sout.str() == "");
|
|
||||||
BOOST_TEST(serr.str() == "");
|
BOOST_TEST(serr.str() == "");
|
||||||
BOOST_REQUIRE(parsedOptions.has_value());
|
BOOST_REQUIRE(parsedOptions.has_value());
|
||||||
BOOST_TEST(parsedOptions.value() == expectedOptions);
|
BOOST_TEST(parsedOptions.value() == expectedOptions);
|
||||||
@ -426,11 +427,10 @@ BOOST_AUTO_TEST_CASE(invalid_options_input_modes_combinations)
|
|||||||
for (auto const& [optionName, inputModes]: invalidOptionInputModeCombinations)
|
for (auto const& [optionName, inputModes]: invalidOptionInputModeCombinations)
|
||||||
for (string const& inputMode: inputModes)
|
for (string const& inputMode: inputModes)
|
||||||
{
|
{
|
||||||
stringstream sout, serr;
|
stringstream serr;
|
||||||
vector<string> commandLine = {"solc", optionName, "file", inputMode};
|
vector<string> commandLine = {"solc", optionName, "file", inputMode};
|
||||||
optional<CommandLineOptions> parsedOptions = parseCommandLine(commandLine, sout, serr);
|
optional<CommandLineOptions> parsedOptions = parseCommandLine(commandLine, serr);
|
||||||
|
|
||||||
BOOST_TEST(sout.str() == "");
|
|
||||||
BOOST_TEST(serr.str() == "The following options are not supported in the current input mode: " + optionName + "\n");
|
BOOST_TEST(serr.str() == "The following options are not supported in the current input mode: " + optionName + "\n");
|
||||||
BOOST_REQUIRE(!parsedOptions.has_value());
|
BOOST_REQUIRE(!parsedOptions.has_value());
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,10 @@ string test::stripPreReleaseWarning(string const& _stderrContent)
|
|||||||
R"(Warning( \(3805\))?: This is a pre-release compiler version, please do not use it in production\.\n)"
|
R"(Warning( \(3805\))?: This is a pre-release compiler version, please do not use it in production\.\n)"
|
||||||
R"((\n)?)"
|
R"((\n)?)"
|
||||||
};
|
};
|
||||||
|
static regex const noOutputRegex{
|
||||||
|
R"(Compiler run successful, no output requested\.\n)"
|
||||||
|
};
|
||||||
|
|
||||||
return regex_replace(_stderrContent, preReleaseWarningRegex, "");
|
string output = regex_replace(_stderrContent, preReleaseWarningRegex, "");
|
||||||
|
return regex_replace(move(output), noOutputRegex, "");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user