This is an automated email from the ASF dual-hosted git repository.

hansva 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 dc1696b126 issue #7666: install marketplace lib/core jars (sticky on 
uninstall) (#7668)
dc1696b126 is described below

commit dc1696b126a5a507899fddc3d142bdba48be34af
Author: Matt Casters <[email protected]>
AuthorDate: Wed Jul 29 08:42:57 2026 +0200

    issue #7666: install marketplace lib/core jars (sticky on uninstall) (#7668)
    
    Plugin zips place Maven provided-scope libraries under lib/core for the
    shared system classpath. Marketplace was skipping those paths, so optional
    plugins (e.g. Azure Key Vault SecretClient) failed after install.
    
    Install now copies lib/core entries (with a log when replacing different
    content). Uninstall still leaves lib/core jars in place so shared stacks
    remain available to other plugins.
---
 .../hop/marketplace/install/PluginInstaller.java   | 23 +++++++++++-------
 .../hop/marketplace/install/PluginUninstaller.java | 11 +++++----
 .../marketplace/install/PluginInstallerTest.java   | 28 +++++++++++++---------
 3 files changed, 39 insertions(+), 23 deletions(-)

diff --git 
a/plugins/misc/marketplace/src/main/java/org/apache/hop/marketplace/install/PluginInstaller.java
 
b/plugins/misc/marketplace/src/main/java/org/apache/hop/marketplace/install/PluginInstaller.java
index e8410b1c7d..9bbb7e05c7 100644
--- 
a/plugins/misc/marketplace/src/main/java/org/apache/hop/marketplace/install/PluginInstaller.java
+++ 
b/plugins/misc/marketplace/src/main/java/org/apache/hop/marketplace/install/PluginInstaller.java
@@ -224,17 +224,23 @@ public class PluginInstaller {
     Path stageRoot = hopHome.resolve(STAGING_DIR).resolve(artifactId);
     try {
       for (String relative : relativePaths) {
-        // Never overwrite core beam libraries from a marketplace zip
-        if (isProtectedPath(relative)) {
-          log.logBasic("Skipping protected path from marketplace package: " + 
relative);
-          continue;
-        }
         Path from = stageRoot.resolve(relative);
         Path to = hopHome.resolve(relative);
         if (Files.isDirectory(from)) {
           Files.createDirectories(to);
         } else if (Files.isRegularFile(from)) {
           Files.createDirectories(to.getParent());
+          // Shared classpath jars (Maven provided → lib/core). Install them 
so marketplace
+          // packages match the full client assembly; warn when replacing 
different content.
+          if (isSharedCorePath(relative)
+              && Files.isRegularFile(to)
+              && Files.mismatch(from, to) != -1L) {
+            log.logBasic(
+                "Replacing shared lib/core jar with different content from "
+                    + artifactId
+                    + ": "
+                    + relative);
+          }
           Files.copy(from, to, StandardCopyOption.REPLACE_EXISTING);
         }
       }
@@ -244,10 +250,11 @@ public class PluginInstaller {
   }
 
   /**
-   * Core install paths marketplace zips must not overwrite. Beam SDKs live 
under the Beam plugin
-   * ({@code plugins/engines/beam/lib-beam}) and are installed/uninstalled 
with that plugin.
+   * Paths under {@code lib/core/} hold shared system-classpath jars (plugin 
assembly {@code
+   * provided} scope). Marketplace <strong>installs</strong> these jars so 
optional plugins work the
+   * same as the full client; uninstall never removes them (sticky shared 
libraries).
    */
-  static boolean isProtectedPath(String relative) {
+  static boolean isSharedCorePath(String relative) {
     String normalized = relative.replace('\\', '/');
     return normalized.equals("lib/core") || normalized.startsWith("lib/core/");
   }
diff --git 
a/plugins/misc/marketplace/src/main/java/org/apache/hop/marketplace/install/PluginUninstaller.java
 
b/plugins/misc/marketplace/src/main/java/org/apache/hop/marketplace/install/PluginUninstaller.java
index e4b1ddb8c4..e7d2fe31ef 100644
--- 
a/plugins/misc/marketplace/src/main/java/org/apache/hop/marketplace/install/PluginUninstaller.java
+++ 
b/plugins/misc/marketplace/src/main/java/org/apache/hop/marketplace/install/PluginUninstaller.java
@@ -26,7 +26,10 @@ import java.util.Set;
 import org.apache.hop.core.exception.HopException;
 import org.apache.hop.core.logging.ILogChannel;
 
-/** Removes a marketplace-installed plugin using its receipt. Never touches 
core-protected paths. */
+/**
+ * Removes a marketplace-installed plugin using its receipt. Shared {@code 
lib/core} jars stay in
+ * place so other plugins (and the system classpath) keep working.
+ */
 public class PluginUninstaller {
 
   private final ILogChannel log;
@@ -46,11 +49,11 @@ public class PluginUninstaller {
               + "'. Only plugins installed via the marketplace can be 
uninstalled this way.");
     }
 
-    // Delete files deepest-first; skip protected paths (e.g. lib/core)
+    // Delete files deepest-first; leave shared lib/core jars (sticky, may be 
used by others)
     Set<Path> dirs = new HashSet<>();
     for (String relative : receipt.getPaths()) {
-      if (PluginInstaller.isProtectedPath(relative)) {
-        log.logBasic("Leaving protected path in place: " + relative);
+      if (PluginInstaller.isSharedCorePath(relative)) {
+        log.logBasic("Leaving shared lib/core path in place: " + relative);
         continue;
       }
       Path path = hopHome.resolve(relative);
diff --git 
a/plugins/misc/marketplace/src/test/java/org/apache/hop/marketplace/install/PluginInstallerTest.java
 
b/plugins/misc/marketplace/src/test/java/org/apache/hop/marketplace/install/PluginInstallerTest.java
index 112bb7cae7..0e85de4156 100644
--- 
a/plugins/misc/marketplace/src/test/java/org/apache/hop/marketplace/install/PluginInstallerTest.java
+++ 
b/plugins/misc/marketplace/src/test/java/org/apache/hop/marketplace/install/PluginInstallerTest.java
@@ -49,12 +49,13 @@ class PluginInstallerTest {
   }
 
   @Test
-  void protectedPaths() {
-    assertFalse(PluginInstaller.isProtectedPath("lib/beam/foo.jar"));
-    
assertFalse(PluginInstaller.isProtectedPath("plugins/engines/beam/lib-beam/x.jar"));
-    assertTrue(PluginInstaller.isProtectedPath("lib/core/bar.jar"));
-    
assertFalse(PluginInstaller.isProtectedPath("plugins/engines/beam/hop.jar"));
-    
assertFalse(PluginInstaller.isProtectedPath("plugins/tech/parquet/lib/x.jar"));
+  void sharedCorePaths() {
+    assertFalse(PluginInstaller.isSharedCorePath("lib/beam/foo.jar"));
+    
assertFalse(PluginInstaller.isSharedCorePath("plugins/engines/beam/lib-beam/x.jar"));
+    assertTrue(PluginInstaller.isSharedCorePath("lib/core/bar.jar"));
+    assertTrue(PluginInstaller.isSharedCorePath("lib/core"));
+    
assertFalse(PluginInstaller.isSharedCorePath("plugins/engines/beam/hop.jar"));
+    
assertFalse(PluginInstaller.isSharedCorePath("plugins/tech/parquet/lib/x.jar"));
   }
 
   @Test
@@ -93,14 +94,18 @@ class PluginInstallerTest {
       assertTrue(
           Files.isRegularFile(
               
hopHome.resolve(PluginInstaller.RECEIPTS_DIR).resolve("hop-test-plugin.json")));
-      // protected path from zip must not be written
-      assertFalse(Files.exists(hopHome.resolve("lib/core/evil.jar")));
+      // provided-scope jars land under lib/core and must be installed (system 
classpath)
+      Path sharedJar = hopHome.resolve("lib/core/shared.jar");
+      assertTrue(Files.isRegularFile(sharedJar));
+      assertEquals("shared-lib", Files.readString(sharedJar));
 
       new PluginUninstaller(log, hopHome).uninstall("hop-test-plugin");
       assertFalse(Files.exists(pluginJar));
       assertFalse(
           Files.exists(
               
hopHome.resolve(PluginInstaller.RECEIPTS_DIR).resolve("hop-test-plugin.json")));
+      // lib/core is sticky: left in place so other plugins can share it
+      assertTrue(Files.isRegularFile(sharedJar));
     } finally {
       server.stop(0);
     }
@@ -208,9 +213,10 @@ class PluginInstallerTest {
       zos.putNextEntry(new ZipEntry("plugins/tech/test/version.xml"));
       zos.write("<version>1.0.0</version>".getBytes(StandardCharsets.UTF_8));
       zos.closeEntry();
-      // Should be ignored on activate
-      zos.putNextEntry(new ZipEntry("lib/core/evil.jar"));
-      zos.write("nope".getBytes(StandardCharsets.UTF_8));
+      // Shared system-classpath jar (assembly provided → lib/core); must 
install, sticky on
+      // uninstall
+      zos.putNextEntry(new ZipEntry("lib/core/shared.jar"));
+      zos.write("shared-lib".getBytes(StandardCharsets.UTF_8));
       zos.closeEntry();
     }
     return bos.toByteArray();

Reply via email to