Diff of /trunk/wharfie/lib/makefile.py [r17] .. [r18]  Maximize  Restore

Switch to side-by-side view

--- a/trunk/wharfie/lib/makefile.py
+++ b/trunk/wharfie/lib/makefile.py
@@ -25,10 +25,36 @@
 # We use templates, which are checking their execution context,
 # to be sure, that target commands are really only executed
 # in the change root of the image.
+#
+# We use snar files to create incremental archives. Those files are targeted
+# to incremental backups, where the filestructure stays roughly the same. So
+# beside the name and timestamps of the files, it also relies on inodes.
+#
+# As we are packing and extracting the images for every step, the inodes are
+# constantly changing. As tar doesn't support to ignore inodes on incremental
+# backups, we are refreshing the backups in every step.
+#
+#          input snar    output snar    output tar
+# level 0: <none>        l0.snar        l0.tar
+# level 1: l0.snar       l1.snar        l1.tar
+# level 2: l1.snar       l2.snar        l2.tar
+#
+# When we prepare the rootfs for level 2, we have to do the following:
+#
+# - tar -xf l0.tar -g l0.snar
+#
+# - tar -xf l1.tar -g l1.snar
+# - cp l0.snar l1.snar
+# - tar -cf /dev/zero -g l1.snar .
+#
+# - tar -xf l2.tar -g l2.snar
+# - cp l1.snar l2.snar
+# - tar -cf /dev/zero -g l2.snar .
+#
+#################################################################################
 templateTrgCmd = "#!/bin/bash\n[ -f ../Wharfile ] && exit 2;\n%s\nexit \$$?\n"
 templateHostCmd = "#!/bin/bash\n[ ! -f ../Wharfile ] && exit 2;\n%s\nexit \$$?\n"
 
-archiveName = 'rootfs.tar';
 makeTargets = list();
 environment = list();
 finalTarget = list();
@@ -36,18 +62,15 @@
 #
 # Write a Makefile
 #
-def write_makefile(filename, dry_run, installpath='.'):
+def write_makefile(filename, dry_run, installpath='.', incremental=False):
+    backup_levels=list()
     f = open(filename, 'w');
     # write header
     f.write("ifneq (${VERBOSE},y)\n")
     f.write("Q=@\n")
     f.write("endif\n")
     f.write("\n")
-    f.write("OUTPUT_FILE=%s\n" % archiveName)
-    f.write("%s: %s\n" % (archiveName, "".join(finalTarget)));
-    f.write("\tcp $< $@\n");
-    f.write("\n");
-
+    f.write("all: %s\n\n" % (finalTarget[0]));
     
     # write all environment variables
     for env in environment:
@@ -61,7 +84,7 @@
         f.write("%s: %s\n" % (target['name'], " ".join(target['dep'])));
         # target and host commands have to extract and repack always.
         # simple commands don't do that.
-        if 'trgcmd' in target or 'hostcmd' in target:
+        if 'trgcmd' in target or 'hostcmd' in target or 'temporary' in target:
             f.write("\t${Q}-mkdir $$(basename $@ .tar)\n");
 
             if 'trgcmd' in target:
@@ -69,32 +92,53 @@
                 f.write("\t${Q}echo '******************************'\n");
                 f.write("\t${Q}echo '%s'\n" % target['comment']);
                 f.write("\t${Q}echo '******************************'\n");
-                f.write("\t${Q}(echo -e \"%s\") | tee ./$$(basename $@ .tar)/.trg.sh\n" % cmd.replace('\\n', '\\\\\\n').replace('\n', '\\n').replace('!', '"\'!\'"'));
-                f.write("\t${Q}chmod a+x ./$$(basename $@ .tar)/.trg.sh\n");
+                f.write("\t${Q}(echo -e \"%s\") | ${SUDO} tee .trg.sh\n" % cmd.replace('\\n', '\\\\\\n').replace('\n', '\\n').replace('!', '"\'!\'"'));
+                f.write("\t${Q}${SUDO} chmod a+x .trg.sh\n");
 
             if 'hostcmd' in target:
                 cmd = templateHostCmd % (target['hostcmd'].replace('$', '\\$$').replace('"', '\\"'));
                 f.write("\t${Q}echo '******************************'\n");
                 f.write("\t${Q}echo '%s'\n" % target['comment']);
                 f.write("\t${Q}echo '******************************'\n");
-                f.write("\t${Q}(echo -e \"%s\") | tee ./$$(basename $@ .tar)/.hst.sh\n" % cmd.replace('\\n', '\\\\\\\\n').replace('\n', '\\n').replace('!', '"\'!\'"'));
-                f.write("\t${Q}chmod a+x ./$$(basename $@ .tar)/.hst.sh\n");
+                f.write("\t${Q}(echo -e \"%s\") | ${SUDO} tee .hst.sh\n" % cmd.replace('\\n', '\\\\\\\\n').replace('\n', '\\n').replace('!', '"\'!\'"'));
+                f.write("\t${Q}${SUDO} chmod a+x .hst.sh\n");
 
             # start command here ...
             f.write("\t${Q}${SUDO} bash -c \"");
-        
-            f.write("cd $$(basename $@ .tar); tar -xf ../$<; "); 
+
+            # extracting from multiple backup levels
+            backup_levels.append(target["dep"][0])
+            f.write("cd $$(basename $@ .tar);")
+            lastincrement = None
+            for increment in backup_levels[-1:]:
+                if lastincrement == None:
+                    # level-0 backup
+                    f.write("[ -f ../%s.snar ]" % increment);
+                    f.write(" && tar -g ../%s.snar -xf ../%s" % (increment, increment)); 
+                    f.write(" || tar -xf ../%s;" % increment);
+                else:
+                    # level-x backup, update snar after extract
+                    f.write("tar -g ../%s.snar -xf ../%s;" % (increment, increment)); 
+
+                lastincrement = increment
+
             if not dry_run:
-                f.write("if [ -f .trg.sh ]; then chroot . ./.trg.sh || exit 1; fi; rm -f ./.trg.sh;");
-                f.write("if [ -f .hst.sh ]; then ./.hst.sh || exit 1; fi; rm -f ./.hst.sh;");
+                f.write("if [ -f ../.trg.sh ]; then mv ../.trg.sh .; chroot . ./.trg.sh || exit 1; fi; rm -f ./.trg.sh;");
+                f.write("if [ -f ../.hst.sh ]; then ../.hst.sh || exit 1; fi; rm -f ../.hst.sh;");
             if not 'temporary' in target or not target['temporary']:
+                # copy over snar file from previous level and add changes to the new one
+                f.write("[ ! -f ../$<.snar ] || cp ../$<.snar ../$@.snar;");
+            if incremental:
+                f.write("tar -g ../$@.snar -cf '../$@' .;");
+            else:
                 f.write("tar -cf '../$@' .;");
-                f.write("\"\n");
+            f.write("\"\n");
             # ... end command
             
 
             if 'temporary' in target and target['temporary']:
-                f.write("\t${Q}cp $< $@\n");
+                f.write("\t[ ! -f $< ] || cp $< $@;");
+                f.write("\t[ ! -f $<.snar ] || cp $<.snar $@.snar;\n");
 
             f.write("\t${Q}-${SUDO} rm -Rf ./$$(basename $@ .tar)\n");
         #