diff --git a/include/fs.hpp b/include/fs.hpp index fdb618e..097312b 100644 --- a/include/fs.hpp +++ b/include/fs.hpp @@ -10,6 +10,7 @@ using namespace std; namespace cellar { namespace fs { extern vector listdir(string path); + extern bool recursive_copy(string, string); } } diff --git a/src/bottles/commands.txt b/src/bottles/commands.txt index 6a6b55f..0379110 100644 --- a/src/bottles/commands.txt +++ b/src/bottles/commands.txt @@ -2,3 +2,4 @@ list print_bottles List all available WINE bottles. active print_active_bottle Get the currently active WINE bottle. activate switch_active_bottle Switch the active WINE bottle. config config_command Change configuration options. +create create_bottle diff --git a/src/bottles/create.cpp b/src/bottles/create.cpp new file mode 100644 index 0000000..d652802 --- /dev/null +++ b/src/bottles/create.cpp @@ -0,0 +1,79 @@ +#include +#include +#include + +#include +#include +#include + +#include "bottles.hpp" +#include "internal/bottles.hpp" +#include "internal/launch.hpp" +#include "fs.hpp" +#include "output.hpp" + +using namespace std; +using namespace cellar; + +void cellar::bottles::create_bottle(int argc, vector argv) { + TCLAP::CmdLine cmdparse("create a new WINE bottle", ' ', "", false); + + TCLAP::ValueArg namearg("n", "name", "Friendly name for the bottle.", false, "", "name"); + cmdparse.add(namearg); + + TCLAP::ValueArg descarg("d", "desc", "Short (or longer) description for the bottle.", false, "", "desc"); + cmdparse.add(descarg); + + TCLAP::UnlabeledValueArg bottlearg("bottle", "Bottle name. Follows the rules of -b.", true, "", "bottle"); + cmdparse.add(bottlearg); + + cmdparse.parse(argv); + + + string homepath = getenv("HOME"); + string bottlechoice = bottlearg.getValue(); + string fullbottlepath; + if (bottlechoice.substr(0,1) == "/" || bottlechoice.substr(0,1) == ".") { // absolute or relative path + fullbottlepath = 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); + fullbottlepath = bottlechoice; + } else { + if (bottlechoice.substr(0,6) == ".wine.") { + output::statement("tip: cellar can add the \".wine.\" prefix automatically"); + bottlechoice.replace(0,6,""); + } + + fullbottlepath = homepath + "/.wine." + bottlechoice; + } + + if (boost::filesystem::exists(fullbottlepath)) { + output::error(bottlechoice + " already exists"); + return; + } + + if (fullbottlepath != homepath + "/.wine.template") { + // all this gets skipped if we're creating the template bottle + if (boost::filesystem::exists(homepath + "/.wine.template")) { + fs::recursive_copy(homepath + "/.wine.template", fullbottlepath); + return; + } else { + output::error("no template bottle"); + return; + } + } else { + if (boost::filesystem::exists(homepath + "/.wine")) { + output::statement("using existing bottle at ~/.wine as template bottle"); + fs::recursive_copy(homepath + "/.wine", fullbottlepath); + } else { + output::statement("creating template bottle from scratch"); + setenv("WINEPREFIX", fullbottlepath.c_str(), 1); + launch::popen("wineboot -u"); + } + } +} diff --git a/src/fs.cpp b/src/fs.cpp index cff1148..9004938 100644 --- a/src/fs.cpp +++ b/src/fs.cpp @@ -9,23 +9,40 @@ #include "output.hpp" using namespace std; +using namespace boost; vector cellar::fs::listdir(string path) { vector result; - boost::filesystem::path cwd(path); - boost::filesystem::directory_iterator iter_end; + filesystem::path cwd(path); + filesystem::directory_iterator iter_end; - for (boost::filesystem::directory_iterator iter_cwd(cwd); iter_cwd != iter_end; ++iter_cwd) { - try { - string item = iter_cwd->path().filename().native(); - - result.push_back(item); - } - catch (const exception& exc) { - // TODO: better error handling - cellar::output::error("fuck"); - } + for (filesystem::directory_iterator iter_cwd(cwd); iter_cwd != iter_end; ++iter_cwd) { + string item = iter_cwd->path().filename().native(); + + result.push_back(item); } return result; } +bool cellar::fs::recursive_copy(string src, string dst) { + if (!filesystem::exists(dst)) { + bool success = filesystem::create_directory(dst); + if (!success) { return false; } + } + + for (string itemrel : cellar::fs::listdir(src)) { + string itemabs = src + "/" + itemrel; + string targetabs = dst + "/" + itemrel; + + auto itemstat = filesystem::symlink_status(itemabs); + + if (filesystem::is_directory(itemstat)) { recursive_copy(itemabs, targetabs); } + else if (filesystem::is_symlink(itemstat)) { + auto symlinkpath = filesystem::read_symlink(itemabs); + filesystem::create_symlink(symlinkpath, targetabs); + } + else { filesystem::copy(itemabs, targetabs); } + } + + return true; +}