Skip to content

Commit 5c03d6d

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 5c03d6d

File tree

3 files changed

+217
-5
lines changed

3 files changed

+217
-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+
disableRestrictedFileHistory = Boolean.TRUE.toString().equals(event.getNewValue());
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+
setDisableHistoryProperty();
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 setDisableHistoryProperty() {
1511+
String preferenceValue = Platform.getPreferencesService().getString(ResourcesPlugin.PI_RESOURCES,
1512+
DISABLE_RESTRICTED_FILE_HISTORY_PREFERENCE, "", null); //$NON-NLS-1$
1513+
disableRestrictedFileHistory = Boolean.TRUE.toString().equals(preferenceValue);
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: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
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+
* Test for disabling file history based on a preference. Sets the preference
39+
* {@code org.eclipse.core.resources/disable_history_property=disable_history},
40+
* adds the session property {@code disable_history} on some test file and
41+
* performs edits. After setting the preference and session property, no new
42+
* file history is expected.
43+
*/
44+
@ExtendWith(WorkspaceResetExtension.class)
45+
public class DisableHistoryTests {
46+
47+
private static final String DISABLE_PREFERENCE_NAME = "disableRestrictedFileHistory";
48+
49+
private IProject project;
50+
51+
@BeforeEach
52+
public void createTestProject() throws Exception {
53+
project = getWorkspace().getRoot().getProject("Project");
54+
createInWorkspace(project);
55+
}
56+
57+
@AfterEach
58+
public void cleanUp() throws Exception {
59+
setHistoryDisablePreference(false);
60+
}
61+
62+
@Test
63+
public void testDisableHistoryBeforeEdit() throws Exception {
64+
IFile file = project.getFile("test.txt");
65+
file.create("initial".getBytes(), IResource.FORCE, null);
66+
setHistoryDisablePreference(true);
67+
setRestricted(file);
68+
writeContents(file, "edit 1");
69+
writeContents(file, "edit 2");
70+
IFileState[] history = file.getHistory(null);
71+
assertEquals(0, history.length, "Unexpected history after disable: " + toString(history));
72+
}
73+
74+
@Test
75+
public void testDisableHistoryAfterEdit() throws Exception {
76+
IFile file = project.getFile("test.txt");
77+
file.create("initial".getBytes(), IResource.FORCE, null);
78+
writeContents(file, "edit 1");
79+
writeContents(file, "edit 2");
80+
IFileState[] history = file.getHistory(null);
81+
assertEquals(2, history.length, "Unexpected history before disable: " + toString(history));
82+
setHistoryDisablePreference(true);
83+
setRestricted(file);
84+
writeContents(file, "edit 3");
85+
history = file.getHistory(null);
86+
assertEquals(2, history.length, "Unexpected history after disable: " + toString(history));
87+
}
88+
89+
@Test
90+
public void testDisableHistoryBeforeMove() throws Exception {
91+
IFile file = project.getFile("test.txt");
92+
file.create("initial".getBytes(), IResource.FORCE, null);
93+
writeContents(file, "edit 1");
94+
writeContents(file, "edit 2");
95+
IFileState[] history = file.getHistory(null);
96+
assertEquals(2, history.length, "Unexpected history before disable: " + toString(history));
97+
setHistoryDisablePreference(true);
98+
setRestricted(file);
99+
IFile movedFile = project.getFile("test2.txt");
100+
file.move(movedFile.getFullPath(), IResource.FORCE, null);
101+
history = movedFile.getHistory(null);
102+
assertEquals(2, history.length, "Unexpected history after move: " + toString(history));
103+
writeContents(movedFile, "edit 3");
104+
history = movedFile.getHistory(null);
105+
assertEquals(2, history.length, "Unexpected history after edit: " + toString(history));
106+
}
107+
108+
@Test
109+
public void testDisableHistoryBeforeMovingParentFolder() throws Exception {
110+
IFolder folder = project.getFolder("test_folder");
111+
folder.create(true, true, null);
112+
IFile file = folder.getFile("test.txt");
113+
file.create("initial".getBytes(), IResource.FORCE, null);
114+
writeContents(file, "edit 1");
115+
writeContents(file, "edit 2");
116+
IFileState[] history = file.getHistory(null);
117+
assertEquals(2, history.length, "Unexpected history before disable: " + toString(history));
118+
setHistoryDisablePreference(true);
119+
setRestricted(file);
120+
IFolder movedFolder = project.getFolder("test_folder2");
121+
folder.move(movedFolder.getFullPath(), true, null);
122+
IFile movedFile = movedFolder.getFile("test.txt");
123+
history = movedFile.getHistory(null);
124+
assertEquals(2, history.length, "Unexpected history after move: " + toString(history));
125+
writeContents(movedFile, "edit 3");
126+
history = movedFile.getHistory(null);
127+
assertEquals(2, history.length, "Unexpected history after edit: " + toString(history));
128+
}
129+
130+
@Test
131+
public void testDisableHistoryBeforeDelete() throws Exception {
132+
IFile file = project.getFile("test.txt");
133+
file.create("initial".getBytes(), IResource.FORCE, null);
134+
writeContents(file, "edit 1");
135+
writeContents(file, "edit 2");
136+
IFileState[] history = file.getHistory(null);
137+
assertEquals(2, history.length, "Unexpected history before disable: " + toString(history));
138+
setHistoryDisablePreference(true);
139+
setRestricted(file);
140+
writeContents(file, "edit 3");
141+
file.delete(true, null);
142+
history = file.getHistory(null);
143+
assertEquals(2, history.length, "Unexpected history after delete: " + toString(history));
144+
}
145+
146+
@Test
147+
public void testDisableHistoryBeforeDeletingParentFolder() throws Exception {
148+
IFolder folder = project.getFolder("test_folder");
149+
folder.create(true, true, null);
150+
IFile file = folder.getFile("test.txt");
151+
file.create("initial".getBytes(), IResource.FORCE, null);
152+
writeContents(file, "edit 1");
153+
writeContents(file, "edit 2");
154+
IFileState[] history = file.getHistory(null);
155+
assertEquals(2, history.length, "Unexpected history before disable: " + toString(history));
156+
setHistoryDisablePreference(true);
157+
setRestricted(file);
158+
writeContents(file, "edit 3");
159+
folder.delete(true, null);
160+
history = file.getHistory(null);
161+
assertEquals(2, history.length, "Unexpected history after delete: " + toString(history));
162+
}
163+
164+
private void writeContents(IFile file, String contents) throws CoreException {
165+
file.setContents(contents.getBytes(), IResource.KEEP_HISTORY, null);
166+
}
167+
168+
private static String toString(IFileState... states) {
169+
return Arrays.toString(states);
170+
}
171+
172+
private static void setRestricted(IFile file) throws CoreException {
173+
file.setContentRestricted(true);
174+
}
175+
176+
private static void setHistoryDisablePreference(boolean enabled) throws BackingStoreException {
177+
IEclipsePreferences node = InstanceScope.INSTANCE.getNode(ResourcesPlugin.PI_RESOURCES);
178+
if (enabled) {
179+
node.put(DISABLE_PREFERENCE_NAME, Boolean.TRUE.toString());
180+
} else {
181+
node.remove(DISABLE_PREFERENCE_NAME);
182+
}
183+
node.flush();
184+
}
185+
}

0 commit comments

Comments
 (0)