13 my $ua = LWP::UserAgent->new;
14 my $json = JSON->new->utf8->indent;
17 "https://api.github.com$url"
20 $res->is_success or croak $res->status_line;
22 return $json->decode($res->content);
30 while (my($key, $value) = each %parameters) {
31 $parameters .= "&$key=$value";
37 my $result = json_api("$url?per_page=100&page=$page$parameters");
38 if (ref($result) eq 'ARRAY' && scalar @$result > 0) {
39 push @$data, @$result;
59 # both hash and hashref are acceptable
62 my $args = (ref $_[0] eq 'HASH') ? $_[0] : {@_};
64 return bless $args, $class;
72 $self->{repos} = undef;
73 $self->{account} = $args;
76 return $self->{account};
84 $self->{repos} = undef;
85 $self->{repository} = $args;
88 return $self->{repository};
96 $self->{directory} = File::Spec->rel2abs($args);
99 return $self->{directory};
104 return $self->{repos} if ($self->{repos});
108 my $account = $self->account or croak "account is not set";
110 if (my $repository = $self->repository) {
111 $result = [ utils::json_api("/repos/$account/$repository") ];
114 $result = utils::get("/users/$account/repos");
117 foreach my $repos (@$result) {
118 push @{$self->{repos}},
119 GitHubBackup::Repository->new({
120 directory => sub {$self->directory},
126 return $self->{repos};
132 foreach my $repos (@{$self->repos}) {
140 package GitHubBackup::Repository;
149 use File::Path qw(mkpath);
158 return bless $args, $class;
162 return (shift)->{repos}{clone_url};
166 return (shift)->{repos}{full_name};
172 my $path = $self->full_name;
173 if (my $base = $self->{directory}->()) {
174 $path = File::Spec->catfile($base, $path);
187 print "fetch ", $dir, "\n";
188 Git::Repository->run(fetch => '--all');
192 print "clone ", $dir, "\n";
194 Git::Repository->run(clone => '--mirror' => $url => $dir);
202 my $dir = $self->directory . '.git';
203 my $url = $self->clone_url;
205 $self->sync($url => $dir);
212 return $self->{forks} if ($self->{forks});
214 $self->{forks} = utils::get("/repos/" . $self->full_name . "/forks");
216 return $self->{forks};
222 my $dir = $self->directory . '.git';
225 my $remotes = Git::Repository->run(branch => '--remotes');
227 foreach my $fork (@{$self->forks}) {
228 if ($remotes =~ /$fork->{full_name}/) {
229 print "skip ", $fork->{full_name}, "\n";
232 print "add ", $fork->{full_name}, "\n";
233 Git::Repository->run(remote => add => $fork->{full_name} => $fork->{clone_url});
234 push @fetch, $fork->{full_name};
237 foreach my $fork (@fetch) {
238 print "fetch ", $fork, "\n";
239 Git::Repository->run(fetch => $fork);
248 my $dir = $self->directory . '.wiki.git';
249 my $url = 'https://github.com/' . $self->full_name . '.wiki.git';
251 $self->sync($url => $dir);
258 return $self->{issues} if ($self->{issues});
260 my $open = utils::get("/repos/" . $self->full_name . "/issues");
261 my $closed = utils::get("/repos/" . $self->full_name . "/issues", state => 'closed');
263 if ($open) { push @{$self->{issues}}, @$open }
264 if ($closed) { push @{$self->{issues}}, @$closed }
266 return $self->{issues};
272 my $ua = LWP::UserAgent->new;
273 my $json = JSON->new->utf8->indent;
275 my $dir = $self->directory . '.issues';
276 mkpath $dir unless (-d $dir);
278 foreach my $issue (@{$self->issues}) {
279 my $number = $issue->{number};
280 print "save issue/$number\n";
282 open my $fh, ">$number.json";
283 print $fh $json->encode($issue);
286 if (exists $issue->{pull_request}{patch_url}) {
287 $ua->mirror($issue->{pull_request}{patch_url} => "$number.patch");