View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.resolver.internal.ant.tasks;
20  
21  import java.util.ArrayList;
22  import java.util.Arrays;
23  import java.util.Collection;
24  import java.util.HashSet;
25  import java.util.List;
26  import java.util.TreeSet;
27  import java.util.regex.Matcher;
28  import java.util.regex.Pattern;
29  
30  import org.apache.tools.ant.BuildException;
31  import org.eclipse.aether.artifact.Artifact;
32  
33  /**
34   * Represents the layout type for a Maven repository.
35   * <p>
36   * This is an Ant {@code DataType} used to configure the repository layout in tasks such as
37   * {@code <repository>}. It determines how artifact coordinates are translated into paths
38   * when accessing the repository.
39   * </p>
40   *
41   * <h2>Supported Layouts:</h2>
42   * <ul>
43   *   <li><strong>default</strong> – the standard Maven 2+ repository layout (recommended)</li>
44   * </ul>
45   * Since default is currently the default layout (and no other types are currently supported), it is safe to omit this.
46   * <h2>Usage Example:</h2>
47   * <pre>{@code
48   * <repositories>
49   *   <repository id="central" url="https://repo.maven.apache.org/maven2">
50   *      <layout>default</layout>
51   *   </repository>
52   * </repositories>
53   * }</pre>
54   *
55   * <p>
56   * This type is typically used as a nested element inside {@code <repository>} definitions.
57   * </p>
58   *
59   * @see org.apache.maven.resolver.internal.ant.types.RemoteRepository
60   */
61  class Layout {
62  
63      public static final String GID = "{groupId}";
64  
65      public static final String GID_DIRS = "{groupIdDirs}";
66  
67      public static final String AID = "{artifactId}";
68  
69      public static final String VER = "{version}";
70  
71      public static final String BVER = "{baseVersion}";
72  
73      public static final String EXT = "{extension}";
74  
75      public static final String CLS = "{classifier}";
76  
77      private final String[] tokens;
78  
79      Layout(String layout) throws BuildException {
80          Collection<String> valid = new HashSet<>(Arrays.asList(GID, GID_DIRS, AID, VER, BVER, EXT, CLS));
81          List<String> tokens = new ArrayList<>();
82          Matcher m = Pattern.compile("(\\{[^}]*\\})|([^{]+)").matcher(layout);
83          while (m.find()) {
84              if (m.group(1) != null && !valid.contains(m.group(1))) {
85                  throw new BuildException("Invalid variable '" + m.group() + "' in layout, supported variables are "
86                          + new TreeSet<String>(valid));
87              }
88              tokens.add(m.group());
89          }
90          this.tokens = tokens.toArray(new String[0]);
91      }
92  
93      public String getPath(Artifact artifact) {
94          StringBuilder buffer = new StringBuilder(128);
95  
96          for (int i = 0; i < tokens.length; i++) {
97              String token = tokens[i];
98              if (GID.equals(token)) {
99                  buffer.append(artifact.getGroupId());
100             } else if (GID_DIRS.equals(token)) {
101                 buffer.append(artifact.getGroupId().replace('.', '/'));
102             } else if (AID.equals(token)) {
103                 buffer.append(artifact.getArtifactId());
104             } else if (VER.equals(token)) {
105                 buffer.append(artifact.getVersion());
106             } else if (BVER.equals(token)) {
107                 buffer.append(artifact.getBaseVersion());
108             } else if (CLS.equals(token)) {
109                 if (artifact.getClassifier().length() <= 0) {
110                     if (i > 0) {
111                         String lt = tokens[i - 1];
112                         if (!lt.isEmpty() && "-_".indexOf(lt.charAt(lt.length() - 1)) >= 0) {
113                             buffer.setLength(buffer.length() - 1);
114                         }
115                     }
116                 } else {
117                     buffer.append(artifact.getClassifier());
118                 }
119             } else if (EXT.equals(token)) {
120                 buffer.append(artifact.getExtension());
121             } else {
122                 buffer.append(token);
123             }
124         }
125 
126         return buffer.toString();
127     }
128 }