blob: 5b2cd89eb56e233d058a71692fae29d6d51ae752 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2016 Andrew Gvozdev and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Andrew Gvozdev - Initial API and implementation
* James Blackburn (Broadcom Corp.)
* Liviu Ionescu - bug 392416
*******************************************************************************/
package org.eclipse.jdt.core.tests.nd.util;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.junit.Assert;
/**
* This class contains utility methods for creating resources
* such as projects, files, folders etc. which are being used
* in test fixture of unit tests.
*
* Some classes with similar idea worth to look at:
* org.eclipse.core.filebuffers.tests.ResourceHelper,
* org.eclipse.cdt.ui.tests.text.ResourceHelper.
*/
public class ResourceHelper {
private final static IProgressMonitor NULL_MONITOR = new NullProgressMonitor();
private static final int MAX_RETRY= 5;
private final static Set<String> externalFilesCreated = new HashSet<String>();
private final static Set<IResource> resourcesCreated = new HashSet<IResource>();
/**
* Creates a plain Eclipse project.
*
* @param projectName
* @return the project handle
* @throws CoreException if project could not be created
*/
public static IProject createProject(String projectName) throws CoreException {
IWorkspaceRoot root= ResourcesPlugin.getWorkspace().getRoot();
IProject project= root.getProject(projectName);
if (!project.exists()) {
project.create(NULL_MONITOR);
} else {
project.refreshLocal(IResource.DEPTH_INFINITE, null);
}
if (!project.isOpen())
project.open(NULL_MONITOR);
resourcesCreated.add(project);
return project;
}
/**
* Deletes project by name.
*
* @param projectName
* @throws CoreException
*/
public static void deleteProject(String projectName) throws CoreException {
IWorkspaceRoot root= ResourcesPlugin.getWorkspace().getRoot();
IProject project= root.getProject(projectName);
if (project.exists())
delete(project);
}
/**
* Deletes given project with content.
*
* @param project
* @throws CoreException
*/
public static void delete(final IProject project) throws CoreException {
delete(project, true);
}
/**
* Deletes project.
*
* @param project
* @param deleteContent whether to delete project content
* @throws CoreException
*/
public static void delete(final IProject project, boolean deleteContent) throws CoreException {
for (int i= 0; i < MAX_RETRY; i++) {
try {
project.delete(deleteContent, true, NULL_MONITOR);
i= MAX_RETRY;
} catch (CoreException x) {
if (i == MAX_RETRY - 1) {
Package.log(x.getStatus());
}
try {
Thread.sleep(1000); // sleep a second
} catch (InterruptedException e) {
}
}
}
}
/**
* Creates a file with specified content.
*
* @param file - file name.
* @param contents - contents of the file.
* @return file handle.
* @throws CoreException - if the file can't be created.
*/
public static IFile createFile(IFile file, String contents) throws CoreException {
if (contents == null) {
contents= "";
}
InputStream inputStream = new ByteArrayInputStream(contents.getBytes());
file.create(inputStream, true, NULL_MONITOR);
resourcesCreated.add(file);
return file;
}
/**
* Creates new file from project root with empty content. The filename
* can include relative path as a part of the name but the the path
* has to be present on disk.
*
* @param project - project where to create the file.
* @param name - filename.
* @return file handle.
* @throws CoreException if something goes wrong.
*/
public static IFile createFile(IProject project, String name) throws CoreException {
if (new Path(name).segmentCount() > 1)
createFolder(project, new Path(name).removeLastSegments(1).toString());
return createFile(project.getFile(name), null);
}
/**
* Creates new file from workspace root with empty content. The filename
* can include relative path as a part of the name but the the path
* has to be present on disk.
* The intention of the method is to create files which do not belong to any project.
*
* @param name - filename.
* @return full path of the created file.
*
* @throws CoreException...
* @throws IOException...
*/
public static IPath createWorkspaceFile(String name) throws CoreException, IOException {
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
IPath fullPath = workspaceRoot.getLocation().append(name);
java.io.File file = new java.io.File(fullPath.toOSString());
if (!file.exists()) {
boolean result = file.createNewFile();
Assert.assertTrue(result);
}
Assert.assertTrue(file.exists());
externalFilesCreated.add(fullPath.toOSString());
workspaceRoot.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());
return fullPath;
}
/**
* Creates new folder from project root. The folder name
* can include relative path as a part of the name.
* Nonexistent parent directories are being created.
*
* @param project - project where to create the folder.
* @param name - folder name.
* @return folder handle.
* @throws CoreException if something goes wrong.
*/
public static IFolder createFolder(IProject project, String name) throws CoreException {
final IPath p = new Path(name);
IContainer folder = project;
for (String seg : p.segments()) {
folder = folder.getFolder(new Path(seg));
if (!folder.exists())
((IFolder)folder).create(true, true, NULL_MONITOR);
}
resourcesCreated.add(folder);
return (IFolder)folder;
}
/**
* Creates new folder from workspace root. The folder name
* can include relative path as a part of the name.
* Nonexistent parent directories are being created as per {@link File#mkdirs()}.
* The intention of the method is to create folders which do not belong to any project.
*
* @param name - folder name.
* @return absolute location of the folder on the file system.
* @throws IOException if something goes wrong.
*/
public static IPath createWorkspaceFolder(String name) throws CoreException, IOException {
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
IPath fullPath = workspaceRoot.getLocation().append(name);
java.io.File folder = new java.io.File(fullPath.toOSString());
if (!folder.exists()) {
boolean result = folder.mkdirs();
Assert.assertTrue(result);
}
Assert.assertTrue(folder.exists());
externalFilesCreated.add(fullPath.toOSString());
workspaceRoot.refreshLocal(IResource.DEPTH_INFINITE, NULL_MONITOR);
return fullPath;
}
/**
* Creates new temporary folder with generated name from workspace root.
*
* @return absolute location of the folder on the file system.
* @throws IOException if something goes wrong.
*/
public static IPath createTemporaryFolder() throws CoreException, IOException {
return ResourceHelper.createWorkspaceFolder("tmp/" + System.currentTimeMillis() + '.' + UUID.randomUUID());
}
/**
* Creates new eclipse file-link from project root to file system file. The filename
* can include relative path as a part of the name but the the path
* has to be present on disk.
*
* @param project - project where to create the file.
* @param fileLink - filename of the link being created.
* @param realFile - file on the file system, the target of the link.
* @return file handle.
* @throws CoreException if something goes wrong.
*/
public static IFile createLinkedFile(IProject project, String fileLink, IPath realFile) throws CoreException {
IFile file = project.getFile(fileLink);
file.createLink(realFile, IResource.REPLACE, null);
Assert.assertTrue(file.exists());
resourcesCreated.add(file);
return file;
}
/**
* Creates new eclipse file-link from project root to file system file. The filename
* can include relative path as a part of the name but the the path
* has to be present on disk.
*
* @param project - project where to create the file.
* @param fileLink - filename of the link being created.
* @param realFile - file on the file system, the target of the link.
* @return file handle.
* @throws CoreException if something goes wrong.
*/
public static IFile createLinkedFile(IProject project, String fileLink, String realFile) throws CoreException {
return createLinkedFile(project, fileLink, new Path(realFile));
}
/**
* Creates new eclipse file-link from project root to EFS file.
*
* @param project - project where to create the file.
* @param fileLink - filename of the link being created.
* @param realFile - file on the EFS file system, the target of the link.
* @return file handle.
* @throws CoreException if something goes wrong.
*/
public static IFile createEfsFile(IProject project, String fileLink, URI realFile) throws CoreException {
IFile file= project.getFile(fileLink);
file.createLink(realFile, IResource.ALLOW_MISSING_LOCAL, NULL_MONITOR);
resourcesCreated.add(file);
return file;
}
/**
* Creates new eclipse file-link from project root to EFS file.
*
* @param project - project where to create the file.
* @param fileLink - filename of the link being created.
* @param realFile - file on the EFS file system, the target of the link.
* @return file handle.
* @throws CoreException if something goes wrong.
* @throws URISyntaxException if wrong URI syntax
*/
public static IFile createEfsFile(IProject project, String fileLink, String realFile) throws CoreException, URISyntaxException {
return createEfsFile(project,fileLink,new URI(realFile));
}
/**
* Creates new eclipse folder-link from project root to file system folder. The folder name
* can include relative path as a part of the name but the the path
* has to be present on disk.
*
* @param project - project where to create the file.
* @param folderLink - name of the link being created.
* @param realFolder - folder on the file system, the target of the link.
* @return file handle.
* @throws CoreException if something goes wrong.
*/
public static IFolder createLinkedFolder(IProject project, String folderLink, IPath realFolder) throws CoreException {
IFolder folder = project.getFolder(folderLink);
folder.createLink(realFolder, IResource.REPLACE | IResource.ALLOW_MISSING_LOCAL, null);
Assert.assertTrue(folder.exists());
resourcesCreated.add(folder);
return folder;
}
/**
* Creates new eclipse folder-link from project root to file system folder. The folder name
* can include relative path as a part of the name but the the path
* has to be present on disk.
*
* @param project - project where to create the file.
* @param folderLink - name of the link being created.
* @param realFolder - folder on the file system, the target of the link.
* @return file handle.
* @throws CoreException if something goes wrong.
*/
public static IFolder createLinkedFolder(IProject project, String folderLink, String realFolder) throws CoreException {
return createLinkedFolder(project, folderLink, new Path(realFolder));
}
/**
* Creates new eclipse folder-link from project root to EFS folder.
*
* @param project - project where to create the folder.
* @param folderLink - folder name of the link being created.
* @param realFolder - folder on the EFS file system, the target of the link.
* @return folder handle.
* @throws CoreException if something goes wrong.
*/
public static IFolder createEfsFolder(IProject project, String folderLink, URI realFolder) throws CoreException {
IFolder folder= project.getFolder(folderLink);
if (folder.exists()) {
Assert.assertEquals("Folder with the same name but different location already exists",
realFolder, folder.getLocationURI());
return folder;
}
folder.createLink(realFolder, IResource.ALLOW_MISSING_LOCAL, new NullProgressMonitor());
resourcesCreated.add(folder);
return folder;
}
/**
* Creates new eclipse folder-link from project root to EFS folder.
*
* @param project - project where to create the folder.
* @param folderLink - folder name of the link being created.
* @param realFolder - folder on the EFS file system, the target of the link.
* @return folder handle.
* @throws CoreException if something goes wrong.
* @throws URISyntaxException if wrong URI syntax
*/
public static IFolder createEfsFolder(IProject project, String folderLink, String realFolder) throws CoreException, URISyntaxException {
return createEfsFolder(project,folderLink,new URI(realFolder));
}
/**
* Checks if symbolic links are supported on the system.
* Used in particular by method {@link #createSymbolicLink(IPath, IPath)}
* and other flavors to create symbolic links.
*
* Note that Windows links .lnk are not supported here.
* @return {@code true} if symbolic links are suppoted, {@code false} otherwise.
*/
public static boolean isSymbolicLinkSupported() {
return ! Platform.getOS().equals(Platform.OS_WIN32);
}
/**
* Creates new symbolic file system link from file or folder on project root
* to another file system file. The filename can include relative path
* as a part of the name but the the path has to be present on disk.
*
* @param project - project where to create the file.
* @param linkName - name of the link being created.
* @param realPath - file or folder on the file system, the target of the link.
* @return file handle.
*
* @throws UnsupportedOperationException on Windows where links are not supported.
* @throws IOException...
* @throws CoreException...
*/
public static IResource createSymbolicLink(IProject project, String linkName, IPath realPath)
throws IOException, CoreException, UnsupportedOperationException {
if (!isSymbolicLinkSupported()) {
throw new UnsupportedOperationException("Windows links .lnk are not supported.");
}
Assert.assertTrue("Path for symbolic link does not exist: [" + realPath.toOSString() + "]",
new File(realPath.toOSString()).exists());
IPath linkedPath = project.getLocation().append(linkName);
createSymbolicLink(linkedPath, realPath);
IResource resource = project.getFile(linkName);
resource.refreshLocal(IResource.DEPTH_ZERO, null);
if (!resource.exists()) {
resource = project.getFolder(linkName);
resource.refreshLocal(IResource.DEPTH_ZERO, null);
}
Assert.assertTrue("Failed to create resource form symbolic link", resource.exists());
externalFilesCreated.add(linkedPath.toOSString());
ResourcesPlugin.getWorkspace().getRoot().refreshLocal(IResource.DEPTH_INFINITE, NULL_MONITOR);
return resource;
}
/**
* Creates new symbolic file system link from file or folder to another filesystem file.
* The target path has to be present on disk.
*
* @param linkPath - filesystem path of the link being created.
* @param realPath - file or folder on the file system, the target of the link.
*
* @throws UnsupportedOperationException on Windows where links are not supported.
* @throws IOException if execution of the command fails.
*/
public static void createSymbolicLink(IPath linkPath, IPath realPath) throws IOException {
if (!isSymbolicLinkSupported()) {
throw new UnsupportedOperationException("Windows links .lnk are not supported.");
}
String command[] = { "ln", "-s", realPath.toOSString(), linkPath.toOSString()};
Process process = Runtime.getRuntime().exec(command);
// Wait for up to 2.5s...
for (int i = 0; i < 5; i++) {
try {
Assert.assertTrue("ln process exited with non-zero status", process.waitFor() == 0);
// If exitValue succeeded, then the process has exited successfully.
break;
} catch (InterruptedException e) {
// Clear interrupted state, see Java bug http://bugs.sun.com/view_bug.do?bug_id=6420270
Thread.interrupted();
}
// Wait for a 500ms before checking again.
try { Thread.sleep(500); } catch (InterruptedException e) {/*don't care*/}
}
Assert.assertTrue("Symbolic link not created, command=[" + command + "]", linkPath.toFile().exists());
}
/**
* Creates new symbolic file system link from file or folder on project root
* to another file system file. The filename can include relative path
* as a part of the name but the the path has to be present on disk.
*
* @param project - project where to create the file.
* @param linkName - name of the link being created.
* @param realPath - file or folder on the file system, the target of the link.
* @return file handle.
*
* @throws UnsupportedOperationException on Windows where links are not supported.
* @throws IOException...
* @throws CoreException...
*/
public static IResource createSymbolicLink(IProject project, String linkName, String realPath)
throws IOException, CoreException, UnsupportedOperationException {
return createSymbolicLink(project, linkName, new Path(realPath));
}
/**
* Get contents of file on file-system.
*
* @param fullPath - full path to the file on the file-system.
* @return contents of the file.
* @throws IOException on IO problem.
*/
public static String getContents(IPath fullPath) throws IOException {
FileInputStream stream = new FileInputStream(fullPath.toFile());
try {
// Avoid using java.nio.channels.FileChannel,
// see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4715154
Reader reader = new BufferedReader(new InputStreamReader(stream, Charset.defaultCharset()));
StringBuilder builder = new StringBuilder();
char[] buffer = new char[8192];
int read;
while ((read = reader.read(buffer, 0, buffer.length)) > 0) {
builder.append(buffer, 0, read);
}
return builder.toString();
} finally {
stream.close();
}
}
/**
* Get contents of file on file-system.
*
* @param fullPath - full path to the file on the file-system.
* @return contents of the file.
* @throws IOException on IO problem.
*/
public static String getContents(String fullPath) throws IOException {
return getContents(new Path(fullPath));
}
/**
* Clean-up any files created as part of a unit test.
* This method removes *all* Workspace IResources and any external
* files / folders created with the #createWorkspaceFile #createWorkspaceFolder
* methods in this class
*/
public static void cleanUp() throws CoreException, IOException {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
root.refreshLocal(IResource.DEPTH_INFINITE, NULL_MONITOR);
// Delete all external files & folders created using ResourceHelper
for (String loc : externalFilesCreated) {
File f = new File(loc);
if (f.exists())
deleteRecursive(f);
}
externalFilesCreated.clear();
// Remove IResources created by this helper
for (IResource r : resourcesCreated) {
if (r.exists()) {
try {
r.delete(true, NULL_MONITOR);
} catch (CoreException e) {
// Ignore
}
}
}
resourcesCreated.clear();
}
/**
* Recursively delete a directory / file
*
* For safety this method only deletes files created under the workspace
*/
private static final void deleteRecursive(File f) throws IllegalArgumentException {
// Ensure that the file being deleted is a child of the workspace
// root to prevent anything nasty happening
if (!f.getAbsolutePath().startsWith(
ResourcesPlugin.getWorkspace().getRoot().getLocation().toFile().getAbsolutePath())) {
throw new IllegalArgumentException("File must exist within the workspace!");
}
if (f.isDirectory()) {
for (File f1 : f.listFiles()) {
deleteRecursive(f1);
}
}
f.delete();
}
}