Merge lp:~terceiro/lava-dispatcher/filter-ansi-color-codes into lp:lava-dispatcher

Proposed by Antonio Terceiro
Status: Rejected
Rejected by: Neil Williams
Proposed branch: lp:~terceiro/lava-dispatcher/filter-ansi-color-codes
Merge into: lp:lava-dispatcher
Prerequisite: lp:~terceiro/lava-dispatcher/fix-unit-tests
Diff against target: 242 lines (+104/-8)
11 files modified
lava_dispatcher/client/targetdevice.py (+1/-1)
lava_dispatcher/device/fastmodel.py (+4/-2)
lava_dispatcher/device/ipmi_pxe.py (+1/-1)
lava_dispatcher/device/master.py (+1/-1)
lava_dispatcher/device/qemu.py (+1/-1)
lava_dispatcher/device/sdmux.py (+1/-1)
lava_dispatcher/device/target.py (+1/-1)
lava_dispatcher/tests/__init__.py (+1/-0)
lava_dispatcher/tests/simulate_uefi_on_fastmodel.py (+10/-0)
lava_dispatcher/tests/test_utils.py (+61/-0)
lava_dispatcher/utils.py (+22/-0)
To merge this branch: bzr merge lp:~terceiro/lava-dispatcher/filter-ansi-color-codes
Reviewer Review Type Date Requested Status
Antonio Terceiro Needs Resubmitting
Review via email: mp+178188@code.launchpad.net

This proposal supersedes a proposal from 2013-08-02.

Description of the change

Filter out ANSI color codes when matching for patterns. This shoulf fix #1197582

To post a comment you must log in.
Revision history for this message
Antonio Terceiro (terceiro) wrote :

This does not fix the problem yet - no need for reviewing now. I will resubmit when it's done.

review: Needs Resubmitting
646. By Antonio Terceiro

Need to filter out non-color codes as well, such as cursor positioning, screen
clearing etc.

647. By Antonio Terceiro

Deal with slow/broken serial connection when filtering out ANSI escape sequences

648. By Antonio Terceiro

Merge branch for supporting specifying a bootloader on deployment of prebuilt images as well

649. By Antonio Terceiro

filter other escape sequences

650. By Antonio Terceiro

update from parent branch

651. By Antonio Terceiro

update from trunk

Unmerged revisions

651. By Antonio Terceiro

update from trunk

650. By Antonio Terceiro

update from parent branch

649. By Antonio Terceiro

filter other escape sequences

648. By Antonio Terceiro

Merge branch for supporting specifying a bootloader on deployment of prebuilt images as well

647. By Antonio Terceiro

Deal with slow/broken serial connection when filtering out ANSI escape sequences

646. By Antonio Terceiro

Need to filter out non-color codes as well, such as cursor positioning, screen
clearing etc.

645. By Antonio Terceiro

Filter out ANSI color escape sequences when reading input from child processes

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lava_dispatcher/client/targetdevice.py'
2--- lava_dispatcher/client/targetdevice.py 2013-07-24 16:56:18 +0000
3+++ lava_dispatcher/client/targetdevice.py 2013-08-08 15:29:54 +0000
4@@ -62,7 +62,7 @@
5 if image is None:
6 self.target_device.deploy_linaro(hwpack, rootfs, bootloader)
7 else:
8- self.target_device.deploy_linaro_prebuilt(image)
9+ self.target_device.deploy_linaro_prebuilt(image, bootloader)
10
11 def _boot_linaro_image(self):
12 if self.proc:
13
14=== modified file 'lava_dispatcher/device/fastmodel.py'
15--- lava_dispatcher/device/fastmodel.py 2013-07-24 14:04:25 +0000
16+++ lava_dispatcher/device/fastmodel.py 2013-08-08 15:29:54 +0000
17@@ -171,10 +171,11 @@
18 rootfs = download_image(rootfs, self.context, decompress=False)
19 odir = os.path.dirname(rootfs)
20
21- self._bootloader = bootloader
22
23 generate_fastmodel_image(self.context, hwpack, rootfs, odir, bootloader)
24+
25 self._sd_image = '%s/sd.img' % odir
26+ self._bootloader = bootloader
27
28 self._copy_needed_files_from_directory(odir)
29 self._copy_needed_files_from_partition(self.config.boot_part, 'rtsm')
30@@ -182,8 +183,9 @@
31
32 self._customize_linux(self._sd_image)
33
34- def deploy_linaro_prebuilt(self, image):
35+ def deploy_linaro_prebuilt(self, image, bootloader='u_boot'):
36 self._sd_image = download_image(image, self.context)
37+ self._bootloader = bootloader
38
39 self._copy_needed_files_from_partition(self.config.boot_part, 'rtsm')
40 self._copy_needed_files_from_partition(self.config.root_part, 'boot')
41
42=== modified file 'lava_dispatcher/device/ipmi_pxe.py'
43--- lava_dispatcher/device/ipmi_pxe.py 2013-07-16 16:06:42 +0000
44+++ lava_dispatcher/device/ipmi_pxe.py 2013-08-08 15:29:54 +0000
45@@ -79,7 +79,7 @@
46 self._customize_linux(image_file)
47 self._deploy_image(image_file, '/dev/sda')
48
49- def deploy_linaro_prebuilt(self, image):
50+ def deploy_linaro_prebuilt(self, image, bootloader):
51 image_file = download_image(image, self.context, self.scratch_dir)
52 self._customize_linux(image_file)
53 self._deploy_image(image_file, '/dev/sda')
54
55=== modified file 'lava_dispatcher/device/master.py'
56--- lava_dispatcher/device/master.py 2013-07-17 09:16:46 +0000
57+++ lava_dispatcher/device/master.py 2013-08-08 15:29:54 +0000
58@@ -149,7 +149,7 @@
59 _deploy_linaro_android_system(master, system_url)
60 _deploy_linaro_android_data(master, data_url)
61
62- def deploy_linaro_prebuilt(self, image):
63+ def deploy_linaro_prebuilt(self, image, bootloader):
64 self.boot_master_image()
65
66 if self.context.job_data.get('health_check', False):
67
68=== modified file 'lava_dispatcher/device/qemu.py'
69--- lava_dispatcher/device/qemu.py 2013-07-24 14:04:25 +0000
70+++ lava_dispatcher/device/qemu.py 2013-08-08 15:29:54 +0000
71@@ -51,7 +51,7 @@
72 self._sd_image = generate_image(self, hwpack, rootfs, odir, bootloader)
73 self._customize_linux(self._sd_image)
74
75- def deploy_linaro_prebuilt(self, image):
76+ def deploy_linaro_prebuilt(self, image, bootloader='u_boot'):
77 self._sd_image = download_image(image, self.context)
78 self._customize_linux(self._sd_image)
79
80
81=== modified file 'lava_dispatcher/device/sdmux.py'
82--- lava_dispatcher/device/sdmux.py 2013-07-16 16:04:07 +0000
83+++ lava_dispatcher/device/sdmux.py 2013-08-08 15:29:54 +0000
84@@ -93,7 +93,7 @@
85 self._customize_linux(img)
86 self._write_image(img)
87
88- def deploy_linaro_prebuilt(self, image):
89+ def deploy_linaro_prebuilt(self, image, bootloader=None):
90 img = download_image(image, self.context)
91 self._customize_linux(img)
92 self._write_image(img)
93
94=== modified file 'lava_dispatcher/device/target.py'
95--- lava_dispatcher/device/target.py 2013-07-17 09:16:46 +0000
96+++ lava_dispatcher/device/target.py 2013-08-08 15:29:54 +0000
97@@ -91,7 +91,7 @@
98 def deploy_android(self, boot, system, userdata):
99 raise NotImplementedError('deploy_android_image')
100
101- def deploy_linaro_prebuilt(self, image):
102+ def deploy_linaro_prebuilt(self, image, bootloader):
103 raise NotImplementedError('deploy_linaro_prebuilt')
104
105 def power_off(self, proc):
106
107=== modified file 'lava_dispatcher/tests/__init__.py'
108--- lava_dispatcher/tests/__init__.py 2013-07-16 16:09:31 +0000
109+++ lava_dispatcher/tests/__init__.py 2013-08-08 15:29:54 +0000
110@@ -3,6 +3,7 @@
111
112 def test_suite():
113 module_names = [
114+ 'lava_dispatcher.tests.test_utils',
115 'lava_dispatcher.tests.test_config',
116 'lava_dispatcher.tests.test_device_version',
117 ]
118
119=== added file 'lava_dispatcher/tests/simulate_uefi_on_fastmodel.py'
120--- lava_dispatcher/tests/simulate_uefi_on_fastmodel.py 1970-01-01 00:00:00 +0000
121+++ lava_dispatcher/tests/simulate_uefi_on_fastmodel.py 2013-08-08 15:29:54 +0000
122@@ -0,0 +1,10 @@
123+import sys
124+import time
125+
126+chars = 0
127+for char in "\033[23;01H2.0 \033[1m\033[33m\033[40mShell> \033[0m\033[37m\033[40m":
128+ sys.stdout.write(char)
129+ sys.stdout.flush()
130+ chars += 1
131+ if chars % 10 == 0:
132+ time.sleep(0.1)
133
134=== added file 'lava_dispatcher/tests/test_utils.py'
135--- lava_dispatcher/tests/test_utils.py 1970-01-01 00:00:00 +0000
136+++ lava_dispatcher/tests/test_utils.py 2013-08-08 15:29:54 +0000
137@@ -0,0 +1,61 @@
138+# Copyright (C) 2013 Linaro Limited
139+#
140+# Author: Antonio Terceiro <antonio.terceiro@linaro.org>
141+#
142+# This file is part of LAVA Dispatcher.
143+#
144+# LAVA Dispatcher is free software; you can redistribute it and/or modify
145+# it under the terms of the GNU General Public License as published by
146+# the Free Software Foundation; either version 2 of the License, or
147+# (at your option) any later version.
148+#
149+# LAVA Dispatcher is distributed in the hope that it will be useful,
150+# but WITHOUT ANY WARRANTY; without even the implied warranty of
151+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
152+# GNU General Public License for more details.
153+#
154+# You should have received a copy of the GNU General Public License
155+# along with this program; if not, see <http://www.gnu.org/licenses>.
156+
157+from unittest import TestCase
158+import pexpect
159+
160+import os
161+
162+from lava_dispatcher.utils import logging_spawn, remove_ansi_escape_codes
163+
164+class TestLoggingSpawn(TestCase):
165+
166+ def test_filter_out_ansi_color_codes(self):
167+ proc = logging_spawn('printf "I AM \033[1mOK\033[m\n"') # OK in bold
168+ proc.expect(["I AM OK", pexpect.EOF])
169+ self.assertIsNot(proc.match, pexpect.EOF)
170+
171+ def test_filter_out_multiple_ansi_color_escape_sequences(self):
172+ # "I AM" in bold light green, "OK" in bold
173+ proc = logging_spawn('printf "\033[1;32;40mI AM\033[m \033[1mOK\033[m\n"')
174+ proc.expect(["I AM OK", pexpect.EOF])
175+ self.assertIsNot(proc.match, pexpect.EOF)
176+
177+ def test_filter_out_cursor_positioning_codes(self):
178+ proc = logging_spawn('printf "I AM \033[23;01H\033[1mOK\033[m\n"')
179+ proc.expect(["I AM OK", pexpect.EOF])
180+ self.assertIsNot(proc.match, pexpect.EOF)
181+
182+ def test_filter_out_uefi_ansi_crap(self):
183+ program = os.path.join(os.path.dirname(__file__),
184+ 'simulate_uefi_on_fastmodel.py')
185+ proc = logging_spawn('python %s' % program)
186+ proc.expect(['2.0 Shell>', pexpect.EOF])
187+ self.assertIsNot(proc.match, pexpect.EOF)
188+
189+ def test_filter_out_other_types_of_escape_sequences(self):
190+ proc = logging_spawn('printf "\x1b[=3hTHIS \x1b[=3hIS \x1b[=3hOK"')
191+ proc.expect(['THIS IS OK'])
192+ self.assertIsNot(proc.match, pexpect.EOF)
193+
194+ def test_filter_out_incomplete_sequences_followed_by_others(self):
195+ data = "\x1b[01;01\x1b[=3hHELLO"
196+ self.assertEqual(remove_ansi_escape_codes(data), "HELLO")
197+
198+
199
200=== modified file 'lava_dispatcher/utils.py'
201--- lava_dispatcher/utils.py 2013-07-24 16:56:18 +0000
202+++ lava_dispatcher/utils.py 2013-08-08 15:29:54 +0000
203@@ -29,6 +29,7 @@
204 import time
205 import urlparse
206 import subprocess
207+import re
208
209 from shlex import shlex
210
211@@ -213,6 +214,24 @@
212 ['.+', pexpect.EOF, pexpect.TIMEOUT],
213 timeout=1, lava_no_logging=1)
214
215+ def read_nonblocking(self, size, timeout):
216+ read = super(logging_spawn, self).read_nonblocking
217+
218+ raw = read(size, timeout)
219+ filtered = remove_ansi_escape_codes(raw)
220+
221+ while '\x1b' in filtered:
222+ # This happens when the serial connection is too slow -- or just
223+ # broken -- and the escape sequences are split across different
224+ # reads. We have to accumulate more reads until we find the entire
225+ # sequence to be able to filter it out.
226+ raw = raw + read(size, timeout)
227+ logging.debug("Input with potentially incomplete ANSI "
228+ "escape sequence: %r" % raw)
229+ filtered = remove_ansi_escape_codes(raw)
230+
231+ return filtered
232+
233
234 def connect_to_serial(context):
235 """
236@@ -276,3 +295,6 @@
237 logging.debug("Finalizing child proccess with PID %d" % proc.pid)
238 proc.kill(9)
239 proc.close()
240+
241+def remove_ansi_escape_codes(string):
242+ return re.sub('(\x1b\[[0-9;=]*)+[a-zA-Z]', '', string)

Subscribers

People subscribed via source and target branches