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

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Brian Westrich, Jean-Baptiste Quenot
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.tasks;
25
26 import hudson.FilePath;
27 import hudson.Launcher;
28 import hudson.Util;
29 import hudson.Extension;
30 import hudson.model.AbstractBuild;
31 import hudson.model.AbstractProject;
32 import hudson.model.BuildListener;
33 import hudson.model.Result;
34 import hudson.util.FormValidation;
35 import org.kohsuke.stapler.StaplerRequest;
36 import org.kohsuke.stapler.DataBoundConstructor;
37 import org.kohsuke.stapler.AncestorInPath;
38 import org.kohsuke.stapler.QueryParameter;
39
40 import java.io.File;
41 import java.io.IOException;
42
43 import net.sf.json.JSONObject;
44
45 /**
46 * Copies the artifacts into an archive directory.
47 *
48 * @author Kohsuke Kawaguchi
49 */
50 public class ArtifactArchiver extends Recorder {
51
52 /**
53 * Comma- or space-separated list of patterns of files/directories to be archived.
54 */
55 private final String artifacts;
56
57 /**
58 * Possibly null 'excludes' pattern as in Ant.
59 */
60 private final String excludes;
61
62 /**
63 * Just keep the last successful artifact set, no more.
64 */
65 private final boolean latestOnly;
66
67 private static final Boolean allowEmptyArchive =
68 Boolean.getBoolean(ArtifactArchiver.class.getName()+".warnOnEmpty");
69
70 @DataBoundConstructor
71 public ArtifactArchiver(String artifacts, String excludes, boolean latestOnly) {
72 this.artifacts = artifacts.trim();
73 this.excludes = Util.fixEmptyAndTrim(excludes);
74 this.latestOnly = latestOnly;
75 }
76
77 public String getArtifacts() {
78 return artifacts;
79 }
80
81 public String getExcludes() {
82 return excludes;
83 }
84
85 public boolean isLatestOnly() {
86 return latestOnly;
87 }
88
89 private void listenerWarnOrError(BuildListener listener, String message) {
90 if (allowEmptyArchive) {
91 listener.getLogger().println(String.format("WARN: %s", message));
92 } else {
93 listener.error(message);
94 }
95 }
96
97 @Override
98 public boolean perform(AbstractBuild<?,?> build, Launcher launcher, BuildListener listener) throws InterruptedException {
99 if(artifacts.length()==0) {
100 listener.error(Messages.ArtifactArchiver_NoIncludes());
101 build.setResult(Result.FAILURE);
102 return true;
103 }
104
105 File dir = build.getArtifactsDir();
106 dir.mkdirs();
107
108 listener.getLogger().println(Messages.ArtifactArchiver_ARCHIVING_ARTIFACTS());
109 try {
110 FilePath ws = build.getWorkspace();
111 if (ws==null) { // #3330: slave down?
112 return true;
113 }
114
115 String artifacts = build.getEnvironment(listener).expand(this.artifacts);
116 if(ws.copyRecursiveTo(artifacts,excludes,new FilePath(dir))==0) {
117 if(build.getResult().isBetterOrEqualTo(Result.UNSTABLE)) {
118 // If the build failed, don't complain that there was no matching artifact.
119 // The build probably didn't even get to the point where it produces artifacts.
120 listenerWarnOrError(listener, Messages.ArtifactArchiver_NoMatchFound(artifacts));
121 String msg = null;
122 try {
123 msg = ws.validateAntFileMask(artifacts);
124 } catch (Exception e) {
125 listenerWarnOrError(listener, e.getMessage());
126 }
127 if(msg!=null)
128 listenerWarnOrError(listener, msg);
129 }
130 if (!allowEmptyArchive) {
131 build.setResult(Result.FAILURE);
132 }
133 return true;
134 }
135 } catch (IOException e) {
136 Util.displayIOException(e,listener);
137 e.printStackTrace(listener.error(
138 Messages.ArtifactArchiver_FailedToArchive(artifacts)));
139 return true;
140 }
141
142 return true;
143 }
144
145 @Override
146 public boolean prebuild(AbstractBuild<?, ?> build, BuildListener listener) {
147 if(latestOnly) {
148 AbstractBuild<?,?> b = build.getProject().getLastCompletedBuild();
149 Result bestResultSoFar = Result.NOT_BUILT;
150 while(b!=null) {
151 if (b.getResult().isBetterThan(bestResultSoFar)) {
152 bestResultSoFar = b.getResult();
153 } else {
154 // remove old artifacts
155 File ad = b.getArtifactsDir();
156 if(ad.exists()) {
157 listener.getLogger().println(Messages.ArtifactArchiver_DeletingOld(b.getDisplayName()));
158 try {
159 Util.deleteRecursive(ad);
160 } catch (IOException e) {
161 e.printStackTrace(listener.error(e.getMessage()));
162 }
163 }
164 }
165 b = b.getPreviousBuild();
166 }
167 }
168 return true;
169 }
170
171 public BuildStepMonitor getRequiredMonitorService() {
172 return BuildStepMonitor.NONE;
173 }
174
175 /**
176 * @deprecated as of 1.286
177 * Some plugin depends on this, so this field is left here and points to the last created instance.
178 * Use {@link jenkins.model.Jenkins#getDescriptorByType(Class)} instead.
179 */
180 public static volatile DescriptorImpl DESCRIPTOR;
181
182 @Extension
183 public static class DescriptorImpl extends BuildStepDescriptor<Publisher> {
184 public DescriptorImpl() {
185 DESCRIPTOR = this; // backward compatibility
186 }
187
188 public String getDisplayName() {
189 return Messages.ArtifactArchiver_DisplayName();
190 }
191
192 /**
193 * Performs on-the-fly validation on the file mask wildcard.
194 */
195 public FormValidation doCheckArtifacts(@AncestorInPath AbstractProject project, @QueryParameter String value) throws IOException {
196 return FilePath.validateFileMask(project.getSomeWorkspace(),value);
197 }
198
199 @Override
200 public ArtifactArchiver newInstance(StaplerRequest req, JSONObject formData) throws FormException {
201 return req.bindJSON(ArtifactArchiver.class,formData);
202 }
203
204 public boolean isApplicable(Class<? extends AbstractProject> jobType) {
205 return true;
206 }
207 }
208 }
209