--- a/src/CLIParser.h Wed Jan 16 19:31:37 2019 +0100
+++ b/src/CLIParser.h Thu Jan 17 13:14:37 2019 +0100
@@ -20,6 +20,8 @@
#include <vector>
#include <relpipe/writer/typedefs.h>
+#include <relpipe/cli/CLI.h>
+#include <relpipe/cli/RelpipeCLIException.h>
#include "Configuration.h"
#include "FileAttributeFinder.h"
@@ -31,23 +33,72 @@
using namespace relpipe::writer;
class CLIParser {
+private:
+
+ string_t readNext(std::vector<string_t> arguments, int& i) {
+ if (i < arguments.size()) return arguments[i++];
+ else throw relpipe::cli::RelpipeCLIException(L"Missing CLI argument" + (i > 0 ? (L" after " + arguments[i - 1]) : L""), relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
+ }
+
+ void addField(Configuration& c, string_t& group, string_t& name, std::vector<string_t>& aliases, std::map<string_t, string_t>& options) {
+ if (group.size()) {
+ c.fields.push_back(RequestedField(group, name, aliases, options));
+ group.clear();
+ name.clear();
+ aliases.clear();
+ options.clear();
+ }
+ }
+
public:
+ static const string_t OPTION_FILE;
+ static const string_t OPTION_XATTR;
+ static const string_t OPTION_AS;
+ static const string_t OPTION_OPTION;
+
Configuration parse(const std::vector<string_t>& arguments) {
Configuration c;
- // TODO: parse arguments
- c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_PATH_ORIGINAL));
- // c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_PATH_ABSOLUTE));
- // c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_PATH_CANONICAL));
- // c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_NAME));
- c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_TYPE));
- // c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_TYPE,{L"type_a", L"type_b"}));
- c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_SYMLINK_TARGET_TYPE));
- // c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_SYMLINK_TARGET));
- c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_SIZE));
- c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_OWNER));
- c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_GROUP));
- c.fields.push_back(RequestedField(RequestedField::GROUP_XATTR, L"user.xdg.origin.url"));
+ if (arguments.empty()) {
+ // default set of fields:
+ c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_PATH_ORIGINAL));
+ // c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_PATH_ABSOLUTE));
+ // c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_PATH_CANONICAL));
+ // c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_NAME));
+ c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_TYPE));
+ // c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_TYPE,{L"type_a", L"type_b"})); // one field → two attributes with same value
+ // c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_SYMLINK_TARGET_TYPE));
+ // c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_SYMLINK_TARGET));
+ c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_SIZE));
+ c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_OWNER));
+ c.fields.push_back(RequestedField(RequestedField::GROUP_FILE, FileAttributeFinder::FIELD_GROUP));
+ // c.fields.push_back(RequestedField(RequestedField::GROUP_XATTR, L"user.xdg.origin.url"));
+ } else {
+ string_t currentGroup;
+ string_t currentName;
+ std::vector<string_t> currentAliases;
+ std::map<string_t, string_t> currentOptions;
+
+ for (int i = 0; i < arguments.size();) {
+ string_t option = readNext(arguments, i);
+
+ if (option == CLIParser::OPTION_FILE || option == CLIParser::OPTION_XATTR) {
+ addField(c, currentGroup, currentName, currentAliases, currentOptions); // previous field
+ currentGroup = option.substr(2); // cut off --
+ currentName = readNext(arguments, i);
+ } else if (option == OPTION_AS) {
+ currentAliases.push_back(readNext(arguments, i));
+ } else if (option == OPTION_OPTION) {
+ string_t key = readNext(arguments, i);
+ string_t value = readNext(arguments, i);
+ currentOptions[key] = value;
+ } else {
+ throw relpipe::cli::RelpipeCLIException(L"Unsupported CLI option: " + option, relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
+ }
+ }
+
+ addField(c, currentGroup, currentName, currentAliases, currentOptions); // last field
+ }
return c;
}
@@ -55,6 +106,11 @@
}
};
+const string_t CLIParser::OPTION_FILE = L"--" + RequestedField::GROUP_FILE;
+const string_t CLIParser::OPTION_XATTR = L"--" + RequestedField::GROUP_XATTR;
+const string_t CLIParser::OPTION_AS = L"--as";
+const string_t CLIParser::OPTION_OPTION = L"--option";
+
}
}
}
--- a/src/relpipe-in-filesystem.cpp Wed Jan 16 19:31:37 2019 +0100
+++ b/src/relpipe-in-filesystem.cpp Thu Jan 17 13:14:37 2019 +0100
@@ -28,6 +28,7 @@
#include <relpipe/writer/TypeId.h>
#include <relpipe/cli/CLI.h>
+#include <relpipe/cli/RelpipeCLIException.h>
#include "FilesystemCommand.h"
#include "CLIParser.h"
@@ -53,6 +54,10 @@
fwprintf(stderr, L"Caught Writer exception: %ls\n", e.getMessge().c_str());
fwprintf(stderr, L"Debug: Input stream: eof=%ls, lastRead=%d\n", (cin.eof() ? L"true" : L"false"), cin.gcount());
resultCode = CLI::EXIT_CODE_DATA_ERROR;
+ } catch (RelpipeCLIException e) {
+ fwprintf(stderr, L"Caught CLI exception: %ls\n", e.getMessge().c_str());
+ fwprintf(stderr, L"Debug: Input stream: eof=%ls, lastRead=%d\n", (cin.eof() ? L"true" : L"false"), cin.gcount());
+ resultCode = e.getExitCode();
}
return resultCode;