tahoe-lafs/src/allmydata/scripts/tahoe_cp.py

146 lines
5.0 KiB
Python
Raw Normal View History

import os.path
import urllib
import simplejson
from allmydata.scripts.common import get_alias, escape_path, DefaultAliasMarker
from allmydata.scripts.common_http import do_http
def ascii_or_none(s):
if s is None:
return s
return str(s)
def get_info(nodeurl, aliases, target):
rootcap, path = get_alias(aliases, target, None)
if rootcap == DefaultAliasMarker:
# this is a local file
pathname = os.path.abspath(os.path.expanduser(path))
if not os.path.exists(pathname):
return ("empty", "local", pathname)
if os.path.isdir(pathname):
return ("directory", "local", pathname)
else:
assert os.path.isfile(pathname)
return ("file", "local", pathname)
else:
# this is a tahoe object
url = nodeurl + "uri/%s" % urllib.quote(rootcap)
if path:
url += "/" + escape_path(path)
resp = do_http("GET", url + "?t=json")
if resp.status == 404:
# doesn't exist yet
return ("empty", "tahoe", False, None, None, url)
parsed = simplejson.loads(resp.read())
nodetype, d = parsed
mutable = d.get("mutable", False) # older nodes don't provide 'mutable'
rw_uri = ascii_or_none(d.get("rw_uri"))
ro_uri = ascii_or_none(d.get("ro_uri"))
if nodetype == "dirnode":
return ("directory", "tahoe", mutable, rw_uri, ro_uri, url)
else:
return ("file", "tahoe", mutable, rw_uri, ro_uri, url)
def copy(nodeurl, config, aliases, sources, destination,
verbosity, stdout, stderr):
if nodeurl[-1] != "/":
nodeurl += "/"
recursive = config["recursive"]
#print "sources:", sources
#print "dest:", destination
target = get_info(nodeurl, aliases, destination)
#print target
source_info = dict([(get_info(nodeurl, aliases, source), source)
for source in sources])
source_files = [s for s in source_info if s[0] == "file"]
source_dirs = [s for s in source_info if s[0] == "directory"]
empty_sources = [s for s in source_info if s[0] == "empty"]
if empty_sources:
for s in empty_sources:
print >>stderr, "no such file or directory %s" % source_info[s]
return 1
#print "source_files", " ".join([source_info[s] for s in source_files])
#print "source_dirs", " ".join([source_info[s] for s in source_dirs])
if source_dirs and not recursive:
print >>stderr, "cannot copy directories without --recursive"
return 1
if target[0] == "file":
# cp STUFF foo.txt, where foo.txt already exists. This limits the
# possibilities considerably.
if len(sources) > 1:
print >>stderr, "target '%s' is not a directory" % destination
return 1
if source_dirs:
print >>stderr, "cannot copy directory into a file"
return 1
return copy_to_file(source_files[0], target)
if target[0] == "empty":
if recursive:
return copy_to_directory(source_files, source_dirs, target)
if len(sources) > 1:
# if we have -r, we'll auto-create the target directory. Without
# it, we'll only create a file.
print >>stderr, "cannot copy multiple files into a file without -r"
return 1
# cp file1 newfile
return copy_to_file(source_files[0], target)
if target[0] == "directory":
return copy_to_directory(source_files, source_dirs, target)
print >>stderr, "unknown target"
return 1
def get_file_data(source):
assert source[0] == "file"
if source[1] == "local":
return open(source[2], "rb").read()
return do_http("GET", source[-1]).read()
class WriteError(Exception):
pass
def check_PUT(resp):
if resp.status in (200, 201):
return True
raise WriteError("Error during PUT: %s %s %s" % (resp.status, resp.reason,
resp.read()))
def put_file_data(data, target):
if target[1] == "local":
open(target[2], "wb").write(data)
return True
resp = do_http("PUT", target[-1], data)
return check_PUT(resp)
def put_uri(uri, target):
resp = do_http("PUT", target[-1] + "?t=uri", uri)
return check_PUT(resp)
def copy_to_file(source, target):
assert source[0] == "file"
# do we need to copy bytes?
if source[1] == "local" or source[2] == True or target[1] == "local":
# yes
data = get_file_data(source)
put_file_data(data, target)
return
# no, we're getting data from an immutable source, and we're copying into
# the tahoe grid, so we can just copy the URI.
uri = source[3] or source[4] # prefer rw_uri, fall back to ro_uri
# TODO: if the original was mutable, and we're creating the target,
# should be we create a mutable file to match? At the moment we always
# create immutable files.
put_uri(uri, target)
def copy_to_directory(source_files, source_dirs, target):
NotImplementedError