Homebrew/homebrew — pull request #26575 by earlchew (2014-02-10 17:35:58+00:00)
Title: Issues/26524/dev

In case this pull request might be deemed unsuitable, I've included a relatively detailed description here so that others who have similar needs might find it useful for reference.

The Homebrew guidance is to install into /usr/local.

In some situations it is desirable to deploy the installation in some other physically location for administrative reasons (eg managing volume space or permissions), or potentially to enable mobility solutions such as deploying the installation on a USB thumb drive.

Allowing /usr/local to be a symlink to the physical deployment location permits both the Homebrew /usr/local guidance and the local deployment requirements to be satisfied:

1. The installation is logically located at /usr/local.
2. The installation is physically deployed elsewhere.

These commits are a consequence of the path to directory containing the brew shell script (eg /usr/local/bin) comprising symlinks are part of some of its directory components.

##### Commit 7c4a951 homebrew/bin/brew

This script does two things:

1. exports HOMEBREW_BREW_FILE
2. execs brew.rb

This commit changes (1) to ensure that HOMEBREW_BREW_FILE remains the logical location (eg /usr/local/bin/brew) of the brew script, while leaving (2) unaltered.

The goal is to ensure that packages are installed via the logical location (ie /usr/local in this example) rather than the deployment location (eg /mnt/development/packages).

On master, the result is:
> HOMEBREW_BREW_FILE=/mnt/development/homebrew/bin/brew
> exec /mnt/development/homebrew/Library/brew.rb update

With this change, the result is:
> HOMEBREW_BREW_FILE=/usr/local/bin/brew
> exec /mnt/development/homebrew/Library/brew.rb update

Thus HOMEBREW_BREW_FILE retains the logical location, while the backend Ruby script is execed from the physical location as before.

##### Commit 4970975 extend/pathname.rb

This commit addresses the following issue when resolving symlinks. Consider the following:

```
/tmp/local -> /tmp/package
/tmp/package/bin/script -> ../../test/script
```

Verify that the link can be resolved:

```
% head -1 /tmp/local/bin/script
#!/bin/sh
```

Consider this script that tries to interpret /tmp/local/bin/script:

```
require 'pathname'

pn = Pathname.new('/tmp/local/bin/script')
puts pn.dirname # prints /tmp/local/bin
puts pn.readlink # prints ../../test/script

ln = pn.dirname + pn.readlink

puts ln.to_s + " does not exit" if ln.exist?
```

This prints:

```
/tmp/local/bin
../../test/script
/tmp/test/script does not exit
```

The issue is that the operating system always uses the physical path to the directory (not the logical path) when resolving (relative) symbolic links.

Thus to obtain correct results, symbolic link resolution should use:

```
pn.dirname.realpath + pn.readlink
```

##### Commit b50fb2d homebrew/global.rb

This commit is a consequence of 7c4a951. The previous commit 7c4a951 allows HOMEBREW_BREW_FILE to indicate the logical location of the brew script. So we have:

```
HOMEBREW_BREW_FILE /usr/local/bin/brew
HOMEBREW_BREW_FILE.dirname /usr/local/bin
HOMEBREW_BREW_FILE.parent /usr/local/bin/.. => /usr/local
HOMEBREW_PREFIX /usr/local
```

The issue addressed by this commit is that the variable HOMEBREW_PREFIX needs to be the physical location (eg /mnt/development/packages in the example above), rather than the logical location (ie /usr/local).

This is because HOMEBREW_PREFIX is used to construct a relative symlink from the physical installation location (HOMEBREW_PREFIX) to the Homebrew deployment location (/mnt/development/homebrew in this example).

It is important to use the physical location for HOMEBREW_PREFIX because, as identified in the other commit 4970975, the operating system willl use physical pathnames when resolving symlinks.