/* * Copyright 2000-2010 JetBrains s.r.o. * * Licensed 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 jetbrains.buildServer.eclipse.agent; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; import jetbrains.buildServer.RunBuildException; import jetbrains.buildServer.agent.BuildRunnerContext; import jetbrains.buildServer.agent.runner.CommandLineBuildService; import jetbrains.buildServer.agent.runner.ProcessListener; import jetbrains.buildServer.agent.runner.ProgramCommandLine; import jetbrains.buildServer.agent.runner.SimpleProgramCommandLine; import jetbrains.buildServer.eclipse.EclipseConstants; import jetbrains.buildServer.eclipse.agent.builder.FeatureBasedProjectBuilder; import jetbrains.buildServer.eclipse.agent.builder.JavaProjectBuilder; import jetbrains.buildServer.eclipse.agent.builder.PluginsProjectBuilder; import jetbrains.buildServer.eclipse.agent.builder.SiteProjectBuilder; import jetbrains.buildServer.eclipse.java.BuildDescriptor; import jetbrains.buildServer.eclipse.java.PlatformDescriptor; import org.apache.log4j.Logger; import org.jetbrains.annotations.NotNull; public class EclipseBuilderFactory extends CommandLineBuildService /*BuildServiceAdapter*/{ private static final String DEFAULT_JAVAC_SOURCE = "1.5"; private static final String DEFAULT_JAVAC_TARGET = "1.5"; private final static Logger LOG = Logger.getLogger(EclipseBuilderFactory.class); protected IBuilder myBuilder; protected EclipseBuilderFactory() { LOG.debug("New factory instance created"); } protected IBuilder getBuilder() { return myBuilder; } @Override public ProgramCommandLine makeProgramCommandLine() throws RunBuildException { final LinkedList runnerCommands = new LinkedList(Arrays.asList(getBuilder().makeCommandLines())); if (runnerCommands == null || runnerCommands.size() == 0) { throw new RunBuildException(String.format("The '%s' did not return any command", getBuilder().getName())); } else if (runnerCommands.size() == 1) { LOG.debug("Single command detected. Run in general."); return runnerCommands.getFirst(); } else { //have to concatenate several command into single line. LOG.debug("Batch command detected. Construct summary command."); final LinkedList mergedArguments = new LinkedList(); for (final ProgramCommandLine command : runnerCommands) { LOG.debug(String.format("Processing command: %s %s", command.getExecutablePath(), command.getArguments())); if (!mergedArguments.isEmpty()) { mergedArguments.add("&&"); } mergedArguments.add(command.getExecutablePath());//program for (String arg : command.getArguments()) {//args mergedArguments.add(arg); } } return makeOsRunnable(mergedArguments); } } private SimpleProgramCommandLine makeOsRunnable(final @NotNull LinkedList args) throws RunBuildException { final String shell; if (isWindows()) { args.add(0, "/C"); shell = "cmd"; } else if (isUnix()) { args.add(0, "'"); args.add("'"); args.add(0, "-c"); shell = "sh"; } else if (isMacos()) { args.add(0, "'"); args.add("'"); args.add(0, "-c"); shell = "sh"; } else { throw new RunBuildException(String.format("Unsupported OS: sun.desktop='%s'", System.getProperty("sun.desktop"))); } LOG.debug(String.format("Summary command: %s", args)); return new SimpleProgramCommandLine(getRunnerContext(), shell, args); } private boolean isWindows() { final String osName = System.getProperty("sun.desktop").toLowerCase(); return osName.contains("windows"); } private boolean isUnix() { return !isWindows() && !isMacos(); } private boolean isMacos() { return false; } @Override public void afterInitialized() throws RunBuildException { final BuildRunnerContext context = getRunnerContext(); final PlatformDescriptor platform = getPlatform(context); LOG.debug(String.format("Eclipse platform exists: %s", platform)); final BuildDescriptor buildDescriptor = getBuildDescriptor(platform, context); LOG.debug(String.format("Created build descriptor: %s", buildDescriptor)); /** * Prepare */ myBuilder = null; if (buildDescriptor.isSite()) { myBuilder = new SiteProjectBuilder(getRunnerContext(), platform, buildDescriptor); } else if (buildDescriptor.isProduct() || buildDescriptor.isFeature()) { myBuilder = new FeatureBasedProjectBuilder(getRunnerContext(), platform, buildDescriptor); } else if (buildDescriptor.isPlugin()) { myBuilder = new PluginsProjectBuilder(getRunnerContext(), platform, buildDescriptor); } else if (buildDescriptor.isJava()) { myBuilder = new JavaProjectBuilder(getRunnerContext(), platform, buildDescriptor); } //provide command line if (myBuilder != null) { LOG.debug(String.format("'%s' created", myBuilder)); myBuilder.init(); } else { //nothing found nothing build... throw new RunBuildException(String.format("Could not find appropriate runner: platform [%s], build [%s]", platform, buildDescriptor)); } super.afterInitialized(); } @Override public void afterProcessSuccessfullyFinished() throws RunBuildException { getBuilder().destroy(); LOG.debug("afterProcessSuccessfullyFinished()"); super.afterProcessSuccessfullyFinished(); } protected BuildDescriptor getBuildDescriptor(@NotNull final PlatformDescriptor platform, @NotNull final BuildRunnerContext context) throws RunBuildException { //.project final String mainProjectPath = context.getRunnerParameters().get(EclipseConstants.SETTINGS_RELATIVE_PATH_TO_PROJECT); LOG.debug(String.format("found %s='%s'", EclipseConstants.SETTINGS_RELATIVE_PATH_TO_PROJECT, mainProjectPath)); if (mainProjectPath == null) { throw new RunBuildException(String.format("Path to main eclipse's project file is not set. Make sure this one is specified in the runner configuration.")); } final File mainProject = new File(context.getWorkingDirectory(), mainProjectPath);//TODO: is it MUST be in working folder? LOG.debug(String.format("checking main project file '%s'", mainProject)); if (!mainProject.exists()) { throw new RunBuildException(String.format("Main eclipse's project file '%s' does not exist. Make sure this one is properly specified in the runner configuration.", mainProject)); } //output String outputPath = context.getRunnerParameters().get(EclipseConstants.SETTINGS_ARTIFACTS_OUTPUT_PATH); if (outputPath == null || outputPath.trim().length() == 0) { LOG.debug(String.format("Output path is empty. Use working directory as destination", outputPath)); outputPath = "."; } final File outputDirectory = new File(context.getWorkingDirectory(), outputPath);//TODO: is it MUST be in working folder? if (!outputDirectory.exists()) { outputDirectory.mkdirs(); LOG.debug(String.format("New output directory '%s' created", outputDirectory)); } //source final String javacSource; final String params = context.getRunnerParameters().get(EclipseConstants.PDE_BUILD_PROP_JAVAC_SOURCE); if (params != null && params.trim().length() > 0) { javacSource = params.trim(); } else { javacSource = DEFAULT_JAVAC_SOURCE;//let so... } //target final String javacTarget; final String paramt = context.getRunnerParameters().get(EclipseConstants.PDE_BUILD_PROP_JAVAC_TARGET); if (paramt != null && paramt.trim().length() > 0) { javacTarget = paramt.trim(); } else { javacTarget = DEFAULT_JAVAC_TARGET;//let so... } try { final BuildDescriptor descriptor = BuildDescriptor.create(platform, getJavaHome(), mainProject, outputDirectory, javacSource, javacTarget); descriptor.validate(); return descriptor; } catch (IOException e) { throw new RunBuildException(e.getMessage()); } catch (IllegalArgumentException e) { throw new RunBuildException(e.getMessage()); } } private File getJavaHome() { return new File(System.getProperty("java.home"));//TODO: it's possible to set unique JAVA for build } protected PlatformDescriptor getPlatform(@NotNull final BuildRunnerContext context) throws RunBuildException { /** * looking for path */ //check build setting String eclipseHome = context.getRunnerParameters().get(EclipseConstants.SETTINGS_ECLIPSE_BASE); if (eclipseHome == null) { LOG.debug(String.format("No \"%s\" found in RunnerParameters", EclipseConstants.SETTINGS_ECLIPSE_BASE)); //check system properties eclipseHome = context.getBuildParameters().getSystemProperties().get(EclipseConstants.ECLIPSE_HOME_PROP_NAME); if (eclipseHome == null) { LOG.debug(String.format("No \"%s\" found in SystemProperties", EclipseConstants.ECLIPSE_HOME_PROP_NAME)); //check environment variables eclipseHome = context.getBuildParameters().getEnvironmentVariables().get(EclipseConstants.ECLIPSE_HOME_ENV_NAME); if (eclipseHome == null) { //TODO: check ECLIPSE_HOME also throw new RunBuildException( String.format("Path to an Eclipse platform is not set. Make sure this one is specified in the runner configuration or '%s' System property or '%s' Environment variable is defined.", EclipseConstants.ECLIPSE_HOME_PROP_NAME, EclipseConstants.ECLIPSE_HOME_ENV_NAME)); } LOG.debug(String.format("%s=\"%s\" found in EnvironmentVariables", EclipseConstants.ECLIPSE_HOME_ENV_NAME, eclipseHome)); } else { LOG.debug(String.format("%s=\"%s\" found in SystemProperties", EclipseConstants.ECLIPSE_HOME_PROP_NAME, eclipseHome)); } LOG.debug(String.format("%s=\"%s\" found in RunnerParameters", EclipseConstants.SETTINGS_ECLIPSE_BASE, eclipseHome)); } /** * check the path is valid */ final File home = new File(eclipseHome); if (!home.exists() || !home.isDirectory()) { throw new RunBuildException(String.format("The specified Path to Eclipse platform \"%s\" does not exist or is not a directory.", eclipseHome)); } /** * load platform description */ final PlatformDescriptor descriptor = PlatformDescriptor.create(home); try { descriptor.validate(); } catch (IllegalArgumentException e) { throw new RunBuildException(e.getMessage()); } return descriptor; } @Override public List getListeners() { return Collections. singletonList(new BuildLogger(getLogger())); } public static String getJavaExecutable(final @NotNull BuildRunnerContext context) { return "java";//TODO: use settings!!!! } }