Deploying Homebrew through casper.

WesWhet
Release Candidate Programs Tester

We are looking to use homebrew to make installing some things easier. Has anyone done a mass deploy of Homebrew?

13 REPLIES 13

timsutton
Contributor

Mass-deploying Homebrew sounds a pain, but you might find this helpful if you want to deploy a set of specific dependencies/"brews":

https://github.com/timsutton/brew-pkg

It's a simple homebrew command plugin I wrote to make it easier to build an installer package out of something already built with Homebrew.

hkim
Contributor II

I don't understand why this should be difficult, the pre req is XCode with Command Line Tools, and then it's a simple terminal command,

ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"

Am I missing something here?

timsutton
Contributor

Installer scripts are simple too, just run a file called "postinstall" - no deployment issues, right?

I know the installation is simple, but there may be assumptions of a single local user, since that's who it's developed for. The issue of it taking ownership of /usr/local by a single user is one that I think would make it a pain in certain environments. Yes, it can be installed elsewhere, but they caution heavily against it, and you'd need to do more work to support it.

From the OP there's no explanation of the target environment/use case. If your target is developers / researchers who need tools compiled but aren't admins, and you give them write access to /usr/local, maybe this is all just fine.

hkim
Contributor II

I was going to go on a rant about how MacPorts blah blah blah but again to each their own. Yes I can see that being a PITA with homebrew (actually I never loved using brew because of some of these exact issues).

Throwing a chmod 777 on /usr/local/brew isn't going to cut it I assume.

That all being said, this just screams to me to use puppet to deploy homebrew

timsutton
Contributor

No, chmodding 777 /usr/local might in fact resolve any issues, if that's acceptable.

In the coming months, Homebrew is setting up a CI infrastructure from Kickstarter funding to actually provide binaries for almost everything, so that should make it a more interesting/usable alternative to MacPorts.

WesWhet
Release Candidate Programs Tester

@hkim. I already tried running that command. The installer script can't be run as root and in that script it prompts for the user to hit enter. (I'm attempting to modify their Ruby script ATM to possibly work with Casper)

@timsutton. Thanks! I'll take a look and get back to you. We want to use Homebrew to install www.rsyslog.com otherwise trying to install rsyslog is a nightmare.

timsutton
Contributor

tayworm in ##osx-server reported that he was running that Homebrew install command in a script run by Munki (which is running as root), and that Homebrew appeared to be installed properly.

If you'd want to track him down or read more, you can see the log here:

http://osx.michaellynn.org/freenode-osx-server/freenode-osx-server_2013-02-11.html

ooadmin
New Contributor

OK…I made this work. There are a few steps, but here goes:

1st, I edited the perl script that brew uses to install itself to remove the pesky "Press ENTER" part. Here's the text of the edited script, which I saved as InstallHomebrew.sh:

#!/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby
# This script installs to /usr/local only. To install elsewhere you can just
# untar https://github.com/mxcl/homebrew/tarball/master anywhere you like or
# change the value of HOMEBREW_PREFIX.
HOMEBREW_PREFIX = '/usr/local'

module Tty extend self
  def blue; bold 34; end
  def white; bold 39; end
  def red; underline 31; end
  def reset; escape 0; end
  def bold n; escape "1;#{n}" end
  def underline n; escape "4;#{n}" end
  def escape n; "�33[#{n}m" if STDOUT.tty? end
end

class Array
  def shell_s
    cp = dup
    first = cp.shift
    cp.map{ |arg| arg.gsub " ", "\ " }.unshift(first) * " "
  end
end

def ohai *args
  puts "#{Tty.blue}==>#{Tty.white} #{args.shell_s}#{Tty.reset}"
end

def warn warning
  puts "#{Tty.red}Warning#{Tty.reset}: #{warning.chomp}"
end

def system *args
  abort "Failed during: #{args.shell_s}" unless Kernel.system *args
end

def sudo *args
  args = if args.length > 1
    args.unshift "/usr/bin/sudo"
  else
    "/usr/bin/sudo #{args.first}"
  end
  ohai *args
  system *args
end

def getc  # NOTE only tested on OS X
  system "/bin/stty raw -echo"
  if RUBY_VERSION >= '1.8.7'
    STDIN.getbyte
  else
    STDIN.getc
  end
ensure
  system "/bin/stty -raw echo"
end

def macos_version
  @macos_version ||= /(10.d+)(.d+)?/.match(`/usr/bin/sw_vers -productVersion`).captures.first.to_f
end

def git
  @git ||= if ENV['GIT'] and File.executable? ENV['GIT']
    ENV['GIT']
  elsif Kernel.system '/usr/bin/which -s git'
    'git'
  else
    s = `xcrun -find git 2>/dev/null`.chomp
    s if $? and not s.empty?
  end
end

# The block form of Dir.chdir fails later if Dir.CWD doesn't exist which I
# guess is fair enough. Also sudo prints a warning message for no good reason
Dir.chdir "/usr"

####################################################################### script
abort "MacOS too old, see: https://github.com/mistydemeo/tigerbrew" if macos_version < 10.5
abort "Don't run this as root!" if Process.uid == 0
abort <<-EOABORT unless `groups`.split.include? "admin"
This script requires the user #{ENV['USER']} to be an Administrator. If this
sucks for you then you can install Homebrew in your home directory or however
you please; please refer to our homepage. If you still want to use this script
set your user to be an Administrator in System Preferences or `su' to a
non-root user with Administrator privileges.
EOABORT
abort <<-EOABORT unless Dir["#{HOMEBREW_PREFIX}/.git/*"].empty?
It appears Homebrew is already installed. If your intent is to reinstall you
should do the following before running this installer again:
    rm -rf #{HOMEBREW_PREFIX}/Cellar #{HOMEBREW_PREFIX}/.git && brew cleanup
EOABORT
# Tests will fail if the prefix exists, but we don't have execution
# permissions. Abort in this case.
abort <<-EOABORT if File.directory? HOMEBREW_PREFIX and not File.executable? HOMEBREW_PREFIX
The Homeprew prefix, #{HOMEBREW_PREFIX}, exists but is not searchable. If this is
not intentional, please restore the default permissions and try running the
installer again:
    sudo chmod 755 #{HOMEBREW_PREFIX}
EOABORT

ohai "This script will install:"
puts "#{HOMEBREW_PREFIX}/bin/brew"
puts "#{HOMEBREW_PREFIX}/Library/..."
puts "#{HOMEBREW_PREFIX}/share/man/man1/brew.1"

chmods = %w( . bin etc include lib lib/pkgconfig Library sbin share var var/log share/locale share/man
             share/man/man1 share/man/man2 share/man/man3 share/man/man4
             share/man/man5 share/man/man6 share/man/man7 share/man/man8
             share/info share/doc share/aclocal ).
            map{ |d| "#{HOMEBREW_PREFIX}/#{d}" }.
            select{ |d| File.directory? d and (not File.readable? d or not File.writable? d or not File.executable? d) }
chgrps = chmods.reject{ |d| File.stat(d).grpowned? }

unless chmods.empty?
  ohai "The following directories will be made group writable:"
  puts *chmods
end
unless chgrps.empty?
  ohai "The following directories will have their group set to #{Tty.underline 39}admin#{Tty.reset}:"
  puts *chgrps
end

if File.directory? HOMEBREW_PREFIX
  sudo "/bin/chmod", "g+rwx", *chmods unless chmods.empty?
  sudo "/usr/bin/chgrp", "admin", *chgrps unless chgrps.empty?
else
  sudo "/bin/mkdir #{HOMEBREW_PREFIX}"
  sudo "/bin/chmod g+rwx #{HOMEBREW_PREFIX}"
  # the group is set to wheel by default for some reason
  sudo "/usr/bin/chgrp admin #{HOMEBREW_PREFIX}"
end

ohai "Downloading and Installing Homebrew..."
Dir.chdir HOMEBREW_PREFIX do
  if git
    # we do it in four steps to avoid merge errors when reinstalling
    system git, "init", "-q"
    system git, "remote", "add", "origin", "https://github.com/mxcl/homebrew"

    args = git, "fetch", "origin", "master:refs/remotes/origin/master", "-n"
    args << "--depth=1" if ARGV.include? "--fast"
    system *args

    system git, "reset", "--hard", "origin/master"
  else
    # -m to stop tar erroring out if it can't modify the mtime for root owned directories
    # pipefail to cause the exit status from curl to propogate if it fails
    # we use -k for curl because Leopard has a bunch of bad SSL certificates
    curl_flags = "fsSL"
    curl_flags << "k" if macos_version == 10.5
    system "/bin/bash -o pipefail -c '/usr/bin/curl -#{curl_flags} https://github.com/mxcl/homebrew/tarball/master | /usr/bin/tar xz -m --strip 1'"
  end
end

warn "#{HOMEBREW_PREFIX}/bin is not in your PATH." unless ENV['PATH'].split(':').include? "#{HOMEBREW_PREFIX}/bin"

if macos_version < 10.7
  warn "Now install Xcode: https://developer.apple.com/xcode/" unless File.exist? "/usr/bin/cc"
else
  `/usr/bin/cc --version 2> /dev/null` =~ %r[clang-(d{2,})]
  version = $1.to_i
  warn %{Install the "Command Line Tools for Xcode": http://connect.apple.com} if version < 425
end

ohai "Installation successful!"
puts "You should run `brew doctor' *before* you install anything."
puts "Now type: brew help"

Next, I put that script in a .pkg to be installed into /usr/local/bin with global execution rights, and put the package in my imaging workflow

Finally, I created a script triggered by login containing only this:

#!/bin/sh

sudo -u $3 /usr/local/bin/InstallHomebrew.sh

IT WORKS!

ronb
New Contributor II

We had an existing script that seems to be broken with Mavericks -

#!/bin/bash chown $3:_developer /usr/local/ #download and install homebrew su $3 -c "/bin/bash -o pipefail -c '/usr/bin/curl -skSfL https://github.com/mxcl/homebrew/tarball/master | (cd usr/local ; /usr/bin/tar xz -m --strip 1)'" chown -R $3:_developer /usr/local/lib

Not being a great shell scripter yet, have had no luck repairing the errors -
"bin/bash: line 0: cd: usr/local: No such file or directory
.gitignore: Can't create '.gitignore'
CODEOFCONDUCT.md: Can't create 'CODEOFCONDUCT.md'"

I tried ooadmin's scripts above, no luck on that either. Any idea's of what's changed with Mavericks? The first line that changed ownership worked, but not the main command line.

charles_hitch
Contributor II

Edit... So believe your error is because you don't have a / before usr/local....

#!/bin/bash

chown $3:_developer /usr/local/

#download and install homebrew
su $3 -c "/bin/bash -o pipefail -c '/usr/bin/curl -skSfL https://github.com/mxcl/homebrew/tarball/master | (cd /usr/local ; /usr/bin/tar xz -m --strip 1)'"

chown -R $3:_developer /usr/local/lib

Nix4Life
Valued Contributor

hkim;

I'd like to hear more about your casper/puppet setup

jesseshipley
Contributor

I just got this working myself by reading through the brew script they have you curl and execute. Not too much really happens in it.

#!/bin/sh
#Getting Username
user=`ls -la /dev/console | cut -d " " -f 4`

#Modifying permissions and creating directories
chmod g+rwx /usr/local
chgrp admin /usr/local
mkdir /Library/Caches/Homebrew
chmod g+rwx /Library/Caches/Homebrew
chown -R $user /Library/Caches
chmod g+rwx /usr/local/bin
chgrp admin /usr/local/bin

#Downlading and installing Homebrew
cd /usr/local
git init -q
git config remote.origin.url https://github.com/Homebrew/homebrew
git fetch origin master:refs/remotes/origin/master -n
git reset --hard origin/master
chown -R $user $(ls | grep -v bin)
chown $user /usr/local/bin/brew
chgrp admin /usr/local/bin/brew

#Creating .bash_profile with new path but checking there isn't one already
if [ ! -f /Users/$user/.bash_profile ]; then
    sudo -u $user echo "PATH=/usr/local/bin:$PATH" >> /Users/$user/.bash_profile
fi

jimmy-swings
Contributor II

Apologies to rehash an old topic, but this seemed to be the most relevant audience.

I'm attempting to create a offline brew package for installation and usage by non-administrative users.

Once installed, users should be able to use brew to install most packages. Packages that require elevated access I assume we'll still need to look at an appropriate way to distribute these.

I'm just about to check out @timsutton's work but reading through the various scripts above, it suggests that most of your user group has no proxy infrastructure, therefore allowing full unauthenticated internet connectivity to github from each machine. If this isn't the case, I'd be interested in hearing on how you have configured proxy details on your managed machines, including usernames / passwords for casper service accounts as well as standard users.