diff --git a/pom.xml b/pom.xml index f8e4177c664e864f9c5875e0cbc2d82dfd9d1d20..0843f06ec81e26f3bee40c58599ff9dad1397a28 100644 --- a/pom.xml +++ b/pom.xml @@ -133,7 +133,7 @@ org.openjfx javafx-maven-plugin - 0.0.7 + 0.0.8 diff --git a/src/main/java/com/light/GitManagerApp.java b/src/main/java/com/light/GitManagerApp.java index 6a75c62aed29ae077fa1718923bcdef99200c8c5..c6df68b6a6900c6c78b76f051310f628b26383ba 100644 --- a/src/main/java/com/light/GitManagerApp.java +++ b/src/main/java/com/light/GitManagerApp.java @@ -10,9 +10,7 @@ import com.light.util.FxApplicationContextUtils; import com.light.util.FxUtil; import com.light.util.H2PoolUtils; import javafx.application.Application; -import javafx.geometry.Insets; import javafx.scene.Scene; -import javafx.scene.image.Image; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.layout.StackPane; @@ -20,9 +18,6 @@ import javafx.stage.Stage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static com.light.util.FxApplicationContextUtils.THEME_LIST; -import static com.light.util.FxUtil.MAIN_MODAL_ID; - public class GitManagerApp extends Application { public static final Logger LOGGER = LoggerFactory.getLogger(GitManagerApp.class); @@ -37,26 +32,27 @@ public class GitManagerApp extends Application { super.init(); AsyncTask.runOnce("初始化数据库和主题数据", () -> { String gitDbInit = H2PoolUtils.queryDictByLabel("GIT_DB_INIT", "0"); - if ("0".equals(gitDbInit)) { + if ("1".equals(gitDbInit)) { H2PoolUtils.createTable(); H2PoolUtils.initGitProjectDictData(); } - THEME_LIST.add(new PrimerLight()); - THEME_LIST.add(new PrimerDark()); - THEME_LIST.add(new NordLight()); - THEME_LIST.add(new NordDark()); - THEME_LIST.add(new CupertinoLight()); - THEME_LIST.add(new CupertinoDark()); - THEME_LIST.add(new Dracula()); + FxApplicationContextUtils.THEME_LIST.add(new PrimerLight()); + FxApplicationContextUtils.THEME_LIST.add(new PrimerDark()); + FxApplicationContextUtils.THEME_LIST.add(new NordLight()); + FxApplicationContextUtils.THEME_LIST.add(new NordDark()); + FxApplicationContextUtils.THEME_LIST.add(new CupertinoLight()); + FxApplicationContextUtils.THEME_LIST.add(new CupertinoDark()); + FxApplicationContextUtils.THEME_LIST.add(new Dracula()); // 设置主题 String themeName = H2PoolUtils.queryDictByLabel("GIT_CURRENT_THEME", "Primer Light"); FxApplicationContextUtils.CURRENT_THEME_NAME.set(themeName); - THEME_LIST.stream().filter(theme -> theme.getName().equals(themeName)) + FxApplicationContextUtils.THEME_LIST.stream() + .filter(theme -> theme.getName().equals(themeName)) .findFirst() .ifPresentOrElse(theme -> Application.setUserAgentStylesheet(theme.getUserAgentStylesheet()), - () -> Application.setUserAgentStylesheet(THEME_LIST.getFirst().getUserAgentStylesheet()) + () -> Application.setUserAgentStylesheet(FxApplicationContextUtils.THEME_LIST.getFirst().getUserAgentStylesheet()) ); // 查询所有项目数据 @@ -72,7 +68,7 @@ public class GitManagerApp extends Application { // 遮罩层 var modalPane = new ModalPane(); - modalPane.setId(MAIN_MODAL_ID); + modalPane.setId(FxUtil.MAIN_MODAL_ID); // 左右布局 HBox container = new HBox(); @@ -84,16 +80,16 @@ public class GitManagerApp extends Application { HBox.setHgrow(contentPane, Priority.ALWAYS); root.getChildren().addAll(modalPane, container); - FxUtil.setAnchors(root, Insets.EMPTY); // 场景 Scene scene = new Scene(root); stage.setTitle("Git批量管理工具"); stage.setMinWidth(1100); stage.setMinHeight(650); - stage.getIcons().add(new Image(this.getClass().getResource("/icons/git.png").toExternalForm())); + stage.getIcons().add(FxUtil.getImage("/icons/git.png")); stage.setScene(scene); stage.show(); + // 加载样式,并将scene保存到全局容器变量中 scene.getStylesheets().add(STYLE_SHEET); FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.put("scene", scene); LOGGER.info("项目启动完成,耗时 {} ms", System.currentTimeMillis() - startTime); diff --git a/src/main/java/com/light/component/AuthHandler.java b/src/main/java/com/light/component/AuthHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..198dd04fd7b934d532276429b038f6009709c21e --- /dev/null +++ b/src/main/java/com/light/component/AuthHandler.java @@ -0,0 +1,6 @@ +package com.light.component; + +public interface AuthHandler { + + void handler(String username, String password) throws Exception; +} diff --git a/src/main/java/com/light/component/AuthenticationPane.java b/src/main/java/com/light/component/AuthenticationPane.java index b1372b00648bd54dcbd8ba4d113ee060e80a947a..59ee198d3f176319d9280ac237701e0f8562603b 100644 --- a/src/main/java/com/light/component/AuthenticationPane.java +++ b/src/main/java/com/light/component/AuthenticationPane.java @@ -1,65 +1,51 @@ package com.light.component; import com.light.enums.Level; -import com.light.exception.AuthException; import com.light.exception.H2Exception; -import com.light.exception.JGitException; -import com.light.exception.TimeOutException; import com.light.layout.ModalDialog; import com.light.model.GitAuthInfo; -import com.light.model.GitProject; -import com.light.thread.AsyncTask; -import com.light.util.*; -import javafx.application.Platform; -import javafx.beans.property.SimpleDoubleProperty; +import com.light.util.H2PoolUtils; +import com.light.util.JGitUtils; +import com.light.util.NoticeUtils; import javafx.geometry.Insets; -import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.PasswordField; import javafx.scene.control.TextField; import javafx.scene.layout.VBox; import org.apache.commons.lang3.StringUtils; -import org.eclipse.jgit.transport.CredentialsProvider; - -import java.io.File; -import java.util.Date; public class AuthenticationPane extends ModalDialog { - /** - * 没有权限 - * - * @param clone - * @param index 只有克隆时使用 - * @param remoteUrl - * @param file - */ - public AuthenticationPane(boolean clone, int index, String remoteUrl, File file) { - this(clone, index, remoteUrl, file, null, null, null); - } + private AuthHandler handler; + private static AuthenticationPane authPane; + private final TextField usernameField = new TextField(); + private final PasswordField passwordField = new PasswordField(); + private final Button saveButton = new Button("确定"); - public AuthenticationPane(boolean clone, int index, String remoteUrl, File file, SimpleDoubleProperty rate, GitProject project, Button updateButton) { - super(); - String repoType = JGitUtils.getType(remoteUrl); - header.setTitle(repoType); - content.setBody(createContent(clone, index, repoType, remoteUrl, file, rate, project, updateButton)); - content.setFooter(null); -// FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.put("authDialogShowing", true); + public static AuthenticationPane getInstance() { + if (authPane == null) { + authPane = new AuthenticationPane(); + } + return authPane; } - private VBox createContent(boolean clone, int index, String repoType, String remoteUrl, File file, SimpleDoubleProperty rate, GitProject project, Button updateButton) { - var usernameField = new TextField(); + public AuthenticationPane() { + super(); usernameField.setPromptText("手机/邮箱/用户名"); usernameField.setMaxWidth(300); - var passwordField = new PasswordField(); passwordField.setPromptText("请输入密码"); passwordField.setMaxWidth(300); - Button saveButton = new Button("确定"); saveButton.setMaxWidth(300); - var root = new VBox(10, usernameField, passwordField, saveButton); root.setPadding(new Insets(20)); + header.setTitle(null); + content.setBody(root); + content.setFooter(null); + initEvent(); + } + + private void initEvent() { saveButton.setOnMouseClicked(event -> { String username = usernameField.getText(); String password = passwordField.getText(); @@ -67,66 +53,39 @@ public class AuthenticationPane extends ModalDialog { NoticeUtils.show(null, "用户名密码不能为空", Level.WARN); return; } - GitAuthInfo authInfo = new GitAuthInfo(0, repoType, username, password, ""); - // 入库 - int num = 0; + // 处理公共方法 try { - GitAuthInfo existsAuthInfo = H2PoolUtils.queryAuthInfo(repoType); - if (existsAuthInfo != null) { - // 克隆或者下载时权限异常会执行这段代码 - num = H2PoolUtils.updateAuthInfo(repoType, username, password); - } else { - num = H2PoolUtils.insertAuthInfo(authInfo); - } - } catch (H2Exception e) { - NoticeUtils.show(null, e.getMessage(), Level.WARN); - return; + handler.handler(username, password); + } catch (Exception e) { + NoticeUtils.show(null, "更新权限异常", Level.DANGER); } - if (num > 0) { - JGitUtils.AUTH_INFO_MAP.put(repoType, authInfo); - if (clone) { - if (-1 != index) { - // 克隆项目时没有权限会执行这段代码 - DownloadHBox downloadHBox = (DownloadHBox) FxApplicationContextUtils.DOWNLOAD_LIST.get(index); - downloadHBox.cloneRepo(JGitUtils.createCredential(username, password), false); - } else { - // 第一次克隆 - FxApplicationContextUtils.DOWNLOAD_LIST.add(new DownloadHBox(remoteUrl, file, authInfo, FxApplicationContextUtils.DOWNLOAD_LIST.size())); - } - } else { - // 更新 - if (null != project) { - // 更新更新数量+1 - FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.incrementAndGet())); - AsyncTask.runOnce("更新项目", () -> { - try { - CredentialsProvider provider = JGitUtils.createCredential(username, password); - boolean pull = JGitUtils.pull(remoteUrl, file, provider, rate); - if (pull) { - project.updateTime().set(DateUtils.formatDateTime(new Date())); - H2PoolUtils.updateGitProject(project); - project.selected().set(false); - } - } catch (AuthException e) { - // 弹出输入权限界面 - if (!(Boolean) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("authDialogShowing")) { - AuthenticationPane authPane = new AuthenticationPane(false, -1, remoteUrl, file, rate, project, updateButton); - Platform.runLater(() -> authPane.show((Scene) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("scene"))); - } - } catch (TimeOutException | JGitException e) { + // 关闭界面 + close(); + event.consume(); + }); + } - } - // 更新更新数量-1 - FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.decrementAndGet())); - updateButton.setDisable(false); - }); - } - } - // 关闭界面 - close(); - FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.put("authDialogShowing", false); + public GitAuthInfo dealAuthInfo(String username, String password, String repoType) { + GitAuthInfo authInfo = new GitAuthInfo(0, repoType, username, password, ""); + // 入库 + try { + GitAuthInfo existsAuthInfo = H2PoolUtils.queryAuthInfo(repoType); + if (existsAuthInfo != null) { + // 克隆或者下载时权限异常会执行这段代码 + H2PoolUtils.updateAuthInfo(repoType, username, password); + } else { + H2PoolUtils.insertAuthInfo(authInfo); } - }); - return root; + JGitUtils.AUTH_INFO_MAP.put(repoType, authInfo); + } catch (H2Exception e) { + NoticeUtils.show(null, e.getMessage(), Level.WARN); + return null; + } + return authInfo; + } + + public void refreshData(String remoteUrl, AuthHandler handler) { + this.handler = handler; + header.setTitle(JGitUtils.getType(remoteUrl)); } } diff --git a/src/main/java/com/light/component/CustomProgressMonitor.java b/src/main/java/com/light/component/CustomProgressMonitor.java index e403099cdda87a2cf36ca7fb3ab861359e6af8c4..0a279e50c14a6a6e3e321ba3cc160b5c9ebcb3bb 100644 --- a/src/main/java/com/light/component/CustomProgressMonitor.java +++ b/src/main/java/com/light/component/CustomProgressMonitor.java @@ -1,7 +1,10 @@ package com.light.component; +import javafx.application.Platform; import javafx.beans.property.SimpleDoubleProperty; +import javafx.scene.control.Label; import javafx.scene.control.ProgressBar; +import org.apache.commons.lang3.StringUtils; import org.eclipse.jgit.lib.BatchingProgressMonitor; import java.time.Duration; @@ -16,9 +19,16 @@ public class CustomProgressMonitor extends BatchingProgressMonitor { private final SimpleDoubleProperty rate; + private final Label label; + public CustomProgressMonitor(ProgressBar progressBar, SimpleDoubleProperty rate) { + this(progressBar, rate, null); + } + + public CustomProgressMonitor(ProgressBar progressBar, SimpleDoubleProperty rate, Label label) { this.progressBar = progressBar; this.rate = rate; + this.label = label; progress = new AtomicInteger(0); total = new AtomicInteger(100); } @@ -35,18 +45,21 @@ public class CustomProgressMonitor extends BatchingProgressMonitor { @Override protected void onUpdate(String taskName, int workCurr, int workTotal, int percentDone, Duration duration) { - if (progressBar != null) { - progressBar.setProgress((double) (progress.get() + percentDone) / total.get()); - } if (null != rate) { rate.set((double) (progress.get() + percentDone) / total.get()); } + if (label != null && StringUtils.isNoneBlank(taskName, String.valueOf(workCurr), String.valueOf(workTotal), String.valueOf(percentDone))) { + Platform.runLater(() -> label.setText(taskName + ": " + percentDone + "% (" + workCurr + '/' + workTotal + ')')); + progressBar.setProgress((double) (progress.get() + percentDone) / total.get()); + } } @Override protected void onEndTask(String taskName, int workCurr, int workTotal, int percentDone, Duration duration) { progress.addAndGet(percentDone); total.addAndGet(percentDone); -// System.out.println("taskName: " + taskName + " workCurr: " + workCurr + " workTotal: " + workTotal + " percentDone: " + percentDone); + if (label != null && StringUtils.isNoneBlank(taskName, String.valueOf(workCurr), String.valueOf(workTotal), String.valueOf(percentDone))) { + Platform.runLater(() -> label.setText(taskName + ": " + percentDone + "% (" + workCurr + '/' + workTotal + ')')); + } } } diff --git a/src/main/java/com/light/component/DownAndUpdatePane.java b/src/main/java/com/light/component/DownAndUpdatePane.java index 54672bf47675faf3e8cdd4913be49ad84db2d71b..2756e6bf3f3d02882267ec494aeb9423a5b66d28 100644 --- a/src/main/java/com/light/component/DownAndUpdatePane.java +++ b/src/main/java/com/light/component/DownAndUpdatePane.java @@ -16,6 +16,8 @@ public class DownAndUpdatePane extends ModalDialog { private HBox createContent(ObservableList list) { ListView listView = new ListView<>(list); + listView.setMinWidth(400d); + listView.setMaxWidth(600d); listView.getStyleClass().add("du-list"); return new HBox(listView); } diff --git a/src/main/java/com/light/component/DownloadHBox.java b/src/main/java/com/light/component/DownloadHBox.java index 4d58311fcee2739c2de49f6a2be6980e32f51b81..c4e26105a6dbbf2e4befeb1bb292c38161a8cdc5 100644 --- a/src/main/java/com/light/component/DownloadHBox.java +++ b/src/main/java/com/light/component/DownloadHBox.java @@ -16,6 +16,7 @@ import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleStringProperty; +import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.scene.control.Button; @@ -39,9 +40,8 @@ public class DownloadHBox extends HBox { private final File localRepoFile; private final Button retryButton; private final ProgressBar progressBar = new ProgressBar(0.0); - private final CustomProgressMonitor customProgressMonitor = new CustomProgressMonitor(progressBar, null); - private final int index; - + private final Label text = new Label(); + private final CustomProgressMonitor customProgressMonitor = new CustomProgressMonitor(progressBar, null, text); private CredentialsProvider provider; /** @@ -50,20 +50,18 @@ public class DownloadHBox extends HBox { * @param remoteUrl 远程仓库路径 * @param localRepoFile 本地克隆地址 * @param authInfo 权限 - * @param index 在下载列表中的位置 */ - public DownloadHBox(String remoteUrl, File localRepoFile, GitAuthInfo authInfo, int index) { + public DownloadHBox(String remoteUrl, File localRepoFile, GitAuthInfo authInfo) { super(10); setAlignment(Pos.CENTER); this.remoteUrl = remoteUrl; this.localRepoFile = localRepoFile; - this.index = index; var label = new Label(getRepoName(remoteUrl)); - progressBar.setMaxWidth(300); - var vbox = new VBox(10, label, progressBar); + progressBar.setMinHeight(3d); + var vbox = new VBox(5, label, progressBar, text); retryButton = new Button(null, new FontIcon(BootstrapIcons.PLAY)); retryButton.getStyleClass().addAll(Styles.BUTTON_ICON, Styles.FLAT, Styles.ACCENT); @@ -73,12 +71,17 @@ public class DownloadHBox extends HBox { removeButton.getStyleClass().addAll(Styles.BUTTON_ICON, Styles.FLAT, Styles.ACCENT); getChildren().addAll(vbox, retryButton, removeButton); HBox.setHgrow(vbox, Priority.ALWAYS); + setPadding(new Insets(5, 2, 5, 2)); // 监控器和权限 provider = JGitUtils.createCredential(authInfo.username(), authInfo.password()); retryButton.setOnMouseClicked(event -> cloneRepo(provider, true)); - removeButton.setOnMouseClicked(event -> FxApplicationContextUtils.DOWNLOAD_LIST.remove(this)); + removeButton.setOnMouseClicked(event -> { + FxApplicationContextUtils.DOWNLOAD_LIST.remove(this); + // 更新下载数量-1 + FxApplicationContextUtils.DOWNLOAD_PROPERTY.set(String.valueOf(FxApplicationContextUtils.DOWNLOAD_NUMBER.decrementAndGet())); + }); // 更新下载数量+1 FxApplicationContextUtils.DOWNLOAD_PROPERTY.set(String.valueOf(FxApplicationContextUtils.DOWNLOAD_NUMBER.incrementAndGet())); cloneRepo(provider, false); @@ -104,10 +107,9 @@ public class DownloadHBox extends HBox { branch = JGitUtils.cloneRepo(remoteUrl, localRepoFile, provider, customProgressMonitor); } catch (AuthException e) { // 弹出输入权限界面 - if (!(Boolean) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("authDialogShowing")) { - AuthenticationPane authPane = new AuthenticationPane(true, index, remoteUrl, localRepoFile); - Platform.runLater(() -> authPane.show((Scene) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("scene"))); - } + AuthenticationPane authPane = AuthenticationPane.getInstance(); + authPane.refreshData(remoteUrl, (username, password) -> this.cloneRepo(JGitUtils.createCredential(username, password), true)); + Platform.runLater(() -> authPane.show((Scene) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("scene"))); retryButton.setVisible(true); return; } catch (TimeOutException | JGitException e) { diff --git a/src/main/java/com/light/component/OperationTableCell.java b/src/main/java/com/light/component/OperationTableCell.java index a383e447344f354f9f5ee77c3f186b51661b73e9..ebaee278bf916ef97ab2e0740418e4c572ff88d5 100644 --- a/src/main/java/com/light/component/OperationTableCell.java +++ b/src/main/java/com/light/component/OperationTableCell.java @@ -4,26 +4,20 @@ import atlantafx.base.theme.Styles; import com.light.exception.AuthException; import com.light.exception.JGitException; import com.light.exception.TimeOutException; -import com.light.model.GitAuthInfo; import com.light.model.GitProject; import com.light.thread.AsyncTask; -import com.light.util.DateUtils; import com.light.util.FxApplicationContextUtils; -import com.light.util.H2PoolUtils; import com.light.util.JGitUtils; -import javafx.application.Platform; +import com.light.view.ManagerView; import javafx.beans.property.SimpleDoubleProperty; import javafx.geometry.Pos; -import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.layout.HBox; import javafx.util.Callback; -import org.eclipse.jgit.transport.CredentialsProvider; import java.io.File; -import java.util.Date; /** * 操作列 - 按钮 @@ -63,9 +57,11 @@ public class OperationTableCell extends TableCell { } private void initEvent() { - // TODO Auto-generated method stub updateButton.setOnMouseClicked(event -> { + JGitUtils.GITHUB_FAIL_NUMBER.set(0); + JGitUtils.GITEE_FAIL_NUMBER.set(0); updateButton.setDisable(true); + rate.set(0.0); GitProject project = getTableRow().getItem(); if (null != project) { // 更新更新数量+1 @@ -74,24 +70,10 @@ public class OperationTableCell extends TableCell { File localRepoFile = new File(project.local().get()); String remoteUrl = project.remote(); try { - GitAuthInfo existsAuthInfo = JGitUtils.isExistsAuthInfo(project.remote()); - CredentialsProvider provider = null; - if (existsAuthInfo != null) { - provider = JGitUtils.createCredential(existsAuthInfo.username(), existsAuthInfo.password()); - } - boolean pull = JGitUtils.pull(remoteUrl, localRepoFile, provider, rate); - if (pull) { - project.updateTime().set(DateUtils.formatDateTime(new Date())); - H2PoolUtils.updateGitProject(project); - project.selected().set(false); - } + ManagerView.pull(project, localRepoFile, remoteUrl, rate); } catch (AuthException e) { - // 弹出输入权限界面 - if (!(Boolean) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("authDialogShowing")) { - AuthenticationPane authPane = new AuthenticationPane(false, -1, remoteUrl, localRepoFile, rate, project, updateButton); - Platform.runLater(() -> authPane.show((Scene) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("scene"))); - } - } catch (TimeOutException | JGitException e) { + ManagerView.showAuthPane(remoteUrl, localRepoFile, project, rate, updateButton); + } catch (TimeOutException | JGitException ignored) { } // 更新更新数量-1 diff --git a/src/main/java/com/light/layout/MenuPane.java b/src/main/java/com/light/layout/MenuPane.java index 0bd572fb1efbf5adb099f764320e056f9fe4d4d1..2a4a86ab4dcaecc3aebf6b5585733b4cc1414f0b 100644 --- a/src/main/java/com/light/layout/MenuPane.java +++ b/src/main/java/com/light/layout/MenuPane.java @@ -121,46 +121,5 @@ public class MenuPane extends StackPane { downloadLabel.setOnMouseClicked(event -> { downloadPane.show(getScene()); }); - - /** - * 正在下载视图 - * 项目名 进度条 暂停按钮 取消按钮 - */ - /*downloadLabel.setOnMouseClicked(event -> { - //纵向布局 - VBox vBox = new VBox(10); - List hBoxList = new ArrayList<>(); - for(int i=1; i<=10; i++){ - //横向布局 - HBox hBox = new HBox(15); - hBox.setAlignment(Pos.CENTER); - hBox.getStyleClass().add("menu"); - - //项目名 - Label projectName = new Label("项目" + i); - projectName.setAlignment(Pos.CENTER_LEFT); - //进度条 - ProgressBar bar = new ProgressBar(0); - bar.setProgress(0.8); - - //暂停按钮 - Button stopBtn = new Button("暂停"); - stopBtn.setAlignment(Pos.CENTER_RIGHT); - stopBtn.setOnAction(ss -> { - if("暂停".equals(stopBtn.getText())){ - stopBtn.setText("开始"); - }else if("开始".equals(stopBtn.getText())){ - stopBtn.setText("暂停"); - } - }); - //取消按钮 - Button cannel = new Button("取消"); - cannel.setAlignment(Pos.CENTER_RIGHT); - hBox.getChildren().addAll(projectName,bar,stopBtn,cannel); - hBoxList.add(hBox); - } - vBox.getChildren().addAll(hBoxList); - contentPane.setContent(vBox); - });*/ } } diff --git a/src/main/java/com/light/thread/GitThreadPool.java b/src/main/java/com/light/thread/GitThreadPool.java index 3b158c174805939f600ec5bb3456f1ba35ec7db4..0572585c426895897f7fdb04914147cbc0169af5 100644 --- a/src/main/java/com/light/thread/GitThreadPool.java +++ b/src/main/java/com/light/thread/GitThreadPool.java @@ -11,7 +11,7 @@ public class GitThreadPool { public static final Logger LOGGER = LoggerFactory.getLogger(GitThreadPool.class); // 普通线程池 - public static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(5); + public static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(10); // 定时线程池 public static final ScheduledExecutorService SCHEDULED_EXECUTOR_SERVICE = Executors.newScheduledThreadPool(5); diff --git a/src/main/java/com/light/util/FxUtil.java b/src/main/java/com/light/util/FxUtil.java index 999b9c298e11e332aca48358af618086ae740192..db43480d74e4684b0bf657ee5a7d6bcf5c002d39 100644 --- a/src/main/java/com/light/util/FxUtil.java +++ b/src/main/java/com/light/util/FxUtil.java @@ -14,12 +14,9 @@ import javafx.scene.shape.Rectangle; import javafx.stage.Stage; import javafx.stage.Window; +import java.util.Objects; import java.util.concurrent.Callable; -/** - * @author ChenFei - * @date 2022/12/9 - */ public class FxUtil { /** @@ -29,7 +26,7 @@ public class FxUtil { * @return */ public static String getResource(String resources) { - return FxUtil.class.getResource(resources).toExternalForm(); + return Objects.requireNonNull(FxUtil.class.getResource(resources)).toExternalForm(); } /** @@ -162,4 +159,13 @@ public class FxUtil { AnchorPane.setLeftAnchor(node, insets.getLeft()); } } + + /** + * 添加通知 + * + * @param message + */ + public static void addNoticeList(String message) { + FxApplicationContextUtils.HISTORY_NOTICE_LIST.add(0, message); + } } diff --git a/src/main/java/com/light/util/H2PoolUtils.java b/src/main/java/com/light/util/H2PoolUtils.java index 66db42641b31565d24b3c4545801bd30ce940539..2325b58bf4fe30e4b5101efde627579798ae003c 100644 --- a/src/main/java/com/light/util/H2PoolUtils.java +++ b/src/main/java/com/light/util/H2PoolUtils.java @@ -29,26 +29,21 @@ public class H2PoolUtils { public static final Logger LOGGER = LoggerFactory.getLogger(H2PoolUtils.class); private static JdbcConnectionPool connectionPool = null; - - private static final String DB_DRIVER; private static final String DB_URL; private static final String DB_URL_PREFIX; private static final String DB_URL_SUFFIX; private static final String DB_USERNAME; private static final String DB_PASSWORD; - private static final int DB_POOL_MAXIDLE; private static final int DB_POOL_MAXACTIVE; static { Properties properties = new Properties(); try { properties.load(H2PoolUtils.class.getResourceAsStream("/db.properties")); - DB_DRIVER = properties.getProperty("jdbc.driver", "org.h2.Driver"); DB_URL_PREFIX = properties.getProperty("jdbc.url.prefix", "jdbc:h2:file:"); DB_URL_SUFFIX = properties.getProperty("jdbc.url.suffix", "/.h2/git-db;AUTO_SERVER=TRUE"); DB_USERNAME = properties.getProperty("jdbc.username", "git"); DB_PASSWORD = properties.getProperty("jdbc.password", "git@123"); - DB_POOL_MAXIDLE = Integer.parseInt(properties.getProperty("jdbc.pool.maxIdle", "5")); DB_POOL_MAXACTIVE = Integer.parseInt(properties.getProperty("jdbc.pool.maxActive", "20")); DB_URL = DB_URL_PREFIX + System.getProperty("user.home") + DB_URL_SUFFIX; } catch (IOException e) { diff --git a/src/main/java/com/light/util/JGitUtils.java b/src/main/java/com/light/util/JGitUtils.java index 8bd8502577d7a097e17d7dfc0a7f082ea65c0572..7602c0572446c6b2df0e13106353d36b13e36d90 100644 --- a/src/main/java/com/light/util/JGitUtils.java +++ b/src/main/java/com/light/util/JGitUtils.java @@ -6,20 +6,24 @@ import com.light.exception.JGitException; import com.light.exception.TimeOutException; import com.light.model.GitAuthInfo; import com.light.model.GitProject; +import javafx.application.Platform; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleStringProperty; +import org.apache.commons.collections4.CollectionUtils; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.PullCommand; import org.eclipse.jgit.api.PullResult; import org.eclipse.jgit.transport.CredentialsProvider; +import org.eclipse.jgit.transport.RemoteConfig; import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; public class JGitUtils { public static final Logger LOGGER = LoggerFactory.getLogger(JGitUtils.class); @@ -30,6 +34,10 @@ public class JGitUtils { // 存放解析出来的本地项目 private static final List PROJECT_FILE = new ArrayList<>(); + // github和gitee更新失败次数,超过10次则不更新 + public static final AtomicInteger GITHUB_FAIL_NUMBER = new AtomicInteger(0); + public static final AtomicInteger GITEE_FAIL_NUMBER = new AtomicInteger(0); + /** * 凭证管理 * @@ -136,8 +144,23 @@ public class JGitUtils { public static void parseLocalProject() { PROJECT_FILE.forEach(path -> { try (Git git = Git.open(path)) { - String remotePath = git.remoteList().call().get(0).getURIs().get(0).toString(); - String name = remotePath.substring(remotePath.lastIndexOf("/") + 1, remotePath.lastIndexOf(".")); + List call = git.remoteList().call(); + if (CollectionUtils.isEmpty(call)) { + // 本地项目 - 不加载 + return; + } + String remotePath = call.get(0).getURIs().get(0).toString(); + if (!remotePath.contains("/")) { + // 本地项目 - 不加载 + LOGGER.warn(remotePath); + return; + } + String name; + if (remotePath.contains(".") && remotePath.lastIndexOf(".") > remotePath.lastIndexOf("/")) { + name = remotePath.substring(remotePath.lastIndexOf("/") + 1, remotePath.lastIndexOf(".")); + } else { + name = remotePath.substring(remotePath.lastIndexOf("/") + 1); + } String author = remotePath.substring(0, remotePath.lastIndexOf("/")); String branch = git.getRepository().getBranch(); String absolutePath = path.getAbsolutePath(); @@ -160,6 +183,7 @@ public class JGitUtils { // 插入之前验证是否已经存在 if (H2PoolUtils.existsGitProjects(newProject)) { LOGGER.warn("项目 {},作者 {} 已经存在,不再新增", name, author); + Platform.runLater(() -> FxApplicationContextUtils.HISTORY_NOTICE_LIST.add("项目 " + name + ",作者 " + author + " 已经存在,不再新增")); newProject = null; } else { // 不存在则继续新增,并设置id @@ -168,6 +192,7 @@ public class JGitUtils { } } catch (Exception e) { LOGGER.error("本地项目 {} 解析失败:{}", path.getAbsolutePath(), e.getMessage()); + Platform.runLater(() -> FxApplicationContextUtils.HISTORY_NOTICE_LIST.add("本地项目 " + path.getAbsolutePath() + " 解析失败:" + e.getMessage())); } }); @@ -183,6 +208,7 @@ public class JGitUtils { } catch (Exception e) { String message = e.getMessage(); LOGGER.error("项目 {} 克隆异常:{}", remoteUrl, message); + Platform.runLater(() -> FxApplicationContextUtils.HISTORY_NOTICE_LIST.add("项目 " + remoteUrl + " 克隆异常:" + message)); if (message.contains("authorized") || message.contains("Authentication")) { // 权限异常 throw new AuthException(); @@ -207,11 +233,20 @@ public class JGitUtils { } catch (Exception e) { String message = e.getMessage(); LOGGER.error("项目 {} 更新异常:{}", remoteUrl, message); - FxApplicationContextUtils.HISTORY_NOTICE_LIST.add(e.getMessage()); + Platform.runLater(() -> FxApplicationContextUtils.HISTORY_NOTICE_LIST.add("项目 " + remoteUrl + " 更新异常:" + message)); + if ("Github".equals(getType(remoteUrl))) { + GITHUB_FAIL_NUMBER.incrementAndGet(); + } if (message.contains("authorized") || message.contains("Authentication")) { + if ("Gitee".equals(getType(remoteUrl))) { + GITEE_FAIL_NUMBER.incrementAndGet(); + } // 权限异常 throw new AuthException(); } else if (message.contains("time out") || message.contains("timeout")) { + if ("Gitee".equals(getType(remoteUrl))) { + GITEE_FAIL_NUMBER.incrementAndGet(); + } // 超时异常 throw new TimeOutException(); } diff --git a/src/main/java/com/light/view/HomeView.java b/src/main/java/com/light/view/HomeView.java index 8e620893a31960e96c247d1f857eeba50c5322ec..5a9176eee7b9b1e645b08c529b11fd81e2032efa 100644 --- a/src/main/java/com/light/view/HomeView.java +++ b/src/main/java/com/light/view/HomeView.java @@ -16,10 +16,12 @@ import javafx.scene.layout.BorderPane; import javafx.scene.layout.VBox; import javafx.stage.DirectoryChooser; import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; import org.kordamp.ikonli.antdesignicons.AntDesignIconsOutlined; import org.kordamp.ikonli.javafx.FontIcon; import java.io.File; +import java.util.Objects; import static com.light.util.NoticeUtils.show; @@ -49,7 +51,6 @@ public class HomeView extends BorderPane { this.setCenter(downloadVBox); initEvent(); - FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.put("authDialogShowing", false); } private void initEvent() { @@ -62,7 +63,7 @@ public class HomeView extends BorderPane { } else { // 检查仓库地址是不是为空 File file = new File(targetPathField.getText()); - if (file.isFile() || (file.isDirectory() && file.listFiles().length > 0)) { + if (file.isFile() || (file.isDirectory() && Objects.requireNonNull(file.listFiles()).length > 0)) { show(null, "仓库地址不为空", Level.WARN); return; } @@ -74,15 +75,17 @@ public class HomeView extends BorderPane { // 判断权限信息是否存在 GitAuthInfo authInfo = JGitUtils.isExistsAuthInfo(remoteUrl); if (authInfo != null) { - FxApplicationContextUtils.DOWNLOAD_LIST.add(new DownloadHBox(remoteUrl, file, authInfo, FxApplicationContextUtils.DOWNLOAD_LIST.size())); + FxApplicationContextUtils.DOWNLOAD_LIST.add(new DownloadHBox(remoteUrl, file, authInfo)); } else { - AuthenticationPane authPane = new AuthenticationPane(true, -1, remoteUrl, file); + // 弹出权限界面 + AuthenticationPane authPane = getAuthenticationPane(remoteUrl, file); authPane.show(getScene()); } // 清空信息 clonePathField.setText(""); targetPathField.setText(""); downloadButton.setDisable(true); + btn.consume(); } } catch (Exception e) { show(null, "下载失败,请稍后重试", Level.DANGER); @@ -128,4 +131,17 @@ public class HomeView extends BorderPane { } }); } + + @NotNull + private static AuthenticationPane getAuthenticationPane(String remoteUrl, File file) throws Exception { + AuthenticationPane authPane = AuthenticationPane.getInstance(); + authPane.refreshData(remoteUrl, (username, password) -> { + GitAuthInfo authInfo = authPane.dealAuthInfo(username, password, JGitUtils.getType(remoteUrl)); + if (authInfo != null) { + // 第一次克隆 + FxApplicationContextUtils.DOWNLOAD_LIST.add(new DownloadHBox(remoteUrl, file, authInfo)); + } + }); + return authPane; + } } \ No newline at end of file diff --git a/src/main/java/com/light/view/ManagerView.java b/src/main/java/com/light/view/ManagerView.java index 35f8a77d47d098548546249e7aa0b823d184dad6..2f5596d3212b7a984113cde9c478465adcf6e1fc 100644 --- a/src/main/java/com/light/view/ManagerView.java +++ b/src/main/java/com/light/view/ManagerView.java @@ -3,6 +3,7 @@ package com.light.view; import atlantafx.base.controls.CustomTextField; import atlantafx.base.theme.Styles; import atlantafx.base.theme.Tweaks; +import com.google.common.collect.Lists; import com.light.component.AuthenticationPane; import com.light.component.LevelTableCell; import com.light.component.OperationTableCell; @@ -37,13 +38,15 @@ import org.apache.commons.lang3.StringUtils; import org.eclipse.jgit.transport.CredentialsProvider; import org.kordamp.ikonli.bootstrapicons.BootstrapIcons; import org.kordamp.ikonli.javafx.FontIcon; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.File; import java.util.Date; import java.util.List; public class ManagerView extends StackPane { - + public static final Logger LOGGER = LoggerFactory.getLogger(ManagerView.class); // 上半部分:搜索、更新 private CustomTextField searchField; private final Button updateButton = new Button("更新"); @@ -182,44 +185,39 @@ public class ManagerView extends StackPane { // 全部更新按钮 updateButton.setOnMouseClicked(event -> { + JGitUtils.GITHUB_FAIL_NUMBER.set(0); + JGitUtils.GITEE_FAIL_NUMBER.set(0); List list = tableView.getItems().stream().filter(param -> param.selected().get()).toList(); if (!list.isEmpty()) { updateButton.setDisable(true); } - list.forEach(param -> { - SimpleDoubleProperty rate = param.downloadRate(); - rate.set(0.0); - // 更新更新数量+1 - FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.incrementAndGet())); - AsyncTask.runOnce("更新项目", () -> { + // 更新更新数量 + FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.addAndGet(list.size()))); + List> partitioned = Lists.partition(list, list.size() / 5); + partitioned.forEach(partitionList -> AsyncTask.runOnce("更新项目", () -> { + partitionList.forEach(param -> { + SimpleDoubleProperty rate = param.downloadRate(); File localRepoFile = new File(param.local().get()); String remoteUrl = param.remote(); try { - GitAuthInfo existsAuthInfo = JGitUtils.isExistsAuthInfo(param.remote()); - CredentialsProvider provider = null; - if (existsAuthInfo != null) { - provider = JGitUtils.createCredential(existsAuthInfo.username(), existsAuthInfo.password()); - } - boolean pull = JGitUtils.pull(remoteUrl, localRepoFile, provider, rate); - if (pull) { - param.updateTime().set(DateUtils.formatDateTime(new Date())); - H2PoolUtils.updateGitProject(param); - param.selected().set(false); + if ("Gitee".equals(JGitUtils.getType(remoteUrl)) && JGitUtils.GITEE_FAIL_NUMBER.get() < 10) { + pull(param, localRepoFile, remoteUrl, rate); + } else if ("Github".equals(JGitUtils.getType(remoteUrl)) && JGitUtils.GITHUB_FAIL_NUMBER.get() < 5) { + pull(param, localRepoFile, remoteUrl, rate); } } catch (AuthException e) { - // 弹出输入权限界面 - if (!(Boolean) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("authDialogShowing")) { - AuthenticationPane authPane = new AuthenticationPane(false, -1, remoteUrl, localRepoFile, rate, param, updateButton); - Platform.runLater(() -> authPane.show((Scene) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("scene"))); - } - } catch (TimeOutException | JGitException e) { + LOGGER.error("项目 {} 需要权限", remoteUrl); + } catch (TimeOutException | JGitException ignored) { + } catch (Exception e) { + LOGGER.error("项目更新异常:{}", e.getMessage()); } // 更新更新数量-1 FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.decrementAndGet())); - updateButton.setDisable(false); }); - }); + updateButton.setDisable(false); + })); + event.consume(); }); // 删除 @@ -231,6 +229,53 @@ public class ManagerView extends StackPane { FxApplicationContextUtils.GIT_PROJECT_OBSERVABLE_LIST.remove(project); } }); + tableView.setItems(FxApplicationContextUtils.GIT_PROJECT_OBSERVABLE_LIST); + searchField.setText(""); + selectAll.setSelected(!selectAll.isSelected()); + }); + } + + public static void showAuthPane(String remoteUrl, File file, GitProject project, SimpleDoubleProperty rate, Button updateButton) throws Exception { + // 弹出输入权限界面 + AuthenticationPane authPane = AuthenticationPane.getInstance(); + authPane.refreshData(remoteUrl, (username, password) -> { + GitAuthInfo authInfo = authPane.dealAuthInfo(username, password, JGitUtils.getType(remoteUrl)); + if (authInfo != null) { + // 更新 + // 更新更新数量+1 + FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.incrementAndGet())); + try { + CredentialsProvider provider = JGitUtils.createCredential(username, password); + boolean pull = JGitUtils.pull(remoteUrl, file, provider, rate); + if (pull) { + project.updateTime().set(DateUtils.formatDateTime(new Date())); + H2PoolUtils.updateGitProject(project); + project.selected().set(false); + } + } catch (AuthException e1) { + // 弹出输入权限界面 + Platform.runLater(() -> authPane.show((Scene) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("scene"))); + } catch (TimeOutException | JGitException ignored) { + + } + // 更新更新数量-1 + FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.decrementAndGet())); + } }); + Platform.runLater(() -> authPane.show((Scene) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("scene"))); + } + + public static void pull(GitProject project, File localRepoFile, String remoteUrl, SimpleDoubleProperty rate) { + GitAuthInfo existsAuthInfo = JGitUtils.isExistsAuthInfo(project.remote()); + CredentialsProvider provider = null; + if (existsAuthInfo != null) { + provider = JGitUtils.createCredential(existsAuthInfo.username(), existsAuthInfo.password()); + } + boolean pull = JGitUtils.pull(remoteUrl, localRepoFile, provider, rate); + if (pull) { + project.updateTime().set(DateUtils.formatDateTime(new Date())); + H2PoolUtils.updateGitProject(project); + project.selected().set(false); + } } } diff --git a/src/main/resources/db.properties b/src/main/resources/db.properties index 907a0be903c75b4c00f99c2dd81c28e1fc9b8816..17a6ddf7b55ef823fcc695b9fcf422d37e3442d9 100644 --- a/src/main/resources/db.properties +++ b/src/main/resources/db.properties @@ -1,9 +1,7 @@ #h2 database settings -jdbc.driver=org.h2.Driver jdbc.url.prefix=jdbc:h2:file: jdbc.url.suffix=/.h2/git-db;AUTO_SERVER=TRUE jdbc.username=git jdbc.password=git@123 #connection pool settings -jdbc.pool.maxIdle=5 jdbc.pool.maxActive=20 \ No newline at end of file diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index c194821669b699dee59b62671ef8b5bc5a26a68c..55961187a8a387ac5cf86169a9533b4bd6f6b0d1 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -30,34 +30,6 @@ - - - - - ${LOG_PATTERN} - UTF-8 - - - ${LOG_HOME}/debug.log - - - - ${LOG_HOME}/bak/debug-%d{yyyy-MM-dd}.%i.log - - 50MB - - 30 - - 500MB - - - - DEBUG - ACCEPT - DENY - - - @@ -78,114 +50,6 @@ 500MB - - - INFO - ACCEPT - DENY - - - - - - - - ${LOG_PATTERN} - UTF-8 - - - ${LOG_HOME}/warn.log - - - - ${LOG_HOME}/bak/warn-%d{yyyy-MM-dd}.%i.log - - 50MB - - 30 - - 500MB - - - - WARN - ACCEPT - DENY - - - - - - - - ${LOG_PATTERN} - UTF-8 - - - ${LOG_HOME}/error.log - - - - ${LOG_HOME}/bak/error-%d{yyyy-MM-dd}.%i.log - - 50MB - - 30 - - 500MB - - - - ERROR - ACCEPT - DENY - - - - - - - - - ${LOG_PATTERN} - UTF-8 - - - ${LOG_HOME}/common.log - - - - ${LOG_HOME}/bak/common-%d{yyyy-MM-dd}.%i.log - - 50MB - - 30 - - 500MB - - - - - - - - - ${LOG_PATTERN} - UTF-8 - - - ${LOG_HOME}/class.log - - - - ${LOG_HOME}/bak/class-%d{yyyy-MM-dd}.%i.log - - 50MB - - 30 - - 500MB - @@ -210,20 +74,6 @@ - - - - - - - - - - @@ -232,10 +82,7 @@ - - - \ No newline at end of file