package xyz.rexlin600.gitlab.biz.impl; import cn.hutool.core.thread.ThreadFactoryBuilder; import lombok.extern.slf4j.Slf4j; import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; import org.gitlab.api.GitlabAPI; import org.gitlab.api.models.GitlabProject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import xyz.rexlin600.gitlab.biz.GitlabService; import xyz.rexlin600.gitlab.common.apiparam.Response; import xyz.rexlin600.gitlab.common.apiparam.ResponseGenerator; import xyz.rexlin600.gitlab.config.GitLabConfigBean; import xyz.rexlin600.gitlab.req.GitlabCloneReq; import xyz.rexlin600.gitlab.util.GitlabUtil; import java.time.Instant; import java.util.List; import java.util.concurrent.*; import java.util.stream.Collectors; /** * GitlabService 实现类 * * @author: rexlin600 * @date: 2020-02-15 */ @Service @Slf4j public class GitlabServiceImpl implements GitlabService { /** * 线程池 */ private ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNamePrefix("gitlab4clone-pool-%d").build(); private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( 5, 10, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy()); /** * GitLab 配置 */ @Autowired private GitLabConfigBean gitLabConfigBean; /** * 列表查询 * * @param req * @return */ @Override public Response list(GitlabCloneReq req) { GitlabAPI gitlabApi = GitlabAPI.connect(gitLabConfigBean.getHost(), gitLabConfigBean.getToken()); List<GitlabProject> allProjects = gitlabApi.getAllProjects(); List<GitlabProject> matchList = getMatchGitlabProjects(req, allProjects); return ResponseGenerator.success(matchList); } /** * 克隆项目 * * @param req * @return */ @Override public Response clone(GitlabCloneReq req) { long start = Instant.now().toEpochMilli(); // 建立 GitLab 连接、获取所有项目 GitlabAPI gitlabApi = GitlabAPI.connect(gitLabConfigBean.getHost(), gitLabConfigBean.getToken()); List<GitlabProject> allProjects = gitlabApi.getAllProjects(); log.info("==> 建立 GitLab【{}】连接,并获取所有的项目成功,共计【{}】个项目", gitLabConfigBean.getHost(), allProjects.size()); // 筛选匹配名称的项目 List<GitlabProject> matchList = getMatchGitlabProjects(req, allProjects); // 未找到匹配项目 if (CollectionUtils.isEmpty(matchList)) { return ResponseGenerator.success("未找到匹配的项目"); } // 输出地址匹配 if (StringUtils.isEmpty(req.getDir())) { log.error("==> 未指定 clone 后存放的位置,请检查参数"); return ResponseGenerator.fail("未指定克隆目录"); } CountDownLatch countDownLatch = new CountDownLatch(matchList.size()); // 组装 git 地址 final UsernamePasswordCredentialsProvider provider = new UsernamePasswordCredentialsProvider( gitLabConfigBean.getUsername(), gitLabConfigBean.getPassword()); final List<GitlabProject> finalMatchList = matchList; for (int i = 0; i < finalMatchList.size(); i++) { int finalI = i; threadPoolExecutor.execute(new Runnable() { GitlabProject m = finalMatchList.get(finalI); @Override public void run() { log.info("==> clone 第【{}】个项目=【{}】到本地目录=【{}】】", (finalI + 1), m.getName(), req.getDir()); GitlabUtil.clone(req, provider, m, countDownLatch); } }); } // 等待线程执行结束再返回 try { boolean await = countDownLatch.await(Long.valueOf(gitLabConfigBean.getMaxTime().longValue()), TimeUnit.SECONDS); if (!await) { log.info("<== 克隆项目已经等待=【{}】秒,请自己核查克隆是否完成", gitLabConfigBean.getMaxTime()); return ResponseGenerator.success("克隆超时,后续克隆将继续进行"); } } catch (Exception e) { log.error("==> 克隆等待出现异常=【{}】", e.getMessage()); return ResponseGenerator.fail("克隆失败"); } long end = Instant.now().toEpochMilli(); log.info("<== 克隆结束,全流程共计耗时=【{}】ms", (end - start)); return ResponseGenerator.success("克隆结束"); } /** * 筛选匹配的项目 * * @param req * @param allProjects * @return */ private List<GitlabProject> getMatchGitlabProjects(GitlabCloneReq req, List<GitlabProject> allProjects) { // 筛选匹配名称的项目 List<GitlabProject> matchList = allProjects; if (!StringUtils.isEmpty(req.getName())) { log.info("==> 筛选模糊匹配 name=【{}】 的全部项目", req.getName()); matchList = allProjects.stream() .filter(m -> m.getName().contains(req.getName())) .collect(Collectors.toList()); } // 筛选匹配 owner 的项目 if (!StringUtils.isEmpty(req.getOwner())) { log.info("==> 筛选指定 owner=【{}】 的全部项目", req.getOwner()); matchList = matchList.stream().filter(m -> m.getOwner().equals(req.getOwner())).collect(Collectors.toList()); } // 筛选指定 namespace 的项目 if (!StringUtils.isEmpty(req.getNamespaceName())) { log.info("==> 筛选指定 namespaceName=【{}】 的全部项目", req.getNamespaceName()); matchList = matchList.stream().filter(m -> m.getNamespace().getName().equals(req.getNamespaceName())).collect(Collectors.toList()); } log.info("==> 满足筛选条件的共计【{}】个项目", matchList.size()); return matchList; } }