/* Copyright (C) 2009 Mobile Sorcery AB This program is free software; you can redistribute it and/or modify it under the terms of the Eclipse Public License v1.0. 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 Eclipse Public License v1.0 for more details. You should have received a copy of the Eclipse Public License v1.0 along with this program. It is also available at http://www.eclipse.org/legal/epl-v10.html */ package com.mobilesorcery.sdk.builder.app; import java.io.File; import java.io.IOException; import java.text.MessageFormat; import java.util.Date; import org.eclipse.core.internal.jobs.JobManager; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceDescription; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.equinox.app.IApplication; import org.eclipse.equinox.app.IApplicationContext; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.PlatformUI; import org.osgi.framework.Bundle; import com.mobilesorcery.sdk.core.CoreMoSyncPlugin; import com.mobilesorcery.sdk.core.MoSyncProject; import com.mobilesorcery.sdk.core.Util; import com.mobilesorcery.sdk.finalizer.core.FinalizerParser; import com.mobilesorcery.sdk.finalizer.ui.FinalizeJob; import com.mobilesorcery.sdk.ui.ImportProjectsRunnable; /* Rudimentary headless build */ public class HeadlessBuild implements IApplication { public class BuildRunnable implements Runnable { private final String[] args; private Integer result; private Exception exception; public BuildRunnable(String[] args) { this.args = args; } public Thread start() { Thread buildThread = new Thread(this, "Headless build thread"); //$NON-NLS-1$ buildThread.start(); return buildThread; } @Override public void run() { try { result = startBuild(args); } catch (Exception e) { exception = e; } } public Exception getException() { return exception; } public Integer getResult() { return result; } } @Override public Object start(IApplicationContext context) throws Exception { String osName = System.getProperty("os.name"); boolean isMac = osName.startsWith("Mac") || osName.startsWith("Darwin"); Display dummy = null; if (isMac) { // I know, it's quite ridiculus. dummy = PlatformUI.createDisplay(); Bundle ideBundle = Platform.getBundle("org.eclipse.ui.ide"); if (ideBundle != null) { ideBundle.start(); } } // Make sure it's headless from the start. CoreMoSyncPlugin.setHeadless(true); if (CoreMoSyncPlugin.getDefault().isDebugging()) { CoreMoSyncPlugin.trace( "*** Started headless build at {0,time}, {0,date}", new Date()); } try { // OK, kill the splash context.applicationRunning(); String[] args = (String[]) context.getArguments().get( IApplicationContext.APPLICATION_ARGS); BuildRunnable buildRunnable = new BuildRunnable(args); buildRunnable.start().join(); if (buildRunnable.getException() != null) { System.err.println(buildRunnable.getException()); throw buildRunnable.getException(); } } finally { if (dummy != null) { dummy.dispose(); } if (CoreMoSyncPlugin.getDefault().isDebugging()) { CoreMoSyncPlugin.trace( "*** Stopped headless build at {0,time}, {0,date}", new Date()); } } return EXIT_OK; } Integer startBuild(String[] args) throws Exception { IWorkspace ws = ResourcesPlugin.getWorkspace(); int i = 0; String projectName = null; String importProject = null; String finalizerScript = null; String cfgId = null; while (i < args.length) { String arg = args[i]; String nextArg = i == args.length - 1 ? "" : args[i + 1]; //$NON-NLS-1$ if ("-project".equals(arg)) { //$NON-NLS-1$ projectName = nextArg; i++; } else if ("-import".equals(arg)) { importProject = nextArg; i++; } else if ("-f".equals(arg)) { //$NON-NLS-1$ finalizerScript = nextArg; i++; } else if ("-cfg".equals(arg)) { //$NON-NLS-1$ cfgId = nextArg; i++; } i++; } if (projectName == null && importProject == null) { printUsage(); throw new Exception(Messages.HeadlessBuild_Usage); } if (importProject != null) { IPath projectDescriptionFile = new Path(importProject).append(".project"); IPath projectMetaDataFile = new Path(importProject).append(MoSyncProject.MOSYNC_PROJECT_META_DATA_FILENAME); if (projectName == null) { IProjectDescription desc = ResourcesPlugin.getWorkspace().loadProjectDescription(projectDescriptionFile); projectName = desc.getName(); } ImportProjectsRunnable importer = new ImportProjectsRunnable(new File[] { projectMetaDataFile.toFile() }, new String[] { projectName }, ImportProjectsRunnable.DO_NOT_COPY); importer.createJob(true).join(); } IProject project = ws.getRoot().getProject(projectName); if (!project.exists() || !project.isOpen()) { throw new IOException(Messages.HeadlessBuild_IllegalProjectState); } MoSyncProject mosyncProject = MoSyncProject.create(project); if (cfgId != null && mosyncProject.getBuildConfiguration(cfgId) == null) { String availableCfgs = Util.join(mosyncProject .getBuildConfigurations().toArray(), ", "); throw new IOException( MessageFormat .format("Unknown build configuration: {0}. Available configurations for this project are: {1}", cfgId, availableCfgs)); } String script = null; if (finalizerScript != null) { script = Util.readFile(finalizerScript); } FinalizerParser parser = new FinalizerParser(project); if (script == null) { script = parser.extractScriptFromProject(mosyncProject); } FinalizeJob job = new FinalizeJob(mosyncProject, script, cfgId); job.setUser(true); job.setRule(mosyncProject.getWrappedProject().getWorkspace().getRuleFactory().buildRule()); job.schedule(); job.join(); IStatus result = job.getResult(); if (result.getSeverity() != IStatus.OK) { throw new CoreException(result); } return EXIT_OK; } private void printUsage() { System.err.println(Messages.HeadlessBuild_Usage); } @Override public void stop() { } }