Skip to content
This repository

Search $PATH for a binary rather than shelling out to `which` #1573

Merged
merged 1 commit into from over 2 years ago

6 participants

Aaron Patterson Erik Michaels-Ober Yehuda Katz Xavier Noria Frederick Ros Brad Folkens
Aaron Patterson
Collaborator

I'm trying to speed up startup time for rake environment (on rails). Creating subshells came up on my list, so I'm trying to eliminate them.

This patch changes Bundler to search the PATH environment variable rather than shelling out to which. The function isn't 100% perfect as it doesn't handle "./sudo" the same way the shell does, but our input for this function is known so I don't think it matters.

Erik Michaels-Ober
Collaborator

Looks good. Thanks for your continued work on Rails performance improvements.

Erik Michaels-Ober sferik merged commit 36c9f92 into from December 02, 2011
Erik Michaels-Ober sferik closed this December 02, 2011
Yehuda Katz

@tenderlove - just curious... did you benchmark the difference (i.e. is the newer code actually faster than shelling out)?

Erik Michaels-Ober
Collaborator

@fxn addressed your nitpick in 26fa77a.

Xavier Noria
Collaborator

@sferik that was fast :).

Aaron Patterson
Collaborator

@wycats

require 'rubygems'
require 'benchmark/ips'

def sand_which cmd
  `which #{cmd}`
end

def blair_which cmd
  if File.executable? cmd
    cmd
  else
    path = ENV['PATH'].split(File::PATH_SEPARATOR).find { |path|
      File.executable? File.join(path, cmd)
    }
    path && File.expand_path(cmd, path)
  end
end

Benchmark.ips do |x|
  x.report("sand") { sand_which 'sudo' }
  x.report("blair") { blair_which 'sudo' }
end
[aaron@higgins git]$ ruby lol.rb 
                sand      251.0 (±4.8%) i/s -       1265 in   5.051489s (cycle=23)
               blair     3222.0 (±8.2%) i/s -      16218 in   5.076616s (cycle=306)
[aaron@higgins git]$

It's over 10x faster. Probably because the one that shells out has to shell out.

Frederick Ros

That's a pitty: I proposed the same change on 2011-11-03 (#1516)... Today, nobody even had a look at it :(
Happy to see it merged by another channel, but kind of puzzled with the way mine has been handled ... Definitively not a way to encourage people to participate.

Brad Folkens

ENV['PATH'] is sometimes nil and breaks in a production environment I have with Passenger... Can we change it to ENV['PATH'].to_s or something to avoid that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 1 unique commit by 1 author.

Dec 02, 2011
Aaron Patterson Search $PATH for a binary rather than shelling out to `which` d3a69d3
This page is out of date. Refresh to see the latest.

Showing 1 changed file with 12 additions and 1 deletion. Show diff stats Hide diff stats

  1. 13  lib/bundler.rb
13  lib/bundler.rb
@@ -229,7 +229,7 @@ def requires_sudo?
229 229
 
230 230
       path = bundle_path
231 231
       path = path.parent until path.exist?
232  
-      sudo_present = !(`which sudo` rescue '').empty?
  232
+      sudo_present = which "sudo"
233 233
       bin_dir = Pathname.new(Bundler.system_bindir)
234 234
       bin_dir = bin_dir.parent until bin_dir.exist?
235 235
 
@@ -246,6 +246,17 @@ def mkdir_p(path)
246 246
       end
247 247
     end
248 248
 
  249
+    def which(binary)
  250
+      if File.executable? binary
  251
+        binary
  252
+      else
  253
+        path = ENV['PATH'].split(File::PATH_SEPARATOR).find { |path|
  254
+          File.executable? File.join(path, binary)
  255
+        }
  256
+        path && File.expand_path(binary, path)
  257
+      end
  258
+    end
  259
+
249 260
     def sudo(str)
250 261
       `sudo -p 'Enter your password to install the bundled RubyGems to your system: ' #{str}`
251 262
     end
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.