[前][次][番号順一覧][スレッド一覧]

ruby-changes:56530

From: Hiroshi <ko1@a...>
Date: Mon, 15 Jul 2019 09:40:44 +0900 (JST)
Subject: [ruby-changes:56530] Hiroshi SHIBATA: 0a711b0edf (master): Put vcs .rb to under the lib direcotory.

https://git.ruby-lang.org/ruby.git/commit/?id=0a711b0edf

From 0a711b0edff6eaf978cfc17cdd6a7cc6c17c6686 Mon Sep 17 00:00:00 2001
From: Hiroshi SHIBATA <hsbt@r...>
Date: Mon, 15 Jul 2019 08:34:24 +0900
Subject: Put vcs .rb to under the lib direcotory.

  Because it's the common library for tool files.

diff --git a/tool/file2lastrev.rb b/tool/file2lastrev.rb
index e39e742..68c660e 100755
--- a/tool/file2lastrev.rb
+++ b/tool/file2lastrev.rb
@@ -7,7 +7,7 @@ require 'optparse' https://github.com/ruby/ruby/blob/trunk/tool/file2lastrev.rb#L7
 
 # this file run with BASERUBY, which may be older than 1.9, so no
 # require_relative
-require File.expand_path('../vcs', __FILE__)
+require File.expand_path('../lib/vcs', __FILE__)
 
 Program = $0
 
diff --git a/tool/lib/vcs.rb b/tool/lib/vcs.rb
new file mode 100644
index 0000000..dd6162c
--- /dev/null
+++ b/tool/lib/vcs.rb
@@ -0,0 +1,669 @@ https://github.com/ruby/ruby/blob/trunk/tool/lib/vcs.rb#L1
+# vcs
+require 'fileutils'
+require 'optparse'
+
+# This library is used by several other tools/ scripts to detect the current
+# VCS in use (e.g. SVN, Git) or to interact with that VCS.
+
+ENV.delete('PWD')
+
+unless File.respond_to? :realpath
+  require 'pathname'
+  def File.realpath(arg)
+    Pathname(arg).realpath.to_s
+  end
+end
+
+def IO.pread(*args)
+  STDERR.puts(args.inspect) if $DEBUG
+  popen(*args) {|f|f.read}
+end
+
+if RUBY_VERSION < "2.0"
+  class IO
+    @orig_popen = method(:popen)
+
+    if defined?(fork)
+      def self.popen(command, *rest, &block)
+        if command.kind_of?(Hash)
+          env = command
+          command = rest.shift
+        end
+        opts = rest.last
+        if opts.kind_of?(Hash)
+          dir = opts.delete(:chdir)
+          rest.pop if opts.empty?
+          opts.delete(:external_encoding)
+        end
+
+        if block
+          @orig_popen.call("-", *rest) do |f|
+            if f
+              yield(f)
+            else
+              Dir.chdir(dir) if dir
+              ENV.replace(env) if env
+              exec(*command)
+            end
+          end
+        else
+          f = @orig_popen.call("-", *rest)
+          unless f
+            Dir.chdir(dir) if dir
+            ENV.replace(env) if env
+            exec(*command)
+          end
+          f
+        end
+      end
+    else
+      require 'shellwords'
+      def self.popen(command, *rest, &block)
+        if command.kind_of?(Hash)
+          env = command
+          oldenv = ENV.to_hash
+          command = rest.shift
+        end
+        opts = rest.last
+        if opts.kind_of?(Hash)
+          dir = opts.delete(:chdir)
+          rest.pop if opts.empty?
+          opts.delete(:external_encoding)
+        end
+
+        command = command.shelljoin if Array === command
+        Dir.chdir(dir || ".") do
+          ENV.replace(env) if env
+          @orig_popen.call(command, *rest, &block)
+          ENV.replace(oldenv) if oldenv
+        end
+      end
+    end
+  end
+else
+  module DebugPOpen
+    verbose, $VERBOSE = $VERBOSE, nil if RUBY_VERSION < "2.1"
+    refine IO.singleton_class do
+      def popen(*args)
+        STDERR.puts args.inspect if $DEBUG
+        super
+      end
+    end
+  ensure
+    $VERBOSE = verbose unless verbose.nil?
+  end
+  using DebugPOpen
+  module DebugSystem
+    def system(*args)
+      STDERR.puts args.inspect if $DEBUG
+      exception = false
+      opts = Hash.try_convert(args[-1])
+      if RUBY_VERSION >= "2.6"
+        unless opts
+          opts = {}
+          args << opts
+        end
+        exception = opts.fetch(:exception) {opts[:exception] = true}
+      elsif opts
+        exception = opts.delete(:exception) {true}
+        args.pop if opts.empty?
+      end
+      ret = super(*args)
+      raise "Command failed with status (#$?): #{args[0]}" if exception and !ret
+      ret
+    end
+  end
+  module Kernel
+    prepend(DebugSystem)
+  end
+end
+
+class VCS
+  prepend(DebugSystem) if defined?(DebugSystem)
+  class NotFoundError < RuntimeError; end
+
+  @@dirs = []
+  def self.register(dir, &pred)
+    @@dirs << [dir, self, pred]
+  end
+
+  def self.detect(path, options = {}, argv = ::ARGV)
+    uplevel_limit = options.fetch(:uplevel_limit, 0)
+    curr = path
+    begin
+      @@dirs.each do |dir, klass, pred|
+        if pred ? pred[curr, dir] : File.directory?(File.join(curr, dir))
+          vcs = klass.new(curr)
+          vcs.parse_options(argv)
+          return vcs
+        end
+      end
+      if uplevel_limit
+        break if uplevel_limit.zero?
+        uplevel_limit -= 1
+      end
+      prev, curr = curr, File.realpath(File.join(curr, '..'))
+    end until curr == prev # stop at the root directory
+    raise VCS::NotFoundError, "does not seem to be under a vcs: #{path}"
+  end
+
+  def self.local_path?(path)
+    String === path or path.respond_to?(:to_path)
+  end
+
+  attr_reader :srcdir
+
+  def initialize(path)
+    @srcdir = path
+    super()
+  end
+
+  def parse_options(opts, parser = OptionParser.new)
+    case opts
+    when Array
+      parser.on("--[no-]dryrun") {|v| @dryrun = v}
+      parser.on("--[no-]debug") {|v| @debug = v}
+      parser.parse(opts)
+      @debug = $DEBUG unless defined?(@debug)
+      @dryrun = @debug unless defined?(@dryrun)
+    when Hash
+      unless (keys = opts.keys - [:debug, :dryrun]).empty?
+        raise "Unknown options: #{keys.join(', ')}"
+      end
+      @debug = opts.fetch(:debug) {$DEBUG}
+      @dryrun = opts.fetch(:dryrun) {@debug}
+    end
+  end
+
+  attr_reader :dryrun, :debug
+  alias dryrun? dryrun
+  alias debug? debug
+
+  NullDevice = defined?(IO::NULL) ? IO::NULL :
+    %w[/dev/null NUL NIL: NL:].find {|dev| File.exist?(dev)}
+
+  # return a pair of strings, the last revision and the last revision in which
+  # +path+ was modified.
+  def get_revisions(path)
+    if self.class.local_path?(path)
+      path = relative_to(path)
+    end
+    last, changed, modified, *rest = (
+      begin
+        if NullDevice
+          save_stderr = STDERR.dup
+          STDERR.reopen NullDevice, 'w'
+        end
+        _get_revisions(path, @srcdir)
+      rescue Errno::ENOENT => e
+        raise VCS::NotFoundError, e.message
+      ensure
+        if save_stderr
+          STDERR.reopen save_stderr
+          save_stderr.close
+        end
+      end
+    )
+    last or raise VCS::NotFoundError, "last revision not found"
+    changed or raise VCS::NotFoundError, "changed revision not found"
+    if modified
+      /\A(\d+)-(\d+)-(\d+)\D(\d+):(\d+):(\d+(?:\.\d+)?)\s*(?:Z|([-+]\d\d)(\d\d))\z/ =~ modified or
+        raise "unknown time format - #{modified}"
+      match = $~[1..6].map { |x| x.to_i }
+      off = $7 ? "#{$7}:#{$8}" : "+00:00"
+      match << off
+      begin
+        modified = Time.new(*match)
+      rescue ArgumentError
+        modified = Time.utc(*$~[1..6]) + $7.to_i * 3600 + $8.to_i * 60
+      end
+    end
+    return last, changed, modified, *rest
+  end
+
+  def modified(path)
+    _, _, modified, * = get_revisions(path)
+    modified
+  end
+
+  def relative_to(path)
+    if path
+      srcdir = File.realpath(@srcdir)
+      path = File.realdirpath(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
+
+  def after_export(dir)
+  end
+
+  def revision_name(rev)
+    self.class.revision_name(rev)
+  end
+
+  def short_revision(rev)
+    self.class.short_revision(rev)
+  end
+
+  class SVN < self
+    register(".svn")
+    COMMAND = ENV['SVN'] || 'svn'
+
+    def self.revision_name(rev)
+      "r#{rev}"
+    end
+
+    def self.short_revision(rev)
+      rev
+    end
+
+    def _get_revisions(path, srcdir = nil)
+      if srcdir and local_path?(path)
+        path = File.join(srcdir, path)
+      end
+      if srcdir
+        info_xml = IO.pread(%W"#{COMMAND} info --xml #{srcdir}")
+        info_xml = nil unless info_xml[/<url>(.*)<\/url>/, 1] == path.to_s
+      end
+      info_xml ||= IO.pread(%W"#{COMMAND} info --xml #{path}")
+      _, last, _, changed, _ = info_xml.split(/revision="(\d+)"/)
+      modified = info_xml[/<date>([^<>]*)/, 1]
+      branch = info_xml[%r'<relative-url>\^/(?:branches/|tags/)?([^<>]+)', 1]
+      [last, changed, modified, branch]
+    end
+
+    def self.search_root(path)
+      return unless local_path?(path)
+      parent = File.realpath(path)
+      begin
+        parent = File.dirname(wkdir = parent)
+        return wkdir if File.directory?(wkdir + "/.svn")
+      end until parent == wkdir
+    end
+
+    def get_info
+      @info ||= IO.pread(%W"#{COMMAND} info --xml #{@srcdir}")
+    end
+
+    def url
+      unless @url
+        url = get_info[/<root>(.*)<\/root>/, 1]
+        @url = URI.parse(url+"/") if url
+      end
+      @url
+    end
+
+    def wcroot
+      unless @wcroot
+        info = get_info
+        @wcroot = info[/<wcroot-abspath>(.*)<\/wcroot-abspath>/, 1]
+        @wcroot ||= self.class.search_root(@srcdir)
+      end
+      @wcroot
+    end
+
+    def branch(name)
+      return trunk if name == "trunk"
+      url + "branches/#{name}"
+    end
+
+    def tag(name)
+      url + "tags/#{name}"
+    end
+
+    def trunk
+      url + "trunk"
+    end
+    alias master trunk
+
+    def branch_list(pat)
+      IO.popen(%W"#{COMMAND} ls #{branch('')}") do |f|
+        f.each do |line|
+          line.chomp!
+          line.chomp!('/')
+          yield(line) if File.fnmatch?(pat, line)
+        end
+      end
+    end
+
+    def grep(pat, tag, *files, &block)
+      cmd = %W"#{COMMAND} cat"
+      files.map! {|n| File.join(tag, n)} if tag
+      set = block.binding.eval("proc {|match| $~ = match}")
+      IO.popen([cmd, *files]) do |f|
+        f.grep(pat) do |s|
+          set[$~]
+          yield s
+         (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]