/* * Boo Development Tools for the Eclipse IDE * Copyright (C) 2005 Rodrigo B. de Oliveira (rbo@acm.org) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package monolipse.core.internal; import java.io.*; import java.util.*; import monolipse.core.*; import monolipse.core.foundation.*; import monolipse.core.runtime.*; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; public class BooBuilder extends IncrementalProjectBuilder { public static final String BUILDER_ID = BooCore.ID_PLUGIN + ".booBuilder"; private String projectLocation; protected void startupOnInitialize() { super.startupOnInitialize(); projectLocation = canonicalPathFor(getProject().getLocation().toOSString()); } private void addMarker(String path, String message, int lineNumber, int severity) { String canonicalPath = canonicalPathFor(path); String relativePath = canonicalPath.startsWith(projectLocation) ? canonicalPath.substring(projectLocation.length() + 1) : canonicalPath; relativePath = relativePath.replace('\\', '/'); IFile file = getProject().getFile(relativePath); BooMarkers.addMarker(file, message, lineNumber, severity); } private String canonicalPathFor(String path) { try { return new File(path).getCanonicalPath(); } catch (IOException e) { e.printStackTrace(); return path; } } protected void clean(IProgressMonitor monitor) throws CoreException { IAssemblySource[] sources = getAssemblySources(); for (int i = 0; i < sources.length; ++i) { try { clean(sources[i], monitor); } catch (Exception x) { BooMarkers.addMarker(sources[i].getFolder(), x.getMessage(), -1, IMarker.SEVERITY_ERROR); } } } private void clean(IAssemblySource source, final IProgressMonitor monitor) throws CoreException { IFile outputFile = source.getOutputFile(); final IContainer outputFolder = outputFile.getParent(); deleteIfExists(outputFile, monitor); source.visitReferences(new AssemblyReferenceVisitor() { public boolean visit(ILocalAssemblyReference reference) throws CoreException { deleteIfExists(outputFolder.getFile(new Path(reference.getFile().getName())), monitor); return true; } }); } private void deleteIfExists(IFile outputFile, IProgressMonitor monitor) throws CoreException { if (outputFile.exists()) { outputFile.delete(true, monitor); } } /* * (non-Javadoc) * * @see org.eclipse.core.internal.events.InternalBuilder#build(int, * java.util.Map, org.eclipse.core.runtime.IProgressMonitor) */ protected IProject[] build(int kind, Map<String, String> args, IProgressMonitor monitor) throws CoreException { if (kind == FULL_BUILD) { fullBuild(monitor); } else { IResourceDelta delta = getDelta(getProject()); if (delta == null) { fullBuild(monitor); } else { incrementalBuild(delta, monitor); } } return null; } protected void fullBuild(final IProgressMonitor monitor) throws CoreException { BooCore.logInfo("full build requested"); compile(getAssemblySources(), monitor); } private IAssemblySource[] getAssemblySources() throws CoreException { return getBooProject().getAssemblySources(); } private IMonoProject getBooProject() throws CoreException { return BooProject.get(getProject()); } protected void incrementalBuild(IResourceDelta delta, IProgressMonitor monitor) throws CoreException { BooCore.logInfo("incremental build requested"); compile(getBooProject().getAffectedAssemblySources(delta), monitor); } boolean ensureCanBeBuilt(IAssemblySource source) throws CoreException { if (!validateRuntime()) return cantBeBuilt(source, "the location for the mono runtime is not set."); return ensureReferences(source); } private boolean ensureReferences(IAssemblySource source) throws CoreException { for (IAssemblyReference r : source.getReferences()) { if (r instanceof AssemblyReferenceError) { return cantBeBuilt(source, "reference '" + r.getRemembrance() + "' couldn't be loaded: " + ((AssemblyReferenceError)r).error().getLocalizedMessage()); } if (r instanceof IAssemblySourceReference) { if (BooMarkers.hasErrors(((IAssemblySourceReference)r).getAssemblySource())) { return cantBeBuilt(source, "reference '" + r.getAssemblyName() + "' contains errors."); } } else if (r instanceof ILocalAssemblyReference) { if (!((ILocalAssemblyReference)r).getFile().exists()) { return cantBeBuilt(source, "reference '" + r.getAssemblyName() + "' cannot be found."); } } } return true; } private boolean cantBeBuilt(IAssemblySource source, String reason) { BooMarkers.addErrorMarker(source, "'" + source.getFolder().getName() + "' can't be built because " + reason); return false; } boolean validateRuntime() { return null != BooCore.getRuntime(); } void compile(IAssemblySource[] sources, IProgressMonitor monitor) throws CoreException { sources = getBooProject().getAssemblySourceOrder(sources); for (int i=0; i<sources.length; ++i) { compile(sources[i], monitor); } } void compile(IAssemblySource source, IProgressMonitor monitor) throws CoreException { BooMarkers.deleteMarkers(source.getFolder()); try { if (!ensureCanBeBuilt(source)) return; IFile[] srcFiles = source.getSourceFiles(); if (srcFiles.length == 0) { cantBeBuilt(source, "no source files"); return; } ensureOutputFolderFor(source, monitor); CompilerError[] errors = launchCompiler(source, srcFiles); if (reportErrors(source, errors) > 0) return; refreshOutputFolder(source, monitor); setDerivedOutputFile(source, monitor); if (source.getLanguage() == AssemblySourceLanguage.BOO) { IFolder outputFolder = (IFolder)source.getOutputFile().getParent(); copyLocalReferences(source, outputFolder, monitor); copyResources(source, outputFolder, monitor); } } catch (Exception e) { BooMarkers.addErrorMarker(source, e.getMessage()); BooCore.logException(e); } } private void setDerivedOutputFile(IAssemblySource source, IProgressMonitor monitor) throws CoreException { IFile outputFile = source.getOutputFile(); if (outputFile.exists()) outputFile.setDerived(true, monitor); } private void refreshOutputFolder(IAssemblySource source, IProgressMonitor monitor) throws CoreException { IFile outputFile = source.getOutputFile(); outputFile.getParent().refreshLocal(IResource.DEPTH_ONE, monitor); } private void ensureOutputFolderFor(IAssemblySource source, IProgressMonitor monitor) throws CoreException { WorkspaceUtilities.ensureDerivedParentExists(source.getOutputFile(), monitor); } private void copyResources(final IAssemblySource source, final IFolder outputFolder, final IProgressMonitor monitor) throws CoreException { source.getFolder().accept(new IResourceVisitor() { public boolean visit(IResource resource) throws CoreException { if (!(resource instanceof IFile)) return true; IFile file = (IFile)resource; if ("config".equals(file.getFileExtension())) { IO.copyFileToFolder(file, outputFolder, monitor); } return true; } }); } private void copyLocalReferences(final IAssemblySource source, final IFolder outputFolder, final IProgressMonitor monitor) throws CoreException { source.visitReferences(new AssemblyReferenceVisitor() { @Override public boolean visit(ILocalAssemblyReference reference) throws CoreException { IO.copyFileToFolder(reference.getFile(), outputFolder, monitor); return true; } @Override public boolean visit(IAssemblySourceReference reference) throws CoreException { IAssemblySource assemblySource = reference.getAssemblySource(); if (assemblySource.getOutputFolder().equals(outputFolder)) return true; IFile outputFile = assemblySource.getOutputFile(); IO.copyFileToFolder(outputFile, outputFolder, monitor); copyDebugInfoOf(outputFile, outputFolder, monitor); return true; } private void copyDebugInfoOf(IFile assemblyFile, final IFolder outputFolder, final IProgressMonitor monitor) throws CoreException { IFile debugInfoFile = debugInfoFileFor(assemblyFile); //debugInfoFile.refreshLocal(0, monitor); if (debugInfoFile.exists()) IO.copyFileToFolder(debugInfoFile, outputFolder, monitor); } private IFile debugInfoFileFor(IFile assemblyFile) { IPath debugInfo = assemblyFile.getProjectRelativePath().addFileExtension(".mdb"); return assemblyFile.getProject().getFile(debugInfo); } @Override public boolean visit(IBooAssemblyReference reference) throws CoreException { String assemblyPath = reference.getCompilerReference(); IFile outputFile = outputFolder.getFile(new Path(assemblyPath).lastSegment()); if (outputFile.exists()) return true; try { IO.copyFile(assemblyPath, outputFile, monitor); } catch (IOException e) { e.printStackTrace(); } return true; } }); } private CompilerError[] launchCompiler(IAssemblySource source, IFile[] files) throws IOException, CoreException { CompilerLauncher launcher = CompilerLauncher.createLauncher(source); launcher.addSourceFiles(files); return launcher.run(); } int reportErrors(IAssemblySource source, CompilerError[] errors) throws IOException { int errorCount = 0; for (CompilerError error : errors) { boolean isError = error.severity == CompilerError.ERROR; String path = error.getPath(); if (path == null) BooMarkers.addErrorMarker(source, error.message); else addMarker(path, error.message, error.line, isError ? IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING); if (isError) ++errorCount; } return errorCount; } }