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