### Eclipse Workspace Patch 1.0 #P org.eclipse.pde.ui Index: src/org/eclipse/pde/internal/ui/wizards/exports/PluginExportWizard.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/wizards/exports/PluginExportWizard.java,v retrieving revision 1.55 diff -u -r1.55 PluginExportWizard.java --- src/org/eclipse/pde/internal/ui/wizards/exports/PluginExportWizard.java 24 Nov 2008 16:52:13 -0000 1.55 +++ src/org/eclipse/pde/internal/ui/wizards/exports/PluginExportWizard.java 3 Dec 2008 22:32:22 -0000 @@ -46,6 +46,7 @@ info.useJarFormat = fPage.useJARFormat(); info.exportSource = fPage.doExportSource(); info.allowBinaryCycles = fPage.allowBinaryCycles(); + info.useWorkspaceCompiledClasses = fPage.useWorkspaceCompiledClasses(); info.destinationDirectory = fPage.getDestination(); info.zipFileName = fPage.getFileName(); info.items = fPage.getSelectedItems(); Index: src/org/eclipse/pde/internal/ui/wizards/exports/BaseExportWizardPage.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/wizards/exports/BaseExportWizardPage.java,v retrieving revision 1.77 diff -u -r1.77 BaseExportWizardPage.java --- src/org/eclipse/pde/internal/ui/wizards/exports/BaseExportWizardPage.java 3 Dec 2008 18:33:32 -0000 1.77 +++ src/org/eclipse/pde/internal/ui/wizards/exports/BaseExportWizardPage.java 3 Dec 2008 22:32:22 -0000 @@ -287,6 +287,10 @@ return fOptionsTab.doBinaryCycles(); } + protected boolean useWorkspaceCompiledClasses() { + return fOptionsTab.useWorkspaceCompiledClasses(); + } + protected boolean doGenerateAntFile() { return fOptionsTab.doGenerateAntFile(); } Index: src/org/eclipse/pde/internal/ui/wizards/exports/ExportOptionsTab.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/wizards/exports/ExportOptionsTab.java,v retrieving revision 1.12 diff -u -r1.12 ExportOptionsTab.java --- src/org/eclipse/pde/internal/ui/wizards/exports/ExportOptionsTab.java 26 Oct 2008 18:24:02 -0000 1.12 +++ src/org/eclipse/pde/internal/ui/wizards/exports/ExportOptionsTab.java 3 Dec 2008 22:32:22 -0000 @@ -31,6 +31,7 @@ private static final String S_QUALIFIER = "qualifier"; //$NON-NLS-1$ private static final String S_QUALIFIER_NAME = "qualifierName"; //$NON-NLS-1$ private static final String S_ALLOW_BINARY_CYCLES = "allowBinaryCycles"; //$NON-NLS-1$ + private static final String S_USE_WORKSPACE_COMPILED_CLASSES = "useWorkspaceCompiledClasses"; //$NON-NLS-1$ private Button fIncludeSource; protected Button fJarButton; @@ -40,6 +41,7 @@ private Button fQualifierButton; private Text fQualifierText; private Button fAllowBinaryCycles; + private Button fUseWSCompiledClasses; public ExportOptionsTab(BaseExportWizardPage page) { super(page); @@ -56,6 +58,7 @@ addQualifierOption(container); addAntSection(container); addAllowBinaryCyclesSection(container); + addUseWorkspaceCompiledClassesSection(container); return container; } @@ -79,6 +82,11 @@ fAllowBinaryCycles.setText(PDEUIMessages.ExportOptionsTab_allowBinaryCycles); } + protected void addUseWorkspaceCompiledClassesSection(Composite comp) { + fUseWSCompiledClasses = new Button(comp, SWT.CHECK); + fUseWSCompiledClasses.setText("Use class files compiled in the workspace"); + } + protected String getJarButtonText() { return PDEUIMessages.BaseExportWizardPage_packageJARs; } @@ -143,6 +151,7 @@ fQualifierText.setText(getInitialQualifierText(settings)); fQualifierText.setEnabled(fQualifierButton.getSelection()); fAllowBinaryCycles.setSelection(getInitialAllowBinaryCyclesSelection(settings)); + fUseWSCompiledClasses.setSelection(getInitialUseWorkspaceCompiledClassesSelection(settings)); hookListeners(); } @@ -153,6 +162,7 @@ settings.put(S_QUALIFIER, fQualifierButton.getSelection()); settings.put(S_QUALIFIER_NAME, fQualifierText.getText()); settings.put(S_ALLOW_BINARY_CYCLES, fAllowBinaryCycles.getSelection()); + settings.put(S_USE_WORKSPACE_COMPILED_CLASSES, fUseWSCompiledClasses.getSelection()); saveCombo(settings, S_ANT_FILENAME, fAntCombo); } @@ -165,12 +175,17 @@ protected boolean getInitialJarButtonSelection(IDialogSettings settings) { String selected = settings.get(S_JAR_FORMAT); - return selected == null ? TargetPlatformHelper.getTargetVersion() >= 3.1 : "true".equals(selected); //$NON-NLS-1$ + return selected == null ? TargetPlatformHelper.getTargetVersion() >= 3.1 : Boolean.valueOf(selected).booleanValue(); } protected boolean getInitialAllowBinaryCyclesSelection(IDialogSettings settings) { String selected = settings.get(S_ALLOW_BINARY_CYCLES); - return selected == null ? true : "true".equals(selected); //$NON-NLS-1$ + return selected == null ? true : Boolean.valueOf(selected).booleanValue(); + } + + protected boolean getInitialUseWorkspaceCompiledClassesSelection(IDialogSettings settings) { + String selected = settings.get(S_USE_WORKSPACE_COMPILED_CLASSES); + return selected == null ? false : Boolean.valueOf(selected).booleanValue(); } protected void hookListeners() { @@ -233,6 +248,10 @@ return fAllowBinaryCycles.getSelection(); } + protected boolean useWorkspaceCompiledClasses() { + return fUseWSCompiledClasses.getSelection(); + } + protected boolean useJARFormat() { return fJarButton.getSelection(); } Index: src/org/eclipse/pde/internal/ui/wizards/exports/FeatureExportWizard.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/wizards/exports/FeatureExportWizard.java,v retrieving revision 1.62 diff -u -r1.62 FeatureExportWizard.java --- src/org/eclipse/pde/internal/ui/wizards/exports/FeatureExportWizard.java 24 Nov 2008 16:52:13 -0000 1.62 +++ src/org/eclipse/pde/internal/ui/wizards/exports/FeatureExportWizard.java 3 Dec 2008 22:32:22 -0000 @@ -63,6 +63,7 @@ info.useJarFormat = fPage.useJARFormat(); info.exportSource = fPage.doExportSource(); info.allowBinaryCycles = fPage.allowBinaryCycles(); + info.useWorkspaceCompiledClasses = fPage.useWorkspaceCompiledClasses(); info.destinationDirectory = fPage.getDestination(); info.zipFileName = fPage.getFileName(); if (fPage2 != null && ((FeatureExportWizardPage) fPage).doMultiPlatform()) #P org.eclipse.pde.ui.tests Index: src/org/eclipse/pde/ui/tests/ee/ExportBundleTests.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/ee/ExportBundleTests.java,v retrieving revision 1.3 diff -u -r1.3 ExportBundleTests.java --- src/org/eclipse/pde/ui/tests/ee/ExportBundleTests.java 24 Nov 2008 16:52:10 -0000 1.3 +++ src/org/eclipse/pde/ui/tests/ee/ExportBundleTests.java 3 Dec 2008 22:32:23 -0000 @@ -80,6 +80,7 @@ info.useJarFormat = true; info.exportSource = false; info.allowBinaryCycles = false; + info.useWorkspaceCompiledClasses = false; info.destinationDirectory = EXPORT_PATH.toOSString(); info.zipFileName = null; info.items = new Object[]{PluginRegistry.findModel(project.getProject())}; @@ -121,6 +122,7 @@ info.useJarFormat = true; info.exportSource = false; info.allowBinaryCycles = false; + info.useWorkspaceCompiledClasses = false; info.destinationDirectory = EXPORT_PATH.toOSString(); info.zipFileName = null; info.items = new Object[]{PluginRegistry.findModel(project.getProject())}; #P org.eclipse.pde.core Index: src/org/eclipse/pde/internal/core/exports/FeatureExportOperation.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/exports/FeatureExportOperation.java,v retrieving revision 1.19 diff -u -r1.19 FeatureExportOperation.java --- src/org/eclipse/pde/internal/core/exports/FeatureExportOperation.java 24 Nov 2008 16:52:09 -0000 1.19 +++ src/org/eclipse/pde/internal/core/exports/FeatureExportOperation.java 3 Dec 2008 22:32:25 -0000 @@ -17,10 +17,10 @@ import java.util.*; import javax.xml.parsers.*; import org.eclipse.ant.core.*; -import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.*; import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.jdt.launching.environments.IExecutionEnvironment; import org.eclipse.jdt.launching.environments.IExecutionEnvironmentsManager; @@ -33,6 +33,7 @@ import org.eclipse.pde.internal.build.site.QualifierReplacer; import org.eclipse.pde.internal.core.*; import org.eclipse.pde.internal.core.build.WorkspaceBuildModel; +import org.eclipse.pde.internal.core.builders.PDEMarkerFactory; import org.eclipse.pde.internal.core.feature.FeatureChild; import org.eclipse.pde.internal.core.ifeature.*; import org.eclipse.pde.internal.core.util.CoreUtility; @@ -47,6 +48,7 @@ private String fDevProperties; private static boolean fHasErrors; protected HashMap fAntBuildProperties; + protected IProject[] fWorkspaceProjects; protected State fStateCopy; @@ -76,7 +78,9 @@ if (configurations == null) configurations = new String[][] {null}; - monitor.beginTask("", configurations.length * fInfo.items.length * 11); //$NON-NLS-1$ + monitor.beginTask("", (configurations.length * fInfo.items.length * 11) + 1); //$NON-NLS-1$ + testBuildWorkspaceBeforeExport(new SubProgressMonitor(monitor, 1)); + // TODO Proper progress for the build! for (int i = 0; i < configurations.length; i++) { for (int j = 0; j < fInfo.items.length; j++) { if (monitor.isCanceled()) @@ -95,6 +99,8 @@ } } catch (InvocationTargetException e) { return new Status(IStatus.ERROR, PDECore.PLUGIN_ID, PDECoreMessages.FeatureBasedExportOperation_ProblemDuringExport, e.getCause() != null ? e.getCause() : e); + } catch (CoreException e) { + return new Status(IStatus.ERROR, PDECore.PLUGIN_ID, PDECoreMessages.FeatureBasedExportOperation_ProblemDuringExport, e.getCause() != null ? e.getCause() : e); } finally { monitor.done(); } @@ -205,8 +211,9 @@ protected void doExport(String featureID, String version, String featureLocation, String os, String ws, String arch, IProgressMonitor monitor) throws CoreException, InvocationTargetException { fHasErrors = false; - monitor.beginTask("", 9); //$NON-NLS-1$ + monitor.beginTask("", 10); //$NON-NLS-1$ monitor.setTaskName(PDECoreMessages.FeatureExportJob_taskName); + try { HashMap properties = createAntBuildProperties(os, ws, arch); BuildScriptGenerator generator = new BuildScriptGenerator(); @@ -505,7 +512,14 @@ generator.setArchivesFormat(format); generator.setPDEState(getState(os, ws, arch)); generator.setNextId(TargetPlatformHelper.getPDEState().getNextId()); - generator.setStateExtraData(TargetPlatformHelper.getBundleClasspaths(TargetPlatformHelper.getPDEState()), TargetPlatformHelper.getPatchMap(TargetPlatformHelper.getPDEState())); + + if (fInfo.useWorkspaceCompiledClasses) { + generator.setUseWorkspaceBinaries(true); + generator.setStateExtraData(TargetPlatformHelper.getBundleClasspaths(TargetPlatformHelper.getPDEState()), TargetPlatformHelper.getPatchMap(TargetPlatformHelper.getPDEState()), getWorkspacePluginOutputFolders()); + } else { + generator.setStateExtraData(TargetPlatformHelper.getBundleClasspaths(TargetPlatformHelper.getPDEState()), TargetPlatformHelper.getPatchMap(TargetPlatformHelper.getPDEState())); + } + AbstractScriptGenerator.setForceUpdateJar(false); AbstractScriptGenerator.setEmbeddedSource(fInfo.exportSource); @@ -732,4 +746,218 @@ } return false; } + + protected void testBuildWorkspaceBeforeExport(IProgressMonitor monitor) throws CoreException { + try { + monitor.beginTask("Compiling classes in workspace before export", 1); + if (fInfo.useWorkspaceCompiledClasses) { + IProject[] projects = getExportedWorkspaceProjects(); + for (int i = 0; i < projects.length; i++) { + projects[i].build(IncrementalProjectBuilder.INCREMENTAL_BUILD, monitor); + } + + List errors = new ArrayList(); + for (int i = 0; i < projects.length; i++) { + IMarker[] markers = projects[i].findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE); + if (markers.length > 0) { + for (int j = 0; j < markers.length; j++) { + Integer severity = (Integer) (markers[j].getAttribute(IMarker.SEVERITY)); + if (severity != null && severity.intValue() >= IMarker.SEVERITY_ERROR) { + if (markers[j].getType().equals(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER) || markers[j].getType().equals(PDEMarkerFactory.MARKER_ID)) { + errors.add(projects[i]); + } + } + } + } + } + + if (!errors.isEmpty()) { + // TODO Inform user of errors? + PDECore.log(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, "Build problems present in projects being exported.")); + } + } + } finally { + monitor.done(); + } + } + + /** + * Returns an array of projects in their suggested build order + * containing all of the projects specified by baseProjects + * and all of their referenced projects. + * + * @param baseProjects a collection of projects + * @return an array of projects in their suggested build order + * containing all of the projects specified by baseProjects + * @throws CoreException if an error occurs while computing referenced + * projects + */ + protected IProject[] computeReferencedBuildOrder(IProject[] baseProjects) throws CoreException { + HashSet unorderedProjects = new HashSet(); + for (int i = 0; i < baseProjects.length; i++) { + unorderedProjects.add(baseProjects[i]); + addReferencedProjects(baseProjects[i], unorderedProjects); + } + IProject[] projectSet = (IProject[]) unorderedProjects.toArray(new IProject[unorderedProjects.size()]); + return computeBuildOrder(projectSet); + } + + /** + * Adds all projects referenced by project to the given + * set. + * + * @param project project + * @param references set to which referenced projects are added + * @throws CoreException if an error occurs while computing referenced + * projects + */ + protected void addReferencedProjects(IProject project, Set references) throws CoreException { + if (project.isOpen()) { + IProject[] projects = project.getReferencedProjects(); + for (int i = 0; i < projects.length; i++) { + IProject refProject = projects[i]; + if (refProject.exists() && !references.contains(refProject)) { + references.add(refProject); + addReferencedProjects(refProject, references); + } + } + } + } + + /** + * Returns a list of projects in their suggested build order from the + * given unordered list of projects. + * + * @param projects the list of projects to sort into build order + * @return a new array containing all projects from projects sorted + * according to their build order. + */ + private IProject[] computeBuildOrder(IProject[] projects) { + String[] orderedNames = ResourcesPlugin.getWorkspace().getDescription().getBuildOrder(); + if (orderedNames != null) { + List orderedProjects = new ArrayList(projects.length); + //Projects may not be in the build order but should be built if selected + List unorderedProjects = new ArrayList(projects.length); + for (int i = 0; i < projects.length; ++i) { + unorderedProjects.add(projects[i]); + } + + for (int i = 0; i < orderedNames.length; i++) { + String projectName = orderedNames[i]; + for (Iterator iterator = unorderedProjects.iterator(); iterator.hasNext();) { + IProject project = (IProject) iterator.next(); + if (project.getName().equals(projectName)) { + orderedProjects.add(project); + iterator.remove(); + break; + } + } + } + //Add anything not specified before we return + orderedProjects.addAll(unorderedProjects); + return (IProject[]) orderedProjects.toArray(new IProject[orderedProjects.size()]); + } + + // Computing build order returned null, try the project prerequisite order + IWorkspace.ProjectOrder po = ResourcesPlugin.getWorkspace().computeProjectOrder(projects); + return po.projects; + } + + /** + * Returns a map containing information associating libraries to the output locations the + * workspace compiles them to. Uses information in the build.properties and the classpath. + * The map will be of the following form: + * String symbolic name > lib output map + * The lib output map will be of the following form: + * String lib name > Set of IPath output folders + * + * @return a map of library output folders for each plugin in the workspace + */ + protected Map getWorkspacePluginOutputFolders() throws CoreException { + IProject[] projects = getExportedWorkspaceProjects(); + Map result = new HashMap(projects.length); + for (int i = 0; i < projects.length; i++) { + IFile buildFile = projects[i].getFile("build.properties"); //$NON-NLS-1$ + if (buildFile.exists()) { + IBuildModel buildModel = new WorkspaceBuildModel(buildFile); + buildModel.load(); + IJavaProject javaProject = JavaCore.create(projects[i]); + if (javaProject.exists()) { + Map modelOutput = getPluginOutputFolders(buildModel, javaProject); + if (!modelOutput.isEmpty()) { + IPluginModelBase model = PDECore.getDefault().getModelManager().findModel(projects[i]); + if (model != null) { + result.put(model.getBundleDescription().getSymbolicName(), modelOutput); + } + } + } + } + } + return result; + } + + private Map getPluginOutputFolders(IBuildModel buildModel, IJavaProject javaProject) throws JavaModelException { + Map outputEntries = new HashMap(); + + IBuildEntry[] buildEntries = buildModel.getBuild().getBuildEntries(); + for (int i = 0; i < buildEntries.length; i++) { + String name = buildEntries[i].getName(); + if (name.startsWith(IBuildPropertiesConstants.PROPERTY_SOURCE_PREFIX)) { + Set outputPaths = new HashSet(); + + String[] sourceFolders = buildEntries[i].getTokens(); + for (int j = 0; j < sourceFolders.length; j++) { + + IClasspathEntry[] classpathEntries = javaProject.getRawClasspath(); + for (int k = 0; k < classpathEntries.length; k++) { + if (classpathEntries[k].getEntryKind() == IClasspathEntry.CPE_SOURCE) { + IPath sourcePath = classpathEntries[k].getPath().removeFirstSegments(1); // Entries include project as first segment + if (sourcePath.equals(new Path(sourceFolders[j]))) { + IPath outputPath = classpathEntries[k].getOutputLocation(); + if (outputPath == null) { + outputPath = javaProject.getOutputLocation(); + } + outputPaths.add(outputPath.removeFirstSegments(1)); // Entries include project as first segment + } + } + } + } + if (!outputPaths.isEmpty()) { + outputEntries.put(name.substring(IBuildPropertiesConstants.PROPERTY_SOURCE_PREFIX.length()), outputPaths); + } + } + } + return outputEntries; + } + + protected IProject[] getExportedWorkspaceProjects() throws CoreException { + if (fWorkspaceProjects == null) { + // TODO This won't work for nested features either + Set projects = new HashSet(); + for (int i = 0; i < fInfo.items.length; i++) { + if (fInfo.items[i] instanceof IPluginModelBase) { + IPath installLocation = new Path(((IPluginModelBase) fInfo.items[i]).getInstallLocation()); + IProject project = PDECore.getWorkspace().getRoot().getProject(installLocation.lastSegment()); + if (project.exists()) { + projects.add(project); + } + } else if (fInfo.items[i] instanceof IFeatureModel) { + IFeatureModel feature = (IFeatureModel) fInfo.items[i]; + IFeaturePlugin[] plugins = feature.getFeature().getPlugins(); + for (int j = 0; j < plugins.length; j++) { + IPluginModelBase plugin = PDECore.getDefault().getModelManager().findModel(plugins[i].getId()); + IPath installLocation = new Path(plugin.getInstallLocation()); + IProject project = PDECore.getWorkspace().getRoot().getProject(installLocation.lastSegment()); + if (project.exists()) { + projects.add(project); + } + } + + } + } + fWorkspaceProjects = computeReferencedBuildOrder((IProject[]) projects.toArray(new IProject[projects.size()])); + } + return fWorkspaceProjects; + } + } Index: src/org/eclipse/pde/internal/core/exports/FeatureBasedExportOperation.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/exports/FeatureBasedExportOperation.java,v retrieving revision 1.7 diff -u -r1.7 FeatureBasedExportOperation.java --- src/org/eclipse/pde/internal/core/exports/FeatureBasedExportOperation.java 24 Nov 2008 16:52:09 -0000 1.7 +++ src/org/eclipse/pde/internal/core/exports/FeatureBasedExportOperation.java 3 Dec 2008 22:32:25 -0000 @@ -33,7 +33,7 @@ protected IStatus run(IProgressMonitor monitor) { try { createDestination(); - monitor.beginTask("", 10); //$NON-NLS-1$ + monitor.beginTask("", 11); //$NON-NLS-1$ // create a feature to contain all plug-ins String featureID = "org.eclipse.pde.container.feature"; //$NON-NLS-1$ fFeatureLocation = fBuildTempLocation + File.separator + featureID; @@ -42,6 +42,7 @@ createBuildPropertiesFile(fFeatureLocation); if (fInfo.useJarFormat) createPostProcessingFiles(); + testBuildWorkspaceBeforeExport(new SubProgressMonitor(monitor, 1)); doExport(featureID, null, fFeatureLocation, TargetPlatform.getOS(), TargetPlatform.getWS(), TargetPlatform.getOSArch(), new SubProgressMonitor(monitor, 7)); if (monitor.isCanceled()) { return Status.CANCEL_STATUS; Index: src/org/eclipse/pde/internal/core/exports/FeatureExportInfo.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/exports/FeatureExportInfo.java,v retrieving revision 1.6 diff -u -r1.6 FeatureExportInfo.java --- src/org/eclipse/pde/internal/core/exports/FeatureExportInfo.java 26 Oct 2008 18:20:32 -0000 1.6 +++ src/org/eclipse/pde/internal/core/exports/FeatureExportInfo.java 3 Dec 2008 22:32:25 -0000 @@ -17,6 +17,7 @@ public boolean exportSource; public boolean exportMetadata; public boolean allowBinaryCycles; + public boolean useWorkspaceCompiledClasses; public String destinationDirectory; public String zipFileName; public String qualifier;