/*
?* Author: Chris, David Corbin
?*
?* Copyright (c) 2005 RubyPeople.
?*
?* This file is part of the Ruby Development Tools (RDT) plugin for eclipse.
* RDT is subject to the "Common Public License (CPL) v 1.0". You may not use
* RDT except in compliance with the License. For further information see
* org.rubypeople.rdt/rdt.license.
?*/
package org.rubypeople.rdt.internal.core.builder;
import java.io.DataOutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.rubypeople.rdt.core.ILoadpathEntry;
import org.rubypeople.rdt.core.IRubyModelMarker;
import org.rubypeople.rdt.core.RubyCore;
import org.rubypeople.rdt.core.RubyModelException;
import org.rubypeople.rdt.internal.core.LoadpathEntry;
import org.rubypeople.rdt.internal.core.RubyModelManager;
import org.rubypeople.rdt.internal.core.RubyProject;
public class RubyBuilder extends IncrementalProjectBuilder
{
public static boolean DEBUG;
private IProject currentProject;
private RubyProject rubyProject;
private IWorkspaceRoot workspaceRoot;
protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException
{
this.currentProject = getProject();
if (currentProject == null || !currentProject.isAccessible())
return null;
AbstractRdtCompiler compiler = createCompiler(kind);
long start = 0;
if (DEBUG)
{
RubyCore.trace("Started " + buildType(kind) + " build of " + buildDescription()); //$NON-NLS-1$
start = System.currentTimeMillis();
}
compiler.compile(monitor);
if (DEBUG)
{
RubyCore.trace("Finished build of " + buildDescription()); //$NON-NLS-1$
long end = System.currentTimeMillis();
System.out.println(currentProject.getName() + ": " + (end - start) + "ms");
}
return getRequiredProjects(true);
}
protected void clean(IProgressMonitor monitor) throws CoreException
{
this.currentProject = getProject();
if (currentProject == null || !currentProject.isAccessible())
return;
initializeBuilder();
AbstractRdtCompiler compiler = new CleanRdtCompiler(currentProject);
compiler.cleanStarting();
RubyModelManager.getRubyModelManager().indexManager.indexAll(currentProject);
super.clean(monitor);
}
private void initializeBuilder()
{
this.rubyProject = (RubyProject) RubyCore.create(currentProject);
this.workspaceRoot = currentProject.getWorkspace().getRoot();
}
/*
* Return the list of projects for which it requires a resource delta. This builder's project is implicitly included
* and need not be specified. Builders must re-specify the list of interesting projects every time they are run as
* this is not carried forward beyond the next build. Missing projects should be specified but will be ignored until
* they are added to the workspace.
*/
private IProject[] getRequiredProjects(boolean includeBinaryPrerequisites)
{
if (rubyProject == null || workspaceRoot == null)
return new IProject[0];
ArrayList<IProject> projects = new ArrayList<IProject>();
try
{
ILoadpathEntry[] entries = rubyProject.getExpandedLoadpath(true);
for (int i = 0, l = entries.length; i < l; i++)
{
ILoadpathEntry entry = entries[i];
IPath path = entry.getPath();
IProject p = null;
switch (entry.getEntryKind())
{
case ILoadpathEntry.CPE_PROJECT:
p = workspaceRoot.getProject(path.lastSegment()); // missing
// projects
// are
// considered
// too
if (((LoadpathEntry) entry).isOptional() && !RubyProject.hasRubyNature(p)) // except if
// entry is
// optional
p = null;
break;
case ILoadpathEntry.CPE_LIBRARY:
if (includeBinaryPrerequisites && path.segmentCount() > 1)
{
// some binary resources on the class path can come from
// projects that are not included in the project
// references
IResource resource = workspaceRoot.findMember(path.segment(0));
if (resource instanceof IProject)
p = (IProject) resource;
}
}
if (p != null && !projects.contains(p))
projects.add(p);
}
}
catch (RubyModelException e)
{
return new IProject[0];
}
IProject[] result = new IProject[projects.size()];
projects.toArray(result);
return result;
}
private AbstractRdtCompiler createCompiler(int kind)
{
if (isPartialBuild(kind))
return new IncrementalRdtCompiler(currentProject, getDelta(currentProject));
return new CleanRdtCompiler(currentProject);
}
private String buildType(int kind)
{
return isPartialBuild(kind) ? "Incremental" : "Full";
}
private String buildDescription()
{
return currentProject.getName() + " @ " + new Date(System.currentTimeMillis());
}
private boolean isPartialBuild(int kind)
{
return kind == INCREMENTAL_BUILD || kind == AUTO_BUILD;
}
public static void setVerbose(boolean verbose)
{
RubyBuilder.DEBUG = verbose;
}
public static void writeState(Object savedState, DataOutputStream out)
{
// TODO Actually write out build state to the stream!
}
public static void removeProblemsAndTasksFor(IResource resource)
{
try
{
if (resource != null && resource.exists())
{
resource.deleteMarkers(IRubyModelMarker.RUBY_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
resource.deleteMarkers(IRubyModelMarker.TASK_MARKER, false, IResource.DEPTH_INFINITE);
// delete managed markers
Set<String> markerTypes = RubyModelManager.getRubyModelManager().compilationParticipants
.managedMarkerTypes();
if (markerTypes.size() == 0)
return;
Iterator<String> iterator = markerTypes.iterator();
while (iterator.hasNext())
resource.deleteMarkers(iterator.next(), false, IResource.DEPTH_INFINITE);
}
}
catch (CoreException e)
{
// assume there were no problems
}
}
public static void buildStarting()
{
// TODO Auto-generated method stub
}
public static void buildFinished()
{
// TODO Auto-generated method stub
}
}