Browse code

* Merge from trunk, revision 238: * s3cmd, S3/S3.py, S3/Utils.py, S3/S3Uri.py, S3/Exceptions.py: Yet anoter Unicode round. Unicodised all command line arguments before processing.

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
Showing 5 changed files
... ...
@@ -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)