From bfffa2dd7fe96aa24441c78ca23b0bcae9e413a8 Mon Sep 17 00:00:00 2001 From: Nicholas O'Connor Date: Mon, 27 Mar 2017 22:14:41 -0700 Subject: [PATCH] remove command, which supports dry runs (so does create) --- include/cellar.hpp | 1 + include/fs.hpp | 5 ++++ src/bottles/commands.txt | 1 + src/bottles/remove.cpp | 45 +++++++++++++++++++++++++++++++++ src/cellar.cpp.cog | 5 ++++ src/fs.cpp | 54 ++++++++++++++++++++++++++++++---------- 6 files changed, 98 insertions(+), 13 deletions(-) create mode 100644 src/bottles/remove.cpp diff --git a/include/cellar.hpp b/include/cellar.hpp index 7c80176..361411a 100644 --- a/include/cellar.hpp +++ b/include/cellar.hpp @@ -13,6 +13,7 @@ namespace cellar { extern bottles::Bottle active_bottle; + extern bool dryrun; extern bool verbose; } diff --git a/include/fs.hpp b/include/fs.hpp index 071ddb9..ba2835d 100644 --- a/include/fs.hpp +++ b/include/fs.hpp @@ -9,9 +9,14 @@ using namespace std; namespace cellar { namespace fs { + typedef void (*CopyCallbackFunc)(string,string); + typedef void (*RemoveCallbackFunc)(string); extern vector listdir(string path); + extern bool recursive_copy(string, string); extern bool recursive_remove(string); + extern bool recursive_copy(string, string, CopyCallbackFunc); + extern bool recursive_remove(string, RemoveCallbackFunc); } } diff --git a/src/bottles/commands.txt b/src/bottles/commands.txt index 26d6251..c9dfbf9 100644 --- a/src/bottles/commands.txt +++ b/src/bottles/commands.txt @@ -3,3 +3,4 @@ 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 Create a new WINE bottle. +remove remove_bottle Remove a WINE bottle. diff --git a/src/bottles/remove.cpp b/src/bottles/remove.cpp new file mode 100644 index 0000000..86787ca --- /dev/null +++ b/src/bottles/remove.cpp @@ -0,0 +1,45 @@ +#include +#include +#include + +#include +#include + +#include "bottles.hpp" +#include "internal/bottles.hpp" +#include "fs.hpp" +#include "output.hpp" + +using namespace std; +using namespace cellar; + +void cellar::bottles::remove_bottle(int argc, vector argv) { + string homepath = getenv("HOME"); + string bottlechoice = argv[1]; + 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 + " doesn't exist"); + return; + } + + fs::recursive_remove(fullbottlepath); +} diff --git a/src/cellar.cpp.cog b/src/cellar.cpp.cog index 41ecac1..1a80078 100644 --- a/src/cellar.cpp.cog +++ b/src/cellar.cpp.cog @@ -28,6 +28,7 @@ using namespace std; using namespace cellar; using json = nlohmann::json; +bool cellar::dryrun; bool cellar::verbose; bottles::Bottle cellar::active_bottle; @@ -52,6 +53,9 @@ int main(int argc, char* argv[]) { 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); @@ -63,6 +67,7 @@ int main(int argc, char* argv[]) { cmdparse.parse(argc, argv); + dryrun = dryrunarg.getValue(); verbose = verbosearg.getValue(); // BULLSHIT: trying to use str.format on this string causes bizarre compiler errors diff --git a/src/fs.cpp b/src/fs.cpp index 073dfec..c98437f 100644 --- a/src/fs.cpp +++ b/src/fs.cpp @@ -5,13 +5,22 @@ #include #include +#include "cellar.hpp" #include "fs.hpp" #include "output.hpp" using namespace std; using namespace boost; +using namespace cellar; +using namespace fs; -vector cellar::fs::listdir(string path) { +// these are not necessarily the final function signatures for callbacks +// this only exists so i don't have to come back and do the ductwork for +// callback functionality later +void cbnull_copy(string src, string dst) { return; } +void cbnull_remove(string src) { return; } + +vector fs::listdir(string path) { vector result; filesystem::path cwd(path); filesystem::directory_iterator iter_end; @@ -24,42 +33,61 @@ vector cellar::fs::listdir(string path) { return result; } -bool cellar::fs::recursive_copy(string src, string dst) { +bool fs::recursive_copy(string src, string dst, CopyCallbackFunc callback) { if (!filesystem::exists(dst)) { - bool success = filesystem::create_directory(dst); - if (!success) { return false; } + if (dryrun) { output::statement("mkdir: " + dst); } + else { + bool success = filesystem::create_directory(dst); + if (!success) { return false; } + } } - for (string itemrel : cellar::fs::listdir(src)) { + for (string itemrel : 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); } + if (filesystem::is_directory(itemstat)) { recursive_copy(itemabs, targetabs, callback); } else if (filesystem::is_symlink(itemstat)) { auto symlinkpath = filesystem::read_symlink(itemabs); - filesystem::create_symlink(symlinkpath, targetabs); + if (dryrun) { output::statement("symlink: " + symlinkpath.native() + " => " + targetabs); } + else { filesystem::create_symlink(symlinkpath, targetabs); } } - else { filesystem::copy(itemabs, targetabs); } + else { + if (dryrun) { output::statement("copy: " + itemabs + " => " + targetabs); } + else { filesystem::copy(itemabs, targetabs); } + } + + callback(itemabs, targetabs); } return true; } -bool cellar::fs::recursive_remove(string target) { +bool fs::recursive_copy(string src, string dst) { return recursive_copy(src, dst, cbnull_copy); } + +bool fs::recursive_remove(string target, RemoveCallbackFunc callback) { if (!filesystem::exists(target)) { return false; } - for (string itemrel : cellar::fs::listdir(target)) { + for (string itemrel : listdir(target)) { string itemabs = target + "/" + itemrel; auto itemstat = filesystem::symlink_status(itemabs); - if (filesystem::is_directory(itemstat)) { recursive_remove(itemabs); } - else { filesystem::remove(itemabs); } + if (filesystem::is_directory(itemstat)) { recursive_remove(itemabs, callback); } + else { + if (dryrun) { output::error("rm: " + itemabs); } + else { filesystem::remove(itemabs); } + } + + callback(itemabs); } - filesystem::remove(target); + if (dryrun) { output::error("rm: " + target); } + else { filesystem::remove(target); } return true; } + +bool fs::recursive_remove(string target) { return recursive_remove(target, cbnull_remove); }