提交 1d60c2f1 编写于 作者: S Simon Fels 提交者: GitHub

Merge pull request #36 from morphis/feature/cli-valueless-flags

Add support for command line flags without value
......@@ -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());
}
}
......
/*
/*
* 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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册