Files
yay/doc/lua.md
T
Jo 1501438fba AUR: Add AURPreInstall hooks (#2854)
* add lua hooks on aur package installs

* add abort command to differentiate errors and aborts

* u
2026-06-15 13:31:13 +02:00

4.3 KiB

Lua configuration (init.lua)

yay can optionally load a Lua configuration file, init.lua. init.lua overlays whatever is in config.json, and any command-line flag you pass still wins over init.lua.

Location

init.lua is looked up, in order:

  1. $XDG_CONFIG_HOME/yay/init.lua
  2. $HOME/.config/yay/init.lua

Setting options with yay.opt

Assign to keys on the yay.opt table using the exact option names shown below.

yay.opt.bottom_up = false
yay.opt.clean_after = true
yay.opt.sort_by = "votes"
yay.opt.request_split_n = 150
yay.opt.editor = os.getenv("EDITOR") or "vi"

Unknown keys and values of the wrong type are treated as errors. yay aborts startup and reports the offending keys/values so misconfigurations fail fast.

Available options

Strings

aururl, aurrpcurl, build_dir, editor, editor_flags, makepkg_bin, makepkg_conf, pacman_bin, pacman_conf, redownload, rebuild, git_bin, gpg_bin, gpg_flags, mflags, sort_by, search_by, git_flags, remove_make, sudo_bin, sudo_flags

Integers

request_split_n, completion_refresh_time, max_concurrent_downloads

Booleans

bottom_up, sudo_loop, devel, clean_after, keep_src, provides, pgp_fetch, clean_menu, diff_menu, edit_menu, combined_upgrade, use_ask, batch_install, single_line_results, separate_sources, debug, rpc, double_confirm

A ready-to-copy example lives at doc/init.lua.

AUR pre-install hooks

init.lua can register hooks with a small autocmd API:

yay.create_autocmd("AURPreInstall", {
  desc = "inspect or modify AUR package files",
  callback = function(event)
    -- event.match is the package base.
    -- event.data has package metadata and local file paths.
  end,
})

AURPreInstall runs once per AUR package base, in sorted package-base order, after the AUR PKGBUILD repositories are downloaded and merged. It runs before the clean, diff, and edit menus, and before source downloads or builds.

Use yay.abort("message") for controlled policy stops without a Lua traceback. If a callback raises a Lua error, yay aborts the install before build work starts and includes the Lua traceback for debugging.

Changing fields in the Lua event table does not change yay's internal package state. Hooks can still edit files through Lua's normal io and os libraries; later menus and build steps will see those file changes.

AURPreInstall event

The callback receives this table:

{
  event = "AURPreInstall",
  match = "pkgbase",
  data = {
    base = "pkgbase",
    dir = "/path/to/build/pkgbase",
    pkgbuild_path = "/path/to/build/pkgbase/PKGBUILD",
    srcinfo_path = "/path/to/build/pkgbase/.SRCINFO",
    pkgbuild = "...PKGBUILD contents...",
    version = "1:1.2.3-4",
    last_modified = 1700000000,
    installed = true,
    packages = {
      {
        name = "pkgname",
        version = "1:1.2.3-4",
        local_version = "1:1.2.3-3",
        reason = "explicit",
        upgrade = true,
        devel = false,
      },
    },
    srcinfo = {
      pkgbase = "pkgbase",
      pkgver = "1.2.3",
      pkgrel = "4",
      epoch = "1",
      version = "1:1.2.3-4",
      pkgdesc = "description",
      url = "https://example.invalid",
      arch = { "x86_64" },
      license = { "MIT" },
      depends = { "glibc" },
      makedepends = { "go" },
      checkdepends = { "bats" },
      optdepends = { "pkg: optional feature" },
      provides = { "virtual-pkg" },
      conflicts = { "old-pkg" },
      replaces = { "older-pkg" },
    },
  },
}

data.packages contains the target packages for that base. Split packages are listed separately. reason is one of explicit, dependency, make_dependency, check_dependency, or unknown.

Example

yay.create_autocmd("AURPreInstall", {
  desc = "block forbidden sources and patch a PKGBUILD",
  callback = function(event)
    if event.data.pkgbuild:match("forbidden.example") then
      yay.abort(event.match .. ": forbidden source URL")
    end

    if event.match == "demo-pkg" then
      local path = event.data.pkgbuild_path
      local f = assert(io.open(path, "r"))
      local body = f:read("*a")
      f:close()

      body = body:gsub("options=%('strip'%)", "options=('!strip')")

      f = assert(io.open(path, "w"))
      f:write(body)
      f:close()
    end
  end,
})