line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Git::CPAN::Patch::Import; |
2
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:YANICK'; |
3
|
|
|
|
|
|
|
$Git::CPAN::Patch::Import::VERSION = '2.3.1'; |
4
|
2
|
|
|
2
|
|
1368
|
use 5.10.0; |
|
2
|
|
|
|
|
7
|
|
5
|
|
|
|
|
|
|
|
6
|
2
|
|
|
2
|
|
11
|
use strict; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
40
|
|
7
|
2
|
|
|
2
|
|
8
|
use warnings; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
56
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
{ |
10
|
2
|
|
|
2
|
|
9
|
no warnings; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
65
|
|
11
|
2
|
|
|
2
|
|
27
|
use 5.010; |
|
2
|
|
|
|
|
6
|
|
12
|
|
|
|
|
|
|
|
13
|
2
|
|
|
2
|
|
833
|
use File::chmod (); # must be before 'autodie' to hush the warnings |
|
2
|
|
|
|
|
4250
|
|
|
2
|
|
|
|
|
43
|
|
14
|
|
|
|
|
|
|
|
15
|
2
|
|
|
2
|
|
424
|
use autodie; |
|
2
|
|
|
|
|
10349
|
|
|
2
|
|
|
|
|
13
|
|
16
|
|
|
|
|
|
|
|
17
|
2
|
|
|
2
|
|
12459
|
use Archive::Extract; |
|
2
|
|
|
|
|
227496
|
|
|
2
|
|
|
|
|
98
|
|
18
|
|
|
|
|
|
|
$Archive::Extract::PREFER_BIN = 1; |
19
|
|
|
|
|
|
|
|
20
|
2
|
|
|
2
|
|
36
|
use File::Find; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
112
|
|
21
|
2
|
|
|
2
|
|
12
|
use File::Basename; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
92
|
|
22
|
2
|
|
|
2
|
|
399
|
use File::Spec::Functions; |
|
2
|
|
|
|
|
689
|
|
|
2
|
|
|
|
|
148
|
|
23
|
2
|
|
|
2
|
|
14
|
use File::Temp qw(tempdir); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
98
|
|
24
|
2
|
|
|
2
|
|
11
|
use File::Path; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
77
|
|
25
|
2
|
|
|
2
|
|
737
|
use File::chdir; |
|
2
|
|
|
|
|
2792
|
|
|
2
|
|
|
|
|
180
|
|
26
|
2
|
|
|
2
|
|
14
|
use Path::Class qw/ file /; |
|
2
|
|
|
|
|
14
|
|
|
2
|
|
|
|
|
127
|
|
27
|
2
|
|
|
2
|
|
12
|
use Cwd qw/ getcwd /; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
57
|
|
28
|
2
|
|
|
2
|
|
16
|
use version; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
13
|
|
29
|
2
|
|
|
2
|
|
560
|
use Git::Repository; |
|
2
|
|
|
|
|
10618
|
|
|
2
|
|
|
|
|
14
|
|
30
|
2
|
|
|
2
|
|
1102
|
use CLASS; |
|
2
|
|
|
|
|
498
|
|
|
2
|
|
|
|
|
10
|
|
31
|
2
|
|
|
2
|
|
1388
|
use DateTime; |
|
2
|
|
|
|
|
816575
|
|
|
2
|
|
|
|
|
110
|
|
32
|
|
|
|
|
|
|
|
33
|
2
|
|
|
2
|
|
1349
|
use CPANPLUS; |
|
2
|
|
|
|
|
360954
|
|
|
2
|
|
|
|
|
124
|
|
34
|
2
|
|
|
2
|
|
889
|
use BackPAN::Index; |
|
2
|
|
|
|
|
327968
|
|
|
2
|
|
|
|
|
47
|
|
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
our $BackPAN_URL = "http://backpan.perl.org/"; |
39
|
|
|
|
|
|
|
our $PERL_GIT_URL = 'git://perl5.git.perl.org/perl.git'; |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
sub backpan_index { |
42
|
0
|
|
|
0
|
0
|
|
state $backpan = do { |
43
|
0
|
|
|
|
|
|
say "Loading BackPAN index (this may take a while)"; |
44
|
0
|
|
|
|
|
|
BackPAN::Index->new; |
45
|
|
|
|
|
|
|
}; |
46
|
0
|
|
|
|
|
|
return $backpan; |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
sub cpanplus { |
50
|
0
|
|
|
0
|
0
|
|
state $cpanplus = CPANPLUS::Backend->new; |
51
|
0
|
|
|
|
|
|
return $cpanplus; |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# Make sure we can read tarballs and change directories |
55
|
|
|
|
|
|
|
sub _fix_permissions { |
56
|
0
|
|
|
0
|
|
|
my $dir = shift; |
57
|
|
|
|
|
|
|
|
58
|
0
|
|
|
|
|
|
File::chmod::chmod "u+rx", $dir; |
59
|
|
|
|
|
|
|
find(sub { |
60
|
0
|
0
|
|
0
|
|
|
-d $_ ? File::chmod::chmod "u+rx", $_ : File::chmod::chmod "u+r", $_; |
61
|
0
|
|
|
|
|
|
}, $dir); |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
sub init_repo { |
65
|
0
|
|
|
0
|
0
|
|
my $module = shift; |
66
|
0
|
|
|
|
|
|
my $opts = shift; |
67
|
|
|
|
|
|
|
|
68
|
0
|
|
|
|
|
|
my $dirname = "."; |
69
|
0
|
0
|
|
|
|
|
if ( defined $opts->{mkdir} ) { |
70
|
0
|
|
0
|
|
|
|
( $dirname = $opts->{mkdir} || $module ) =~ s/::/-/g; |
71
|
|
|
|
|
|
|
|
72
|
0
|
0
|
|
|
|
|
if( -d $dirname ) { |
73
|
0
|
0
|
|
|
|
|
die "$dirname already exists\n" unless $opts->{update}; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
else { |
76
|
0
|
|
|
|
|
|
say "creating directory $dirname"; |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
# mkpath() does not play nice with overloaded objects |
79
|
0
|
|
|
|
|
|
mkpath "$dirname"; |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
{ |
84
|
0
|
|
|
|
|
|
local $CWD = $dirname; |
|
0
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
|
86
|
0
|
0
|
|
|
|
|
if ( -d '.git' ) { |
87
|
0
|
0
|
0
|
|
|
|
if ( !$opts->{force} and !$opts->{update} ) { |
88
|
0
|
|
|
|
|
|
die "Aborting: git repository already present.\n", |
89
|
|
|
|
|
|
|
"use '--force' if it's really what you want to do\n"; |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
else { |
93
|
0
|
|
|
|
|
|
Git::Repository->run('init'); |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
0
|
|
|
|
|
|
return File::Spec->rel2abs($dirname); |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
sub releases_in_git { |
102
|
0
|
|
|
0
|
0
|
|
my $repo = Git::Repository->new; |
103
|
0
|
0
|
|
|
|
|
return unless contains_git_revisions(); |
104
|
0
|
|
|
|
|
|
my @releases = map { m{\bgit-cpan-version:\s*(\S+)}x; $1 } |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
grep /^\s*git-cpan-version:/, |
106
|
|
|
|
|
|
|
$repo->run(log => '--pretty=format:%b'); |
107
|
0
|
|
|
|
|
|
return @releases; |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
sub rev_exists { |
112
|
0
|
|
|
0
|
0
|
|
my $rev = shift; |
113
|
0
|
|
|
|
|
|
my $repo = Git::Repository->new; |
114
|
|
|
|
|
|
|
|
115
|
0
|
|
|
|
|
|
return eval { $repo->run( 'rev-parse', $rev ); }; |
|
0
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
sub contains_git_revisions { |
120
|
0
|
0
|
|
0
|
0
|
|
return unless -d ".git"; |
121
|
0
|
|
|
|
|
|
return rev_exists("HEAD"); |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
sub import_one_backpan_release { |
126
|
0
|
|
|
0
|
0
|
|
my $release = shift; |
127
|
0
|
|
|
|
|
|
my $opts = shift; |
128
|
0
|
|
0
|
|
|
|
my $backpan_urls = $opts->{backpan} || $BackPAN_URL; |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
# allow multiple backpan URLs to be supplied |
131
|
0
|
0
|
|
|
|
|
$backpan_urls = [ $backpan_urls ] unless (ref($backpan_urls) eq 'ARRAY'); |
132
|
|
|
|
|
|
|
|
133
|
0
|
|
|
|
|
|
my $repo = Git::Repository->new; |
134
|
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
|
my( $last_commit, $last_version ); |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
# figure out if there is already an imported module |
138
|
0
|
0
|
|
|
|
|
if ( $last_commit = eval { $repo->run("rev-parse", "-q", "--verify", "cpan/master") } ) { |
|
0
|
|
|
|
|
|
|
139
|
0
|
|
|
|
|
|
$last_version = $repo->run("cpan-last-version"); |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
my $tmp_dir = File::Temp->newdir( |
143
|
0
|
0
|
|
|
|
|
$opts->{tempdir} ? (DIR => $opts->{tempdir}) : () |
144
|
|
|
|
|
|
|
); |
145
|
|
|
|
|
|
|
|
146
|
0
|
|
|
|
|
|
my $archive_file = catfile($tmp_dir, $release->filename); |
147
|
0
|
|
|
|
|
|
mkpath dirname $archive_file; |
148
|
|
|
|
|
|
|
|
149
|
0
|
|
|
|
|
|
my $response; |
150
|
0
|
|
|
|
|
|
for my $backpan_url (@$backpan_urls) { |
151
|
0
|
|
|
|
|
|
my $release_url = $backpan_url . "/" . $release->prefix; |
152
|
|
|
|
|
|
|
|
153
|
0
|
|
|
|
|
|
say "Downloading $release_url"; |
154
|
0
|
|
|
|
|
|
$response = get_from_url($release_url, $archive_file); |
155
|
0
|
0
|
|
|
|
|
last if $response->is_success; |
156
|
|
|
|
|
|
|
|
157
|
0
|
|
|
|
|
|
say " failed @{[ $response->status_line ]}"; |
|
0
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
0
|
0
|
|
|
|
|
if( !$response->is_success ) { |
161
|
0
|
|
|
|
|
|
say "Fetch failed. Skipping."; |
162
|
0
|
|
|
|
|
|
return; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
0
|
0
|
|
|
|
|
if( !-e $archive_file ) { |
166
|
0
|
|
|
|
|
|
say "$archive_file is missing. Skipping."; |
167
|
0
|
|
|
|
|
|
return; |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
0
|
|
|
|
|
|
say "extracting distribution"; |
171
|
0
|
|
|
|
|
|
my $ae = Archive::Extract->new( archive => $archive_file ); |
172
|
0
|
0
|
|
|
|
|
unless( $ae->extract( to => $tmp_dir ) ) { |
173
|
0
|
|
|
|
|
|
say "Couldn't extract $archive_file to $tmp_dir because ".$ae->error; |
174
|
0
|
|
|
|
|
|
say "Skipping"; |
175
|
0
|
|
|
|
|
|
return; |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
0
|
|
|
|
|
|
my $dir = $ae->extract_path; |
179
|
0
|
0
|
|
|
|
|
if( !$dir ) { |
180
|
0
|
|
|
|
|
|
say "The archive is empty, skipping"; |
181
|
0
|
|
|
|
|
|
return; |
182
|
|
|
|
|
|
|
} |
183
|
0
|
|
|
|
|
|
_fix_permissions($dir); |
184
|
|
|
|
|
|
|
|
185
|
0
|
|
|
|
|
|
my $tree = do { |
186
|
|
|
|
|
|
|
# don't overwrite the user's index |
187
|
0
|
|
|
|
|
|
local $ENV{GIT_INDEX_FILE} = catfile($tmp_dir, "temp_git_index"); |
188
|
0
|
|
|
|
|
|
local $ENV{GIT_DIR} = catfile( getcwd(), '.git' ); |
189
|
0
|
|
|
|
|
|
local $ENV{GIT_WORK_TREE} = $dir; |
190
|
|
|
|
|
|
|
|
191
|
0
|
|
|
|
|
|
local $CWD = $dir; |
192
|
|
|
|
|
|
|
|
193
|
0
|
|
|
|
|
|
my $write_tree_repo = Git::Repository->new( work_tree => $dir ) ; |
194
|
|
|
|
|
|
|
|
195
|
0
|
|
|
|
|
|
$write_tree_repo->run( qw(add -v --force .) ); |
196
|
0
|
|
|
|
|
|
$write_tree_repo->run( "write-tree" ); |
197
|
|
|
|
|
|
|
}; |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
# Create a commit for the imported tree object and write it into |
200
|
|
|
|
|
|
|
# refs/remotes/cpan/master |
201
|
0
|
|
|
|
|
|
local %ENV = %ENV; |
202
|
0
|
|
0
|
|
|
|
$ENV{GIT_AUTHOR_DATE} ||= $release->date; |
203
|
|
|
|
|
|
|
|
204
|
0
|
|
|
|
|
|
my $author = $CLASS->cpanplus->author_tree($release->cpanid); |
205
|
0
|
|
0
|
|
|
|
$ENV{GIT_AUTHOR_NAME} ||= $author->author; |
206
|
0
|
|
0
|
|
|
|
$ENV{GIT_AUTHOR_EMAIL} ||= $author->email; |
207
|
|
|
|
|
|
|
|
208
|
0
|
|
|
|
|
|
my @parents = grep { $_ } $last_commit; |
|
0
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
# commit message |
212
|
0
|
|
|
|
|
|
my $name = $release->dist; |
213
|
0
|
|
0
|
|
|
|
my $version = $release->version || ''; |
214
|
0
|
0
|
|
|
|
|
my $message = join ' ', ( $last_version ? "import" : "initial import of"), "$name $version from CPAN\n"; |
215
|
0
|
|
|
|
|
|
$message .= <<"END"; |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
git-cpan-module: $name |
218
|
|
|
|
|
|
|
git-cpan-version: $version |
219
|
0
|
|
|
|
|
|
git-cpan-authorid: @{[ $author->cpanid ]} |
220
|
0
|
|
|
|
|
|
git-cpan-file: @{[ $release->prefix ]} |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
END |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
my $commit = $repo->run( { input => $message }, 'commit-tree', $tree, |
225
|
0
|
|
|
|
|
|
map { ( -p => $_ ) } @parents ); |
|
0
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
# finally, update the fake branch and create a tag for convenience |
228
|
0
|
|
|
|
|
|
my $dist = $release->dist; |
229
|
0
|
|
|
|
|
|
print $repo->run('update-ref', '-m' => "import $dist", 'refs/heads/cpan/master', $commit ); |
230
|
|
|
|
|
|
|
|
231
|
0
|
0
|
|
|
|
|
if( $version ) { |
232
|
0
|
|
|
|
|
|
my $tag = $version; |
233
|
0
|
|
|
|
|
|
$tag =~ s{^\.}{0.}; # git does not like a leading . as a tag name |
234
|
0
|
|
|
|
|
|
$tag =~ s{\.$}{}; # nor a trailing one |
235
|
0
|
0
|
|
|
|
|
if( $repo->run( "tag", "-l" => $tag ) ) { |
236
|
0
|
|
|
|
|
|
say "Tag $tag already exists, overwriting"; |
237
|
|
|
|
|
|
|
} |
238
|
0
|
|
|
|
|
|
print $repo->run( "tag", "-f" => $tag, $commit ); |
239
|
0
|
|
|
|
|
|
say "created tag '$tag' ($commit)"; |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
sub get_from_url { |
245
|
0
|
|
|
0
|
0
|
|
my($url, $file) = @_; |
246
|
|
|
|
|
|
|
|
247
|
0
|
|
|
|
|
|
require LWP::UserAgent; |
248
|
0
|
|
|
|
|
|
my $ua = LWP::UserAgent->new; |
249
|
|
|
|
|
|
|
|
250
|
0
|
|
|
|
|
|
my $req = HTTP::Request->new( GET => $url ); |
251
|
0
|
|
|
|
|
|
my $res = $ua->request($req, $file); |
252
|
|
|
|
|
|
|
|
253
|
0
|
|
|
|
|
|
return $res; |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
sub import_from_backpan { |
258
|
0
|
|
|
0
|
0
|
|
my ( $distname, $opts ) = @_; |
259
|
|
|
|
|
|
|
|
260
|
0
|
|
|
|
|
|
$distname =~ s/::/-/g; |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
# handle --mkdir and raise an error if the target directory has already been git-initialized |
263
|
0
|
|
|
|
|
|
my $repo_dir = init_repo($distname, $opts); |
264
|
|
|
|
|
|
|
|
265
|
0
|
|
|
|
|
|
local $CWD = $repo_dir; |
266
|
|
|
|
|
|
|
|
267
|
0
|
|
|
|
|
|
my $backpan = $CLASS->backpan_index; |
268
|
0
|
0
|
|
|
|
|
my $dist = $backpan->dist($distname) |
269
|
|
|
|
|
|
|
or die "Error: no distributions found. ", |
270
|
|
|
|
|
|
|
"Are you sure you spelled the module name correctly?\n"; |
271
|
|
|
|
|
|
|
|
272
|
0
|
|
|
|
|
|
fixup_repository(); |
273
|
|
|
|
|
|
|
|
274
|
0
|
|
|
|
|
|
my %existing_releases; |
275
|
0
|
0
|
|
|
|
|
%existing_releases = map { $_ => 1 } releases_in_git() if $opts->{update}; |
|
0
|
|
|
|
|
|
|
276
|
0
|
|
|
|
|
|
my $release_added = 0; |
277
|
0
|
|
|
|
|
|
for my $release ($dist->releases->search( undef, { order_by => "date" } )) { |
278
|
0
|
0
|
|
|
|
|
next if $existing_releases{$release->version}; |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
# skip .ppm files |
281
|
0
|
0
|
|
|
|
|
next if $release->filename =~ m{\.ppm\b}; |
282
|
|
|
|
|
|
|
|
283
|
0
|
|
|
|
|
|
say "importing $release"; |
284
|
0
|
|
|
|
|
|
import_one_backpan_release( |
285
|
|
|
|
|
|
|
$release, |
286
|
|
|
|
|
|
|
$opts, |
287
|
|
|
|
|
|
|
); |
288
|
0
|
|
|
|
|
|
$release_added++; |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
|
291
|
0
|
0
|
|
|
|
|
if( !$release_added ) { |
292
|
0
|
0
|
|
|
|
|
if( !keys %existing_releases ) { |
293
|
0
|
|
|
|
|
|
say "Empty repository for $dist. Deleting."; |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
# We can't delete it if we're inside it. |
296
|
0
|
|
|
|
|
|
$CWD = ".."; |
297
|
0
|
|
|
|
|
|
rmtree $repo_dir; |
298
|
|
|
|
|
|
|
|
299
|
0
|
|
|
|
|
|
return; |
300
|
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
else { |
302
|
0
|
|
|
|
|
|
say "No updates for $dist."; |
303
|
0
|
|
|
|
|
|
return; |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
0
|
|
|
|
|
|
my $repo = Git::Repository->new; |
308
|
0
|
0
|
|
|
|
|
if( !rev_exists("master") ) { |
309
|
0
|
|
|
|
|
|
print $repo->run('checkout', '-t', '-b', 'master', 'cpan/master'); |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
else { |
312
|
0
|
|
|
|
|
|
print $repo->run('checkout', 'master', '.'), |
313
|
|
|
|
|
|
|
$repo->run('merge', 'cpan/master'); |
314
|
|
|
|
|
|
|
} |
315
|
|
|
|
|
|
|
|
316
|
0
|
|
|
|
|
|
return $repo_dir; |
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
sub fixup_repository { |
321
|
0
|
|
|
0
|
0
|
|
my $repo = Git::Repository->new; |
322
|
|
|
|
|
|
|
|
323
|
0
|
0
|
|
|
|
|
return unless -d ".git"; |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
# We do our work in cpan/master, it might not exist if this |
326
|
|
|
|
|
|
|
# repo was cloned from gitpan. |
327
|
0
|
0
|
0
|
|
|
|
if( !rev_exists("cpan/master") and rev_exists("master") ) { |
328
|
0
|
|
|
|
|
|
print $repo->run('branch', '-t', 'cpan/master', 'master'); |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
|
332
|
2
|
|
|
2
|
|
5281
|
use MetaCPAN::API; |
|
2
|
|
|
|
|
177321
|
|
|
2
|
|
|
|
|
1668
|
|
333
|
|
|
|
|
|
|
my $mcpan = MetaCPAN::API->new; |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
sub find_release { |
336
|
0
|
|
|
0
|
0
|
|
my $input = shift; |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
return eval { $mcpan->release( |
339
|
|
|
|
|
|
|
distribution => $mcpan->module($input)->{distribution} |
340
|
|
|
|
|
|
|
) } |
341
|
0
|
|
0
|
|
|
|
|| eval { $mcpan->release( distribution => $input ) } |
342
|
|
|
|
|
|
|
|| die "could not find release for '$input' on metacpan\n"; |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
} |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
sub main { |
347
|
0
|
|
|
0
|
0
|
|
my $module = shift; |
348
|
0
|
|
|
|
|
|
my $opts = shift; |
349
|
|
|
|
|
|
|
|
350
|
0
|
0
|
|
|
|
|
if ( delete $opts->{backpan} ) { |
351
|
0
|
|
|
|
|
|
return import_from_backpan( $module, $opts ); |
352
|
|
|
|
|
|
|
} |
353
|
|
|
|
|
|
|
|
354
|
0
|
|
|
|
|
|
my $repo = Git::Repository->new; |
355
|
|
|
|
|
|
|
|
356
|
0
|
|
|
|
|
|
my ( $last_commit, $last_version ); |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
# figure out if there is already an imported module |
359
|
0
|
0
|
|
|
|
|
if ( $last_commit = eval { $repo->run("rev-parse", "-q", "--verify", "cpan/master") } ) { |
|
0
|
|
|
|
|
|
|
360
|
0
|
|
0
|
|
|
|
$module ||= $repo->run("cpan-which"); |
361
|
0
|
|
|
|
|
|
$last_version = $repo->run("cpan-last-version"); |
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
|
364
|
0
|
0
|
|
|
|
|
die("Usage: git-cpan import Foo::Bar\n") unless $module; |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
# first we figure out a module object from the module argument |
367
|
|
|
|
|
|
|
|
368
|
0
|
|
|
|
|
|
my $release = find_release($module); |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
# based on the version number it figured out for us we decide whether or not to |
371
|
|
|
|
|
|
|
# actually import. |
372
|
|
|
|
|
|
|
|
373
|
0
|
|
|
|
|
|
my $name = $release->{name}; |
374
|
0
|
|
|
|
|
|
my $version = $release->{version}; |
375
|
0
|
|
|
|
|
|
my $dist = $release->{distribution}; |
376
|
|
|
|
|
|
|
|
377
|
0
|
0
|
|
|
|
|
if ( $dist eq 'perl' ) { |
378
|
0
|
|
|
|
|
|
say "$name is a core modules, ", |
379
|
|
|
|
|
|
|
"clone perl from $PERL_GIT_URL instead."; |
380
|
0
|
|
|
|
|
|
exit; |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
|
383
|
0
|
|
|
|
|
|
my $prettyname = $dist . ( " ($module)" x ( $dist ne $module ) ); |
384
|
|
|
|
|
|
|
|
385
|
0
|
0
|
0
|
|
|
|
if ( $last_version and $opts->{checkversion} ) { |
386
|
|
|
|
|
|
|
# if last_version is defined this is an update |
387
|
0
|
|
|
|
|
|
my $imported = version->new($last_version); |
388
|
0
|
|
|
|
|
|
my $will_import = version->new($release->{version}); |
389
|
|
|
|
|
|
|
|
390
|
0
|
0
|
|
|
|
|
die "$name has already been imported\n" if $imported == $will_import; |
391
|
|
|
|
|
|
|
|
392
|
0
|
0
|
|
|
|
|
die "imported version $imported is more recent than $will_import, can't import\n" |
393
|
|
|
|
|
|
|
if $imported > $will_import; |
394
|
|
|
|
|
|
|
|
395
|
0
|
|
|
|
|
|
say "updating $prettyname from $imported to $will_import"; |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
} else { |
398
|
0
|
|
|
|
|
|
say "importing $prettyname"; |
399
|
|
|
|
|
|
|
} |
400
|
|
|
|
|
|
|
|
401
|
0
|
|
|
|
|
|
require LWP::UserAgent; |
402
|
|
|
|
|
|
|
|
403
|
0
|
|
|
|
|
|
my $ua = LWP::UserAgent->new; |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
# download the dist and extract into a temporary directory |
406
|
0
|
|
|
|
|
|
my $tmp_dir = tempdir( CLEANUP => 0 ); |
407
|
|
|
|
|
|
|
|
408
|
0
|
|
|
|
|
|
say "downloading $dist"; |
409
|
|
|
|
|
|
|
|
410
|
0
|
|
|
|
|
|
my $tarball = file( $tmp_dir, $release->{archive} ); |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
$ua->mirror( |
413
|
0
|
0
|
|
|
|
|
$release->{download_url} => $tarball |
414
|
|
|
|
|
|
|
) or die "couldn't fetch tarball\n"; |
415
|
|
|
|
|
|
|
|
416
|
0
|
|
|
|
|
|
say "extracting distribution"; |
417
|
|
|
|
|
|
|
|
418
|
0
|
|
|
|
|
|
my $archive = Archive::Extract->new( archive => $tarball ); |
419
|
0
|
|
|
|
|
|
$archive->extract( to => $tmp_dir ); |
420
|
|
|
|
|
|
|
|
421
|
0
|
0
|
|
|
|
|
my $dist_dir = $archive->extract_path |
422
|
|
|
|
|
|
|
or die "extraction failed\n"; |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
# create a tree object for the CPAN module |
425
|
|
|
|
|
|
|
# this imports the source code without touching the user's working directory or |
426
|
|
|
|
|
|
|
# index |
427
|
|
|
|
|
|
|
|
428
|
0
|
|
|
|
|
|
my $tree = do { |
429
|
|
|
|
|
|
|
# don't overwrite the user's index |
430
|
0
|
|
|
|
|
|
local $ENV{GIT_INDEX_FILE} = catfile($tmp_dir, "temp_git_index"); |
431
|
0
|
|
|
|
|
|
local $ENV{GIT_DIR} = catfile( getcwd(), '.git' ); |
432
|
0
|
|
|
|
|
|
local $ENV{GIT_WORK_TREE} = $dist_dir; |
433
|
|
|
|
|
|
|
|
434
|
0
|
|
|
|
|
|
local $CWD = $dist_dir; |
435
|
|
|
|
|
|
|
|
436
|
0
|
|
|
|
|
|
my $write_tree_repo = Git::Repository->new( work_tree => $dist_dir ); |
437
|
|
|
|
|
|
|
|
438
|
0
|
|
|
|
|
|
$write_tree_repo->run( qw(add -v --force .) ); |
439
|
0
|
|
|
|
|
|
$write_tree_repo->run( "write-tree" ); |
440
|
|
|
|
|
|
|
}; |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
# create a commit for the imported tree object and write it into |
443
|
|
|
|
|
|
|
# refs/heads/cpan/master |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
{ |
446
|
0
|
|
|
|
|
|
local %ENV = %ENV; |
|
0
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
|
448
|
0
|
|
|
|
|
|
my $author_obj = $mcpan->author($release->{author}); |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
# try to find a date for the version using the backpan index |
451
|
|
|
|
|
|
|
# secondly, if the CPANPLUS author object is a fake one (e.g. when importing a |
452
|
|
|
|
|
|
|
# URI), get the user object by using the ID from the backpan index |
453
|
0
|
0
|
|
|
|
|
unless ( $ENV{GIT_AUTHOR_DATE} ) { |
454
|
0
|
|
|
|
|
|
my $mtime = eval { |
455
|
0
|
|
|
|
|
|
DateTime->from_epoch( epoch => $release->{stat}{mtime})->ymd; |
456
|
|
|
|
|
|
|
}; |
457
|
|
|
|
|
|
|
|
458
|
0
|
0
|
|
|
|
|
warn $@ if $@; |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
# CPAN::Checksums makes YYYY-MM-DD dates, but GIT_AUTHOR_DATE |
461
|
|
|
|
|
|
|
# doesn't support that. |
462
|
0
|
0
|
|
|
|
|
$mtime .= 'T00:00::00' |
463
|
|
|
|
|
|
|
if $mtime =~ m/\A (\d\d\d\d) - (\d\d?) - (\d\d?) \z/x; |
464
|
|
|
|
|
|
|
|
465
|
0
|
0
|
|
|
|
|
if ( $mtime ) { |
466
|
0
|
|
|
|
|
|
$ENV{GIT_AUTHOR_DATE} = $mtime; |
467
|
|
|
|
|
|
|
} else { |
468
|
0
|
|
|
|
|
|
my %dists; |
469
|
|
|
|
|
|
|
|
470
|
0
|
0
|
|
|
|
|
if ( $opts->{backpan} ) { |
471
|
|
|
|
|
|
|
# we need the backpan index for dates |
472
|
0
|
|
|
|
|
|
my $backpan = $CLASS->backpan_index; |
473
|
|
|
|
|
|
|
|
474
|
0
|
|
|
|
|
|
%dists = map { $_->filename => $_ } |
475
|
0
|
|
|
|
|
|
$backpan->releases($release->{name}); |
476
|
|
|
|
|
|
|
} |
477
|
|
|
|
|
|
|
|
478
|
0
|
0
|
|
|
|
|
if ( my $bp_dist = $dists{$dist} ) { |
479
|
|
|
|
|
|
|
|
480
|
0
|
|
|
|
|
|
$ENV{GIT_AUTHOR_DATE} = $bp_dist->date; |
481
|
|
|
|
|
|
|
|
482
|
0
|
0
|
|
|
|
|
if ( $author_obj->isa("CPANPLUS::Module::Author::Fake") ) { |
483
|
0
|
|
|
|
|
|
$author_obj = $mcpan->author_tree($bp_dist->cpanid); |
484
|
|
|
|
|
|
|
} |
485
|
|
|
|
|
|
|
} else { |
486
|
0
|
|
|
|
|
|
say "Couldn't find upload date for $dist"; |
487
|
|
|
|
|
|
|
|
488
|
0
|
0
|
|
|
|
|
if ( $author_obj->isa("CPANPLUS::Module::Author::Fake") ) { |
489
|
0
|
|
|
|
|
|
say "Couldn't find author for $dist"; |
490
|
|
|
|
|
|
|
} |
491
|
|
|
|
|
|
|
} |
492
|
|
|
|
|
|
|
} |
493
|
|
|
|
|
|
|
} |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
# create the commit object |
496
|
0
|
0
|
|
|
|
|
$ENV{GIT_AUTHOR_NAME} = $author_obj->{name} unless $ENV{GIT_AUTHOR_NAME}; |
497
|
0
|
0
|
|
|
|
|
$ENV{GIT_AUTHOR_EMAIL} = $author_obj->{email}[0] unless $ENV{GIT_AUTHOR_EMAIL}; |
498
|
|
|
|
|
|
|
|
499
|
0
|
0
|
|
|
|
|
my @parents = ( grep { $_ } $last_commit, @{ $opts->{parent} || [] } ); |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
|
501
|
0
|
0
|
|
|
|
|
my $message = join ' ', |
502
|
|
|
|
|
|
|
( $last_version ? "import" : "initial import of" ), |
503
|
|
|
|
|
|
|
"$name $version from CPAN\n"; |
504
|
0
|
|
|
|
|
|
$message .= <<"END"; |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
git-cpan-module: $name |
507
|
|
|
|
|
|
|
git-cpan-version: $version |
508
|
0
|
|
|
|
|
|
git-cpan-authorid: @{[ $author_obj->{pauseid} ]} |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
END |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
my $commit = $repo->run( |
513
|
|
|
|
|
|
|
{ input => $message }, |
514
|
0
|
|
|
|
|
|
'commit-tree', $tree, map { ( -p => $_ ) } @parents ); |
|
0
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
# finally, update the fake remote branch and create a tag for convenience |
517
|
|
|
|
|
|
|
|
518
|
0
|
|
|
|
|
|
print $repo->run('update-ref', '-m' => "import $dist", 'refs/remotes/cpan/master', $commit ); |
519
|
|
|
|
|
|
|
|
520
|
0
|
|
|
|
|
|
print $repo->run( tag => $version, $commit ); |
521
|
|
|
|
|
|
|
|
522
|
0
|
|
|
|
|
|
say "created tag '$version' ($commit)"; |
523
|
|
|
|
|
|
|
} |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
} |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
1; |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
=pod |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
=encoding UTF-8 |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
=head1 NAME |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
Git::CPAN::Patch::Import |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
=head1 VERSION |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
version 2.3.1 |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
=head1 DESCRIPTION |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
This is the guts of Git::CPAN::Patch::Import moved here to make it callable |
544
|
|
|
|
|
|
|
as a function so git-backpan-init goes faster. |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
=head1 NAME |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
Git::CPAN::Patch::Import - The meat of git-cpan-import |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
=head1 AUTHOR |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
Yanick Champoux <yanick@cpan.org> |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
This software is copyright (c) 2017 by Yanick Champoux. |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
559
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
=cut |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
__END__ |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
1; |