Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AVRO-4109: [C++] Remove boost::program_options #3286

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 87 additions & 35 deletions lang/c++/impl/avrogencpp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
#include <utility>

#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>

#include "Compiler.hh"
#include "NodeImpl.hh"
Expand Down Expand Up @@ -852,8 +851,6 @@ void CodeGen::generate(const ValidSchema &schema) {
os_.flush();
}

namespace po = boost::program_options;

static string readGuard(const string &filename) {
std::ifstream ifs(filename.c_str());
string buf;
Expand All @@ -875,49 +872,104 @@ static string readGuard(const string &filename) {
return candidate;
}

struct ProgramOptions {
bool helpRequested = false;
bool versionRequested = false;
bool noUnionTypedef = false;
std::string includePrefix = "avro";
std::string nameSpace;
std::string inputFile;
std::string outputFile;
};

static void printUsage() {
std::cout << "Allowed options:\n"
<< " -h [ --help ] produce help message\n"
<< " -V [ --version ] produce version information\n"
<< " -p [ --include-prefix ] arg (=avro) prefix for include headers, - for none, default: avro\n"
<< " -U [ --no-union-typedef ] do not generate typedefs for unions in records\n"
<< " -n [ --namespace ] arg set namespace for generated code\n"
<< " -i [ --input ] arg input file\n"
<< " -o [ --output ] arg output file to generate\n";
}

static bool parseArgs(int argc, char **argv, ProgramOptions &opts) {
for (int i = 1; i < argc; ++i) {
std::string arg = argv[i];

if (arg == "-h" || arg == "--help") {
opts.helpRequested = true;
return true;
}

if (arg == "-V" || arg == "--version") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also check if there are any more arguments? For example, if someone type avrogencpp -V -U, should we just show the version or error out?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

avrogencpp -V -U prints the version without my change. So I think it is consistent with the original behavior.

opts.versionRequested = true;
return true;
}

if (arg == "-U" || arg == "--no-union-typedef") {
opts.noUnionTypedef = true;
} else if (arg == "-p" || arg == "--include-prefix") {
if (i + 1 >= argc) {
wgtmac marked this conversation as resolved.
Show resolved Hide resolved
std::cerr << "Missing value for option: " << arg << std::endl;
return false;
}
opts.includePrefix = argv[++i];
} else if (arg == "-n" || arg == "--namespace") {
if (i + 1 >= argc) {
std::cerr << "Missing value for option: " << arg << std::endl;
return false;
}
opts.nameSpace = argv[++i];
} else if (arg == "-i" || arg == "--input") {
if (i + 1 >= argc) {
std::cerr << "Missing value for option: " << arg << std::endl;
return false;
}
opts.inputFile = argv[++i];
} else if (arg == "-o" || arg == "--output") {
if (i + 1 >= argc) {
std::cerr << "Missing value for option: " << arg << std::endl;
return false;
}
opts.outputFile = argv[++i];
} else {
std::cerr << "Unknown option: " << arg << std::endl;
return false;
}
}

return true;
}

int main(int argc, char **argv) {
const string NS("namespace");
const string OUT_FILE("output");
const string IN_FILE("input");
const string INCLUDE_PREFIX("include-prefix");
const string NO_UNION_TYPEDEF("no-union-typedef");

po::options_description desc("Allowed options");
// clang-format off
desc.add_options()
("help,h", "produce help message")
("version,V", "produce version information")
("include-prefix,p", po::value<string>()->default_value("avro"), "prefix for include headers, - for none, default: avro")
("no-union-typedef,U", "do not generate typedefs for unions in records")
("namespace,n", po::value<string>(), "set namespace for generated code")
("input,i", po::value<string>(), "input file")
("output,o", po::value<string>(), "output file to generate");
// clang-format on

po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);

if (vm.count("help")) {
std::cout << desc << std::endl;
ProgramOptions opts;
if (!parseArgs(argc, argv, opts)) {
printUsage();
return 1;
}

if (opts.helpRequested) {
printUsage();
return 0;
}

if (vm.count("version")) {
if (opts.versionRequested) {
std::cout << AVRO_VERSION << std::endl;
return 0;
}

if (vm.count(IN_FILE) == 0 || vm.count(OUT_FILE) == 0) {
std::cout << desc << std::endl;
if (opts.inputFile.empty() || opts.outputFile.empty()) {
std::cerr << "Input and output files are required.\n\n";
printUsage();
return 1;
}

string ns = vm.count(NS) > 0 ? vm[NS].as<string>() : string();
string outf = vm.count(OUT_FILE) > 0 ? vm[OUT_FILE].as<string>() : string();
string inf = vm.count(IN_FILE) > 0 ? vm[IN_FILE].as<string>() : string();
string incPrefix = vm[INCLUDE_PREFIX].as<string>();
bool noUnion = vm.count(NO_UNION_TYPEDEF) != 0;
std::string ns = opts.nameSpace;
std::string outf = opts.outputFile;
std::string inf = opts.inputFile;
std::string incPrefix = opts.includePrefix;
bool noUnion = opts.noUnionTypedef;

if (incPrefix == "-") {
incPrefix.clear();
Expand Down
Loading