Skip to content

Commit fd10b40

Browse files
committed
Add preference for disabling history of restricted files
This change adds a new preference to org.eclipse.core.resources: disableRestrictedFileHistory If the preference is set to 'true' and a file is restricted, setting the contents of the file will result in no new history entry for the edit. Example preference for product customization: org.eclipse.core.resources/disableRestrictedFileHistory=true Fixes: #2588
1 parent e85fd97 commit fd10b40

File tree

3 files changed

+230
-5
lines changed

3 files changed

+230
-5
lines changed

resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/FileSystemResourceManager.java

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,18 +84,24 @@
8484
*/
8585
public class FileSystemResourceManager implements ICoreConstants, IManager {
8686

87+
private static final String DISABLE_RESTRICTED_FILE_HISTORY_PREFERENCE = "disableRestrictedFileHistory"; //$NON-NLS-1$
88+
8789
/**
8890
* The history store is initialized lazily - always use the accessor method
8991
*/
9092
protected IHistoryStore _historyStore;
9193
protected Workspace workspace;
9294

9395
private volatile boolean lightweightAutoRefreshEnabled;
96+
private volatile boolean disableRestrictedFileHistory;
9497

95-
private final IPreferenceChangeListener lightweightAutoRefreshPrefListener = event -> {
96-
if (ResourcesPlugin.PREF_LIGHTWEIGHT_AUTO_REFRESH.equals(event.getKey())) {
98+
private final IPreferenceChangeListener prefListener = event -> {
99+
String preferenceName = event.getKey();
100+
if (ResourcesPlugin.PREF_LIGHTWEIGHT_AUTO_REFRESH.equals(preferenceName)) {
97101
lightweightAutoRefreshEnabled = Platform.getPreferencesService().getBoolean(ResourcesPlugin.PI_RESOURCES,
98102
ResourcesPlugin.PREF_LIGHTWEIGHT_AUTO_REFRESH, false, null);
103+
} else if (DISABLE_RESTRICTED_FILE_HISTORY_PREFERENCE.equals(preferenceName)) {
104+
setDisableRestrictedFileHistory();
99105
}
100106
};
101107

@@ -1203,15 +1209,16 @@ public void shutdown(IProgressMonitor monitor) throws CoreException {
12031209
_historyStore.shutdown(monitor);
12041210
}
12051211
InstanceScope.INSTANCE.getNode(ResourcesPlugin.PI_RESOURCES)
1206-
.removePreferenceChangeListener(lightweightAutoRefreshPrefListener);
1212+
.removePreferenceChangeListener(prefListener);
12071213
}
12081214

12091215
@Override
12101216
public void startup(IProgressMonitor monitor) {
12111217
InstanceScope.INSTANCE.getNode(ResourcesPlugin.PI_RESOURCES)
1212-
.addPreferenceChangeListener(lightweightAutoRefreshPrefListener);
1218+
.addPreferenceChangeListener(prefListener);
12131219
lightweightAutoRefreshEnabled = Platform.getPreferencesService().getBoolean(ResourcesPlugin.PI_RESOURCES,
12141220
ResourcesPlugin.PREF_LIGHTWEIGHT_AUTO_REFRESH, false, null);
1221+
setDisableRestrictedFileHistory();
12151222
}
12161223

12171224
/**
@@ -1497,7 +1504,26 @@ public void writeSilently(IProject target) throws CoreException {
14971504

14981505
public boolean storeHistory(IResource file) {
14991506
WorkspaceDescription description = workspace.internalGetDescription();
1500-
return description.isKeepDerivedState() || !file.isDerived();
1507+
return (description.isKeepDerivedState() || !file.isDerived()) && !disableHistory(file);
1508+
}
1509+
1510+
private void setDisableRestrictedFileHistory() {
1511+
String value = Platform.getPreferencesService().getString(ResourcesPlugin.PI_RESOURCES,
1512+
DISABLE_RESTRICTED_FILE_HISTORY_PREFERENCE, "", null); //$NON-NLS-1$
1513+
disableRestrictedFileHistory = Boolean.parseBoolean(value);
15011514
}
15021515

1516+
private boolean disableHistory(IResource resource) {
1517+
if (resource.getType() == IResource.FILE) {
1518+
if (disableRestrictedFileHistory) {
1519+
IFile file = (IFile) resource;
1520+
try {
1521+
return file.isContentRestricted();
1522+
} catch (CoreException e) {
1523+
Policy.log(e.getStatus());
1524+
}
1525+
}
1526+
}
1527+
return false;
1528+
}
15031529
}

resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/localstore/AllLocalStoreTests.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
SafeFileInputOutputStreamTest.class, //
3636
SymlinkResourceTest.class, //
3737
UnifiedTreeTest.class, //
38+
DisableHistoryTests.class, //
3839
})
3940
public class AllLocalStoreTests {
4041

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2026 Simeon Andreev 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+
* Simeon Andreev - initial API and implementation
13+
*******************************************************************************/
14+
package org.eclipse.core.tests.internal.localstore;
15+
16+
import static org.eclipse.core.resources.ResourcesPlugin.getWorkspace;
17+
import static org.eclipse.core.tests.resources.ResourceTestUtil.createInWorkspace;
18+
import static org.junit.jupiter.api.Assertions.assertEquals;
19+
20+
import java.util.Arrays;
21+
import org.eclipse.core.resources.IFile;
22+
import org.eclipse.core.resources.IFileState;
23+
import org.eclipse.core.resources.IFolder;
24+
import org.eclipse.core.resources.IProject;
25+
import org.eclipse.core.resources.IResource;
26+
import org.eclipse.core.resources.ResourcesPlugin;
27+
import org.eclipse.core.runtime.CoreException;
28+
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
29+
import org.eclipse.core.runtime.preferences.InstanceScope;
30+
import org.eclipse.core.tests.resources.util.WorkspaceResetExtension;
31+
import org.junit.jupiter.api.AfterEach;
32+
import org.junit.jupiter.api.BeforeEach;
33+
import org.junit.jupiter.api.Test;
34+
import org.junit.jupiter.api.extension.ExtendWith;
35+
import org.osgi.service.prefs.BackingStoreException;
36+
37+
/**
38+
* Tests disabling file history based on a workspace instance preference and a
39+
* per-file restriction flag. The tests set the preference
40+
* {@code org.eclipse.core.resources/disableRestrictedFileHistory} to
41+
* {@code true} and mark specific files as having restricted content (via
42+
* {@link IFile#setContentRestricted(boolean)}). After the preference is enabled
43+
* and the file is marked restricted, subsequent edits to that file are not
44+
* expected to create new file history states.
45+
*/
46+
@ExtendWith(WorkspaceResetExtension.class)
47+
public class DisableHistoryTests {
48+
49+
private static final String DISABLE_PREFERENCE_NAME = "disableRestrictedFileHistory";
50+
51+
private IProject project;
52+
53+
@BeforeEach
54+
public void createTestProject() throws Exception {
55+
project = getWorkspace().getRoot().getProject("Project");
56+
createInWorkspace(project);
57+
}
58+
59+
@AfterEach
60+
public void cleanUp() throws Exception {
61+
setHistoryDisablePreference(false);
62+
}
63+
64+
@Test
65+
public void testDisableHistoryBeforeEdit() throws Exception {
66+
IFile file = project.getFile("test.txt");
67+
file.create("initial".getBytes(), IResource.FORCE, null);
68+
setHistoryDisablePreference(true);
69+
setRestricted(file);
70+
writeContents(file, "edit 1");
71+
writeContents(file, "edit 2");
72+
IFileState[] history = file.getHistory(null);
73+
assertEquals(0, history.length, "Unexpected history after disable: " + toString(history));
74+
}
75+
76+
@Test
77+
public void testDisableHistoryAfterEdit() throws Exception {
78+
IFile file = project.getFile("test.txt");
79+
file.create("initial".getBytes(), IResource.FORCE, null);
80+
writeContents(file, "edit 1");
81+
writeContents(file, "edit 2");
82+
IFileState[] history = file.getHistory(null);
83+
assertEquals(2, history.length, "Unexpected history before disable: " + toString(history));
84+
setHistoryDisablePreference(true);
85+
setRestricted(file);
86+
writeContents(file, "edit 3");
87+
history = file.getHistory(null);
88+
assertEquals(2, history.length, "Unexpected history after disable: " + toString(history));
89+
}
90+
91+
@Test
92+
public void testDisableHistoryBeforeMove() throws Exception {
93+
IFile file = project.getFile("test.txt");
94+
file.create("initial".getBytes(), IResource.FORCE, null);
95+
writeContents(file, "edit 1");
96+
writeContents(file, "edit 2");
97+
IFileState[] history = file.getHistory(null);
98+
assertEquals(2, history.length, "Unexpected history before disable: " + toString(history));
99+
setHistoryDisablePreference(true);
100+
setRestricted(file);
101+
IFile movedFile = project.getFile("test2.txt");
102+
file.move(movedFile.getFullPath(), IResource.FORCE, null);
103+
history = movedFile.getHistory(null);
104+
assertEquals(2, history.length, "Unexpected history after move: " + toString(history));
105+
writeContents(movedFile, "edit 3");
106+
history = movedFile.getHistory(null);
107+
assertEquals(2, history.length, "Unexpected history after edit: " + toString(history));
108+
}
109+
110+
@Test
111+
public void testDisableHistoryBeforeMovingParentFolder() throws Exception {
112+
IFolder folder = project.getFolder("test_folder");
113+
folder.create(true, true, null);
114+
IFile file = folder.getFile("test.txt");
115+
file.create("initial".getBytes(), IResource.FORCE, null);
116+
writeContents(file, "edit 1");
117+
writeContents(file, "edit 2");
118+
IFileState[] history = file.getHistory(null);
119+
assertEquals(2, history.length, "Unexpected history before disable: " + toString(history));
120+
setHistoryDisablePreference(true);
121+
setRestricted(file);
122+
IFolder movedFolder = project.getFolder("test_folder2");
123+
folder.move(movedFolder.getFullPath(), true, null);
124+
IFile movedFile = movedFolder.getFile("test.txt");
125+
history = movedFile.getHistory(null);
126+
assertEquals(2, history.length, "Unexpected history after move: " + toString(history));
127+
writeContents(movedFile, "edit 3");
128+
history = movedFile.getHistory(null);
129+
assertEquals(2, history.length, "Unexpected history after edit: " + toString(history));
130+
}
131+
132+
@Test
133+
public void testDisableHistoryBeforeDelete() throws Exception {
134+
IFile file = project.getFile("test.txt");
135+
file.create("initial".getBytes(), IResource.FORCE, null);
136+
writeContents(file, "edit 1");
137+
writeContents(file, "edit 2");
138+
IFileState[] history = file.getHistory(null);
139+
assertEquals(2, history.length, "Unexpected history before disable: " + toString(history));
140+
setHistoryDisablePreference(true);
141+
setRestricted(file);
142+
writeContents(file, "edit 3");
143+
file.delete(true, null);
144+
history = file.getHistory(null);
145+
assertEquals(2, history.length, "Unexpected history after delete: " + toString(history));
146+
}
147+
148+
@Test
149+
public void testDisableHistoryBeforeDeletingParentFolder() throws Exception {
150+
IFolder folder = project.getFolder("test_folder");
151+
folder.create(true, true, null);
152+
IFile file = folder.getFile("test.txt");
153+
file.create("initial".getBytes(), IResource.FORCE, null);
154+
writeContents(file, "edit 1");
155+
writeContents(file, "edit 2");
156+
IFileState[] history = file.getHistory(null);
157+
assertEquals(2, history.length, "Unexpected history before disable: " + toString(history));
158+
setHistoryDisablePreference(true);
159+
setRestricted(file);
160+
writeContents(file, "edit 3");
161+
folder.delete(true, null);
162+
history = file.getHistory(null);
163+
assertEquals(2, history.length, "Unexpected history after delete: " + toString(history));
164+
}
165+
166+
@Test
167+
public void testHistoryNotDisabledForUnrestrictedFile() throws Exception {
168+
IFile file = project.getFile("unrestricted.txt");
169+
file.create("initial".getBytes(), IResource.FORCE, null);
170+
setHistoryDisablePreference(true);
171+
writeContents(file, "edit 1");
172+
writeContents(file, "edit 2");
173+
IFileState[] history = file.getHistory(null);
174+
assertEquals(2, history.length, "History should still be created for unrestricted files: " + toString(history));
175+
}
176+
177+
private void writeContents(IFile file, String contents) throws CoreException {
178+
file.setContents(contents.getBytes(), IResource.KEEP_HISTORY, null);
179+
}
180+
181+
private static String toString(IFileState... states) {
182+
return Arrays.toString(states);
183+
}
184+
185+
private static void setRestricted(IFile file) throws CoreException {
186+
file.setContentRestricted(true);
187+
}
188+
189+
private static void setHistoryDisablePreference(boolean enabled) throws BackingStoreException {
190+
IEclipsePreferences node = InstanceScope.INSTANCE.getNode(ResourcesPlugin.PI_RESOURCES);
191+
if (enabled) {
192+
node.put(DISABLE_PREFERENCE_NAME, Boolean.TRUE.toString());
193+
} else {
194+
node.remove(DISABLE_PREFERENCE_NAME);
195+
}
196+
node.flush();
197+
}
198+
}

0 commit comments

Comments
 (0)