Dist-Zilla-Plugin-Docker-API

 view release on metacpan or  search on metacpan

lib/Dist/Zilla/Plugin/Docker/API/Client.pm  view on Meta::CPAN

    },
);

has logger => (
    is       => 'ro',
    required => 1,
);

has logger_fatal => (
    is       => 'ro',
    required => 1,
);

has docker_config_path => (
    is      => 'ro',
    lazy    => 1,
    builder => sub {
        $ENV{DOCKER_CONFIG}
            ? Path::Tiny::path($ENV{DOCKER_CONFIG}, 'config.json')
            : Path::Tiny::path($ENV{HOME} // '', '.docker', 'config.json');
    },
);

has _docker_config => (
    is      => 'ro',
    lazy    => 1,
    builder => sub {
        my ($self) = @_;
        my $path = $self->docker_config_path;
        return {} unless $path && -r "$path";
        my $data = eval { decode_json(Path::Tiny::path($path)->slurp_utf8) };
        if ($@ || !$data) {
            $self->logger->("Warning: cannot parse $path: $@") if $@;
            return {};
        }
        return $data;
    },
);

# Cheapest round trip that proves an engine is actually listening on the
# socket. Used by the plugin's before_build precheck, so a missing daemon
# is reported before Dist::Zilla does any work rather than after.
sub engine_info {
    my ($self) = @_;

    my $version = eval { $self->docker->system->version };
    croak $@ if $@;
    croak 'the engine returned no version information'
        unless ref $version eq 'HASH';

    my ($engine) = grep { ($_->{Name} // '') =~ /engine/i }
        @{ $version->{Components} // [] };

    return {
        version     => $version->{Version},
        api_version => $version->{ApiVersion},
        engine      => $engine ? $engine->{Name} : undef,
    };
}

# The engine's tag endpoint takes the repository and the tag as two separate
# parameters (POST /images/{name}/tag?repo=&tag=), so a full image reference
# has to be taken apart before it goes over the wire. Passing the whole thing
# as `repo` leaves `tag` empty and the engine fills in its own default:
# podman then rejects `example/app:1.0:latest` with a 500 and every version
# tag is quietly lost. Splitting happens here rather than in API::Docker,
# which mirrors the endpoint and should keep doing so.
sub _split_image_ref {
    my ( $self, $ref ) = @_;

    my $colon = rindex $ref, ':';
    return ( $ref, undef ) if $colon < 0;
    # A colon before the last slash belongs to a registry host:port, not to a
    # tag: registry.example.com:5000/team/app carries no tag at all.
    return ( $ref, undef ) if rindex($ref, '/') > $colon;

    return ( substr($ref, 0, $colon), substr($ref, $colon + 1) );
}

sub build_image {
    my ($self, %arg) = @_;

    my $context = $arg{context_tar};
    my $dockerfile = $arg{dockerfile} // 'Dockerfile';
    my @tags = @{ $arg{tags} // [] };
    my %labels = %{ $arg{labels} // {} };
    my %buildargs = %{ $arg{buildargs} // {} };
    my $pull = $arg{pull} // 0;
    my $nocache = $arg{nocache} // 0;
    my $rm = $arg{rm} // 1;
    my $forcerm = $arg{forcerm} // 1;
    my $target = $arg{target};
    my $network_mode = $arg{network_mode};
    my $platform = $arg{platform};
    my $verbose = $arg{verbose} // 0;

    my $docker = $self->docker;

    my %build_opts = (
        dockerfile => $dockerfile,
        t => @tags ? $tags[0] : undef,
        pull => $pull ? 1 : 0,
        nocache => $nocache ? 1 : 0,
        rm => $rm ? 1 : 0,
        forcerm => $forcerm ? 1 : 0,
    );

    $build_opts{labels} = \%labels if %labels;
    $build_opts{buildargs} = \%buildargs if %buildargs;
    $build_opts{target} = $target if defined $target && length $target;
    $build_opts{networkmode} = $network_mode if defined $network_mode && length $network_mode;
    $build_opts{platform} = $platform if defined $platform && length $platform;

    my $image_id;
    my @processed_tags;

    # Concise mode (default): only forward Dockerfile step headers — both the
    # legacy builder ("Step N/M : ...") and BuildKit ("#N [N/M] ..."). Skip the
    # noisy intermediate container chatter. Verbose mode forwards every line.
    # The line buffer is used in both modes so the Dist::Zilla logger (which
    # appends its own newline) doesn't get a stream chunk with a trailing \n.
    my $line_buf = '';
    my $progress_cb = sub {
        my ($event) = @_;
        if ($event->{errorDetail}) {
            $self->logger_fatal->("Docker build error: " . $event->{errorDetail}{message});
        }



( run in 1.624 second using v1.01-cache-2.11-cpan-cb04b646d8c )