~sylvain-pineau/checkbox/0.15

« back to all changes in this revision

Viewing changes to plainbox/plainbox/impl/box.py

Plainbox - Add support for saving a subset of session state after all tests

Show diffs side-by-side

added added

removed removed

Lines of Context:
39
39
 
40
40
from plainbox import __version__ as version
41
41
from plainbox.impl.checkbox import CheckBox
 
42
from plainbox.impl.exporter import get_all_exporters
42
43
from plainbox.impl.job import JobDefinition
43
44
from plainbox.impl.result import JobResult
44
45
from plainbox.impl.rfc822 import load_rfc822_records
58
59
        self._checkbox = CheckBox()
59
60
 
60
61
    def main(self, argv=None):
61
 
        basicConfig(level="WARNING")
62
62
        # TODO: setup sane logging system that works just as well for Joe user
63
63
        # that runs checkbox from the CD as well as for checkbox developers and
64
64
        # custom debugging needs.  It would be perfect^Hdesirable not to create
65
65
        # another broken, never-rotated, uncapped logging crap that kills my
66
66
        # SSD by writing junk to ~/.cache/
 
67
        basicConfig(level="WARNING")
 
68
        parser = self._construct_parser()
 
69
        ns = parser.parse_args(argv)
 
70
        # Set the desired log level
 
71
        if ns.log_level:
 
72
            getLogger("").setLevel(ns.log_level)
 
73
        # Load built-in job definitions
 
74
        job_list = self.get_builtin_jobs()
 
75
        # Load additional job definitions
 
76
        job_list.extend(self._load_jobs(ns.load_extra))
 
77
        # Now either do a special action or run the jobs
 
78
        if ns.special == "list-jobs":
 
79
            self._print_job_list(ns, job_list)
 
80
        elif ns.special == "list-expr":
 
81
            self._print_expression_list(ns, job_list)
 
82
        elif ns.special == "dep-graph":
 
83
            self._print_dot_graph(ns, job_list)
 
84
        else:
 
85
            if ns.output_format == '?':
 
86
                self._print_output_format_list(ns)
 
87
            else:
 
88
                exporter_cls = get_all_exporters()[ns.output_format]
 
89
                if ns.output_options:
 
90
                    option_list = ns.output_options.split(',')
 
91
                else:
 
92
                    option_list = None
 
93
                try:
 
94
                    exporter = exporter_cls(option_list)
 
95
                except ValueError as exc:
 
96
                    raise SystemExit(str(exc))
 
97
                else:
 
98
                    self._run_jobs(ns, job_list, exporter)
 
99
 
 
100
    def _construct_parser(self):
67
101
        parser = ArgumentParser(prog="plainbox")
68
102
        parser.add_argument(
69
103
            "-v", "--version", action="version",
99
133
        group.add_argument(
100
134
            '-n', '--dry-run', action='store_true',
101
135
            help="Don't actually run any jobs")
 
136
        group = parser.add_argument_group("output options")
 
137
        assert 'text' in get_all_exporters()
 
138
        group.add_argument(
 
139
            '-f', '--output-format', default='text',
 
140
            metavar='FORMAT', choices=['?',] + list(get_all_exporters().keys()),
 
141
            help='Save test results in the specified FORMAT')
 
142
        group.add_argument(
 
143
            '-p', '--output-options', default='',
 
144
            metavar='OPTIONS',
 
145
            help='Comma-separated list of options for the export mechanism')
 
146
        group.add_argument(
 
147
            '-o', '--output-file', default='-',
 
148
            metavar='FILE', type=FileType("wt"),
 
149
            help=('Save test results to the specified FILE'
 
150
                  ' (or to stdout if FILE is -)'))
102
151
        group = parser.add_argument_group("special options")
103
152
        group.add_argument(
104
153
            '--list-jobs', help="List jobs instead of running them",
112
161
        group.add_argument(
113
162
            '--dot-resources', action='store_true',
114
163
            help="Render resource relationships (for --dot)")
115
 
        ns = parser.parse_args(argv)
 
164
        return parser
116
165
 
117
 
        # Set the desired log level
118
 
        if ns.log_level:
119
 
            getLogger("").setLevel(ns.log_level)
120
 
        # Load built-in job definitions
121
 
        job_list = self.get_builtin_jobs()
122
 
        # Load additional job definitions
123
 
        job_list.extend(self._load_jobs(ns.load_extra))
124
 
        # Now either do a special action or run the jobs
125
 
        if ns.special == "list-jobs":
126
 
            self._print_job_list(ns, job_list)
127
 
        elif ns.special == "list-expr":
128
 
            self._print_expression_list(ns, job_list)
129
 
        elif ns.special == "dep-graph":
130
 
            self._print_dot_graph(ns, job_list)
131
 
        else:
132
 
            self._run_jobs(ns, job_list)
 
166
    def _print_output_format_list(self, ns):
 
167
        print("Available output formats: {}".format(
 
168
            ', '.join(get_all_exporters())))
133
169
 
134
170
    def _get_matching_job_list(self, ns, job_list):
135
171
        # Find jobs that matched patterns
195
231
                        expression.text.replace('"', "'")))
196
232
        print("}")
197
233
 
198
 
    def _run_jobs(self, ns, job_list):
 
234
    def _run_jobs(self, ns, job_list, exporter):
199
235
        # Compute the run list, this can give us notification about problems in
200
236
        # the selected jobs. Currently we just display each problem
201
237
        matching_job_list = self._get_matching_job_list(ns, job_list)
212
248
            runner = JobRunner(self._checkbox, session.session_dir,
213
249
                               outcome_callback=outcome_callback)
214
250
            self._run_jobs_with_session(ns, session, runner)
215
 
        print("[ Results ]".center(80, '='))
216
 
        for job_name in sorted(session.job_state_map):
217
 
            job_state = session.job_state_map[job_name]
218
 
            if job_state.result.outcome != JobResult.OUTCOME_NONE:
219
 
                print("{}: {}".format(job_name, job_state.result.outcome))
 
251
            self._save_results(ns, session, exporter)
 
252
 
 
253
    def _save_results(self, ns, session, exporter):
 
254
        if ns.output_file is sys.stdout:
 
255
            print("[ Results ]".center(80, '='))
 
256
        else:
 
257
            print("Saving results to {}".format(ns.output_file.name))
 
258
        data = exporter.get_session_data_subset(session)
 
259
        with ns.output_file as stream:
 
260
            exporter.dump(data, stream)
220
261
 
221
262
    def ask_for_outcome(self, prompt=None, allowed=None):
222
263
        if prompt is None: