]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/scripts/common.py
Rename stringutils to encodingutil, and drop listdir_unicode and open_unicode (since...
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / scripts / common.py
1
2 import os, sys, urllib
3 import codecs
4 from twisted.python import usage
5 from allmydata.util.encodingutil import unicode_to_url, quote_output
6 from allmydata.util.assertutil import precondition
7
8 class BaseOptions:
9     # unit tests can override these to point at StringIO instances
10     stdin = sys.stdin
11     stdout = sys.stdout
12     stderr = sys.stderr
13
14     optFlags = [
15         ["quiet", "q", "Operate silently."],
16         ["version", "V", "Display version numbers and exit."],
17         ["version-and-path", None, "Display version numbers and paths to their locations and exit."],
18         ]
19
20     def opt_version(self):
21         import allmydata
22         print >>self.stdout, allmydata.get_package_versions_string()
23         sys.exit(0)
24
25     def opt_version_and_path(self):
26         import allmydata
27         print >>self.stdout, allmydata.get_package_versions_string(show_paths=True)
28         sys.exit(0)
29
30
31 class BasedirMixin:
32     optFlags = [
33         ["multiple", "m", "allow multiple basedirs to be specified at once"],
34         ]
35
36     def postOptions(self):
37         if not self.basedirs:
38             raise usage.UsageError("<basedir> parameter is required")
39         if self['basedir']:
40             del self['basedir']
41         self['basedirs'] = [os.path.abspath(os.path.expanduser(b)) for b in self.basedirs]
42
43     def parseArgs(self, *args):
44         self.basedirs = []
45         if self['basedir']:
46             precondition(isinstance(self['basedir'], (str, unicode)), self['basedir'])
47             self.basedirs.append(self['basedir'])
48         if self['multiple']:
49             precondition(not [x for x in args if not isinstance(x, (str, unicode))], args)
50             self.basedirs.extend(args)
51         else:
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()
56                     if rbdp:
57                         precondition(isinstance(registry.get_base_dir_path(), (str, unicode)), registry.get_base_dir_path())
58                         self.basedirs.append(rbdp)
59                 else:
60                     precondition(isinstance(os.path.expanduser("~/.tahoe"), (str, unicode)), os.path.expanduser("~/.tahoe"))
61                     self.basedirs.append(os.path.expanduser("~/.tahoe"))
62             if len(args) > 0:
63                 precondition(isinstance(args[0], (str, unicode)), args[0])
64                 self.basedirs.append(args[0])
65             if len(args) > 1:
66                 raise usage.UsageError("I wasn't expecting so many arguments")
67
68 class NoDefaultBasedirMixin(BasedirMixin):
69     def parseArgs(self, *args):
70         # create-client won't default to --basedir=~/.tahoe
71         self.basedirs = []
72         if self['basedir']:
73             precondition(isinstance(self['basedir'], (str, unicode)), self['basedir'])
74             self.basedirs.append(self['basedir'])
75         if self['multiple']:
76             precondition(not [x for x in args if not isinstance(x, (str, unicode))], args)
77             self.basedirs.extend(args)
78         else:
79             if len(args) > 0:
80                 precondition(isinstance(args[0], (str, unicode)), args[0])
81                 self.basedirs.append(args[0])
82             if len(args) > 1:
83                 raise usage.UsageError("I wasn't expecting so many arguments")
84         if not self.basedirs:
85             raise usage.UsageError("--basedir must be provided")
86
87 DEFAULT_ALIAS = u"tahoe"
88
89
90 def get_aliases(nodedir):
91     from allmydata import uri
92     aliases = {}
93     aliasfile = os.path.join(nodedir, "private", "aliases")
94     rootfile = os.path.join(nodedir, "private", "root_dir.cap")
95     try:
96         f = open(rootfile, "r")
97         rootcap = f.read().strip()
98         if rootcap:
99             aliases[u"tahoe"] = uri.from_string_dirnode(rootcap).to_string()
100     except EnvironmentError:
101         pass
102     try:
103         f = codecs.open(aliasfile, "r", "utf-8")
104         for line in f.readlines():
105             line = line.strip()
106             if line.startswith("#") or not line:
107                 continue
108             name, cap = line.split(u":", 1)
109             # normalize it: remove http: prefix, urldecode
110             cap = cap.strip().encode('utf-8')
111             aliases[name] = uri.from_string_dirnode(cap).to_string()
112     except EnvironmentError:
113         pass
114     return aliases
115
116 class DefaultAliasMarker:
117     pass
118
119 pretend_platform_uses_lettercolon = False # for tests
120 def platform_uses_lettercolon_drivename():
121     if ("win32" in sys.platform.lower()
122         or "cygwin" in sys.platform.lower()
123         or pretend_platform_uses_lettercolon):
124         return True
125     return False
126
127
128 class TahoeError(Exception):
129     def __init__(self, msg):
130         Exception.__init__(self, msg)
131         self.msg = msg
132
133     def display(self, err):
134         print >>err, self.msg
135
136
137 class UnknownAliasError(TahoeError):
138     def __init__(self, msg):
139         TahoeError.__init__(self, "error: " + msg)
140
141
142 def get_alias(aliases, path_unicode, default):
143     """
144     Transform u"work:path/filename" into (aliases[u"work"], u"path/filename".encode('utf-8')).
145     If default=None, then an empty alias is indicated by returning
146     DefaultAliasMarker. We special-case strings with a recognized cap URI
147     prefix, to make it easy to access specific files/directories by their
148     caps.
149     If the transformed alias is either not found in aliases, or is blank
150     and default is not found in aliases, an UnknownAliasError is
151     raised.
152     """
153     precondition(isinstance(path_unicode, unicode), path_unicode)
154
155     from allmydata import uri
156     path = path_unicode.encode('utf-8').strip(" ")
157     if uri.has_uri_prefix(path):
158         # We used to require "URI:blah:./foo" in order to get a subpath,
159         # stripping out the ":./" sequence. We still allow that for compatibility,
160         # but now also allow just "URI:blah/foo".
161         sep = path.find(":./")
162         if sep != -1:
163             return path[:sep], path[sep+3:]
164         sep = path.find("/")
165         if sep != -1:
166             return path[:sep], path[sep+1:]
167         return path, ""
168     colon = path.find(":")
169     if colon == -1:
170         # no alias
171         if default == None:
172             return DefaultAliasMarker, path
173         if default not in aliases:
174             raise UnknownAliasError("No alias specified, and the default "
175                                     "'tahoe' alias doesn't exist. To create "
176                                     "it, use 'tahoe create-alias tahoe'.")
177         return aliases[default], path
178     if colon == 1 and default is None and platform_uses_lettercolon_drivename():
179         # treat C:\why\must\windows\be\so\weird as a local path, not a tahoe
180         # file in the "C:" alias
181         return DefaultAliasMarker, path
182
183     # decoding must succeed because path is valid UTF-8 and colon & space are ASCII
184     alias = path[:colon].decode('utf-8')
185     if u"/" in alias:
186         # no alias, but there's a colon in a dirname/filename, like
187         # "foo/bar:7"
188         if default == None:
189             return DefaultAliasMarker, path
190         if default not in aliases:
191             raise UnknownAliasError("No alias specified, and the default "
192                                     "'tahoe' alias doesn't exist. To create "
193                                     "it, use 'tahoe create-alias tahoe'.")
194         return aliases[default], path
195     if alias not in aliases:
196         raise UnknownAliasError("Unknown alias %s, please create it with 'tahoe add-alias' or 'tahoe create-alias'." %
197                                 quote_output(alias))
198     return aliases[alias], path[colon+1:]
199
200 def escape_path(path):
201     segments = path.split("/")
202     return "/".join([urllib.quote(unicode_to_url(s)) for s in segments])