#!/usr/bin/python3

import sys
import difflib
import os.path
import argparse
import subprocess as sp


def run(*cmd, **kw):
    '''Wrapper for sp.run with better defaults, returns the output as list of
    lines, including terminating newlines'''
    args = {
        'check': True,
        'stdout': sp.PIPE,
        'universal_newlines': True,
    }
    args.update(kw)
    res = sp.run(cmd, **args)
    return [
        line + '\n'
        for line in res.stdout.split('\n')
    ]


def store(store_path, host, lines):
    """Store output into a file if folder is set"""
    if not store_path:
        return
    with open(os.path.join(store_path, host), 'w') as f:
        f.writelines(lines)


def compare(host, local, remote, summary):
    diff = difflib.unified_diff(
        local,
        remote,
        fromfile='localhost',
        tofile=host,
        n=0,
    )
    if summary:
        print("Summary of differences with {}:".format(host), end='')
        diff = list(diff)
        for sig in ['-', '+']:
            count = len([row for row in diff if row.startswith(sig)])
            print(' {}{}'.format(sig, count), end='')
        print()
    else:
        print('Differences with {}:'.format(host))
        sys.stdout.writelines(diff)


if __name__ == '__main__':
    parser = argparse.ArgumentParser('Compare installed package versions')
    parser.add_argument('--hostfile', help='File with list of hostnames')
    parser.add_argument('--summary', action='store_true', default=False,
                        help="Only show summary")
    parser.add_argument('--store-path', type=str,
                        help="Path of folder to store package lists")
    args = parser.parse_args()

    hosts = ['source-system']
    if args.hostfile:
        with open(args.hostfile) as f:
            hosts = [line.strip() for line in f.readlines()]

    cmd = (
        'sha1sum /var/lib/apt/lists/*Packages | sort -k 2; '
        'dpkg -l | tail -n +6 | awk \'{print $1 " " $2 "=" $3}\' | sort -k 2'
    )
    local = run(cmd, shell=True)
    store(args.store_path, 'localhost', local)
    outputs = {}
    for host in hosts:
        print('Fetching package version list from {host}.'.format(host=host))
        outputs[host] = run('ssh', host, cmd)
        store(args.store_path, host, outputs[host])

    for host in hosts:
        compare(host, local, outputs[host], args.summary)
