tags:

views:

118

answers:

8

I've got a Perl script that as one of its final steps creates a compressed version of a file it has created. Due to some unfortunate setups, we cannot guarantee that a given customer will have a specific compression function. I want to put something like this together:

if ($has_jar) {
    system("jar -c $compressed_file $infile");
}
elsif ($has_zip) {
    system("zip -j $compressed_file $infile");
}
else {
    copy($infile, $compressed_file);
}

Where if they don't have either of the compression apps, it will just copy the file into the location of the compressed file without compressing it.

My sticky wicket here is that I'm not quite sure what the best way is to determine if they have jar or zip. It looks like I can used exec() instead of system() and take advantage of the fact that it only returns if it fails, but the script actually does do a couple of things after this, so that wouldn't work.

I also need this to be a portable solution as this script runs on both Windows and various Unix distros. Thanks in advance.

+1  A: 

Look through the directories specified by the PATH environment variable.

Paul Nathan
Yeah, that would work, although I was definitely hoping for something more "slick."
Morinar
There is nothing more slick. Either you try to run the executable, and report failure or see if there is a suitable executable in the path, try to run it **and** report any failures.
Sinan Ünür
+2  A: 

For *nix based systems, this should work:

my $has_jar = `which jar` ne '';

This could potentially work for Windows as well if you include which.

Alternatively, you could try the command suggested by this answer,

my $has_jar = `for %i in (jar.exe) do @echo.   %~$PATH:i` ne '';

It most likely doesn't return '' if it doesn't find it, however, but I don't have Perl available on a Windows machine to test it out.

Sebastian P.
That would definitely work on the *nix systems, but I don't really have the ability to include which on the Windows installs. If it was that easy, I'd just bundle zip with the app and not have this question in the first place.
Morinar
In that case, I added another potential, but untested, solution.
Sebastian P.
+1  A: 

Usually, things like that don't suddenly disappear from the system, so I suggest to check the presence of the tools during setup/installation and save the one to use in the config.

Aaron Digulla
Good idea, but it's not really an option due to the way we patch customers and the way things are setup.
Morinar
+1  A: 

How about just try to run the program. If it can't be run, then you know there's a problem.

John Saunders
+1  A: 

Why not use the Archive::Zip package to do the compression, eliminating the need for an external program altogether?

Rob K
It's not a package we require our customers to have and trying to get it on all their machines is a lesson in futility. Trust me, this is pretty much my only option and I need to find a way to make it work.
Morinar
If you're already requiring them to have non-default packages, what's the problem with requiring this one?
Rob K
+4  A: 

I think your best bet is File::Which.

innaM
Also not a bad idea, although once again, our customers don't have that package installed and getting it to all of them is not a trivial task.
Morinar
Then you might as well simply "steal" the code.
innaM
Morinar: you can bundle it
Alexandr Ciornii
Correct, in a perfect world. I just know that another developer here pushed on our config team to get XML::Simple bundled as part of our patch and we have customers having issues with it almost a year later.
Morinar
+2  A: 

See my multi-which.

Sinan Ünür
Oooh, I like that. Relatively simple and easy to integrate into my existing script. Barring something crazy, I'll most likely be using this.
Morinar
Just implemented this and everything is working exact as I want it to... I know this is a similar answer to Paul Nathan's, but Sinan provided a pretty great piece of code to work from.Thanks for all the solutions everyone, far more than I had anticipated.
Morinar
@Morinar Thank you.
Sinan Ünür
+1  A: 

There are a couple of things to think about if you are going to do this:

  • Use system and exec in the list form so the shell doesn't get a chance to interpret special characters.

  • Can you store this as configuration instead of putting it in the code? See how CPAN.pm does it, for instance.

  • How do you know that you are running what you think you are running? If someone makes a trojan horse of the same name, is your program going to happily execute it? Note that using the PATH, as noted in Sinan's multi-which, still has this problem since it relies on the user setting the PATH.

brian d foy
That's definitely good advice all the way around. I changed my calls to system to use list form as I independently discovered the same thing. I really can't store this in any configuration as we just don't have a mechanism in place, and no, there is no way to know what I'm running or not. While I agree that that is probably a concern, the environments that our application runs on are generally quite controlled and sanitary so having a trojan or similar dropped in isn't really a concern here.
Morinar