Add gzipped executable action

Several binary formulae ship a gzipped executable that needs the same
guarded post-install expansion and mode handling.

- resolve serialised source and destination path bases
- skip absent payloads and replace stale expanded sources
- install each executable with an explicit literal permission mode
This commit is contained in:
Mike McQuaid
2026-07-26 18:13:04 +01:00
parent 6ae6def23a
commit a959228644
6 changed files with 81 additions and 4 deletions
+16
View File
@@ -608,6 +608,20 @@ module Homebrew
add_step("configure_gcc_runtime")
end
sig {
params(
source: ::T.any(::String, ::Pathname),
target: ::T.any(::String, ::Pathname),
source_base: ::T.nilable(::T.any(::String, ::Symbol)),
target_base: ::T.nilable(::T.any(::String, ::Symbol)),
).void
}
def install_gzipped_executable(source, target, source_base: nil, target_base: nil)
add_step("install_gzipped_executable",
"source" => path_spec(source, base: source_base, default_base: @default_source_base),
"target" => path_spec(target, base: target_base, default_base: @default_target_base))
end
private
sig { params(guard: PathSpec, block: ::T.proc.void).void }
@@ -852,6 +866,8 @@ module Homebrew
opoo expand_template_tokens(step_string(step, "message"))
when "configure_gcc_runtime"
run_configure_gcc_runtime
when "install_gzipped_executable"
run_install_gzipped_executable(step)
when "set_permissions"
run_set_permissions(step)
when "set_ownership"
@@ -60,6 +60,30 @@ module Homebrew
EOS
specs.write(specs.read.gsub(" %o ", "\\0%(homebrew_rpath) ")) if homebrew_rpath
end
sig { params(step: Step).void }
def run_install_gzipped_executable(step)
source = resolve_path(step_path(step, "source"))
return unless source.exist?
require "zlib"
target = resolve_path(step_path(step, "target"))
target.dirname.mkpath
temporary_target = target.dirname/".#{target.basename}.install-step"
FileUtils.rm_f temporary_target
begin
Zlib::GzipReader.open(source.to_s) do |gzip|
IO.copy_stream(gzip, temporary_target.to_s)
end
FileUtils.rm_f target
FileUtils.mv temporary_target, target
source.unlink
ensure
FileUtils.rm_f temporary_target
end
target.chmod 0755
end
end
end
end
@@ -17,7 +17,7 @@ module RuboCop
PERMISSION_STEP_METHODS = [:set_permissions, :set_ownership].freeze
COMMAND_STEP_METHODS = [:run, :terminate_process].freeze
NOTICE_STEP_METHODS = [:warn].freeze
FORMULA_ACTION_STEP_METHODS = [:configure_gcc_runtime].freeze
FORMULA_ACTION_STEP_METHODS = [:configure_gcc_runtime, :install_gzipped_executable].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,
@@ -770,6 +770,41 @@ RSpec.describe Homebrew::InstallSteps do
expect(specs.read).to include("%(homebrew_rpath)", "-idirafter /usr/include/x86_64-linux-gnu")
end
specify "dispatches gzipped executable installation" do
steps = Homebrew::InstallSteps::DSL.build do
install_gzipped_executable "compressed.gz", "bin/executable"
end
runner = Homebrew::InstallSteps::Runner.new(context:)
expect(runner).to receive(:run_install_gzipped_executable)
runner.run(steps)
end
specify "installs a gzipped executable with a fixed mode", :aggregate_failures do
require "zlib"
source = root/"prefix/bin/executable.gz"
source.dirname.mkpath
Zlib::GzipWriter.open(source.to_s) do |gzip|
gzip.orig_name = "stored-name"
gzip.write "executable"
end
stored_name = source.dirname/"stored-name"
stored_name.write "preserve"
steps = Homebrew::InstallSteps::DSL.build(default_source_base: :prefix, default_target_base: :prefix) do
install_gzipped_executable "bin/executable.gz", "bin/executable"
end
Homebrew::InstallSteps::Runner.new(context:).run(steps)
target = root/"prefix/bin/executable"
expect(target.read).to eq("executable")
expect(target.stat.mode & 0777).to eq(0755)
expect(source).not_to exist
expect(stored_name.read).to eq("preserve")
end
describe "runs gtk_update_icon_cache rebuild action" do
let(:formula) { instance_double(Formula, opt_bin: root/"opt/bin") }
let(:steps) do
@@ -42,7 +42,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`, `configure_gcc_runtime`, `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`, `configure_gcc_runtime`, `install_gzipped_executable`, `if_path_exists`, `unless_path_exists`, `on_macos`, `on_linux`.
end
end
RUBY
@@ -68,6 +68,7 @@ RSpec.describe RuboCop::Cop::FormulaAudit::InstallSteps do
terminate_process "foo", attempts: 3
warn "foo exists"
configure_gcc_runtime
install_gzipped_executable "compressed.gz", "bin/executable"
write "foo/banner", <<~TEXT
literal banner
TEXT
@@ -103,7 +104,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`, `configure_gcc_runtime`, `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`, `configure_gcc_runtime`, `install_gzipped_executable`, `if_path_exists`, `unless_path_exists`, `on_macos`, `on_linux`.
end
end
end
@@ -117,7 +118,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`, `configure_gcc_runtime`, `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`, `configure_gcc_runtime`, `install_gzipped_executable`, `if_path_exists`, `unless_path_exists`, `on_macos`, `on_linux`.
end
end
RUBY
+1
View File
@@ -1118,6 +1118,7 @@ end
Use the named actions below for formula families that share post-install algorithms. Unique complex logic should be installed as a packaged helper and invoked with `run` instead of adding a formula-specific action.
* `configure_gcc_runtime`: generate the Linux GCC runtime links and specs.
* `install_gzipped_executable`: unpack and install a gzipped executable.
#### Service data directory steps