Merge lp:~jeffmarcom/opencompute/add-checkbox-ocp-package into lp:opencompute/checkbox

Proposed by Jeff Marcom
Status: Merged
Approved by: Jeff Lane 
Approved revision: 2150
Merged at revision: 2143
Proposed branch: lp:~jeffmarcom/opencompute/add-checkbox-ocp-package
Merge into: lp:opencompute/checkbox
Diff against target: 649 lines (+547/-6)
10 files modified
bin/checkbox-ocp (+18/-0)
checkbox_ocp/cli_interface.py (+477/-0)
debian/changelog (+9/-2)
debian/checkbox-ocp.install (+3/-0)
debian/checkbox-ocp.links (+1/-0)
debian/checkbox-ocp.postinst (+7/-0)
debian/control (+10/-1)
debian/rules (+3/-1)
examples/checkbox-ocp.ini (+17/-0)
setup.py (+2/-2)
To merge this branch: bzr merge lp:~jeffmarcom/opencompute/add-checkbox-ocp-package
Reviewer Review Type Date Requested Status
Jeff Lane  Approve
Review via email: mp+181350@code.launchpad.net

Commit message

This adds a checkbox-ocp package to the list of built debian packages. This commit also bumps the overall changelog version to 1.16.6 so that it does not conflict with a previous checkbox installed package version.

Description of the change

This adds a checkbox-ocp package to the list of built debian packages. This commit also bumps the overall changelog version to 1.16.6 so that it does not conflict with a previous checkbox installed package version.

To post a comment you must log in.
2150. By Jeff Marcom

Updated checkbox-ocp.ini to call proper module interface

Signed-off-by: Jeff Marcom <email address hidden>

Revision history for this message
Jeff Lane  (bladernr) wrote :

Builds and seems to be ok.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'bin/checkbox-ocp'
2--- bin/checkbox-ocp 1970-01-01 00:00:00 +0000
3+++ bin/checkbox-ocp 2013-08-21 16:43:19 +0000
4@@ -0,0 +1,18 @@
5+#!/bin/bash
6+
7+export XDG_CACHE_HOME=${XDG_CACHE_HOME:-$HOME/.cache}
8+export CHECKBOX_DATA=${CHECKBOX_DATA:-.}
9+export CHECKBOX_SHARE=${CHECKBOX_SHARE:-.}
10+export CHECKBOX_OPTIONS=${CHECKBOX_OPTIONS:---whitelist-file=$CHECKBOX_SHARE/data/whitelists/opencompute-ready-local.whitelist}
11+export PYTHONPATH=$PYTHONPATH:$CHECKBOX_SHARE
12+
13+if [ $CHECKBOX_DATA != '.' ]
14+then
15+ old_data=$HOME/.checkbox
16+ if [ -d $old_data ] && [ ! -d $CHECKBOX_DATA ]
17+ then
18+ mv -f $old_data $CHECKBOX_DATA
19+ fi
20+fi
21+
22+python3 $CHECKBOX_SHARE/run "$@" $CHECKBOX_SHARE/configs/$(basename $0).ini
23
24=== added directory 'checkbox_ocp'
25=== added file 'checkbox_ocp/__init__.py'
26=== added file 'checkbox_ocp/cli_interface.py'
27--- checkbox_ocp/cli_interface.py 1970-01-01 00:00:00 +0000
28+++ checkbox_ocp/cli_interface.py 2013-08-21 16:43:19 +0000
29@@ -0,0 +1,477 @@
30+#
31+# This file is part of Checkbox.
32+#
33+# Copyright 2008 Canonical Ltd.
34+#
35+# Checkbox is free software: you can redistribute it and/or modify
36+# it under the terms of the GNU General Public License as published by
37+# the Free Software Foundation, either version 3 of the License, or
38+# (at your option) any later version.
39+#
40+# Checkbox is distributed in the hope that it will be useful,
41+# but WITHOUT ANY WARRANTY; without even the implied warranty of
42+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43+# GNU General Public License for more details.
44+#
45+# You should have received a copy of the GNU General Public License
46+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
47+#
48+import re
49+import sys
50+import string
51+import termios
52+
53+from gettext import gettext as _
54+
55+from checkbox.user_interface import (UserInterface, ANSWER_TO_STATUS,
56+ ALL_ANSWERS, YES_ANSWER, NO_ANSWER, SKIP_ANSWER)
57+
58+
59+ANSWER_TO_OPTION = {
60+ YES_ANSWER: _("yes"),
61+ NO_ANSWER: _("no"),
62+ SKIP_ANSWER: _("skip")}
63+
64+OPTION_TO_ANSWER = dict((o, a) for a, o in ANSWER_TO_OPTION.items())
65+
66+
67+class CLIDialog:
68+ """Command line dialog wrapper."""
69+
70+ def __init__(self, text):
71+ self.text = text
72+ self.visible = False
73+
74+ def put(self, text):
75+ sys.stdout.write(text)
76+ sys.stdout.flush()
77+
78+ def put_line(self, line):
79+ self.put("%s\n" % line)
80+
81+ def put_newline(self):
82+ self.put("\n")
83+
84+ def get(self, label=None, limit=1, separator=termios.CEOT):
85+ if label is not None:
86+ self.put_newline()
87+ self.put(label)
88+
89+ fileno = sys.stdin.fileno()
90+ saved_attributes = termios.tcgetattr(fileno)
91+ attributes = termios.tcgetattr(fileno)
92+ attributes[3] &= ~(termios.ICANON | termios.ECHO)
93+ attributes[6][termios.VMIN] = 1
94+ attributes[6][termios.VTIME] = 0
95+ termios.tcsetattr(fileno, termios.TCSANOW, attributes)
96+
97+ input = []
98+ escape = 0
99+ try:
100+ while len(input) < limit:
101+ ch = sys.stdin.read(1)
102+ if ord(ch) == separator:
103+ break
104+ elif ord(ch) == 0o33: # ESC
105+ escape = 1
106+ elif ord(ch) == termios.CERASE or ord(ch) == 0o10:
107+ if len(input):
108+ self.put("\010 \010")
109+ del input[-1]
110+ elif ord(ch) == termios.CKILL:
111+ self.put("\010 \010" * len(input))
112+ input = []
113+ else:
114+ if not escape:
115+ input.append(ch)
116+ self.put(ch)
117+ elif escape == 1:
118+ if ch == "[":
119+ escape = 2
120+ else:
121+ escape = 0
122+ elif escape == 2:
123+ escape = 0
124+ finally:
125+ termios.tcsetattr(fileno, termios.TCSANOW, saved_attributes)
126+
127+ return "".join(input)
128+
129+ def show(self):
130+ self.visible = True
131+ self.put_newline()
132+ self.put_line(self.text)
133+
134+
135+class CLIChoiceDialog(CLIDialog):
136+
137+ def __init__(self, text):
138+ super(CLIChoiceDialog, self).__init__(text)
139+ self.keys = []
140+ self.options = []
141+
142+ def get(self, *args, **kwargs):
143+ response = super(CLIChoiceDialog, self).get(*args, **kwargs)
144+ try:
145+ return self.keys.index(response[0])
146+ except ValueError:
147+ return -1
148+
149+ def run(self, label=None, defaults=[]):
150+ if not self.visible:
151+ self.show()
152+
153+ try:
154+ # Only one option
155+ if len(self.keys) <= 1:
156+ self.get(_("Press any key to continue..."))
157+ return 0
158+ # Multiple choices
159+ while True:
160+ self.put_newline()
161+ for key, option in zip(self.keys, self.options):
162+ default = "*" if option in defaults else " "
163+ self.put_line("%s %s: %s" % (default, key, option))
164+
165+ response = self.get(_("Please choose (%s): ") %
166+ ("/".join(self.keys)))
167+ if response >= 0:
168+ return response
169+
170+ if label is not None:
171+ self.put_line(label)
172+
173+ except KeyboardInterrupt:
174+ self.put_newline()
175+ raise
176+
177+ def add_option(self, option, key=None):
178+ if key is None:
179+ keys = option.lower() + \
180+ string.ascii_letters + \
181+ string.digits + \
182+ string.punctuation
183+
184+ keys = keys.replace(' ', '')
185+ keys = keys.replace('+', '')
186+
187+ for key in keys:
188+ if key not in self.keys:
189+ break
190+ self.keys.append(key)
191+ self.options.append(option)
192+
193+
194+class CLIReportDialog(CLIDialog):
195+ """
196+ Display test results
197+ """
198+ STATUS = {'pass': '{0}',
199+ 'fail': '{0}'}
200+
201+ def __init__(self, text, results):
202+ super(CLIReportDialog, self).__init__(text)
203+ self.results = results
204+
205+ def run(self):
206+ """
207+ Show root of the tree
208+ and provide the ability to further display subtress
209+ """
210+ root = self.results
211+ title = self.text
212+ self._display(title, root)
213+
214+ def _is_suite(self, root):
215+ """
216+ Return True if root contains a suite
217+ that is, a job containing other jobs
218+ """
219+ return all(issubclass(type(value), dict)
220+ for value in root.values())
221+
222+ def _display(self, title, root):
223+ """
224+ Display dialog until user decides to exit
225+ (recursively for subtrees)
226+ """
227+ while True:
228+ self.put_newline()
229+ self.put_newline()
230+ self.put_line(title)
231+ self.put_newline()
232+
233+ keys = []
234+ options = []
235+
236+ def add_option(option, key=None):
237+ """
238+ Add option to list
239+ and generate automatic key value
240+ if not provided
241+ """
242+ if key is None:
243+ key = string.ascii_lowercase[len(keys)]
244+ keys.append(key)
245+ options.append(option)
246+
247+ for job_name, job_data in sorted(root.items()):
248+ if self._is_suite(job_data):
249+ add_option(job_name)
250+ self.put_line('{key}: {option}'
251+ .format(key=keys[-1],
252+ option=options[-1]))
253+ else:
254+ job_status = job_data.get('status')
255+ status_string = (self.STATUS.get(job_status, '{0}')
256+ .format(job_status))
257+ self.put_line(' {name} [{status}]'
258+ .format(name=job_name,
259+ status=status_string))
260+
261+ add_option(_("Space when finished"), " ")
262+ self.put_line('{key}: {option}'
263+ .format(key=keys[-1],
264+ option=options[-1]))
265+
266+ response = self.get(_("Please choose (%s): ") % ("/".join(keys)))
267+
268+ if response != ' ':
269+ try:
270+ selected_option = options[keys.index(response)]
271+ except ValueError:
272+ # Display again menu
273+ continue
274+
275+ # Display new menu with the contents of the selected option
276+ self._display(selected_option, root[selected_option])
277+ else:
278+ # Exit from this menu display
279+ # (display again parent menu or exit)
280+ break
281+
282+
283+class CLITextDialog(CLIDialog):
284+
285+ limit = 255
286+ separator = termios.CEOT
287+
288+ def run(self, label=None):
289+ if not self.visible:
290+ self.show()
291+
292+ self.put_newline()
293+ try:
294+ return self.get(label, self.limit, self.separator)
295+ except KeyboardInterrupt:
296+ self.put_newline()
297+ raise
298+
299+
300+class CLILineDialog(CLITextDialog):
301+
302+ limit = 80
303+ separator = ord("\n")
304+
305+
306+class Twirly(object):
307+ def __init__(self):
308+ self.index = 0
309+ self.twirlies = "-\\|/"
310+
311+ def next(self):
312+ next_twirly = self.twirlies[self.index]
313+ self.index = (self.index + 1) % len(self.twirlies)
314+ return next_twirly
315+
316+
317+class CLIProgressDialog(CLIDialog):
318+ """Command line progress dialog wrapper."""
319+
320+ def __init__(self, text):
321+ super(CLIProgressDialog, self).__init__(text)
322+ self.progress_count = 0
323+ self.twirly = Twirly()
324+
325+ def set(self, progress=None):
326+ self.progress_count = (self.progress_count + 1) % 5
327+ if self.progress_count:
328+ return
329+
330+ if progress != None:
331+ self.put("\r%u%%" % (progress * 100))
332+ else:
333+ self.put("\b\b")
334+ self.put(self.twirly.next())
335+ self.put(" ")
336+ sys.stdout.flush()
337+
338+
339+class CLIInterface(UserInterface):
340+
341+ def _toggle_results(self, key, options, results):
342+ if isinstance(results, dict):
343+ if key in results:
344+ del results[key]
345+
346+ elif key in options:
347+ if isinstance(options[key], dict):
348+ results[key] = {}
349+ elif isinstance(options[key], (list, tuple)):
350+ results[key] = []
351+ else:
352+ results[key] = None
353+
354+ for k in options[key]:
355+ self._toggle_results(k, options[key], results[key])
356+
357+ elif isinstance(results, (list, tuple)):
358+ if key in results:
359+ results.remove(key)
360+ elif key in options:
361+ results.append(key)
362+
363+ def show_progress_start(self, text):
364+ self.progress = CLIProgressDialog(text)
365+ self.progress.show()
366+
367+ def show_progress_pulse(self):
368+ self.progress.set()
369+
370+ def show_text(self, text, previous=None, next=None):
371+ dialog = CLIChoiceDialog(text)
372+ dialog.run()
373+
374+ def show_entry(self, text, value, showSubmitToHexr=False, label=None, previous=None, next=None):
375+ dialog = CLILineDialog(text)
376+
377+ return (dialog.run(), False)
378+
379+ def show_check(self, text, options=[], default=[]):
380+ dialog = CLIChoiceDialog(text)
381+ for option in options:
382+ dialog.add_option(option)
383+
384+ dialog.add_option(_("Space when finished"), " ")
385+
386+ results = default
387+ while True:
388+ response = dialog.run(defaults=results)
389+ if response >= len(options):
390+ break
391+
392+ result = options[response]
393+ self._toggle_results(result, options, results)
394+
395+ return (results, False)
396+
397+ def show_radio(self, text, options=[], default=None):
398+ dialog = CLIChoiceDialog(text)
399+ for option in options:
400+ dialog.add_option(option)
401+
402+ # Show options dialog
403+ response = dialog.run()
404+ return options[response]
405+
406+ def show_tree(self, text, options={}, default={}, deselect_warning=""):
407+ keys = sorted(options.keys())
408+
409+ dialog = CLIChoiceDialog(text)
410+ for option in keys:
411+ dialog.add_option(option)
412+
413+ dialog.add_option(_("Combine with character above to expand node"),
414+ "+")
415+ dialog.add_option(_("Space when finished"), " ")
416+
417+ do_expand = False
418+ results = default
419+ while True:
420+ response = dialog.run(defaults=results)
421+ if response > len(options):
422+ break
423+
424+ elif response == len(options):
425+ response = dialog.get()
426+ do_expand = True
427+
428+ else:
429+ do_expand = False
430+
431+ # Invalid response
432+ if response < 0:
433+ continue
434+
435+ # Toggle results
436+ result = keys[response]
437+ if not do_expand:
438+ self._toggle_results(result, options, results)
439+ continue
440+
441+ # Expand tree
442+ dialog.visible = False
443+ if options[result]:
444+ branch_results = results.get(result, {})
445+ self.show_tree(result, options[result], branch_results)
446+ if branch_results and result not in results:
447+ results[result] = branch_results
448+
449+ return results
450+
451+ def show_report(self, text, results):
452+ """
453+ Show test case results in a tree hierarchy
454+ """
455+ dialog = CLIReportDialog(text, results)
456+ dialog.run()
457+
458+ def show_test(self, test, runner):
459+ options = list([ANSWER_TO_OPTION[a] for a in ALL_ANSWERS])
460+ if "command" in test:
461+ options.append(_("test"))
462+
463+ if re.search(r"\$output", test["description"]):
464+ output = runner(test)[1]
465+ else:
466+ output = ""
467+
468+ while True:
469+ # Show option dialog
470+ description = string.Template(test["description"]).substitute({
471+ "output": output.strip()})
472+ dialog = CLIChoiceDialog(description)
473+
474+ for option in options:
475+ dialog.add_option(option, option[0])
476+
477+ # Get option from dialog
478+ response = dialog.run()
479+ option = options[response]
480+ if response < len(ALL_ANSWERS):
481+ break
482+
483+ output = runner(test)[1]
484+
485+ options[-1] = _("test again")
486+
487+ answer = OPTION_TO_ANSWER[option]
488+ if answer == NO_ANSWER:
489+ text = _("Further information:")
490+ dialog = CLITextDialog(text)
491+ test["data"] = dialog.run(_("Please type here and press"
492+ " Ctrl-D when finished:\n"))
493+ else:
494+ test["data"] = ""
495+
496+ test["status"] = ANSWER_TO_STATUS[answer]
497+
498+ def show_info(self, text, options=[], default=None):
499+ return self.show_radio(text, options, default)
500+
501+ def show_error(self, primary_text,
502+ secondary_text=None, detailed_text=None):
503+ text = filter(None, [primary_text, secondary_text, detailed_text])
504+ text = '\n'.join(text)
505+ dialog = CLIChoiceDialog("Error: %s" % text)
506+ dialog.run()
507
508=== modified file 'debian/changelog'
509--- debian/changelog 2013-08-19 20:46:26 +0000
510+++ debian/changelog 2013-08-21 16:43:19 +0000
511@@ -1,4 +1,12 @@
512-checkbox (0.16.6~OCP) UNRELEASED; urgency=low
513+checkbox (1.16.6~OCP) UNRELEASED; urgency=low
514+
515+ [ Jeff Marcom ]
516+ * Added checkbox-ocp package
517+
518+ -- Jeff Marcom <jeff.marcom@canonical.com> Wed, 21 Aug 2013 12:20:24 -0400
519+
520+
521+checkbox (0.16.6~OCPubuntu1) UNRELEASED; urgency=low
522
523 * INITIAL RELEASE:
524 based on checkbox 0.16.6 from lp:checkbox with modificiations specific to
525@@ -17,4 +25,3 @@
526 checkbox/tests/ - Cleaned up unit tests that were looking for things
527 removed in this merge.
528
529- -- Jeff Marcom <jeff.marcom@canonical.com> Wed, 31 Jul 2013 19:36:52 -0400
530
531=== added file 'debian/checkbox-ocp.install'
532--- debian/checkbox-ocp.install 1970-01-01 00:00:00 +0000
533+++ debian/checkbox-ocp.install 2013-08-21 16:43:19 +0000
534@@ -0,0 +1,3 @@
535+usr/bin/checkbox-ocp
536+usr/lib/python*/*-packages/checkbox_ocp/*
537+usr/share/checkbox/examples/checkbox-ocp.ini
538
539=== added file 'debian/checkbox-ocp.links'
540--- debian/checkbox-ocp.links 1970-01-01 00:00:00 +0000
541+++ debian/checkbox-ocp.links 2013-08-21 16:43:19 +0000
542@@ -0,0 +1,1 @@
543+usr/share/man/man1/checkbox.1.gz usr/share/man/man1/checkbox-ocp.1.gz
544
545=== added file 'debian/checkbox-ocp.postinst'
546--- debian/checkbox-ocp.postinst 1970-01-01 00:00:00 +0000
547+++ debian/checkbox-ocp.postinst 2013-08-21 16:43:19 +0000
548@@ -0,0 +1,7 @@
549+#! /bin/sh -e
550+
551+base_package="checkbox"
552+. /usr/share/debconf/confmodule
553+. /usr/share/checkbox/install/postinst
554+
555+#DEBHELPER#
556
557=== modified file 'debian/control'
558--- debian/control 2013-07-05 16:43:48 +0000
559+++ debian/control 2013-08-21 16:43:19 +0000
560@@ -47,7 +47,7 @@
561 python3-gi
562 Suggests: bonnie++,
563 bootchart,
564- checkbox-cli | checkbox-gtk,
565+ checkbox-cli | checkbox-ocp, checkbox-gtk,
566 curl,
567 ethtool,
568 fwts,
569@@ -80,6 +80,15 @@
570 .
571 This package provides a command line interface for answering tests.
572
573+Package: checkbox-ocp
574+Architecture: all
575+Depends: checkbox (>= ${source:Version}), ${misc:Depends}
576+Description: Command line interface of checkbox for the Open Compute Project
577+ This project provides an extensible interface for system testing on
578+ Open Compute platforms.
579+ .
580+ This package provides a command line interface for answering tests.
581+
582 Package: checkbox-urwid
583 Architecture: all
584 Depends: checkbox (>= ${source:Version}), python3-urwid, ${misc:Depends}
585
586=== modified file 'debian/rules'
587--- debian/rules 2013-07-05 16:43:48 +0000
588+++ debian/rules 2013-08-21 16:43:19 +0000
589@@ -25,6 +25,7 @@
590
591 override_dh_installdeb:
592 cp debian/checkbox.postrm debian/checkbox-cli.postrm
593+ cp debian/checkbox.postrm debian/checkbox-ocp.postrm
594 cp debian/checkbox.postrm debian/checkbox-urwid.postrm
595 cp debian/checkbox.postrm debian/checkbox-gtk.postrm
596 cp debian/checkbox.postrm debian/checkbox-qt.postrm
597@@ -34,6 +35,7 @@
598 override_dh_installdocs:
599 dh_installdocs -pcheckbox ./README
600 dh_installdocs -pcheckbox-cli ./README
601+ dh_installdocs -pcheckbox-ocp ./README
602 dh_installdocs -pcheckbox-urwid ./README
603 dh_installdocs -pcheckbox-gtk ./README
604 dh_installdocs -pcheckbox-qt ./README
605@@ -42,6 +44,6 @@
606
607 override_dh_clean:
608 -find . -name \*.mo -exec rm {} \;
609- -rm -f debian/checkbox-cli.postrm debian/checkbox-urwid.postrm debian/checkbox-gtk.postrm debian/checkbox-qt.postrm debian/checkbox-hw-collection.postrm
610+ -rm -f debian/checkbox-cli.postrm debian/checkbox-ocp.postrm debian/checkbox-cli.postrmebian/checkbox-urwid.postrm debian/checkbox-gtk.postrm debian/checkbox-qt.postrm debian/checkbox-hw-collection.postrm
611 debconf-updatepo
612 dh_clean
613
614=== added file 'examples/checkbox-ocp.ini'
615--- examples/checkbox-ocp.ini 1970-01-01 00:00:00 +0000
616+++ examples/checkbox-ocp.ini 2013-08-21 16:43:19 +0000
617@@ -0,0 +1,17 @@
618+[DEFAULT]
619+
620+# Space separated list of files to include as a dependency for the
621+# CLI interface.
622+includes = %(checkbox_share)s/configs/checkbox.ini
623+
624+[checkbox/plugins/user_interface]
625+
626+# Module where the user interface implementation is defined.
627+interface_module = checkbox_ocp.cli_interface
628+
629+# Class implementing the UserInterface interface.
630+interface_class = CLIInterface
631+
632+[checkbox/plugins]
633+
634+blacklist = hexr_prompt hexr_transport
635
636=== modified file 'setup.py'
637--- setup.py 2013-07-05 16:43:48 +0000
638+++ setup.py 2013-08-21 16:43:19 +0000
639@@ -266,8 +266,8 @@
640 ],
641 },
642 scripts=[
643- "bin/checkbox-cli", "bin/checkbox-gtk", "bin/checkbox-urwid",
644- "bin/checkbox-qt", "bin/checkbox-hw-collection"],
645+ "bin/checkbox-cli", "bin/checkbox-ocp", "bin/checkbox-gtk",
646+ "bin/checkbox-urwid", "bin/checkbox-qt", "bin/checkbox-hw-collection"],
647 packages=find_packages(),
648 package_data={
649 "": ["cputable"]},

Subscribers

People subscribed via source and target branches