source: lab.git/Dev/github/GitHubBackup.pm @ 55d0513

Last change on this file since 55d0513 was 55d0513, checked in by Ken-ichi Mito <mitty@…>, 11 years ago

utils::get with %parameters

  • Property mode set to 100644
File size: 5.6 KB
RevLine 
[6a2e5f1]1package utils;
2use strict;
3use warnings;
4use utf8;
5use Carp qw(croak);
6
7use LWP::UserAgent;
8use JSON;
9my $ua = LWP::UserAgent->new;
10my $json = JSON->new->utf8->indent;
11
12sub json_api {
13    my $url = shift;
14   
15    my $res = $ua->get(
16        "https://api.github.com$url"
17    );
18   
19    $res->is_success or croak $res->status_line;
20   
21    return $json->decode($res->content);
22}
23
[fc647d5]24sub get {
25    my $url = shift;
[55d0513]26    my %parameters = @_;
27   
28    my $parameters = '';
29    while (my($key, $value) = each %parameters) {
30        $parameters .= "&$key=$value";
31    }
[fc647d5]32   
33    my $page = 1;
34    my $data;
35    while(1) {
[55d0513]36        my $result = json_api("$url?per_page=100&page=$page$parameters");
[fc647d5]37        if (ref($result) eq 'ARRAY' && scalar @$result > 0) {
38            push @$data, @$result;
39            $page++;
40           
41            next;
42        }
43        last;
44    }
45   
46    return $data;
47}
[19233f5]48
[6a2e5f1]49package GitHubBackup;
50
51use strict;
52use warnings;
53use utf8;
54use Carp qw(croak);
[6f31bfb]55use File::Spec;
[6a2e5f1]56
57
58# both hash and hashref are acceptable
59sub new {
60    my $class = shift;
61    my $args = (ref $_[0] eq 'HASH') ? $_[0] : {@_};
[19233f5]62   
[6f31bfb]63    return bless $args, $class;
[6a2e5f1]64}
65
[19df400]66sub account {
67    my $self = shift;
68    my $args = shift;
69   
70    if (defined $args) {
71        $self->{repos} = undef;
72        $self->{account} = $args;
73    }
74   
75    return $self->{account};
76}
77
78sub repository {
79    my $self = shift;
80    my $args = shift;
81   
82    if (defined $args) {
83        $self->{repos} = undef;
84        $self->{repository} = $args;
85    }
86   
87    return $self->{repository};
88}
89
[6f31bfb]90sub directory {
91    my $self = shift;
92    my $args = shift;
93   
94    if (defined $args) {
95        $self->{directory} = File::Spec->rel2abs($args);
96    }
97   
98    return $self->{directory};
99}
100
[6a2e5f1]101sub repos {
102    my $self = shift;
[19233f5]103    return $self->{repos} if ($self->{repos});
[6a2e5f1]104   
105    my $account = $self->account or croak "account is not set";
106    if (my $repository = $self->repository) {
107        $self->{repos} = [
[19233f5]108            GitHubBackup::Repository->new({
[b8d7413]109                directory => sub {$self->directory},
[19233f5]110                full_name => "$account/$repository",
111            })
[6a2e5f1]112        ];
113       
114        return $self->{repos};
115    }
116   
[fc647d5]117    my $result = utils::get("/users/$account/repos");
118    foreach my $repos (@$result) {
[6a2e5f1]119        push @{$self->{repos}},
120            GitHubBackup::Repository->new({
[b8d7413]121                directory => sub {$self->directory},
[6a2e5f1]122                full_name => $repos->{full_name},
123                clone_url => $repos->{clone_url},
124            })
125        ;
126    }
127   
128    return $self->{repos};
129}
130
[19df400]131sub backup {
132    my $self = shift;
133   
134    foreach my $repos (@{$self->repos}) {
135        $repos->backup;
136    }
137   
138    return $self;
139}
140
[6a2e5f1]141
142package GitHubBackup::Repository;
143
144use strict;
145use warnings;
146use utf8;
147use Carp qw(croak);
[19233f5]148use Git::Repository;
149use File::chdir;
[6f31bfb]150use File::Spec;
151use File::Path qw(mkpath);
[b8d7413]152
[19233f5]153sub new {
154    my $class = shift;
155    my $args  = shift;
156   
157    if (! exists $args->{clone_url}) {
158        my $result = utils::json_api('/repos/' . $args->{full_name});
159        $args->{clone_url} = $result->{clone_url};
160    }
161   
[6f31bfb]162    return bless $args, $class;
[19233f5]163}
164
[b8d7413]165sub directory {
166    my $self = shift;
167   
[6f31bfb]168    my $path = $self->{full_name};
169    if (my $base = $self->{directory}->()) {
170        $path = File::Spec->catfile($base, $path);
171    }
172   
173    return $path;
[b8d7413]174}
175
[6473c3b]176sub sync {
[19233f5]177    my $self = shift;
[6473c3b]178    my $url = shift;
179    my $dir = shift;
[19233f5]180   
181    if (-d "$dir") {
182        local $CWD = $dir;
[19df400]183        print "fetch ", $dir, "\n";
[19233f5]184        Git::Repository->run(fetch => '--all');
185        return $self;
186    }
187   
[19df400]188    print "clone ", $dir, "\n";
[6f31bfb]189    mkpath $dir;
[6473c3b]190    Git::Repository->run(clone => '--mirror' => $url => $dir);
191   
192    return $self;
193}
194
195sub clone_git {
196    my $self = shift;
197   
198    my $dir = $self->directory . '.git';
199    my $url = $self->{clone_url};
200   
201    $self->sync($url => $dir);
202   
[19233f5]203    return $self;
204}
205
[55d0513]206sub forks {
[682d2d9]207    my $self = shift;
208    return $self->{forks} if ($self->{forks});
209   
[fc647d5]210    $self->{forks} = utils::get("/repos/" . $self->{full_name} . "/forks");
[682d2d9]211   
[55d0513]212    return $self->{forks};
[682d2d9]213}
214
[19233f5]215sub set_forks {
216    my $self = shift;
[682d2d9]217   
218    my $dir = $self->directory . '.git';
219    local $CWD = $dir;
220   
221    my $remotes = Git::Repository->run(branch => '--remotes');
[6473c3b]222    my @fetch;
[55d0513]223    foreach my $fork (@{$self->forks}) {
[682d2d9]224        if ($remotes =~ /$fork->{full_name}/) {
225            print "skip ", $fork->{full_name}, "\n";
226            next;
227        }
228        print "add ", $fork->{full_name}, "\n";
229        Git::Repository->run(remote => add => $fork->{full_name} => $fork->{clone_url});
[6473c3b]230        push @fetch, $fork->{full_name};
[682d2d9]231    }
232   
[6473c3b]233    foreach my $fork (@fetch) {
234        print "fetch ", $fork, "\n";
235        Git::Repository->run(fetch => $fork);
236    }
[682d2d9]237   
238    return $self;
[19233f5]239}
240
241sub clone_wiki {
242    my $self = shift;
[6473c3b]243   
244    my $dir = $self->directory . '.wiki.git';
245    my $url = 'https://github.com/' . $self->{full_name} . '.wiki.git';
246   
247    $self->sync($url => $dir);
248   
249    return $self;
[19233f5]250}
251
[55d0513]252sub issues {
253    my $self = shift;
254    return $self->{issues} if ($self->{issues});
255   
256    my $open   = utils::get("/repos/" . $self->{full_name} . "/issues");
257    my $closed = utils::get("/repos/" . $self->{full_name} . "/issues", state => 'closed');
258   
259    if ($open)   { push @{$self->{issues}}, @$open }
260    if ($closed) { push @{$self->{issues}}, @$closed }
261   
262    return $self->{issues};
263}
264
[19233f5]265sub save_issues {
266    my $self = shift;
[55d0513]267   
268    $self->issues;
[19233f5]269}
[6a2e5f1]270
[19df400]271sub backup {
272    my $self = shift;
273   
274    $self->clone_git;
275    $self->set_forks;
276    $self->clone_wiki;
277    $self->save_issues;
278   
279    return $self;
280}
[6a2e5f1]281
282
2831;
284__END__
Note: See TracBrowser for help on using the repository browser.