Commit 2ce5da65 authored by Bart van der Velden's avatar Bart van der Velden

Extract HandleCommandLine to its own set of files. (#66)

parent 16450630
......@@ -180,16 +180,26 @@ set(EXTRA_LIBS ${EXTRA_LIBS} utils collection)
set(EXTRA_LIBS ${EXTRA_LIBS} ${TAGLIB_LIBRARIES})
set(EXTRA_LIBS ${EXTRA_LIBS} ${Boost_LIBRARIES})
set(COMMON_SOURCES
HandleCommandLine.cpp
${PROJECT_BINARY_DIR}/src/version.cpp
)
set(COMMON_INCLUDES
version.h
HandleCommandLine.h
)
#--------------------------------------------------------------------
# Add the console application
set(CMD_SOURCES
${COMMON_SOURCES}
main.cpp
${PROJECT_BINARY_DIR}/src/version.cpp
)
set(CMD_INCLUDES
version.h
${COMMON_INCLUDES}
)
add_executable(musiccollection
......@@ -203,8 +213,8 @@ target_link_libraries(musiccollection ${EXTRA_LIBS})
# Add the test GUI application
set(GUI_SOURCES
${COMMON_SOURCES}
mainui.cpp
${PROJECT_BINARY_DIR}/src/version.cpp
ui/mainwindow.cpp
ui/about.cpp
)
......@@ -212,7 +222,7 @@ set(GUI_SOURCES
set(GUI_INCLUDES
ui/mainwindow.h
ui/about.h
version.h
${COMMON_INCLUDES}
)
set(UI
......
/*****************************************************************************
* Copyright 2014 Bart van der Velden <bart@muckingabout.eu> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*****************************************************************************/
#include "HandleCommandLine.h"
#include <boost/program_options.hpp>
#include <boost/exception/all.hpp>
#include <boost/exception/get_error_info.hpp>
#include "version.h"
using namespace std;
namespace fs = boost::filesystem;
namespace po = boost::program_options;
static const char* DefaultLogFile = "mc";
static const char* DefaultConfigFile = "musiccollection.cfg";
static const char* CopyrightNotice = "Copyright 2012-2014 Bart van der Velden";
void AddErrorMessage(string& orgMessage, const string& newMessage)
{
if (orgMessage.length() == 0)
{
orgMessage = newMessage;
}
else
{
orgMessage += "\n";
orgMessage += newMessage;
}
}
//! Parse the command line
/*! The options for this program can come from two sources: the command line and a (default)
configuration file.
--help, --h or -h : show the help. This option can only be combined with the version command
Any other command or configuration will be ignored. This option is only available from the
command line.
--version, --v pr -v: show the version. This option can only be combined with the help command.
Any other command or configuration will be ignored. This option is only available from the
command line.
--configfile: read options from the supplied configuration file. If this option is not given,
an attempt is made to read from the file musiccollection.cfg in the current directory.
Options
found in the configuration file are merged with options given on the command line.
*/
bool HandleCommandLine(
int argc,
char **argv,
vector<fs::path>& folders,
fs::path& logFile,
string& message)
{
auto retVal = true;
try
{
po::positional_options_description pod;
pod.add("folder", -1);
po::variables_map vm;
fs::path configFile(DefaultConfigFile);
// Generic options: help and version. These can only be used from the command line
po::options_description genericOptions("Generic options");
genericOptions.add_options()
("help,h", "show this help")
("version,v", "show version information")
("configfile",
po::value<fs::path>(&configFile)->default_value(DefaultConfigFile),
"the configuration file to read for other options. musiccollection.cfg is used "
"if no configuration file name is supplied");
// Configuration options: logfile and directories. These can be used both from
// the command line and a configuration file. Only one logfile is used. If a logfile is
// specified on the command line and in the configuration file, the command line option
// takes precedence. Multiple directory values from the command line and the configuration
// file are merged.
po::options_description configOptions("Configuration");
configOptions.add_options()
("logfile",
po::value<fs::path>(),
"the file to log to")
("directory",
po::value<vector<fs::path> >()->composing(),
"directory to scan. A directory can also be given without the --directory.");
po::options_description cmdLineOptions;
cmdLineOptions.add(genericOptions).add(configOptions);
try
{
po::store(po::command_line_parser(argc, argv).options(cmdLineOptions).positional(pod).run(), vm);
ifstream ifs(configFile.native());
po::store(po::parse_config_file(ifs, configOptions), vm);
po::notify(vm);
}
catch (boost::program_options::invalid_syntax& e)
{
message = "Caught an invalid_syntax exception: ";
message += e.what();
retVal = false;
}
if (vm.count("help"))
{
// Help is the only action required.
stringstream ss;
ss << cmdLineOptions;
message = ss.str();
retVal = false;
}
if (vm.count("version"))
{
// version may be asked at the same time as help, but it doesn't have to be
// The program will not continue after asking it for its version information
Version version;
stringstream ss;
ss << "MusicCollection, version: " << version.GetMajor() << "." <<
version.GetMinor() << ", git revision: " << version.GetGitSha1() << "\n";
ss << CopyrightNotice << "\n";
if (message.length() == 0)
{
message = ss.str();
}
else
{
message += "\n";
message += ss.str();
}
retVal = false;
}
if (retVal == true)
{
if (vm.count("directory") == 0)
{
stringstream ss;
ss << "Need to supply at least one directory\n";
ss << cmdLineOptions << "\n";
message == ss.str();
retVal = false;
}
else
{
cout << "Directories are: \n";
folders = vm["directory"].as< vector<fs::path> >();
for (vector<fs::path>::iterator it = folders.begin(); it != folders.end(); ++it)
{
//cout << "\t" << *it << "\n";
}
retVal = true;
}
if (vm.count("logfile") == 1)
{
logFile = vm["logfile"].as<fs::path> ();
}
else
{
logFile = DefaultLogFile;
}
}
}
catch(po::unknown_option& option)
{
stringstream ss;
ss << "Unknown option: " << option.get_option_name() << "\n";
AddErrorMessage(message, ss.str());
retVal = false;
}
catch(boost::exception&)
{
stringstream ss;
ss << "Unhandled exception: " << "\n";
ss << boost::current_exception_diagnostic_information() << "\n";
AddErrorMessage(message, ss.str());
retVal = false;
}
return retVal;
}
/*****************************************************************************
* Copyright 2014 Bart van der Velden <bart@muckingabout.eu> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*****************************************************************************/
#ifndef MUSICCOLLECTION_HANDLECOMMANDLINE_H_INCLUDED
#define MUSICCOLLECTION_HANDLECOMMANDLINE_H_INCLUDED
#include <string>
#include <vector>
#include <boost/filesystem.hpp>
//! Parse the command line
/*! The options for this program can come from two sources: the command line and a (default)
configuration file.
--help, --h or -h : show the help. This option can only be combined with the version command
Any other command or configuration will be ignored. This option is only available from the
command line.
--version, --v pr -v: show the version. This option can only be combined with the help command.
Any other command or configuration will be ignored. This option is only available from the
command line.
--configfile: read options from the supplied configuration file. If this option is not given,
an attempt is made to read from the file musiccollection.cfg in the current directory.
Options
found in the configuration file are merged with options given on the command line.
\param argc the original argc as received through main()
\param argv the original argv as received through main()
\param folders the folders that were given as argument or read from the configuration file
\param logFile the path to the logfile either as argument or read from the configuration file
\param message an error message when the function returns false
\return True if no errors occurred, otherwise false
*/
bool HandleCommandLine(
int argc,
char** argv,
std::vector<boost::filesystem::path>& folders,
boost::filesystem::path& logFile,
std::string& message);
#endif // MUSICCOLLECTION_HANDLECOMMANDLINE_H_INCLUDED
......@@ -16,7 +16,6 @@
*****************************************************************************/
#include <iostream>
#include <boost/program_options.hpp>
#include <boost/chrono.hpp>
#include <boost/locale.hpp>
......@@ -27,8 +26,10 @@
#include <boost/log/sinks/text_file_backend.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/detail/utf8_codecvt_facet.hpp>
#include "version.h"
#include "HandleCommandLine.h"
#include "scandir.h"
#include "utils.h"
#include <boost/algorithm/string.hpp>
......@@ -48,23 +49,23 @@ namespace keywords = boost::log::keywords;
namespace sinks = boost::log::sinks;
static const int Second = 1000;
static const char* DefaultLogFile = "mc";
static const char* DefaultConfigFile = "musiccollection.cfg";
static const char* CopyrightNotice = "Copyright 2012-2014 Bart van der Velden";
//! Setup logging to the given logFile
/*!
*/
void InitLogging(const string& logFile)
void InitLogging(const fs::path& logFile)
{
//fs::path ext = logFile.
fs::path logFilePattern(logFile);
logFilePattern += ".%N.log";
boost::shared_ptr<sinks::synchronous_sink<sinks::text_file_backend > > sink = logging::add_file_log
(
keywords::file_name = logFile + ".%N" + ".log",
(
keywords::file_name = logFilePattern,
keywords::open_mode = ios_base::out,
keywords::rotation_size = 10 * 1024 * 1024,
keywords::time_based_rotation = boost::log::sinks::file::rotation_at_time_point(0, 0, 0),
keywords::format = "[%TimeStamp%]: %Message%"
);
);
logging::core::get()->set_filter
(
......@@ -76,79 +77,6 @@ void InitLogging(const string& logFile)
logging::add_common_attributes();
}
// Parse the command line
bool HandleCommandLine(int argc, char **argv, vector<fs::path>& folders, string& logFile)
{
auto retVal = true;
try
{
po::positional_options_description pod;
pod.add("folder", -1);
po::variables_map vm;
po::options_description desc("Allowed options");
desc.add_options()
("help,h", "show this help")
("version,v", "show version information")
("logfile", po::value<string>(), "the file to log to")
("folder", po::value<vector<fs::path> >(), "folder to scan");
po::store(po::command_line_parser(argc, argv).options(desc).positional(pod).run(), vm);
ifstream ifs(DefaultConfigFile);
po::store(po::parse_config_file<char>(ifs, desc), vm);
po::notify(vm);
if (vm.count("help"))
{
cout << desc << "\n";
retVal = false;
}
if (vm.count("version"))
{
Version version;
cout << "MusicCollection version " << version.GetMajor() << "." <<
version.GetMinor() << "\n";
cout << CopyrightNotice << "\n";
retVal = false;
}
if (retVal == true)
{
if (vm.count("folder") == 0)
{
cout << "Need to supply at least one folder\n";
cout << desc << "\n";
retVal = false;
}
else
{
cout << "Folders are: \n";
folders = vm["folder"].as< vector<fs::path> >();
for (vector<fs::path>::iterator it = folders.begin(); it != folders.end(); ++it)
{
cout << "\t" << *it << "\n";
}
retVal = true;
}
if (vm.count("logfile") == 1)
{
logFile = vm["logfile"].as< string > ();
}
else
{
logFile = DefaultLogFile;
}
}
}
catch(po::unknown_option& option)
{
cout << "Unknown option: " << option.get_option_name() << "\n";
retVal = false;
}
return retVal;
}
// Return true if at least one of the scanners is not yet finished
bool Scanning(const vector<utils::ScanDirPtr>& dirScans)
{
......@@ -240,8 +168,9 @@ int main(int argc, char **argv)
{
int retVal = 0;
vector<fs::path> folders;
string logFile;
if (HandleCommandLine(argc, argv, folders, logFile))
fs::path logFile;
string errMsg;
if (HandleCommandLine(argc, argv, folders, logFile, errMsg))
{
InitLogging(logFile);
......@@ -292,6 +221,8 @@ int main(int argc, char **argv)
}
else
{
// Write errMsg to the console
cout << errMsg << "\n";
retVal = 1;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment