files.new_contents: """ Test Management Tool """
  
  from tmt.base import Tree, Test, Plan, Story, Run, Result
  from tmt.steps.provision import Guest
  
  __all__ = ['Tree', 'Test', 'Plan', 'Story', 'Run', 'Guest', 'Result']
  
  
  [... the rest is omitted ...]
files.new_path: tmt/__init__.py
files.old_contents: """ Test Management Tool """
  
  from tmt.base import Tree, Test, Plan, Story, Run, Guest, Result
  
  __all__ = ['Tree', 'Test', 'Plan', 'Story', 'Run', 'Guest', 'Result']
  
  
  [... the rest is omitted ...]
files.old_path: tmt/__init__.py
files.new_contents: 
  """ Base Metadata Classes """
  
  import os
  import re
  import fmf
  import yaml
  import click
  import pprint
  import subprocess
  
  import tmt.steps
  import tmt.utils
  import tmt.export
  import tmt.templates
  
  import tmt.steps.discover
  import tmt.steps.provision
  import tmt.steps.prepare
  import tmt.steps.execute
  import tmt.steps.report
  import tmt.steps.finish
  
  from tmt.utils import verdict
  from fmf.utils import listed
  from click import echo, style
  
  DEFAULT_TEST_DURATION = '5m'
  
  class Node(tmt.utils.Common):
      """
      General node object
  
      Corresponds to given fmf.Tree node.
      Implements common Test, Plan and Story methods.
      """
  
      # Supported attributes
      _keys = ['name']
  
      def __init__(self, node, parent=None):
          """ Initialize the node """
          super(Node, self).__init__(parent=parent, name=node.name)
          self.node = node
  
      def __str__(self):
          """ Node name """
          return self.name
  
      def _sources(self):
          """ Show source files """
          echo(tmt.utils.format(
              'sources', self.node.sources, key_color='magenta'))
  
      def _check(self, key, expected, default=None, listify=False):
          """
          Check that the key is of expected type
  
          Handle default and convert into a list if requested.
          """
          value = getattr(self, key)
          # Handle default
          if value is None:
              setattr(self, key, default)
              return
          # Check for correct type
          if not isinstance(value, expected):
              expected = tmt.utils.listify(expected)
              expected_names = fmf.utils.listed(
                  [type_.__name__ for type_ in expected], join='or')
              class_name = self.__class__.__name__.lower()
              raise tmt.utils.SpecificationError(
                  f"Invalid '{key}' in {class_name} '{self.name}' (should be "
                  f"a '{expected_names}', got a '{type(value).__name__}').")
          # Convert into a list if requested
          if listify:
              setattr(self, key, tmt.utils.listify(value))
  
      def
  
  [... the rest is omitted ...]
files.new_path: tmt/base.py
files.old_contents: 
  """ Base Metadata Classes """
  
  import os
  import re
  import fmf
  import yaml
  import click
  import pprint
  import random
  import string
  import subprocess
  
  import tmt.steps
  import tmt.utils
  import tmt.export
  import tmt.templates
  
  import tmt.steps.discover
  import tmt.steps.provision
  import tmt.steps.prepare
  import tmt.steps.execute
  import tmt.steps.report
  import tmt.steps.finish
  
  from tmt.utils import verdict
  from fmf.utils import listed
  from click import echo, style
  
  DEFAULT_TEST_DURATION = '5m'
  
  class Node(tmt.utils.Common):
      """
      General node object
  
      Corresponds to given fmf.Tree node.
      Implements common Test, Plan and Story methods.
      """
  
      # Supported attributes
      _keys = ['name']
  
      def __init__(self, node, parent=None):
          """ Initialize the node """
          super(Node, self).__init__(parent=parent, name=node.name)
          self.node = node
  
      def __str__(self):
          """ Node name """
          return self.name
  
      def _sources(self):
          """ Show source files """
          echo(tmt.utils.format(
              'sources', self.node.sources, key_color='magenta'))
  
      def _check(self, key, expected, default=None, listify=False):
          """
          Check that the key is of expected type
  
          Handle default and convert into a list if requested.
          """
          value = getattr(self, key)
          # Handle default
          if value is None:
              setattr(self, key, default)
              return
          # Check for correct type
          if not isinstance(value, expected):
              expected = tmt.utils.listify(expected)
              expected_names = fmf.utils.listed(
                  [type_.__name__ for type_ in expected], join='or')
              class_name = self.__class__.__name__.lower()
              raise tmt.utils.SpecificationError(
                  f"Invalid '{key}' in {class_name} '{self.name}' (should be "
                  f"a '{expected_names}', got a '{type(value).__name__}').")
          # Convert into a list if requested
          if listify:
              setattr(self, key, tmt.utils
  
  [... the rest is omitted ...]
files.old_path: tmt/base.py
files.new_contents: import os
  import re
  import click
  import random
  import string
  
  import fmf
  import tmt
  
  
  class Provision(tmt.steps.Step):
      """ Provision an environment for testing or use localhost """
  
      # Default implementation for provision is a virtual machine
      how = 'virtual'
  
      def __init__(self, data, plan):
          """ Initialize provision step data """
          super().__init__(data, plan)
          # List of provisioned guests and loaded guest data
          self._guests = []
          self._guest_data = {}
  
      def load(self):
          """ Load guest data from the workdir """
          super().load()
          try:
              self._guest_data = tmt.utils.yaml_to_dict(self.read('guests.yaml'))
          except tmt.utils.FileError:
              self.debug('Provisioned guests not found.', level=2)
  
      def save(self):
          """ Save guest data to the workdir """
          super().save()
          try:
              guests = dict(
                  [(guest.name, guest.save()) for guest in self.guests()])
              self.write('guests.yaml', tmt.utils.dict_to_yaml(guests))
          except tmt.utils.FileError:
              self.debug('Failed to save provisioned guests.')
  
      def wake(self):
          """ Wake up the step (process workdir and command line) """
          super().wake()
  
          # Choose the right plugin and wake it up
          for data in self.data:
              plugin = ProvisionPlugin.delegate(self, data)
              self._plugins.append(plugin)
              # If guest data loaded, perform a complete wake up
              plugin.wake(data=self._guest_data.get(plugin.name))
              if plugin.guest():
                  self._guests.append(plugin.guest())
  
          # Nothing more to do if already done
          if self.status() == 'done':
              self.debug(
                  'Provision wake up complete (already done before).', level=2)
          # Save status and step data (now we know what to do)
          else:
              self.status('todo')
              self.save()
  
      def show(self):
          """ Show discover details """
          for data in self.data:
              ProvisionPlugin.delegate(self, data).show()
  
      def summary(self):
          """ Give a concise summary of the provisioning """
          # Summary of provisioned guests
          guests = fmf.utils.listed
  
  [... the rest is omitted ...]
files.new_path: tmt/steps/provision/__init__.py
files.old_contents: import os
  import click
  
  import fmf
  import tmt
  
  class Provision(tmt.steps.Step):
      """ Provision an environment for testing or use localhost """
  
      # Default implementation for provision is a virtual machine
      how = 'virtual'
  
      def __init__(self, data, plan):
          """ Initialize provision step data """
          super().__init__(data, plan)
          # List of provisioned guests and loaded guest data
          self._guests = []
          self._guest_data = {}
  
      def load(self):
          """ Load guest data from the workdir """
          super().load()
          try:
              self._guest_data = tmt.utils.yaml_to_dict(self.read('guests.yaml'))
          except tmt.utils.FileError:
              self.debug('Provisioned guests not found.', level=2)
  
      def save(self):
          """ Save guest data to the workdir """
          super().save()
          try:
              guests = dict(
                  [(guest.name, guest.save()) for guest in self.guests()])
              self.write('guests.yaml', tmt.utils.dict_to_yaml(guests))
          except tmt.utils.FileError:
              self.debug('Failed to save provisioned guests.')
  
      def wake(self):
          """ Wake up the step (process workdir and command line) """
          super().wake()
  
          # Choose the right plugin and wake it up
          for data in self.data:
              plugin = ProvisionPlugin.delegate(self, data)
              self._plugins.append(plugin)
              # If guest data loaded, perform a complete wake up
              plugin.wake(data=self._guest_data.get(plugin.name))
              if plugin.guest():
                  self._guests.append(plugin.guest())
  
          # Nothing more to do if already done
          if self.status() == 'done':
              self.debug(
                  'Provision wake up complete (already done before).', level=2)
          # Save status and step data (now we know what to do)
          else:
              self.status('todo')
              self.save()
  
      def show(self):
          """ Show discover details """
          for data in self.data:
              ProvisionPlugin.delegate(self, data).show()
  
      def summary(self):
          """ Give a concise summary of the provisioning """
          # Summary of provisioned guests
          guests = fmf.utils.listed(self.guests(), 'guest')
         
  
  [... the rest is omitted ...]
files.old_path: tmt/steps/provision/__init__.py
files.new_contents: import tmt
  import click
  
  class ProvisionConnect(tmt.steps.provision.ProvisionPlugin):
      """
      Connect to a provisioned guest using ssh
  
      Private key authentication:
  
          provision:
              how: connect
              guest: host.example.org
              user: root
              key: /home/psss/.ssh/example_rsa
  
      Password authentication:
  
          provision:
              how: connect
              guest: host.example.org
              user: root
              password: secret
  
      User defaults to 'root', so if you have private key correctly set
      the minimal configuration can look like this:
  
          provision:
              how: connect
              guest: host.example.org
      """
  
      # Guest instance
      _guest = None
  
      # Supported methods
      _methods = [tmt.steps.Method(name='connect', doc=__doc__, order=50)]
  
      @classmethod
      def options(cls, how=None):
          """ Prepare command line options for connect """
          return [
              click.option(
                  '-g', '--guest', metavar='GUEST',
                  help='Select remote host to connect to (hostname or ip).'),
              click.option(
                  '-k', '--key', metavar='PRIVATE_KEY',
                  help='Private key for login into the guest system.'),
              click.option(
                  '-u', '--user', metavar='USER',
                  help='Username to use for all guest operations.'),
              click.option(
                  '-p', '--password', metavar='PASSWORD',
                  help='Password for login into the guest system.'),
              ] + super().options(how)
  
      def default(self, option, default=None):
          """ Return default data for given option """
          # User root as the default user
          if option == 'user':
              return 'root'
          # No other defaults available
          return default
  
      def show(self):
          """ Show provision details """
          super().show(['guest', 'key', 'user', 'password'])
  
      def wake(self, data=None):
          """ Override options and wake up the guest """
          super().wake(['guest', 'key', 'user', 'password'])
          if data:
              self._guest = tmt.Guest(data, name=self.name, parent=self.step)
  
      def go(self):
          """ Prepare the connection """
          super
  
  [... the rest is omitted ...]
files.new_path: tmt/steps/provision/connect.py
files.old_contents: import tmt
  import click
  
  class ProvisionConnect(tmt.steps.provision.ProvisionPlugin):
      """
      Connect to a provisioned guest using ssh
  
      Private key authentication:
  
          provision:
              how: connect
              guest: host.example.org
              user: root
              key: /home/psss/.ssh/example_rsa
  
      Password authentication:
  
          provision:
              how: connect
              guest: host.example.org
              user: root
              password: secret
  
      User defaults to 'root', so if you have private key correctly set
      the minimal configuration can look like this:
  
          provision:
              how: connect
              guest: host.example.org
      """
  
      # Guest instance
      _guest = None
  
      # Supported methods
      _methods = [tmt.steps.Method(name='connect', doc=__doc__, order=50)]
  
      @classmethod
      def options(cls, how=None):
          """ Prepare command line options for connect """
          return [
              click.option(
                  '-g', '--guest', metavar='GUEST',
                  help='Select remote host to connect to (hostname or ip).'),
              click.option(
                  '-k', '--key', metavar='PRIVATE_KEY',
                  help='Private key for login into the guest system.'),
              click.option(
                  '-u', '--user', metavar='USER',
                  help='Username to use for all guest operations.'),
              click.option(
                  '-p', '--password', metavar='PASSWORD',
                  help='Password for login into the guest system.'),
              ] + super().options(how)
  
      def default(self, option, default=None):
          """ Return default data for given option """
          # User root as the default user
          if option == 'user':
              return 'root'
          # No other defaults available
          return default
  
      def show(self):
          """ Show provision details """
          super().show(['guest', 'key', 'user', 'password'])
  
      def wake(self, data=None):
          """ Override options and wake up the guest """
          super().wake(['guest', 'key', 'user', 'password'])
          if data:
              self._guest = tmt.Guest(data, name=self.name, parent=self.step)
  
      def go(self):
          """ Prepare the connection """
          super
  
  [... the rest is omitted ...]
files.old_path: tmt/steps/provision/connect.py