package hudson.plugins.qmake; import hudson.EnvVars; import hudson.Extension; import hudson.FilePath; import hudson.Launcher; import hudson.Util; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.BuildListener; import hudson.tasks.BuildStepDescriptor; import hudson.tasks.Builder; import hudson.util.FormValidation; import net.sf.json.JSONObject; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; import javax.servlet.ServletException; import java.io.File; import java.io.PrintStream; import java.io.IOException; /** * Executes <tt>qmake</tt> and <tt>make</tt> as the build process for a QT-based build. * * @author Tyler Mace */ public class QmakeBuilder extends Builder { private String projectFile; private String extraArguments; @Deprecated private transient String extraConfig; // unused, deprecated private boolean cleanBuild; private QmakeBuilderImpl builderImpl; @DataBoundConstructor public QmakeBuilder(String projectFile, String extraArguments) { this.projectFile = projectFile; this.extraArguments = extraArguments; this.cleanBuild = false; builderImpl = new QmakeBuilderImpl(); } public String getProjectFile() { return this.projectFile; } public String getExtraArguments() { return this.extraArguments; } public boolean getCleanBuild() { return this.cleanBuild; } @Override public boolean perform(AbstractBuild<?,?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { PrintStream logger = listener.getLogger(); logger.println("MODULE: " + build.getModuleRoot()); final boolean isWindows = !launcher.isUnix(); if (builderImpl == null) { builderImpl = new QmakeBuilderImpl(); } EnvVars envVars = build.getEnvironment(listener); String theProjectFile; try { theProjectFile = builderImpl.preparePath(envVars, this.projectFile, isWindows, logger); } catch (IOException ioe) { logger.println("IO Exception with the project file: " + projectFile); logger.println(ioe.getMessage()); return false; } builderImpl.setQmakeBin( envVars, getDescriptor().qmakePath(), isWindows ); String qmakeCall = builderImpl.buildQMakeCall(theProjectFile, extraArguments ); FilePath workDir = new FilePath(build.getWorkspace(), theProjectFile); workDir = workDir.getParent(); logger.println("QMake call : " + qmakeCall); try { int result = launcher.launch().cmds(Util.tokenize(qmakeCall)).envs(envVars).stdout(logger).pwd(workDir).join(); if (result != 0) return false; String makeExe = "make"; if (!launcher.isUnix()) makeExe = "nmake"; result = launcher.launch().cmds(makeExe).envs(envVars).stdout(logger).pwd(workDir).join(); if (result != 0) { return false; } else { return true; } } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException ie) { ie.printStackTrace(); } return false; } @Override public DescriptorImpl getDescriptor() { return (DescriptorImpl)super.getDescriptor(); } /** * Descriptor for {@link QmakeBuilder}. Used as a singleton. * The class is marked as public so that it can be accessed from views. * * <p> * See <tt>views/hudson/plugins/hello_world/QmakeBuilder/*.jelly</tt> * for the actual HTML fragment for the configuration screen. */ @Extension public static final class DescriptorImpl extends BuildStepDescriptor<Builder> { /** * To persist global configuration information, * simply store it in a field and call save(). * * <p> * If you don't want fields to be persisted, use <tt>transient</tt>. */ private String qmakePath; public DescriptorImpl() { super(QmakeBuilder.class); load(); } /** * Performs on-the-fly validation of the form field 'projectFile'. * * @param value */ public FormValidation doCheckProjectFile(@QueryParameter final String value) throws IOException, ServletException { if(value.length()==0) return FormValidation.error("Please set a project file"); if(value.length() < 1) return FormValidation.warning("Isn't the name too short?"); File file = new File(value); if (file.isDirectory()) return FormValidation.error("Project file is a directory"); //TODO add more checks return FormValidation.ok(); } /** * This human readable name is used in the configuration screen. */ public String getDisplayName() { return "QMake Build"; } @Override public boolean isApplicable(Class<? extends AbstractProject> jobType) { return true; } @Override public boolean configure(StaplerRequest req, JSONObject o) throws FormException { // to persist global configuration information, // set that to properties and call save(). qmakePath = o.getString("qmakePath"); save(); return super.configure(req, o); } public String qmakePath() { return qmakePath; } } }