processing.app.contrib.AvailableContribution Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pde Show documentation
Show all versions of pde Show documentation
Processing is a programming language, development environment, and online community.
This PDE package contains the Processing IDE.
The newest version!
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2013-16 The Processing Foundation
Copyright (c) 2011-12 Ben Fry and Casey Reas
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
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 processing.app.contrib;
import java.io.*;
import processing.app.Base;
import processing.app.Language;
import processing.app.Platform;
import processing.app.Util;
import processing.core.PApplet;
import processing.data.StringDict;
import processing.data.StringList;
/**
* A class to hold information about a Contribution that can be downloaded.
*/
public class AvailableContribution extends Contribution {
protected final ContributionType type; // Library, tool, etc.
protected final String link; // Direct link to download the file
public AvailableContribution(ContributionType type, StringDict params) {
this.type = type;
this.link = params.get("download");
categories = parseCategories(params);
imports = parseImports(params);
name = params.get("name");
authors = params.get("authors");
// if (authors == null) {
// authors = params.get("authorList");
// }
url = params.get("url");
sentence = params.get("sentence");
paragraph = params.get("paragraph");
String versionStr = params.get("version");
if (versionStr != null) {
version = PApplet.parseInt(versionStr, 0);
}
setPrettyVersion(params.get("prettyVersion"));
String lastUpdatedStr = params.get("lastUpdated");
if (lastUpdatedStr != null) {
try {
lastUpdated = Long.parseLong(lastUpdatedStr);
} catch (NumberFormatException e) {
lastUpdated = 0;
}
}
String minRev = params.get("minRevision");
if (minRev != null) {
minRevision = PApplet.parseInt(minRev, 0);
}
String maxRev = params.get("maxRevision");
if (maxRev != null) {
maxRevision = PApplet.parseInt(maxRev, 0);
}
}
/**
* @param contribArchive
* a zip file containing the library to install
* @param confirmReplace
* true to open a dialog asking the user to confirm removing/moving
* the library when a library by the same name already exists
* @param status
* the StatusPanel. Pass null if this function is called for an
* install-on-startup
* @return
*/
public LocalContribution install(Base base, File contribArchive,
boolean confirmReplace, StatusPanel status) {
// Unzip the file into the modes, tools, or libraries folder inside the
// sketchbook. Unzipping to /tmp is problematic because it may be on
// another file system, so move/rename operations will break.
// File sketchbookContribFolder = type.getSketchbookFolder();
File tempFolder = null;
try {
tempFolder = type.createTempFolder();
} catch (IOException e) {
if (status != null)
status.setErrorMessage(Language.text("contrib.errors.temporary_directory"));
return null;
}
Util.unzip(contribArchive, tempFolder);
// System.out.println("temp folder is " + tempFolder);
// Base.openFolder(tempFolder);
// Now go looking for a legit contrib inside what's been unpacked.
File contribFolder = null;
// Sometimes contrib authors place all their folders in the base directory
// of the .zip file instead of in single folder as the guidelines suggest.
if (type.isCandidate(tempFolder)) {
/*
// Can't just rename the temp folder, because a contrib with this name
// may already exist. Instead, create a new temp folder, and rename the
// old one to be the correct folder.
File enclosingFolder = null;
try {
enclosingFolder = Base.createTempFolder(type.toString(), "tmp", sketchbookContribFolder);
} catch (IOException e) {
status.setErrorMessage("Could not create a secondary folder to install.");
return null;
}
contribFolder = new File(enclosingFolder, getName());
tempFolder.renameTo(contribFolder);
tempFolder = enclosingFolder;
*/
if (status != null) {
status.setErrorMessage(Language.interpolate("contrib.errors.needs_repackage", getName(), type.getTitle()));
}
return null;
}
// if (contribFolder == null) {
// Find the first legitimate looking folder in what we just unzipped
contribFolder = type.findCandidate(tempFolder);
// }
LocalContribution installedContrib = null;
if (contribFolder == null) {
if (status != null) {
status.setErrorMessage(Language.interpolate("contrib.errors.no_contribution_found", type));
}
} else {
File propFile = new File(contribFolder, type + ".properties");
if (writePropertiesFile(propFile)) {
// 1. contribFolder now has a legit contribution, load it to get info.
LocalContribution newContrib = type.load(base, contribFolder);
// 1.1. get info we need to delete the newContrib folder later
File newContribFolder = newContrib.getFolder();
// 2. Check to make sure nothing has the same name already,
// backup old if needed, then move things into place and reload.
installedContrib =
newContrib.copyAndLoad(base, confirmReplace, status);
// Restart no longer needed. Yay!
// if (newContrib != null && type.requiresRestart()) {
// installedContrib.setRestartFlag();
// //status.setMessage("Restart Processing to finish the installation.");
// }
// 3.1 Unlock all the jars if it is a mode or tool
if (newContrib.getType() == ContributionType.MODE) {
((ModeContribution) newContrib).clearClassLoader(base);
}
else if (newContrib.getType() == ContributionType.TOOL) {
((ToolContribution) newContrib).clearClassLoader();
}
// 3.2 Delete the newContrib, do a garbage collection, hope and pray
// that Java will unlock the temp folder on Windows now
newContrib = null;
System.gc();
if (Platform.isWindows()) {
// we'll even give it a second to finish up ... because file ops are
// just that flaky on Windows.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 4. Okay, now actually delete that temp folder
Util.removeDir(newContribFolder, false);
} else {
if (status != null) {
status.setErrorMessage(Language.text("contrib.errors.overwriting_properties"));
}
}
}
// Remove any remaining boogers
if (tempFolder.exists()) {
Util.removeDir(tempFolder, false);
}
return installedContrib;
}
public boolean isInstalled() {
return false;
}
public ContributionType getType() {
return type;
}
/**
* We overwrite those fields that aren't proper in the properties file with
* the curated version from the Processing site. This ensures that things have
* been cleaned up (for instance, that the "sentence" is really a sentence)
* and that bad data from the contrib's .properties file doesn't break the
* manager. However, it also ensures that valid fields in the properties file
* aren't overwritten, since the properties file may be more recent than the
* contributions.txt file.
*/
public boolean writePropertiesFile(File propFile) {
try {
StringDict properties = Util.readSettings(propFile);
String name = properties.get("name");
if (name == null || name.isEmpty()) {
name = getName();
}
String category;
StringList categoryList = parseCategories(properties);
if (categoryList.size() == 1 &&
categoryList.get(0).equals(UNKNOWN_CATEGORY)) {
category = getCategoryStr();
} else {
category = categoryList.join(",");
}
StringList importsList = parseImports(properties);
String authors = properties.get(AUTHORS_PROPERTY);
// if (authors == null) {
// authors = properties.get("authorList"); // before 3.0a11
// }
if (authors == null || authors.isEmpty()) {
authors = getAuthorList();
}
String url = properties.get("url");
if (url == null || url.isEmpty()) {
url = getUrl();
}
String sentence = properties.get("sentence");
if (sentence == null || sentence.isEmpty()) {
sentence = getSentence();
}
String paragraph = properties.get("paragraph");
if (paragraph == null || paragraph.isEmpty()) {
paragraph = getParagraph();
}
int version;
try {
version = Integer.parseInt(properties.get("version"));
} catch (NumberFormatException e) {
version = getVersion();
System.err.println("The version number for “" + name + "” is not a number.");
System.err.println("Please contact the author to fix it according to the guidelines.");
}
String prettyVersion = properties.get("prettyVersion");
if (prettyVersion != null && prettyVersion.isEmpty()) {
prettyVersion = null;
}
String compatibleContribsList = null;
if (getType() == ContributionType.EXAMPLES) {
compatibleContribsList = properties.get(MODES_PROPERTY);
}
long lastUpdated;
try {
lastUpdated = Long.parseLong(properties.get("lastUpdated"));
} catch (NumberFormatException nfe) {
lastUpdated = getLastUpdated();
// Better comment these out till all contribs have a lastUpdated
// System.err.println("The last updated date for the “" + name
// + "” contribution is not set properly.");
// System.err
// .println("Please contact the author to fix it according to the guidelines.");
}
int minRev;
try {
minRev = Integer.parseInt(properties.get("minRevision"));
} catch (NumberFormatException e) {
minRev = getMinRevision();
// System.err.println("The minimum compatible revision for the “" + name
// + "” contribution is not set properly. Assuming minimum revision 0.");
}
int maxRev;
try {
maxRev = Integer.parseInt(properties.get("maxRevision"));
} catch (NumberFormatException e) {
maxRev = getMaxRevision();
// System.err.println("The maximum compatible revision for the “" + name
// + "” contribution is not set properly. Assuming maximum revision INF.");
}
if (propFile.delete() && propFile.createNewFile() && propFile.setWritable(true)) {
PrintWriter writer = PApplet.createWriter(propFile);
writer.println("name=" + name);
writer.println("category=" + category);
writer.println(AUTHORS_PROPERTY + "=" + authors);
writer.println("url=" + url);
writer.println("sentence=" + sentence);
writer.println("paragraph=" + paragraph);
writer.println("version=" + version);
if (prettyVersion != null) {
writer.println("prettyVersion=" + prettyVersion);
}
writer.println("lastUpdated=" + lastUpdated);
writer.println("minRevision=" + minRev);
writer.println("maxRevision=" + maxRev);
if ((getType() == ContributionType.LIBRARY || getType() == ContributionType.MODE) && importsList != null) {
writer.println("imports=" + importsList.join(","));
}
if (getType() == ContributionType.EXAMPLES) {
if (compatibleContribsList != null) {
writer.println(MODES_PROPERTY + "=" + compatibleContribsList);
}
}
writer.flush();
writer.close();
}
return true;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
}