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);
|
||||
}
|
Reference in New Issue
Block a user