Java tutorial
/* * Copyright 2016 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.diffplug.gradle.pde; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Optional; import org.apache.commons.io.FileUtils; import org.gradle.api.Project; import org.osgi.framework.Version; import com.diffplug.common.base.Comparison; import com.diffplug.common.base.Preconditions; import com.diffplug.common.base.StringPrinter; import com.diffplug.common.swt.os.OS; import com.diffplug.common.swt.os.SwtPlatform; import com.diffplug.gradle.FileMisc; import com.diffplug.gradle.GoomphCacheLocations; import com.diffplug.gradle.eclipserunner.EclipseApp; import com.diffplug.gradle.eclipserunner.EclipseRunner; import com.diffplug.gradle.eclipserunner.NativeRunner; import com.diffplug.gradle.p2.P2Model; /** Wraps a PDE installation for the given eclipse release.*/ public class PdeInstallation implements EclipseRunner { /** * Returns a PdeInstallation based on `GOOMPH_PDE_VER`, and other factors. * * You must specify which version of Eclipse should be used by Goomph. * - Option #1: To use an officially supported release, use this: * + `GOOMPH_PDE_VER`=4.5.2 (or any official release) * - Option #2: To use any release (e.g. milestone, nightly, etc) * + `GOOMPH_PDE_VER`=<any version> * + `GOOMPH_PDE_UDPATE_SITE`=<url to update site> * + `GOOMPH_PDE_ID`=<the ID used for caching, cannot be a version listed in Option #1) * * You must do one or the other, specify only `VER` for Option #1, * or specify `VER`, `UPDATE_SITE`, and `ID` for Option #2. */ public static PdeInstallation fromProject(Project project) { String version = (String) project.getProperties().get("GOOMPH_PDE_VER"); String updateSite = (String) project.getProperties().get("GOOMPH_PDE_UDPATE_SITE"); String id = (String) project.getProperties().get("GOOMPH_PDE_ID"); // to use a default PDE build, use String USAGE = StringPrinter.buildStringFromLines( "You must specify which version of Eclipse should be used by Goomph.", "Option #1: To use an officially supported release, use this:", "GOOMPH_PDE_VER=4.5.2 (or any of " + EclipseRelease.supportedRange() + ")", "Option #2: To use any release (e.g. milestone, nightly, etc)", "GOOMPH_PDE_VER=<any version>", "GOOMPH_PDE_UDPATE_SITE=<url to update site>", "GOOMPH_PDE_ID=<the ID used for caching, cannot be a version listed in Option #1)", "", "You must do one or the other, specify only VER for Option #1,", "or specify VER, UPDATE_SITE, and ID for Option #2"); if (version == null) { throw new IllegalArgumentException(USAGE); } if (updateSite == null && id == null) { try { return new PdeInstallation(EclipseRelease.official(version)); } catch (IllegalArgumentException e) { throw new IllegalArgumentException(USAGE, e); } } if (updateSite == null || id == null) { throw new IllegalArgumentException(USAGE); } return from(EclipseRelease.createWithIdVersionUpdatesite(id, version, updateSite)); } /** Returns an EclipseRunner for running PDE build against the given release. */ public static PdeInstallation from(EclipseRelease release) { return new PdeInstallation(release); } final EclipseRelease release; public PdeInstallation(EclipseRelease release) { this.release = Objects.requireNonNull(release); // warn if mac and pre-Mars if (OS.getNative().isMac()) { if (Comparison.compare(release.version(), Version.parseVersion("4.5.0")) == Comparison.LESSER) { throw new IllegalArgumentException( "On mac, must be 4.5.0 (Mars) or later, because of folder layout problems."); } } } /** The root of this installation. */ private File getRootFolder() { return new File(GoomphCacheLocations.pdeBootstrap(), release.toString() + FileMisc.macApp()); } /** The `org.eclipse.pde.build` folder containing the product build properties file. */ File getPdeBuildFolder() throws Exception { ensureInstalled(); return Objects.requireNonNull(pdeBuildFolder); } /** Returns the "productBuild.xml" file. */ File getPdeBuildProductBuildXml() throws Exception { return getPdeBuildFolder().toPath().resolve("scripts/productBuild/productBuild.xml").toFile(); } /** Returns a command which will execute the PDE builder for a product. */ public EclipseApp productBuildCmd(File buildDir) throws Exception { EclipseApp antApp = new EclipseApp(EclipseApp.AntRunner.ID); antApp.addArg("buildfile", getPdeBuildProductBuildXml().getAbsolutePath()); antApp.addArg("Dbuilder=" + FileMisc.quote(buildDir)); return antApp; } /** * The "org.eclipse.pde.build" folder for this installation. * * Set when install() succeeds and when isInstalled() returns true, so it is * guaranteed to be set when ensureInstalled completes. */ private File pdeBuildFolder; static final String TOKEN = "installed"; /** Makes sure that the installation is prepared. */ private void ensureInstalled() throws Exception { if (!isInstalled()) { install(); } } /** Returns true iff it is installed. */ private boolean isInstalled() throws IOException { Optional<String> pdeBuild = FileMisc.readToken(getRootFolder(), TOKEN); pdeBuildFolder = pdeBuild.map(File::new).orElse(null); return pdeBuildFolder != null; } /** Installs the bootstrap installation. */ private void install() throws Exception { System.out.print("Installing pde " + release + "... "); P2Model.DirectorApp directorApp = p2model().directorApp(getRootFolder(), "goomph-pde-bootstrap-" + release); // share the install for quickness directorApp.bundlepool(GoomphCacheLocations.bundlePool()); // create a native launcher directorApp.platform(SwtPlatform.getRunning()); directorApp.runUsingBootstrapper(); // parse out the pde.build version File bundleInfo = new File(getContentsEclipse(), "configuration/org.eclipse.equinox.simpleconfigurator/bundles.info"); Preconditions.checkArgument(bundleInfo.isFile(), "Needed to find the pde.build folder: %s", bundleInfo); String pdeBuildLine = Files.readAllLines(bundleInfo.toPath()).stream() .filter(line -> line.startsWith("org.eclipse.pde.build,")).findFirst().get(); String pdeBuildVersion = pdeBuildLine.split(",")[1]; // find the plugins folder pdeBuildFolder = new File(GoomphCacheLocations.bundlePool(), "plugins/org.eclipse.pde.build_" + pdeBuildVersion); FileMisc.writeToken(getRootFolder(), TOKEN, pdeBuildFolder.getAbsolutePath()); System.out.println("Success."); } /** Returns the Contents/Eclipse folder on mac, or just the root folder on other OSes. */ private File getContentsEclipse() { if (OS.getNative().isMac()) { return new File(getRootFolder(), "Contents/Eclipse"); } else { return getRootFolder(); } } /** Creates a model containing pde build and the native launder. */ P2Model p2model() { P2Model model = new P2Model(); // the update site for the release we're downloading artifacts for model.addRepo(release.updateSite()); // the required IDE root product model.addIU("org.eclipse.platform.ide"); // ant builder model.addFeature("org.eclipse.jdt"); // pde build model.addFeature("org.eclipse.pde"); return model; } /** Returns the eclipse console executable. */ private String getEclipseConsoleExecutable() { return OS.getNative().winMacLinux("eclipsec.exe", "Contents/MacOS/eclipse", "eclipse"); } @Override public void run(List<String> args) throws Exception { ensureInstalled(); // set a clean workspace List<String> actualArgs = new ArrayList<>(); actualArgs.add("-data"); File workspace = new File(getRootFolder(), FileMisc.macContentsEclipse() + "workspace"); actualArgs.add(workspace.getAbsolutePath()); // add the user's args actualArgs.addAll(args); // run the code try { new NativeRunner(new File(getRootFolder(), getEclipseConsoleExecutable())).run(actualArgs); } finally { // clean the workspace directory FileUtils.deleteDirectory(workspace); } } }