#!/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 modules.discourse import DiscourseModule from modules.jenkins import JenkinsModule from modules.utilities import * from os import path from shutil import copytree, rmtree ENABLED_MODULES = [DiscourseModule, 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. """ src = path.join("templates", "index.html") dest = path.join("output", "index.html") log.debug("summary_page: " + str(summary_page)) jinja2_template(src, dest, page=summary_page) 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 if not args.no_modify_db: 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)] log.debug(run) 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") parser.add_argument("--no-modify-db", action="store_true", help="Don't insert any data into the DB, just read") 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() # Copy the assets # FIXME: clunky and racey try: copytree("assets", "output/assets") except FileExistsError: rmtree("output/assets") copytree("assets", "output/assets")