Skip to content

Hierarchical dependencies #3425

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions app/src/processing/app/Sketch.java
Original file line number Diff line number Diff line change
Expand Up @@ -931,14 +931,14 @@ public boolean addFile(File sourceFile) {


public void importLibrary(UserLibrary lib) throws IOException {
importLibrary(lib.getSrcFolder());
importLibrary(lib.getSrcFolder(), lib.getDepSpec());
}

/**
* Add import statements to the current tab for all of packages inside
* the specified jar file.
*/
private void importLibrary(File jarPath) throws IOException {
private void importLibrary(File jarPath, String depSpec) throws IOException {
// make sure the user didn't hide the sketch folder
ensureExistence();

Expand All @@ -960,7 +960,11 @@ private void importLibrary(File jarPath) throws IOException {
for (String aList : list) {
buffer.append("#include <");
buffer.append(aList);
buffer.append(">\n");
buffer.append(">");
if (depSpec != null) {
buffer.append(" //!Lib \"" + depSpec + "\"");
}
buffer.append("\n");
}
buffer.append('\n');
buffer.append(editor.getText());
Expand Down
55 changes: 55 additions & 0 deletions app/src/processing/app/syntax/SketchTextArea.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
import org.fife.ui.rtextarea.RTextAreaUI;
import org.fife.ui.rtextarea.RUndoManager;
import processing.app.*;
import processing.app.packages.UserLibrary;
import processing.app.packages.LibrarySelection;
import processing.app.preproc.PdePreprocessor;

import javax.swing.*;
import javax.swing.event.EventListenerList;
Expand Down Expand Up @@ -396,6 +399,7 @@ public void mouseMoved(MouseEvent e) {
t = new TokenImpl(t);
}
Cursor c2;
String tipText = null;
if (t != null && t.isHyperlink()) {
if (hoveredOverLinkOffset == -1 ||
hoveredOverLinkOffset != t.getOffset()) {
Expand Down Expand Up @@ -432,12 +436,63 @@ public void mouseMoved(MouseEvent e) {
c2 = Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR);
hoveredOverLinkOffset = -1;
// linkGeneratorResult = null;

int pos = viewToModel(e.getPoint());
if (pos > -1) {
int lineNo = -1;
try {
lineNo = getLineOfOffset(pos);
} catch (BadLocationException ex) {}
String line = getTextLine(lineNo);
if (line != null) {
tipText = getImportInfo(line);
}
}
}
if (getCursor() != c2) {
setCursor(c2);
// TODO: Repaint just the affected line(s).
repaint(); // Link either left or went into.
}
setToolTipText(tipText);
}

private String getImportInfo(String line) {
java.util.List<String[]> incs = PdePreprocessor.findIncludes(line);
LibrarySelection libSel = null;
if (!incs.isEmpty()) {
// Note: does not have a valid preferSet, so answer may be inaccurate
libSel = BaseNoGui.findLibraryByImport(incs.get(0), new HashSet<>());
}
String info = null;
if (libSel != null) {
UserLibrary lib = libSel.get();
info = getLibDescription(lib, incs.get(0));
for (LibrarySelection recLibSel : lib.getRequiredLibsRec()) {
// TODO: also check import spec of recursive deps
info += "\n* " + getLibDescription(recLibSel.get(), null);
}
}
return info;
}

private String getLibDescription(UserLibrary lib, String[] importSpec) {
String ver = lib.getVersion();
if (ver != null) {
ver = " " + ver;
} else {
ver = "";
}
String folder = "";
if (lib instanceof UserLibrary) {
folder = ": " + lib.getSrcFolder().toString();
}
String desc = lib.getName() + " (" + lib.getGlobalName() + ")" + ver + folder;
if (importSpec != null && importSpec[1] != null &&
!lib.matchesDepSpecVersion(importSpec[1])) {
desc += "\nWARNING: "+lib.getGlobalName()+" is an incorrect version.";
}
return desc;
}

private void stopScanningForLinks() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,14 @@

import java.util.Comparator;
import java.util.List;
import java.util.SortedSet;

import static processing.app.I18n._;

public abstract class ContributedLibrary extends DownloadableContribution {

public abstract String getGlobalName();

public abstract String getName();

public abstract String getMaintainer();
Expand Down Expand Up @@ -142,10 +145,10 @@ public boolean equals(Object obj) {
boolean versionEquals = thisVersion == otherVersion ||
(thisVersion != null && otherVersion != null && thisVersion.equals(otherVersion));

String thisName = getName();
String otherName = ((ContributedLibrary) obj).getName();
String thisName = getGlobalName();
String otherName = ((ContributedLibrary) obj).getGlobalName();

boolean nameEquals = thisName == null || otherName == null || thisName.equals(otherName);
boolean nameEquals = thisName != null && otherName != null && thisName.equals(otherName);

return versionEquals && nameEquals;
}
Expand Down
65 changes: 61 additions & 4 deletions arduino-core/src/processing/app/BaseNoGui.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
import processing.app.helpers.filefilters.OnlyFilesWithExtension;
import processing.app.legacy.PApplet;
import processing.app.packages.LibraryList;
import processing.app.packages.LibrarySelection;
import processing.app.packages.UserLibrary;
import processing.app.preproc.PdePreprocessor;

import java.io.*;
import java.net.URISyntaxException;
Expand Down Expand Up @@ -850,10 +852,10 @@ static private void createToolPreferences(ContributionsIndexer indexer) {
}

static public void populateImportToLibraryTable() {
// Populate importToLibraryTable. Each header filename maps to
// a list of libraries. Compiler.java will use only the first
// library on each list. The others are used only to advise
// user of ambiguously matched and duplicate libraries.
// Populate importToLibraryTable. Each header filename maps to a list of
// libraries. Compiler.java will use the dependency specs in the source
// files to decide which library to use from the list. The list is also
// used to advise user of ambiguously matched and duplicate libraries.
importToLibraryTable = new HashMap<String, LibraryList>();
for (UserLibrary lib : librariesIndexer.getInstalledLibraries()) {
try {
Expand Down Expand Up @@ -962,6 +964,61 @@ static public void populateImportToLibraryTable() {
}
}

static public LibrarySelection findLibraryByImport(String[] importSpec,
Set<UserLibrary> preferSet) {
LibraryList list = importToLibraryTable.get(importSpec[0]);
if (list == null || list.isEmpty()) {
return null;
}
int index = 0;
if (importSpec[1] != null && !importSpec[1].isEmpty()) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i).matchesDepSpec(importSpec[1])) {
index = i;
}
}
} else if (preferSet != null) {
// No dep spec - prefer library already imported in this context
for (int i = 0; i < list.size(); i++) {
if (preferSet.contains(list.get(i))) {
index = i;
}
}
}
// Keep track of libraries already imported in this context
LibrarySelection libSel = new LibrarySelection(list, index);
preferSet.add(libSel.get());
return libSel;
}

static public LibrarySelection findLibraryByCode(String code) {
List<String[]> incs = PdePreprocessor.findIncludes(code);
if (incs.isEmpty()) {
return null;
}
return findLibraryByImport(incs.get(0), null);
}

static public List<LibrarySelection> findLibrariesByCode(String code,
Set<UserLibrary> preferSet)
throws IOException {
List<LibrarySelection> libs = new ArrayList<>();
List<String[]> incs = PdePreprocessor.findIncludes(code);
for (String[] inc : incs) {
LibrarySelection lib = findLibraryByImport(inc, preferSet);
if (lib != null) {
libs.add(lib);
}
}
return libs;
}

static public List<LibrarySelection> findLibrariesByCode(File file,
Set<UserLibrary> preferSet)
throws IOException {
return findLibrariesByCode(FileUtils.readFileToString(file), preferSet);
}

static public void initParameters(String args[]) throws IOException {
String preferencesFile = null;

Expand Down
81 changes: 64 additions & 17 deletions arduino-core/src/processing/app/debug/Compiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import processing.app.legacy.PApplet;
import processing.app.packages.LegacyUserLibrary;
import processing.app.packages.UserLibrary;
import processing.app.packages.LibrarySelection;
import processing.app.tools.DoubleQuotedArgumentsOnWindowsCommandLine;

public class Compiler implements MessageConsumer {
Expand Down Expand Up @@ -489,12 +490,15 @@ private void adviseDuplicateLibraries() {
System.out.println(I18n.format(_("Multiple libraries were found for \"{0}\""),
importedDuplicateHeaders.get(i)));
boolean first = true;
for (UserLibrary lib : importedDuplicateLibraries.get(i)) {
if (first) {
System.out.println(I18n.format(_(" Used: {0}"),
lib.getInstalledFolder().getPath()));
first = false;
} else {
LibrarySelection libSel = importedDuplicateLibraries.get(i);

System.out.println(I18n.format(_(" Used: {0}"),
libSel.get().getInstalledFolder().getPath()));
first = false;

for (int j = 0; j < libSel.getList().size(); j++) {
if (j != libSel.getIndex()) {
UserLibrary lib = libSel.getList().get(j);
System.out.println(I18n.format(_(" Not used: {0}"),
lib.getInstalledFolder().getPath()));
}
Expand Down Expand Up @@ -608,6 +612,36 @@ private PreferencesMap createBuildPreferences(String _buildPath,
return p;
}

static public List<File> findAllSources(File sourcePath, boolean recurse) {
List<File> allSources = new ArrayList<>();
allSources.addAll(findFilesInFolder(sourcePath, "S", recurse));
allSources.addAll(findFilesInFolder(sourcePath, "c", recurse));
allSources.addAll(findFilesInFolder(sourcePath, "cpp", recurse));
allSources.addAll(findFilesInFolder(sourcePath, "h", recurse));
allSources.addAll(findFilesInFolder(sourcePath, "hh", recurse));
allSources.addAll(findFilesInFolder(sourcePath, "hpp", recurse));
return allSources;
}

static public List<LibrarySelection> findRequiredLibs(File sourcePath, boolean recurse, Set<UserLibrary> preferSet) {
List<File> files = findAllSources(sourcePath, recurse);
List<LibrarySelection> result = new ArrayList<>();
for (File file : files) {
List<LibrarySelection> libSels = null;
try {
libSels = BaseNoGui.findLibrariesByCode(file, preferSet);
} catch (IOException e) {
continue;
}
for (LibrarySelection libSel : libSels) {
if (!result.contains(libSel)) {
result.add(libSel);
}
}
}
return result;
}

private List<File> compileFiles(File outputPath, File sourcePath,
boolean recurse, List<File> includeFolders)
throws RunnerException, PreferencesMapException {
Expand Down Expand Up @@ -1353,17 +1387,30 @@ public void preprocess(String buildPath, PdePreprocessor preprocessor) throws Ru
// grab the imports from the code just preproc'd

importedLibraries = new LibraryList();
importedDuplicateHeaders = new ArrayList<String>();
importedDuplicateLibraries = new ArrayList<LibraryList>();
for (String item : preprocessor.getExtraImports()) {
LibraryList list = BaseNoGui.importToLibraryTable.get(item);
if (list != null) {
UserLibrary lib = list.peekFirst();
if (lib != null && !importedLibraries.contains(lib)) {
importedDuplicateHeaders = new ArrayList<>();
importedDuplicateLibraries = new ArrayList<>();
Set<UserLibrary> preferSet = new HashSet<>();
for (String[] item : preprocessor.getExtraImports()) {
LibrarySelection libSel = BaseNoGui.findLibraryByImport(item, preferSet);
if (libSel != null) {
UserLibrary lib = libSel.get();
if (!importedLibraries.contains(lib)) {
importedLibraries.add(lib);
if (list.size() > 1) {
importedDuplicateHeaders.add(item);
importedDuplicateLibraries.add(list);
if (libSel.getList().size() > 1) {
importedDuplicateHeaders.add(item[0]);
importedDuplicateLibraries.add(libSel);
}
// Add recursive dependencies
for (LibrarySelection libSelRec : lib.getRequiredLibsRec()) {
if (!importedLibraries.contains(libSelRec.get())) {
importedLibraries.add(libSelRec.get());
// This is probably just confusing. People can examine the
// tooltips if they need this information.
//if (libSelRec.getList().size() > 1) {
// importedDuplicateHeaders.add("UNKNOWN"); // FIXME
// importedDuplicateLibraries.add(libSelRec);
//}
}
}
}
}
Expand Down Expand Up @@ -1398,7 +1445,7 @@ public void preprocess(String buildPath, PdePreprocessor preprocessor) throws Ru
*/
private LibraryList importedLibraries;
private List<String> importedDuplicateHeaders;
private List<LibraryList> importedDuplicateLibraries;
private List<LibrarySelection> importedDuplicateLibraries;

/**
* Map an error from a set of processed .java files back to its location
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public static LegacyUserLibrary create(File libFolder) {
res.setInstalled(true);
res.layout = LibraryLayout.FLAT;
res.name = libFolder.getName();
res.globalName = res.name;
res.setTypes(Arrays.asList("Contributed"));
res.setCategory("Uncategorized");
return res;
Expand Down
26 changes: 26 additions & 0 deletions arduino-core/src/processing/app/packages/LibrarySelection.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package processing.app.packages;

public class LibrarySelection {
private LibraryList list;
private int index;
public LibrarySelection(LibraryList list, int index) {
this.list = list;
this.index = index;
}
public UserLibrary get() {
return list.get(index);
}
public LibraryList getList() {
return list;
}
public int getIndex() {
return index;
}
public boolean equals(Object otherObj) {
if (!(otherObj instanceof LibrarySelection)) {
return false;
}
LibrarySelection other = (LibrarySelection) otherObj;
return this.get().equals(other.get());
}
}
Loading