Skip to content

Commit 177afca

Browse files
Merge pull request #513 from GameTechDev/feature/ipm-cli
Feature/ipm cli
2 parents 2cbc481 + 2699601 commit 177afca

32 files changed

+848
-160
lines changed

IntelPresentMon/CommonUtilities/cli/CliFramework.cpp

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,52 @@
44
#include <vector>
55
#include <format>
66
#include <ranges>
7+
#include <memory>
78

89
namespace pmon::util::cli
910
{
10-
OptionsContainer::OptionsContainer(const char* description, const char* name) : app_{ description, name } {}
11+
void StripOptionGroupListFromHelp_(std::string& help)
12+
{
13+
const std::string kGroup = "[Option Group:";
14+
const std::string kSub = "SUBCOMMANDS:";
15+
16+
auto begin = help.begin();
17+
auto end = help.end();
18+
19+
// Find start of the first "[Option Group:"
20+
auto itStart = std::search(begin, end, kGroup.begin(), kGroup.end());
21+
if (itStart == end) return; // nothing to strip
22+
23+
// Find the first "SUBCOMMANDS:" after that
24+
auto itEnd = std::search(itStart, end, kSub.begin(), kSub.end());
25+
26+
// If not found, erase to end
27+
if (itEnd == end) {
28+
help.erase(static_cast<size_t>(itStart - begin));
29+
return;
30+
}
31+
32+
// Trim trailing newlines before the header so we don't leave a blank gap
33+
auto itTrimEnd = itEnd;
34+
while (itTrimEnd != itStart) {
35+
auto prev = itTrimEnd - 1;
36+
if (*prev == '\n' || *prev == '\r') itTrimEnd = prev;
37+
else break;
38+
}
39+
40+
help.erase(static_cast<size_t>(itStart - begin),
41+
static_cast<size_t>(itTrimEnd - itStart));
42+
}
43+
44+
OptionsContainer::OptionsContainer(const char* description, const char* name) : app_{ description, name } {
45+
struct NoGroupListFormatter : CLI::Formatter {
46+
std::string make_footer(const CLI::App* app) const override {
47+
// Suppress entirely
48+
return "";
49+
}
50+
};
51+
app_.formatter(std::make_shared<NoGroupListFormatter>());
52+
}
1153
std::string OptionsContainer::GetName() const
1254
{
1355
return app_.get_name();
@@ -26,12 +68,17 @@ namespace pmon::util::cli
2668
{
2769
activeGroup_ = name;
2870
if (name.empty()) {
29-
app_.add_option_group({})->silent();
71+
pCurrentSubcommand_->add_option_group({})->silent();
3072
}
3173
else {
32-
app_.add_option_group(std::move(name), std::move(desc));
74+
pCurrentSubcommand_->add_option_group(std::move(name), std::move(desc));
3375
}
3476
}
77+
CLI::App* OptionsContainer::AddSubcommand_(std::string name, std::string desc)
78+
{
79+
pCurrentSubcommand_ = app_.add_subcommand(std::move(name), std::move(desc));
80+
return pCurrentSubcommand_;
81+
}
3582
void OptionsContainer::RegisterElement_(OptionsElement_* pElement)
3683
{
3784
elementPtrs_.push_back(pElement);
@@ -50,6 +97,12 @@ namespace pmon::util::cli
5097
return app_.exit(e);
5198
}
5299
}
100+
std::string OptionsContainer::GetDiagnostics_() const
101+
{
102+
auto out = diagnostics_.str();
103+
StripOptionGroupListFromHelp_(out);
104+
return out;
105+
}
53106

54107
OptionsContainer::ConvertedNarrowOptions_::ConvertedNarrowOptions_(int argc, const wchar_t* const* wargv)
55108
{
@@ -74,7 +127,7 @@ namespace pmon::util::cli
74127
Flag::Flag(OptionsContainer* pParent, std::string names, std::string description)
75128
{
76129
// create the option
77-
pOption_ = pParent->app_.add_flag(std::move(names), data_, std::move(description));
130+
pOption_ = pParent->pCurrentSubcommand_->add_flag(std::move(names), data_, std::move(description));
78131
// add to active group
79132
pOption_->group(pParent->activeGroup_);
80133
// capture main name for the option (used when forwarding)

IntelPresentMon/CommonUtilities/cli/CliFramework.h

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ namespace pmon::util::cli
4040
std::vector<std::pair<std::string, std::string>> GetForwardedOptions() const;
4141
private:
4242
void AddGroup_(std::string name, std::string desc);
43+
CLI::App* AddSubcommand_(std::string name, std::string desc);
4344
void RegisterElement_(OptionsElement_* pElement);
4445
protected:
4546
// types
@@ -61,12 +62,14 @@ namespace pmon::util::cli
6162
// functions
6263
void Finalize_(int argc, const char* const* argv);
6364
int Exit_(const CLI::ParseError& e, bool captureDiagnostics);
65+
std::string GetDiagnostics_() const;
6466
// data
6567
std::ostringstream diagnostics_;
6668
std::vector<OptionsElement_*> elementPtrs_;
6769
bool finalized_ = false;
6870
std::string activeGroup_;
6971
CLI::App app_;
72+
CLI::App* pCurrentSubcommand_ = &app_;
7073
};
7174

7275
template<class T>
@@ -105,7 +108,7 @@ namespace pmon::util::cli
105108
}
106109
static std::string GetDiagnostics()
107110
{
108-
return Get_().diagnostics_.str();
111+
return Get_().GetDiagnostics_();
109112
}
110113
private:
111114
static T& Get_()
@@ -126,7 +129,7 @@ namespace pmon::util::cli
126129
data_{ defaultValue }
127130
{
128131
// create the option
129-
pOption_ = pParent->app_.add_option(std::move(names), data_, std::move(description));
132+
pOption_ = pParent->pCurrentSubcommand_->add_option(std::move(names), data_, std::move(description));
130133
// if customizer is a Validator object, add it to the option
131134
if constexpr (std::is_base_of_v<CLI::Validator, std::decay_t<U>> ) {
132135
if (customizer.get_modifying()) {
@@ -146,7 +149,7 @@ namespace pmon::util::cli
146149
data_{ defaultValue }
147150
{
148151
// create the option
149-
pOption_ = pParent->app_.add_option(std::move(names), data_, std::move(description));
152+
pOption_ = pParent->pCurrentSubcommand_->add_option(std::move(names), data_, std::move(description));
150153
OptionCommonPostCreate_(pParent);
151154
}
152155
Option(const Option&) = delete;
@@ -227,7 +230,10 @@ namespace pmon::util::cli
227230
CLI::Option* GetOption_(T& el) const { return el.pOption_; }
228231
CLI::App& GetApp_(OptionsContainer& con) const { return con.app_; }
229232
void SetForwarding_(OptionsElement_& el, bool forwarding = false) { el.forwarding_ = forwarding; }
230-
void AddGroup_(OptionsContainer& con, std::string name, std::string desc = {}) { con.AddGroup_(std::move(name), std::move(desc)); }
233+
void AddGroup_(OptionsContainer& con, std::string name, std::string desc = {}) {
234+
con.AddGroup_(std::move(name), std::move(desc)); }
235+
const CLI::App* AddSubcommand_(OptionsContainer& con, std::string name, std::string desc = {}) {
236+
return con.AddSubcommand_(std::move(name), std::move(desc)); }
231237
};
232238

233239
class MutualExclusion : RuleBase_
@@ -303,6 +309,24 @@ namespace pmon::util::cli
303309
}
304310
};
305311

312+
class Subcommand : RuleBase_
313+
{
314+
public:
315+
Subcommand(OptionsContainer* pCon, std::string name, std::string desc = {})
316+
{
317+
pSubcommand_ = AddSubcommand_(*pCon, std::move(name), std::move(desc));
318+
}
319+
bool Active() const
320+
{
321+
if (pSubcommand_) {
322+
return pSubcommand_->parsed();
323+
}
324+
return false;
325+
}
326+
private:
327+
const CLI::App* pSubcommand_ = nullptr;
328+
};
329+
306330
class SilentGroup : RuleBase_
307331
{
308332
public:

IntelPresentMon/CommonUtilities/log/BasicFileDriver.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ namespace pmon::util::log
3131
{
3232
pFormatter_ = std::move(pFormatter);
3333
}
34+
std::shared_ptr<ITextFormatter> BasicFileDriver::GetFormatter() const
35+
{
36+
return pFormatter_;
37+
}
3438
void BasicFileDriver::SetFileStrategy(std::shared_ptr<IFileStrategy> pFileStrategy)
3539
{
3640
pFileStrategy_ = std::move(pFileStrategy);

IntelPresentMon/CommonUtilities/log/BasicFileDriver.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace pmon::util::log
1212
std::shared_ptr<IFileStrategy> pFileStrategy = {});
1313
void Submit(const Entry&) override;
1414
void SetFormatter(std::shared_ptr<ITextFormatter> pFormatter) override;
15+
std::shared_ptr<ITextFormatter> GetFormatter() const override;
1516
void SetFileStrategy(std::shared_ptr<IFileStrategy> pFileStrategy);
1617
void Flush() override;
1718
private:

IntelPresentMon/CommonUtilities/log/Channel.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,23 @@ namespace pmon::util::log
4242
}
4343
}
4444
}
45+
// find in vector with tag
46+
template<typename T>
47+
std::shared_ptr<T> Find_(const std::vector<std::pair<std::string, std::shared_ptr<T>>>& vec, const std::string& tag)
48+
{
49+
if (tag.empty()) {
50+
return {};
51+
}
52+
else {
53+
using PairType = std::decay_t<decltype(vec)>::value_type;
54+
if (auto i = rn::find(vec, tag, &PairType::first); i != vec.end()) {
55+
return i->second;
56+
}
57+
else {
58+
return {};
59+
}
60+
}
61+
}
4562
// command packets that can be put on the entry queue in place of log entries
4663
// used to control the worker thread. Each packet encodes what functionality
4764
// to call in the variant visit routine
@@ -184,6 +201,25 @@ namespace pmon::util::log
184201
std::lock_guard lk{ mtx_ };
185202
AttachComponent_(std::move(pComponent), std::move(tag));
186203
}
204+
std::shared_ptr<IChannelComponent> ChannelInternal_::GetComponentBlocking(std::string tag) const
205+
{
206+
if (tag.empty()) {
207+
return {};
208+
}
209+
std::lock_guard lk{ mtx_ };
210+
// search in order driver, policy, channelObject with that priority
211+
if (auto p = Find_(driverPtrs_, tag)) {
212+
return p;
213+
}
214+
else if (auto p = Find_(policyPtrs_, tag)) {
215+
return p;
216+
}
217+
else if (auto p = Find_(objectPtrs_, tag)) {
218+
return p;
219+
}
220+
221+
return {};
222+
}
187223
void ChannelInternal_::RemoveComponentByTagBlocking(const std::string& tag)
188224
{
189225
std::lock_guard lk{ mtx_ };
@@ -275,6 +311,10 @@ namespace pmon::util::log
275311
RemoveComponentByTagBlocking(tag);
276312
}
277313
}
314+
std::shared_ptr<IChannelComponent> Channel::GetComponent(std::string tag) const
315+
{
316+
return GetComponentBlocking(std::move(tag));
317+
}
278318
void Channel::FlushEntryPointExit()
279319
{
280320
EnqueuePacketWait<FlushEntryPointPacket_>();

IntelPresentMon/CommonUtilities/log/Channel.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ namespace pmon::util::log
2929
void SignalExit();
3030
void DisableTraceResolution();
3131
void AttachComponentBlocking(std::shared_ptr<IChannelComponent>, std::string);
32+
std::shared_ptr<IChannelComponent> GetComponentBlocking(std::string) const;
3233
void RemoveComponentByTagBlocking(const std::string&);
3334
void EnqueueEntry(Entry&&);
3435
void EnqueueEntry(const Entry&);
@@ -43,7 +44,7 @@ namespace pmon::util::log
4344
void AttachComponent_(std::shared_ptr<IChannelComponent>, std::string);
4445
// data
4546
// mutex used for infrequent operations like managing components
46-
std::mutex mtx_;
47+
mutable std::mutex mtx_;
4748
bool resolvingTraces_ = true;
4849
bool exiting_ = false;
4950
std::vector<std::pair<std::string, std::shared_ptr<IDriver>>> driverPtrs_;
@@ -68,6 +69,7 @@ namespace pmon::util::log
6869
void Submit(const Entry&) noexcept override;
6970
void Flush() override;
7071
void AttachComponent(std::shared_ptr<IChannelComponent>, std::string = {}) override;
72+
std::shared_ptr<IChannelComponent> GetComponent(std::string tag) const override;
7173
void FlushEntryPointExit() override;
7274
};
7375
}

IntelPresentMon/CommonUtilities/log/IChannel.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ namespace pmon::util::log
2020
{
2121
public:
2222
virtual void AttachComponent(std::shared_ptr<IChannelComponent>, std::string = {}) = 0;
23+
virtual std::shared_ptr<IChannelComponent> GetComponent(std::string tag) const = 0;
2324
virtual void FlushEntryPointExit() = 0;
2425
};
2526
}

IntelPresentMon/CommonUtilities/log/IDriver.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@ namespace pmon::util::log
1818
{
1919
public:
2020
virtual void SetFormatter(std::shared_ptr<ITextFormatter>) = 0;
21+
virtual std::shared_ptr<ITextFormatter> GetFormatter() const = 0;
2122
};
2223
}

IntelPresentMon/CommonUtilities/log/MsvcDebugDriver.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,9 @@ namespace pmon::util::log
2222
{
2323
pFormatter_ = std::move(pFormatter);
2424
}
25+
std::shared_ptr<ITextFormatter> MsvcDebugDriver::GetFormatter() const
26+
{
27+
return pFormatter_;
28+
}
2529
void MsvcDebugDriver::Flush() {}
2630
}

IntelPresentMon/CommonUtilities/log/MsvcDebugDriver.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace pmon::util::log
1212
MsvcDebugDriver(std::shared_ptr<ITextFormatter> pFormatter = {});
1313
void Submit(const Entry&) override;
1414
void SetFormatter(std::shared_ptr<ITextFormatter> pFormatter) override;
15+
std::shared_ptr<ITextFormatter> GetFormatter() const override;
1516
void Flush() override;
1617
private:
1718
std::shared_ptr<ITextFormatter> pFormatter_;

0 commit comments

Comments
 (0)