/*******************************************************************************
* 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;
}
}