001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.tools.ant.taskdefs.optional;
019:
020: import java.io.BufferedOutputStream;
021: import java.io.File;
022: import java.io.FileOutputStream;
023: import java.io.IOException;
024: import java.io.OutputStream;
025: import java.io.PrintStream;
026: import java.util.Enumeration;
027: import java.util.Vector;
028: import org.apache.tools.ant.BuildException;
029: import org.apache.tools.ant.Project;
030: import org.apache.tools.ant.Task;
031: import org.apache.tools.ant.util.FileUtils;
032: import org.apache.tools.ant.taskdefs.Execute;
033: import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
034: import org.apache.tools.ant.taskdefs.LogOutputStream;
035: import org.apache.tools.ant.taskdefs.LogStreamHandler;
036: import org.apache.tools.ant.taskdefs.PumpStreamHandler;
037: import org.apache.tools.ant.taskdefs.condition.Os;
038: import org.apache.tools.ant.types.Commandline;
039: import org.apache.tools.ant.types.Path;
040:
041: /**
042: * Invokes the rpm tool to build a Linux installation file.
043: *
044: */
045: public class Rpm extends Task {
046:
047: private static final String PATH1 = "PATH=";
048: private static final String PATH2 = "Path=";
049: private static final String PATH3 = "path=";
050: private static final int PATH_LEN = PATH1.length();
051:
052: /**
053: * the spec file
054: */
055: private String specFile;
056:
057: /**
058: * the rpm top dir
059: */
060: private File topDir;
061:
062: /**
063: * the rpm command to use
064: */
065: private String command = "-bb";
066:
067: /**
068: * The executable to use for building the packages.
069: * @since Ant 1.6
070: */
071: private String rpmBuildCommand = null;
072:
073: /**
074: * clean BUILD directory
075: */
076: private boolean cleanBuildDir = false;
077:
078: /**
079: * remove spec file
080: */
081: private boolean removeSpec = false;
082:
083: /**
084: * remove sources
085: */
086: private boolean removeSource = false;
087:
088: /**
089: * the file to direct standard output from the command
090: */
091: private File output;
092:
093: /**
094: * the file to direct standard error from the command
095: */
096: private File error;
097:
098: /**
099: * Halt on error return value from rpm build.
100: */
101: private boolean failOnError = false;
102:
103: /**
104: * Don't show output of RPM build command on console. This does not affect
105: * the printing of output and error messages to files.
106: */
107: private boolean quiet = false;
108:
109: /**
110: * Execute the task
111: *
112: * @throws BuildException is there is a problem in the task execution.
113: */
114: public void execute() throws BuildException {
115:
116: Commandline toExecute = new Commandline();
117:
118: toExecute
119: .setExecutable(rpmBuildCommand == null ? guessRpmBuildCommand()
120: : rpmBuildCommand);
121: if (topDir != null) {
122: toExecute.createArgument().setValue("--define");
123: toExecute.createArgument().setValue("_topdir" + topDir);
124: }
125:
126: toExecute.createArgument().setLine(command);
127:
128: if (cleanBuildDir) {
129: toExecute.createArgument().setValue("--clean");
130: }
131: if (removeSpec) {
132: toExecute.createArgument().setValue("--rmspec");
133: }
134: if (removeSource) {
135: toExecute.createArgument().setValue("--rmsource");
136: }
137:
138: toExecute.createArgument().setValue("SPECS/" + specFile);
139:
140: ExecuteStreamHandler streamhandler = null;
141: OutputStream outputstream = null;
142: OutputStream errorstream = null;
143: if (error == null && output == null) {
144: if (!quiet) {
145: streamhandler = new LogStreamHandler(this ,
146: Project.MSG_INFO, Project.MSG_WARN);
147: } else {
148: streamhandler = new LogStreamHandler(this ,
149: Project.MSG_DEBUG, Project.MSG_DEBUG);
150: }
151: } else {
152: if (output != null) {
153: try {
154: BufferedOutputStream bos = new BufferedOutputStream(
155: new FileOutputStream(output));
156: outputstream = new PrintStream(bos);
157: } catch (IOException e) {
158: throw new BuildException(e, getLocation());
159: }
160: } else if (!quiet) {
161: outputstream = new LogOutputStream(this ,
162: Project.MSG_INFO);
163: } else {
164: outputstream = new LogOutputStream(this ,
165: Project.MSG_DEBUG);
166: }
167: if (error != null) {
168: try {
169: BufferedOutputStream bos = new BufferedOutputStream(
170: new FileOutputStream(error));
171: errorstream = new PrintStream(bos);
172: } catch (IOException e) {
173: throw new BuildException(e, getLocation());
174: }
175: } else if (!quiet) {
176: errorstream = new LogOutputStream(this ,
177: Project.MSG_WARN);
178: } else {
179: errorstream = new LogOutputStream(this ,
180: Project.MSG_DEBUG);
181: }
182: streamhandler = new PumpStreamHandler(outputstream,
183: errorstream);
184: }
185:
186: Execute exe = getExecute(toExecute, streamhandler);
187: try {
188: log("Building the RPM based on the " + specFile + " file");
189: int returncode = exe.execute();
190: if (Execute.isFailure(returncode)) {
191: String msg = "'" + toExecute.getExecutable()
192: + "' failed with exit code " + returncode;
193: if (failOnError) {
194: throw new BuildException(msg);
195: } else {
196: log(msg, Project.MSG_ERR);
197: }
198: }
199: } catch (IOException e) {
200: throw new BuildException(e, getLocation());
201: } finally {
202: FileUtils.close(outputstream);
203: FileUtils.close(errorstream);
204: }
205: }
206:
207: /**
208: * The directory which will have the expected
209: * subdirectories, SPECS, SOURCES, BUILD, SRPMS ; optional.
210: * If this isn't specified,
211: * the <tt>baseDir</tt> value is used
212: *
213: * @param td the directory containing the normal RPM directories.
214: */
215: public void setTopDir(File td) {
216: this .topDir = td;
217: }
218:
219: /**
220: * What command to issue to the rpm build tool; optional.
221: * The default is "-bb"
222: * @param c the command to use.
223: */
224: public void setCommand(String c) {
225: this .command = c;
226: }
227:
228: /**
229: * The name of the spec File to use; required.
230: * @param sf the spec file name to use.
231: */
232: public void setSpecFile(String sf) {
233: if ((sf == null) || (sf.trim().equals(""))) {
234: throw new BuildException("You must specify a spec file",
235: getLocation());
236: }
237: this .specFile = sf;
238: }
239:
240: /**
241: * Flag (optional, default=false) to remove
242: * the generated files in the BUILD directory
243: * @param cbd a <code>boolean</code> value.
244: */
245: public void setCleanBuildDir(boolean cbd) {
246: cleanBuildDir = cbd;
247: }
248:
249: /**
250: * Flag (optional, default=false) to remove the spec file from SPECS
251: * @param rs a <code>boolean</code> value.
252: */
253: public void setRemoveSpec(boolean rs) {
254: removeSpec = rs;
255: }
256:
257: /**
258: * Flag (optional, default=false)
259: * to remove the sources after the build.
260: * See the <tt>--rmsource</tt> option of rpmbuild.
261: * @param rs a <code>boolean</code> value.
262: */
263: public void setRemoveSource(boolean rs) {
264: removeSource = rs;
265: }
266:
267: /**
268: * Optional file to save stdout to.
269: * @param output the file to save stdout to.
270: */
271: public void setOutput(File output) {
272: this .output = output;
273: }
274:
275: /**
276: * Optional file to save stderr to
277: * @param error the file to save error output to.
278: */
279: public void setError(File error) {
280: this .error = error;
281: }
282:
283: /**
284: * The executable to run when building; optional.
285: * The default is <code>rpmbuild</code>.
286: *
287: * @since Ant 1.6
288: * @param c the rpm build executable
289: */
290: public void setRpmBuildCommand(String c) {
291: this .rpmBuildCommand = c;
292: }
293:
294: /**
295: * If <code>true</code>, stop the build process when the rpmbuild command
296: * exits with an error status.
297: * @param value <code>true</code> if it should halt, otherwise
298: * <code>false</code>. The default is <code>false</code>.
299: *
300: * @since Ant 1.6.3
301: */
302: public void setFailOnError(boolean value) {
303: failOnError = value;
304: }
305:
306: /**
307: * If true, output from the RPM build command will only be logged to DEBUG.
308: * @param value <code>false</code> if output should be logged, otherwise
309: * <code>true</code>. The default is <code>false</code>.
310: *
311: * @since Ant 1.6.3
312: */
313: public void setQuiet(boolean value) {
314: quiet = value;
315: }
316:
317: /**
318: * Checks whether <code>rpmbuild</code> is on the PATH and returns
319: * the absolute path to it - falls back to <code>rpm</code>
320: * otherwise.
321: *
322: * @return the command used to build RPM's
323: *
324: * @since 1.6
325: */
326: protected String guessRpmBuildCommand() {
327: Vector env = Execute.getProcEnvironment();
328: String path = null;
329: for (Enumeration e = env.elements(); e.hasMoreElements();) {
330: String var = (String) e.nextElement();
331: if (var.startsWith(PATH1) || var.startsWith(PATH2)
332: || var.startsWith(PATH3)) {
333: path = var.substring(PATH_LEN);
334: break;
335: }
336: }
337:
338: if (path != null) {
339: Path p = new Path(getProject(), path);
340: String[] pElements = p.list();
341: for (int i = 0; i < pElements.length; i++) {
342: File f = new File(pElements[i], "rpmbuild"
343: + (Os.isFamily("dos") ? ".exe" : ""));
344: if (f.canRead()) {
345: return f.getAbsolutePath();
346: }
347: }
348: }
349:
350: return "rpm";
351: }
352:
353: /**
354: * Get the execute object.
355: * @param toExecute the command line to use.
356: * @param streamhandler the stream handler to use.
357: * @return the execute object.
358: * @since Ant 1.6.3
359: */
360: protected Execute getExecute(Commandline toExecute,
361: ExecuteStreamHandler streamhandler) {
362: Execute exe = new Execute(streamhandler, null);
363:
364: exe.setAntRun(getProject());
365: if (topDir == null) {
366: topDir = getProject().getBaseDir();
367: }
368: exe.setWorkingDirectory(topDir);
369:
370: exe.setCommandline(toExecute.getCommandline());
371: return exe;
372: }
373: }
|