Skip to main content

INSTALL

Produce the final package directory: the pkg/ tree that gets cached, shared between projects, published to depots, and resolved into by products.

Once INSTALL succeeds, envy writes the completion marker and the package is immutable. Consumers resolve into it from then on, and nothing edits it in place. Work that has to touch the machine belongs in SETUP.

The three shapes​

ShapeMeaning
omittedThe staged tree becomes the package.
stringA shell script, run in work/stage/.
function INSTALL(install_dir, stage_dir, fetch_dir, tmp_dir, opts)File surgery, platform installers, hand-assembled trees. May return a string to run as a script.

omitted​

FETCH = "https://vendor.example/tool-1.2-linux-x86_64.tar.gz"
STAGE = { strip = 1 }
-- no INSTALL

Two things can happen, and neither costs a copy of the tree. If extraction already went straight into pkg/, which is the usual case for a spec with no function verbs, envy marks the entry complete. Otherwise it renames the staged tree into place.

string​

BUILD = function(install_dir) return "./configure --prefix=" .. install_dir .. "\nmake -j" end
INSTALL = "make install"

The autotools pair. The script's working directory is work/stage/, so make install finds the tree BUILD configured, and the --prefix from BUILD sends the output into pkg/.

function for file surgery​

The most common reason to write INSTALL is that the vendor's layout is not the layout you want.

-- The archive ships `taplo-darwin-aarch64`, but the product should be plain `taplo`.
INSTALL = function(install_dir, stage_dir, fetch_dir, tmp_dir, opts)
local bin = envy.path.join(install_dir, "taplo" .. envy.EXE_EXT)
if envy.PLATFORM == "windows" then
envy.copy(envy.path.join(stage_dir, "taplo.exe"), bin)
else
local arch = (envy.ARCH == "arm64") and "aarch64" or envy.ARCH
envy.copy(envy.path.join(stage_dir, "taplo-" .. envy.PLATFORM .. "-" .. arch), bin)
envy.run("chmod +x " .. bin)
end
end

Keeping only part of a build's output has the same shape:

INSTALL = function(install_dir, stage_dir, fetch_dir, tmp_dir, opts)
local src = (envy.PLATFORM == "darwin") and envy.path.join(stage_dir, "build", "bin")
or envy.path.join(stage_dir, "bin")
for _, tool in ipairs(opts.tools) do
envy.move(envy.path.join(src, tool .. envy.EXE_EXT),
envy.path.join(install_dir, tool .. envy.EXE_EXT))
end
end

function running a platform installer​

Some vendors ship only an installer. Run it, but point it at install_dir so the result is still a normal cache-managed package. This one packages the AWS CLI because a project wants the CLI itself, not because envy needs it: s3:// URLs are handled by the AWS SDK compiled into envy.

INSTALL = function(install_dir, stage_dir, fetch_dir, tmp_dir, opts)
if envy.PLATFORM == "darwin" then
envy.run("installer -pkg " .. fetch_dir .. "AWSCLIV2.pkg" ..
" -target CurrentUserHomeDirectory -applyChoiceChangesXML " ..
tmp_dir .. "choices.xml")
elseif envy.PLATFORM == "windows" then
envy.run('msiexec.exe /a "' .. fetch_dir .. 'AWSCLIV2.msi" /qn TARGETDIR="' ..
install_dir .. '"')
else
envy.run(stage_dir .. "aws/install --install-dir " .. install_dir .. "aws-cli" ..
" --bin-dir " .. install_dir .. "bin")
end
end

An installer that insists on a system location, or on running once per machine, is not a package. See user-managed.

function returning a script​

Same rule as BUILD. A returned string runs as a shell script with the working directory set to work/stage/. Returning anything other than nil or a string is an error.

EXPORTABLE​

EXPORTABLE = true

One boolean, evaluated when the spec loads, that decides what a depot may publish for this package:

ValueWhat a depot shipsWhy
trueThe installed pkg/ treeThe build is reproducible and relocatable, so consumers can skip it.
absent or falseThe fetch/ artifactsThe install has to run on each machine, for example a platform installer or a path baked in at install time. Sharing the download is still worthwhile.

That is also why a non-exportable package keeps its fetch/ directory after completing, while an exportable one deletes it.

Because the value is evaluated at load time, a per-platform decision is ordinary Lua:

EXPORTABLE = envy.PLATFORM ~= "windows" -- the Windows installer is not relocatable

User-managed packages are never exported. There is nothing in the cache to export.

See also​