93 std::string& ioPORFilepath,
94 std::string& ioXapianDBFilepath,
95 std::string& ioSQLDBTypeString,
96 std::string& ioSQLDBConnectionString,
97 unsigned short& ioDeploymentNumber,
98 bool& ioIncludeNonIATAPOR,
99 bool& ioIndexPORInXapian,
101 std::string& ioLogFilename,
102 std::string& ioCommand) {
105 boost::program_options::options_description generic (
"Generic options");
106 generic.add_options()
107 (
"prefix",
"print installation prefix")
108 (
"version,v",
"print version string")
109 (
"help,h",
"produce help message");
113 boost::program_options::options_description config (
"Configuration");
117 "POR file-path (e.g., ori_por_public.csv)")
120 "Xapian database filepath (e.g., /tmp/opentrep/xapian_traveldb)")
123 "SQL database type (e.g., nodb for no SQL database, sqlite for SQLite, mysql for MariaDB/MySQL, pg for PostgreSQL)")
125 boost::program_options::value< std::string >(&ioSQLDBConnectionString),
126 "SQL database connection string (e.g., ~/tmp/opentrep/sqlite_travel.db for SQLite, \"db=trep_trep user=trep password=trep\" for MariaDB/MySQL or PostgreSQL)")
129 "Deployment number (from to N, where N=1 normally)")
132 "Whether or not to include POR not referenced by IATA (0 = only IATA-referenced POR, 1 = all POR are included)")
135 "Whether or not to index the POR in Xapian (0 = do not touch the Xapian index, 1 = re-index all the POR in Xapian)")
138 "Whether or not to add and index the POR in the SQL-based database (0 = do not touch the SQL-based database, 1 = add and re-index all the POR in the SQL-based database)")
141 "Filepath for the logs")
143 boost::program_options::value< std::string >(&ioCommand)->default_value(
""),
144 "Execute the given semicolon-separated dbmgr command(s) (e.g., \"list_nb ; list_by_iata nce\") in non-interactive mode, and then exit")
149 boost::program_options::options_description hidden (
"Hidden options");
152 boost::program_options::value< std::vector<std::string> >(),
153 "Show the copyright (license)");
155 boost::program_options::options_description cmdline_options;
156 cmdline_options.add(generic).add(config).add(hidden);
158 boost::program_options::options_description config_file_options;
159 config_file_options.add(config).add(hidden);
161 boost::program_options::options_description visible (
"Allowed options");
162 visible.add(generic).add(config);
164 boost::program_options::positional_options_description p;
165 p.add (
"copyright", -1);
167 boost::program_options::variables_map vm;
168 boost::program_options::
169 store (boost::program_options::command_line_parser (argc, argv).
170 options (cmdline_options).positional(p).run(), vm);
172 std::ifstream ifs (
"opentrep-dbmgr.cfg");
173 boost::program_options::store (parse_config_file (ifs, config_file_options),
175 boost::program_options::notify (vm);
177 if (vm.count (
"help")) {
178 std::cout << visible << std::endl;
182 if (vm.count (
"version")) {
183 std::cout << PACKAGE_NAME <<
", version " << PACKAGE_VERSION << std::endl;
187 if (vm.count (
"prefix")) {
188 std::cout <<
"Installation prefix: " << PREFIXDIR << std::endl;
192 if (vm.count (
"porfile")) {
193 ioPORFilepath = vm[
"porfile"].as< std::string >();
196 if (vm.count (
"deploymentnb")) {
197 ioDeploymentNumber = vm[
"deploymentnb"].as<
unsigned short >();
198 std::cout <<
"Deployment number " << ioDeploymentNumber << std::endl;
201 if (vm.count (
"xapiandb")) {
202 ioXapianDBFilepath = vm[
"xapiandb"].as< std::string >();
203 std::cout <<
"Xapian index/database filepath is: " << ioXapianDBFilepath
204 << ioDeploymentNumber << std::endl;
208 if (vm.count (
"sqldbtype")) {
209 ioSQLDBTypeString = vm[
"sqldbtype"].as< std::string >();
210 std::cout <<
"SQL database type is: " << ioSQLDBTypeString
227 ioAddPORInDB =
false;
228 ioSQLDBConnectionString =
"";
244 if (vm.count (
"sqldbconx")) {
245 ioSQLDBConnectionString = vm[
"sqldbconx"].as< std::string >();
252 const std::string& lSQLDBConnString =
254 ioSQLDBConnectionString,
257 std::cout <<
"SQL database connection string is: " << lSQLDBConnString
261 std::cout <<
"Are non-IATA-referenced POR included? "
262 << ioIncludeNonIATAPOR << std::endl;
264 std::cout <<
"Index the POR in Xapian? "
265 << ioIndexPORInXapian << std::endl;
267 std::cout <<
"Add and re-index the POR in the SQL-based database? "
268 << ioAddPORInDB << std::endl;
270 if (vm.count (
"log")) {
271 ioLogFilename = vm[
"log"].as< std::string >();
274 if (vm.count (
"command")) {
275 ioCommand = vm[
"command"].as< std::string >();
279 std::cout <<
"Type the 'info' command to get a few details (e.g., file-path)"
638 const std::string& iLogFilename,
639 const std::string& iPORFilepathStr,
647 switch (lCommandType) {
651 std::cout << std::endl;
652 std::cout <<
"Commands: " << std::endl;
653 std::cout <<
" CTRL-L (Control and L keys)" <<
"\t" <<
"Clean the screen"
655 std::cout <<
" help" <<
"\t\t\t\t" <<
"Display this help" << std::endl;
656 std::cout <<
" info" <<
"\t\t\t\t"
657 <<
"Display details for the current session "
658 <<
"(e.g., file-paths for the log file, SQL database)"
660 std::cout <<
" tutorial" <<
"\t\t\t" <<
"Display examples" << std::endl;
661 std::cout <<
" quit" <<
"\t\t\t\t" <<
"Quit the application" << std::endl;
662 std::cout <<
" create_user" <<
"\t\t\t"
663 <<
"On SQL database, create the 'trep' user and the 'trep_trep' "
664 <<
"database. SQL database administrative rights are required."
666 std::cout <<
" reset_connection_string" <<
"\t"
667 <<
"Reset/update the connection string to a MySQL or PostgreSQL database."
668 <<
" The connection string must be given"
670 std::cout <<
" create_tables" <<
"\t\t\t"
671 <<
"Create/reset the SQL database (eg, SQLite3, PostgreSQL, MySQL) tables"
673 std::cout <<
" create_indexes" <<
"\t\t\t"
674 <<
"Create/reset the SQL database (eg, SQLite3, PostgreSQL, MySQL) indices"
676 std::cout <<
" toggle_deployment_number" <<
"\t"
677 <<
"Toggle the deployment number/version. "
678 <<
"To see the deployment version/number, type 'info'"
680 std::cout <<
" toggle_noniata_indexing_flag" <<
"\t"
681 <<
"Toggle the flag for the indexing (or not) of the non-IATA referenced POR."
682 <<
" To see the flag, type 'info'"
684 std::cout <<
" toggle_xapian_idexing_flag" <<
"\t"
685 <<
"Toggle the flag for the Xapian indexing (or not) of the POR."
686 <<
" To see the flag, type 'info'"
688 std::cout <<
" toggle_sqldb_inserting_flag" <<
"\t"
689 <<
"Toggle the flag for inserting (or not) the POR into the SQL database."
690 <<
" To see the flag, type 'info'"
692 std::cout <<
" fill_from_por_file" <<
"\t\t"
693 <<
"Parse the file of POR and fill-in the SQL database optd_por table."
694 << std::endl <<
"\t\t\t\t"
695 <<
"That command (re-)creates both the Xapian index and the SQL tables (as well as the indices), if needed."
696 << std::endl <<
"\t\t\t\t"
697 <<
"Note that, as that command takes minutes, the connection to the SQL database may be lost and the program will exit abnormally."
698 << std::endl <<
"\t\t\t\t"
699 <<
"In that latter case, just re-execute the program and check how far the indexation went by executing the following command."
701 std::cout <<
" list_nb" <<
"\t\t\t"
702 <<
"Display the number of the entries of the database."
704 std::cout <<
" list_all" <<
"\t\t\t"
705 <<
"List all the entries of the database, page by page."
706 <<
"Type the 'list_cont' command for a page down" << std::endl;
707 std::cout <<
" list_by_iata" <<
"\t\t\t"
708 <<
"List all the entries for a given IATA code"
710 std::cout <<
" list_by_icao" <<
"\t\t\t"
711 <<
"List all the entries for a given ICAO code"
713 std::cout <<
" list_by_faa" <<
"\t\t\t"
714 <<
"List all the entries for a given FAA code"
716 std::cout <<
" list_by_unlocode" <<
"\t\t\t"
717 <<
"List all the entries for a given UN/LOCODE code"
719 std::cout <<
" list_by_uiccode" <<
"\t\t\t"
720 <<
"List all the entries for a given UIC code"
722 std::cout <<
" list_by_geonameid" <<
"\t\t"
723 <<
"List all the entries for a given Geoname ID"
725 std::cout << std::endl;
737 std::cout << std::endl;
738 std::cout <<
"Log file-path: " <<
"\t\t\t\t\t" << iLogFilename
740 std::cout <<
"POR file-path: " <<
"\t\t\t\t\t" << iPORFilepathStr
742 std::cout <<
"Xapian index/database file-path: " <<
"\t\t"
743 << lXapianDBFP << std::endl;
744 std::cout <<
"SQL database type: " <<
"\t\t\t\t" << iDBType.
describe()
746 std::cout <<
"SQL database connection string: " <<
"\t\t" << lSQLConnStr
748 std::cout <<
"Deployment number/version: " <<
"\t\t\t"
749 << ioDeploymentNumber <<
"/"
752 std::cout <<
"Whether to index NON-IATA-referenced POR: " <<
"\t"
753 << ioIncludeNonIATAPOR << std::endl;
754 std::cout <<
"Whether to index the POR in Xapian: " <<
"\t\t"
755 << ioShouldIndexPORInXapian << std::endl;
756 std::cout <<
"Whether to insert the POR in the SQL DB: " <<
"\t"
757 << ioShouldAddPORInSQLDB << std::endl;
758 std::cout << std::endl;
764 std::cout << std::endl;
765 std::cout <<
"Typical succession of commands" << std::endl;
766 std::cout <<
" -------- " << std::endl;
767 std::cout <<
"Check with the 'info' command and adjust the various flags:"
769 std::cout <<
" toggle_deployment_number" << std::endl;
770 std::cout <<
" toggle_noniata_indexing_flag" << std::endl;
771 std::cout <<
" toggle_xapian_idexing_flag" << std::endl;
772 std::cout <<
" toggle_sqldb_inserting_flag" << std::endl;
773 std::cout << std::endl;
774 std::cout <<
" -------- " << std::endl;
775 std::cout <<
"Re-indexing of the POR data file:" << std::endl;
776 std::cout <<
" fill_from_por_file" << std::endl;
777 std::cout << std::endl;
778 std::cout <<
" -------- " << std::endl;
779 std::cout <<
"Check the content of the SQL database:" << std::endl;
780 std::cout <<
" list_nb" << std::endl;
781 std::cout <<
" list_by_iata nce" << std::endl;
782 std::cout <<
" list_by_icao lfmn" << std::endl;
783 std::cout <<
" list_by_faa jfk" << std::endl;
784 std::cout <<
" list_by_unlocode deham" << std::endl;
785 std::cout <<
" list_by_uiccode 87775007" << std::endl;
786 std::cout <<
" list_by_geonameid 6299418" << std::endl;
787 std::cout << std::endl;
788 std::cout <<
" -------- " << std::endl;
789 std::cout <<
"Management of the database user and database:" << std::endl;
790 std::cout <<
"* For PostgreSQL:" << std::endl;
791 std::cout <<
" reset_connection_string db=postgres user=$USER password=<passwd>"
793 std::cout <<
"* For MySQL:" << std::endl;
794 std::cout <<
" reset_connection_string db=mysql user=root password=<passwd>"
796 std::cout <<
" create_user" << std::endl;
797 std::cout <<
" reset_connection_string db=trep_trep user=trep password=trep"
799 std::cout <<
" create_tables" << std::endl;
800 std::cout <<
" create_indexes" << std::endl;
801 std::cout << std::endl;
818 std::cout << nbOfEntries
819 <<
" POR (points of reference) have been found in the Xapian "
820 <<
"index. Type 'info' to know where that Xapian index is "
821 "located." << std::endl;
828 std::cout << nbOfEntries
829 <<
" POR (points of reference) have been found in the "
830 << iDBType.
describe() <<
" database" << std::endl;
845 const std::string lIataCodeStr (
"NCE");
854 std::cout << nbOfMatches <<
" (geographical) location(s) have been found "
855 <<
"matching the IATA code ('" << lIataCodeStr <<
"')."
858 if (nbOfMatches != 0) {
860 for (OPENTREP::LocationList_T::const_iterator itLocation =
861 lLocationList.begin();
862 itLocation != lLocationList.end(); ++itLocation, ++idx) {
864 std::cout <<
" [" << idx <<
"]: " << lLocation.
toString() << std::endl;
868 std::cout <<
"List of unmatched words:" << std::endl;
869 std::cout <<
" [" << 1 <<
"]: " << lIataCodeStr << std::endl;
886 std::string lIataCodeStr (
"nce");
896 std::cout << nbOfMatches <<
" (geographical) location(s) have been found "
897 <<
"matching the IATA code ('" << lIataCodeStr <<
"')."
900 if (nbOfMatches != 0) {
902 for (OPENTREP::LocationList_T::const_iterator itLocation =
903 lLocationList.begin();
904 itLocation != lLocationList.end(); ++itLocation, ++idx) {
906 std::cout <<
" [" << idx <<
"]: " << lLocation << std::endl;
910 std::cout <<
"List of unmatched words:" << std::endl;
911 std::cout <<
" [" << 1 <<
"]: " << lIataCodeStr << std::endl;
928 std::string lIcaoCodeStr (
"lfmn");
938 std::cout << nbOfMatches <<
" (geographical) location(s) have been found "
939 <<
"matching the ICAO code ('" << lIcaoCodeStr <<
"')."
942 if (nbOfMatches != 0) {
944 for (OPENTREP::LocationList_T::const_iterator itLocation =
945 lLocationList.begin();
946 itLocation != lLocationList.end(); ++itLocation, ++idx) {
948 std::cout <<
" [" << idx <<
"]: " << lLocation << std::endl;
952 std::cout <<
"List of unmatched words:" << std::endl;
953 std::cout <<
" [" << 1 <<
"]: " << lIcaoCodeStr << std::endl;
970 std::string lFaaCodeStr (
"jfk");
980 std::cout << nbOfMatches <<
" (geographical) location(s) have been found "
981 <<
"matching the FAA code ('" << lFaaCodeStr <<
"')."
984 if (nbOfMatches != 0) {
986 for (OPENTREP::LocationList_T::const_iterator itLocation =
987 lLocationList.begin();
988 itLocation != lLocationList.end(); ++itLocation, ++idx) {
990 std::cout <<
" [" << idx <<
"]: " << lLocation << std::endl;
994 std::cout <<
"List of unmatched words:" << std::endl;
995 std::cout <<
" [" << 1 <<
"]: " << lFaaCodeStr << std::endl;
1012 std::string lUNLOCodeStr (
"deham");
1022 std::cout << nbOfMatches <<
" (geographical) location(s) have been found "
1023 <<
"matching the UN/LOCODE code ('" << lUNLOCodeStr <<
"')."
1026 if (nbOfMatches != 0) {
1028 for (OPENTREP::LocationList_T::const_iterator itLocation =
1029 lLocationList.begin();
1030 itLocation != lLocationList.end(); ++itLocation, ++idx) {
1032 std::cout <<
" [" << idx <<
"]: " << lLocation << std::endl;
1036 std::cout <<
"List of unmatched words:" << std::endl;
1037 std::cout <<
" [" << 1 <<
"]: " << lUNLOCodeStr << std::endl;
1054 std::string lUICCodeStr (
"87775007");
1062 lUICCode = boost::lexical_cast<OPENTREP::UICCode_T> (lUICCodeStr);
1064 }
catch (boost::bad_lexical_cast& eCast) {
1065 lUICCode = 87775007;
1066 std::cerr <<
"The UIC code ('" << lUICCodeStr
1067 <<
"') cannot be understood. The default value ("
1068 << lUICCode <<
") is kept." << std::endl;
1077 std::cout << nbOfMatches <<
" (geographical) location(s) have been found "
1078 <<
"matching the UIC code ('" << lUICCodeStr <<
"')."
1081 if (nbOfMatches != 0) {
1083 for (OPENTREP::LocationList_T::const_iterator itLocation =
1084 lLocationList.begin();
1085 itLocation != lLocationList.end(); ++itLocation, ++idx) {
1087 std::cout <<
" [" << idx <<
"]: " << lLocation << std::endl;
1091 std::cout <<
"List of unmatched words:" << std::endl;
1092 std::cout <<
" [" << 1 <<
"]: " << lUICCodeStr << std::endl;
1110 std::string lGeonameIDStr (
"6299418");
1118 lGeonameID = boost::lexical_cast<OPENTREP::GeonamesID_T> (lGeonameIDStr);
1120 }
catch (boost::bad_lexical_cast& eCast) {
1121 lGeonameID = 6299418;
1122 std::cerr <<
"The Geoname ID ('" << lGeonameIDStr
1123 <<
"') cannot be understood. The default value ("
1124 << lGeonameID <<
") is kept." << std::endl;
1133 std::cout << nbOfMatches <<
" (geographical) location(s) have been found "
1134 <<
"matching the Geoname ID ('" << lGeonameIDStr <<
"')."
1137 if (nbOfMatches != 0) {
1139 for (OPENTREP::LocationList_T::const_iterator itLocation =
1140 lLocationList.begin();
1141 itLocation != lLocationList.end(); ++itLocation, ++idx) {
1143 std::cout <<
" [" << idx <<
"]: " << lLocation << std::endl;
1147 std::cout <<
"List of unmatched items:" << std::endl;
1148 std::cout <<
" [" << 1 <<
"]: " << lGeonameIDStr << std::endl;
1157 std::cout <<
"Creating the 'trep' user and 'trep_trep' database"
1178 if (lCreationSuccessful ==
true) {
1179 std::cout <<
"The 'trep' user and 'trep_trep' database have been created"
1182 std::cout <<
"The 'trep' user and 'trep_trep' database could not be "
1183 <<
"created. See the log file ('" << iLogFilename
1184 <<
"') for details." << std::endl;
1188 std::cerr <<
"The 'trep' user and '" << iDBType.
describe()
1189 <<
"' database could not be created: "
1190 << eSQLDBException.
what() <<
". This may happen when the "
1191 <<
"deployment-slot database (e.g., 'trep0') does not "
1192 <<
"exist yet and/or the connecting user/role lacks the "
1193 <<
"privilege to create databases. On PostgreSQL, that "
1194 <<
"database may need to be pre-created (e.g., "
1195 <<
"'createdb -h localhost -U trep trep0'), or the 'trep' "
1196 <<
"role may need the CREATEDB privilege." << std::endl;
1206 const std::string lConnectionStringStr =
toString (ioTokenList);
1209 std::cout <<
"Reset the connection string" << std::endl;
1226 lConnectionString (lConnectionStringStr);
1230 std::cout <<
"The connection string has been reset" << std::endl;
1233 std::cerr <<
"The connection string ('" << lConnectionStringStr
1234 <<
"') cannot be understood for the '" << iDBType.
describe()
1235 <<
"' database type: " << eParsing.
what() <<
". "
1236 <<
"The connection string has not been changed." << std::endl;
1248 std::cout <<
"The new deployment number/version is: " << ioDeploymentNumber
1261 std::cout <<
"The new flag is: " << ioIncludeNonIATAPOR << std::endl;
1269 ioShouldIndexPORInXapian =
1273 std::cout <<
"The new flag is: " << ioShouldIndexPORInXapian << std::endl;
1284 std::cout <<
"The new flag is: " << ioShouldAddPORInSQLDB << std::endl;
1292 std::cout <<
"Creating/resetting the " << iDBType.
describe()
1293 <<
" database tables" << std::endl;
1307 std::cout <<
"The " << iDBType.
describe()
1308 <<
" tables has been created/resetted" << std::endl;
1311 std::cerr <<
"The " << iDBType.
describe() <<
" database tables could "
1312 <<
"not be created/reset: " << eSQLDBException.
what()
1313 <<
". Make sure that the '" << iDBType.
describe()
1314 <<
"' database has already been created (see the "
1315 <<
"'create_user' command) and that the corresponding "
1316 <<
"connection string is correct (see the 'info' command)."
1326 std::cout <<
"Creating/resetting the " << iDBType.
describe()
1327 <<
" database indices" << std::endl;
1339 std::cout <<
"The " << iDBType.
describe()
1340 <<
" indices has been created/resetted" << std::endl;
1343 std::cerr <<
"The " << iDBType.
describe() <<
" database indices "
1344 <<
"could not be created/reset: " << eSQLDBException.
what()
1345 <<
". Make sure that the '" << iDBType.
describe()
1346 <<
"' database and tables have already been created (see "
1347 <<
"the 'create_user' and 'create_tables' commands)."
1357 std::cout <<
"Indexing the POR file and filling in the SQL database may "
1358 <<
"take a few minutes on some architectures "
1359 <<
"(and a few seconds on fastest ones)..."
1367 std::cout << lNbOfEntries <<
" entries have been processed" << std::endl;
1380 std::ostringstream oStr;
1381 oStr <<
"That command is not yet understood: '" << iUserInput
1382 <<
"' => " << ioTokenList;
1384 std::cout << oStr.str() << std::endl;
1389 return lCommandType;
1396 const unsigned int lHistorySize (100);
1397 const std::string lHistoryFilename (
"opentrep-dbmgr.hist");
1398 const std::string lHistoryBackupFilename (
"opentrep-dbmgr.hist.bak");
1401 std::string lLogFilename;
1404 std::string lPORFilepathStr;
1407 std::string lXapianDBNameStr;
1410 std::string lSQLDBTypeStr;
1413 std::string lSQLDBConnectionStr;
1429 std::string lCommandStr;
1432 const int lOptionParserStatus =
1434 lSQLDBTypeStr, lSQLDBConnectionStr, lDeploymentNumber,
1435 lIncludeNonIATAPOR, lShouldIndexPORInXapian,
1436 lShouldAddPORInSQLDB, lLogFilename, lCommandStr);
1443 std::ofstream logOutputFile;
1445 logOutputFile.open (lLogFilename.c_str());
1446 logOutputFile.clear();
1455 lDBType, lSQLDBConnStr,
1458 lShouldIndexPORInXapian,
1459 lShouldAddPORInSQLDB);
1465 if (lCommandStr.empty() ==
false) {
1474 for (TokenList_T::const_iterator itCommand = lCommandLineList.begin();
1475 itCommand != lCommandLineList.end()
1477 const std::string& lSingleCommandStr = *itCommand;
1481 std::cout <<
"opentrep> " << lSingleCommandStr << std::endl;
1486 SplitTokens (lSingleCommandStr, lTokenList);
1490 lNonInteractiveCommandType =
1492 lDBType, lLogFilename, lPORFilepathStr,
1493 lDeploymentNumber, lIncludeNonIATAPOR,
1494 lShouldIndexPORInXapian, lShouldAddPORInSQLDB);
1499 std::cout <<
"End of the session. Exiting." << std::endl;
1502 logOutputFile.close();
1517 std::string lUserInput;
1518 bool EndOfInput (
false);
1523 std::ostringstream oPromptStr;
1524 oPromptStr <<
"opentrep> ";
1528 lUserInput = lReader.
GetLine (oPromptStr.str(), lTokenListByReadline,
1536 std::cout << std::endl;
1544 lDBType, lLogFilename, lPORFilepathStr,
1545 lDeploymentNumber, lIncludeNonIATAPOR,
1546 lShouldIndexPORInXapian, lShouldAddPORInSQLDB);
1551 std::cout <<
"End of the session. Exiting." << std::endl;
1554 logOutputFile.close();