[PATCH 08/14] Move Anaconda version detection from isys to Python code

Martin Kolman mkolman at redhat.com
Thu Aug 21 20:10:29 UTC 2014


There is now pyanaconda/version.py.in module with a __version__
variable, which automatically gets the Anaconda version from
automake during build and is saved as pyanaconda/version.py.

As a side effect, the absence of compiled isys no longer crashes
"anaconda --help". Also "anaconda --version" on freshly
cloned/unpackaged Anaconda now correctly returns "anaconda unknown".

Also handle issues with auto* and version.py. Automake is really kind of
terrible at python, so filter the generated version.py out of the dist
files so that builds from a dist tarball don't end up with a both a $srcdir
and $builddir copy of version.py. Ignore a pylint error about importing version
since version.py ends up in a different directory than the rest of the
pyanaconda module.

Related: rhbz:#1088459
Signed-off-by: Martin Kolman <mkolman at redhat.com>
---
 .gitignore                  |  1 +
 anaconda                    | 18 +++++-----
 configure.ac                |  1 +
 pyanaconda/Makefile.am      |  6 +++-
 pyanaconda/exception.py     |  4 +--
 pyanaconda/isys/Makefile.am |  3 +-
 pyanaconda/isys/__init__.py |  4 +--
 pyanaconda/isys/isys.c      |  6 ----
 pyanaconda/startup_utils.py | 80 +++++++++++++++++++++++++++++++++++++++++++++
 pyanaconda/version.py.in    |  1 +
 10 files changed, 102 insertions(+), 22 deletions(-)
 create mode 100644 pyanaconda/startup_utils.py
 create mode 100644 pyanaconda/version.py.in

diff --git a/.gitignore b/.gitignore
index d50106c..3ba6538 100644
--- a/.gitignore
+++ b/.gitignore
@@ -80,3 +80,4 @@ widgets/gtk-doc.make
 widgets/src/gettext.h
 anaconda.po
 data/liveinst/gnome/fedora-welcome.po
+pyanaconda/version.py
diff --git a/anaconda b/anaconda
index c91ae6b..d33d712 100755
--- a/anaconda
+++ b/anaconda
@@ -205,11 +205,13 @@ def symlink_updates(dest_dir, update_dir):
                 continue
             os.symlink(dest_path, update_path)
 
-def getAnacondaVersion():
-    # Using _isys here so we don't drag in the logging stuff, which is always
-    # complicated.
-    from pyanaconda import _isys
-    return _isys.getAnacondaVersion()
+def getAnacondaVersionString():
+    # we are importing the startup module directly so that it can be replaced
+    # by updates image, if it was replaced before the updates image can be
+    # loaded, it could not be easily replaced
+    from pyanaconda import startup_utils
+    return startup_utils.get_anaconda_version_string()
+
 
 def parseArguments(argv=None, boot_cmdline=None):
     from pyanaconda.anaconda_argparse import AnacondaArgumentParser
@@ -233,7 +235,7 @@ def parseArguments(argv=None, boot_cmdline=None):
     # If this seems like too much trouble, *don't add a new option*!
 
     # Version
-    ap.add_argument('--version', action='version', version="%(prog)s " + getAnacondaVersion())
+    ap.add_argument('--version', action='version', version="%(prog)s " + getAnacondaVersionString())
 
     # Interface
     ap.add_argument("-C", "--cmdline", dest="display_mode", action="store_const", const="c",
@@ -760,7 +762,7 @@ if __name__ == "__main__":
         if "RUNKS" in flags.cmdline:
             opts.display_mode = 'c'
 
-    log.info("%s %s", sys.argv[0], getAnacondaVersion())
+    log.info("%s %s", sys.argv[0], getAnacondaVersionString())
 
     # TODO: uncomment this when we're sure that we're doing the right thing
     # with flags.cmdline *everywhere* it appears...
@@ -786,7 +788,7 @@ if __name__ == "__main__":
     from pyanaconda import keyboard
     from pyanaconda.iutil import ProxyString, ProxyStringError
 
-    verdesc = "%s for %s %s" % (getAnacondaVersion(),
+    verdesc = "%s for %s %s" % (getAnacondaVersionString(),
                                 product.productName, product.productVersion)
     if product.isFinal:
         print "anaconda %s started." % verdesc
diff --git a/configure.ac b/configure.ac
index 08e6e75..d8853f3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -236,6 +236,7 @@ AC_CONFIG_FILES([Makefile
                  po/Makefile.in
                  scripts/Makefile
                  pyanaconda/Makefile
+                 pyanaconda/version.py
                  pyanaconda/isys/Makefile
                  pyanaconda/packaging/Makefile
                  pyanaconda/ui/Makefile
diff --git a/pyanaconda/Makefile.am b/pyanaconda/Makefile.am
index ae1159c..2d48bd2 100644
--- a/pyanaconda/Makefile.am
+++ b/pyanaconda/Makefile.am
@@ -24,4 +24,8 @@ MAINTAINERCLEANFILES = Makefile.in
 # anaconda Python code
 pkgpyexecdir    = $(pyexecdir)/py$(PACKAGE_NAME)
 anacondadir     = $(pkgpyexecdir)
-anaconda_PYTHON = $(srcdir)/*.py
+
+# Filter version.py out of the distributed python files since it will
+# be generated by the configure script
+anaconda_PYTHON = $(filter-out %/version.py,$(wildcard $(srcdir)/*.py))
+nodist_anaconda_PYTHON = $(builddir)/version.py
diff --git a/pyanaconda/exception.py b/pyanaconda/exception.py
index 7a8941e..3ec6ebf 100644
--- a/pyanaconda/exception.py
+++ b/pyanaconda/exception.py
@@ -24,7 +24,6 @@
 from meh import Config
 from meh.handler import ExceptionHandler
 from meh.dump import ReverseExceptionDump
-from pyanaconda import isys
 from pyanaconda import iutil
 import sys
 import os
@@ -40,6 +39,7 @@ from pyanaconda.threads import threadMgr
 from pyanaconda.i18n import _
 from pyanaconda import flags
 from pyanaconda import product
+from pyanaconda import startup_utils
 
 from gi.repository import GLib
 
@@ -225,7 +225,7 @@ def initExceptionHandling(anaconda):
         fileList.extend([anaconda.opts.ksfile])
 
     conf = Config(programName="anaconda",
-                  programVersion=isys.getAnacondaVersion(),
+                  programVersion=startup_utils.get_anaconda_version_string(),
                   programArch=os.uname()[4],
                   attrSkipList=["_intf._actions",
                                 "_intf._currentAction._xklwrapper",
diff --git a/pyanaconda/isys/Makefile.am b/pyanaconda/isys/Makefile.am
index 3f37d45..5b24cf7 100644
--- a/pyanaconda/isys/Makefile.am
+++ b/pyanaconda/isys/Makefile.am
@@ -23,8 +23,7 @@ ISYS_SRCS = isofs.c linkdetect.c auditd.c log.c mem.c
 
 dist_noinst_HEADERS = $(srcdir)/*.h
 
-ISYS_CFLAGS = -DVERSION='"$(PACKAGE_VERSION)-$(PACKAGE_RELEASE)"' \
-              $(NETWORKMANAGER_CFLAGS) $(LIBNL_CFLAGS) $(LIBNM_GLIB_CFLAGS) \
+ISYS_CFLAGS = $(NETWORKMANAGER_CFLAGS) $(LIBNL_CFLAGS) $(LIBNM_GLIB_CFLAGS) \
               $(SELINUX_CFLAGS)
 ISYS_LIBS   = $(RESOLV_LIBS) $(ZLIB_LIBS) \
               $(DEVMAPPER_LIBS) $(X11_LIBS) $(SELINUX_LIBS) \
diff --git a/pyanaconda/isys/__init__.py b/pyanaconda/isys/__init__.py
index 91bc505..30e8517 100755
--- a/pyanaconda/isys/__init__.py
+++ b/pyanaconda/isys/__init__.py
@@ -1,7 +1,7 @@
 #
 # isys.py - installer utility functions and glue for C module
 #
-# Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007  Red Hat, Inc.
+# Copyright (C) 2001-2014  Red Hat, Inc.
 # All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
@@ -108,8 +108,6 @@ def isPaeAvailable():
 
     return isPAE
 
-def getAnacondaVersion():
-    return _isys.getAnacondaVersion()
 
 auditDaemon = _isys.auditdaemon
 
diff --git a/pyanaconda/isys/isys.c b/pyanaconda/isys/isys.c
index 7848504..d166738 100644
--- a/pyanaconda/isys/isys.c
+++ b/pyanaconda/isys/isys.c
@@ -80,7 +80,6 @@ static PyObject * py_bind_textdomain_codeset(PyObject * o, PyObject * args);
 static PyObject * doSegvHandler(PyObject *s, PyObject *args);
 static PyObject * doAuditDaemon(PyObject *s);
 static PyObject * doIsCapsLockEnabled(PyObject * s, PyObject * args);
-static PyObject * doGetAnacondaVersion(PyObject * s, PyObject * args);
 static PyObject * doInitLog(PyObject * s);
 static PyObject * doTotalMemory(PyObject * s);
 
@@ -94,7 +93,6 @@ static PyMethodDef isysModuleMethods[] = {
     { "handleSegv", (PyCFunction) doSegvHandler, METH_VARARGS, NULL },
     { "auditdaemon", (PyCFunction) doAuditDaemon, METH_NOARGS, NULL },
     { "isCapsLockEnabled", (PyCFunction) doIsCapsLockEnabled, METH_VARARGS, NULL },
-    { "getAnacondaVersion", (PyCFunction) doGetAnacondaVersion, METH_VARARGS, NULL },
     { "initLog", (PyCFunction) doInitLog, METH_VARARGS, NULL },
     { "total_memory", (PyCFunction) doTotalMemory, METH_NOARGS, NULL },
     { NULL, NULL, 0, NULL }
@@ -250,10 +248,6 @@ static PyObject * doIsCapsLockEnabled(PyObject * s, PyObject * args) {
     return PyBool_FromLong(state.locked_mods & LockMask);
 }
 
-static PyObject * doGetAnacondaVersion(PyObject * s, PyObject * args) {
-    return Py_BuildValue("s", VERSION);
-}
-
 static PyObject * doInitLog(PyObject * s) {
     openLog();
     Py_INCREF(Py_None);
diff --git a/pyanaconda/startup_utils.py b/pyanaconda/startup_utils.py
new file mode 100644
index 0000000..30d5974
--- /dev/null
+++ b/pyanaconda/startup_utils.py
@@ -0,0 +1,80 @@
+#
+# startup.py - code used during early startup with minimal dependencies
+#
+# Copyright (C) 2014  Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions of
+# the GNU General Public License v.2, or (at your option) any later version.
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY expressed or implied, including the implied warranties of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.  You should have received a copy of the
+# GNU General Public License along with this program; if not, write to the
+# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
+# source code or documentation are not subject to the GNU General Public
+# License and may only be used or replicated with the express permission of
+# Red Hat, Inc.
+#
+# Red Hat Author(s): Martin Kolman <mkolman at redhat.com>
+#
+import imp
+
+
+def module_exists(module_path):
+    """Report is a given module exists in the current module import pth or not.
+    Supports checking bot modules ("foo") os submodules ("foo.bar.baz")
+
+    :param str module_path: (sub)module identifier
+
+    :returns: True if (sub)module exists in path, False if not
+    :rtype: bool
+    """
+
+    module_path_components = module_path.split(".")
+    module_name = module_path_components.pop()
+    parent_module_path = None
+    if module_path_components:
+        # the path specifies a submodule ("bar.foo")
+        # we need to chain-import all the modules in the submodule path before
+        # we can check if the submodule itself exists
+        for name in module_path_components:
+            module_info = imp.find_module(name, parent_module_path)
+            module = imp.load_module(name, *module_info)
+            if module:
+                parent_module_path = module.__path__
+            else:
+                # one of the parents was not found, abort search
+                return False
+    # if we got this far we should have either some path or the module is
+    # not a submodule and the default set of paths will be used (path=None)
+    try:
+        # if the module is not found imp raises an ImportError
+        imp.find_module(module_name, parent_module_path)
+        return True
+    except ImportError:
+        return False
+
+
+def get_anaconda_version_string():
+    """Return a string describing current Anaconda version.
+    If the current version can't be determined the string
+    "unknown" will be returned.
+
+    :returns: string describing Anaconda version
+    :rtype: str
+    """
+
+    # we are importing the version module directly so that we don't drag in any
+    # non-necessary stuff; we also need to handle the possibility of the
+    # import itself failing
+    if module_exists("pyanaconda.version"):
+        # Ignore pylint not finding the version module, since thanks to automake
+        # there's a good chance that version.py is not in the same directory as
+        # the rest of pyanaconda.
+        from pyanaconda import version # pylint: disable=no-name-in-module
+        return version.__version__
+    else:
+        return "unknown"
+
diff --git a/pyanaconda/version.py.in b/pyanaconda/version.py.in
new file mode 100644
index 0000000..8b5161a
--- /dev/null
+++ b/pyanaconda/version.py.in
@@ -0,0 +1 @@
+__version__ = "@PACKAGE_VERSION at -@PACKAGE_RELEASE@"
-- 
1.9.3



More information about the anaconda-patches mailing list