pre-install package support with zypp
authorGui Chen <gui.chen@intel.com>
Fri, 13 Apr 2012 02:26:04 +0000 (10:26 +0800)
committerGui Chen <gui.chen@intel.com>
Fri, 13 Apr 2012 02:26:04 +0000 (10:26 +0800)
use '%prepackages' in ks file to specify the packages needed to be pre-installed,
pre-installing would not run with scriptlet, and it's only used for zypp now.

Signed-off-by: Gui Chen <gui.chen@intel.com>
mic/imager/baseimager.py
mic/kickstart/__init__.py
mic/utils/rpmmisc.py
plugins/backend/yumpkgmgr.py
plugins/backend/zypppkgmgr.py

index 1658a04..83bdc01 100644 (file)
@@ -834,6 +834,14 @@ class BaseImageCreator(object):
         for rpm_path in self._get_local_packages():
             pkg_manager.installLocal(rpm_path)
 
+    def __preinstall_packages(self, pkg_manager):
+        if not self.ks:
+            return
+
+        self._preinstall_pkgs = kickstart.get_pre_packages(self.ks)
+        for pkg in self._preinstall_pkgs:
+            pkg_manager.preInstall(pkg)
+
     def install(self, repo_urls = {}):
         """Install packages into the install root.
 
@@ -882,6 +890,7 @@ class BaseImageCreator(object):
 
         try:
             try:
+                self.__preinstall_packages(pkg_manager)
                 self.__select_packages(pkg_manager)
                 self.__select_groups(pkg_manager)
                 self.__deselect_packages(pkg_manager)
index 36e8feb..d306fb3 100644 (file)
@@ -25,6 +25,7 @@ import string
 from mic import msger
 from mic.utils import errors, misc, runner, fs_related as fs
 
+import pykickstart.sections as kssections
 import pykickstart.commands as kscommands
 import pykickstart.constants as ksconstants
 import pykickstart.errors as kserrors
@@ -38,6 +39,21 @@ import custom_commands.moblinrepo as moblinrepo
 import custom_commands.micboot as micboot
 import custom_commands.partition as partition
 
+class PrepackageSection(kssections.Section):
+    sectionOpen = "%prepackages"
+
+    def handleLine(self, line):
+        if not self.handler:
+            return
+
+        (h, s, t) = line.partition('#')
+        line = h.rstrip()
+
+        self.handler.prepackages.add([line])
+
+    def handleHeader(self, lineno, args):
+        kssections.Section.handleHeader(self, lineno, args)
+
 def read_kickstart(path):
     """Parse a kickstart file and return a KickstartParser instance.
 
@@ -64,8 +80,10 @@ def read_kickstart(path):
     class KSHandlers(superclass):
         def __init__(self, mapping={}):
             superclass.__init__(self, mapping=commandMap[using_version])
+            self.prepackages = ksparser.Packages()
 
     ks = ksparser.KickstartParser(KSHandlers())
+    ks.registerSection(PrepackageSection(ks.handler))
 
     try:
         ks.readKickstart(path)
@@ -734,6 +752,9 @@ def convert_method_to_repo(ks):
     except (AttributeError, kserrors.KickstartError):
         pass
 
+def get_pre_packages(ks, required = []):
+    return ks.handler.prepackages.packageList + required
+
 def get_packages(ks, required = []):
     return ks.handler.packages.packageList + required
 
index ed63dc2..fd25fe8 100644 (file)
@@ -109,6 +109,7 @@ class RPMInstallCallback:
         self.ts = ts
         self.filelog = False
         self.logString = []
+        self.headmsg = "Installing"
 
     def _dopkgtup(self, hdr):
         tmpepoch = hdr['epoch']
@@ -217,7 +218,7 @@ class RPMInstallCallback:
                         pkgname = os.path.basename(rpmloc)
                 if self.output and (sys.stdout.isatty() or self.total_installed == self.total_actions):
                     fmt = self._makefmt(percent)
-                    msg = fmt % ("Installing", pkgname)
+                    msg = fmt % (self.headmsg, pkgname)
                     if msg != self.lastmsg:
                         self.lastmsg = msg
 
index b855034..efa26bd 100644 (file)
@@ -173,6 +173,10 @@ class Yum(BackendPlugin, yum.YumBase):
         self.doRepoSetup()
         self.doSackSetup()
 
+    def preInstall(self, pkg):
+        # FIXME: handle pre-install package
+        return None
+
     def selectPackage(self, pkg):
         """Select a given package.
         Can be specified with name.arch or name*
index a700dc4..8df1f6d 100755 (executable)
@@ -66,9 +66,12 @@ class Zypp(BackendPlugin):
         self.repo_manager_options = None
         self.Z = None
         self.ts = None
-        self.probFilterFlags = []
+        self.ts_pre = None
         self.incpkgs = {}
         self.excpkgs = {}
+        self.pre_pkgs = []
+        self.probFilterFlags = [ rpm.RPMPROB_FILTER_OLDPACKAGE,
+                                 rpm.RPMPROB_FILTER_REPLACEPKG ]
 
         self.has_prov_query = True
 
@@ -85,6 +88,10 @@ class Zypp(BackendPlugin):
             self.ts.closeDB()
             self.ts = None
 
+        if self.ts_pre:
+            self.ts_pre.closeDB()
+            self.ts = None
+
         self.closeRpmDB()
 
         if not os.path.exists("/etc/fedora-release") and \
@@ -370,6 +377,9 @@ class Zypp(BackendPlugin):
     def installHasFile(self, file):
         return False
 
+    def preInstall(self, pkg):
+        self.pre_pkgs.append(pkg)
+
     def runInstall(self, checksize = 0):
         os.environ["HOME"] = "/"
         self.buildTransaction()
@@ -636,6 +646,34 @@ class Zypp(BackendPlugin):
                 self.close()
                 raise
 
+    def preinstallPkgs(self):
+        if not self.ts_pre:
+            self.__initialize_transaction()
+
+        self.ts_pre.order()
+        cb = rpmmisc.RPMInstallCallback(self.ts_pre)
+        cb.headmsg = "Preinstall"
+        installlogfile = "%s/__catched_stderr.buf" % (self.instroot)
+
+        # start to catch stderr output from librpm
+        msger.enable_logstderr(installlogfile)
+
+        errors = self.ts_pre.run(cb.callback, '')
+        # stop catch
+        msger.disable_logstderr()
+        self.ts_pre.closeDB()
+        self.ts_pre = None
+
+        if errors is not None:
+            if len(errors) == 0:
+                msger.warning('scriptlet or other non-fatal errors occurred '
+                              'during transaction.')
+
+            else:
+                for e in errors:
+                    msger.warning(e[0])
+                raise RepoError('Could not run transaction.')
+
     def installPkgs(self, package_objects):
         if not self.ts:
             self.__initialize_transaction()
@@ -645,6 +683,7 @@ class Zypp(BackendPlugin):
         for flag in self.probFilterFlags:
             probfilter |= flag
         self.ts.setProbFilter(probfilter)
+        self.ts_pre.setProbFilter(probfilter)
 
         localpkgs = self.localpkgs.keys()
 
@@ -670,10 +709,18 @@ class Zypp(BackendPlugin):
                 raise RpmError("Error: %s doesn't exist" % rpmpath)
 
             h = rpmmisc.readRpmHeader(self.ts, rpmpath)
+
+            if pkgname in self.pre_pkgs:
+                msger.verbose("pre-install package added: %s" % pkgname)
+                self.ts_pre.addInstall(h, rpmpath, 'u')
+
             self.ts.addInstall(h, rpmpath, 'u')
 
         unresolved_dependencies = self.ts.check()
         if not unresolved_dependencies:
+            if self.pre_pkgs:
+                self.preinstallPkgs()
+
             self.ts.order()
             cb = rpmmisc.RPMInstallCallback(self.ts)
             installlogfile = "%s/__catched_stderr.buf" % (self.instroot)
@@ -725,6 +772,13 @@ class Zypp(BackendPlugin):
             # Set to not verify DSA signatures.
             self.ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES|rpm._RPMVSF_NODIGESTS)
 
+        if not self.ts_pre:
+            self.ts_pre = rpm.TransactionSet(self.instroot)
+            # Just unpack the files, don't run scripts
+            self.ts_pre.setFlags(rpm.RPMTRANS_FLAG_ALLFILES | rpm.RPMTRANS_FLAG_NOSCRIPTS)
+            # Set to not verify DSA signatures.
+            self.ts_pre.setVSFlags(rpm._RPMVSF_NOSIGNATURES|rpm._RPMVSF_NODIGESTS)
+
     def checkPkg(self, pkg):
         ret = 1
         if not os.path.exists(pkg):