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