-
-
Save alloy/77795 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'time' | |
git = ARGV.shift | |
svn = ARGV.shift | |
class Git2SVN | |
def initialize(git, svn) | |
@git = git | |
@svn = svn | |
@repo = File.expand_path File.join(@svn, "repo") | |
@scratch = File.expand_path File.join(@svn, "scratch") | |
@rev_data = File.join(@svn, "last_revs.yaml") | |
end | |
def sh(cmd) | |
puts "CMD: #{cmd}" | |
system cmd | |
end | |
def create_svn | |
return if File.exist?(@repo) | |
sh "svnadmin create #{@repo}" | |
sh "echo '#!/bin/sh\\nexit 0\\n' > #{@repo}/hooks/pre-revprop-change" | |
sh "chmod a+x #{@repo}/hooks/pre-revprop-change" | |
end | |
def create_scratch | |
return if File.exist?(@scratch) | |
clone_git | |
sh "svn co file://#{@repo} tmp" | |
sh "mv tmp/.svn #{@scratch}" | |
end | |
def clone_git | |
sh "git clone #{@git} #{@scratch}" | |
end | |
def enter | |
Dir.chdir @scratch | |
end | |
def load_data | |
if File.exists?(@rev_data) | |
@last_revs = YAML.load @rev_data | |
else | |
@last_revs = [] | |
end | |
@current_revs = `git rev-list --all`.split("\n").reverse | |
end | |
def save_data | |
File.open(@rev_data, "w") do |f| | |
f << @last_revs.to_yaml | |
end | |
end | |
def outstanding_revs | |
@current_revs - @last_revs | |
end | |
def set_rev(rev) | |
sh "git reset --hard #{rev}" | |
end | |
Commit = Struct.new(:hash, :when, :tree, :parent, :author, :committer, :log) | |
def current_info | |
data = `git cat-file commit HEAD`.split("\n") | |
c = Commit.new | |
c.hash = `git rev-parse HEAD`.strip | |
c.tree = data.shift.split(" ",2).last | |
c.parent = data.shift.split(" ",2).last | |
com = data.shift.split(" ",2) | |
m = /(.*) (\d+) [+-]\d+/.match(com.last) | |
c.author = m[1] | |
c.when = Time.gm *Time.at(m[2].to_i).to_a | |
c.committer = data.shift.split(" ",2).last | |
data.shift | |
c.log = data.join("\n") | |
return c | |
end | |
def write_log(c) | |
File.open("current-log", "w") do |f| | |
f.puts c.log | |
end | |
end | |
def fix_props(c, rev) | |
sh "svn propset -r #{rev} --revprop svn:author '#{c.author}'" | |
sh "svn propset -r #{rev} --revprop svn:date '#{c.when.xmlschema(6)}'" | |
sh "svn propset -r #{rev} --revprop git:hash '#{c.hash}'" | |
end | |
def drive_changes | |
dirs = {} | |
stats = `git diff-tree --name-status -t -r --root HEAD`.split("\n") | |
stats.shift | |
stats.each do |line| | |
stat, name = line.split(/\s+/, 2) | |
case stat | |
when "A" | |
dir = File.dirname(name).split("/") | |
dir.shift if dir.first == "." | |
path = nil | |
until dir.empty? | |
if path.nil? | |
path = dir.shift | |
else | |
path = File.join(path, dir.shift) | |
end | |
unless dirs[path] | |
if /^\?/.match(`svn status '#{path}'`) | |
`svn add '#{path}' 2>&1` | |
end | |
dirs[path] = true | |
end | |
end | |
`svn add --force '#{name}' 2>&1` | |
when "D" | |
`svn rm '#{name}'` | |
when "M", "T" | |
# noop | |
else | |
raise "Unknown status '#{stat}'" | |
end | |
end | |
end | |
def update | |
sh "git pull" | |
revs = outstanding_revs() | |
revs.each_with_index do |rev, idx| | |
puts "=== #{rev} (#{idx + 1}/#{revs.size}) ===" | |
set_rev rev | |
drive_changes() | |
c = current_info() | |
write_log(c) | |
m = /Committed revision (\d+)/.match(`svn commit -F current-log`) | |
fix_props(c, m[1].to_i) if m | |
end | |
end | |
end | |
g = Git2SVN.new "~/git/test", "." | |
g.create_svn | |
g.create_scratch | |
g.enter | |
g.load_data | |
g.update |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment