File Coverage

File:lib/CheckSpelling/GitSources.pm
Coverage:76.3%

linestmtbrancondsubtimecode
1#! -*-perl-*-
2package CheckSpelling::GitSources;
3
4
3
3
3
112667
4
80
use Cwd 'abs_path';
5
3
3
3
5
1
84
use File::Basename;
6
3
3
3
4
1
41
use File::Temp qw/ tempfile tempdir /;
7
3
3
3
3
4
51
use JSON::PP;
8
3
3
3
155
2
1576
use CheckSpelling::Util;
9
10
3
3
3
460
2125
55
unless (eval 'use URI::Escape; 1') {
11    eval 'use URI::Escape::XS qw/uri_escape/';
12}
13
14my %git_roots = ();
15my %github_urls = ();
16my $pull_base;
17my $pull_head;
18
19sub github_repo {
20
3
190
    my ($source) = @_;
21
3
11
    $source =~ s<https://[^/]+/|.*:><>;
22
3
5
    $source =~ s<\.git$><>;
23
3
9
    return '' unless $source =~ m#^[^/]+/[^/]+$#;
24
2
6
    return $source;
25}
26
27sub file_ref {
28
0
0
    my ($file, $line) = @_;
29
0
0
    $file =~ s/ /%20/g;
30
0
0
    return "$file:$line";
31}
32
33sub find_git {
34
6
5
    our $git_dir;
35
6
16
    return $git_dir if defined $git_dir;
36
3
19
    if ($ENV{PATH} =~ /(.*)/) {
37
3
10
        my $path = $1;
38
3
11
        for my $maybe_git (split /:/, $path) {
39
33
88
            if (-x "$maybe_git/git") {
40
3
3
                $git_dir = $maybe_git;
41
3
27
                return $git_dir;
42            }
43        }
44    }
45}
46
47sub git_source_and_rev {
48
26
396301
    my ($file) = @_;
49
26
20
    our (%git_roots, %github_urls, $pull_base, $pull_head);
50
51
26
13
    my $last_git_dir;
52
26
16
    my $dir = $file;
53
26
17
    my @children;
54
26
99
    while ($dir ne '.' && $dir ne '/') {
55
37
496
        my $child = basename($dir);
56
37
34
        push @children, $child;
57
37
290
        my $parent = dirname($dir);
58
37
39
        last if $dir eq $parent;
59
37
21
        $dir = $parent;
60
37
60
        last if defined $git_roots{$dir};
61
16
15
        my $git_dir = "$dir/.git";
62
16
106
        if (-e $git_dir) {
63
6
24
            if (-d $git_dir) {
64
5
14
                $git_roots{$dir} = $git_dir;
65
5
5
                last;
66            }
67
1
24
            if (-s $git_dir) {
68
1
33
                open $git_dir_file, '<', $git_dir;
69
1
5
                my $git_dir_path = <$git_dir_file>;
70
1
3
                close $git_dir_file;
71
1
4
                if ($git_dir_path =~ /^gitdir: (.*)$/) {
72
1
19
                    $last_git_dir = $git_roots{$dir} = abs_path("$dir/$1");
73                }
74            }
75        }
76    }
77
26
58
    $last_git_dir ||= $git_roots{$dir};
78
26
25
    my $length = scalar @children - 1;
79
26
28
    for (my $i = 0; $i < $length; $i++) {
80
11
9
        $dir .= "/$children[$i]";
81
11
39
        $git_roots{$dir} = $last_git_dir;
82    }
83
84
26
24
    return () unless defined $last_git_dir;
85
26
36
    $file = join '/', (reverse @children);
86
87
26
12
    my ($prefix, $remote_url, $rev, $branch);
88
26
30
    unless (defined $github_urls{$last_git_dir}) {
89
6
11
        my $full_path = $ENV{PATH};
90
6
9
        $ENV{PATH} = find_git();
91
6
9
        my $git_dir = $ENV{GIT_DIR};
92
6
50
        $ENV{GIT_DIR} = $last_git_dir;
93
6
14087
        my $git_remotes = `git remote`;
94
6
47
        my @remotes = split /\n/, $git_remotes;
95
6
10
        my $origin;
96
6
7
33
56
        if (grep { /^origin$/ } @remotes) {
97
6
12
            $origin = 'origin';
98        } elsif (@remotes) {
99
0
0
            $origin = $remotes[0];
100        }
101
6
9
        my $remote_url;
102        my $rev;
103
6
16
        if ($origin) {
104
6
17049
            $remote_url = `git remote get-url "$origin" 2>/dev/null`;
105
6
55
            chomp $remote_url;
106
6
16808
            $rev = `git rev-parse HEAD 2>/dev/null`;
107
6
34
            chomp $rev;
108
6
9
            my $private_synthetic_sha = $ENV{PRIVATE_SYNTHETIC_SHA};
109
6
21
            if (defined $private_synthetic_sha) {
110
0
0
                $rev = $ENV{PRIVATE_MERGE_SHA} if ($rev eq $private_synthetic_sha);
111            }
112        }
113
6
13110
        $branch = `git branch --show-current` unless $branch;
114
6
33
        chomp $branch;
115
6
56
        $ENV{PATH} = $full_path;
116
6
28
        if ($git_dir) {
117
0
0
            $ENV{GIT_DIR} = $git_dir;
118        } else {
119
6
45
            delete $ENV{GIT_DIR};
120        }
121
6
8
        my $url_base;
122
6
11
        $remote_url = '' if $remote_url eq '.';
123
6
8
        if ($remote_url) {
124
6
53
            unless ($remote_url =~ m<^https?://>) {
125
2
26
                $remote_url =~ s!.*\@([^:]+):!https://$1/!;
126            }
127
6
16
            $remote_url =~ s!\.git$!!;
128        } elsif ($ENV{GITHUB_SERVER_URL} ne '' && $ENV{GITHUB_REPOSITORY} ne '') {
129
0
0
            $remote_url = "$ENV{GITHUB_SERVER_URL}/$ENV{GITHUB_REPOSITORY}";
130
0
0
            $rev = $ENV{GITHUB_HEAD_REF} || $ENV{GITHUB_SHA} unless $rev;
131
0
0
            $branch = $ENV{GITHUB_HEAD_REF} unless $branch;
132        }
133
6
13
        $url_base = "$remote_url/blame" if $remote_url;
134
6
6
        if ($url_base) {
135
6
12
            if ($pull_base) {
136
0
0
                $url_base =~ s<^$pull_base/><$pull_head/>i;
137            }
138
6
7
            $prefix = "$url_base/$rev/";
139        }
140
141
6
55
        $github_urls{$last_git_dir} = [$prefix, $remote_url, $rev, $branch];
142    }
143
26
549
    my $real_last_git_dir = basename($last_git_dir) eq '.git' ? dirname($last_git_dir) : $last_git_dir;
144
26
26
14
111
    return $file, $real_last_git_dir, @{$github_urls{$last_git_dir}};
145}
146
1471;