mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00

Also enables sandbox for --interactive and --debug use of install and test, using automatic retention. Closes #66. Signed-off-by: Andrew Janke <andrew@apjanke.net>
188 lines
5.0 KiB
Ruby
188 lines
5.0 KiB
Ruby
require "fileutils"
|
|
require "tmpdir"
|
|
require "etc"
|
|
|
|
# Homebrew extends Ruby's `FileUtils` to make our code more readable.
|
|
# @see http://ruby-doc.org/stdlib-1.8.7/libdoc/fileutils/rdoc/FileUtils.html Ruby's FileUtils API
|
|
module FileUtils
|
|
# Create a temporary directory then yield. When the block returns,
|
|
# recursively delete the temporary directory. Passing opts[:retain]
|
|
# or calling `do |staging| ... staging.retain!` in the block will skip
|
|
# the deletion and retain the temporary directory's contents.
|
|
def mktemp(prefix = name, opts = {})
|
|
Mktemp.new(prefix, opts).run do |staging|
|
|
yield staging
|
|
end
|
|
end
|
|
|
|
module_function :mktemp
|
|
|
|
# Performs mktemp's functionality, and tracks the results.
|
|
# Each instance is only intended to be used once.
|
|
class Mktemp
|
|
include FileUtils
|
|
|
|
# Path to the tmpdir used in this run, as a Pathname.
|
|
attr_reader :tmpdir
|
|
|
|
def initialize(prefix = name, opts = {})
|
|
@prefix = prefix
|
|
@retain = opts[:retain]
|
|
@quiet = false
|
|
end
|
|
|
|
# Instructs this Mktemp to retain the staged files
|
|
def retain!
|
|
@retain = true
|
|
end
|
|
|
|
# True if the staged temporary files should be retained
|
|
def retain?
|
|
@retain
|
|
end
|
|
|
|
# Instructs this Mktemp to not emit messages when retention is triggered
|
|
def quiet!
|
|
@quiet = true
|
|
end
|
|
|
|
def to_s
|
|
"[Mktemp: #{tmpdir} retain=#{@retain} quiet=#{@quiet}]"
|
|
end
|
|
|
|
def run
|
|
@tmpdir = Pathname.new(Dir.mktmpdir("#{@prefix}-", HOMEBREW_TEMP))
|
|
|
|
# Make sure files inside the temporary directory have the same group as the
|
|
# brew instance.
|
|
#
|
|
# Reference from `man 2 open`
|
|
# > When a new file is created, it is given the group of the directory which
|
|
# contains it.
|
|
group_id = if HOMEBREW_BREW_FILE.grpowned?
|
|
HOMEBREW_BREW_FILE.stat.gid
|
|
else
|
|
Process.gid
|
|
end
|
|
begin
|
|
# group_id.to_s makes OS X 10.6.7 (ruby-1.8.7-p174) and earlier happy.
|
|
chown(nil, group_id.to_s, tmpdir)
|
|
rescue Errno::EPERM
|
|
opoo "Failed setting group \"#{Etc.getgrgid(group_id).name}\" on #{tmp}"
|
|
end
|
|
|
|
begin
|
|
Dir.chdir(tmpdir) { yield self }
|
|
ensure
|
|
ignore_interrupts { rm_rf(tmpdir) } unless retain?
|
|
end
|
|
ensure
|
|
if retain? && !@tmpdir.nil? && !@quiet
|
|
ohai "Kept temporary files"
|
|
puts "Temporary files retained at #{@tmpdir}"
|
|
end
|
|
end
|
|
end
|
|
|
|
# @private
|
|
alias_method :old_mkdir, :mkdir
|
|
|
|
# A version of mkdir that also changes to that folder in a block.
|
|
def mkdir(name, &_block)
|
|
old_mkdir(name)
|
|
if block_given?
|
|
chdir name do
|
|
yield
|
|
end
|
|
end
|
|
end
|
|
module_function :mkdir
|
|
|
|
# The #copy_metadata method in all current versions of Ruby has a
|
|
# bad bug which causes copying symlinks across filesystems to fail;
|
|
# see #14710.
|
|
# This was resolved in Ruby HEAD after the release of 1.9.3p194, but
|
|
# never backported into the 1.9.3 branch. Fixed in 2.0.0.
|
|
# The monkey-patched method here is copied directly from upstream fix.
|
|
if RUBY_VERSION < "2.0.0"
|
|
# @private
|
|
class Entry_
|
|
alias_method :old_copy_metadata, :copy_metadata
|
|
def copy_metadata(path)
|
|
st = lstat
|
|
unless st.symlink?
|
|
File.utime st.atime, st.mtime, path
|
|
end
|
|
begin
|
|
if st.symlink?
|
|
begin
|
|
File.lchown st.uid, st.gid, path
|
|
rescue NotImplementedError
|
|
end
|
|
else
|
|
File.chown st.uid, st.gid, path
|
|
end
|
|
rescue Errno::EPERM
|
|
# clear setuid/setgid
|
|
if st.symlink?
|
|
begin
|
|
File.lchmod st.mode & 01777, path
|
|
rescue NotImplementedError
|
|
end
|
|
else
|
|
File.chmod st.mode & 01777, path
|
|
end
|
|
else
|
|
if st.symlink?
|
|
begin
|
|
File.lchmod st.mode, path
|
|
rescue NotImplementedError
|
|
end
|
|
else
|
|
File.chmod st.mode, path
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
# Run `scons` using a Homebrew-installed version rather than whatever is in the `PATH`.
|
|
def scons(*args)
|
|
system Formulary.factory("scons").opt_bin/"scons", *args
|
|
end
|
|
|
|
# Run the `rake` from the `ruby` Homebrew is using rather than whatever is in the `PATH`.
|
|
def rake(*args)
|
|
system RUBY_BIN/"rake", *args
|
|
end
|
|
|
|
if method_defined?(:ruby)
|
|
# @private
|
|
alias_method :old_ruby, :ruby
|
|
end
|
|
|
|
# Run the `ruby` Homebrew is using rather than whatever is in the `PATH`.
|
|
def ruby(*args)
|
|
system RUBY_PATH, *args
|
|
end
|
|
|
|
# Run `xcodebuild` without Homebrew's compiler environment variables set.
|
|
def xcodebuild(*args)
|
|
removed = ENV.remove_cc_etc
|
|
system "xcodebuild", *args
|
|
ensure
|
|
ENV.update(removed)
|
|
end
|
|
end
|
|
|
|
# Shim File.write for Ruby 1.8.7, where it's absent
|
|
unless File.respond_to?(:write)
|
|
class File
|
|
def self.write(filename, contents)
|
|
File.open(filename, 'w') do |file|
|
|
file.write contents
|
|
end
|
|
end
|
|
end
|
|
end
|