def __init__(self, name, quotefn=quote_output):
TahoeError.__init__(self, "No such file or directory %s" % quotefn(name))
+class FilenameWithTrailingSlashError(TahoeError):
+ def __init__(self, name, quotefn=quote_output):
+ TahoeError.__init__(self, "source '%s' is not a directory, but ends with a slash" % quotefn(name))
+
+class WeirdSourceError(TahoeError):
+ def __init__(self, absname):
+ quoted = quote_local_unicode_path(absname)
+ TahoeError.__init__(self, "source '%s' is neither a file nor a directory, I can't handle it" % quoted)
def GET_to_file(url):
resp = do_http("GET", url)
def get_child_target(self, name):
precondition(isinstance(name, unicode), name)
+ precondition(len(name), name) # don't want ""
if self.children is None:
self.populate(recurse=False)
if name in self.children:
sources = [] # list of source objects
for ss in source_specs:
- si = self.get_source_info(ss)
+ try:
+ si = self.get_source_info(ss)
+ except FilenameWithTrailingSlashError as e:
+ self.to_stderr(str(e))
+ return 1
precondition(isinstance(si, FileSources + DirectorySources), si)
sources.append(si)
precondition(isinstance(source_spec, unicode), source_spec)
rootcap, path_utf8 = get_alias(self.aliases, source_spec, None)
path = path_utf8.decode("utf-8")
+ # any trailing slash is removed in abspath_expanduser_unicode(), so
+ # make a note of it here, to throw an error later
+ had_trailing_slash = path.endswith("/")
if rootcap == DefaultAliasMarker:
# no alias, so this is a local file
pathname = abspath_expanduser_unicode(path)
if os.path.isdir(pathname):
t = LocalDirectorySource(self.progress, pathname, name)
else:
- assert os.path.isfile(pathname)
+ if had_trailing_slash:
+ raise FilenameWithTrailingSlashError(source_spec,
+ quotefn=quote_local_unicode_path)
+ if not os.path.isfile(pathname):
+ raise WeirdSourceError(pathname)
t = LocalFileSource(pathname, name) # non-empty
else:
# this is a tahoe object
url = self.nodeurl + "uri/%s" % urllib.quote(rootcap)
name = None
if path:
+ if path.endswith("/"):
+ path = path[:-1]
url += "/" + escape_path(path)
last_slash = path.rfind(u"/")
name = path
self.progress, name)
t.init_from_parsed(parsed)
else:
+ if had_trailing_slash:
+ raise FilenameWithTrailingSlashError(source_spec)
writecap = to_str(d.get("rw_uri"))
readcap = to_str(d.get("ro_uri"))
mutable = d.get("mutable", False) # older nodes don't provide it
-
- last_slash = source_spec.rfind(u"/")
- if last_slash != -1:
- # TODO: this looks funny and redundant with the 'name'
- # assignment above. cf #2329
- name = source_spec[last_slash+1:]
-
t = TahoeFileSource(self.nodeurl, mutable, writecap, readcap, name)
return t
# these test cases come from ticket #2329 comment 40
# trailing slash on target *directory* should not matter, test both
-# trailing slash on files should cause error
+# trailing slash on target files should cause error
+# trailing slash on source directory should not matter, test a few
+# trailing slash on source files should cause error
COPYOUT_TESTCASES = """
cp $FILECAP to/existing-file : to/existing-file
cp -r $FILECAP $DIRCAP to/existing-file/ : E7-BADSLASH
# single source to a (present) target directory
-cp $FILECAP to : E2-DESTNAME
-cp -r $FILECAP to : E2-DESTNAME
-cp $DIRCAP/file to : to/file
-cp -r $DIRCAP/file to : to/file
-cp $PARENTCAP/dir to : E4-NEED-R
-cp -r $PARENTCAP/dir to : to/dir/file
-cp $DIRCAP to : E4-NEED-R
-cp -r $DIRCAP to : to/file
-cp $DIRALIAS to : E4-NEED-R
-cp -r $DIRALIAS to : to/file
+cp $FILECAP to : E2-DESTNAME
+cp -r $FILECAP to : E2-DESTNAME
+cp $DIRCAP/file to : to/file
+cp -r $DIRCAP/file to : to/file
+# these two are errors
+cp $DIRCAP/file/ to : E8-BADSLASH
+cp -r $DIRCAP/file/ to : E8-BADSLASH
+cp $PARENTCAP/dir to : E4-NEED-R
+cp -r $PARENTCAP/dir to : to/dir/file
+# but these two should ignore the trailing source slash
+cp $PARENTCAP/dir/ to : E4-NEED-R
+cp -r $PARENTCAP/dir/ to : to/dir/file
+cp $DIRCAP to : E4-NEED-R
+cp -r $DIRCAP to : to/file
+cp $DIRALIAS to : E4-NEED-R
+cp -r $DIRALIAS to : to/file
cp $FILECAP to/ : E2-DESTNAME
cp -r $FILECAP to/ : E2-DESTNAME
return set(["E6-MANYONE"])
if err == "target is not a directory, but ends with a slash":
return set(["E7-BADSLASH"])
+ if (err.startswith("source ") and
+ "is not a directory, but ends with a slash" in err):
+ return set(["E8-BADSLASH"])
self.fail("unrecognized error ('%s') %s" % (case, res))
d.addCallback(_check)
return d