<commit_before>/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2017 Couchbase, Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include "config.h"

#include <getopt.h>
#include <nlohmann/json.hpp>
#include <programs/getpass.h>
#include <programs/hostname_utils.h>
#include <protocol/connection/client_connection.h>
#include <utilities/terminate_handler.h>

#include <iostream>

/**
 * Request a stat from the server
 * @param sock socket connected to the server
 * @param key the name of the stat to receive (empty == ALL)
 * @param json if true print as json otherwise print old-style
 */
static void request_stat(MemcachedConnection& connection,
                         const std::string& key,
                         bool json,
                         bool format) {
    try {
        if (json) {
            auto stats = connection.stats(key);
            std::cout << stats.dump(format ? 1 : -1, '\t') << std::endl;
        } else {
            connection.stats(
                    [](const std::string& key,
                       const std::string& value) -> void {
                        std::cout << key << " " << value << std::endl;
                    },
                    key);
        }
    } catch (const ConnectionError& ex) {
        std::cerr << ex.what() << std::endl;
    }
}

static void usage() {
    std::cout << "Usage: mcstat [options] statkey ..." << std::endl
              << "  -h hostname[:port]  Host (and optional port number) to retrieve stats from"
              << std::endl
              << "                      (for IPv6 use: [address]:port if you'd like to specify port)"
              << std::endl
              << "  -p port      Port number" << std::endl
              << "  -u username  Username (currently synonymous with -b)"
              << std::endl
              << "  -b bucket    Bucket name" << std::endl
              << "  -P password  Password (if bucket is password-protected)"
              << std::endl
              << "  -S stdin     Read password from stdin (if bucket is password-protected)"
              << std::endl
              << "  -s           Connect to node securely (using SSL)"
              << std::endl
              << "  -j           Print result as JSON (unformatted)"
              << std::endl
              << "  -J           Print result in JSON (formatted)"
              << std::endl
              << "  -4           Use IPv4 (default)" << std::endl
              << "  -6           Use IPv6" << std::endl
              << "  -C certfile  Use certfile as a client certificate"
              << std::endl
              << "  -K keyfile  Use keyfile as a client key" << std::endl
              << "  statkey ...  Statistic(s) to request" << std::endl;
}

int main(int argc, char** argv) {
    // Make sure that we dump callstacks on the console
    install_backtrace_terminate_handler();

    int cmd;
    std::string port{"11210"};
    std::string host{"localhost"};
    std::string user{};
    std::string password{};
    std::string bucket{};
    std::string ssl_cert;
    std::string ssl_key;
    sa_family_t family = AF_UNSPEC;
    bool secure = false;
    bool json = false;
    bool format = false;

    /* Initialize the socket subsystem */
    cb_initialize_sockets();

    while ((cmd = getopt(argc, argv, "46h:p:u:b:P:SsjJC:K:")) != EOF) {
        switch (cmd) {
        case '6' :
            family = AF_INET6;
            break;
        case '4' :
            family = AF_INET;
            break;
        case 'h' :
            host.assign(optarg);
            break;
        case 'p':
            port.assign(optarg);
            break;
        case 'b' :
            bucket.assign(optarg);
            break;
        case 'u' :
            user.assign(optarg);
            break;
        case 'P':
            password.assign(optarg);
            break;
        case 'S':
            password.assign(getpass());
            break;
        case 's':
            secure = true;
            break;
        case 'J':
            format = true;
            // FALLTHROUGH
        case 'j':
            json = true;
            break;
        case 'C':
            ssl_cert.assign(optarg);
            break;
        case 'K':
            ssl_key.assign(optarg);
            break;
        default:
            usage();
            return EXIT_FAILURE;
        }
    }

    if (password.empty()) {
        const char* env_password = std::getenv("CB_PASSWORD");<commit_msg>Allow for long options for mcstat<commit_after>/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2017 Couchbase, Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include "config.h"

#include <getopt.h>
#include <nlohmann/json.hpp>
#include <programs/getpass.h>
#include <programs/hostname_utils.h>
#include <protocol/connection/client_connection.h>
#include <utilities/terminate_handler.h>

#include <iostream>

/**
 * Request a stat from the server
 * @param sock socket connected to the server
 * @param key the name of the stat to receive (empty == ALL)
 * @param json if true print as json otherwise print old-style
 */
static void request_stat(MemcachedConnection& connection,
                         const std::string& key,
                         bool json,
                         bool format) {
    try {
        if (json) {
            auto stats = connection.stats(key);
            std::cout << stats.dump(format ? 1 : -1, '\t') << std::endl;
        } else {
            connection.stats(
                    [](const std::string& key,
                       const std::string& value) -> void {
                        std::cout << key << " " << value << std::endl;
                    },
                    key);
        }
    } catch (const ConnectionError& ex) {
        std::cerr << ex.what() << std::endl;
    }
}

static void usage() {
    std::cerr << R"(Usage: mcstat [options] statkey ...

Options:

  -h or --host hostname[:port]   The host (with an optional port) to connect to
                                 (for IPv6 use: [address]:port if you'd like to
                                 specify port)
  -p or --port port              The port number to connect to
  -b or --bucket bucketname      The name of the bucket to operate on
  -u or --user username          The name of the user to authenticate as
  -P or --password password      The <PASSWORD> to use for authentication
                                 (use '-' to read from standard input)
  -s or --ssl                    Connect to the server over SSL
  -C or --ssl-cert filename      Read the SSL certificate from the specified file
  -K or --ssl-key filename       Read the SSL private key from the specified file
  -4 or --ipv4                   Connect over IPv4
  -6 or --ipv6                   Connect over IPv6
  -j or --json                   Print result as JSON (unformatted)
  -J or --json=pretty            Print result in JSON (formatted)
  --help                         This help text
  statkey ...  Statistic(s) to request
)";

    exit(EXIT_FAILURE);
}

int main(int argc, char** argv) {
    // Make sure that we dump callstacks on the console
    install_backtrace_terminate_handler();

    int cmd;
    std::string port{"11210"};
    std::string host{"localhost"};
    std::string user{};
    std::string password{};
    std::string bucket{};
    std::string ssl_cert;
    std::string ssl_key;
    sa_family_t family = AF_UNSPEC;
    bool secure = false;
    bool json = false;
    bool format = false;

    /* Initialize the socket subsystem */
    cb_initialize_sockets();

    struct option long_options[] = {
            {"ipv4", no_argument, nullptr, '4'},
            {"ipv6", no_argument, nullptr, '6'},
            {"host", required_argument, nullptr, 'h'},
            {"port", required_argument, nullptr, 'p'},
            {"bucket", required_argument, nullptr, 'b'},
            {"password", required_argument, nullptr, 'P'},
            {"user", required_argument, nullptr, 'u'},
            {"ssl", no_argument, nullptr, 's'},
            {"ssl-cert", required_argument, nullptr, 'C'},
            {"ssl-key", required_argument, nullptr, 'K'},
            {"json", optional_argument, nullptr, 'j'},
            {"help", no_argument, nullptr, 0},
            {nullptr, 0, nullptr, 0}};

    while ((cmd = getopt_long(argc,
                              argv,
                              "46h:p:u:b:P:SsjJC:K:",
                              long_options,
                              nullptr)) != EOF) {
        switch (cmd) {
        case '6' :
            family = AF_INET6;
            break;
        case '4' :
            family = AF_INET;
            break;
        case 'h' :
            host.assign(optarg);
            break;
        case 'p':
            port.assign(optarg);
            break;
        case 'b' :
            bucket.assign(optarg);
            break;
        case 'u' :
            user.assign(optarg);
            break;
        case 'P':
            password.assign(optarg);
            break;
        case 'S':
            // Deprecated and not shown in the help text
            std::cerr << "mcstat: -S is deprecated. Use \'-P -\" instead"
                      << std::endl;
            password.assign(getpass());
            break;
        case 's':
            secure = true;
            break;
        case 'J':
            format = true;
            // FALLTHROUGH
        case 'j':
            json = true;
            if (optarg && std::string{optarg} == "pretty") {
                format = true;
            }
            break;
        case 'C':
            ssl_cert.assign(optarg);
            break;
        case 'K':
            ssl_key.assign(optarg);
            break;
        default:
            usage();
            return EXIT_FAILURE;
        }
    }

    if (password == "-") {
        password.assign(getpass());
    } else if (password.empty()) {
        const char* env_password = std::getenv("CB_PASSWORD");
{'fraction_non_alphanumeric': 0.11757314665230659, 'fraction_numerical': 0.005654281098546042, 'mean_word_length': 1.6145002346316284, 'pattern_counts': {'":': 0, '<': 120, '<?xml version=': 0, '>': 20, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 5, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7556774', 'n_tokens_mistral': 3127, 'n_tokens_neox': 3040, 'n_words': 980}