Creating a Homebrew formula for standalone application - macos

I'm trying to create a homebrew formula for an application that doesn't need to be compiled. I've tried looking through the formula cookbook, but I'm missing something to make things properly work. Below is my use-case with more generic filenames.
Inside the container is two files: one is the script for the application, the other being a file for man pages. We'll use the following filenames to keep things generic:
myapp.py (executable script)
resource.txt (a resource file that the script needs)
myapp.1 (man page)
What are the best ways to get these into the correct locations? Presume I have the ability to modify the code in the script for choosing the location to load the resource.
Thanks.

You can either modify your script at install time to use the correct location of the resource or just assume it’s in the same directory and let Homebrew do the magic for you. I wrote an example formula for the latter case in another answer.
Here’s how it looks like for your needs:
class Foo < Formula
desc "Blah blah"
url "https://github.com/foo/foo/archive/master.zip"
version "1.2.3"
def install
man1.install "myapp.1"
libexec.install Dir["*"]
bin.write_exec_script (libexec/"myapp.py")
end
end
It installs myapp.1 in the correct directory. You can also use man2, man3, etc for other man directories.
It then installs all the remaining files under libexec then create an exec script in bin/myapp.py. This will be a simple shell script that execs your script in libexec. That way, your script will executes from libexec and thus will be able to find resource.txt that’s located in the same directory.
If you’d like to call it myapp and not myapp.py it’d look like that:
def install
man1.install "myapp.1"
libexec.install "resource.txt"
libexec.install "myapp.py" => "myapp"
bin.write_exec_script (libexec/"myapp")
end

Related

How do I not have a duplicated custom bash script directory on my machine and add it as a link that is picked up with PATH?

I have a /.cust_dev_cmds/ directory on my MBP machine that is part of a parent sysadmin-work directory that uses a git repo here. I would like to be able to:
Not have to use a for loop in my .bash_profile to source all the *.sh files.
Add the directory to PATH with and export line in the .bash_profile instead.
# from my .bash_profile
export PATH="/Users/<my-usr-name>/Public/sharable-dev-scripts:$PATH"
This does show up with a echo $PATH but when I try to invoke a function from within the scripts I have created that worked with sourcing directly within the .bash_profile in a loop (like with point #1 above) like this
# create a directory with a builtin command
mkdir test-dir
# use one of my custom ones to create a simple readme.md within that directory:
mkr !!:1
# I am getting >>> mkr: command not found
Use whatever type of link to not have a duplicated directory structure on the machine.
Any good explanations to read up on here without using $10 words would be great.
Define a means to test the link works and works through PATH. It would also be nice that something like declare -F would be available to see that the scripts within the directory are in fact becoming part of callable functions in the shell.
is there a command anyone knows to do this?
Step this up a notch for a shared network directory. I have created a shared directory through apple > System Preferences > Sharing, and turned on the ability to share this directory in the Public folder.
Is there a tutorial that can outline this with something like VirtualBox and an Ubuntu guest that is accessing the commands from the MBP shared directory?
I have realized point #1, so really the question begins with #2 so no one would suggest the first one. I have read a bit on links but the way most of the articles I come across describing them are difficult to wrap my head around- especially when wishing to add this functionality to PATH. I believe the answer may revolve around how links are followed, but it may be better to back up and punt- dig back into linking first- then export my directory appropriately without a link, and eventually get the proper resolution to this situation.
The last thought on links before I try a few hacks on my own is do I need to only add a link to the Public directory and somehow place a flag to look at all the directories within the /Public, or is it better to drill all the way down to the /Public/shared-directory/.cust_dev_cmds? Any direction would be greatly appreciated. My goal is to be able to have a few custom command directories for various tasks, and eventually have them across networks/instances.
When you want all functions that you wrote in files in /.cust_dev_cmds/, the normal way would be sourcing all the files.
When you want to avoid a loop, you can use
utildir="$HOME/.cust_dev_cmds/" # I think the path is relative to your home).
source <(cat ${utildir}/*)
When you want the functions found with the PATH, you should make a file for each function.
Before:
# cat talk
ask() { echo "How are you?"; }
answer() { echo "Fine, thank you"; }
After:
# cat ask
echo "How are you?"
# cat answer
echo "Fine, thank you"
When you want all users to use the same set of functions, consider a master script that sources all scripts (the masterfile can use user=dependent settings like HOME or VERSION):
# cat /Public/shared-directory/setup_functions
utildir="$HOME/.cust_dev_cmds/" # I think the path is relative to your home).
source <(cat ${utildir}/*)
source some_other_file
Now each user only needs to source one file.

How to programmatically decompress .tar.xz file (without intermediates) in ruby running on ubuntu 14.04?

SO...
I am writing a ruby script to initialize a production host in order to run an application (create user groups, users, SSH keys, etc.) and I am stuck on installing NPM / Node. I don't want to use a package manager to install it, but rather simply grab the .tar.xz file for the version I want (in this case, 6.9.1) and unpack it to a location I want with the binaries added to my path. Currently, we will get this from Node downloads...
I have found this SO answer that I am using to try and get my script working. It looks like Ruby does not have an out of the box way to handle ".xz" files, but my Ubuntu distribution does have a later version of tar so it can handle "tar -xJf ...". I was thinking to do something along the lines of...
require 'fileutils'
require 'open-uri'
uri = "https://nodejs.org/dist/v6.9.1/node-v6.9.1-linux-x64.tar.xz"
source = open(uri)
data = system("cat", IO.binread(source), "|", "tar", "-xJf", "-")
# put data where I want using FileUtils
...I could definitely get this working with an intermediate file and more system commands (or even just a curl call for that matter, but I am trying to not use system calls where possible). I see there are Gems that I can use such as this, but I would like to not include any dependencies. Any thoughts on achieving an elegant solution?
system is too weak. You want IO::popen for this.
IO.popen(['tar', '-xJC', target_dir, '-f', '-'], 'wb') do |io|
io.write(IO.binread(source))
end
popen will open a subprocess, and give you io connected to its stdin/stdout. No need for FileUtils, -C option tells tar where to put stuff.

Cannot understand folder structure for ruby project in linux

I am learning rspec and cucumber from the book - The Rspec book. This question is not about those two things. It is more about linux. My book gives me instructions which make no sense. Please help me to understand it.
Create a bin in the project root directory (sibling to lib and spec), and add a bin/codebreaker file. If you’re on a *nix system, enter this code in that file:
#!/usr/bin/env ruby
$LOAD_PATH.unshift File.expand_path( '../../lib' , __FILE__)
require 'codebreaker'
game = Codebreaker::Game.new(STDOUT)
game.start
Shouldn't that be a bin/codebreaker folder ? Anyway, I made a folder bin, under project root. I also made a file bin/codebreaker.rb with the above code and continued.
If you’re on *nix, now run chmod +x bin/codebreaker so we can execute
it, and then run this:
$ bin/codebreaker
Welcome to Codebreaker!
Enter guess:
Now look at that! Who knew that this little bit of code was actually going to start to make something work?
I don't get the above output when I go to project root and execute bin/codebreaker from there. I only see this output -
bash: bin/codebreaker: Is a directory
Am I missing something ? How do I make this work ?
The instructions tell you to create a file named codebreaker. However, you created a file named codebreaker.rb, not codebreaker. In addition to the file named codebreaker.rb which you weren't supposed to create, you also created a directory named codereaker which you also weren't supposed to create.
I don't know CodeBreaker, but the instructions you posted should work, although they are a little ugly (e.g. manually fiddling with $LOAD_PATH instead of simply using require_relative). Just follow them. Or if you do deviate from them as you did with naming your file codebreaker.rb instead of codebreaker, then you must of course also adapt all further instructions to that change, e.g. for example running bin/codebreaker.rb instead of bin/codebreaker.

Do a global file search

Is there any way in Ruby where I can do a global search for a given file?
I tried Dir.glob but it searches in the current directory. And for the Find module I need to pass a list of directories to search. In my case, I need to search for a particular file which might be in any directory.
How can I do this in Ruby?
Find recurses into subdirectories, so just start at the root path, it'll go everywhere:
Find.find('/') do |path|
# look for your filename
end
On systems that have the locate command line tool, like Linux and Mac OSX, you can find files very fast like this:
filename = "test"
array_of_files_found = `locate #{filename}`.split("\n")
Be aware of the dangers of passing user-supplied parameters to the command line. See this answer for details
Also note that on OSX, you might need to create the database that powers the locate command like this:
sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.locate.plist

How to make open sourced scripts 'installable'?

I've finished a little useful script written in Bash, hosted on github. It's tested and documented. Now, I struggle with how to make it installable, i.e. where should I put it and how.
It seems other such projects use make and configure but I couldn't really find any information on how to do this for bash scripts.
Also I'm unsure into which directory to put my script.
I know how to make it usable by myself but if a user downloads it, I want to provide the means for him to install it easily.
There is no standard for this because most of the time, a project isn't a single script file. Also single file scripts don't need a build step (the script is already in an executable form) and configuration usually comes from an external config file (so no need for a configure script, either).
But I suggest to add a comment near the top of the file which explains what it does and how to install it (i.e. chmod +x + copy to folder).
Alternatively, you could create an installer script which contains your original script plus a header which asks the user where she wants to install the real script and which does everything (mkdir, set permissions with sudo, etc) but it really feels like overkill in your case.
If you want to make it installable so the package manager can easily install and remove (!) it, you need to look at the documentation for rpm or Debian packaging. These are the two most used package managers but they can't install a script per-user (so it would probably end up in /usr/bin)
instruct them to create a file named after the script in their home directory, chmod ug+x the file so it has executable permissions than put the script inside the file, don't forget the #!/bin/bash up top of the vim. This example is a script to copy a file, archive the copied file than remove the copied file leaving only the original file and the archived file.
#!/bin/bash
#### The following will copy the desired file
cp -r /home/wes/Documents/Hum430 /home/wes/docs
#### Next archives the copied file
tar -zcvf Hum430.tar.gz /home/wes/docs
#### and lastly removes the un-archived copy leaving only the original and the archived file.
rm -r /home/wes/docs
### run the file with ./filename (whatever the file is named)

Resources