[kupfer] commands: Allow using text commandlines and improve error reporting



commit 856844d07be7a2969c1d8a88ca99d24cdce7d7ab
Author: Ulrik Sverdrup <ulrik sverdrup gmail com>
Date:   Tue Mar 1 21:22:14 2011 +0100

    commands: Allow using text commandlines and improve error reporting
    
    Allow 'Command' objects so the user can enter commandlines directly as
    text input for the Filter.. and Send to.. actions.
    
    Report stderr output if the subprocess exists with non-successful
    status.

 kupfer/plugin/commands.py |   78 ++++++++++++++++++++++----------------------
 1 files changed, 39 insertions(+), 39 deletions(-)
---
diff --git a/kupfer/plugin/commands.py b/kupfer/plugin/commands.py
index c756a90..7df73da 100644
--- a/kupfer/plugin/commands.py
+++ b/kupfer/plugin/commands.py
@@ -15,6 +15,7 @@ import shlex
 import gobject
 
 from kupfer.objects import TextSource, Leaf, TextLeaf, Action, FileLeaf
+from kupfer.objects import OperationError
 from kupfer.obj.fileactions import Execute
 from kupfer import utils, icons
 from kupfer import commandexec
@@ -26,19 +27,39 @@ def unicode_shlex_split(ustr, **kwargs):
 	s_str = ustr.encode("UTF-8")
 	return [kupferstring.tounicode(t) for t in shlex.split(s_str, **kwargs)]
 
+def get_commandline_argv(commandline):
+	# use shlex to allow simple quoting
+	try:
+		argv = unicode_shlex_split(commandline)
+	except ValueError:
+		# Exception raised on unpaired quotation marks
+		argv = commandline.split(None, 1)
+	return argv
+
+def finish_command(token, acommand, stdout, stderr, post_result=True):
+	"""Show async error if @acommand returns error output & error status.
+	Else post async result if @post_result.
+	"""
+	max_error_msg=512
+	pretty.print_debug(__name__, "Exited:", acommand)
+	ctx = commandexec.DefaultActionExecutionContext()
+	if acommand.exit_status != 0 and not stdout and stderr:
+		try:
+			errstr = kupferstring.fromlocale(stderr)[:max_error_msg]
+			raise OperationError(errstr)
+		except OperationError:
+			ctx.register_late_error(token)
+	elif post_result:
+		leaf = TextLeaf(kupferstring.fromlocale(stdout))
+		ctx.register_late_result(token, leaf)
+
 
 class GetOutput (Action):
 	def __init__(self):
 		Action.__init__(self, _("Run (Get Output)"))
 
 	def activate(self, leaf):
-		# use shlex to allow simple quoting
-		commandline = leaf.object
-		try:
-			argv = unicode_shlex_split(commandline)
-		except ValueError:
-			# Exception raised on unpaired quotation marks
-			argv = commandline.split(None, 1)
+		argv = get_commandline_argv(leaf.object)
 		ctx = commandexec.DefaultActionExecutionContext()
 		token = ctx.get_async_token()
 		pretty.print_debug(__name__, "Spawning with timeout 15 seconds")
@@ -46,9 +67,7 @@ class GetOutput (Action):
 		acom.token = token
 
 	def finish_callback(self, acommand, stdout, stderr):
-		ctx = commandexec.DefaultActionExecutionContext()
-		leaf = TextLeaf(kupferstring.fromlocale(stdout))
-		ctx.register_late_result(acommand.token, leaf)
+		finish_command(acommand.token, acommand, stdout, stderr)
 
 	def get_description(self):
 		return _("Run program and return its output")
@@ -58,7 +77,10 @@ class WriteToCommand (Action):
 		Action.__init__(self, _("Send to Command..."))
 
 	def activate(self, leaf, iobj):
-		argv = [iobj.object]
+		if isinstance(iobj, Command):
+			argv = get_commandline_argv(iobj.object)
+		else:
+			argv = [iobj.object]
 		ctx = commandexec.DefaultActionExecutionContext()
 		token = ctx.get_async_token()
 		pretty.print_debug(__name__, "Spawning without timeout")
@@ -74,47 +96,25 @@ class WriteToCommand (Action):
 
 	def object_types(self):
 		yield FileLeaf
+		yield Command
 
 	def valid_object(self, iobj, for_item=None):
+		if isinstance(iobj, Command):
+			return True
 		return not iobj.is_dir() and os.access(iobj.object, os.X_OK | os.R_OK)
 
 	def finish_callback(self, acommand, stdout, stderr):
-		pretty.print_debug(__name__, "Exited:", acommand)
-		pass
+		finish_command(acommand.token, acommand, stdout, stderr, False)
 
 	def get_description(self):
 		return _("Run program and supply text on the standard input")
 
-class FilterThroughCommand (Action):
+class FilterThroughCommand (WriteToCommand):
 	def __init__(self):
 		Action.__init__(self, _("Filter through Command..."))
 
-	def activate(self, leaf, iobj):
-		argv = [iobj.object]
-		ctx = commandexec.DefaultActionExecutionContext()
-		token = ctx.get_async_token()
-		pretty.print_debug(__name__, "Spawning without timeout")
-		acom = utils.AsyncCommand(argv, self.finish_callback, None,
-		                          stdin=leaf.object)
-		acom.token = token
-
-	def item_types(self):
-		yield TextLeaf
-
-	def requires_object(self):
-		return True
-
-	def object_types(self):
-		yield FileLeaf
-
-	def valid_object(self, iobj, for_item=None):
-		return not iobj.is_dir() and os.access(iobj.object, os.X_OK | os.R_OK)
-
 	def finish_callback(self, acommand, stdout, stderr):
-		pretty.print_debug(__name__, "Exited:", acommand)
-		ctx = commandexec.DefaultActionExecutionContext()
-		leaf = TextLeaf(kupferstring.fromlocale(stdout))
-		ctx.register_late_result(acommand.token, leaf)
+		finish_command(acommand.token, acommand, stdout, stderr)
 
 	def get_description(self):
 		return _("Run program and supply text on the standard input")



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]