summaryrefslogtreecommitdiff
path: root/tool/vcs.rb
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-11-09 06:20:57 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-11-09 06:20:57 +0000
commitae6f7929bdd0956019657e14c7e873e5ed5e4d4a (patch)
treee5fb02f5c6a68df63f46acb85ae3004b76148edd /tool/vcs.rb
parent671707b5460e4fef2d2a9dd5832fb5a50e5c9178 (diff)
vcs.rb: split
* tool/vcs.rb: split from file2lastrev.rb. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@43609 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'tool/vcs.rb')
-rw-r--r--tool/vcs.rb102
1 files changed, 102 insertions, 0 deletions
diff --git a/tool/vcs.rb b/tool/vcs.rb
new file mode 100644
index 0000000..e7cb610
--- /dev/null
+++ b/tool/vcs.rb
@@ -0,0 +1,102 @@
+# vcs
+
+ENV.delete('PWD')
+
+unless File.respond_to? :realpath
+ require 'pathname'
+ def File.realpath(arg)
+ Pathname(arg).realpath.to_s
+ end
+end
+
+class VCS
+ class NotFoundError < RuntimeError; end
+
+ @@dirs = []
+ def self.register(dir)
+ @@dirs << [dir, self]
+ end
+
+ def self.detect(path)
+ @@dirs.each do |dir, klass|
+ return klass.new(path) if File.directory?(File.join(path, dir))
+ prev = path
+ loop {
+ curr = File.realpath(File.join(prev, '..'))
+ break if curr == prev # stop at the root directory
+ return klass.new(path) if File.directory?(File.join(curr, dir))
+ prev = curr
+ }
+ end
+ raise VCS::NotFoundError, "does not seem to be under a vcs: #{path}"
+ end
+
+ def initialize(path)
+ @srcdir = path
+ super()
+ end
+
+ # return a pair of strings, the last revision and the last revision in which
+ # +path+ was modified.
+ def get_revisions(path)
+ path = relative_to(path)
+ last, changed, *rest = Dir.chdir(@srcdir) {self.class.get_revisions(path)}
+ last or raise "last revision not found"
+ changed or raise "changed revision not found"
+ return last, changed, *rest
+ end
+
+ def relative_to(path)
+ if path
+ srcdir = File.realpath(@srcdir)
+ path = File.realpath(path)
+ list1 = srcdir.split(%r{/})
+ list2 = path.split(%r{/})
+ while !list1.empty? && !list2.empty? && list1.first == list2.first
+ list1.shift
+ list2.shift
+ end
+ if list1.empty? && list2.empty?
+ "."
+ else
+ ([".."] * list1.length + list2).join("/")
+ end
+ else
+ '.'
+ end
+ end
+
+ class SVN < self
+ register(".svn")
+
+ def self.get_revisions(path)
+ begin
+ nulldevice = %w[/dev/null NUL NIL: NL:].find {|dev| File.exist?(dev)}
+ if nulldevice
+ save_stderr = STDERR.dup
+ STDERR.reopen nulldevice, 'w'
+ end
+ info_xml = `svn info --xml "#{path}"`
+ ensure
+ if save_stderr
+ STDERR.reopen save_stderr
+ save_stderr.close
+ end
+ end
+ _, last, _, changed, _ = info_xml.split(/revision="(\d+)"/)
+ [last, changed]
+ end
+ end
+
+ class GIT < self
+ register(".git")
+
+ def self.get_revisions(path)
+ logcmd = %Q[git log -n1 --grep="^ *git-svn-id: .*@[0-9][0-9]* "]
+ idpat = /git-svn-id: .*?@(\d+) \S+\Z/
+ last = `#{logcmd}`[idpat, 1]
+ changed = path ? `#{logcmd} "#{path}"`[idpat, 1] : last
+ [last, changed]
+ end
+ end
+end