4 from twisted.python import usage
5 from allmydata.util.assertutil import precondition
6 from allmydata.util.encodingutil import unicode_to_url, quote_output, argv_to_abspath
7 from allmydata.util.fileutil import abspath_expanduser_unicode
10 # unit tests can override these to point at StringIO instances
16 ["quiet", "q", "Operate silently."],
17 ["version", "V", "Display version numbers and exit."],
18 ["version-and-path", None, "Display version numbers and paths to their locations and exit."],
21 def opt_version(self):
23 print >>self.stdout, allmydata.get_package_versions_string()
26 def opt_version_and_path(self):
28 print >>self.stdout, allmydata.get_package_versions_string(show_paths=True)
34 ["multiple", "m", "allow multiple basedirs to be specified at once"],
37 def postOptions(self):
39 raise usage.UsageError("<basedir> parameter is required")
42 self['basedirs'] = self.basedirs
44 def parseArgs(self, *args):
47 precondition(isinstance(self['basedir'], str), self['basedir'])
48 self.basedirs.append(argv_to_abspath(self['basedir']))
50 self.basedirs.extend(map(argv_to_abspath, args))
52 if len(args) == 0 and not self.basedirs:
53 if sys.platform == 'win32':
54 from allmydata.windows import registry
55 rbdp = registry.get_base_dir_path()
57 precondition(isinstance(registry.get_base_dir_path(), unicode), registry.get_base_dir_path())
58 self.basedirs.append(rbdp)
60 self.basedirs.append(abspath_expanduser_unicode(u"~/.tahoe"))
62 self.basedirs.append(argv_to_abspath(args[0]))
64 raise usage.UsageError("I wasn't expecting so many arguments")
66 class NoDefaultBasedirMixin(BasedirMixin):
67 def parseArgs(self, *args):
68 # create-client won't default to --basedir=~/.tahoe
71 self.basedirs.append(argv_to_abspath(self['basedir']))
73 self.basedirs.extend(map(argv_to_abspath, args))
76 self.basedirs.append(argv_to_abspath(args[0]))
78 raise usage.UsageError("I wasn't expecting so many arguments")
80 raise usage.UsageError("--basedir must be provided")
82 DEFAULT_ALIAS = u"tahoe"
85 def get_aliases(nodedir):
86 from allmydata import uri
88 aliasfile = os.path.join(nodedir, "private", "aliases")
89 rootfile = os.path.join(nodedir, "private", "root_dir.cap")
91 f = open(rootfile, "r")
92 rootcap = f.read().strip()
94 aliases[u"tahoe"] = uri.from_string_dirnode(rootcap).to_string()
95 except EnvironmentError:
98 f = codecs.open(aliasfile, "r", "utf-8")
99 for line in f.readlines():
101 if line.startswith("#") or not line:
103 name, cap = line.split(u":", 1)
104 # normalize it: remove http: prefix, urldecode
105 cap = cap.strip().encode('utf-8')
106 aliases[name] = uri.from_string_dirnode(cap).to_string()
107 except EnvironmentError:
111 class DefaultAliasMarker:
114 pretend_platform_uses_lettercolon = False # for tests
115 def platform_uses_lettercolon_drivename():
116 if ("win32" in sys.platform.lower()
117 or "cygwin" in sys.platform.lower()
118 or pretend_platform_uses_lettercolon):
123 class TahoeError(Exception):
124 def __init__(self, msg):
125 Exception.__init__(self, msg)
128 def display(self, err):
129 print >>err, self.msg
132 class UnknownAliasError(TahoeError):
133 def __init__(self, msg):
134 TahoeError.__init__(self, "error: " + msg)
137 def get_alias(aliases, path_unicode, default):
139 Transform u"work:path/filename" into (aliases[u"work"], u"path/filename".encode('utf-8')).
140 If default=None, then an empty alias is indicated by returning
141 DefaultAliasMarker. We special-case strings with a recognized cap URI
142 prefix, to make it easy to access specific files/directories by their
144 If the transformed alias is either not found in aliases, or is blank
145 and default is not found in aliases, an UnknownAliasError is
148 precondition(isinstance(path_unicode, unicode), path_unicode)
150 from allmydata import uri
151 path = path_unicode.encode('utf-8').strip(" ")
152 if uri.has_uri_prefix(path):
153 # We used to require "URI:blah:./foo" in order to get a subpath,
154 # stripping out the ":./" sequence. We still allow that for compatibility,
155 # but now also allow just "URI:blah/foo".
156 sep = path.find(":./")
158 return path[:sep], path[sep+3:]
161 return path[:sep], path[sep+1:]
163 colon = path.find(":")
167 return DefaultAliasMarker, path
168 if default not in aliases:
169 raise UnknownAliasError("No alias specified, and the default "
170 "'tahoe' alias doesn't exist. To create "
171 "it, use 'tahoe create-alias tahoe'.")
172 return aliases[default], path
173 if colon == 1 and default is None and platform_uses_lettercolon_drivename():
174 # treat C:\why\must\windows\be\so\weird as a local path, not a tahoe
175 # file in the "C:" alias
176 return DefaultAliasMarker, path
178 # decoding must succeed because path is valid UTF-8 and colon & space are ASCII
179 alias = path[:colon].decode('utf-8')
181 # no alias, but there's a colon in a dirname/filename, like
184 return DefaultAliasMarker, path
185 if default not in aliases:
186 raise UnknownAliasError("No alias specified, and the default "
187 "'tahoe' alias doesn't exist. To create "
188 "it, use 'tahoe create-alias tahoe'.")
189 return aliases[default], path
190 if alias not in aliases:
191 raise UnknownAliasError("Unknown alias %s, please create it with 'tahoe add-alias' or 'tahoe create-alias'." %
193 return aliases[alias], path[colon+1:]
195 def escape_path(path):
196 segments = path.split("/")
197 return "/".join([urllib.quote(unicode_to_url(s)) for s in segments])