From db2f3c57147c21da8a549a6052256540d3c41e3e Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 25 Jan 2016 19:42:17 +0100 Subject: [PATCH] Provide remappings for solc. --- solc/CommandLineInterface.cpp | 105 +++++++++++++++++++++++----------- solc/CommandLineInterface.h | 4 ++ 2 files changed, 77 insertions(+), 32 deletions(-) diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 4c9de3c86..7c842c833 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -297,6 +297,48 @@ void CommandLineInterface::handleFormal() cout << "Formal version:" << endl << m_compiler->formalTranslation() << endl; } +void CommandLineInterface::readInputFilesAndConfigureRemappings() +{ + if (!m_args.count("input-file")) + { + string s; + while (!cin.eof()) + { + getline(cin, s); + m_sourceCodes[g_stdinFileName].append(s + '\n'); + } + } + else + for (string const& infile: m_args["input-file"].as>()) + { + auto eq = find(infile.begin(), infile.end(), '='); + if (eq != infile.end()) + m_remappings.push_back(make_pair( + string(infile.begin(), eq), + string(eq + 1, infile.end()) + )); + else + { + auto path = boost::filesystem::path(infile); + if (!boost::filesystem::exists(path)) + { + cerr << "Skipping non existant input file \"" << infile << "\"" << endl; + continue; + } + + if (!boost::filesystem::is_regular_file(path)) + { + cerr << "\"" << infile << "\" is not a valid file. Skipping" << endl; + continue; + } + + m_sourceCodes[infile] = dev::contentsString(infile); + } + } + // Add empty remapping to try the path itself. + m_remappings.push_back(make_pair(string(), string())); +} + bool CommandLineInterface::parseLibraryOption(string const& _input) { namespace fs = boost::filesystem; @@ -457,33 +499,7 @@ Allowed options)", bool CommandLineInterface::processInput() { - if (!m_args.count("input-file")) - { - string s; - while (!cin.eof()) - { - getline(cin, s); - m_sourceCodes[g_stdinFileName].append(s + '\n'); - } - } - else - for (string const& infile: m_args["input-file"].as>()) - { - auto path = boost::filesystem::path(infile); - if (!boost::filesystem::exists(path)) - { - cerr << "Skipping non existant input file \"" << infile << "\"" << endl; - continue; - } - - if (!boost::filesystem::is_regular_file(path)) - { - cerr << "\"" << infile << "\" is not a valid file. Skipping" << endl; - continue; - } - - m_sourceCodes[infile] = dev::contentsString(infile); - } + readInputFilesAndConfigureRemappings(); if (m_args.count("libraries")) for (string const& library: m_args["libraries"].as>()) @@ -499,13 +515,38 @@ bool CommandLineInterface::processInput() function(string const&)> fileReader = [this](string const& _path) { - auto path = boost::filesystem::path(_path); - if (!boost::filesystem::exists(path)) + // Try to find the longest prefix match in all remappings. At the end, there will be an + // empty remapping so that we also try the path itself. + int errorLevel = 0; + size_t longestPrefix = 0; + string bestMatchPath; + for (auto const& redir: m_remappings) + { + auto const& virt = redir.first; + if (longestPrefix > 0 && virt.length() <= longestPrefix) + continue; + if (virt.length() > _path.length() || !std::equal(virt.begin(), virt.end(), _path.begin())) + continue; + string path = redir.second; + path.append(_path.begin() + virt.length(), _path.end()); + auto boostPath = boost::filesystem::path(path); + if (!boost::filesystem::exists(boostPath)) + errorLevel = max(errorLevel, 0); + else if (!boost::filesystem::is_regular_file(boostPath)) + errorLevel = max(errorLevel, 1); + else + { + longestPrefix = virt.length(); + bestMatchPath = path; + } + } + if (!bestMatchPath.empty()) + return make_pair(m_sourceCodes[bestMatchPath] = dev::contentsString(bestMatchPath), string()); + if (errorLevel == 0) return make_pair(string(), string("File not found.")); - else if (!boost::filesystem::is_regular_file(path)) - return make_pair(string(), string("Not a valid file.")); else - return make_pair(m_sourceCodes[_path] = dev::contentsString(_path), string()); + return make_pair(string(), string("Not a valid file.")); + }; m_compiler.reset(new CompilerStack(m_args.count(g_argAddStandard) > 0, fileReader)); diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index 7c7aa4b49..7fdc9c0d0 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -61,6 +61,8 @@ private: void handleGasEstimation(std::string const& _contract); void handleFormal(); + /// Fills @a m_sourceCodes initially and @a m_redirects. + void readInputFilesAndConfigureRemappings(); /// Tries to read from the file @a _input or interprets _input literally if that fails. /// It then tries to parse the contents and appends to m_libraries. bool parseLibraryOption(std::string const& _input); @@ -76,6 +78,8 @@ private: boost::program_options::variables_map m_args; /// map of input files to source code strings std::map m_sourceCodes; + /// list of path prefix remappings, e.g. github.com/ethereum -> /usr/local/ethereum + std::vector> m_remappings; /// map of library names to addresses std::map m_libraries; /// Solidity compiler stack