1
2
3
4
5 package com.qulice.maven;
6
7 import com.google.common.base.Predicates;
8 import com.google.common.collect.Collections2;
9 import com.google.common.collect.Iterables;
10 import com.jcabi.log.Logger;
11 import com.qulice.spi.Binary;
12 import java.io.File;
13 import java.net.MalformedURLException;
14 import java.net.URI;
15 import java.net.URL;
16 import java.net.URLClassLoader;
17 import java.nio.charset.Charset;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.List;
21 import java.util.Properties;
22 import javax.annotation.Nullable;
23 import org.apache.commons.io.FileUtils;
24 import org.apache.commons.io.FilenameUtils;
25 import org.apache.commons.io.filefilter.DirectoryFileFilter;
26 import org.apache.commons.io.filefilter.IOFileFilter;
27 import org.apache.commons.io.filefilter.WildcardFileFilter;
28 import org.apache.maven.artifact.DependencyResolutionRequiredException;
29 import org.apache.maven.model.Build;
30 import org.apache.maven.model.Resource;
31 import org.apache.maven.project.MavenProject;
32 import org.codehaus.plexus.context.Context;
33
34
35
36
37
38 @SuppressWarnings("PMD.GodClass")
39 public final class DefaultMavenEnvironment implements MavenEnvironment {
40
41
42
43
44 private MavenProject iproject;
45
46
47
48
49 private Context icontext;
50
51
52
53
54 private final Properties iproperties;
55
56
57
58
59 private MojoExecutor exectr;
60
61
62
63
64 private final Collection<String> exc;
65
66
67
68
69 private final Collection<String> assertion;
70
71
72
73
74 private String charset;
75
76
77
78
79 public DefaultMavenEnvironment() {
80 this.iproperties = new Properties();
81 this.exc = new ArrayList<>(0);
82 this.assertion = new ArrayList<>(0);
83 this.charset = "UTF-8";
84 }
85
86 @Override
87 public String param(final String name, final String value) {
88 String ret = this.iproperties.getProperty(name);
89 if (ret == null && this.iproject != null) {
90 ret = this.iproject.getProperties().getProperty(name);
91 }
92 if (ret == null) {
93 ret = value;
94 }
95 return ret;
96 }
97
98 @Override
99 public File basedir() {
100 return this.iproject.getBasedir();
101 }
102
103 @Override
104 public File tempdir() {
105 final File dir = new File(
106 this.iproject.getBuild().getDirectory(), "tempdir"
107 );
108 if (!dir.mkdirs() && !dir.isDirectory()) {
109 throw new IllegalStateException(
110 String.format("Cannot create tempdir at %s", dir)
111 );
112 }
113 return dir;
114 }
115
116 @Override
117 public File outdir() {
118 return new File(this.iproject.getBuild().getOutputDirectory());
119 }
120
121 @Override
122 public Collection<File> testdirs() {
123 final Collection<File> dirs = new ArrayList<>(0);
124 final List<String> roots = this.iproject.getTestCompileSourceRoots();
125 if (roots != null) {
126 for (final String root : roots) {
127 dirs.add(this.resolve(root));
128 }
129 }
130 return dirs;
131 }
132
133 @Override
134 public Collection<String> classpath() {
135 final Collection<String> paths = new ArrayList<>(0);
136 final String blank = "%20";
137 final String whitespace = " ";
138 try {
139 for (final String name
140 : this.iproject.getTestClasspathElements()) {
141 paths.add(
142 name.replace(
143 File.separatorChar, '/'
144 ).replaceAll(whitespace, blank)
145 );
146 }
147 } catch (final DependencyResolutionRequiredException ex) {
148 throw new IllegalStateException("Failed to read classpath", ex);
149 }
150 return paths;
151 }
152
153 @Override
154 public ClassLoader classloader() {
155 final List<URL> urls = new ArrayList<>(0);
156 for (final String path : this.classpath()) {
157 try {
158 urls.add(
159 URI.create(String.format("file:///%s", path)).toURL()
160 );
161 } catch (final MalformedURLException ex) {
162 throw new IllegalStateException("Failed to build URL", ex);
163 }
164 }
165 final URLClassLoader loader = new PrivilegedClassLoader(urls).run();
166 for (final URL url : loader.getURLs()) {
167 Logger.debug(this, "Classpath: %s", url);
168 }
169 return loader;
170 }
171
172 @Override
173 public MavenProject project() {
174 return this.iproject;
175 }
176
177 @Override
178 public Properties properties() {
179 return this.iproperties;
180 }
181
182 @Override
183 public Context context() {
184 return this.icontext;
185 }
186
187 @Override
188 public Properties config() {
189 return this.iproperties;
190 }
191
192 @Override
193 public MojoExecutor executor() {
194 return this.exectr;
195 }
196
197 @Override
198 public Collection<String> asserts() {
199 return this.assertion;
200 }
201
202 @Override
203 public Collection<File> files(final String pattern) {
204 final Collection<File> files = new ArrayList<>(0);
205 final IOFileFilter filter = WildcardFileFilter.builder().setWildcards(pattern).get();
206 for (final File sources : this.sources()) {
207 if (sources.exists()) {
208 for (final File found : FileUtils.listFiles(
209 sources,
210 filter,
211 DirectoryFileFilter.INSTANCE
212 )) {
213 if (new Binary(found).yes()) {
214 Logger.debug(
215 this,
216 "Skipping binary file %s",
217 found
218 );
219 } else {
220 files.add(found);
221 }
222 }
223 }
224 }
225 return files;
226 }
227
228 @Override
229 public boolean exclude(final String check, final String name) {
230 return Iterables.any(
231 this.excludes(check),
232 new PathPredicate(name)
233 );
234 }
235
236 @Override
237 public Collection<String> excludes(final String checker) {
238 return Collections2.filter(
239 Collections2.transform(
240 this.exc,
241 new CheckerExcludes(checker)
242 ),
243 Predicates.notNull()
244 );
245 }
246
247
248
249
250
251 public void setProject(final MavenProject proj) {
252 this.iproject = proj;
253 }
254
255
256
257
258
259 public void setContext(final Context ctx) {
260 this.icontext = ctx;
261 }
262
263
264
265
266
267 public void setMojoExecutor(final MojoExecutor exec) {
268 this.exectr = exec;
269 }
270
271
272
273
274
275
276 public void setProperty(final String name, final String value) {
277 this.iproperties.setProperty(name, value);
278 }
279
280
281
282
283
284 public void setExcludes(final Collection<String> exprs) {
285 this.exc.clear();
286 this.exc.addAll(exprs);
287 }
288
289
290
291
292
293 public void setAssertion(final Collection<String> ass) {
294 this.assertion.clear();
295 this.assertion.addAll(ass);
296 }
297
298
299
300
301
302 public void setEncoding(final String encoding) {
303 this.charset = encoding;
304 }
305
306 @Override
307 public Charset encoding() {
308 if (this.charset == null || this.charset.isEmpty()) {
309 this.charset = "UTF-8";
310 }
311 return Charset.forName(this.charset);
312 }
313
314 private Collection<File> sources() {
315 final Collection<File> dirs = new ArrayList<>(0);
316 final Build build = this.iproject.getBuild();
317 final File output = this.buildDirectory(build);
318 this.addRoots(dirs, this.iproject.getCompileSourceRoots(), output);
319 this.addRoots(dirs, this.iproject.getTestCompileSourceRoots(), output);
320 if (build != null) {
321 this.addResources(dirs, build.getResources(), output);
322 this.addResources(dirs, build.getTestResources(), output);
323 }
324 if (dirs.isEmpty()) {
325 dirs.add(new File(this.basedir(), "src"));
326 }
327 return dirs;
328 }
329
330 @Nullable
331 private File buildDirectory(@Nullable final Build build) {
332 File dir = null;
333 if (build != null && build.getDirectory() != null) {
334 dir = this.resolve(build.getDirectory());
335 }
336 return dir;
337 }
338
339 private void addRoots(final Collection<File> dirs,
340 final List<String> roots, @Nullable final File output) {
341 if (roots != null) {
342 for (final String root : roots) {
343 final File resolved = this.resolve(root);
344 if (DefaultMavenEnvironment.outside(resolved, output)) {
345 dirs.add(resolved);
346 } else {
347 Logger.debug(
348 this,
349 "Skipping generated source root %s under %s",
350 resolved, output
351 );
352 }
353 }
354 }
355 }
356
357 private void addResources(final Collection<File> dirs,
358 final List<Resource> resources, @Nullable final File output) {
359 if (resources != null) {
360 for (final Resource res : resources) {
361 final File resolved = this.resolve(res.getDirectory());
362 if (DefaultMavenEnvironment.outside(resolved, output)) {
363 dirs.add(resolved);
364 } else {
365 Logger.debug(
366 this,
367 "Skipping generated resource directory %s under %s",
368 resolved, output
369 );
370 }
371 }
372 }
373 }
374
375 private static boolean outside(final File file,
376 @Nullable final File parent) {
377 boolean answer = true;
378 if (parent != null) {
379 final String head = FilenameUtils.normalize(
380 parent.getAbsolutePath(), true
381 );
382 final String tail = FilenameUtils.normalize(
383 file.getAbsolutePath(), true
384 );
385 if (head != null && tail != null
386 && (tail.equals(head) || tail.startsWith(head.concat("/")))) {
387 answer = false;
388 }
389 }
390 return answer;
391 }
392
393 private File resolve(final String path) {
394 final File file = new File(path);
395 final File resolved;
396 if (file.isAbsolute()) {
397 resolved = file;
398 } else {
399 resolved = new File(this.basedir(), path);
400 }
401 return resolved;
402 }
403 }