Homebrew formula - renaming files on install - ruby

i have the following homebrew formulaL
class Software < Formula
desc "Software"
homepage "https://blabla"
version "1.6.0"
if OS.mac? && Hardware::CPU.intel?
url "https://blabla/releases/download/v1.6.0/software-darwin-10.12-amd64"
sha256 "ce02a97fb95aca9bba44413d4158f5f2c182f5eb2823bedf1400f556bb9b"
end
if OS.mac? && Hardware::CPU.arm?
url "https://blabla/releases/download/v1.6.0/software-darwin-10.12-arm64"
sha256 "1c69849ba82c10d15706d110ae63bd97c387da2a8cf925653e1bb5c6fc"
end
if OS.linux? && Hardware::CPU.intel?
url "https://blabla/releases/download/v1.6.0/software-linux-amd64"
sha256 "9b7245823a60c85e027929b776753848d4fbdaaa333a49ae171684893"
end
def install
bin.install "software*" => "software"
end
test do
system "#{bin}/software --version"
end
end
The problematic part is:
def install
bin.install "software*" => "software"
end
The files that get downloaded depends on which OS a user is on
before installation. I want to automatically find the downloaded file (whatever the name is), hence why I am trying to use a regex as bin.install "software"* with a star to find the downloaded file and install it as software
however, I get an error stating software* cannot be found
please how would I rectify this issue?

Some Suggestions (But See Caveats Below)
Per the Homebrew bin.install documentation, the purpose of bin.install is to rename a file within the formula's location within the Cellar, and the key doesn't seem to accept either a glob or a regex. However, since you have the full power of Ruby available to you in addition to the Homebrew formula DSL, you might consider doing something like the following:
def install
binfile_with_extension =
File.basename(Dir.glob "#{prefix}/bin/software*")
bin.install binfile_with_extension => "software"
end
This of course assumes there's only one software-* executable. If there's more than one, then you may need to do something to return value of the glob (which should be an Array) to select the correct one for your architecture.
Alternatively, rather than renaming the file itself, you may simply want to symlink it so that you aren't changing something the application might expect. The documentation says that you have full access to both FileUtils and the DSL's bin.install_symlink method, so you might consider using some combination of those instead. For example, to create a hardlink in the cellar for your architecture-named file, then symlink it into the correct bin directory using relative symlinks, the following should work:
def install
file = Dir.glob("#{prefix}/bin/software*").first
FileUtils.ln file, "#{prefix}/bin/software"
bin.install_symlink bin/"software"
end
There may be better Homebrew-native options for renaming symlinks differently from the file they link to, but I was unable to find one. That doesn't mean one doesn't exist, though.
Additionally, whether or not hardlinking or symlinking is necessary in the first place depends on the application. Some applications care about the name they are invoked by (think busybox as an example) while others don't. YMMV.
Caveats
I'm not currently a Homebrew developer, so there may be other or better ways to do this. Nevertheless, a combination of Ruby globs and the Hombrew DSL features should get you where you want to go.
Please do note that I haven't tested this myself, so the suggestions above may or may not work without tweaking. I offer it simply as a place to start since I don't think bin.install is intended to do what you want by itself.

Related

Access downloaded files in a formula's test block

I'm creating a Homebrew formula for a C library that includes its own test suite. As part of the test block for the formula, I'd like to run the tests that are included with the downloaded files. The tests run as a make target (make test). However, Homebrew test blocks run in their own temporary directory and the downloaded files are not in the path. That is, the following doesn't work because it can't find the files:
test do
system "make", "test"
end
How can I access the location into which the files were originally downloaded and unpacked? I haven't been able to find any information about that in the docs. Or is there a better solution for Homebrew tests in this case?
The test do block is meant to test if a formula has correctly been installed, not to run test suits. If the tests don’t take too long you can run them as part of the install:
def install
# ...
system "make", "test"
# ...
end
To answer your question there’s no reliable way to get the original unpacked directory because it’s destroyed after install and the user may have deleted the cached tarball (with e.g. brew cleanup) so you’d have to re-download it.
A solution is to copy the necessary test files somewhere during the install step then use them directly or copy them in the current directory when testing, e.g.:
def install
# ...
libexec.install "tests"
end
test do
cp_r (libexec/"tests"), "."
cd "tests" do
# I’m assuming the Makefile's paths can be given
# as variables here.
system "make", "test", "LIB=#{lib}", "INCLUDE=#{include}"
end
end

From a Ruby Gem, how can I get the directory path to the project?

Suppose I am developing a Ruby gem that will be installed in a project by being added to its gemfile. From my gem, I want to know the root directory path to the project. How can I get that?
There is no perfect solution to this problem but you could create a fallback based solution that would work in most general cases. If Rails is defined, we use Rails.root. If Bundler is defined, we use the Bundler.root but it would only work when the Gemfile is defined at the project root (which is true in most cases). Else fallback to Dir.pwd
def project_root
if defined?(Rails)
return Rails.root
end
if defined?(Bundler)
return Bundler.root
end
Dir.pwd
end
If you're using Rails, use Rails.root.
If you don't know the 'main project' is Rails... there isn't neccesarily a great way to do it.
Global $0 is the command name that the ruby script was invoked with. But this won't neccesarily include a path. You can try File.expand_path $0, but there are a very many reasons that would cause this to not give you what you want, including the program may have changed it's "working directory". Dir.pwd will give you the "current working directory", which may be the directory of the "project" only if the project was invoked from the "project directory" and the code hasn't changed the current working directory.
In general, there's actually no build-in notion of a "project" or "project directory" in ruby -- you can have a ruby script that isn't really part of a project at all, it's just a file living wherever in the file system you want.
I don't think there's a general reliable way to do this, it depends on how "the project" was set up, which of course a gem can't be sure of.
But if you're using Rails, Rails.root, because Rails has conventions for how it's set up and invoked, and implements the feature Rails.root in it's startup processes to record the Rails 'project directory'.

Detect if executable exists on system path with node

Question
Is there a simple way to tell if a system executable is available on the system path using node? For example if a user has python installed at /usr/bin/python and /usr/bin is in $PATH how can I detect that in Node? And conversely detect when something isn't installed or is just not on path, i.e. /usr/opt/local/mycustompath/python? Ideally hoping their is an npm package available ...
I'm sure this is a quick google search with the right search term, but I'm failing due to the fact where and which are pretty generic search terms.
Background
I'm working on some dev config for a node tool and would like to be able to detect whether python (or pip) is already available on path, and if not, ask the user to tell install it or tell us where to find it. I'm currently planning on doing this with where on windows machines and which on *nix machines, but was hoping there might be a single cross platform way of doing this.
Package hasbin has since been published to the npm registry, which provides this functionality:
Install it (as part of your project) with npm install hasbin
To test the availability of Python, use it as follows (do not append .exe to the executable file name):
var isPyAvailable = require('hasbin').sync('python')
The package has various other helpful methods, such as the ability to find the first available binary among several - see its GitHub repository.
Zero dependencies+ simple + stupid == 👇🏻
const { execSync } = require('child_process');
const shell = (cmd) => execSync(cmd, { encoding: 'utf8' });
function executableIsAvailable(name){
try{ shell(`which ${name}`); return true}
catch(error){return false}
}
// Then use it
executableIsAvailable('docker-compose') // true
executableIsAvailable('python') // true
executableIsAvailable('mvn') // false
Suppose no one run nodejs in windows at this era!
You have to find a way to do it, as there is no "generic" or "out-of-box" way to do it.
One way is, you can use check if the desired package/binary is installed via your package manager then you can use utility whereis which attempts to locate the desired program in a list of standard Linux places, listed in $PATH.
Of course you can use also the utility which but whereis provides a bit more information. You can check about the difference of which and whereis here.
Generally speaking, as in your example, user might has manually installed some package at some random location, but not listed in $PATH.
In this way there is no way to check if the package is installed at all, rather than to try to find the binary name or related files in complete tree of file system.

How to I load a gem from source?

I have git cloned a repo from Github, now I want to experiment with it, as in I want to poke around the code and mess with it. I've created a file test.rb that should load this gem, but I want to load my locally checked out version, what's the right way to do this?
Right now I'm just using a bunch of "require_relative 'the_gem_name/lib/file'", which feels wrong.
When you require 'foo' Ruby checks all the directories in the load path for a file foo.rb and loads the first one it finds. If no file named foo.rb is found, and you’re not using Rubygems, a LoadError is raised.
If you are using Rubygems (which is likely given that it is included in Ruby 1.9+), then instead of immediately raising a LoadError all the installed Gems are searched to see if one contains a file foo.rb. If such a Gem is found, then it is added to the load path and the file is loaded.
You can manipulate the load path yourself if you want to ensure a particular version of a library is used. Normally this isn’t something that’s recommended, but this is the kind of situation that you’d want to do it.
There are two ways of adding directories to the load path. First you can do it in the actual code, using the $LOAD_PATH (or $:) global variable:
$LOAD_PATH.unshift '/path/to/the/gems/lib/'
require 'the_gem'
Note that you normally want to add the lib dir of the gem, not the top level dir of the gem (actually this can vary depending on the actual Gem, and it’s possible to need to add more than one dir, but lib is the norm).
The other way is to use the -I command line switch to the ruby executable:
$ ruby -I/path/to/the/gems/lib/ test.rb
This way might be a bit cleaner, as normally you don’t want to be messing with the load path from inside your code, but if you’re just testing the library it probably doesn’t matter much.
Following apneadiving's suggestion in the comments, I created a Gemfile and added this line
source "http://rubygems.org"
gem 'gem_name', path: '~/path/to/gem/source/folder'
Then bundle install, and bundle exec ruby test.rb and it worked.

Is it possible Ruby installation by copying the ruby folder?

This is a very silly question...
I have a doubt regarding the ruby installation. Will the ruby be installed in a windows server if we copy the Ruby187 folder from another server and add that in the PATH of the environment variable?
Or Do we need to install the Ruby from the installer always, in order to install it ?
Thanks in advance
I actually did something similar to this yesterday at work. A fellow co-worker, who does not have Ruby installed on their system, needs the ability to run my scripts while I am on vacation. So, I copied the entire Ruby folder from my C: to a shared network drive.
You will not only have to add the path to the Ruby folder to your PATH variable but you also may want to associate the Ruby extension .rb with Ruby. Not needed but just a thought.
One issue I ran into was here at work we don't have permission to alter our PATH variable manually. So, in order for my co-worker to launch the scripts I needed ran, I wrote a small C++ app that merely run a command line call to the Ruby interpreter and then to the script to run.
So, in short, yes, it is possible. =)
EDIT: In regards to why you would add the path to the Ruby installation to the PATH variable, it is so you can call Ruby from the command line with simply C:\>ruby some_script.rb. Without that added to your PATH, you'd need to type the entire path every time like C:\>C:\ruby192\bin\ruby some_script.rb. However, you'd still need to type "ruby" first.
In regards to the association of ".rb" files to the Ruby Interpreter, it is an option while installing Ruby on Windows using the installer provided at ruby-lang.org. With that, you would not need to type "ruby" before the script name on the command line. C:\>some_script.rb would work. I don't know exactly how to do this with a network version of Ruby but one way might be to right-click on a ".rb" file, choose "Open with..." and locate the Ruby.exe file in \ruby192\bin\ruby.exe.
I hope that explains what you were asking about in the comments.

Resources