text: import abc
  import logging
  from typing import Set
  
  from piper.config.pipe import Pipe
  from piper.config.reader import get_pipe_name, read_all_pipes
  from piper.custom.tasks import performer
  from piper.tools.python import main_python, Python
  
  logger = logging.getLogger(__name__)
  
  
  class PiperCommand(abc.ABC):
  
      def __init__(self, python: Python = main_python):
          self.main_python = python
  
      @abc.abstractmethod
      def _phase_name(self) -> str:
          pass
  
      def _perform_tasks(self, pipe: Pipe, step: str):
          return performer.perform_tasks(self._phase_name(), step, pipe)
  
      @abc.abstractmethod
      def _manage(self, pipe: Pipe):
          pass
  
      def _manage_from_pipe_recursive(self, pipe: Pipe, done: Set[Pipe]):
  
          if not pipe.group:
  
              # Manage dependencies first, then the pipe
              for p in [*pipe.flat_dependencies(), pipe]:
                  if p not in done:
                      logger.info("")
                      logger.info("="*60)
                      logger.info(f"=== {p.name.center(52, ' ')} ===")
                      logger.info("="*60)
                      self._perform_tasks(p, "pre")
                      self._manage(p)
                      self._perform_tasks(p, "post")
                      logger.info("=" * 60)
                      logger.info("")
                      logger.info("")
                      done.add(p)
  
          else:
  
              # Manage each element of the group
              for pipe in pipe.group:
                  self._manage_from_pipe_recursive(pipe, done=done)
  
      def manage_from_pipe(self, pipe: Pipe):
          self._manage_from_pipe_recursive(pipe, done=set())
  
      def manage(self, context: str, package: str = None) -> (Pipe, Pipe):
  
          # Read the target pipe and all the pipes
          target = package or get_pipe_name(context)
          pipes = read_all_pipes(context)
  
          # Manage this target pipe
          if target not in pipes:
              raise ValueError(f"The specified pipe does not exist: {context}")
          pipe = pipes[target]
          self.manage_from_pipe(pipe)
          return pipe, pipes
  