This repository has been archived by the owner on Dec 2, 2020. It is now read-only.
forked from mattheath/puppet-php
-
Notifications
You must be signed in to change notification settings - Fork 29
/
php_source.rb
318 lines (253 loc) · 11.4 KB
/
php_source.rb
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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
require 'puppet/util/execution'
Puppet::Type.type(:php_version).provide(:php_source) do
include Puppet::Util::Execution
desc "Provides PHP versions compiled from the official source code repository"
def create
# Not removing all pear.conf and .pearrc files from PHP path results in
# the PHP configure not properly setting the pear binary to be installed
# Source: https://github.com/josegonzalez/homebrew-php/blob/master/Formula/abstract-php.rb
home_path = @resource[:user_home]
user_pear = "#{home_path}/pear.conf"
user_pearrc = "#{home_path}/.pearrc"
if File.exists?(user_pear) || File.exists?(user_pearrc)
puts "Backing up all known pear.conf and .pearrc files"
FileUtils.mv(user_pear, "#{user_pear}-backup") if File.exists? user_pear
FileUtils.mv(user_pearrc, "#{user_pearrc}-backup") if File.exists? user_pearrc
end
begin
install "#{@resource[:version]}"
FileUtils.rm_f("#{user_pear}-backup") if File.exists? "#{user_pear}-backup"
FileUtils.rm_f("#{user_pearrc}-backup") if File.exists? "#{user_pearrc}-backup"
rescue Exception => e
# Clean up the failed install
destroy
# Move PEAR files back into place
FileUtils.mv("#{user_pear}-backup", user_pear) if File.exists? "#{user_pear}-backup"
FileUtils.mv("#{user_pearrc}-backup", user_pearrc) if File.exists? "#{user_pearrc}-backup"
# Rethrow error
throw e
end
end
def destroy
puts "DESTROYING PHP #{@resource[:version]}"
FileUtils.rm_rf "#{@resource[:phpenv_root]}/versions/#{@resource[:version]}"
end
def exists?
# First check if the version folder exists
does_exist = File.directory? "#{@resource[:phpenv_root]}/versions/#{@resource[:version]}"
# We also want to ensure that all of the binaries exist
required_binaries = %w(php phpize php-config pear pecl)
required_binaries.map { |bin|
does_exist &&= File.exists? "#{@resource[:phpenv_root]}/versions/#{@resource[:version]}/bin/#{bin}"
}
# Including php-fpm if the version is >= 5.3.3
# This will fix previously broken installs
does_exist &&= File.exists? "#{@resource[:phpenv_root]}/versions/#{@resource[:version]}/sbin/php-fpm" unless @resource[:version].match(/\A5\.3\.[12]\z/)
# Double check we can run PHP if it exists
# Should identify broken versions eg. due to zlib changing...
if does_exist
output = %x( #{@resource[:phpenv_root]}/versions/#{@resource[:version]}/bin/php -i 2>&1 )
php_exitstatus = $?.exitstatus
puts "Reinstalling PHP #{@resource[:version]}" unless php_exitstatus == 0
does_exist &&= (php_exitstatus == 0)
end
does_exist
end
def install(version)
# First destroy any prior installation to avoid conflicts
# We'll only be installing if the exists method has failed so has determined nothing is installed here
# This does mean if new binaries are added to the required list in the exists check, it's likely all
# installed versions of PHP will be reinstalled - running destroy should ensure this proceeds as expected
destroy
# First check we have a cached copy of the source repository, with this version tag
confirm_cached_source(version)
# Checkout the version as a build branch and prepare for building
prep_build(version)
# Configure - this is the hard part
puts "Installing PHP #{@resource[:version]}, this may take a while..."
configure(version)
# Change libexecdir, this is how homebrew does it.
makefile = "#{@resource[:phpenv_root]}/php-src/Makefile"
makefileOutdata = File.read(makefile).gsub(/^INSTALL_IT = \$\(mkinstalldirs\) '([^']+)' (.+) LIBEXECDIR=([^\s]+) (.+)$/, "INSTALL_IT = $(mkinstalldirs) '#{@resource[:phpenv_root]}/versions/#{@resource[:version]}/libexec/apache2' \\2 LIBEXECDIR='#{@resource[:phpenv_root]}/versions/#{@resource[:version]}/libexec/apache2' \\4")
# Fix for openssl when building 5.5
# Discussed here: https://github.com/Homebrew/homebrew-php/issues/1941
makefileOutdata = makefileOutdata.gsub(/^EXTRA_LIBS = (.*)/, "EXTRA_LIBS = \\1 #{@resource[:homebrew_path]}/opt/openssl/lib/libssl.dylib #{@resource[:homebrew_path]}/opt/openssl/lib/libcrypto.dylib")
File.open(makefile, 'w') do |out|
out << makefileOutdata
end
# Make & install
make
make_install
make_clean
# Ensure we've actually installed something...
raise "Failed to install PHP #{@resource[:version]}" unless exists?
# Fix permissions
puts %x( chown -R #{@resource[:user]}:staff #{@resource[:phpenv_root]}/versions/#{@resource[:version]} )
end
private
# Check that the cached repository is in place, and the version requested exists
# as a tag in the repository
#
def confirm_cached_source(version)
raise "Source repository is not present" if !File.directory?("#{@resource[:phpenv_root]}/php-src/.git")
# Check if tag exists in current repo, if not fetch & recheck
if !version_present_in_cache?(version)
update_repository
raise "Version #{version} not found in PHP source" if !version_present_in_cache?(version)
end
end
# Update and fetch new tags from the remote repository
#
def update_repository
%x( cd #{@resource[:phpenv_root]}/php-src/ && git fetch --tags )
end
# Check for a specific version within the PHP source repository
#
def version_present_in_cache?(version)
tag = %x( cd #{@resource[:phpenv_root]}/php-src/ && git tag -l "php-#{version}" )
tag.strip == "php-#{version}"
end
# Prepare the source repository for building by checkout out the correct
# tag, and cleaning the source tree
#
def prep_build(version)
# Reset back to master and ensure the build branch is removed
%x( cd #{@resource[:phpenv_root]}/php-src/ && git checkout -f master && git branch -D build &> /dev/null )
# Checkout version as build branch
%x( cd #{@resource[:phpenv_root]}/php-src/ && git checkout php-#{version} -b build )
# Clean everything
%x( cd #{@resource[:phpenv_root]}/php-src/ && git clean -f -d -x )
end
# Configure our version of PHP for compilation
#
def configure(version)
# Final bit of cleanup, just in case
%x( cd #{@resource[:phpenv_root]}/php-src/ && rm -rf configure autom4te.cache )
# Run buildconf to prepare build system for compilation
puts "export PHP_AUTOCONF=#{autoconf} && export PHP_AUTOHEADER=#{autoheader} && cd #{@resource[:phpenv_root]}/php-src/ && ./buildconf --force"
puts %x( export PHP_AUTOCONF=#{autoconf} && export PHP_AUTOHEADER=#{autoheader} && cd #{@resource[:phpenv_root]}/php-src/ && ./buildconf --force )
exit_code = $?
# Ensure buildconf exited successfully
unless exit_code == 0
puts "Buildconf exit code: #{exit_code}\n\n"
raise "Error occured while running buildconf for PHP #{@resource[:version]}"
end
# Build configure options
install_path = "#{@resource[:phpenv_root]}/versions/#{@resource[:version]}"
config_path = "/opt/boxen/config/php/#{@resource[:version]}"
args = get_configure_args(version, install_path, config_path)
args = args.join(" ")
# Right, the hard part - configure for our system
# Some env variables are needed for configuration
env = "export ac_cv_exeext=''"
# PHP 5.5+ requires a later version of Bison than OSX provides (2.6 vs 2.3)
if Gem::Version.new(@resource[:version]) > Gem::Version.new('5.4.17')
env << " && export PATH=/opt/boxen/homebrew/opt/bisonphp26/bin:$PATH"
end
# Construct and run configure command
configure_command = "cd #{@resource[:phpenv_root]}/php-src/ && #{env} && ./configure #{args}"
puts "Configuring PHP #{version}: #{configure_command}"
puts %x( #{configure_command} )
exit_code = $?
# Ensure Configure exited successfully
unless exit_code == 0
puts "Configure exit code: #{exit_code}\n\n"
raise "Error occured while configuring PHP #{@resource[:version]}"
end
# Configure should create a Makefile - we need this
raise "Could not configure PHP #{@resource[:version]} - no makefile" unless File.exists? "#{@resource[:phpenv_root]}/php-src/Makefile"
end
def make
# PHP > 5.4.17 requires a later version of Bison than OSX provides (2.6 vs 2.3)
if Gem::Version.new(@resource[:version]) > Gem::Version.new('5.4.17')
env = " && export PATH=/opt/boxen/homebrew/opt/bisonphp26/bin:$PATH"
end
puts %x( cd #{@resource[:phpenv_root]}/php-src/ #{env} && make 2>&1 )
raise "Could not compile PHP @resource[:version]" unless $? == 0
end
def make_install
puts %x( cd #{@resource[:phpenv_root]}/php-src/ && make install )
raise "Could not install PHP @resource[:version]" unless $? == 0
end
def make_clean
puts %x( cd #{@resource[:phpenv_root]}/php-src/ && make clean )
end
# Get a default set of configure options
#
def get_configure_args(version, install_path, config_path)
args = [
"--prefix=#{install_path}",
"--localstatedir=/var",
"--sysconfdir=#{config_path}",
"--with-config-file-path=#{config_path}",
"--with-config-file-scan-dir=#{config_path}/conf.d",
"--with-iconv-dir=/usr",
"--enable-dba",
"--with-ndbm=/usr",
"--enable-exif",
"--enable-soap",
"--enable-wddx",
"--enable-ftp",
"--enable-sockets",
"--enable-zip",
"--enable-pcntl",
"--enable-shmop",
"--enable-sysvsem",
"--enable-sysvshm",
"--enable-sysvmsg",
"--enable-mbstring",
"--enable-mbregex",
"--enable-bcmath",
"--enable-calendar",
"--with-ldap",
"--with-ldap-sasl=/usr",
"--with-xmlrpc",
"--with-kerberos=/usr",
"--with-xsl=/usr",
"--with-gd",
"--enable-gd-native-ttf",
"--with-freetype-dir=#{@resource[:homebrew_path]}/opt/freetypephp",
"--with-jpeg-dir=#{@resource[:homebrew_path]}/opt/jpeg",
"--with-png-dir=#{@resource[:homebrew_path]}/opt/libpng",
"--with-gettext=#{@resource[:homebrew_path]}/opt/gettext",
"--with-gmp=#{@resource[:homebrew_path]}/opt/gmp",
"--with-zlib=#{@resource[:homebrew_path]}/opt/zlibphp",
"--without-snmp",
"--with-libedit",
"--with-mhash",
"--with-curl=#{@resource[:homebrew_path]}/opt/curl",
"--with-openssl=#{@resource[:homebrew_path]}/opt/openssl",
"--with-bz2=/usr",
"--with-mysql-sock=/tmp/mysql.sock",
"--with-mysqli=mysqlnd",
"--with-pdo-mysql=mysqlnd",
]
# with-mysql isn't available after PHP 7.
if Gem::Version.new(@resource[:version]) < Gem::Version.new('7.0.0')
args << "--with-mysql=mysqlnd"
end
# PHP-FPM isn't available until 5.3.3
if Gem::Version.new(@resource[:version]) > Gem::Version.new('5.3.2')
args << "--enable-fpm"
end
# libevent was removed in 5.3.8
if Gem::Version.new(@resource[:version]) < Gem::Version.new('5.3.8')
args << "--with-libevent-dir=#{@resource[:homebrew_path]}/opt/libevent"
end
# User specified configure params
args << @resource[:configure_params]
args
end
def autoconf
autoconf = "#{@resource[:homebrew_path]}/bin/autoconf"
# We need an old version of autoconf for PHP 5.3...
autoconf << "213" if @resource[:version].match(/5\.3\../)
autoconf
end
def autoheader
autoheader = "#{@resource[:homebrew_path]}/bin/autoheader"
# We need an old version of autoheader for PHP 5.3...
autoheader << "213" if @resource[:version].match(/5\.3\../)
autoheader
end
end