From aa2d0e0c3cae5e3356a5d5d6d89f4e09b88a6c11 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 11 Feb 2013 18:11:52 +0100 Subject: [PATCH] Factoring Library class, step 2: first try parsing library metadata --- app/src/processing/app/Base.java | 97 ++++++------- app/src/processing/app/Sketch.java | 23 +--- app/src/processing/app/debug/Compiler.java | 10 +- .../app/helpers/StringMatchers.java | 21 +++ app/src/processing/app/packages/Library.java | 127 +++++++++++++----- .../processing/app/packages/LibraryList.java | 40 ++++++ .../processing/app/syntax/PdeKeywords.java | 2 +- 7 files changed, 207 insertions(+), 113 deletions(-) create mode 100644 app/src/processing/app/helpers/StringMatchers.java diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 183cd6484..ef17d0ffe 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -1044,25 +1044,17 @@ public class Base { } public LibraryList getIDELibs() { - LibraryList libs = new LibraryList(); if (libraries == null) - return libs; - for (Library lib : libraries) { - if (!FileUtils.isSubDirectory(getSketchbookFolder(), lib.getRootFolder())) - libs.add(lib); - } - return libs; + return new LibraryList(); + LibraryList res = new LibraryList(libraries); + res.removeAll(getUserLibs()); + return res; } public LibraryList getUserLibs() { - LibraryList libs = new LibraryList(); if (libraries == null) - return libs; - for (Library lib : libraries) { - if (FileUtils.isSubDirectory(getSketchbookFolder(), lib.getRootFolder())) - libs.add(lib); - } - return libs; + return new LibraryList(); + return libraries.filterLibrariesInSubfolder(getSketchbookFolder()); } public void rebuildImportMenu(JMenu importMenu, final Editor editor) { @@ -1124,28 +1116,16 @@ public class Base { // Add examples from libraries LibraryList ideLibs = getIDELibs(); - Collections.sort(ideLibs, Library.CASE_INSENSITIVE_ORDER); - for (Library lib : ideLibs) { - File folder = lib.getRootFolder(); - String name = lib.getName(); - addSketchesSubmenu(menu, name, folder, false); - // Allows "fat" libraries to have examples in the root folder - if (folder.getName().equals(Base.getTargetPlatform().getName())) - addSketchesSubmenu(menu, name, folder.getParentFile(), false); - } + ideLibs.sort(); + for (Library lib : ideLibs) + addSketchesSubmenu(menu, lib, false); LibraryList userLibs = getUserLibs(); if (userLibs.size()>0) { menu.addSeparator(); - Collections.sort(userLibs, Library.CASE_INSENSITIVE_ORDER); - for (Library lib : userLibs) { - File folder = lib.getRootFolder(); - String name = lib.getName(); - addSketchesSubmenu(menu, name, folder, false); - // Allows "fat" libraries to have examples in the root folder - if (folder.getName().equals(Base.getTargetPlatform().getName())) - addSketchesSubmenu(menu, name, folder.getParentFile(), false); - } + userLibs.sort(); + for (Library lib : userLibs) + addSketchesSubmenu(menu, lib, false); } } catch (IOException e) { e.printStackTrace(); @@ -1155,7 +1135,7 @@ public class Base { public LibraryList scanLibraries(List folders) { LibraryList res = new LibraryList(); for (File folder : folders) - res.addAll(scanLibraries(folder)); + res.addOrReplaceAll(scanLibraries(folder)); return res; } @@ -1178,8 +1158,7 @@ public class Base { continue; } - Library lib = Library.fromFolder(subfolder, Base.getTargetPlatform().getName()); - + Library lib = Library.create(subfolder); // (also replace previously found libs with the same name) if (lib != null) res.addOrReplace(lib); @@ -1206,18 +1185,20 @@ public class Base { // Libraries located in the latest folders on the list can override // other libraries with the same name. libraries = scanLibraries(librariesFolders); - + String currentArch = Base.getTargetPlatform().getName(); + libraries = libraries.filterByArchitecture(currentArch); + // Populate importToLibraryTable importToLibraryTable = new HashMap(); for (Library lib : libraries) { try { - String headers[] = headerListFromIncludePath(lib.getRootFolder()); + String headers[] = headerListFromIncludePath(lib.getSrcFolder()); for (String header : headers) { importToLibraryTable.put(header, lib); } } catch (IOException e) { showWarning(_("Error"), I18n - .format("Unable to list header files in {0}", lib.getRootFolder()), e); + .format("Unable to list header files in {0}", lib.getSrcFolder()), e); } } @@ -1495,6 +1476,13 @@ public class Base { return ifound; // actually ignored, but.. } + private boolean addSketchesSubmenu(JMenu menu, Library lib, + boolean replaceExisting) + throws IOException { + return addSketchesSubmenu(menu, lib.getName(), lib.getFolder(), + replaceExisting); + } + private boolean addSketchesSubmenu(JMenu menu, String name, File folder, final boolean replaceExisting) throws IOException { @@ -1564,26 +1552,25 @@ public class Base { protected void addLibraries(JMenu menu, LibraryList libs) throws IOException { LibraryList list = new LibraryList(libs); - Collections.sort(list, Library.CASE_INSENSITIVE_ORDER); - - ActionListener listener = new ActionListener() { - public void actionPerformed(ActionEvent event) { - String jarPath = event.getActionCommand(); - try { - activeEditor.getSketch().importLibrary(jarPath); - } catch (IOException e) { - showWarning(_("Error"), I18n.format("Unable to list header files in {0}", jarPath), e); - } - } - }; + list.sort(); for (Library lib : list) { - File folder = lib.getRootFolder(); - + @SuppressWarnings("serial") + AbstractAction action = new AbstractAction(lib.getName()) { + public void actionPerformed(ActionEvent event) { + Library l = (Library) getValue("library"); + try { + activeEditor.getSketch().importLibrary(l); + } catch (IOException e) { + showWarning(_("Error"), I18n.format("Unable to list header files in {0}", l.getSrcFolder()), e); + } + } + }; + action.putValue("library", lib); + // Add new element at the bottom - JMenuItem item = new JMenuItem(lib.getName()); - item.addActionListener(listener); - item.setActionCommand(folder.getAbsolutePath()); + JMenuItem item = new JMenuItem(action); + item.putClientProperty("library", lib); menu.add(item); // XXX: DAM: should recurse here so that library folders can be nested diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java index df09bab1a..fe65a9761 100644 --- a/app/src/processing/app/Sketch.java +++ b/app/src/processing/app/Sketch.java @@ -89,12 +89,6 @@ public class Sketch { /** Class path determined during build. */ private String classPath; - /** - * This is *not* the "Processing" libraries path, this is the Java libraries - * path, as in java.library.path=BlahBlah, which identifies search paths for - * DLLs or JNILIBs. - */ - private String libraryPath; /** * List of library folders. */ @@ -1122,15 +1116,19 @@ public class Sketch { } + public void importLibrary(Library lib) throws IOException { + importLibrary(lib.getSrcFolder()); + } + /** * Add import statements to the current tab for all of packages inside * the specified jar file. */ - public void importLibrary(String jarPath) throws IOException { + public void importLibrary(File jarPath) throws IOException { // make sure the user didn't hide the sketch folder ensureExistence(); - String list[] = Base.headerListFromIncludePath(new File(jarPath)); + String list[] = Base.headerListFromIncludePath(jarPath); // import statements into the main sketch file (code[0]) // if the current code is a .java file, insert into current @@ -1424,8 +1422,6 @@ public class Sketch { // grab the imports from the code just preproc'd importedLibraries = new LibraryList(); - //Remember to clear library path before building it. - libraryPath = ""; for (String item : preprocessor.getExtraImports()) { Library lib = Base.importToLibraryTable.get(item); @@ -1433,8 +1429,6 @@ public class Sketch { if (lib != null && !importedLibraries.contains(lib)) { importedLibraries.add(lib); - //classPath += Compiler.contentsToClassPath(libFolder); - libraryPath += File.pathSeparator + lib.getRootFolder().getAbsolutePath(); } } @@ -1889,11 +1883,6 @@ public class Sketch { } - public String getLibraryPath() { - return libraryPath; - } - - public SketchCode[] getCode() { return code; } diff --git a/app/src/processing/app/debug/Compiler.java b/app/src/processing/app/debug/Compiler.java index ebb997116..c1e94bee4 100644 --- a/app/src/processing/app/debug/Compiler.java +++ b/app/src/processing/app/debug/Compiler.java @@ -86,7 +86,7 @@ public class Compiler implements MessageConsumer { if (prefs.get("build.variant.path").length() != 0) includePaths.add(prefs.get("build.variant.path")); for (Library lib : sketch.getImportedLibraries()) - includePaths.add(lib.getRootFolder().getPath()); + includePaths.add(lib.getSrcFolder().getPath()); // 1. compile the sketch (already in the buildPath) sketch.setCompilingProgress(30); @@ -582,11 +582,11 @@ public class Compiler implements MessageConsumer { void compileLibraries(List includePaths) throws RunnerException { File outputPath = new File(prefs.get("build.path")); for (Library lib : sketch.getImportedLibraries()) { - File libFolder = lib.getRootFolder(); - if (lib.isNewLib()) { - recursiveCompileLibrary(outputPath, libFolder, includePaths); - } else { + File libFolder = lib.getSrcFolder(); + if (lib.isPre15Lib()) { compileLibrary(outputPath, libFolder, includePaths); + } else { + recursiveCompileLibrary(outputPath, libFolder, includePaths); } } } diff --git a/app/src/processing/app/helpers/StringMatchers.java b/app/src/processing/app/helpers/StringMatchers.java new file mode 100644 index 000000000..686d9b2ab --- /dev/null +++ b/app/src/processing/app/helpers/StringMatchers.java @@ -0,0 +1,21 @@ +package processing.app.helpers; + +public class StringMatchers { + + /** + * Tries to match input with pattern. The pattern can use the + * "*" and "?" globs to match any-char-sequence and any-char respectively. + * + * @param input + * The string to be checked + * @param pattern + * The pattern to match + * @return true if the input matches the pattern, + * false otherwise. + */ + public static boolean wildcardMatch(String input, String pattern) { + String regex = pattern.replace("?", ".?").replace("*", ".*?"); + return input.matches(regex); + } + +} diff --git a/app/src/processing/app/packages/Library.java b/app/src/processing/app/packages/Library.java index 27f72254b..f795a1f8b 100644 --- a/app/src/processing/app/packages/Library.java +++ b/app/src/processing/app/packages/Library.java @@ -1,64 +1,114 @@ package processing.app.packages; +import static processing.app.helpers.StringMatchers.wildcardMatch; + import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Comparator; import java.util.List; +import processing.app.helpers.PreferencesMap; + public class Library { private String name; - private File folder; + private String version; + private File folder, srcFolder; private List architectures; - private boolean oldLib = true; + private boolean pre15Lib; /** - * Scans inside a library folder to see if it contains a version suitable for - * the actual selected architecture. If a suitable version is found the folder - * containing that version is selected, otherwise null is selected.
- *
- * If an old-style library is detected, we assume that the library is suitable - * for the current architecture and the libFolder parameter is used.
+ * Scans inside a folder and create a Library object out of it. Automatically + * detects pre-1.5 libraries. Automatically fills metadata from + * library.properties file if found. * * @param libFolder - * @param arch - * Currently selected architecture * @return */ - static public Library fromFolder(File libFolder, String arch) { + static public Library create(File libFolder) { // A library is considered "new" if it contains a file called // "library.properties" - File libraryPropFile = new File(libFolder, "library.properties"); - if (!libraryPropFile.exists() || !libraryPropFile.isFile()) { - // construct an old style library - Library res = new Library(); - res.folder = libFolder; - res.name = libFolder.getName(); - res.oldLib = true; - return res; + File check = new File(libFolder, "library.properties"); + if (!check.exists() || !check.isFile()) + return createPre15Library(libFolder); + else + return createLibrary(libFolder); + } + + private static Library createLibrary(File libFolder) { + // Parse metadata + File propertiesFile = new File(libFolder, "library.properties"); + PreferencesMap properties = new PreferencesMap(); + try { + properties.load(propertiesFile); + } catch (IOException e) { + e.printStackTrace(); + return null; } - // Search for a subfolder for actual architecture, return null if not found - File archSubfolder = new File(libFolder, arch); - if (!archSubfolder.exists() || !archSubfolder.isDirectory()) + // Library sanity checks + // --------------------- + + // 1. Check mandatory properties + if (!properties.containsKey("name")) + return null; + if (!properties.containsKey("version")) + return null; + if (!properties.containsKey("architectures")) return null; + // 2. Check mandatory folders + File srcFolder = new File(libFolder, "src"); + if (!srcFolder.exists() && !srcFolder.isDirectory()) + return null; + + // TODO: 3. check if root folder contains prohibited stuff + + // Extract metadata info + // TODO: do for all metadata + List archs = new ArrayList(); + for (String arch : properties.get("architectures").split(",")) + archs.add(arch.trim()); + Library res = new Library(); - res.folder = archSubfolder; - res.name = libFolder.getName(); - res.oldLib = false; + res.folder = libFolder; + res.srcFolder = srcFolder; + res.name = properties.get("name").trim(); + res.architectures = archs; + res.version = properties.get("version").trim(); + res.pre15Lib = false; return res; } - public File getRootFolder() { - return folder; + private static Library createPre15Library(File libFolder) { + // construct an old style library + Library res = new Library(); + res.folder = libFolder; + res.srcFolder = libFolder; + res.name = libFolder.getName(); + res.architectures = Arrays.asList(new String[] { "*" }); + res.pre15Lib = true; + return res; } - public String getName() { - return name; + public List getSrcFolders(String reqArch) { + if (!supportsArchitecture(reqArch)) + return null; + List res = new ArrayList(); + res.add(srcFolder); + File archSpecificFolder = new File(srcFolder, reqArch); + if (archSpecificFolder.exists() && archSpecificFolder.isDirectory()) + res.add(archSpecificFolder); + return res; } - public void setName(String _name) { - name = _name; + public boolean supportsArchitecture(String reqArch) { + for (String arch : architectures) + if (wildcardMatch(reqArch, arch)) + return true; + return false; } public static final Comparator CASE_INSENSITIVE_ORDER = new Comparator() { @@ -68,12 +118,19 @@ public class Library { } }; - public boolean isOldLib() { - return oldLib; + public File getSrcFolder() { + return srcFolder; } - public boolean isNewLib() { - return !oldLib; + public String getName() { + return name; } + public boolean isPre15Lib() { + return pre15Lib; + } + + public File getFolder() { + return folder; + } } diff --git a/app/src/processing/app/packages/LibraryList.java b/app/src/processing/app/packages/LibraryList.java index 94fe5089e..343ff4bde 100644 --- a/app/src/processing/app/packages/LibraryList.java +++ b/app/src/processing/app/packages/LibraryList.java @@ -1,6 +1,11 @@ package processing.app.packages; +import java.io.File; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +import processing.app.helpers.FileUtils; @SuppressWarnings("serial") public class LibraryList extends ArrayList { @@ -27,4 +32,39 @@ public class LibraryList extends ArrayList { add(lib); } + public void addOrReplaceAll(Collection c) { + for (Library l : c) + addOrReplace(l); + } + + public void sort() { + Collections.sort(this, Library.CASE_INSENSITIVE_ORDER); + } + + public Library search(String name, String arch) { + for (Library lib : this) { + if (!lib.getName().equals(name)) + continue; + if (!lib.supportsArchitecture(arch)) + continue; + return lib; + } + return null; + } + + public LibraryList filterByArchitecture(String reqArch) { + LibraryList res = new LibraryList(); + for (Library lib : this) + if (lib.supportsArchitecture(reqArch)) + res.add(lib); + return res; + } + + public LibraryList filterLibrariesInSubfolder(File subFolder) { + LibraryList res = new LibraryList(); + for (Library lib : this) + if (FileUtils.isSubDirectory(subFolder, lib.getFolder())) + res.add(lib); + return res; + } } diff --git a/app/src/processing/app/syntax/PdeKeywords.java b/app/src/processing/app/syntax/PdeKeywords.java index 4b8d8dfbe..701978a45 100644 --- a/app/src/processing/app/syntax/PdeKeywords.java +++ b/app/src/processing/app/syntax/PdeKeywords.java @@ -61,7 +61,7 @@ public class PdeKeywords extends CTokenMarker { keywordToReference = new Hashtable(); getKeywords(Base.getLibStream("keywords.txt")); for (Library lib : Base.getLibraries()) { - File keywords = new File(lib.getRootFolder(), "keywords.txt"); + File keywords = new File(lib.getFolder(), "keywords.txt"); if (keywords.exists()) getKeywords(new FileInputStream(keywords)); } } catch (Exception e) {