2014-08-21 12:23:42 +02:00
|
|
|
package processing.app;
|
|
|
|
|
2014-08-21 13:18:54 +02:00
|
|
|
import static processing.app.I18n._;
|
|
|
|
|
2014-08-21 12:35:01 +02:00
|
|
|
import java.io.File;
|
2014-08-21 19:47:33 +02:00
|
|
|
import java.io.FileInputStream;
|
2014-08-21 13:43:10 +02:00
|
|
|
import java.io.IOException;
|
2014-08-21 19:47:33 +02:00
|
|
|
import java.io.InputStream;
|
2014-08-21 13:18:54 +02:00
|
|
|
import java.util.Arrays;
|
2014-08-21 18:43:13 +02:00
|
|
|
import java.util.Date;
|
2014-08-21 13:18:54 +02:00
|
|
|
import java.util.HashMap;
|
2014-08-21 14:06:25 +02:00
|
|
|
import java.util.List;
|
2014-08-21 13:18:54 +02:00
|
|
|
import java.util.Map;
|
2014-08-21 18:43:13 +02:00
|
|
|
import java.util.logging.Level;
|
|
|
|
import java.util.logging.Logger;
|
|
|
|
|
|
|
|
import org.apache.commons.logging.impl.LogFactoryImpl;
|
|
|
|
import org.apache.commons.logging.impl.NoOpLog;
|
2014-08-21 12:35:01 +02:00
|
|
|
|
2014-08-22 16:49:39 +02:00
|
|
|
import cc.arduino.packages.DiscoveryManager;
|
|
|
|
|
2014-08-21 13:38:28 +02:00
|
|
|
import processing.app.debug.TargetBoard;
|
2014-08-21 13:18:54 +02:00
|
|
|
import processing.app.debug.TargetPackage;
|
|
|
|
import processing.app.debug.TargetPlatform;
|
|
|
|
import processing.app.debug.TargetPlatformException;
|
2014-08-21 20:13:05 +02:00
|
|
|
import processing.app.helpers.BasicUserNotifier;
|
2014-08-21 12:35:01 +02:00
|
|
|
import processing.app.helpers.OSUtils;
|
2014-08-21 13:38:28 +02:00
|
|
|
import processing.app.helpers.PreferencesMap;
|
2014-08-21 19:47:33 +02:00
|
|
|
import processing.app.helpers.UserNotifier;
|
2014-08-21 13:18:54 +02:00
|
|
|
import processing.app.helpers.filefilters.OnlyDirs;
|
2014-08-21 14:06:25 +02:00
|
|
|
import processing.app.helpers.filefilters.OnlyFilesWithExtension;
|
2014-08-21 13:43:10 +02:00
|
|
|
import processing.app.legacy.PApplet;
|
2014-08-21 14:06:25 +02:00
|
|
|
import processing.app.packages.Library;
|
|
|
|
import processing.app.packages.LibraryList;
|
2014-08-21 12:35:01 +02:00
|
|
|
|
2014-08-21 12:23:42 +02:00
|
|
|
public class BaseNoGui {
|
|
|
|
|
|
|
|
public static final int REVISION = 158;
|
|
|
|
/** This might be replaced by main() if there's a lib/version.txt file. */
|
|
|
|
static String VERSION_NAME = "0158";
|
|
|
|
/** Set true if this a proper release rather than a numbered revision. */
|
|
|
|
static public boolean RELEASE = false;
|
|
|
|
|
2014-08-21 13:18:54 +02:00
|
|
|
// Current directory to use for relative paths specified on the
|
|
|
|
// commandline
|
|
|
|
static String currentDirectory = System.getProperty("user.dir");
|
|
|
|
|
2014-08-22 16:49:39 +02:00
|
|
|
private static DiscoveryManager discoveryManager = new DiscoveryManager();
|
|
|
|
|
2014-08-21 14:06:25 +02:00
|
|
|
// maps #included files to their library folder
|
|
|
|
public static Map<String, Library> importToLibraryTable;
|
|
|
|
|
|
|
|
// maps library name to their library folder
|
|
|
|
static private LibraryList libraries;
|
|
|
|
|
2014-08-21 20:13:05 +02:00
|
|
|
static UserNotifier notifier = new BasicUserNotifier();
|
2014-08-21 19:47:33 +02:00
|
|
|
|
2014-08-21 13:18:54 +02:00
|
|
|
static public Map<String, TargetPackage> packages;
|
|
|
|
|
2014-08-21 13:33:46 +02:00
|
|
|
static Platform platform;
|
|
|
|
|
2014-08-21 13:18:54 +02:00
|
|
|
static File portableFolder = null;
|
|
|
|
|
|
|
|
// Returns a File object for the given pathname. If the pathname
|
|
|
|
// is not absolute, it is interpreted relative to the current
|
|
|
|
// directory when starting the IDE (which is not the same as the
|
|
|
|
// current working directory!).
|
|
|
|
static public File absoluteFile(String path) {
|
|
|
|
if (path == null) return null;
|
|
|
|
|
|
|
|
File file = new File(path);
|
|
|
|
if (!file.isAbsolute()) {
|
|
|
|
file = new File(currentDirectory, path);
|
|
|
|
}
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
|
2014-08-22 18:35:15 +02:00
|
|
|
/**
|
|
|
|
* Get the number of lines in a file by counting the number of newline
|
|
|
|
* characters inside a String (and adding 1).
|
|
|
|
*/
|
|
|
|
static public int countLines(String what) {
|
|
|
|
int count = 1;
|
|
|
|
for (char c : what.toCharArray()) {
|
|
|
|
if (c == '\n') count++;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2014-08-21 12:35:01 +02:00
|
|
|
static public String getAvrBasePath() {
|
|
|
|
String path = getHardwarePath() + File.separator + "tools" +
|
|
|
|
File.separator + "avr" + File.separator + "bin" + File.separator;
|
|
|
|
if (OSUtils.isLinux() && !(new File(path)).exists()) {
|
|
|
|
return ""; // use distribution provided avr tools if bundled tools missing
|
|
|
|
}
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
2014-08-21 13:38:28 +02:00
|
|
|
static public PreferencesMap getBoardPreferences() {
|
|
|
|
TargetBoard board = getTargetBoard();
|
|
|
|
|
|
|
|
PreferencesMap prefs = new PreferencesMap(board.getPreferences());
|
|
|
|
for (String menuId : board.getMenuIds()) {
|
2014-08-22 12:47:43 +02:00
|
|
|
String entry = PreferencesData.get("custom_" + menuId);
|
2014-08-21 13:38:28 +02:00
|
|
|
if (board.hasMenu(menuId) && entry != null &&
|
|
|
|
entry.startsWith(board.getId())) {
|
|
|
|
String selectionId = entry.substring(entry.indexOf("_") + 1);
|
|
|
|
prefs.putAll(board.getMenuPreferences(menuId, selectionId));
|
|
|
|
prefs.put("name", prefs.get("name") + ", " +
|
|
|
|
board.getMenuLabel(menuId, selectionId));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return prefs;
|
|
|
|
}
|
|
|
|
|
2014-08-21 12:35:01 +02:00
|
|
|
static public File getContentFile(String name) {
|
|
|
|
String path = System.getProperty("user.dir");
|
|
|
|
|
|
|
|
// Get a path to somewhere inside the .app folder
|
|
|
|
if (OSUtils.isMacOS()) {
|
|
|
|
// <key>javaroot</key>
|
|
|
|
// <string>$JAVAROOT</string>
|
|
|
|
String javaroot = System.getProperty("javaroot");
|
|
|
|
if (javaroot != null) {
|
|
|
|
path = javaroot;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
File working = new File(path);
|
|
|
|
return new File(working, name);
|
|
|
|
}
|
|
|
|
|
2014-08-21 19:00:29 +02:00
|
|
|
static public TargetPlatform getCurrentTargetPlatformFromPackage(String pack) {
|
2014-08-22 12:47:43 +02:00
|
|
|
return getTargetPlatform(pack, PreferencesData.get("target_platform"));
|
2014-08-21 19:00:29 +02:00
|
|
|
}
|
|
|
|
|
2014-08-22 16:49:39 +02:00
|
|
|
public static DiscoveryManager getDiscoveryManager() {
|
|
|
|
return discoveryManager;
|
|
|
|
}
|
|
|
|
|
2014-08-21 12:35:01 +02:00
|
|
|
static public File getHardwareFolder() {
|
|
|
|
// calculate on the fly because it's needed by Preferences.init() to find
|
|
|
|
// the boards.txt and programmers.txt preferences files (which happens
|
|
|
|
// before the other folders / paths get cached).
|
|
|
|
return getContentFile("hardware");
|
|
|
|
}
|
|
|
|
|
|
|
|
static public String getHardwarePath() {
|
|
|
|
return getHardwareFolder().getAbsolutePath();
|
|
|
|
}
|
|
|
|
|
2014-08-21 14:06:25 +02:00
|
|
|
static public LibraryList getLibraries() {
|
|
|
|
return libraries;
|
|
|
|
}
|
|
|
|
|
2014-08-21 19:47:33 +02:00
|
|
|
/**
|
|
|
|
* Return an InputStream for a file inside the Processing lib folder.
|
|
|
|
*/
|
|
|
|
static public InputStream getLibStream(String filename) throws IOException {
|
|
|
|
return new FileInputStream(new File(getContentFile("lib"), filename));
|
|
|
|
}
|
|
|
|
|
2014-08-21 13:33:46 +02:00
|
|
|
static public Platform getPlatform() {
|
|
|
|
return platform;
|
|
|
|
}
|
|
|
|
|
2014-08-21 13:18:54 +02:00
|
|
|
static public File getPortableFolder() {
|
|
|
|
return portableFolder;
|
|
|
|
}
|
|
|
|
|
2014-08-21 19:47:33 +02:00
|
|
|
/**
|
|
|
|
* Convenience method to get a File object for the specified filename inside
|
|
|
|
* the settings folder.
|
|
|
|
* For now, only used by Preferences to get the preferences.txt file.
|
|
|
|
* @param filename A file inside the settings folder.
|
|
|
|
* @return filename wrapped as a File object inside the settings folder
|
|
|
|
*/
|
|
|
|
static public File getSettingsFile(String filename) {
|
|
|
|
return new File(getSettingsFolder(), filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
static public File getSettingsFolder() {
|
2014-08-22 13:41:41 +02:00
|
|
|
if (getPortableFolder() != null)
|
|
|
|
return getPortableFolder();
|
2014-08-21 19:47:33 +02:00
|
|
|
|
|
|
|
File settingsFolder = null;
|
|
|
|
|
2014-08-22 12:47:43 +02:00
|
|
|
String preferencesPath = PreferencesData.get("settings.path");
|
2014-08-21 19:47:33 +02:00
|
|
|
if (preferencesPath != null) {
|
|
|
|
settingsFolder = absoluteFile(preferencesPath);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
try {
|
|
|
|
settingsFolder = getPlatform().getSettingsFolder();
|
|
|
|
} catch (Exception e) {
|
|
|
|
showError(_("Problem getting data folder"),
|
|
|
|
_("Error getting the Arduino data folder."), e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// create the folder if it doesn't exist already
|
|
|
|
if (!settingsFolder.exists()) {
|
|
|
|
if (!settingsFolder.mkdirs()) {
|
|
|
|
showError(_("Settings issues"),
|
|
|
|
_("Arduino cannot run because it could not\n" +
|
|
|
|
"create a folder to store your settings."), null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return settingsFolder;
|
|
|
|
}
|
|
|
|
|
2014-08-21 13:18:54 +02:00
|
|
|
static public File getSketchbookFolder() {
|
|
|
|
if (portableFolder != null)
|
2014-08-22 12:47:43 +02:00
|
|
|
return new File(portableFolder, PreferencesData.get("sketchbook.path"));
|
|
|
|
return absoluteFile(PreferencesData.get("sketchbook.path"));
|
2014-08-21 13:18:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static public File getSketchbookHardwareFolder() {
|
|
|
|
return new File(getSketchbookFolder(), "hardware");
|
|
|
|
}
|
|
|
|
|
2014-08-21 13:38:28 +02:00
|
|
|
public static TargetBoard getTargetBoard() {
|
2014-08-22 12:47:43 +02:00
|
|
|
String boardId = PreferencesData.get("board");
|
2014-08-21 13:38:28 +02:00
|
|
|
return getTargetPlatform().getBoard(boardId);
|
|
|
|
}
|
|
|
|
|
2014-08-21 13:18:54 +02:00
|
|
|
/**
|
|
|
|
* Returns the currently selected TargetPlatform.
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
static public TargetPlatform getTargetPlatform() {
|
2014-08-22 12:47:43 +02:00
|
|
|
String packageName = PreferencesData.get("target_package");
|
|
|
|
String platformName = PreferencesData.get("target_platform");
|
2014-08-21 13:18:54 +02:00
|
|
|
return getTargetPlatform(packageName, platformName);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a specific TargetPlatform searching Package/Platform
|
|
|
|
*
|
|
|
|
* @param packageName
|
|
|
|
* @param platformName
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
static public TargetPlatform getTargetPlatform(String packageName,
|
|
|
|
String platformName) {
|
|
|
|
TargetPackage p = packages.get(packageName);
|
|
|
|
if (p == null)
|
|
|
|
return null;
|
|
|
|
return p.get(platformName);
|
|
|
|
}
|
|
|
|
|
2014-08-21 14:06:25 +02:00
|
|
|
static public LibraryList getUserLibs() {
|
|
|
|
if (libraries == null)
|
|
|
|
return new LibraryList();
|
|
|
|
return libraries.filterLibrariesInSubfolder(getSketchbookFolder());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Given a folder, return a list of the header files in that folder (but not
|
|
|
|
* the header files in its sub-folders, as those should be included from
|
|
|
|
* within the header files at the top-level).
|
|
|
|
*/
|
|
|
|
static public String[] headerListFromIncludePath(File path) throws IOException {
|
|
|
|
String[] list = path.list(new OnlyFilesWithExtension(".h"));
|
|
|
|
if (list == null) {
|
|
|
|
throw new IOException();
|
|
|
|
}
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2014-08-21 18:43:13 +02:00
|
|
|
static public void initLogger() {
|
|
|
|
System.setProperty(LogFactoryImpl.LOG_PROPERTY, NoOpLog.class.getCanonicalName());
|
|
|
|
Logger.getLogger("javax.jmdns").setLevel(Level.OFF);
|
|
|
|
}
|
|
|
|
|
2014-08-21 13:18:54 +02:00
|
|
|
static public void initPackages() {
|
|
|
|
packages = new HashMap<String, TargetPackage>();
|
|
|
|
loadHardware(getHardwareFolder());
|
|
|
|
loadHardware(getSketchbookHardwareFolder());
|
|
|
|
if (packages.size() == 0) {
|
|
|
|
System.out.println(_("No valid configured cores found! Exiting..."));
|
|
|
|
System.exit(3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-21 13:33:46 +02:00
|
|
|
static protected void initPlatform() {
|
|
|
|
try {
|
|
|
|
Class<?> platformClass = Class.forName("processing.app.Platform");
|
|
|
|
if (OSUtils.isMacOS()) {
|
|
|
|
platformClass = Class.forName("processing.app.macosx.Platform");
|
|
|
|
} else if (OSUtils.isWindows()) {
|
|
|
|
platformClass = Class.forName("processing.app.windows.Platform");
|
|
|
|
} else if (OSUtils.isLinux()) {
|
|
|
|
platformClass = Class.forName("processing.app.linux.Platform");
|
|
|
|
}
|
|
|
|
platform = (Platform) platformClass.newInstance();
|
|
|
|
} catch (Exception e) {
|
2014-08-21 19:55:50 +02:00
|
|
|
showError(_("Problem Setting the Platform"),
|
|
|
|
_("An unknown error occurred while trying to load\n" +
|
|
|
|
"platform-specific code for your machine."), e);
|
2014-08-21 13:33:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-21 13:18:54 +02:00
|
|
|
static public void initPortableFolder() {
|
|
|
|
// Portable folder
|
|
|
|
portableFolder = getContentFile("portable");
|
|
|
|
if (!portableFolder.exists())
|
|
|
|
portableFolder = null;
|
|
|
|
}
|
|
|
|
|
2014-08-21 18:43:13 +02:00
|
|
|
static public void initVersion() {
|
|
|
|
try {
|
|
|
|
File versionFile = getContentFile("lib/version.txt");
|
|
|
|
if (versionFile.exists()) {
|
|
|
|
String version = PApplet.loadStrings(versionFile)[0];
|
|
|
|
if (!version.equals(VERSION_NAME) && !version.equals("${version}")) {
|
|
|
|
VERSION_NAME = version;
|
|
|
|
RELEASE = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
|
|
|
|
// help 3rd party installers find the correct hardware path
|
2014-08-22 12:47:43 +02:00
|
|
|
PreferencesData.set("last.ide." + VERSION_NAME + ".hardwarepath", getHardwarePath());
|
|
|
|
PreferencesData.set("last.ide." + VERSION_NAME + ".daterun", "" + (new Date()).getTime() / 1000);
|
2014-08-21 18:43:13 +02:00
|
|
|
}
|
|
|
|
|
2014-08-22 18:27:50 +02:00
|
|
|
/**
|
|
|
|
* Return true if the name is valid for a Processing sketch.
|
|
|
|
*/
|
|
|
|
static public boolean isSanitaryName(String name) {
|
|
|
|
return sanitizeName(name).equals(name);
|
|
|
|
}
|
|
|
|
|
2014-08-21 13:18:54 +02:00
|
|
|
static protected void loadHardware(File folder) {
|
|
|
|
if (!folder.isDirectory()) return;
|
|
|
|
|
|
|
|
String list[] = folder.list(new OnlyDirs());
|
|
|
|
|
|
|
|
// if a bad folder or something like that, this might come back null
|
|
|
|
if (list == null) return;
|
|
|
|
|
|
|
|
// alphabetize list, since it's not always alpha order
|
|
|
|
// replaced hella slow bubble sort with this feller for 0093
|
|
|
|
Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
|
|
|
|
|
|
|
|
for (String target : list) {
|
|
|
|
// Skip reserved 'tools' folder.
|
|
|
|
if (target.equals("tools"))
|
|
|
|
continue;
|
|
|
|
File subfolder = new File(folder, target);
|
|
|
|
|
|
|
|
try {
|
2014-08-22 13:41:41 +02:00
|
|
|
packages.put(target, new TargetPackage(target, subfolder));
|
2014-08-21 13:18:54 +02:00
|
|
|
} catch (TargetPlatformException e) {
|
|
|
|
System.out.println("WARNING: Error loading hardware folder " + target);
|
|
|
|
System.out.println(" " + e.getMessage());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-22 18:35:15 +02:00
|
|
|
/**
|
|
|
|
* Grab the contents of a file as a string.
|
|
|
|
*/
|
|
|
|
static public String loadFile(File file) throws IOException {
|
|
|
|
String[] contents = PApplet.loadStrings(file);
|
|
|
|
if (contents == null) return null;
|
|
|
|
return PApplet.join(contents, "\n");
|
|
|
|
}
|
|
|
|
|
2014-08-22 13:41:41 +02:00
|
|
|
static public void populateImportToLibraryTable() {
|
|
|
|
// Populate importToLibraryTable
|
2014-08-21 14:06:25 +02:00
|
|
|
importToLibraryTable = new HashMap<String, Library>();
|
2014-08-22 13:41:41 +02:00
|
|
|
for (Library lib : getLibraries()) {
|
|
|
|
try {
|
|
|
|
String headers[] = headerListFromIncludePath(lib.getSrcFolder());
|
|
|
|
for (String header : headers) {
|
|
|
|
Library old = importToLibraryTable.get(header);
|
|
|
|
if (old != null) {
|
|
|
|
// If a library was already found with this header, keep
|
|
|
|
// it if the library's name matches the header name.
|
|
|
|
String name = header.substring(0, header.length() - 2);
|
|
|
|
if (old.getFolder().getPath().endsWith(name))
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
importToLibraryTable.put(header, lib);
|
|
|
|
}
|
|
|
|
} catch (IOException e) {
|
|
|
|
showWarning(_("Error"), I18n
|
|
|
|
.format("Unable to list header files in {0}", lib.getSrcFolder()), e);
|
|
|
|
}
|
|
|
|
}
|
2014-08-21 14:06:25 +02:00
|
|
|
}
|
|
|
|
|
2014-08-21 18:43:13 +02:00
|
|
|
static public void prescanParameters(String args[]) {
|
|
|
|
String preferencesFile = null;
|
|
|
|
|
|
|
|
// Do a first pass over the commandline arguments, the rest of them
|
|
|
|
// will be processed by the Base constructor. Note that this loop
|
|
|
|
// does not look at the last element of args, to prevent crashing
|
|
|
|
// when no parameter was specified to an option. Later, Base() will
|
|
|
|
// then show an error for these.
|
|
|
|
for (int i = 0; i < args.length - 1; i++) {
|
|
|
|
if (args[i].equals("--preferences-file")) {
|
|
|
|
++i;
|
|
|
|
preferencesFile = args[i];
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (args[i].equals("--curdir")) {
|
|
|
|
i++;
|
|
|
|
currentDirectory = args[i];
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// run static initialization that grabs all the prefs
|
2014-08-22 12:47:43 +02:00
|
|
|
PreferencesData.init(absoluteFile(preferencesFile));
|
2014-08-21 18:43:13 +02:00
|
|
|
}
|
|
|
|
|
2014-08-22 18:12:34 +02:00
|
|
|
/**
|
|
|
|
* Recursively remove all files within a directory,
|
|
|
|
* used with removeDir(), or when the contents of a dir
|
|
|
|
* should be removed, but not the directory itself.
|
|
|
|
* (i.e. when cleaning temp files from lib/build)
|
|
|
|
*/
|
|
|
|
static public void removeDescendants(File dir) {
|
|
|
|
if (!dir.exists()) return;
|
|
|
|
|
|
|
|
String files[] = dir.list();
|
|
|
|
for (int i = 0; i < files.length; i++) {
|
|
|
|
if (files[i].equals(".") || files[i].equals("..")) continue;
|
|
|
|
File dead = new File(dir, files[i]);
|
|
|
|
if (!dead.isDirectory()) {
|
2014-08-22 18:27:50 +02:00
|
|
|
if (!PreferencesData.getBoolean("compiler.save_build_files")) {
|
2014-08-22 18:12:34 +02:00
|
|
|
if (!dead.delete()) {
|
|
|
|
// temporarily disabled
|
|
|
|
System.err.println(I18n.format(_("Could not delete {0}"), dead));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
removeDir(dead);
|
|
|
|
//dead.delete();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove all files in a directory and the directory itself.
|
|
|
|
*/
|
|
|
|
static public void removeDir(File dir) {
|
|
|
|
if (dir.exists()) {
|
|
|
|
removeDescendants(dir);
|
|
|
|
if (!dir.delete()) {
|
|
|
|
System.err.println(I18n.format(_("Could not delete {0}"), dir));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-22 18:27:50 +02:00
|
|
|
/**
|
|
|
|
* Produce a sanitized name that fits our standards for likely to work.
|
|
|
|
* <p/>
|
|
|
|
* Java classes have a wider range of names that are technically allowed
|
|
|
|
* (supposedly any Unicode name) than what we support. The reason for
|
|
|
|
* going more narrow is to avoid situations with text encodings and
|
|
|
|
* converting during the process of moving files between operating
|
|
|
|
* systems, i.e. uploading from a Windows machine to a Linux server,
|
|
|
|
* or reading a FAT32 partition in OS X and using a thumb drive.
|
|
|
|
* <p/>
|
|
|
|
* This helper function replaces everything but A-Z, a-z, and 0-9 with
|
|
|
|
* underscores. Also disallows starting the sketch name with a digit.
|
|
|
|
*/
|
|
|
|
static public String sanitizeName(String origName) {
|
|
|
|
char c[] = origName.toCharArray();
|
|
|
|
StringBuffer buffer = new StringBuffer();
|
|
|
|
|
|
|
|
// can't lead with a digit, so start with an underscore
|
|
|
|
if ((c[0] >= '0') && (c[0] <= '9')) {
|
|
|
|
buffer.append('_');
|
|
|
|
}
|
|
|
|
for (int i = 0; i < c.length; i++) {
|
|
|
|
if (((c[i] >= '0') && (c[i] <= '9')) ||
|
|
|
|
((c[i] >= 'a') && (c[i] <= 'z')) ||
|
|
|
|
((c[i] >= 'A') && (c[i] <= 'Z')) ||
|
|
|
|
((i > 0) && (c[i] == '-')) ||
|
|
|
|
((i > 0) && (c[i] == '.'))) {
|
|
|
|
buffer.append(c[i]);
|
|
|
|
} else {
|
|
|
|
buffer.append('_');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// let's not be ridiculous about the length of filenames.
|
|
|
|
// in fact, Mac OS 9 can handle 255 chars, though it can't really
|
|
|
|
// deal with filenames longer than 31 chars in the Finder.
|
|
|
|
// but limiting to that for sketches would mean setting the
|
|
|
|
// upper-bound on the character limit here to 25 characters
|
|
|
|
// (to handle the base name + ".class")
|
|
|
|
if (buffer.length() > 63) {
|
|
|
|
buffer.setLength(63);
|
|
|
|
}
|
|
|
|
return buffer.toString();
|
|
|
|
}
|
|
|
|
|
2014-08-21 13:43:10 +02:00
|
|
|
/**
|
|
|
|
* Spew the contents of a String object out to a file.
|
|
|
|
*/
|
|
|
|
static public void saveFile(String str, File file) throws IOException {
|
|
|
|
File temp = File.createTempFile(file.getName(), null, file.getParentFile());
|
|
|
|
PApplet.saveStrings(temp, new String[] { str });
|
|
|
|
if (file.exists()) {
|
|
|
|
boolean result = file.delete();
|
|
|
|
if (!result) {
|
|
|
|
throw new IOException(
|
|
|
|
I18n.format(
|
|
|
|
_("Could not remove old version of {0}"),
|
|
|
|
file.getAbsolutePath()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
boolean result = temp.renameTo(file);
|
|
|
|
if (!result) {
|
|
|
|
throw new IOException(
|
|
|
|
I18n.format(
|
|
|
|
_("Could not replace {0}"),
|
|
|
|
file.getAbsolutePath()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-21 14:06:25 +02:00
|
|
|
static public void scanAndUpdateLibraries(List<File> folders) throws IOException {
|
|
|
|
libraries = scanLibraries(folders);
|
|
|
|
}
|
|
|
|
|
|
|
|
static public LibraryList scanLibraries(List<File> folders) throws IOException {
|
|
|
|
LibraryList res = new LibraryList();
|
|
|
|
for (File folder : folders)
|
|
|
|
res.addOrReplaceAll(scanLibraries(folder));
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static public LibraryList scanLibraries(File folder) throws IOException {
|
|
|
|
LibraryList res = new LibraryList();
|
|
|
|
|
|
|
|
String list[] = folder.list(new OnlyDirs());
|
|
|
|
// if a bad folder or something like that, this might come back null
|
|
|
|
if (list == null)
|
|
|
|
return res;
|
|
|
|
|
|
|
|
for (String libName : list) {
|
|
|
|
File subfolder = new File(folder, libName);
|
2014-08-22 18:27:50 +02:00
|
|
|
if (!isSanitaryName(libName)) {
|
2014-08-21 14:06:25 +02:00
|
|
|
String mess = I18n.format(_("The library \"{0}\" cannot be used.\n"
|
|
|
|
+ "Library names must contain only basic letters and numbers.\n"
|
|
|
|
+ "(ASCII only and no spaces, and it cannot start with a number)"),
|
|
|
|
libName);
|
2014-08-21 19:55:50 +02:00
|
|
|
showMessage(_("Ignoring bad library name"), mess);
|
2014-08-21 14:06:25 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
Library lib = Library.create(subfolder);
|
|
|
|
// (also replace previously found libs with the same name)
|
|
|
|
if (lib != null)
|
|
|
|
res.addOrReplace(lib);
|
|
|
|
} catch (IOException e) {
|
|
|
|
System.out.println(I18n.format(_("Invalid library found in {0}: {1}"),
|
|
|
|
subfolder, e.getMessage()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2014-08-21 19:47:33 +02:00
|
|
|
static public void showError(String title, String message, Throwable e) {
|
|
|
|
notifier.showError(title, message, e, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Show an error message that's actually fatal to the program.
|
|
|
|
* This is an error that can't be recovered. Use showWarning()
|
|
|
|
* for errors that allow P5 to continue running.
|
|
|
|
*/
|
|
|
|
static public void showError(String title, String message, Throwable e, int exit_code) {
|
|
|
|
notifier.showError(title, message, e, exit_code);
|
|
|
|
}
|
|
|
|
|
2014-08-21 19:55:50 +02:00
|
|
|
/**
|
|
|
|
* "No cookie for you" type messages. Nothing fatal or all that
|
|
|
|
* much of a bummer, but something to notify the user about.
|
|
|
|
*/
|
|
|
|
static public void showMessage(String title, String message) {
|
|
|
|
notifier.showMessage(title, message);
|
|
|
|
}
|
2014-08-21 20:25:23 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Non-fatal error message with optional stack trace side dish.
|
|
|
|
*/
|
|
|
|
static public void showWarning(String title, String message, Exception e) {
|
|
|
|
notifier.showWarning(title, message, e);
|
|
|
|
}
|
|
|
|
|
2014-08-21 12:23:42 +02:00
|
|
|
}
|