package hudson.plugins.analysis.views; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; import com.infradna.tool.bridge_method_injector.WithBridgeMethods; import hudson.console.ConsoleNote; import hudson.model.ModelObject; import hudson.model.AbstractBuild; import hudson.model.Run; import hudson.plugins.analysis.Messages; /** * Renders a source file containing an annotation for the whole file or a specific line number. * * @author Ulli Hafner */ @SuppressWarnings("PMD.CyclomaticComplexity") public class ConsoleDetail implements ModelObject { /** Filename dummy if the console log is the source of the warning. */ public static final String CONSOLE_LOG_FILENAME = "Console Log"; /** The current build as owner of this object. */ private final Run<?, ?> owner; /** The rendered source file. */ private String sourceCode = StringUtils.EMPTY; private final int from; private final int to; private final int end; private final int start; /** * Creates a new instance of this console log viewer object. * * @param owner * the current build as owner of this object * @param from * first line in the console log * @param to * last line in the console log */ public ConsoleDetail(final Run<?, ?> owner, final int from, final int to) { this.owner = owner; this.from = from; this.to = to; start = Math.max(0, from - 10); end = to + 10; readConsole(); } private void readConsole() { BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader(new FileInputStream(owner.getLogFile()), "UTF8")); StringBuilder console = new StringBuilder(1024); console.append("<table>\n"); int lineCount = 0; for (String line = reader.readLine(); line != null && lineCount <= end; line = reader.readLine()) { if (lineCount >= start) { console.append("<tr><td "); if (lineCount >= from && lineCount <= to) { console.append("style=\"background-color:#FCAF3E\""); } console.append(">\n"); console.append(StringEscapeUtils.escapeHtml(line)); console.append("</td></tr>\n"); } lineCount++; } console.append("</table>\n"); sourceCode = ConsoleNote.removeNotes(console.toString()); } catch (IOException exception) { sourceCode = sourceCode + exception.getLocalizedMessage(); } finally { IOUtils.closeQuietly(reader); } } @Override public String getDisplayName() { return Messages.ConsoleLog_Title(start, end); } /** * Gets the file name of this source file. * * @return the file name */ public String getFileName() { return getDisplayName(); } /** * Returns the build as owner of this object. * * @return the build */ @WithBridgeMethods(value=AbstractBuild.class, adapterMethod="getAbstractBuild") public Run<?, ?> getOwner() { return owner; } /** * Added for backward compatibility. It generates <pre>AbstractBuild getOwner()</pre> bytecode during the build * process, so old implementations can use that signature. * * @see {@link WithBridgeMethods} */ @Deprecated private final Object getAbstractBuild(Run owner, Class targetClass) { return owner instanceof AbstractBuild ? (AbstractBuild) owner : null; } /** * Returns the line that should be highlighted. * * @return the line to highlight */ public String getSourceCode() { return sourceCode; } /** * Creates a new instance of this console log viewer object. * * @param owner * the current build as owner of this object * @param from * first line in the console log * @param to * last line in the console log * @deprecated use {@link #ConsoleDetail(Run, int, int)} instead */ @Deprecated public ConsoleDetail(final AbstractBuild<?, ?> owner, final int from, final int to) { this((Run<?, ?>) owner, from ,to); } }