package org.applause.lang.ui.builder; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.regex.Pattern; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang.ArrayUtils; import org.applause.lang.applauseDsl.Application; 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.IncrementalProjectBuilder; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.emf.ecore.EObject; import org.eclipse.xpand2.XpandExecutionContextImpl; import org.eclipse.xpand2.XpandFacade; import org.eclipse.xpand2.output.FileHandle; import org.eclipse.xpand2.output.Outlet; import org.eclipse.xpand2.output.Output; import org.eclipse.xpand2.output.OutputImpl; import org.eclipse.xpand2.output.VetoException; import org.eclipse.xtend.expression.Variable; import org.eclipse.xtend.type.impl.java.JavaBeansMetaModel; import org.eclipse.xtext.EcoreUtil2; import org.eclipse.xtext.builder.IXtextBuilderParticipant.IBuildContext; import org.eclipse.xtext.resource.IEObjectDescription; import org.eclipse.xtext.resource.IResourceDescription.Delta; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Iterables; public abstract class AbstractBuildStrategy { private IProject modelProject; private IProject platformProject; private IBuildContext context; protected IBuildContext getContext() { return context; } public void setContext(IBuildContext context) { this.context = context; } public IProject getModelProject() { return modelProject; } public void setModelProject(IProject modelProject) { this.modelProject = modelProject; } public IProject getPlatformProject() { return platformProject; } public void setPlatformProject(IProject platformProject) { this.platformProject = platformProject; } protected abstract boolean canBuildProject(); public void build(IProgressMonitor monitor) throws CoreException { if (canBuildProject()) { final IFolder folder = getPlatformProject().getFolder(getGeneratedSourcesFolderName()); // FIXME: maybe we should just create the folder if it's missing?! if (!folder.exists()) return; List<EObject> objects = new ArrayList<EObject>(); for (Delta d : context.getDeltas()) { if (d.getNew() != null) { for (IEObjectDescription desc : d.getNew().getExportedObjects()) { EObject obj = context.getResourceSet().getEObject(desc.getEObjectURI(), true); EcoreUtil2.resolveAll(context.getResourceSet()); objects.add(obj); } } } Iterable<Application> applicationObjects = Iterables.filter(objects, Application.class); if(!Iterables.isEmpty(applicationObjects)) { deletePreviouslyGeneratedFiles(monitor, folder); } for (Application app : applicationObjects) { OutputImpl output = new OutputImpl(); Outlet outlet = createOutlet(folder); configureOutlet(outlet); output.addOutlet(outlet); // IFolder rootFolder = (IFolder) getPlatformProject().getAdapter(IFolder.class); // // IPath location = getPlatformProject().getFullPath(); // // IFolder rootFolder = ResourcesPlugin.getWorkspace().getRoot().getFolder(location); // Outlet projectRootOutlet = createOutlet(rootFolder); // projectRootOutlet.setName("ROOT"); // output.addOutlet(projectRootOutlet); generate(app, output); copyResources(app, getModelProject().getFolder("/Images")); getPlatformProject().build(IncrementalProjectBuilder.CLEAN_BUILD, monitor); return; } } } protected boolean isFileInHighResFolder(IFile file) { String[] segments = file.getFullPath().segments(); return ArrayUtils.contains(segments, "highres"); } protected void copyResources(Application app, IFolder sourceFolder) throws CoreException { Collection<IFile> allImageFiles = collectAllImageFiles(sourceFolder); Predicate<IFile> highresPredicate = new Predicate<IFile>() { @Override public boolean apply(IFile input) { if (input.getName().contains("@2x")) { return true; } else if (isFileInHighResFolder(input)) { return true; } return false; } }; Iterable<IFile> highresImages = Iterables.filter(allImageFiles, highresPredicate); Predicate<IFile> lowresPredicate = Predicates.not(highresPredicate); Iterable<IFile> lowresImages = Iterables.filter(allImageFiles, lowresPredicate); copyLowResImages(lowresImages); copyHighResImages(highresImages); copySplash(app, sourceFolder); } protected abstract void copySplash(Application app, IFolder folder) throws CoreException; protected abstract IFolder getHighResImageDestinationFolder(IFile file); protected abstract String getHighResImageFileName(String normalizedFileName); protected abstract IFolder getImageDestinationFolder(IFile file); protected abstract String getImageFileName(String normalizedFileName); private String getNormalizedFileName(IFile file) { String baseName = FilenameUtils.getBaseName(file.getName()); if (baseName.endsWith("@2x")) { return baseName.substring(0, baseName.lastIndexOf("@2x")) + "." + file.getFileExtension(); } else { return file.getName(); } } private void copyHighResImages(Iterable<IFile> highresImages) throws CoreException { for (IFile file : highresImages) { IFolder destinationFolder = getHighResImageDestinationFolder(file); String imageFileName = getHighResImageFileName(getNormalizedFileName(file)); if ( (destinationFolder != null) && (imageFileName != null)) { if (isValidFilename(FilenameUtils.getBaseName(imageFileName))) { IFile targetFile = destinationFolder.getFile(imageFileName); if (!targetFile.exists()) { file.copy(targetFile.getFullPath(), true, null); } } } } } private void copyLowResImages(Iterable<IFile> lowresImages) throws CoreException { for (IFile file : lowresImages) { IFolder destinationFolder = getImageDestinationFolder(file); String imageFileName = getImageFileName(getNormalizedFileName(file)); if ( (destinationFolder != null) && (imageFileName != null)) { if (isValidFilename(FilenameUtils.getBaseName(imageFileName))) { IFile targetFile = destinationFolder.getFile(imageFileName); if (!targetFile.exists()) { file.copy(targetFile.getFullPath(), true, null); } } } } } protected static final String[] IMAGE_FILE_EXTS = {"png", "jpg"}; protected boolean isImageFile(IFile file) { return (ArrayUtils.contains(IMAGE_FILE_EXTS, file.getFileExtension())); } protected boolean isValidFilename(String filename) { return true; } protected Collection<IFile> collectAllImageFiles(IFolder sourceFolder) throws CoreException { Collection<IFile> files = new ArrayList<IFile>(); IResource[] members = sourceFolder.members(); for (IResource resource : members) { if (resource instanceof IFile) { IFile file = (IFile)resource; if (isImageFile(file)) { files.add(file); } } else if (resource instanceof IFolder) { files.addAll(collectAllImageFiles((IFolder)resource)); } } return files; } private Outlet createOutlet(final IFolder folder) { Outlet outlet = new Outlet() { @Override public FileHandle createFileHandle(String qualifiedName) throws VetoException { return AbstractBuildStrategy.this.createFileHandle(folder, this, qualifiedName); } }; return outlet; } protected void deletePreviouslyGeneratedFiles(IProgressMonitor monitor, final IFolder folder) throws CoreException { for (IResource res : folder.members()) { if (res instanceof IFile) { IFile file = (IFile) res; file.delete(true, monitor); } } } protected abstract void configureOutlet(Outlet outlet); protected FileHandle createFileHandle(IFolder folder, Outlet outlet, String qualifiedName) { IFile file = folder.getFile(new Path(qualifiedName)); try { file.setDerived(true, new NullProgressMonitor()); } catch (CoreException e) { } return new EclipseBasedFileHandle(file, outlet); } protected abstract String getGeneratedSourcesFolderName(); public void generate(Application app, Output output) { System.out.println("Generating code for platform project " + getPlatformProject().getName() + " from model in model project " + context.getBuiltProject()); XpandExecutionContextImpl ctx = new XpandExecutionContextImpl(output, null, Collections.<String, Variable>emptyMap(), null, null); ctx.registerMetaModel(new JavaBeansMetaModel()); try { XpandFacade.create(ctx).evaluate(getMainTemplateName(), app); } catch (Exception e) { e.printStackTrace(); } } protected abstract String getMainTemplateName(); protected IFile findFile(IContainer container, String fileSpec) { Pattern pattern = Pattern.compile(fileSpec); try { IResource[] members = container.members(); for (IResource resource : members) { if (resource instanceof IFile) { IFile file = (IFile) resource; if (pattern.matcher(file.getName()).matches()) { return file; } } } } catch (CoreException e) { e.printStackTrace(); } return null; } public abstract String getName(); }