git-svn-id: https://s3tools.svn.sourceforge.net/svnroot/s3tools/s3cmd/branches/0.9.8.x@239 830e0280-6d2a-0410-9c65-932aecc39d9d
Michal Ludvig authored on 2008/09/15 21:15:08... | ... |
@@ -1,5 +1,12 @@ |
1 | 1 |
2008-09-15 Michal Ludvig <michal@logix.cz> |
2 | 2 |
|
3 |
+ * Merge from trunk, revision 238: |
|
4 |
+ * s3cmd, S3/S3.py, S3/Utils.py, S3/S3Uri.py, S3/Exceptions.py: |
|
5 |
+ Yet anoter Unicode round. Unicodised all command line arguments |
|
6 |
+ before processing. |
|
7 |
+ |
|
8 |
+2008-09-15 Michal Ludvig <michal@logix.cz> |
|
9 |
+ |
|
3 | 10 |
* Merge from trunk, revision 221: |
4 | 11 |
* s3cmd: Refuse 'sync' together with '--encrypt'. |
5 | 12 |
|
... | ... |
@@ -10,7 +10,15 @@ try: |
10 | 10 |
except ImportError: |
11 | 11 |
import elementtree.ElementTree as ET |
12 | 12 |
|
13 |
-class S3Error (Exception): |
|
13 |
+class S3Exception(Exception): |
|
14 |
+ def __str__(self): |
|
15 |
+ ## Is this legal? |
|
16 |
+ return unicode(self) |
|
17 |
+ |
|
18 |
+ def __unicode__(self): |
|
19 |
+ return self.message |
|
20 |
+ |
|
21 |
+class S3Error (S3Exception): |
|
14 | 22 |
def __init__(self, response): |
15 | 23 |
self.status = response["status"] |
16 | 24 |
self.reason = response["reason"] |
... | ... |
@@ -26,7 +34,7 @@ class S3Error (Exception): |
26 | 26 |
debug("ErrorXML: " + child.tag + ": " + repr(child.text)) |
27 | 27 |
self.info[child.tag] = child.text |
28 | 28 |
|
29 |
- def __str__(self): |
|
29 |
+ def __unicode__(self): |
|
30 | 30 |
retval = "%d (%s)" % (self.status, self.reason) |
31 | 31 |
try: |
32 | 32 |
retval += (": %s" % self.info["Code"]) |
... | ... |
@@ -34,13 +42,11 @@ class S3Error (Exception): |
34 | 34 |
pass |
35 | 35 |
return retval |
36 | 36 |
|
37 |
-class S3UploadError(Exception): |
|
37 |
+class S3UploadError(S3Exception): |
|
38 | 38 |
pass |
39 | 39 |
|
40 |
-class S3DownloadError(Exception): |
|
40 |
+class S3DownloadError(S3Exception): |
|
41 | 41 |
pass |
42 | 42 |
|
43 |
-class ParameterError(Exception): |
|
43 |
+class ParameterError(S3Exception): |
|
44 | 44 |
pass |
45 |
- |
|
46 |
- |
... | ... |
@@ -8,6 +8,7 @@ import sys |
8 | 8 |
from BidirMap import BidirMap |
9 | 9 |
from logging import debug |
10 | 10 |
from S3 import S3 |
11 |
+from Utils import unicodise |
|
11 | 12 |
|
12 | 13 |
class S3Uri(object): |
13 | 14 |
type = None |
... | ... |
@@ -41,18 +42,6 @@ class S3Uri(object): |
41 | 41 |
def public_url(self): |
42 | 42 |
raise ValueError("This S3 URI does not have Anonymous URL representation") |
43 | 43 |
|
44 |
- def _unicodise(self, string): |
|
45 |
- """ |
|
46 |
- Convert 'string' to Unicode or raise an exception. |
|
47 |
- """ |
|
48 |
- debug("Unicodising %r" % string) |
|
49 |
- if type(string) == unicode: |
|
50 |
- return string |
|
51 |
- try: |
|
52 |
- return string.decode("utf-8") |
|
53 |
- except UnicodeDecodeError: |
|
54 |
- raise UnicodeDecodeError("Conversion to unicode failed: %r" % string) |
|
55 |
- |
|
56 | 44 |
class S3UriS3(S3Uri): |
57 | 45 |
type = "s3" |
58 | 46 |
_re = re.compile("^s3://([^/]+)/?(.*)", re.IGNORECASE) |
... | ... |
@@ -62,7 +51,7 @@ class S3UriS3(S3Uri): |
62 | 62 |
raise ValueError("%s: not a S3 URI" % string) |
63 | 63 |
groups = match.groups() |
64 | 64 |
self._bucket = groups[0] |
65 |
- self._object = self._unicodise(groups[1]) |
|
65 |
+ self._object = unicodise(groups[1]) |
|
66 | 66 |
|
67 | 67 |
def bucket(self): |
68 | 68 |
return self._bucket |
... | ... |
@@ -98,7 +87,7 @@ class S3UriS3FS(S3Uri): |
98 | 98 |
raise ValueError("%s: not a S3fs URI" % string) |
99 | 99 |
groups = match.groups() |
100 | 100 |
self._fsname = groups[0] |
101 |
- self._path = self._unicodise(groups[1]).split("/") |
|
101 |
+ self._path = unicodise(groups[1]).split("/") |
|
102 | 102 |
|
103 | 103 |
def fsname(self): |
104 | 104 |
return self._fsname |
... | ... |
@@ -117,7 +106,7 @@ class S3UriFile(S3Uri): |
117 | 117 |
groups = match.groups() |
118 | 118 |
if groups[0] not in (None, "file://"): |
119 | 119 |
raise ValueError("%s: not a file:// URI" % string) |
120 |
- self._path = self._unicodise(groups[1]).split("/") |
|
120 |
+ self._path = unicodise(groups[1]).split("/") |
|
121 | 121 |
|
122 | 122 |
def path(self): |
123 | 123 |
return "/".join(self._path) |
... | ... |
@@ -173,3 +173,22 @@ def mkdir_with_parents(dir_name): |
173 | 173 |
warning("%s: %s" % (cur_dir, e)) |
174 | 174 |
return False |
175 | 175 |
return True |
176 |
+ |
|
177 |
+def unicodise(string): |
|
178 |
+ """ |
|
179 |
+ Convert 'string' to Unicode or raise an exception. |
|
180 |
+ """ |
|
181 |
+ debug("Unicodising %r" % string) |
|
182 |
+ if type(string) == unicode: |
|
183 |
+ return string |
|
184 |
+ try: |
|
185 |
+ return string.decode("utf-8") |
|
186 |
+ except UnicodeDecodeError: |
|
187 |
+ raise UnicodeDecodeError("Conversion to unicode failed: %r" % string) |
|
188 |
+ |
|
189 |
+def try_unicodise(string): |
|
190 |
+ try: |
|
191 |
+ return unicodise(string) |
|
192 |
+ except UnicodeDecodeError: |
|
193 |
+ return string |
|
194 |
+ |
... | ... |
@@ -21,12 +21,14 @@ from optparse import OptionParser, Option, OptionValueError, IndentedHelpFormatt |
21 | 21 |
from logging import debug, info, warning, error |
22 | 22 |
from distutils.spawn import find_executable |
23 | 23 |
|
24 |
-## Output UTF-8 in all cases, even on output redirects |
|
25 |
-_unicode_stdout = codecs.getwriter("utf-8")(sys.stdout) |
|
26 |
-_unicode_stderr = codecs.getwriter("utf-8")(sys.stderr) |
|
24 |
+## Output native on TTY, UTF-8 otherwise (redirects) |
|
25 |
+_stdout = sys.stdout.isatty() and sys.stdout or codecs.getwriter("utf-8")(sys.stdout) |
|
26 |
+_stderr = sys.stderr.isatty() and sys.stderr or codecs.getwriter("utf-8")(sys.stderr) |
|
27 |
+#_stdout = codecs.getwriter("utf-8")(sys.stdout) |
|
28 |
+#_stderr = codecs.getwriter("utf-8")(sys.stderr) |
|
27 | 29 |
|
28 | 30 |
def output(message): |
29 |
- _unicode_stdout.write(message + "\n") |
|
31 |
+ _stdout.write(message + "\n") |
|
30 | 32 |
|
31 | 33 |
def check_args_type(args, type, verbose_type): |
32 | 34 |
for arg in args: |
... | ... |
@@ -926,7 +928,7 @@ def main(): |
926 | 926 |
## debugging/verbose output for config file parser on request |
927 | 927 |
logging.basicConfig(level=options.verbosity, |
928 | 928 |
format='%(levelname)s: %(message)s', |
929 |
- stream = _unicode_stderr) |
|
929 |
+ stream = _stderr) |
|
930 | 930 |
|
931 | 931 |
if options.show_version: |
932 | 932 |
output("s3cmd version %s" % PkgInfo.version) |
... | ... |
@@ -1015,9 +1017,12 @@ def main(): |
1015 | 1015 |
error("Missing command. Please run with --help for more information.") |
1016 | 1016 |
sys.exit(1) |
1017 | 1017 |
|
1018 |
+ ## Unicodise all remaining arguments: |
|
1019 |
+ args = [unicodise(arg) for arg in args] |
|
1020 |
+ |
|
1018 | 1021 |
command = args.pop(0) |
1019 | 1022 |
try: |
1020 |
- debug("Command: " + commands[command]["cmd"]) |
|
1023 |
+ debug("Command: %s" % commands[command]["cmd"]) |
|
1021 | 1024 |
## We must do this lookup in extra step to |
1022 | 1025 |
## avoid catching all KeyError exceptions |
1023 | 1026 |
## from inner functions. |
... | ... |
@@ -1033,10 +1038,10 @@ def main(): |
1033 | 1033 |
try: |
1034 | 1034 |
cmd_func(args) |
1035 | 1035 |
except S3Error, e: |
1036 |
- error("S3 error: " + str(e)) |
|
1036 |
+ error("S3 error: %s" % e) |
|
1037 | 1037 |
sys.exit(1) |
1038 | 1038 |
except ParameterError, e: |
1039 |
- error("Parameter problem: " + str(e)) |
|
1039 |
+ error("Parameter problem: %s" % e) |
|
1040 | 1040 |
sys.exit(1) |
1041 | 1041 |
|
1042 | 1042 |
if __name__ == '__main__': |
... | ... |
@@ -1050,6 +1055,7 @@ if __name__ == '__main__': |
1050 | 1050 |
from S3.S3Uri import * |
1051 | 1051 |
from S3 import Utils |
1052 | 1052 |
from S3.Exceptions import * |
1053 |
+ from S3.Utils import unicodise |
|
1053 | 1054 |
|
1054 | 1055 |
main() |
1055 | 1056 |
sys.exit(0) |