/
github-backup.pl
executable file
·120 lines (95 loc) · 3.08 KB
/
github-backup.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/usr/bin/perl
# Copy bare GitHub repositories to local machine (including wikis).
# Source: https://github.com/jreisinger/varia/blob/master/github-backup.pl
use strict;
use warnings;
use LWP::Simple qw(get);
use JSON;
use Cwd;
use File::Spec;
use File::Copy qw(move);
use File::Path qw(rmtree);
use POSIX qw(strftime);
use Getopt::Long;
use autodie;
# Option to clone a normal repository, not a bare one
my $nomirror = ''; # create mirror (bare repository) by default
my $wiki = ''; # don't clone wikis by default
usage() unless GetOptions( 'nomirror' => \$nomirror, 'wiki' => \$wiki );
# Where to clone repos (last command line argument)
my $dest_dir = pop @ARGV;
usage() unless defined $dest_dir and -d $dest_dir;
# Github users to backup
my @usernames = @ARGV;
usage() unless @usernames > 0;
# Get all repos for the username
my $FAILED;
for my $username (@usernames) {
print "\n> Working on user '$username'\n";
# Prepare destination dir
my $dest_dir = File::Spec->catfile( $dest_dir, $username );
my $time = strftime "%F_%T", localtime $^T;
my $backup_dir = "$dest_dir.$time";
if ( -d $dest_dir ) {
move($dest_dir, $backup_dir);
}
mkdir $dest_dir or die "Can't create '$dest_dir': $!";
for my $repo ( @{ get_repo_info($username) } ) {
my $name = $repo->{'name'};
my $ssh_url = $repo->{'ssh_url'};
my $has_wiki = $repo->{'has_wiki'};
print ">> Working on repo '$name'\n";
# Repo
clone_repo( $ssh_url, $dest_dir );
# Wiki
if ( $has_wiki eq 'true' and $wiki ) {
( my $wiki_url = $ssh_url ) =~ s#\.git$#.wiki.git#;
# Returns error if wiki is enabled but is empty
clone_repo( $wiki_url, $dest_dir );
}
}
if ($FAILED) {
warn "\nSome repos ($FAILED of them) of $username were not cloned,
backup it at $backup_dir\n";
} else {
rmtree($backup_dir);
}
}
sub usage {
die
"Usage: $0 [ --nomirror --wiki ] username1 [ username2 ... usernameN ] existing_dir\n";
}
sub get_repo_info {
## Return array ref containig HoH.
my $username = shift;
# API v3
use Net::SSL;
use LWP::UserAgent;
my $ua = LWP::UserAgent->new(
ssl_opts => { verify_hostname => 0 },
);
my $url = "https://api.github.com/users/$username/repos";
my $response = $ua->get($url);
my $html = $response->content;
#my $html = get($url);
die "Couldn't get data from $url\n" unless defined $html;
my $decoded_json = decode_json $html;
# One array ref field has info on one repo.
return $decoded_json;
}
sub clone_repo {
my $repo_url = shift;
my $dest_dir = shift;
my $old_dir = getcwd();
chdir $dest_dir if getcwd ne $dest_dir;
my $git_cmd = "git clone --quiet --mirror $repo_url";
$git_cmd = "git clone --quiet $repo_url" if $nomirror;
if ( system $git_cmd ) {
# Return wasn't zero, meaning failure
$FAILED++;
warn "'$repo_url' NOT cloned!\n";
} else {
print "'$repo_url' cloned to $dest_dir.\n";
}
chdir $old_dir;
}