#!/usr/bin/python3

import argparse
import json
import os
import re
import shlex
import subprocess
import tempfile

parser = argparse.ArgumentParser()
parser.add_argument('--output', '-o', default='compile_commands.json',
                    help='The output file [default: compile_commands.json]')
args = parser.parse_args()

directory = os.getcwd()

with tempfile.NamedTemporaryFile() as makefile_copy:
    # rebuilding the makefile is an exception to --dry-run, and we don't want
    # to run the whole configure machinery, so copy the Makefile to a temporary
    # path to short-circuit the exception.
    with open('Makefile', 'rb') as original_makefile:
        original = original_makefile.readlines()

    # Also remove include lines to prevent included makefiles from being rebuilt
    patched = [line for line in original if not re.search(b'^-?include', line)]
    makefile_copy.write(b''.join(patched))

    # get the build commands
    output = subprocess.check_output(['make',
                                      '-f', makefile_copy.name,
                                      'MAKE=false',   # block recursive make
                                      'V=1',          # simplify the output
                                      '--always-make', '--dry-run', 'all-am'],
                                     universal_newlines=True)

# This assumes a very specific output format.  We can change it or add more in
# the future, if necessary.
cc_pattern = re.compile(r'([a-z]+) (.*?) -o ([^ ]*) (`test .[^`]*`)?([^ ]+\.c)')

result = []
for line in output.splitlines():
    match = cc_pattern.fullmatch(line)
    if not match:
        continue

    # match group 1 is the compiler name (e.g. "cc"), discard it
    flags = shlex.split(match.group(2))
    output = match.group(3)
    # match group 4 is the `test ...` VPATH stuff (discard it)
    source = match.group(5)

    result.append({
        'directory': directory,
        'output': output,
        'file': source,
        'arguments': ['cc', *flags, '-o', output, source]
    })

result.sort(key=lambda d: (d['file'], d['output']))

with open(args.output, 'w+') as output_file:
    json.dump(result, output_file, sort_keys=True, indent=4)
