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.index;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.io.File;
26 import java.util.Arrays;
27 import java.util.Comparator;
28 import java.util.Set;
29 import java.util.TreeSet;
30
31 import org.apache.maven.index.context.IndexingContext;
32
33 /**
34 * A default repository scanner for Maven 2 repository.
35 *
36 * @author Jason Van Zyl
37 * @author Tamas Cservenak
38 */
39 @Singleton
40 @Named
41 public class DefaultScanner implements Scanner {
42
43 private final ArtifactContextProducer artifactContextProducer;
44
45 @Inject
46 public DefaultScanner(ArtifactContextProducer artifactContextProducer) {
47 this.artifactContextProducer = artifactContextProducer;
48 }
49
50 public ScanningResult scan(ScanningRequest request) {
51 request.getArtifactScanningListener().scanningStarted(request.getIndexingContext());
52
53 ScanningResult result = new ScanningResult(request);
54
55 scanDirectory(request.getStartingDirectory(), request);
56
57 request.getArtifactScanningListener().scanningFinished(request.getIndexingContext(), result);
58
59 return result;
60 }
61
62 private void scanDirectory(File dir, ScanningRequest request) {
63 if (dir == null) {
64 return;
65 }
66
67 File[] fileArray = dir.listFiles();
68
69 if (fileArray != null) {
70 Set<File> files = new TreeSet<>(new ScannerFileComparator());
71
72 files.addAll(Arrays.asList(fileArray));
73
74 for (File f : files) {
75 if (f.getName().startsWith(".")) {
76 continue; // skip all hidden files and directories
77 }
78
79 if (f.isDirectory()) {
80 scanDirectory(f, request);
81 }
82 // else if ( !AbstractIndexCreator.isIndexable( f ) )
83 // {
84 // continue; // skip non-indexable files
85 // }
86 else {
87 processFile(f, request);
88 }
89 }
90 }
91 }
92
93 private void processFile(File file, ScanningRequest request) {
94 IndexingContext context = request.getIndexingContext();
95
96 ArtifactContext ac = artifactContextProducer.getArtifactContext(context, file);
97
98 if (ac != null) {
99 request.getArtifactScanningListener().artifactDiscovered(ac);
100 }
101 }
102
103 // ==
104
105 /**
106 * A special comparator to overcome some very bad limitations of nexus-indexer during scanning: using this
107 * comparator, we force to "discover" POMs last, before the actual artifact file. The reason for this, is to
108 * guarantee that scanner will provide only "best" informations 1st about same artifact, since the POM->artifact
109 * direction of discovery is not trivial at all (pom read -> packaging -> extension -> artifact file). The artifact
110 * -> POM direction is trivial.
111 */
112 private static class ScannerFileComparator implements Comparator<File> {
113 public int compare(File o1, File o2) {
114 if (o1.getName().endsWith(".pom") && !o2.getName().endsWith(".pom")) {
115 // 1st is pom, 2nd is not
116 return 1;
117 } else if (!o1.getName().endsWith(".pom") && o2.getName().endsWith(".pom")) {
118 // 2nd is pom, 1st is not
119 return -1;
120 } else {
121 // both are "same" (pom or not pom)
122 // Use reverse order so that timestamped snapshots
123 // use latest - not first
124 return o2.getName().compareTo(o1.getName());
125 }
126 }
127 }
128 }