#!/usr/bin/python2.7

#
# This file and its contents are supplied under the terms of the
# Common Development and Distribution License ("CDDL"), version 1.0.
# You may only use this file in accordance with the terms of version
# 1.0 of the CDDL.
#
# A full copy of the text of the CDDL should have accompanied this
# source.  A copy of the CDDL is also available via the Internet at
# http://www.illumos.org/license/CDDL.
#

#
# Copyright 2018 Adam Stevko
#

#
# userland-bump - bump component revision to trigger rebuild or bump component version
#

from __future__ import print_function

import argparse
import subprocess
import os
import re
import sys
import json


def load_db(file_name):
    with open(file_name, 'r') as f:
        return json.loads(f.read())


def convert_fmri_to_path(fmri):

    result = None

    ws_tools = os.path.dirname(os.path.realpath(sys.argv[0]))
    component_translate = os.path.join(ws_tools, 'component-translate')

    args = [component_translate, '--fmri', fmri]
    proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    for out in proc.stdout:
        result = out.rstrip()

    return result


def locate_dependents(path, data):
    result = []

    for component in data.keys():
        if path in data[component]:
            result.append(component)

    return result


def bump_component_revision(contents):
    contents_new = []

    component_version_idx = 0
    component_revision_idx = 0
    has_component_revision = False
    for idx, line in enumerate(contents):
        if re.match('^COMPONENT_VERSION=', line):
            component_version_idx = idx

        if re.match('^COMPONENT_REVISION', line):
            has_component_revision = True
            component_revision_idx = idx

    if has_component_revision:
        contents_new.extend(contents[:component_revision_idx])

        component_revision = contents[component_revision_idx].split('=')[-1]
        try:
            component_revision_int = int(component_revision)
        except ValueError:
            print('\tSkipping component, COMPONENT_REVISION field malformed: {}'.format(component_revision))
            return contents
        else:
            component_revision_int += 1
            contents_new.append('COMPONENT_REVISION=\t{}\n'.format(component_revision_int))

        contents_new.extend(contents[component_revision_idx + 1:])
    else:
        contents_new.extend(contents[:component_version_idx + 1])
        contents_new.append('COMPONENT_REVISION=\t1\n')
        contents_new.extend(contents[component_version_idx + 1:])

    return contents_new


def rebuild_dependent_fmris(fmri, db_path=None, workspace=None, subdir='components', verbose=False, dry_run=False):
    data = load_db(db_path)

    path = convert_fmri_to_path(fmri)
    dependent_paths = locate_dependents(path=path, data=data)
    if not dry_run:
        for component_path in dependent_paths:
            if verbose:
                print('Processing {}'.format(component_path))
    
            contents = []
            makefile = os.path.join(workspace, subdir, component_path, 'Makefile')
            with open(makefile, 'r') as f:
                contents = f.readlines()
    
            contents = bump_component_revision(contents)
    
            with open(makefile, 'w') as f:
                for line in contents:
                    f.write(line)
    else:
        for component_path in dependent_paths:
            print('{0}'.format(component_path))


def main():
    db_default_path = os.path.join(os.path.dirname(sys.argv[0]).rsplit('/', 1)[0], 'components', 'dependencies.json')
    workspace_default_path = os.path.dirname(os.path.dirname(sys.argv[0]))

    parser = argparse.ArgumentParser()
    parser.add_argument('--db-path', default=db_default_path, help=argparse.SUPPRESS)
    parser.add_argument('-w', '--workspace', default=workspace_default_path, help='Path to workspace')
    parser.add_argument('--subdir', default='components', help='Directory holding components')
    parser.add_argument('--rebuild-dependents', action='store_true', default=False,
                        help='Bump COMPONENT_REVISION of dependent components')
    parser.add_argument('-n', '--dry-run', action='store_true', default=False,
                        help='Do not execute, only print the list of resolved components')
    parser.add_argument('--fmri', required=True, help='Component FMRI')
    parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Verbose output')
    args = parser.parse_args()

    db_path = args.db_path
    rebuild_dependents = args.rebuild_dependents
    dry_run = args.dry_run
    fmri = args.fmri
    verbose = args.verbose
    workspace = args.workspace
    subdir = args.subdir

    if rebuild_dependents:
        rebuild_dependent_fmris(fmri=fmri, db_path=db_path, workspace=workspace, subdir=subdir, verbose=verbose, dry_run=dry_run)


if __name__ == '__main__':
    main()