1 /******************************************************************************* 2 * Copyright (c) 2008, 2012 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 package org.eclipse.pde.internal.core.exports; 15 16 import java.util.HashSet; 17 import java.util.LinkedHashMap; 18 import java.util.LinkedHashSet; 19 import java.util.Map; 20 import java.util.Set; 21 import org.eclipse.core.resources.IFile; 22 import org.eclipse.core.resources.IMarker; 23 import org.eclipse.core.resources.IProject; 24 import org.eclipse.core.resources.IResource; 25 import org.eclipse.core.resources.IncrementalProjectBuilder; 26 import org.eclipse.core.runtime.CoreException; 27 import org.eclipse.core.runtime.IPath; 28 import org.eclipse.core.runtime.IProgressMonitor; 29 import org.eclipse.core.runtime.Path; 30 import org.eclipse.debug.core.ILaunch; 31 import org.eclipse.debug.core.ILaunchConfiguration; 32 import org.eclipse.debug.core.model.LaunchConfigurationDelegate; 33 import org.eclipse.jdt.core.IClasspathEntry; 34 import org.eclipse.jdt.core.IJavaModelMarker; 35 import org.eclipse.jdt.core.IJavaProject; 36 import org.eclipse.jdt.core.JavaCore; 37 import org.eclipse.jdt.core.JavaModelException; 38 import org.eclipse.pde.core.build.IBuildEntry; 39 import org.eclipse.pde.core.build.IBuildModel; 40 import org.eclipse.pde.core.plugin.IPluginModelBase; 41 import org.eclipse.pde.internal.build.IBuildPropertiesConstants; 42 import org.eclipse.pde.internal.core.PDECore; 43 import org.eclipse.pde.internal.core.build.WorkspaceBuildModel; 44 import org.eclipse.pde.internal.core.builders.PDEMarkerFactory; 45 import org.eclipse.pde.internal.core.ifeature.IFeatureModel; 46 import org.eclipse.pde.internal.core.ifeature.IFeaturePlugin; 47 import org.eclipse.pde.internal.core.project.PDEProject; 48 49 /** 50 * Helper class for the various export operation classes, making it easier to export using workspace 51 * compiled files rather than having PDE Build compile everything on its own. Provides access to 52 * methods in debug that determine what projects need to be built before the operation as well as 53 * checking for errors. 54 * 55 * @see FeatureExportOperation 56 * @see PluginExportOperation 57 */ 58 public class WorkspaceExportHelper extends LaunchConfigurationDelegate { 59 60 private IProject[] fWorkspaceProjects; 61 62 @Override launch(ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor)63 public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor) throws CoreException { 64 // This class is not intended to be launched. 65 } 66 67 /** 68 * Builds the workspace projects that are being exported or are required plug-ins 69 * of the exported items. Uses the incremental builder. 70 * 71 * @param exportedItems The plugins or features being exported 72 * @param monitor a progress monitor or <code>null</code> if progress reporting is not desired 73 * @throws CoreException 74 */ buildBeforeExport(Object[] exportedItems, IProgressMonitor monitor)75 public void buildBeforeExport(Object[] exportedItems, IProgressMonitor monitor) throws CoreException { 76 IProject[] projects = getExportedWorkspaceProjects(exportedItems); 77 for (IProject project : projects) { 78 project.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, monitor); 79 } 80 } 81 82 /** 83 * Checks the workspace projects that are being exported or are required plug-ins 84 * of the exported items for build errors. A project will be reported as having an 85 * error if it has a marker with a severity of error and is of Java model or PDE type. 86 * 87 * @param exportedItems the plugins or features being exported 88 * @return set of IProjects containing errors 89 * @throws CoreException 90 */ checkForErrors(Object[] exportedItems)91 public Set<IProject> checkForErrors(Object[] exportedItems) throws CoreException { 92 IProject[] projects = getExportedWorkspaceProjects(exportedItems); 93 Set<IProject> projectsWithErrors = new HashSet<>(projects.length); 94 for (IProject project : projects) { 95 IMarker[] markers = project.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE); 96 if (markers.length > 0) { 97 for (IMarker marker : markers) { 98 Integer severity = (Integer) (marker.getAttribute(IMarker.SEVERITY)); 99 if (severity != null && severity.intValue() >= IMarker.SEVERITY_ERROR) { 100 if (marker.getType().equals(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER) || marker.getType().equals(PDEMarkerFactory.MARKER_ID)) { 101 projectsWithErrors.add(project); 102 break; 103 } 104 } 105 } 106 } 107 } 108 return projectsWithErrors; 109 } 110 111 /** 112 * Returns a map containing information associating libraries to the output locations the 113 * workspace compiles them to. Uses information in the build.properties and the classpath. 114 * The map will be of the following form: 115 * String symbolic name > lib output map 116 * The lib output map will be of the following form: 117 * String lib name > Set of IPath output folders 118 * 119 * @param exportedItems the plugins or features being exported 120 * @return a map of library output folders for each plugin in the workspace 121 */ getWorkspaceOutputFolders(Object[] exportedItems)122 public Map<String, Map<String, Set<IPath>>> getWorkspaceOutputFolders(Object[] exportedItems) throws CoreException { 123 IProject[] projects = getExportedWorkspaceProjects(exportedItems); 124 Map<String, Map<String, Set<IPath>>> result = new LinkedHashMap<>(projects.length); 125 for (IProject project : projects) { 126 IFile buildFile = PDEProject.getBuildProperties(project); 127 if (buildFile.exists()) { 128 IBuildModel buildModel = new WorkspaceBuildModel(buildFile); 129 buildModel.load(); 130 IJavaProject javaProject = JavaCore.create(project); 131 if (javaProject.exists()) { 132 Map<String, Set<IPath>> modelOutput = getPluginOutputFolders(buildModel, javaProject); 133 if (!modelOutput.isEmpty()) { 134 IPluginModelBase model = PDECore.getDefault().getModelManager().findModel(project); 135 if (model != null) { 136 result.put(model.getBundleDescription().getSymbolicName(), modelOutput); 137 } 138 } 139 } 140 } 141 } 142 return result; 143 } 144 getPluginOutputFolders(IBuildModel buildModel, IJavaProject javaProject)145 private Map<String, Set<IPath>> getPluginOutputFolders(IBuildModel buildModel, IJavaProject javaProject) throws JavaModelException { 146 Map<String, Set<IPath>> outputEntries = new LinkedHashMap<>(); 147 148 IBuildEntry[] buildEntries = buildModel.getBuild().getBuildEntries(); 149 for (IBuildEntry buildEntry : buildEntries) { 150 String name = buildEntry.getName(); 151 if (name.startsWith(IBuildPropertiesConstants.PROPERTY_SOURCE_PREFIX)) { 152 Set<IPath> outputPaths = new LinkedHashSet<>(); 153 154 String[] sourceFolders = buildEntry.getTokens(); 155 for (String sourceFolder : sourceFolders) { 156 157 IClasspathEntry[] classpathEntries = javaProject.getRawClasspath(); 158 for (IClasspathEntry classpathEntry : classpathEntries) { 159 if (classpathEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { 160 IPath sourcePath = classpathEntry.getPath().removeFirstSegments(1); // Entries include project as first segment 161 if (sourcePath.equals(new Path(sourceFolder))) { 162 IPath outputPath = classpathEntry.getOutputLocation(); 163 if (outputPath == null) { 164 outputPath = javaProject.getOutputLocation(); 165 } 166 outputPaths.add(outputPath.removeFirstSegments(1)); // Entries include project as first segment 167 } 168 } 169 } 170 } 171 if (!outputPaths.isEmpty()) { 172 outputEntries.put(name.substring(IBuildPropertiesConstants.PROPERTY_SOURCE_PREFIX.length()), outputPaths); 173 } 174 } 175 } 176 return outputEntries; 177 } 178 getExportedWorkspaceProjects(Object[] exportedItems)179 private IProject[] getExportedWorkspaceProjects(Object[] exportedItems) throws CoreException { 180 if (fWorkspaceProjects == null) { 181 // TODO This won't work for nested features either 182 Set<IProject> projects = new HashSet<>(); 183 for (Object exportedItem : exportedItems) { 184 if (exportedItem instanceof IPluginModelBase) { 185 IPath installLocation = new Path(((IPluginModelBase) exportedItem).getInstallLocation()); 186 IProject project = PDECore.getWorkspace().getRoot().getProject(installLocation.lastSegment()); 187 if (project.exists()) { 188 projects.add(project); 189 } 190 } else if (exportedItem instanceof IFeatureModel) { 191 IFeatureModel feature = (IFeatureModel) exportedItem; 192 IFeaturePlugin[] plugins = feature.getFeature().getPlugins(); 193 for (IFeaturePlugin plugin : plugins) { 194 IPluginModelBase model = PDECore.getDefault().getModelManager().findModel(plugin.getId()); 195 if (model != null) { 196 IPath installLocation = new Path(model.getInstallLocation()); 197 IProject project = PDECore.getWorkspace().getRoot().getProject(installLocation.lastSegment()); 198 if (project.exists()) { 199 projects.add(project); 200 } 201 } 202 } 203 204 } 205 } 206 fWorkspaceProjects = computeReferencedBuildOrder(projects.toArray(new IProject[projects.size()])); 207 } 208 return fWorkspaceProjects; 209 } 210 211 } 212