public inbox for isar-users@googlegroups.com
 help / color / mirror / Atom feed
From: Jan Kiszka <jan.kiszka@siemens.com>
To: isar-users <isar-users@googlegroups.com>
Subject: [PATCH v5 25/27] Add OE class and library elements for terminal support
Date: Sun, 22 Sep 2019 20:17:09 +0200	[thread overview]
Message-ID: <b032b3fb4025e0f2a42ce714fd9db4960c869a9c.1569176231.git.jan.kiszka@siemens.com> (raw)
In-Reply-To: <cover.1569176231.git.jan.kiszka@siemens.com>
In-Reply-To: <cover.1569176231.git.jan.kiszka@siemens.com>

From: Jan Kiszka <jan.kiszka@siemens.com>

This imports the terminal class from OE core revision 95ad56262963 along
with its dependencies under meta/lib/oe and a helper script. Files are
almost unmodified, just augmented by a note for their origin, SPDX tags
where missing and freed of three whitespace issues.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 meta/classes/terminal.bbclass       | 112 +++++++++++++
 meta/lib/oe/classutils.py           |  49 ++++++
 meta/lib/oe/data.py                 |  53 ++++++
 meta/lib/oe/maketype.py             | 112 +++++++++++++
 meta/lib/oe/terminal.py             | 315 ++++++++++++++++++++++++++++++++++++
 meta/lib/oe/types.py                | 187 +++++++++++++++++++++
 scripts/oe-gnome-terminal-phonehome |  14 ++
 7 files changed, 842 insertions(+)
 create mode 100644 meta/classes/terminal.bbclass
 create mode 100644 meta/lib/oe/classutils.py
 create mode 100644 meta/lib/oe/data.py
 create mode 100644 meta/lib/oe/maketype.py
 create mode 100644 meta/lib/oe/terminal.py
 create mode 100644 meta/lib/oe/types.py
 create mode 100755 scripts/oe-gnome-terminal-phonehome

diff --git a/meta/classes/terminal.bbclass b/meta/classes/terminal.bbclass
new file mode 100644
index 0000000..8436d7f
--- /dev/null
+++ b/meta/classes/terminal.bbclass
@@ -0,0 +1,112 @@
+#
+# Imported from openembedded-core
+#
+# SPDX-License-Identifier: MIT
+#
+
+OE_TERMINAL ?= 'auto'
+OE_TERMINAL[type] = 'choice'
+OE_TERMINAL[choices] = 'auto none \
+                        ${@oe_terminal_prioritized()}'
+
+OE_TERMINAL_EXPORTS += 'EXTRA_OEMAKE CACHED_CONFIGUREVARS CONFIGUREOPTS EXTRA_OECONF'
+OE_TERMINAL_EXPORTS[type] = 'list'
+
+XAUTHORITY ?= "${HOME}/.Xauthority"
+SHELL ?= "bash"
+
+def oe_terminal_prioritized():
+    import oe.terminal
+    return " ".join(o.name for o in oe.terminal.prioritized())
+
+def emit_terminal_func(command, envdata, d):
+    import bb.build
+    cmd_func = 'do_terminal'
+
+    envdata.setVar(cmd_func, 'exec ' + command)
+    envdata.setVarFlag(cmd_func, 'func', '1')
+
+    runfmt = d.getVar('BB_RUNFMT') or "run.{func}.{pid}"
+    runfile = runfmt.format(func=cmd_func, task=cmd_func, taskfunc=cmd_func, pid=os.getpid())
+    runfile = os.path.join(d.getVar('T'), runfile)
+    bb.utils.mkdirhier(os.path.dirname(runfile))
+
+    with open(runfile, 'w') as script:
+        script.write(bb.build.shell_trap_code())
+        bb.data.emit_func(cmd_func, script, envdata)
+        script.write(cmd_func)
+        script.write("\n")
+    os.chmod(runfile, 0o755)
+
+    return runfile
+
+def oe_terminal(command, title, d):
+    import oe.data
+    import oe.terminal
+
+    envdata = bb.data.init()
+
+    for v in os.environ:
+        envdata.setVar(v, os.environ[v])
+        envdata.setVarFlag(v, 'export', '1')
+
+    for export in oe.data.typed_value('OE_TERMINAL_EXPORTS', d):
+        value = d.getVar(export)
+        if value is not None:
+            os.environ[export] = str(value)
+            envdata.setVar(export, str(value))
+            envdata.setVarFlag(export, 'export', '1')
+        if export == "PSEUDO_DISABLED":
+            if "PSEUDO_UNLOAD" in os.environ:
+                del os.environ["PSEUDO_UNLOAD"]
+            envdata.delVar("PSEUDO_UNLOAD")
+
+    # Add in all variables from the user's original environment which
+    # haven't subsequntly been set/changed
+    origbbenv = d.getVar("BB_ORIGENV", False) or {}
+    for key in origbbenv:
+        if key in envdata:
+            continue
+        value = origbbenv.getVar(key)
+        if value is not None:
+            os.environ[key] = str(value)
+            envdata.setVar(key, str(value))
+            envdata.setVarFlag(key, 'export', '1')
+
+    # Use original PATH as a fallback
+    path = d.getVar('PATH') + ":" + origbbenv.getVar('PATH')
+    os.environ['PATH'] = path
+    envdata.setVar('PATH', path)
+
+    # A complex PS1 might need more escaping of chars.
+    # Lets not export PS1 instead.
+    envdata.delVar("PS1")
+
+    # Replace command with an executable wrapper script
+    command = emit_terminal_func(command, envdata, d)
+
+    terminal = oe.data.typed_value('OE_TERMINAL', d).lower()
+    if terminal == 'none':
+        bb.fatal('Devshell usage disabled with OE_TERMINAL')
+    elif terminal != 'auto':
+        try:
+            oe.terminal.spawn(terminal, command, title, None, d)
+            return
+        except oe.terminal.UnsupportedTerminal:
+            bb.warn('Unsupported terminal "%s", defaulting to "auto"' %
+                    terminal)
+        except oe.terminal.ExecutionError as exc:
+            bb.fatal('Unable to spawn terminal %s: %s' % (terminal, exc))
+
+    try:
+        oe.terminal.spawn_preferred(command, title, None, d)
+    except oe.terminal.NoSupportedTerminals as nosup:
+        nosup.terms.remove("false")
+        cmds = '\n\t'.join(nosup.terms).replace("{command}",
+                    "do_terminal").replace("{title}", title)
+        bb.fatal('No valid terminal found, unable to open devshell.\n' +
+                'Tried the following commands:\n\t%s' % cmds)
+    except oe.terminal.ExecutionError as exc:
+        bb.fatal('Unable to spawn terminal %s: %s' % (terminal, exc))
+
+oe_terminal[vardepsexclude] = "BB_ORIGENV"
diff --git a/meta/lib/oe/classutils.py b/meta/lib/oe/classutils.py
new file mode 100644
index 0000000..d879191
--- /dev/null
+++ b/meta/lib/oe/classutils.py
@@ -0,0 +1,49 @@
+#
+# Imported from openembedded-core
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+class ClassRegistryMeta(type):
+    """Give each ClassRegistry their own registry"""
+    def __init__(cls, name, bases, attrs):
+        cls.registry = {}
+        type.__init__(cls, name, bases, attrs)
+
+class ClassRegistry(type, metaclass=ClassRegistryMeta):
+    """Maintain a registry of classes, indexed by name.
+
+Note that this implementation requires that the names be unique, as it uses
+a dictionary to hold the classes by name.
+
+The name in the registry can be overridden via the 'name' attribute of the
+class, and the 'priority' attribute controls priority. The prioritized()
+method returns the registered classes in priority order.
+
+Subclasses of ClassRegistry may define an 'implemented' property to exert
+control over whether the class will be added to the registry (e.g. to keep
+abstract base classes out of the registry)."""
+    priority = 0
+    def __init__(cls, name, bases, attrs):
+        super(ClassRegistry, cls).__init__(name, bases, attrs)
+        try:
+            if not cls.implemented:
+                return
+        except AttributeError:
+            pass
+
+        try:
+            cls.name
+        except AttributeError:
+            cls.name = name
+        cls.registry[cls.name] = cls
+
+    @classmethod
+    def prioritized(tcls):
+        return sorted(list(tcls.registry.values()),
+                      key=lambda v: (v.priority, v.name), reverse=True)
+
+    def unregister(cls):
+        for key in cls.registry.keys():
+            if cls.registry[key] is cls:
+                del cls.registry[key]
diff --git a/meta/lib/oe/data.py b/meta/lib/oe/data.py
new file mode 100644
index 0000000..b832e9b
--- /dev/null
+++ b/meta/lib/oe/data.py
@@ -0,0 +1,53 @@
+#
+# Imported from openembedded-core
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+import json
+import oe.maketype
+
+def typed_value(key, d):
+    """Construct a value for the specified metadata variable, using its flags
+    to determine the type and parameters for construction."""
+    var_type = d.getVarFlag(key, 'type')
+    flags = d.getVarFlags(key)
+    if flags is not None:
+        flags = dict((flag, d.expand(value))
+                     for flag, value in list(flags.items()))
+    else:
+        flags = {}
+
+    try:
+        return oe.maketype.create(d.getVar(key) or '', var_type, **flags)
+    except (TypeError, ValueError) as exc:
+        bb.msg.fatal("Data", "%s: %s" % (key, str(exc)))
+
+def export2json(d, json_file, expand=True, searchString="",replaceString=""):
+    data2export = {}
+    keys2export = []
+
+    for key in d.keys():
+        if key.startswith("_"):
+            continue
+        elif key.startswith("BB"):
+            continue
+        elif key.startswith("B_pn"):
+            continue
+        elif key.startswith("do_"):
+            continue
+        elif d.getVarFlag(key, "func"):
+            continue
+
+        keys2export.append(key)
+
+    for key in keys2export:
+        try:
+            data2export[key] = d.getVar(key, expand).replace(searchString,replaceString)
+        except bb.data_smart.ExpansionError:
+            data2export[key] = ''
+        except AttributeError:
+            pass
+
+    with open(json_file, "w") as f:
+        json.dump(data2export, f, skipkeys=True, indent=4, sort_keys=True)
diff --git a/meta/lib/oe/maketype.py b/meta/lib/oe/maketype.py
new file mode 100644
index 0000000..969a22b
--- /dev/null
+++ b/meta/lib/oe/maketype.py
@@ -0,0 +1,112 @@
+#
+# Imported from openembedded-core
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+"""OpenEmbedded variable typing support
+
+Types are defined in the metadata by name, using the 'type' flag on a
+variable.  Other flags may be utilized in the construction of the types.  See
+the arguments of the type's factory for details.
+"""
+
+import inspect
+import oe.types as types
+try:
+    # Python 3.7+
+    from collections.abc import Callable
+except ImportError:
+    # Python < 3.7
+    from collections import Callable
+
+available_types = {}
+
+class MissingFlag(TypeError):
+    """A particular flag is required to construct the type, but has not been
+    provided."""
+    def __init__(self, flag, type):
+        self.flag = flag
+        self.type = type
+        TypeError.__init__(self)
+
+    def __str__(self):
+        return "Type '%s' requires flag '%s'" % (self.type, self.flag)
+
+def factory(var_type):
+    """Return the factory for a specified type."""
+    if var_type is None:
+        raise TypeError("No type specified. Valid types: %s" %
+                        ', '.join(available_types))
+    try:
+        return available_types[var_type]
+    except KeyError:
+        raise TypeError("Invalid type '%s':\n  Valid types: %s" %
+                        (var_type, ', '.join(available_types)))
+
+def create(value, var_type, **flags):
+    """Create an object of the specified type, given the specified flags and
+    string value."""
+    obj = factory(var_type)
+    objflags = {}
+    for flag in obj.flags:
+        if flag not in flags:
+            if flag not in obj.optflags:
+                raise MissingFlag(flag, var_type)
+        else:
+            objflags[flag] = flags[flag]
+
+    return obj(value, **objflags)
+
+def get_callable_args(obj):
+    """Grab all but the first argument of the specified callable, returning
+    the list, as well as a list of which of the arguments have default
+    values."""
+    if type(obj) is type:
+        obj = obj.__init__
+
+    sig = inspect.signature(obj)
+    args = list(sig.parameters.keys())
+    defaults = list(s for s in sig.parameters.keys() if sig.parameters[s].default != inspect.Parameter.empty)
+    flaglist = []
+    if args:
+        if len(args) > 1 and args[0] == 'self':
+            args = args[1:]
+        flaglist.extend(args)
+
+    optional = set()
+    if defaults:
+        optional |= set(flaglist[-len(defaults):])
+    return flaglist, optional
+
+def factory_setup(name, obj):
+    """Prepare a factory for use."""
+    args, optional = get_callable_args(obj)
+    extra_args = args[1:]
+    if extra_args:
+        obj.flags, optional = extra_args, optional
+        obj.optflags = set(optional)
+    else:
+        obj.flags = obj.optflags = ()
+
+    if not hasattr(obj, 'name'):
+        obj.name = name
+
+def register(name, factory):
+    """Register a type, given its name and a factory callable.
+
+    Determines the required and optional flags from the factory's
+    arguments."""
+    factory_setup(name, factory)
+    available_types[factory.name] = factory
+
+
+# Register all our included types
+for name in dir(types):
+    if name.startswith('_'):
+        continue
+
+    obj = getattr(types, name)
+    if not isinstance(obj, Callable):
+        continue
+
+    register(name, obj)
diff --git a/meta/lib/oe/terminal.py b/meta/lib/oe/terminal.py
new file mode 100644
index 0000000..0d875c3
--- /dev/null
+++ b/meta/lib/oe/terminal.py
@@ -0,0 +1,315 @@
+#
+# Imported from openembedded-core
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+import logging
+import oe.classutils
+import shlex
+from bb.process import Popen, ExecutionError
+from distutils.version import LooseVersion
+
+logger = logging.getLogger('BitBake.OE.Terminal')
+
+
+class UnsupportedTerminal(Exception):
+    pass
+
+class NoSupportedTerminals(Exception):
+    def __init__(self, terms):
+        self.terms = terms
+
+
+class Registry(oe.classutils.ClassRegistry):
+    command = None
+
+    def __init__(cls, name, bases, attrs):
+        super(Registry, cls).__init__(name.lower(), bases, attrs)
+
+    @property
+    def implemented(cls):
+        return bool(cls.command)
+
+
+class Terminal(Popen, metaclass=Registry):
+    def __init__(self, sh_cmd, title=None, env=None, d=None):
+        fmt_sh_cmd = self.format_command(sh_cmd, title)
+        try:
+            Popen.__init__(self, fmt_sh_cmd, env=env)
+        except OSError as exc:
+            import errno
+            if exc.errno == errno.ENOENT:
+                raise UnsupportedTerminal(self.name)
+            else:
+                raise
+
+    def format_command(self, sh_cmd, title):
+        fmt = {'title': title or 'Terminal', 'command': sh_cmd, 'cwd': os.getcwd() }
+        if isinstance(self.command, str):
+            return shlex.split(self.command.format(**fmt))
+        else:
+            return [element.format(**fmt) for element in self.command]
+
+class XTerminal(Terminal):
+    def __init__(self, sh_cmd, title=None, env=None, d=None):
+        Terminal.__init__(self, sh_cmd, title, env, d)
+        if not os.environ.get('DISPLAY'):
+            raise UnsupportedTerminal(self.name)
+
+class Gnome(XTerminal):
+    command = 'gnome-terminal -t "{title}" -x {command}'
+    priority = 2
+
+    def __init__(self, sh_cmd, title=None, env=None, d=None):
+        # Recent versions of gnome-terminal does not support non-UTF8 charset:
+        # https://bugzilla.gnome.org/show_bug.cgi?id=732127; as a workaround,
+        # clearing the LC_ALL environment variable so it uses the locale.
+        # Once fixed on the gnome-terminal project, this should be removed.
+        if os.getenv('LC_ALL'): os.putenv('LC_ALL','')
+
+        XTerminal.__init__(self, sh_cmd, title, env, d)
+
+class Mate(XTerminal):
+    command = 'mate-terminal --disable-factory -t "{title}" -x {command}'
+    priority = 2
+
+class Xfce(XTerminal):
+    command = 'xfce4-terminal -T "{title}" -e "{command}"'
+    priority = 2
+
+class Terminology(XTerminal):
+    command = 'terminology -T="{title}" -e {command}'
+    priority = 2
+
+class Konsole(XTerminal):
+    command = 'konsole --separate --workdir . -p tabtitle="{title}" -e {command}'
+    priority = 2
+
+    def __init__(self, sh_cmd, title=None, env=None, d=None):
+        # Check version
+        vernum = check_terminal_version("konsole")
+        if vernum and LooseVersion(vernum) < '2.0.0':
+            # Konsole from KDE 3.x
+            self.command = 'konsole -T "{title}" -e {command}'
+        elif vernum and LooseVersion(vernum) < '16.08.1':
+            # Konsole pre 16.08.01 Has nofork
+            self.command = 'konsole --nofork --workdir . -p tabtitle="{title}" -e {command}'
+        XTerminal.__init__(self, sh_cmd, title, env, d)
+
+class XTerm(XTerminal):
+    command = 'xterm -T "{title}" -e {command}'
+    priority = 1
+
+class Rxvt(XTerminal):
+    command = 'rxvt -T "{title}" -e {command}'
+    priority = 1
+
+class Screen(Terminal):
+    command = 'screen -D -m -t "{title}" -S devshell {command}'
+
+    def __init__(self, sh_cmd, title=None, env=None, d=None):
+        s_id = "devshell_%i" % os.getpid()
+        self.command = "screen -D -m -t \"{title}\" -S %s {command}" % s_id
+        Terminal.__init__(self, sh_cmd, title, env, d)
+        msg = 'Screen started. Please connect in another terminal with ' \
+            '"screen -r %s"' % s_id
+        if (d):
+            bb.event.fire(bb.event.LogExecTTY(msg, "screen -r %s" % s_id,
+                                              0.5, 10), d)
+        else:
+            logger.warning(msg)
+
+class TmuxRunning(Terminal):
+    """Open a new pane in the current running tmux window"""
+    name = 'tmux-running'
+    command = 'tmux split-window -c "{cwd}" "{command}"'
+    priority = 2.75
+
+    def __init__(self, sh_cmd, title=None, env=None, d=None):
+        if not bb.utils.which(os.getenv('PATH'), 'tmux'):
+            raise UnsupportedTerminal('tmux is not installed')
+
+        if not os.getenv('TMUX'):
+            raise UnsupportedTerminal('tmux is not running')
+
+        if not check_tmux_pane_size('tmux'):
+            raise UnsupportedTerminal('tmux pane too small or tmux < 1.9 version is being used')
+
+        Terminal.__init__(self, sh_cmd, title, env, d)
+
+class TmuxNewWindow(Terminal):
+    """Open a new window in the current running tmux session"""
+    name = 'tmux-new-window'
+    command = 'tmux new-window -c "{cwd}" -n "{title}" "{command}"'
+    priority = 2.70
+
+    def __init__(self, sh_cmd, title=None, env=None, d=None):
+        if not bb.utils.which(os.getenv('PATH'), 'tmux'):
+            raise UnsupportedTerminal('tmux is not installed')
+
+        if not os.getenv('TMUX'):
+            raise UnsupportedTerminal('tmux is not running')
+
+        Terminal.__init__(self, sh_cmd, title, env, d)
+
+class Tmux(Terminal):
+    """Start a new tmux session and window"""
+    command = 'tmux new -c "{cwd}" -d -s devshell -n devshell "{command}"'
+    priority = 0.75
+
+    def __init__(self, sh_cmd, title=None, env=None, d=None):
+        if not bb.utils.which(os.getenv('PATH'), 'tmux'):
+            raise UnsupportedTerminal('tmux is not installed')
+
+        # TODO: consider using a 'devshell' session shared amongst all
+        # devshells, if it's already there, add a new window to it.
+        window_name = 'devshell-%i' % os.getpid()
+
+        self.command = 'tmux new -c "{{cwd}}" -d -s {0} -n {0} "{{command}}"'.format(window_name)
+        Terminal.__init__(self, sh_cmd, title, env, d)
+
+        attach_cmd = 'tmux att -t {0}'.format(window_name)
+        msg = 'Tmux started. Please connect in another terminal with `tmux att -t {0}`'.format(window_name)
+        if d:
+            bb.event.fire(bb.event.LogExecTTY(msg, attach_cmd, 0.5, 10), d)
+        else:
+            logger.warning(msg)
+
+class Custom(Terminal):
+    command = 'false' # This is a placeholder
+    priority = 3
+
+    def __init__(self, sh_cmd, title=None, env=None, d=None):
+        self.command = d and d.getVar('OE_TERMINAL_CUSTOMCMD')
+        if self.command:
+            if not '{command}' in self.command:
+                self.command += ' {command}'
+            Terminal.__init__(self, sh_cmd, title, env, d)
+            logger.warning('Custom terminal was started.')
+        else:
+            logger.debug(1, 'No custom terminal (OE_TERMINAL_CUSTOMCMD) set')
+            raise UnsupportedTerminal('OE_TERMINAL_CUSTOMCMD not set')
+
+
+def prioritized():
+    return Registry.prioritized()
+
+def get_cmd_list():
+    terms = Registry.prioritized()
+    cmds = []
+    for term in terms:
+        if term.command:
+            cmds.append(term.command)
+    return cmds
+
+def spawn_preferred(sh_cmd, title=None, env=None, d=None):
+    """Spawn the first supported terminal, by priority"""
+    for terminal in prioritized():
+        try:
+            spawn(terminal.name, sh_cmd, title, env, d)
+            break
+        except UnsupportedTerminal:
+            continue
+    else:
+        raise NoSupportedTerminals(get_cmd_list())
+
+def spawn(name, sh_cmd, title=None, env=None, d=None):
+    """Spawn the specified terminal, by name"""
+    logger.debug(1, 'Attempting to spawn terminal "%s"', name)
+    try:
+        terminal = Registry.registry[name]
+    except KeyError:
+        raise UnsupportedTerminal(name)
+
+    # We need to know when the command completes but some terminals (at least
+    # gnome and tmux) gives us no way to do this. We therefore write the pid
+    # to a file using a "phonehome" wrapper script, then monitor the pid
+    # until it exits.
+    import tempfile
+    import time
+    pidfile = tempfile.NamedTemporaryFile(delete = False).name
+    try:
+        sh_cmd = bb.utils.which(os.getenv('PATH'), "oe-gnome-terminal-phonehome") + " " + pidfile + " " + sh_cmd
+        pipe = terminal(sh_cmd, title, env, d)
+        output = pipe.communicate()[0]
+        if output:
+            output = output.decode("utf-8")
+        if pipe.returncode != 0:
+            raise ExecutionError(sh_cmd, pipe.returncode, output)
+
+        while os.stat(pidfile).st_size <= 0:
+            time.sleep(0.01)
+            continue
+        with open(pidfile, "r") as f:
+            pid = int(f.readline())
+    finally:
+        os.unlink(pidfile)
+
+    while True:
+        try:
+            os.kill(pid, 0)
+            time.sleep(0.1)
+        except OSError:
+           return
+
+def check_tmux_pane_size(tmux):
+    import subprocess as sub
+    # On older tmux versions (<1.9), return false. The reason
+    # is that there is no easy way to get the height of the active panel
+    # on current window without nested formats (available from version 1.9)
+    vernum = check_terminal_version("tmux")
+    if vernum and LooseVersion(vernum) < '1.9':
+        return False
+    try:
+        p = sub.Popen('%s list-panes -F "#{?pane_active,#{pane_height},}"' % tmux,
+                shell=True,stdout=sub.PIPE,stderr=sub.PIPE)
+        out, err = p.communicate()
+        size = int(out.strip())
+    except OSError as exc:
+        import errno
+        if exc.errno == errno.ENOENT:
+            return None
+        else:
+            raise
+
+    return size/2 >= 19
+
+def check_terminal_version(terminalName):
+    import subprocess as sub
+    try:
+        cmdversion = '%s --version' % terminalName
+        if terminalName.startswith('tmux'):
+            cmdversion = '%s -V' % terminalName
+        newenv = os.environ.copy()
+        newenv["LANG"] = "C"
+        p = sub.Popen(['sh', '-c', cmdversion], stdout=sub.PIPE, stderr=sub.PIPE, env=newenv)
+        out, err = p.communicate()
+        ver_info = out.decode().rstrip().split('\n')
+    except OSError as exc:
+        import errno
+        if exc.errno == errno.ENOENT:
+            return None
+        else:
+            raise
+    vernum = None
+    for ver in ver_info:
+        if ver.startswith('Konsole'):
+            vernum = ver.split(' ')[-1]
+        if ver.startswith('GNOME Terminal'):
+            vernum = ver.split(' ')[-1]
+        if ver.startswith('MATE Terminal'):
+            vernum = ver.split(' ')[-1]
+        if ver.startswith('tmux'):
+            vernum = ver.split()[-1]
+        if ver.startswith('tmux next-'):
+            vernum = ver.split()[-1][5:]
+    return vernum
+
+def distro_name():
+    try:
+        p = Popen(['lsb_release', '-i'])
+        out, err = p.communicate()
+        distro = out.split(':')[1].strip().lower()
+    except:
+        distro = "unknown"
+    return distro
diff --git a/meta/lib/oe/types.py b/meta/lib/oe/types.py
new file mode 100644
index 0000000..ad8dd36
--- /dev/null
+++ b/meta/lib/oe/types.py
@@ -0,0 +1,187 @@
+#
+# Imported from openembedded-core
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+import errno
+import re
+import os
+
+
+class OEList(list):
+    """OpenEmbedded 'list' type
+
+    Acts as an ordinary list, but is constructed from a string value and a
+    separator (optional), and re-joins itself when converted to a string with
+    str().  Set the variable type flag to 'list' to use this type, and the
+    'separator' flag may be specified (defaulting to whitespace)."""
+
+    name = "list"
+
+    def __init__(self, value, separator = None):
+        if value is not None:
+            list.__init__(self, value.split(separator))
+        else:
+            list.__init__(self)
+
+        if separator is None:
+            self.separator = " "
+        else:
+            self.separator = separator
+
+    def __str__(self):
+        return self.separator.join(self)
+
+def choice(value, choices):
+    """OpenEmbedded 'choice' type
+
+    Acts as a multiple choice for the user.  To use this, set the variable
+    type flag to 'choice', and set the 'choices' flag to a space separated
+    list of valid values."""
+    if not isinstance(value, str):
+        raise TypeError("choice accepts a string, not '%s'" % type(value))
+
+    value = value.lower()
+    choices = choices.lower()
+    if value not in choices.split():
+        raise ValueError("Invalid choice '%s'.  Valid choices: %s" %
+                         (value, choices))
+    return value
+
+class NoMatch(object):
+    """Stub python regex pattern object which never matches anything"""
+    def findall(self, string, flags=0):
+        return None
+
+    def finditer(self, string, flags=0):
+        return None
+
+    def match(self, flags=0):
+        return None
+
+    def search(self, string, flags=0):
+        return None
+
+    def split(self, string, maxsplit=0):
+        return None
+
+    def sub(pattern, repl, string, count=0):
+        return None
+
+    def subn(pattern, repl, string, count=0):
+        return None
+
+NoMatch = NoMatch()
+
+def regex(value, regexflags=None):
+    """OpenEmbedded 'regex' type
+
+    Acts as a regular expression, returning the pre-compiled regular
+    expression pattern object.  To use this type, set the variable type flag
+    to 'regex', and optionally, set the 'regexflags' type to a space separated
+    list of the flags to control the regular expression matching (e.g.
+    FOO[regexflags] += 'ignorecase').  See the python documentation on the
+    're' module for a list of valid flags."""
+
+    flagval = 0
+    if regexflags:
+        for flag in regexflags.split():
+            flag = flag.upper()
+            try:
+                flagval |= getattr(re, flag)
+            except AttributeError:
+                raise ValueError("Invalid regex flag '%s'" % flag)
+
+    if not value:
+        # Let's ensure that the default behavior for an undefined or empty
+        # variable is to match nothing. If the user explicitly wants to match
+        # anything, they can match '.*' instead.
+        return NoMatch
+
+    try:
+        return re.compile(value, flagval)
+    except re.error as exc:
+        raise ValueError("Invalid regex value '%s': %s" %
+                         (value, exc.args[0]))
+
+def boolean(value):
+    """OpenEmbedded 'boolean' type
+
+    Valid values for true: 'yes', 'y', 'true', 't', '1'
+    Valid values for false: 'no', 'n', 'false', 'f', '0', None
+    """
+    if value is None:
+        return False
+
+    if isinstance(value, bool):
+        return value
+
+    if not isinstance(value, str):
+        raise TypeError("boolean accepts a string, not '%s'" % type(value))
+
+    value = value.lower()
+    if value in ('yes', 'y', 'true', 't', '1'):
+        return True
+    elif value in ('no', 'n', 'false', 'f', '0'):
+        return False
+    raise ValueError("Invalid boolean value '%s'" % value)
+
+def integer(value, numberbase=10):
+    """OpenEmbedded 'integer' type
+
+    Defaults to base 10, but this can be specified using the optional
+    'numberbase' flag."""
+
+    return int(value, int(numberbase))
+
+_float = float
+def float(value, fromhex='false'):
+    """OpenEmbedded floating point type
+
+    To use this type, set the type flag to 'float', and optionally set the
+    'fromhex' flag to a true value (obeying the same rules as for the
+    'boolean' type) if the value is in base 16 rather than base 10."""
+
+    if boolean(fromhex):
+        return _float.fromhex(value)
+    else:
+        return _float(value)
+
+def path(value, relativeto='', normalize='true', mustexist='false'):
+    value = os.path.join(relativeto, value)
+
+    if boolean(normalize):
+        value = os.path.normpath(value)
+
+    if boolean(mustexist):
+        try:
+            open(value, 'r')
+        except IOError as exc:
+            if exc.errno == errno.ENOENT:
+                raise ValueError("{0}: {1}".format(value, os.strerror(errno.ENOENT)))
+
+    return value
+
+def is_x86(arch):
+    """
+    Check whether arch is x86 or x86_64
+    """
+    if arch.startswith('x86_') or re.match('i.*86', arch):
+        return True
+    else:
+        return False
+
+def qemu_use_kvm(kvm, target_arch):
+    """
+    Enable kvm if target_arch == build_arch or both of them are x86 archs.
+    """
+
+    use_kvm = False
+    if kvm and boolean(kvm):
+        build_arch = os.uname()[4]
+        if is_x86(build_arch) and is_x86(target_arch):
+            use_kvm = True
+        elif build_arch == target_arch:
+            use_kvm = True
+    return use_kvm
diff --git a/scripts/oe-gnome-terminal-phonehome b/scripts/oe-gnome-terminal-phonehome
new file mode 100755
index 0000000..5a321a2
--- /dev/null
+++ b/scripts/oe-gnome-terminal-phonehome
@@ -0,0 +1,14 @@
+#!/bin/sh
+#
+# Imported from openembedded-core
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Gnome terminal won't tell us which PID a given command is run as
+# or allow a single instance so we can't tell when it completes.
+# This allows us to figure out the PID of the target so we can tell
+# when its done.
+#
+echo $$ > $1
+shift
+exec $@
-- 
2.16.4


  parent reply	other threads:[~2019-09-22 18:17 UTC|newest]

Thread overview: 78+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-09-22 18:16 [PATCH v5 00/27] Pending patches, fix for isar-bootstrap, devshell Jan Kiszka
2019-09-22 18:16 ` [PATCH v5 01/27] buildchroot: Properly deploy the build result Jan Kiszka
2019-09-22 18:16 ` [PATCH v5 02/27] sdk: Use clean-package-cache rather than open-coded cleanup Jan Kiszka
2019-09-22 18:16 ` [PATCH v5 03/27] sdk: Deploy earlier Jan Kiszka
2019-09-22 18:16 ` [PATCH v5 04/27] Remove unneeded PF tweakings Jan Kiszka
2019-09-22 18:16 ` [PATCH v5 05/27] image: Stop changing PF, tune WORKDIR and STAMP directly Jan Kiszka
2019-09-25 12:47   ` [PATCH v6 " Jan Kiszka
2019-09-22 18:16 ` [PATCH v5 06/27] image: Make WORKDIR and STAMPs IMAGE_TYPE-specific Jan Kiszka
2019-09-22 18:16 ` [PATCH v5 07/27] Adjust STAMP variables to use PN, rather than PF Jan Kiszka
2019-09-22 18:16 ` [PATCH v5 08/27] Align WORKDIR structure with OE Jan Kiszka
2019-09-22 18:16 ` [PATCH v5 09/27] isar-bootstrap: Unshare host bootstraps across different target distros Jan Kiszka
2019-09-22 18:16 ` [PATCH v5 10/27] isar-bootstrap: Clean up and fix rebuild Jan Kiszka
2019-09-22 18:16 ` [PATCH v5 11/27] gitlab-ci: Keep logs as artifacts on failure Jan Kiszka
2019-09-22 18:16 ` [PATCH v5 12/27] Detect false sharing of recipes Jan Kiszka
2019-09-24 18:02   ` [PATCH v6 " Jan Kiszka
2019-09-29 14:57     ` Baurzhan Ismagulov
2019-09-30  6:00       ` Jan Kiszka
2019-09-30  9:56         ` Baurzhan Ismagulov
2019-09-30 10:14           ` Jan Kiszka
2019-09-30 14:53             ` Baurzhan Ismagulov
2019-09-30 15:26               ` Jan Kiszka
2019-09-30 15:39                 ` Baurzhan Ismagulov
2019-09-30 16:34                   ` Jan Kiszka
2019-09-30 17:20                     ` Baurzhan Ismagulov
2019-09-30 17:26                       ` Jan Kiszka
2019-09-30 20:29                         ` Baurzhan Ismagulov
2019-09-22 18:16 ` [PATCH v5 13/27] dpkg-base: Move do_deploy_deb before do_build Jan Kiszka
2019-10-02  7:09   ` Baurzhan Ismagulov
2019-09-22 18:16 ` [PATCH v5 14/27] base-apt: Move do_cache_config " Jan Kiszka
2019-09-22 18:16 ` [PATCH v5 15/27] wic-img: Use private tmp dir Jan Kiszka
2019-09-22 18:17 ` [PATCH v5 16/27] rootfs: Take isar-apt shared lock during repository operations Jan Kiszka
2019-09-22 18:17 ` [PATCH v5 17/27] Use deb.debian.org mirrors Jan Kiszka
2019-09-23 10:03   ` Baurzhan Ismagulov
2019-09-23 10:09     ` Jan Kiszka
2019-10-02 11:13   ` Baurzhan Ismagulov
2019-09-22 18:17 ` [PATCH v5 18/27] linux-custom: Control linux-libc-dev deployment manually Jan Kiszka
2019-09-22 18:17 ` [PATCH v5 19/27] dpkg-base: Wait for umount to succeed Jan Kiszka
2019-09-30 11:07   ` Baurzhan Ismagulov
2019-09-30 12:22     ` Jan Kiszka
2019-09-30 13:33       ` Baurzhan Ismagulov
2019-10-07 15:48   ` Baurzhan Ismagulov
2019-09-22 18:17 ` [PATCH v5 20/27] dpkg-base: Permit multiple clean runs Jan Kiszka
2019-09-22 18:17 ` [PATCH v5 21/27] buildchroot: Factor out common packages Jan Kiszka
2019-09-22 18:17 ` [PATCH v5 22/27] buildchroot: Do not build cross when there are no arch-specific outputs Jan Kiszka
2019-09-22 18:17 ` [PATCH v5 23/27] Add git-buildpackage support Jan Kiszka
2019-09-22 18:17 ` [PATCH v5 24/27] dbpg-raw: Only list top-level files in <pn>.install Jan Kiszka
2019-09-23  9:52   ` Baurzhan Ismagulov
2019-09-23 10:29     ` Jan Kiszka
2019-09-23 10:30       ` Baurzhan Ismagulov
2019-09-22 18:17 ` Jan Kiszka [this message]
2019-09-22 18:17 ` [PATCH v5 26/27] dpkg-base: Add devshell target Jan Kiszka
2019-09-22 18:17 ` [PATCH v5 27/27] linux-custom: Add libncurses-dev to KBUILD_DEPENDS Jan Kiszka
2019-09-23  6:33 ` [PATCH v5 00/27] Pending patches, fix for isar-bootstrap, devshell Baurzhan Ismagulov
2019-09-23  7:33   ` Jan Kiszka
2019-09-23  7:50     ` Baurzhan Ismagulov
2019-09-23  9:50 ` Baurzhan Ismagulov
2019-09-23 10:07   ` Jan Kiszka
2019-09-23 10:23     ` Baurzhan Ismagulov
2019-09-23 10:28       ` Jan Kiszka
2019-09-25  8:41         ` Baurzhan Ismagulov
2019-09-25  8:51           ` Jan Kiszka
2019-09-25  9:22             ` Baurzhan Ismagulov
2019-09-25  9:26               ` Jan Kiszka
2019-09-25  9:35                 ` Baurzhan Ismagulov
2019-09-25  9:35                 ` Jan Kiszka
2019-09-25 10:52                   ` Baurzhan Ismagulov
2019-09-25 11:05                     ` Jan Kiszka
2019-09-25 12:08                       ` Baurzhan Ismagulov
2019-09-25 12:29                         ` Jan Kiszka
2019-09-25 12:44                           ` Baurzhan Ismagulov
2019-09-23 14:24   ` Henning Schild
2019-09-28 15:46     ` Baurzhan Ismagulov
2019-09-25 10:23 ` Henning Schild
2019-09-25 11:41   ` Jan Kiszka
2019-09-30  9:29     ` Baurzhan Ismagulov
2019-09-30 10:02       ` Jan Kiszka
2019-09-30 13:00       ` Baurzhan Ismagulov
2019-10-01 14:47 ` Baurzhan Ismagulov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b032b3fb4025e0f2a42ce714fd9db4960c869a9c.1569176231.git.jan.kiszka@siemens.com \
    --to=jan.kiszka@siemens.com \
    --cc=isar-users@googlegroups.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox