c++ - ¿Cómo implementar subcomandos usando Boost.Program_options?
boost-program-options (2)
Me gustaría implementar subcomandos en mi programa. También necesito la capacidad de tener diferentes opciones de argumentos para diferentes subcomandos. ¿Cuál es la mejor manera de hacerlo utilizando Boost.Program_options?
Los subcomandos se utilizan en programas como svn, git y apt-get.
Por ejemplo, en GIT algunos de los subcomandos disponibles son:
git status
git push
git add
git pull
Mi pregunta es básicamente la misma que la de este chico: http://boost.2283326.n4.nabble.com/subcommands-with-program-options-like-svn-command-td2585537.html
Puede quitar el nombre del subcomando de la línea de comandos usando opciones posicionales ; consulte este tutorial .
Parece que no hay ningún soporte integrado para los subcomandos: tendrá que configurar la opción allow_unregistered
en el analizador de nivel superior, encontrar el nombre del comando y luego ejecutarlo a través de un segundo analizador para obtener cualquier opción específica del subcomando.
Si entiendo el problema correctamente, desea analizar las opciones de la línea de comandos del siguiente formulario:
[--generic-option ...] cmd [--cmd-specific-option ... ]
Aquí está mi ejemplo de solución. Para mayor claridad, omitiré cualquier código de validación, pero espero que pueda ver cómo se agregaría de manera bastante simple.
En este ejemplo, tenemos el subcomando "ls" y posiblemente otros. Cada subcomando tiene algunas opciones específicas, y además hay opciones genéricas. Así que comencemos analizando las opciones genéricas y el nombre del comando.
po::options_description global("Global options");
global.add_options()
("debug", "Turn on debug output")
("command", po::value<std::string>(), "command to execute")
("subargs", po::value<std::vector<std::string> >(), "Arguments for command");
po::positional_options_description pos;
pos.add("command", 1).
add("subargs", -1);
po::variables_map vm;
po::parsed_options parsed = po::command_line_parser(argc, argv).
options(global).
positional(pos).
allow_unregistered().
run();
po::store(parsed, vm);
Observe que hemos creado una sola opción posicional para el nombre del comando y múltiples opciones posicionales para las opciones del comando.
Ahora nos bifurcamos en el nombre del comando relevante y volvemos a analizar. En lugar de pasar el argc
y el argv
originales, ahora pasamos las opciones no reconocidas, en forma de una matriz de cadenas. La función collect_unrecognized
puede proporcionar esto; todo lo que tenemos que hacer es eliminar el nombre del comando (posicional) y volver a analizar con la options_description
correspondiente.
std::string cmd = vm["command"].as<std::string>();
if (cmd == "ls")
{
// ls command has the following options:
po::options_description ls_desc("ls options");
ls_desc.add_options()
("hidden", "Show hidden files")
("path", po::value<std::string>(), "Path to list");
// Collect all the unrecognized options from the first pass. This will include the
// (positional) command name, so we need to erase that.
std::vector<std::string> opts = po::collect_unrecognized(parsed.options, po::include_positional);
opts.erase(opts.begin());
// Parse again...
po::store(po::command_line_parser(opts).options(ls_desc).run(), vm);
Tenga en cuenta que utilizamos el mismo variables_map
de variables_map
para las opciones específicas del comando que para las genéricas. A partir de esto podemos realizar las acciones relevantes.
Los fragmentos de código aquí se toman de un archivo fuente compilable que incluye algunas pruebas unitarias. Puedes encontrarlo here en la esencia. Por favor, siéntase libre de descargar y jugar con él.