cellar/src/core/cellar.cpp.cog

154 lines
5.7 KiB
C++

// vim: filetype=cpp
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include "config.hpp"
#include "tclap/CmdLine.h"
#include "nlohmann/json.hpp"
#include "bottles.hpp"
#include "internal/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;
}
cellar::bottles::setup_bottle_home();
try {
const string desc = "bottle management tool for WINE connoisseurs";
const string versionstr = version::short_version();
TCLAP::CmdLine cmdparse(desc, ' ', versionstr, false);
TCLAP::ValueArg<string> 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<string> command("command", "Specific command to run.", true, "help", "command");
cmdparse.add(command);
TCLAP::UnlabeledMultiArg<string> subargs("subargs", "Sub-arguments", false, "", "subarg");
cmdparse.add(subargs);
cmdparse.parse(argc, argv);
dryrun = dryrunarg.getValue();
verbose = dryrun || verbosearg.getValue();
// TODO: i'm sure stdlib has come a long way in formatting strings since this ancient hack was put in
/*[[[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 ~nicole/.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 {
string homepath = getenv("HOME");
string fullbottlepath = homepath + "/.local/share/cellar/bottles/" + 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<string> 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;
}
}