Skip to content

Commit

Permalink
Wait for jobs to complete and perform up to three retries
Browse files Browse the repository at this point in the history
Currently exporting the API description sometimes fails because there
could be a race between a resource change event and disposal of the api
component.

This changes the following things:
- the API description is performed as the very first step
- if generation fails wait until all running jobs are done
- then retry up to three times
  • Loading branch information
laeubi committed Oct 8, 2023
1 parent 3e8dda1 commit 7c33f3e
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobManager;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jdt.core.IClasspathEntry;
Expand All @@ -59,6 +61,7 @@
import org.eclipse.pde.api.tools.internal.ApiDescriptionXmlCreator;
import org.eclipse.pde.api.tools.internal.problems.ApiProblemFactory;
import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
import org.eclipse.pde.api.tools.internal.provisional.IApiBaselineManager;
import org.eclipse.pde.api.tools.internal.provisional.IApiMarkerConstants;
import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent;
import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblemTypes;
Expand Down Expand Up @@ -338,7 +341,13 @@ protected void createExistingProjects(String projectsdir, boolean buildimmediate
* @param baselineLocation local file system directory to host exported
* component
*/
protected void exportApiComponent(IProject project, IApiComponent apiComponent, IPath baselineLocation) throws Exception {
protected static void exportApiComponent(IProject project, IApiComponent apiComponent, IPath baselineLocation)
throws Exception {
// create API Description, this should be the first step because
// otherwise we might trigger a resource change that maybe invalidates
// our component before we can process it!
String xml = componentToXml(apiComponent);
// now we have the xml and can go on...
File root = baselineLocation.toFile();
File componentDir = new File(root, project.getName());
componentDir.mkdirs();
Expand All @@ -358,17 +367,20 @@ protected void exportApiComponent(IProject project, IApiComponent apiComponent,
// copy over .class files
IFolder output = project.getFolder("bin"); //$NON-NLS-1$
FileUtils.copyFolder(output, componentDir);
// API Description
ApiDescriptionXmlCreator visitor = new ApiDescriptionXmlCreator(apiComponent);
apiComponent.getApiDescription().accept(visitor, null);
String xml = visitor.getXML();
// copy description
File desc = new File(componentDir, ".api_description"); //$NON-NLS-1$
desc.createNewFile();
try (FileOutputStream stream = new FileOutputStream(desc)) {
stream.write(xml.getBytes(StandardCharsets.UTF_8));
}
}

private static String componentToXml(IApiComponent apiComponent) throws CoreException {
ApiDescriptionXmlCreator visitor = new ApiDescriptionXmlCreator(apiComponent);
apiComponent.getApiDescription().accept(visitor, null);
return visitor.getXML();
}

/**
* Create the project described in record. If it is successful return true.
*
Expand Down Expand Up @@ -1209,4 +1221,34 @@ private static String toString(IMarker[] markers) throws CoreException {
}
return contents.toString();
}

protected static void exportProjects(IApiBaselineManager manager, IProject[] projects, IPath baselineLocation)
throws Exception {
for (IProject currentProject : projects) {
exportComponent(manager, baselineLocation, currentProject, 3);
}
}

private static void exportComponent(IApiBaselineManager manager, IPath baselineLocation, IProject currentProject,
int retry) throws Exception {
IApiComponent component = manager.getWorkspaceComponent(currentProject.getName());
assertNotNull("The project was not found in the workspace baseline: " + currentProject.getName(), //$NON-NLS-1$
component);
try {
exportApiComponent(currentProject, component, baselineLocation);
} catch (Exception e) {
if (retry == 0 || !component.isDisposed()) {
throw e;
}
// if the component is disposed we have the unlucky situation that
// while we try to export the component the basline was disposed, we
// can simply retry the operation here...
IJobManager jobManager = Job.getJobManager();
while (!jobManager.isIdle()) {
Thread.onSpinWait();
}

exportComponent(manager, baselineLocation, currentProject, retry - 1);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -343,11 +343,7 @@ private void setupTest(String testName) throws Exception {
// create the API baseline
IProject[] projects = getEnv().getWorkspace().getRoot().getProjects();
IPath baselineLocation = ApiTestsPlugin.getDefault().getStateLocation().append(referenceBaselineLocation);
for (IProject currentProject : projects) {
IApiComponent component = manager.getWorkspaceComponent(currentProject.getName());
assertNotNull("The project was not found in the workspace baseline: " + currentProject.getName(), component); //$NON-NLS-1$
exportApiComponent(currentProject, component, baselineLocation);
}
exportProjects(manager, projects, baselineLocation);
this.baseline = ApiModelFactory.newApiBaseline(API_BASELINE);
int length = projects.length;
IApiComponent[] components = new IApiComponent[length];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,7 @@ private void setupTest(String testName) throws Exception {
IProject[] projects = getEnv().getWorkspace().getRoot().getProjects();
int length = projects.length;
IPath baselineLocation = ApiTestsPlugin.getDefault().getStateLocation().append(referenceBaselineLocation);
for (int i = 0; i < length; i++) {
IProject currentProject = projects[i];
IApiComponent apiComponent = manager.getWorkspaceComponent(currentProject.getName());
assertNotNull("The project was not found in the workspace baseline: " + currentProject.getName(), apiComponent); //$NON-NLS-1$
exportApiComponent(currentProject, apiComponent, baselineLocation);
}
exportProjects(manager, projects, baselineLocation);
this.baseline = ApiModelFactory.newApiBaseline(API_BASELINE);
IApiComponent[] components = new IApiComponent[length];
for (int i = 0; i < length; i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,7 @@ protected void setUp() throws Exception {
// create the API baseline
projects = getEnv().getWorkspace().getRoot().getProjects();
IPath baselineLocation = ApiTestsPlugin.getDefault().getStateLocation().append(BASELINE);
IApiComponent component = null;
for (IProject project : projects) {
component = manager.getWorkspaceComponent(project.getName());
assertNotNull("The project was not found in the workspace baseline: " + project.getName(), component); //$NON-NLS-1$
exportApiComponent(project, component, baselineLocation);
}
exportProjects(manager, projects, baselineLocation);
baseline = ApiModelFactory.newApiBaseline("API-baseline"); //$NON-NLS-1$
IApiComponent[] components = new IApiComponent[projects.length];
for (int i = 0; i < projects.length; i++) {
Expand Down

0 comments on commit 7c33f3e

Please sign in to comment.