usr/src/lib/install_transfer/ips.py
changeset 1721 4ee0239d9a9f
parent 1709 ee7123806386
child 1723 d23bbc08f2ac
equal deleted inserted replaced
1720:ebaf262338a3 1721:4ee0239d9a9f
    27 
    27 
    28 import abc
    28 import abc
    29 import copy
    29 import copy
    30 import gettext
    30 import gettext
    31 import locale
    31 import locale
       
    32 import logging
    32 import os
    33 import os
    33 import shutil
    34 import shutil
       
    35 import sys
    34 
    36 
    35 import pkg.client.api as api
    37 import pkg.client.api as api
    36 import pkg.client.api_errors as api_errors
    38 import pkg.client.api_errors as api_errors
    37 import pkg.client.image as image
    39 import pkg.client.image as image
    38 import pkg.client.progress as progress
    40 import pkg.client.progress as progress
       
    41 import pkg.client.printengine as printengine
    39 import pkg.client.publisher as publisher
    42 import pkg.client.publisher as publisher
    40 import pkg.misc as misc
    43 import pkg.misc as misc
    41 
    44 
    42 from pkg.fmri import PkgFmri
    45 from pkg.fmri import PkgFmri
    43 from pkg.client import global_settings
    46 from pkg.client import global_settings
    68 
    71 
    69 global_settings.client_name = PKG_CLIENT_NAME
    72 global_settings.client_name = PKG_CLIENT_NAME
    70 misc.setlocale(locale.LC_ALL, "")
    73 misc.setlocale(locale.LC_ALL, "")
    71 gettext.install("pkg", "/usr/share/locale")
    74 gettext.install("pkg", "/usr/share/locale")
    72 
    75 
    73 
       
    74 class InstallCLIProgressTracker(progress.NullProgressTracker):
       
    75     ''' Subclass of the IPS api's NullProgressTracker to handle a simple
       
    76         form of progress reporting.  If requested with 'show_stdout', we
       
    77         output progress to stdout by posting a logging INFO message.
       
    78         Otherwise we just output progress to log files by posting a
       
    79         logging DEBUG message.
       
    80     '''
       
    81 
       
    82     def __init__(self, trans_logger, show_stdout=False):
       
    83         super(InstallCLIProgressTracker, self).__init__()
       
    84         self.trans_logger = trans_logger
       
    85         self.show_stdout = show_stdout
       
    86         self._dl_cur_pkg = None
       
    87         self._dl_started = False
       
    88         self._act_started = False
       
    89         self._ind_started = False
       
    90         self._item_started = False
       
    91         self._package_dict = {}
       
    92 
       
    93     def _logger_output(self, message):
       
    94         if self.show_stdout:
       
    95             self.trans_logger.info(message)
       
    96         else:
       
    97             self.trans_logger.debug(message)
       
    98 
       
    99     def eval_output_start(self):
       
   100         self._logger_output("Creating Plan ... Started.")
       
   101 
       
   102     def eval_output_done(self):
       
   103         self._logger_output("Creating Plan ... Done.")
       
   104 
       
   105     def refresh_output_start(self):
       
   106         self._logger_output("Refreshing Catalog ... Started.")
       
   107 
       
   108     def refresh_output_done(self):
       
   109         self._logger_output("Refreshing Catalog ... Done.")
       
   110 
       
   111     def dl_output(self):
       
   112         if not self._dl_started:
       
   113             self._logger_output("Download Phase ... Started.")
       
   114             self._dl_started = True
       
   115 
       
   116         if self._dl_cur_pkg != self.cur_pkg:
       
   117             if (self.cur_pkg in self._package_dict):
       
   118                 fmri = self._package_dict[self.cur_pkg]
       
   119                 self._logger_output("Download: %s ..." % fmri.get_fmri())
       
   120             else:
       
   121                 # only hits this at end when the cur_pkg becomes empty str
       
   122                 self._logger_output("Download: %s ..." % self.cur_pkg)
       
   123             self._dl_cur_pkg = self.cur_pkg
       
   124 
       
   125     def dl_output_done(self):
       
   126         self._logger_output("Download Phase ... Done.")
       
   127         self._dl_started = False
       
   128         self._dl_cur_pkg = None
       
   129 
       
   130     def act_output(self, force=False):
       
   131         if not self._act_started:
       
   132             self._logger_output("%s ... Started." % self.act_phase)
       
   133             self._act_started = True
       
   134 
       
   135     def act_output_done(self):
       
   136         self._logger_output("%s ... Done." % self.act_phase)
       
   137         self._act_started = False
       
   138 
       
   139     def ind_output(self, force=False):
       
   140         if not self._ind_started:
       
   141             self._logger_output("%s ... Started." % self.ind_phase)
       
   142             self._ind_started = True
       
   143 
       
   144     def ind_output_done(self):
       
   145         self._logger_output("%s ... Done." % self.ind_phase)
       
   146         self._ind_started = False
       
   147 
       
   148     def item_output(self, force=False):
       
   149         if not self._item_started:
       
   150             self._logger_output("%s ... Started." % self.item_phase)
       
   151             self._item_started = True
       
   152 
       
   153     def item_output_done(self):
       
   154         self._logger_output("%s ... Done." % self.item_phase)
       
   155         self._item_started = False
       
   156 
       
   157     def set_package_dict(self, package_dict):
       
   158         self._package_dict = package_dict
       
   159 
       
   160 
       
   161 class InstallFancyProgressTracker(progress.FancyUNIXProgressTracker):
       
   162     ''' Subclass of the IPS api's FancyUNIXProgressTracker; we leverage
       
   163         that class's progress reporting, allowing it to output straight to
       
   164         stdout.  The overridden methods we define allow us to capture the
       
   165         parts of the progress that we want recorded to the install log.
       
   166 
       
   167         This progress tracking class should only be used when the
       
   168         application is being run on a terminal with UNIX-like semantics
       
   169         and will fail to initialize otherwise.
       
   170     '''
       
   171     def __init__(self, trans_logger, quiet=False, verbose=0):
       
   172         super(InstallFancyProgressTracker, self).__init__(quiet=quiet,
       
   173             verbose=verbose)
       
   174 
       
   175         self.trans_logger = trans_logger
       
   176         self._dl_cur_pkg = None
       
   177         self._dl_started = False
       
   178         self._act_started = False
       
   179         self._ind_started = False
       
   180         self._item_started = False
       
   181         self._package_dict = {}
       
   182 
       
   183     def eval_output_start(self):
       
   184         super(InstallFancyProgressTracker, self).eval_output_start()
       
   185         self.trans_logger.debug("Creating Plan ... Started.")
       
   186 
       
   187     def eval_output_done(self):
       
   188         super(InstallFancyProgressTracker, self).eval_output_done()
       
   189         self.trans_logger.debug("Creating Plan ... Done.")
       
   190 
       
   191     def refresh_output_start(self):
       
   192         super(InstallFancyProgressTracker, self).refresh_output_start()
       
   193         self.trans_logger.debug("Refreshing Catalog ... Started.")
       
   194 
       
   195     def refresh_output_done(self):
       
   196         super(InstallFancyProgressTracker, self).refresh_output_done()
       
   197         self.trans_logger.debug("Refreshing Catalog ... Done.")
       
   198 
       
   199     def dl_output(self, force=False):
       
   200         super(InstallFancyProgressTracker, self).dl_output(force=force)
       
   201         if not self._dl_started:
       
   202             self.trans_logger.debug("Download Phase ... Started.")
       
   203             self._dl_started = True
       
   204 
       
   205         if self._dl_cur_pkg != self.cur_pkg:
       
   206             if (self.cur_pkg in self._package_dict):
       
   207                 fmri = self._package_dict[self.cur_pkg]
       
   208                 self.trans_logger.debug("Download: %s ..." % fmri.get_fmri())
       
   209             else:
       
   210                 # only hits this at end when the cur_pkg becomes empty str
       
   211                 self.trans_logger.debug("Download: %s ..." % self.cur_pkg)
       
   212             self._dl_cur_pkg = self.cur_pkg
       
   213 
       
   214     def dl_output_done(self):
       
   215         super(InstallFancyProgressTracker, self).dl_output_done()
       
   216         self.trans_logger.debug("Download Phase ... Done.")
       
   217         self._dl_started = False
       
   218         self._dl_cur_pkg = None
       
   219 
       
   220     def act_output(self, force=False):
       
   221         super(InstallFancyProgressTracker, self).act_output(force=force)
       
   222         if not self._act_started:
       
   223             self.trans_logger.debug("%s ... Started." % self.act_phase)
       
   224             self._act_started = True
       
   225 
       
   226     def act_output_done(self):
       
   227         super(InstallFancyProgressTracker, self).act_output_done()
       
   228         self.trans_logger.debug("%s ... Done." % self.act_phase)
       
   229         self._act_started = False
       
   230 
       
   231     def ind_output(self, force=False):
       
   232         super(InstallFancyProgressTracker, self).ind_output(force=force)
       
   233         if not self._ind_started:
       
   234             self.trans_logger.debug("%s ... Started." % self.ind_phase)
       
   235             self._ind_started = True
       
   236 
       
   237     def ind_output_done(self):
       
   238         super(InstallFancyProgressTracker, self).ind_output_done()
       
   239         self.trans_logger.debug("%s ... Done." % self.ind_phase)
       
   240         self._ind_started = False
       
   241 
       
   242     def item_output(self, force=False):
       
   243         super(InstallFancyProgressTracker, self).item_output(force=force)
       
   244         if not self._item_started:
       
   245             self.trans_logger.debug("%s ... Started." % self.item_phase)
       
   246             self._item_started = True
       
   247 
       
   248     def item_output_done(self):
       
   249         super(InstallFancyProgressTracker, self).item_output_done()
       
   250         self.trans_logger.debug("%s ... Done." % self.item_phase)
       
   251         self._item_started = False
       
   252 
       
   253     def set_package_dict(self, package_dict):
       
   254         self._package_dict = package_dict
       
   255 
       
   256 
       
   257 class AbstractIPS(Checkpoint):
    76 class AbstractIPS(Checkpoint):
   258     '''Subclass for transfer IPS checkpoint'''
    77     '''Subclass for transfer IPS checkpoint'''
   259     __metaclass__ = abc.ABCMeta
    78     __metaclass__ = abc.ABCMeta
   260 
    79 
   261     # Variables associated with the package image
    80     # Variables associated with the package image
   262     DEF_REPO_URI = "http://pkg.opensolaris.org/release"
    81     DEF_REPO_URI = "http://pkg.opensolaris.org/release"
   263     DEF_PROG_TRACKER = progress.CommandLineProgressTracker()
       
   264 
    82 
   265     # Variables used in calculating the image size
    83     # Variables used in calculating the image size
   266     DEFAULT_PROG_EST = 10
    84     DEFAULT_PROG_EST = 10
   267     DEFAULT_SIZE = 1000
    85     DEFAULT_SIZE = 1000
   268     DEFAULT_PKG_NUM = 5
    86     DEFAULT_PKG_NUM = 5
   309 
   127 
   310         # Flag to cancel whatever action is going on.
   128         # Flag to cancel whatever action is going on.
   311         self._cancel_event = False
   129         self._cancel_event = False
   312 
   130 
   313         # Set the progress tracker for IPS operations.
   131         # Set the progress tracker for IPS operations.
       
   132         trackers = []
   314         if self.show_stdout:
   133         if self.show_stdout:
   315             # If we've been requested to show progress to stdout, try to
   134             # Try to create a Fancy progress tracker.  If we're not running on a
   316             # intantiate the Fancy progress tracker.  If we're not running
   135             # capable terminal, then bump the loglevel up to INFO.  This is a
   317             # on a capable terminal, fall back to the CLI progress tracker.
   136             # hack, but it will cause the log messages to appear on stdout
       
   137             # and in the log file.
   318             try:
   138             try:
   319                 self.prog_tracker = InstallFancyProgressTracker(self.logger)
   139                 t = progress.FancyUNIXProgressTracker(output_file=sys.stdout)
       
   140                 trackers.append(t)
       
   141                 loglevel = logging.DEBUG
   320             except progress.ProgressTrackerException:
   142             except progress.ProgressTrackerException:
   321                 self.prog_tracker = InstallCLIProgressTracker(self.logger,
   143                 loglevel = logging.INFO
   322                     show_stdout=self.show_stdout)
       
   323         else:
   144         else:
   324             # Else if we've not been requested to show progress at all,
   145             loglevel = logging.DEBUG
   325             # instantiate the the CLI progress tracker.
   146 
   326             self.prog_tracker = InstallCLIProgressTracker(self.logger,
   147         # Set up the logging progress tracker-- this is a
   327                 show_stdout=self.show_stdout)
   148         # CommandLineProgressTracker hooked up to a special printengine.
       
   149         pe = printengine.LoggingPrintEngine(self.logger, loglevel)
       
   150         logt = progress.CommandLineProgressTracker(print_engine=pe)
       
   151         trackers.append(logt)
       
   152 
       
   153         self.prog_tracker = progress.MultiProgressTracker(trackers)
   328 
   154 
   329         # local attributes used to create the publisher.
   155         # local attributes used to create the publisher.
   330         self._publ = None
   156         self._publ = None
   331         self._origin = []
   157         self._origin = []
   332         self._mirror = []
   158         self._mirror = []
   747                                                      licensed[fmri][0])
   573                                                      licensed[fmri][0])
   748                             self.logger.info("Package licenses may be viewed "
   574                             self.logger.info("Package licenses may be viewed "
   749                                 "using the command:")
   575                                 "using the command:")
   750                             self.logger.info("  pkg info --license <pkg_fmri>")
   576                             self.logger.info("  pkg info --license <pkg_fmri>")
   751 
   577 
   752                         # building up a collection of packages so we have
   578                         # Describe the install plan in the debug log.
   753                         # the publisher and version info for each package
       
   754                         package_dict = {}
       
   755                         plan = self.api_inst.describe().get_changes()
   579                         plan = self.api_inst.describe().get_changes()
   756                         for pkg_plan in plan:
   580                         self.logger.debug("Installation Plan:")
   757                             fmri = PkgFmri(pkg_plan[1].__str__())
   581                         for src_pkg, dest_pkg in plan:
   758                             package_dict[fmri.get_name()] = fmri
   582                             self.logger.debug("    %s" % str(dest_pkg))
   759                         self.prog_tracker.set_package_dict(package_dict)
       
   760 
   583 
   761                         # Execute the transfer action
   584                         # Execute the transfer action
   762                         self.api_inst.prepare()
   585                         self.api_inst.prepare()
   763                         self.api_inst.execute_plan()
   586                         self.api_inst.execute_plan()
   764                         self.api_inst.reset()
   587                         self.api_inst.reset()