views:

145

answers:

2

Using a ruby file (or any rake facility) I need to find out if the user who executes my script is able to execute certain shell commands. In particular g++ etc. Hopefully system independent so if there is some g++.bat, g++.exe or just g++ (etc) it should say yes nevertheless, as long as its on the path and executable on the users system.

Example: if the user has a no-extention executable version of the file and a .cmd version of the file it should say "yes" for the no extension version on a linux system and "yes" to the .cmd version on a windows system. Since the users shell can only execute that version of the file.

The purpose of this is to allow the script to be self-configuring (as much as possible).

Any suggestions on how I might go about doing this?

+2  A: 

Well, File contains both exists? and executable?. ENV['PATH'] gets the directories executables are in (at least on *nix - can someone confirm for Windows?). Combine the two with a bit of magic and you should have a solution.

Edit:

irb(main):001:0> ENV['PATH'].split(':').collect {|d| Dir.entries d if Dir.exists? d}.flatten.include? 'adduser'
=> true
irb(main):002:0> ENV['PATH'].split(':').collect {|d| Dir.entries d if Dir.exists? d}.flatten.include? 'foo'
=> false
Xiong Chiamiov
Only in 1.9 (but that is not a problem). The problem is scanning the path does not really tell the difference between scripts. For example, I can execute "g++ --version" but giving g++ as input will yield false. Now I could test for a partial match, but that can cause problems on its own, I don't feel its worth the quirks.
srcspider
Sorry, what do you mean by "the difference between scripts"? `ENV['PATH'].split(':').collect {|d| Dir.entries d if Dir.exists? d}.flatten.include? 'g++'` returns true on my machine.
Xiong Chiamiov
I tested it on windows xp, and it didn't work. Had the following line in a file: puts ENV['PATH'].split(':').collect {|d| Dir.entries d if Dir.exists? d}.flatten.include? 'gcc'. Returned false. From the command line gcc --version is: gcc (TDM-2 mingw) 4.4.1 and ruby --version is: ruby 1.9.1p376.
srcspider
I think that the PATH separator on Windows is `;`, rather than `:`. If you pop into `irb` and take a look at `ENV['PATH']` you'll find out.
Xiong Chiamiov
+2  A: 

A quick and dirty way is to simply attempt to execute g++ via the system command and check the return code, for example:

def gpp_exists
  return system("g++ --version")
end

You'd have to do some trickery to avoid getting unwanted output on the console (e.g. redirecting stdout/stderr based on correct OS syntax), but it couldn't be too bad.

maerics
Mm, I considered that, but was put off by `system "g++"` returning false. Didn't consider `--version`, which is a good idea, and, while more specific, better imo than my approach.
Xiong Chiamiov
+1. Usually, the best way to check whether or not you can run some executable is to just run the damn executable. After all, even *if* you check that it exists *and* that it is executable *and* that it is in the path, there are still a ton of reasons why it wouldn't work: permissions, resource restrictions, wrong library versions, a corrupted executable due to a filesystem error, not enough memory ...
Jörg W Mittag
In Rake there is a command sh which works pretty much like system above. That's what I've experimented with, as it can pass to the block the result to and status, but my two problems with it are that first of all you're assuming --version there, and should I not pass anything I would be assuming it exits; and second I can't seem to think of a (universal) way of preventing output to the shell used to execute the script.
srcspider
@srcspider, redirecting output from the shell can be done as follows in UNIX `g++ --version > /dev/null 2> so you just need to detect the OS family then append the appropriate redirection strings.
maerics
@maerics, I think I can "finesse" a solution to my problem with that and might just work pretty well for what I'm trying to do.With regard to detecting OS family I can do that easily though the instantiated application object: Rake.application.windows? and Rake.application.unix? Possible simply assume unix syntax will work should it not be windows as the implementation is a little funcky (http://rake.rubyforge.org/classes/Rake/Application.html#M000093). I'm going to tag your question as the answer, but your comment is really the true answer.
srcspider