Skip to content

Commit

Permalink
Refactor of command line argument parsing to single file (#388)
Browse files Browse the repository at this point in the history
Now command line parsing is broken down into a shared module so
it can be reused across samples. This makes samples smaller and
reduces bloat.

Commit log:
* Initial work on simplifying command line parsing
* Continued work on simplifying command line parsing
* Reformatted samples with, hopefully, the correct clang format setting this times
* Another attempt at fixing clang format issues
* Adjustments to CommandLineUtils and samples to allow building on Windows and Linux
* Adjusted secure_tunnel sample to use AWS String instead of std string
* Remove commented out namespace usage in secure_tunnel sample
* Adjusted samples command line parser to show input type for commands
* Minor command line parsing format fixes
* Adjusted based on review feedback
* Minor formatting fix
* Removed const in main function in samples
* Clang format fixes
* Added additional command groups
* Renamed AddCommonX509Commands utility function
  • Loading branch information
TwistedTwigleg authored Mar 14, 2022
1 parent a245b31 commit cc6e330
Show file tree
Hide file tree
Showing 22 changed files with 675 additions and 811 deletions.
2 changes: 2 additions & 0 deletions samples/greengrass/basic_discovery/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ project(basic-discovery CXX)

file(GLOB SRC_FILES
"*.cpp"
"../../utils/CommandLineUtils.cpp"
"../../utils/CommandLineUtils.h"
)

add_executable(${PROJECT_NAME} ${SRC_FILES})
Expand Down
109 changes: 30 additions & 79 deletions samples/greengrass/basic_discovery/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,47 +14,11 @@
#include <iostream>
#include <mutex>

#include "../../utils/CommandLineUtils.h"

using namespace Aws::Crt;
using namespace Aws::Discovery;

static void s_printHelp()
{
fprintf(stdout, "Usage:\n");
fprintf(
stdout,
"basic-discovery --region <optional: region> --cert <path to cert>"
" --key <path to key> --ca_file <optional: path to custom ca>"
" --thing_name <thing name> --topic <optional: topic> "
" --mode <optional: both|publish|subscribe> --message <optional: message to publish>"
" --proxy-host <optional: proxy host name> --proxy-port <optional: proxy port>\n\n");
fprintf(stdout, "region: the region for your green grass groups, default us-east-1\n");
fprintf(stdout, "cert: path to your client certificate in PEM format\n");
fprintf(stdout, "key: path to your key in PEM format\n");
fprintf(stdout, "ca_file: ca file to use in verifying TLS connections.\n");
fprintf(stdout, "\tIt's the path to a CA file in PEM format\n");
fprintf(stdout, "thing_name: the name of your IOT thing\n");
fprintf(stdout, "topic: targeted topic. Default is test/topic\n");
fprintf(stdout, "mode: default both\n");
fprintf(stdout, "message: message to publish. default 'Hello World'\n");
fprintf(stdout, "proxy-host: proxy host to use for discovery call. Default is to not use a proxy.\n");
fprintf(stdout, "proxy-port: proxy port to use for discovery call.\n");
}

bool s_cmdOptionExists(char **begin, char **end, const String &option)
{
return std::find(begin, end, option) != end;
}

char *s_getCmdOption(char **begin, char **end, const String &option)
{
char **itr = std::find(begin, end, option);
if (itr != end && ++itr != end)
{
return *itr;
}
return 0;
}

int main(int argc, char *argv[])
{
/************************ Setup the Lib ****************************/
Expand All @@ -75,50 +39,37 @@ int main(int argc, char *argv[])
String message("Hello World");

/*********************** Parse Arguments ***************************/
if (!(s_cmdOptionExists(argv, argv + argc, "--cert") && s_cmdOptionExists(argv, argv + argc, "--key") &&
s_cmdOptionExists(argv, argv + argc, "--thing_name")))
{
s_printHelp();
return 0;
}

certificatePath = s_getCmdOption(argv, argv + argc, "--cert");
keyPath = s_getCmdOption(argv, argv + argc, "--key");
thingName = s_getCmdOption(argv, argv + argc, "--thing_name");

if (s_cmdOptionExists(argv, argv + argc, "--ca_file"))
Utils::CommandLineUtils cmdUtils = Utils::CommandLineUtils();
cmdUtils.RegisterProgramName("basic-discovery");
cmdUtils.AddCommonMQTTCommands();
cmdUtils.AddCommonProxyCommands();
cmdUtils.AddCommonTopicMessageCommands();
cmdUtils.RemoveCommand("endpoint");
cmdUtils.RegisterCommand(
"region", "<str>", "The region for your Greengrass groups (optional, default='us-east-1').");
cmdUtils.RegisterCommand("thing_name", "<str>", "The name of your IOT thing");
cmdUtils.RegisterCommand(
"mode", "<str>", "Mode options: 'both', 'publish', or 'subscribe' (optional, default='both').");
const char **const_argv = (const char **)argv;
cmdUtils.SendArguments(const_argv, const_argv + argc);

if (cmdUtils.HasCommand("help"))
{
caFile = s_getCmdOption(argv, argv + argc, "--ca_file");
}

if (s_cmdOptionExists(argv, argv + argc, "--region"))
{
region = s_getCmdOption(argv, argv + argc, "--region");
}

if (s_cmdOptionExists(argv, argv + argc, "--topic"))
{
topic = s_getCmdOption(argv, argv + argc, "--topic");
}

if (s_cmdOptionExists(argv, argv + argc, "--mode"))
{
mode = s_getCmdOption(argv, argv + argc, "--mode");
}

if (s_cmdOptionExists(argv, argv + argc, "--message"))
{
message = s_getCmdOption(argv, argv + argc, "--message");
}

if (s_cmdOptionExists(argv, argv + argc, "--proxy-host"))
{
proxyHost = s_getCmdOption(argv, argv + argc, "--proxy-host");
cmdUtils.PrintHelp();
exit(-1);
}

if (s_cmdOptionExists(argv, argv + argc, "--proxy-port"))
certificatePath = cmdUtils.GetCommandRequired("cert");
keyPath = cmdUtils.GetCommandRequired("key");
thingName = cmdUtils.GetCommandRequired("thing_name");
caFile = cmdUtils.GetCommandOrDefault("ca_file", caFile);
region = cmdUtils.GetCommandOrDefault("region", region);
topic = cmdUtils.GetCommandOrDefault("topic", topic);
mode = cmdUtils.GetCommandOrDefault("mode", mode);
message = cmdUtils.GetCommandOrDefault("message", message);
proxyHost = cmdUtils.GetCommandOrDefault("proxy_host", proxyHost);
if (cmdUtils.HasCommand("proxy_port"))
{
String portString = s_getCmdOption(argv, argv + argc, "--proxy-port");
String portString = cmdUtils.GetCommand("proxy_port");
proxyPort = static_cast<uint16_t>(atoi(portString.c_str()));
}

Expand Down
2 changes: 2 additions & 0 deletions samples/greengrass/ipc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ project(greengrass-ipc CXX)

file(GLOB SRC_FILES
"*.cpp"
"../../utils/CommandLineUtils.cpp"
"../../utils/CommandLineUtils.h"
)

add_executable(${PROJECT_NAME} ${SRC_FILES})
Expand Down
47 changes: 12 additions & 35 deletions samples/greengrass/ipc/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,14 @@

#include <aws/greengrass/GreengrassCoreIpcClient.h>

#include "../../utils/CommandLineUtils.h"

using namespace Aws::Crt;
using namespace Aws::Greengrass;

static void s_printHelp()
{
fprintf(stdout, "Usage:\n");
fprintf(stdout, "greengrass-ipc --topic <optional: topic> --message <optional: message to publish>\n\n");
fprintf(stdout, "topic: targeted topic. Default is test/topic\n");
fprintf(stdout, "message: message to publish. default 'Hello World'\n");
}

/* Used to check that the publish has been received so that the demo can exit successfully. */
static std::atomic_bool s_publishReceived(false);

bool s_cmdOptionExists(char **begin, char **end, const String &option)
{
return std::find(begin, end, option) != end;
}

char *s_getCmdOption(char **begin, char **end, const String &option)
{
char **itr = std::find(begin, end, option);
if (itr != end && ++itr != end)
{
return *itr;
}
return 0;
}

int main(int argc, char *argv[])
{
/************************ Setup the Lib ****************************/
Expand All @@ -48,21 +27,19 @@ int main(int argc, char *argv[])
String message("Hello World");

/*********************** Parse Arguments ***************************/
if (s_cmdOptionExists(argv, argv + argc, "--help"))
{
s_printHelp();
return 0;
}
Utils::CommandLineUtils cmdUtils = Utils::CommandLineUtils();
cmdUtils.RegisterProgramName("greengrass-ipc");
cmdUtils.AddCommonTopicMessageCommands();
const char **const_argv = (const char **)argv;
cmdUtils.SendArguments(const_argv, const_argv + argc);

if (s_cmdOptionExists(argv, argv + argc, "--topic"))
if (cmdUtils.HasCommand("help"))
{
topic = s_getCmdOption(argv, argv + argc, "--topic");
}

if (s_cmdOptionExists(argv, argv + argc, "--message"))
{
message = s_getCmdOption(argv, argv + argc, "--message");
cmdUtils.PrintHelp();
exit(-1);
}
topic = cmdUtils.GetCommandOrDefault("topic", topic);
message = cmdUtils.GetCommandOrDefault("message", message);

/**
* Create the default ClientBootstrap, which will create the default
Expand Down
2 changes: 2 additions & 0 deletions samples/identity/fleet_provisioning/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ project(fleet-provisioning CXX)

file(GLOB SRC_FILES
"*.cpp"
"../../utils/CommandLineUtils.cpp"
"../../utils/CommandLineUtils.h"
)

add_executable(${PROJECT_NAME} ${SRC_FILES})
Expand Down
78 changes: 22 additions & 56 deletions samples/identity/fleet_provisioning/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,47 +32,13 @@
#include <string>
#include <thread>

#include "../../utils/CommandLineUtils.h"

using namespace Aws::Crt;
using namespace Aws::Iotidentity;
using namespace std::this_thread; // sleep_for, sleep_until
using namespace std::chrono; // nanoseconds, system_clock, seconds

static void s_printHelp()
{
fprintf(stdout, "Usage:\n");
fprintf(
stdout,
"fleet-provisioning --endpoint <endpoint> --ca_file <optional: path to custom ca> --cert <path to cert>"
" --key <path to key> --templateName <template name> --templateParameters <template parameters> --csr "
"<optional: path to csr> \n\n");
fprintf(stdout, "endpoint: the endpoint of the mqtt server not including a port\n");
fprintf(stdout, "cert: path to your client certificate in PEM format\n");
fprintf(stdout, "csr: path to CSR in PEM format\n");
fprintf(stdout, "key: path to your key in PEM format\n");
fprintf(
stdout,
"ca_file: Optional, if the mqtt server uses a certificate that's not already"
" in your trust store, set this.\n");
fprintf(stdout, "\tIt's the path to a CA file in PEM format\n");
fprintf(stdout, "template_name: the name of your provisioning template\n");
fprintf(stdout, "template_parameters: template parameters json\n");
}

static bool s_cmdOptionExists(char **begin, char **end, const String &option)
{
return std::find(begin, end, option) != end;
}

static char *s_getCmdOption(char **begin, char **end, const String &option)
{
char **itr = std::find(begin, end, option);
if (itr != end && ++itr != end)
{
return *itr;
}
return 0;
}

static void sleep(int sleeptime)
{
std::cout << "Sleeping for " << sleeptime << " seconds..." << std::endl;
Expand Down Expand Up @@ -110,29 +76,29 @@ int main(int argc, char *argv[])
apiHandle.InitializeLogging(Aws::Crt::LogLevel::Trace, stderr);

/*********************** Parse Arguments ***************************/
if (!(s_cmdOptionExists(argv, argv + argc, "--endpoint") && s_cmdOptionExists(argv, argv + argc, "--cert") &&
s_cmdOptionExists(argv, argv + argc, "--key") && s_cmdOptionExists(argv, argv + argc, "--template_name") &&
s_cmdOptionExists(argv, argv + argc, "--template_parameters")))
Utils::CommandLineUtils cmdUtils = Utils::CommandLineUtils();
cmdUtils.RegisterProgramName("fleet-provisioning");
cmdUtils.AddCommonMQTTCommands();
cmdUtils.RegisterCommand("template_name", "<str>", "The name of your provisioning template");
cmdUtils.RegisterCommand("template_parameters", "<json>", "Template parameters json");
cmdUtils.RegisterCommand("csr", "<path>", "Path to CSR in PEM format (optional)");
const char **const_argv = (const char **)argv;
cmdUtils.SendArguments(const_argv, const_argv + argc);

if (cmdUtils.HasCommand("help"))
{
s_printHelp();
return 0;
}

endpoint = s_getCmdOption(argv, argv + argc, "--endpoint");
certificatePath = s_getCmdOption(argv, argv + argc, "--cert");
keyPath = s_getCmdOption(argv, argv + argc, "--key");
templateName = s_getCmdOption(argv, argv + argc, "--template_name");
templateParameters = s_getCmdOption(argv, argv + argc, "--template_parameters");

if (s_cmdOptionExists(argv, argv + argc, "--ca_file"))
{
caFile = s_getCmdOption(argv, argv + argc, "--ca_file");
cmdUtils.PrintHelp();
exit(-1);
}

// if CSRFile provided
if (s_cmdOptionExists(argv, argv + argc, "--csr"))
endpoint = cmdUtils.GetCommandRequired("endpoint");
certificatePath = cmdUtils.GetCommandRequired("cert");
keyPath = cmdUtils.GetCommandRequired("key");
templateName = cmdUtils.GetCommandRequired("template_name");
templateParameters = cmdUtils.GetCommandRequired("template_parameters");
caFile = cmdUtils.GetCommandOrDefault("ca_file", caFile);
if (cmdUtils.HasCommand("csr"))
{
csrFile = getFileData(s_getCmdOption(argv, argv + argc, "--csr")).c_str();
csrFile = getFileData(cmdUtils.GetCommand("csr").c_str()).c_str();
}

/********************** Now Setup an Mqtt Client ******************/
Expand Down
2 changes: 2 additions & 0 deletions samples/jobs/describe_job_execution/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ project(describe-job-execution CXX)

file(GLOB SRC_FILES
"*.cpp"
"../../utils/CommandLineUtils.cpp"
"../../utils/CommandLineUtils.h"
)

add_executable(${PROJECT_NAME} ${SRC_FILES})
Expand Down
Loading

0 comments on commit cc6e330

Please sign in to comment.