#!/usr/bin/env python

# Copyright 2012 Nextdoor.com, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Git hook to inject a bug ID header into commit message.

The bug ID is taken from the BUG_ID environment variable, typically
set by git-change.
"""

__author__ = 'jacob@nextdoor.com (Jacob Hesch)'

import os
import re
import sys

OTHER_HEADERS = ('Change-Id')
HEADER_PATTERN = re.compile(r'^[a-zA-Z][-a-zA-Z0-9]+:\s+[a-zA-Z0-9]')
BUG_HEADER_PATTERN = re.compile(r'^Bug:\s+\d+\s*$', flags=re.IGNORECASE)


def is_header_line(line):
    """Returns True if the given line is a header line."""
    if not HEADER_PATTERN.match(line):
        return False
    name, _ = line.split(':')
    name = name.lower()
    for header in OTHER_HEADERS:
        if header.lower().startswith(name):
            return True
    return False


def add_bug_id(lines):
    """Modifies the given sequence of lines to include the bug ID header."""
    index_max = len(lines) - 1
    index = index_max
    header_line = 'Bug: %s\n' % os.environ['BUG_ID']

    # First see if there's an existing bug ID header and if so,
    # replace it.
    while index >= 0:
        if BUG_HEADER_PATTERN.match(lines[index]):
            lines[index] = header_line
            return lines
        index -= 1
    index = index_max

    # Find the first line of the trailing comment section.
    while index > 0 and lines[index].startswith('#') and lines[index - 1].startswith('#'):
        index -= 1

    # Skip over trailing blank lines.
    while index > 0 and lines[index - 1] == '\n':
        index -= 1

    # Place the bug ID header above the Change-Id header, if it exists
    # as the last line.
    if index > 0 and lines[index - 1].lower().startswith('change-id:'):
        index -= 1

    # Separate the previous line from the bug ID header line with a
    # blank line unless the previous line is blank or another header.
    if index > 0 and lines[index - 1] != '\n' and not is_header_line(lines[index - 1]):
        header_line = '\n%s' % header_line

    if index == 0:
        if index_max == 0:
            # The user probably specified a message with -m. Place the
            # bug ID header after the message.
            lines.append('\n')
            index = 2
        else:
            # The new bug ID header is the first line, so place a
            # blank line above it so the user doesn't have to.
            header_line = '\n\n%s' % header_line

    lines.insert(index, header_line)

    return lines


def add_bug_id_to_file(message_file):
    with open(message_file, 'r') as f:
        lines = f.readlines()

    lines = add_bug_id(lines)

    with open(message_file, 'w+') as f:
        for line in lines:
            f.write(line)


def main():
    argc = len(sys.argv)
    if argc > 2 and sys.argv[2] not in ('commit', 'message'):
        print 'arg 2 is %s' % sys.argv[2]
        return
    if 'BUG_ID' in os.environ:
        add_bug_id_to_file(sys.argv[1])


if __name__ == '__main__':
    main()
