summaryrefslogtreecommitdiffstats
path: root/meta/lib/oe/terminal.py
diff options
context:
space:
mode:
Diffstat (limited to 'meta/lib/oe/terminal.py')
-rw-r--r--meta/lib/oe/terminal.py208
1 files changed, 208 insertions, 0 deletions
diff --git a/meta/lib/oe/terminal.py b/meta/lib/oe/terminal.py
new file mode 100644
index 0000000000..0a623c75b1
--- /dev/null
+++ b/meta/lib/oe/terminal.py
@@ -0,0 +1,208 @@
1import logging
2import oe.classutils
3import shlex
4from bb.process import Popen, ExecutionError
5
6logger = logging.getLogger('BitBake.OE.Terminal')
7
8
9class UnsupportedTerminal(Exception):
10 pass
11
12class NoSupportedTerminals(Exception):
13 pass
14
15
16class Registry(oe.classutils.ClassRegistry):
17 command = None
18
19 def __init__(cls, name, bases, attrs):
20 super(Registry, cls).__init__(name.lower(), bases, attrs)
21
22 @property
23 def implemented(cls):
24 return bool(cls.command)
25
26
27class Terminal(Popen):
28 __metaclass__ = Registry
29
30 def __init__(self, sh_cmd, title=None, env=None, d=None):
31 fmt_sh_cmd = self.format_command(sh_cmd, title)
32 try:
33 Popen.__init__(self, fmt_sh_cmd, env=env)
34 except OSError as exc:
35 import errno
36 if exc.errno == errno.ENOENT:
37 raise UnsupportedTerminal(self.name)
38 else:
39 raise
40
41 def format_command(self, sh_cmd, title):
42 fmt = {'title': title or 'Terminal', 'command': sh_cmd}
43 if isinstance(self.command, basestring):
44 return shlex.split(self.command.format(**fmt))
45 else:
46 return [element.format(**fmt) for element in self.command]
47
48class XTerminal(Terminal):
49 def __init__(self, sh_cmd, title=None, env=None, d=None):
50 Terminal.__init__(self, sh_cmd, title, env, d)
51 if not os.environ.get('DISPLAY'):
52 raise UnsupportedTerminal(self.name)
53
54class Gnome(XTerminal):
55 command = 'gnome-terminal -t "{title}" -x {command}'
56 priority = 2
57
58class Mate(XTerminal):
59 command = 'mate-terminal -t "{title}" -x {command}'
60 priority = 2
61
62class Xfce(XTerminal):
63 command = 'xfce4-terminal -T "{title}" -e "{command}"'
64 priority = 2
65
66class Konsole(XTerminal):
67 command = 'konsole -T "{title}" -e {command}'
68 priority = 2
69
70 def __init__(self, sh_cmd, title=None, env=None, d=None):
71 # Check version
72 vernum = check_konsole_version("konsole")
73 if vernum:
74 if vernum.split('.')[0] == "2":
75 logger.debug(1, 'Konsole from KDE 4.x will not work as devshell, skipping')
76 raise UnsupportedTerminal(self.name)
77 XTerminal.__init__(self, sh_cmd, title, env, d)
78
79class XTerm(XTerminal):
80 command = 'xterm -T "{title}" -e {command}'
81 priority = 1
82
83class Rxvt(XTerminal):
84 command = 'rxvt -T "{title}" -e {command}'
85 priority = 1
86
87class Screen(Terminal):
88 command = 'screen -D -m -t "{title}" -S devshell {command}'
89
90 def __init__(self, sh_cmd, title=None, env=None, d=None):
91 s_id = "devshell_%i" % os.getpid()
92 self.command = "screen -D -m -t \"{title}\" -S %s {command}" % s_id
93 Terminal.__init__(self, sh_cmd, title, env, d)
94 msg = 'Screen started. Please connect in another terminal with ' \
95 '"screen -r %s"' % s_id
96 if (d):
97 bb.event.fire(bb.event.LogExecTTY(msg, "screen -r %s" % s_id,
98 0.5, 10), d)
99 else:
100 logger.warn(msg)
101
102class TmuxRunning(Terminal):
103 """Open a new pane in the current running tmux window"""
104 name = 'tmux-running'
105 command = 'tmux split-window "{command}"'
106 priority = 2.75
107
108 def __init__(self, sh_cmd, title=None, env=None, d=None):
109 if not bb.utils.which(os.getenv('PATH'), 'tmux'):
110 raise UnsupportedTerminal('tmux is not installed')
111
112 if not os.getenv('TMUX'):
113 raise UnsupportedTerminal('tmux is not running')
114
115 Terminal.__init__(self, sh_cmd, title, env, d)
116
117class Tmux(Terminal):
118 """Start a new tmux session and window"""
119 command = 'tmux new -d -s devshell -n devshell "{command}"'
120 priority = 0.75
121
122 def __init__(self, sh_cmd, title=None, env=None, d=None):
123 if not bb.utils.which(os.getenv('PATH'), 'tmux'):
124 raise UnsupportedTerminal('tmux is not installed')
125
126 # TODO: consider using a 'devshell' session shared amongst all
127 # devshells, if it's already there, add a new window to it.
128 window_name = 'devshell-%i' % os.getpid()
129
130 self.command = 'tmux new -d -s {0} -n {0} "{{command}}"'.format(window_name)
131 Terminal.__init__(self, sh_cmd, title, env, d)
132
133 attach_cmd = 'tmux att -t {0}'.format(window_name)
134 msg = 'Tmux started. Please connect in another terminal with `tmux att -t {0}`'.format(window_name)
135 if d:
136 bb.event.fire(bb.event.LogExecTTY(msg, attach_cmd, 0.5, 10), d)
137 else:
138 logger.warn(msg)
139
140class Custom(Terminal):
141 command = 'false' # This is a placeholder
142 priority = 3
143
144 def __init__(self, sh_cmd, title=None, env=None, d=None):
145 self.command = d and d.getVar('OE_TERMINAL_CUSTOMCMD', True)
146 if self.command:
147 if not '{command}' in self.command:
148 self.command += ' {command}'
149 Terminal.__init__(self, sh_cmd, title, env, d)
150 logger.warn('Custom terminal was started.')
151 else:
152 logger.debug(1, 'No custom terminal (OE_TERMINAL_CUSTOMCMD) set')
153 raise UnsupportedTerminal('OE_TERMINAL_CUSTOMCMD not set')
154
155
156def prioritized():
157 return Registry.prioritized()
158
159def spawn_preferred(sh_cmd, title=None, env=None, d=None):
160 """Spawn the first supported terminal, by priority"""
161 for terminal in prioritized():
162 try:
163 spawn(terminal.name, sh_cmd, title, env, d)
164 break
165 except UnsupportedTerminal:
166 continue
167 else:
168 raise NoSupportedTerminals()
169
170def spawn(name, sh_cmd, title=None, env=None, d=None):
171 """Spawn the specified terminal, by name"""
172 logger.debug(1, 'Attempting to spawn terminal "%s"', name)
173 try:
174 terminal = Registry.registry[name]
175 except KeyError:
176 raise UnsupportedTerminal(name)
177
178 pipe = terminal(sh_cmd, title, env, d)
179 output = pipe.communicate()[0]
180 if pipe.returncode != 0:
181 raise ExecutionError(sh_cmd, pipe.returncode, output)
182
183def check_konsole_version(konsole):
184 import subprocess as sub
185 try:
186 p = sub.Popen(['sh', '-c', '%s --version' % konsole],stdout=sub.PIPE,stderr=sub.PIPE)
187 out, err = p.communicate()
188 ver_info = out.rstrip().split('\n')
189 except OSError as exc:
190 import errno
191 if exc.errno == errno.ENOENT:
192 return None
193 else:
194 raise
195 vernum = None
196 for ver in ver_info:
197 if ver.startswith('Konsole'):
198 vernum = ver.split(' ')[-1]
199 return vernum
200
201def distro_name():
202 try:
203 p = Popen(['lsb_release', '-i'])
204 out, err = p.communicate()
205 distro = out.split(':')[1].strip().lower()
206 except:
207 distro = "unknown"
208 return distro