#
# Rumba - Structured command results
#
#    Copyright (C) 2017-2026 imec
#
#    Dimitri Staessens <dimitri.staessens@ugent.be>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., http://www.fsf.org/about/contact/.
#

import dataclasses


class CommandError(Exception):
    """Raised when a command returns a non-zero exit code."""

    def __init__(self, result):
        self.result = result
        msg = ("Command '%s' on node '%s' failed with exit code %d.\n"
               "stdout: %s\nstderr: %s"
               % (result.command, result.node, result.exit_code,
                  result.stdout, result.stderr))
        super().__init__(msg)


@dataclasses.dataclass
class CommandResult:
    """Structured result of a command execution."""
    exit_code: int
    stdout: str
    stderr: str
    command: str
    node: str

    @property
    def succeeded(self):
        """True if the command exited with code 0."""
        return self.exit_code == 0

    def check(self):
        """Raise CommandError if exit code is non-zero.

        :returns: self (for chaining).
        :raises CommandError: If exit code is non-zero.
        """
        if not self.succeeded:
            raise CommandError(self)
        return self
