tahoe cp -r: add --caps-only flag, to write filecaps into local files instead of...
authorBrian Warner <warner@lothar.com>
Sun, 15 Mar 2009 23:19:58 +0000 (16:19 -0700)
committerBrian Warner <warner@lothar.com>
Sun, 15 Mar 2009 23:19:58 +0000 (16:19 -0700)
src/allmydata/scripts/cli.py
src/allmydata/scripts/tahoe_cp.py
src/allmydata/test/test_system.py

index 196a3fc07999a42ddc4fa3bbd453fcd92091f7c7..de8d6249bc9787779f03975e8c71b48c79707c81 100644 (file)
@@ -169,6 +169,9 @@ class CpOptions(VDriveOptions):
     optFlags = [
         ("recursive", "r", "Copy source directory recursively."),
         ("verbose", "v", "Be noisy about what is happening."),
+        ("caps-only", None,
+         "When copying to local files, write out filecaps instead of actual "
+         "data. (only useful for debugging and tree-comparison purposes)"),
         ]
     def parseArgs(self, *args):
         if len(args) < 2:
index 026a6cd950ff2046c64ea8b7e09487ed85796c26..797f87823df08202a166afa76c13370eae0d9a9e 100644 (file)
@@ -2,6 +2,7 @@
 import os.path
 import urllib
 import simplejson
+from cStringIO import StringIO
 from twisted.python.failure import Failure
 from allmydata.scripts.common import get_alias, escape_path, DefaultAliasMarker
 from allmydata.scripts.common_http import do_http
@@ -73,7 +74,7 @@ class LocalFileSource:
     def need_to_copy_bytes(self):
         return True
 
-    def open(self):
+    def open(self, caps_only):
         return open(self.pathname, "rb")
 
 class LocalFileTarget:
@@ -183,7 +184,9 @@ class TahoeFileSource:
             return True
         return False
 
-    def open(self):
+    def open(self, caps_only):
+        if caps_only:
+            return StringIO(self.readcap)
         url = self.nodeurl + "uri/" + urllib.quote(self.readcap)
         return GET_to_file(url)
 
@@ -435,6 +438,7 @@ class Copier:
             def progress(message):
                 print >>self.stderr, message
             self.progressfunc = progress
+        self.caps_only = options["caps-only"]
         self.cache = {}
         try:
             self.try_copy()
@@ -713,7 +717,7 @@ class Copier:
             # if the target is a local directory, this will just write the
             # bytes to disk. If it is a tahoe directory, it will upload the
             # data, and stash the new filecap for a later set_children call.
-            f = source.open()
+            f = source.open(self.caps_only)
             target.put_file(f)
             return self.announce_success("file copied")
         # otherwise we're copying tahoe to tahoe, and using immutable files,
@@ -729,7 +733,7 @@ class Copier:
             # if the target is a local directory, this will just write the
             # bytes to disk. If it is a tahoe directory, it will upload the
             # data, and stash the new filecap for a later set_children call.
-            f = source.open()
+            f = source.open(self.caps_only)
             target.put_file(name, f)
             return
         # otherwise we're copying tahoe to tahoe, and using immutable files,
@@ -753,3 +757,22 @@ class Copier:
 
 def copy(options):
     return Copier().do_copy(options)
+
+# error cases that need improvement:
+#  local-file-in-the-way
+#   touch proposed
+#   tahoe cp -r my:docs/proposed/denver.txt proposed/denver.txt
+
+# things that maybe should be errors but aren't
+#  local-dir-in-the-way
+#   mkdir denver.txt
+#   tahoe cp -r my:docs/proposed/denver.txt denver.txt
+#   (creates denver.txt/denver.txt)
+
+# error cases that look good:
+#  tahoe cp -r my:docs/missing missing
+#  disconnect servers
+#   tahoe cp -r my:docs/missing missing  -> No JSON object could be decoded
+#  tahoe-file-in-the-way (when we want to make a directory)
+#   tahoe put README my:docs
+#   tahoe cp -r docs/proposed my:docs/proposed
index e1d16a25ad5a93a2c2aba893580031aabf771ad8..f66c4e4cb478abfc33e3a334fdcfcc20943a2e17 100644 (file)
@@ -1711,6 +1711,16 @@ class SystemTest(SystemTestMixin, unittest.TestCase):
         # and copy it a second time, which ought to overwrite the same files
         d.addCallback(run, "cp", "-r", "tahoe:dir1", dn_copy)
 
+        # and again, only writing filecaps
+        dn_copy2 = os.path.join(self.basedir, "dir1-copy-capsonly")
+        d.addCallback(run, "cp", "-r", "--caps-only", "tahoe:dir1", dn_copy2)
+        def _check_capsonly((out,err)):
+            # these should all be LITs
+            x = open(os.path.join(dn_copy2, "subdir2", "rfile4")).read()
+            y = uri.from_string_filenode(x)
+            self.failUnlessEqual(y.data, "rfile4")
+        d.addCallback(_check_capsonly)
+
         # and tahoe-to-tahoe
         d.addCallback(run, "cp", "-r", "tahoe:dir1", "tahoe:dir1-copy")
         d.addCallback(run, "ls")