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.tools.plugin.extractor;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.util.HashSet;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Set;
27  import java.util.TreeMap;
28  
29  import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException;
30  import org.apache.maven.plugin.descriptor.MojoDescriptor;
31  import org.apache.maven.project.MavenProject;
32  import org.apache.maven.tools.plugin.PluginToolsRequest;
33  import org.codehaus.plexus.logging.AbstractLogEnabled;
34  import org.codehaus.plexus.util.DirectoryScanner;
35  import org.codehaus.plexus.util.FileUtils;
36  
37  /**
38   * @deprecated Scripting support for Mojos is deprecated and is planned to be removed in Maven 4.0
39   * @author jdcasey
40   */
41  @Deprecated
42  public abstract class AbstractScriptedMojoDescriptorExtractor extends AbstractLogEnabled
43          implements MojoDescriptorExtractor {
44      @Override
45      public boolean isDeprecated() {
46          return true;
47      }
48  
49      /** {@inheritDoc} */
50      @Override
51      public List<MojoDescriptor> execute(PluginToolsRequest request)
52              throws ExtractionException, InvalidPluginDescriptorException {
53          getLogger().debug("Running: " + getClass().getName());
54          String metadataExtension = getMetadataFileExtension(request);
55          String scriptExtension = getScriptFileExtension(request);
56  
57          MavenProject project = request.getProject();
58  
59          @SuppressWarnings("unchecked")
60          Map<String, Set<File>> scriptFilesKeyedByBasedir =
61                  gatherFilesByBasedir(project.getBasedir(), project.getScriptSourceRoots(), scriptExtension, request);
62  
63          List<MojoDescriptor> mojoDescriptors;
64          if (!(metadataExtension == null || metadataExtension.isEmpty())) {
65              @SuppressWarnings("unchecked")
66              Map<String, Set<File>> metadataFilesKeyedByBasedir = gatherFilesByBasedir(
67                      project.getBasedir(), project.getScriptSourceRoots(), metadataExtension, request);
68  
69              mojoDescriptors = extractMojoDescriptorsFromMetadata(metadataFilesKeyedByBasedir, request);
70          } else {
71              mojoDescriptors = extractMojoDescriptors(scriptFilesKeyedByBasedir, request);
72          }
73  
74          copyScriptsToOutputDirectory(
75                  scriptFilesKeyedByBasedir, project.getBuild().getOutputDirectory(), request);
76  
77          if (!mojoDescriptors.isEmpty()) {
78              getLogger().warn("Scripting support for mojos is deprecated and is planned to be removed in Maven 4.");
79              getLogger().warn("Found " + mojoDescriptors.size() + " scripted mojos.");
80          }
81  
82          return mojoDescriptors;
83      }
84  
85      /**
86       * @param scriptFilesKeyedByBasedir not null
87       * @param outputDirectory not null
88       * @param request the request
89       * @throws ExtractionException if any
90       */
91      protected void copyScriptsToOutputDirectory(
92              Map<String, Set<File>> scriptFilesKeyedByBasedir, String outputDirectory, PluginToolsRequest request)
93              throws ExtractionException {
94          File outputDir = new File(outputDirectory);
95  
96          if (!outputDir.exists()) {
97              outputDir.mkdirs();
98          }
99  
100         for (Map.Entry<String, Set<File>> entry : scriptFilesKeyedByBasedir.entrySet()) {
101             File sourceDir = new File(entry.getKey());
102 
103             Set<File> scripts = entry.getValue();
104 
105             for (File scriptFile : scripts) {
106                 String relativePath =
107                         scriptFile.getPath().substring(sourceDir.getPath().length());
108 
109                 if (relativePath.charAt(0) == File.separatorChar) {
110                     relativePath = relativePath.substring(1);
111                 }
112 
113                 File outputFile = new File(outputDir, relativePath).getAbsoluteFile();
114 
115                 if (!outputFile.getParentFile().exists()) {
116                     outputFile.getParentFile().mkdirs();
117                 }
118 
119                 try {
120                     FileUtils.copyFile(scriptFile, outputFile);
121                 } catch (IOException e) {
122                     throw new ExtractionException(
123                             "Cannot copy script file: " + scriptFile + " to output: " + outputFile, e);
124                 }
125             }
126         }
127     }
128 
129     /**
130      * @param basedir not null
131      * @param directories not null
132      * @param scriptFileExtension not null
133      * @param request the request
134      * @return map with subdirs paths as key
135      */
136     protected Map<String, Set<File>> gatherFilesByBasedir(
137             File basedir, List<String> directories, String scriptFileExtension, PluginToolsRequest request) {
138         Map<String, Set<File>> sourcesByBasedir = new TreeMap<>();
139 
140         for (String resourceDir : directories) {
141             Set<File> sources = new HashSet<>();
142 
143             getLogger()
144                     .debug("Scanning script dir: " + resourceDir + " with extractor: "
145                             + getClass().getName());
146             File dir = new File(resourceDir);
147             if (!dir.isAbsolute()) {
148                 dir = new File(basedir, resourceDir).getAbsoluteFile();
149             }
150 
151             resourceDir = dir.getPath();
152 
153             if (dir.exists()) {
154                 DirectoryScanner scanner = new DirectoryScanner();
155 
156                 scanner.setBasedir(dir);
157                 scanner.addDefaultExcludes();
158                 scanner.setIncludes(new String[] {"**/*" + scriptFileExtension});
159                 scanner.scan();
160 
161                 String[] relativePaths = scanner.getIncludedFiles();
162 
163                 for (String relativePath : relativePaths) {
164                     File scriptFile = new File(dir, relativePath).getAbsoluteFile();
165 
166                     if (scriptFile.isFile() && relativePath.endsWith(scriptFileExtension)) {
167                         sources.add(scriptFile);
168                     }
169                 }
170 
171                 sourcesByBasedir.put(resourceDir, sources);
172             }
173         }
174 
175         return sourcesByBasedir;
176     }
177 
178     /**
179      * Should be implemented in the sub classes.
180      *
181      * @param metadataFilesByBasedir could be null
182      * @param request The plugin request, never <code>null</code>.
183      * @return always null
184      * @throws ExtractionException if any
185      * @throws InvalidPluginDescriptorException if any
186      */
187     protected List<MojoDescriptor> extractMojoDescriptorsFromMetadata(
188             Map<String, Set<File>> metadataFilesByBasedir, PluginToolsRequest request)
189             throws ExtractionException, InvalidPluginDescriptorException {
190         return null;
191     }
192 
193     /**
194      * Should be implemented in the sub classes.
195      * @param request the request
196      * @return always null
197      */
198     protected String getMetadataFileExtension(PluginToolsRequest request) {
199         return null;
200     }
201 
202     /**
203      * Should be implemented in the sub classes.
204      *
205      * @param scriptFilesKeyedByBasedir could be null
206      * @param request The plugin request, never <code>null</code>.
207      * @return always null
208      * @throws ExtractionException if any
209      * @throws InvalidPluginDescriptorException if any
210      */
211     protected List<MojoDescriptor> extractMojoDescriptors(
212             Map<String, Set<File>> scriptFilesKeyedByBasedir, PluginToolsRequest request)
213             throws ExtractionException, InvalidPluginDescriptorException {
214         return null;
215     }
216 
217     /**
218      * @param request the request
219      * @return the file extension like <code>.bsh</code> for BeanShell.
220      */
221     protected abstract String getScriptFileExtension(PluginToolsRequest request);
222 }