Skip to content

Commit a59ce1e

Browse files
EcljpseB0Tjukzi
authored andcommitted
Provide API for IFile create(byte[], ...)
1 parent 7f0bc7c commit a59ce1e

File tree

3 files changed

+175
-43
lines changed
  • resources
    • bundles/org.eclipse.core.resources/src/org/eclipse/core
    • tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources

3 files changed

+175
-43
lines changed

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

Lines changed: 96 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -124,49 +124,12 @@ public void create(InputStream content, int updateFlags, IProgressMonitor monito
124124
try (content) {
125125
checkValidPath(path, FILE, true);
126126
final ISchedulingRule rule = workspace.getRuleFactory().createRule(this);
127-
SubMonitor newChild = subMonitor.newChild(1);
128127
try {
129-
workspace.prepareOperation(rule, newChild);
130-
checkDoesNotExist();
131-
Container parent = (Container) getParent();
132-
ResourceInfo info = parent.getResourceInfo(false, false);
133-
parent.checkAccessible(getFlags(info));
134-
checkValidGroupContainer(parent, false, false);
135-
128+
workspace.prepareOperation(rule, subMonitor.newChild(1));
129+
checkCreatable();
136130
workspace.beginOperation(true);
137131
IFileStore store = getStore();
138-
IFileInfo localInfo = store.fetchInfo();
139-
if (BitMask.isSet(updateFlags, IResource.FORCE)) {
140-
if (!Workspace.caseSensitive) {
141-
if (localInfo.exists()) {
142-
String name = getLocalManager().getLocalName(store);
143-
if (name == null || localInfo.getName().equals(name)) {
144-
delete(true, null);
145-
} else {
146-
// The file system is not case sensitive and there is already a file
147-
// under this location.
148-
message = NLS.bind(Messages.resources_existsLocalDifferentCase, IPath.fromOSString(store.toString()).removeLastSegments(1).append(name).toOSString());
149-
throw new ResourceException(IResourceStatus.CASE_VARIANT_EXISTS, getFullPath(), message, null);
150-
}
151-
}
152-
}
153-
} else {
154-
if (localInfo.exists()) {
155-
//return an appropriate error message for case variant collisions
156-
if (!Workspace.caseSensitive) {
157-
String name = getLocalManager().getLocalName(store);
158-
if (name != null && !localInfo.getName().equals(name)) {
159-
message = NLS.bind(Messages.resources_existsLocalDifferentCase, IPath.fromOSString(store.toString()).removeLastSegments(1).append(name).toOSString());
160-
throw new ResourceException(IResourceStatus.CASE_VARIANT_EXISTS, getFullPath(), message, null);
161-
}
162-
}
163-
message = NLS.bind(Messages.resources_fileExists, store.toString());
164-
throw new ResourceException(IResourceStatus.FAILED_WRITE_LOCAL, getFullPath(), message, null);
165-
}
166-
}
167-
subMonitor.worked(40);
168-
169-
info = workspace.createResource(this, updateFlags);
132+
IFileInfo localInfo = create(updateFlags, subMonitor.newChild(40), store);
170133
boolean local = content != null;
171134
if (local) {
172135
try {
@@ -181,9 +144,7 @@ public void create(InputStream content, int updateFlags, IProgressMonitor monito
181144
throw e;
182145
}
183146
}
184-
internalSetLocal(local, DEPTH_ZERO);
185-
if (!local)
186-
getResourceInfo(true, true).clearModificationStamp();
147+
setLocal(local);
187148
} catch (OperationCanceledException e) {
188149
workspace.getWorkManager().operationCanceled();
189150
throw e;
@@ -203,6 +164,98 @@ public void create(InputStream content, boolean force, IProgressMonitor monitor)
203164
create(content, (force ? IResource.FORCE : IResource.NONE), monitor);
204165
}
205166

167+
@Override
168+
public void create(byte[] content, int updateFlags, IProgressMonitor monitor) throws CoreException {
169+
SubMonitor subMonitor = SubMonitor.convert(monitor, NLS.bind(Messages.resources_creating, getFullPath()), 100);
170+
try {
171+
checkValidPath(path, FILE, true);
172+
final ISchedulingRule rule = workspace.getRuleFactory().createRule(this);
173+
try {
174+
workspace.prepareOperation(rule, subMonitor.newChild(1));
175+
checkCreatable();
176+
workspace.beginOperation(true);
177+
IFileStore store = getStore();
178+
IFileInfo localInfo = create(updateFlags, subMonitor.newChild(40), store);
179+
boolean local = content != null;
180+
if (local) {
181+
try {
182+
internalSetContents(content, localInfo, updateFlags, false, subMonitor.newChild(59));
183+
} catch (CoreException | OperationCanceledException e) {
184+
// CoreException when a problem happened creating the file on disk
185+
// OperationCanceledException when the operation of setting contents has been
186+
// canceled
187+
// In either case delete from the workspace and disk
188+
workspace.deleteResource(this);
189+
store.delete(EFS.NONE, null);
190+
throw e;
191+
}
192+
}
193+
setLocal(local);
194+
} catch (OperationCanceledException e) {
195+
workspace.getWorkManager().operationCanceled();
196+
throw e;
197+
} finally {
198+
workspace.endOperation(rule, true);
199+
}
200+
} finally {
201+
subMonitor.done();
202+
}
203+
}
204+
205+
private void checkCreatable() throws CoreException {
206+
checkDoesNotExist();
207+
Container parent = (Container) getParent();
208+
ResourceInfo info = parent.getResourceInfo(false, false);
209+
parent.checkAccessible(getFlags(info));
210+
checkValidGroupContainer(parent, false, false);
211+
}
212+
213+
private IFileInfo create(int updateFlags, SubMonitor subMonitor, IFileStore store)
214+
throws CoreException, ResourceException {
215+
String message;
216+
IFileInfo localInfo = store.fetchInfo();
217+
if (BitMask.isSet(updateFlags, IResource.FORCE)) {
218+
if (!Workspace.caseSensitive) {
219+
if (localInfo.exists()) {
220+
String name = getLocalManager().getLocalName(store);
221+
if (name == null || localInfo.getName().equals(name)) {
222+
delete(true, null);
223+
} else {
224+
// The file system is not case sensitive and there is already a file
225+
// under this location.
226+
message = NLS.bind(Messages.resources_existsLocalDifferentCase,
227+
IPath.fromOSString(store.toString()).removeLastSegments(1).append(name).toOSString());
228+
throw new ResourceException(IResourceStatus.CASE_VARIANT_EXISTS, getFullPath(), message, null);
229+
}
230+
}
231+
}
232+
} else {
233+
if (localInfo.exists()) {
234+
// return an appropriate error message for case variant collisions
235+
if (!Workspace.caseSensitive) {
236+
String name = getLocalManager().getLocalName(store);
237+
if (name != null && !localInfo.getName().equals(name)) {
238+
message = NLS.bind(Messages.resources_existsLocalDifferentCase,
239+
IPath.fromOSString(store.toString()).removeLastSegments(1).append(name).toOSString());
240+
throw new ResourceException(IResourceStatus.CASE_VARIANT_EXISTS, getFullPath(), message, null);
241+
}
242+
}
243+
message = NLS.bind(Messages.resources_fileExists, store.toString());
244+
throw new ResourceException(IResourceStatus.FAILED_WRITE_LOCAL, getFullPath(), message, null);
245+
}
246+
}
247+
subMonitor.done();
248+
249+
workspace.createResource(this, updateFlags);
250+
return localInfo;
251+
}
252+
253+
private void setLocal(boolean local) throws CoreException {
254+
internalSetLocal(local, DEPTH_ZERO);
255+
if (!local)
256+
getResourceInfo(true, true).clearModificationStamp();
257+
}
258+
206259
@Override
207260
public String getCharset() throws CoreException {
208261
return getCharset(true);

resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/IFile.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,50 @@ public interface IFile extends IResource, IEncodedStorage, IAdaptable {
357357
*/
358358
void create(InputStream source, int updateFlags, IProgressMonitor monitor) throws CoreException;
359359

360+
/**
361+
* Creates the file with the given content as byte array. Same as calling
362+
* {@link #create(InputStream, int, IProgressMonitor)} with flags depending on
363+
* the boolean parameters and a {@code new ByteArrayInputStream(content)} as
364+
* {@code InputStream}. This method is preferably over the streaming API when
365+
* the content is available as byte array anyway.
366+
*
367+
* @param content the content as byte array
368+
* @param force a flag controlling how to deal with resources that are not in
369+
* sync with the local file system
370+
* @param derived Specifying this flag is equivalent to atomically calling
371+
* {@link IResource#setDerived(boolean)} immediately after
372+
* creating the resource
373+
* @param monitor a progress monitor, or <code>null</code> if progress reporting
374+
* is not desired
375+
* @throws CoreException if this method fails or is canceled.
376+
* @since 3.21
377+
*/
378+
public default void create(byte[] content, boolean force, boolean derived, IProgressMonitor monitor)
379+
throws CoreException {
380+
int createFlags = (force ? IResource.FORCE : IResource.NONE) | (derived ? IResource.DERIVED : IResource.NONE);
381+
create(content, createFlags, monitor);
382+
}
383+
384+
/**
385+
* Creates the file with the given content as byte array. Same as calling
386+
* {@link #create(InputStream, int, IProgressMonitor)} and a
387+
* {@code new ByteArrayInputStream(content)} as {@code InputStream}. This method
388+
* is preferably over the streaming API when the content is available as byte
389+
* array anyway.
390+
*
391+
* @param content the content as byte array
392+
* @param createFlags bit-wise or of flag constants ({@link IResource#FORCE},
393+
* {@link IResource#DERIVED}, and
394+
* {@link IResource#TEAM_PRIVATE})
395+
* @param monitor a progress monitor, or <code>null</code> if progress
396+
* reporting is not desired
397+
* @throws CoreException if this method fails or is canceled.
398+
* @since 3.21
399+
*/
400+
public default void create(byte[] content, int createFlags, IProgressMonitor monitor) throws CoreException {
401+
create(new ByteArrayInputStream(content), createFlags, monitor);
402+
}
403+
360404
/**
361405
* Creates a new file resource as a member of this handle's parent resource.
362406
* The file's contents will be located in the file specified by the given

resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/IFileTest.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import static org.eclipse.core.tests.resources.ResourceTestUtil.removeFromWorkspace;
3333
import static org.junit.Assert.assertArrayEquals;
3434
import static org.junit.Assert.assertEquals;
35+
import static org.junit.Assert.assertFalse;
3536
import static org.junit.Assert.assertNull;
3637
import static org.junit.Assert.assertThrows;
3738
import static org.junit.Assert.assertTrue;
@@ -290,6 +291,7 @@ public void testAppendContents() throws Exception {
290291
}
291292
}
292293

294+
@SuppressWarnings("deprecation") // org.eclipse.core.resources.IResource.isLocal(int)
293295
@Test
294296
public void testAppendContents2() throws Exception {
295297
IFile file = projects[0].getFile("file1");
@@ -455,6 +457,29 @@ public void testCreateDerived() throws CoreException {
455457
assertTrue("2.0", !derived.isDerived());
456458
assertTrue("2.1", !derived.isTeamPrivateMember());
457459
}
460+
@Test
461+
public void testCreateBytes() throws CoreException {
462+
IFile derived = projects[0].getFile("derived.txt");
463+
createInWorkspace(projects[0]);
464+
removeFromWorkspace(derived);
465+
466+
FussyProgressMonitor monitor = new FussyProgressMonitor();
467+
derived.create("derived".getBytes(), false, true, monitor);
468+
monitor.assertUsedUp();
469+
assertTrue(derived.isDerived());
470+
assertFalse(derived.isTeamPrivateMember());
471+
assertEquals("derived", derived.readString());
472+
473+
monitor.prepare();
474+
derived.delete(false, monitor);
475+
monitor.assertUsedUp();
476+
monitor.prepare();
477+
derived.create("notDerived".getBytes(), false, false, monitor);
478+
monitor.assertUsedUp();
479+
assertFalse(derived.isDerived());
480+
assertFalse(derived.isTeamPrivateMember());
481+
assertEquals("notDerived", derived.readString());
482+
}
458483

459484
@Test
460485
public void testDeltaOnCreateDerived() throws CoreException {
@@ -944,6 +969,16 @@ public void testSetContents2() throws IOException, CoreException {
944969
}
945970
}
946971

972+
@Test
973+
public void testCreateByteArray() throws IOException, CoreException {
974+
IFile target = projects[0].getFile("file1");
975+
String testString = createRandomString();
976+
FussyProgressMonitor monitor = new FussyProgressMonitor();
977+
target.create(testString.getBytes(), true, false, monitor);
978+
monitor.assertUsedUp();
979+
assertEquals(testString, target.readString());
980+
}
981+
947982
@Test
948983
public void testReadAll() throws IOException, CoreException {
949984
List<Charset> charsets = List.of(StandardCharsets.ISO_8859_1, StandardCharsets.UTF_8, StandardCharsets.UTF_16BE,

0 commit comments

Comments
 (0)