#!/usr/bin/env python3 # Copyright (C) 2020 Simon Quigley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import argparse import logging as log import sqlite3 from jinja2 import Template from modules.jenkins import JenkinsModule from os import path ENABLED_MODULES = [JenkinsModule] def sqlite_run(command, db, return_output=False): """Run the given SQLite command on our db command must be a command that SQLite can run db must be a valid path to a db, or it's done in memory """ conn = sqlite3.connect(db) c = conn.cursor() for cmd in command: log.debug("Executing: %s" % cmd) c.execute(cmd) conn.commit() # Make sure we return an output if requested try: if return_output: rows = c.fetchall() return rows except Exception as e: print(e) finally: conn.close() def summary(): """Reading summary_page, generate a summary page using the averages summary_page should be a dict, with keys being the human-readable module name and the value being another dict, which has averages for each day. Example: {"foo": {1: (100, 200, 300)}} Special-casing is done right in the template file, as different modules are going to have different averages. """ # Open the template file as a Jinja2 Template t_path = path.join("templates", "index.html") with open(t_path) as templatef: template = "" for text in templatef.readlines(): template += text template = Template(template) # Render the template with the values from summary_page log.debug("summary_page: " + str(summary_page)) template = template.render(page=summary_page) # Write it back to the output file # We don't have to worry about creating the output dir, since the # module-specific template rendering should already do this for us # # FIXME: Writing to/from files is done in several places, maybe centralize # the code in its own "internal" module? with open(path.join("output", "index.html"), "w+") as f: f.write(template) def main(module): """Given a specific module, set it up and insert recent values""" # Initialize the module module = module() # Stage the setup commands to be ran and run them run = [module.sqlite_setup(), module.sqlite_add()] log.debug(sqlite_run(run, db=args.db_location)) # This is going to be a dict of tuples, with the key being the day and # the value being a tuple with the averages _averages = {} # Pull some useful data and have the module render a template # The output is in MODULENAME_DAYday.html # This generates a report for each of the given day windows for day in (1, 7, 30, 90, 180): # Fetch the data and log to debug run = [module.sqlite_time_range(days=day)] data = sqlite_run(run, db=args.db_location, return_output=True) log.debug(data) # Render the template, which also returns the average values _averages[day] = module.render_template(day, data) # Put the values from _averages on the summary page summary_page[module.name] = _averages if __name__ == "__main__": # Parse CLI arguments parser = argparse.ArgumentParser() parser.add_argument("--db-location", type=str, default=":memory:", help="Specify the location for the SQLite database") parser.add_argument("--log", type=str, default="WARNING", help="Default logging level") args = parser.parse_args() # Ensure the logging level is set properly num_level = getattr(log, args.log.upper(), None) if not isinstance(num_level, int): raise ValueError("Invalid log level: %s" % args.log) # Fully configure the logger log.basicConfig(format="%(asctime)s\t%(levelname)s\t%(message)s", level=num_level) # Initialize a dict to store data for the summary page summary_page = {} for module in ENABLED_MODULES: log.info("Working on %s..." % module.__name__) main(module) # Render the summary page summary()