commit 7166d5124f93a16ad7109c39f6d61f9983114ed1
parent c03721848b2ee6646dda993951bb93c7363b81a4
Author: deurzen <m.vandeurzen@student.ru.nl>
Date: Fri, 5 Apr 2019 09:18:57 +0200
refactors code
Diffstat:
13 files changed, 361 insertions(+), 188 deletions(-)
diff --git a/Makefile b/Makefile
@@ -6,11 +6,10 @@ CXXFLAGS += -lboost_system -lboost_filesystem
OBJDIR = obj
SRCDIR = src
+TARGET = bin/$(PROJECT)
DEPS = $(OBJ_FILES:%.o=%.d)
-TARGET = bin/$(PROJECT)
-
H_FILES := $(shell find $(SRCDIR) -name '*.hh')
SRC_FILES := $(shell find $(SRCDIR) -name '*.cc')
OBJ_FILES := $(patsubst src/%.cc,obj/%.o,${SRC_FILES})
@@ -18,7 +17,7 @@ OBJ_FILES := $(patsubst src/%.cc,obj/%.o,${SRC_FILES})
all: build
install:
- install $(RELEASE) /usr/$(BIN)
+ install $(TARGET) /usr/bin/$(PROJECT)
bin:
@[ -d bin ] || mkdir bin
diff --git a/README.md b/README.md
@@ -1 +0,0 @@
-# bulkrename
diff --git a/src/bulkrename.cc b/src/bulkrename.cc
@@ -0,0 +1,32 @@
+#include "bulkrename.hh"
+
+#include <fstream>
+#include <iostream>
+
+::std::unique_ptr<bulkrename_t>
+bulkrename_t::init(const ::std::string& dir)
+{
+ return ::std::make_unique<bulkrename_t>(dir);
+}
+
+void
+bulkrename_t::setup()
+{
+ tree.populate(dir_it);
+}
+
+void
+bulkrename_t::run()
+{
+ filehandler.write_out(tree);
+
+ try {
+ filehandler.edit();
+ filehandler.read_in(tree);
+ } catch(const ::std::runtime_error& e) {
+ ::std::cerr << "bulkrename: " << e.what() << ::std::endl;
+ exit(1);
+ }
+
+ filehandler.propagate_rename(tree);
+}
diff --git a/src/bulkrename.hh b/src/bulkrename.hh
@@ -0,0 +1,31 @@
+#ifndef __BULKRENAME_BULKRENAME_GUARD__
+#define __BULKRENAME_BULKRENAME_GUARD__
+
+#include "node.hh"
+#include "file.hh"
+
+#include <filesystem>
+#include <boost/filesystem.hpp>
+#include <memory>
+
+
+class bulkrename_t
+{
+public:
+ explicit bulkrename_t(const ::std::string& dir)
+ : dir_it(dir), tree(dir)
+ {}
+
+ void setup();
+ void run();
+
+ static ::std::unique_ptr<bulkrename_t> init(const ::std::string&);
+
+private:
+ ::boost::filesystem::directory_iterator dir_it;
+ nodetree_t tree;
+ filehandler_t filehandler;
+
+};
+
+#endif//__BULKRENAME_BULKRENAME_GUARD__
diff --git a/src/file.cc b/src/file.cc
@@ -0,0 +1,74 @@
+#include "file.hh"
+
+#include <stdio.h>
+#include <sys/wait.h>
+#include <set>
+#include <unordered_map>
+
+
+void
+filehandler_t::write_out(const nodetree_t& tree)
+{
+ tree.print(out);
+ out.close();
+}
+
+void
+filehandler_t::read_in(const nodetree_t& tree)
+{
+ static ::std::unordered_map<::std::string, ::std::set<::std::string>> names_per_directory;
+
+ ::std::vector<file_ptr_t> files = tree.get_files();
+ ::std::vector<::std::string> filenames;
+
+ in.open(tmpfile.c_str());
+
+ bool conflict_found = false;
+
+ for (auto& file : files) {
+ ::std::string name;
+ ::std::getline(in, name);
+
+ if (!in)
+ throw ::std::runtime_error("amount of names does not match amount of files");
+
+ if (name.empty())
+ throw ::std::runtime_error("file name must be non-empty");
+
+ auto dirname = file->get_path().parent_path().string();
+ auto filename = file->get_path().filename().string();
+ if (names_per_directory.count(dirname)) {
+ if (names_per_directory[dirname].find(name) != names_per_directory[dirname].end())
+ conflict_found = true;
+
+ names_per_directory[dirname].insert(filename);
+ } else {
+ ::std::set<::std::string> set;
+ set.insert(filename);
+ names_per_directory[dirname] = set;
+ }
+
+ file->set_name(name);
+ }
+
+ in.close();
+
+ if (conflict_found)
+ throw ::std::runtime_error("multiple files within a directory are given the same name");
+}
+
+void
+filehandler_t::edit() const
+{
+ int ret = system((::std::string("$EDITOR ") + tmpfile).c_str());
+ if (WEXITSTATUS(ret) != 0)
+ throw ::std::runtime_error("renaming canceled");
+}
+
+void
+filehandler_t::propagate_rename(const nodetree_t& tree) const
+{
+ ::std::vector<file_ptr_t> files = tree.get_files();
+ for (auto& file : files)
+ file->rename();
+}
diff --git a/src/file.hh b/src/file.hh
@@ -0,0 +1,44 @@
+#ifndef __BULKRENAME_FILE_GUARD__
+#define __BULKRENAME_FILE_GUARD__
+
+#include "node.hh"
+
+#include <fstream>
+#include <string.h>
+#include <iostream>
+#include <string>
+#include <cstdio>
+
+
+class filehandler_t
+{
+public:
+ filehandler_t()
+ {
+ char* tmpname = strdup("/tmp/tmpfileXXXXXXXXXX");
+ mkstemp(tmpname);
+ tmpfile = tmpname;
+ free(tmpname);
+ out = ::std::ofstream(tmpfile);
+ }
+
+ ~filehandler_t()
+ {
+ out.close();
+ in.close();
+ }
+
+ void write_out(const nodetree_t&);
+ void read_in(const nodetree_t&);
+
+ void edit() const;
+ void propagate_rename(const nodetree_t&) const;
+
+private:
+ ::std::string tmpfile;
+ ::std::ifstream in;
+ ::std::ofstream out;
+
+};
+
+#endif//__BULKRENAME_FILE_GUARD__
diff --git a/src/filehandler.cc b/src/filehandler.cc
@@ -1,40 +0,0 @@
-#include "filehandler.hh"
-
-#include <cstdlib>
-#include <cstring>
-
-
-void
-FileHandler::write_out(const ::std::vector<Node*> &nodes)
-{
- for (Node* n : nodes) {
- out << n->getfile()->name() << ::std::endl;
- }
- out.close();
-}
-
-void
-FileHandler::read_in(const ::std::vector<Node*> &nodes)
-{
- in.open(tmpfile.c_str());
-
- for (Node* n : nodes) {
- ::std::string name;
- ::std::getline(in, name);
- if(!in)
- throw ::std::runtime_error("amount of new files does not match amount of old files");
-
- n->getfile()->setnewname(name);
- }
-
- in.close();
-}
-
-void
-FileHandler::rename(const ::std::vector<Node*> &nodes) const
-{
- for (Node* n : nodes) {
- File* file = n->getfile();
- if (file->valid()) file->move(n->name());
- }
-}
diff --git a/src/filehandler.hh b/src/filehandler.hh
@@ -1,34 +0,0 @@
-#ifndef __BULKRENAME_FILEHANDLER_GUARD__
-#define __BULKRENAME_FILEHANDLER_GUARD__
-
-#include "node.hh"
-
-#include <fstream>
-#include <iostream>
-#include <string>
-#include <vector>
-#include <cstdio>
-
-class FileHandler {
-public:
- FileHandler() {
- char *tmpname = strdup("/tmp/tmpfileXXXXXXXXXX");
- mkstemp(tmpname);
- out = ::std::ofstream(tmpname);
- tmpfile = tmpname;
- }
-
- ~FileHandler() { remove(tmpfile.c_str()); };
-
- void write_out(const ::std::vector<Node*>& nodes);
- void edit() const { system((::std::string("vim ")+tmpfile).c_str()); }
- void read_in(const ::std::vector<Node*>& nodes);
- void rename(const ::std::vector<Node*>& nodes) const;
-
-private:
- ::std::string tmpfile;
- ::std::ifstream in;
- ::std::ofstream out;
-};
-
-#endif//__BULKRENAME_FILEHANDLER_GUARD__
diff --git a/src/main.cc b/src/main.cc
@@ -1,30 +1,16 @@
-#include "statehandler.hh"
-#include "filehandler.hh"
+#include "bulkrename.hh"
#include <string>
-#include <boost/filesystem.hpp>
+#include <filesystem>
int
-main(int argc, char **argv)
+main(int argc, char** argv)
{
- using ::boost::filesystem::recursive_directory_iterator;
+ auto brn = bulkrename_t::init(argc > 1 ? argv[1] : ".");
- StateHandler sh;
- recursive_directory_iterator dir( (argc > 1) ? argv[1] : "." );
- sh.populate(dir);
-
- FileHandler fh;
- fh.write_out(sh.getnodes());
- fh.edit();
-
- try {
- fh.read_in(sh.getnodes());
- } catch(const ::std::runtime_error& e) {
- ::std::cerr << "bulkrename: " << e.what() << ::std::endl;
- }
-
- fh.rename(sh.getnodes());
+ brn->setup();
+ brn->run();
return 0;
}
diff --git a/src/node.cc b/src/node.cc
@@ -0,0 +1,98 @@
+#include "node.hh"
+
+void
+dir_t::populate(::boost::filesystem::directory_iterator dir_it)
+{
+ for (auto& entry : dir_it) {
+ if (::boost::filesystem::is_directory(entry)) {
+ dir_ptr_t dir = new dir_t(entry.path(), parent);
+ children.push_back(dir);
+ dir->populate(::boost::filesystem::directory_iterator(entry));
+ } else if (::boost::filesystem::is_regular_file(entry)) {
+ file_ptr_t file = new file_t(entry.path(), parent);
+ children.push_back(file);
+ }
+ }
+}
+
+
+void
+nodetree_t::populate(::boost::filesystem::directory_iterator dir_it)
+{
+ root->populate(dir_it);
+}
+
+void
+file_t::print(::std::ostream& out) const
+{
+ out << path.filename().string() << ::std::endl;
+}
+
+void
+dir_t::print(::std::ostream& out) const
+{
+ for (auto& child : children)
+ child->print(out);
+}
+
+void
+nodetree_t::print(::std::ostream& out) const
+{
+ root->print(out);
+}
+
+::std::vector<file_ptr_t>
+dir_t::file_leaves() const
+{
+ ::std::vector<file_ptr_t> files;
+ for (auto& child : children)
+ if (child->get_type() == nodetype_t::dir)
+ for (auto& file : dynamic_cast<dir_ptr_t>(child)->file_leaves())
+ files.push_back(file);
+ else
+ files.push_back(dynamic_cast<file_ptr_t>(child));
+
+ return files;
+}
+
+void
+file_t::rename() const
+{
+ if (name != new_name)
+ ::boost::filesystem::rename(path, path.parent_path().string() + "/" + new_name);
+}
+
+::std::vector<file_ptr_t>
+nodetree_t::get_files() const
+{
+ return root->file_leaves();
+}
+
+
+::std::ostream&
+operator<<(::std::ostream& out, node_ptr_t node)
+{
+ node->print(out);
+ return out;
+}
+
+::std::ostream&
+operator<<(::std::ostream& out, file_ptr_t file)
+{
+
+ return out;
+}
+
+::std::ostream&
+operator<<(::std::ostream& out, dir_ptr_t dir)
+{
+
+ return out;
+}
+
+::std::ostream&
+operator<<(::std::ostream& out, nodetree_t tree)
+{
+ tree.print(out);
+ return out;
+}
diff --git a/src/node.hh b/src/node.hh
@@ -1,69 +1,110 @@
#ifndef __BULKRENAME_NODE_GUARD__
#define __BULKRENAME_NODE_GUARD__
-#include <string>
-#include <utility>
-#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem.hpp>
+#include <fstream>
#include <iostream>
+
enum class nodetype_t
{
file,
dir
};
-class File;
-class Directory;
-class Node {
+typedef class node_t* node_ptr_t;
+
+typedef class node_t
+{
public:
- nodetype_t type() const { return t; }
- ::std::string name() const { return n; }
+ /* node_t(nodetype_t _type, node_ptr_t _parent, const ::std::string& _name) */
+ node_t(nodetype_t _type, node_ptr_t _parent, const ::boost::filesystem::path& _path)
+ : type(_type), parent(_parent), path(_path)
+ {}
- virtual const Node* fwd() const = 0;
- virtual File* getfile() = 0;
- virtual void setnewname(const ::std::string& s) = 0;
+ virtual bool has_next() const = 0;
+ virtual void print(::std::ostream& out) const = 0;
+
+ const nodetype_t get_type() const { return type; }
+ const ::boost::filesystem::path get_path() const { return path; }
protected:
- explicit Node(nodetype_t type, ::std::string s): t(type), n(::std::move(s)) {}
+ nodetype_t type;
+ node_ptr_t parent;
+ ::boost::filesystem::path path;
+ ::std::string name;
- nodetype_t t{};
- ::std::string n{};
+}* node_ptr_t;
+
+::std::ostream& operator<<(::std::ostream&, node_ptr_t);
-};
-class File: public Node {
+typedef class file_t : public node_t
+{
public:
- explicit File(const ::std::string& s): Node(nodetype_t::file, s), nn(Node::name()) {}
+ explicit file_t(const ::boost::filesystem::path& path, node_ptr_t parent)
+ : node_t(nodetype_t::file, parent, path), new_name(path.string())
+ {}
- const Node* fwd() const override { return nullptr; };
- File* getfile() override { return this; }
+ bool has_next() const override { return false; }
+ void print(::std::ostream& out) const override;
- void setnewname(const ::std::string& s) override { nn = s; }
- ::std::string getnewname() { return nn; }
- bool valid() { return nn != name(); }
+ void set_name(const ::std::string& name) { new_name = name; }
- void move(const ::std::string& prefix) const {
- ::boost::filesystem::rename(prefix + name(), prefix + nn);
- }
+ void rename() const;
private:
- ::std::string nn{};
+ ::std::string new_name;
-};
+}* file_ptr_t;
+
+::std::ostream& operator<<(::std::ostream&, file_ptr_t);
+
+
+typedef class dir_t : public node_t
+{
+public:
+ explicit dir_t(const ::boost::filesystem::path& path, node_ptr_t parent)
+ : node_t(nodetype_t::dir, parent, path)
+ {}
+
+ void populate(::boost::filesystem::directory_iterator);
+ bool has_next() const override { return !children.empty(); }
+ void print(::std::ostream& out) const override;
+
+ ::std::vector<file_ptr_t> file_leaves() const;
+
+private:
+ ::std::vector<node_ptr_t> children;
+
+}* dir_ptr_t;
-class Directory: public Node {
+::std::ostream& operator<<(::std::ostream&, dir_ptr_t);
+
+
+class nodetree_t
+{
public:
- explicit Directory(const ::std::string& s, Node& n): Node(nodetype_t::dir, s), next(&n) {}
+ explicit nodetree_t(const ::std::string& _root_name)
+ : root_name(_root_name), root(new dir_t(_root_name, nullptr))
+ {}
- const Node* fwd() const override { return next; }
- File* getfile() override { return next->getfile(); }
+ nodetree_t& operator=(const nodetree_t&) = delete;
+ nodetree_t(const nodetree_t&) = delete;
- void setnewname(const ::std::string& s) override { }
+ void populate(::boost::filesystem::directory_iterator);
+ void print(::std::ostream& out) const;
+
+ ::std::vector<file_ptr_t> get_files() const;
private:
- Node* next;
+ ::std::string root_name;
+ dir_ptr_t root;
};
+::std::ostream& operator<<(::std::ostream&, nodetree_t);
+
+
#endif//__BULKRENAME_NODE_GUARD__
diff --git a/src/statehandler.cc b/src/statehandler.cc
@@ -1,32 +0,0 @@
-#include "statehandler.hh"
-#include "node.hh"
-
-#include <iostream>
-
-
-void
-StateHandler::populate(::boost::filesystem::recursive_directory_iterator dir)
-{
- ::boost::filesystem::recursive_directory_iterator end;
- for (; dir != end; ++dir)
- if (is_regular_file(dir->path()))
- nodes.push_back(convert(dir->path()));
-}
-
-Node*
-StateHandler::convert(::boost::filesystem::path path)
-{
- ::std::string dir, file;
- dir = path.parent_path().string() + "/";
- file = path.filename().string();
-
- File* f = new File(file);
- return new Directory(dir, *f);
-}
-
-void
-StateHandler::print()
-{
- for (Node* f : nodes)
- ::std::cout << f->name() << f->fwd()->name() << ::std::endl;
-}
diff --git a/src/statehandler.hh b/src/statehandler.hh
@@ -1,25 +0,0 @@
-#ifndef __BULKRENAME_STATEHANDLER_GUARD__
-#define __BULKRENAME_STATEHANDLER_GUARD__
-
-#include <boost/filesystem/operations.hpp>
-#include "node.hh"
-
-#include <vector>
-#include <string>
-
-class StateHandler {
-public:
- StateHandler() = default;
- ~StateHandler() = default;
-
- void populate(::boost::filesystem::recursive_directory_iterator dir);
- Node* convert(::boost::filesystem::path path);
-
- void print();
- const std::vector<Node*> getnodes() const { return nodes; }
-
-private:
- std::vector<Node*> nodes;
-};
-
-#endif//__BULKRENAME_STATEHANDLER_GUARD__