Fixed Processing library detection and added an error when the library cannot be found. Multiple missing libraries results in multiple errors. Still encountering classpath errors, and introduced a bug that copies the directory into itself again. Hate to check in a bug, but I have to stop for the night and sleep.

This commit is contained in:
lonnen
2010-09-02 07:34:03 +00:00
parent 56445cb6a3
commit 0989d502b3
5 changed files with 654 additions and 618 deletions
@@ -13,6 +13,8 @@ import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
@@ -21,6 +23,9 @@ import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Plugin;
import processing.plugin.core.builder.Utilities;
@@ -87,11 +92,34 @@ public final class ProcessingCore extends Plugin {
}
}
/**
* Resolves the plug-in resources folder to a File and returns it. This will include the
* Processing libraries and the core libraries folder.
*
* @return File reference to the core resources
*/
public File getPluginResourceFolder(){
URL fileLocation = ProcessingCore.getProcessingCore().getPluginResource("");
try {
File folder = new File(FileLocator.toFileURL(fileLocation).getPath());
if (folder.exists())
return folder;
} catch (Exception e) {
ProcessingLog.logError(e);
}
return null;
}
/** Returns a file handle to the plug-in's local cache folder. */
public File getBuiltInCacheFolder(){
return new File(this.getStateLocation().toString());
}
/** Returns a file handle to the temp folder in the plug-in's local cache*/
public File getPluginTempFolder(){
return new File(getBuiltInCacheFolder(), "temp");
}
/** Returns the plug-in's resource bundle */
public ResourceBundle getResourceBundle(){
return resourceBundle;
@@ -114,19 +142,19 @@ public final class ProcessingCore extends Plugin {
}
/** Returns true if the resource is a Processing file */
public static boolean isPDEFile(IResource resource){
public static boolean isProcessingFile(IResource resource){
if (resource.getType() == IResource.FILE)
return isPDEFilename(resource.getName());
return isProcessingFile(resource.getName());
return false;
}
/** Returns true if the file is a Processing file */
public static boolean isPDEFile(IFile resource) {
return isPDEFilename(resource.getName());
public static boolean isProcessingFile(IFile resource) {
return isProcessingFile(resource.getName());
}
/** Returns true if the file has a Processing extension */
public static boolean isPDEFilename(String filename){
public static boolean isProcessingFile(String filename){
return filename.endsWith(".pde");
}
@@ -142,7 +170,7 @@ public final class ProcessingCore extends Plugin {
public static boolean isLibrary(File rootFolder){
return isLibrary(rootFolder, false);
}
/**
* Returns true if the folder is a Processing library root folder.
* When complain is false only errors are logged and reported. When
@@ -150,31 +178,51 @@ public final class ProcessingCore extends Plugin {
* libraries will also be reported.
*/
public static boolean isLibrary(File rootFolder, boolean complain){
if (rootFolder != null){
String name = rootFolder.getName();
try {
File libraryJar = new File(rootFolder.getCanonicalPath() +
File.separatorChar + "library" + File.separatorChar +
name + ".jar");
if (libraryJar.exists())
if (Utilities.sanitizeName(name).equals(name)){
return true;
} else {
if(complain){
if (rootFolder == null) return false;
if(!rootFolder.isDirectory()) return false;
String name = rootFolder.getName();
try {
File libraryJar = new File(rootFolder.getCanonicalPath() +
File.separatorChar + "library" + File.separatorChar +
name + ".jar");
if (libraryJar.exists())
if (Utilities.sanitizeName(name).equals(name)){
return true;
} else {
if(complain){
String mess =
"The library \"" + name + "\" 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)";
ProcessingLog.logInfo("Ignoring bad library " + name + "\n" + mess);
}
}
} catch (IOException e) {
ProcessingLog.logError("Problem checking librarary " +
name + ", could not resolve canonical path.", e);
}
}
} catch (IOException e) {
ProcessingLog.logError("Problem checking library " +
name + ", could not resolve canonical path.", e);
}
return false;
}
/**
* Finds the folder containing the Processing core libraries, which are bundled with the
* plugin. This folder doesn't exist in the workspace, so we return it as a File, not IFile.
* If something goes wrong, logs an error and returns null.
*
* @return File containing the core libraries folder or null
*/
public File getCoreLibsFolder() {
URL fileLocation = getPluginResource("libraries");
try {
File folder = new File(FileLocator.toFileURL(fileLocation).getPath());
if (folder.exists())
return folder;
} catch (Exception e) {
ProcessingLog.logError(e);
}
return null;
}
}
@@ -1,11 +1,8 @@
package processing.plugin.core.builder;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.StringWriter;
import java.net.URL;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@@ -17,17 +14,12 @@ import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.launching.IVMInstall;
import org.eclipse.jdt.launching.JavaRuntime;
import processing.app.Preferences;
import processing.app.debug.RunnerException;
@@ -35,7 +27,6 @@ import processing.app.preproc.PdePreprocessor;
import processing.app.preproc.PreprocessResult;
import processing.plugin.core.ProcessingCore;
import processing.plugin.core.ProcessingCorePreferences;
import processing.plugin.core.ProcessingLog;
/**
@@ -107,47 +98,33 @@ public class SketchBuilder extends IncrementalProjectBuilder{
// truly separated from the UI. Possible create it in the PDE, and extend it
// here for marker management and such.
// /** Data folder, located in the sketch folder, may not exist */
// private IFolder dataFolder;
// /** Data folder, located in the sketch folder, may not exist */
// private IFolder dataFolder;
/** Full paths to source folders for the JDT */
private ArrayList<IPath>srcFolderPathList;
/** Full paths to jars required to compile the sketch */
private ArrayList<IPath>libraryJarPathList;
/** Code folder, located in the sketch folder, may not exist */
private IFolder codeFolder;
/** A temporary build folder, will be created if it doesn't exist */
private IFolder buildFolder;
/** The output applet folder for after the compile */
private IFolder appletFolder;
/** The core libraries folder in the plug-in resources. */
private File coreLibs;
/** The SketchBook libraries folder, may not exist */
private File sketchBookLibs;
/** the library path for the compiler */
private String libraryPath;
/** the class path for the compiler */
private String classPath;
/** a list of library folders */
private ArrayList<File> importedLibraries; // list of library folders
/** a table resolving a package to the folder containing its .jar */
private HashMap<String,File> importToLibraryTable;
/** Supplied as a build argument, usually empty */
private String packageName = "";
private File buildFolder;
/** Clean any leftover state from previous builds. */
protected void clean(SketchProject sketch, IProgressMonitor monitor) throws CoreException{
deleteP5ProblemMarkers(sketch);
if (buildFolder != null && buildFolder.exists()){
for( IResource r : buildFolder.members()){
r.delete(IResource.FORCE, monitor);
}
}
srcFolderPathList = new ArrayList<IPath>();
libraryJarPathList = new ArrayList<IPath>();
// if this is the first run of the builder the build folder will not be stored yet,
// but if there is an old build folder from a trial run it should still be nuked.
// get the handle to it from the project's configuration
Utilities.deleteFolderContents(sketch.getBuildFolder());
// any other cleaning stuff goes here
// Eventually, a model should control the markers, and once a model is
// written it should be controlled by the SketchProject. Cleaning the model
@@ -202,48 +179,45 @@ public class SketchBuilder extends IncrementalProjectBuilder{
return null;
}
// Setup the folders
codeFolder = sketch.getFolder("code");
buildFolder = sketch.getFolder("bin"); // TODO relocate to MyPlugin.getPlugin().getStateLocation().getFolder("bin")
appletFolder = sketch.getFolder("applet");
// Get handles to the folders
codeFolder = sketchProject.getCodeFolder();
buildFolder = sketchProject.getBuildFolder(); // null if it couldn't be created
if (buildFolder == null){
ProcessingLog.logError("Build folder could not be accessed.", null);
return null;
}
monitor.beginTask("Sketch Build", 400); // not sure how much work to do here
if(!sketch.isOpen()) { return null; } // has to be open to access it
if(checkCancel(monitor)) { return null; }
// 1 . PREPARE
if (!buildFolder.exists())
buildFolder.create(IResource.NONE, true, null);
monitor.worked(100); // 100 for every step of the process?
if(checkCancel(monitor)){ return null; }
// 2 . PREPROCESS
PdePreprocessor preproc = new PdePreprocessor(sketch.getName(), 4);
String[] codeFolderPackages = null;
classPath = buildFolder.getLocation().toOSString();
// check the contents of the code folder to see if there are files that need to be added to the imports
// If the code folder exists:
// Find any .jar files in it and its subfolders
// Add their paths to the library jar list for addition to the class path later on
// Get the packages of those jars so they can be added to the imports
// Add it to the class path source folders
if (codeFolder.exists()){
libraryPath = codeFolder.getLocation().toOSString();
// get a list of .jar files in the code folder and its subfolders
String codeFolderClassPath = Utilities.contentsToClassPath(codeFolder.getLocation().toFile());
// append the jar files to the class path
classPath += File.pathSeparator + codeFolderClassPath;
// get the list of packages in those jars
for( String s : codeFolderClassPath.split(File.separator)){
libraryJarPathList.add(new Path(s));
}
codeFolderPackages = Utilities.packageListFromClassPath(codeFolderClassPath);
} else { libraryPath = ""; }
srcFolderPathList.add(codeFolder.getFullPath()); // not sure about this one
}
// concat all .pde files to the 'main' pde
// store line number for the starting and ending points of each bit
// concatenate the individual .pde files into one large file using temporary
// 'session properties' attached to the IResource files, mark the start and end lines that they
// contribute to the bigCode file. This information will be used later for mapping errors backwards
StringBuffer bigCode = new StringBuffer();
int bigCount = 0; // line count
for( IResource file : sketch.members()){
if(file.getFileExtension() != null && file.getFileExtension().equalsIgnoreCase("pde")){
if("pde".equalsIgnoreCase(file.getFileExtension())){
file.setSessionProperty(new QualifiedName(BUILDER_ID, "preproc start"), bigCount);
String content = Utilities.readFile((IFile) file);
bigCode.append(content);
@@ -257,31 +231,22 @@ public class SketchBuilder extends IncrementalProjectBuilder{
if(checkCancel(monitor)) { return null; }
PreprocessResult result = null;
try{
IFile outputFile = buildFolder.getFile(sketch.getName() + ".java");
StringWriter stream = new StringWriter();
result = preproc.write(stream, bigCode.toString(), codeFolderPackages);
// Eclipse idiom for generating the java file and marking it as a generated file
ByteArrayInputStream inStream = new ByteArrayInputStream(stream.toString().getBytes());
try{
final File java = new File(buildFolder, sketch.getName() + ".java");
final PrintWriter stream = new PrintWriter(new FileWriter(java));
try{
if (outputFile.exists()) {
outputFile.setContents(inStream, true, false, monitor);
} else {
outputFile.create(inStream, true, monitor);
}
outputFile.setDerived(true, monitor);
result = preproc.write(stream, bigCode.toString(), codeFolderPackages);
srcFolderPathList.add(new Path(buildFolder.getCanonicalPath()));
} finally {
stream.close();
inStream.close();
}
} catch(antlr.RecognitionException re){
IResource errorFile = null; // if this remains null, the error is reported back on the sketch itself with no line
IResource errorFile = null; // if this remains null, the error is reported back on the sketch itself with no line number
int errorLine = re.getLine() - 1;
for( IResource file : sketch.members()){
if(file.getFileExtension() != null && file.getFileExtension().equalsIgnoreCase("pde")){
if("pde".equalsIgnoreCase(file.getFileExtension())){
int low = (Integer) file.getSessionProperty(new QualifiedName(BUILDER_ID, "preproc start"));
int high = (Integer) file.getSessionProperty(new QualifiedName(BUILDER_ID, "preproc end"));
if( low <= errorLine && high > errorLine){
@@ -298,13 +263,11 @@ public class SketchBuilder extends IncrementalProjectBuilder{
errorLine = -1;
}
//DEBUG
//System.out.println("error line - error file - offset");
//System.out.println(errorLine + " - " + errorFile + " - " + getPreprocOffset((IFile) folderContents[errorFile]));
String msg = re.getMessage();
//TODO better remapping of errors, matching errors often get put after the document end. see highlightLine() inside editor.
//TODO better errors handling, matching errors often get put after the document end. see highlightLine() inside editor.
// try to find a way to put all this error handling code in one spot. All of the message parsing and resource blaming,
// so it doesn't appear multiple times in the source.
if (msg.equals("expecting RCURLY, found 'null'"))
msg = "Found one too many { characters without a } to match it.";
if (msg.indexOf("expecting RBRACK") != -1)
@@ -331,7 +294,7 @@ public class SketchBuilder extends IncrementalProjectBuilder{
// int errorColumn = Integer.parseInt(matches[2]); // unused in the builder
for( IResource file : sketch.members()){
if(file.getFileExtension() != null && file.getFileExtension().equalsIgnoreCase("pde")){
if("pde".equalsIgnoreCase(file.getFileExtension())){
int low = (Integer) file.getSessionProperty(new QualifiedName(BUILDER_ID, "preproc start"));
int high = (Integer) file.getSessionProperty(new QualifiedName(BUILDER_ID, "preproc end"));
if( low <= errorLine && high > errorLine){
@@ -363,7 +326,7 @@ public class SketchBuilder extends IncrementalProjectBuilder{
int errorLine = re.getCodeLine() + 1;
for( IResource file : sketch.members()){
if(file.getFileExtension() != null && file.getFileExtension().equalsIgnoreCase("pde")){
if("pde".equalsIgnoreCase(file.getFileExtension())){
int low = (Integer) file.getSessionProperty(new QualifiedName(BUILDER_ID, "preproc start"));
int high = (Integer) file.getSessionProperty(new QualifiedName(BUILDER_ID, "preproc end"));
if( low <= errorLine && high > errorLine){
@@ -386,7 +349,7 @@ public class SketchBuilder extends IncrementalProjectBuilder{
String msg = re.getMessage();
//TODO better remapping of errors, matching errors often get put after the document end. see highlightLine() inside editor.
//TODO see better error mapping todo above
if (msg.equals("expecting RCURLY, found 'null'"))
msg = "Found one too many { characters without a } to match it.";
if (msg.indexOf("expecting RBRACK") != -1)
@@ -400,137 +363,118 @@ public class SketchBuilder extends IncrementalProjectBuilder{
reportProblem(msg, errorFile, errorLine, true);
return null; // exit the build
} catch (CoreException e){
ProcessingLog.logError(e); // logging the error is a better
return null;
} catch (Exception e){
ProcessingLog.logError(e);
return null;
}
monitor.worked(10);
if(checkCancel(monitor)) { return null; }
if(checkCancel(monitor)) { return null; }
////////// LIBRARY STUFF MOVED TO SKETCH PROJECT
// Get the imports from the code that was preproc'd
// importedLibraries = new ArrayList<File>();
ArrayList<String> libs = new ArrayList<String>(); // a list of all the libraries that can be found
// coreLibs = getCoreLibsFolder().getAbsoluteFile();
// sketchBookLibs = getSketchBookLibsFolder(sketch).getAbsoluteFile();
libs.addAll( Utilities.getLibraryJars(ProcessingCore.getProcessingCore().getCoreLibsFolder()) );
libs.addAll( Utilities.getLibraryJars(Utilities.getSketchBookLibsFolder(sketch)) );
// Clean the library table and rebuild it
// importToLibraryTable = new HashMap<String,File>();
// setup the library table
HashMap<String, IPath> importToLibraryTable = new HashMap<String, IPath>();
// addLibraries internally checks for null folders
// try{
// addLibraries(coreLibs);
// addLibraries(sketchBookLibs);
// } catch (IOException e){
// ProcessingLog.logError("Libraries could not be loaded.", e);
// }
//
// for (String item : result.extraImports){
// // remove things up to the last dot
// int dot = item.lastIndexOf('.');
// String entry = (dot == -1) ? item : item.substring(0, dot);
// File libFolder = importToLibraryTable.get(entry);
// if (libFolder != null ){
// importedLibraries.add(libFolder);
// classPath += Utilities.contentsToClassPath(libFolder);
// libraryPath += File.pathSeparator + libFolder.getAbsolutePath();
// }
// }
// Finally add the regular Java CLASSPATH
String javaClassPath = System.getProperty("java.class.path");
// Remove quotes if any ... an annoying ( and frequent ) Windows problem
if (javaClassPath.startsWith("\"") && javaClassPath.endsWith("\""))
javaClassPath = javaClassPath.substring(1,javaClassPath.length()-1);
classPath += File.pathSeparator + javaClassPath;
monitor.worked(10);
if(checkCancel(monitor)) { return null; }
// 3. loop over the code[] and save each .java file
for( IResource file : sketch.members()){
if(file.getFileExtension() != null && file.getFileExtension().equalsIgnoreCase("java")){
String filename = file.getName() + ".java";
try{
String program = Utilities.readFile((IFile) file);
String[] pkg = Utilities.match(program, Utilities.PACKAGE_REGEX);
// if no package, add one
if(pkg == null){
pkg = new String[] { packageName };
// add the package name to the source
program = "package " + packageName + ";" + program;
}
IFolder packageFolder = buildFolder.getFolder(pkg[0].replace('.', '/'));
if (!packageFolder.exists())
packageFolder.create(IResource.NONE, true, null);
IFile modFile = packageFolder.getFile(file.getName() + ".java");
ByteArrayInputStream inStream = new ByteArrayInputStream(program.getBytes());
try{
if (modFile.exists()) {
modFile.setContents(inStream, true, false, monitor);
} else {
modFile.create(inStream, true, monitor);
}
modFile.setDerived(true, monitor);
} finally {
inStream.close();
}
} catch (Exception e){
ProcessingLog.logError("Problem moving " + filename + " to the build folder.", e);
}
} else if (file.getFileExtension() != null && file.getFileExtension().equalsIgnoreCase("pde")){
// The compiler will need this to have a proper offset
// not sure why every file gets the same offset, but ok I'll go with it... [lonnen] aug 20 2011
file.setSessionProperty(new QualifiedName(BUILDER_ID, "preproc start"), result.headerOffset);
// System.out.println("Libraries found (path sep: " + File.separator + " ) :");
for (String s : libs ){
// System.out.println(s);
String[] packages = Utilities.packageListFromClassPath(s);
for (String pkg : packages){
importToLibraryTable.put(pkg, new Path(s));
// System.out.println(pkg);
}
}
// System.out.println("There were a few extra imports: " + result.extraImports.size());
for (int i=0; i < result.extraImports.size(); i++){
String item = result.extraImports.get(i);
// remove things up to the last dot
int dot = item.lastIndexOf('.');
String entry = (dot == -1) ? item : item.substring(0, dot);
// System.out.println(entry);
IPath libPath = importToLibraryTable.get(entry);
if (libPath != null ){
libraryJarPathList.add(libPath); // huzzah! we've found it, make sure its fed to the compiler
} else {
// The user is trying to import something we won't be able to find.
reportProblem(
"Library import " + entry +" could not be found. Check the library folder in your sketchbook.",
sketch.getFile( sketch.getName() + ".pde"), i+1, true
);
}
}
// Adding the ol' Java classpath is handled by Eclipse. We don't worry about it.
monitor.worked(10);
if(checkCancel(monitor)) { return null; }
//COMPILE
//
// // setup the VM
// IPath containerPath = new Path(JavaRuntime.JRE_CONTAINER);
// IVMInstall vm = JavaRuntime.getDefaultVMInstall();
// IPath vmPath = containerPath.append(vm.getVMInstallType().getId()).append(vm.getName());
//
// // Collect all the paths in one place
// ArrayList<IPath> paths = new ArrayList<IPath>();
//
// // Split up the classPath, convert each member to a path
// // and store them individually
// System.out.println("classPath entries:");
// for( String s : classPath.split(File.pathSeparator)){
// if (!s.isEmpty()){
// System.out.println(s);
// paths.add(new Path(s));
// }
// }
//
// IClasspathEntry[] classpathEntries = new IClasspathEntry[paths.size()+1];
//
// System.out.println("IClasspathEntry[] items:");
// for (int i = 0; i<paths.size(); i++){
// System.out.println(paths.get(i).toString());
// classpathEntries[i+1] = JavaCore.newSourceEntry(paths.get(i));
// }
//
// // Add some extra paths, like the build folder
// classpathEntries[0]=JavaCore.newContainerEntry(vmPath.makeAbsolute());
//
// // reset to the new class path, don't add to the old
// sketchProject.getJavaProject().getOutputLocation();
// sketchProject.getJavaProject().setRawClasspath(classpathEntries, new NullProgressMonitor());
// // end this builder and let the Java builder run
// I don't think this next part is necessary.
// At this point we've written the derived java file and the code folder,
// if it exists, is marked to be added to the classpath. There's not much sense
// to copying things to the code folder and further messing with the offsets.
// // 3. loop over the code[] and save each .java file
//
// for( IResource file : sketch.members()){
// if("java".equalsIgnoreCase(file.getFileExtension())){
// String filename = file.getName() + ".java";
// try{
// String program = Utilities.readFile((IFile) file);
// String[] pkg = Utilities.match(program, Utilities.PACKAGE_REGEX);
// // if no package, add one
// if(pkg == null){
// pkg = new String[] { packageName };
// // add the package name to the source
// program = "package " + packageName + ";" + program;
// }
// IFolder packageFolder = buildFolder.getFolder(pkg[0].replace('.', '/'));
// if (!packageFolder.exists())
// packageFolder.create(IResource.NONE, true, null);
//
// IFile modFile = packageFolder.getFile(file.getName() + ".java");
//
// ByteArrayInputStream inStream = new ByteArrayInputStream(program.getBytes());
// try{
// if (modFile.exists()) {
// modFile.setContents(inStream, true, false, monitor);
// } else {
// modFile.create(inStream, true, monitor);
// }
// modFile.setDerived(true, monitor);
// } finally {
// inStream.close();
// }
// } catch (Exception e){
// ProcessingLog.logError("Problem moving " + filename + " to the build folder.", e);
// }
// } else if("pde".equalsIgnoreCase(file.getFileExtension())){
// // The compiler will need this to have a proper offset
// // not sure why every file gets the same offset, but ok I'll go with it... [lonnen] aug 20 2011
// file.setSessionProperty(new QualifiedName(BUILDER_ID, "preproc start"), result.headerOffset);
// }
// }
monitor.worked(10);
if(checkCancel(monitor)) { return null; }
// Even though the list types are specified, Java still tosses errors when I try
// to directly convert them or cast them. So instead I'm stuck doing this.
IPath[] libPaths = new IPath[libraryJarPathList.size()];
int i=0;
for(IPath path : libraryJarPathList) libPaths[i++] = path;
IPath[] srcPaths = new IPath[srcFolderPathList.size()];
i=0;
for(IPath path : srcFolderPathList) srcPaths[i++] = path;
sketchProject.updateClasspathEntries( srcPaths, libPaths);
return null;
}
@@ -544,17 +488,15 @@ public class SketchBuilder extends IncrementalProjectBuilder{
* @throws CoreException
*/
protected static void deleteP5ProblemMarkers(IResource resource) throws CoreException{
if(resource != null && resource.exists())
if(resource != null && resource.exists()){
resource.deleteMarkers(SketchBuilder.PREPROCMARKER, true, IResource.DEPTH_INFINITE);
resource.deleteMarkers(SketchBuilder.COMPILEMARKER, true, IResource.DEPTH_INFINITE);
resource.deleteMarkers(SketchBuilder.COMPILEMARKER, true, IResource.DEPTH_INFINITE);
}
}
protected static void deleteP5ProblemMarkers(SketchProject sketch)throws CoreException{
if(sketch != null){
IProject proj = sketch.getProject();
if (proj.exists())
deleteP5ProblemMarkers(proj);
}
if(sketch != null)
deleteP5ProblemMarkers(sketch.getProject());
}
/**
@@ -568,7 +510,7 @@ public class SketchBuilder extends IncrementalProjectBuilder{
* @param line_number what line did the problem occur on
* @param isError is this an error
*/
private void reportProblem( String msg, IResource file, int lineNumber, boolean isError){
private void reportProblem(String msg, IResource file, int lineNumber, boolean isError){
try{
IMarker marker = file.createMarker(SketchBuilder.PREPROCMARKER);
marker.setAttribute(IMarker.MESSAGE, msg);
@@ -599,50 +541,4 @@ public class SketchBuilder extends IncrementalProjectBuilder{
if (isInterrupted()){ return true; }
return false;
}
/**
* Finds any Processing Libraries in the folder and loads them into the HashMap
* importToLibraryTable so they can be imported later. Based on the Base.addLibraries,
* but adapted to avoid GUI elements
*
* @param folder the folder containing libraries
* @return true if libraries were imported, false otherwise
*/
// public boolean addLibraries(File folder) throws IOException{
// if (folder == null) return false;
// if (!folder.isDirectory()) return false;
//
// File list[] = folder.listFiles(new FilenameFilter() {
// public boolean accept(File dir, String name) {
// // skip .DS_Store files, .svn folders, etc
// if (name.charAt(0) == '.') return false;
// if (name.equals("CVS")) return false;
// return (new File(dir, name).isDirectory());
// }
// });
//
// // if a bad folder or something like that, this might come back null
// if (list == null) return false;
//
// boolean ifound = false;
//
// for (File potentialFile : list){
// if(ProcessingCore.isLibrary(potentialFile, true)){
// File libraryFolder = new File(potentialFile, "library");
// // get the path of all .jar files in this code folder
// String libraryClassPath = Utilities.contentsToClassPath(libraryFolder);
// // associate each import with a library folder
// String packages[] = Utilities.packageListFromClassPath(libraryClassPath);
// for (String pkg:packages){
// importToLibraryTable.put(pkg, libraryFolder);
// }
// ifound = true;
// } else {
// if (addLibraries(potentialFile)) // recurse!
// ifound = true;
// }
// }
//
// return ifound;
// }
}
@@ -1,9 +1,11 @@
package processing.plugin.core.builder;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import org.eclipse.core.resources.ICommand;
@@ -23,22 +25,22 @@ import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.launching.IVMInstall;
import org.eclipse.jdt.launching.JavaRuntime;
import processing.plugin.core.ProcessingCore;
import processing.plugin.core.ProcessingCorePreferences;
import processing.plugin.core.ProcessingLog;
public class SketchProject implements IProjectNature {
/** value: <code>"processing.plugin.core.processingnature"</code> */
public static final String NATURE_ID = ProcessingCore.PLUGIN_ID + ".sketchNature";
/** The basic project entry being managed */
protected IProject project;
/**
* Return the SketchProject associated with the given IProject, or null
* if the project is not associated with a SketchProject.
@@ -76,7 +78,7 @@ public class SketchProject implements IProjectNature {
description.setNatureIds(newIds.toArray(new String[newIds.size()]));
return;
}
IProjectDescription description = project.getDescription();
List<String> newIds = new ArrayList<String>();
@@ -126,113 +128,41 @@ public class SketchProject implements IProjectNature {
public IJavaProject getJavaProject(){
return JavaCore.create(project);
}
/** Associate the sketch builder with this nature's project */
public void configure() throws CoreException {
if (!project.isOpen())
return;
// Setup the folders
IFolder codeFolder = project.getFolder("code");
IFolder dataFolder = project.getFolder("data");
IFolder buildFolder = project.getFolder("bin"); // TODO relocate to MyPlugin.getPlugin().getStateLocation().getFolder("bin")
IFolder appletFolder = project.getFolder("applet");
IFolder javaBuildFolder = project.getFolder("compile");
File coreResources = getCoreResourcesFolder();
File sketchbookLibs = getSketchBookLibsFolder(project);
if(!codeFolder.exists())
buildFolder.create(IResource.NONE, true, null);
if(!dataFolder.exists())
dataFolder.create(IResource.NONE, true, null);
if(!buildFolder.exists())
buildFolder.create(IResource.NONE, true, null);
if(!appletFolder.exists())
appletFolder.create(IResource.NONE, true, null);
if(!javaBuildFolder.exists())
javaBuildFolder.create(IResource.NONE, true, null);
// Setup the Java project underlying the Sketch
IJavaProject jproject = JavaCore.create(project);
// Get a default VM to toss in the mix
IPath containerPath = new Path(JavaRuntime.JRE_CONTAINER);
IVMInstall vm = JavaRuntime.getDefaultVMInstall();
IPath vmPath = containerPath.append(vm.getVMInstallType().getId()).append(vm.getName());
// Setup dynamic classpath containers so we don't have to recalculate them and set them every time
List<IClasspathEntry> entries = new ArrayList<IClasspathEntry>();
entries.add(JavaCore.newContainerEntry(vmPath.makeAbsolute())); // JVM
entries.add(JavaCore.newSourceEntry(buildFolder.getFullPath().makeAbsolute())); // java source
entries.add(JavaCore.newContainerEntry(codeFolder.getFullPath().makeAbsolute())); // data source
if(coreResources != null){
entries.add(
JavaCore.newLibraryEntry( new Path(coreResources.getAbsolutePath()).append("lib/core.jar"),
null, //no source
null, //no source
false //not exported
)
);
}
if(sketchbookLibs != null)
entries.add(JavaCore.newContainerEntry(new Path(sketchbookLibs.getAbsolutePath()))); // sketchbook libs container
// casting doesn't work so we have to explicitly unpack the list.
IClasspathEntry[] classpathEntries = new IClasspathEntry[entries.size()];
for(int i=0; i< entries.size(); i++ ){
classpathEntries[i] = entries.get(i);
}
// Combine all of these entries and set the raw classpath of the project.
// None of these should require further modification because they are dynamic
// Also provide an explicit output folder and a null progress monitor
jproject.setRawClasspath( classpathEntries, javaBuildFolder.getFullPath(), null);
getCodeFolder();
getDataFolder();
// Check the description to see if it already has the builder
IProjectDescription description = this.project.getDescription();
List<ICommand> newCmds = new ArrayList<ICommand>();
newCmds.addAll(Arrays.asList(description.getBuildSpec()));
int ploc = -1; // builder ID location
for (int i = 0; i < newCmds.size(); i++){
if (newCmds.get(i).getBuilderName().equals(SketchBuilder.BUILDER_ID))
ploc = i;
}
if (ploc == 0) // its there and where we want it
return;
if (ploc > 0)
newCmds.remove(ploc); // its not where we want it, remove it and add to the beginning
ICommand command = description.newCommand();
command.setBuilderName(SketchBuilder.BUILDER_ID);
newCmds.add(0, command);
description.setBuildSpec(
(ICommand[]) newCmds.toArray(new ICommand[newCmds.size()]));
project.setDescription(description,null);
// refresh the local space, folders were created
project.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());
// schedule and run a build once its added.
/*new Job("Build Sketch"){
protected IStatus run(IProgressMonitor monitor){
try{
project.build(
IncrementalProjectBuilder.FULL_BUILD,
SketchBuilder.BUILDER_ID,
null,
monitor);
} catch (CoreException e){
ProcessingLog.logError(e);
}
return Status.OK_STATUS;
}
}.schedule();*/
// refresh the local space, folders may have been created
project.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());
}
/**
@@ -253,7 +183,7 @@ public class SketchProject implements IProjectNature {
description.setBuildSpec(newCmds.toArray(new ICommand[newCmds.size()]));
}
}
// clean up your tokens
SketchBuilder.deleteP5ProblemMarkers(project);
}
@@ -262,9 +192,9 @@ public class SketchProject implements IProjectNature {
public QualifiedName getPropertyName(String localName){
return new QualifiedName(ProcessingCore.PLUGIN_ID, localName);
}
/**
* Sets a persistent property in the pojects property store
* Sets a persistent property in the poject's property store
* If there is an exception it will be reported and the project
* will not persist.
**/
@@ -275,88 +205,141 @@ public class SketchProject implements IProjectNature {
ProcessingLog.logError(e);
}
}
/** Trigger a full build of the project being managed */
public void fullBuild(IProgressMonitor monitor) throws CoreException{
project.build(IncrementalProjectBuilder.FULL_BUILD, monitor);
}
/**
* Finds the folder containing the Processing core libraries, which are bundled with the
* plugin. This folder doesn't exist in the workspace, so we return it as a File, not IFile.
* If something goes wrong, logs an error and returns null.
*
* @return File containing the core libraries folder or null
*/
public File getCoreLibsFolder() {
URL fileLocation = ProcessingCore.getProcessingCore().getPluginResource("libraries");
try {
File folder = new File(FileLocator.toFileURL(fileLocation).getPath());
if (folder.exists())
return folder;
} catch (Exception e) {
ProcessingLog.logError(e);
}
return null;
}
/**
* Resolves the plug-in resources folder to a File and returns it. This will include the
* Processing libraries and the core libraries folder.
*
* @return File reference to the core resources
*/
public File getCoreResourcesFolder(){
URL fileLocation = ProcessingCore.getProcessingCore().getPluginResource("");
try {
File folder = new File(FileLocator.toFileURL(fileLocation).getPath());
if (folder.exists())
return folder;
} catch (Exception e) {
ProcessingLog.logError(e);
}
return null;
}
/**
* Find the folder containing the users libraries, which should be in the sketchbook.
* Looks in the user's preferences first, then look relative to the sketch location.
*
* @return File containing the Sketch book library folder, or null if it can't be located
*/
public File getSketchBookLibsFolder(IProject proj) {
IPath sketchbook = ProcessingCorePreferences.current().getSketchbookPath();
if (sketchbook == null)
sketchbook = findSketchBookLibsFolder(proj);
if (sketchbook == null)
return null;
return new File(sketchbook.toOSString());
}
/**
* Tries to locate the sketchbook library folder relative to the project path
* based on the default sketch / sketchbook setup. If such a folder exists, loop
* through its contents until a valid library is found and then return the path
* to the sketchbook. If no valid libraries are found (empty folder, improper
* sketchbook setup), or if no valid folder is found, return null.
*
* @return IPath containing the location of the new library folder, or null
*/
public IPath findSketchBookLibsFolder(IProject proj) {
/** Return the sketch's code folder or null if it cannot be retrieved */
public IFolder getCodeFolder(){
try{
IPath guess = proj.getLocation().removeLastSegments(1).append("libraries");
File folder = new File(guess.toOSString());
if(folder.isDirectory())
for( File file : folder.listFiles()){
if(file.isDirectory())
if (ProcessingCore.isLibrary(file))
return guess;
}
IFolder code = project.getFolder("code");
if(!code.exists())
code.create(IResource.NONE, true, null);
return code;
} catch (Exception e){
ProcessingLog.logError(e);
ProcessingLog.logError("Code folder could not be created.", e);
return null;
}
}
/** Return the sketch's code folder or null if it cannot be retrieved */
public IFolder getDataFolder(){
try{
IFolder data = project.getFolder("data");
if(!data.exists())
data.create(IResource.NONE, true, null);
return data;
} catch (Exception e){
ProcessingLog.logError("Data folder could not be created.", e);
return null;
}
}
/** Return the sketch's code folder or null if it cannot be retrieved. */
public IFolder getAppletFolder(){
try{
IFolder applet = project.getFolder("applet");
if(!applet.exists())
applet.create(IResource.NONE, true, null);
return project.getFolder("applet");
} catch (Exception e){
ProcessingLog.logError("Applet folder could not be created.", e);
return null;
}
}
/**
* Return a vanilla File handle to the output folder for the Java compiler
* inside the cached build folder, or null if it cannot be created.
*/
public File getJavaBuildFolder(){
File build = getBuildFolder();
if(build != null){
File compile = new File(build, "compile");
compile.mkdirs();
if(compile.exists())
return compile;
}
ProcessingLog.logError("Could not create the temporary build (compile) folder.", null);
return null;
}
}
/**
* Returns a vanilla File handle to the project specific build folder, which is located inside
* the temp directory of the plug-in's local cache, or null if it doesn't exist
*/
public File getBuildFolder(){
//File tempBuildFolder = File.createTempFile("")
File tempBuildFolder = new File(ProcessingCore.getProcessingCore().getPluginTempFolder(), project.getName());
tempBuildFolder.mkdirs();
if(tempBuildFolder.exists())
return tempBuildFolder;
ProcessingLog.logError("Could not create the temporary build (preprocess) folder.", null);
return null;
//return project.getFolder("bin").getFullPath().toFile();
}
/**
* Register a new set of class path entries from the provided source folder list and library jars.
* This method completely replaces the old class path.
*
* @param srcFolderPathList A list of absolute paths to source folders
* @param libraryJarPathList A list of absolute paths to source folders
*/
public void updateClasspathEntries( IPath[] srcFolderPathList, IPath[] libraryJarPathList) {
IJavaProject jproject = this.getJavaProject();
// Get a default VM to toss in the mix
IPath containerPath = new Path(JavaRuntime.JRE_CONTAINER);
IVMInstall vm = JavaRuntime.getDefaultVMInstall();
IPath vmPath = containerPath.append(vm.getVMInstallType().getId()).append(vm.getName());
// Duplicate entries cause errors, so prep them with a set
HashSet<IClasspathEntry> entries = new HashSet<IClasspathEntry>();
// VM
entries.add(JavaCore.newContainerEntry(vmPath.makeAbsolute())); // JVM
// if we were given a list of source folders, add them to the list
// this should include the build folder and the code folder, if it was necessary
if(srcFolderPathList != null){
for( IPath p : srcFolderPathList){
entries.add(JavaCore.newSourceEntry(p.makeAbsolute()));
}
}
if(libraryJarPathList != null){
for(IPath p : libraryJarPathList){
//System.out.println(p.toString());
entries.add(
JavaCore.newLibraryEntry(p.makeAbsolute(),
null, // no source
null, // no source
false // not exported
)
);
}
}
// things are added in no particular order
IClasspathEntry[] classpathEntries = new IClasspathEntry[entries.size()];
int i = 0;
for (IClasspathEntry cpe : entries) classpathEntries[i++] = cpe;
// Combine all of these entries and set the raw classpath of the project.
// None of these should require further modification because they are dynamic
// Also provide an explicit output folder and a null progress monitor
try {
jproject.setRawClasspath( classpathEntries, new Path(this.getJavaBuildFolder().getCanonicalPath()), null);
} catch (Exception e) {
ProcessingLog.logError("There was a problem setting the compiler class path.", e);
}
}
}
@@ -2,6 +2,7 @@ package processing.plugin.core.builder;
import java.io.BufferedReader;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -16,7 +17,12 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import processing.plugin.core.ProcessingCore;
import processing.plugin.core.ProcessingCorePreferences;
import processing.plugin.core.ProcessingLog;
/**
@@ -174,7 +180,7 @@ public class Utilities {
/**
* Get a list of packages contained in a .zip file
*/
static private void packageListFromZip(String filename, Hashtable table) {
static public void packageListFromZip(String filename, Hashtable table) {
try {
ZipFile file = new ZipFile(filename);
Enumeration entries = file.entries();
@@ -206,7 +212,7 @@ public class Utilities {
* class is found in a folder, add its containing set of folders to the package
* list. If another folder is found, walk down into that folder and continue.
*/
static private void packageListFromFolder(File dir, String sofar, Hashtable table) {
static public void packageListFromFolder(File dir, String sofar, Hashtable table) {
boolean foundClass = false;
String files[] = dir.list();
@@ -227,169 +233,269 @@ public class Utilities {
}
}
}
/**
* 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'))) {
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();
}
/**
* Match a string with a regular expression, and returns the match as an
* array. The first index is the matching expression, and array elements
* [1] and higher represent each of the groups (sequences found in parens).
*
* This uses multiline matching (Pattern.MULTILINE) and dotall mode
* (Pattern.DOTALL) by default, so that ^ and $ match the beginning and
* end of any lines found in the source, and the . operator will also
* pick up newline characters.
*/
static public String[] match(String what, String regexp) {
Pattern p = matchPattern(regexp);
Matcher m = p.matcher(what);
if (m.find()) {
int count = m.groupCount() + 1;
String[] groups = new String[count];
for (int i = 0; i < count; i++) {
groups[i] = m.group(i);
}
return groups;
}
return null;
}
static protected HashMap<String, Pattern> matchPatterns;
static Pattern matchPattern(String regexp) {
Pattern p = null;
if (matchPatterns == null) {
matchPatterns = new HashMap<String, Pattern>();
} else {
p = matchPatterns.get(regexp);
}
if (p == null) {
if (matchPatterns.size() == 10) {
// Just clear out the match patterns here if more than 10 are being
// used. It's not terribly efficient, but changes that you have >10
// different match patterns are very slim, unless you're doing
// something really tricky (like custom match() methods), in which
// case match() won't be efficient anyway. (And you should just be
// using your own Java code.) The alternative is using a queue here,
// but that's a silly amount of work for negligible benefit.
matchPatterns.clear();
}
p = Pattern.compile(regexp, Pattern.MULTILINE | Pattern.DOTALL);
matchPatterns.put(regexp, p);
}
return p;
}
/**
* Find the folder containing the users libraries, which should be in the sketchbook.
* Looks in the user's preferences first, then look relative to the sketch location.
*
* @return File containing the Sketch book library folder, or null if it can't be located
*/
public static File getSketchBookLibsFolder(IProject proj) {
IPath sketchbook = ProcessingCorePreferences.current().getSketchbookPath();
if (sketchbook == null)
sketchbook = findSketchBookLibsFolder(proj);
if (sketchbook == null)
return null;
return new File(sketchbook.toOSString());
}
/**
* Split a String on a specific delimiter. Unlike Java's String.split()
* method, this does not parse the delimiter as a regexp because it's more
* confusing than necessary, and String.split() is always available for
* those who want regexp.
*/
static public String[] split(String what, String delim) {
ArrayList<String> items = new ArrayList<String>();
int index;
int offset = 0;
while ((index = what.indexOf(delim, offset)) != -1) {
items.add(what.substring(offset, index));
offset = index + delim.length();
}
items.add(what.substring(offset));
String[] outgoing = new String[items.size()];
items.toArray(outgoing);
return outgoing;
}
/**
* Split a string into pieces along a specific character.
* Most commonly used to break up a String along a space or a tab
* character.
* <P>
* This operates differently than the others, where the
* single delimeter is the only breaking point, and consecutive
* delimeters will produce an empty string (""). This way,
* one can split on tab characters, but maintain the column
* alignments (of say an excel file) where there are empty columns.
*/
static public String[] split(String what, char delim) {
// do this so that the exception occurs inside the user's
// program, rather than appearing to be a bug inside split()
if (what == null) return null;
//return split(what, String.valueOf(delim)); // huh
/**
* Tries to locate the sketchbook library folder relative to the project path
* based on the default sketch / sketchbook setup. If such a folder exists, loop
* through its contents until a valid library is found and then return the path
* to the sketchbook. If no valid libraries are found (empty folder, improper
* sketchbook setup), or if no valid folder is found, return null.
*
* @return IPath containing the location of the new library folder, or null
*/
public static IPath findSketchBookLibsFolder(IProject proj) {
try{
IPath guess = proj.getLocation().removeLastSegments(1).append("libraries");
File folder = new File(guess.toOSString());
if(folder.isDirectory())
for( File file : folder.listFiles()){
if(file.isDirectory())
if (ProcessingCore.isLibrary(file))
return guess;
}
} catch (Exception e){
ProcessingLog.logError(e);
}
return null;
}
char chars[] = what.toCharArray();
int splitCount = 0; //1;
for (int i = 0; i < chars.length; i++) {
if (chars[i] == delim) splitCount++;
}
// make sure that there is something in the input string
//if (chars.length > 0) {
// if the last char is a delimeter, get rid of it..
//if (chars[chars.length-1] == delim) splitCount--;
// on second thought, i don't agree with this, will disable
//}
if (splitCount == 0) {
String splits[] = new String[1];
splits[0] = new String(what);
return splits;
}
//int pieceCount = splitCount + 1;
String splits[] = new String[splitCount + 1];
int splitIndex = 0;
int startIndex = 0;
for (int i = 0; i < chars.length; i++) {
if (chars[i] == delim) {
splits[splitIndex++] =
new String(chars, startIndex, i-startIndex);
startIndex = i + 1;
}
}
//if (startIndex != chars.length) {
splits[splitIndex] =
new String(chars, startIndex, chars.length-startIndex);
//}
return splits;
}
/**
* If the folder is the root of a Processing library, return a String containing
* the canonical path to the library's Jar. If it is not, return null.
*/
public static String getLibraryJarPath(File folder){
if( ProcessingCore.isLibrary(folder) ){
try {
return folder.getCanonicalPath().concat( File.separatorChar + "library" + File.separatorChar + folder.getName() + ".jar" );
} catch (IOException e) {
ProcessingLog.logError("Could not get the library jar for library " + folder.getName(), e);
}
}
return null;
}
/**
* Looks in the provided folder for valid libraries and returns a list of paths to them.
* Returns an empty list if there are no valid libraries.
*
* @param folder
* @return
*/
public static ArrayList<String> getLibraryJars(File folder){
ArrayList<String> libPaths = new ArrayList<String>();
if(folder == null) return libPaths;
if(!folder.exists()) return libPaths;
for (File f : folder.listFiles()){
if ( ProcessingCore.isLibrary(f) ){
// if it is a library, add the jar
String path = getLibraryJarPath(f);
if (path!= null)
libPaths.add(path);
} else if (f.isDirectory()){
// if it is not a library, but is a directory, recurse
// and add all libraries in it to our list
libPaths.addAll(getLibraryJars(f));
}
// we don't care about anything else.
}
return libPaths;
}
/**
* 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'))) {
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();
}
/**
* Match a string with a regular expression, and returns the match as an
* array. The first index is the matching expression, and array elements
* [1] and higher represent each of the groups (sequences found in parens).
*
* This uses multiline matching (Pattern.MULTILINE) and dotall mode
* (Pattern.DOTALL) by default, so that ^ and $ match the beginning and
* end of any lines found in the source, and the . operator will also
* pick up newline characters.
*/
static public String[] match(String what, String regexp) {
Pattern p = matchPattern(regexp);
Matcher m = p.matcher(what);
if (m.find()) {
int count = m.groupCount() + 1;
String[] groups = new String[count];
for (int i = 0; i < count; i++) {
groups[i] = m.group(i);
}
return groups;
}
return null;
}
static protected HashMap<String, Pattern> matchPatterns;
static public Pattern matchPattern(String regexp) {
Pattern p = null;
if (matchPatterns == null) {
matchPatterns = new HashMap<String, Pattern>();
} else {
p = matchPatterns.get(regexp);
}
if (p == null) {
if (matchPatterns.size() == 10) {
// Just clear out the match patterns here if more than 10 are being
// used. It's not terribly efficient, but changes that you have >10
// different match patterns are very slim, unless you're doing
// something really tricky (like custom match() methods), in which
// case match() won't be efficient anyway. (And you should just be
// using your own Java code.) The alternative is using a queue here,
// but that's a silly amount of work for negligible benefit.
matchPatterns.clear();
}
p = Pattern.compile(regexp, Pattern.MULTILINE | Pattern.DOTALL);
matchPatterns.put(regexp, p);
}
return p;
}
/**
* Split a String on a specific delimiter. Unlike Java's String.split()
* method, this does not parse the delimiter as a regexp because it's more
* confusing than necessary, and String.split() is always available for
* those who want regexp.
*/
static public String[] split(String what, String delim) {
ArrayList<String> items = new ArrayList<String>();
int index;
int offset = 0;
while ((index = what.indexOf(delim, offset)) != -1) {
items.add(what.substring(offset, index));
offset = index + delim.length();
}
items.add(what.substring(offset));
String[] outgoing = new String[items.size()];
items.toArray(outgoing);
return outgoing;
}
/**
* Split a string into pieces along a specific character.
* Most commonly used to break up a String along a space or a tab
* character.
* <P>
* This operates differently than the others, where the
* single delimeter is the only breaking point, and consecutive
* delimeters will produce an empty string (""). This way,
* one can split on tab characters, but maintain the column
* alignments (of say an excel file) where there are empty columns.
*/
static public String[] split(String what, char delim) {
// do this so that the exception occurs inside the user's
// program, rather than appearing to be a bug inside split()
if (what == null) return null;
//return split(what, String.valueOf(delim)); // huh
char chars[] = what.toCharArray();
int splitCount = 0; //1;
for (int i = 0; i < chars.length; i++) {
if (chars[i] == delim) splitCount++;
}
// make sure that there is something in the input string
//if (chars.length > 0) {
// if the last char is a delimeter, get rid of it..
//if (chars[chars.length-1] == delim) splitCount--;
// on second thought, i don't agree with this, will disable
//}
if (splitCount == 0) {
String splits[] = new String[1];
splits[0] = new String(what);
return splits;
}
//int pieceCount = splitCount + 1;
String splits[] = new String[splitCount + 1];
int splitIndex = 0;
int startIndex = 0;
for (int i = 0; i < chars.length; i++) {
if (chars[i] == delim) {
splits[splitIndex++] =
new String(chars, startIndex, i-startIndex);
startIndex = i + 1;
}
}
//if (startIndex != chars.length) {
splits[splitIndex] =
new String(chars, startIndex, chars.length-startIndex);
//}
return splits;
}
public static void deleteFolderContents(File folder) {
if (folder == null) return;
if (!folder.isDirectory()) return;
for (File f : folder.listFiles()){
if(!f.delete()){
if(f.isDirectory()) {
deleteFolderContents(f);
} else {
// that's odd. could not be deleted and isn't a directory. it might be locked or have permissions issues
ProcessingLog.logError( "Could not delete " + f.getName()
+ ". If it causes problems, you may have to manually delete it. You can find it here: "
+ f.getAbsolutePath(), null);
}
}
}
}
}
@@ -114,17 +114,20 @@ public class NewSketchWizard extends Wizard implements INewWizard {
// create the folders
IContainer container = (IContainer) proj;
// Configuring the project will set up the folder structure
//data
IFolder dataFolder = container.getFolder(new Path("data"));
dataFolder.create(true, true, monitor);
monitor.worked(33);
//code
IFolder codeFolder = container.getFolder(new Path("code"));
codeFolder.create(true, true, monitor);
monitor.worked(33);
//bin
IFolder binFolder = container.getFolder(new Path("bin"));
binFolder.create(true, true, monitor);
// IFolder dataFolder = container.getFolder(new Path("data"));
// dataFolder.create(true, true, monitor);
// monitor.worked(33);
// //code
// IFolder codeFolder = container.getFolder(new Path("code"));
// codeFolder.create(true, true, monitor);
// monitor.worked(33);
// //bin
// IFolder binFolder = container.getFolder(new Path("bin"));
// binFolder.create(true, true, monitor);
monitor.worked(34);
if (monitor.isCanceled()){throw new OperationCanceledException();}