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
|
require 'stringio'
class Patches
include Enumerable
# The patches defined in a formula and the DATA from that file
def initialize patches
@patches = []
return if patches.nil?
n = 0
normalize_patches(patches).each do |patch_p, urls|
# Wrap the urls list in an array if it isn't already;
# DATA.each does each line, which doesn't work so great
urls = [urls] unless urls.kind_of? Array
urls.each do |url|
@patches << Patch.new(patch_p, '%03d-homebrew.diff' % n, url)
n += 1
end
end
end
def external_patches?
not external_curl_args.empty?
end
def each(&blk)
@patches.each(&blk)
end
def empty?
@patches.empty?
end
def download!
return unless external_patches?
# downloading all at once is much more efficient, especially for FTP
curl(*external_curl_args)
external_patches.each{|p| p.stage!}
end
private
def external_patches
@patches.select{|p| p.external?}
end
# Collects the urls and output names of all external patches
def external_curl_args
external_patches.collect{|p| p.curl_args}.flatten
end
def normalize_patches patches
if patches.kind_of? Hash
patches
else
{ :p1 => patches } # We assume -p1
end
end
end
class Patch
# Used by formula to unpack after downloading
attr_reader :compression
attr_reader :compressed_filename
# Used by audit
attr_reader :url
def initialize patch_p, filename, url
@patch_p = patch_p
@patch_filename = filename
@compressed_filename = nil
@compression = nil
@url = nil
if url.kind_of? IO or url.kind_of? StringIO
# File-like objects. Most common when DATA is passed.
write_data url
elsif looks_like_url(url)
@url = url # Save URL to mark this as an external patch
else
# it's a file on the local filesystem
# use URL as the filename for patch
@patch_filename = url
end
end
# rename the downloaded file to take compression into account
def stage!
return unless external?
detect_compression!
case @compression
when :gzip
@compressed_filename = @patch_filename + '.gz'
FileUtils.mv @patch_filename, @compressed_filename
when :bzip2
@compressed_filename = @patch_filename + '.bz2'
FileUtils.mv @patch_filename, @compressed_filename
end
end
def external?
not @url.nil?
end
def patch_args
["-#{@patch_p}", '-i', @patch_filename]
end
def curl_args
[@url, '-o', @patch_filename]
end
private
# Detect compression type from the downloaded patch.
def detect_compression!
# If nil we have not tried to detect yet
if @compression.nil?
path = Pathname.new(@patch_filename)
if path.exist?
@compression = path.compression_type
@compression ||= :none # If nil, convert to :none
end
end
end
# Write the given file object (DATA) out to a local file for patch
def write_data f
pn = Pathname.new @patch_filename
pn.write(brew_var_substitution(f.read.to_s))
end
# Do any supported substitutions of HOMEBREW vars in a DATA patch
def brew_var_substitution s
s.gsub("HOMEBREW_PREFIX", HOMEBREW_PREFIX)
end
def looks_like_url str
str =~ %r[^\w+\://]
end
end
|