bool Shell_options::custom_cmdline_handler()

in mysqlshdk/shellcore/shell_options.cc [1056:1312]


bool Shell_options::custom_cmdline_handler(Iterator *iterator) {
  const auto option = iterator->option();

  if ("--" == option) {
    if (m_shell_cli_operation)
      throw std::invalid_argument(
          "MySQL Shell can handle only one operation at a time");
    iterator->next_no_value();
    m_shell_cli_operation.reset(new shcore::cli::Shell_cli_operation());
    m_shell_cli_operation->parse(iterator->iterator());
  } else if ("--file" == option || "-f" == option) {
    handle_missing_value(iterator);

    const std::string file = iterator->value();
    iterator->next();

    storage.run_file = file;

    if (shcore::str_endswith(file, ".js")) {
      storage.initial_mode = shcore::IShell_core::Mode::JavaScript;
    } else if (shcore::str_endswith(file, ".py")) {
      storage.initial_mode = shcore::IShell_core::Mode::Python;
    } else if (shcore::str_endswith(file, ".sql")) {
      storage.initial_mode = shcore::IShell_core::Mode::SQL;
    }

    // the rest of the cmdline options, starting from here are all passed
    // through to the script
    storage.script_argv.push_back(file);
    const auto cmdline = iterator->iterator();
    while (cmdline->valid()) storage.script_argv.push_back(cmdline->get());
  } else if ("-c" == option || "--pyc" == option) {
    // Like --py -f , but with an inline command
    // Needed for backwards compatibility with python executable when
    // subprocess spawns it
#ifdef HAVE_PYTHON
    handle_missing_value(iterator);

    storage.initial_mode = shcore::IShell_core::Mode::Python;
    storage.execute_statement = iterator->value();
    iterator->next();

    // the rest of the cmdline options, starting from the next one are all
    // passed through to the script

    storage.script_argv.push_back("-c");
    const auto cmdline = iterator->iterator();
    while (cmdline->valid()) storage.script_argv.push_back(cmdline->get());
#else
    throw std::invalid_argument("Python is not supported.");
#endif
  } else if ("--pym" == option) {
#ifndef HAVE_PYTHON
    throw std::invalid_argument("Python is not supported.");
#endif
    handle_missing_value(iterator);

    const std::string module = iterator->value();
    iterator->next();

    storage.run_module = module;
    storage.initial_mode = shcore::IShell_core::Mode::Python;

    // the rest of the cmdline options, starting from here are all passed
    // through to the script
    storage.script_argv.push_back(module);
    const auto cmdline = iterator->iterator();
    while (cmdline->valid()) storage.script_argv.push_back(cmdline->get());
  } else if ("--uri" == option || '-' != option[0]) {
    handle_missing_value(iterator);

    storage.set_uri(iterator->value());

    {
      char *value = const_cast<char *>(iterator->value());
      const auto nopwd = mysqlshdk::db::uri::hide_password_in_uri(value);
      obfuscate_uri_password(nopwd, value);
    }

    iterator->next();
  } else if ("--user" == option || "--dbuser" == option || "-u" == option) {
    handle_missing_value(iterator);

    if ("--dbuser" == option) {
      // Deprecated handler is not going to be invoked, need to inform the
      // user that --dbuser should not longer be used.
      // Console is not available at this time, need to use stdout.
      m_on_warning(
          "WARNING: The --dbuser option was deprecated, "
          "please use --user instead.");
    }

    storage.connection_data.set_user(iterator->value());

    iterator->next();
  } else if ("--ssh" == option) {
    handle_missing_value(iterator);

    storage.ssh.uri = iterator->value();
    storage.ssh.uri_data =
        shcore::get_ssh_connection_options(storage.ssh.uri, false);
    if (storage.ssh.uri_data.has_password()) {
      char *value = const_cast<char *>(iterator->value());
      const auto nopwd = mysqlshdk::db::uri::hide_password_in_uri(value);
      obfuscate_uri_password(nopwd, value);
    }

    iterator->next();
  } else if ("--password" == option || "-p" == option ||
             "--dbpassword" == option || "--password1" == option) {
    // Note that in any connection attempt, password prompt will be done if
    // the password is missing.
    // The behavior of the password cmd line argument is as follows:

    // ARGUMENT           EFFECT
    // --password         forces password prompt no matter it was already
    // provided
    // --password value   forces password prompt no matter it was already
    // provided (value is not taken as password)
    // --password=        sets password to empty (password is available but
    // empty so it will not be prompted)
    // -p<value> sets the password to <value>
    // --password=<value> sets the password to <value>

    if ("--dbpassword" == option) {
      // Deprecated handler is not going to be invoked, need to inform the
      // user that --dbpassword should not longer be used.
      // Console is not available at this time, need to use stdout.
      m_on_warning(
          "WARNING: The --dbpassword option was deprecated, "
          "please use --password instead.");
    }

    if (shcore::Options::Iterator::Type::NO_VALUE == iterator->type()) {
      storage.prompt_password = true;
      iterator->next_no_value();
    } else if (shcore::Options::Iterator::Type::SEPARATE_VALUE !=
               iterator->type()) {
      // --password=value || -pvalue
      const auto value = iterator->value();
      storage.connection_data.set_mfa_password(0, value);

      const std::string stars(strlen(value), '*');

      strncpy(const_cast<char *>(value), stars.c_str(), stars.length() + 1);
      iterator->next();
      storage.prompt_password = false;
    } else {  // --password value (value is ignored)
      storage.prompt_password = true;
      iterator->next_no_value();
    }
  } else if ("--import" == option) {
    m_on_warning(
        "WARNING: The --import option was deprecated and will be removed in "
        "a future version of the MySQL Shell. Please consider using the CLI "
        "call for import-json instead.\nFor additional information: mysqlsh -- "
        "util import-json --help");

    const auto cmdline = iterator->iterator();

    storage.import_args.push_back(cmdline->get());  // omit --import

    // Gets the positional arguments for --import
    // As they define the target database object for the data
    while (cmdline->valid()) {
      // We append --import arguments until next shell option in program
      // argument list, i.e. -* or --*. Single char '-' is a --import argument.
      const char *arg = cmdline->peek();
      if (arg[0] == '-' && arg[1] != '\0') {
        break;
      }
      storage.import_args.push_back(cmdline->get());
    }

    if (storage.import_args[1] == "-") {
      // STDIN import will be handled directly in main
      // Here we store the import options
      while (cmdline->valid()) storage.import_opts.push_back(cmdline->get());
    } else {
      // Non STDIN import is handled as a CLI API call
      if (m_shell_cli_operation)
        throw std::invalid_argument(
            "MySQL Shell can handle only one operation at a time");
      m_shell_cli_operation =
          std::make_unique<shcore::cli::Shell_cli_operation>();
      m_shell_cli_operation->set_object_name("util");
      m_shell_cli_operation->set_method_name("importJson");

      m_shell_cli_operation->add_cmdline_argument(storage.import_args.at(1));

      // Parses the positional arguments to set them on the CLI operation
      switch (storage.import_args.size()) {
        case 4: {
          const std::string &target = storage.import_args.at(2);
          const std::string &column = storage.import_args.at(3);
          m_shell_cli_operation->add_cmdline_argument("--table=" + target);
          m_shell_cli_operation->add_cmdline_argument("--tableColumn=" +
                                                      column);
          break;
        }
        case 3: {
          const std::string &target = storage.import_args.at(2);
          m_shell_cli_operation->add_cmdline_argument("--collection=" + target);
          break;
        }
        case 2:
          break;
        default:
          throw std::runtime_error(
              "Usage: --import <filename> [<collection>|<table> <column>] "
              "[options]");
      }

      // All of the options above are valid
      m_shell_cli_operation->parse(cmdline);
    }
  } else if ("-m" == option) {
    bool handled = false;

    if (iterator->value()) {
      const std::string value = option + iterator->value();
      const char *replacement = nullptr;

      if ("-ma" == value) {
        handled = true;
      } else if ("-mc" == value) {
        replacement = "--mc";
      } else if ("-mx" == value) {
        replacement = "--mx";
      }

      if (nullptr != replacement) {
        handled = true;
      }

      if (handled) {
        deprecated(m_on_warning, replacement,
                   std::bind(&Shell_options::override_session_type, this, _1,
                             _2))(value, nullptr);
        iterator->next();
      }
    }

    if (!handled) {
      throw std::invalid_argument(iterator->iterator()->first() +
                                  std::string(": unknown option -m"));
    }
  } else if ("--dba-log-sql" == option) {
    m_on_warning(
        "WARNING: The --dba-log-sql option was deprecated, "
        "please use --log-sql instead.");
    return false;
  } else {
    return false;
  }
  return true;
}