File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\maven-plugin\src\main\java\hudson\maven\reporters\MavenFingerprinter.java.html

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 package hudson.maven.reporters;
25
26 import hudson.Extension;
27 import hudson.FilePath;
28 import hudson.maven.MavenBuild;
29 import hudson.maven.MavenBuildInformation;
30 import hudson.maven.MavenBuildProxy;
31 import hudson.maven.MavenBuildProxy.BuildCallable;
32 import hudson.maven.MavenModule;
33 import hudson.maven.MavenModuleSetBuild;
34 import hudson.maven.MavenReporter;
35 import hudson.maven.MavenReporterDescriptor;
36 import hudson.maven.MojoInfo;
37 import hudson.model.BuildListener;
38 import hudson.model.FingerprintMap;
39 import hudson.tasks.Fingerprinter.FingerprintAction;
40
41 import java.io.File;
42 import java.io.IOException;
43 import java.lang.reflect.Method;
44 import java.util.Collection;
45 import java.util.HashMap;
46 import java.util.HashSet;
47 import java.util.List;
48 import java.util.Map;
49 import java.util.Map.Entry;
50 import java.util.Set;
51 import java.util.logging.Level;
52 import java.util.logging.Logger;
53
54 import jenkins.model.Jenkins;
55
56 import org.apache.maven.artifact.Artifact;
57 import org.apache.maven.artifact.DefaultArtifact;
58 import org.apache.maven.artifact.handler.DefaultArtifactHandler;
59 import org.apache.maven.artifact.repository.ArtifactRepository;
60 import org.apache.maven.artifact.versioning.VersionRange;
61 import org.apache.maven.project.MavenProject;
62 import org.apache.maven.project.ProjectBuilderConfiguration;
63
64 /**
65 * Records fingerprints of the builds to keep track of dependencies.
66 *
67 * @author Kohsuke Kawaguchi
68 */
69 public class MavenFingerprinter extends MavenReporter {
70
71 /**
72 * Files whose fingerprints were already recorded.
73 */
74 private transient Set<File> files;
75 /**
76 * Fingerprints for files that were used.
77 */
78 private transient Map<String,String> used;
79 /**
80 * Fingerprints for files that were produced.
81 */
82 private transient Map<String,String> produced;
83
84 public boolean preBuild(MavenBuildProxy build, MavenProject pom, BuildListener listener) throws InterruptedException, IOException {
85 files = new HashSet<File>();
86 used = new HashMap<String,String>();
87 produced = new HashMap<String,String>();
88 return true;
89 }
90
91 /**
92 * Mojos perform different dependency resolution, so we need to check this for each mojo.
93 */
94 public boolean postExecute(MavenBuildProxy build, MavenProject pom, MojoInfo mojo, BuildListener listener, Throwable error) throws InterruptedException, IOException {
95 // TODO (kutzi, 2011/09/06): it should be perfectly safe to move all these records to the
96 // postBuild method as artifacts should only be added by mojos, but never removed/modified.
97 record(pom.getArtifacts(),used);
98 record(pom.getArtifact(),produced);
99 record(pom.getAttachedArtifacts(),produced);
100 record(pom.getGroupId() + ":" + pom.getArtifactId(),pom.getFile(),produced);
101
102 return true;
103 }
104
105 /**
106 * Sends the collected fingerprints over to the master and record them.
107 */
108 public boolean postBuild(MavenBuildProxy build, MavenProject pom, BuildListener listener) throws InterruptedException, IOException {
109
110 recordParents(build, pom);
111
112 build.executeAsync(new BuildCallable<Void,IOException>() {
113 private static final long serialVersionUID = -1360161848504044869L;
114
115 // record is transient, so needs to make a copy first
116 private final Map<String,String> u = used;
117 private final Map<String,String> p = produced;
118
119 public Void call(MavenBuild build) throws IOException, InterruptedException {
120 FingerprintMap map = Jenkins.getInstance().getFingerprintMap();
121
122 for (Entry<String, String> e : p.entrySet())
123 map.getOrCreate(build, e.getKey(), e.getValue()).add(build);
124 for (Entry<String, String> e : u.entrySet())
125 map.getOrCreate(null, e.getKey(), e.getValue()).add(build);
126
127 Map<String,String> all = new HashMap<String, String>(u);
128 all.putAll(p);
129
130 // add action
131 FingerprintAction fa = build.getAction(FingerprintAction.class);
132 if (fa!=null) fa.add(all);
133 else build.getActions().add(new FingerprintAction(build,all));
134 return null;
135 }
136 });
137 return true;
138 }
139
140 private void recordParents(MavenBuildProxy build, MavenProject pom) throws IOException, InterruptedException {
141 MavenProject parent = pom.getParent();
142 while (parent != null) {
143 File parentFile = parent.getFile();
144
145 if (parentFile == null) {
146 // Parent artifact contains no actual file, so we resolve against
147 // the local repository
148 ArtifactRepository localRepository = getLocalRepository(build.getMavenBuildInformation(), parent, pom);
149 if (localRepository != null) {
150 Artifact parentArtifact = getArtifact(parent);
151 // Don't use ArtifactRepository.find(), for compatibility with Maven 2.x
152 if (parentArtifact != null) {
153 parentFile = new File(localRepository.getBasedir(),
154 localRepository.pathOf(parentArtifact));
155 }
156 }
157 }
158
159 if (parentFile != null) {
160 // we need to include the artifact Id for poms as well, otherwise a
161 // project with the same groupId would override its parent's
162 // fingerprint
163 record(parent.getGroupId() + ":" + parent.getArtifactId(),
164 parentFile, used);
165 }
166 parent = parent.getParent();
167 }
168 }
169
170 private Artifact getArtifact(MavenProject parent) {
171 Artifact art = parent.getArtifact();
172 if (art == null) {
173 // happens for Maven 2.x
174 DefaultArtifactHandler artifactHandler = new DefaultArtifactHandler("pom");
175 art = new DefaultArtifact(parent.getGroupId(), parent.getArtifactId(), VersionRange.createFromVersion(parent.getVersion()),
176 null, "pom", "", artifactHandler);
177 }
178 return art;
179 }
180
181 private ArtifactRepository getLocalRepository(MavenBuildInformation mavenBuildInformation, MavenProject parent, MavenProject pom) {
182
183 if (mavenBuildInformation.isMaven3OrLater()) {
184 return parent.getProjectBuildingRequest().getLocalRepository();
185 } else if (mavenBuildInformation.isAtLeastMavenVersion("2.2")) {
186 // principally this should also work with Maven 2.1, but it's not tested, so err on the safe side
187 return getArtifactRepositoryMaven21(pom);
188 } else if (mavenBuildInformation.isAtLeastMavenVersion("2.0")) {
189 // Maven 2.0 has no corresponding mechanism
190 return null;
191 } else {
192 LOGGER.warning("Unknown Maven version: "+mavenBuildInformation.getMavenVersion());
193 return null;
194 }
195 }
196
197 @SuppressWarnings("deprecation")
198 private ArtifactRepository getArtifactRepositoryMaven21(MavenProject pom) {
199 ProjectBuilderConfiguration projectBuilderConfiguration;
200 try {
201 // Since maven-plugin is compiled against maven-core-3x, we need to retrieve
202 // this maven 2 object via reflection
203 Method method = MavenProject.class.getMethod("getProjectBuilderConfiguration");
204 projectBuilderConfiguration = (ProjectBuilderConfiguration) method.invoke(pom);
205 return projectBuilderConfiguration.getLocalRepository();
206 } catch (Exception e) {
207 LOGGER.log(Level.WARNING, "Could not retrieve BuilderConfigration", e);
208 return null;
209 }
210 }
211
212 private void record(Collection<Artifact> artifacts, Map<String,String> record) throws IOException, InterruptedException {
213 for (Artifact a : artifacts)
214 record(a,record);
215 }
216
217 /**
218 * Records the fingerprint of the given {@link Artifact}.
219 */
220 private void record(Artifact a, Map<String,String> record) throws IOException, InterruptedException {
221 File f = a.getFile();
222 record(a.getGroupId(), f, record);
223 }
224
225 /**
226 * Records the fingerprint of the given file.
227 *
228 * <p>
229 * This method contains the logic to avoid doubly recording the fingerprint
230 * of the same file.
231 */
232 private void record(String fileNamePrefix, File f, Map<String, String> record) throws IOException, InterruptedException {
233 if(f==null || files.contains(f) || !f.isFile())
234 return;
235
236 // new file
237 files.add(f);
238 String digest = new FilePath(f).digest();
239 record.put(fileNamePrefix+':'+f.getName(),digest);
240 }
241
242 @Extension
243 public static final class DescriptorImpl extends MavenReporterDescriptor {
244 public String getDisplayName() {
245 return Messages.MavenFingerprinter_DisplayName();
246 }
247
248 public MavenReporter newAutoInstance(MavenModule module) {
249 return new MavenFingerprinter();
250 }
251 }
252
253 /**
254 * Creates {@link FingerprintAction} for {@link MavenModuleSetBuild}
255 * by aggregating all fingerprints from module builds.
256 */
257 public static void aggregate(MavenModuleSetBuild mmsb) throws IOException {
258 Map<String,String> records = new HashMap<String, String>();
259 for (List<MavenBuild> builds : mmsb.getModuleBuilds().values()) {
260 for (MavenBuild build : builds) {
261 FingerprintAction fa = build.getAction(FingerprintAction.class);
262 if(fa!=null)
263 records.putAll(fa.getRecords());
264 }
265 }
266 if(!records.isEmpty()) {
267 FingerprintMap map = Jenkins.getInstance().getFingerprintMap();
268 for (Entry<String, String> e : records.entrySet())
269 map.getOrCreate(null, e.getKey(), e.getValue()).add(mmsb);
270 mmsb.addAction(new FingerprintAction(mmsb,records));
271 }
272 }
273
274 private static final long serialVersionUID = 1L;
275
276 private static final Logger LOGGER = Logger.getLogger(MavenFingerprinter.class.getName());
277 }
278