corking, and a major refactor to accomodate it
This commit is contained in:
		@@ -11,7 +11,6 @@
 | 
			
		||||
 | 
			
		||||
#include "bottles.hpp"
 | 
			
		||||
#include "internal/bottles.hpp"
 | 
			
		||||
#include "dll.hpp"
 | 
			
		||||
#include "fs.hpp"
 | 
			
		||||
#include "output.hpp"
 | 
			
		||||
 | 
			
		||||
@@ -56,7 +55,7 @@ Bottle::Bottle(string patharg) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DLL_PUBLIC map<string, Bottle> cellar::bottles::get_bottles() {
 | 
			
		||||
map<string, Bottle> cellar::bottles::get_bottles() {
 | 
			
		||||
	map<string, Bottle> result;
 | 
			
		||||
 | 
			
		||||
	string homepath = getenv("HOME");
 | 
			
		||||
@@ -73,6 +72,31 @@ DLL_PUBLIC map<string, Bottle> cellar::bottles::get_bottles() {
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
string cellar::bottles::resolve_bottle(string bottlechoice) {
 | 
			
		||||
    string result;
 | 
			
		||||
    if (bottlechoice.substr(0,1) == "/" || bottlechoice.substr(0,1) == ".") { // absolute or relative path
 | 
			
		||||
        result = 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);
 | 
			
		||||
        result = 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;
 | 
			
		||||
        result = fullbottlepath;
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cellar::bottles::print_bottles(int argc, vector<string> argv) {
 | 
			
		||||
    map<string, Bottle> bottles = get_bottles();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,3 +4,6 @@ activate switch_active_bottle Switch the active WINE bottle.
 | 
			
		||||
config config_command Change configuration options.
 | 
			
		||||
create create_bottle Create a new WINE bottle.
 | 
			
		||||
remove remove_bottle Remove a WINE bottle.
 | 
			
		||||
cork cork_command Cork a bottle, to be "uncorked" later.
 | 
			
		||||
press press_command
 | 
			
		||||
uncork uncork_command Uncork a bottle.
 | 
			
		||||
 
 | 
			
		||||
@@ -45,6 +45,12 @@ bool Bottle::save_config() {
 | 
			
		||||
 | 
			
		||||
    ofstream configstream(jsonpath);
 | 
			
		||||
    configstream << this->config.dump(4);
 | 
			
		||||
    configstream.close();
 | 
			
		||||
 | 
			
		||||
    if (fs::exists(jsonpath + ".old")) {
 | 
			
		||||
        // at this point it should be safe to remove the old config
 | 
			
		||||
        fs::remove(jsonpath + ".old");
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										98
									
								
								src/bottles/cork.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								src/bottles/cork.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include <boost/algorithm/string/join.hpp>
 | 
			
		||||
#include <boost/filesystem/operations.hpp>
 | 
			
		||||
#include <boost/filesystem/path.hpp>
 | 
			
		||||
#include "json.hpp"
 | 
			
		||||
 | 
			
		||||
#include "bottles.hpp"
 | 
			
		||||
#include "internal/bottles.hpp"
 | 
			
		||||
#include "launch.hpp"
 | 
			
		||||
#include "internal/launch.hpp"
 | 
			
		||||
#include "fs.hpp"
 | 
			
		||||
#include "output.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
using namespace cellar;
 | 
			
		||||
using namespace cellar::bottles;
 | 
			
		||||
 | 
			
		||||
using json = nlohmann::json;
 | 
			
		||||
 | 
			
		||||
void cellar::bottles::cork(string bottlearg, bool remove) {
 | 
			
		||||
    string bottlepath = resolve_bottle(bottlearg);
 | 
			
		||||
    // ensure bottle is corkable
 | 
			
		||||
    if (!boost::filesystem::exists(bottlepath + "/cellar.json")) {
 | 
			
		||||
        output::error("cannot cork anonymous (or nonexistent) wine bottles");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    // ensure corked bottle directory exists
 | 
			
		||||
    string homedir = getenv("HOME");
 | 
			
		||||
    string datadir = homedir + "/.local/share/cellar";
 | 
			
		||||
    string corkdir = datadir + "/corked";
 | 
			
		||||
    string corkpath = corkdir + "/" + bottlearg + ".json";
 | 
			
		||||
    if (!boost::filesystem::exists(datadir)) { boost::filesystem::create_directory(datadir); }
 | 
			
		||||
    if (!boost::filesystem::exists(corkdir)) { boost::filesystem::create_directory(corkdir); }
 | 
			
		||||
 | 
			
		||||
    if (boost::filesystem::exists(corkpath)) {
 | 
			
		||||
        output::error("bottle " + bottlearg + " already corked");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    boost::filesystem::copy(bottlepath + "/cellar.json", datadir + "/corked/" + bottlearg + ".json");
 | 
			
		||||
 | 
			
		||||
    if (remove) { fs::recursive_remove(bottlepath); }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cellar::bottles::cork_command(int argc, vector<string> argv) { 
 | 
			
		||||
    if (argv[1] == "-k" || argv[1] == "--keep") { cork(argv[2], false); }
 | 
			
		||||
    else { cork(argv[1], true); }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cellar::bottles::uncork(string bottlearg) {
 | 
			
		||||
    string homedir = getenv("HOME");
 | 
			
		||||
    string datadir = homedir + "/.local/share/cellar";
 | 
			
		||||
    if (!boost::filesystem::exists(datadir + "/corked/" + bottlearg + ".json")) {
 | 
			
		||||
        output::error("no bottle named " + bottlearg + " to uncork");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    string bottlepath = resolve_bottle(bottlearg);
 | 
			
		||||
    if (boost::filesystem::exists(bottlepath)) {
 | 
			
		||||
        output::error("refusing to clobber existing bottle " + bottlearg);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    output::statement("creating wine prefix at " + bottlepath, true);
 | 
			
		||||
    setenv("WINEPREFIX", bottlepath.c_str(), 1);
 | 
			
		||||
    vector<string> createargs = {"cellar create", bottlearg};
 | 
			
		||||
    create_bottle(2, createargs);
 | 
			
		||||
    boost::filesystem::copy(datadir + "/corked/" + bottlearg + ".json", bottlepath + "/cellar.json");
 | 
			
		||||
 | 
			
		||||
    active_bottle = Bottle(bottlepath);
 | 
			
		||||
 | 
			
		||||
    if (active_bottle.config.find("winetricks") != active_bottle.config.end()) {
 | 
			
		||||
        vector<string> winetrickery = active_bottle.config.at("winetricks");
 | 
			
		||||
        output::statement("running winetricks with args: " + boost::algorithm::join(winetrickery, " "));
 | 
			
		||||
        launch::winetricks(winetrickery.size(), winetrickery);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (active_bottle.config.find("pressed") != active_bottle.config.end()) {
 | 
			
		||||
        auto presseddir = boost::filesystem::path(datadir + "/pressed");
 | 
			
		||||
        auto pressed = active_bottle.config.at("pressed");
 | 
			
		||||
        for (auto pressed_iter = pressed.begin(); pressed_iter != pressed.end(); pressed_iter++) {
 | 
			
		||||
            string exec = pressed_iter.key();
 | 
			
		||||
            vector<string> args = pressed_iter.value();
 | 
			
		||||
 | 
			
		||||
            output::statement("running pressed installer " + exec + " with arguments: " + boost::algorithm::join(args, " "), true);
 | 
			
		||||
            vector<string> subargv;
 | 
			
		||||
            subargv.push_back("wine");
 | 
			
		||||
            subargv.push_back((presseddir / exec).native());
 | 
			
		||||
            for (string arg : args) { subargv.push_back(arg); }
 | 
			
		||||
            launch::popen(subargv);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cellar::bottles::uncork_command(int argc, vector<string> argv) { uncork(argv[1]); }
 | 
			
		||||
							
								
								
									
										70
									
								
								src/bottles/press.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/bottles/press.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include <boost/filesystem/operations.hpp>
 | 
			
		||||
#include <boost/filesystem/path.hpp>
 | 
			
		||||
#include "json.hpp"
 | 
			
		||||
 | 
			
		||||
#include "bottles.hpp"
 | 
			
		||||
#include "internal/bottles.hpp"
 | 
			
		||||
#include "launch.hpp"
 | 
			
		||||
#include "internal/launch.hpp"
 | 
			
		||||
#include "fs.hpp"
 | 
			
		||||
#include "output.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
using namespace cellar;
 | 
			
		||||
using namespace cellar::bottles;
 | 
			
		||||
 | 
			
		||||
using json = nlohmann::json;
 | 
			
		||||
 | 
			
		||||
void cellar::bottles::press(string exec, vector<string> args, bool noexec) {
 | 
			
		||||
    // ensure pressed installer directory exists
 | 
			
		||||
    string homedir = getenv("HOME");
 | 
			
		||||
    string datadir = homedir + "/.local/share/cellar";
 | 
			
		||||
    string presseddir = datadir + "/pressed";
 | 
			
		||||
    if (!boost::filesystem::exists(datadir)) { boost::filesystem::create_directory(datadir); }
 | 
			
		||||
    if (!boost::filesystem::exists(presseddir)) { boost::filesystem::create_directory(presseddir); }
 | 
			
		||||
 | 
			
		||||
    string filename = boost::filesystem::path(exec).filename().native();
 | 
			
		||||
    auto pressedpath = boost::filesystem::path(presseddir);
 | 
			
		||||
    string pressedfile = (pressedpath / filename).native();
 | 
			
		||||
    if (boost::filesystem::exists(pressedfile)) {
 | 
			
		||||
        output::warning("clobbering existing version of " + filename);
 | 
			
		||||
        boost::filesystem::remove(pressedfile);
 | 
			
		||||
    }
 | 
			
		||||
    boost::filesystem::copy(exec, pressedfile);
 | 
			
		||||
 | 
			
		||||
    vector<string> argv;
 | 
			
		||||
    argv.push_back("wine");
 | 
			
		||||
    argv.push_back(pressedfile);
 | 
			
		||||
 | 
			
		||||
    if (!noexec) { launch::popen(argv); }
 | 
			
		||||
 | 
			
		||||
    if (active_bottle.config.find("pressed") == active_bottle.config.end()) {
 | 
			
		||||
        json pressed;
 | 
			
		||||
        active_bottle.config["pressed"] = pressed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    active_bottle.config["pressed"].emplace(filename, args);
 | 
			
		||||
    active_bottle.save_config();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cellar::bottles::press_command(int argc, vector<string> argv) {
 | 
			
		||||
    bool noexec = false;
 | 
			
		||||
    string exec;
 | 
			
		||||
    vector<string> subargv;
 | 
			
		||||
    int startarg = 1;
 | 
			
		||||
    if (argv[1] == "-n") {
 | 
			
		||||
        noexec = true;
 | 
			
		||||
        startarg = 2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (int curarg = startarg; curarg < argc; curarg++) {
 | 
			
		||||
        if (curarg == startarg) { exec = argv[curarg]; }
 | 
			
		||||
        else { subargv.push_back(argv[curarg]); }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    press(exec, subargv, noexec);
 | 
			
		||||
}
 | 
			
		||||
@@ -31,7 +31,7 @@ using json = nlohmann::json;
 | 
			
		||||
bool cellar::dryrun;
 | 
			
		||||
bool cellar::verbose;
 | 
			
		||||
 | 
			
		||||
bottles::Bottle cellar::active_bottle;
 | 
			
		||||
bottles::Bottle cellar::bottles::active_bottle;
 | 
			
		||||
 | 
			
		||||
void cellar::print_header() {
 | 
			
		||||
    output::statement("cellar - bottle management tool for WINE connoisseurs");
 | 
			
		||||
@@ -90,18 +90,18 @@ int main(int argc, char* argv[]) {
 | 
			
		||||
                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");
 | 
			
		||||
                active_bottle = bottles::Bottle(env_wineprefix);
 | 
			
		||||
                bottles::active_bottle = bottles::Bottle(env_wineprefix);
 | 
			
		||||
            } else {
 | 
			
		||||
                string homepath = getenv("HOME");
 | 
			
		||||
                string fullbottlepath = homepath + "/.wine";
 | 
			
		||||
                active_bottle = bottles::Bottle(fullbottlepath);
 | 
			
		||||
                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
 | 
			
		||||
                active_bottle = bottles::Bottle(bottlechoice);
 | 
			
		||||
                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
 | 
			
		||||
@@ -109,7 +109,7 @@ int main(int argc, char* argv[]) {
 | 
			
		||||
                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);
 | 
			
		||||
                active_bottle = bottles::Bottle(bottlechoice);
 | 
			
		||||
                bottles::active_bottle = bottles::Bottle(bottlechoice);
 | 
			
		||||
            } else {
 | 
			
		||||
                if (bottlechoice.substr(0,6) == ".wine.") {
 | 
			
		||||
                    output::statement("tip: cellar can add the \".wine.\" prefix automatically");
 | 
			
		||||
@@ -118,15 +118,15 @@ int main(int argc, char* argv[]) {
 | 
			
		||||
               
 | 
			
		||||
                string homepath = getenv("HOME");
 | 
			
		||||
                string fullbottlepath = homepath + "/.wine." + bottlechoice;
 | 
			
		||||
                active_bottle = bottles::Bottle(fullbottlepath);
 | 
			
		||||
                bottles::active_bottle = bottles::Bottle(fullbottlepath);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        active_bottle.load_config();
 | 
			
		||||
        bottles::active_bottle.load_config();
 | 
			
		||||
 | 
			
		||||
        if (set_environment) {
 | 
			
		||||
            output::statement("WINEPREFIX=" + active_bottle.path, true);
 | 
			
		||||
            setenv("WINEPREFIX", active_bottle.path.c_str(), 1);
 | 
			
		||||
            output::statement("WINEPREFIX=" + bottles::active_bottle.path, true);
 | 
			
		||||
            setenv("WINEPREFIX", bottles::active_bottle.path.c_str(), 1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        string usercmd = command.getValue();
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,9 @@
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include <boost/algorithm/string/join.hpp>
 | 
			
		||||
#include <boost/algorithm/string.hpp>
 | 
			
		||||
#include "subprocess.hpp"
 | 
			
		||||
 | 
			
		||||
#include "launch.hpp"
 | 
			
		||||
@@ -28,8 +29,26 @@ void cellar::launch::launch_command(int argc, vector<string> args) {
 | 
			
		||||
    launch::launch_program(args);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BULLSHIT: subprocess.hpp throws linker errors if included in multiple files
 | 
			
		||||
void cellar::launch::popen(string argv) {
 | 
			
		||||
    auto wine = subprocess::Popen(argv);
 | 
			
		||||
    wine.wait();
 | 
			
		||||
    vector<string> argvsplit;
 | 
			
		||||
    boost::algorithm::split(argvsplit, argv, boost::is_any_of(" "));
 | 
			
		||||
    string exec = argvsplit[0];
 | 
			
		||||
    vector<string> subargv;
 | 
			
		||||
    for (int curarg = 1; curarg < argvsplit.size(); curarg++) {
 | 
			
		||||
        subargv.push_back(argvsplit[curarg]);
 | 
			
		||||
    }
 | 
			
		||||
    auto subproc = subprocess::popen(exec, subargv);
 | 
			
		||||
    cout << subproc.stdout().rdbuf();
 | 
			
		||||
    cerr << subproc.stderr().rdbuf();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cellar::launch::popen(vector<string> argv) {
 | 
			
		||||
    string exec = argv[0];
 | 
			
		||||
    vector<string> subargv;
 | 
			
		||||
    for (int curarg = 1; curarg < argv.size(); curarg++) {
 | 
			
		||||
        subargv.push_back(argv[curarg]);
 | 
			
		||||
    }
 | 
			
		||||
    auto subproc = subprocess::popen(exec, subargv);
 | 
			
		||||
    cout << subproc.stdout().rdbuf();
 | 
			
		||||
    cerr << subproc.stderr().rdbuf();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,6 @@
 | 
			
		||||
//#include "subprocess.hpp"
 | 
			
		||||
 | 
			
		||||
#include "bottles.hpp"
 | 
			
		||||
#include "cellar.hpp"
 | 
			
		||||
#include "launch.hpp"
 | 
			
		||||
#include "internal/launch.hpp"
 | 
			
		||||
#include "output.hpp"
 | 
			
		||||
@@ -26,14 +25,14 @@ void cellar::launch::winetricks(int argc, vector<string> argv) {
 | 
			
		||||
    //output::statement(winetricks_str);
 | 
			
		||||
    launch::popen(winetricks_str);
 | 
			
		||||
 | 
			
		||||
    if (cellar::active_bottle.config.find("winetricks") == cellar::active_bottle.config.end()) {
 | 
			
		||||
        cellar::active_bottle.config.emplace("winetricks", vector<string>());
 | 
			
		||||
    if (bottles::active_bottle.config.find("winetricks") == bottles::active_bottle.config.end()) {
 | 
			
		||||
        bottles::active_bottle.config.emplace("winetricks", vector<string>());
 | 
			
		||||
    }
 | 
			
		||||
    for (string winetrick : winetricks_argv) {
 | 
			
		||||
        if (winetrick == "winetricks") { continue; }
 | 
			
		||||
        else if (winetrick.substr(0,1) == "-") { continue; } // opts don't get saved
 | 
			
		||||
        else { cellar::active_bottle.config["winetricks"].push_back(winetrick); }
 | 
			
		||||
        else { bottles::active_bottle.config["winetricks"].push_back(winetrick); }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    cellar::active_bottle.save_config();
 | 
			
		||||
    bottles::active_bottle.save_config();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user