This is an automated email from the ASF dual-hosted git repository.
mattcasters pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git
The following commit(s) were added to refs/heads/main by this push:
new f43bd97186 Issue #8251: Multi-user session isolation and hardening for
Git plugin (#8365)
f43bd97186 is described below
commit f43bd971869e2cb484771f3c86031c7b6c81da4f
Author: Matt Casters <[email protected]>
AuthorDate: Tue Sep 15 12:43:37 2026 +0200
Issue #8251: Multi-user session isolation and hardening for Git plugin
(#8365)
- Resolve cross-session bleeding in multi-user Hop Web by removing
process-wide static singletons from GitPerspective and GitCommitPerspective.
- Guard all public perspective methods with isInitialized() and display
asyncExec checks to prevent SWT invalid thread access and NPEs when
perspectives are disabled or uninitialized.
- Safely fall back to ExplorerPerspective.refresh() and web commit dialogs
when GitPerspective or GitCommitPerspective are disabled in the active session.
- Fix resource and listener leaks: auto-close PlotWalk, cancel automatic
fetch timers, close git repositories, and unregister from HopGuiKeyHandler on
shell disposal.
- Replace java.io.File usage with Apache Commons VFS (HopVfs).
- Synchronize GitConfigSingleton to ensure thread-safe config access.
- Add comprehensive session isolation and uninitialized safety tests in
GitGuiPluginSessionIsolationTest.
---
.../org/apache/hop/git/GitCommitPerspective.java | 252 ++++++---
.../main/java/org/apache/hop/git/GitGuiPlugin.java | 118 +++--
.../java/org/apache/hop/git/GitPerspective.java | 579 ++++++++++++++-------
.../apache/hop/git/config/GitConfigSingleton.java | 17 +-
.../git/info/GitInfoExplorerFileTypeHandler.java | 14 +-
.../hop/git/GitGuiPluginSessionIsolationTest.java | 87 ++++
6 files changed, 763 insertions(+), 304 deletions(-)
diff --git
a/plugins/misc/git/src/main/java/org/apache/hop/git/GitCommitPerspective.java
b/plugins/misc/git/src/main/java/org/apache/hop/git/GitCommitPerspective.java
index f20044f05c..6202c45141 100644
---
a/plugins/misc/git/src/main/java/org/apache/hop/git/GitCommitPerspective.java
+++
b/plugins/misc/git/src/main/java/org/apache/hop/git/GitCommitPerspective.java
@@ -17,7 +17,6 @@
package org.apache.hop.git;
-import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -118,7 +117,7 @@ public class GitCommitPerspective implements
IHopPerspective {
private static final String STAGED_LABEL =
"GitCommitPerspective.Status.Staged.Label";
private static final String UNSTAGED_LABEL =
"GitCommitPerspective.Status.Unstaged.Label";
private static final String UNTRACKED_LABEL =
"GitCommitPerspective.Status.Untracked.Label";
- private static GitCommitPerspective instance;
+ private static GitCommitPerspective testFallback;
private HopGui hopGui;
private SashForm wSashForm;
@@ -136,19 +135,25 @@ public class GitCommitPerspective implements
IHopPerspective {
private GuiMenuWidgets menuWidgets;
public GitCommitPerspective() {
- instance = this;
+ if (HopGui.peekInstance() == null) {
+ testFallback = this;
+ }
}
public static GitCommitPerspective getInstance() {
- try {
- GitCommitPerspective fromGui =
HopGui.findSessionPerspective(GitCommitPerspective.class);
- if (fromGui != null) {
- return fromGui;
- }
- } catch (Throwable e) {
- // No HopGuiImpl in unit tests
+ HopGui hopGui = HopGui.peekInstance();
+ if (hopGui != null) {
+ return HopGui.findSessionPerspective(GitCommitPerspective.class);
}
- return instance;
+ return testFallback;
+ }
+
+ public static void setTestFallback(GitCommitPerspective fallback) {
+ testFallback = fallback;
+ }
+
+ public boolean isInitialized() {
+ return hopGui != null && wTree != null && !wTree.isDisposed();
}
@Override
@@ -160,7 +165,7 @@ public class GitCommitPerspective implements
IHopPerspective {
@GuiOsxKeyboardShortcut(command = true, shift = true, key = 'o', global =
true)
@Override
public void activate() {
- if (hopGui == null) {
+ if (!isInitialized()) {
// The perspective is switched off in disabledGuiElements.xml: it was
never initialized, so
// there is nothing to switch to. The git toolbar and menu items that
lead here live on the
// explorer perspective and are still there.
@@ -184,6 +189,9 @@ public class GitCommitPerspective implements
IHopPerspective {
@Override
public void perspectiveActivated() {
+ if (!isInitialized()) {
+ return;
+ }
// TODO: avoid refresh when perspective is activated, detect change in the
config, metadata,
// file explorer
refresh();
@@ -191,7 +199,7 @@ public class GitCommitPerspective implements
IHopPerspective {
@Override
public boolean isActive() {
- return hopGui != null && hopGui.isActivePerspective(this);
+ return isInitialized() && hopGui.isActivePerspective(this);
}
@Override
@@ -211,29 +219,9 @@ public class GitCommitPerspective implements
IHopPerspective {
retrieveState();
refresh();
- // Refresh the state when a file changes
- // TODO: For now we refresh when we active the perspective
- // hopGui
- // .getEventsHandler()
- // .addEventListener(
- // getClass().getName(),
- // e -> refresh(),
- // HopGuiEvents.ProjectUpdated.name(),
- // HopGuiEvents.PipelineCreated.name(),
- // HopGuiEvents.PipelineUpdated.name(),
- // HopGuiEvents.PipelineDeleted.name(),
- // HopGuiEvents.WorkflowCreated.name(),
- // HopGuiEvents.WorkflowUpdated.name(),
- // HopGuiEvents.WorkflowDeleted.name(),
- // HopGuiEvents.MetadataCreated.name(),
- // HopGuiEvents.MetadataChanged.name(),
- // HopGuiEvents.MetadataDeleted.name(),
- // HopGuiEvents.FileCreated.name(),
- // HopGuiEvents.FileChanged.name(),
- // HopGuiEvents.FileDeleted.name()
- // );
-
HopGuiKeyHandler.getInstance().addParentObjectToHandle(this);
+ wSashForm.addListener(
+ SWT.Dispose, e ->
HopGuiKeyHandler.getInstance().removeParentObjectToHandle(this));
}
protected void createTree(Composite parent) {
@@ -353,10 +341,15 @@ public class GitCommitPerspective implements
IHopPerspective {
@GuiKeyboardShortcut(control = true, key = 'k', global = true)
@GuiOsxKeyboardShortcut(command = true, key = 'k', global = true)
public void selectAllChanged() {
+ if (!isInitialized()) {
+ return;
+ }
checkChangedFiles();
- wMessage.selectAll();
- wMessage.setFocus();
+ if (wMessage != null && !wMessage.isDisposed()) {
+ wMessage.selectAll();
+ wMessage.setFocus();
+ }
}
/**
@@ -411,7 +404,11 @@ public class GitCommitPerspective implements
IHopPerspective {
}
protected void retrieveState() {
- if (wMessage == null || wMessage.isDisposed()) {
+ if (!isInitialized() || wMessage == null || wMessage.isDisposed()) {
+ return;
+ }
+ if (wMessage.getDisplay() != org.eclipse.swt.widgets.Display.getCurrent())
{
+ wMessage.getDisplay().asyncExec(this::retrieveState);
return;
}
try {
@@ -430,6 +427,9 @@ public class GitCommitPerspective implements
IHopPerspective {
}
protected void saveState() {
+ if (!isInitialized() || wMessage == null || wMessage.isDisposed()) {
+ return;
+ }
try {
List<String> messages = new ArrayList<>();
messages.add(wMessage.getText());
@@ -490,6 +490,9 @@ public class GitCommitPerspective implements
IHopPerspective {
@GuiKeyboardShortcut(control = true, alt = true, key = 'A')
@GuiOsxKeyboardShortcut(control = true, alt = true, key = 'A')
public void addFilesToGit() {
+ if (!isInitialized()) {
+ return;
+ }
try {
List<UIFile> files = getSelectedFiles();
if (files.isEmpty()) {
@@ -497,6 +500,9 @@ public class GitCommitPerspective implements
IHopPerspective {
}
UIGit git = GitGuiPlugin.getInstance().getGit();
+ if (git == null) {
+ return;
+ }
for (UIFile file : files) {
git.add(file.getName());
}
@@ -534,6 +540,9 @@ public class GitCommitPerspective implements
IHopPerspective {
@GuiKeyboardShortcut(control = true, alt = true, key = 'U')
@GuiOsxKeyboardShortcut(control = true, alt = true, key = 'U')
public void unstageFiles() {
+ if (!isInitialized()) {
+ return;
+ }
try {
List<UIFile> files = getSelectedStagedFiles();
if (files.isEmpty()) {
@@ -541,6 +550,9 @@ public class GitCommitPerspective implements
IHopPerspective {
}
UIGit git = GitGuiPlugin.getInstance().getGit();
+ if (git == null) {
+ return;
+ }
Set<String> unstagedFileNames = new HashSet<>();
for (UIFile file : files) {
git.resetPath(file.getName());
@@ -574,12 +586,18 @@ public class GitCommitPerspective implements
IHopPerspective {
label = "i18n::GitCommitPerspective.Menu.AddToGitIgnore.Text",
image = "ignore.svg")
public void addFilesToGitIgnore() {
+ if (!isInitialized()) {
+ return;
+ }
List<UIFile> files = getSelectedFiles();
if (files.isEmpty()) {
return;
}
UIGit git = GitGuiPlugin.getInstance().getGit();
+ if (git == null) {
+ return;
+ }
for (UIFile file : files) {
git.addPathToIgnore(file.getName());
}
@@ -607,10 +625,16 @@ public class GitCommitPerspective implements
IHopPerspective {
@GuiKeyboardShortcut(key = SWT.DEL)
@GuiOsxKeyboardShortcut(key = SWT.DEL)
public void deleteFiles() {
+ if (!isInitialized()) {
+ return;
+ }
try {
List<UIFile> files = getSelectedFiles();
if (!files.isEmpty()) {
UIGit git = GitGuiPlugin.getInstance().getGit();
+ if (git == null) {
+ return;
+ }
ExplorerPerspective perspective = ExplorerPerspective.getInstance();
List<String> filesToClose = new ArrayList<>();
@@ -639,8 +663,10 @@ public class GitCommitPerspective implements
IHopPerspective {
refresh();
// Refresh perspectives (file explorer, metadata)
- // TODO: Find a better way
- GitPerspective.getInstance().refresh(true);
+ GitPerspective gitPerspective = GitPerspective.getInstance();
+ if (gitPerspective != null && gitPerspective.isInitialized()) {
+ gitPerspective.refresh(true);
+ }
}
} catch (Exception e) {
new ErrorDialog(
@@ -668,6 +694,9 @@ public class GitCommitPerspective implements
IHopPerspective {
@GuiKeyboardShortcut(alt = true, control = true, key = 'Z')
@GuiOsxKeyboardShortcut(alt = true, control = true, key = 'Z')
public void restoreFiles() {
+ if (!isInitialized()) {
+ return;
+ }
try {
// Restore only selected staged file, use delete for untracked files
List<UIFile> files = this.getSelectedStagedFiles();
@@ -694,6 +723,9 @@ public class GitCommitPerspective implements
IHopPerspective {
boolean deleteAddedFiles = dialog.getToggleState();
UIGit git = GitGuiPlugin.getInstance().getGit();
+ if (git == null) {
+ return;
+ }
List<String> filesToClose = new ArrayList<>();
List<String> filesToReload = new ArrayList<>();
@@ -733,8 +765,10 @@ public class GitCommitPerspective implements
IHopPerspective {
refresh();
// Refresh perspectives (file explorer, metadata)
- // TODO: Find a better way
- GitPerspective.getInstance().refresh(true);
+ GitPerspective gitPerspective = GitPerspective.getInstance();
+ if (gitPerspective != null && gitPerspective.isInitialized()) {
+ gitPerspective.refresh(true);
+ }
}
} catch (Exception e) {
@@ -748,15 +782,11 @@ public class GitCommitPerspective implements
IHopPerspective {
private String getAbsolutePath(String root, String relativePath) {
try {
- FileObject fileObj = HopVfs.getFileObject(new File(root,
relativePath).getAbsolutePath());
- String path =
- fileObj.exists()
- ? HopVfs.getFilename(fileObj)
- : new File(root, relativePath).getAbsolutePath();
-
- return path;
+ FileObject rootObj = HopVfs.getFileObject(root);
+ FileObject fileObj = rootObj.resolveFile(relativePath);
+ return HopVfs.getFilename(fileObj);
} catch (Exception ignored) {
- return new File(root, relativePath).getAbsolutePath();
+ return root + "/" + relativePath;
}
}
@@ -770,11 +800,12 @@ public class GitCommitPerspective implements
IHopPerspective {
@GuiKeyboardShortcut(control = true, key = 'D')
@GuiOsxKeyboardShortcut(control = true, key = 'D')
public void showTextDiff() {
+ if (!isInitialized() || wTree.getSelectionCount() == 0) {
+ return;
+ }
try {
TreeItem treeItem = wTree.getSelection()[0];
- if (treeItem != null) {
- UIFile file = (UIFile) treeItem.getData();
-
+ if (treeItem != null && treeItem.getData() instanceof UIFile file) {
String commitIdNew = VCS.WORKINGTREE;
String commitIdOld = Constants.HEAD;
@@ -782,7 +813,7 @@ public class GitCommitPerspective implements
IHopPerspective {
}
} catch (Exception e) {
new ErrorDialog(
- HopGui.getInstance().getShell(),
+ getShell(),
BaseMessages.getString(PKG,
"GitGuiPlugin.Dialog.ShowDiffError.Header"),
BaseMessages.getString(PKG,
"GitGuiPlugin.Dialog.ShowDiffError.Message"),
e);
@@ -798,20 +829,25 @@ public class GitCommitPerspective implements
IHopPerspective {
@GuiKeyboardShortcut(control = true, shift = true, key = 'D')
@GuiOsxKeyboardShortcut(control = true, shift = true, key = 'D')
public void showGraphDiff() {
+ if (!isInitialized() || wTree.getSelectionCount() == 0) {
+ return;
+ }
try {
TreeItem treeItem = wTree.getSelection()[0];
- if (treeItem != null) {
- UIFile file = (UIFile) treeItem.getData();
-
+ if (treeItem != null && treeItem.getData() instanceof UIFile file) {
String commitIdNew = VCS.WORKINGTREE;
String commitIdOld = Constants.HEAD;
ExplorerPerspective perspective = HopGui.getExplorerPerspective();
- if (perspective.getPipelineFileType().isHandledBy(file.getName(),
false)) {
+ if (perspective != null
+ && perspective.getPipelineFileType() != null
+ && perspective.getPipelineFileType().isHandledBy(file.getName(),
false)) {
// A pipeline
//
GitGuiPlugin.getInstance().showPipelineFileDiff(file.getName(),
commitIdNew, commitIdOld);
- } else if
(perspective.getWorkflowFileType().isHandledBy(file.getName(), false)) {
+ } else if (perspective != null
+ && perspective.getWorkflowFileType() != null
+ && perspective.getWorkflowFileType().isHandledBy(file.getName(),
false)) {
// A workflow
//
GitGuiPlugin.getInstance().showWorkflowFileDiff(file.getName(),
commitIdNew, commitIdOld);
@@ -819,7 +855,7 @@ public class GitCommitPerspective implements
IHopPerspective {
}
} catch (Exception e) {
new ErrorDialog(
- HopGui.getInstance().getShell(),
+ getShell(),
BaseMessages.getString(PKG,
"GitGuiPlugin.Dialog.ShowDiffError.Header"),
BaseMessages.getString(PKG,
"GitGuiPlugin.Dialog.ShowDiffError.Message"),
e);
@@ -827,7 +863,14 @@ public class GitCommitPerspective implements
IHopPerspective {
}
public void commitFiles(boolean push) {
+ if (!isInitialized()) {
+ return;
+ }
try {
+ UIGit uiGit = GitGuiPlugin.getInstance().getGit();
+ if (uiGit == null) {
+ return;
+ }
// Selected staged or unstaged files
List<UIFile> filesToCommit = this.getSelectedFiles(wTree.getItems(), new
ArrayList<>(), true);
@@ -854,7 +897,6 @@ public class GitCommitPerspective implements
IHopPerspective {
}
// Standard author by default
- UIGit uiGit = GitGuiPlugin.getInstance().getGit();
String authorName = uiGit.getAuthorName(VCS.WORKINGTREE);
String message = wMessage.getText();
boolean amend = wAmend.getSelection();
@@ -905,7 +947,10 @@ public class GitCommitPerspective implements
IHopPerspective {
refresh();
// Refresh file and git perspectives
- GitPerspective.getInstance().refresh(true);
+ GitPerspective gitPerspective = GitPerspective.getInstance();
+ if (gitPerspective != null && gitPerspective.isInitialized()) {
+ gitPerspective.refresh(true);
+ }
wAmend.setSelection(false);
@@ -915,7 +960,7 @@ public class GitCommitPerspective implements
IHopPerspective {
pushed = uiGit.push();
} catch (Exception e) {
new ErrorDialog(
- HopGui.getInstance().getShell(),
+ getShell(),
BaseMessages.getString(PKG,
"GitGuiPlugin.Dialog.PushError.Header"),
BaseMessages.getString(PKG,
"GitGuiPlugin.Dialog.PushError.Message"),
e);
@@ -936,7 +981,7 @@ public class GitCommitPerspective implements
IHopPerspective {
getCommitIdLabel(commitId)));
} catch (Exception e) {
new ErrorDialog(
- HopGui.getInstance().getShell(),
+ getShell(),
BaseMessages.getString(PKG,
"GitGuiPlugin.Dialog.CommitError.Header"),
BaseMessages.getString(PKG,
"GitGuiPlugin.Dialog.CommitError.Message"),
e);
@@ -967,9 +1012,11 @@ public class GitCommitPerspective implements
IHopPerspective {
* #updateGui()} so it lives exactly as long as the user's next action.
*/
private void showStatus(Image image, String message) {
- wStatus.setImage(image);
- wStatus.setText(message);
- wStatus.setVisible(true);
+ if (wStatus != null && !wStatus.isDisposed()) {
+ wStatus.setImage(image);
+ wStatus.setText(message);
+ wStatus.setVisible(true);
+ }
}
/**
@@ -1062,21 +1109,49 @@ public class GitCommitPerspective implements
IHopPerspective {
/* Update toolbar, button and menu state */
public void updateGui() {
+ if (!isInitialized()) {
+ return;
+ }
+ if (wTree.getDisplay() != org.eclipse.swt.widgets.Display.getCurrent()) {
+ wTree.getDisplay().asyncExec(this::updateGui);
+ return;
+ }
boolean gitEnabled = GitGuiPlugin.getInstance().getGit() != null;
- boolean commitEnabled = gitEnabled && !wMessage.getText().trim().isEmpty();
- wToolBar.setEnabled(gitEnabled);
- wTree.setEnabled(gitEnabled);
- wAmend.setEnabled(gitEnabled);
- wMessage.setEnabled(gitEnabled);
+ boolean commitEnabled =
+ gitEnabled
+ && wMessage != null
+ && !wMessage.isDisposed()
+ && !wMessage.getText().trim().isEmpty();
+
+ if (wToolBar != null && !wToolBar.isDisposed()) {
+ wToolBar.setEnabled(gitEnabled);
+ }
+ if (wTree != null && !wTree.isDisposed()) {
+ wTree.setEnabled(gitEnabled);
+ }
+ if (wAmend != null && !wAmend.isDisposed()) {
+ wAmend.setEnabled(gitEnabled);
+ }
+ if (wMessage != null && !wMessage.isDisposed()) {
+ wMessage.setEnabled(gitEnabled);
+ }
- toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_ADD,
!getSelectedUnstagedFiles().isEmpty());
- toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_UNSTAGE,
!getSelectedStagedFiles().isEmpty());
- toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_RESTORE,
!getSelectedStagedFiles().isEmpty());
- toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_DELETE,
!getSelectedFiles().isEmpty());
+ if (toolBarWidgets != null) {
+ toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_ADD,
!getSelectedUnstagedFiles().isEmpty());
+ toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_UNSTAGE,
!getSelectedStagedFiles().isEmpty());
+ toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_RESTORE,
!getSelectedStagedFiles().isEmpty());
+ toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_DELETE,
!getSelectedFiles().isEmpty());
+ }
- wStatus.setVisible(false);
- wCommit.setEnabled(commitEnabled);
- wCommitAndPush.setEnabled(commitEnabled);
+ if (wStatus != null && !wStatus.isDisposed()) {
+ wStatus.setVisible(false);
+ }
+ if (wCommit != null && !wCommit.isDisposed()) {
+ wCommit.setEnabled(commitEnabled);
+ }
+ if (wCommitAndPush != null && !wCommitAndPush.isDisposed()) {
+ wCommitAndPush.setEnabled(commitEnabled);
+ }
}
@GuiToolbarElement(
@@ -1087,10 +1162,14 @@ public class GitCommitPerspective implements
IHopPerspective {
@GuiKeyboardShortcut(key = SWT.F5)
@GuiOsxKeyboardShortcut(key = SWT.F5)
public void refresh() {
+ if (!isInitialized()) {
+ return;
+ }
+ if (wTree.getDisplay() != org.eclipse.swt.widgets.Display.getCurrent()) {
+ wTree.getDisplay().asyncExec(this::refresh);
+ return;
+ }
try {
- if (wTree == null || wTree.isDisposed()) {
- return;
- }
wTree.setRedraw(false);
wTree.removeAll();
@@ -1156,7 +1235,14 @@ public class GitCommitPerspective implements
IHopPerspective {
}
protected Shell getShell() {
- return hopGui.getShell();
+ if (wSashForm != null && !wSashForm.isDisposed()) {
+ return wSashForm.getShell();
+ }
+ if (hopGui != null) {
+ return hopGui.getShell();
+ }
+ HopGui currentHop = HopGui.peekInstance();
+ return currentHop != null ? currentHop.getShell() : null;
}
@Override
diff --git
a/plugins/misc/git/src/main/java/org/apache/hop/git/GitGuiPlugin.java
b/plugins/misc/git/src/main/java/org/apache/hop/git/GitGuiPlugin.java
index 31e302bdfa..3e6853c468 100644
--- a/plugins/misc/git/src/main/java/org/apache/hop/git/GitGuiPlugin.java
+++ b/plugins/misc/git/src/main/java/org/apache/hop/git/GitGuiPlugin.java
@@ -157,6 +157,9 @@ public class GitGuiPlugin
public void addRootChangedListener() {
git = null;
ExplorerPerspective explorerPerspective =
ExplorerPerspective.getInstance();
+ if (explorerPerspective == null) {
+ return;
+ }
// Listener to what's going on in the explorer perspective...
//
@@ -165,9 +168,38 @@ public class GitGuiPlugin
explorerPerspective.getRefreshListeners().add(this);
explorerPerspective.getSelectionListeners().add(this);
+ HopGui hopGui = HopGui.peekInstance();
+ if (hopGui != null && hopGui.getShell() != null &&
!hopGui.getShell().isDisposed()) {
+ hopGui
+ .getShell()
+ .addListener(
+ SWT.Dispose,
+ e -> {
+ if (git != null) {
+ try {
+ git.closeRepo();
+ } catch (Exception ignored) {
+ }
+ git = null;
+ }
+ });
+ }
+
enableButtons();
}
+ private void refreshGitPerspective(boolean refreshAll) {
+ GitPerspective gitPerspective = GitPerspective.getInstance();
+ if (gitPerspective != null && gitPerspective.isInitialized()) {
+ gitPerspective.refresh(refreshAll);
+ } else if (refreshAll) {
+ ExplorerPerspective explorerPerspective =
ExplorerPerspective.getInstance();
+ if (explorerPerspective != null) {
+ explorerPerspective.refresh();
+ }
+ }
+ }
+
@GuiMenuElement(
root = ExplorerPerspective.GUI_PLUGIN_CONTEXT_MENU_PARENT_ID,
parentId = ExplorerPerspective.GUI_PLUGIN_CONTEXT_MENU_PARENT_ID,
@@ -188,7 +220,12 @@ public class GitGuiPlugin
if (EnvironmentUtils.getInstance().isWeb()) {
gitCommitOnWeb();
} else {
- GitCommitPerspective.getInstance().activate();
+ GitCommitPerspective perspective = GitCommitPerspective.getInstance();
+ if (perspective != null && perspective.isInitialized()) {
+ perspective.activate();
+ } else {
+ gitCommitOnWeb();
+ }
}
}
@@ -331,13 +368,16 @@ public class GitGuiPlugin
label = "i18n::GitGuiPlugin.Menu.Branch.Pull.Text",
image = "pull.svg")
public void gitPull() {
+ if (git == null) {
+ return;
+ }
try {
boolean merged = git.pull();
// Refresh the explorer file, refs and commit history. A pull fetches
the remote refs even
// when there was nothing to merge into the current branch.
//
- GitPerspective.getInstance().refresh(true);
+ refreshGitPerspective(true);
if (merged) {
MessageBox pullSuccessful =
@@ -545,12 +585,7 @@ public class GitGuiPlugin
// Refresh the git history, file explorer tree, change colors...
//
- // TODO: To remove when git perspective work on web
- if (EnvironmentUtils.getInstance().isWeb()) {
- ExplorerPerspective.getInstance().refresh();
- } else {
- GitPerspective.getInstance().refresh(true);
- }
+ refreshGitPerspective(true);
enableButtons();
}
@@ -617,12 +652,16 @@ public class GitGuiPlugin
// Close the tabs of the files which were deleted
//
List<String> filenamesToClose = new ArrayList<>();
+ FileObject rootObj = HopVfs.getFileObject(git.getDirectory());
for (String filePath : pathsToClean) {
- if (!new File(git.getDirectory(), filePath).exists()) {
+ if (!rootObj.resolveFile(filePath).exists()) {
filenamesToClose.add(filenames.get(filePath));
}
}
-
ExplorerPerspective.getInstance().closeTabsForFilenames(filenamesToClose);
+ ExplorerPerspective explorer = ExplorerPerspective.getInstance();
+ if (explorer != null) {
+ explorer.closeTabsForFilenames(filenamesToClose);
+ }
// Show confirmation message once after all files have been deleted
MessageBox box =
@@ -642,12 +681,7 @@ public class GitGuiPlugin
// Refresh the git history, file explorer tree, change colors...
//
- // TODO: To remove when git perspective work on web
- if (EnvironmentUtils.getInstance().isWeb()) {
- ExplorerPerspective.getInstance().refresh();
- } else {
- GitPerspective.getInstance().refresh(true);
- }
+ refreshGitPerspective(true);
enableButtons();
}
@@ -658,16 +692,17 @@ public class GitGuiPlugin
* @return The filename to match open tabs with
*/
private String getOpenFilename(String relativePath) {
- File file = new File(git.getDirectory(), relativePath);
+ if (git == null) {
+ return relativePath;
+ }
try {
- FileObject fileObject = HopVfs.getFileObject(file.getAbsolutePath());
- if (fileObject.exists()) {
- return HopVfs.getFilename(fileObject);
- }
+ FileObject root = HopVfs.getFileObject(git.getDirectory());
+ FileObject fileObject = root.resolveFile(relativePath);
+ return HopVfs.getFilename(fileObject);
} catch (Exception ignored) {
// Fall back to the absolute filename below
}
- return file.getAbsolutePath();
+ return git.getDirectory() + "/" + relativePath;
}
@GuiMenuElement(
@@ -677,6 +712,9 @@ public class GitGuiPlugin
label = "i18n::GitGuiPlugin.Menu.Branch.Create.Text",
image = "branch-add.svg")
public void gitCreateBranch() {
+ if (git == null) {
+ return;
+ }
EnterStringDialog enterStringDialog =
new EnterStringDialog(
HopGui.getInstance().getShell(),
@@ -700,7 +738,7 @@ public class GitGuiPlugin
// Refresh the git history, file explorer tree, change colors...
//
- GitPerspective.getInstance().refresh(true);
+ refreshGitPerspective(true);
}
}
@@ -711,6 +749,9 @@ public class GitGuiPlugin
label = "i18n::GitGuiPlugin.Menu.Branch.Rename.Text",
image = "ui/images/rename.svg")
public void gitRenameBranch() {
+ if (git == null) {
+ return;
+ }
String oldName =
HopGui.getInstance().getStatusToolbarWidgets().getToolbarItemText(ID_TOOLBAR_ITEM_GIT);
EnterStringDialog enterStringDialog =
@@ -724,6 +765,7 @@ public class GitGuiPlugin
boolean renamed = git.renameBranch(oldName, newName);
if (renamed) {
this.setBranchLabel(newName);
+ refreshGitPerspective(false);
}
}
}
@@ -735,6 +777,9 @@ public class GitGuiPlugin
label = "i18n::GitGuiPlugin.Menu.Branch.Merge.Text",
image = "git-merge.svg")
public void gitMergeBranch() {
+ if (git == null) {
+ return;
+ }
List<String> branches = git.getBranches();
EnterSelectionDialog selectionDialog =
new EnterSelectionDialog(
@@ -767,16 +812,19 @@ public class GitGuiPlugin
// Refresh the git history, file explorer tree, change colors...
//
- GitPerspective.getInstance().refresh(true);
+ refreshGitPerspective(true);
}
}
private void gitCheckoutBranch(String name) {
+ if (git == null) {
+ return;
+ }
git.checkout(name);
// Refresh the git history, file explorer tree, change colors...
//
- GitPerspective.getInstance().refresh(true);
+ refreshGitPerspective(true);
}
@GuiMenuElement(
@@ -786,6 +834,9 @@ public class GitGuiPlugin
label = "i18n::GitGuiPlugin.Menu.Branch.Delete.Text",
image = "ui/images/delete.svg")
public void gitDeleteBranch() {
+ if (git == null) {
+ return;
+ }
List<String> branches = git.getBranches();
EnterSelectionDialog selectionDialog =
new EnterSelectionDialog(
@@ -810,7 +861,7 @@ public class GitGuiPlugin
// Refresh the git history, file explorer tree, change colors...
//
- GitPerspective.getInstance().refresh(true);
+ refreshGitPerspective(true);
}
}
@@ -833,6 +884,9 @@ public class GitGuiPlugin
private ExplorerFile getSelectedFile() {
ExplorerPerspective explorerPerspective =
ExplorerPerspective.getInstance();
+ if (explorerPerspective == null) {
+ return null;
+ }
return explorerPerspective.getSelectedFile();
}
@@ -870,9 +924,15 @@ public class GitGuiPlugin
enableButtons();
// Refresh Git perspectives when a project is activated
- GitPerspective.getInstance().refresh(false);
- GitCommitPerspective.getInstance().retrieveState();
- GitCommitPerspective.getInstance().refresh();
+ GitPerspective gitPerspective = GitPerspective.getInstance();
+ if (gitPerspective != null && gitPerspective.isInitialized()) {
+ gitPerspective.refresh(false);
+ }
+ GitCommitPerspective gitCommitPerspective =
GitCommitPerspective.getInstance();
+ if (gitCommitPerspective != null && gitCommitPerspective.isInitialized()) {
+ gitCommitPerspective.retrieveState();
+ gitCommitPerspective.refresh();
+ }
}
private FileObject findGitConfig(String rootFolderName, boolean
searchParentFolders)
diff --git
a/plugins/misc/git/src/main/java/org/apache/hop/git/GitPerspective.java
b/plugins/misc/git/src/main/java/org/apache/hop/git/GitPerspective.java
index 6a0e58af45..1113944603 100644
--- a/plugins/misc/git/src/main/java/org/apache/hop/git/GitPerspective.java
+++ b/plugins/misc/git/src/main/java/org/apache/hop/git/GitPerspective.java
@@ -194,7 +194,7 @@ public class GitPerspective implements IHopPerspective {
public static final String OPTION_SHOW_ALL_REF = "Git.ShowAllRef";
- private static GitPerspective instance;
+ private static GitPerspective testFallback;
private HopGui hopGui;
private SashForm wSashForm;
@@ -225,19 +225,28 @@ public class GitPerspective implements IHopPerspective {
private Timer fetchAutomaticTimer;
public GitPerspective() {
- instance = this;
+ if (HopGui.peekInstance() == null) {
+ testFallback = this;
+ }
}
public static GitPerspective getInstance() {
try {
- GitPerspective fromGui =
HopGui.findSessionPerspective(GitPerspective.class);
- if (fromGui != null) {
- return fromGui;
+ if (HopGui.peekInstance() != null) {
+ return HopGui.findSessionPerspective(GitPerspective.class);
}
} catch (Throwable e) {
- // No HopGuiImpl in unit tests
+ // No HopGui in headless unit tests
}
- return instance;
+ return testFallback;
+ }
+
+ /**
+ * Whether this perspective has been attached to a {@link HopGui} instance
and its controls have
+ * been created and are still live.
+ */
+ public boolean isInitialized() {
+ return hopGui != null && wSashForm != null && !wSashForm.isDisposed();
}
@Override
@@ -249,7 +258,7 @@ public class GitPerspective implements IHopPerspective {
@GuiOsxKeyboardShortcut(command = true, shift = true, key = 'g', global =
true)
@Override
public void activate() {
- if (hopGui == null) {
+ if (!isInitialized()) {
// The perspective is switched off in disabledGuiElements.xml: it was
never initialized, so
// there is nothing to switch to. The git toolbar and menu items that
lead here live on the
// explorer perspective and are still there.
@@ -273,15 +282,20 @@ public class GitPerspective implements IHopPerspective {
@Override
public void perspectiveActivated() {
+ if (!isInitialized()) {
+ return;
+ }
// TODO: avoid refresh when perspective is activated, detect change in the
file explorer model
refresh();
- wSearchText.setFocus();
+ if (wSearchText != null && !wSearchText.isDisposed()) {
+ wSearchText.setFocus();
+ }
}
@Override
public boolean isActive() {
- return hopGui != null && hopGui.isActivePerspective(this);
+ return isInitialized() && hopGui.isActivePerspective(this);
}
@Override
@@ -312,12 +326,22 @@ public class GitPerspective implements IHopPerspective {
// Add key listeners
HopGuiKeyHandler.getInstance().addParentObjectToHandle(this);
+ wSashForm.addListener(
+ SWT.Dispose,
+ e -> {
+ stopFetchAutomaticTimer();
+ HopGuiKeyHandler.getInstance().removeParentObjectToHandle(this);
+ });
hopGui
.getEventsHandler()
.addEventListener(
getClass().getName() + "ProjectActivated",
- e -> hopGui.getDisplay().asyncExec(this::clearSearchFilters),
+ e -> {
+ if (hopGui != null && !hopGui.getDisplay().isDisposed()) {
+ hopGui.getDisplay().asyncExec(this::clearSearchFilters);
+ }
+ },
HopGuiEvents.ProjectActivated.name());
}
@@ -525,14 +549,18 @@ public class GitPerspective implements IHopPerspective {
}
protected void refreshFiles() {
+ if (!isInitialized() || wFileTree == null || wFileTree.isDisposed()) {
+ return;
+ }
try {
setDiffText("");
wFileTree.setRedraw(false);
wFileTree.removeAll();
RevCommit commit = getSelectedCommit();
- if (commit != null) {
- Git git = GitGuiPlugin.getInstance().getGit().getGit();
+ UIGit uiGit = GitGuiPlugin.getInstance().getGit();
+ if (commit != null && uiGit != null && uiGit.getGit() != null) {
+ Git git = uiGit.getGit();
try (TreeWalk treeWalk = new TreeWalk(git.getRepository())) {
if (commit.getParentCount() > 0) {
treeWalk.addTree(commit.getParent(0).getTree());
@@ -570,7 +598,9 @@ public class GitPerspective implements IHopPerspective {
}
}
- wFileTree.setRedraw(true);
+ if (!wFileTree.isDisposed()) {
+ wFileTree.setRedraw(true);
+ }
refreshFileDiff();
} catch (Exception e) {
@@ -585,22 +615,25 @@ public class GitPerspective implements IHopPerspective {
if (commit != null && fileName != null) {
UIGit git = GitGuiPlugin.getInstance().getGit();
+ if (git != null) {
+ String commitId = commit.name();
+ String parentCommitId = git.getParentCommitId(commitId);
+ String diff = git.diff(parentCommitId, commitId, fileName);
- String commitId = commit.name();
- String parentCommitId = git.getParentCommitId(commitId);
- String diff = git.diff(parentCommitId, commitId, fileName);
-
- setDiffText(diff);
+ setDiffText(diff);
- // Enable visual diff button?
- visualDiffEnabled = FileTypeUtils.isHopFileType(fileName);
+ // Enable visual diff button?
+ visualDiffEnabled = FileTypeUtils.isHopFileType(fileName);
+ }
}
- fileToolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_FILE_SHOW_TEXT_DIFF,
visualDiffEnabled);
+ if (fileToolBarWidgets != null) {
+ fileToolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_FILE_SHOW_TEXT_DIFF,
visualDiffEnabled);
+ }
}
public Ref getSelectedReference() {
- if (wRefTree.getSelectionCount() < 1) {
+ if (wRefTree == null || wRefTree.isDisposed() ||
wRefTree.getSelectionCount() < 1) {
return null;
}
TreeItem item = wRefTree.getSelection()[0];
@@ -612,7 +645,9 @@ public class GitPerspective implements IHopPerspective {
}
public RevCommit getSelectedCommit() {
- if (wHistoryTable.getSelectionCount() < 1) {
+ if (wHistoryTable == null
+ || wHistoryTable.isDisposed()
+ || wHistoryTable.getSelectionCount() < 1) {
return null;
}
@@ -625,7 +660,7 @@ public class GitPerspective implements IHopPerspective {
}
public String getSelectedFile() {
- if (wFileTree.getSelectionCount() < 1) {
+ if (wFileTree == null || wFileTree.isDisposed() ||
wFileTree.getSelectionCount() < 1) {
return null;
}
@@ -790,6 +825,9 @@ public class GitPerspective implements IHopPerspective {
label = "i18n::GitPerspective.Menu.ResetToCommit.Text",
image = "git-reset.svg")
public void resetToCommit() {
+ if (!isInitialized()) {
+ return;
+ }
RevCommit commit = getSelectedCommit();
if (commit != null) {
ResetTypeDialog dialog = new ResetTypeDialog(getShell());
@@ -797,10 +835,10 @@ public class GitPerspective implements IHopPerspective {
if (resetType != null) {
UIGit git = GitGuiPlugin.getInstance().getGit();
-
- git.reset(commit.getId().name(), resetType);
-
- refresh(true);
+ if (git != null) {
+ git.reset(commit.getId().name(), resetType);
+ refresh(true);
+ }
}
}
}
@@ -812,9 +850,15 @@ public class GitPerspective implements IHopPerspective {
label = "i18n::GitPerspective.Menu.RevertCommit.Text",
image = "git-restore.svg")
public void revertCommit() {
+ if (!isInitialized()) {
+ return;
+ }
RevCommit commit = getSelectedCommit();
if (commit != null) {
UIGit uigit = GitGuiPlugin.getInstance().getGit();
+ if (uigit == null) {
+ return;
+ }
// Check if the git repository is clean
if (!uigit.isClean()) {
@@ -840,9 +884,10 @@ public class GitPerspective implements IHopPerspective {
try {
Git git = uigit.getGit();
- RevCommit revertCommit = git.revert().include(commit).call();
-
- refresh(true);
+ if (git != null) {
+ RevCommit revertCommit = git.revert().include(commit).call();
+ refresh(true);
+ }
} catch (Exception e) {
new ErrorDialog(
getShell(),
@@ -867,6 +912,9 @@ public class GitPerspective implements IHopPerspective {
toolTip = "i18n::GitPerspective.Toolbar.RevertFile.Tooltip",
image = "git-restore.svg")
public void revertFile() {
+ if (!isInitialized()) {
+ return;
+ }
RevCommit commit = getSelectedCommit();
String path = getSelectedFile();
@@ -875,6 +923,9 @@ public class GitPerspective implements IHopPerspective {
}
UIGit git = GitGuiPlugin.getInstance().getGit();
+ if (git == null) {
+ return;
+ }
String commitId = commit.getId().name();
// Undo what the commit did to the file: put back the version of its parent
@@ -948,9 +999,15 @@ public class GitPerspective implements IHopPerspective {
toolTip = "i18n::GitPerspective.Toolbar.CherryPickCommit.Tooltip",
image = "cherry-pick.svg")
public void cherryPickCommit() {
+ if (!isInitialized()) {
+ return;
+ }
RevCommit commit = getSelectedCommit();
if (commit != null) {
UIGit uigit = GitGuiPlugin.getInstance().getGit();
+ if (uigit == null) {
+ return;
+ }
// Check if the git repository is clean
if (!uigit.isClean()) {
@@ -964,22 +1021,23 @@ public class GitPerspective implements IHopPerspective {
try {
Git git = uigit.getGit();
+ if (git != null) {
+ CherryPickResult result =
git.cherryPick().include(commit).setNoCommit(false).call();
+
+ if (result.getStatus() ==
CherryPickResult.CherryPickStatus.CONFLICTING) {
+ MessageBox dialog = new MessageBox(getShell(), SWT.ICON_WARNING |
SWT.YES | SWT.NO);
+ dialog.setText(
+ BaseMessages.getString(PKG,
"GitGuiPlugin.Dialog.CherryPickCommit.Header"));
+ dialog.setMessage(
+ BaseMessages.getString(
+ PKG,
+ "GitGuiPlugin.Dialog.CherryPickCommitConflicts.Message",
+ commit,
+ result.getFailingPaths()));
+ }
- CherryPickResult result =
git.cherryPick().include(commit).setNoCommit(false).call();
-
- if (result.getStatus() ==
CherryPickResult.CherryPickStatus.CONFLICTING) {
- MessageBox dialog = new MessageBox(getShell(), SWT.ICON_WARNING |
SWT.YES | SWT.NO);
- dialog.setText(
- BaseMessages.getString(PKG,
"GitGuiPlugin.Dialog.CherryPickCommit.Header"));
- dialog.setMessage(
- BaseMessages.getString(
- PKG,
- "GitGuiPlugin.Dialog.CherryPickCommitConflicts.Message",
- commit,
- result.getFailingPaths()));
+ refresh(true);
}
-
- refresh(true);
} catch (Exception e) {
new ErrorDialog(
getShell(),
@@ -1002,6 +1060,9 @@ public class GitPerspective implements IHopPerspective {
toolTip = "i18n::GitPerspective.Toolbar.CherryPickFile.Tooltip",
image = "cherry-pick.svg")
public void cherryPickFile() {
+ if (!isInitialized()) {
+ return;
+ }
RevCommit commit = getSelectedCommit();
String path = getSelectedFile();
@@ -1010,6 +1071,9 @@ public class GitPerspective implements IHopPerspective {
}
UIGit git = GitGuiPlugin.getInstance().getGit();
+ if (git == null) {
+ return;
+ }
String commitId = commit.getId().name();
if (!confirmFileAction(
@@ -1051,11 +1115,16 @@ public class GitPerspective implements IHopPerspective {
label = "i18n::GitPerspective.Menu.Checkout.Text",
image = "ui/images/check.svg")
public void checkoutReference() {
+ if (!isInitialized()) {
+ return;
+ }
Ref ref = getSelectedReference();
if (ref != null) {
- GitGuiPlugin.getInstance().getGit().checkout(ref.getName());
-
- refresh(true);
+ UIGit git = GitGuiPlugin.getInstance().getGit();
+ if (git != null) {
+ git.checkout(ref.getName());
+ refresh(true);
+ }
}
}
@@ -1067,11 +1136,16 @@ public class GitPerspective implements IHopPerspective {
label = "i18n::GitPerspective.Menu.CheckoutRevision.Text",
image = "ui/images/check.svg")
public void checkoutCommit() {
+ if (!isInitialized()) {
+ return;
+ }
RevCommit commit = getSelectedCommit();
if (commit != null) {
- GitGuiPlugin.getInstance().getGit().checkout(commit.getName());
-
- refresh(true);
+ UIGit git = GitGuiPlugin.getInstance().getGit();
+ if (git != null) {
+ git.checkout(commit.getName());
+ refresh(true);
+ }
}
}
@@ -1087,6 +1161,9 @@ public class GitPerspective implements IHopPerspective {
toolTip = "i18n::GitPerspective.History.Toolbar.CreateTag.Tooltip",
image = "tag-add.svg")
public void addTag() {
+ if (!isInitialized()) {
+ return;
+ }
RevCommit commit = getSelectedCommit();
if (commit != null) {
EnterStringDialog dialog =
@@ -1099,7 +1176,7 @@ public class GitPerspective implements IHopPerspective {
String name = dialog.open();
if (name != null) {
UIGit git = GitGuiPlugin.getInstance().getGit();
- if (git.createTag(name, commit.getId().name())) {
+ if (git != null && git.createTag(name, commit.getId().name())) {
refresh(false);
}
}
@@ -1119,6 +1196,9 @@ public class GitPerspective implements IHopPerspective {
toolTip = "i18n::GitPerspective.History.Toolbar.CreateBranch.Tooltip",
image = "branch-add.svg")
public void addBranchFromCommit() {
+ if (!isInitialized()) {
+ return;
+ }
RevCommit commit = getSelectedCommit();
if (commit != null) {
EnterStringDialog dialog =
@@ -1131,7 +1211,7 @@ public class GitPerspective implements IHopPerspective {
String name = dialog.open();
if (name != null) {
UIGit git = GitGuiPlugin.getInstance().getGit();
- if (git.createBranch(name, commit.getId().name())) {
+ if (git != null && git.createBranch(name, commit.getId().name())) {
// Refresh the explorer file, refs and commit history
refresh(true);
}
@@ -1147,6 +1227,9 @@ public class GitPerspective implements IHopPerspective {
label = "i18n::GitPerspective.Menu.CreateBranchFrom.Text",
image = "branch-add.svg")
public void addBranchFromRef() {
+ if (!isInitialized()) {
+ return;
+ }
Ref ref = getSelectedReference();
if (ref != null) {
EnterStringDialog dialog =
@@ -1159,7 +1242,7 @@ public class GitPerspective implements IHopPerspective {
String name = dialog.open();
if (name != null) {
UIGit git = GitGuiPlugin.getInstance().getGit();
- if (git.createBranch(name, ref.getName())) {
+ if (git != null && git.createBranch(name, ref.getName())) {
// Refresh the explorer file, refs and commit history
refresh(true);
}
@@ -1174,15 +1257,20 @@ public class GitPerspective implements IHopPerspective {
label = "i18n::GitPerspective.Menu.MergeInto.Text",
image = "git-merge.svg")
public void mergeBranch() {
+ if (!isInitialized()) {
+ return;
+ }
Ref ref = getSelectedReference();
if (ref != null) {
try {
UIGit git = GitGuiPlugin.getInstance().getGit();
- String name = git.getShortenedName(ref.getName());
- git.mergeBranch(name, MergeStrategy.RECURSIVE);
+ if (git != null) {
+ String name = git.getShortenedName(ref.getName());
+ git.mergeBranch(name, MergeStrategy.RECURSIVE);
- // Refresh the explorer file, refs and commit history
- refresh(true);
+ // Refresh the explorer file, refs and commit history
+ refresh(true);
+ }
} catch (Exception e) {
new ErrorDialog(
getShell(),
@@ -1207,11 +1295,17 @@ public class GitPerspective implements IHopPerspective {
toolTip = "i18n::GitPerspective.History.Toolbar.Fetch.Tooltip",
image = "fetch.svg")
public void fetch() {
+ if (!isInitialized()) {
+ return;
+ }
try {
- GitGuiPlugin.getInstance().getGit().fetch();
+ UIGit git = GitGuiPlugin.getInstance().getGit();
+ if (git != null) {
+ git.fetch();
- // Refresh refs and commit history
- refresh(false);
+ // Refresh refs and commit history
+ refresh(false);
+ }
} catch (Exception e) {
new ErrorDialog(
getShell(),
@@ -1235,11 +1329,17 @@ public class GitPerspective implements IHopPerspective {
@GuiKeyboardShortcut(control = true, key = 'T')
@GuiOsxKeyboardShortcut(control = true, key = 'T')
public void pull() {
+ if (!isInitialized()) {
+ return;
+ }
try {
- GitGuiPlugin.getInstance().getGit().pull();
+ UIGit git = GitGuiPlugin.getInstance().getGit();
+ if (git != null) {
+ git.pull();
- // Refresh the explorer file, refs and commit history
- refresh(true);
+ // Refresh the explorer file, refs and commit history
+ refresh(true);
+ }
} catch (Exception e) {
new ErrorDialog(
getShell(),
@@ -1255,11 +1355,17 @@ public class GitPerspective implements IHopPerspective {
toolTip = "i18n::GitGuiPlugin.Toolbar.Push.Tooltip",
image = "push.svg")
public void push() {
+ if (!isInitialized()) {
+ return;
+ }
try {
- GitGuiPlugin.getInstance().getGit().push();
+ UIGit git = GitGuiPlugin.getInstance().getGit();
+ if (git != null) {
+ git.push();
- // Refresh refs and commit history
- refresh(false);
+ // Refresh refs and commit history
+ refresh(false);
+ }
} catch (Exception e) {
new ErrorDialog(
getShell(),
@@ -1277,17 +1383,22 @@ public class GitPerspective implements IHopPerspective {
label = "i18n::GitPerspective.Menu.Push.Text",
image = "push.svg")
public void pushReference() {
+ if (!isInitialized()) {
+ return;
+ }
Ref ref = getSelectedReference();
if (ref == null) {
return;
}
try {
UIGit git = GitGuiPlugin.getInstance().getGit();
- String type = ref.getName().startsWith(Constants.R_TAGS) ? VCS.TYPE_TAG
: VCS.TYPE_BRANCH;
- git.push(type, git.getShortenedName(ref.getName()));
+ if (git != null) {
+ String type = ref.getName().startsWith(Constants.R_TAGS) ?
VCS.TYPE_TAG : VCS.TYPE_BRANCH;
+ git.push(type, git.getShortenedName(ref.getName()));
- // Refresh refs and commit history
- refresh(false);
+ // Refresh refs and commit history
+ refresh(false);
+ }
} catch (Exception e) {
new ErrorDialog(
getShell(),
@@ -1307,19 +1418,26 @@ public class GitPerspective implements IHopPerspective {
@GuiKeyboardShortcut(key = SWT.F2)
@GuiOsxKeyboardShortcut(key = SWT.F2)
public void renameReference() {
+ if (!isInitialized()) {
+ return;
+ }
Ref ref = this.getSelectedReference();
- if (ref != null) {
+ if (ref != null && wRefTree.getSelectionCount() > 0) {
boolean isRemote = ref.getName().startsWith(Constants.R_REMOTES);
if (!isRemote && !ref.getName().startsWith(Constants.R_HEADS)) {
// Only branches can be renamed
return;
}
- if (isRemote &&
GitGuiPlugin.getInstance().getGit().isRemoteHead(ref.getName())) {
+ UIGit git = GitGuiPlugin.getInstance().getGit();
+ if (git == null) {
+ return;
+ }
+ if (isRemote && git.isRemoteHead(ref.getName())) {
return;
}
- UIGit git = GitGuiPlugin.getInstance().getGit();
String oldName = git.getShortenedName(ref.getName());
+ TreeItem selectedItem = wRefTree.getSelection()[0];
// The control that will be the editor must be a child of the Tree
Text text = new Text(wRefTree, SWT.BORDER);
@@ -1358,7 +1476,7 @@ public class GitPerspective implements IHopPerspective {
text.selectAll();
text.setFocus();
PropsUi.setLook(text);
- wRefTreeEditor.setEditor(text, wRefTree.getSelection()[0]);
+ wRefTreeEditor.setEditor(text, selectedItem);
}
}
@@ -1371,6 +1489,9 @@ public class GitPerspective implements IHopPerspective {
@GuiKeyboardShortcut(key = SWT.DEL)
@GuiOsxKeyboardShortcut(key = SWT.DEL)
public void deleteReference() {
+ if (!isInitialized()) {
+ return;
+ }
Ref ref = this.getSelectedReference();
if (ref != null) {
if (ref.getName().startsWith(Constants.R_HEADS)) {
@@ -1386,6 +1507,9 @@ public class GitPerspective implements IHopPerspective {
protected void deleteBranch(Ref ref) {
if (ref != null) {
UIGit git = GitGuiPlugin.getInstance().getGit();
+ if (git == null) {
+ return;
+ }
String name = git.getShortenedName(ref.getName());
// Prevent deletion of the current branch
@@ -1418,6 +1542,9 @@ public class GitPerspective implements IHopPerspective {
return;
}
UIGit git = GitGuiPlugin.getInstance().getGit();
+ if (git == null) {
+ return;
+ }
String name = git.getShortenedName(ref.getName());
// The default branch of the remote is protected against an accidental
delete
@@ -1462,6 +1589,9 @@ public class GitPerspective implements IHopPerspective {
*/
private void renameRemoteBranch(Ref ref, String oldName, String newName) {
UIGit git = GitGuiPlugin.getInstance().getGit();
+ if (git == null) {
+ return;
+ }
// The tree shows remote branches with their remote in front of them.
Accept a new name with
// or without it, the branch is renamed on the same remote either way.
@@ -1522,6 +1652,9 @@ public class GitPerspective implements IHopPerspective {
protected void deleteTag(Ref ref) {
if (ref != null) {
UIGit git = GitGuiPlugin.getInstance().getGit();
+ if (git == null) {
+ return;
+ }
String name = git.getShortenedName(ref.getName());
MessageBox dialog = new MessageBox(getShell(), SWT.ICON_QUESTION |
SWT.YES | SWT.NO);
@@ -1588,15 +1721,20 @@ public class GitPerspective implements IHopPerspective {
toolTip = "i18n::GitPerspective.Toolbar.ShowHiddenAllRef.Tooltip",
image = "ui/images/hide.svg")
public void showAllRef() {
+ if (!isInitialized()) {
+ return;
+ }
showAllRef = !showAllRef;
// Update toolbar item icon
- ToolItem toolItem =
this.historyToolBarWidgets.findToolItem(TOOLBAR_ITEM_SHOW_HIDDEN);
- if (toolItem != null) {
- if (showAllRef) {
- toolItem.setImage(GuiResource.getInstance().getImageShow());
- } else {
- toolItem.setImage(GuiResource.getInstance().getImageHide());
+ if (this.historyToolBarWidgets != null) {
+ ToolItem toolItem =
this.historyToolBarWidgets.findToolItem(TOOLBAR_ITEM_SHOW_HIDDEN);
+ if (toolItem != null && !toolItem.isDisposed()) {
+ if (showAllRef) {
+ toolItem.setImage(GuiResource.getInstance().getImageShow());
+ } else {
+ toolItem.setImage(GuiResource.getInstance().getImageHide());
+ }
}
}
@@ -1620,6 +1758,9 @@ public class GitPerspective implements IHopPerspective {
@GuiKeyboardShortcut(control = true, key = 'D')
@GuiOsxKeyboardShortcut(control = true, key = 'D')
public void showTextDiff() {
+ if (!isInitialized()) {
+ return;
+ }
RevCommit commit = getSelectedCommit();
String fileName = getSelectedFile();
@@ -1629,6 +1770,9 @@ public class GitPerspective implements IHopPerspective {
try {
UIGit git = GitGuiPlugin.getInstance().getGit();
+ if (git == null) {
+ return;
+ }
String commitIdNew = commit.getId().name();
String commitIdOld = git.getParentCommitId(commitIdNew);
@@ -1641,8 +1785,7 @@ public class GitPerspective implements IHopPerspective {
GitGuiPlugin.getInstance().showTextFileDiff(fileName, commitIdNew,
commitIdOld);
} catch (Exception e) {
- new ErrorDialog(
- hopGui.getShell(), "Error", "Error while doing text diff on file : "
+ fileName, e);
+ new ErrorDialog(getShell(), "Error", "Error while doing text diff on
file : " + fileName, e);
}
}
@@ -1660,6 +1803,9 @@ public class GitPerspective implements IHopPerspective {
@GuiKeyboardShortcut(control = true, shift = true, key = 'D')
@GuiOsxKeyboardShortcut(control = true, shift = true, key = 'D')
public void showGraphDiff() {
+ if (!isInitialized()) {
+ return;
+ }
RevCommit commit = getSelectedCommit();
String fileName = getSelectedFile();
@@ -1669,6 +1815,9 @@ public class GitPerspective implements IHopPerspective {
try {
UIGit git = GitGuiPlugin.getInstance().getGit();
+ if (git == null) {
+ return;
+ }
String commitIdNew = commit.getId().name();
String commitIdOld = git.getParentCommitId(commitIdNew);
@@ -1680,17 +1829,21 @@ public class GitPerspective implements IHopPerspective {
}
ExplorerPerspective perspective = HopGui.getExplorerPerspective();
- if (perspective.getPipelineFileType().isHandledBy(fileName, false)) {
+ if (perspective != null
+ && perspective.getPipelineFileType() != null
+ && perspective.getPipelineFileType().isHandledBy(fileName, false)) {
// A pipeline
GitGuiPlugin.getInstance().showPipelineFileDiff(fileName, commitIdNew,
commitIdOld);
- } else if (perspective.getWorkflowFileType().isHandledBy(fileName,
false)) {
+ } else if (perspective != null
+ && perspective.getWorkflowFileType() != null
+ && perspective.getWorkflowFileType().isHandledBy(fileName, false)) {
// A workflow
GitGuiPlugin.getInstance().showWorkflowFileDiff(fileName, commitIdNew,
commitIdOld);
}
} catch (Exception e) {
new ErrorDialog(
- hopGui.getShell(), "Error", "Error while doing visual diff on file :
" + fileName, e);
+ getShell(), "Error", "Error while doing visual diff on file : " +
fileName, e);
}
}
@@ -1718,6 +1871,13 @@ public class GitPerspective implements IHopPerspective {
}
public void updateGui() {
+ if (!isInitialized()) {
+ return;
+ }
+ if (wHistoryTable.getDisplay() !=
org.eclipse.swt.widgets.Display.getCurrent()) {
+ wHistoryTable.getDisplay().asyncExec(this::updateGui);
+ return;
+ }
UIGit git = GitGuiPlugin.getInstance().getGit();
boolean isGitEnabled = git != null;
@@ -1734,27 +1894,41 @@ public class GitPerspective implements IHopPerspective {
}
}
- wRefTree.setEnabled(isGitEnabled);
- wHistoryToolBar.setEnabled(isGitEnabled);
- wHistoryTable.setEnabled(isGitEnabled);
- wFileToolBar.setEnabled(isGitEnabled);
- wFileTree.setEnabled(isGitEnabled);
+ if (wRefTree != null && !wRefTree.isDisposed()) {
+ wRefTree.setEnabled(isGitEnabled);
+ }
+ if (wHistoryToolBar != null && !wHistoryToolBar.isDisposed()) {
+ wHistoryToolBar.setEnabled(isGitEnabled);
+ }
+ if (wHistoryTable != null && !wHistoryTable.isDisposed()) {
+ wHistoryTable.setEnabled(isGitEnabled);
+ }
+ if (wFileToolBar != null && !wFileToolBar.isDisposed()) {
+ wFileToolBar.setEnabled(isGitEnabled);
+ }
+ if (wFileTree != null && !wFileTree.isDisposed()) {
+ wFileTree.setEnabled(isGitEnabled);
+ }
- historyToolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_CREATE_BRANCH,
isCommitSelected);
- historyToolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_CREATE_TAG,
isCommitSelected);
- historyToolBarWidgets.enableToolbarItem(
- TOOLBAR_ITEM_COMMIT_CHERRY_PICK, isCommitSelected &&
!isCommitInCurrentBranch);
+ if (historyToolBarWidgets != null) {
+ historyToolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_CREATE_BRANCH,
isCommitSelected);
+ historyToolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_CREATE_TAG,
isCommitSelected);
+ historyToolBarWidgets.enableToolbarItem(
+ TOOLBAR_ITEM_COMMIT_CHERRY_PICK, isCommitSelected &&
!isCommitInCurrentBranch);
+ }
String selectFile = getSelectedFile();
boolean isFileSelected = selectFile != null;
- fileToolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_FILE_SHOW_TEXT_DIFF,
isFileSelected);
- fileToolBarWidgets.enableToolbarItem(
- TOOLBAR_ITEM_FILE_SHOW_GRAPH_DIFF,
FileTypeUtils.isHopFileType(selectFile));
- // Reverting a file puts back the version of the commit's parent, which a
root commit does not
- // have and a merge commit has more than one of
- fileToolBarWidgets.enableToolbarItem(
- TOOLBAR_ITEM_FILE_REVERT, isFileSelected && hasSingleParent);
- fileToolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_FILE_CHERRY_PICK,
isFileSelected);
+ if (fileToolBarWidgets != null) {
+ fileToolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_FILE_SHOW_TEXT_DIFF,
isFileSelected);
+ fileToolBarWidgets.enableToolbarItem(
+ TOOLBAR_ITEM_FILE_SHOW_GRAPH_DIFF,
FileTypeUtils.isHopFileType(selectFile));
+ // Reverting a file puts back the version of the commit's parent, which
a root commit does not
+ // have and a merge commit has more than one of
+ fileToolBarWidgets.enableToolbarItem(
+ TOOLBAR_ITEM_FILE_REVERT, isFileSelected && hasSingleParent);
+ fileToolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_FILE_CHERRY_PICK,
isFileSelected);
+ }
}
protected void createHistoryTable(Composite parent) {
@@ -1919,11 +2093,14 @@ public class GitPerspective implements IHopPerspective {
* should be refreshed.
*/
public void refresh(boolean refreshAll) {
+ if (!isInitialized()) {
+ return;
+ }
+ if (wHistoryTable.getDisplay() !=
org.eclipse.swt.widgets.Display.getCurrent()) {
+ wHistoryTable.getDisplay().asyncExec(() -> refresh(refreshAll));
+ return;
+ }
try {
- if (wHistoryTable == null || wHistoryTable.isDisposed()) {
- return;
- }
-
UIGit uiGit = GitGuiPlugin.getInstance().getGit();
// Drop UI state bound to the previous repository before reading
selection / rebuilding.
@@ -1939,8 +2116,14 @@ public class GitPerspective implements IHopPerspective {
// Refresh the file explorer perspective (file tree, change colors...)
// Refresh the metadata perspective (if file metadata provider)
if (refreshAll) {
- ExplorerPerspective.getInstance().refresh();
- MetadataPerspective.getInstance().refresh();
+ ExplorerPerspective explorerPerspective =
ExplorerPerspective.getInstance();
+ if (explorerPerspective != null) {
+ explorerPerspective.refresh();
+ }
+ MetadataPerspective metadataPerspective =
MetadataPerspective.getInstance();
+ if (metadataPerspective != null) {
+ metadataPerspective.refresh();
+ }
}
refreshRef(uiGit.getGit());
@@ -1969,11 +2152,15 @@ public class GitPerspective implements IHopPerspective {
}
protected void refreshRef(Git git) {
+ if (!isInitialized() || wRefTree == null || wRefTree.isDisposed() || git
== null) {
+ return;
+ }
try {
wRefTree.setRedraw(false);
wRefTree.removeAll();
- String currentBranch = GitGuiPlugin.getInstance().getGit().getBranch();
+ UIGit uiGit = GitGuiPlugin.getInstance().getGit();
+ String currentBranch = uiGit != null ? uiGit.getBranch() : null;
// Local branches
TreeItem localItem = new TreeItem(wRefTree, SWT.NONE);
@@ -2018,7 +2205,9 @@ public class GitPerspective implements IHopPerspective {
TreeMemory.setExpandedFromMemory(wRefTree, GIT_PERSPECTIVE_REF_TREE);
- wRefTree.setRedraw(true);
+ if (!wRefTree.isDisposed()) {
+ wRefTree.setRedraw(true);
+ }
} catch (Exception e) {
LogChannel.UI.logError("Error refresh git commit history", e);
}
@@ -2056,104 +2245,132 @@ public class GitPerspective implements
IHopPerspective {
}
protected void refreshHistory(String startRef) {
- Git git = GitGuiPlugin.getInstance().getGit().getGit();
+ if (!isInitialized()) {
+ return;
+ }
+ UIGit uiGit = GitGuiPlugin.getInstance().getGit();
+ if (uiGit == null) {
+ return;
+ }
+ Git git = uiGit.getGit();
+ if (git == null) {
+ return;
+ }
DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("yyyy/MM/dd
HH:mm").withZone(ZoneId.systemDefault());
try {
Repository repository = git.getRepository();
- PlotWalk walk = new PlotWalk(repository);
+ try (PlotWalk walk = new PlotWalk(repository)) {
- ObjectId startCommitId = null;
- if (!Utils.isEmpty(startRef)) {
- startCommitId = repository.resolve(startRef);
- }
+ ObjectId startCommitId = null;
+ if (!Utils.isEmpty(startRef)) {
+ startCommitId = repository.resolve(startRef);
+ }
- List<RevCommit> marks = new ArrayList<>();
+ List<RevCommit> marks = new ArrayList<>();
- // Always show HEAD
- marks.add(walk.parseCommit(repository.resolve(Constants.HEAD)));
+ // Always show HEAD
+ ObjectId headId = repository.resolve(Constants.HEAD);
+ if (headId != null) {
+ marks.add(walk.parseCommit(headId));
+ }
- // Show add all branches and tags
- if (showAllRef) {
- for (Ref ref : git.branchList().call()) {
- RevCommit commit = walk.parseCommit(ref.getObjectId());
- if (!marks.contains(commit)) {
- marks.add(commit);
+ // Show add all branches and tags
+ if (showAllRef) {
+ for (Ref ref : git.branchList().call()) {
+ RevCommit commit = walk.parseCommit(ref.getObjectId());
+ if (!marks.contains(commit)) {
+ marks.add(commit);
+ }
}
+ } else if (startCommitId != null) {
+ marks.add(walk.parseCommit(startCommitId));
}
- } else if (startCommitId != null) {
- marks.add(walk.parseCommit(startCommitId));
- }
- walk.markStart(marks);
+ if (!marks.isEmpty()) {
+ walk.markStart(marks);
+ }
- SwtCommitList plotList = new SwtCommitList();
- plotList.source(walk);
- plotList.fillTo(Integer.MAX_VALUE);
+ SwtCommitList plotList = new SwtCommitList();
+ plotList.source(walk);
+ plotList.fillTo(Integer.MAX_VALUE);
- wHistoryTable.setRedraw(false);
- wHistoryTable.removeAll();
+ if (wHistoryTable != null && !wHistoryTable.isDisposed()) {
+ wHistoryTable.setRedraw(false);
+ wHistoryTable.removeAll();
- // Check if there are changes in the working directory
- Map<String, UIFile> filesToCommit =
GitGuiPlugin.getInstance().getChangedFiles();
- if (!filesToCommit.isEmpty()) {
- TableItem item = new TableItem(wHistoryTable, SWT.NONE);
- item.setText(
- 1,
- BaseMessages.getString(
- PKG, "GitPerspective.History.UncommittedChanges.Label",
filesToCommit.size()));
- item.setForeground(GuiResource.getInstance().getColorGray());
- }
+ // Check if there are changes in the working directory
+ Map<String, UIFile> filesToCommit =
GitGuiPlugin.getInstance().getChangedFiles();
+ if (filesToCommit != null && !filesToCommit.isEmpty()) {
+ TableItem item = new TableItem(wHistoryTable, SWT.NONE);
+ item.setText(
+ 1,
+ BaseMessages.getString(
+ PKG, "GitPerspective.History.UncommittedChanges.Label",
filesToCommit.size()));
+ item.setForeground(GuiResource.getInstance().getColorGray());
+ }
- String search = wSearchText.getText().toLowerCase().trim();
+ String search =
+ (wSearchText != null && !wSearchText.isDisposed())
+ ? wSearchText.getText().toLowerCase().trim()
+ : "";
+
+ TableItem selectedItem = null;
+ for (PlotCommit<SwtCommitList.Lane> commit : plotList) {
+ String message = commit.getShortMessage();
+ String author = commit.getAuthorIdent().getName();
+ String id =
commit.getId().abbreviate(Constants.OBJECT_ID_ABBREV_STRING_LENGTH).name();
+
+ // Apply filter if the search text is not empty
+ if (!search.isEmpty()
+ && !message.toLowerCase().contains(search)
+ && !author.toLowerCase().contains(search)
+ && !id.toLowerCase().contains(search)) {
+ continue;
+ }
- TableItem selectedItem = null;
- for (PlotCommit<SwtCommitList.Lane> commit : plotList) {
- String message = commit.getShortMessage();
- String author = commit.getAuthorIdent().getName();
- String id =
commit.getId().abbreviate(Constants.OBJECT_ID_ABBREV_STRING_LENGTH).name();
+ TableItem item = new TableItem(wHistoryTable, SWT.NONE);
+ item.setText(1, message);
+ item.setText(2, author);
+ item.setText(
+ 3,
+ formatter
+ .withZone(commit.getCommitterIdent().getZoneId())
+ .format(commit.getCommitterIdent().getWhenAsInstant()));
+ item.setText(4, id);
+ item.setData(commit);
+
+ if (startCommitId != null && commit.getId().equals(startCommitId))
{
+ selectedItem = item;
+ }
+ }
- // Apply filter if the search text is not empty
- if (!search.isEmpty()
- && !message.toLowerCase().contains(search)
- && !author.toLowerCase().contains(search)
- && !id.toLowerCase().contains(search)) {
- continue;
- }
+ if (selectedItem != null) {
+ wHistoryTable.setSelection(selectedItem);
+ }
- TableItem item = new TableItem(wHistoryTable, SWT.NONE);
- item.setText(1, message);
- item.setText(2, author);
- item.setText(
- 3,
- formatter
- .withZone(commit.getCommitterIdent().getZoneId())
- .format(commit.getCommitterIdent().getWhenAsInstant()));
- item.setText(4, id);
- item.setData(commit);
-
- if (commit.getId().equals(startCommitId)) {
- selectedItem = item;
+ wHistoryTable.setRedraw(true);
+ wHistoryTable.redraw();
}
- }
- if (selectedItem != null) {
- wHistoryTable.setSelection(selectedItem);
+ refreshFiles();
}
-
- wHistoryTable.setRedraw(true);
- wHistoryTable.redraw();
-
- refreshFiles();
} catch (Exception e) {
LogChannel.UI.logError("Error refresh git history", e);
}
}
protected Shell getShell() {
- return hopGui.getShell();
+ if (wSashForm != null && !wSashForm.isDisposed()) {
+ return wSashForm.getShell();
+ }
+ if (hopGui != null) {
+ return hopGui.getShell();
+ }
+ HopGui currentHop = HopGui.peekInstance();
+ return currentHop != null ? currentHop.getShell() : null;
}
@Override
diff --git
a/plugins/misc/git/src/main/java/org/apache/hop/git/config/GitConfigSingleton.java
b/plugins/misc/git/src/main/java/org/apache/hop/git/config/GitConfigSingleton.java
index 124852af3d..9336de776f 100644
---
a/plugins/misc/git/src/main/java/org/apache/hop/git/config/GitConfigSingleton.java
+++
b/plugins/misc/git/src/main/java/org/apache/hop/git/config/GitConfigSingleton.java
@@ -57,20 +57,19 @@ public class GitConfigSingleton {
HopConfig.getInstance().getConfigMap().put(GitConfig.HOP_CONFIG_GIT_CONFIG_KEY,
gitConfig);
}
- public static GitConfigSingleton getInstance() {
- return configSingleton;
- }
-
- public static GitConfig getConfig() {
+ public static synchronized GitConfigSingleton getInstance() {
if (configSingleton == null) {
configSingleton = new GitConfigSingleton();
}
- return configSingleton.gitConfig;
+ return configSingleton;
+ }
+
+ public static synchronized GitConfig getConfig() {
+ return getInstance().gitConfig;
}
- public static void saveConfig() throws HopException {
- HopConfig.getInstance()
- .saveOption(GitConfig.HOP_CONFIG_GIT_CONFIG_KEY,
configSingleton.gitConfig);
+ public static synchronized void saveConfig() throws HopException {
+ HopConfig.getInstance().saveOption(GitConfig.HOP_CONFIG_GIT_CONFIG_KEY,
getConfig());
HopConfig.getInstance().saveToFile();
}
}
diff --git
a/plugins/misc/git/src/main/java/org/apache/hop/git/info/GitInfoExplorerFileTypeHandler.java
b/plugins/misc/git/src/main/java/org/apache/hop/git/info/GitInfoExplorerFileTypeHandler.java
index 32d2014f16..7b3fbb5a58 100644
---
a/plugins/misc/git/src/main/java/org/apache/hop/git/info/GitInfoExplorerFileTypeHandler.java
+++
b/plugins/misc/git/src/main/java/org/apache/hop/git/info/GitInfoExplorerFileTypeHandler.java
@@ -372,6 +372,9 @@ public class GitInfoExplorerFileTypeHandler extends
BaseExplorerFileTypeHandler
if (wFiles.getSelectionIndices().length == 0) {
return;
}
+ if (wRevisions.table.getSelectionCount() == 0) {
+ return;
+ }
TableItem fileItem = wFiles.table.getSelection()[0];
String filename = fileItem.getText(1);
if (StringUtils.isEmpty(filename)) {
@@ -380,6 +383,9 @@ public class GitInfoExplorerFileTypeHandler extends
BaseExplorerFileTypeHandler
GitGuiPlugin guiPlugin = GitGuiPlugin.getInstance();
UIGit git = guiPlugin.getGit();
+ if (git == null) {
+ return;
+ }
try {
@@ -415,11 +421,15 @@ public class GitInfoExplorerFileTypeHandler extends
BaseExplorerFileTypeHandler
}
ExplorerPerspective perspective = HopGui.getExplorerPerspective();
- if (perspective.getPipelineFileType().isHandledBy(filename, false)) {
+ if (perspective != null
+ && perspective.getPipelineFileType() != null
+ && perspective.getPipelineFileType().isHandledBy(filename, false)) {
// A pipeline
//
showPipelineFileDiff(filename, commitIdNew, commitIdOld);
- } else if (perspective.getWorkflowFileType().isHandledBy(filename,
false)) {
+ } else if (perspective != null
+ && perspective.getWorkflowFileType() != null
+ && perspective.getWorkflowFileType().isHandledBy(filename, false)) {
// A workflow
//
showWorkflowFileDiff(filename, commitIdNew, commitIdOld);
diff --git
a/plugins/misc/git/src/test/java/org/apache/hop/git/GitGuiPluginSessionIsolationTest.java
b/plugins/misc/git/src/test/java/org/apache/hop/git/GitGuiPluginSessionIsolationTest.java
index a59f66edc3..b91161068d 100644
---
a/plugins/misc/git/src/test/java/org/apache/hop/git/GitGuiPluginSessionIsolationTest.java
+++
b/plugins/misc/git/src/test/java/org/apache/hop/git/GitGuiPluginSessionIsolationTest.java
@@ -17,10 +17,13 @@
package org.apache.hop.git;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
+import org.apache.hop.git.config.GitConfigSingleton;
import org.junit.jupiter.api.Test;
class GitGuiPluginSessionIsolationTest {
@@ -52,4 +55,88 @@ class GitGuiPluginSessionIsolationTest {
}
}
}
+
+ @Test
+ void gitPerspectiveIsNotAProcessWideStaticSingletonField() {
+ for (Field field : GitPerspective.class.getDeclaredFields()) {
+ if ("instance".equals(field.getName())) {
+ assertFalse(
+ Modifier.isStatic(field.getModifiers()),
+ "GitPerspective must not keep a process-wide static instance
field");
+ }
+ }
+ }
+
+ @Test
+ void gitCommitPerspectiveIsNotAProcessWideStaticSingletonField() {
+ for (Field field : GitCommitPerspective.class.getDeclaredFields()) {
+ if ("instance".equals(field.getName())) {
+ assertFalse(
+ Modifier.isStatic(field.getModifiers()),
+ "GitCommitPerspective must not keep a process-wide static instance
field");
+ }
+ }
+ }
+
+ @Test
+ void gitCommitPerspectiveUninitializedIsSafe() {
+ GitCommitPerspective perspective = new GitCommitPerspective();
+ assertFalse(perspective.isInitialized());
+ assertDoesNotThrow(perspective::activate);
+ assertDoesNotThrow(perspective::perspectiveActivated);
+ assertDoesNotThrow(perspective::retrieveState);
+ assertDoesNotThrow(perspective::saveState);
+ assertDoesNotThrow(perspective::refresh);
+ assertDoesNotThrow(perspective::updateGui);
+ assertDoesNotThrow(perspective::selectAllChanged);
+ assertDoesNotThrow(perspective::addFilesToGit);
+ assertDoesNotThrow(perspective::unstageFiles);
+ assertDoesNotThrow(perspective::addFilesToGitIgnore);
+ assertDoesNotThrow(perspective::deleteFiles);
+ assertDoesNotThrow(perspective::restoreFiles);
+ assertDoesNotThrow(perspective::showTextDiff);
+ assertDoesNotThrow(perspective::showGraphDiff);
+ assertDoesNotThrow(() -> perspective.commitFiles(false));
+ }
+
+ @Test
+ void gitPerspectiveUninitializedIsSafe() {
+ GitPerspective perspective = new GitPerspective();
+ assertFalse(perspective.isInitialized());
+ assertDoesNotThrow(perspective::activate);
+ assertDoesNotThrow(perspective::perspectiveActivated);
+ assertDoesNotThrow(() -> perspective.refresh());
+ assertDoesNotThrow(() -> perspective.refresh(true));
+ assertDoesNotThrow(perspective::updateGui);
+ assertDoesNotThrow(perspective::clearGitUiState);
+ assertDoesNotThrow(perspective::clearSearchFilters);
+ assertDoesNotThrow(perspective::copyRevisionId);
+ assertDoesNotThrow(perspective::copyPath);
+ assertDoesNotThrow(perspective::resetToCommit);
+ assertDoesNotThrow(perspective::revertCommit);
+ assertDoesNotThrow(perspective::revertFile);
+ assertDoesNotThrow(perspective::cherryPickCommit);
+ assertDoesNotThrow(perspective::cherryPickFile);
+ assertDoesNotThrow(perspective::checkoutReference);
+ assertDoesNotThrow(perspective::checkoutCommit);
+ assertDoesNotThrow(perspective::addTag);
+ assertDoesNotThrow(perspective::addBranchFromCommit);
+ assertDoesNotThrow(perspective::addBranchFromRef);
+ assertDoesNotThrow(perspective::mergeBranch);
+ assertDoesNotThrow(perspective::fetch);
+ assertDoesNotThrow(perspective::pull);
+ assertDoesNotThrow(perspective::push);
+ assertDoesNotThrow(perspective::pushReference);
+ assertDoesNotThrow(perspective::renameReference);
+ assertDoesNotThrow(perspective::deleteReference);
+ assertDoesNotThrow(perspective::showAllRef);
+ assertDoesNotThrow(perspective::showTextDiff);
+ assertDoesNotThrow(perspective::showGraphDiff);
+ }
+
+ @Test
+ void gitConfigSingletonThreadSafe() {
+ assertNotNull(GitConfigSingleton.getInstance());
+ assertNotNull(GitConfigSingleton.getConfig());
+ }
}