summaryrefslogtreecommitdiffstats
path: root/bin/git-qt-grafts
blob: 4fd7a6ebab7631749d8f93d4e1adb5527c5d013f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#!/usr/bin/perl -w
####################################################################################################
#
# git-qt-grafts
#
# Sets up the proper grafts for a Qt repository
#
# Copyright (C) 2015 The Qt Company Ltd.
# Contact: http://www.qt.io/licensing/
#
####################################################################################################

use File::Basename;
use Cwd 'abs_path';
use strict;

my $history_location;

# Syntax:  fileContents(filename)
# Returns: String with contents of the file, or empty string if file
#          doens't exist.
sub fileContents {
    my ($filename) = @_;
    my $filecontents = "";
    if (-e $filename) {
        my $FD;
        open($FD, "< $filename") || die "Could not open $filename for reading, read block?";
        local $/;
        binmode $FD;
        $filecontents = <$FD>;
        close $FD;
    }
    return $filecontents;
}

sub fileContains {
    my ($filename, $text) = @_;
    # purposely not using perl grep here
    foreach my $line (split /\n/, fileContents("$filename")) {
        return 1 if ("$line" eq "$text");
    }
    return 0;
}

sub showUsage {
    my $prg = basename($0);
    print "Usage: $prg <path to Qt history>:\n";
}

while ( @ARGV ) {
    my $arg = shift @ARGV;
    if ($arg eq "-?" || $arg eq "-h" || $arg eq "-help" || $arg eq "?") {
        showUsage();
        exit 0;
    } elsif (!$history_location) {
        $history_location = $arg;
    } else {
        print "Unknown option: $arg\n\n";
        showUsage();
        exit 1;
    }
}

# Get current git-dir
my $git_dir = `git rev-parse --git-dir`;
chomp $git_dir;
if (!$git_dir) {
    print "Cannot find any Git dir!\n";
    exit 1;
}

# validate path for history repo
if (!$history_location || !-e $history_location) {
    print "You need to provide a path to the monolithic Qt repo!\n";
    exit 1;
}
my $history_git_dir = `cd $history_location && git rev-parse --git-dir`;
chomp $history_git_dir;
if (!$history_git_dir  || !-e "$history_location/$history_git_dir/objects") {
    print "Monolithic Qt repo path is not a valid Git repo!\n";
    exit 1;
}
$history_git_dir = abs_path("$history_location/$history_git_dir");
my $history_alternates_objects = "$history_git_dir/objects";

# check if we already point to this alternate object store
my $git_alternates_file = "$git_dir/objects/info/alternates";
my $found_alternate = fileContains($git_alternates_file, $history_alternates_objects);

# get first commit SHA1 of this repo which mentions branching from a commit
my $GIT_REVLIST;
my $git_pid = open($GIT_REVLIST, "git rev-list --reverse --grep='Branched from .*at commit' HEAD |")
    or die ("Failed to launch Git");
my @commits;
while (<$GIT_REVLIST>) {
    chomp;
    push(@commits, $_);
}
close($GIT_REVLIST);

my $found_any_grafts = 0;
mkdir("$git_dir/info");
my $graft_file = "$git_dir/info/grafts";
my @graft_lines;

foreach my $commit (@commits) {
    # find the graft point which the commit mentions
    my $commit_msg = `git show -s --format=%b $commit`;
    my $graft_to_commit = $commit_msg;
    $graft_to_commit =~ s/^.+Branched from .+at commit\n([a-f0-9]+)\n.*/$1/s;
    next if (!$graft_to_commit || $graft_to_commit eq $commit_msg);

    # Preserve any existing parents of the commit.
    my @existing_parents;
    my $GIT_CAT_FILE;
    open($GIT_CAT_FILE, "git cat-file commit $commit |") or die ("Failed to launch Git");
    while (<$GIT_CAT_FILE>) {
        if (/^parent ([0-9a-z]{40})/i) {
            push(@existing_parents, $1);
        }
    }
    close($GIT_CAT_FILE);

    # check that we don't already have this graft already setup
    my $graft_line = "$commit $graft_to_commit";
    $graft_line .= " " . join(" ", @existing_parents) if (@existing_parents);
    my $found_graft = fileContains($graft_file, $graft_line);
    if ($found_graft) {
        print "Graft for $commit already exists. Skipping...\n";
        $found_any_grafts = 1;
        next;
    }

    # verify that alternate object store contains the commit we want to graft to
    if (system("cd $history_location && git cat-file -e $graft_to_commit") != 0) {
        print "History repo ($history_location) does not contain commit $graft_to_commit!\n";
        print "Skipping this graft...\n";
        next;
    }

    print "Grafted $commit -> $graft_to_commit\n";
    push(@graft_lines, $graft_line);
    $found_any_grafts = 1;
}
if (!$found_any_grafts) {
    print "This repo does not refer to a graft point, so no grafts added!\n";
    exit 0;
}

# if our alternates file didn't contain the "history repo" path already
# add its path now
if (!$found_alternate) {
    my $ALTERNATES_FILE;
    open($ALTERNATES_FILE, ">> $git_alternates_file") || die "Could not open $git_alternates_file for writing, wrong permissions?";
    print $ALTERNATES_FILE "$history_alternates_objects\n";
    # Add alternates from alternates file in the history repo, in case it has additional alternates.
    my $HISTORY_ALTERNATES_FILE;
    if (open($HISTORY_ALTERNATES_FILE, "< $history_git_dir/objects/info/alternates")) {
        print("Reusing existing alternates in history repository\n");
        while (<$HISTORY_ALTERNATES_FILE>) {
            chomp;
            print $ALTERNATES_FILE $_ if (!fileContains($git_alternates_file, $_));
        }
        close($HISTORY_ALTERNATES_FILE);
    }
    close($ALTERNATES_FILE);
}

# Add graft lines from graft file in the history repo, in case it has additional grafts.
my $HISTORY_GRAFT_FILE;
if (open($HISTORY_GRAFT_FILE, "< $history_git_dir/info/grafts")) {
    print("Reusing existing grafts in history repository\n");
    while (<$HISTORY_GRAFT_FILE>) {
        chomp;
        push(@graft_lines, $_) if (!fileContains($graft_file, $_));
    }
    close($HISTORY_GRAFT_FILE);
}

# add graft
if (@graft_lines) {
    my $GRAFT_FILE;
    open($GRAFT_FILE, ">> $graft_file") || die "Could not open $graft_file for writing, wrong permissions?";
    print $GRAFT_FILE join("\n", @graft_lines) . "\n";
    close($GRAFT_FILE);
}