use Zef:ver($?DISTRIBUTION.meta // $?DISTRIBUTION.meta// '*'):api($?DISTRIBUTION.meta // '*'):auth($?DISTRIBUTION.meta // ''); use Zef::Distribution::Local:ver(Zef.^ver):api(Zef.^api):auth(Zef.^auth); class Zef::Service::Shell::DistributionBuilder does Builder { =begin pod =title class Zef::Service::Shell::DistributionBuilder =subtitle A META6-supplied raku module based implementation of the Builder interface =head1 Synopsis =begin code :lang use Zef; use Zef::Service::Shell::DistributionBuilder; my $builder = Zef::Service::Shell::DistributionBuilder.new; # Add logging if we want to see output my $stdout = Supplier.new; my $stderr = Supplier.new; $stdout.Supply.tap: { say $_ }; $stderr.Supply.tap: { note $_ }; # Assuming our current directory is a raku distribution with something like # `"builder" : "Distribution::Builder::MakeFromJSON"` in its META6.json # and has no dependencies (or all dependencies already installed)... my $dist-to-build = Zef::Distribution::Local.new($*CWD); my Str @includes = $*CWD.absolute; my $built-ok = so $builder.build($dist-to-build, :@includes, :$stdout, :$stderr); say $built-ok ?? "OK" !! "Something went wrong"; =end code =head1 Description C class for handling local distributions that include a C<"builder" : "..."> in their C. For example C<"builder" : "Distribution::Builder::MakeFromJSON"> will spawn a process where it passes the module C the path of the distribution and the parsed meta data (from which it may use other instructions from non-standard fields in the C). =head1 Methods =head2 method probe method probe(--> Bool:D) Returns C if this module can successfully launch the C command (i.e. always returns C). =head2 method build-matcher method build-matcher(Zef::Distribution::Local $dist --> Bool:D) Returns C if this module knows how to test C<$uri>. This module always returns C right now since it just uses the C command. =head2 method build method build(Zef::Distribution::Local $dist, Str :@includes, Supplier :$stdout, Supplier :$stderr --> Bool:D) Launches a process to invoke whatever module is in the C field of the C<$dist> META6.json while passing that module the meta data of C<$dist> it is to build (allowing non-spec keys to be used by such modules to allow consumers/authors to supply additional data). A C can be supplied as C<:$stdout> and C<:$stderr> to receive any output. See C in the ecosystem for an example of such a C, and see C for an example of a distribution built using such a C. Returns C if the C process spawned to run the build module exits 0. =end pod #| Return true always since it just requires launching another raku process method probe { True } #| Return true if this Builder understands the given meta data (has a 'builder' key) of the provided distribution method build-matcher(Zef::Distribution::Local $dist) { so $dist.builder } #| Run the build step of this distribution. method build(Zef::Distribution::Local $dist, Str :@includes, Supplier :$stdout, Supplier :$stderr --> Bool:D) { die "path does not exist: {$dist.path}" unless $dist.path.IO.e; # todo: remove this ( and corresponding code in Zef::Distribution.build-depends-specs ) in the near future # Always use the full name 'Distribution::Builder::MakeFromJSON', not 'MakeFromJSON' my $dist-builder-compat = "$dist.builder()" eq 'MakeFromJSON' ?? "Distribution::Builder::MakeFromJSON" !! "$dist.builder()"; my $tmp-meta-file = do given $*TMPDIR.child("zef-distribution-builder/") { my $dir = $_.child(Date.today); mkdir $dir; $dir = $dir.child("{time}-{$*PID}-{$*THREAD.id}"); mkdir $dir; $dir.child('META6.json').absolute; } $tmp-meta-file.IO.spurt(Zef::to-json($dist.meta.hash), :close); my $cmd = "exit((require ::(q|$dist-builder-compat|)).new(" ~ ":meta(Distribution::Path.new({$tmp-meta-file.IO.parent.absolute.raku}\.IO).meta.hash)" ~ ").build(q|$dist.path()|)" ~ '??0!!1)'; my @exec = |($*EXECUTABLE.absolute, |@includes.grep(*.defined).map({ "-I{$_}" }), '-e', "$cmd"); $stdout.emit("Command: {@exec.join(' ')}"); my $ENV := %*ENV; my $passed; react { my $proc = Zef::zrun-async(@exec, :w); whenever $proc.stdout.lines { $stdout.emit($_) } whenever $proc.stderr.lines { $stderr.emit($_) } whenever $proc.start(:$ENV, :cwd($dist.path)) { $passed = $_.so } } return $passed; } }