2014-04-02 11:47:23 +02:00
# include <ios>
2013-09-14 21:44:20 +02:00
# include <iostream>
# include <stdio.h>
# include <fstream>
2014-04-08 01:44:27 +02:00
# include <map>
# include <string>
2014-04-01 08:52:07 +02:00
// http://www.ridgesolutions.ie/index.php/2013/05/30/boost-link-error-undefined-reference-to-boostfilesystemdetailcopy_file/
# define BOOST_NO_CXX11_SCOPED_ENUMS
2013-09-14 21:44:20 +02:00
# include <boost/filesystem.hpp>
# include <opm/parser/eclipse/Parser/ParserItem.hpp>
# include <opm/parser/eclipse/Parser/ParserIntItem.hpp>
# include <opm/parser/eclipse/Parser/ParserStringItem.hpp>
# include <opm/parser/eclipse/Parser/ParserDoubleItem.hpp>
# include <opm/parser/eclipse/Parser/ParserKeyword.hpp>
# include <opm/parser/eclipse/Parser/ParserRecord.hpp>
# include <opm/parser/eclipse/Parser/Parser.hpp>
2014-04-08 01:44:27 +02:00
2013-09-14 21:44:20 +02:00
using namespace Opm ;
2014-04-01 08:52:07 +02:00
using namespace boost : : filesystem ;
2013-09-14 21:44:20 +02:00
2014-04-08 01:44:27 +02:00
typedef std : : pair < std : : string , std : : pair < std : : string , ParserKeywordConstPtr > > KeywordElementType ;
typedef std : : map < std : : string , std : : pair < std : : string , ParserKeywordConstPtr > > KeywordMapType ;
2014-03-31 14:25:45 +02:00
2014-05-08 16:26:14 +02:00
static void createHeader ( std : : iostream & of ) {
2013-09-14 21:44:20 +02:00
of < < " #include <opm/parser/eclipse/Parser/ParserKeyword.hpp> " < < std : : endl ;
of < < " #include <opm/parser/eclipse/Parser/ParserItem.hpp> " < < std : : endl ;
of < < " #include <opm/parser/eclipse/Parser/ParserIntItem.hpp> " < < std : : endl ;
of < < " #include <opm/parser/eclipse/Parser/ParserStringItem.hpp> " < < std : : endl ;
of < < " #include <opm/parser/eclipse/Parser/ParserDoubleItem.hpp> " < < std : : endl ;
of < < " #include <opm/parser/eclipse/Parser/ParserRecord.hpp> " < < std : : endl ;
of < < " #include <opm/parser/eclipse/Parser/Parser.hpp> " < < std : : endl ;
of < < " namespace Opm { " < < std : : endl < < std : : endl ;
}
2014-04-08 01:44:27 +02:00
2014-05-08 16:26:14 +02:00
static void createTestHeader ( std : : iostream & of , const std : : string & test_module ) {
2014-04-08 01:44:27 +02:00
of < < " #define BOOST_TEST_MODULE " < < test_module < < std : : endl ;
of < < " #include <boost/test/unit_test.hpp> " < < std : : endl ;
of < < " #include <memory> " < < std : : endl ;
of < < " #include <opm/parser/eclipse/Parser/ParserKeyword.hpp> " < < std : : endl ;
of < < " #include <opm/parser/eclipse/Parser/ParserItem.hpp> " < < std : : endl ;
of < < " #include <opm/parser/eclipse/Parser/ParserIntItem.hpp> " < < std : : endl ;
of < < " #include <opm/parser/eclipse/Parser/ParserStringItem.hpp> " < < std : : endl ;
of < < " #include <opm/parser/eclipse/Parser/ParserDoubleItem.hpp> " < < std : : endl ;
of < < " #include <opm/parser/eclipse/Parser/ParserFloatItem.hpp> " < < std : : endl ;
of < < " #include <opm/parser/eclipse/Parser/ParserRecord.hpp> " < < std : : endl ;
of < < " #include <opm/parser/eclipse/Units/UnitSystem.hpp> " < < std : : endl ;
of < < " using namespace Opm; " < < std : : endl < < std : : endl ;
of < < " std::shared_ptr<UnitSystem> unitSystem( UnitSystem::newMETRIC() ); " < < std : : endl ;
}
2014-05-08 16:26:14 +02:00
static void startFunction ( std : : iostream & of ) {
2013-09-14 21:44:20 +02:00
of < < " void Parser::addDefaultKeywords() { " < < std : : endl ;
}
2014-05-08 16:26:14 +02:00
static void endFunction ( std : : iostream & of ) {
2013-09-14 21:44:20 +02:00
of < < " } " < < std : : endl ;
}
2014-04-08 01:44:27 +02:00
2014-05-08 16:26:14 +02:00
static bool areStreamsEqual ( std : : istream & lhs , std : : istream & rhs )
2014-04-08 01:44:27 +02:00
{
for ( ; ; )
{
char l = lhs . get ( ) ;
char r = rhs . get ( ) ;
if ( ! lhs | | ! rhs ) // if either at end of file
break ;
if ( l ! = r ) // false if chars differ
return false ;
}
return ! lhs & & ! rhs ; // true if both end of file
}
2014-05-08 16:26:14 +02:00
static void generateKeywordSignature ( std : : iostream & of , KeywordMapType & keywordMap )
2014-12-08 16:34:28 +01:00
{
2014-04-08 01:44:27 +02:00
for ( auto iter = keywordMap . begin ( ) ; iter ! = keywordMap . end ( ) ; + + iter ) {
KeywordElementType keywordElement = * iter ;
2014-11-13 15:45:54 +01:00
const std : : string & keywordName = keywordElement . first ;
const std : : string & fileName = keywordElement . second . first ;
2014-04-08 01:44:27 +02:00
Json : : JsonObject * jsonKeyword = new Json : : JsonObject ( boost : : filesystem : : path ( fileName ) ) ;
2015-05-29 14:34:38 +02:00
of < < keywordName < < std : : endl < < jsonKeyword - > to_string ( ) < < std : : endl ;
2014-12-08 16:34:28 +01:00
2014-04-08 01:44:27 +02:00
delete jsonKeyword ;
}
}
//-----------------------------------------------------------------
2014-05-08 16:26:14 +02:00
static void startTest ( std : : iostream & of , const std : : string & test_name ) {
2014-04-08 01:44:27 +02:00
of < < " BOOST_AUTO_TEST_CASE( " < < test_name < < " ) { " < < std : : endl ;
}
2014-05-08 16:26:14 +02:00
static void endTest ( std : : iostream & of ) {
2014-04-08 01:44:27 +02:00
of < < " } " < < std : : endl < < std : : endl ;
}
2014-05-08 16:26:14 +02:00
static void testKeyword ( ParserKeywordConstPtr parserKeyword , const std : : string & keywordName , const boost : : filesystem : : path & jsonFile , std : : iostream & of ) {
2014-10-14 11:57:36 +02:00
std : : string testName ( " test " + keywordName + " Keyword " ) ;
startTest ( of , testName ) ;
2014-06-11 15:08:58 +02:00
of < < " Json::JsonObject jsonKeyword(boost::filesystem::path( " < < jsonFile < < " )); " < < std : : endl ;
of < < " ParserKeywordConstPtr parserKeyword = ParserKeyword::createFromJson(jsonKeyword); " < < std : : endl ;
2014-04-08 01:44:27 +02:00
2014-06-11 15:08:58 +02:00
of < < " ParserKeywordPtr " ;
2014-04-08 01:44:27 +02:00
parserKeyword - > inlineNew ( of , " inlineKeyword " , " " ) ;
2014-12-08 16:34:28 +01:00
2014-04-08 01:44:27 +02:00
of < < " BOOST_CHECK( parserKeyword->equal( *inlineKeyword)); " < < std : : endl ;
if ( parserKeyword - > hasDimension ( ) ) {
of < < " { " < < std : : endl ;
2015-02-20 00:21:32 +01:00
of < < " ParserRecordConstPtr parserRecord = parserKeyword->getRecord(0); " < < std : : endl ;
2014-04-08 01:44:27 +02:00
of < < " for (size_t i=0; i < parserRecord->size(); i++) { " < < std : : endl ;
of < < " ParserItemConstPtr item = parserRecord->get( i ); " < < std : : endl ;
of < < " for (size_t j=0; j < item->numDimensions(); j++) { " < < std : : endl ;
of < < " std::string dimString = item->getDimension(j); " < < std : : endl ;
of < < " BOOST_CHECK_NO_THROW( unitSystem->getNewDimension( dimString )); " < < std : : endl ;
2014-12-08 16:34:28 +01:00
of < < " } " < < std : : endl ;
2014-04-08 01:44:27 +02:00
of < < " } " < < std : : endl ;
of < < " } " < < std : : endl ;
}
endTest ( of ) ;
}
2014-05-08 16:26:14 +02:00
static void generateTestForKeyword ( std : : iostream & of , KeywordElementType keywordElement ) {
2014-11-13 15:45:54 +01:00
const std : : string & keywordName = keywordElement . first ;
const std : : string & fileName = keywordElement . second . first ;
2014-04-08 01:44:27 +02:00
ParserKeywordConstPtr parserKeyword = keywordElement . second . second ;
testKeyword ( parserKeyword , keywordName , fileName , of ) ;
}
2014-05-08 16:26:14 +02:00
static void generateKeywordTest ( const char * test_file_name , KeywordMapType & keywordMap ) {
2014-04-08 01:44:27 +02:00
std : : fstream test_file_stream ( test_file_name , std : : fstream : : out ) ;
createTestHeader ( test_file_stream , " TEST_KEYWORDS " ) ;
2014-12-08 16:34:28 +01:00
for ( auto iter = keywordMap . begin ( ) ; iter ! = keywordMap . end ( ) ; + + iter )
2014-04-08 01:44:27 +02:00
generateTestForKeyword ( test_file_stream , * iter ) ;
2014-12-08 16:34:28 +01:00
2014-04-08 01:44:27 +02:00
test_file_stream . close ( ) ;
}
//-----------------------------------------------------------------
2014-05-08 16:26:14 +02:00
static void generateSourceForKeyword ( std : : iostream & of , KeywordElementType keywordElement )
2014-03-31 14:25:45 +02:00
{
2014-11-13 15:45:54 +01:00
const std : : string & keywordName = keywordElement . first ;
2014-04-08 01:44:27 +02:00
ParserKeywordConstPtr parserKeyword = keywordElement . second . second ;
2014-04-07 13:58:12 +02:00
std : : string indent ( " " ) ;
of < < " { " < < std : : endl ;
2014-06-11 15:08:58 +02:00
of < < indent < < " ParserKeywordPtr " ;
2014-04-07 13:58:12 +02:00
parserKeyword - > inlineNew ( of , keywordName , indent ) ;
2014-08-25 15:40:31 +02:00
of < < indent < < " parser->addParserKeyword( " < < keywordName < < " ); " < < std : : endl ;
2014-04-07 13:58:12 +02:00
of < < " } " < < std : : endl < < std : : endl ;
2014-12-08 16:34:28 +01:00
2014-04-07 13:58:12 +02:00
std : : cout < < " Creating keyword: " < < keywordName < < std : : endl ;
2014-03-31 14:25:45 +02:00
}
2014-05-08 16:26:14 +02:00
static void generateKeywordSource ( const char * source_file_name , KeywordMapType & keywordMap ) {
2014-04-08 01:44:27 +02:00
std : : fstream source_file_stream ( source_file_name , std : : fstream : : out ) ;
2014-08-25 15:40:31 +02:00
2014-04-08 01:44:27 +02:00
createHeader ( source_file_stream ) ;
2014-08-25 15:40:31 +02:00
for ( auto iter = keywordMap . begin ( ) ; iter ! = keywordMap . end ( ) ; + + iter ) {
// the stupid default compiler flags will cause a warning if a function is
// defined without declaring a prototype before. So let's give the compiler a
// cookie to make it happy...
2014-11-13 15:45:54 +01:00
source_file_stream < < " void add " < < iter - > first < < " Keyword(Opm::Parser *parser); \n " ;
2014-08-25 15:40:31 +02:00
2014-11-13 15:45:54 +01:00
source_file_stream < < " void add " < < iter - > first < < " Keyword(Opm::Parser *parser) \n " ;
2014-04-08 01:44:27 +02:00
generateSourceForKeyword ( source_file_stream , * iter ) ;
2014-08-25 15:40:31 +02:00
}
2014-04-08 01:44:27 +02:00
2014-08-25 15:40:31 +02:00
startFunction ( source_file_stream ) ;
for ( auto iter = keywordMap . begin ( ) ; iter ! = keywordMap . end ( ) ; + + iter )
2014-11-13 15:45:54 +01:00
source_file_stream < < " add " < < iter - > first < < " Keyword(this); \n " ;
2014-04-08 01:44:27 +02:00
endFunction ( source_file_stream ) ;
2014-08-25 15:40:31 +02:00
source_file_stream < < " } // end namespace Opm \n " ;
2014-04-08 01:44:27 +02:00
source_file_stream . close ( ) ;
2014-03-31 14:25:45 +02:00
}
2014-04-08 01:44:27 +02:00
//-----------------------------------------------------------------
2014-05-08 16:26:14 +02:00
static void scanKeyword ( const boost : : filesystem : : path & file , KeywordMapType & keywordMap ) {
2014-11-14 13:27:27 +01:00
std : : string internalName = file . filename ( ) . string ( ) ;
if ( ! ParserKeyword : : validInternalName ( internalName ) ) {
2014-06-11 16:28:48 +02:00
std : : cerr < < " Warning: Ignoring incorrectly named file ' " < < file . string ( ) < < " '. \n " ;
return ;
}
2014-03-31 14:25:45 +02:00
2014-11-14 13:27:27 +01:00
KeywordMapType : : iterator existingEntry = keywordMap . find ( internalName ) ;
bool alreadyExists = existingEntry ! = keywordMap . end ( ) ;
if ( alreadyExists ) {
2014-11-18 11:51:35 +01:00
std : : cerr < < " Warning: Ignoring the the keyword " < < internalName < < " found in ' " < < existingEntry - > second . first < < " ', " < < std : : endl
< < " \t replacing it with data from ' " < < file . string ( ) < < " ' " < < std : : endl ;
keywordMap . erase ( existingEntry ) ;
2014-11-14 13:27:27 +01:00
}
2014-06-11 16:28:48 +02:00
Json : : JsonObject * jsonKeyword ;
try {
jsonKeyword = new Json : : JsonObject ( file ) ;
2014-12-15 16:19:14 +01:00
} catch ( const std : : exception & e ) {
std : : cerr < < " Parsing JSON keyword definition from file ' " < < file . string ( ) < < " ' failed: "
< < e . what ( ) < < " \n " ;
std : : exit ( 1 ) ;
2014-04-07 13:58:12 +02:00
}
2014-06-11 16:28:48 +02:00
{
ParserKeywordConstPtr parserKeyword ( ParserKeyword : : createFromJson ( * jsonKeyword ) ) ;
if ( parserKeyword - > getName ( ) ! = boost : : filesystem : : basename ( file ) )
std : : cerr < < " Warning: The name ' " < < parserKeyword - > getName ( ) < < " specified in the JSON definitions of file ' " < < file
< < " ' does not match the file's name! \n " ;
2014-11-13 15:45:54 +01:00
std : : pair < std : : string , ParserKeywordConstPtr > elm ( file . string ( ) , parserKeyword ) ;
std : : pair < std : : string , std : : pair < std : : string , ParserKeywordConstPtr > > pair ( parserKeyword - > getName ( ) , elm ) ;
2014-06-11 16:28:48 +02:00
keywordMap . insert ( pair ) ;
}
delete jsonKeyword ;
2013-09-14 21:44:20 +02:00
}
2014-05-08 16:26:14 +02:00
static void scanAllKeywords ( const boost : : filesystem : : path & directory , KeywordMapType & keywordMap ) {
2014-11-18 11:51:35 +01:00
boost : : filesystem : : directory_iterator end_iterator ;
for ( boost : : filesystem : : directory_iterator iter ( directory ) ; iter ! = end_iterator ; iter + + ) {
2013-09-14 21:44:20 +02:00
if ( boost : : filesystem : : is_directory ( * iter ) )
2014-04-08 01:44:27 +02:00
scanAllKeywords ( * iter , keywordMap ) ;
2013-09-14 21:44:20 +02:00
else
2014-04-08 01:44:27 +02:00
scanKeyword ( * iter , keywordMap ) ;
2013-09-14 21:44:20 +02:00
}
}
2014-04-08 01:44:27 +02:00
//-----------------------------------------------------------------
2014-04-01 08:52:07 +02:00
2014-05-08 16:26:14 +02:00
static void printUsage ( ) {
2014-04-01 08:52:07 +02:00
std : : cout < < " Generates source code for populating the parser's list of known keywords. " < < std : : endl ;
std : : cout < < " Usage: createDefaultKeywordList <configroot> <sourcefilename> [<dumpfilename>] " < < std : : endl ;
2014-11-17 13:31:36 +01:00
std : : cout < < " <configroot>: Path to keyword (JSON) files, first level below this will be read in alfanumerical order. Ignoring repeated keywords. " < < std : : endl ;
2014-04-01 08:52:07 +02:00
std : : cout < < " <sourcefilename>: Path to source file to generate " < < std : : endl ;
2014-04-08 01:44:27 +02:00
std : : cout < < " <testfilename> : Path to source file with keyword testing " < < std : : endl ;
2014-04-01 08:52:07 +02:00
std : : cout < < " <dumpfilename>: Path to dump file containing state of keyword list at " < < std : : endl ;
std : : cout < < " last build (used for build triggering). " < < std : : endl ;
}
2014-04-07 17:07:24 +02:00
2014-05-08 16:26:14 +02:00
static void ensurePath ( const char * file_name ) {
2014-04-07 17:07:24 +02:00
boost : : filesystem : : path file ( file_name ) ;
if ( ! boost : : filesystem : : is_directory ( file . parent_path ( ) ) )
boost : : filesystem : : create_directory ( file . parent_path ( ) ) ;
}
2014-11-17 13:31:36 +01:00
static std : : vector < boost : : filesystem : : path > getPathsInAlfanumOrder ( const char * config_root )
{
boost : : filesystem : : path root ( config_root ) ;
std : : vector < std : : string > paths_in_root ;
2014-11-18 11:51:35 +01:00
boost : : filesystem : : directory_iterator end_iterator ;
for ( boost : : filesystem : : directory_iterator iter ( root ) ; iter ! = end_iterator ; iter + + ) {
2014-11-17 13:31:36 +01:00
if ( boost : : filesystem : : is_directory ( * iter ) ) {
paths_in_root . push_back ( iter - > path ( ) . string ( ) ) ;
}
}
std : : sort ( paths_in_root . begin ( ) , paths_in_root . end ( ) ) ;
std : : vector < boost : : filesystem : : path > paths_in_alfanum_order ;
std : : cout < < " Paths will be scanned for keyword definitions in the following order, ignoring repeats: " < < std : : endl ;
for ( auto it = paths_in_root . begin ( ) ; it ! = paths_in_root . end ( ) ; + + it ) {
std : : cerr < < " -- " < < * it < < std : : endl ;
paths_in_alfanum_order . push_back ( boost : : filesystem : : path ( * it ) ) ;
}
return paths_in_alfanum_order ;
}
2014-04-15 09:48:19 +02:00
int main ( int /* argc */ , char * * argv ) {
2014-04-01 08:52:07 +02:00
const char * config_root = argv [ 1 ] ;
const char * source_file_name = argv [ 2 ] ;
2014-04-08 01:44:27 +02:00
const char * test_file_name = argv [ 3 ] ;
const char * signature_file_name = argv [ 4 ] ;
2014-04-01 08:52:07 +02:00
if ( ! argv [ 1 ] ) {
printUsage ( ) ;
return 0 ;
}
2014-04-08 01:44:27 +02:00
KeywordMapType keywordMap ;
2014-11-11 13:11:23 +01:00
2014-04-08 01:44:27 +02:00
bool needToGenerate = false ;
std : : stringstream signature_stream ;
2014-04-01 08:52:07 +02:00
2014-04-07 17:07:24 +02:00
ensurePath ( source_file_name ) ;
2014-04-08 01:44:27 +02:00
ensurePath ( test_file_name ) ;
ensurePath ( signature_file_name ) ;
2014-11-17 13:31:36 +01:00
std : : vector < boost : : filesystem : : path > paths_in_alfanum_order = getPathsInAlfanumOrder ( config_root ) ;
for ( auto it = paths_in_alfanum_order . begin ( ) ; it ! = paths_in_alfanum_order . end ( ) ; + + it ) {
scanAllKeywords ( * it , keywordMap ) ;
}
2014-04-08 01:44:27 +02:00
generateKeywordSignature ( signature_stream , keywordMap ) ;
if ( ! boost : : filesystem : : exists ( path ( source_file_name ) ) )
needToGenerate = true ;
if ( ! boost : : filesystem : : exists ( path ( test_file_name ) ) )
needToGenerate = true ;
if ( ! needToGenerate ) {
if ( boost : : filesystem : : exists ( path ( signature_file_name ) ) ) {
std : : fstream signature_stream_on_disk ( signature_file_name , std : : fstream : : in ) ;
needToGenerate = ! areStreamsEqual ( signature_stream , signature_stream_on_disk ) ;
signature_stream_on_disk . close ( ) ;
} else
needToGenerate = true ;
2014-04-01 08:52:07 +02:00
}
2014-04-08 01:44:27 +02:00
if ( needToGenerate ) {
std : : cout < < " Generating keywords: " < < std : : endl ;
generateKeywordSource ( source_file_name , keywordMap ) ;
generateKeywordTest ( test_file_name , keywordMap ) ;
{
std : : fstream signature_stream_on_disk ( signature_file_name , std : : fstream : : out ) ;
signature_stream . seekg ( std : : ios_base : : beg ) ;
signature_stream_on_disk < < signature_stream . rdbuf ( ) ;
signature_stream_on_disk . close ( ) ;
2014-04-02 15:17:18 +02:00
}
2014-04-02 11:47:23 +02:00
}
else {
2014-04-08 01:44:27 +02:00
std : : cout < < " No keyword changes detected. " < < std : : endl ;
2014-04-02 11:47:23 +02:00
}
return 0 ;
2014-04-01 08:52:07 +02:00
}