source: trunk/src/allmydata/scripts/common.py @ d3a8ef76

Last change on this file since d3a8ef76 was d3a8ef76, checked in by david-sarah <david-sarah@…>, at 2010-08-01T23:53:10Z

Unicode basedir changes for ticket798 branch.

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