source: lab.git/Dev/github/GitHubBackup.pm @ 6473c3b

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

sync wiki pages

  • Property mode set to 100644
File size: 5.2 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
[19233f5]24
[6a2e5f1]25package GitHubBackup;
26
27use strict;
28use warnings;
29use utf8;
30use Carp qw(croak);
[6f31bfb]31use File::Spec;
[6a2e5f1]32
33
34# both hash and hashref are acceptable
35sub new {
36    my $class = shift;
37    my $args = (ref $_[0] eq 'HASH') ? $_[0] : {@_};
[19233f5]38   
[6f31bfb]39    return bless $args, $class;
[6a2e5f1]40}
41
[19df400]42sub account {
43    my $self = shift;
44    my $args = shift;
45   
46    if (defined $args) {
47        $self->{repos} = undef;
48        $self->{account} = $args;
49    }
50   
51    return $self->{account};
52}
53
54sub repository {
55    my $self = shift;
56    my $args = shift;
57   
58    if (defined $args) {
59        $self->{repos} = undef;
60        $self->{repository} = $args;
61    }
62   
63    return $self->{repository};
64}
65
[6f31bfb]66sub directory {
67    my $self = shift;
68    my $args = shift;
69   
70    if (defined $args) {
71        $self->{directory} = File::Spec->rel2abs($args);
72    }
73   
74    return $self->{directory};
75}
76
[6a2e5f1]77sub repos {
78    my $self = shift;
[19233f5]79    return $self->{repos} if ($self->{repos});
[6a2e5f1]80   
81    my $account = $self->account or croak "account is not set";
82    if (my $repository = $self->repository) {
83        $self->{repos} = [
[19233f5]84            GitHubBackup::Repository->new({
[b8d7413]85                directory => sub {$self->directory},
[19233f5]86                full_name => "$account/$repository",
87            })
[6a2e5f1]88        ];
89       
90        return $self->{repos};
91    }
92   
93    my $page = 1;
94    my @repos;
95    while (1) {
96        my $result = utils::json_api("/users/$account/repos?per_page=100&page=$page");
97        if (ref($result) eq 'ARRAY' && scalar @$result > 0) {
98            push @repos, @$result;
99            $page++;
100           
101            next;
102        }
103        last;
104    }
105   
106    foreach my $repos (@repos) {
107        push @{$self->{repos}},
108            GitHubBackup::Repository->new({
[b8d7413]109                directory => sub {$self->directory},
[6a2e5f1]110                full_name => $repos->{full_name},
111                clone_url => $repos->{clone_url},
112            })
113        ;
114    }
115   
116    return $self->{repos};
117}
118
[19df400]119sub backup {
120    my $self = shift;
121   
122    foreach my $repos (@{$self->repos}) {
123        $repos->backup;
124    }
125   
126    return $self;
127}
128
[6a2e5f1]129
130package GitHubBackup::Repository;
131
132use strict;
133use warnings;
134use utf8;
135use Carp qw(croak);
[19233f5]136use Git::Repository;
137use File::chdir;
[6f31bfb]138use File::Spec;
139use File::Path qw(mkpath);
[b8d7413]140
[19233f5]141sub new {
142    my $class = shift;
143    my $args  = shift;
144   
145    if (! exists $args->{clone_url}) {
146        my $result = utils::json_api('/repos/' . $args->{full_name});
147        $args->{clone_url} = $result->{clone_url};
148    }
149   
[6f31bfb]150    return bless $args, $class;
[19233f5]151}
152
[b8d7413]153sub directory {
154    my $self = shift;
155   
[6f31bfb]156    my $path = $self->{full_name};
157    if (my $base = $self->{directory}->()) {
158        $path = File::Spec->catfile($base, $path);
159    }
160   
161    return $path;
[b8d7413]162}
163
[6473c3b]164sub sync {
[19233f5]165    my $self = shift;
[6473c3b]166    my $url = shift;
167    my $dir = shift;
[19233f5]168   
169    if (-d "$dir") {
170        local $CWD = $dir;
[19df400]171        print "fetch ", $dir, "\n";
[19233f5]172        Git::Repository->run(fetch => '--all');
173        return $self;
174    }
175   
[19df400]176    print "clone ", $dir, "\n";
[6f31bfb]177    mkpath $dir;
[6473c3b]178    Git::Repository->run(clone => '--mirror' => $url => $dir);
179   
180    return $self;
181}
182
183sub clone_git {
184    my $self = shift;
185   
186    my $dir = $self->directory . '.git';
187    my $url = $self->{clone_url};
188   
189    $self->sync($url => $dir);
190   
[19233f5]191    return $self;
192}
193
[682d2d9]194sub get_forks {
195    my $self = shift;
196    return $self->{forks} if ($self->{forks});
197   
198    my $page = 1;
199    while (1) {
200        my $result = utils::json_api("/repos/" . $self->{full_name} . "/forks?per_page=100&page=$page");
201        if (ref($result) eq 'ARRAY' && scalar @$result > 0) {
202            push @{$self->{forks}}, @$result;
203            $page++;
204           
205            next;
206        }
207        last;
208    }
209   
210    return $self;
211}
212
[19233f5]213sub set_forks {
214    my $self = shift;
[682d2d9]215   
216    $self->get_forks;
217   
218    my $dir = $self->directory . '.git';
219    local $CWD = $dir;
220   
221    my $remotes = Git::Repository->run(branch => '--remotes');
[6473c3b]222    my @fetch;
[682d2d9]223    foreach my $fork (@{$self->{forks}}) {
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
252sub save_issues {
253    my $self = shift;
254}
[6a2e5f1]255
[19df400]256sub backup {
257    my $self = shift;
258   
259    $self->clone_git;
260    $self->set_forks;
261    $self->clone_wiki;
262    $self->save_issues;
263   
264    return $self;
265}
[6a2e5f1]266
267
2681;
269__END__
Note: See TracBrowser for help on using the repository browser.