All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bmuschko.gradle.docker.tasks.image.DockerBuildImage.groovy Maven / Gradle / Ivy

There is a newer version: 6.7.0
Show newest version
/*
 * Copyright 2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.bmuschko.gradle.docker.tasks.image

import com.bmuschko.gradle.docker.DockerRegistryCredentials
import com.bmuschko.gradle.docker.tasks.AbstractDockerRemoteApiTask
import com.bmuschko.gradle.docker.tasks.RegistryCredentialsAware
import com.github.dockerjava.api.DockerClient
import com.github.dockerjava.api.command.BuildImageCmd
import com.github.dockerjava.api.model.AuthConfig
import com.github.dockerjava.api.model.AuthConfigurations
import com.github.dockerjava.api.model.BuildResponseItem
import com.github.dockerjava.core.command.BuildImageResultCallback
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.SetProperty
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity

class DockerBuildImage extends AbstractDockerRemoteApiTask implements RegistryCredentialsAware {

    /**
     * Input directory containing the build context. Defaults to "$buildDir/docker".
     */
    @InputDirectory
    @PathSensitive(PathSensitivity.RELATIVE)
    final DirectoryProperty inputDir = newInputDirectory()

    /**
     * The Dockerfile to use to build the image.  If null, will use 'Dockerfile' in the
     * build context, i.e. "$inputDir/Dockerfile".
     */
    @InputFile
    @PathSensitive(PathSensitivity.RELATIVE)
    @Optional
    final RegularFileProperty dockerFile = newInputFile()

    /**
     * Tags for image.
     */
    @Input
    @Optional
    final SetProperty tags = project.objects.setProperty(String)

    @Input
    @Optional
    final Property noCache = project.objects.property(Boolean)

    @Input
    @Optional
    final Property remove = project.objects.property(Boolean)

    @Input
    @Optional
    final Property quiet = project.objects.property(Boolean)

    @Input
    @Optional
    final Property pull = project.objects.property(Boolean)

    @Input
    @Optional
    final Property> labels = project.objects.property(Map)

    @Input
    @Optional
    final Property network = project.objects.property(String)

    @Input
    @Optional
    final Property> buildArgs = project.objects.property(Map)

    @Input
    @Optional
    final SetProperty cacheFrom = project.objects.setProperty(String)

    /**
     * Size of /dev/shm in bytes.
     * The size must be greater than 0.
     * If omitted the system uses 64MB.
     */
    @Input
    @Optional
    final Property shmSize = project.objects.property(Long)

    /**
     * The target Docker registry credentials for building image.
     */
    @Nested
    @Optional
    DockerRegistryCredentials registryCredentials

    @Internal
    final Property imageId = project.objects.property(String)

    DockerBuildImage() {
        inputDir.set(project.layout.buildDirectory.dir('docker'))
        tags.set([])
        noCache.set(false)
        remove.set(false)
        quiet.set(false)
        pull.set(false)
        cacheFrom.set([])
    }

    @Override
    void runRemoteCommand(DockerClient dockerClient) {
        logger.quiet "Building image using context '${inputDir.get().asFile}'."
        BuildImageCmd buildImageCmd

        if (dockerFile.getOrNull()) {
            logger.quiet "Using Dockerfile '${dockerFile.get().asFile}'"
            buildImageCmd = dockerClient.buildImageCmd()
                    .withBaseDirectory(inputDir.get().asFile)
                    .withDockerfile(dockerFile.get().asFile)
        } else {
            buildImageCmd = dockerClient.buildImageCmd(inputDir.get().asFile)
        }

        if (tags.getOrNull()) {
            def tagListString = tags.get().collect {"'${it}'"}.join(", ")
            logger.quiet "Using tags ${tagListString} for image."
            buildImageCmd.withTags(tags.get().collect { it.toString() }.toSet() )
        }

        if (noCache.getOrNull()) {
            buildImageCmd.withNoCache(noCache.get())
        }

        if (remove.getOrNull()) {
            buildImageCmd.withRemove(remove.get())
        }

        if (quiet.getOrNull()) {
            buildImageCmd.withQuiet(quiet.get())
        }

        if (pull.getOrNull()) {
            buildImageCmd.withPull(pull.get())
        }

        if (network.getOrNull()) {
            buildImageCmd.withNetworkMode(network.get())
        }

        if (labels.getOrNull()) {
            buildImageCmd.withLabels(labels.get().collectEntries { [it.key, it.value.toString()] })
        }

        if(shmSize.getOrNull() != null) { // 0 is valid input
            buildImageCmd.withShmsize(shmSize.get())
        }

        if (registryCredentials) {
            AuthConfig authConfig = new AuthConfig()
            authConfig.registryAddress = registryCredentials.url.get()
            authConfig.username = registryCredentials.username.getOrNull()
            authConfig.password = registryCredentials.password.getOrNull()
            authConfig.email = registryCredentials.email.getOrNull()
            AuthConfigurations authConfigurations = new AuthConfigurations()
            authConfigurations.addConfig(authConfig)
            buildImageCmd.withBuildAuthConfigs(authConfigurations)
        }

        if (buildArgs.getOrNull()) {
            buildArgs.get().each { arg, value ->
                buildImageCmd = buildImageCmd.withBuildArg(arg, value)
            }
        }

        if (cacheFrom.getOrNull()) {
            buildImageCmd = buildImageCmd.withCacheFrom(cacheFrom.get())
        }

        String createdImageId = buildImageCmd.exec(createCallback()).awaitImageId()
        imageId.set(createdImageId)
        logger.quiet "Created image with ID '$createdImageId'."
    }

    private BuildImageResultCallback createCallback() {
        if (nextHandler) {
            return new BuildImageResultCallback() {
                @Override
                void onNext(BuildResponseItem item) {
                    try {
                        nextHandler.execute(item)
                    } catch (Exception e) {
                        logger.error('Failed to handle build response', e)
                        return
                    }
                    super.onNext(item)
                }
            }
        }

        new BuildImageResultCallback() {
            @Override
            void onNext(BuildResponseItem item) {
                try {
                    def possibleStream = item.stream
                    if (possibleStream) {
                        logger.quiet(possibleStream.trim())
                    }
                } catch(Exception e) {
                    logger.error('Failed to handle build response', e)
                    return
                }
                super.onNext(item)
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy