Java tutorial
/* * Copyright 2000-2012 Octopus Deploy Pty. Ltd. * * 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 octopus.teamcity.agent; import com.intellij.openapi.diagnostic.Logger; import jetbrains.buildServer.RunBuildException; import jetbrains.buildServer.agent.*; import jetbrains.buildServer.agent.runner.LoggingProcessListener; import jetbrains.buildServer.messages.DefaultMessagesInfo; import octopus.teamcity.common.OctopusConstants; import org.jetbrains.annotations.NotNull; import org.springframework.util.StringUtils; import java.io.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Map; public abstract class OctopusBuildProcess implements BuildProcess { private final AgentRunningBuild runningBuild; private final BuildRunnerContext context; private Process process; private File extractedTo; private OutputReaderThread standardError; private OutputReaderThread standardOutput; private boolean isFinished; private BuildProgressLogger logger; protected OctopusBuildProcess(@NotNull AgentRunningBuild runningBuild, @NotNull BuildRunnerContext context) { this.runningBuild = runningBuild; this.context = context; } public void start() throws RunBuildException { extractOctoExe(); OctopusCommandBuilder arguments = createCommand(); startOcto(arguments); } protected abstract OctopusCommandBuilder createCommand(); protected abstract String getLogMessage(); protected BuildRunnerContext getContext() { return context; } private void extractOctoExe() throws RunBuildException { final File tempDirectory = runningBuild.getBuildTempDirectory(); try { extractedTo = new File(tempDirectory, "octo-temp"); if (!extractedTo.exists()) { if (!extractedTo.mkdirs()) throw new RuntimeException("Unable to create temp output directory " + extractedTo); } EmbeddedResourceExtractor extractor = new EmbeddedResourceExtractor(); extractor.extractTo(extractedTo.getAbsolutePath()); } catch (Exception e) { final String message = "Unable to create temporary file in " + tempDirectory + " for Octopus: " + e.getMessage(); Logger.getInstance(getClass().getName()).error(message, e); throw new RunBuildException(message); } } private void startOcto(final OctopusCommandBuilder command) throws RunBuildException { String[] userVisibleCommand = command.buildMaskedCommand(); String[] realCommand = command.buildCommand(); logger = runningBuild.getBuildLogger(); logger.activityStarted("Octopus Deploy", DefaultMessagesInfo.BLOCK_TYPE_INDENTATION); logger.message( "Running command: octo.exe " + StringUtils.arrayToDelimitedString(userVisibleCommand, " ")); logger.progressMessage(getLogMessage()); try { Runtime runtime = Runtime.getRuntime(); String octopusVersion = getSelectedOctopusVersion(); ArrayList<String> arguments = new ArrayList<String>(); arguments.add(new File(extractedTo, octopusVersion + "\\octo.exe").getAbsolutePath()); arguments.addAll(Arrays.asList(realCommand)); process = runtime.exec(arguments.toArray(new String[arguments.size()]), null, context.getWorkingDirectory()); final LoggingProcessListener listener = new LoggingProcessListener(logger); standardError = new OutputReaderThread(process.getErrorStream(), new OutputWriter() { public void write(String text) { listener.onErrorOutput(text); } }); standardOutput = new OutputReaderThread(process.getInputStream(), new OutputWriter() { public void write(String text) { listener.onStandardOutput(text); } }); standardError.start(); standardOutput.start(); } catch (IOException e) { final String message = "Error from Octo.exe: " + e.getMessage(); Logger.getInstance(getClass().getName()).error(message, e); throw new RunBuildException(message); } } private String getSelectedOctopusVersion() { final Map<String, String> parameters = getContext().getRunnerParameters(); final OctopusConstants constants = OctopusConstants.Instance; final String key = constants.getOctopusVersion(); if (!parameters.containsKey(key)) { return constants.getVersion2().replace("+", ""); } final String octopusVersion = parameters.get(constants.getOctopusVersion()); if (octopusVersion == null || octopusVersion.length() == 0) { return constants.getVersion2().replace("+", ""); } return octopusVersion.replace("+", ""); } public boolean isInterrupted() { return false; } public boolean isFinished() { return isFinished; } public void interrupt() { if (process != null) { process.destroy(); } } @NotNull public BuildFinishedStatus waitFor() throws RunBuildException { int exitCode; try { exitCode = process.waitFor(); standardError.join(); standardOutput.join(); logger.message("Octo.exe exit code: " + exitCode); logger.activityFinished("Octopus Deploy", DefaultMessagesInfo.BLOCK_TYPE_INDENTATION); isFinished = true; } catch (InterruptedException e) { isFinished = true; final String message = "Unable to wait for Octo.exe: " + e.getMessage(); Logger.getInstance(getClass().getName()).error(message, e); throw new RunBuildException(message); } if (exitCode == 0) return BuildFinishedStatus.FINISHED_SUCCESS; runningBuild.getBuildLogger().progressFinished(); String message = "Unable to create or deploy release. Please check the build log for details on the error."; if (runningBuild.getFailBuildOnExitCode()) { runningBuild.getBuildLogger().buildFailureDescription(message); return BuildFinishedStatus.FINISHED_FAILED; } else { runningBuild.getBuildLogger().error(message); return BuildFinishedStatus.FINISHED_SUCCESS; } } private interface OutputWriter { void write(String text); } private class OutputReaderThread extends Thread { private final InputStream is; private final OutputWriter output; OutputReaderThread(InputStream is, OutputWriter output) { this.is = is; this.output = output; } public void run() { InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String line; try { while ((line = br.readLine()) != null) { output.write(line.replaceAll("[\\r\\n]", "")); } } catch (IOException e) { output.write("ERROR: " + e.getMessage()); } } } }