Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions Library/Homebrew/install_steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,36 @@ def ln_sf(source, target, source_base: nil, target_base: nil, source_formula: ni
symlink(source, target, source_base:, target_base:, source_formula:, target_formula:, force: true, uninstall:)
end

sig { void }
def compile_gsettings_schemas
add_rebuild_action("compile_gsettings_schemas", "share/glib-2.0/schemas")
end

sig { void }
def gio_querymodules
add_rebuild_action("gio_querymodules", "lib/gio/modules")
end

sig { void }
def gdk_pixbuf_query_loaders
add_step("gdk_pixbuf_query_loaders")
end

sig { void }
def gtk_update_icon_cache
add_rebuild_action("gtk_update_icon_cache", "share/icons/hicolor")
end

sig { void }
def update_mime_database
add_rebuild_action("update_mime_database", "share/mime")
end

sig { void }
def update_desktop_database
add_rebuild_action("update_desktop_database", "share/applications")
end

private

sig { params(type: ::String, fields: ::T.untyped).void }
Expand All @@ -177,6 +207,11 @@ def add_step(type, **fields)
@steps << ::T.cast(::Utils.deep_compact_blank(step), Step)
end

sig { params(type: ::String, path: ::String).void }
def add_rebuild_action(type, path)
add_step(type, "path" => path_spec(path, base: :homebrew_prefix))
end

sig {
params(
path: ::T.any(::String, ::Pathname),
Expand Down Expand Up @@ -255,6 +290,18 @@ def run_install_step(step)
target.dirname.mkpath
FileUtils.rm_f target if step["force"] == true
File.symlink link_source(step.fetch("source")), target
when "compile_gsettings_schemas"
run_formula_tool("glib", "glib-compile-schemas", resolve_path(step.fetch("path")))
when "gio_querymodules"
run_formula_tool("glib", "gio-querymodules", resolve_path(step.fetch("path")))
when "gdk_pixbuf_query_loaders"
run_formula_tool("gdk-pixbuf", "gdk-pixbuf-query-loaders", "--update-cache")
when "gtk_update_icon_cache"
run_formula_tool("gtk+3", "gtk3-update-icon-cache", "-q", "-t", "-f", resolve_path(step.fetch("path")))
when "update_mime_database"
run_formula_tool("shared-mime-info", "update-mime-database", resolve_path(step.fetch("path")))
when "update_desktop_database"
run_formula_tool("desktop-file-utils", "update-desktop-database", resolve_path(step.fetch("path")))
else
raise ArgumentError, "unknown install step: #{step.fetch("type")}"
end
Expand Down Expand Up @@ -299,6 +346,11 @@ def normalise_path_spec(spec)
end
end

sig { params(formula: String, executable: String, args: T.untyped).void }
def run_formula_tool(formula, executable, *args)
@context.send(:safe_system, Formula[formula].opt_bin/executable, *args)
end

sig { params(base: String, formula: T.nilable(String)).returns(Pathname) }
def root_path(base, formula)
case base
Expand Down
20 changes: 16 additions & 4 deletions Library/Homebrew/json_api_postinstall_preflight_postflight_plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,20 @@ future step types that invoke non-Homebrew code.
Future cask work should sandbox all `*flight` run scripts from non-Homebrew and
non-system sources, for example scripts shipped by upstream artifacts.

For each future operation type, check `homebrew/core` and `homebrew/cask`
separately and add formula support only when needed by `homebrew/core` or cask
support only when needed by `homebrew/cask`.

RuboCop autocorrection converts the simplest existing `post_install` and
`*flight` Ruby blocks to steps blocks when every statement is a supported file
preparation operation with literal paths and known bases. Future post-install
and `*flight` DSLs should include the same style of conservative autocorrection
from the matching legacy Ruby pattern where possible.

Before opening follow-up PRs, run `bundle exec rake lint` from `docs/` to catch
markdown lint issues and run `brew style homebrew/core homebrew/cask` to catch
tap-wide formula or cask opportunities exposed by the new DSLs.

## Formula Patterns

Local scan source: `homebrew/core` at `fb0ca6682b4`.
Expand Down Expand Up @@ -161,15 +169,19 @@ be resolved before the download can be enqueued.
`uninstall: true` symlink cleanup available for install-phase steps. Keep
the tap-wide autocorrect audit in a follow-up commit so the implementation
can land before converted casks.
- [ ] PR 4, desktop and cache rebuild actions.
- [x] PR 4, desktop and cache rebuild actions.
Estimated existing formulae/casks affected: about `35` formulae run rebuild
tools such as `glib-compile-schemas`, `gtk*-update-icon-cache`,
`gio-querymodules`, `gdk-pixbuf-query-loaders`, `update-mime-database` and
`update-desktop-database`; no cask count was identified in the initial scan.
Scope: shared named action types for GSettings schemas, GIO modules,
GDK Pixbuf loaders, GTK icon caches, MIME databases and desktop databases,
runner dispatch through Homebrew-owned tools and docs.
Notes for implementation: add named action types rather than raw commands;
define idempotence and failure handling; include RuboCop autocorrection for
exact known command patterns only; decide whether any action invokes
non-Homebrew code and should be ready for future sandboxing.
define idempotence and failure handling; decide whether any action invokes
non-Homebrew code and should be ready for future sandboxing. Land RuboCop
autocorrection and tap-wide conversions in a separate follow-up after the
new DSL methods are available in a stable Homebrew release.
- [ ] PR 5, default config and template writes.
Estimated existing formulae/casks affected: about `71` formulae write or
patch default configuration/data files, and a subset of the `78` file-prep
Expand Down
31 changes: 31 additions & 0 deletions Library/Homebrew/test/install_steps_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,37 @@
)
end

specify "runs named desktop and cache rebuild actions" do
steps = Homebrew::InstallSteps::DSL.build do
compile_gsettings_schemas
gio_querymodules
gdk_pixbuf_query_loaders
gtk_update_icon_cache
update_mime_database
update_desktop_database
end

formula = instance_double(Formula, opt_bin: root/"opt/bin")
allow(Formula).to receive(:[]).with("glib").and_return(formula)
allow(Formula).to receive(:[]).with("gdk-pixbuf").and_return(formula)
allow(Formula).to receive(:[]).with("gtk+3").and_return(formula)
allow(Formula).to receive(:[]).with("shared-mime-info").and_return(formula)
allow(Formula).to receive(:[]).with("desktop-file-utils").and_return(formula)
expect(context).to receive(:safe_system).with(root/"opt/bin/glib-compile-schemas",
HOMEBREW_PREFIX/"share/glib-2.0/schemas").ordered
expect(context).to receive(:safe_system).with(root/"opt/bin/gio-querymodules",
HOMEBREW_PREFIX/"lib/gio/modules").ordered
expect(context).to receive(:safe_system).with(root/"opt/bin/gdk-pixbuf-query-loaders", "--update-cache").ordered
expect(context).to receive(:safe_system).with(root/"opt/bin/gtk3-update-icon-cache", "-q", "-t", "-f",
HOMEBREW_PREFIX/"share/icons/hicolor").ordered
expect(context).to receive(:safe_system).with(root/"opt/bin/update-mime-database",
HOMEBREW_PREFIX/"share/mime").ordered
expect(context).to receive(:safe_system).with(root/"opt/bin/update-desktop-database",
HOMEBREW_PREFIX/"share/applications").ordered

Homebrew::InstallSteps::Runner.new(context:).run(steps)
end

specify "does not add the default base to home paths" do
steps = Homebrew::InstallSteps::DSL.build(default_base: :var) do
mkdir_p "~/example"
Expand Down
16 changes: 15 additions & 1 deletion docs/Cask-Cookbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,21 @@ postflight_steps do
end
```

`mkdir`, `mkdir_p`, `touch`, `move`, `mv`, `move_children`, `symlink`, `ln_s` and `ln_sf` are available in steps blocks. Relative paths default to `staged_path` for `base:`, `source_base:` and `target_base:`. Symlink steps can use `uninstall: true` to remove the symlink during uninstall. A steps block may only contain those step calls with literal arguments; it cannot call the wider cask DSL or arbitrary Ruby code. Each phase may define either its Ruby flight block or its matching steps block, not both.
A steps block may only contain supported step calls with literal arguments; it cannot call the wider cask DSL or arbitrary Ruby code. Each phase may define either its Ruby flight block or its matching steps block, not both.

#### File preparation steps

Relative paths default to `staged_path` for `base:`, `source_base:` and `target_base:`. Symlink steps can use `uninstall: true` to remove the symlink during uninstall.

* `mkdir`: create one directory; example: `mkdir "Shared"`.
* `mkdir_p`: create a directory and any missing parents; example: `mkdir_p "Shared"`.
* `touch`: create or update a file timestamp; example: `touch "Shared/state"`.
* `move`: move one file or directory; example: `move "payload", "Shared/payload"`.
* `mv`: alias for `move`; example: `mv "payload", "Shared/payload"`.
* `move_children`: move the contents of one directory into another; example: `move_children "payload", "Shared/payload"`.
* `symlink`: create a symlink; example: `symlink "Shared/payload", "Payload", source_base: :relative`.
* `ln_s`: alias for `symlink`; example: `ln_s "Shared/payload", "Payload", source_base: :relative`.
* `ln_sf`: create or replace a symlink; example: `ln_sf "Shared/payload", "Payload", source_base: :relative, uninstall: true`.

Flight blocks are not currently run in the cask sandbox. They should be written as though they may be sandboxed in the future: prefer the mini-DSL helpers below and keep filesystem writes limited to paths owned by the cask.

Expand Down
27 changes: 26 additions & 1 deletion docs/Formula-Cookbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -1116,7 +1116,32 @@ class Foo < Formula
end
```

`mkdir`, `mkdir_p` and `touch` default to paths relative to `var`. `move`, `mv`, `move_children`, `symlink`, `ln_s` and `ln_sf` default their source and target paths to `prefix`. Use `base:`, `source_base:` or `target_base:` when a step needs another formula path such as `pkgetc`; use `source_base: :relative` for relative symlink sources. A formula may define either `post_install_steps` or `post_install`, not both.
A formula may define either `post_install_steps` or `post_install`, not both.

#### File preparation steps

`mkdir`, `mkdir_p` and `touch` default to paths relative to `var`. `move`, `mv`, `move_children`, `symlink`, `ln_s` and `ln_sf` default their source and target paths to `prefix`. Use `base:`, `source_base:` or `target_base:` when a step needs another formula path such as `pkgetc`; use `source_base: :relative` for relative symlink sources.

* `mkdir`: create one directory; example: `mkdir "log/foo"`.
* `mkdir_p`: create a directory and any missing parents; example: `mkdir_p "log/foo"`.
* `touch`: create or update a file timestamp; example: `touch "foo/state"`.
* `move`: move one file or directory; example: `move "default.conf", "foo/default.conf"`.
* `mv`: alias for `move`; example: `mv "default.conf", "foo/default.conf"`.
* `move_children`: move the contents of one directory into another; example: `move_children "defaults", "foo/defaults"`.
* `symlink`: create a symlink; example: `symlink "cert.pem", "foo/cert.pem", source_base: :relative`.
* `ln_s`: alias for `symlink`; example: `ln_s "cert.pem", "foo/cert.pem", source_base: :relative`.
* `ln_sf`: create or replace a symlink; example: `ln_sf "cert.pem", "foo/cert.pem", source_base: :relative`.

#### Desktop and cache rebuild steps

These steps rebuild shared desktop and cache state using Homebrew-owned tools.

* `compile_gsettings_schemas`: compile GSettings schemas in `share/glib-2.0/schemas`.
* `gio_querymodules`: rebuild the GIO module cache in `lib/gio/modules`.
* `gdk_pixbuf_query_loaders`: update the GDK Pixbuf loader cache.
* `gtk_update_icon_cache`: refresh the `hicolor` GTK icon cache.
* `update_mime_database`: rebuild the shared MIME database in `share/mime`.
* `update_desktop_database`: rebuild the desktop entry database in `share/applications`.

```ruby
class Foo < Formula
Expand Down
Loading