/* * Definition of a task for jedit build environment. * :tabSize=2:indentSize=2:noTabs=true: * :folding=explicit:collapseFolds=1: * * Copyright (C) 2012 Jarek Czekalski * * 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 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 org.jedit.ant; //{{{ imports import java.io.File; import java.util.Iterator; import java.util.Properties; import org.apache.ivy.ant.IvyRetrieve; import org.apache.ivy.ant.IvyResolve; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.taskdefs.Delete; import org.apache.tools.ant.taskdefs.Expand; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.PropertySet; import org.apache.tools.ant.types.resources.FileResource; import org.apache.tools.ant.types.resources.FileResourceIterator; //}}} /** Takes <code>plugininfo</code> as nested argument and downloads plugin dependencies. Then checks all downloaded jars and tries to satisfy their dependencies. Repeats it until all the dependencies are sastified. Task attributes:<ul> <li><code>todir</code> - destination directory <li><code>ivyfilesdir</code> - directory to place ivy files in. The ivy files are numbered from <code>0</code> to <code>n</code>. <li><code>template</code> - ivy file serving as a template </ul> <p>Warning: erase the contents of <code>todir</code> directory. */ public class DownloadPluginDepsRecTask extends Task { private String sToDir; private File toDir; private String sIvyFilesDir; private String sTemplateFile; /** Plugin info received from caller. We don't want to change it. */ private PluginInfoType pi0; private Project p; private static final String sIvyFilePref = "ivy.plugin.deps"; //{{{ execute method @Override public void execute() { p = getProject(); checkAttrs(); clearOldIvyFiles(); toDir.mkdirs(); PluginInfoType pi = pi0.clone(); log("Initial dependencies of " + pi.getJarName() + " " + pi.getVersion() + ":\n"); log(pi.getDepsString()); boolean bNewDeps = true; int iRound = 0; while (true) { p.log("Downloading recursively plugin dependencies for " + pi.getJarName() + ", round " + iRound); downloadDeps(pi, iRound); bNewDeps = addJarDeps(pi); if (!bNewDeps) { break; } iRound += 1; if (iRound >= 3) { throw new BuildException("Too many rounds (" + iRound + ") while " + "trying to download plugin dependencies recursively."); } } log("Final recursive dependencies of " + pi.getJarName() + " " + pi.getVersion() + ":\n"); log(pi.getDepsString()); } //}}} //{{{ checkAttrs method private void checkAttrs() { if (pi0 == null) { throw new BuildException("pluginInfo not provided"); } if (sToDir == null) { throw new BuildException("todir not provided"); } if (sIvyFilesDir == null) { throw new BuildException("ivyfilesdir not provided"); } if (sTemplateFile == null) { throw new BuildException("template not provided"); } toDir = Misc.getProjectFile(p, sToDir); } //}}} //{{{ clearOldIvyFiles method private void clearOldIvyFiles() { Delete del = (Delete)p.createTask("delete"); del.setDir(Misc.getProjectFile(p, sIvyFilesDir)); del.setIncludes(sIvyFilePref + ".*.xml"); del.execute(); } //}}} //{{{ clearDestDir method private void clearDestDir() { Delete del = (Delete)p.createTask("delete"); del.setDir(toDir); del.setIncludes("*"); del.execute(); } //}}} //{{{ downloadDeps method private void downloadDeps(PluginInfoType pi, int iRound) { // A simplest way in case a plugin needs to be updated is to // erase all and download again. Ivy doesn't really download them // each time, but copies from the cache clearDestDir(); // generate ivy file File ivyFile = new File(Misc.getProjectFile(p, sIvyFilesDir), sIvyFilePref + "." + iRound + ".xml"); GenPluginDepsIvyFileTask gen = new GenPluginDepsIvyFileTask(); gen.setProject(p); gen.setTemplate(sTemplateFile); gen.setOutFile(ivyFile.toString()); gen.add(pi); gen.execute(); // download zips using ivy:resolve and ivy:retrieve tasks p.log(ivyFile+""); IvyResolve res = new IvyResolve(); res.setProject(p); res.setFile(ivyFile); res.setLog("download-only"); res.execute(); IvyRetrieve ret = new IvyRetrieve(); ret.setProject(p); ret.setFile(ivyFile); ret.setPattern(toDir.toString() + "/[artifact].zip"); // ret.setOrganisation("jedit"); // ret.setModule(pi.getJarName()); // ret.setKeep(false); ret.setLog("download-only"); ret.execute(); // unzip them Expand unzip = (Expand)p.createTask("unzip"); unzip.setDest(toDir); FileSet fsZips = new FileSet(); fsZips.setProject(p); fsZips.setDir(toDir); fsZips.setIncludes("*.zip"); unzip.add(fsZips); unzip.execute(); // delete zips Delete del = new Delete(); del.setProject(p); del.add(fsZips); del.execute(); } //}}} //{{{ addJarDeps method /** Opens jars in <code>toDir</code> and adds their plugin dependencies to current dependencies list <code>pi</code>. @param pi Plugin info to which new deps will be added. @return <code>true</code> if new deps were added, <code>false</code> if the jars needn't nothing more than currently in <code>pi</code>. */ private boolean addJarDeps(PluginInfoType pi) { boolean bNewDeps = false; for (String sFile: toDir.list()) { if (sFile.endsWith(".jar")) { StringBuilder sbMsg = new StringBuilder(); PluginInfoType piJar = new PluginInfoType(); piJar.setProject(p); piJar.setJar(new File(toDir, sFile).toString()); if (pi.joinDeps(piJar, sbMsg)) { bNewDeps = true; p.log(piJar.getJarName() + " " + piJar.getVersion() + " needs also:"); p.log(sbMsg.toString()); } } } return bNewDeps; } //}}} // methods setting task parameters {{{ public void add(PluginInfoType pi) { this.pi0 = pi; } public void setToDir(String s) { sToDir = s; } public void setIvyFilesDir(String s) { sIvyFilesDir = s; } public void setTemplate(String s) { sTemplateFile = s; } //}}} }