rakelib/scm.rb
changeset 85 6d918f722075
parent 81 2a1efb99c83d
child 88 112075e99cef
--- a/rakelib/scm.rb	Thu Nov 24 20:22:25 2016 +0000
+++ b/rakelib/scm.rb	Thu Nov 24 20:47:41 2016 +0000
@@ -6,6 +6,22 @@
 module Rake::StX
 end
 
+# Cross-platform way of finding an executable in the $PATH.
+#
+#   which('ruby') #=> /usr/bin/ruby
+def which(cmd)
+  exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
+  ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
+    exts.each { |ext|
+      exe = File.join(path, "#{cmd}#{ext}")
+      return exe if File.executable?(exe) && !File.directory?(exe)
+    }
+  end
+  return nil
+end
+
+cvs_rsh_set = false
+
 module Rake::Stx::SCM
   # Not quite sure why following code
   #
@@ -22,6 +38,60 @@
     end
   end
 
+  # Make sure CVS_RSH environment variable is properly set. Prefer MSYS2 ssh.exe
+  # over plink.exe. For details, see `hglib.rb`, method `sshconf()`  
+  module_function
+  def ensure_cvs_rsh_set()        
+    if @cvs_rsh_set then
+      return
+    end
+    ssh = nil
+    ssh_configured = ENV['CVS_RSH']    
+    ssh_in_path = which('ssh') ? true : false
+    plink_in_path = which('plink') ? true : false
+    if Gem.win_platform? then                        
+      # If CVS_RSH is not set or is set to plink.exe, try to change to 
+      # MSYS2 ssh.exe as it gives better performance on (fast) LANs.      
+      if /^.*[pP]link(\.exe)?"?\s*(-ssh)?\s*(-2)?$/ =~ ssh_configured then            
+        if ssh_in_path then
+          ssh = 'ssh'
+        else 
+          if (File.exist? "c:\\msys64\\usr\\bin\\ssh.exe") then              
+            ssh = "\"c:\\msys64\\usr\\bin\\ssh.exe\""
+          end
+        end
+        # Sigh, we should not tamper with SSH configuration wildly. User may have
+        # her ssh and mercurial properly configured to use `plink.exe` and `pageant`.
+        # If we just start using `ssh.exe` clone/pull might not work beause
+        # `ssh.exe` cannot talk to `pageant`. So, if we don't find OpenSSH's 
+        # style of agent, don't use `ssh.exe` event if available.
+        if ssh then
+          if ENV['SSH_AUTH_SOCK'] then
+            # Good, OpenSSH agent running but still, be nice and  tell the 
+            # user SSH configuration has been tampered wirh. 
+            info("Setting CVS_RSH=\"#{ssh}\" for faster transfers")
+          else 
+            # No agent, no fun. Be nice and give user a hit
+            warn("Not using CVS_RSH=\"#{ssh}\" option because SSH agent is not running")
+            warn("For faster CVS checkout over LAN, consider using ssh-agent or ssh-pageant (if you want to use PuTTY's pageant)")
+            ssh = nil
+          end
+        end
+      end       
+    else                 
+      if not ssh_configured then
+        ssh = "ssh"
+      end
+    end
+    if ssh then 
+      ENV['CVS_RSH'] = ssh
+    end
+    cvs_rsh_set = true
+  end
+
+
+  public
+
   class CheckoutException < Exception
   end # class CheckoutException
 
@@ -120,6 +190,7 @@
   end
 
   def self._update_cvs(repository, directory, branch, root, **kwargs)
+    ensure_cvs_rsh_set()
     wc = root / directory
     if File.directory? wc
       if not sh %W{cvs -z 9 update -A -d}, cwd: wc
@@ -169,7 +240,7 @@
 
   end
 
-  def self._checkout_svn(repository, directory, branch, root, **kwargs)
+  def self._checkout_svn(repository, directory, branch, root, **kwargs)    
     url = "#{repository.canonical}/#{directory}/#{branch}"
     if not sh %W{svn --non-interactive --trust-server-cert co #{url} #{directory}}, cwd: root
       raise CheckoutException.new("SVN: Cannot checkout from #{url}")
@@ -223,6 +294,7 @@
   end
 
   def self._checkout_cvs(repository, directory, branch, root, **kwargs)    
+    ensure_cvs_rsh_set()
     if not sh %W{cvs -z 9 -d #{repository.canonical} co #{directory}}, cwd: root
       raise CheckoutException.new("CVS: Cannot checkout #{directory}from #{repository.url}")
     end