mirror of
https://github.com/Homebrew/brew.git
synced 2026-08-12 22:29:27 +04:00
Add PHP configuration action
Five PHP formulae share PEAR, PECL and versioned extension configuration that must be rebuilt after installation. - preserve PEAR directory traversal and repair stale PECL links - create the common PECL extension layout from `php-config` - rewrite versioned opcache paths without changing commented settings - cover the shared filesystem and command behaviour end to end
This commit is contained in:
@@ -658,6 +658,11 @@ module Homebrew
|
||||
add_step("configure_clang_system")
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def configure_php
|
||||
add_step("configure_php")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
sig { params(guard: PathSpec, block: ::T.proc.bind(DSL).void).void }
|
||||
@@ -914,6 +919,8 @@ module Homebrew
|
||||
run_configure_glibc_runtime
|
||||
when "configure_clang_system"
|
||||
run_configure_clang_system
|
||||
when "configure_php"
|
||||
run_configure_php
|
||||
when "set_permissions"
|
||||
run_set_permissions(step)
|
||||
when "set_ownership"
|
||||
|
||||
@@ -136,6 +136,65 @@ module Homebrew
|
||||
require "utils/clang"
|
||||
Utils::Clang.write_system_config_files(config_dir:, macos_version:, kernel_version:, arch:)
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def run_configure_php
|
||||
pear_prefix = context_path("pkgshare")/"pear"
|
||||
channels = [pear_prefix/".channels", pear_prefix/".channels/.alias"]
|
||||
channels.select(&:directory?).each { |directory| FileUtils.chmod 0755, directory }
|
||||
pear_files = %w[.depdblock .filemap .depdb .lock].map { |file| pear_prefix/file }.select(&:file?)
|
||||
pear_files.concat(channels.flat_map do |directory|
|
||||
directory.directory? ? directory.children.select(&:file?) : []
|
||||
end)
|
||||
FileUtils.chmod 0644, pear_files
|
||||
|
||||
pecl_path = HOMEBREW_PREFIX/"lib/php/pecl"
|
||||
pecl_path.mkpath
|
||||
prefix_pecl = context_path("prefix")/"pecl"
|
||||
prefix_pecl.unlink if prefix_pecl.symlink?
|
||||
File.symlink pecl_path, prefix_pecl unless prefix_pecl.exist?
|
||||
php_basename = File.basename(run_command_output(context_path("bin")/"php-config", "--extension-dir").strip)
|
||||
(pecl_path/php_basename).mkpath
|
||||
|
||||
version_major_minor = context_version_major_minor
|
||||
raise ArgumentError, "PHP configuration requires a version" if version_major_minor.nil?
|
||||
|
||||
pear_dir = (context_name == "php") ? "pear" : "pear@#{version_major_minor}"
|
||||
pear_path = HOMEBREW_PREFIX/"share"/pear_dir
|
||||
FileUtils.cp_r "#{pear_prefix}/.", pear_path
|
||||
php_ext_dir = context_path("opt_prefix")/"lib/php"/php_basename
|
||||
{
|
||||
"php_ini" => context_path("etc")/"php/#{version_major_minor}/php.ini",
|
||||
"php_dir" => pear_path,
|
||||
"doc_dir" => pear_path/"doc",
|
||||
"ext_dir" => pecl_path/php_basename,
|
||||
"bin_dir" => context_path("opt_prefix")/"bin",
|
||||
"data_dir" => pear_path/"data",
|
||||
"cfg_dir" => pear_path/"cfg",
|
||||
"www_dir" => pear_path/"htdocs",
|
||||
"man_dir" => HOMEBREW_PREFIX/"share/man",
|
||||
"test_dir" => pear_path/"test",
|
||||
"php_bin" => context_path("opt_prefix")/"bin/php",
|
||||
}.each do |key, value|
|
||||
value.mkpath if /(?<!bin|man)_dir$/.match?(key)
|
||||
run_command context_path("bin")/"pear", "config-set", key, value, "system"
|
||||
end
|
||||
run_command context_path("bin")/"pear", "update-channels"
|
||||
return if context_name == "php"
|
||||
|
||||
ext_config_path = context_path("etc")/"php/#{version_major_minor}/conf.d/ext-opcache.ini"
|
||||
ext_config_path.dirname.mkpath
|
||||
zend_extension_line = %Q(zend_extension="#{php_ext_dir}/opcache.so")
|
||||
if ext_config_path.exist?
|
||||
require "utils/inreplace"
|
||||
Utils::Inreplace.inreplace(ext_config_path, /^\s*zend_extension\s*=.*$/, zend_extension_line)
|
||||
else
|
||||
ext_config_path.atomic_write <<~INI
|
||||
[opcache]
|
||||
#{zend_extension_line}
|
||||
INI
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -20,7 +20,7 @@ module RuboCop
|
||||
NOTICE_STEP_METHODS = [:warn].freeze
|
||||
FORMULA_ACTION_STEP_METHODS =
|
||||
[:configure_gcc_runtime, :install_gzipped_executable, :configure_glibc_runtime,
|
||||
:configure_clang_system].freeze
|
||||
:configure_clang_system, :configure_php].freeze
|
||||
STEP_SCOPE_METHODS = [:if_path_exists, :unless_path_exists, :on_macos, :on_linux].freeze
|
||||
ALLOWED_STEP_METHODS = T.let(
|
||||
[*FILE_PREPARATION_STEP_METHODS, *LINK_STEP_METHODS, *CONFIG_WRITE_STEP_METHODS, *SERVICE_DATA_STEP_METHODS,
|
||||
|
||||
@@ -927,6 +927,93 @@ RSpec.describe Homebrew::InstallSteps do
|
||||
Homebrew::InstallSteps::Runner.new(context: clang_context).run(steps)
|
||||
end
|
||||
|
||||
describe "configures PHP" do
|
||||
let(:steps) do
|
||||
Homebrew::InstallSteps::DSL.build do
|
||||
configure_php
|
||||
end
|
||||
end
|
||||
let(:homebrew_prefix) { root/"homebrew" }
|
||||
let(:pear_prefix) { root/"prefix/share/php@8.4/pear" }
|
||||
let(:pecl_path) { homebrew_prefix/"lib/php/pecl" }
|
||||
let(:ext_config_path) { homebrew_prefix/"etc/php/8.4/conf.d/ext-opcache.ini" }
|
||||
let(:php_context) do
|
||||
root_path = root
|
||||
context.tap do |value|
|
||||
value.define_singleton_method(:name) { "php@8.4" }
|
||||
value.define_singleton_method(:version) { Version.new("8.4.1") }
|
||||
value.define_singleton_method(:pkgshare) { root_path/"prefix/share/php@8.4" }
|
||||
value.define_singleton_method(:opt_prefix) { root_path/"opt/php@8.4" }
|
||||
value.define_singleton_method(:etc) { root_path/"homebrew/etc" }
|
||||
end
|
||||
end
|
||||
let(:runner) { Homebrew::InstallSteps::Runner.new(context: php_context) }
|
||||
|
||||
before do
|
||||
stub_const("HOMEBREW_PREFIX", homebrew_prefix)
|
||||
(pear_prefix/".channels/.alias").mkpath
|
||||
(pear_prefix/".channels/pear.php.net.reg").write "channel"
|
||||
(pear_prefix/".channels/.alias/pear.txt").write "alias"
|
||||
(pear_prefix/".depdblock").write "lock"
|
||||
FileUtils.chmod 0700, [pear_prefix/".channels", pear_prefix/".channels/.alias"]
|
||||
FileUtils.chmod 0600, [pear_prefix/".channels/pear.php.net.reg", pear_prefix/".channels/.alias/pear.txt",
|
||||
pear_prefix/".depdblock"]
|
||||
(homebrew_prefix/"share").mkpath
|
||||
File.symlink root/"missing-pecl", root/"prefix/pecl"
|
||||
allow(runner).to receive(:run_command_output)
|
||||
.with(root/"prefix/bin/php-config", "--extension-dir")
|
||||
.and_return("/usr/local/lib/php/20240924\n")
|
||||
allow(runner).to receive(:run_command)
|
||||
end
|
||||
|
||||
specify "updates PEAR, PECL and opcache configuration", :aggregate_failures do
|
||||
expect(runner).to receive(:run_command).with(
|
||||
root/"prefix/bin/pear", "config-set", "ext_dir", pecl_path/"20240924", "system"
|
||||
).ordered
|
||||
expect(runner).to receive(:run_command).with(root/"prefix/bin/pear", "update-channels").ordered
|
||||
|
||||
runner.run(steps)
|
||||
|
||||
expect((pear_prefix/".channels").stat.mode & 0777).to eq(0755)
|
||||
expect((pear_prefix/".channels/.alias").stat.mode & 0777).to eq(0755)
|
||||
expect((pear_prefix/".channels/pear.php.net.reg").stat.mode & 0777).to eq(0644)
|
||||
expect((pear_prefix/".channels/.alias/pear.txt").stat.mode & 0777).to eq(0644)
|
||||
expect((pear_prefix/".depdblock").stat.mode & 0777).to eq(0644)
|
||||
expect(root/"prefix/pecl").to be_a_symlink
|
||||
expect((root/"prefix/pecl").readlink).to eq(pecl_path)
|
||||
expect(pecl_path/"20240924").to be_a_directory
|
||||
expect(homebrew_prefix/"share/pear@8.4/.depdblock").to exist
|
||||
expect(ext_config_path.read).to eq <<~INI
|
||||
[opcache]
|
||||
zend_extension="#{root}/opt/php@8.4/lib/php/20240924/opcache.so"
|
||||
INI
|
||||
end
|
||||
|
||||
specify "only replaces the active opcache extension setting" do
|
||||
ext_config_path.dirname.mkpath
|
||||
ext_config_path.write <<~INI
|
||||
; zend_extension=keep.so
|
||||
zend_extension = old.so
|
||||
description=zend_extension=also-keep
|
||||
INI
|
||||
|
||||
runner.run(steps)
|
||||
|
||||
expect(ext_config_path.read).to eq <<~INI
|
||||
; zend_extension=keep.so
|
||||
zend_extension="#{root}/opt/php@8.4/lib/php/20240924/opcache.so"
|
||||
description=zend_extension=also-keep
|
||||
INI
|
||||
end
|
||||
|
||||
specify "audits existing opcache extension settings" do
|
||||
ext_config_path.dirname.mkpath
|
||||
ext_config_path.write "[opcache]\n"
|
||||
|
||||
expect { runner.run(steps) }.to raise_error(Utils::Inreplace::Error)
|
||||
end
|
||||
end
|
||||
|
||||
describe "runs gtk_update_icon_cache rebuild action" do
|
||||
let(:formula) { instance_double(Formula, opt_bin: root/"opt/bin") }
|
||||
let(:steps) do
|
||||
|
||||
@@ -41,7 +41,7 @@ RSpec.describe RuboCop::Cop::FormulaAudit::InstallSteps do
|
||||
|
||||
post_install_steps do
|
||||
system "true"
|
||||
^^^^^^^^^^^^^ FormulaAudit/InstallSteps: Steps blocks may only contain install step DSL calls: `mkdir`, `mkdir_p`, `touch`, `move`, `mv`, `move_children`, `move_contents`, `copy`, `remove`, `inreplace`, `symlink`, `ln_s`, `ln_sf`, `link_dir`, `link_children`, `write`, `init_data_dir`, `compile_gsettings_schemas`, `gio_querymodules`, `gdk_pixbuf_query_loaders`, `gtk_update_icon_cache`, `update_mime_database`, `update_desktop_database`, `set_permissions`, `run`, `terminate_process`, `warn`, `change_dylib_id`, `configure_gcc_runtime`, `install_gzipped_executable`, `configure_glibc_runtime`, `configure_clang_system`, `if_path_exists`, `unless_path_exists`, `on_macos`, `on_linux`.
|
||||
^^^^^^^^^^^^^ FormulaAudit/InstallSteps: Steps blocks may only contain install step DSL calls: `mkdir`, `mkdir_p`, `touch`, `move`, `mv`, `move_children`, `move_contents`, `copy`, `remove`, `inreplace`, `symlink`, `ln_s`, `ln_sf`, `link_dir`, `link_children`, `write`, `init_data_dir`, `compile_gsettings_schemas`, `gio_querymodules`, `gdk_pixbuf_query_loaders`, `gtk_update_icon_cache`, `update_mime_database`, `update_desktop_database`, `set_permissions`, `run`, `terminate_process`, `warn`, `change_dylib_id`, `configure_gcc_runtime`, `install_gzipped_executable`, `configure_glibc_runtime`, `configure_clang_system`, `configure_php`, `if_path_exists`, `unless_path_exists`, `on_macos`, `on_linux`.
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
@@ -72,6 +72,7 @@ RSpec.describe RuboCop::Cop::FormulaAudit::InstallSteps do
|
||||
install_gzipped_executable "compressed.gz", "bin/executable"
|
||||
configure_glibc_runtime
|
||||
configure_clang_system
|
||||
configure_php
|
||||
write "foo/banner", <<~TEXT
|
||||
literal banner
|
||||
TEXT
|
||||
@@ -107,7 +108,7 @@ RSpec.describe RuboCop::Cop::FormulaAudit::InstallSteps do
|
||||
post_install_steps do
|
||||
on_macos do
|
||||
system "true"
|
||||
^^^^^^^^^^^^^ FormulaAudit/InstallSteps: Steps blocks may only contain install step DSL calls: `mkdir`, `mkdir_p`, `touch`, `move`, `mv`, `move_children`, `move_contents`, `copy`, `remove`, `inreplace`, `symlink`, `ln_s`, `ln_sf`, `link_dir`, `link_children`, `write`, `init_data_dir`, `compile_gsettings_schemas`, `gio_querymodules`, `gdk_pixbuf_query_loaders`, `gtk_update_icon_cache`, `update_mime_database`, `update_desktop_database`, `set_permissions`, `run`, `terminate_process`, `warn`, `change_dylib_id`, `configure_gcc_runtime`, `install_gzipped_executable`, `configure_glibc_runtime`, `configure_clang_system`, `if_path_exists`, `unless_path_exists`, `on_macos`, `on_linux`.
|
||||
^^^^^^^^^^^^^ FormulaAudit/InstallSteps: Steps blocks may only contain install step DSL calls: `mkdir`, `mkdir_p`, `touch`, `move`, `mv`, `move_children`, `move_contents`, `copy`, `remove`, `inreplace`, `symlink`, `ln_s`, `ln_sf`, `link_dir`, `link_children`, `write`, `init_data_dir`, `compile_gsettings_schemas`, `gio_querymodules`, `gdk_pixbuf_query_loaders`, `gtk_update_icon_cache`, `update_mime_database`, `update_desktop_database`, `set_permissions`, `run`, `terminate_process`, `warn`, `change_dylib_id`, `configure_gcc_runtime`, `install_gzipped_executable`, `configure_glibc_runtime`, `configure_clang_system`, `configure_php`, `if_path_exists`, `unless_path_exists`, `on_macos`, `on_linux`.
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -121,7 +122,7 @@ RSpec.describe RuboCop::Cop::FormulaAudit::InstallSteps do
|
||||
|
||||
post_install_steps do
|
||||
write "foo.conf", "prefix = #{prefix}"
|
||||
^^^^^^^^^ FormulaAudit/InstallSteps: Steps blocks may only contain install step DSL calls: `mkdir`, `mkdir_p`, `touch`, `move`, `mv`, `move_children`, `move_contents`, `copy`, `remove`, `inreplace`, `symlink`, `ln_s`, `ln_sf`, `link_dir`, `link_children`, `write`, `init_data_dir`, `compile_gsettings_schemas`, `gio_querymodules`, `gdk_pixbuf_query_loaders`, `gtk_update_icon_cache`, `update_mime_database`, `update_desktop_database`, `set_permissions`, `run`, `terminate_process`, `warn`, `change_dylib_id`, `configure_gcc_runtime`, `install_gzipped_executable`, `configure_glibc_runtime`, `configure_clang_system`, `if_path_exists`, `unless_path_exists`, `on_macos`, `on_linux`.
|
||||
^^^^^^^^^ FormulaAudit/InstallSteps: Steps blocks may only contain install step DSL calls: `mkdir`, `mkdir_p`, `touch`, `move`, `mv`, `move_children`, `move_contents`, `copy`, `remove`, `inreplace`, `symlink`, `ln_s`, `ln_sf`, `link_dir`, `link_children`, `write`, `init_data_dir`, `compile_gsettings_schemas`, `gio_querymodules`, `gdk_pixbuf_query_loaders`, `gtk_update_icon_cache`, `update_mime_database`, `update_desktop_database`, `set_permissions`, `run`, `terminate_process`, `warn`, `change_dylib_id`, `configure_gcc_runtime`, `install_gzipped_executable`, `configure_glibc_runtime`, `configure_clang_system`, `configure_php`, `if_path_exists`, `unless_path_exists`, `on_macos`, `on_linux`.
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
|
||||
@@ -1155,6 +1155,7 @@ Use the named actions below for formula families that share post-install algorit
|
||||
* `install_gzipped_executable`: unpack and install a gzipped executable.
|
||||
* `configure_glibc_runtime`: generate requested glibc locales and timezone links.
|
||||
* `configure_clang_system`: generate macOS Clang system configuration files.
|
||||
* `configure_php`: configure shared PEAR and PECL state.
|
||||
|
||||
#### Service data directory steps
|
||||
|
||||
|
||||
Reference in New Issue
Block a user