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