1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
|
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
# Run `make` 3.81 or newer.
# Uses the system make on Leopard and newer, and the
# path to the actually-installed make on Tiger or older.
def make(*args)
if Utils.popen_read("/usr/bin/make", "--version").match(/Make (\d\.\d+)/)[1] > "3.80"
system "/usr/bin/make", *args
else
make = Formula["make"].opt_bin/"make"
make_path = make.exist? ? make.to_s : (Formula["make"].opt_bin/"gmake").to_s
system make_path, *args
end
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
|