/******************************************************************************* * Copyright (c) 2007, 2013 Alphonse Van Assche and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Alphonse Van Assche - initial API and implementation * Alexander Kurtakov - cleanups and simplification *******************************************************************************/ package org.eclipse.linuxtools.internal.rpm.rpmlint.builder; import java.io.IOException; import java.io.InputStream; import java.util.List; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.runtime.CoreException; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; import org.eclipse.linuxtools.internal.rpm.rpmlint.Activator; import org.eclipse.linuxtools.internal.rpm.rpmlint.RpmlintLog; import org.eclipse.linuxtools.internal.rpm.rpmlint.parser.RpmlintItem; import org.eclipse.linuxtools.internal.rpm.rpmlint.parser.RpmlintParser; import org.eclipse.linuxtools.rpm.ui.editor.markers.SpecfileErrorHandler; import org.eclipse.linuxtools.rpm.ui.editor.markers.SpecfileTaskHandler; import org.eclipse.linuxtools.rpm.ui.editor.parser.SpecfileParser; /** * Visitor that generates markers for rpmlint found warnings and errors. * */ public class RpmlintMarkerVisitor implements IResourceVisitor { private List<RpmlintItem> rpmlintItems; private boolean firstWarningInResource; private SpecfileParser parser; private SpecfileErrorHandler errorHandler; private SpecfileTaskHandler taskHandler; /** * Creates a visitor for handling .rpm and .spec files and adding markers * for rpmlint warnings/errors. * * @param rpmlintItems * The rpmlint identified warnings and errors. */ public RpmlintMarkerVisitor(List<RpmlintItem> rpmlintItems) { this.rpmlintItems = rpmlintItems; parser = new SpecfileParser(); } @Override public boolean visit(IResource resource) throws CoreException { if (resource.getType() == IResource.FILE) { if (Activator.SPECFILE_EXTENSION .equals(resource.getFileExtension())) { firstWarningInResource = true; for (RpmlintItem item : rpmlintItems) { if (item.getFileName().equals( resource.getLocation().toOSString())) { IFile currentFile = ((IFile) resource); if (firstWarningInResource) { RpmlintParser.deleteMarkers(resource); // remove internal marks on the current resource currentFile .deleteMarkers( SpecfileErrorHandler.SPECFILE_ERROR_MARKER_ID, false, IResource.DEPTH_ZERO); firstWarningInResource = false; } String specContent = fileToString(currentFile); int lineNumber; // FIXME: workaround the wrong line number with // configure-without-libdir-spec if (item.getId() .equals("configure-without-libdir-spec")) { //$NON-NLS-1$ item.setLineNbr(-1); lineNumber = RpmlintParser.getRealLineNbr(specContent, "./configure"); //$NON-NLS-1$ if (lineNumber == -1) { lineNumber = RpmlintParser.getRealLineNbr(specContent, "%configure"); //$NON-NLS-1$ } item.setLineNbr(lineNumber); } lineNumber = item.getLineNbr(); if (lineNumber == -1) { lineNumber = RpmlintParser.getRealLineNbr(specContent, item.getRefferedContent()); if (lineNumber == -1) { lineNumber = 1; } } lineNumber -= 1; // end workaround // BTW we mark specfile with the internal marker. parser.setErrorHandler(getSpecfileErrorHandler( currentFile, specContent)); parser.setTaskHandler(getSpecfileTaskHandler( currentFile, specContent)); parser.parse(specContent); IDocument document = new Document(specContent); int charStart = getLineOffset(document, lineNumber); int charEnd = charStart + getLineLength(document, lineNumber); RpmlintParser.addMarker(currentFile, item.getId() + ": " //$NON-NLS-1$ + item.getMessage(), lineNumber, charStart, charEnd, item.getSeverity(), item.getId(), item.getRefferedContent()); } } } else if (Activator.RPMFILE_EXTENSION.equals(resource .getFileExtension())) { firstWarningInResource = true; for (RpmlintItem item : rpmlintItems) { IFile currentFile = ((IFile) resource); if (firstWarningInResource) { RpmlintParser.deleteMarkers(resource); // remove internal marks on the current resource currentFile.deleteMarkers( SpecfileErrorHandler.SPECFILE_ERROR_MARKER_ID, false, IResource.DEPTH_ZERO); firstWarningInResource = false; } RpmlintParser.addMarker(currentFile, item.getId() + ": " //$NON-NLS-1$ + item.getMessage(), item.getSeverity(), item.getId(), item.getRefferedContent()); } } } return true; } private SpecfileErrorHandler getSpecfileErrorHandler(IFile file, String specContent) { if (errorHandler == null) { errorHandler = new SpecfileErrorHandler(file, new Document( specContent)); } else { errorHandler.setFile(file); errorHandler.setDocument(new Document(specContent)); } return errorHandler; } private SpecfileTaskHandler getSpecfileTaskHandler(IFile file, String specContent) { if (taskHandler == null) { taskHandler = new SpecfileTaskHandler(file, new Document( specContent)); } else { taskHandler.setFile(file); taskHandler.setDocument(new Document(specContent)); } return taskHandler; } private static int getLineOffset(IDocument document, int lineNumber) { try { return document.getLineOffset(lineNumber); } catch (BadLocationException e) { RpmlintLog.logError(e); return 1; } } private static int getLineLength(IDocument document, int lineNumber) { try { return document.getLineLength(lineNumber); } catch (BadLocationException e) { RpmlintLog.logError(e); return 1; } } private static String fileToString(IFile file) { String ret = ""; //$NON-NLS-1$ try (InputStream in = file.getContents()) { int nbrOfByte = in.available(); byte[] bytes = new byte[nbrOfByte]; in.read(bytes); ret = new String(bytes); } catch (CoreException | IOException e) { RpmlintLog.logError(e); } return ret; } }