From 29cb42eb50e50af0878ec62f6d7c896ca17ef043 Mon Sep 17 00:00:00 2001 From: Federico Fissore Date: Tue, 31 Mar 2015 17:00:01 +0200 Subject: [PATCH] Bundled core is again inside the hardware folder. Fixed a handful of glitches when dealing with multiple installed cores --- app/lib/java-semver-0.8.0.jar | Bin 0 -> 44721 bytes app/lib/java-semver.LICENSE.MIT.txt | 0 .../libraries/filters/BuiltInPredicate.java | 17 --- .../ui/ContributedLibraryTableCell.java | 12 +- .../ui/DropdownBuiltInLibrariesItem.java | 8 +- .../ui/LibrariesIndexTableModel.java | 59 ++++---- .../libraries/ui/LibraryManagerUI.java | 4 +- .../ui/ContributedPlatformTableCell.java | 18 ++- .../ui/ContributionIndexTableModel.java | 59 ++++---- .../packages/ui/ContributionManagerUI.java | 22 ++- .../ui/FilteredAbstractTableModel.java | 22 +++ .../app/debug/TargetPackageStub.java | 5 + ...DependentDownloadableContributionStub.java | 6 + ...tributionBuiltInAtTheBottomComparator.java | 16 ++ .../contributions/VersionComparator.java | 24 +-- .../arduino/contributions/VersionHelper.java | 23 +++ .../filters/BuiltInPredicate.java | 17 +++ .../filters/InstalledPredicate.java | 0 .../libraries/ContributedLibrary.java | 12 -- .../packages/ContributedPlatform.java | 2 - .../packages/ContributedTargetPackage.java | 5 + .../packages/ContributionsIndexer.java | 141 ++++++++++++------ .../packages/DownloadableContribution.java | 12 ++ .../src/processing/app/BaseNoGui.java | 36 ++--- .../app/debug/LegacyTargetPackage.java | 5 + .../processing/app/debug/TargetPackage.java | 13 +- build/build.xml | 106 +++++-------- 27 files changed, 359 insertions(+), 285 deletions(-) create mode 100644 app/lib/java-semver-0.8.0.jar create mode 100644 app/lib/java-semver.LICENSE.MIT.txt delete mode 100644 app/src/cc/arduino/contributions/libraries/filters/BuiltInPredicate.java create mode 100644 arduino-core/src/cc/arduino/contributions/DownloadableContributionBuiltInAtTheBottomComparator.java create mode 100644 arduino-core/src/cc/arduino/contributions/VersionHelper.java create mode 100644 arduino-core/src/cc/arduino/contributions/filters/BuiltInPredicate.java rename {app => arduino-core}/src/cc/arduino/contributions/filters/InstalledPredicate.java (100%) diff --git a/app/lib/java-semver-0.8.0.jar b/app/lib/java-semver-0.8.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..967f0d1549ee6f6404e5b1136968ea4e18fbf6a9 GIT binary patch literal 44721 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
  • KDc2FHnn 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 { - - @Override - public boolean apply(ContributedLibrary input) { - return input.isReadOnly(); - } - - @Override - public boolean equals(Object obj) { - return obj instanceof BuiltInPredicate; - } -} diff --git a/app/src/cc/arduino/contributions/libraries/ui/ContributedLibraryTableCell.java b/app/src/cc/arduino/contributions/libraries/ui/ContributedLibraryTableCell.java index 35bdf6558..15c03c06d 100644 --- a/app/src/cc/arduino/contributions/libraries/ui/ContributedLibraryTableCell.java +++ b/app/src/cc/arduino/contributions/libraries/ui/ContributedLibraryTableCell.java @@ -29,15 +29,16 @@ package cc.arduino.contributions.libraries.ui; import cc.arduino.contributions.VersionComparator; +import cc.arduino.contributions.VersionHelper; import cc.arduino.contributions.filters.InstalledPredicate; import cc.arduino.contributions.libraries.ContributedLibrary; import cc.arduino.contributions.libraries.ContributedLibraryComparator; -import cc.arduino.contributions.libraries.filters.BuiltInPredicate; -import cc.arduino.contributions.libraries.filters.InstalledLibraryPredicate; +import cc.arduino.contributions.filters.BuiltInPredicate; import cc.arduino.contributions.libraries.filters.OnlyUpstreamReleasePredicate; import cc.arduino.contributions.ui.InstallerTableCell; import cc.arduino.contributions.ui.listeners.DelegatingKeyListener; import cc.arduino.utils.ReverseComparator; +import com.github.zafarkhaja.semver.Version; import com.google.common.base.Function; import com.google.common.base.Predicates; import com.google.common.collect.Collections2; @@ -66,7 +67,6 @@ import static processing.app.I18n.format; @SuppressWarnings("serial") public class ContributedLibraryTableCell extends InstallerTableCell { - private final LibraryManagerUI indexer; private JPanel panel; private JButton installButton; private Component installButtonPlaceholder; @@ -77,9 +77,7 @@ public class ContributedLibraryTableCell extends InstallerTableCell { private JPanel inactiveButtonsPanel; private JLabel statusLabel; - public ContributedLibraryTableCell(LibraryManagerUI indexer) { - this.indexer = indexer; - + public ContributedLibraryTableCell() { { installButton = new JButton(_("Install")); installButton.addActionListener(new ActionListener() { @@ -359,7 +357,7 @@ public class ContributedLibraryTableCell extends InstallerTableCell { // ...version. if (installed != null) { - String installedVer = installed.getVersion(); + Version installedVer = VersionHelper.valueOf(installed.getVersion()); if (installedVer == null) { desc += " " + _("Version unknown"); } else { diff --git a/app/src/cc/arduino/contributions/libraries/ui/DropdownBuiltInLibrariesItem.java b/app/src/cc/arduino/contributions/libraries/ui/DropdownBuiltInLibrariesItem.java index ef5181b60..0c10e62d6 100644 --- a/app/src/cc/arduino/contributions/libraries/ui/DropdownBuiltInLibrariesItem.java +++ b/app/src/cc/arduino/contributions/libraries/ui/DropdownBuiltInLibrariesItem.java @@ -1,20 +1,20 @@ package cc.arduino.contributions.libraries.ui; -import cc.arduino.contributions.libraries.ContributedLibrary; -import cc.arduino.contributions.libraries.filters.BuiltInPredicate; +import cc.arduino.contributions.filters.BuiltInPredicate; +import cc.arduino.contributions.packages.DownloadableContribution; import cc.arduino.contributions.ui.DropdownItem; import com.google.common.base.Predicate; import static processing.app.I18n._; -public class DropdownBuiltInLibrariesItem implements DropdownItem { +public class DropdownBuiltInLibrariesItem implements DropdownItem { public String toString() { return _("Built-in"); } @Override - public Predicate getFilterPredicate() { + public Predicate getFilterPredicate() { return new BuiltInPredicate(); } } diff --git a/app/src/cc/arduino/contributions/libraries/ui/LibrariesIndexTableModel.java b/app/src/cc/arduino/contributions/libraries/ui/LibrariesIndexTableModel.java index 384e1cedc..2ad94c7e7 100644 --- a/app/src/cc/arduino/contributions/libraries/ui/LibrariesIndexTableModel.java +++ b/app/src/cc/arduino/contributions/libraries/ui/LibrariesIndexTableModel.java @@ -28,16 +28,22 @@ */ package cc.arduino.contributions.libraries.ui; -import cc.arduino.contributions.VersionComparator; +import cc.arduino.contributions.DownloadableContributionBuiltInAtTheBottomComparator; +import cc.arduino.contributions.VersionHelper; +import cc.arduino.contributions.filters.InstalledPredicate; import cc.arduino.contributions.libraries.ContributedLibrary; import cc.arduino.contributions.libraries.LibrariesIndexer; import cc.arduino.contributions.packages.ContributedPlatform; import cc.arduino.contributions.ui.FilteredAbstractTableModel; +import com.github.zafarkhaja.semver.Version; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Collections2; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; @SuppressWarnings("serial") public class LibrariesIndexTableModel extends FilteredAbstractTableModel { @@ -45,13 +51,18 @@ public class LibrariesIndexTableModel extends FilteredAbstractTableModel { + public final String name; - public final List releases = new ArrayList(); - public final List versions = new ArrayList(); - public ContributedLibrary selected = null; + public final List releases; + public final List versions; + + public ContributedLibrary selected; public ContributedLibraryReleases(ContributedLibrary library) { - name = library.getName(); + this.name = library.getName(); + this.versions = new LinkedList(); + this.releases = new LinkedList(); + this.selected = null; add(library); } @@ -61,40 +72,28 @@ public class LibrariesIndexTableModel extends FilteredAbstractTableModel installedReleases = new LinkedList(Collections2.filter(releases, new Predicate() { - @Override - public boolean apply(ContributedLibrary contributedLibrary) { - return contributedLibrary.isInstalled(); - } - })); + List installedReleases = new LinkedList(Collections2.filter(releases, new InstalledPredicate())); + Collections.sort(installedReleases, new DownloadableContributionBuiltInAtTheBottomComparator()); - return getLatestOf(installedReleases); + if (installedReleases.isEmpty()) { + return null; + } + + return installedReleases.get(0); } public ContributedLibrary getLatest() { return getLatestOf(releases); } - private ContributedLibrary getLatestOf(List libs) { - Collections.sort(new LinkedList(libs), new Comparator() { - @Override - public int compare(ContributedLibrary lib1, ContributedLibrary lib2) { - return VersionComparator.VERSION_COMPARATOR.compare(lib1.getVersion(), lib2.getVersion()); - } - }); - - if (libs.isEmpty()) { - return null; - } - - return libs.get(libs.size() - 1); - } - public ContributedLibrary getSelected() { return selected; } @@ -223,7 +222,7 @@ public class LibrariesIndexTableModel extends FilteredAbstractTableModel getReleasesVersions(int row) { + public List getReleasesVersions(int row) { return contributions.get(row).versions; } diff --git a/app/src/cc/arduino/contributions/libraries/ui/LibraryManagerUI.java b/app/src/cc/arduino/contributions/libraries/ui/LibraryManagerUI.java index 39dd31e84..84ed30333 100644 --- a/app/src/cc/arduino/contributions/libraries/ui/LibraryManagerUI.java +++ b/app/src/cc/arduino/contributions/libraries/ui/LibraryManagerUI.java @@ -61,12 +61,12 @@ public class LibraryManagerUI extends InstallerJDialog { @Override protected InstallerTableCell createCellRenderer() { - return new ContributedLibraryTableCell(this); + return new ContributedLibraryTableCell(); } @Override protected InstallerTableCell createCellEditor() { - return new ContributedLibraryTableCell(this) { + return new ContributedLibraryTableCell() { @Override protected void onInstall(ContributedLibrary selectedLibrary, ContributedLibrary installedLibrary) { if (selectedLibrary.isReadOnly()) { diff --git a/app/src/cc/arduino/contributions/packages/ui/ContributedPlatformTableCell.java b/app/src/cc/arduino/contributions/packages/ui/ContributedPlatformTableCell.java index 881f27e8d..0cb2d1796 100644 --- a/app/src/cc/arduino/contributions/packages/ui/ContributedPlatformTableCell.java +++ b/app/src/cc/arduino/contributions/packages/ui/ContributedPlatformTableCell.java @@ -29,7 +29,9 @@ package cc.arduino.contributions.packages.ui; import cc.arduino.contributions.VersionComparator; +import cc.arduino.contributions.VersionHelper; import cc.arduino.contributions.filters.InstalledPredicate; +import cc.arduino.contributions.filters.BuiltInPredicate; import cc.arduino.contributions.packages.ContributedBoard; import cc.arduino.contributions.packages.ContributedPlatform; import cc.arduino.contributions.packages.ContributedPlatformComparator; @@ -263,7 +265,7 @@ public class ContributedPlatformTableCell extends InstallerTableCell { java.util.List releases = new LinkedList(editorValue.releases); java.util.List uninstalledReleases = new LinkedList(Collections2.filter(releases, Predicates.not(new InstalledPredicate()))); - java.util.List installedBuiltIn = new LinkedList(); + java.util.List installedBuiltIn = new LinkedList(Collections2.filter(releases, Predicates.and(new InstalledPredicate(), new BuiltInPredicate()))); if (installed != null && !installedBuiltIn.contains(installed)) { uninstalledReleases.addAll(installedBuiltIn); @@ -330,8 +332,7 @@ public class ContributedPlatformTableCell extends InstallerTableCell { upgradable = false; } else { installable = false; - //removable = !installed.isReadOnly() && !hasBuiltInRelease; - removable = !hasBuiltInRelease; + removable = !installed.isReadOnly() && !hasBuiltInRelease; upgradable = new ContributedPlatformComparator().compare(selected, installed) > 0; } if (installable) { @@ -352,17 +353,18 @@ public class ContributedPlatformTableCell extends InstallerTableCell { if (author != null && !author.isEmpty()) { desc += " " + format("by {0}", author); } - if (removable) { - desc += " " + format(_("version {0}"), installed.getVersion()) + " INSTALLED"; + if (installed != null) { + desc += " " + format(_("version {0}"), VersionHelper.valueOf(installed.getVersion())) + " INSTALLED"; } desc += "
    "; desc += _("Boards included in this package:") + "
    "; - for (ContributedBoard board : selected.getBoards()) - desc += format("{0}, ", board.getName()); + for (ContributedBoard board : selected.getBoards()) { + desc += board.getName() + ", "; + } desc = desc.substring(0, desc.lastIndexOf(',')) + ".
    "; - if (author != null && !author.isEmpty()) { + if (url != null && !url.isEmpty()) { desc += " " + format("
    More info", url); } diff --git a/app/src/cc/arduino/contributions/packages/ui/ContributionIndexTableModel.java b/app/src/cc/arduino/contributions/packages/ui/ContributionIndexTableModel.java index ca364be06..06089f6eb 100644 --- a/app/src/cc/arduino/contributions/packages/ui/ContributionIndexTableModel.java +++ b/app/src/cc/arduino/contributions/packages/ui/ContributionIndexTableModel.java @@ -28,34 +28,40 @@ */ package cc.arduino.contributions.packages.ui; +import cc.arduino.contributions.DownloadableContributionBuiltInAtTheBottomComparator; +import cc.arduino.contributions.VersionHelper; +import cc.arduino.contributions.filters.InstalledPredicate; import cc.arduino.contributions.packages.ContributedPackage; import cc.arduino.contributions.packages.ContributedPlatform; import cc.arduino.contributions.packages.ContributionsIndex; import cc.arduino.contributions.ui.FilteredAbstractTableModel; +import com.github.zafarkhaja.semver.Version; import com.google.common.base.Predicate; import com.google.common.base.Predicates; +import com.google.common.collect.Collections2; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedList; import java.util.List; -import static processing.app.I18n._; - @SuppressWarnings("serial") public class ContributionIndexTableModel extends FilteredAbstractTableModel { public final static int DESCRIPTION_COL = 0; public static class ContributedPlatformReleases { - public ContributedPackage packager; - public String arch; - public List releases = new ArrayList(); - public List versions = new ArrayList(); + public final ContributedPackage packager; + public final String arch; + public final List releases; + public final List versions; public ContributedPlatform selected = null; public ContributedPlatformReleases(ContributedPlatform platform) { - packager = platform.getParentPackage(); - arch = platform.getArchitecture(); + this.packager = platform.getParentPackage(); + this.arch = platform.getArchitecture(); + this.releases = new LinkedList(); + this.versions = new LinkedList(); add(platform); } @@ -67,39 +73,26 @@ public class ContributionIndexTableModel extends FilteredAbstractTableModel installedPlatforms = new LinkedList(); - for (ContributedPlatform platform : releases) { - if (platform.isInstalled()) { - installedPlatforms.add(platform); - } + List installedReleases = new LinkedList(Collections2.filter(releases, new InstalledPredicate())); + Collections.sort(installedReleases, new DownloadableContributionBuiltInAtTheBottomComparator()); + + if (installedReleases.isEmpty()) { + return null; } - if (installedPlatforms.size() > 1) { - throw new IllegalStateException(_("More than one platform is currently installed! Only one can be installed at any given time")); - } - - if (!installedPlatforms.isEmpty()) { - return installedPlatforms.get(0); - } - - return null; + return installedReleases.get(0); } public ContributedPlatform getLatest() { - ContributedPlatform latest = null; - for (ContributedPlatform plat : releases) { - if (latest == null) - latest = plat; - // TODO a better version compare - if (plat.getVersion().compareTo(latest.getVersion()) > 0) - latest = plat; - } - return latest; + return getLatestOf(releases); } public ContributedPlatform getSelected() { @@ -224,7 +217,7 @@ public class ContributionIndexTableModel extends FilteredAbstractTableModel getReleasesVersions(int row) { + public List getReleasesVersions(int row) { return contributions.get(row).versions; } diff --git a/app/src/cc/arduino/contributions/packages/ui/ContributionManagerUI.java b/app/src/cc/arduino/contributions/packages/ui/ContributionManagerUI.java index fafc67a5c..e003a7a19 100644 --- a/app/src/cc/arduino/contributions/packages/ui/ContributionManagerUI.java +++ b/app/src/cc/arduino/contributions/packages/ui/ContributionManagerUI.java @@ -66,13 +66,17 @@ public class ContributionManagerUI extends InstallerJDialog { protected InstallerTableCell createCellEditor() { return new ContributedPlatformTableCell() { @Override - protected void onInstall(ContributedPlatform selectedPlatform, ContributedPlatform installed) { - onInstallPressed(selectedPlatform, installed); + protected void onInstall(ContributedPlatform selected, ContributedPlatform installed) { + if (selected.isReadOnly()) { + onRemovePressed(installed, false); + } else { + onInstallPressed(selected, installed); + } } @Override protected void onRemove(ContributedPlatform installedPlatform) { - onRemovePressed(installedPlatform); + onRemovePressed(installedPlatform, true); } }; } @@ -157,7 +161,7 @@ public class ContributionManagerUI extends InstallerJDialog { try { setProgressVisible(true, _("Installing...")); installer.install(platformToInstall); - if (platformToRemove != null) { + if (platformToRemove != null && !platformToRemove.isReadOnly()) { installer.remove(platformToRemove); } onIndexesUpdated(); @@ -172,12 +176,14 @@ public class ContributionManagerUI extends InstallerJDialog { installerThread.start(); } - public void onRemovePressed(final ContributedPlatform platform) { + public void onRemovePressed(final ContributedPlatform platform, boolean showWarning) { clearErrorMessage(); - int chosenOption = JOptionPane.showConfirmDialog(getParent(), I18n.format(_("Do you want to remove {0}?\nIf you do so you won't be able to use {0} any more."), platform.getName()), _("Please confirm boards deletion"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); - if (chosenOption != JOptionPane.YES_OPTION) { - return; + if (showWarning) { + int chosenOption = JOptionPane.showConfirmDialog(getParent(), I18n.format(_("Do you want to remove {0}?\nIf you do so you won't be able to use {0} any more."), platform.getName()), _("Please confirm boards deletion"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + if (chosenOption != JOptionPane.YES_OPTION) { + return; + } } installerThread = new Thread(new Runnable() { diff --git a/app/src/cc/arduino/contributions/ui/FilteredAbstractTableModel.java b/app/src/cc/arduino/contributions/ui/FilteredAbstractTableModel.java index e09cfb2a7..05999ad37 100644 --- a/app/src/cc/arduino/contributions/ui/FilteredAbstractTableModel.java +++ b/app/src/cc/arduino/contributions/ui/FilteredAbstractTableModel.java @@ -28,12 +28,34 @@ */ package cc.arduino.contributions.ui; +import cc.arduino.contributions.VersionComparator; +import cc.arduino.contributions.packages.DownloadableContribution; import com.google.common.base.Predicate; import javax.swing.table.AbstractTableModel; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; public abstract class FilteredAbstractTableModel extends AbstractTableModel { abstract public void updateIndexFilter(String[] filters, Predicate... additionalFilters); + protected static T getLatestOf(List contribs) { + contribs = new LinkedList(contribs); + Collections.sort(contribs, new Comparator() { + @Override + public int compare(T contrib1, T contrib2) { + return VersionComparator.VERSION_COMPARATOR.compare(contrib1.getVersion(), contrib2.getVersion()); + } + }); + + if (contribs.isEmpty()) { + return null; + } + + return contribs.get(contribs.size() - 1); + } + } diff --git a/app/src/processing/app/debug/TargetPackageStub.java b/app/src/processing/app/debug/TargetPackageStub.java index b3dcd1d0e..d564a9e4e 100644 --- a/app/src/processing/app/debug/TargetPackageStub.java +++ b/app/src/processing/app/debug/TargetPackageStub.java @@ -30,4 +30,9 @@ public class TargetPackageStub implements TargetPackage { public TargetPlatform get(String platform) { return null; } + + @Override + public boolean hasPlatform(TargetPlatform platform) { + return false; + } } diff --git a/app/test/cc/arduino/packages/contributions/HostDependentDownloadableContributionStub.java b/app/test/cc/arduino/packages/contributions/HostDependentDownloadableContributionStub.java index 3178e00f1..effa9f31b 100644 --- a/app/test/cc/arduino/packages/contributions/HostDependentDownloadableContributionStub.java +++ b/app/test/cc/arduino/packages/contributions/HostDependentDownloadableContributionStub.java @@ -3,6 +3,12 @@ package cc.arduino.packages.contributions; import cc.arduino.contributions.packages.HostDependentDownloadableContribution; public class HostDependentDownloadableContributionStub extends HostDependentDownloadableContribution { + + @Override + public String getVersion() { + return null; + } + @Override public String getHost() { return null; diff --git a/arduino-core/src/cc/arduino/contributions/DownloadableContributionBuiltInAtTheBottomComparator.java b/arduino-core/src/cc/arduino/contributions/DownloadableContributionBuiltInAtTheBottomComparator.java new file mode 100644 index 000000000..8c9d8e61d --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/DownloadableContributionBuiltInAtTheBottomComparator.java @@ -0,0 +1,16 @@ +package cc.arduino.contributions; + +import cc.arduino.contributions.packages.DownloadableContribution; + +import java.util.Comparator; + +public class DownloadableContributionBuiltInAtTheBottomComparator implements Comparator { + @Override + public int compare(DownloadableContribution p1, DownloadableContribution p2) { + if (p1.isReadOnly() == p2.isReadOnly()) { + return 0; + } + + return p1.isReadOnly() ? 1 : -1; + } +} diff --git a/arduino-core/src/cc/arduino/contributions/VersionComparator.java b/arduino-core/src/cc/arduino/contributions/VersionComparator.java index 156f078e8..a1f0961b5 100644 --- a/arduino-core/src/cc/arduino/contributions/VersionComparator.java +++ b/arduino-core/src/cc/arduino/contributions/VersionComparator.java @@ -47,8 +47,8 @@ public class VersionComparator implements Comparator { if (b == null) return 1; - Version versionA = valueOf(a); - Version versionB = valueOf(b); + Version versionA = VersionHelper.valueOf(a); + Version versionB = VersionHelper.valueOf(b); return versionA.compareTo(versionB); } @@ -65,26 +65,10 @@ public class VersionComparator implements Comparator { return true; } - Version versionA = valueOf(a); - Version versionB = valueOf(b); + Version versionA = VersionHelper.valueOf(a); + Version versionB = VersionHelper.valueOf(b); return versionA.greaterThan(versionB); } - private Version valueOf(String ver) { - if (ver.endsWith("b")) { - ver = ver.substring(0, ver.lastIndexOf("b")) + ".1"; - } - String[] verParts = ver.split("\\."); - if (verParts.length < 3) { - if (verParts.length == 2) { - return Version.forIntegers(Integer.valueOf(verParts[0]), Integer.valueOf(verParts[1])); - } else { - return Version.forIntegers(Integer.valueOf(verParts[0])); - } - } else { - return Version.valueOf(ver); - } - } - } diff --git a/arduino-core/src/cc/arduino/contributions/VersionHelper.java b/arduino-core/src/cc/arduino/contributions/VersionHelper.java new file mode 100644 index 000000000..10d64af84 --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/VersionHelper.java @@ -0,0 +1,23 @@ +package cc.arduino.contributions; + +import com.github.zafarkhaja.semver.Version; + +public class VersionHelper { + + public static Version valueOf(String ver) { + if (ver == null) { + return null; + } + String[] verParts = ver.split("\\."); + if (verParts.length < 3) { + if (verParts.length == 2) { + return Version.forIntegers(Integer.valueOf(verParts[0]), Integer.valueOf(verParts[1])); + } else { + return Version.forIntegers(Integer.valueOf(verParts[0])); + } + } else { + return Version.valueOf(ver); + } + } + +} diff --git a/arduino-core/src/cc/arduino/contributions/filters/BuiltInPredicate.java b/arduino-core/src/cc/arduino/contributions/filters/BuiltInPredicate.java new file mode 100644 index 000000000..76962079d --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/filters/BuiltInPredicate.java @@ -0,0 +1,17 @@ +package cc.arduino.contributions.filters; + +import cc.arduino.contributions.packages.DownloadableContribution; +import com.google.common.base.Predicate; + +public class BuiltInPredicate implements Predicate { + + @Override + public boolean apply(DownloadableContribution input) { + return input.isReadOnly(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof BuiltInPredicate; + } +} diff --git a/app/src/cc/arduino/contributions/filters/InstalledPredicate.java b/arduino-core/src/cc/arduino/contributions/filters/InstalledPredicate.java similarity index 100% rename from app/src/cc/arduino/contributions/filters/InstalledPredicate.java rename to arduino-core/src/cc/arduino/contributions/filters/InstalledPredicate.java diff --git a/arduino-core/src/cc/arduino/contributions/libraries/ContributedLibrary.java b/arduino-core/src/cc/arduino/contributions/libraries/ContributedLibrary.java index b67329762..bec9873e1 100644 --- a/arduino-core/src/cc/arduino/contributions/libraries/ContributedLibrary.java +++ b/arduino-core/src/cc/arduino/contributions/libraries/ContributedLibrary.java @@ -40,8 +40,6 @@ public abstract class ContributedLibrary extends DownloadableContribution { public abstract String getName(); - public abstract String getVersion(); - public abstract String getMaintainer(); public abstract String getAuthor(); @@ -64,16 +62,6 @@ public abstract class ContributedLibrary extends DownloadableContribution { public abstract List getRequires(); - private boolean readOnly; - - public boolean isReadOnly() { - return readOnly; - } - - public void setReadOnly(boolean readOnly) { - this.readOnly = readOnly; - } - public static final Comparator CASE_INSENSITIVE_ORDER = new Comparator() { @Override public int compare(ContributedLibrary o1, ContributedLibrary o2) { diff --git a/arduino-core/src/cc/arduino/contributions/packages/ContributedPlatform.java b/arduino-core/src/cc/arduino/contributions/packages/ContributedPlatform.java index f790bb064..ce8460d70 100644 --- a/arduino-core/src/cc/arduino/contributions/packages/ContributedPlatform.java +++ b/arduino-core/src/cc/arduino/contributions/packages/ContributedPlatform.java @@ -37,8 +37,6 @@ public abstract class ContributedPlatform extends DownloadableContribution { public abstract String getName(); - public abstract String getVersion(); - public abstract String getCategory(); public abstract String getArchitecture(); diff --git a/arduino-core/src/cc/arduino/contributions/packages/ContributedTargetPackage.java b/arduino-core/src/cc/arduino/contributions/packages/ContributedTargetPackage.java index a04c5d79f..1a481a5a2 100644 --- a/arduino-core/src/cc/arduino/contributions/packages/ContributedTargetPackage.java +++ b/arduino-core/src/cc/arduino/contributions/packages/ContributedTargetPackage.java @@ -73,6 +73,11 @@ public class ContributedTargetPackage implements TargetPackage { return platforms.get(platform); } + @Override + public boolean hasPlatform(TargetPlatform platform) { + return platforms.containsKey(platform.getId()); + } + @Override public String toString() { return "TargetPackage: " + getId(); diff --git a/arduino-core/src/cc/arduino/contributions/packages/ContributionsIndexer.java b/arduino-core/src/cc/arduino/contributions/packages/ContributionsIndexer.java index a5a069c0f..6e7326162 100644 --- a/arduino-core/src/cc/arduino/contributions/packages/ContributionsIndexer.java +++ b/arduino-core/src/cc/arduino/contributions/packages/ContributionsIndexer.java @@ -28,21 +28,27 @@ */ package cc.arduino.contributions.packages; +import cc.arduino.contributions.DownloadableContributionBuiltInAtTheBottomComparator; +import cc.arduino.contributions.filters.BuiltInPredicate; +import cc.arduino.contributions.filters.InstalledPredicate; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.module.mrbean.MrBeanModule; +import com.google.common.base.Function; +import com.google.common.base.Predicates; +import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableListMultimap; +import com.google.common.collect.Multimaps; import processing.app.debug.TargetPackage; import processing.app.debug.TargetPlatform; import processing.app.debug.TargetPlatformException; +import processing.app.helpers.PreferencesMap; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import static processing.app.helpers.filefilters.OnlyDirs.ONLY_DIRS; @@ -102,7 +108,47 @@ public class ContributionsIndexer { index = mapper.readValue(indexIn, ContributionsIndex.class); } - public void syncWithFilesystem() { + public void syncWithFilesystem(File hardwareFolder) throws IOException { + syncBuiltInHardwareFolder(hardwareFolder); + + syncLocalPackagesFolder(); + } + + public void syncBuiltInHardwareFolder(File hardwareFolder) throws IOException { + for (File folder : hardwareFolder.listFiles(ONLY_DIRS)) { + ContributedPackage pack = index.findPackage(folder.getName()); + if (pack != null) { + syncBuiltInPackageWithFilesystem(pack, folder); + + File toolsFolder = new File(hardwareFolder, "tools"); + if (toolsFolder.isDirectory()) { + for (File toolFolder : toolsFolder.listFiles(ONLY_DIRS)) { + File builtInToolsMetadata = new File(toolFolder, "builtin_tools_versions.txt"); + if (builtInToolsMetadata.isFile()) { + PreferencesMap toolsMetadata = new PreferencesMap(builtInToolsMetadata).subTree(pack.getName()); + for (Map.Entry toolMetadata : toolsMetadata.entrySet()) { + syncToolWithFilesystem(pack, toolFolder, toolMetadata.getKey(), toolMetadata.getValue()); + } + } + } + } + } + } + } + + private void syncBuiltInPackageWithFilesystem(ContributedPackage pack, File hardwareFolder) throws IOException { + // Scan all hardware folders and mark as installed all the tools found. + for (File platformFolder : hardwareFolder.listFiles(ONLY_DIRS)) { + File platformTxt = new File(platformFolder, "platform.txt"); + String version = new PreferencesMap(platformTxt).get("version"); + ContributedPlatform platform = syncHardwareWithFilesystem(pack, platformFolder, platformFolder.getName(), version); + if (platform != null) { + platform.setReadOnly(true); + } + } + } + + public void syncLocalPackagesFolder() { if (!packagesFolder.isDirectory()) return; @@ -110,8 +156,9 @@ public class ContributionsIndexer { // platforms found. for (File folder : packagesFolder.listFiles(ONLY_DIRS)) { ContributedPackage pack = index.findPackage(folder.getName()); - if (pack != null) + if (pack != null) { syncPackageWithFilesystem(pack, folder); + } } } @@ -120,8 +167,9 @@ public class ContributionsIndexer { File hardwareFolder = new File(root, "hardware"); if (hardwareFolder.isDirectory()) { for (File platformFolder : hardwareFolder.listFiles(ONLY_DIRS)) { - for (File versionFolder : platformFolder.listFiles(ONLY_DIRS)) - syncHardwareWithFilesystem(pack, platformFolder, versionFolder); + for (File versionFolder : platformFolder.listFiles(ONLY_DIRS)) { + syncHardwareWithFilesystem(pack, versionFolder, platformFolder.getName(), versionFolder.getName()); + } } } @@ -129,39 +177,35 @@ public class ContributionsIndexer { File toolsFolder = new File(root, "tools"); if (toolsFolder.isDirectory()) { for (File toolFolder : toolsFolder.listFiles(ONLY_DIRS)) { - for (File versionFolder : toolFolder.listFiles(ONLY_DIRS)) - syncToolWithFilesystem(pack, toolFolder, versionFolder); + for (File versionFolder : toolFolder.listFiles(ONLY_DIRS)) { + syncToolWithFilesystem(pack, versionFolder, toolFolder.getName(), versionFolder.getName()); + } } } } - private void syncToolWithFilesystem(ContributedPackage pack, File toolFolder, - File versionFolder) { - ContributedTool tool = pack.findTool(toolFolder.getName(), - versionFolder.getName()); - if (tool == null) + private void syncToolWithFilesystem(ContributedPackage pack, File installationFolder, String toolName, String version) { + ContributedTool tool = pack.findTool(toolName, version); + if (tool == null) { return; + } DownloadableContribution contrib = tool.getDownloadableContribution(); if (contrib == null) { - System.err.println(tool + - " seems to have no downloadable contributions for your " + - "operating system, but it is installed in\n" + versionFolder); + System.err.println(tool + " seems to have no downloadable contributions for your operating system, but it is installed in\n" + installationFolder); return; } contrib.setInstalled(true); - contrib.setInstalledFolder(versionFolder); + contrib.setInstalledFolder(installationFolder); } - private void syncHardwareWithFilesystem(ContributedPackage pack, - File platformFolder, - File versionFolder) { - String architecture = platformFolder.getName(); - String version = versionFolder.getName(); + private ContributedPlatform syncHardwareWithFilesystem(ContributedPackage pack, File installationFolder, String architecture, String version) { ContributedPlatform platform = pack.findPlatform(architecture, version); if (platform != null) { platform.setInstalled(true); - platform.setInstalledFolder(versionFolder); + platform.setReadOnly(false); + platform.setInstalledFolder(installationFolder); } + return platform; } @Override @@ -170,28 +214,29 @@ public class ContributionsIndexer { } public List createTargetPackages() throws TargetPlatformException { - List res = new ArrayList(); + List packages = new ArrayList(); - for (ContributedPackage pack : index.getPackages()) { - ContributedTargetPackage targetPackage; - targetPackage = new ContributedTargetPackage(pack.getName()); + for (ContributedPackage aPackage : index.getPackages()) { + ContributedTargetPackage targetPackage = new ContributedTargetPackage(aPackage.getName()); - for (ContributedPlatform platform : pack.getPlatforms()) { - if (!platform.isInstalled()) - continue; + List platforms = new LinkedList(Collections2.filter(aPackage.getPlatforms(), new InstalledPredicate())); + Collections.sort(platforms, new DownloadableContributionBuiltInAtTheBottomComparator()); + for (ContributedPlatform platform : platforms) { String arch = platform.getArchitecture(); File folder = platform.getInstalledFolder(); - TargetPlatform targetPlatform; - targetPlatform = new ContributedTargetPlatform(arch, folder, targetPackage, index); - targetPackage.addPlatform(targetPlatform); + TargetPlatform targetPlatform = new ContributedTargetPlatform(arch, folder, targetPackage, index); + if (!targetPackage.hasPlatform(targetPlatform)) { + targetPackage.addPlatform(targetPlatform); + } } - if (targetPackage.hasPlatforms()) - res.add(targetPackage); + if (targetPackage.hasPlatforms()) { + packages.add(targetPackage); + } } - return res; + return packages; } /** @@ -217,11 +262,21 @@ public class ContributionsIndexer { public Set getInstalledTools() { Set tools = new HashSet(); for (ContributedPackage pack : index.getPackages()) { - for (ContributedPlatform platform : pack.getPlatforms()) { - if (!platform.isInstalled()) - continue; - for (ContributedTool tool : platform.getResolvedTools()) { - tools.add(tool); + Collection platforms = Collections2.filter(pack.getPlatforms(), new InstalledPredicate()); + ImmutableListMultimap platformsByName = Multimaps.index(platforms, new Function() { + @Override + public String apply(ContributedPlatform contributedPlatform) { + return contributedPlatform.getName(); + } + }); + + for (Map.Entry> entry : platformsByName.asMap().entrySet()) { + Collection platformsWithName = entry.getValue(); + if (platformsWithName.size() > 1) { + platformsWithName = Collections2.filter(platformsWithName, Predicates.not(new BuiltInPredicate())); + } + for (ContributedPlatform platform : platformsWithName) { + tools.addAll(platform.getResolvedTools()); } } } diff --git a/arduino-core/src/cc/arduino/contributions/packages/DownloadableContribution.java b/arduino-core/src/cc/arduino/contributions/packages/DownloadableContribution.java index dc10306ef..79e092cd1 100644 --- a/arduino-core/src/cc/arduino/contributions/packages/DownloadableContribution.java +++ b/arduino-core/src/cc/arduino/contributions/packages/DownloadableContribution.java @@ -40,6 +40,8 @@ public abstract class DownloadableContribution { public abstract String getUrl(); + public abstract String getVersion(); + public abstract String getChecksum(); public abstract long getSize(); @@ -78,6 +80,16 @@ public abstract class DownloadableContribution { this.installedFolder = installedFolder; } + private boolean readOnly; + + public boolean isReadOnly() { + return readOnly; + } + + public void setReadOnly(boolean readOnly) { + this.readOnly = readOnly; + } + @Override public String toString() { String res = ""; diff --git a/arduino-core/src/processing/app/BaseNoGui.java b/arduino-core/src/processing/app/BaseNoGui.java index 9bd0c62de..4c6736612 100644 --- a/arduino-core/src/processing/app/BaseNoGui.java +++ b/arduino-core/src/processing/app/BaseNoGui.java @@ -578,12 +578,11 @@ public class BaseNoGui { static public void initPackages() throws Exception { indexer = new ContributionsIndexer(BaseNoGui.getSettingsFolder()); File indexFile = indexer.getIndexFile(); - File avrCoreFolder = FileUtils.newFile(indexFile.getParentFile(), "packages", "arduino", "hardware", "avr"); - if (!indexFile.isFile() || !(avrCoreFolder.exists() && avrCoreFolder.isDirectory())) { - File distFile = findDefaultPackageFile(); - if (distFile != null) { - new ArchiveExtractor(getPlatform()).extract(distFile, BaseNoGui.getSettingsFolder(), 0, true); - } else if (!indexFile.isFile()) { + if (!indexFile.isFile()) { + File defaultPackageJsonFile = new File(getContentFile("dist"), "package_index.json"); + if (defaultPackageJsonFile.isFile()) { + FileUtils.copyFile(defaultPackageJsonFile, indexFile); + } else { // Otherwise create an empty packages index FileOutputStream out = null; try { @@ -598,7 +597,7 @@ public class BaseNoGui { } } indexer.parseIndex(); - indexer.syncWithFilesystem(); + indexer.syncWithFilesystem(getHardwareFolder()); packages = new HashMap(); loadHardware(getHardwareFolder()); @@ -626,18 +625,6 @@ public class BaseNoGui { librariesIndexer.parseIndex(); } - private static File findDefaultPackageFile() { - File distFolder = getContentFile("dist"); - if (!distFolder.exists()) { - return null; - } - File[] files = distFolder.listFiles(new OnlyFilesWithExtension("tar.bz2", "zip", "tar.gz", "tar")); - if (files.length > 1) { - throw new IllegalStateException("More than one file in " + distFolder); - } - return files[0]; - } - static protected void initPlatform() { try { Class platformClass = Class.forName("processing.app.Platform"); @@ -697,7 +684,7 @@ public class BaseNoGui { try { packages.put(target, new LegacyTargetPackage(target, subfolder)); } catch (TargetPlatformException e) { - System.out.println("WARNING: Error loading hardware folder " + target); + System.out.println("WARNING: Error loading hardware folder " + new File(folder, target)); System.out.println(" " + e.getMessage()); } } @@ -777,12 +764,9 @@ public class BaseNoGui { PreferencesData.removeAllKeysWithPrefix(prefix); for (ContributedTool tool : indexer.getInstalledTools()) { - String path = tool.getDownloadableContribution().getInstalledFolder() - .getAbsolutePath(); - String toolId = tool.getName(); - PreferencesData.set(prefix + toolId + ".path", path); - toolId += "-" + tool.getVersion(); - PreferencesData.set(prefix + toolId + ".path", path); + String path = tool.getDownloadableContribution().getInstalledFolder().getAbsolutePath(); + PreferencesData.set(prefix + tool.getName() + ".path", path); + PreferencesData.set(prefix + tool.getName() + "-" + tool.getVersion() + ".path", path); } } diff --git a/arduino-core/src/processing/app/debug/LegacyTargetPackage.java b/arduino-core/src/processing/app/debug/LegacyTargetPackage.java index 8d381706c..42d6b0730 100644 --- a/arduino-core/src/processing/app/debug/LegacyTargetPackage.java +++ b/arduino-core/src/processing/app/debug/LegacyTargetPackage.java @@ -77,6 +77,11 @@ public class LegacyTargetPackage implements TargetPackage { return platforms.get(platform); } + @Override + public boolean hasPlatform(TargetPlatform platform) { + return platforms.containsKey(platform.getId()); + } + @Override public String getId() { return id; diff --git a/arduino-core/src/processing/app/debug/TargetPackage.java b/arduino-core/src/processing/app/debug/TargetPackage.java index 5644272d0..2df6880b0 100644 --- a/arduino-core/src/processing/app/debug/TargetPackage.java +++ b/arduino-core/src/processing/app/debug/TargetPackage.java @@ -25,12 +25,13 @@ import java.util.Map; public interface TargetPackage { - public String getId(); - - public Map getPlatforms(); + String getId(); - public Collection platforms(); + Map getPlatforms(); - public TargetPlatform get(String platform); - + Collection platforms(); + + TargetPlatform get(String platform); + + boolean hasPlatform(TargetPlatform platform); } diff --git a/build/build.xml b/build/build.xml index 62ad948e3..732d5d4b7 100644 --- a/build/build.xml +++ b/build/build.xml @@ -160,9 +160,10 @@ - - - + + + + @@ -348,8 +349,6 @@ - - @@ -368,33 +367,17 @@ - + - - + + - - - - - - - - - - - - - - - - @@ -629,40 +612,20 @@ - + - - - - - - - - - - - + - - - - - - - - - - @@ -875,8 +838,6 @@ - - @@ -904,20 +865,12 @@ - + - - - - - - - - - - + - - + + - + + - - + + - - - + + + + + + + + + + + + + + + + + + + + + +