Skip to content

Instantly share code, notes, and snippets.

@cowboy
Created April 12, 2011 21:19
Show Gist options
  • Save cowboy/916434 to your computer and use it in GitHub Desktop.
Save cowboy/916434 to your computer and use it in GitHub Desktop.
Ruby: Clone Yer GitHub Repos, Fast!
# /usr/bin/env ruby
puts <<-EOF
Clone Yer GitHub Repos, Fast! - v0.2.1 - 4/13/2011
http://benalman.com/
For when you're on a new computer and need all your stuff, fast!
EOF
copyright = <<-EOF
Copyright (c) 2011 "Cowboy" Ben Alman
Dual licensed under the MIT and GPL licenses.
http://benalman.com/about/license/
EOF
help = <<-EOF
Usage:
ruby #{File.basename($0)} [ filter [, filter... ] ]
Notes:
* All forks are cloned into a "forks" subdir.
* Pre-existing repos are skipped.
* Any filter arg can contain ? and * wildcard characters. Wrap args in quotes
if * is used!
EOF
# User wants help? User gets help.
if !ARGV.empty? && %w{-h --help}.find {|a| a == ARGV[0]}
puts "\n#{help}\n#{copyright}"
exit
end
# Handle ctrl-c abort.
trap('INT') do
puts "\nAborted!"
exit 1
end
user = '' # Set this if you don't want to be asked every time!
puts "\n" if user.empty?
while user.empty?
print 'GitHub username: '
user = STDIN.gets.chomp
end
puts <<-EOF
If you would like private repos to be cloned, you can enter the password for
GitHub user "#{user}" now.
If this is the wrong user, press Ctrl-C, and try again.
Note that this password is only used to authenticate to GitHub for downloading
private repos, and is not stored anywhere. If you don't have any private repos,
just press ENTER.
EOF
print 'GitHub password: '
# Get password. Should be invisible on systems that support stty, YMMV.
system 'stty -echo'
pass = STDIN.gets.chomp
system 'stty echo'
require 'open-uri'
require 'json'
require 'fileutils'
# Fetch and parse user JSON.
print "\n\nFetching repository list... "
options = pass.empty? ? {} : {:http_basic_authentication => [user, pass]}
json = open("http://github.com/api/v1/json/#{user}", options).read
data = JSON.parse(json)
# Create an array of filters from command line arguments, converting wildcard
# * and ? chars to their regex equivalent.
filters = ARGV.map do |a|
Regexp.new('^' + Regexp.escape(a).gsub(/\\\*/, '.*').gsub(/\\\?/, '.') + '$')
end
# If args were passed, filter out any repos whose names don't match any of the
# passed args.
repos = data['user']['repositories'].select do |r|
filters.empty? || filters.find {|re| r['name'] =~ re}
end.compact
# No matching repos? FAIL.
if repos.empty?
puts "No repos found, exiting!"
exit 1
end
puts "#{repos.length} repo#{repos.length == 1 ? '' : 's'} found.\n\n"
# Clone all matching repos that haven't already been cloned.
repos.each do |r|
path = (r['fork'] ? 'forks/' : '') + r['name']
uri = "git@github.com:#{user}/#{r['name']}.git"
if File.exist?(path)
puts "Skipping #{path} (clone already exists).\n"
else
unless system %Q{git clone "#{uri}" "#{path}"}
# Cleanup potentially broken git clone.
FileUtils.rm_rf path
puts "\nAn error or abort ocurred!"
exit 1
end
end
end
puts "\nDone!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment