Merge pull request #36 from morphis/feature/cli-valueless-flags
Add support for command line flags without value
This commit is contained in:
commit
1d60c2f1f5
2 changed files with 68 additions and 26 deletions
|
|
@ -44,9 +44,10 @@ static constexpr const char* option = " --%1% %2%";
|
|||
void add_to_desc_for_flags(po::options_description& desc,
|
||||
const std::set<cli::Flag::Ptr>& flags) {
|
||||
for (auto flag : flags) {
|
||||
auto v = po::value<std::string>()->notifier(
|
||||
[flag](const std::string& s) { flag->notify(s); });
|
||||
desc.add_options()(flag->name().as_string().c_str(), v,
|
||||
po::value_semantic *spec = nullptr;
|
||||
flag->specify_option(spec);
|
||||
if (!spec) continue;
|
||||
desc.add_options()(flag->name().as_string().c_str(), spec,
|
||||
flag->description().as_string().c_str());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Copyright (C) 2016 Canonical, Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
|
@ -31,6 +31,8 @@
|
|||
#include "anbox/do_not_copy_or_move.h"
|
||||
#include "anbox/optional.h"
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
namespace anbox {
|
||||
namespace cli {
|
||||
|
||||
|
|
@ -76,16 +78,19 @@ typedef SizeConstrainedString<80> Description;
|
|||
/// @brief Flag models an input parameter to a command.
|
||||
class Flag : public DoNotCopyOrMove {
|
||||
public:
|
||||
typedef boost::program_options::value_semantic* Specification;
|
||||
|
||||
// Safe us some typing.
|
||||
typedef std::shared_ptr<Flag> Ptr;
|
||||
|
||||
/// @brief notify announces a new value to the flag.
|
||||
virtual void notify(const std::string& value) = 0;
|
||||
/// @brief name returns the name of the Flag.
|
||||
const Name& name() const;
|
||||
/// @brief description returns a human-readable description of the flag.
|
||||
const Description& description() const;
|
||||
|
||||
/// @brief specify the program option of the flag.
|
||||
virtual void specify_option(Specification& spec) = 0;
|
||||
|
||||
protected:
|
||||
/// @brief Flag creates a new instance, initializing name and description
|
||||
/// from the given values.
|
||||
|
|
@ -115,12 +120,15 @@ class TypedFlag : public Flag {
|
|||
/// @brief value returns the optional value associated with the flag.
|
||||
const Optional<T>& value() const { return value_; }
|
||||
|
||||
/// @brief notify tries to unwrap a value of type T from value.
|
||||
void notify(const std::string& s) override {
|
||||
std::stringstream ss{s};
|
||||
T value;
|
||||
ss >> value;
|
||||
value_ = value;
|
||||
/// @brief Option generated by specify_option tries to unwrap a value
|
||||
/// of type T from value.
|
||||
void specify_option(Flag::Specification& spec) override {
|
||||
spec = boost::program_options::value<std::string>()->notifier([&](const std::string& s) {
|
||||
std::stringstream ss{s};
|
||||
T value;
|
||||
ss >> value;
|
||||
value_ = value;
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -141,11 +149,15 @@ class TypedReferenceFlag : public Flag {
|
|||
TypedReferenceFlag(const Name& name, const Description& description, T& value)
|
||||
: Flag{name, description}, value_{value} {}
|
||||
|
||||
/// @brief notify tries to unwrap a value of type T from value,
|
||||
/// relying on operator>> to read from given string s.
|
||||
void notify(const std::string& s) override {
|
||||
std::stringstream ss{s};
|
||||
ss >> value_.get();
|
||||
/// @brief Option generated by specify_option tries to unwrap a value of type T
|
||||
/// from value, relying on operator>> to read from given string s.
|
||||
void specify_option(Flag::Specification& spec) override {
|
||||
spec = boost::program_options::value<std::string>()->notifier([&](const std::string& s) {
|
||||
std::stringstream ss{s};
|
||||
T value;
|
||||
ss >> value;
|
||||
value_ = value;
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -153,9 +165,8 @@ class TypedReferenceFlag : public Flag {
|
|||
};
|
||||
|
||||
/// @brief OptionalTypedReferenceFlag handles Optional<T> references, making
|
||||
/// sure that
|
||||
/// a value is always read on notify, even if the Optional<T> wasn't initialized
|
||||
/// previously.
|
||||
/// sure that a value is always read on notify, even if the Optional<T> wasn't
|
||||
/// initialized previously.
|
||||
template <typename T>
|
||||
class OptionalTypedReferenceFlag : public Flag {
|
||||
public:
|
||||
|
|
@ -165,18 +176,40 @@ class OptionalTypedReferenceFlag : public Flag {
|
|||
Optional<T>& value)
|
||||
: Flag{name, description}, value_{value} {}
|
||||
|
||||
/// @brief notify tries to unwrap a value of type T from value.
|
||||
void notify(const std::string& s) override {
|
||||
std::stringstream ss{s};
|
||||
T value;
|
||||
ss >> value;
|
||||
value_.get() = value;
|
||||
/// @brief Option generated by specify_option tries to unwrap a value of
|
||||
/// type T from value.
|
||||
void specify_option(Flag::Specification& spec) override {
|
||||
spec = boost::program_options::value<std::string>()->notifier([&](const std::string& s) {
|
||||
std::stringstream ss{s};
|
||||
T value;
|
||||
ss >> value;
|
||||
value_.get() = value;
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
std::reference_wrapper<Optional<T>> value_;
|
||||
};
|
||||
|
||||
/// @brief BoolSwitchFlag implements Flag, updating the given mutable reference
|
||||
/// to a boolean value.
|
||||
class BoolSwitchFlag : public Flag {
|
||||
public:
|
||||
typedef std::shared_ptr<BoolSwitchFlag> Ptr;
|
||||
|
||||
BoolSwitchFlag(const Name& name, const Description& description, bool& value)
|
||||
: Flag{name, description}, value_(value) {}
|
||||
|
||||
/// @brief Option generated by specify_option tries to unwrap a boolean
|
||||
/// value from value.
|
||||
void specify_option(Flag::Specification& spec) override {
|
||||
spec = boost::program_options::bool_switch(&value_.get());
|
||||
}
|
||||
|
||||
private:
|
||||
std::reference_wrapper<bool> value_;
|
||||
};
|
||||
|
||||
/// @brief Command abstracts an individual command available from the daemon.
|
||||
class Command : public DoNotCopyOrMove {
|
||||
public:
|
||||
|
|
@ -337,6 +370,14 @@ typename OptionalTypedReferenceFlag<T>::Ptr make_flag(const Name& name,
|
|||
return std::make_shared<OptionalTypedReferenceFlag<T>>(name, desc, value);
|
||||
}
|
||||
|
||||
/// @brief make_flag returns a flag with the given name and description,
|
||||
/// updating the given boolean value.
|
||||
inline BoolSwitchFlag::Ptr make_flag(const Name& name,
|
||||
const Description &desc,
|
||||
bool &value) {
|
||||
return std::make_shared<BoolSwitchFlag>(name, desc, value);
|
||||
}
|
||||
|
||||
} // namespace cli
|
||||
} // namespace anbox
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue