NAME
dual_etc_paths - collect etc dirs from both the physical and logical trees
SYNOPSIS
dual_etc_paths
DESCRIPTION
Calls FindBin::libs twice with base=etc and different path arguments to export two independent arrays of etc directories:
use FindBin::libs qw( base=etc abspath export=remote );
use FindBin::libs qw( base=etc noabspath export=local );
@remote holds the etc directories found walking up from $Bin_p (the physical path, symlinks resolved). @local holds the etc directories found walking up from $Bin_l (the logical path, symlinks preserved).
When no symlinks appear in the path, both arrays are identical. They differ when the script is invoked through a directory symlink.
Symlink scenario
Consider a layout where /home/user/app is a directory symlink pointing to the real source tree under /work/projects/app:
/home/user/ # logical subtree (sandbox)
+-- etc/
| \-- database.conf # points at test database
\-- app -> /work/projects/app # directory symlink
/work/projects/ # physical subtree (production)
+-- etc/
| \-- database.conf # points at production database
\-- app/
\-- bin/
\-- myscript # $0
Invoked as /home/user/app/bin/myscript:
$Bin_p = /work/projects/app/bin # symlink resolved
$Bin_l = /home/user/app/bin # symlink preserved
@remote => ( '/work/projects/etc' ) # production database.conf
@local => ( '/home/user/etc' ) # test database.conf
Choosing which config to read
Export alone does not select a config file. With both arrays available the script can pick deliberately:
use List::Util qw( first );
# nearest production config
my $prod_etc = first { -d } @remote;
# nearest sandbox override (falls back to production if none)
my $conf_dir = ( first { -d } @local ) // $prod_etc
or die "No etc dir found\n";
my $db_conf = "$conf_dir/database.conf";
This lets the same script run against either environment simply by controlling whether it is invoked via the symlink path (sandbox) or directly (production), with no changes to the source.
Identical results without symlinks
On a filesystem with no directory symlinks in the path, $Bin_l eq $Bin_p and both walks produce the same list. Keeping both calls is harmless in that case; @remote and @local simply hold the same paths.