| git.druid.rocks | index | druid520 | mp | src/ | hook.pl |
src/hook.pl
#!/usr/bin/env perl
use v5.16;
use strict;
use warnings FATAL => 'all';
use FindBin;
use lib "$FindBin::Bin";
use mplib::config qw($CFG);
use mplib::util qw(fail);
use mplib::hooks qw(run_hook);
# lets a phase script fire an arbitrary, port-author-chosen hook point
# mid-phase -- "$MP_HOOK my-custom-step" (MP_HOOK is exported to every
# phase script by mplib::hooks::port_env_args, pointing at this file) --
# reusing the exact same run_hook() every built-in pre_/post_<phase>
# already goes through: hook_my-custom-step= in mp.conf, HOOKS_DIR/
# my-custom-step/*, and that directory's own optional hooks.conf pipeline
# all just work, with zero extra code on the port-author or mp side.
# the fixed lifecycle names run_hook is already invoked with elsewhere
# (mplib::resolve's install_pkg_body/remove_pkg_body/sync_ports) -- a
# custom-triggered event reusing one of these would re-fire whatever
# hook_<phase>=/HOOKS_DIR/<phase>/* is configured for it a second time,
# mid-phase, before (or instead of) the real lifecycle boundary, with no
# indication anything unusual happened. a typo or copy-paste mistake in a
# phase script ("$MP_HOOK pre_install") is the realistic way this
# happens, not malice, so reject it outright rather than silently
# double-firing something that may not be idempotent.
my %reserved = map { $_ => 1 } qw(
pre_fetch post_fetch pre_patch post_patch pre_build post_build
pre_check post_check pre_install post_install pre_remove post_remove
pre_sync post_sync on_fail
);
# MP_SYSROOT (exported by mplib::hooks::port_env_args whenever the
# calling phase is running inside a with_sysroot_scope callback) is
# turned into the same --sysroot= flag `mp install --sysroot=<name>`
# itself uses, so config::load's own top-level sysroot handling (which
# derives WD/HOOKSDIR/INSTPREFIX from it) puts this separate process into
# the exact same scope the calling phase script is in -- without this, a
# custom hook fired via $MP_HOOK from a sysroot-scoped phase would always
# silently resolve against the DEFAULT root's mp.conf/HOOKS_DIR instead.
unshift @ARGV, "--sysroot=$ENV{MP_SYSROOT}" if defined $ENV{MP_SYSROOT} && $ENV{MP_SYSROOT} ne '';
my $flags = mplib::config::parse_flags(\@ARGV);
mplib::config::load($flags);
fail("hook needs an event name") unless @ARGV;
my $name = shift @ARGV;
fail("hook event name must look like an identifier (letters/digits/underscore/hyphen)")
unless $name =~ /^[A-Za-z][A-Za-z0-9_-]*$/;
fail("'$name' is a reserved built-in lifecycle hook name, pick a different custom event name")
if $reserved{$name};
run_hook($name, $ENV{MP_PKG});