evaluationDependsOn(":node:capsule") import com.github.dockerjava.api.model.Identifier import net.corda.build.docker.DockerImage import net.corda.build.docker.DockerUtils import net.corda.build.docker.ObjectInputStreamWithCustomClassLoader import java.nio.file.Files import java.nio.file.StandardCopyOption import java.time.LocalDateTime import java.time.format.DateTimeFormatter import java.util.stream.Collectors import java.util.stream.Stream apply plugin: 'kotlin' apply plugin: 'application' // We need to set mainClassName before applying the shadow plugin. mainClassName = 'net.corda.core.ConfigExporterMain' apply plugin: 'com.github.johnrengelman.shadow' dependencies{ compile project(':node') } shadowJar { baseName = 'config-exporter' classifier = null version = null zip64 true exclude '**/Log4j2Plugins.dat' } enum ImageVariant { UBUNTU_ZULU("zulu", "Dockerfile", "1.8"), UBUNTU_ZULU_11("zulu", "Dockerfile11", "11"), AL_CORRETTO("corretto", "DockerfileAL", "1.8"), OFFICIAL(UBUNTU_ZULU) String knownAs String dockerFile String javaVersion String versionString(String baseTag, String version) { return "${baseTag}-${knownAs}" + (knownAs.isEmpty() ? "" : "-") + "java${javaVersion}-" + version } ImageVariant(ImageVariant other) { this.knownAs = other.knownAs this.dockerFile = other.dockerFile this.javaVersion = other.javaVersion } ImageVariant(String knownAs, String dockerFile, String javaVersion) { this.knownAs = knownAs this.dockerFile = dockerFile this.javaVersion = javaVersion } static final String getRepository(Project project) { return project.properties.getOrDefault("docker.image.repository", "corda/corda") } static private final String runTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) def getName(Project project) { return versionString(getRepository(project), project.version.toString().toLowerCase()) } Set buildTags(Project project) { final String suffix = project.version.toString().toLowerCase().contains("snapshot") ? runTime : "RELEASE" return [suffix, "latest"].stream().map { toAppend -> "${getName(project)}:${toAppend}".toString() }.map(Identifier.&fromCompoundString).collect(Collectors.toSet()) } static Set toBeBuilt = Arrays.stream(values()).collect(Collectors.toSet()) } class BuildDockerFolderTask extends DefaultTask { @Option(option = "image", description = "Docker image variants that will be built") void setVariants(List variants) { ImageVariant.toBeBuilt = new HashSet<>(variants) } @OptionValues("image") Collection allVariants() { return EnumSet.allOf(ImageVariant.class) } @Input Iterable variantsToBuild() { return ImageVariant.toBeBuilt } @InputFiles FileCollection getDockerBuildFiles() { return project.fileTree("${project.projectDir}/src/docker/build") } @InputFiles FileCollection getShellScripts() { return project.fileTree("${project.projectDir}/src/bash") } @Lazy private File cordaJar = project.findProject(":node:capsule").tasks.buildCordaJAR.outputs.files.singleFile @Lazy private File configExporter = project.tasks.shadowJar.outputs.files.singleFile @Lazy private File dbMigrator = project.findProject(":tools:dbmigration").tasks.shadowJar.outputs.files.singleFile @InputFiles private FileCollection getRequiredArtifacts() { FileCollection res = project.tasks.shadowJar.outputs.files def capsuleProject = project.findProject(":node:capsule") def capsuleTaksOutput = capsuleProject.tasks.buildCordaJAR.outputs.files res += capsuleTaksOutput return res } @OutputFiles FileCollection getDockerFiles() { return project.objects.fileCollection().from(ImageVariant.toBeBuilt.stream().map { new File(dockerBuildDir, it.dockerFile) }.collect(Collectors.toList())) } @OutputDirectory final File dockerBuildDir = project.file("${project.buildDir}/docker/build") @TaskAction def run() { for(ImageVariant imageVariant : ImageVariant.toBeBuilt) { def sourceFile = project.projectDir.toPath().resolve("src/docker/${imageVariant.dockerFile}") def destinationFile = dockerBuildDir.toPath().resolve(imageVariant.dockerFile) Files.copy(sourceFile, destinationFile, StandardCopyOption.REPLACE_EXISTING) } Files.copy(cordaJar.toPath(), dockerBuildDir.toPath().resolve("corda.jar"), StandardCopyOption.REPLACE_EXISTING) Files.copy(configExporter.toPath(), dockerBuildDir.toPath().resolve("config-exporter.jar"), StandardCopyOption.REPLACE_EXISTING) ["src/bash/run-corda.sh", "src/config/starting-node.conf", "src/bash/generate-config.sh"].forEach { def source = project.file(it).toPath() Files.copy(source, dockerBuildDir.toPath().resolve(source.fileName), StandardCopyOption.REPLACE_EXISTING) } } } class BuildDockerImageTask extends DefaultTask { @Option(option = "image", description = "Docker image variants that will be built") void setVariants(List variants) { ImageVariant.toBeBuilt = new HashSet<>(variants) } @OptionValues("image") Collection allVariants() { return EnumSet.allOf(ImageVariant.class) } final File dockerBuildDir = project.file("${project.buildDir}/docker/build") @OutputDirectory final File dockerBuiltImageDir = project.file("${project.buildDir}/docker/images") @Input String getRepository() { return ImageVariant.getRepository(project) } @InputFiles FileCollection dockerFiles private Map images @OutputFiles FileCollection getImageFiles() { return project.objects.fileCollection().from(ImageVariant.toBeBuilt.stream().map { imageVariant -> dockerBuiltImageDir.toPath().resolve(imageVariant.toString()).toFile() }.collect(Collectors.toList())) } void from(BuildDockerFolderTask buildDockerFolderTask) { dockerFiles = buildDockerFolderTask.outputs.files } @Override Task configure(Closure closure) { return super.configure(closure) } @TaskAction def run() { this.@images = ImageVariant.toBeBuilt.stream().map { imageVariant -> new Tuple2<>(imageVariant, new DockerImage( baseDir: dockerBuildDir, dockerFile: imageVariant.dockerFile, tags: imageVariant.buildTags(project))) }.collect(Collectors.toMap({it.first}, {it.second})) DockerUtils.buildImages(project, this.@images.values()) images.entrySet().forEach { entry -> ImageVariant imageVariant = entry.key def destinationFile = dockerBuiltImageDir.toPath().resolve(imageVariant.toString()) new ObjectOutputStream(Files.newOutputStream(destinationFile)).withStream { it.writeObject(entry.value) } } } } class PushDockerImage extends DefaultTask { @Option(option = "image", description = "Docker image variants that will be built") void setVariants(List variants) { ImageVariant.toBeBuilt = new HashSet<>(variants) } @OptionValues("image") Collection allVariants() { return EnumSet.allOf(ImageVariant.class) } private static String registryURL @Option(option = "registry-url", description = "Docker image registry where images will be pushed, defaults to DockerHub") void setRegistryURL(String registryURL) { PushDockerImage.registryURL = registryURL } @InputFiles FileCollection imageFiles def from(BuildDockerImageTask buildDockerImageTask) { imageFiles = buildDockerImageTask.outputs.files } @TaskAction def run() { def classLoader = DockerImage.class.classLoader Stream imageStream = imageFiles.files.stream().filter{ it.isFile() }.map { new ObjectInputStreamWithCustomClassLoader(Files.newInputStream(it.toPath()), classLoader).withStream { DockerImage image = it.readObject() if(PushDockerImage.registryURL) { image.destination = PushDockerImage.registryURL } image } } DockerUtils.pushImages(project, imageStream) } } def buildDockerFolderTask = tasks.register("buildDockerFolder", BuildDockerFolderTask) def buildDockerImageTask = tasks.register("buildDockerImage", BuildDockerImageTask) { from(buildDockerFolderTask.get()) } tasks.register("pushDockerImage", PushDockerImage) { from(buildDockerImageTask.get()) }