Merged from trunk 10654:10690
authorFabian Groffen <grobian@gentoo.org>
Tue, 17 Jun 2008 16:48:53 +0000 (16:48 -0000)
committerFabian Groffen <grobian@gentoo.org>
Tue, 17 Jun 2008 16:48:53 +0000 (16:48 -0000)
   | 10656   | Fix config._accept_chost_re so it's only an instance         |
   | zmedico | variable.                                                    |

   | 10658   | Add some write access checks in post_merge() in order to     |
   | zmedico | avoid triggering permission related exceptions.              |

   | 10659   | Make some post_merge() things conditional on the vdb lock    |
   | zmedico | being held (mtimedb commit and info dirs processing).        |

   | 10660   | Bug #223417 - Due to 1 second mtime granularity in <         |
   | zmedico | python-1.5, mtime checks are not always sufficient to        |
   |         | invalidate vardbapi caches. Therefore, the caches need to be |
   |         | actively invalidated when packages are added and removed.    |

   | 10661   | Re-enable vardbapi.cpv_all() cache now that bug #223417 is   |
   | zmedico | solved.                                                      |

   | 10669   | Tweak the config._accept_chost() regex.                      |
   | zmedico |                                                              |

   | 10671   | Document the new ACCEPT_CHOSTS variable.                     |
   | zmedico |                                                              |

   | 10673   | Fix typo.                                                    |
   | zmedico |                                                              |

   | 10675   | Add support for an new "eblank" elog function that shows a   |
   | zmedico | blank line. Consecutive eblank calls are all collapsed into  |
   |         | a single blank line. Thanks to Joe Peterson <lavajoe@g.o>    |
   |         | for this patch.                                              |

   | 10677   | * Rename NEUTRAL color to BLANK for eblank. * Document the   |
   | zmedico | new BLANK code in color.map.5. * Implement python version of |
   |         | eblank for mod_echo.                                         |

   | 10679   | Fix BLANK order and color.                                   |
   | zmedico |                                                              |

   | 10681   | Add "blank" to the default PORTAGE_ELOG_CLASSES setting.     |
   | zmedico |                                                              |

   | 10683   | Add a "Interaction with previous installed version" section  |
   | zmedico | to document the upgrade/downgrade phase execution order      |
   |         | change from bug #226505.                                     |

   | 10685   | Add note about bug #226505.                                  |
   | zmedico |                                                              |

   | 10687   | * Document eblank and eqawarn in the ebuild.5 man page. *    |
   | zmedico | Create "Ebuild Helper Functions" section docbook format,     |
   |         | including all the functions documented in the ebuild.5 man   |
   |         | page.                                                        |

   | 10690   | fix typo                                                     |
   | genone  |                                                              |

svn path=/main/branches/prefix/; revision=10692

17 files changed:
RELEASE-NOTES
bin/isolated-functions.sh
cnf/make.conf
cnf/make.globals
doc/package/ebuild.docbook
doc/package/ebuild/helper_functions.docbook [new file with mode: 0644]
doc/package/ebuild/phases.docbook
doc/portage.docbook
man/color.map.5
man/ebuild.5
man/emerge.1
man/make.conf.5
pym/_emerge/__init__.py
pym/portage/__init__.py
pym/portage/dbapi/vartree.py
pym/portage/elog/mod_echo.py
pym/portage/output.py

index 49a0e5941bc6c842cde2d1d4361f54dd357a2ed3..6b15a2f728741169535d5feda94d25c046290d7a 100644 (file)
@@ -35,6 +35,15 @@ portage-2.2
 portage-2.1.5
 ==================================
 
+* The pkg_postinst phase is now called after the previous version of a
+  package has been removed. As a consequence, it is no longer possible
+  to call has_version in pkg_postinst to detect whether the current
+  install operation is an upgrade or downgrade. If this information is
+  needed during the pkg_postinst phase, do the has_version call in an
+  earlier phase (such as pkg_preinst) and store the result in a global
+  variable to be accessed by pkg_postinst when it is called. Bug #226505
+  tracks all issues related to this phase execution order change.
+
 * Blockers are now resolved automatically in many more cases
   than before.  When it's safe, blocked packages are uninstalled
   automatically so that users are no longer inconvenienced with the
index e23af3cb687ac2dd66d1eec8a45efcba26b37d3b..2df4a8d03e12ee4ab6a5975322e352bd28b975ab 100755 (executable)
@@ -168,7 +168,7 @@ elog_base() {
        local messagetype
        [ -z "${1}" -o -z "${T}" -o ! -d "${T}/logging" ] && return 1
        case "${1}" in
-               INFO|WARN|ERROR|LOG|QA)
+               BLANK|INFO|WARN|ERROR|LOG|QA)
                        messagetype="${1}"
                        shift
                        ;;
@@ -181,15 +181,28 @@ elog_base() {
        return 0
 }
 
+eblank() {
+       [[ ${LAST_E_CMD} == "eblank" ]] && return 0
+       elog_base BLANK
+       [[ ${RC_ENDCOL} != "yes" && ${LAST_E_CMD} == "ebegin" ]] && echo
+       echo -e " ${BLANK}*${NORMAL}"
+       LAST_E_CMD="eblank"
+       return 0
+}
+
 eqawarn() {
        elog_base QA "$*"
+       [[ ${RC_ENDCOL} != "yes" && ${LAST_E_CMD} == "ebegin" ]] && echo
        vecho -e " ${WARN}*${NORMAL} $*" >&2
+       LAST_E_CMD="eqawarn"
        return 0
 }
 
 elog() {
        elog_base LOG "$*"
+       [[ ${RC_ENDCOL} != "yes" && ${LAST_E_CMD} == "ebegin" ]] && echo
        echo -e " ${GOOD}*${NORMAL} $*"
+       LAST_E_CMD="elog"
        return 0
 }
 
@@ -290,6 +303,7 @@ eend() {
 
        _eend ${retval} eerror "$*"
 
+       LAST_E_CMD="eend"
        return ${retval}
 }
 
@@ -348,6 +362,7 @@ unset_colors() {
        COLS="25 80"
        ENDCOL=
 
+       BLANK=
        GOOD=
        WARN=
        BAD=
@@ -370,6 +385,7 @@ set_colors() {
        if [ -n "${PORTAGE_COLORMAP}" ] ; then
                eval ${PORTAGE_COLORMAP}
        else
+               BLANK=$'\e[37m'
                GOOD=$'\e[32;01m'
                WARN=$'\e[33;01m'
                BAD=$'\e[31;01m'
index c9a9d607460fb4d7fa0d6fa0fcb9d940e9f91141..ba1bd2d5d23f400703af8136592326330361f6af 100644 (file)
 
 # logging related variables:
 # PORTAGE_ELOG_CLASSES: selects messages to be logged, possible values are:
-#                          info, warn, error, log, qa, *
+#                          blank, info, warn, error, log, qa, *
 #                       Warning: commenting this will disable elog
-PORTAGE_ELOG_CLASSES="warn error log"
+PORTAGE_ELOG_CLASSES="blank log warn error"
 
 # PORTAGE_ELOG_SYSTEM: selects the module(s) to process the log messages. Modules
 #                      included in portage are (empty means logging is disabled):
index e5e949adcf29bf327edb7c514029a28b6cf0e192..cc9f4a01b88489ca68a3e73fb51e5c8a495984f1 100644 (file)
@@ -91,7 +91,7 @@ DEFAULT_PATH="@DEFAULT_PATH@"
 PORTAGE_WORKDIR_MODE="0700"
 
 # Some defaults for elog
-PORTAGE_ELOG_CLASSES="log warn error"
+PORTAGE_ELOG_CLASSES="blank log warn error"
 PORTAGE_ELOG_SYSTEM="save_summary echo"
 
 PORTAGE_ELOG_MAILURI="@rootuser@"
index 5466f99db38669a5fa8bcb9907b78221bec7de52..4bdb8129d92bb8cc08456f5ecbb951960194b144 100644 (file)
@@ -1,4 +1,5 @@
 <chapter id='package-ebuild'>
 <title>Ebuild</title>
 &package_ebuild_phases;
+&package_ebuild_helper_functions;
 </chapter>
diff --git a/doc/package/ebuild/helper_functions.docbook b/doc/package/ebuild/helper_functions.docbook
new file mode 100644 (file)
index 0000000..ab83d4e
--- /dev/null
@@ -0,0 +1,57 @@
+<sect1 id='package-ebuild-helper-functions'>
+       <title>Helper Functions</title>
+       <sect2 id='package-ebuild-helper-functions-output'>
+       <title>Output</title>
+       <sect3 id='package-ebuild-helper-functions-output-ebegin'>
+       <title>ebegin</title>
+       <para>
+       Like einfo, we output a helpful message and then hint that the following
+       operation may take some time to complete. Once the task is finished, you
+       need to call eend.
+       </para>
+       </sect3>
+       <sect3 id='package-ebuild-helper-functions-output-eblank'>
+       <title>eblank</title>
+       <para>
+       Show a blank line. Consecutive eblank calls collapse into
+       a single blank line.
+       </para>
+       </sect3>
+       <sect3 id='package-ebuild-helper-functions-output-eend'>
+       <title>eend</title>
+       <para>
+       Followup the ebegin message with an appropriate "OK" or "!!" (for errors)
+       marker. If status is non-zero, then the additional error message is
+       displayed.
+       </para>
+       </sect3>
+       <sect3 id='package-ebuild-helper-functions-output-einfo'>
+       <title>einfo</title>
+       <para>
+       Same as elog, but should be used when the message isn't important
+       to the user (like progress or status messages during the build process).
+       </para>
+       </sect3>
+       <sect3 id='package-ebuild-helper-functions-output-elog'>
+       <title>elog</title>
+       <para>
+       If you need to display a message that you wish the user to read
+       and take notice of, then use elog. It works just like echo(1),
+       but adds a little more to the output so as to catch the user's eye.
+       The message will also be logged by portage for later review.
+       </para>
+       </sect3>
+       <sect3 id='package-ebuild-helper-functions-output-eqawarn'>
+       <title>eqawarn</title>
+       <para>
+       Same as einfo, but should be used when showing a QA warning to the user.
+       </para>
+       </sect3>
+       <sect3 id='package-ebuild-helper-functions-output-ewarn'>
+       <title>ewarn</title>
+       <para>
+       Same as einfo, but should be used when showing a warning to the user.
+       </para>
+       </sect3>
+       </sect2>
+</sect1>
index 5c7f049691d651fb24bca6ebc93fe73262b49ac4..383c605cea2575c9afdf94c8f32c1da3caba0210 100644 (file)
        </listitem>
        </itemizedlist>
        </para>
+       <sect2 id='package-ebuild-phases-previous-installed'>
+       <title>Interaction with previous installed version</title>
+       <para>
+       The order for upgrade and downgrade operations changed in
+       version 2.1.5, but the order for reinstall operations remained unchanged.
+       </para>
+       <sect3 id='package-ebuild-phases-before-2.1.5'>
+       <title>Upgrade/downgrade order used by versions less than 2.1.5 (deprecated)</title>
+       <para>
+       <itemizedlist>
+       <listitem>
+               pkg_preinst
+       </listitem>
+       <listitem>
+               pkg_postinst
+       </listitem>
+       <listitem>
+               pkg_prerm
+       </listitem>
+       <listitem>
+               pkg_postrm
+       </listitem>
+       </itemizedlist>
+       </para>
+       </sect3>
+       <sect3 id='package-ebuild-phases-after-2.1.5'>
+       <title>Upgrade/downgrade order starting with version 2.1.5</title>
+       <para>
+       The new order for upgrades and downgrades is identical to the order used
+       for reinstall operations:
+       </para>
+       <para>
+       <itemizedlist>
+       <listitem>
+               pkg_preinst
+       </listitem>
+       <listitem>
+               pkg_prerm
+       </listitem>
+       <listitem>
+               pkg_postrm
+       </listitem>
+       <listitem>
+               pkg_postinst
+       </listitem>
+       </itemizedlist>
+       </para>
+       <para>
+       Now that pkg_postinst is called after all other phases, it's not possible to
+       call has_version in pkg_postinst to detect whether the current install
+       operation is an upgrade or downgrade. If this information is needed during the
+       pkg_postinst phase, do the has_version call in an earlier phase (such as
+       pkg_preinst) and store the result in a global variable to be accessed by
+       pkg_postinst when it is called.
+       </para>
+       </sect3>
+       </sect2>
 </sect1>
index d158c1a2195e29cf8b8ab349620a4f29b6a4d47a..8c29303e66c0d5898dfd4f99a5a7b8d8c602ece6 100644 (file)
@@ -14,6 +14,7 @@
        <!ENTITY package SYSTEM "package.docbook">
        <!ENTITY package_ebuild SYSTEM "package/ebuild.docbook">
        <!ENTITY package_ebuild_phases SYSTEM "package/ebuild/phases.docbook">
+       <!ENTITY package_ebuild_helper_functions SYSTEM "package/ebuild/helper_functions.docbook">
        <!ENTITY qa SYSTEM "qa.docbook">
        <!ENTITY config SYSTEM "config.docbook">
        <!ENTITY config_bashrc SYSTEM "config/bashrc.docbook">
index 39f76a4cb882eff14ea63cc13c5e83d15e3b4c6e..acb23ee9212be407d14fce3d6ac0cc7ecc096ae8 100644 (file)
@@ -15,6 +15,9 @@ value defined internally.
 \fBBAD\fR = \fI"red"\fR
 Defines color used for some words occuring in bad context.
 .TP
+\fBBLANK\fR = \fI"lightgray"\fR
+Defines color used to display eblank lines.
+.TP
 \fBBRACKET\fR = \fI"blue"\fR
 Defines color used for brackets.
 .TP
index 44bbc45aa7a752507bf242ff514f39099bc0d82f..adbb6d824b0bd1ea1ea4022a5337e68a260ba3f8 100644 (file)
@@ -580,6 +580,10 @@ VERINS="$(best_version net\-ftp/glftpd)"
 .RE
 .SH "HELPER FUNCTIONS: OUTPUT"
 .TP
+\fBeblank\fR
+Show a blank line. Consecutive eblank calls collapse into
+a single blank line.
+.TP
 \fBeinfo\fR \fI"disposable message"\fR
 Same as \fBelog\fR, but should be used when the message isn't important to the
 user (like progress or status messages during the build process).
@@ -593,6 +597,9 @@ will also be logged by portage for later review.
 \fBewarn\fR \fI"warning message"\fR
 Same as \fBeinfo\fR, but should be used when showing a warning to the user.
 .TP
+\fBeqawarn\fR \fI"QA warning message"\fR
+Same as \fBeinfo\fR, but should be used when showing a QA warning to the user.
+.TP
 \fBeerror\fR \fI"error message"\fR
 Same as \fBeinfo\fR, but should be used when showing an error to the user.
 .TP
index 1a1dbf5250c3317c0ed9a979f3dd41409bfdcc93..b83b7ecbb174a1706e6df01718ad52d0bd9b8122 100644 (file)
@@ -567,10 +567,8 @@ problems or are known to have issues on different systems.  It resides in
 \fI/usr/portage/profiles\fR.
 .TP
 .BR CHOST
-The \CHOST\fR variable in \fBmake.conf\fR(5) is used to mask binary packages
-that have been built with a different \CHOST\fR setting. The only
-way to unmask such a binary package is to change the \CHOST\fR environment
-variable so that it exactly matches that of the binary package.
+Use the \fBACCEPT_CHOSTS\fR variable in \fBmake.conf\fR(5) to control
+\fBCHOST\fR acceptance for binary packages.
 .TP
 .BR EAPI
 The \fBEAPI\fR variable in an \fBebuild\fR(5) file is used to mask packages
index b24844b6b52be6abc40b0a066b83e3ccfc47dda5..1a32e46f6a68174539fbad8915049cdd7d6bcf4d 100644 (file)
@@ -21,6 +21,13 @@ settings.  Clearing these variables requires a clear\-all as in:
 export USE="\-*"
 .SH "VARIABLES"
 .TP
+\fBACCEPT_CHOSTS\fR = \fI[space delimited list of CHOST values]\fR
+Specifies acceptable \fBCHOST\fR values for binary packages. Regular
+expression syntax is supported, so it is necessary to escape
+\fBCHOST\fR characters if they have special meaning in regular expressions.
+.br
+Defaults to the value of $CHOST.
+.TP
 \fBACCEPT_KEYWORDS\fR = \fI[space delimited list of KEYWORDS]\fR
 Enable testing of ebuilds that have not yet been deemed 'stable'.  Users
 of the 'x86' architecture would set this to '~x86' while ppc users would
index fc8428ae62a3c72ea06172e12c30af411a44876f..79b598f46c4e328ebf43451d0eb40c81600d2454 100644 (file)
@@ -1020,7 +1020,7 @@ class FakeVartree(portage.vartree):
                                vdb_lock = portage.locks.lockdir(vdb_path)
                        real_dbapi = real_vartree.dbapi
                        slot_counters = {}
-                       for cpv in real_dbapi.cpv_all(use_cache=0):
+                       for cpv in real_dbapi.cpv_all():
                                cache_key = ("installed", self.root, cpv, "nomerge")
                                pkg = self._pkg_cache.get(cache_key)
                                if pkg is not None:
@@ -6807,7 +6807,8 @@ def chk_updated_info_files(root, infodirs, prev_mtimes, retval):
                                if inforoot=='':
                                        continue
 
-                               if not os.path.isdir(inforoot):
+                               if not os.path.isdir(inforoot) or \
+                                       not os.access(inforoot, os.W_OK):
                                        continue
                                errmsg = ""
                                file_list = os.listdir(inforoot)
@@ -6971,15 +6972,21 @@ def post_emerge(trees, mtimedb, retval):
 
        vdb_path = os.path.join(target_root, portage.VDB_PATH)
        portage.util.ensure_dirs(vdb_path)
-       vdb_lock = portage.locks.lockdir(vdb_path)
-       try:
-               if "noinfo" not in settings.features:
-                       chk_updated_info_files(target_root + EPREFIX, infodirs, info_mtimes, retval)
-               mtimedb.commit()
-       finally:
-               portage.locks.unlockdir(vdb_lock)
+       vdb_lock = None
+       if os.access(vdb_path, os.W_OK):
+               vdb_lock = portage.locks.lockdir(vdb_path)
+
+       if vdb_lock:
+               try:
+                       if "noinfo" not in settings.features:
+                               chk_updated_info_files(target_root, EPREFIX_LSTRIP
+                                       infodirs, info_mtimes, retval)
+                       mtimedb.commit()
+               finally:
+                       if vdb_lock:
+                               portage.locks.unlockdir(vdb_lock)
 
-       chk_updated_cfg_files(target_root + EPREFIX, config_protect)
+       chk_updated_cfg_files(target_root, EPREFIX_LSTRIP, config_protect)
        
        display_news_notification(trees)
        
@@ -9233,8 +9240,8 @@ def emerge_main():
                                setconfig.active.append(s)
                                if myaction in unmerge_actions and \
                                                not sets[s].supportsOperation("unmerge"):
-                                       sys.stderr.write("emerge: the given set %s does " + \
-                                               "not support unmerge operations\n" % s)
+                                       sys.stderr.write("emerge: the given set '%s' does " % s + \
+                                               "not support unmerge operations\n")
                                        return 1
                                if not setconfig.getSetAtoms(s):
                                        print "emerge: '%s' is an empty set" % s
index 2fd9217f76e97f4fc7125232c4743c51f1eaf2e6..b8d7bfd958dc0ce7d6634155c537732955096214 100644 (file)
@@ -1005,7 +1005,6 @@ class config(object):
        ]
 
        _environ_filter = frozenset(_environ_filter)
-       _accept_chost_re = None
 
        def __init__(self, clone=None, mycpv=None, config_profile_path=None,
                config_incrementals=None, config_root=None, target_root=None,
@@ -1043,6 +1042,7 @@ class config(object):
                self.puse     = []
                self.modifiedkeys = []
                self.uvlist = []
+               self._accept_chost_re = None
 
                self.virtuals = {}
                self.virts_p = {}
@@ -2415,7 +2415,7 @@ class config(object):
                        if not accept_chost:
                                self._accept_chost_re = re.compile(".*")
                        elif len(accept_chost) == 1:
-                               self._accept_chost_re = re.compile(accept_chost[0])
+                               self._accept_chost_re = re.compile(r'^%s$' % accept_chost[0])
                        else:
                                self._accept_chost_re = re.compile(
                                        r'^(%s)$' % "|".join(accept_chost))
@@ -4501,7 +4501,7 @@ def doebuild_environment(myebuild, mydo, myroot, mysettings, debug, use_cache, m
 
        # Allow color.map to control colors associated with einfo, ewarn, etc...
        mycolors = []
-       for c in ("GOOD", "WARN", "BAD", "HILITE", "BRACKET"):
+       for c in ("BLANK", "GOOD", "WARN", "BAD", "HILITE", "BRACKET"):
                mycolors.append("%s=$'%s'" % (c, portage.output.codes[c]))
        mysettings["PORTAGE_COLORMAP"] = "\n".join(mycolors)
 
index 26165a4c89a0cf2d194d53c3286d1523e14af4d9..24c2522ed85330664259a9f88c44740ae745ecb8 100644 (file)
@@ -136,7 +136,7 @@ class LinkageMap(object):
                libs = {}
                obj_properties = {}
                lines = []
-               for cpv in self._dbapi.cpv_all(use_cache=0):
+               for cpv in self._dbapi.cpv_all():
                        lines += self._dbapi.aux_get(cpv, ["NEEDED.ELF.2"])[0].split('\n')
                # Cache NEEDED.* files avoid doing excessive IO for every rebuild.
                self._dbapi.flush_cache()
@@ -627,6 +627,22 @@ class vardbapi(dbapi):
        def checkblockers(self, origdep):
                pass
 
+       def _add(self, pkg_dblink):
+               self._clear_cache(pkg_dblink)
+
+       def _remove(self, pkg_dblink):
+               self._clear_cache(pkg_dblink)
+
+       def _clear_cache(self, pkg_dblink):
+               # Due to 1 second mtime granularity in <python-2.5, mtime checks
+               # are not always sufficient to invalidate vardbapi caches. Therefore,
+               # the caches need to be actively invalidated here.
+               self.mtdircache.pop(pkg_dblink.cat, None)
+               self.matchcache.pop(pkg_dblink.cat, None)
+               self.cpcache.pop(pkg_dblink.mysplit[0], None)
+               from portage import dircache
+               dircache.pop(pkg_dblink.dbcatdir, None)
+
        def match(self, origdep, use_cache=1):
                "caching match function"
                mydep = dep_expand(
@@ -1380,24 +1396,15 @@ class dblink(object):
                """
                if not os.path.exists(self.dbdir):
                        return
-               try:
-                       for x in os.listdir(self.dbdir):
-                               os.unlink(self.dbdir+"/"+x)
-                       os.rmdir(self.dbdir)
-               except OSError, e:
-                       print "!!! Unable to remove db entry for this package."
-                       print "!!! It is possible that a directory is in this one. Portage will still"
-                       print "!!! register this package as installed as long as this directory exists."
-                       print "!!! You may delete this directory with 'rm -Rf "+self.dbdir+"'"
-                       print "!!! "+str(e)
-                       print
-                       sys.exit(1)
-
-               # Due to mtime granularity, mtime checks do not always properly
-               # invalidate vardbapi caches.
-               self.vartree.dbapi.mtdircache.pop(self.cat, None)
-               self.vartree.dbapi.matchcache.pop(self.cat, None)
-               self.vartree.dbapi.cpcache.pop(self.mysplit[0], None)
+
+               # Check validity of self.dbdir before attempting to remove it.
+               if not self.dbdir.startswith(self.dbroot):
+                       writemsg("portage.dblink.delete(): invalid dbdir: %s\n" % \
+                               self.dbdir, noiselevel=-1)
+                       return
+               import shutil
+               shutil.rmtree(self.dbdir)
+               self.vartree.dbapi._remove(self)
 
        def clearcontents(self):
                """
@@ -2735,11 +2742,7 @@ class dblink(object):
                                f.write(line)
                        f.close()
 
-               # Due to mtime granularity, mtime checks do not always properly
-               # invalidate vardbapi caches.
-               self.vartree.dbapi.mtdircache.pop(self.cat, None)
-               self.vartree.dbapi.matchcache.pop(self.cat, None)
-               self.vartree.dbapi.cpcache.pop(self.mysplit[0], None)
+               self.vartree.dbapi._add(self)
                contents = self.getcontents()
 
                # regenerate reverse NEEDED map
index 30d88f005067224f973864f68af17a8231bd7747..1c83600a45e80b59fb36599afd38660b6e2fcba8 100644 (file)
@@ -33,7 +33,8 @@ def finalize(mysettings=None):
                                                "WARN": printer.ewarn,
                                                "ERROR": printer.eerror,
                                                "LOG": printer.einfo,
-                                               "QA": printer.ewarn}
+                                               "QA": printer.ewarn,
+                                               "BLANK": printer.eblank}
                                if isinstance(msgcontent, basestring):
                                        msgcontent = [msgcontent]
                                for line in msgcontent:
index a7a500cd4f120efcf208cc8a87a85c79819c83a9..4d0ab42ec9716c5e545e639fdb954c082e12b9d9 100644 (file)
@@ -138,6 +138,7 @@ codes["bg_darkyellow"] = codes["bg_brown"]
 
 # Colors from /etc/init.d/functions.sh
 codes["NORMAL"]     = esc_seq + "0m"
+codes["BLANK"]      = codes["lightgray"]
 codes["GOOD"]       = codes["green"]
 codes["WARN"]       = codes["yellow"]
 codes["BAD"]        = codes["red"]
@@ -543,6 +544,20 @@ class EOutput(object):
                        sys.stdout.flush()
                self.__last_e_cmd = "ewarn"
 
+       def eblank(self, msg):
+               """
+               Shows a blank line. Consecutive eblank calls are all collapsed
+               into a single blank line.
+               """
+               if self.__last_e_cmd == "eblank":
+                       return
+               if not self.quiet:
+                       if self.__last_e_cmd == "ebegin":
+                               sys.stdout.write("\n")
+                       sys.stdout.write(colorize("BLANK", " * ") + "\n")
+                       sys.stdout.flush()
+               self.__last_e_cmd = "eblank"
+
        def ewend(self, errno, *msg):
                """
                Indicates the completion of a process, optionally displaying a message