]> gitweb.hamatoma.de Git - crepublib/commitdiff
dirtools sync
authorkawi <winfriedkappeler@atron.de>
Mon, 5 Jan 2015 14:25:34 +0000 (15:25 +0100)
committerkawi <winfriedkappeler@atron.de>
Mon, 5 Jan 2015 14:25:34 +0000 (15:25 +0100)
os/ReDirTools.cpp
os/ReDirTools.hpp

index 0a7e61be2eccd31f142b733c7bbb3c01caa29183..3c746dacdee29a8e0910759c4e8fa8c815c62cf6 100644 (file)
@@ -21,6 +21,7 @@ static const char* s_helpSummary[] = {
     "help          shows info about the arguments/options",
     "list          shows the meta data of the selected files",
     "statistic     shows statistics about a direcctory tree",
+    "synchronize   adapts the content of a directory tree to another",
     NULL
 };
 
@@ -69,6 +70,23 @@ const char* s_statisticExamples[] = {
     NULL
 };
 
+const char* s_syncUsage[] = {
+    "<command>:",
+    "sy(nchronize) <opts> <source1> [<source2> ...] <target>",
+    "   Synchronizes the content of a directory tree with another.",
+    "   Newer or missing files will be copied",
+    "   If a source name ends with the separator (/ in linux, \\ in win) the target",
+    "   will be completed with the basename of the source.",
+    "   Example:",
+    "   'sync home backup' copies the file home/x.txt to backup/home/x.txt",
+    "   'sync data/ backup/data2' copies the file home/x.txt to backup/data2/x.txt",
+    NULL
+};
+const char* s_syncExamples[] = {
+    "dirtool sync --basename-pattern=;*.txt;*.doc e:\\data\\ d:\\backup\\data2",
+    "dirtool sync --type=r --max-size=1G usr etc /media/backup",
+    NULL
+};
 
 /**
  * Constructor.
@@ -949,6 +967,128 @@ void ReDirBatch::createBatch(int argc, char* argv[]){
     }
 }
 
+/**
+ * creates a subdirectory (and the parent directories if neccessary.
+ *
+ * @param path      the name of the subdir to create
+ */
+void makeDirWithParents(ReByteBuffer& path, int minWidth){
+    ReByteBuffer path2(path);
+    struct stat info;
+    do {
+        path2 = path;
+        int ix = path.indexOf(ReTraverser::m_separatorStr, minWidth);
+        path2.setLength(minWidth);
+        
+    } while(false);
+}
+/**
+ * Constructor.
+ */
+ReDirSync::ReDirSync() :
+    ReDirOptions(s_syncUsage, s_syncExamples)
+{
+    m_programArgs.addBool("mustexist",
+        i18n("files which don't exist on the target will not be copied"),
+        'm', "must-exist", false);
+    addStandardFilterOptions();
+}
+
+/**
+ * Gets the arguments for the "list" command and execute this.
+ *
+ * @param argc      the number of arguments
+ * @param argav     the argument vector
+ */
+void ReDirSync::synchronize(int argc, char* argv[]){
+    ReDirEntryFilter_t filter;
+    const char* sep = ReTraverser::m_separatorStr;
+    struct stat info;
+    try {
+        time_t start = time(NULL);
+        m_programArgs.init(argc, argv);
+        ReByteBuffer buffer;
+        if (m_programArgs.getArgCount() < 2)
+            help(i18n("missing argument(s) (source / target)"));
+        ReByteBuffer target(m_programArgs.getArg(m_programArgs.getArgCount() - 1));
+        if (! target.endsWith(sep, 1))
+            target.append(sep, 1);
+        if (stat(target.str(), &info) != 0)
+            help(i18n("target does not exist: $1"), target.str());
+        else if (! S_ISDIR(info.st_mode))
+            help(i18n("target is not a directory: $1"), target.str());
+        size_t lengthTargetBase = target.length();
+        bool verbose = ! m_programArgs.getBool("quiet");
+        bool chatterMode = true;
+        setFilterFromProgramArgs(filter);
+        int64_t sumSizes = 0;
+        int files = 0;
+        int dirs = 0;
+        ReByteBuffer source;
+        ReByteBuffer targetFile;
+        int maxFileTimeDiff = 2;
+        for (int ix = 0; ix < m_programArgs.getArgCount() - 1; ix++){
+            source.set(m_programArgs.getArg(ix), -1);
+            target.setLength(lengthTargetBase);
+
+            if (stat(target.str(), &info) != 0)
+                help(i18n("source does not exist: $1"), source.str());
+            else if (! S_ISDIR(info.st_mode))
+                help(i18n("source is not a directory: $1"), source.str());
+            if (! source.endsWith(sep, 1)){
+                // the basename of the source will be appended to the target:
+                int startNode = source.rindexOf(sep, 1, 0, source.length() - 1);
+                target.append(source.str() + startNode, -1); 
+            }
+            size_t ixSourceRelative = source.length();
+            size_t ixTargetRelative = target.length();
+
+            ReTraverser traverser(source.str());
+            traverser.setMinLevel(filter.m_maxDepth);
+            traverser.setMaxLevel(filter.m_maxDepth);
+            int level;
+            ReDirStatus_t* entry;
+            ReByteBuffer line;
+            while( (entry = traverser.nextFile(level, &filter)) != NULL){
+                // append the new relative path from source to target:
+                target.setLength(ixTargetRelative);
+                target.append(entry->m_path.str() + ixSourceRelative, -1);
+                if (stat(target.str(), &info) != 0)
+                    makeDirWithParents(target, ixTargetRelative);
+                targetFile.set(target).append(entry->node(), -1);
+                bool exists = stat(targetFile.str(), &info) == 0;
+                if (! exists && ! copyExistingOnly 
+                    || entry->filetimeToTime(entry->modified()) - info.st_mtime 
+                        > maxFileTimeDiff) {
+                    if (chatterMode)
+                        printf("%s%s same time\n", entry->m_path.str(), entry->node);
+                    continue;
+                } else {
+
+                if (entry->isDirectory())
+                    dirs++;
+                else{
+                    files++;
+                    sumSizes += entry->fileSize();
+                }
+                if (verbose)
+                    printf("%s\n", line.str());
+            }
+        }
+        if (verbose){
+            int duration = int(time(NULL) - start);
+#if defined __linux__
+            const char* prefix = "#";
+#elif defined __WIN32__
+            const char* prefix = "rem";
+#endif
+            printf ("%s %d dir(s) and %d file(s) with %.6f MByte in %02d:%02d sec\n",
+                prefix, dirs, files, sumSizes / 1E6, duration / 60, duration % 60);
+        }
+    } catch(ReOptionException& exc){
+        help(exc.getMessage());
+    }
+}
 
 /**
  * Gets the arguments for the "statistic" command and execute this.
index 301b000a6ffb090df5df455fc77c09f4ad23e351..7914afd43948bbdd2d67e43be2d2db73b998ecbd 100644 (file)
@@ -35,24 +35,32 @@ protected:
     int m_countCompoundUsage;
 };
 
-class ReDirList : public ReDirOptions {
+class ReDirBatch : public ReDirOptions {
 public:
-    ReDirList();
+    ReDirBatch();
 public:
-    void list(int argc, char* argv[]);
+    void createBatch(int argc, char* argv[]);
     virtual bool printOneFile(ReDirStatus_t* entry)
     { return false; }
 };
 
-class ReDirBatch : public ReDirOptions {
+class ReDirSync : public ReDirOptions {
 public:
-    ReDirBatch();
+    ReDirSync();
 public:
-    void createBatch(int argc, char* argv[]);
+    void synchronize(int argc, char* argv[]);
+};
+
+class ReDirList : public ReDirOptions {
+public:
+    ReDirList();
+public:
+    void list(int argc, char* argv[]);
     virtual bool printOneFile(ReDirStatus_t* entry)
     { return false; }
 };
 
+
 class ReDirStatisticData{
 public:
        ReDirStatisticData();