/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.tools.ant.taskdefs.optional; import java.io.BufferedOutputStream; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.nio.file.Files; import java.util.Map; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.taskdefs.Execute; import org.apache.tools.ant.taskdefs.ExecuteStreamHandler; import org.apache.tools.ant.taskdefs.LogOutputStream; import org.apache.tools.ant.taskdefs.LogStreamHandler; import org.apache.tools.ant.taskdefs.PumpStreamHandler; import org.apache.tools.ant.taskdefs.condition.Os; import org.apache.tools.ant.types.Commandline; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.util.FileUtils; /** * Invokes the rpm tool to build a Linux installation file. * */ public class Rpm extends Task { private static final String PATH1 = "PATH"; private static final String PATH2 = "Path"; private static final String PATH3 = "path"; /** * the spec file */ private String specFile; /** * the rpm top dir */ private File topDir; /** * the rpm command to use */ private String command = "-bb"; /** * The executable to use for building the packages. * @since Ant 1.6 */ private String rpmBuildCommand = null; /** * clean BUILD directory */ private boolean cleanBuildDir = false; /** * remove spec file */ private boolean removeSpec = false; /** * remove sources */ private boolean removeSource = false; /** * the file to direct standard output from the command */ private File output; /** * the file to direct standard error from the command */ private File error; /** * Halt on error return value from rpm build. */ private boolean failOnError = false; /** * Don't show output of RPM build command on console. This does not affect * the printing of output and error messages to files. */ private boolean quiet = false; /** * Execute the task * * @throws BuildException is there is a problem in the task execution. */ @Override public void execute() throws BuildException { Commandline toExecute = new Commandline(); toExecute.setExecutable(rpmBuildCommand == null ? guessRpmBuildCommand() : rpmBuildCommand); if (topDir != null) { toExecute.createArgument().setValue("--define"); toExecute.createArgument().setValue("_topdir " + topDir); } toExecute.createArgument().setLine(command); if (cleanBuildDir) { toExecute.createArgument().setValue("--clean"); } if (removeSpec) { toExecute.createArgument().setValue("--rmspec"); } if (removeSource) { toExecute.createArgument().setValue("--rmsource"); } toExecute.createArgument().setValue("SPECS/" + specFile); ExecuteStreamHandler streamhandler = null; OutputStream outputstream = null; OutputStream errorstream = null; if (error == null && output == null) { if (!quiet) { streamhandler = new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_WARN); } else { streamhandler = new LogStreamHandler(this, Project.MSG_DEBUG, Project.MSG_DEBUG); } } else { if (output != null) { OutputStream fos = null; try { fos = Files.newOutputStream(output.toPath()); //NOSONAR BufferedOutputStream bos = new BufferedOutputStream(fos); outputstream = new PrintStream(bos); } catch (IOException e) { FileUtils.close(fos); throw new BuildException(e, getLocation()); } } else if (!quiet) { outputstream = new LogOutputStream(this, Project.MSG_INFO); } else { outputstream = new LogOutputStream(this, Project.MSG_DEBUG); } if (error != null) { OutputStream fos = null; try { fos = Files.newOutputStream(error.toPath()); BufferedOutputStream bos = new BufferedOutputStream(fos); errorstream = new PrintStream(bos); } catch (IOException e) { FileUtils.close(fos); throw new BuildException(e, getLocation()); } } else if (!quiet) { errorstream = new LogOutputStream(this, Project.MSG_WARN); } else { errorstream = new LogOutputStream(this, Project.MSG_DEBUG); } streamhandler = new PumpStreamHandler(outputstream, errorstream); } Execute exe = getExecute(toExecute, streamhandler); try { log("Building the RPM based on the " + specFile + " file"); int returncode = exe.execute(); if (Execute.isFailure(returncode)) { String msg = "'" + toExecute.getExecutable() + "' failed with exit code " + returncode; if (failOnError) { throw new BuildException(msg); } log(msg, Project.MSG_ERR); } } catch (IOException e) { throw new BuildException(e, getLocation()); } finally { FileUtils.close(outputstream); FileUtils.close(errorstream); } } /** * The directory which will have the expected * subdirectories, SPECS, SOURCES, BUILD, SRPMS ; optional. * If this isn't specified, * the <tt>baseDir</tt> value is used * * @param td the directory containing the normal RPM directories. */ public void setTopDir(File td) { this.topDir = td; } /** * What command to issue to the rpm build tool; optional. * The default is "-bb" * @param c the command to use. */ public void setCommand(String c) { this.command = c; } /** * The name of the spec File to use; required. * @param sf the spec file name to use. */ public void setSpecFile(String sf) { if (sf == null || sf.trim().isEmpty()) { throw new BuildException("You must specify a spec file", getLocation()); } this.specFile = sf; } /** * Flag (optional, default=false) to remove * the generated files in the BUILD directory * @param cbd a <code>boolean</code> value. */ public void setCleanBuildDir(boolean cbd) { cleanBuildDir = cbd; } /** * Flag (optional, default=false) to remove the spec file from SPECS * @param rs a <code>boolean</code> value. */ public void setRemoveSpec(boolean rs) { removeSpec = rs; } /** * Flag (optional, default=false) * to remove the sources after the build. * See the <tt>--rmsource</tt> option of rpmbuild. * @param rs a <code>boolean</code> value. */ public void setRemoveSource(boolean rs) { removeSource = rs; } /** * Optional file to save stdout to. * @param output the file to save stdout to. */ public void setOutput(File output) { this.output = output; } /** * Optional file to save stderr to * @param error the file to save error output to. */ public void setError(File error) { this.error = error; } /** * The executable to run when building; optional. * The default is <code>rpmbuild</code>. * * @since Ant 1.6 * @param c the rpm build executable */ public void setRpmBuildCommand(String c) { this.rpmBuildCommand = c; } /** * If <code>true</code>, stop the build process when the rpmbuild command * exits with an error status. * @param value <code>true</code> if it should halt, otherwise * <code>false</code>. The default is <code>false</code>. * * @since Ant 1.6.3 */ public void setFailOnError(boolean value) { failOnError = value; } /** * If true, output from the RPM build command will only be logged to DEBUG. * @param value <code>false</code> if output should be logged, otherwise * <code>true</code>. The default is <code>false</code>. * * @since Ant 1.6.3 */ public void setQuiet(boolean value) { quiet = value; } /** * Checks whether <code>rpmbuild</code> is on the PATH and returns * the absolute path to it - falls back to <code>rpm</code> * otherwise. * * @return the command used to build RPM's * * @since 1.6 */ protected String guessRpmBuildCommand() { Map<String, String> env = Execute.getEnvironmentVariables(); String path = env.get(PATH1); if (path == null) { path = env.get(PATH2); if (path == null) { path = env.get(PATH3); } } if (path != null) { Path p = new Path(getProject(), path); String[] pElements = p.list(); for (String pElement : pElements) { File f = new File(pElement, "rpmbuild" + (Os.isFamily("dos") ? ".exe" : "")); if (f.canRead()) { return f.getAbsolutePath(); } } } return "rpm"; } /** * Get the execute object. * @param toExecute the command line to use. * @param streamhandler the stream handler to use. * @return the execute object. * @since Ant 1.6.3 */ protected Execute getExecute(Commandline toExecute, ExecuteStreamHandler streamhandler) { Execute exe = new Execute(streamhandler, null); exe.setAntRun(getProject()); if (topDir == null) { topDir = getProject().getBaseDir(); } exe.setWorkingDirectory(topDir); exe.setCommandline(toExecute.getCommandline()); return exe; } }