diff options
Diffstat (limited to 'plugins/org.eclipse.emf.cdo.releng.setup/src/org/eclipse/emf/cdo/releng/internal/setup/SetupTaskPerformer.java')
-rw-r--r-- | plugins/org.eclipse.emf.cdo.releng.setup/src/org/eclipse/emf/cdo/releng/internal/setup/SetupTaskPerformer.java | 540 |
1 files changed, 540 insertions, 0 deletions
diff --git a/plugins/org.eclipse.emf.cdo.releng.setup/src/org/eclipse/emf/cdo/releng/internal/setup/SetupTaskPerformer.java b/plugins/org.eclipse.emf.cdo.releng.setup/src/org/eclipse/emf/cdo/releng/internal/setup/SetupTaskPerformer.java new file mode 100644 index 0000000000..a101cd47c5 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.releng.setup/src/org/eclipse/emf/cdo/releng/internal/setup/SetupTaskPerformer.java @@ -0,0 +1,540 @@ +/* + * Copyright (c) 2004-2013 Eike Stepper (Berlin, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.emf.cdo.releng.internal.setup; + +import org.eclipse.emf.cdo.releng.internal.setup.ui.ProgressLogDialog; +import org.eclipse.emf.cdo.releng.setup.Branch; +import org.eclipse.emf.cdo.releng.setup.Project; +import org.eclipse.emf.cdo.releng.setup.Setup; +import org.eclipse.emf.cdo.releng.setup.SetupTask; +import org.eclipse.emf.cdo.releng.setup.SetupTaskContext; +import org.eclipse.emf.cdo.releng.setup.Trigger; +import org.eclipse.emf.cdo.releng.setup.util.OS; +import org.eclipse.emf.cdo.releng.setup.util.log.ProgressLog; +import org.eclipse.emf.cdo.releng.setup.util.log.ProgressLogRunnable; + +import org.eclipse.emf.common.util.BasicEList; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; + +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IPath; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Eike Stepper + */ +public class SetupTaskPerformer extends HashMap<Object, Object> implements SetupTaskContext +{ + private static final String RELENG_URL = System.getProperty("releng.url", + "http://download.eclipse.org/modeling/emf/cdo/updates/integration").replace('\\', '/'); + + private static final long serialVersionUID = 1L; + + private static ProgressLog progress; + + private Trigger trigger; + + private File branchDir; + + private Setup setup; + + private transient boolean restartNeeded; + + private List<String> logMessageBuffer; + + public SetupTaskPerformer(File branchDir) + { + trigger = Trigger.BOOTSTRAP; + + this.branchDir = branchDir; + + initialize(); + } + + public SetupTaskPerformer(boolean manual) throws Exception + { + trigger = manual ? Trigger.MANUAL : Trigger.STARTUP; + + IPath branchDirPath = ResourcesPlugin.getWorkspace().getRoot().getLocation().removeLastSegments(1); + branchDir = new File(branchDirPath.toOSString()).getCanonicalFile(); + + initialize(); + } + + private void initialize() + { + ResourceSet resourceSet = new ResourceSetImpl(); + resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xmi", new XMIResourceFactoryImpl()); + + URI uri = URI.createFileURI(branchDir.toString() + "/setup.xmi"); + Resource resource = resourceSet.getResource(uri, true); + + setup = (Setup)resource.getContents().get(0); + + Branch branch = setup.getBranch(); + String branchName = branch.getName(); + + Project project = branch.getProject(); + String projectName = project.getName(); + + put("setup.git.prefix", setup.getPreferences().getGitPrefix()); + put("setup.install.dir", getInstallDir()); + put("setup.project.dir", getProjectDir()); + put("setup.branch.dir", getBranchDir()); + put("setup.eclipse.dir", getEclipseDir()); + put("setup.tp.dir", getTargetPlatformDir()); + put("setup.ws.dir", getWorkspaceDir()); + put("setup.project.name", projectName); + put("setup.branch.name", branchName); + put("releng.url", RELENG_URL); + } + + public void dispose() + { + setup = null; + branchDir = null; + } + + public void log(String line) + { + if (progress != null) + { + if (logMessageBuffer != null) + { + for (String value : logMessageBuffer) + { + progress.log(value); + } + + logMessageBuffer = null; + } + + progress.log(line); + } + else + { + if (logMessageBuffer == null) + { + logMessageBuffer = new ArrayList<String>(); + } + + logMessageBuffer.add(line); + } + } + + public boolean isCancelled() + { + if (progress != null) + { + return progress.isCancelled(); + } + + return false; + } + + public Trigger getTrigger() + { + return trigger; + } + + public boolean isRestartNeeded() + { + return restartNeeded; + } + + public void setRestartNeeded() + { + restartNeeded = true; + } + + private static final Pattern PATTERN = Pattern.compile("\\$\\{([^${}|]+)(\\|([^}]+))?}"); + + protected String lookup(String key) + { + Object object = get(key); + if (object != null) + { + return object.toString(); + } + + return System.getProperty(key, key); + } + + interface StringFilter + { + public String filter(String value); + } + + private static final Map<String, StringFilter> FILTERS = new HashMap<String, StringFilter>(); + + static + { + FILTERS.put("uri", new StringFilter() + { + public String filter(String value) + { + return URI.createFileURI(value).toString(); + } + }); + FILTERS.put("upper", new StringFilter() + { + public String filter(String value) + { + return value.toUpperCase(); + } + }); + FILTERS.put("lower", new StringFilter() + { + public String filter(String value) + { + return value.toLowerCase(); + } + }); + } + + protected String filter(String value, String filterName) + { + StringFilter filter = FILTERS.get(filterName); + if (filter != null) + { + return filter.filter(value); + } + + return value; + } + + public String expandString(String string) + { + StringBuilder result = new StringBuilder(); + int previous = 0; + for (Matcher matcher = PATTERN.matcher(string); matcher.find();) + { + result.append(string.substring(previous, matcher.start())); + String key = matcher.group(1); + String value = lookup(key); + String filters = matcher.group(3); + if (filters != null) + { + for (String filterName : filters.split("\\|")) + { + value = filter(value, filterName); + } + } + result.append(value); + previous = matcher.end(); + } + result.append(string.substring(previous)); + return result.toString(); + } + + public OS getOS() + { + return OS.INSTANCE; + } + + public String getP2ProfileName() + { + Branch branch = setup.getBranch(); + Project project = branch.getProject(); + + String profileName = project.getName() + "_" + branch.getName(); + profileName = profileName.replace('.', '_'); + profileName = profileName.replace('-', '_'); + profileName = profileName.replace('/', '_'); + profileName = profileName.replace('\\', '_'); + return profileName; + } + + public File getP2ProfileDir() + { + return new File(getP2AgentDir(), "org.eclipse.equinox.p2.engine/profileRegistry/" + getP2ProfileName() + ".profile"); + } + + public File getP2AgentDir() + { + return new File(getP2PoolDir(), "p2"); + } + + public File getP2PoolDir() + { + return new File(getInstallDir(), ".p2pool-ide"); + } + + public File getInstallDir() + { + return getProjectDir().getParentFile(); + } + + public File getProjectDir() + { + return branchDir.getParentFile(); + } + + public File getBranchDir() + { + return branchDir; + } + + public File getEclipseDir() + { + return new File(branchDir, "eclipse"); + } + + // TODO Is this Bucky-specific? + public File getTargetPlatformDir() + { + return new File(branchDir, "tp"); + } + + public File getWorkspaceDir() + { + return new File(branchDir, "ws"); + } + + public Setup getSetup() + { + return setup; + } + + public void perform() throws Exception + { + EList<SetupTask> setupTasks = setup.getSetupTasks(true, trigger); + if (setupTasks.isEmpty()) + { + return; + } + + Map<SetupTask, SetupTask> substitutions = getSubstitutions(setupTasks); + setup = copySetup(setupTasks, substitutions); + + perform(setupTasks); + } + + private void perform(EList<SetupTask> setupTasks) throws Exception + { + final EList<SetupTask> neededTasks = getNeededTasks(setupTasks); + if (neededTasks.isEmpty()) + { + return; + } + + if (Activator.SETUP_IDE && trigger != Trigger.MANUAL) + { + File logFile = new File(getInstallDir(), "setup.log"); + IWorkbenchWindow window = PlatformUI.getWorkbench().getWorkbenchWindows()[0]; + final Shell shell = window.getShell(); + ProgressLogDialog.run(shell, logFile, "Setting up IDE", new ProgressLogRunnable() + { + public boolean run(ProgressLog log) throws Exception + { + doPerform(neededTasks); + return isRestartNeeded(); + } + }); + } + else + { + doPerform(neededTasks); + } + } + + private void doPerform(EList<SetupTask> neededTasks) throws Exception + { + Branch branch = setup.getBranch(); + log("Setting up " + branch.getProject().getName() + " " + branch.getName()); + + for (SetupTask neededTask : neededTasks) + { + neededTask.perform(this); + neededTask.dispose(); + } + } + + private Map<SetupTask, SetupTask> getSubstitutions(EList<SetupTask> setupTasks) + { + SetupTaskComparator.sort(setupTasks); + + Map<Object, SetupTask> overrides = new HashMap<Object, SetupTask>(); + Map<SetupTask, SetupTask> substitutions = new HashMap<SetupTask, SetupTask>(); + + for (SetupTask setupTask : setupTasks) + { + Object overrideToken = setupTask.getOverrideToken(); + SetupTask overriddenTask = overrides.put(overrideToken, setupTask); + if (overriddenTask != null) + { + substitutions.put(overriddenTask, setupTask); + } + } + + // Shorten the paths through the substitutions map + for (Map.Entry<SetupTask, SetupTask> entry : substitutions.entrySet()) + { + SetupTask task = entry.getValue(); + + for (;;) + { + SetupTask overridingTask = substitutions.get(task); + if (overridingTask == null) + { + break; + } + + entry.setValue(overridingTask); + } + } + + return substitutions; + } + + private Setup copySetup(EList<SetupTask> setupTasks, Map<SetupTask, SetupTask> substitutions) + { + Set<EObject> roots = new LinkedHashSet<EObject>(); + roots.add(setup); + + for (EObject eObject : setup.eCrossReferences()) + { + EObject rootContainer = EcoreUtil.getRootContainer(eObject); + roots.add(rootContainer); + } + + EcoreUtil.Copier copier = new EcoreUtil.Copier(); + Setup setup = (Setup)copier.copyAll(roots).iterator().next(); + + for (Map.Entry<SetupTask, SetupTask> entry : substitutions.entrySet()) + { + SetupTask overriddenTask = entry.getKey(); + SetupTask overridingTask = entry.getValue(); + + EObject copy = copier.get(overridingTask); + copier.put(overriddenTask, copy); + } + + copier.copyReferences(); + + for (ListIterator<SetupTask> it = setupTasks.listIterator(); it.hasNext();) + { + SetupTask setupTask = it.next(); + if (substitutions.containsKey(setupTask)) + { + it.remove(); + } + else + { + SetupTask copy = (SetupTask)copier.get(setupTask); + it.set(copy); + } + } + + SetupTaskComparator.sort(setupTasks); + return setup; + } + + private EList<SetupTask> getNeededTasks(EList<SetupTask> setupTasks) throws Exception + { + EList<SetupTask> result = new BasicEList<SetupTask>(); + + for (Iterator<SetupTask> it = setupTasks.iterator(); it.hasNext();) + { + SetupTask setupTask = it.next(); + if (setupTask.isNeeded(this)) + { + result.add(setupTask); + } + else + { + setupTask.dispose(); + } + } + + return result; + } + + public static ProgressLog getProgress() + { + return progress; + } + + public static void setProgress(ProgressLog progress) + { + SetupTaskPerformer.progress = progress; + } + + /** + * @author Eike Stepper + */ + public static class SetupTaskComparator implements Comparator<SetupTask> + { + public static void sort(EList<SetupTask> setupTasks) + { + Collections.sort(setupTasks, new SetupTaskComparator()); + } + + public int compare(SetupTask t1, SetupTask t2) + { + boolean t1RequiresT2 = t1.requires(t2); + boolean t2RequiresT1 = t2.requires(t1); + if (t1RequiresT2 && t2RequiresT1) + { + throw new IllegalStateException("Requirements cycle detected between " + t1 + " and " + t2); + } + + if (t1RequiresT2 && !t2RequiresT1) + { + return 1; + } + + if (!t1RequiresT2 && t2RequiresT1) + { + return -1; + } + + int scope1 = t1.getScope().getValue(); + int scope2 = t2.getScope().getValue(); + if (scope1 < scope2) + { + return -1; + } + + if (scope1 > scope2) + { + return 1; + } + + String uri1 = EcoreUtil.getURI(t1).toString(); + String uri2 = EcoreUtil.getURI(t2).toString(); + return uri1.compareTo(uri2); // Arbitrary but symmetric within one ResourceSet + } + } +} |