blob: aca7626395155a1d8b84dc14729f32c13abd496e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.streampark.console.core.task;
import org.apache.streampark.common.Constant;
import org.apache.streampark.common.util.CommandUtils;
import org.apache.streampark.common.util.Utils;
import org.apache.streampark.console.base.util.GitUtils;
import org.apache.streampark.console.core.entity.Project;
import org.apache.streampark.console.core.enums.BuildStateEnum;
import ch.qos.logback.classic.Logger;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.InvalidRemoteException;
import org.eclipse.jgit.lib.StoredConfig;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
@Slf4j
public class ProjectBuildTask extends AbstractLogFileTask {
final Project project;
final Consumer<BuildStateEnum> stateUpdateConsumer;
final Consumer<Logger> notifyReleaseConsumer;
public ProjectBuildTask(
String logPath,
Project project,
Consumer<BuildStateEnum> stateUpdateConsumer,
Consumer<Logger> notifyReleaseConsumer) {
super(logPath, true);
this.project = project;
this.stateUpdateConsumer = stateUpdateConsumer;
this.notifyReleaseConsumer = notifyReleaseConsumer;
}
@Override
protected void doRun() throws Throwable {
log.info("Project {} start build", project.getName());
fileLogger.info(project.getLog4BuildStart());
boolean cloneSuccess = cloneSourceCode(project);
if (!cloneSuccess) {
fileLogger.error("[StreamPark] clone or pull error.");
stateUpdateConsumer.accept(BuildStateEnum.FAILED);
return;
}
boolean build = projectBuild(project);
if (!build) {
stateUpdateConsumer.accept(BuildStateEnum.FAILED);
fileLogger.error("build error, project name: {} ", project.getName());
return;
}
stateUpdateConsumer.accept(BuildStateEnum.SUCCESSFUL);
this.deploy(project);
notifyReleaseConsumer.accept(fileLogger);
}
@Override
protected void processException(Throwable t) {
stateUpdateConsumer.accept(BuildStateEnum.FAILED);
fileLogger.error("Build error, project name: {}", project.getName(), t);
}
@Override
protected void doFinally() {}
private boolean cloneSourceCode(Project project) {
try {
project.cleanCloned();
fileLogger.info("clone {}, {} starting...", project.getName(), project.getUrl());
fileLogger.info(project.getLog4CloneStart());
Git git = GitUtils.clone(project);
StoredConfig config = git.getRepository().getConfig();
config.setBoolean("http", project.getUrl(), "sslVerify", false);
config.setBoolean("https", project.getUrl(), "sslVerify", false);
config.save();
File workTree = git.getRepository().getWorkTree();
printWorkTree(workTree, "");
String successMsg =
String.format("[StreamPark] project [%s] git clone successful!%n", project.getName());
fileLogger.info(successMsg);
git.close();
return true;
} catch (Exception e) {
if (e instanceof InvalidRemoteException) {
if (project.isHttpRepositoryUrl()) {
String url =
project
.getUrl()
.replaceAll(
"(https://|http://)(.*?)/(.*?)/(.*?)(\\.git|)\\s*$", "git@$2:$3/$4.git");
project.setUrl(url);
fileLogger.info(
"clone project by https(http) failed, Now try to clone project by ssh...");
return cloneSourceCode(project);
}
}
fileLogger.error(
String.format(
"[StreamPark] project [%s] branch [%s] git clone failed, err: %s",
project.getName(), project.getBranches(), e));
fileLogger.error(String.format("project %s clone error ", project.getName()), e);
return false;
}
}
private void printWorkTree(File workTree, String space) {
File[] files = workTree.listFiles();
for (File file : Objects.requireNonNull(files)) {
if (!file.getName().startsWith(".git")) {
continue;
}
if (file.isFile()) {
fileLogger.info("{} / {}", space, file.getName());
} else if (file.isDirectory()) {
fileLogger.info("{} / {}", space, file.getName());
printWorkTree(file, space.concat("/").concat(file.getName()));
}
}
}
private boolean projectBuild(Project project) {
int code =
CommandUtils.execute(
project.getMavenWorkHome(),
Collections.singletonList(project.getMavenArgs()),
(line) -> fileLogger.info(line));
return code == 0;
}
private void deploy(Project project) throws Exception {
File path = project.getAppSource();
List<File> apps = new ArrayList<>();
// find the compiled tar.gz (Stream Park project) file or jar (normal or official standard flink
// project) under the project path
findTarOrJar(apps, path);
if (apps.isEmpty()) {
throw new RuntimeException(
"[StreamPark] can't find tar.gz or jar in " + path.getAbsolutePath());
}
for (File app : apps) {
String appPath = app.getAbsolutePath();
// 1). tar.gz file
if (appPath.endsWith("tar.gz")) {
File deployPath = project.getDistHome();
if (!deployPath.exists()) {
deployPath.mkdirs();
}
// xzvf jar
if (app.exists()) {
String cmd =
String.format(
"tar -xzvf %s -C %s", app.getAbsolutePath(), deployPath.getAbsolutePath());
CommandUtils.execute(cmd);
}
} else {
// 2) .jar file(normal or official standard flink project)
Utils.requireCheckJarFile(app.toURI().toURL());
String moduleName = app.getName().replace(Constant.JAR_SUFFIX, "");
File distHome = project.getDistHome();
File targetDir = new File(distHome, moduleName);
if (!targetDir.exists()) {
targetDir.mkdirs();
}
File targetJar = new File(targetDir, app.getName());
app.renameTo(targetJar);
}
}
}
private void findTarOrJar(List<File> list, File path) {
for (File file : path.listFiles()) {
// navigate to the target directory:
if (file.isDirectory()) {
if ("target".equals(file.getName())) {
// find the tar.gz file or the jar file in the target path.
// note: only one of the two can be selected, which cannot be satisfied at the same time.
File tar = null;
File jar = null;
for (File targetFile : file.listFiles()) {
// 1) exit once the tar.gz file is found.
if (targetFile.getName().endsWith("tar.gz")) {
tar = targetFile;
break;
}
// 2) try look for jar files, there may be multiple jars found.
if (!targetFile.getName().startsWith("original-")
&& !targetFile.getName().endsWith("-sources.jar")
&& targetFile.getName().endsWith(Constant.JAR_SUFFIX)) {
if (jar == null) {
jar = targetFile;
} else {
if (targetFile.length() > jar.length()) {
jar = targetFile;
}
}
}
}
File target = tar == null ? jar : tar;
if (target != null) {
list.add(target);
}
} else {
findTarOrJar(list, file);
}
}
}
}
}