our
@ISA
=
qw( Exporter )
;
our
@EXPORT
=
qw(
get_versions
get_version
version_exists
is_registered_version
get_version_path
get_shell_version
get_local_version set_local_version
get_global_version set_global_version
set_brew_mode get_brew_mode get_brew_mode_shell validate_brew_mode
get_raku
which whence
get_bin_paths
rehash
)
;
use
5.010;
sub
get_versions {
opendir
(
my
$dh
,
$versions_dir
);
my
@versions
= (
'system'
,
sort
({
$a
cmp
$b
}
grep
({ /^[^.]/ }
readdir
(
$dh
)))
);
closedir
(
$dh
);
return
@versions
;
}
sub
get_shell_version {
if
(
defined
$ENV
{
$env_var
} ||
defined
$ENV
{PL6ENV_VERSION}) {
my
$version
=
$ENV
{
$env_var
} //
$ENV
{PL6ENV_VERSION};
if
(version_exists(
$version
)) {
return
$version
;
}
else
{
say
STDERR
"Version '$version' is set via the RAKU_VERSION environment variable."
;
say
STDERR
"This version is not installed. Ignoring."
;
say
STDERR
''
;
return
undef
;
}
}
else
{
return
undef
;
}
}
sub
get_local_version {
my
(
$vol
,
$path
,
undef
) = splitpath(realpath(), 1);
my
@fragments
= splitdir(
$path
);
while
(
@fragments
) {
for
(
$local_filename
,
'.perl6-version'
) {
my
$filepath
= catpath(
$vol
, catdir(
@fragments
),
$_
);
if
(-f
$filepath
) {
my
$version
= trim(slurp(
$filepath
));
if
(version_exists(
$version
)) {
return
$version
;
}
else
{
say
STDERR
"Version '$version' is given in the"
;
say
STDERR
"$filepath"
;
say
STDERR
"file. This version is not installed. Ignoring."
;
say
STDERR
''
;
}
}
}
pop
@fragments
;
}
return
undef
;
}
sub
set_local_version {
my
$version
=
shift
;
if
(
$version
) {
spurt(
$local_filename
,
shift
);
}
else
{
unlink
$local_filename
;
unlink
'.perl6-version'
;
}
}
sub
get_global_version {
if
(!-e catfile(
$prefix
,
'CURRENT'
)) {
set_global_version(
'system'
, 1);
}
my
$cur
= slurp(catfile(
$prefix
,
'CURRENT'
));
chomp
$cur
;
return
$cur
;
}
sub
set_global_version {
my
$version
=
shift
;
my
$silent
=
shift
;
say
"Switching to $version"
unless
$silent
;
spurt(catfile(
$prefix
,
'CURRENT'
),
$version
);
}
sub
get_version {
my
$version
= get_shell_version();
return
$version
if
defined
$version
;
if
(get_brew_mode() eq
'shim'
) {
$version
= get_local_version();
return
$version
if
defined
$version
;
}
return
get_global_version();
}
sub
set_brew_mode {
my
$mode
=
shift
;
if
(
$mode
eq
'env'
) {
spurt(catfile(
$prefix
,
'MODE'
),
'env'
);
}
elsif
(
$mode
eq
'shim'
) {
spurt(catfile(
$prefix
,
'MODE'
),
'shim'
);
rehash();
}
else
{
say
STDERR
"Mode must either be 'env' or 'shim'"
;
}
}
sub
get_brew_mode {
my
$silent
=
shift
;
if
(!-e catfile(
$prefix
,
'MODE'
)) {
spurt(catfile(
$prefix
,
'MODE'
),
'env'
);
}
my
$mode
= trim(slurp(catfile(
$prefix
,
'MODE'
)));
if
(
$mode
ne
'env'
&&
$mode
ne
'shim'
) {
say
STDERR
'Invalid mode found: '
.
$mode
unless
$silent
;
say
STDERR
'Resetting to env-mode'
unless
$silent
;
set_brew_mode(
'env'
);
$mode
=
'env'
;
}
return
$mode
;
}
sub
validate_brew_mode {
if
(get_brew_mode() eq
'env'
) {
say
STDERR
"This command is not available in 'env' mode. Switch to to 'shim' mode using '$brew_name mode shim'"
;
exit
1;
}
}
sub
version_exists {
my
$version
=
shift
;
return
undef
if
!
defined
$version
;
my
%versionsMap
=
map
{
$_
=> 1 } get_versions();
return
exists
(
$versionsMap
{
$version
});
}
sub
is_registered_version {
my
$version
=
shift
;
my
$version_file
= catdir(
$versions_dir
,
$version
);
if
(-f
$version_file
) {
return
1;
}
else
{
return
0;
}
}
sub
get_version_path {
my
$version
=
shift
;
my
$version_path
= catdir(
$versions_dir
,
$version
);
return
catdir(
$version_path
,
'install'
)
if
-d catdir(
$version_path
,
'install'
,
'bin'
);
return
$version_path
if
-d catdir(
$version_path
,
'bin'
);
return
trim(slurp(
$version_path
))
if
-f
$version_path
;
die
"Invalid version found: $version"
;
}
sub
get_raku {
my
$version
=
shift
;
return
_which(
'raku'
,
$version
) // which(
'perl6'
,
$version
);
}
sub
match_version {
my
$impl
=
shift
//
'moar'
;
my
$ver
=
shift
if
@_
&&
$_
[0] !~ /^--/;
my
@args
=
@_
;
if
(!
defined
$ver
) {
my
$version_regex
=
'^\d\d\d\d\.\d\d(?:\.\d+)?$'
;
my
$combined_regex
=
'('
.
join
(
'|'
, App::Rakubrew::Variables::available_backends())
.
')-(.+)'
;
if
(
$impl
eq
'moar-blead'
) {
$ver
=
'master'
;
}
elsif
(
$impl
=~ /
$combined_regex
/) {
$impl
= $1;
$ver
= $2;
}
elsif
(
$impl
=~ /
$version_regex
/) {
$ver
=
$impl
;
$impl
=
'moar'
;
}
else
{
my
@versions
= App::Rakubrew::Build::available_rakudos();
@versions
=
grep
{ /^\d\d\d\d\.\d\d/ }
@versions
;
$ver
=
$versions
[-1];
}
}
return
(
$impl
,
$ver
,
@args
);
}
sub
which {
my
$prog
=
shift
;
my
$version
=
shift
;
my
$target
= _which(
$prog
,
$version
);
if
(!
$target
) {
say
STDERR
"$brew_name: $prog: command not found"
;
if
(whence(
$prog
)) {
say
STDERR
<<EOT;
The '$prog' command exists in these Raku versions:
EOT
map
{
say
STDERR
$_
} whence(
$prog
);
}
exit
1;
}
return
$target
;
}
sub
_which {
my
$prog
=
shift
;
my
$version
=
shift
;
my
$target
; {
if
(
$version
eq
'system'
) {
my
@targets
= File::Which::which(
$prog
);
@targets
=
map
({
$_
=~ s|\\|/|g;
$_
= canonpath(
$_
);
}
@targets
);
my
$normalized_shim_dir
=
$shim_dir
;
$normalized_shim_dir
=~ s|\\|/|g;
$normalized_shim_dir
= canonpath(
$normalized_shim_dir
);
@targets
=
grep
({
my
(
$volume
,
$directories
,
$file
) = splitpath(
$_
);
my
$target_dir
= catpath(
$volume
,
$directories
);
$target_dir
= canonpath(
$target_dir
);
$target_dir
ne
$normalized_shim_dir
;
}
@targets
);
$target
=
$targets
[0]
if
@targets
;
}
elsif
($^O =~ /win32/i) {
my
@results
= ();
my
@dirs
= get_bin_paths(
$version
);
for
my
$dir
(
@dirs
) {
my
@files
= slurp_dir(
$dir
);
for
my
$file
(
@files
) {
if
(check_prog_name_match(
$prog
,
$file
)) {
push
@results
, catfile(
$dir
,
$file
);
}
}
}
@results
=
sort
{
my
(
undef
,
undef
,
$suffix_a
) = my_fileparse(
$a
);
my
(
undef
,
undef
,
$suffix_b
) = my_fileparse(
$b
);
return
-1
if
$suffix_a
eq
'.exe'
&&
$suffix_b
ne
'.exe'
;
return
1
if
$suffix_a
ne
'.exe'
&&
$suffix_b
eq
'.exe'
;
return
$a
cmp
$b
if
$suffix_a
eq
'.exe'
&&
$suffix_b
eq
'.exe'
;
return
-1
if
$suffix_a
eq
'.bat'
&&
$suffix_b
ne
'.bat'
;
return
1
if
$suffix_a
ne
'.bat'
&&
$suffix_b
eq
'.bat'
;
return
$a
cmp
$b
if
$suffix_a
eq
'.bat'
&&
$suffix_b
eq
'.bat'
;
return
-1
if
$suffix_a
eq
'.raku'
&&
$suffix_b
ne
'.raku'
;
return
1
if
$suffix_a
ne
'.raku'
&&
$suffix_b
eq
'.raku'
;
return
$a
cmp
$b
if
$suffix_a
eq
'.raku'
&&
$suffix_b
eq
'.raku'
;
return
-1
if
$suffix_a
eq
'.p6'
&&
$suffix_b
ne
'.p6'
;
return
1
if
$suffix_a
ne
'.p6'
&&
$suffix_b
eq
'.p6'
;
return
$a
cmp
$b
if
$suffix_a
eq
'.p6'
&&
$suffix_b
eq
'.p6'
;
return
-1
if
$suffix_a
eq
'.pl6'
&&
$suffix_b
ne
'.pl6'
;
return
1
if
$suffix_a
ne
'.pl6'
&&
$suffix_b
eq
'.pl6'
;
return
$a
cmp
$b
if
$suffix_a
eq
'.pl6'
&&
$suffix_b
eq
'.pl6'
;
return
-1
if
$suffix_a
eq
'.pl'
&&
$suffix_b
ne
'.pl'
;
return
1
if
$suffix_a
ne
'.pl'
&&
$suffix_b
eq
'.pl'
;
return
$a
cmp
$b
if
$suffix_a
eq
'.pl'
&&
$suffix_b
eq
'.pl'
;
return
-1
if
$suffix_a
eq
''
&&
$suffix_b
ne
''
;
return
1
if
$suffix_a
ne
''
&&
$suffix_b
eq
''
;
return
$a
cmp
$b
if
$suffix_a
eq
''
&&
$suffix_b
eq
''
;
return
$a
cmp
$b
;
}
@results
;
$target
=
$results
[0];
}
else
{
my
@paths
= get_bin_paths(
$version
,
$prog
);
for
my
$path
(
@paths
) {
if
(-e
$path
) {
$target
=
$path
;
last
;
}
}
}
}
return
$target
;
}
sub
whence {
my
$prog
=
shift
;
my
$pathmode
=
shift
// 0;
my
@matches
= ();
for
my
$version
(get_versions()) {
next
if
$version
eq
'system'
;
for
my
$path
(get_bin_paths(
$version
,
$prog
)) {
if
(-f
$path
) {
if
(
$pathmode
) {
push
@matches
,
$path
;
}
else
{
push
@matches
,
$version
;
}
last
;
}
}
}
return
@matches
;
}
sub
get_bin_paths {
my
$version
=
shift
;
my
$program
=
scalar
(
shift
) ||
undef
;
my
$version_path
= get_version_path(
$version
);
return
(
catfile(
$version_path
,
'bin'
,
$program
// ()),
catfile(
$version_path
,
'share'
,
'perl6'
,
'site'
,
'bin'
,
$program
// ()),
);
}
sub
rehash {
return
if
get_brew_mode() ne
'shim'
;
my
@paths
= ();
for
my
$version
(get_versions()) {
if
(
$version
ne
'system'
) {
push
@paths
, get_bin_paths(
$version
);
}
}
say
"Updating shims"
;
{
opendir
(
my
$dh
,
$shim_dir
);
while
(
my
$entry
=
readdir
$dh
) {
next
if
$entry
=~ /^\./;
unlink
catfile(
$shim_dir
,
$entry
);
}
closedir
$dh
;
}
my
@bins
=
map
{ slurp_dir(
$_
) }
@paths
;
if
($^O =~ /win32/i) {
@bins
=
map
{
my
(
$basename
,
undef
,
undef
) = my_fileparse(
$_
);
$basename
}
@bins
;
@bins
= uniq(
@bins
);
for
(
@bins
) {
spurt(catfile(
$shim_dir
,
$_
.
'.bat'
),
<<EOT);
\@ECHO OFF
SETLOCAL
SET brew_cmd="$brew_exec" internal_win_run \%~n0
FOR /F "delims=" \%\%i IN ('\%brew_cmd\%') DO SET command=\%\%i
IF NOT ERRORLEVEL 0 EXIT /B \%errorlevel\%
IF ERRORLEVEL 1 EXIT /B \%errorlevel\%
"\%command\%" \%*
EOT
}
}
else
{
for
(
@bins
) {
link
$0, catfile(
$shim_dir
,
$_
);
}
}
}