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

cstamas pushed a commit to branch maven-resolver-1.9.x
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git


The following commit(s) were added to refs/heads/maven-resolver-1.9.x by this 
push:
     new 302f64de6 [1.9.x] Better metadata locking support (#1669)
302f64de6 is described below

commit 302f64de6219aa31b713681fbc27f529ec98b0d7
Author: Tamas Cservenak <[email protected]>
AuthorDate: Mon Nov 17 20:36:56 2025 +0100

    [1.9.x] Better metadata locking support (#1669)
    
    The locking in 1.9.x was too coarse, assumed all is `maven-metadata.xml`. 
This is backport from 2.x to support various `metadata.type` values for locking 
(local repo is already ported back).
---
 .../impl/synccontext/named/GAVNameMapper.java      | 11 ++++
 .../java/org/eclipse/aether/util/PathUtils.java    | 75 ++++++++++++++++++++++
 2 files changed, 86 insertions(+)

diff --git 
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/GAVNameMapper.java
 
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/GAVNameMapper.java
index 556a9f686..b08f7867c 100644
--- 
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/GAVNameMapper.java
+++ 
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/GAVNameMapper.java
@@ -24,6 +24,7 @@ import java.util.TreeSet;
 import org.eclipse.aether.RepositorySystemSession;
 import org.eclipse.aether.artifact.Artifact;
 import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.util.PathUtils;
 
 import static java.util.Objects.requireNonNull;
 
@@ -97,6 +98,8 @@ public class GAVNameMapper implements NameMapper {
                 + artifactSuffix;
     }
 
+    private static final String MAVEN_METADATA = "maven-metadata.xml";
+
     private String getMetadataName(Metadata metadata) {
         String name = metadataPrefix;
         if (!metadata.getGroupId().isEmpty()) {
@@ -107,6 +110,14 @@ public class GAVNameMapper implements NameMapper {
                     name += fieldSeparator + metadata.getVersion();
                 }
             }
+            if (!MAVEN_METADATA.equals(metadata.getType())) {
+                name += fieldSeparator
+                        + (fileSystemFriendly ? 
PathUtils.stringToPathSegment(metadata.getType()) : metadata.getType());
+            }
+        } else {
+            if (!MAVEN_METADATA.equals(metadata.getType())) {
+                name += (fileSystemFriendly ? 
PathUtils.stringToPathSegment(metadata.getType()) : metadata.getType());
+            }
         }
         return name + metadataSuffix;
     }
diff --git 
a/maven-resolver-util/src/main/java/org/eclipse/aether/util/PathUtils.java 
b/maven-resolver-util/src/main/java/org/eclipse/aether/util/PathUtils.java
new file mode 100644
index 000000000..e4948264a
--- /dev/null
+++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/PathUtils.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.eclipse.aether.util;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * A reusable utility class for file paths.
+ *
+ * @since 1.9.25 (backported from 2.0.13)
+ */
+public final class PathUtils {
+    private PathUtils() {
+        // hide constructor
+    }
+
+    private static final Map<String, String> ILLEGAL_PATH_SEGMENT_REPLACEMENTS;
+
+    static {
+        HashMap<String, String> illegalPathSegmentReplacements = new 
HashMap<>();
+        illegalPathSegmentReplacements.put("\\", "-BACKSLASH-");
+        illegalPathSegmentReplacements.put("/", "-SLASH-");
+        illegalPathSegmentReplacements.put(":", "-COLON-");
+        illegalPathSegmentReplacements.put("\"", "-QUOTE-");
+        illegalPathSegmentReplacements.put("<", "-LT-");
+        illegalPathSegmentReplacements.put(">", "-GT-");
+        illegalPathSegmentReplacements.put("|", "-PIPE-");
+        illegalPathSegmentReplacements.put("?", "-QMARK-");
+        illegalPathSegmentReplacements.put("*", "-ASTERISK-");
+        ILLEGAL_PATH_SEGMENT_REPLACEMENTS = 
Collections.unmodifiableMap(illegalPathSegmentReplacements);
+    }
+
+    /**
+     * Method that makes sure that passed in string is valid "path segment" 
string. It achieves it by potentially
+     * changing it, replacing illegal characters in it with legal ones.
+     * <p>
+     * Note: this method considers empty string as "valid path segment", it is 
caller duty to ensure empty string
+     * is not used as path segment alone.
+     * <p>
+     * This method is simplistic on purpose, and if frequently used, best if 
results are cached (per session)
+     */
+    public static String stringToPathSegment(String string) {
+        requireNonNull(string);
+        StringBuilder result = new StringBuilder(string);
+        for (Map.Entry<String, String> entry : 
ILLEGAL_PATH_SEGMENT_REPLACEMENTS.entrySet()) {
+            String illegal = entry.getKey();
+            int pos = result.indexOf(illegal);
+            while (pos >= 0) {
+                result.replace(pos, pos + illegal.length(), entry.getValue());
+                pos = result.indexOf(illegal);
+            }
+        }
+        return result.toString();
+    }
+}

Reply via email to