]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/scripts/common.py
fix flakes
[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.stringutils import unicode_to_url
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 allmydata.get_package_versions_string()
23         sys.exit(0)
24
25     def opt_version_and_path(self):
26         import allmydata
27         print 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 = "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["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(":", 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 class UnknownAliasError(Exception):
128     pass
129
130 def get_alias(aliases, path, default):
131     from allmydata import uri
132     # transform "work:path/filename" into (aliases["work"], "path/filename").
133     # If default=None, then an empty alias is indicated by returning
134     # DefaultAliasMarker. We special-case strings with a recognized cap URI
135     # prefix, to make it easy to access specific files/directories by their
136     # caps.
137     # If the transformed alias is either not found in aliases, or is blank
138     # and default is not found in aliases, an UnknownAliasError is
139     # raised.
140     path = path.strip()
141     if uri.has_uri_prefix(path.encode('utf-8')):
142         # We used to require "URI:blah:./foo" in order to get a subpath,
143         # stripping out the ":./" sequence. We still allow that for compatibility,
144         # but now also allow just "URI:blah/foo".
145         sep = path.find(":./")
146         if sep != -1:
147             return path[:sep], path[sep+3:]
148         sep = path.find("/")
149         if sep != -1:
150             return path[:sep], path[sep+1:]
151         return path, ""
152     colon = path.find(":")
153     if colon == -1:
154         # no alias
155         if default == None:
156             return DefaultAliasMarker, path
157         if default not in aliases:
158             raise UnknownAliasError("No alias specified, and the default "
159                                     "'tahoe' alias doesn't exist. To create "
160                                     "it, use 'tahoe create-alias tahoe'.")
161         return aliases[default], path
162     if colon == 1 and default == None and platform_uses_lettercolon_drivename():
163         # treat C:\why\must\windows\be\so\weird as a local path, not a tahoe
164         # file in the "C:" alias
165         return DefaultAliasMarker, path
166     alias = path[:colon]
167     if "/" in alias:
168         # no alias, but there's a colon in a dirname/filename, like
169         # "foo/bar:7"
170         if default == None:
171             return DefaultAliasMarker, path
172         if default not in aliases:
173             raise UnknownAliasError("No alias specified, and the default "
174                                     "'tahoe' alias doesn't exist. To create "
175                                     "it, use 'tahoe create-alias tahoe'.")
176         return aliases[default], path
177     if alias not in aliases:
178         raise UnknownAliasError("Unknown alias '%s', please create it with 'tahoe add-alias' or 'tahoe create-alias'." % alias)
179     return aliases[alias], path[colon+1:]
180
181 def escape_path(path):
182     segments = path.split("/")
183     return "/".join([urllib.quote(unicode_to_url(s)) for s in segments])