| /******************************************************************************* |
| * Copyright (c) 2009, 2020 STMicroelectronics and others. |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Xavier Raynaud <xavier.raynaud@st.com> - initial API and implementation |
| * Red Hat Inc. - ongoing maintenance |
| *******************************************************************************/ |
| package org.eclipse.linuxtools.internal.gcov.action; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| |
| import org.eclipse.cdt.core.model.CModelException; |
| import org.eclipse.cdt.core.model.CoreModel; |
| import org.eclipse.cdt.core.model.IBinary; |
| import org.eclipse.cdt.core.model.ICProject; |
| import org.eclipse.core.resources.IContainer; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.jface.dialogs.IDialogSettings; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.jface.window.Window; |
| import org.eclipse.linuxtools.binutils.utils.STSymbolManager; |
| import org.eclipse.linuxtools.internal.gcov.dialog.OpenGCDialog; |
| import org.eclipse.linuxtools.internal.gcov.view.CovView; |
| import org.eclipse.linuxtools.internal.gcov.view.annotatedsource.GcovAnnotationModelTracker; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.ui.IEditorLauncher; |
| import org.eclipse.ui.PlatformUI; |
| import org.osgi.framework.FrameworkUtil; |
| |
| /** |
| * Action performed when user clicks on a gcda/gcno file |
| * @author Xavier Raynaud <xavier.raynaud@st.com> |
| */ |
| public class OpenGCAction implements IEditorLauncher { |
| |
| private class GCFilePair { |
| final File gcda, gcno; |
| |
| private GCFilePair(IPath file) { |
| String extension = file.getFileExtension(); |
| if ("gcno".equals(extension)) { //$NON-NLS-1$ |
| gcda = file.removeFileExtension().addFileExtension("gcda").toFile(); //$NON-NLS-1$ |
| gcno = file.toFile(); |
| } else if ("gcda".equals(extension)) { //$NON-NLS-1$ |
| gcda = file.toFile(); |
| gcno = file.removeFileExtension().addFileExtension("gcno").toFile(); //$NON-NLS-1$ |
| } else { |
| gcda = null; |
| gcno = null; |
| } |
| } |
| } |
| |
| /** |
| * Helper method to programmatically show coverage for a given file. |
| * @param file The path of the file to view coverage of. |
| * @param binaryPath The absolute path of the binary that produced coverage. If invalid, |
| * a default binary will be used. |
| * @param isCompleteCoverageResultWanted Whether or not to return complete coverage. |
| */ |
| public void autoOpen(final IPath file, final String binaryPath, final boolean isCompleteCoverageResultWanted) { |
| final GCFilePair pair = new GCFilePair(file); |
| if (isFileValid(pair.gcda) && isFileValid(pair.gcno)) { |
| final String safeBinaryPath; |
| if (STSymbolManager.sharedInstance.getBinaryObject(binaryPath) == null) { |
| safeBinaryPath = getDefaultBinary(file); |
| } else { |
| safeBinaryPath = binaryPath; |
| } |
| displayCoverage(file, safeBinaryPath, pair.gcda, isCompleteCoverageResultWanted); |
| } |
| } |
| |
| private boolean exists(String binaryFile) { |
| File f = new File(binaryFile); |
| return f.isFile(); |
| } |
| |
| @Override |
| public void open(IPath file) { |
| final GCFilePair pair = new GCFilePair(file); |
| Shell shell = PlatformUI.getWorkbench().getDisplay().getActiveShell(); |
| if (!isFileValid(pair.gcda)) { |
| String msg = NLS.bind(Messages.OpenGCAction_file_dne_run, pair.gcda); |
| MessageDialog.openError(shell, Messages.OpenGCAction_gcov_error, msg); |
| return; |
| } |
| if (!isFileValid(pair.gcno)) { |
| String msg = NLS.bind(Messages.OpenGCAction_file_dne_compile, pair.gcno); |
| MessageDialog.openError(shell, Messages.OpenGCAction_gcov_error, msg); |
| return; |
| } |
| |
| IDialogSettings ds = PlatformUI.getDialogSettingsProvider(FrameworkUtil.getBundle(OpenGCAction.class)) |
| .getDialogSettings(); |
| IDialogSettings defaultMapping = ds.getSection(OpenGCDialog.class.getName()); |
| if (defaultMapping == null) { |
| defaultMapping = ds.addNewSection(OpenGCDialog.class.getName()); |
| } |
| String defaultBinary = defaultMapping.get(file.toOSString()); |
| if (defaultBinary == null || defaultBinary.isEmpty() || !exists(defaultBinary)) { |
| //FIXME EK-LINUXTOOLS: defaultBinary = getDefaultBinary(file); |
| IResource bin_resource = STSymbolManager.sharedInstance.findOneAndOnlyBinary(file); |
| if (bin_resource != null) { |
| defaultBinary = bin_resource.getLocation().toOSString(); |
| } else { |
| defaultBinary = ""; //$NON-NLS-1$ |
| } |
| } |
| |
| OpenGCDialog d = new OpenGCDialog(shell, defaultBinary, file); |
| if (d.open() != Window.OK) { |
| return; |
| } |
| // start a thread so we can return control from UI thread until needed |
| Thread t = new Thread(() -> { |
| displayCoverage(file, d.getBinaryFile(), pair.gcda, d.isCompleteCoverageResultWanted()); |
| }); |
| t.start(); |
| } |
| |
| private void displayCoverage(IPath file, String binaryPath, File gcda, boolean isCompleteCoverageResultWanted) |
| { |
| //FIXME EK-LINUXTOOLS: IProject project = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(file).getProject(); |
| IProject project = STSymbolManager.sharedInstance.getProjectFromFile(file); |
| //FIXME EK-LINUXTOOLS: Need check for null and correct action |
| |
| GcovAnnotationModelTracker.getInstance().addProject(project, new Path(binaryPath)); |
| PlatformUI.getWorkbench().getDisplay().syncExec(() -> { |
| GcovAnnotationModelTracker.getInstance().annotateAllCEditors(); |
| }); |
| |
| if (isCompleteCoverageResultWanted) { |
| CovView.displayCovResults(binaryPath, gcda.getAbsolutePath()); |
| } else { |
| CovView.displayCovDetailedResult(binaryPath, gcda.getAbsolutePath()); |
| } |
| } |
| |
| private String getDefaultBinaryFromUserPref(IProject project, IFile infoFile) throws IOException, CoreException { |
| if (infoFile.exists()) { |
| try (BufferedReader br = new BufferedReader(new InputStreamReader(infoFile.getContents(true)))) { |
| String line; |
| while ((line = br.readLine())!= null){ |
| String[] tab = line.split("="); //$NON-NLS-1$ |
| if (tab.length > 1){ |
| String name = tab[0].trim(); |
| if (name.equals("Program Name")){ //$NON-NLS-1$ |
| String value = tab[1].trim(); |
| IPath p = new Path(value); |
| if (p.isAbsolute()) { |
| if (p.toFile().isFile()) { |
| return p.toOSString(); |
| } |
| } else if (project != null){ |
| IFile ifile = project.getFile(value); |
| if (ifile.exists()) { |
| return ifile.getLocation().toOSString(); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| private String getDefaultBinary(IPath file) { |
| //FIXME EK-LINUXTOOLS: IFile c = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(file); |
| IFile c = STSymbolManager.sharedInstance.findFileFromPath(file); |
| if (c != null) { |
| IProject project = c.getProject(); |
| if (project != null && project.exists()) { |
| IContainer folder = c.getParent(); |
| IFile infoFile = folder.getFile(new Path("AnalysisInfo.txt")); //$NON-NLS-1$ |
| try { |
| String defaultBinaryFromUserPref = getDefaultBinaryFromUserPref(project, infoFile); |
| if (defaultBinaryFromUserPref != null) { |
| return defaultBinaryFromUserPref; |
| } |
| } catch (IOException|CoreException ex) { |
| // do nothing here. |
| } |
| ICProject cproject = CoreModel.getDefault().create(project); |
| if (cproject != null) { |
| try { |
| IBinary[] b = cproject.getBinaryContainer().getBinaries(); |
| if (b != null && b.length > 0 && b[0] != null) { |
| IResource r = b[0].getResource(); |
| return r.getLocation().toOSString(); |
| } |
| } catch (CModelException e) { |
| } |
| } |
| } |
| } |
| return ""; //$NON-NLS-1$ |
| } |
| |
| private boolean isFileValid(File file) { |
| return file != null && file.isFile() && file.exists(); |
| } |
| } |