From patchwork Mon Feb 21 15:55:15 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damien Hedde X-Patchwork-Id: 1595646 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; secure) header.d=greensocs.com header.i=@greensocs.com header.a=rsa-sha256 header.s=mail header.b=ROLmkmxq; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4K2RmV3SRyz9sGP for ; Tue, 22 Feb 2022 02:58:34 +1100 (AEDT) Received: from localhost ([::1]:38534 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nMB56-0006eM-5i for incoming@patchwork.ozlabs.org; Mon, 21 Feb 2022 10:58:32 -0500 Received: from eggs.gnu.org ([209.51.188.92]:55168) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nMB2G-0006cb-PK for qemu-devel@nongnu.org; Mon, 21 Feb 2022 10:55:37 -0500 Received: from beetle.greensocs.com ([5.135.226.135]:35542) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nMB2D-0002At-MO for qemu-devel@nongnu.org; Mon, 21 Feb 2022 10:55:36 -0500 Received: from crumble.bar.greensocs.com (unknown [172.17.10.6]) by beetle.greensocs.com (Postfix) with ESMTPS id B46CF21C36; Mon, 21 Feb 2022 15:55:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=greensocs.com; s=mail; t=1645458931; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=zDC9u9lt816558qvQ9zL3iwMJrJG4eLRj8Dgvj9bAM0=; b=ROLmkmxqyOTK9XOTfCKXt5z7e61sPx4keR5EVNW6B3EoEbVRORcM2STu+0zThKaRU0U+SI UgfTCRdRuak4AQlh07Hru6lJuLG/eD+aBSYQAty+6xqgfMTv3BP8tfV2rrIFxhxFxIA51W TgG0Y/bt/9OV/M6BjgXxLXPQmxLXAac= From: Damien Hedde To: qemu-devel@nongnu.org Subject: [PATCH 1/5] python: qmp_shell: don't prompt when stdin is non-interactive Date: Mon, 21 Feb 2022 16:55:15 +0100 Message-Id: <20220221155519.2367-2-damien.hedde@greensocs.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220221155519.2367-1-damien.hedde@greensocs.com> References: <20220221155519.2367-1-damien.hedde@greensocs.com> MIME-Version: 1.0 Received-SPF: pass client-ip=5.135.226.135; envelope-from=damien.hedde@greensocs.com; helo=beetle.greensocs.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Damien Hedde , Eduardo Habkost , John Snow , Cleber Rosa Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" In that case, there is no echo anyway. So the prompt is just garbage. Signed-off-by: Damien Hedde --- python/qemu/aqmp/qmp_shell.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/qemu/aqmp/qmp_shell.py b/python/qemu/aqmp/qmp_shell.py index d11bf54b00..a6e0f5af42 100644 --- a/python/qemu/aqmp/qmp_shell.py +++ b/python/qemu/aqmp/qmp_shell.py @@ -367,6 +367,8 @@ def prompt(self) -> str: """ Return the current shell prompt, including a trailing space. """ + if not sys.stdin.isatty(): + return "" if self._transmode: return 'TRANS> ' return '(QEMU) ' From patchwork Mon Feb 21 15:55:16 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damien Hedde X-Patchwork-Id: 1595656 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; secure) header.d=greensocs.com header.i=@greensocs.com header.a=rsa-sha256 header.s=mail header.b=O/eMeSw9; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4K2S0j5TL0z9sGP for ; Tue, 22 Feb 2022 03:09:09 +1100 (AEDT) Received: from localhost ([::1]:49376 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nMBFL-0005xl-1Y for incoming@patchwork.ozlabs.org; Mon, 21 Feb 2022 11:09:07 -0500 Received: from eggs.gnu.org ([209.51.188.92]:55174) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nMB2H-0006ci-Ok for qemu-devel@nongnu.org; Mon, 21 Feb 2022 10:55:37 -0500 Received: from beetle.greensocs.com ([5.135.226.135]:35554) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nMB2E-0002B1-Er for qemu-devel@nongnu.org; Mon, 21 Feb 2022 10:55:36 -0500 Received: from crumble.bar.greensocs.com (unknown [172.17.10.6]) by beetle.greensocs.com (Postfix) with ESMTPS id 072F721C47; Mon, 21 Feb 2022 15:55:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=greensocs.com; s=mail; t=1645458933; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3XildHfwEa3XRRUp9QR/mMklLb2sWGeGTzxz8F8pc/g=; b=O/eMeSw9wC6qBiJXIm8kOfdnv3+PB//wNT6jLv9wi279YS7aeLofYyHp+9QOA+ujiI4o5T Yck9KVBALG5TMbe9/tR9IQYzSGCNS5JXvG99qbOR5GKEbqUYU9aSX4f2vYABbG0csmq3tl /XGwoFOWUbxdRMK3jC4dGRT+ilcqG/o= From: Damien Hedde To: qemu-devel@nongnu.org Subject: [PATCH 2/5] python: qmp_shell: refactor the parsing error handling Date: Mon, 21 Feb 2022 16:55:16 +0100 Message-Id: <20220221155519.2367-3-damien.hedde@greensocs.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220221155519.2367-1-damien.hedde@greensocs.com> References: <20220221155519.2367-1-damien.hedde@greensocs.com> MIME-Version: 1.0 Received-SPF: pass client-ip=5.135.226.135; envelope-from=damien.hedde@greensocs.com; helo=beetle.greensocs.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Damien Hedde , Eduardo Habkost , John Snow , Cleber Rosa Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Instead of handling these error in _excute_cmd(), now raise the exception and let read_exec_command() handle it. Introduce QMPShellParseError (subclass of QMPShellError) to replace QMPShellError. In next commit we will introduce another subclass. Introduce _print_parse_error() method because QMPShell and HMPShell handle the printing differently. Signed-off-by: Damien Hedde --- python/qemu/aqmp/qmp_shell.py | 51 +++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/python/qemu/aqmp/qmp_shell.py b/python/qemu/aqmp/qmp_shell.py index a6e0f5af42..a1bd7d5630 100644 --- a/python/qemu/aqmp/qmp_shell.py +++ b/python/qemu/aqmp/qmp_shell.py @@ -136,6 +136,12 @@ class QMPShellError(QMPError): """ +class QMPShellParseError(QMPShellError): + """ + QMP Shell Parse error class. + """ + + class FuzzyJSON(ast.NodeTransformer): """ This extension of ast.NodeTransformer filters literal "true/false/null" @@ -246,7 +252,7 @@ def _cli_expr(self, for arg in tokens: (key, sep, val) = arg.partition('=') if sep != '=': - raise QMPShellError( + raise QMPShellParseError( f"Expected a key=value pair, got '{arg!s}'" ) @@ -258,14 +264,14 @@ def _cli_expr(self, obj = parent.get(path, {}) if not isinstance(obj, dict): msg = 'Cannot use "{:s}" as both leaf and non-leaf key' - raise QMPShellError(msg.format('.'.join(curpath))) + raise QMPShellParseError(msg.format('.'.join(curpath))) parent[path] = obj parent = obj if optpath[-1] in parent: if isinstance(parent[optpath[-1]], dict): msg = 'Cannot use "{:s}" as both leaf and non-leaf key' - raise QMPShellError(msg.format('.'.join(curpath))) - raise QMPShellError(f'Cannot set "{key}" multiple times') + raise QMPShellParseError(msg.format('.'.join(curpath))) + raise QMPShellParseError(f'Cannot set "{key}" multiple times') parent[optpath[-1]] = value def _build_cmd(self, cmdline: str) -> Optional[QMPMessage]: @@ -290,7 +296,7 @@ def _build_cmd(self, cmdline: str) -> Optional[QMPMessage]: self._transmode = False if len(cmdargs) > 1: msg = 'Unexpected input after close of Transaction sub-shell' - raise QMPShellError(msg) + raise QMPShellParseError(msg) qmpcmd = { 'execute': 'transaction', 'arguments': {'actions': self._actions} @@ -323,17 +329,17 @@ def _print(self, qmp_message: object) -> None: sort_keys=self.pretty) print(str(jsobj)) + def _print_parse_error(self, err: QMPShellParseError) -> None: + print( + f"Error while parsing command line: {err!s}\n" + "command format: " + "[arg-name1=arg1] ... [arg-nameN=argN", + file=sys.stderr + ) + def _execute_cmd(self, cmdline: str) -> bool: - try: - qmpcmd = self._build_cmd(cmdline) - except QMPShellError as err: - print( - f"Error while parsing command line: {err!s}\n" - "command format: " - "[arg-name1=arg1] ... [arg-nameN=argN", - file=sys.stderr - ) - return True + qmpcmd = self._build_cmd(cmdline) + # For transaction mode, we may have just cached the action: if qmpcmd is None: return True @@ -390,7 +396,11 @@ def read_exec_command(self) -> bool: print(event) return True - return self._execute_cmd(cmdline) + try: + return self._execute_cmd(cmdline) + except QMPShellParseError as err: + self._print_parse_error(err) + return True def repl(self) -> Iterator[None]: """ @@ -456,18 +466,19 @@ def _cmd_passthrough(self, cmdline: str, } }) + def _print_parse_error(self, err: QMPShellParseError) -> None: + print(f"{err!s}") + def _execute_cmd(self, cmdline: str) -> bool: if cmdline.split()[0] == "cpu": # trap the cpu command, it requires special setting try: idx = int(cmdline.split()[1]) if 'return' not in self._cmd_passthrough('info version', idx): - print('bad CPU index') - return True + raise QMPShellParseError('bad CPU index') self._cpu_index = idx except ValueError: - print('cpu command takes an integer argument') - return True + raise QMPShellParseError('cpu command takes an integer argument') resp = self._cmd_passthrough(cmdline, self._cpu_index) if resp is None: print('Disconnected') From patchwork Mon Feb 21 15:55:17 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damien Hedde X-Patchwork-Id: 1595655 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; secure) header.d=greensocs.com header.i=@greensocs.com header.a=rsa-sha256 header.s=mail header.b=ipK7BuuD; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4K2S0d1XT9z9sGP for ; Tue, 22 Feb 2022 03:09:03 +1100 (AEDT) Received: from localhost ([::1]:49220 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nMBFE-0005rT-4Z for incoming@patchwork.ozlabs.org; Mon, 21 Feb 2022 11:09:00 -0500 Received: from eggs.gnu.org ([209.51.188.92]:55180) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nMB2H-0006cj-UV for qemu-devel@nongnu.org; Mon, 21 Feb 2022 10:55:37 -0500 Received: from beetle.greensocs.com ([5.135.226.135]:35566) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nMB2F-0002BB-BK for qemu-devel@nongnu.org; Mon, 21 Feb 2022 10:55:37 -0500 Received: from crumble.bar.greensocs.com (unknown [172.17.10.6]) by beetle.greensocs.com (Postfix) with ESMTPS id 1463B21CC4; Mon, 21 Feb 2022 15:55:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=greensocs.com; s=mail; t=1645458934; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=L9InGvuw5dK4vKcHkANkKnIbYK5rhAl1tiLfsUcR2vA=; b=ipK7BuuDSNtm2ro0VYVxoG+obU9SkwToaq5yuLo1oABbKhBlcuhE5WX+xJrmtDA76Xiqea B4gFmrm7gIw/dzkeMGkX0vjAFnpHFKp7Jv5AbiQK/mnx1ixg5aMj4yMyVsHt/Q9m+4nYUw 6roHKE68Fj6h0hfxu6YX1vNBP+NKoOI= From: Damien Hedde To: qemu-devel@nongnu.org Subject: [PATCH 3/5] python: qmp_shell: refactor disconnection handling Date: Mon, 21 Feb 2022 16:55:17 +0100 Message-Id: <20220221155519.2367-4-damien.hedde@greensocs.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220221155519.2367-1-damien.hedde@greensocs.com> References: <20220221155519.2367-1-damien.hedde@greensocs.com> MIME-Version: 1.0 Received-SPF: pass client-ip=5.135.226.135; envelope-from=damien.hedde@greensocs.com; helo=beetle.greensocs.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Damien Hedde , Eduardo Habkost , John Snow , Cleber Rosa Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Introduce QMPShellConnectError (subclass of QMPShellError) to handle disconnection in read_exec_command(). Signed-off-by: Damien Hedde --- python/qemu/aqmp/qmp_shell.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/python/qemu/aqmp/qmp_shell.py b/python/qemu/aqmp/qmp_shell.py index a1bd7d5630..cce7732ba2 100644 --- a/python/qemu/aqmp/qmp_shell.py +++ b/python/qemu/aqmp/qmp_shell.py @@ -142,6 +142,12 @@ class QMPShellParseError(QMPShellError): """ +class QMPShellConnectError(QMPShellError): + """ + QMP Shell Connect error class. + """ + + class FuzzyJSON(ast.NodeTransformer): """ This extension of ast.NodeTransformer filters literal "true/false/null" @@ -347,8 +353,7 @@ def _execute_cmd(self, cmdline: str) -> bool: self._print(qmpcmd) resp = self.cmd_obj(qmpcmd) if resp is None: - print('Disconnected') - return False + raise QMPShellConnectError('Disconnected') self._print(resp) return True @@ -400,6 +405,9 @@ def read_exec_command(self) -> bool: return self._execute_cmd(cmdline) except QMPShellParseError as err: self._print_parse_error(err) + except QMPShellConnectError as err: + print(f"{err!s}"); + return False return True def repl(self) -> Iterator[None]: @@ -481,8 +489,7 @@ def _execute_cmd(self, cmdline: str) -> bool: raise QMPShellParseError('cpu command takes an integer argument') resp = self._cmd_passthrough(cmdline, self._cpu_index) if resp is None: - print('Disconnected') - return False + raise QMPShellConnectError('Disconnected') assert 'return' in resp or 'error' in resp if 'return' in resp: # Success From patchwork Mon Feb 21 15:55:18 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damien Hedde X-Patchwork-Id: 1595647 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; secure) header.d=greensocs.com header.i=@greensocs.com header.a=rsa-sha256 header.s=mail header.b=CN1F5PC0; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4K2RmX0k9wz9sGm for ; Tue, 22 Feb 2022 02:58:36 +1100 (AEDT) Received: from localhost ([::1]:38638 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nMB57-0006ko-9I for incoming@patchwork.ozlabs.org; Mon, 21 Feb 2022 10:58:33 -0500 Received: from eggs.gnu.org ([209.51.188.92]:55228) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nMB2K-0006eW-9K for qemu-devel@nongnu.org; Mon, 21 Feb 2022 10:55:40 -0500 Received: from beetle.greensocs.com ([5.135.226.135]:35576) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nMB2H-0002BZ-Gz for qemu-devel@nongnu.org; Mon, 21 Feb 2022 10:55:39 -0500 Received: from crumble.bar.greensocs.com (unknown [172.17.10.6]) by beetle.greensocs.com (Postfix) with ESMTPS id 1C56D21CCE; Mon, 21 Feb 2022 15:55:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=greensocs.com; s=mail; t=1645458935; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=adKF6/kzoZwx7qMvkl5SLyG2oeu0edQPfJy1BbduMxk=; b=CN1F5PC0yF7P87NhZuM/8+v5oCp/lta5TOIMQoRCsxgon+aW0Knvqja62tWg+CBxQVw76G 2aB5iabEPmmLmNBKIjGUYhzy/EZivUsN0dlaTZ04x60MpR2/1NtyLMY36CtUk5wQWn/xCD 10AxQ4R4OXbNLGr004348GJFMlpGgp8= From: Damien Hedde To: qemu-devel@nongnu.org Subject: [PATCH 4/5] python: qmp_shell: add -e/--exit-on-error option Date: Mon, 21 Feb 2022 16:55:18 +0100 Message-Id: <20220221155519.2367-5-damien.hedde@greensocs.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220221155519.2367-1-damien.hedde@greensocs.com> References: <20220221155519.2367-1-damien.hedde@greensocs.com> MIME-Version: 1.0 Received-SPF: pass client-ip=5.135.226.135; envelope-from=damien.hedde@greensocs.com; helo=beetle.greensocs.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Damien Hedde , Eduardo Habkost , John Snow , Cleber Rosa Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This option makes qmp_shell exit (with error code 1) as soon as one of the following error occurs: + command parsing error + disconnection + command failure (response is an error) _execute_cmd() method now returns None or the response so that read_exec_command() can do the last check. This is meant to be used in combination with an input file redirection. It allows to store a list of commands into a file and try to run them by qmp_shell and easily see if it failed or not. Signed-off-by: Damien Hedde --- python/qemu/aqmp/qmp_shell.py | 39 +++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/python/qemu/aqmp/qmp_shell.py b/python/qemu/aqmp/qmp_shell.py index cce7732ba2..dd38ef8a13 100644 --- a/python/qemu/aqmp/qmp_shell.py +++ b/python/qemu/aqmp/qmp_shell.py @@ -11,7 +11,7 @@ """ Low-level QEMU shell on top of QMP. -usage: qmp-shell [-h] [-H] [-N] [-v] [-p] qmp_server +usage: qmp-shell [-h] [-H] [-N] [-v] [-p] [-e] qmp_server positional arguments: qmp_server < UNIX socket path | TCP address:port > @@ -23,6 +23,8 @@ Skip negotiate (for qemu-ga) -v, --verbose Verbose (echo commands sent and received) -p, --pretty Pretty-print JSON + -e, --exit-on-error Exit when an error occurs (command parsing, + disconnection and command failure) Start QEMU with: @@ -177,9 +179,11 @@ class QMPShell(QEMUMonitorProtocol): :param address: Address of the QMP server. :param pretty: Pretty-print QMP messages. :param verbose: Echo outgoing QMP messages to console. + :param raise_error: Don't continue after an error occured """ def __init__(self, address: SocketAddrT, - pretty: bool = False, verbose: bool = False): + pretty: bool = False, verbose: bool = False, + raise_error: bool = False): super().__init__(address) self._greeting: Optional[QMPMessage] = None self._completer = QMPCompleter() @@ -189,6 +193,7 @@ def __init__(self, address: SocketAddrT, '.qmp-shell_history') self.pretty = pretty self.verbose = verbose + self.raise_error = raise_error def close(self) -> None: # Hook into context manager of parent to save shell history. @@ -343,19 +348,19 @@ def _print_parse_error(self, err: QMPShellParseError) -> None: file=sys.stderr ) - def _execute_cmd(self, cmdline: str) -> bool: + def _execute_cmd(self, cmdline: str) -> Optional[QMPMessage]: qmpcmd = self._build_cmd(cmdline) # For transaction mode, we may have just cached the action: if qmpcmd is None: - return True + return None if self.verbose: self._print(qmpcmd) resp = self.cmd_obj(qmpcmd) if resp is None: raise QMPShellConnectError('Disconnected') self._print(resp) - return True + return resp def connect(self, negotiate: bool = True) -> None: self._greeting = super().connect(negotiate) @@ -401,8 +406,13 @@ def read_exec_command(self) -> bool: print(event) return True + if self.raise_error: + resp = self._execute_cmd(cmdline) + if resp and 'error' in resp: + raise QMPShellError(f"Command failed: {resp['error']}") + return True try: - return self._execute_cmd(cmdline) + self._execute_cmd(cmdline) except QMPShellParseError as err: self._print_parse_error(err) except QMPShellConnectError as err: @@ -477,7 +487,7 @@ def _cmd_passthrough(self, cmdline: str, def _print_parse_error(self, err: QMPShellParseError) -> None: print(f"{err!s}") - def _execute_cmd(self, cmdline: str) -> bool: + def _execute_cmd(self, cmdline: str) -> Optional[QMPMessage]: if cmdline.split()[0] == "cpu": # trap the cpu command, it requires special setting try: @@ -498,7 +508,7 @@ def _execute_cmd(self, cmdline: str) -> bool: else: # Error print('%s: %s' % (resp['error']['class'], resp['error']['desc'])) - return True + return resp def show_banner(self, msg: str = 'Welcome to the HMP shell!') -> None: QMPShell.show_banner(self, msg) @@ -523,6 +533,9 @@ def main() -> None: help='Verbose (echo commands sent and received)') parser.add_argument('-p', '--pretty', action='store_true', help='Pretty-print JSON') + parser.add_argument('-e', '--exit-on-error', action='store_true', + help='Exit when an error occurs (command parsing,' + ' disconnection and command failure)') default_server = os.environ.get('QMP_SOCKET') parser.add_argument('qmp_server', action='store', @@ -541,7 +554,8 @@ def main() -> None: parser.error(f"Bad port number: {args.qmp_server}") return # pycharm doesn't know error() is noreturn - with shell_class(address, args.pretty, args.verbose) as qemu: + with shell_class(address, args.pretty, args.verbose, + args.exit_on_error) as qemu: try: qemu.connect(negotiate=not args.skip_negotiation) except ConnectError as err: @@ -549,8 +563,11 @@ def main() -> None: die(f"Couldn't connect to {args.qmp_server}: {err!s}") die(str(err)) - for _ in qemu.repl(): - pass + try: + for _ in qemu.repl(): + pass + except QMPShellError as err: + die(str(err)) if __name__ == '__main__': From patchwork Mon Feb 21 15:55:19 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damien Hedde X-Patchwork-Id: 1595650 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; secure) header.d=greensocs.com header.i=@greensocs.com header.a=rsa-sha256 header.s=mail header.b=T6RoeFbG; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4K2RsN5ZB0z9sGP for ; Tue, 22 Feb 2022 03:02:47 +1100 (AEDT) Received: from localhost ([::1]:44370 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nMB99-0002EK-LK for incoming@patchwork.ozlabs.org; Mon, 21 Feb 2022 11:02:43 -0500 Received: from eggs.gnu.org ([209.51.188.92]:55238) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nMB2L-0006ek-0R for qemu-devel@nongnu.org; Mon, 21 Feb 2022 10:55:41 -0500 Received: from beetle.greensocs.com ([5.135.226.135]:35588) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nMB2H-0002Bl-Tf for qemu-devel@nongnu.org; Mon, 21 Feb 2022 10:55:40 -0500 Received: from crumble.bar.greensocs.com (unknown [172.17.10.6]) by beetle.greensocs.com (Postfix) with ESMTPS id 82DEC21EBE; Mon, 21 Feb 2022 15:55:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=greensocs.com; s=mail; t=1645458936; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Ye4DkYiS7T2Juwk3S1UpOfiAeeqAlWPrmNV+EwdOzhI=; b=T6RoeFbG9DO9xOhqeSGgbH1dWhdqJ3KuTFH4I40ApJTMdLjN6OC063Q7Eti1MsZmuMNi2E hC0J4VN0fp8jys/TlhFYcUkyBgMGaW2pipqYPeKxNXhbZnOEKpHztld5cmLxVCCTyR++Ke N9C9nq9bipm1LBr4gV7N35hKdVOmY/g= From: Damien Hedde To: qemu-devel@nongnu.org Subject: [PATCH 5/5] python: qmp_shell: handle comment lines and escaped eol Date: Mon, 21 Feb 2022 16:55:19 +0100 Message-Id: <20220221155519.2367-6-damien.hedde@greensocs.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220221155519.2367-1-damien.hedde@greensocs.com> References: <20220221155519.2367-1-damien.hedde@greensocs.com> MIME-Version: 1.0 Received-SPF: pass client-ip=5.135.226.135; envelope-from=damien.hedde@greensocs.com; helo=beetle.greensocs.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Damien Hedde , Eduardo Habkost , John Snow , Cleber Rosa Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" In order to support more user-friendly command list file, this commit adds the support for: + comment lines: line staring by '#' are ignored + escaped enf-of-line: line with trailing ' \' are continued on next one For eol: we impose a space before the '\' in order not to trigger the escape if the '\' is for example at the end of a value in a 'key=value' sequence. Althought it does not have any real interest in interactive mode, the prompt is adapted when in that case. Signed-off-by: Damien Hedde --- python/qemu/aqmp/qmp_shell.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/python/qemu/aqmp/qmp_shell.py b/python/qemu/aqmp/qmp_shell.py index dd38ef8a13..64cd31dcd6 100644 --- a/python/qemu/aqmp/qmp_shell.py +++ b/python/qemu/aqmp/qmp_shell.py @@ -188,6 +188,7 @@ def __init__(self, address: SocketAddrT, self._greeting: Optional[QMPMessage] = None self._completer = QMPCompleter() self._transmode = False + self._escaped_eol = False self._actions: List[QMPMessage] = [] self._histfile = os.path.join(os.path.expanduser('~'), '.qmp-shell_history') @@ -385,6 +386,8 @@ def prompt(self) -> str: """ if not sys.stdin.isatty(): return "" + if self._escaped_eol: + return '> ' if self._transmode: return 'TRANS> ' return '(QEMU) ' @@ -397,6 +400,11 @@ def read_exec_command(self) -> bool: """ try: cmdline = input(self.prompt) + self._escaped_eol = True + while cmdline[-2:] == ' \\': + #only remove the trailing '\', keep the space + cmdline = cmdline[:-1] + input(self.prompt) + self._escaped_eol = False except EOFError: print() return False @@ -406,6 +414,10 @@ def read_exec_command(self) -> bool: print(event) return True + if cmdline[0] == '#': + #consider these lines as comments + return True + if self.raise_error: resp = self._execute_cmd(cmdline) if resp and 'error' in resp: