Skip to content

Instantly share code, notes, and snippets.

@koshigoe
Created February 24, 2012 18:20
Show Gist options
  • Save koshigoe/1902618 to your computer and use it in GitHub Desktop.
Save koshigoe/1902618 to your computer and use it in GitHub Desktop.
clone svn:externals
#!/usr/bin/env ruby
#
# Inspired by https://github.com/andrep/git-svn-clone-externals
#
# MIT License http://koshigoe.mit-license.org
#
require 'fileutils'
module Git
class Svn
CABINET = '.git_externals'
def initialize
@url ||= `git svn info | grep '^URL: ' | cut -d' ' -f2`.chomp
@cwd = File.expand_path '.'
unless system("grep -q '#{CABINET}/*' .git/info/exclude")
open('.git/info/exclude', 'a') do |output|
output.puts "\n#{CABINET}/*"
end
end
end
def clone_externals
each_externals do |property|
puts "clone: #{property[:path]}#{property[:name]}"
checkout_to = "#{CABINET}/#{property[:path]}#{property[:name]}"
link_to = "#{property[:path]}#{property[:name]}"
next if File.exists?(checkout_to)
begin
FileUtils.mkdir_p File.dirname(checkout_to)
if system("git svn clone #{revision(property[:source])} #{property[:source]} #{checkout_to}")
FileUtils.ln_s File.expand_path(checkout_to), link_to, :force => true
unless system("grep -q '#{link_to}' .git/info/exclude")
open('.git/info/exclude', 'a') do |output|
output.puts "\n#{link_to}"
end
end
end
rescue => e
$stderr.puts e.inspect
end
end
end
def rebase_externals
Dir["#{CABINET}/**/.git"].each do |path|
Dir.chdir(File.dirname(path)) do
puts "rebase: #{Dir.pwd}"
system("git svn rebase")
end
end
end
def fetch_externals
Dir["#{CABINET}/**/.git"].each do |path|
Dir.chdir(File.dirname(path)) do
puts "fetch: #{Dir.pwd}"
system("git svn fetch")
end
end
end
protected
def each_externals
@_cursor = nil
IO.popen('git svn show-externals') do |io|
while line = io.gets
line.chomp!
if %r{\A# /(.+)\z} =~ line
@_cursor = $1
elsif @_cursor && line.size > 0
yield parse_property(line)
end
end
end
end
def parse_property(line)
if %r|\A/#{@_cursor}([^\s]+) (.+)\z| =~ line
source, name = $1, $2
source, name = name, source if name.include? '/'
if %r{\A(?:/|\.)} =~ source
path = File.expand_path("#{@_cursor}#{source}").sub("#{@cwd}/", '')
source = "#{@url}/#{path}"
end
{
:path => @_cursor,
:source => source,
:name => name,
}
else
raise ArgumentError, "Invalid property: #{line}"
end
end
def revision(url)
'-' + `LANG=C svn log -l1 #{url}|awk '{if(NR==2){ print $1 }}'`.chomp
end
end
end
unless File.exists? '.git'
raise '.git not found.'
end
def help
$stderr.puts <<EOF
usage: git-svn-externals <subcommand>
Available subcommands:
clone
rebase
fetch
help
EOF
exit
end
case ARGV.first
when 'clone'
Git::Svn.new.clone_externals
when 'rebase'
Git::Svn.new.rebase_externals
when 'fetch'
Git::Svn.new.fetch_externals
when 'help'
help
else
help
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment