// vim: filetype=cpp #include #include #include #include #include #include "config.hpp" #include "tclap/CmdLine.h" #include "nlohmann/json.hpp" #include "bottles.hpp" #include "cellar.hpp" #include "commands.hpp" #include "output.hpp" #include "version.hpp" /*[[[cog import cog with open("src/modules.txt") as modules: for module in modules: cog.outl("#include \"internal/{0}.hpp\"".format(module.strip())) ]]]*/ //[[[end]]] using namespace std; using namespace cellar; using json = nlohmann::json; bool cellar::dryrun; bool cellar::verbose; bottles::Bottle cellar::bottles::active_bottle; void cellar::print_header() { output::statement("cellar - bottle management tool for WINE connoisseurs"); output::statement(version::short_version()); } int main(int argc, char* argv[]) { output::detect_colors(); if (argc == 1) { print_header(); cout << "\n(try \"cellar help\" if you're confused)" << endl; return 0; } try { const string desc = "bottle management tool for WINE connoisseurs"; const string versionstr = version::short_version(); TCLAP::CmdLine cmdparse(desc, ' ', versionstr, false); TCLAP::ValueArg bottlearg("b", "bottle", "Use a wine bottle other than the one at ~/.wine", false, "", "bottle"); cmdparse.add(bottlearg); TCLAP::SwitchArg dryrunarg("d", "dry-run", "Doesn't actually do anything"); cmdparse.add(dryrunarg); TCLAP::SwitchArg verbosearg("v", "verbose", "Enables extra output"); cmdparse.add(verbosearg); TCLAP::UnlabeledValueArg command("command", "Specific command to run.", true, "help", "command"); cmdparse.add(command); TCLAP::UnlabeledMultiArg subargs("subargs", "Sub-arguments", false, "", "subarg"); cmdparse.add(subargs); cmdparse.parse(argc, argv); dryrun = dryrunarg.getValue(); verbose = dryrun || verbosearg.getValue(); // BULLSHIT: trying to use str.format on this string causes bizarre compiler errors /*[[[cog import cog with open("src/modules.txt") as modules: for module in modules: cog.out(""" for (auto item : commands::""" + module.strip() + """_commands()) { commands::command_map[item.first] = item.second; } """, dedent=True, trimblanklines=True) ]]]*/ //[[[end]]] bool set_environment = true; if (!bottlearg.isSet()) { // argument not passed if (getenv("WINEPREFIX")) { string env_wineprefix = getenv("WINEPREFIX"); output::warning("cellar was designed to handle WINEPREFIX for you with the -b argument"); output::warning("WINEPREFIX will be respected for consistency"); bottles::active_bottle = bottles::Bottle(env_wineprefix); } else { string homepath = getenv("HOME"); string fullbottlepath = homepath + "/.wine"; bottles::active_bottle = bottles::Bottle(fullbottlepath); } set_environment = false; } else { string bottlechoice = bottlearg.getValue(); if (bottlechoice.substr(0,1) == "/" || bottlechoice.substr(0,1) == ".") { // absolute or relative path bottles::active_bottle = bottles::Bottle(bottlechoice); } else if (bottlechoice.substr(0,1) == "~") { // "absolute" path in home directory, not expanded by the shell for some reason (i've seen some shit) // this is a naive replacement and will fail if the user tries something like ~nick/.wine // i'm figuring at that point if you're doing that, you'll also recognize if your shell // isn't actually expanding your path... bottlechoice.replace(0,1,getenv("HOME")); // or at least you'll think to use verbose mode to make sure it's loading the right directory output::warning("your shell didn't expand your given path properly, doing a naive replacement", true); bottles::active_bottle = bottles::Bottle(bottlechoice); } else { if (bottlechoice.substr(0,6) == ".wine.") { output::statement("tip: cellar can add the \".wine.\" prefix automatically"); bottlechoice.replace(0,6,""); } string homepath = getenv("HOME"); string fullbottlepath = homepath + "/.wine." + bottlechoice; bottles::active_bottle = bottles::Bottle(fullbottlepath); } } bottles::active_bottle.load_config(); if (set_environment) { output::statement("WINEPREFIX=" + bottles::active_bottle.path, true); setenv("WINEPREFIX", bottles::active_bottle.path.c_str(), 1); } string usercmd = command.getValue(); if (commands::command_map.count(usercmd) > 0) { vector subargv; stringstream sstr; sstr << "cellar "; sstr << usercmd; subargv.push_back(sstr.str()); for (auto item : subargs.getValue()) { subargv.push_back(item); } commands::command_map[usercmd](subargv.size(), subargv); } else { stringstream errstr; errstr << "invalid command: " << usercmd; output::error(errstr.str()); return 1; } return 0; } catch (TCLAP::ArgException &exc) { cerr << "Invalid argument. (" << exc.argId() << ": " << exc.error() << ")" << endl; return 1; } }