#!/usr/bin/perl -w

# Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1.  Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
# 2.  Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
# 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
#     its contributors may be used to endorse or promote products derived
#     from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# Script to put change log comments in as default check-in comment.

use strict;
use File::Basename;
use File::Spec;
use FindBin;
use lib $FindBin::Bin;
use VCSUtils;
use webkitdirs;

my $log = $ARGV[0];

my $baseDir = baseProductDir();

my $editor = $ENV{SVN_LOG_EDITOR};
if (!$editor) {
    $editor = $ENV{CVS_LOG_EDITOR};
}
if (!$editor) {
    my $builtEditorApplication = "$baseDir/Release/Commit Log Editor.app/Contents/MacOS/Commit Log Editor";
    $editor = $builtEditorApplication if -x $builtEditorApplication;
}
if (!$editor) {
    my $builtEditorApplication = "$baseDir/Debug/Commit Log Editor.app/Contents/MacOS/Commit Log Editor";
    $editor = $builtEditorApplication if -x $builtEditorApplication;
}
if (!$editor) {
    my $installedEditorApplication = "$ENV{HOME}/Applications/Commit Log Editor.app/Contents/MacOS/Commit Log Editor";
    $editor = $installedEditorApplication if -x $installedEditorApplication;
}
if (!$editor) {
    $editor = $ENV{EDITOR} || "/usr/bin/vi";
}

my $inChangesToBeCommitted = !isGit();
my @changeLogs = ();
my $logContents = "";
my $existingLog = 0;
open LOG, $log or die;
while (<LOG>) {
    if (isGit()) {
        if (/^# Changes to be committed:$/) {
            $inChangesToBeCommitted = 1;
        } elsif ($inChangesToBeCommitted && /^# \S/) {
            $inChangesToBeCommitted = 0;
        }
    }

    $logContents .= $_;
    $existingLog = isGit() && !(/^#/ || /^\s*$/) unless $existingLog;

    push @changeLogs, makeFilePathRelative($1) if $inChangesToBeCommitted && (/^M....(.*ChangeLog)$/ || /^#\tmodified:   (.*ChangeLog)/) && !/-ChangeLog/;
}
close LOG;

# Don't change anything if there's already a log message
# (as can happen with git-commit --amend)
exec $editor, @ARGV if $existingLog;

my $topLevel = topLevelSourceDirectory();

my %changeLogSort;
my %changeLogContents;
for my $changeLog (@changeLogs) {
    open CHANGELOG, $changeLog or die "Can't open $changeLog";
    my $contents = "";
    my $blankLines = "";
    while (<CHANGELOG>) {
        if (/^\S/) {
            last if $contents;
        }
        if (/\S/) {
            $contents .= $blankLines if $contents;
            $blankLines = "";
            $contents .= $_;
        } else {
            $blankLines .= $_;
        }
    }
    close CHANGELOG;

    $changeLog = File::Spec->abs2rel(File::Spec->rel2abs($changeLog), $topLevel);

    my $label = dirname($changeLog);
    $label = "top level" unless length $label;

    my $sortKey = lc $label;
    if ($label eq "top level") {
        $sortKey = "";
    } elsif ($label eq "Tools") {
        $sortKey = "-, just after top level";
    } elsif ($label eq "WebBrowser") {
        $sortKey = lc "WebKit, WebBrowser after";
    } elsif ($label eq "WebCore") {
        $sortKey = lc "WebFoundation, WebCore after";
    } elsif ($label eq "LayoutTests") {
        $sortKey = lc "~, LayoutTests last";
    }

    $changeLogSort{$sortKey} = $label;
    $changeLogContents{$label} = $contents;
}

my $first = 1;
open NEWLOG, ">$log.edit" or die;
for my $sortKey (sort keys %changeLogSort) {
    my $label = $changeLogSort{$sortKey};
    if (keys %changeLogSort > 1) {
        print NEWLOG "\n" if !$first;
        $first = 0;
        print NEWLOG "$label:\n\n";
    }
    print NEWLOG $changeLogContents{$label};
}
print NEWLOG $logContents;
close NEWLOG;

system $editor, "$log.edit";

open NEWLOG, "$log.edit" or exit;
my $foundComment = 0;
while (<NEWLOG>) {
    $foundComment = 1 if (/\S/ && !/^CVS:/);
}
close NEWLOG;

if ($foundComment) {
    open NEWLOG, "$log.edit" or die;
    open LOG, ">$log" or die;
    while (<NEWLOG>) {
        print LOG;
    }
    close LOG;
    close NEWLOG;
}

unlink "$log.edit";

sub topLevelSourceDirectory
{
    if (isGit()) {
        chomp(my $gitDir = `git rev-parse --git-dir`);
        return dirname($gitDir);
    } elsif (isSVN()) {
        open(INFO, "-|", qw(svn info)) or die;
        my ($root, $url);
        while (my $line = <INFO>) {
            if ($line =~ /^Repository Root: (.*)$/) {
                $root = $1;
            } elsif ($line =~ /^URL: (.*)$/) {
                $url = $1;
            }
        }
        close(INFO);

        my $path = $url;
        $path =~ s/^\Q$root\E//;
        $path =~ s/^\/?(branches\/[^\/]*|trunk)\/?//;
        return File::Spec->rel2abs(File::Spec->catdir(map { ".." } File::Spec->splitdir($path)));
    }
}
