Skip to content

Commit 4a2e6d5

Browse files
committed
Restore natures and buildspec for project descriptions
Currently a private project description does not store natures and builder, but these are mostly important these days. This now also stores natures and builder specs.
1 parent d4985f2 commit 4a2e6d5

File tree

7 files changed

+198
-32
lines changed

7 files changed

+198
-32
lines changed

resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/BuildManager.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -411,9 +411,10 @@ private void basicBuild(final IBuildConfiguration buildConfiguration, final int
411411
try {
412412
final IProject project = buildConfiguration.getProject();
413413
final ICommand[] commands;
414-
if (project.isAccessible())
415-
commands = ((Project) project).internalGetDescription().getBuildSpec(false);
416-
else
414+
if (project.isAccessible()) {
415+
ProjectDescription description = ((Project) project).internalGetDescription();
416+
commands = description == null ? null : description.getBuildSpec(false);
417+
} else
417418
commands = null;
418419
int work = commands == null ? 0 : commands.length;
419420
monitor.beginTask(NLS.bind(Messages.events_building_1, project.getFullPath()), work);
@@ -708,6 +709,9 @@ public ArrayList<BuilderPersistentInfo> createBuildersPersistentInfo(IProject pr
708709
ArrayList<BuilderPersistentInfo> oldInfos = getBuildersPersistentInfo(project);
709710

710711
ProjectDescription desc = ((Project) project).internalGetDescription();
712+
if (desc == null) {
713+
return null;
714+
}
711715
ICommand[] commands = desc.getBuildSpec(false);
712716
if (commands.length == 0)
713717
return null;
@@ -1577,7 +1581,8 @@ public ISchedulingRule getRule(IBuildConfiguration buildConfiguration, int trigg
15771581
final ICommand[] commands;
15781582
if (project.isAccessible()) {
15791583
Set<ISchedulingRule> rules = new HashSet<>();
1580-
commands = ((Project) project).internalGetDescription().getBuildSpec(false);
1584+
ProjectDescription description = ((Project) project).internalGetDescription();
1585+
commands = description == null ? new ICommand[0] : description.getBuildSpec(false);
15811586
boolean hasNullBuildRule = false;
15821587
BuildContext context = new BuildContext(buildConfiguration);
15831588
for (int i = 0; i < commands.length; i++) {

resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/LocalMetaArea.java

Lines changed: 97 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,17 @@
2424
import java.io.IOException;
2525
import java.net.URI;
2626
import java.util.HashMap;
27+
import java.util.LinkedHashMap;
2728
import java.util.Map;
29+
import java.util.Map.Entry;
2830
import org.eclipse.core.filesystem.URIUtil;
31+
import org.eclipse.core.internal.events.BuildCommand;
2932
import org.eclipse.core.internal.localstore.SafeChunkyInputStream;
3033
import org.eclipse.core.internal.localstore.SafeChunkyOutputStream;
3134
import org.eclipse.core.internal.utils.Messages;
3235
import org.eclipse.core.internal.utils.Policy;
3336
import org.eclipse.core.resources.IBuildConfiguration;
37+
import org.eclipse.core.resources.ICommand;
3438
import org.eclipse.core.resources.IProject;
3539
import org.eclipse.core.resources.IResource;
3640
import org.eclipse.core.resources.IResourceStatus;
@@ -330,6 +334,8 @@ public ProjectDescription readOldDescription(IProject project) throws CoreExcept
330334
* location should be used. In the case of failure, log the exception and
331335
* return silently, thus reverting to using the default location and no
332336
* dynamic references. The current format of the location file is:
337+
*
338+
* <pre>
333339
* UTF - project location
334340
* int - number of dynamic project references
335341
* UTF - project reference 1
@@ -347,6 +353,19 @@ public ProjectDescription readOldDescription(IProject project) throws CoreExcept
347353
* UTF - configName if hasConfigName
348354
* ... repeat for number of referenced configurations
349355
* ... repeat for number of build configurations with references
356+
* since 3.23:
357+
* bool - private flag if project should only be read from its private project configuration
358+
* int - number of natures
359+
* UTF - nature id
360+
* ... repeated for N natures
361+
* int - number of buildspecs
362+
* byte - type of buildspec
363+
* (type 1) UTF - name of builder
364+
* int - number of arguments
365+
* UTF arg key
366+
* UTF arg value
367+
* UTF - triggers string
368+
* </pre>
350369
*/
351370
public void readPrivateDescription(IProject target, ProjectDescription description) {
352371
IPath locationFile = locationFor(target).append(F_PROJECT_LOCATION);
@@ -357,6 +376,17 @@ public void readPrivateDescription(IProject target, ProjectDescription descripti
357376
if (!file.exists())
358377
return;
359378
}
379+
try {
380+
readFromFile(target, description, file);
381+
} catch (IOException e) {
382+
//ignore - this is an old location file or an exception occurred
383+
// closing the stream
384+
}
385+
}
386+
387+
@SuppressWarnings("deprecation")
388+
public void readFromFile(IProject target, ProjectDescription description, java.io.File file) throws IOException {
389+
description.setName(target.getName());
360390
try (DataInputStream dataIn = new DataInputStream(new SafeChunkyInputStream(file, 500))) {
361391
try {
362392
String location = dataIn.readUTF();
@@ -408,9 +438,34 @@ public void readPrivateDescription(IProject target, ProjectDescription descripti
408438
m.put(configName, refs);
409439
}
410440
description.setBuildConfigReferences(m);
411-
} catch (IOException e) {
412-
//ignore - this is an old location file or an exception occurred
413-
// closing the stream
441+
// read parts since 3.23
442+
int natures = dataIn.readInt();
443+
String[] natureIds = new String[natures];
444+
for (int i = 0; i < natures; i++) {
445+
natureIds[i] = dataIn.readUTF();
446+
}
447+
description.setNatureIds(natureIds);
448+
int buildspecs = dataIn.readInt();
449+
ICommand[] buildSpecData = new ICommand[buildspecs];
450+
for (int i = 0; i < buildspecs; i++) {
451+
BuildCommand command = new BuildCommand();
452+
buildSpecData[i] = command;
453+
int type = dataIn.read();
454+
if (type == 1) {
455+
command.setName(dataIn.readUTF());
456+
int args = dataIn.readInt();
457+
Map<String, String> map = new LinkedHashMap<>();
458+
for (int j = 0; j < args; j++) {
459+
map.put(dataIn.readUTF(), dataIn.readUTF());
460+
}
461+
command.setArguments(map);
462+
String trigger = dataIn.readUTF();
463+
if (!trigger.isEmpty()) {
464+
ProjectDescriptionReader.parseBuildTriggers(command, trigger);
465+
}
466+
}
467+
}
468+
description.setBuildSpec(buildSpecData);
414469
}
415470
}
416471

@@ -426,13 +481,25 @@ public void writePrivateDescription(IProject target) throws CoreException {
426481
Workspace.clear(file);
427482
//don't write anything if there is no interesting private metadata
428483
ProjectDescription desc = ((Project) target).internalGetDescription();
484+
try {
485+
writeToFile(desc, file);
486+
} catch (IOException e) {
487+
String message = NLS.bind(Messages.resources_exSaveProjectLocation, target.getName());
488+
throw new ResourceException(IResourceStatus.INTERNAL_ERROR, null, message, e);
489+
}
490+
}
491+
492+
public void writeToFile(ProjectDescription desc, java.io.File file) throws IOException {
429493
if (desc == null)
430494
return;
431495
final URI projectLocation = desc.getLocationURI();
432496
final IProject[] prjRefs = desc.getDynamicReferences(false);
433497
final String[] buildConfigs = desc.configNames;
434498
final Map<String, IBuildConfiguration[]> configRefs = desc.getBuildConfigReferences(false);
435-
if (projectLocation == null && prjRefs.length == 0 && buildConfigs.length == 0 && configRefs.isEmpty())
499+
final String[] natureIds = desc.getNatureIds();
500+
final ICommand[] buildSpec = desc.getBuildSpec(false);
501+
if (projectLocation == null && prjRefs.length == 0 && buildConfigs.length == 0 && configRefs.isEmpty()
502+
&& natureIds.length == 0 && buildSpec.length == 0)
436503
return;
437504
//write the private metadata file
438505
try (SafeChunkyOutputStream output = new SafeChunkyOutputStream(file); DataOutputStream dataOut = new DataOutputStream(output);) {
@@ -470,10 +537,33 @@ public void writePrivateDescription(IProject target) throws CoreException {
470537
}
471538
}
472539
}
540+
// write parts since 3.23
541+
dataOut.writeInt(natureIds.length);
542+
for (String id : natureIds) {
543+
dataOut.writeUTF(id);
544+
}
545+
dataOut.writeInt(buildSpec.length);
546+
for (ICommand command : buildSpec) {
547+
if (command instanceof BuildCommand b) {
548+
dataOut.write(1);
549+
dataOut.writeUTF(b.getName());
550+
Map<String, String> arguments = b.getArguments();
551+
dataOut.writeInt(arguments.size());
552+
for (Entry<String, String> entry : arguments.entrySet()) {
553+
dataOut.writeUTF(entry.getKey());
554+
dataOut.writeUTF(entry.getValue());
555+
}
556+
if (ModelObjectWriter.shouldWriteTriggers(b)) {
557+
dataOut.writeUTF(ModelObjectWriter.triggerString(b));
558+
} else {
559+
dataOut.writeUTF(""); //$NON-NLS-1$
560+
}
561+
} else {
562+
dataOut.write(0);
563+
}
564+
}
565+
dataOut.flush();
473566
output.succeed();
474-
} catch (IOException e) {
475-
String message = NLS.bind(Messages.resources_exSaveProjectLocation, target.getName());
476-
throw new ResourceException(IResourceStatus.INTERNAL_ERROR, null, message, e);
477567
}
478568
}
479569
}

resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/ModelObjectWriter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public class ModelObjectWriter implements IModelObjectConstants {
4444
* Returns the string representing the serialized set of build triggers for
4545
* the given command
4646
*/
47-
private static String triggerString(BuildCommand command) {
47+
static String triggerString(BuildCommand command) {
4848
StringBuilder buf = new StringBuilder();
4949
if (command.isBuilding(IncrementalProjectBuilder.AUTO_BUILD))
5050
buf.append(TRIGGER_AUTO).append(',');
@@ -83,7 +83,7 @@ protected void write(BuildCommand command, XMLWriter writer) {
8383
/**
8484
* Returns whether the build triggers for this command should be written.
8585
*/
86-
private boolean shouldWriteTriggers(BuildCommand command) {
86+
static boolean shouldWriteTriggers(BuildCommand command) {
8787
//only write triggers if command is configurable and there exists a trigger
8888
//that the builder does NOT respond to. I.e., don't write out on the default
8989
//cases to avoid dirtying .project files unnecessarily.

resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Project.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -787,7 +787,11 @@ protected void internalCopyProjectOnly(IResource destination, IProjectDescriptio
787787
* @see #getActiveBuildConfig()
788788
*/
789789
IBuildConfiguration internalGetActiveBuildConfig() {
790-
String configName = internalGetDescription().activeConfiguration;
790+
ProjectDescription description = internalGetDescription();
791+
if (description == null) {
792+
return new BuildConfiguration(this, IBuildConfiguration.DEFAULT_CONFIG_NAME);
793+
}
794+
String configName = description.activeConfiguration;
791795
try {
792796
if (configName != null)
793797
return getBuildConfig(configName);
@@ -827,6 +831,9 @@ public ProjectDescription internalGetDescription() {
827831
*/
828832
public IBuildConfiguration[] internalGetReferencedBuildConfigs(String configName, boolean includeMissing) {
829833
ProjectDescription description = internalGetDescription();
834+
if (description == null) {
835+
return new IBuildConfiguration[0];
836+
}
830837
IBuildConfiguration[] refs = description.getAllBuildConfigReferences(this, configName, false);
831838
Collection<IBuildConfiguration> configs = new LinkedHashSet<>(refs.length);
832839
for (IBuildConfiguration ref : refs) {

resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/ProjectDescription.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.List;
3030
import java.util.Map;
3131
import java.util.Map.Entry;
32+
import java.util.Objects;
3233
import java.util.Set;
3334
import org.eclipse.core.filesystem.URIUtil;
3435
import org.eclipse.core.internal.events.BuildCommand;
@@ -546,6 +547,14 @@ public boolean hasPrivateChanges(ProjectDescription description) {
546547
// Configuration level references
547548
if (configRefsHaveChanges(dynamicConfigRefs, description.dynamicConfigRefs))
548549
return true;
550+
// has natures changed?
551+
if (!Set.of(natures).equals(Set.of(description.natures))) {
552+
return true;
553+
}
554+
// has buildspec changed?
555+
if (!Objects.deepEquals(buildSpec, description.buildSpec)) {
556+
return true;
557+
}
549558

550559
return false;
551560
}
@@ -978,4 +987,5 @@ private static IProject[] computeDynamicReferencesForProject(IBuildConfiguration
978987
}
979988
return result.toArray(new IProject[0]);
980989
}
990+
981991
}

resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/ProjectDescriptionReader.java

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -233,26 +233,31 @@ private void endBuildTriggersElement(String elementName) {
233233
state = S_BUILD_COMMAND;
234234
BuildCommand command = (BuildCommand) objectStack.peek();
235235
//presence of this element indicates the builder is configurable
236+
String string = charBuffer.toString();
236237
command.setConfigurable(true);
237238
//clear all existing values
238-
command.setBuilding(IncrementalProjectBuilder.AUTO_BUILD, false);
239-
command.setBuilding(IncrementalProjectBuilder.CLEAN_BUILD, false);
240-
command.setBuilding(IncrementalProjectBuilder.FULL_BUILD, false);
241-
command.setBuilding(IncrementalProjectBuilder.INCREMENTAL_BUILD, false);
242-
243-
//set new values according to value in the triggers element
244-
StringTokenizer tokens = new StringTokenizer(charBuffer.toString(), ","); //$NON-NLS-1$
245-
while (tokens.hasMoreTokens()) {
246-
String next = tokens.nextToken();
247-
if (next.equalsIgnoreCase(TRIGGER_AUTO)) {
248-
command.setBuilding(IncrementalProjectBuilder.AUTO_BUILD, true);
249-
} else if (next.equalsIgnoreCase(TRIGGER_CLEAN)) {
250-
command.setBuilding(IncrementalProjectBuilder.CLEAN_BUILD, true);
251-
} else if (next.equalsIgnoreCase(TRIGGER_FULL)) {
252-
command.setBuilding(IncrementalProjectBuilder.FULL_BUILD, true);
253-
} else if (next.equalsIgnoreCase(TRIGGER_INCREMENTAL)) {
254-
command.setBuilding(IncrementalProjectBuilder.INCREMENTAL_BUILD, true);
255-
}
239+
parseBuildTriggers(command, string);
240+
}
241+
}
242+
243+
static void parseBuildTriggers(BuildCommand command, String string) {
244+
command.setBuilding(IncrementalProjectBuilder.AUTO_BUILD, false);
245+
command.setBuilding(IncrementalProjectBuilder.CLEAN_BUILD, false);
246+
command.setBuilding(IncrementalProjectBuilder.FULL_BUILD, false);
247+
command.setBuilding(IncrementalProjectBuilder.INCREMENTAL_BUILD, false);
248+
249+
// set new values according to value in the triggers element
250+
StringTokenizer tokens = new StringTokenizer(string, ","); //$NON-NLS-1$
251+
while (tokens.hasMoreTokens()) {
252+
String next = tokens.nextToken();
253+
if (next.equalsIgnoreCase(TRIGGER_AUTO)) {
254+
command.setBuilding(IncrementalProjectBuilder.AUTO_BUILD, true);
255+
} else if (next.equalsIgnoreCase(TRIGGER_CLEAN)) {
256+
command.setBuilding(IncrementalProjectBuilder.CLEAN_BUILD, true);
257+
} else if (next.equalsIgnoreCase(TRIGGER_FULL)) {
258+
command.setBuilding(IncrementalProjectBuilder.FULL_BUILD, true);
259+
} else if (next.equalsIgnoreCase(TRIGGER_INCREMENTAL)) {
260+
command.setBuilding(IncrementalProjectBuilder.INCREMENTAL_BUILD, true);
256261
}
257262
}
258263
}

0 commit comments

Comments
 (0)