package com.codeaffine.extras.test.util;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.eclipse.core.resources.IContainer.INCLUDE_HIDDEN;
import static org.eclipse.core.resources.IResource.ALWAYS_DELETE_PROJECT_CONTENT;
import static org.eclipse.core.resources.IResource.FORCE;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.core.commands.ExecutionException;
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.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
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.ui.ide.undo.CreateProjectOperation;
import org.junit.rules.ExternalResource;
public class ProjectHelper extends ExternalResource {
private static int uniqueProjectId;
private static List<ProjectHelper> projects = new LinkedList<ProjectHelper>();
public static void cleanWorkspace() throws CoreException {
projects.clear();
IProject[] allProjects = ResourcesPlugin.getWorkspace().getRoot().getProjects( INCLUDE_HIDDEN );
for( IProject project : allProjects ) {
delete( project );
project.refreshLocal( IResource.DEPTH_ZERO, new NullProgressMonitor() );
}
}
public static void delete( IResource resource ) {
int numAttempts = 0;
boolean success = false;
while( !success ) {
try {
resource.delete( FORCE | ALWAYS_DELETE_PROJECT_CONTENT, new NullProgressMonitor() );
success = true;
numAttempts++;
} catch( CoreException ce ) {
if( numAttempts > 4 ) {
throw new RuntimeException( "Failed to delete resource: " + resource, ce );
}
System.gc();
try {
Thread.sleep( 500 );
} catch( InterruptedException ignore ) {
Thread.currentThread().interrupt();
}
System.gc();
}
}
}
private final String projectName;
private final IPath projectLocation;
private final AtomicInteger uniqueResourceId;
private final List<ProjectHelper> nestedProjectHelpers;
private IProject project;
public ProjectHelper() {
this( null );
}
public ProjectHelper( IPath baseLocation ) {
this.projectName = uniqueProjectName();
this.projectLocation = baseLocation == null ? null : baseLocation.append( projectName );
this.uniqueResourceId = new AtomicInteger();
this.nestedProjectHelpers = new ArrayList<>();
}
public String getName() {
initializeProject();
return project.getName();
}
public IProject getProject() {
initializeProject();
return project;
}
public ProjectHelper createNestedProject() {
ProjectHelper nestedProjectHelper = new ProjectHelper( getProject().getLocation() );
nestedProjectHelpers.add( nestedProjectHelper );
return nestedProjectHelper;
}
public IFolder createFolder() throws CoreException {
return createFolder( "folder-" + uniqueResourceId.incrementAndGet() );
}
public IFolder createFolder( String name ) throws CoreException {
initializeProject();
String[] segments = new Path( name ).segments();
IContainer container = project;
for( String segment : segments ) {
IFolder newFolder = container.getFolder( new Path( segment ) );
if( !newFolder.exists() ) {
newFolder.create( true, true, newProgressMonitor() );
}
container = newFolder;
}
return project.getFolder( new Path( name ) );
}
public IFile createFile( String fileName, String content ) throws CoreException {
return createFile( getProject(), fileName, content );
}
public IFile createFile() throws CoreException {
return createFile( getProject() );
}
public IFile createFile( IContainer parent ) throws CoreException {
String fileName = "file-" + uniqueResourceId.incrementAndGet() + ".txt";
String content = "content of " + fileName;
return createFile( parent, fileName, content );
}
public IFile createFile( IContainer parent, String fileName, String content )
throws CoreException
{
initializeProject();
IFile result = parent.getFile( new Path( fileName ) );
InputStream stream = new ByteArrayInputStream( content.getBytes( UTF_8 ) );
if( !result.exists() ) {
result.create( stream, true, newProgressMonitor() );
} else {
result.setContents( stream, false, false, newProgressMonitor() );
}
return result;
}
@Override
protected void after() {
nestedProjectHelpers.forEach( ProjectHelper::after );
if( isProjectCreated() && projects.remove( this ) ) {
delete( project );
}
}
private boolean isProjectCreated() {
return project != null;
}
private void initializeProject() {
if( !isProjectCreated() ) {
IProjectDescription projectDescription = createProjectDescription();
project = createProject( projectDescription );
projects.add( this );
}
}
private IProject createProject( IProjectDescription projectDescription ) {
String label = "Create project " + projectName;
try {
new CreateProjectOperation( projectDescription, label ).execute( newProgressMonitor(), null );
} catch( ExecutionException ee ) {
throw new RuntimeException( ee );
}
return ResourcesPlugin.getWorkspace().getRoot().getProject( projectName );
}
private IProjectDescription createProjectDescription() {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IProjectDescription result = workspace.newProjectDescription( projectName );
result.setLocation( projectLocation );
return result;
}
private static IProgressMonitor newProgressMonitor() {
return new NullProgressMonitor();
}
private static String uniqueProjectName() {
String result = "test.project." + uniqueProjectId;
uniqueProjectId++;
return result;
}
}