diff --git a/build/org.eclipse.cdt.build.core/src/org/eclipse/cdt/build/core/IBuildConfigurationManager.java b/build/org.eclipse.cdt.build.core/src/org/eclipse/cdt/build/core/IBuildConfigurationManager.java new file mode 100644 index 00000000000..4c5fc81df9a --- /dev/null +++ b/build/org.eclipse.cdt.build.core/src/org/eclipse/cdt/build/core/IBuildConfigurationManager.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.build.core; + +import org.eclipse.launchbar.core.ILaunchDescriptor; +import org.eclipse.launchbar.core.target.ILaunchTarget; + +/** + * The manager which managed build configurations. + * + * @noimplement + */ +public interface IBuildConfigurationManager { + + /** + * Returns a build configuration that knows how to build the thing described + * by the launch descriptor for the given mode running on the given target. + * + * @param descriptor + * @param mode + * @param target + * @return + */ + CBuildConfiguration getBuildConfiguration(ILaunchDescriptor descriptor, String mode, ILaunchTarget target); + +} diff --git a/build/org.eclipse.cdt.build.core/src/org/eclipse/cdt/build/core/IBuildConfigurationProvider.java b/build/org.eclipse.cdt.build.core/src/org/eclipse/cdt/build/core/IBuildConfigurationProvider.java new file mode 100644 index 00000000000..72caa26586c --- /dev/null +++ b/build/org.eclipse.cdt.build.core/src/org/eclipse/cdt/build/core/IBuildConfigurationProvider.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.build.core; + +import org.eclipse.core.resources.IBuildConfiguration; +import org.eclipse.launchbar.core.ILaunchDescriptor; +import org.eclipse.launchbar.core.target.ILaunchTarget; + +/** + * A provider for build configurations. + */ +public interface IBuildConfigurationProvider { + + /** + * Returns a build configuration that knows how to build the thing described + * by the launch descriptor for the given mode running on the given target. + * + * @param descriptor + * @param mode + * @param target + * @return + */ + CBuildConfiguration getBuildConfiguration(ILaunchDescriptor descriptor, String mode, ILaunchTarget target); + + /** + * Load a previously created build configuration. + * + * @param buildConfig + * @return + */ + CBuildConfiguration loadBuildConfiguration(IBuildConfiguration buildConfig); +} diff --git a/build/org.eclipse.cdt.build.core/src/org/eclipse/cdt/build/core/internal/Activator.java b/build/org.eclipse.cdt.build.core/src/org/eclipse/cdt/build/core/internal/Activator.java index d8625d3a090..95481bfb5c0 100644 --- a/build/org.eclipse.cdt.build.core/src/org/eclipse/cdt/build/core/internal/Activator.java +++ b/build/org.eclipse.cdt.build.core/src/org/eclipse/cdt/build/core/internal/Activator.java @@ -7,6 +7,7 @@ *******************************************************************************/ package org.eclipse.cdt.build.core.internal; +import org.eclipse.cdt.build.core.IBuildConfigurationManager; import org.eclipse.cdt.build.core.IToolChainManager; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; @@ -21,8 +22,9 @@ public class Activator extends Plugin { private static Activator plugin; private static ToolChainManager toolChainManager; - private static CBuildConfigurationCleanup configCleanup; + private static CBuildConfigurationManager buildConfigManager; + @Override public void start(BundleContext context) throws Exception { super.start(context); plugin = this; @@ -30,18 +32,22 @@ public class Activator extends Plugin { toolChainManager = new ToolChainManager(); context.registerService(IToolChainManager.class, toolChainManager, null); - configCleanup = new CBuildConfigurationCleanup(); - ResourcesPlugin.getWorkspace().addResourceChangeListener(configCleanup); + buildConfigManager = new CBuildConfigurationManager(); + context.registerService(IBuildConfigurationManager.class, buildConfigManager, null); + ResourcesPlugin.getWorkspace().addResourceChangeListener(buildConfigManager); // Save participant for toolchain data ResourcesPlugin.getWorkspace().addSaveParticipant(getId(), new ScannerInfoSaveParticipant()); } + @Override public void stop(BundleContext context) throws Exception { plugin = null; - ResourcesPlugin.getWorkspace().removeResourceChangeListener(configCleanup); - configCleanup = null; + toolChainManager = null; + + ResourcesPlugin.getWorkspace().removeResourceChangeListener(buildConfigManager); + buildConfigManager = null; super.stop(context); } diff --git a/build/org.eclipse.cdt.build.core/src/org/eclipse/cdt/build/core/internal/CBuildConfigurationCleanup.java b/build/org.eclipse.cdt.build.core/src/org/eclipse/cdt/build/core/internal/CBuildConfigurationManager.java similarity index 63% rename from build/org.eclipse.cdt.build.core/src/org/eclipse/cdt/build/core/internal/CBuildConfigurationCleanup.java rename to build/org.eclipse.cdt.build.core/src/org/eclipse/cdt/build/core/internal/CBuildConfigurationManager.java index bd4cd7ae14c..d0a41bcc7b2 100644 --- a/build/org.eclipse.cdt.build.core/src/org/eclipse/cdt/build/core/internal/CBuildConfigurationCleanup.java +++ b/build/org.eclipse.cdt.build.core/src/org/eclipse/cdt/build/core/internal/CBuildConfigurationManager.java @@ -13,17 +13,54 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; +import java.util.HashMap; +import java.util.Map; +import org.eclipse.cdt.build.core.CBuildConfiguration; +import org.eclipse.cdt.build.core.IBuildConfigurationManager; +import org.eclipse.core.resources.IBuildConfiguration; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdapterFactory; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.launchbar.core.ILaunchDescriptor; +import org.eclipse.launchbar.core.target.ILaunchTarget; import org.osgi.service.prefs.BackingStoreException; import org.osgi.service.prefs.Preferences; -public class CBuildConfigurationCleanup implements IResourceChangeListener { +public class CBuildConfigurationManager + implements IBuildConfigurationManager, IResourceChangeListener, IAdapterFactory { + + Map configMap = new HashMap<>(); + + @Override + public CBuildConfiguration getBuildConfiguration(ILaunchDescriptor descriptor, String mode, ILaunchTarget target) { + // TODO + CBuildConfiguration config = null; + + configMap.put(config.getBuildConfiguration(), config); + return config; + } + + @SuppressWarnings("unchecked") + @Override + public T getAdapter(Object adaptableObject, Class adapterType) { + if (adaptableObject instanceof IBuildConfiguration) { + if (CBuildConfiguration.class.isAssignableFrom(adapterType)) { + return (T) configMap.get(adaptableObject); + } + } + return null; + } + + @Override + public Class[] getAdapterList() { + return new Class[] { CBuildConfiguration.class }; + } @Override public void resourceChanged(IResourceChangeEvent event) { @@ -31,6 +68,15 @@ public class CBuildConfigurationCleanup implements IResourceChangeListener { if (event.getResource().getType() == IResource.PROJECT) { IProject project = event.getResource().getProject(); + // Clean up the configMap + try { + for (IBuildConfiguration buildConfig : project.getBuildConfigs()) { + configMap.remove(buildConfig); + } + } catch (CoreException e) { + Activator.log(e); + } + // Clean up the config settings Preferences parentNode = InstanceScope.INSTANCE.getNode(Activator.getId()).node("config"); //$NON-NLS-1$ if (parentNode != null) { diff --git a/releng/org.eclipse.cdt.target/cdt-e4.6.target b/releng/org.eclipse.cdt.target/cdt-e4.6.target index 3a251897a25..1bbb17660b2 100644 --- a/releng/org.eclipse.cdt.target/cdt-e4.6.target +++ b/releng/org.eclipse.cdt.target/cdt-e4.6.target @@ -1,5 +1,5 @@ - + @@ -46,6 +46,7 @@ + diff --git a/toolchains/arduino/org.eclipse.cdt.arduino-feature/feature.xml b/toolchains/arduino/org.eclipse.cdt.arduino-feature/feature.xml index 25ad2504483..a8abff53292 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino-feature/feature.xml +++ b/toolchains/arduino/org.eclipse.cdt.arduino-feature/feature.xml @@ -21,9 +21,11 @@ - - - + + + + + - + - diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/.settings/org.eclipse.jdt.core.prefs b/toolchains/arduino/org.eclipse.cdt.arduino.core/.settings/org.eclipse.jdt.core.prefs index f42de363afa..0c68a61dca8 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/.settings/org.eclipse.jdt.core.prefs +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/.settings/org.eclipse.jdt.core.prefs @@ -1,7 +1,7 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 -org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.7 +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/META-INF/MANIFEST.MF b/toolchains/arduino/org.eclipse.cdt.arduino.core/META-INF/MANIFEST.MF index 49a4ec7fab5..dab81eed768 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/META-INF/MANIFEST.MF +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.cdt.arduino.core;singleton:=true -Bundle-Version: 1.0.0.qualifier +Bundle-Version: 2.0.0.qualifier Bundle-Activator: org.eclipse.cdt.arduino.core.internal.Activator Bundle-Vendor: %providerName Require-Bundle: org.eclipse.core.runtime, @@ -15,14 +15,13 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.remote.serial.core;bundle-version="1.0.0", com.google.gson;bundle-version="2.2.4", org.apache.commons.compress;bundle-version="1.6.0", - org.eclipse.cdt.build.core;bundle-version="1.0.0", - org.eclipse.cdt.build.gcc.core;bundle-version="1.0.0" -Bundle-RequiredExecutionEnvironment: JavaSE-1.7 + org.freemarker;bundle-version="2.3.22" +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ActivationPolicy: lazy -Bundle-ClassPath: libs/freemarker-2.3.22.jar, - . +Bundle-ClassPath: . Export-Package: org.eclipse.cdt.arduino.core.internal;x-friends:="org.eclipse.cdt.arduino.ui", org.eclipse.cdt.arduino.core.internal.board;x-friends:="org.eclipse.cdt.arduino.ui", org.eclipse.cdt.arduino.core.internal.build;x-friends:="org.eclipse.cdt.arduino.ui", + org.eclipse.cdt.arduino.core.internal.console;x-friends:="org.eclipse.cdt.arduino.ui", org.eclipse.cdt.arduino.core.internal.remote;x-friends:="org.eclipse.cdt.arduino.ui" Bundle-Localization: plugin diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/build.properties b/toolchains/arduino/org.eclipse.cdt.arduino.core/build.properties index 73094ad4b81..f4f2e1fae5d 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/build.properties +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/build.properties @@ -4,5 +4,5 @@ bin.includes = META-INF/,\ plugin.xml,\ templates/,\ about.html,\ - plugin.properties,\ - libs/ + schema/,\ + plugin.properties diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/libs/freemarker-2.3.22.jar b/toolchains/arduino/org.eclipse.cdt.arduino.core/libs/freemarker-2.3.22.jar deleted file mode 100644 index a67a1c127e3..00000000000 Binary files a/toolchains/arduino/org.eclipse.cdt.arduino.core/libs/freemarker-2.3.22.jar and /dev/null differ diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/plugin.xml b/toolchains/arduino/org.eclipse.cdt.arduino.core/plugin.xml index 989488795e8..676505ab53b 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/plugin.xml +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/plugin.xml @@ -1,6 +1,7 @@ + - - - - - - - - diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/pom.xml b/toolchains/arduino/org.eclipse.cdt.arduino.core/pom.xml index 4a4e5afdf8f..d89247c15f9 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/pom.xml +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/pom.xml @@ -12,6 +12,6 @@ org.eclipse.cdt.arduino.core - 1.0.0-SNAPSHOT + 2.0.0-SNAPSHOT eclipse-plugin diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/schema/consoleService.exsd b/toolchains/arduino/org.eclipse.cdt.arduino.core/schema/consoleService.exsd new file mode 100644 index 00000000000..e56c770ca91 --- /dev/null +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/schema/consoleService.exsd @@ -0,0 +1,102 @@ + + + + + + + + + [Enter description of this extension point.] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [Enter the first release in which this extension point appears.] + + + + + + + + + [Enter extension point usage example here.] + + + + + + + + + [Enter API information here.] + + + + + + + + + [Enter information about supplied implementation of this extension point.] + + + + + diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/Activator.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/Activator.java index d46509fda4c..342e8b451cc 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/Activator.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/Activator.java @@ -10,12 +10,15 @@ *******************************************************************************/ package org.eclipse.cdt.arduino.core.internal; -import org.eclipse.cdt.arduino.core.internal.remote.ArduinoRemoteConnectionListener; +import org.eclipse.cdt.arduino.core.internal.board.ArduinoManager; +import org.eclipse.cdt.arduino.core.internal.console.ArduinoConsoleService; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Plugin; import org.eclipse.core.runtime.Status; -import org.eclipse.remote.core.IRemoteServicesManager; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; @@ -45,13 +48,10 @@ public class Activator extends Plugin { public void start(BundleContext bundleContext) throws Exception { plugin = this; - IRemoteServicesManager remoteManager = getService(IRemoteServicesManager.class); - remoteManager.addRemoteConnectionChangeListener(ArduinoRemoteConnectionListener.INSTANCE); + bundleContext.registerService(ArduinoManager.class, new ArduinoManager(), null); } public void stop(BundleContext bundleContext) throws Exception { - IRemoteServicesManager remoteManager = getService(IRemoteServicesManager.class); - remoteManager.removeRemoteConnectionChangeListener(ArduinoRemoteConnectionListener.INSTANCE); plugin = null; } @@ -61,4 +61,10 @@ public class Activator extends Plugin { return ref != null ? context.getService(ref) : null; } + public static ArduinoConsoleService getConsoleService() throws CoreException { + IExtensionPoint point = Platform.getExtensionRegistry().getExtensionPoint(Activator.getId(), "consoleService"); //$NON-NLS-1$ + IExtension extension = point.getExtensions()[0]; // should only be one + return (ArduinoConsoleService) extension.getConfigurationElements()[0].createExecutableExtension("class"); //$NON-NLS-1$ + } + } diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoPreferences.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoPreferences.java index 534b0dc2c74..07d3d81bfa5 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoPreferences.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoPreferences.java @@ -21,7 +21,8 @@ public class ArduinoPreferences { private static final String defaultHome = Paths.get(System.getProperty("user.home"), ".arduinocdt").toString(); //$NON-NLS-1$ //$NON-NLS-2$ private static final String defaultBoardUrls = "http://downloads.arduino.cc/packages/package_index.json" //$NON-NLS-1$ - + "\nhttp://arduino.esp8266.com/stable/package_esp8266com_index.json"; //$NON-NLS-1$ + + "\nhttp://arduino.esp8266.com/stable/package_esp8266com_index.json" //$NON-NLS-1$ + + "\nhttps://adafruit.github.io/arduino-board-index/package_adafruit_index.json"; //$NON-NLS-1$ private static IEclipsePreferences getPrefs() { return InstanceScope.INSTANCE.getNode(Activator.getId()); diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoProjectGenerator.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoProjectGenerator.java index 9b12dbb1de3..b54bf1c024a 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoProjectGenerator.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoProjectGenerator.java @@ -20,7 +20,6 @@ import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.IPathEntry; import org.eclipse.core.resources.ICommand; import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IncrementalProjectBuilder; @@ -36,7 +35,15 @@ public class ArduinoProjectGenerator { this.project = project; } - public void setupArduinoProject(IProgressMonitor monitor) throws CoreException { + public void generate(IProgressMonitor monitor) throws CoreException { + // Generate files + ArduinoTemplateGenerator templateGen = new ArduinoTemplateGenerator(); + Map fmModel = new HashMap<>(); + fmModel.put("projectName", project.getName()); //$NON-NLS-1$ + + sourceFile = project.getFile(project.getName() + ".cpp"); //$NON-NLS-1$ + templateGen.generateFile(fmModel, "arduino.cpp", sourceFile, monitor); //$NON-NLS-1$ + // Add natures to project: C, C++, Arduino IProjectDescription projDesc = project.getDescription(); String[] oldIds = projDesc.getNatureIds(); @@ -55,20 +62,8 @@ public class ArduinoProjectGenerator { project.setDescription(projDesc, monitor); - // Generate files - ArduinoTemplateGenerator templateGen = new ArduinoTemplateGenerator(); - Map fmModel = new HashMap<>(); - fmModel.put("projectName", project.getName()); //$NON-NLS-1$ - - IFolder sourceFolder = project.getFolder("src"); //$NON-NLS-1$ - if (!sourceFolder.exists()) { - sourceFolder.create(true, true, monitor); - } - IPathEntry[] entries = new IPathEntry[] { CoreModel.newOutputEntry(sourceFolder.getFullPath()) }; + IPathEntry[] entries = new IPathEntry[] { CoreModel.newSourceEntry(project.getFullPath()) }; CoreModel.getDefault().create(project).setRawPathEntries(entries, monitor); - - sourceFile = sourceFolder.getFile(project.getName() + ".cpp"); //$NON-NLS-1$ - templateGen.generateFile(fmModel, "arduino.cpp", sourceFile, monitor); //$NON-NLS-1$ } public IFile getSourceFile() { diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoScannerInfoProvider.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoScannerInfoProvider.java index c5db121cbb8..648a20c77d0 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoScannerInfoProvider.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoScannerInfoProvider.java @@ -7,8 +7,6 @@ *******************************************************************************/ package org.eclipse.cdt.arduino.core.internal; -import java.io.IOException; - import org.eclipse.cdt.arduino.core.internal.build.ArduinoBuildConfiguration; import org.eclipse.cdt.core.parser.IScannerInfo; import org.eclipse.cdt.core.parser.IScannerInfoChangeListener; @@ -30,7 +28,7 @@ public class ArduinoScannerInfoProvider implements IScannerInfoProvider { IBuildConfiguration config = project.getActiveBuildConfig(); ArduinoBuildConfiguration arduinoConfig = config.getAdapter(ArduinoBuildConfiguration.class); return arduinoConfig.getScannerInfo(resource); - } catch (IOException | CoreException e) { + } catch (CoreException e) { Activator.log(e); return null; } diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoTemplateGenerator.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoTemplateGenerator.java index 3bebdd46970..3725e794f67 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoTemplateGenerator.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoTemplateGenerator.java @@ -10,6 +10,8 @@ package org.eclipse.cdt.arduino.core.internal; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; import java.io.StringWriter; import java.net.URISyntaxException; import java.net.URL; @@ -23,22 +25,19 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; +import freemarker.cache.TemplateLoader; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; -public class ArduinoTemplateGenerator { +public class ArduinoTemplateGenerator implements TemplateLoader { private final Configuration config; + private Path templateRoot = new Path("/templates"); //$NON-NLS-1$ public ArduinoTemplateGenerator() throws CoreException { config = new Configuration(Configuration.VERSION_2_3_22); - URL templateDirURL = FileLocator.find(Activator.getContext().getBundle(), new Path("/templates"), null); //$NON-NLS-1$ - try { - config.setDirectoryForTemplateLoading(new File(FileLocator.toFileURL(templateDirURL).toURI())); - } catch (IOException | URISyntaxException e) { - throw new CoreException(new Status(IStatus.ERROR, Activator.getId(), "Template configuration", e)); - } + config.setTemplateLoader(this); } public void generateFile(final Object model, String templateFile, final IFile outputFile, IProgressMonitor monitor) @@ -58,8 +57,39 @@ public class ArduinoTemplateGenerator { } } catch (IOException | TemplateException e) { throw new CoreException( - new Status(IStatus.ERROR, Activator.getId(), "Processing template " + templateFile, e)); + new Status(IStatus.ERROR, Activator.getId(), "Processing template " + templateFile, e)); //$NON-NLS-1$ } } + @Override + public Object findTemplateSource(String name) throws IOException { + return FileLocator.find(Activator.getContext().getBundle(), templateRoot.append(name), null); + } + + @Override + public long getLastModified(Object source) { + try { + URL url = (URL) source; + if (url.getProtocol().equals("file")) { //$NON-NLS-1$ + File file = new File(url.toURI()); + return file.lastModified(); + } else { + return 0; + } + } catch (URISyntaxException e) { + return 0; + } + } + + @Override + public Reader getReader(Object source, String encoding) throws IOException { + URL url = (URL) source; + return new InputStreamReader(url.openStream()); + } + + @Override + public void closeTemplateSource(Object arg0) throws IOException { + // Nothing to do + } + } diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/HierarchicalProperties.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/HierarchicalProperties.java index 6effa7af20a..382257608db 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/HierarchicalProperties.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/HierarchicalProperties.java @@ -8,11 +8,13 @@ package org.eclipse.cdt.arduino.core.internal; import java.util.ArrayList; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Properties; +import org.eclipse.core.runtime.Platform; + public class HierarchicalProperties { private String value; @@ -52,7 +54,7 @@ public class HierarchicalProperties { public void putProperty(String qualifiedKey, String value) { if (children == null) { - children = new HashMap<>(); + children = new LinkedHashMap<>(); } int i = qualifiedKey.indexOf('.'); @@ -61,8 +63,8 @@ public class HierarchicalProperties { if (child == null) { child = new HierarchicalProperties(); children.put(qualifiedKey, child); - child.setValue(value); } + child.setValue(value); } else { String key = qualifiedKey.substring(0, i); HierarchicalProperties child = children.get(key); @@ -76,6 +78,27 @@ public class HierarchicalProperties { } public String getValue() { + if (value == null) { + // Try a platform child + String platName = null; + switch (Platform.getOS()) { + case Platform.OS_WIN32: + platName = "windows"; //$NON-NLS-1$ + break; + case Platform.OS_MACOSX: + platName = "macosx"; //$NON-NLS-1$ + break; + case Platform.OS_LINUX: + platName = "linux"; //$NON-NLS-1$ + break; + } + if (platName != null) { + HierarchicalProperties platChild = getChild(platName); + if (platChild != null) { + return platChild.getValue(); + } + } + } return value; } @@ -93,7 +116,7 @@ public class HierarchicalProperties { public void putChild(String key, HierarchicalProperties node) { if (children == null) { - children = new HashMap<>(); + children = new LinkedHashMap<>(); } children.put(key, node); } diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/Messages.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/Messages.java index 78de895b78f..c80f87c6082 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/Messages.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/Messages.java @@ -19,6 +19,11 @@ public class Messages extends NLS { public static String ArduinoLaunchConfigurationDelegate_0; public static String ArduinoLaunchConfigurationDelegate_1; public static String ArduinoLaunchConfigurationDelegate_2; + public static String ArduinoManager_0; + public static String ArduinoManager_1; + public static String ArduinoManager_2; + public static String ArduinoPlatform_0; + public static String ArduinoPlatform_1; public static String ArduinoProjectGenerator_0; static { diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoBoard.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoBoard.java index 01577b9ab0f..bad4694bc65 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoBoard.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoBoard.java @@ -13,6 +13,8 @@ import org.eclipse.cdt.arduino.core.internal.HierarchicalProperties; public class ArduinoBoard { + public static final String MENU_QUALIFIER = "menu_"; //$NON-NLS-1$ + private String name; private String id; @@ -50,10 +52,18 @@ public class ArduinoBoard { return properties.getProperty(key); } + public HierarchicalProperties getMenus() { + return properties.getChild("menu"); //$NON-NLS-1$ + } + public Properties getBoardProperties() { return properties.flatten(); } + public Properties getMenuProperties(String id, String value) { + return getMenus().getChild(id).getChild(value).flatten(); + } + @Override public int hashCode() { final int prime = 31; diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoLibrary.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoLibrary.java index 31ea5052ee3..9c77d69996d 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoLibrary.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoLibrary.java @@ -1,15 +1,18 @@ package org.eclipse.cdt.arduino.core.internal.board; import java.io.File; +import java.io.FileReader; +import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Properties; import org.eclipse.cdt.arduino.core.internal.ArduinoPreferences; -import org.eclipse.cdt.core.model.CoreModel; -import org.eclipse.core.resources.IProject; +import org.eclipse.cdt.arduino.core.internal.build.ArduinoBuildConfiguration; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; @@ -31,6 +34,29 @@ public class ArduinoLibrary { private int size; private String checksum; + private Path installPath; + + public ArduinoLibrary() { + } + + public ArduinoLibrary(Path propertiesFile) throws IOException { + installPath = propertiesFile.getParent(); + + Properties props = new Properties(); + try (FileReader reader = new FileReader(propertiesFile.toFile())) { + props.load(reader); + } + + name = props.getProperty("name"); //$NON-NLS-1$ + version = props.getProperty("version"); //$NON-NLS-1$ + author = props.getProperty("author"); //$NON-NLS-1$ + maintainer = props.getProperty("maintainer"); //$NON-NLS-1$ + sentence = props.getProperty("sentence"); //$NON-NLS-1$ + paragraph = props.getProperty("paragraph"); //$NON-NLS-1$ + category = props.getProperty("category"); //$NON-NLS-1$ + architectures = Arrays.asList(props.getProperty("architectures").split(",")); //$NON-NLS-1$ //$NON-NLS-2$ + } + public String getName() { return name; } @@ -144,8 +170,9 @@ public class ArduinoLibrary { } public Path getInstallPath() { - return ArduinoPreferences.getArduinoHome().resolve("libraries").resolve(name.replace(' ', '_')) //$NON-NLS-1$ - .resolve(version); + return installPath != null ? installPath + : ArduinoPreferences.getArduinoHome().resolve("libraries").resolve(name.replace(' ', '_')) //$NON-NLS-1$ + .resolve(version); } public boolean isInstalled() { @@ -166,39 +193,57 @@ public class ArduinoLibrary { if (srcPath.toFile().isDirectory()) { return Collections.singletonList(srcPath); } else { - // TODO do I need the 'utility' directory? - return Collections.singletonList(installPath); + Path utilityPath = installPath.resolve("utility"); //$NON-NLS-1$ + if (utilityPath.toFile().isDirectory()) { + return Arrays.asList(installPath, utilityPath); + } else { + return Collections.singletonList(installPath); + } } } - private void getSources(IProject project, Collection sources, Path dir, boolean recurse) { + private void getSources(Collection sources, Path dir, boolean recurse) { for (File file : dir.toFile().listFiles()) { if (file.isDirectory()) { if (recurse) { - getSources(project, sources, file.toPath(), recurse); + getSources(sources, file.toPath(), recurse); } } else { - if (CoreModel.isValidSourceUnitName(project, file.getName())) { - sources.add(file.toPath()); + if (ArduinoBuildConfiguration.isSource(file.getName())) { + sources.add(ArduinoBuildConfiguration.pathString(file.toPath())); } } } } - public Collection getSources(IProject project) { - List sources = new ArrayList<>(); + public Collection getSources() { + List sources = new ArrayList<>(); Path installPath = getInstallPath(); Path srcPath = installPath.resolve("src"); //$NON-NLS-1$ if (srcPath.toFile().isDirectory()) { - getSources(project, sources, srcPath, true); + getSources(sources, srcPath, true); } else { - getSources(project, sources, installPath, false); + getSources(sources, installPath, false); Path utilityPath = installPath.resolve("utility"); //$NON-NLS-1$ if (utilityPath.toFile().isDirectory()) { - getSources(project, sources, utilityPath, false); + getSources(sources, utilityPath, false); } } return sources; } + @Override + public boolean equals(Object obj) { + if (obj instanceof ArduinoLibrary) { + return getName().equals(((ArduinoLibrary) obj).getName()); + } else { + return false; + } + } + + @Override + public int hashCode() { + return getName().hashCode(); + } + } diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoManager.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoManager.java index e2483f6ebcd..5fe77c47982 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoManager.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoManager.java @@ -19,10 +19,14 @@ import java.io.InputStream; import java.io.Reader; import java.lang.reflect.Type; import java.net.URL; +import java.net.URLConnection; +import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.PosixFilePermission; import java.util.ArrayList; import java.util.Collection; @@ -59,8 +63,6 @@ import com.google.gson.reflect.TypeToken; public class ArduinoManager { - public static final ArduinoManager instance = new ArduinoManager(); - // Build tool ids public static final String BOARD_OPTION_ID = "org.eclipse.cdt.arduino.option.board"; //$NON-NLS-1$ public static final String PLATFORM_OPTION_ID = "org.eclipse.cdt.arduino.option.platform"; //$NON-NLS-1$ @@ -68,20 +70,23 @@ public class ArduinoManager { public static final String AVR_TOOLCHAIN_ID = "org.eclipse.cdt.arduino.toolChain.avr"; //$NON-NLS-1$ public static final String LIBRARIES_URL = "http://downloads.arduino.cc/libraries/library_index.json"; //$NON-NLS-1$ + private List packageIndices; private LibraryIndex libraryIndex; public void loadIndices() { new Job(Messages.ArduinoBoardManager_0) { protected IStatus run(IProgressMonitor monitor) { - String[] boardUrls = ArduinoPreferences.getBoardUrls().split("\n"); //$NON-NLS-1$ - packageIndices = new ArrayList<>(boardUrls.length); - for (String boardUrl : boardUrls) { - loadPackageIndex(boardUrl, true); - } + synchronized (ArduinoManager.this) { + String[] boardUrls = ArduinoPreferences.getBoardUrls().split("\n"); //$NON-NLS-1$ + packageIndices = new ArrayList<>(boardUrls.length); + for (String boardUrl : boardUrls) { + loadPackageIndex(boardUrl, true); + } - loadLibraryIndex(true); - return Status.OK_STATUS; + loadLibraryIndex(true); + return Status.OK_STATUS; + } } }.schedule(); } @@ -93,6 +98,7 @@ public class ArduinoManager { .resolve(Paths.get(packageUrl.getPath()).getFileName()); File packageFile = packagePath.toFile(); if (download) { + Files.createDirectories(ArduinoPreferences.getArduinoHome()); Files.copy(packageUrl.openStream(), packagePath, StandardCopyOption.REPLACE_EXISTING); } if (packageFile.exists()) { @@ -107,7 +113,7 @@ public class ArduinoManager { } } - public List getPackageIndices() throws CoreException { + public synchronized List getPackageIndices() { if (packageIndices == null) { String[] boardUrls = ArduinoPreferences.getBoardUrls().split("\n"); //$NON-NLS-1$ packageIndices = new ArrayList<>(boardUrls.length); @@ -118,18 +124,20 @@ public class ArduinoManager { return packageIndices; } - private void loadLibraryIndex(boolean download) { + public void loadLibraryIndex(boolean download) { try { URL librariesUrl = new URL(LIBRARIES_URL); Path librariesPath = ArduinoPreferences.getArduinoHome() .resolve(Paths.get(librariesUrl.getPath()).getFileName()); File librariesFile = librariesPath.toFile(); if (download) { + Files.createDirectories(ArduinoPreferences.getArduinoHome()); Files.copy(librariesUrl.openStream(), librariesPath, StandardCopyOption.REPLACE_EXISTING); } if (librariesFile.exists()) { try (Reader reader = new FileReader(librariesFile)) { libraryIndex = new Gson().fromJson(reader, LibraryIndex.class); + libraryIndex.resolve(); } } } catch (IOException e) { @@ -146,7 +154,7 @@ public class ArduinoManager { } public ArduinoBoard getBoard(String boardName, String platformName, String packageName) throws CoreException { - for (PackageIndex index : packageIndices) { + for (PackageIndex index : getPackageIndices()) { ArduinoPackage pkg = index.getPackage(packageName); if (pkg != null) { ArduinoPlatform platform = pkg.getPlatform(platformName); @@ -161,23 +169,11 @@ public class ArduinoManager { return null; } - public List getBoards() throws CoreException { - List boards = new ArrayList<>(); - for (PackageIndex index : packageIndices) { - for (ArduinoPackage pkg : index.getPackages()) { - for (ArduinoPlatform platform : pkg.getLatestPlatforms()) { - boards.addAll(platform.getBoards()); - } - } - } - return boards; - } - public List getInstalledBoards() throws CoreException { List boards = new ArrayList<>(); - for (PackageIndex index : packageIndices) { + for (PackageIndex index : getPackageIndices()) { for (ArduinoPackage pkg : index.getPackages()) { - for (ArduinoPlatform platform : pkg.getInstalledPlatforms()) { + for (ArduinoPlatform platform : pkg.getInstalledPlatforms().values()) { boards.addAll(platform.getBoards()); } } @@ -185,8 +181,8 @@ public class ArduinoManager { return boards; } - public ArduinoPackage getPackage(String packageName) { - for (PackageIndex index : packageIndices) { + public ArduinoPackage getPackage(String packageName) throws CoreException { + for (PackageIndex index : getPackageIndices()) { ArduinoPackage pkg = index.getPackage(packageName); if (pkg != null) { return pkg; @@ -195,8 +191,8 @@ public class ArduinoManager { return null; } - public ArduinoTool getTool(String packageName, String toolName, String version) { - for (PackageIndex index : packageIndices) { + public ArduinoTool getTool(String packageName, String toolName, String version) throws CoreException { + for (PackageIndex index : getPackageIndices()) { ArduinoPackage pkg = index.getPackage(packageName); if (pkg != null) { ArduinoTool tool = pkg.getTool(toolName, version); @@ -208,23 +204,6 @@ public class ArduinoManager { return null; } - public ArduinoTool getLatestTool(String packageName, String toolName) { - for (PackageIndex index : packageIndices) { - ArduinoPackage pkg = index.getPackage(packageName); - if (pkg != null) { - ArduinoTool latestTool = null; - for (ArduinoTool tool : pkg.getTools()) { - if (tool.getName().equals(toolName)) { - if (latestTool == null || compareVersions(latestTool.getVersion(), tool.getVersion()) > 1) { - latestTool = tool; - } - } - } - } - } - return null; - } - private static final String LIBRARIES = "libraries"; //$NON-NLS-1$ private IEclipsePreferences getSettings(IProject project) { @@ -237,10 +216,19 @@ public class ArduinoManager { Type stringSet = new TypeToken>() { }.getType(); Set libraryNames = new Gson().fromJson(librarySetting, stringSet); - LibraryIndex index = ArduinoManager.instance.getLibraryIndex(); + LibraryIndex index = Activator.getService(ArduinoManager.class).getLibraryIndex(); + + ArduinoPlatform platform = project.getActiveBuildConfig().getAdapter(ArduinoBuildConfiguration.class).getBoard() + .getPlatform(); List libraries = new ArrayList<>(libraryNames.size()); for (String name : libraryNames) { - libraries.add(index.getLibrary(name)); + ArduinoLibrary lib = index.getLibrary(name); + if (lib == null) { + lib = platform.getLibrary(name); + } + if (lib != null) { + libraries.add(lib); + } } return libraries; } @@ -258,9 +246,9 @@ public class ArduinoManager { Activator.log(e); } - new Job("Install libraries") { + new Job(Messages.ArduinoManager_0) { protected IStatus run(IProgressMonitor monitor) { - MultiStatus mstatus = new MultiStatus(Activator.getId(), 0, "Installing libraries", null); + MultiStatus mstatus = new MultiStatus(Activator.getId(), 0, Messages.ArduinoManager_1, null); for (ArduinoLibrary library : libraries) { IStatus status = library.install(monitor); if (!status.isOK()) { @@ -272,7 +260,7 @@ public class ArduinoManager { try { for (IBuildConfiguration config : project.getBuildConfigs()) { ArduinoBuildConfiguration arduinoConfig = config.getAdapter(ArduinoBuildConfiguration.class); - arduinoConfig.clearScannerInfo(); + arduinoConfig.clearScannerInfoCache(); } } catch (CoreException e) { mstatus.add(e.getStatus()); @@ -284,115 +272,97 @@ public class ArduinoManager { public static IStatus downloadAndInstall(String url, String archiveFileName, Path installPath, IProgressMonitor monitor) { - try { - URL dl = new URL(url); - Path dlDir = ArduinoPreferences.getArduinoHome().resolve("downloads"); //$NON-NLS-1$ - Files.createDirectories(dlDir); - Path archivePath = dlDir.resolve(archiveFileName); - Files.copy(dl.openStream(), archivePath, StandardCopyOption.REPLACE_EXISTING); - - boolean isWin = Platform.getOS().equals(Platform.OS_WIN32); - - // extract - ArchiveInputStream archiveIn = null; + Exception error = null; + for (int retries = 3; retries > 0 && !monitor.isCanceled(); --retries) { try { - String compressor = null; - String archiver = null; - if (archiveFileName.endsWith("tar.bz2")) { //$NON-NLS-1$ - compressor = CompressorStreamFactory.BZIP2; - archiver = ArchiveStreamFactory.TAR; - } else if (archiveFileName.endsWith(".tar.gz") || archiveFileName.endsWith(".tgz")) { //$NON-NLS-1$ //$NON-NLS-2$ - compressor = CompressorStreamFactory.GZIP; - archiver = ArchiveStreamFactory.TAR; - } else if (archiveFileName.endsWith(".tar.xz")) { //$NON-NLS-1$ - compressor = CompressorStreamFactory.XZ; - archiver = ArchiveStreamFactory.TAR; - } else if (archiveFileName.endsWith(".zip")) { //$NON-NLS-1$ - archiver = ArchiveStreamFactory.ZIP; - } + URL dl = new URL(url); + Path dlDir = ArduinoPreferences.getArduinoHome().resolve("downloads"); //$NON-NLS-1$ + Files.createDirectories(dlDir); + Path archivePath = dlDir.resolve(archiveFileName); + URLConnection conn = dl.openConnection(); + conn.setConnectTimeout(10000); + conn.setReadTimeout(10000); + Files.copy(conn.getInputStream(), archivePath, StandardCopyOption.REPLACE_EXISTING); - InputStream in = new BufferedInputStream(new FileInputStream(archivePath.toFile())); - if (compressor != null) { - in = new CompressorStreamFactory().createCompressorInputStream(compressor, in); - } - archiveIn = new ArchiveStreamFactory().createArchiveInputStream(archiver, in); + boolean isWin = Platform.getOS().equals(Platform.OS_WIN32); - for (ArchiveEntry entry = archiveIn.getNextEntry(); entry != null; entry = archiveIn.getNextEntry()) { - if (entry.isDirectory()) { - continue; + // extract + ArchiveInputStream archiveIn = null; + try { + String compressor = null; + String archiver = null; + if (archiveFileName.endsWith("tar.bz2")) { //$NON-NLS-1$ + compressor = CompressorStreamFactory.BZIP2; + archiver = ArchiveStreamFactory.TAR; + } else if (archiveFileName.endsWith(".tar.gz") || archiveFileName.endsWith(".tgz")) { //$NON-NLS-1$ //$NON-NLS-2$ + compressor = CompressorStreamFactory.GZIP; + archiver = ArchiveStreamFactory.TAR; + } else if (archiveFileName.endsWith(".tar.xz")) { //$NON-NLS-1$ + compressor = CompressorStreamFactory.XZ; + archiver = ArchiveStreamFactory.TAR; + } else if (archiveFileName.endsWith(".zip")) { //$NON-NLS-1$ + archiver = ArchiveStreamFactory.ZIP; } - Path entryPath = installPath.resolve(entry.getName()); - Files.createDirectories(entryPath.getParent()); + InputStream in = new BufferedInputStream(new FileInputStream(archivePath.toFile())); + if (compressor != null) { + in = new CompressorStreamFactory().createCompressorInputStream(compressor, in); + } + archiveIn = new ArchiveStreamFactory().createArchiveInputStream(archiver, in); - if (entry instanceof TarArchiveEntry) { - TarArchiveEntry tarEntry = (TarArchiveEntry) entry; - if (tarEntry.isLink()) { - Path linkPath = installPath.resolve(tarEntry.getLinkName()); - Files.createSymbolicLink(entryPath, entryPath.getParent().relativize(linkPath)); + for (ArchiveEntry entry = archiveIn.getNextEntry(); entry != null; entry = archiveIn + .getNextEntry()) { + if (entry.isDirectory()) { + continue; + } + + // Magic file for git tarballs + Path path = Paths.get(entry.getName()); + if (path.endsWith("pax_global_header")) { //$NON-NLS-1$ + continue; + } + + // Strip the first directory of the path + Path entryPath = installPath.resolve(path.subpath(1, path.getNameCount())); + + Files.createDirectories(entryPath.getParent()); + + if (entry instanceof TarArchiveEntry) { + TarArchiveEntry tarEntry = (TarArchiveEntry) entry; + if (tarEntry.isLink()) { + Path linkPath = Paths.get(tarEntry.getLinkName()); + linkPath = installPath.resolve(linkPath.subpath(1, linkPath.getNameCount())); + Files.deleteIfExists(entryPath); + Files.createSymbolicLink(entryPath, entryPath.getParent().relativize(linkPath)); + } else if (tarEntry.isSymbolicLink()) { + Path linkPath = Paths.get(tarEntry.getLinkName()); + Files.deleteIfExists(entryPath); + Files.createSymbolicLink(entryPath, linkPath); + } else { + Files.copy(archiveIn, entryPath, StandardCopyOption.REPLACE_EXISTING); + } + if (!isWin && !tarEntry.isSymbolicLink()) { + int mode = tarEntry.getMode(); + Files.setPosixFilePermissions(entryPath, toPerms(mode)); + } } else { Files.copy(archiveIn, entryPath, StandardCopyOption.REPLACE_EXISTING); } - if (!isWin) { - int mode = tarEntry.getMode(); - Files.setPosixFilePermissions(entryPath, toPerms(mode)); - } - } else { - Files.copy(archiveIn, entryPath, StandardCopyOption.REPLACE_EXISTING); + } + } finally { + if (archiveIn != null) { + archiveIn.close(); } } - } finally { - if (archiveIn != null) { - archiveIn.close(); - } - } - // Fix up directory - File[] children = installPath.toFile().listFiles(); - if (children.length == 1 && children[0].isDirectory()) { - // make that directory the install path - Path childPath = children[0].toPath(); - Path tmpPath = installPath.getParent().resolve("_t"); //$NON-NLS-1$ - Files.move(childPath, tmpPath); - Files.delete(installPath); - Files.move(tmpPath, installPath); + return Status.OK_STATUS; + } catch (IOException | CompressorException | ArchiveException e) { + error = e; + // retry } - return Status.OK_STATUS; - } catch (IOException | CompressorException | ArchiveException e) { - return new Status(IStatus.ERROR, Activator.getId(), "Installing Platform", e); } - } - - private static Set toPerms(int mode) { - Set perms = new HashSet<>(); - if ((mode & 0400) != 0) { - perms.add(PosixFilePermission.OWNER_READ); - } - if ((mode & 0200) != 0) { - perms.add(PosixFilePermission.OWNER_WRITE); - } - if ((mode & 0100) != 0) { - perms.add(PosixFilePermission.OWNER_EXECUTE); - } - if ((mode & 0040) != 0) { - perms.add(PosixFilePermission.GROUP_READ); - } - if ((mode & 0020) != 0) { - perms.add(PosixFilePermission.GROUP_WRITE); - } - if ((mode & 0010) != 0) { - perms.add(PosixFilePermission.GROUP_EXECUTE); - } - if ((mode & 0004) != 0) { - perms.add(PosixFilePermission.OTHERS_READ); - } - if ((mode & 0002) != 0) { - perms.add(PosixFilePermission.OTHERS_WRITE); - } - if ((mode & 0001) != 0) { - perms.add(PosixFilePermission.OTHERS_EXECUTE); - } - return perms; + // out of retries + return new Status(IStatus.ERROR, Activator.getId(), Messages.ArduinoManager_2, error); } public static int compareVersions(String version1, String version2) { @@ -440,4 +410,52 @@ public class ArduinoManager { return 0; } + private static Set toPerms(int mode) { + Set perms = new HashSet<>(); + if ((mode & 0400) != 0) { + perms.add(PosixFilePermission.OWNER_READ); + } + if ((mode & 0200) != 0) { + perms.add(PosixFilePermission.OWNER_WRITE); + } + if ((mode & 0100) != 0) { + perms.add(PosixFilePermission.OWNER_EXECUTE); + } + if ((mode & 0040) != 0) { + perms.add(PosixFilePermission.GROUP_READ); + } + if ((mode & 0020) != 0) { + perms.add(PosixFilePermission.GROUP_WRITE); + } + if ((mode & 0010) != 0) { + perms.add(PosixFilePermission.GROUP_EXECUTE); + } + if ((mode & 0004) != 0) { + perms.add(PosixFilePermission.OTHERS_READ); + } + if ((mode & 0002) != 0) { + perms.add(PosixFilePermission.OTHERS_WRITE); + } + if ((mode & 0001) != 0) { + perms.add(PosixFilePermission.OTHERS_EXECUTE); + } + return perms; + } + + public static void recursiveDelete(Path directory) throws IOException { + Files.walkFileTree(directory, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + + }); + } } diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPackage.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPackage.java index 1fce5bac8af..1d18767598a 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPackage.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPackage.java @@ -7,12 +7,15 @@ *******************************************************************************/ package org.eclipse.cdt.arduino.core.internal.board; +import java.nio.file.Path; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.eclipse.cdt.arduino.core.internal.ArduinoPreferences; + public class ArduinoPackage { private String name; @@ -63,12 +66,16 @@ public class ArduinoPackage { return Collections.unmodifiableCollection(platforms); } + public Path getInstallPath() { + return ArduinoPreferences.getArduinoHome().resolve("packages").resolve(getName()); //$NON-NLS-1$ + } + /** * Only the latest versions of the platforms. * * @return latest platforms */ - public Collection getLatestPlatforms() { + public Map getAvailablePlatforms() { Map platformMap = new HashMap<>(); for (ArduinoPlatform platform : platforms) { ArduinoPlatform p = platformMap.get(platform.getName()); @@ -76,20 +83,17 @@ public class ArduinoPackage { platformMap.put(platform.getName(), platform); } } - return Collections.unmodifiableCollection(platformMap.values()); + return platformMap; } - public Collection getInstalledPlatforms() { + public Map getInstalledPlatforms() { Map platformMap = new HashMap<>(); for (ArduinoPlatform platform : platforms) { if (platform.isInstalled()) { - ArduinoPlatform p = platformMap.get(platform.getName()); - if (p == null || ArduinoManager.compareVersions(platform.getVersion(), p.getVersion()) > 0) { - platformMap.put(platform.getName(), platform); - } + platformMap.put(platform.getName(), platform); } } - return Collections.unmodifiableCollection(platformMap.values()); + return platformMap; } public ArduinoPlatform getPlatform(String name) { @@ -122,19 +126,6 @@ public class ArduinoPackage { return null; } - public ArduinoTool getLatestTool(String toolName) { - ArduinoTool latestTool = null; - for (ArduinoTool tool : tools) { - if (tool.getName().equals(toolName)) { - if (latestTool == null - || ArduinoManager.compareVersions(tool.getVersion(), latestTool.getVersion()) > 0) { - latestTool = tool; - } - } - } - return latestTool; - } - @Override public boolean equals(Object obj) { if (obj instanceof ArduinoPackage) { diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPlatform.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPlatform.java index bd5c409dfd7..313d479fd38 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPlatform.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPlatform.java @@ -8,8 +8,12 @@ package org.eclipse.cdt.arduino.core.internal.board; import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.net.URL; @@ -17,6 +21,8 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; @@ -24,10 +30,12 @@ import java.util.Properties; import org.eclipse.cdt.arduino.core.internal.Activator; import org.eclipse.cdt.arduino.core.internal.ArduinoPreferences; import org.eclipse.cdt.arduino.core.internal.HierarchicalProperties; +import org.eclipse.cdt.arduino.core.internal.Messages; +import org.eclipse.cdt.arduino.core.internal.build.ArduinoBuildConfiguration; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; public class ArduinoPlatform { @@ -44,8 +52,10 @@ public class ArduinoPlatform { private List toolsDependencies; private ArduinoPackage pkg; - private HierarchicalProperties boardsFile; + private HierarchicalProperties boardsProperties; private Properties platformProperties; + private Map menus = new HashMap<>(); + private Map libraries; void setOwner(ArduinoPackage pkg) { this.pkg = pkg; @@ -93,29 +103,43 @@ public class ArduinoPlatform { return size; } - public List getBoards() throws CoreException { - if (isInstalled() && boardsFile == null) { + public List getBoards() { + if (isInstalled() && boardsProperties == null) { Properties boardProps = new Properties(); - try (Reader reader = new FileReader(getInstallPath().resolve("boards.txt").toFile())) { //$NON-NLS-1$ + + try (InputStream is = new FileInputStream(getInstallPath().resolve("boards.txt").toFile()); //$NON-NLS-1$ + Reader reader = new InputStreamReader(is, "UTF-8")) { //$NON-NLS-1$ boardProps.load(reader); } catch (IOException e) { - throw new CoreException(new Status(IStatus.ERROR, Activator.getId(), "Loading boards.txt", e)); + Activator.log(e); } - boardsFile = new HierarchicalProperties(boardProps); + boardsProperties = new HierarchicalProperties(boardProps); // Replace the boards with a real ones boards = new ArrayList<>(); - for (Map.Entry entry : boardsFile.getChildren().entrySet()) { + for (Map.Entry entry : boardsProperties.getChildren().entrySet()) { if (entry.getValue().getChild("name") != null) { //$NON-NLS-1$ // assume things with names are boards boards.add(new ArduinoBoard(entry.getKey(), entry.getValue()).setOwners(this)); } } + + // Build the menu + HierarchicalProperties menuProp = boardsProperties.getChild("menu"); //$NON-NLS-1$ + if (menuProp != null) { + for (Map.Entry entry : menuProp.getChildren().entrySet()) { + menus.put(entry.getKey(), entry.getValue().getValue()); + } + } } return boards; } + public HierarchicalProperties getBoardsProperties() { + return boardsProperties; + } + public ArduinoBoard getBoard(String name) throws CoreException { for (ArduinoBoard board : getBoards()) { if (name.equals(board.getName())) { @@ -125,6 +149,10 @@ public class ArduinoPlatform { return null; } + public String getMenuText(String id) { + return menus.get(id); + } + public List getToolsDependencies() { return toolsDependencies; } @@ -153,7 +181,7 @@ public class ArduinoPlatform { platformProperties.load(reader1); } } catch (IOException e) { - throw new CoreException(new Status(IStatus.ERROR, Activator.getId(), "Loading platform.txt", e)); + throw new CoreException(new Status(IStatus.ERROR, Activator.getId(), "Loading platform.txt", e)); //$NON-NLS-1$ } } return platformProperties; @@ -164,8 +192,27 @@ public class ArduinoPlatform { } public Path getInstallPath() { - return ArduinoPreferences.getArduinoHome().resolve("hardware").resolve(pkg.getName()).resolve(architecture) //$NON-NLS-1$ + // TODO remove migration in Neon + Path oldPath = ArduinoPreferences.getArduinoHome().resolve("hardware").resolve(pkg.getName()) //$NON-NLS-1$ + .resolve(architecture).resolve(version); + Path newPath = getPackage().getInstallPath().resolve("hardware").resolve(pkg.getName()).resolve(architecture) //$NON-NLS-1$ .resolve(version); + if (Files.exists(oldPath)) { + try { + Files.createDirectories(newPath.getParent()); + Files.move(oldPath, newPath); + for (Path parent = oldPath.getParent(); parent != null; parent = parent.getParent()) { + if (Files.newDirectoryStream(parent).iterator().hasNext()) { + break; + } else { + Files.delete(parent); + } + } + } catch (IOException e) { + Activator.log(e); + } + } + return newPath; } public List getIncludePath() { @@ -174,10 +221,98 @@ public class ArduinoPlatform { installPath.resolve("variants/{build.variant}")); //$NON-NLS-1$ } + private void getSources(Collection sources, Path dir, boolean recurse) { + for (File file : dir.toFile().listFiles()) { + if (file.isDirectory()) { + if (recurse) { + getSources(sources, file.toPath(), recurse); + } + } else { + if (ArduinoBuildConfiguration.isSource(file.getName())) { + sources.add(ArduinoBuildConfiguration.pathString(file.toPath())); + } + } + } + } + + public Collection getSources(String core, String variant) { + List sources = new ArrayList<>(); + Path srcPath = getInstallPath().resolve("cores").resolve(core); //$NON-NLS-1$ + if (srcPath.toFile().isDirectory()) { + getSources(sources, srcPath, true); + } + Path variantPath = getInstallPath().resolve("variants").resolve(variant); //$NON-NLS-1$ + if (variantPath.toFile().isDirectory()) { + getSources(sources, variantPath, true); + } + return sources; + } + + private void initLibraries() throws CoreException { + libraries = new HashMap<>(); + File[] libraryDirs = getInstallPath().resolve("libraries").toFile().listFiles(); //$NON-NLS-1$ + if (libraryDirs != null) { + for (File libraryDir : libraryDirs) { + Path propsPath = libraryDir.toPath().resolve("library.properties"); //$NON-NLS-1$ + if (propsPath.toFile().exists()) { + try { + ArduinoLibrary lib = new ArduinoLibrary(propsPath); + libraries.put(lib.getName(), lib); + } catch (IOException e) { + throw new CoreException( + new Status(IStatus.ERROR, Activator.getId(), "Loading " + propsPath, e)); //$NON-NLS-1$ + } + } + } + } + } + + public synchronized Collection getLibraries() throws CoreException { + if (libraries == null && isInstalled()) { + initLibraries(); + } + return libraries.values(); + } + + public synchronized ArduinoLibrary getLibrary(String name) throws CoreException { + if (libraries == null && isInstalled()) { + initLibraries(); + } + return libraries != null ? libraries.get(name) : null; + } + public IStatus install(IProgressMonitor monitor) { // Check if we're installed already if (isInstalled()) { - return Status.OK_STATUS; + try { + ArduinoManager.recursiveDelete(getInstallPath()); + } catch (IOException e) { + // just log it, shouldn't break the install + Activator.log(e); + } + } + + // Install the tools + for (ToolDependency toolDep : toolsDependencies) { + IStatus status = toolDep.install(monitor); + if (!status.isOK()) { + return status; + } + } + + // On Windows install make from bintray + if (Platform.getOS().equals(Platform.OS_WIN32)) { + try { + Path makePath = ArduinoPreferences.getArduinoHome().resolve("make.exe"); //$NON-NLS-1$ + if (!makePath.toFile().exists()) { + Files.createDirectories(makePath.getParent()); + URL makeUrl = new URL("https://bintray.com/artifact/download/cdtdoug/tools/make.exe"); //$NON-NLS-1$ + Files.copy(makeUrl.openStream(), makePath); + makePath.toFile().setExecutable(true, false); + } + } catch (IOException e) { + return new Status(IStatus.ERROR, Activator.getId(), Messages.ArduinoPlatform_0, e); + } } // Download platform archive @@ -186,35 +321,17 @@ public class ArduinoPlatform { return status; } - // Install the tools - MultiStatus mstatus = null; - for (ToolDependency toolDep : toolsDependencies) { - status = toolDep.install(monitor); - if (!status.isOK()) { - if (mstatus == null) { - mstatus = new MultiStatus(status.getPlugin(), status.getCode(), status.getMessage(), - status.getException()); - } else { - mstatus.add(status); - } - } - } + return Status.OK_STATUS; + } - // On Windows install make from equations.org + public IStatus uninstall(IProgressMonitor monitor) { try { - Path makePath = ArduinoPreferences.getArduinoHome().resolve("tools/make/make.exe"); - if (!makePath.toFile().exists()) { - Files.createDirectories(makePath.getParent()); - URL makeUrl = new URL("ftp://ftp.equation.com/make/32/make.exe"); - Files.copy(makeUrl.openStream(), makePath); - makePath.toFile().setExecutable(true, false); - } - + ArduinoManager.recursiveDelete(getInstallPath()); + // TODO delete tools that aren't needed any more + return Status.OK_STATUS; } catch (IOException e) { - mstatus.add(new Status(IStatus.ERROR, Activator.getId(), "downloading make.exe", e)); + return new Status(IStatus.ERROR, Activator.getId(), Messages.ArduinoPlatform_1, e); } - - return mstatus != null ? mstatus : Status.OK_STATUS; } @Override diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoTool.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoTool.java index f9e453504e0..f39f030da42 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoTool.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoTool.java @@ -7,6 +7,8 @@ *******************************************************************************/ package org.eclipse.cdt.arduino.core.internal.board; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import java.util.Properties; @@ -50,8 +52,26 @@ public class ArduinoTool { } public Path getInstallPath() { - return ArduinoPreferences.getArduinoHome().resolve("tools").resolve(pkg.getName()).resolve(name) //$NON-NLS-1$ + // TODO remove migration in Neon + Path oldPath = ArduinoPreferences.getArduinoHome().resolve("tools").resolve(pkg.getName()).resolve(name) //$NON-NLS-1$ .resolve(version); + Path newPath = getPackage().getInstallPath().resolve("tools").resolve(name).resolve(version); //$NON-NLS-1$ + if (Files.exists(oldPath)) { + try { + Files.createDirectories(newPath.getParent()); + Files.move(oldPath, newPath); + for (Path parent = oldPath.getParent(); parent != null; parent = parent.getParent()) { + if (Files.newDirectoryStream(parent).iterator().hasNext()) { + break; + } else { + Files.delete(parent); + } + } + } catch (IOException e) { + Activator.log(e); + } + } + return newPath; } public boolean isInstalled() { @@ -70,12 +90,14 @@ public class ArduinoTool { } // No valid system - return new Status(IStatus.ERROR, Activator.getId(), "No valid system found for " + name); + return new Status(IStatus.ERROR, Activator.getId(), "No valid system found for " + name); //$NON-NLS-1$ } public Properties getToolProperties() { Properties properties = new Properties(); - properties.put("runtime.tools." + name + ".path", ArduinoBuildConfiguration.pathString(getInstallPath())); // $NON-NLS-1$ //$NON-NLS-2$ + properties.put("runtime.tools." + name + ".path", ArduinoBuildConfiguration.pathString(getInstallPath())); // $NON-NLS-1$ //$NON-NLS-1$//$NON-NLS-2$ + properties.put("runtime.tools." + name + '-' + version + ".path", //$NON-NLS-1$//$NON-NLS-2$ + ArduinoBuildConfiguration.pathString(getInstallPath())); // $NON-NLS-1$ return properties; } diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoToolSystem.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoToolSystem.java index 669dd360b65..7fa5b1b20f0 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoToolSystem.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoToolSystem.java @@ -60,9 +60,21 @@ public class ArduinoToolSystem { case Platform.OS_LINUX: switch (Platform.getOSArch()) { case Platform.ARCH_X86_64: - return "x86_64-pc-linux-gnu".equals(host); //$NON-NLS-1$ + switch (host) { + case "x86_64-pc-linux-gnu": //$NON-NLS-1$ + case "x86_64-linux-gnu": //$NON-NLS-1$ + return true; + default: + return false; + } case Platform.ARCH_X86: - return "i686-pc-linux-gnu".equals(host); //$NON-NLS-1$ + switch (host) { + case "i686-pc-linux-gnu": //$NON-NLS-1$ + case "i686-linux-gnu": //$NON-NLS-1$ + return true; + default: + return false; + } default: return false; } diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/LibraryIndex.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/LibraryIndex.java index 3747d1442ef..4d83992f133 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/LibraryIndex.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/LibraryIndex.java @@ -1,5 +1,6 @@ package org.eclipse.cdt.arduino.core.internal.board; +import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -12,19 +13,20 @@ import java.util.Set; public class LibraryIndex { private List libraries; + public static final String UNCATEGORIZED = "Uncategorized"; //$NON-NLS-1$ // category name to library name private Map> categories = new HashMap<>(); // library name to latest version of library private Map latestLibs = new HashMap<>(); - public void resolve() { + public void resolve() throws IOException { for (ArduinoLibrary library : libraries) { String name = library.getName(); String category = library.getCategory(); if (category == null) { - category = "Uncategorized"; //$NON-NLS-1$ + category = UNCATEGORIZED; } Set categoryLibs = categories.get(category); diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/build/ArduinoBuildConfiguration.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/build/ArduinoBuildConfiguration.java index 044aa2065f8..9874cb3033f 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/build/ArduinoBuildConfiguration.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/build/ArduinoBuildConfiguration.java @@ -1,19 +1,12 @@ -/******************************************************************************* - * Copyright (c) 2015 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - *******************************************************************************/ package org.eclipse.cdt.arduino.core.internal.build; +import java.io.BufferedReader; import java.io.File; -import java.io.FilenameFilter; import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -21,57 +14,71 @@ import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.eclipse.cdt.arduino.core.internal.Activator; import org.eclipse.cdt.arduino.core.internal.ArduinoPreferences; import org.eclipse.cdt.arduino.core.internal.ArduinoTemplateGenerator; +import org.eclipse.cdt.arduino.core.internal.HierarchicalProperties; import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoard; import org.eclipse.cdt.arduino.core.internal.board.ArduinoLibrary; import org.eclipse.cdt.arduino.core.internal.board.ArduinoManager; import org.eclipse.cdt.arduino.core.internal.board.ArduinoPackage; import org.eclipse.cdt.arduino.core.internal.board.ArduinoPlatform; -import org.eclipse.cdt.arduino.core.internal.board.ArduinoTool; import org.eclipse.cdt.arduino.core.internal.board.ToolDependency; -import org.eclipse.cdt.build.core.CBuildConfiguration; -import org.eclipse.cdt.build.core.IToolChain; -import org.eclipse.cdt.build.core.IToolChainManager; +import org.eclipse.cdt.arduino.core.internal.console.ArduinoConsoleParser; +import org.eclipse.cdt.arduino.core.internal.console.ArduinoErrorParser; +import org.eclipse.cdt.arduino.core.internal.remote.ArduinoRemoteConnection; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.model.IOutputEntry; import org.eclipse.cdt.core.model.IPathEntry; import org.eclipse.cdt.core.model.ISourceRoot; +import org.eclipse.cdt.core.parser.ExtendedScannerInfo; import org.eclipse.cdt.core.parser.IScannerInfo; import org.eclipse.core.resources.IBuildConfiguration; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceProxy; import org.eclipse.core.resources.IResourceProxyVisitor; +import org.eclipse.core.resources.ProjectScope; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdapterFactory; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.content.IContentType; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.osgi.service.prefs.BackingStoreException; -import org.osgi.service.prefs.Preferences; -public class ArduinoBuildConfiguration extends CBuildConfiguration { +public class ArduinoBuildConfiguration { private static final String PACKAGE_NAME = "packageName"; //$NON-NLS-1$ private static final String PLATFORM_NAME = "platformName"; //$NON-NLS-1$ private static final String BOARD_NAME = "boardName"; //$NON-NLS-1$ + private final IBuildConfiguration config; + + private static ArduinoManager manager = Activator.getService(ArduinoManager.class); + private ArduinoBoard board; private Properties properties; + // Cache for scanner info + private IScannerInfo cScannerInfo; + private IScannerInfo cppScannerInfo; + private final static boolean isWindows = Platform.getOS().equals(Platform.OS_WIN32); private ArduinoBuildConfiguration(IBuildConfiguration config) { - super(config); + this.config = config; } private static Map cache = new HashMap<>(); @@ -81,15 +88,13 @@ public class ArduinoBuildConfiguration extends CBuildConfiguration { @Override public T getAdapter(Object adaptableObject, Class adapterType) { if (adapterType.equals(ArduinoBuildConfiguration.class) && adaptableObject instanceof IBuildConfiguration) { - synchronized (cache) { - IBuildConfiguration config = (IBuildConfiguration) adaptableObject; - ArduinoBuildConfiguration arduinoConfig = cache.get(config); - if (arduinoConfig == null) { - arduinoConfig = new ArduinoBuildConfiguration(config); - cache.put(config, arduinoConfig); - } - return (T) arduinoConfig; + IBuildConfiguration config = (IBuildConfiguration) adaptableObject; + ArduinoBuildConfiguration arduinoConfig = cache.get(config); + if (arduinoConfig == null) { + arduinoConfig = new ArduinoBuildConfiguration(config); + cache.put(config, arduinoConfig); } + return (T) arduinoConfig; } return null; } @@ -100,13 +105,17 @@ public class ArduinoBuildConfiguration extends CBuildConfiguration { } } - public static ArduinoBuildConfiguration getConfig(IProject project, ArduinoBoard board, IProgressMonitor monitor) - throws CoreException { + public static ArduinoBuildConfiguration getConfig(IProject project, ArduinoRemoteConnection target, + IProgressMonitor monitor) throws CoreException { + ArduinoBoard board = target.getBoard(); + // return it if it exists already for (IBuildConfiguration config : project.getBuildConfigs()) { - ArduinoBuildConfiguration arduinoConfig = config.getAdapter(ArduinoBuildConfiguration.class); - if (board.equals(arduinoConfig.getBoard())) { - return arduinoConfig; + if (!config.getName().equals(IBuildConfiguration.DEFAULT_CONFIG_NAME)) { + ArduinoBuildConfiguration arduinoConfig = config.getAdapter(ArduinoBuildConfiguration.class); + if (arduinoConfig.matches(target)) { + return arduinoConfig; + } } } @@ -128,18 +137,39 @@ public class ArduinoBuildConfiguration extends CBuildConfiguration { // set it up for the board IBuildConfiguration config = project.getBuildConfig(newName); ArduinoBuildConfiguration arduinoConfig = config.getAdapter(ArduinoBuildConfiguration.class); - arduinoConfig.setBoard(board); + arduinoConfig.setBoard(target); return arduinoConfig; } + public void setActive(IProgressMonitor monitor) throws CoreException { + IProject project = config.getProject(); + if (config.equals(project.getActiveBuildConfig())) { + // already set + return; + } + + IProjectDescription projectDesc = project.getDescription(); + projectDesc.setActiveBuildConfig(config.getName()); + project.setDescription(projectDesc, monitor); + + // Reindex - assuming for now each config has different compiler + // settings + CCorePlugin.getIndexManager().reindex(CoreModel.getDefault().create(project)); + } + + public IEclipsePreferences getSettings() { + return (IEclipsePreferences) new ProjectScope(config.getProject()).getNode(Activator.getId()).node("config") //$NON-NLS-1$ + .node(config.getName()); + } + public void setBoard(ArduinoBoard board) throws CoreException { this.board = board; ArduinoPlatform platform = board.getPlatform(); ArduinoPackage pkg = platform.getPackage(); - Preferences settings = getSettings(); + IEclipsePreferences settings = getSettings(); settings.put(PACKAGE_NAME, pkg.getName()); settings.put(PLATFORM_NAME, platform.getName()); settings.put(BOARD_NAME, board.getName()); @@ -150,37 +180,127 @@ public class ArduinoBuildConfiguration extends CBuildConfiguration { } } + public void setBoard(ArduinoRemoteConnection target) throws CoreException { + this.board = target.getBoard(); + + ArduinoPlatform platform = board.getPlatform(); + ArduinoPackage pkg = platform.getPackage(); + + IEclipsePreferences settings = getSettings(); + settings.put(PACKAGE_NAME, pkg.getName()); + settings.put(PLATFORM_NAME, platform.getName()); + settings.put(BOARD_NAME, board.getName()); + + HierarchicalProperties menus = board.getMenus(); + if (menus != null) { + for (String id : menus.getChildren().keySet()) { + String key = ArduinoBoard.MENU_QUALIFIER + id; + String value = target.getRemoteConnection().getAttribute(key); + if (value != null) { + settings.put(key, value); + } + } + } + + try { + settings.flush(); + } catch (BackingStoreException e) { + throw new CoreException(new Status(IStatus.ERROR, Activator.getId(), "Saving preferences", e)); //$NON-NLS-1$ + } + } + + public boolean matches(ArduinoRemoteConnection target) throws CoreException { + ArduinoBoard otherBoard = target.getBoard(); + if (!getBoard().equals(otherBoard)) { + return false; + } + + IEclipsePreferences settings = getSettings(); + HierarchicalProperties menus = board.getMenus(); + if (menus != null) { + for (String id : menus.getChildren().keySet()) { + String key = ArduinoBoard.MENU_QUALIFIER + id; + if (!settings.get(key, "").equals(target.getRemoteConnection().getAttribute(key))) { //$NON-NLS-1$ + return false; + } + } + } + + return true; + } + public ArduinoBoard getBoard() throws CoreException { if (board == null) { - Preferences settings = getSettings(); + IEclipsePreferences settings = getSettings(); String packageName = settings.get(PACKAGE_NAME, ""); //$NON-NLS-1$ String platformName = settings.get(PLATFORM_NAME, ""); //$NON-NLS-1$ String boardName = settings.get(BOARD_NAME, ""); //$NON-NLS-1$ - board = ArduinoManager.instance.getBoard(boardName, platformName, packageName); + board = manager.getBoard(boardName, platformName, packageName); + + if (board == null) { + // Default to Uno or first one we find + board = manager.getBoard("Arduino/Genuino Uno", "Arduino AVR Boards", "arduino"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + if (board == null) { + List boards = manager.getInstalledBoards(); + if (!boards.isEmpty()) { + board = boards.get(0); + } + } + } } return board; } - private Properties getProperties() throws CoreException { + private synchronized Properties getProperties() throws CoreException { if (properties == null) { - ArduinoBoard board = getBoard(); ArduinoPlatform platform = board.getPlatform(); - properties = board.getBoardProperties(); + + // IDE generated properties + properties = new Properties(); + properties.put("runtime.platform.path", platform.getInstallPath().toString()); //$NON-NLS-1$ + properties.put("runtime.ide.version", "10607"); //$NON-NLS-1$ //$NON-NLS-2$ + properties.put("software", "ARDUINO"); //$NON-NLS-1$ //$NON-NLS-2$ + properties.put("build.arch", platform.getArchitecture().toUpperCase()); //$NON-NLS-1$ + String configName = config.getName(); + if (configName.equals(IBuildConfiguration.DEFAULT_CONFIG_NAME)) { + configName = "default"; //$NON-NLS-1$ + } + properties.put("build.path", configName); //$NON-NLS-1$ + properties.put("build.variant.path", //$NON-NLS-1$ + platform.getInstallPath().resolve("variants").resolve("{build.variant}").toString()); //$NON-NLS-1$ //$NON-NLS-2$ + + // Platform properties.putAll(board.getPlatform().getPlatformProperties()); + + // Tools for (ToolDependency toolDep : platform.getToolsDependencies()) { properties.putAll(toolDep.getTool().getToolProperties()); } - properties.put("runtime.ide.version", "10607"); //$NON-NLS-1$ //$NON-NLS-2$ - properties.put("build.arch", platform.getArchitecture().toUpperCase()); //$NON-NLS-1$ - properties.put("build.path", getName()); //$NON-NLS-1$ + + // Board + ArduinoBoard board = getBoard(); + properties.putAll(board.getBoardProperties()); + + // Menus + IEclipsePreferences settings = getSettings(); + HierarchicalProperties menus = board.getMenus(); + if (menus != null) { + for (String menuId : menus.getChildren().keySet()) { + String value = settings.get(ArduinoBoard.MENU_QUALIFIER + menuId, ""); //$NON-NLS-1$ + if (!value.isEmpty()) { + properties.putAll(board.getMenuProperties(menuId, value)); + } + } + } } + // always do this in case the project changes names - properties.put("build.project_name", getProject().getName()); //$NON-NLS-1$ + properties.put("build.project_name", config.getProject().getName()); //$NON-NLS-1$ return properties; } public IFolder getBuildFolder() throws CoreException { - IProject project = getProject(); + IProject project = config.getProject(); return project.getFolder("build"); //$NON-NLS-1$ } @@ -196,11 +316,12 @@ public class ArduinoBuildConfiguration extends CBuildConfiguration { } public IFile generateMakeFile(IProgressMonitor monitor) throws CoreException { - final IProject project = getProject(); + final IProject project = config.getProject(); IFolder buildFolder = getBuildFolder(); if (!buildFolder.exists()) { buildFolder.create(true, true, monitor); + buildFolder.setDerived(true, monitor); ICProject cproject = CoreModel.getDefault().create(project); IOutputEntry output = CoreModel.newOutputEntry(buildFolder.getFullPath()); IPathEntry[] oldEntries = cproject.getRawPathEntries(); @@ -227,7 +348,7 @@ public class ArduinoBuildConfiguration extends CBuildConfiguration { @Override public boolean visit(IResourceProxy proxy) throws CoreException { if (proxy.getType() == IResource.FILE) { - if (CoreModel.isValidSourceUnitName(project, proxy.getName())) { + if (isSource(proxy.getName())) { Path sourcePath = new File(proxy.requestResource().getLocationURI()).toPath(); sourceFiles.add(pathString(projectPath.relativize(sourcePath))); } @@ -240,10 +361,8 @@ public class ArduinoBuildConfiguration extends CBuildConfiguration { // The list of library sources List librarySources = new ArrayList<>(); - for (ArduinoLibrary lib : ArduinoManager.instance.getLibraries(project)) { - for (Path path : lib.getSources(project)) { - librarySources.add(pathString(path)); - } + for (ArduinoLibrary lib : manager.getLibraries(project)) { + librarySources.addAll(lib.getSources()); } buildModel.put("libraries_srcs", librarySources); //$NON-NLS-1$ buildModel.put("libraries_path", pathString(ArduinoPreferences.getArduinoHome().resolve("libraries"))); //$NON-NLS-1$ //$NON-NLS-2$ @@ -263,7 +382,7 @@ public class ArduinoBuildConfiguration extends CBuildConfiguration { } includes += '"' + pathString(include) + '"'; } - for (ArduinoLibrary lib : ArduinoManager.instance.getLibraries(project)) { + for (ArduinoLibrary lib : manager.getLibraries(project)) { for (Path include : lib.getIncludePath()) { includes += " -I\"" + pathString(include) + '"'; //$NON-NLS-1$ } @@ -271,33 +390,24 @@ public class ArduinoBuildConfiguration extends CBuildConfiguration { properties.put("includes", includes); //$NON-NLS-1$ Path platformPath = platform.getInstallPath(); - buildModel.put("platform_path", pathString(platformPath)); //$NON-NLS-1$ - - Path corePath = platformPath.resolve("cores").resolve((String) properties.get("build.core")); //$NON-NLS-1$ //$NON-NLS-2$ - File[] platformFiles = corePath.toFile().listFiles(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.endsWith(".cpp") || name.endsWith(".c"); //$NON-NLS-1$ //$NON-NLS-2$ - } - }); - - String[] platformSource = new String[platformFiles.length]; - for (int i = 0; i < platformSource.length; ++i) { - platformSource[i] = pathString(platformFiles[i].toPath()); - } - buildModel.put("platform_srcs", platformSource); //$NON-NLS-1$ + buildModel.put("platform_path", pathString(platformPath).replace("+", "\\+")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + buildModel.put("platform_srcs", //$NON-NLS-1$ + platform.getSources(properties.getProperty("build.core"), properties.getProperty("build.variant"))); //$NON-NLS-1$ //$NON-NLS-2$ properties.put("object_file", "$@"); //$NON-NLS-1$ //$NON-NLS-2$ properties.put("source_file", "$<"); //$NON-NLS-1$ //$NON-NLS-2$ properties.put("archive_file", "core.a"); //$NON-NLS-1$ //$NON-NLS-2$ + properties.put("archive_file_path", "{build.path}/{archive_file}"); //$NON-NLS-1$ //$NON-NLS-2$ properties.put("object_files", "$(PROJECT_OBJS) $(LIBRARIES_OBJS)"); //$NON-NLS-1$ //$NON-NLS-2$ buildModel.put("recipe_cpp_o_pattern", resolveProperty("recipe.cpp.o.pattern", properties)); //$NON-NLS-1$ //$NON-NLS-2$ buildModel.put("recipe_c_o_pattern", resolveProperty("recipe.c.o.pattern", properties)); //$NON-NLS-1$ //$NON-NLS-2$ + buildModel.put("recipe_S_o_pattern", resolveProperty("recipe.S.o.pattern", properties)); //$NON-NLS-1$ //$NON-NLS-2$ buildModel.put("recipe_ar_pattern", resolveProperty("recipe.ar.pattern", properties)); //$NON-NLS-1$ //$NON-NLS-2$ buildModel.put("recipe_c_combine_pattern", resolveProperty("recipe.c.combine.pattern", properties)); //$NON-NLS-1$ //$NON-NLS-2$ buildModel.put("recipe_objcopy_eep_pattern", resolveProperty("recipe.objcopy.eep.pattern", properties)); //$NON-NLS-1$ //$NON-NLS-2$ buildModel.put("recipe_objcopy_hex_pattern", resolveProperty("recipe.objcopy.hex.pattern", properties)); //$NON-NLS-1$ //$NON-NLS-2$ + buildModel.put("recipe_objcopy_bin_pattern", resolveProperty("recipe.objcopy.bin.pattern", properties)); //$NON-NLS-1$ //$NON-NLS-2$ buildModel.put("recipe_size_pattern", resolveProperty("recipe.size.pattern", properties)); //$NON-NLS-1$ //$NON-NLS-2$ ArduinoTemplateGenerator templateGen = new ArduinoTemplateGenerator(); @@ -305,6 +415,19 @@ public class ArduinoBuildConfiguration extends CBuildConfiguration { return makeFile; } + public static boolean isSource(String filename) { + int i = filename.lastIndexOf('.'); + String ext = filename.substring(i + 1); + switch (ext) { + case "cpp": //$NON-NLS-1$ + case "c": //$NON-NLS-1$ + case "S": //$NON-NLS-1$ + return true; + default: + return false; + } + } + private String resolveProperty(String property, Properties dict) { String res = dict.getProperty(property); if (res == null) { @@ -332,91 +455,54 @@ public class ArduinoBuildConfiguration extends CBuildConfiguration { } public void setEnvironment(Map env) throws CoreException { - // Arduino home to find platforms and libraries - env.put("ARDUINO_HOME", pathString(ArduinoPreferences.getArduinoHome())); //$NON-NLS-1$ + // Everything is specified with full path, do not need to add anything + // to the environment. + } - // Add tools to the path - String pathKey = null; - String path = null; - for (Map.Entry entry : env.entrySet()) { - if (entry.getKey().equalsIgnoreCase("PATH")) { //$NON-NLS-1$ - pathKey = entry.getKey(); - path = entry.getValue(); - break; - } - } - - List toolPaths = new ArrayList<>(); - if (isWindows) { - // Add in the tools/make directory to pick up make - toolPaths.add(ArduinoPreferences.getArduinoHome().resolve("tools/make")); //$NON-NLS-1$ - } - ArduinoBoard board = getBoard(); - ArduinoPlatform platform = board.getPlatform(); - for (ToolDependency dep : platform.getToolsDependencies()) { - ArduinoTool tool = dep.getTool(); - Path installPath = tool.getInstallPath(); - Path binPath = installPath.resolve("bin"); //$NON-NLS-1$ - if (binPath.toFile().exists()) { - toolPaths.add(binPath); - } else { - // use the install dir by default - toolPaths.add(installPath); - } - } - for (Path toolPath : toolPaths) { - if (path != null) { - path = pathString(toolPath) + File.pathSeparatorChar + path; - } else { - path = pathString(toolPath); - } - } - if (pathKey == null) { - pathKey = "PATH"; //$NON-NLS-1$ - } - env.put(pathKey, path); + public String getMakeCommand() { + return isWindows ? ArduinoPreferences.getArduinoHome().resolve("make").toString() : "make"; //$NON-NLS-1$ //$NON-NLS-2$ } public String[] getBuildCommand() throws CoreException { - return new String[] { "make", "-f", getMakeFile().getName() }; //$NON-NLS-1$ //$NON-NLS-2$ + return new String[] { getMakeCommand(), "-f", getMakeFile().getName() }; //$NON-NLS-1$ } public String[] getCleanCommand() throws CoreException { - return new String[] { "make", "-f", getMakeFile().getName(), "clean" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + return new String[] { getMakeCommand(), "-f", getMakeFile().getName(), "clean" }; //$NON-NLS-1$ //$NON-NLS-2$ } public String[] getSizeCommand() throws CoreException { // TODO this shouldn't be in the makefile // should be like the upload command - return new String[] { "make", "-f", getMakeFile().getName(), "size" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + return new String[] { getMakeCommand(), "-f", getMakeFile().getName(), "size" }; //$NON-NLS-1$ //$NON-NLS-2$ } public String getCodeSizeRegex() throws CoreException { - return (String) getBoard().getPlatform().getPlatformProperties().getProperty("recipe.size.regex"); //$NON-NLS-1$ + return getBoard().getPlatform().getPlatformProperties().getProperty("recipe.size.regex"); //$NON-NLS-1$ } public int getMaxCodeSize() throws CoreException { - String sizeStr = (String) getBoard().getBoardProperties().getProperty("upload.maximum_size"); //$NON-NLS-1$ + String sizeStr = getProperties().getProperty("upload.maximum_size"); //$NON-NLS-1$ return sizeStr != null ? Integer.parseInt(sizeStr) : -1; } public String getDataSizeRegex() throws CoreException { - return (String) getBoard().getPlatform().getPlatformProperties().getProperty("recipe.size.regex.data"); //$NON-NLS-1$ + return getBoard().getPlatform().getPlatformProperties().getProperty("recipe.size.regex.data"); //$NON-NLS-1$ } public int getMaxDataSize() throws CoreException { - String sizeStr = (String) getBoard().getBoardProperties().getProperty("upload.maximum_data_size"); //$NON-NLS-1$ + String sizeStr = getProperties().getProperty("upload.maximum_data_size"); //$NON-NLS-1$ return sizeStr != null ? Integer.parseInt(sizeStr) : -1; } public String[] getUploadCommand(String serialPort) throws CoreException { String toolName = getProperties().getProperty("upload.tool"); //$NON-NLS-1$ - ArduinoTool tool = board.getPlatform().getTool(toolName); Properties properties = getProperties(); - properties.put("runtime.tools." + toolName + ".path", pathString(tool.getInstallPath())); //$NON-NLS-1$ //$NON-NLS-2$ + properties.put("serial.port", serialPort); //$NON-NLS-1$ - if (serialPort.startsWith("/dev/")) { + // Little bit of weirdness needed for the bossac tool + if (serialPort.startsWith("/dev/")) { //$NON-NLS-1$ properties.put("serial.port.file", serialPort.substring(5)); //$NON-NLS-1$ } else { properties.put("serial.port.file", serialPort); //$NON-NLS-1$ @@ -426,86 +512,58 @@ public class ArduinoBuildConfiguration extends CBuildConfiguration { properties.put("cmd.path", "{tools." + toolName + ".cmd.path}"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ properties.put("config.path", "{tools." + toolName + ".config.path}"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - properties.put("upload.verbose", "{tools." + toolName + ".upload.params.quiet}"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + // properties for the tool flattened + HierarchicalProperties toolsProps = new HierarchicalProperties(getBoard().getPlatform().getPlatformProperties()) + .getChild("tools"); //$NON-NLS-1$ + if (toolsProps != null) { + HierarchicalProperties toolProps = toolsProps.getChild(toolName); + if (toolProps != null) { + properties.putAll(toolProps.flatten()); + } + } - String command = resolveProperty("tools." + toolName + ".upload.pattern", properties); //$NON-NLS-1$ //$NON-NLS-2$ + // TODO make this a preference + properties.put("upload.verbose", properties.getProperty("upload.params.verbose", "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + + // TODO needed this for esptool + properties.put("upload.resetmethod", "ck"); //$NON-NLS-1$ //$NON-NLS-2$ + + String command = resolveProperty("upload.pattern", properties); //$NON-NLS-1$ + if (command == null) { + return new String[] { "command not specified" }; //$NON-NLS-1$ + } if (isWindows) { - return command.split(" "); //$NON-NLS-1$ + return splitCommand(command); } else { return new String[] { "sh", "-c", command }; //$NON-NLS-1$ //$NON-NLS-2$ } } - public IToolChain getToolChainx() { - try { - IToolChain toolChain = super.getToolChain(); - if (toolChain == null) { - // figure out which one it is - IToolChainManager toolChainManager = Activator.getService(IToolChainManager.class); - ArduinoPlatform platform = board.getPlatform(); - String compilerPath = resolveProperty("compiler.path", platform.getPlatformProperties()); //$NON-NLS-1$ - if (compilerPath != null) { - // TODO what if it is null? - Path path = Paths.get(compilerPath); - for (ToolDependency toolDep : platform.getToolsDependencies()) { - ArduinoTool tool = toolDep.getTool(); - if (path.startsWith(tool.getInstallPath())) { - } - } - } - } - return toolChain; - } catch (CoreException e) { - Activator.log(e); - return null; - } - } - - @Override - public IScannerInfo getScannerInfo(IResource resource) throws IOException { - IScannerInfo info = super.getScannerInfo(resource); - if (info == null) { - // what language is this resource and pick the right recipe - String recipe; - switch (CCorePlugin.getContentType(resource.getProject(), resource.getName()).getId()) { + public IScannerInfo getScannerInfo(IResource resource) throws CoreException { + IContentType contentType = CCorePlugin.getContentType(resource.getProject(), resource.getName()); + if (contentType != null) { + // what language is this resource and pick the right path; + switch (contentType.getId()) { case CCorePlugin.CONTENT_TYPE_CXXSOURCE: case CCorePlugin.CONTENT_TYPE_CXXHEADER: - recipe = "recipe.cpp.o.pattern"; //$NON-NLS-1$ - break; + if (cppScannerInfo == null) { + cppScannerInfo = calculateScannerInfo("recipe.cpp.o.pattern", resource); //$NON-NLS-1$ + } + return cppScannerInfo; default: - recipe = "recipe.c.o.pattern"; //$NON-NLS-1$ - } - - try { - ArduinoPlatform platform = getBoard().getPlatform(); - Properties properties = new Properties(); - properties.putAll(getProperties()); - - Path resourcePath = new File(resource.getLocationURI()).toPath(); - Path sourcePath = getBuildDirectory().toPath().relativize(resourcePath); - properties.put("source_file", pathString(sourcePath)); //$NON-NLS-1$ - properties.put("object_file", "-"); //$NON-NLS-1$ //$NON-NLS-2$ - - String includes = ""; //$NON-NLS-1$ - for (Path include : platform.getIncludePath()) { - includes += " -I\"" + pathString(include) + '"'; //$NON-NLS-1$ + if (cScannerInfo == null) { + cScannerInfo = calculateScannerInfo("recipe.c.o.pattern", resource); //$NON-NLS-1$ } - Collection libs = ArduinoManager.instance.getLibraries(getProject()); - for (ArduinoLibrary lib : libs) { - for (Path path : lib.getIncludePath()) { - includes += " -I\"" + pathString(path) + '"'; //$NON-NLS-1$ - } - } - properties.put("includes", includes); //$NON-NLS-1$ - - List cmd = Arrays.asList(resolveProperty(recipe, properties).split(" ")); //$NON-NLS-1$ - // TODO for reals - info = getToolChain().getScannerInfo(cmd.get(0), cmd.subList(1, cmd.size()), null, resource, null); - } catch (CoreException e) { - throw new IOException(e); + return cScannerInfo; } } - return info; + // use the cpp scanner info if all else fails + return cppScannerInfo; + } + + public void clearScannerInfoCache() { + cppScannerInfo = null; + cScannerInfo = null; } public static String pathString(Path path) { @@ -516,4 +574,109 @@ public class ArduinoBuildConfiguration extends CBuildConfiguration { return str; } + private IScannerInfo calculateScannerInfo(String recipe, IResource resource) throws CoreException { + try { + ArduinoPlatform platform = getBoard().getPlatform(); + Properties properties = new Properties(); + properties.putAll(getProperties()); + + Path tmpFile = Files.createTempFile("cdt", ".cpp"); //$NON-NLS-1$ //$NON-NLS-2$ + properties.put("source_file", pathString(tmpFile)); //$NON-NLS-1$ + properties.put("object_file", "-"); //$NON-NLS-1$ //$NON-NLS-2$ + + String includes = "-E -P -v -dD"; //$NON-NLS-1$ + for (Path include : platform.getIncludePath()) { + includes += " -I\"" + pathString(include) + '"'; //$NON-NLS-1$ + } + Collection libs = manager.getLibraries(config.getProject()); + for (ArduinoLibrary lib : libs) { + for (Path path : lib.getIncludePath()) { + includes += " -I\"" + pathString(path) + '"'; //$NON-NLS-1$ + } + } + properties.put("includes", includes); //$NON-NLS-1$ + + String[] command; + if (isWindows) { + command = splitCommand(resolveProperty(recipe, properties)); + } else { + command = new String[] { "sh", "-c", resolveProperty(recipe, properties) }; //$NON-NLS-1$ //$NON-NLS-2$ + } + ProcessBuilder processBuilder = new ProcessBuilder(command).directory(tmpFile.getParent().toFile()) + .redirectErrorStream(true); + setEnvironment(processBuilder.environment()); + Process process = processBuilder.start(); + + Map symbols = new HashMap<>(); + List includePath = new ArrayList<>(); + Pattern definePattern = Pattern.compile("#define (.*)\\s(.*)"); //$NON-NLS-1$ + boolean inIncludePaths = false; + try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + for (String line = reader.readLine(); line != null; line = reader.readLine()) { + if (inIncludePaths) { + if (line.equals("End of search list.")) { //$NON-NLS-1$ + inIncludePaths = false; + } else { + includePath.add(line.trim()); + } + } else if (line.startsWith("#define ")) { //$NON-NLS-1$ + Matcher matcher = definePattern.matcher(line); + if (matcher.matches()) { + symbols.put(matcher.group(1), matcher.group(2)); + } + } else if (line.equals("#include <...> search starts here:")) { //$NON-NLS-1$ + inIncludePaths = true; + } + } + } + Files.delete(tmpFile); + ExtendedScannerInfo scannerInfo = new ExtendedScannerInfo(symbols, + includePath.toArray(new String[includePath.size()])); + return scannerInfo; + } catch (IOException e) { + throw new CoreException(new Status(IStatus.ERROR, Activator.getId(), "Compiler built-ins", e)); //$NON-NLS-1$ + } + } + + private String[] splitCommand(String command) { + // TODO deal with quotes properly, for now just strip + return command.replaceAll("\"", "").split("\\s+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + public ArduinoConsoleParser[] getBuildConsoleParsers() { + // ../src/Test.cpp:4:1: error: 'x' was not declared in this scope + + return new ArduinoConsoleParser[] { new ArduinoErrorParser("(.*?):(\\d+):(\\d+:)? (fatal )?error: (.*)") { //$NON-NLS-1$ + @Override + protected int getSeverity(Matcher matcher) { + return IMarker.SEVERITY_ERROR; + } + + @Override + protected String getMessage(Matcher matcher) { + return matcher.group(matcher.groupCount()); + } + + @Override + protected int getLineNumber(Matcher matcher) { + return Integer.parseInt(matcher.group(2)); + } + + @Override + protected String getFileName(Matcher matcher) { + return matcher.group(1); + } + + @Override + protected int getLinkOffset(Matcher matcher) { + return 0; + } + + @Override + protected int getLinkLength(Matcher matcher) { + return matcher.group(1).length() + 1 + matcher.group(2).length() + 1 + matcher.group(3).length(); + } + } }; + } + } diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/build/ArduinoBuilder.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/build/ArduinoBuilder.java index a3a907ed17c..18753269114 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/build/ArduinoBuilder.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/build/ArduinoBuilder.java @@ -15,8 +15,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.cdt.arduino.core.internal.Activator; -import org.eclipse.cdt.build.core.CConsoleParser; -import org.eclipse.cdt.build.core.IConsoleService; +import org.eclipse.cdt.arduino.core.internal.console.ArduinoConsoleService; import org.eclipse.cdt.core.model.ICModelMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; @@ -27,8 +26,7 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; /** - * This class is responsible for generating the Makefile for the current build - * config. + * This class is responsible for generating the Makefile for the current build config. */ public class ArduinoBuilder extends IncrementalProjectBuilder { @@ -40,8 +38,8 @@ public class ArduinoBuilder extends IncrementalProjectBuilder { try { project.deleteMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE); - IConsoleService consoleService = Activator.getService(IConsoleService.class); - consoleService.writeOutput(String.format("Building %s\n", project.getName())); + ArduinoConsoleService consoleService = Activator.getConsoleService(); + consoleService.writeOutput(String.format("\nBuilding %s\n", project.getName())); ArduinoBuildConfiguration config = getBuildConfig().getAdapter(ArduinoBuildConfiguration.class); config.generateMakeFile(monitor); @@ -51,17 +49,15 @@ public class ArduinoBuilder extends IncrementalProjectBuilder { config.setEnvironment(processBuilder.environment()); Process process = processBuilder.start(); - consoleService.monitor(process, config.getConsoleParsers().toArray(new CConsoleParser[0]), - config.getBuildDirectory().toPath()); + consoleService.monitor(process, config.getBuildConsoleParsers(), config.getBuildFolder()); if (process.exitValue() == 0) { showSizes(config, consoleService); } config.getBuildFolder().refreshLocal(IResource.DEPTH_INFINITE, monitor); - consoleService.writeOutput("\n"); //$NON-NLS-1$ } catch (IOException e) { - throw new CoreException(new Status(IStatus.ERROR, Activator.getId(), "Build error", e)); //$NON-NLS-1$ + throw new CoreException(new Status(IStatus.ERROR, Activator.getId(), "Build error", e)); } // TODO if there are references we want to watch, return them here @@ -74,8 +70,8 @@ public class ArduinoBuilder extends IncrementalProjectBuilder { IProject project = getProject(); project.deleteMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE); - IConsoleService consoleService = Activator.getService(IConsoleService.class); - consoleService.writeOutput(String.format("Cleaning %s\n", project.getName())); + ArduinoConsoleService consoleService = Activator.getConsoleService(); + consoleService.writeOutput(String.format("\nCleaning %s\n", project.getName())); ArduinoBuildConfiguration config = getBuildConfig().getAdapter(ArduinoBuildConfiguration.class); @@ -84,17 +80,15 @@ public class ArduinoBuilder extends IncrementalProjectBuilder { config.setEnvironment(processBuilder.environment()); Process process = processBuilder.start(); - consoleService.monitor(process, config.getConsoleParsers().toArray(new CConsoleParser[0]), - config.getBuildDirectory().toPath()); + consoleService.monitor(process, config.getBuildConsoleParsers(), config.getBuildFolder()); config.getBuildFolder().refreshLocal(IResource.DEPTH_INFINITE, monitor); - consoleService.writeOutput("\n"); //$NON-NLS-1$ } catch (IOException e) { - throw new CoreException(new Status(IStatus.ERROR, Activator.getId(), "Build error", e)); //$NON-NLS-1$ + throw new CoreException(new Status(IStatus.ERROR, Activator.getId(), "Build error", e)); } } - private void showSizes(ArduinoBuildConfiguration config, IConsoleService console) throws CoreException { + private void showSizes(ArduinoBuildConfiguration config, ArduinoConsoleService console) throws CoreException { try { int codeSize = -1; int dataSize = -1; @@ -102,7 +96,7 @@ public class ArduinoBuilder extends IncrementalProjectBuilder { String codeSizeRegex = config.getCodeSizeRegex(); Pattern codeSizePattern = codeSizeRegex != null ? Pattern.compile(codeSizeRegex) : null; String dataSizeRegex = config.getDataSizeRegex(); - Pattern dataSizePattern = codeSizeRegex != null ? Pattern.compile(dataSizeRegex) : null; + Pattern dataSizePattern = dataSizeRegex != null ? Pattern.compile(dataSizeRegex) : null; if (codeSizePattern == null && dataSizePattern == null) { return; @@ -138,11 +132,13 @@ public class ArduinoBuilder extends IncrementalProjectBuilder { } console.writeOutput(" bytes\n"); - console.writeOutput("Initial RAM usage: " + dataSize); - if (maxCodeSize > 0) { - console.writeOutput(" of maximum " + maxDataSize); + if (maxDataSize >= 0) { + console.writeOutput("Initial RAM usage: " + dataSize); + if (maxCodeSize > 0) { + console.writeOutput(" of maximum " + maxDataSize); + } + console.writeOutput(" bytes\n"); } - console.writeOutput(" bytes\n"); } catch (IOException e) { throw new CoreException(new Status(IStatus.ERROR, Activator.getId(), "Checking sizes", e)); } diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/console/ArduinoConsoleParser.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/console/ArduinoConsoleParser.java new file mode 100644 index 00000000000..582a7f485c7 --- /dev/null +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/console/ArduinoConsoleParser.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.arduino.core.internal.console; + +public abstract class ArduinoConsoleParser { + + private final String pattern; + private final int flags; + private final String lineQualifier; + + protected ArduinoConsoleParser(String pattern, int flags, String lineQualifier) { + this.pattern = pattern; + this.flags = flags; + this.lineQualifier = lineQualifier; + } + + /** + * Returns the pattern to be used for matching. The pattern is a string + * representing a regular expression. + * + * @return the regular expression to be used for matching + */ + public String getPattern() { + return pattern; + } + + /** + * Returns the flags to use when compiling this pattern match listener's + * regular expression, as defined by by + * Pattern.compile(String regex, int flags) + * + * @return the flags to use when compiling this pattern match listener's + * regular expression + * @see java.util.regex.Pattern#compile(java.lang.String, int) + */ + public int getCompilerFlags() { + return flags; + } + + /** + * Returns a simple regular expression used to identify lines that may match + * this pattern matcher's complete pattern, or null. Use of + * this attribute can improve performance by disqualifying lines from the + * search. When a line is found containing a match for this expression, the + * line is searched from the beginning for this pattern matcher's complete + * pattern. Lines not containing this pattern are discarded. + * + * @return a simple regular expression used to identify lines that may match + * this pattern matcher's complete pattern, or null + */ + public String getLineQualifier() { + return lineQualifier; + } + +} diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/console/ArduinoConsoleService.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/console/ArduinoConsoleService.java new file mode 100644 index 00000000000..5ac7dba8731 --- /dev/null +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/console/ArduinoConsoleService.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.arduino.core.internal.console; + +import java.io.IOException; + +import org.eclipse.core.resources.IFolder; + +public interface ArduinoConsoleService { + + void monitor(Process process, ArduinoConsoleParser[] consoleParsers, IFolder buildDirectory) throws IOException; + + void writeOutput(String msg) throws IOException; + + void writeError(String msg) throws IOException; + +} diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/console/ArduinoErrorParser.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/console/ArduinoErrorParser.java new file mode 100644 index 00000000000..4adaac9fc85 --- /dev/null +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/console/ArduinoErrorParser.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.arduino.core.internal.console; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.cdt.arduino.core.internal.Activator; +import org.eclipse.cdt.core.model.ICModelMarker; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; + +public abstract class ArduinoErrorParser extends ArduinoConsoleParser { + + public static final String LINK_OFFSET = "arduino.link.offset"; //$NON-NLS-1$ + public static final String LINK_LENGTH = "arduino.link.length"; //$NON-NLS-1$ + + private final Pattern errorPattern; + + public ArduinoErrorParser(String pattern, int flags, String lineQualifier) { + super(pattern, flags, lineQualifier); + this.errorPattern = Pattern.compile(pattern); + } + + public ArduinoErrorParser(String pattern) { + this(pattern, 0, null); + } + + protected abstract String getFileName(Matcher matcher); + + protected abstract int getLineNumber(Matcher matcher); + + protected abstract String getMessage(Matcher matcher); + + protected abstract int getSeverity(Matcher matcher); + + protected abstract int getLinkOffset(Matcher matcher); + + protected abstract int getLinkLength(Matcher matcher); + + public IMarker generateMarker(IFolder buildDirectory, String text) throws CoreException { + Matcher matcher = errorPattern.matcher(text); + if (matcher.matches()) { + String fileName = getFileName(matcher); + + IFile file = buildDirectory.getFile(fileName); + if (file.exists()) { + for (IMarker marker : file.findMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, false, + IResource.DEPTH_ZERO)) { + if (marker.getAttribute(IMarker.SEVERITY, -1) == getSeverity(matcher) + && marker.getAttribute(IMarker.LINE_NUMBER, -1) == getLineNumber(matcher) + && marker.getAttribute(IMarker.MESSAGE, "").equals(getMessage(matcher))) { //$NON-NLS-1$ + return marker; + } + } + try { + IMarker marker = file.createMarker(ICModelMarker.C_MODEL_PROBLEM_MARKER); + marker.setAttribute(IMarker.MESSAGE, getMessage(matcher)); + marker.setAttribute(IMarker.SEVERITY, getSeverity(matcher)); + marker.setAttribute(IMarker.LINE_NUMBER, getLineNumber(matcher)); + marker.setAttribute(IMarker.CHAR_START, -1); + marker.setAttribute(IMarker.CHAR_END, -1); + marker.setAttribute(LINK_OFFSET, getLinkOffset(matcher)); + marker.setAttribute(LINK_LENGTH, getLinkLength(matcher)); + return marker; + } catch (CoreException e) { + Activator.log(e); + return null; + } + } + } + return null; + } + +} diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/launch/ArduinoLaunch.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/launch/ArduinoLaunch.java new file mode 100644 index 00000000000..51d64d38b0b --- /dev/null +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/launch/ArduinoLaunch.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.arduino.core.internal.launch; + +import org.eclipse.cdt.arduino.core.internal.remote.ArduinoRemoteConnection; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.model.ISourceLocator; +import org.eclipse.launchbar.core.target.ILaunchTarget; +import org.eclipse.launchbar.core.target.launch.TargetedLaunch; +import org.eclipse.remote.core.IRemoteConnection; + +public class ArduinoLaunch extends TargetedLaunch { + + private final ArduinoRemoteConnection remote; + private boolean wasOpen; + + public ArduinoLaunch(ILaunchConfiguration launchConfiguration, String mode, ISourceLocator locator, + ILaunchTarget target) { + super(launchConfiguration, mode, target, locator); + IRemoteConnection connection = target.getAdapter(IRemoteConnection.class); + this.remote = connection.getService(ArduinoRemoteConnection.class); + + DebugPlugin.getDefault().addDebugEventListener(this); + } + + public void start() { + this.wasOpen = remote.getRemoteConnection().isOpen(); + if (wasOpen) { + remote.pause(); + } + } + + @Override + public void handleDebugEvents(DebugEvent[] events) { + super.handleDebugEvents(events); + if (isTerminated() && wasOpen) { + remote.resume(); + wasOpen = false; + } + } + +} diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/launch/ArduinoLaunchConfigurationDelegate.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/launch/ArduinoLaunchConfigurationDelegate.java index 10df23e55ad..62d40b43b40 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/launch/ArduinoLaunchConfigurationDelegate.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/launch/ArduinoLaunchConfigurationDelegate.java @@ -14,53 +14,48 @@ import java.io.IOException; import org.eclipse.cdt.arduino.core.internal.Activator; import org.eclipse.cdt.arduino.core.internal.Messages; -import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoard; import org.eclipse.cdt.arduino.core.internal.build.ArduinoBuildConfiguration; import org.eclipse.cdt.arduino.core.internal.remote.ArduinoRemoteConnection; -import org.eclipse.cdt.build.core.IConsoleService; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; -import org.eclipse.debug.core.model.LaunchConfigurationDelegate; +import org.eclipse.launchbar.core.target.ILaunchTarget; +import org.eclipse.launchbar.core.target.launch.ITargetedLaunch; +import org.eclipse.launchbar.core.target.launch.LaunchConfigurationTargetedDelegate; import org.eclipse.remote.core.IRemoteConnection; -import org.eclipse.remote.core.IRemoteConnectionType; -import org.eclipse.remote.core.IRemoteServicesManager; -public class ArduinoLaunchConfigurationDelegate extends LaunchConfigurationDelegate { +public class ArduinoLaunchConfigurationDelegate extends LaunchConfigurationTargetedDelegate { public static final String TYPE_ID = "org.eclipse.cdt.arduino.core.launchConfigurationType"; //$NON-NLS-1$ public static final String CONNECTION_NAME = Activator.getId() + ".connectionName"; //$NON-NLS-1$ - private static IRemoteConnection getTarget(ILaunchConfiguration configuration) throws CoreException { - IRemoteServicesManager remoteManager = Activator.getService(IRemoteServicesManager.class); - IRemoteConnectionType connectionType = remoteManager.getConnectionType(ArduinoRemoteConnection.TYPE_ID); - String connectionName = configuration.getAttribute(CONNECTION_NAME, ""); //$NON-NLS-1$ - return connectionType.getConnection(connectionName); + @Override + public ITargetedLaunch getLaunch(ILaunchConfiguration configuration, String mode, ILaunchTarget target) + throws CoreException { + return new ArduinoLaunch(configuration, mode, null, target); } @Override - public boolean buildForLaunch(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) - throws CoreException { - IRemoteConnection target = getTarget(configuration); + public boolean buildForLaunch(ILaunchConfiguration configuration, String mode, ILaunchTarget target, + IProgressMonitor monitor) throws CoreException { + IRemoteConnection connection = target.getAdapter(IRemoteConnection.class); if (target != null) { - ArduinoRemoteConnection arduinoTarget = target.getService(ArduinoRemoteConnection.class); - ArduinoBoard targetBoard = arduinoTarget.getBoard(); + ArduinoRemoteConnection arduinoTarget = connection.getService(ArduinoRemoteConnection.class); // 1. make sure proper build config is set active IProject project = configuration.getMappedResources()[0].getProject(); - ArduinoBuildConfiguration arduinoConfig = ArduinoBuildConfiguration.getConfig(project, targetBoard, + ArduinoBuildConfiguration arduinoConfig = ArduinoBuildConfiguration.getConfig(project, arduinoTarget, monitor); arduinoConfig.setActive(monitor); } // 2. Run the build - return super.buildForLaunch(configuration, mode, monitor); + return super.buildForLaunch(configuration, mode, target, monitor); } @Override @@ -73,61 +68,40 @@ public class ArduinoLaunchConfigurationDelegate extends LaunchConfigurationDeleg @Override public void launch(final ILaunchConfiguration configuration, String mode, final ILaunch launch, IProgressMonitor monitor) throws CoreException { - new Job(Messages.ArduinoLaunchConfigurationDelegate_0) { - protected IStatus run(IProgressMonitor monitor) { - try { - IConsoleService consoleService = Activator.getService(IConsoleService.class); - IRemoteConnection target = getTarget(configuration); - if (target == null) { - return new Status(IStatus.ERROR, Activator.getId(), - Messages.ArduinoLaunchConfigurationDelegate_2); - } - ArduinoRemoteConnection arduinoTarget = target.getService(ArduinoRemoteConnection.class); + try { + ILaunchTarget target = ((ITargetedLaunch) launch).getLaunchTarget(); + IRemoteConnection connection = target.getAdapter(IRemoteConnection.class); + if (connection == null) { + throw new CoreException( + new Status(IStatus.ERROR, Activator.getId(), Messages.ArduinoLaunchConfigurationDelegate_2)); + } + ArduinoRemoteConnection arduinoTarget = connection.getService(ArduinoRemoteConnection.class); - // The project - IProject project = (IProject) configuration.getMappedResources()[0]; + // The project + IProject project = (IProject) configuration.getMappedResources()[0]; - // The build config - ArduinoBuildConfiguration arduinoConfig = ArduinoBuildConfiguration.getConfig(project, - arduinoTarget.getBoard(), monitor); - String[] uploadCmd = arduinoConfig.getUploadCommand(arduinoTarget.getPortName()); + // The build config + ArduinoBuildConfiguration arduinoConfig = ArduinoBuildConfiguration.getConfig(project, arduinoTarget, + monitor); + String[] uploadCmd = arduinoConfig.getUploadCommand(arduinoTarget.getPortName()); - // If opened, temporarily close the connection so we can use - // it to download the firmware. - boolean wasOpened = target.isOpen(); - if (wasOpened) { - arduinoTarget.pause(); - } + StringBuffer cmdStr = new StringBuffer(uploadCmd[0]); + for (int i = 1; i < uploadCmd.length; ++i) { + cmdStr.append(' '); + cmdStr.append(uploadCmd[i]); + } + // Start the launch + ((ArduinoLaunch) launch).start(); - // Run the process and capture the results in the console - ProcessBuilder processBuilder = new ProcessBuilder(uploadCmd) - .directory(arduinoConfig.getBuildDirectory()); - arduinoConfig.setEnvironment(processBuilder.environment()); - Process process = processBuilder.start(); + // Run the process and capture the results in the console + ProcessBuilder processBuilder = new ProcessBuilder(uploadCmd).directory(arduinoConfig.getBuildDirectory()); + arduinoConfig.setEnvironment(processBuilder.environment()); + Process process = processBuilder.start(); + DebugPlugin.newProcess(launch, process, cmdStr.toString()); + } catch (IOException e) { + throw new CoreException(new Status(IStatus.ERROR, Activator.getId(), e.getLocalizedMessage(), e)); + } - consoleService.monitor(process, null, null); - try { - process.waitFor(); - } catch (InterruptedException e) { - } - - consoleService.writeOutput("Upload complete\n"); - - // Reopen the connection - if (wasOpened) { - arduinoTarget.resume(); - } - } catch (CoreException e) { - return e.getStatus(); - } catch (IOException e) { - return new Status(IStatus.ERROR, Activator.getId(), e.getLocalizedMessage(), e); - } finally { - DebugPlugin.getDefault().getLaunchManager().removeLaunch(launch); - } - - return Status.OK_STATUS; - }; - }.schedule(); } } diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/launch/ArduinoLaunchConfigurationProvider.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/launch/ArduinoLaunchConfigurationProvider.java index 71db1a293db..9858f1ba956 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/launch/ArduinoLaunchConfigurationProvider.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/launch/ArduinoLaunchConfigurationProvider.java @@ -10,21 +10,25 @@ *******************************************************************************/ package org.eclipse.cdt.arduino.core.internal.launch; -import org.eclipse.cdt.arduino.core.internal.Activator; -import org.eclipse.cdt.arduino.core.internal.ArduinoProjectNature; import org.eclipse.cdt.arduino.core.internal.remote.ArduinoRemoteConnection; -import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.DebugPlugin; -import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationType; -import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.launchbar.core.ILaunchDescriptor; -import org.eclipse.launchbar.core.ProjectPerTargetLaunchConfigProvider; +import org.eclipse.launchbar.core.ProjectLaunchConfigProvider; import org.eclipse.launchbar.core.target.ILaunchTarget; -import org.eclipse.launchbar.core.target.ILaunchTargetManager; +import org.eclipse.remote.core.IRemoteConnection; -public class ArduinoLaunchConfigurationProvider extends ProjectPerTargetLaunchConfigProvider { +public class ArduinoLaunchConfigurationProvider extends ProjectLaunchConfigProvider { + + @Override + public boolean supports(ILaunchDescriptor descriptor, ILaunchTarget target) throws CoreException { + IRemoteConnection connection = target.getAdapter(IRemoteConnection.class); + if (connection != null) { + return connection.getConnectionType().getId().equals(ArduinoRemoteConnection.TYPE_ID); + } + return false; + } @Override public ILaunchConfigurationType getLaunchConfigurationType(ILaunchDescriptor descriptor, ILaunchTarget target) @@ -33,43 +37,4 @@ public class ArduinoLaunchConfigurationProvider extends ProjectPerTargetLaunchCo .getLaunchConfigurationType(ArduinoLaunchConfigurationDelegate.TYPE_ID); } - @Override - public boolean supports(ILaunchDescriptor descriptor, ILaunchTarget target) throws CoreException { - if (!super.supports(descriptor, target)) { - return false; - } - - if (target != null && !target.getTypeId().equals(ArduinoRemoteConnection.TYPE_ID)) { - return false; - } - - // must have the arduino nature - IProject project = descriptor.getAdapter(IProject.class); - return ArduinoProjectNature.hasNature(project); - } - - @Override - protected void populateLaunchConfiguration(ILaunchDescriptor descriptor, ILaunchTarget target, - ILaunchConfigurationWorkingCopy workingCopy) throws CoreException { - super.populateLaunchConfiguration(descriptor, target, workingCopy); - if (target != null) { - workingCopy.setAttribute(ArduinoLaunchConfigurationDelegate.CONNECTION_NAME, target.getName()); - } - } - - @Override - protected ILaunchTarget getLaunchTarget(ILaunchConfiguration configuration) throws CoreException { - String name = configuration.getAttribute(ArduinoLaunchConfigurationDelegate.CONNECTION_NAME, ""); //$NON-NLS-1$ - if (name.isEmpty()) { - return null; - } - ILaunchTargetManager manager = Activator.getService(ILaunchTargetManager.class); - return manager.getLaunchTarget(ArduinoRemoteConnection.TYPE_ID, name); - } - - @Override - protected boolean providesForNullTarget() { - return true; - } - } diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/messages.properties b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/messages.properties index 5fe757de17a..758925d16ab 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/messages.properties +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/messages.properties @@ -10,4 +10,9 @@ ArduinoBoardManager_1=Package index missing from response ArduinoLaunchConfigurationDelegate_1=No active Arduino remote connection. ArduinoLaunchConfigurationDelegate_0=Arduino Launch ArduinoLaunchConfigurationDelegate_2=Target has not been selected for Launch Configuration +ArduinoManager_0=Install libraries +ArduinoManager_1=Installing libraries +ArduinoManager_2=Download failed, please try again. +ArduinoPlatform_0=Download failed, please try again. +ArduinoPlatform_1=Uninstall failed. ArduinoProjectGenerator_0=Write Arduino project file diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/remote/ArduinoLaunchTargetProvider.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/remote/ArduinoLaunchTargetProvider.java deleted file mode 100644 index f2acfb371f9..00000000000 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/remote/ArduinoLaunchTargetProvider.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.eclipse.cdt.arduino.core.internal.remote; - -import org.eclipse.cdt.arduino.core.internal.Activator; -import org.eclipse.launchbar.core.target.ILaunchTarget; -import org.eclipse.launchbar.core.target.ILaunchTargetManager; -import org.eclipse.launchbar.core.target.ILaunchTargetProvider; -import org.eclipse.launchbar.core.target.TargetStatus; -import org.eclipse.launchbar.core.target.TargetStatus.Code; -import org.eclipse.remote.core.IRemoteConnection; -import org.eclipse.remote.core.IRemoteConnectionType; -import org.eclipse.remote.core.IRemoteServicesManager; - -public class ArduinoLaunchTargetProvider implements ILaunchTargetProvider { - - @Override - public void init(ILaunchTargetManager targetManager) { - IRemoteServicesManager remoteManager = Activator.getService(IRemoteServicesManager.class); - IRemoteConnectionType remoteType = remoteManager.getConnectionType(ArduinoRemoteConnection.TYPE_ID); - - // remove any targets that don't have connections - for (ILaunchTarget target : targetManager.getLaunchTargetsOfType(ArduinoRemoteConnection.TYPE_ID)) { - if (remoteType.getConnection(target.getName()) == null) { - targetManager.removeLaunchTarget(target); - } - } - - // add any targets that are missing - for (IRemoteConnection connection : remoteType.getConnections()) { - if (targetManager.getLaunchTarget(ArduinoRemoteConnection.TYPE_ID, connection.getName()) == null) { - targetManager.addLaunchTarget(ArduinoRemoteConnection.TYPE_ID, connection.getName()); - } - } - } - - @Override - public TargetStatus getStatus(ILaunchTarget target) { - ArduinoRemoteConnection connection = target.getAdapter(ArduinoRemoteConnection.class); - if (connection.getRemoteConnection().isOpen()) { - return TargetStatus.OK_STATUS; - } else { - return new TargetStatus(Code.ERROR, "Not connected"); - } - } - -} diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/remote/ArduinoRemoteConnection.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/remote/ArduinoRemoteConnection.java index 2106c0f9f79..f66344b7fef 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/remote/ArduinoRemoteConnection.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/remote/ArduinoRemoteConnection.java @@ -31,10 +31,10 @@ public class ArduinoRemoteConnection implements IRemoteConnectionPropertyService, IRemoteCommandShellService, IRemoteConnectionChangeListener { public static final String TYPE_ID = "org.eclipse.cdt.arduino.core.connectionType"; //$NON-NLS-1$ - public static final String PORT_NAME = "ardiuno.portname"; //$NON-NLS-1$ - public static final String PACKAGE_NAME = "packageName"; //$NON-NLS-1$ - public static final String PLATFORM_NAME = "platformName"; //$NON-NLS-1$ - public static final String BOARD_NAME = "boardName"; //$NON-NLS-1$ + public static final String PORT_NAME = "arduinoPortName"; //$NON-NLS-1$ + public static final String PACKAGE_NAME = "arduinoPackageName"; //$NON-NLS-1$ + public static final String PLATFORM_NAME = "arduinoPlatformName"; //$NON-NLS-1$ + public static final String BOARD_NAME = "arduinoBoardName"; //$NON-NLS-1$ private final IRemoteConnection remoteConnection; private SerialPort serialPort; @@ -95,7 +95,7 @@ public class ArduinoRemoteConnection } public ArduinoBoard getBoard() throws CoreException { - return ArduinoManager.instance.getBoard(remoteConnection.getAttribute(BOARD_NAME), + return Activator.getService(ArduinoManager.class).getBoard(remoteConnection.getAttribute(BOARD_NAME), remoteConnection.getAttribute(PLATFORM_NAME), remoteConnection.getAttribute(PACKAGE_NAME)); } diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/remote/ArduinoRemoteConnectionListener.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/remote/ArduinoRemoteConnectionListener.java deleted file mode 100644 index a031393ae27..00000000000 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/remote/ArduinoRemoteConnectionListener.java +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - *******************************************************************************/ -package org.eclipse.cdt.arduino.core.internal.remote; - -import org.eclipse.cdt.arduino.core.internal.Activator; -import org.eclipse.launchbar.core.target.ILaunchTarget; -import org.eclipse.launchbar.core.target.ILaunchTargetManager; -import org.eclipse.remote.core.IRemoteConnectionChangeListener; -import org.eclipse.remote.core.RemoteConnectionChangeEvent; - -public class ArduinoRemoteConnectionListener implements IRemoteConnectionChangeListener { - - public static ArduinoRemoteConnectionListener INSTANCE = new ArduinoRemoteConnectionListener(); - - @Override - public void connectionChanged(RemoteConnectionChangeEvent event) { - switch (event.getType()) { - case RemoteConnectionChangeEvent.CONNECTION_ADDED: - if (event.getConnection().getConnectionType().getId().equals(ArduinoRemoteConnection.TYPE_ID)) { - ILaunchTargetManager targetManager = Activator.getService(ILaunchTargetManager.class); - targetManager.addLaunchTarget(ArduinoRemoteConnection.TYPE_ID, event.getConnection().getName()); - } - case RemoteConnectionChangeEvent.CONNECTION_REMOVED: - if (event.getConnection().getConnectionType().getId().equals(ArduinoRemoteConnection.TYPE_ID)) { - ILaunchTargetManager targetManager = Activator.getService(ILaunchTargetManager.class); - ILaunchTarget target = targetManager.getLaunchTarget(ArduinoRemoteConnection.TYPE_ID, - event.getConnection().getName()); - if (target != null) { - targetManager.removeLaunchTarget(target); - } - } - } - } - -} diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/remote/ArduinoTargetAdapterFactory.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/remote/ArduinoTargetAdapterFactory.java deleted file mode 100644 index e7734e3481c..00000000000 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/remote/ArduinoTargetAdapterFactory.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.eclipse.cdt.arduino.core.internal.remote; - -import org.eclipse.cdt.arduino.core.internal.Activator; -import org.eclipse.core.runtime.IAdapterFactory; -import org.eclipse.launchbar.core.target.ILaunchTarget; -import org.eclipse.remote.core.IRemoteConnection; -import org.eclipse.remote.core.IRemoteConnectionType; -import org.eclipse.remote.core.IRemoteServicesManager; - -public class ArduinoTargetAdapterFactory implements IAdapterFactory { - - private IRemoteServicesManager remoteManager = Activator.getService(IRemoteServicesManager.class); - - @Override - @SuppressWarnings("unchecked") - public T getAdapter(Object adaptableObject, Class adapterType) { - if (adaptableObject instanceof ILaunchTarget) { - ILaunchTarget target = (ILaunchTarget) adaptableObject; - if (target.getTypeId().equals(ArduinoRemoteConnection.TYPE_ID)) { - IRemoteConnectionType connectionType = remoteManager.getConnectionType(target.getTypeId()); - IRemoteConnection connection = connectionType.getConnection(target.getName()); - if (connection != null) { - return (T) connection.getService(ArduinoRemoteConnection.class); - } - } - } - return null; - } - - @Override - public Class[] getAdapterList() { - return new Class[] { ArduinoRemoteConnection.class }; - } - -} diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/templates/arduino.mk b/toolchains/arduino/org.eclipse.cdt.arduino.core/templates/arduino.mk deleted file mode 100644 index ea72dbc6427..00000000000 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/templates/arduino.mk +++ /dev/null @@ -1,160 +0,0 @@ -ifeq ($(BOARD),uno) -ARCH = avr -BUILD_CORE = arduino -BUILD_VARIANT = standard -BUILD_MCU = atmega328p -BUILD_F_CPU = 16000000L -BUILD_BOARD = AVR_UNO -LOADER = avrdude -LOADER_PROTOCOL = arduino -LOADER_SPEED = 115200 -LOADER_MAX_SIZE = 32256 -LOADER_MAX_DATA = 2048 -endif - -VERSION = 164 - -ifeq ($(ARCH),avr) -CXXFLAGS = -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -MMD \ - -mmcu=$(BUILD_MCU) -DF_CPU=$(BUILD_F_CPU) -DARDUINO=$(VERSION) -DARDUINO_$(BUILD_BOARD) -DARDUINO_ARCH_AVR $(INCLUDES) -CFLAGS = -g -Os -w -ffunction-sections -fdata-sections -MMD \ - -mmcu=$(BUILD_MCU) -DF_CPU=$(BUILD_F_CPU) -DARDUINO=156 -DARDUINO_$(BUILD_BOARD) -DARDUINO_ARCH_AVR $(INCLUDES) - -CXX = avr-g++ -CC = avr-gcc -AR = avr-ar -OBJCOPY = avr-objcopy - -define do_link -$(CC) -Os -Wl,--gc-sections -mmcu=$(BUILD_MCU) -o $(OUTPUT_DIR)/$(EXE).elf $^ -avr-objcopy -O ihex -R .eeprom $(OUTPUT_DIR)/$(EXE).elf $(OUTPUT_DIR)/$(EXE).hex -$(do_link_extra) -avr-size $(OUTPUT_DIR)/$(EXE).elf -@echo Max text: $(LOADER_MAX_SIZE) -@echo Max data + bss: $(LOADER_MAX_DATA) -endef - -define do_eeprom -avr-objcopy -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load \ - --no-change-warnings --change-section-lma .eeprom=0 \ - $(OUTPUT_DIR)/$(EXE).elf $(OUTPUT_DIR)/$(EXE).eep -endef - -define do_load_avrdude -avrdude -C"$(ARDUINO_HOME)/hardware/tools/avr/etc/avrdude.conf" -p$(BUILD_MCU) -c$(LOADER_PROTOCOL) \ - -P$(SERIAL_PORT) -b$(LOADER_SPEED) -D "-Uflash:w:$(OUTPUT_DIR)/$(EXE).hex:i" -endef - -endif # ARCH = avr - -space := -space += -spacify = $(subst $(space),\$(space),$1) - -ifeq ($(OS),Windows_NT) -RMDIR = rmdir /s /q -fixpath = $(subst /,\,$1) -mymkdir = if not exist "$(call fixpath,$1)" mkdir $(call fixpath,$1) -else -RMDIR = rm -fr -fixpath = $1 -mymkdir = mkdir -p $1 -endif - -src_recurse = $(foreach d,$(subst $2/,,$(wildcard $1*)),$(call src_recurse,$3/$d/,$2,$3) $(filter %.c %.cpp,$d)) -src = $(foreach lib,$3,$(if $(wildcard $2/$(lib)/src),$(call src_recurse,$2/$(lib)/src/,$1,$2),\ - $(subst $1/,,\ - $(wildcard $2/$(lib)/*.c)\ - $(wildcard $2/$(lib)/*.cpp)\ - $(wildcard $2/$(lib)/utility/*.c)\ - $(wildcard $2/$(lib)/utility/*.cpp))))) -objs = $(patsubst %.c,$2/%.o,$(filter %.c,$1)) $(patsubst %.cpp,$2/%.o,$(filter %.cpp,$1)) -incs = $(foreach lib,$1,$(if $(wildcard $3/$(lib)/src),-I"$2/$(lib)/src",-I"$2/$(lib)" -I"$2/$(lib)/utility")) - -PROJECT_OBJS = $(call objs,$(call src_recurse,./,.,.),$(OUTPUT_DIR)/src) - -LIB_ROOT = $(ARDUINO_HOME)/hardware/arduino/$(ARCH)/cores/$(BUILD_CORE) -LIB_ROOT_SPC = $(call spacify,$(LIB_ROOT)) -LIB_ROOT_SPC2 = $(subst :,\:,$(subst \,\\\,$(LIB_ROOT_SPC))) -LIB_OBJS = $(call objs,$(call src_recurse,$(LIB_ROOT_SPC)/,$(LIB_ROOT),$(LIB_ROOT_SPC)),$(OUTPUT_DIR)/lib) - -USER_LIB_ROOT = $(ARDUINO_USER_LIBS) -USER_LIB_ROOT_SPC = $(call spacify,$(USER_LIB_ROOT)) -USER_LIB_ROOT_SPC2 = $(subst :,\:,$(subst \,\\\,$(USER_LIB_ROOT_SPC))) -USER_LIBS = $(foreach lib,$(LIBS),$(subst $(USER_LIB_ROOT)/,,$(wildcard $(USER_LIB_ROOT_SPC)/$(lib)))) -USER_INCLUDES = $(call incs,$(USER_LIBS),$(USER_LIB_ROOT),$(USER_LIB_ROOT_SPC)) -USER_OBJS = $(call objs,$(call src,$(USER_LIB_ROOT),$(USER_LIB_ROOT_SPC),$(USER_LIBS)),$(OUTPUT_DIR)/user) - -HW_LIB_ROOT = $(ARDUINO_HOME)/hardware/arduino/$(ARCH)/libraries -HW_LIB_ROOT_SPC = $(call spacify,$(HW_LIB_ROOT)) -HW_LIB_ROOT_SPC2 = $(subst :,\:,$(subst \,\\\,$(HW_LIB_ROOT_SPC))) -HW_LIBS = $(foreach lib, $(LIBS), $(subst $(HW_LIB_ROOT)/,,$(wildcard $(HW_LIB_ROOT_SPC)/$(lib)))) -HW_INCLUDES = $(call incs,$(HW_LIBS),$(HW_LIB_ROOT),$(HW_LIB_ROOT_SPC)) -HW_OBJS = $(call objs,$(call src,$(HW_LIB_ROOT),$(HW_LIB_ROOT_SPC),$(HW_LIBS)),$(OUTPUT_DIR)/hw) - -ARDUINO_LIB_ROOT = $(ARDUINO_HOME)/libraries -ARDUINO_LIB_ROOT_SPC = $(call spacify,$(ARDUINO_LIB_ROOT)) -ARDUINO_LIB_ROOT_SPC2 = $(subst :,\:,$(subst \,\\\,$(ARDUINO_LIB_ROOT_SPC))) -ARDUINO_LIBS = $(foreach lib, $(LIBS), $(subst $(ARDUINO_LIB_ROOT)/,,$(wildcard $(ARDUINO_LIB_ROOT_SPC)/$(lib)))) -ARDUINO_INCLUDES = $(call incs,$(ARDUINO_LIBS),$(ARDUINO_LIB_ROOT),$(ARDUINO_LIB_ROOT_SPC)) -ARDUINO_OBJS = $(call objs,$(call src,$(ARDUINO_LIB_ROOT),$(ARDUINO_LIB_ROOT_SPC),$(ARDUINO_LIBS)),$(OUTPUT_DIR)/arduino) - -INCLUDES = -I"$(ARDUINO_HOME)/hardware/arduino/$(ARCH)/cores/$(BUILD_CORE)" \ - -I"$(ARDUINO_HOME)/hardware/arduino/$(ARCH)/variants/$(BUILD_VARIANT)" \ - $(USER_INCLUDES) $(HW_INCLUDES) $(ARDUINO_INCLUDES) - -OBJS = $(PROJECT_OBJS) $(USER_OBJS) $(HW_OBJS) $(ARDUINO_OBJS) - -all: $(OUTPUT_DIR)/$(EXE).hex - -clean: - $(RMDIR) $(call fixpath,$(OUTPUT_DIR)) - -load: $(OUTPUT_DIR)/$(EXE).hex - $(do_load_$(LOADER)) - -$(OUTPUT_DIR)/$(EXE).hex: $(OBJS) $(OUTPUT_DIR)/core.a - $(do_link) - -$(OUTPUT_DIR)/core.a: $(LIB_OBJS) - $(AR) r $@ $? - -$(OUTPUT_DIR)/lib/%.o: $(LIB_ROOT_SPC2)/%.c - @-$(call mymkdir,$(dir $@)) - $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ "$<" - -$(OUTPUT_DIR)/lib/%.o: $(LIB_ROOT_SPC2)/%.cpp - @-$(call mymkdir,$(dir $@)) - $(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -o $@ "$<" - -$(OUTPUT_DIR)/user/%.o: $(USER_LIB_ROOT_SPC2)/%.c - @-$(call mymkdir,$(dir $@)) - $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ "$<" - -$(OUTPUT_DIR)/user/%.o: $(USER_LIB_ROOT_SPC2)/%.cpp - @-$(call mymkdir,$(dir $@)) - $(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -o $@ "$<" - -$(OUTPUT_DIR)/hw/%.o: $(HW_LIB_ROOT_SPC2)/%.c - @-$(call mymkdir,$(dir $@)) - $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ "$<" - -$(OUTPUT_DIR)/hw/%.o: $(HW_LIB_ROOT_SPC2)/%.cpp - @-$(call mymkdir,$(dir $@)) - $(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -o $@ "$<" - -$(OUTPUT_DIR)/arduino/%.o: $(ARDUINO_LIB_ROOT_SPC2)/%.c - @-$(call mymkdir,$(dir $@)) - $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ "$<" - -$(OUTPUT_DIR)/arduino/%.o: $(ARDUINO_LIB_ROOT_SPC2)/%.cpp - @-$(call mymkdir,$(dir $@)) - $(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -o $@ "$<" - -$(OUTPUT_DIR)/src/%.o: %.c - @-$(call mymkdir,$(dir $@)) - $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $< - -$(OUTPUT_DIR)/src/%.o: %.cpp - @-$(call mymkdir,$(dir $@)) - $(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -o $@ $< diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/templates/board.mk b/toolchains/arduino/org.eclipse.cdt.arduino.core/templates/board.mk index 9eca0cce8e2..1f0971bd120 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/templates/board.mk +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/templates/board.mk @@ -1,4 +1,5 @@ ifeq ($(OS),Windows_NT) +SHELL = $(ComSpec) RMDIR = rmdir /s /q mymkdir = if not exist "$1" mkdir "$1" else @@ -10,7 +11,7 @@ PROJECT_OBJS = \ <#list project_srcs as file> <#assign cpp = file?matches("(.*)\\.cpp")> <#if cpp> - ${build_path}/project/${cpp?groups[1]}.o \ + ${build_path}/project/${cpp?groups[1]}.cpp.o \ @@ -18,34 +19,64 @@ PLATFORM_OBJS = \ <#list platform_srcs as file> <#assign cpp = file?matches("${platform_path}/(.*)\\.cpp")> <#if cpp> - ${build_path}/platform/${cpp?groups[1]}.o \ + ${build_path}/platform/${cpp?groups[1]}.cpp.o \ <#assign c = file?matches("${platform_path}/(.*)\\.c")> <#if c> - ${build_path}/platform/${c?groups[1]}.o \ + ${build_path}/platform/${c?groups[1]}.c.o \ + +<#assign S = file?matches("${platform_path}/(.*)\\.S")> +<#if S> + ${build_path}/platform/${S?groups[1]}.S.o \ LIBRARIES_OBJS = \ <#list libraries_srcs as file> <#assign cpp = file?matches("${libraries_path}/(.*?)/.*?/(.*)\\.cpp")> +<#if !cpp> +<#assign cpp = file?matches("${platform_path}/libraries/(.*?)/(.*)\\.cpp")> + <#if cpp> - ${build_path}/libraries/${cpp?groups[1]}/${cpp?groups[2]}.o \ + ${build_path}/libraries/${cpp?groups[1]}/${cpp?groups[2]}.cpp.o \ <#assign c = file?matches("${libraries_path}/(.*?)/.*?/(.*)\\.c")> -<#if c> - ${build_path}/libraries/${c?groups[1]}/${c?groups[2]}.o \ +<#if !c> +<#assign c = file?matches("${platform_path}/libraries/(.*?)/(.*)\\.c")> - +<#if c> + ${build_path}/libraries/${c?groups[1]}/${c?groups[2]}.c.o \ + + -all: ${build_path}/${project_name}.hex ${build_path}/${project_name}.eep +TARGETS = \ +<#if recipe_objcopy_hex_pattern??> + ${build_path}/${project_name}.hex \ + +<#if recipe_objcopy_epp_pattern??> + ${build_path}/${project_name}.eep \ + +<#if recipe_objcopy_bin_pattern??> + ${build_path}/${project_name}.bin \ + +all: $(TARGETS) + +<#if recipe_objcopy_hex_pattern??> ${build_path}/${project_name}.hex: ${build_path}/${project_name}.elf ${recipe_objcopy_hex_pattern} + +<#if recipe_objcopy_epp_pattern??> ${build_path}/${project_name}.eep: ${build_path}/${project_name}.elf ${recipe_objcopy_eep_pattern} + +<#if recipe_objcopy_bin_pattern??> +${build_path}/${project_name}.bin: ${build_path}/${project_name}.elf + ${recipe_objcopy_bin_pattern} + + ${build_path}/${project_name}.elf: $(PROJECT_OBJS) $(LIBRARIES_OBJS) ${build_path}/core.a ${recipe_c_combine_pattern} @@ -60,45 +91,79 @@ size: <#list project_srcs as file> <#assign cpp = file?matches("(.*)\\.cpp")> <#if cpp> -${build_path}/project/${cpp?groups[1]}.o: ../${file} +${build_path}/project/${cpp?groups[1]}.cpp.o: ../${file} ${build_path}/project/${cpp?groups[1]}.cpp.d @$(call mymkdir,$(dir $@)) ${recipe_cpp_o_pattern} +${build_path}/project/${cpp?groups[1]}.cpp.d: ; + +-include ${build_path}/project/${cpp?groups[1]}.cpp.d + <#list platform_srcs as file> <#assign cpp = file?matches("${platform_path}/(.*)\\.cpp")> <#if cpp> -${build_path}/platform/${cpp?groups[1]}.o: ${file} +${build_path}/platform/${cpp?groups[1]}.cpp.o: ${file} ${build_path}/platform/${cpp?groups[1]}.cpp.d @$(call mymkdir,$(dir $@)) ${recipe_cpp_o_pattern} ${recipe_ar_pattern} +${build_path}/platform/${cpp?groups[1]}.cpp.d: ; + +-include ${build_path}/platform/${cpp?groups[1]}.cpp.d + <#assign c = file?matches("${platform_path}/(.*)\\.c")> <#if c> -${build_path}/platform/${c?groups[1]}.o: ${file} +${build_path}/platform/${c?groups[1]}.c.o: ${file} ${build_path}/platform/${c?groups[1]}.c.d @$(call mymkdir,$(dir $@)) ${recipe_c_o_pattern} ${recipe_ar_pattern} + +${build_path}/platform/${c?groups[1]}.c.d: ; + +-include ${build_path}/platform/${c?groups[1]}.c.d + + +<#assign S = file?matches("${platform_path}/(.*)\\.S")> +<#if S> +${build_path}/platform/${S?groups[1]}.S.o: ${file} + @$(call mymkdir,$(dir $@)) + ${recipe_S_o_pattern} + ${recipe_ar_pattern} <#list libraries_srcs as file> <#assign cpp = file?matches("${libraries_path}/(.*?)/.*?/(.*)\\.cpp")> +<#if !cpp> +<#assign cpp = file?matches("${platform_path}/libraries/(.*?)/(.*)\\.cpp")> + <#if cpp> -${build_path}/libraries/${cpp?groups[1]}/${cpp?groups[2]}.o: ${file} +${build_path}/libraries/${cpp?groups[1]}/${cpp?groups[2]}.cpp.o: ${file} ${build_path}/libraries/${cpp?groups[1]}/${cpp?groups[2]}.cpp.d @$(call mymkdir,$(dir $@)) ${recipe_cpp_o_pattern} +${build_path}/libraries/${cpp?groups[1]}/${cpp?groups[2]}.cpp.d: ; + +-include ${build_path}/libraries/${cpp?groups[1]}/${cpp?groups[2]}.cpp.d + <#assign c = file?matches("${libraries_path}/(.*?)/.*?/(.*)\\.c")> +<#if !c> +<#assign c = file?matches("${platform_path}/libraries/(.*?)/(.*)\\.c")> + <#if c> -${build_path}/libraries/${c?groups[1]}/${c?groups[2]}.o: ${file} +${build_path}/libraries/${c?groups[1]}/${c?groups[2]}.c.o: ${file} ${build_path}/libraries/${c?groups[1]}/${c?groups[2]}.c.d @$(call mymkdir,$(dir $@)) ${recipe_c_o_pattern} +${build_path}/libraries/${c?groups[1]}/${c?groups[2]}.c.d: ; + +-include ${build_path}/libraries/${c?groups[1]}/${c?groups[2]}.c.d + \ No newline at end of file diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/icons/list-add.gif b/toolchains/arduino/org.eclipse.cdt.arduino.ui/icons/list-add.gif new file mode 100644 index 00000000000..5ee82b45c22 Binary files /dev/null and b/toolchains/arduino/org.eclipse.cdt.arduino.ui/icons/list-add.gif differ diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/icons/list-delete.gif b/toolchains/arduino/org.eclipse.cdt.arduino.ui/icons/list-delete.gif new file mode 100644 index 00000000000..5fd7e2d44e3 Binary files /dev/null and b/toolchains/arduino/org.eclipse.cdt.arduino.ui/icons/list-delete.gif differ diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/plugin.xml b/toolchains/arduino/org.eclipse.cdt.arduino.ui/plugin.xml index 86fdc231a0c..0290e808181 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.ui/plugin.xml +++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/plugin.xml @@ -30,6 +30,12 @@ project="true"> + + + + - - - + + + + + + + - - + point="org.eclipse.ui.perspectiveExtensions"> + + + + + + + + + + + + diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/Activator.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/Activator.java index 11f84062e9f..1f57d190028 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/Activator.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/Activator.java @@ -29,6 +29,8 @@ public class Activator extends AbstractUIPlugin { public static final String IMG_ARDUINO = PLUGIN_ID + ".arduino"; //$NON-NLS-1$ public static final String IMG_CONNECTION_TYPE = PLUGIN_ID + ".connectionType"; //$NON-NLS-1$ + public static final String IMG_ADD = PLUGIN_ID + ".add"; + public static final String IMG_DELETE = PLUGIN_ID + ".delete"; // The shared instance private static Activator plugin; @@ -37,7 +39,7 @@ public class Activator extends AbstractUIPlugin { super.start(context); plugin = this; // Load up the Arduino indices - ArduinoManager.instance.loadIndices(); + getService(ArduinoManager.class).loadIndices(); } public void stop(BundleContext context) throws Exception { @@ -50,6 +52,8 @@ public class Activator extends AbstractUIPlugin { ImageRegistry registry = super.createImageRegistry(); registry.put(IMG_ARDUINO, imageDescriptorFromPlugin(PLUGIN_ID, "icons/cprojects.gif")); //$NON-NLS-1$ registry.put(IMG_CONNECTION_TYPE, imageDescriptorFromPlugin(PLUGIN_ID, "icons/arduino.png")); //$NON-NLS-1$ + registry.put(IMG_ADD, imageDescriptorFromPlugin(PLUGIN_ID, "icons/list-add.gif")); //$NON-NLS-1$ + registry.put(IMG_DELETE, imageDescriptorFromPlugin(PLUGIN_ID, "icons/list-delete.gif")); //$NON-NLS-1$ return registry; } diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/Messages.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/Messages.java index c64034526d5..ddbc9fff23e 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/Messages.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/Messages.java @@ -25,8 +25,28 @@ public class Messages extends NLS { public static String NewArduinoTargetWizardPage_4; public static String NewArduinoTargetWizardPage_5; public static String ArduinoBoardsPreferencePage_desc; + public static String LibrariesPropertyPage_0; + public static String LibrariesPropertyPage_1; public static String LibrariesPropertyPage_desc; + public static String ArduinoPlatformsPreferencePage_0; + public static String ArduinoPlatformsPreferencePage_1; + public static String ArduinoPlatformsPreferencePage_10; + public static String ArduinoPlatformsPreferencePage_11; + public static String ArduinoPlatformsPreferencePage_12; + public static String ArduinoPlatformsPreferencePage_13; + public static String ArduinoPlatformsPreferencePage_14; + public static String ArduinoPlatformsPreferencePage_15; + public static String ArduinoPlatformsPreferencePage_2; + public static String ArduinoPlatformsPreferencePage_3; + public static String ArduinoPlatformsPreferencePage_4; + public static String ArduinoPlatformsPreferencePage_5; + public static String ArduinoPlatformsPreferencePage_6; + public static String ArduinoPlatformsPreferencePage_7; + public static String ArduinoPlatformsPreferencePage_8; + public static String ArduinoPlatformsPreferencePage_9; public static String ArduinoPreferencePage_desc; + public static String PlatformDetailsDialog_0; + public static String PlatformDetailsDialog_1; static { // initialize resource bundle diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/launch/ArduinoConsole.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/launch/ArduinoConsole.java new file mode 100644 index 00000000000..fc14c9fe2fc --- /dev/null +++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/launch/ArduinoConsole.java @@ -0,0 +1,162 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.arduino.ui.internal.launch; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Semaphore; + +import org.eclipse.cdt.arduino.core.internal.console.ArduinoConsoleParser; +import org.eclipse.cdt.arduino.core.internal.console.ArduinoConsoleService; +import org.eclipse.cdt.arduino.core.internal.console.ArduinoErrorParser; +import org.eclipse.cdt.arduino.ui.internal.Activator; +import org.eclipse.cdt.arduino.ui.internal.Messages; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.resources.IncrementalProjectBuilder; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.console.ConsolePlugin; +import org.eclipse.ui.console.IConsole; +import org.eclipse.ui.console.MessageConsole; +import org.eclipse.ui.console.MessageConsoleStream; + +public class ArduinoConsole implements ArduinoConsoleService, IResourceChangeListener { + + private static MessageConsole console; + private static MessageConsoleStream out; + private static MessageConsoleStream err; + + private IFolder buildDirectory; + List listeners = new ArrayList<>(); + + public ArduinoConsole() { + if (console == null) { + console = new MessageConsole(Messages.ArduinoLaunchConsole_0, null); + ConsolePlugin.getDefault().getConsoleManager().addConsoles(new IConsole[] { console }); + out = console.newMessageStream(); + err = console.newMessageStream(); + + // set the colors + final Display display = Display.getDefault(); + display.syncExec(new Runnable() { + @Override + public void run() { + out.setColor(display.getSystemColor(SWT.COLOR_BLACK)); + err.setColor(display.getSystemColor(SWT.COLOR_RED)); + } + }); + ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.PRE_BUILD); + } + } + + @Override + public void resourceChanged(IResourceChangeEvent event) { + switch (event.getType()) { + case IResourceChangeEvent.PRE_BUILD: + if (event.getBuildKind() != IncrementalProjectBuilder.AUTO_BUILD) { + // TODO this really should be done from the core and only when + // our projects are being built + console.clearConsole(); + } + break; + } + } + + public IFolder getBuildDirectory() { + return buildDirectory; + } + + @Override + public void monitor(final Process process, ArduinoConsoleParser[] consoleParsers, IFolder buildDirectory) + throws IOException { + this.buildDirectory = buildDirectory; + + // Clear the old listeners + for (ArduinoPatternMatchListener listener : listeners) { + console.removePatternMatchListener(listener); + } + listeners.clear(); + + // Add in the new ones if any + if (consoleParsers != null) { + for (ArduinoConsoleParser parser : consoleParsers) { + ArduinoPatternMatchListener listener; + if (parser instanceof ArduinoErrorParser) { + listener = new ArduinoErrorMatchListener(this, (ArduinoErrorParser) parser); + } else { + continue; + } + listeners.add(listener); + console.addPatternMatchListener(listener); + } + } + + console.activate(); + + final Semaphore sema = new Semaphore(-1); + + // Output stream reader + new Thread(Messages.ArduinoLaunchConsole_2) { + public void run() { + try (BufferedReader processOut = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + for (String line = processOut.readLine(); line != null; line = processOut.readLine()) { + out.write(line); + out.write('\n'); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + sema.release(); + } + } + }.start(); + + // Error stream reader + new Thread(Messages.ArduinoLaunchConsole_2) { + public void run() { + try (BufferedReader processErr = new BufferedReader(new InputStreamReader(process.getErrorStream()))) { + for (String line = processErr.readLine(); line != null; line = processErr.readLine()) { + err.write(line); + out.write('\n'); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + sema.release(); + } + } + }.start(); + + try { + sema.acquire(); + process.waitFor(); + } catch (InterruptedException e) { + Activator.log(e); + } + } + + @Override + public void writeOutput(String msg) throws IOException { + out.write(msg); + } + + @Override + public void writeError(String msg) throws IOException { + err.write(msg); + } + +} diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/launch/ArduinoErrorMatchListener.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/launch/ArduinoErrorMatchListener.java new file mode 100644 index 00000000000..b2113940093 --- /dev/null +++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/launch/ArduinoErrorMatchListener.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.arduino.ui.internal.launch; + +import org.eclipse.cdt.arduino.core.internal.console.ArduinoErrorParser; +import org.eclipse.cdt.arduino.ui.internal.Activator; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.ui.console.PatternMatchEvent; + +public class ArduinoErrorMatchListener extends ArduinoPatternMatchListener { + + public ArduinoErrorMatchListener(ArduinoConsole arduinoConsole, ArduinoErrorParser parser) { + super(arduinoConsole, parser); + } + + @Override + public void matchFound(PatternMatchEvent event) { + try { + String text = textConsole.getDocument().get(event.getOffset(), event.getLength()); + IMarker marker = ((ArduinoErrorParser) parser).generateMarker(arduinoConsole.getBuildDirectory(), text); + if (marker != null) { + textConsole.addHyperlink(new ArduinoHyperlink(marker), + event.getOffset() + marker.getAttribute(ArduinoErrorParser.LINK_OFFSET, 0), + marker.getAttribute(ArduinoErrorParser.LINK_LENGTH, event.getLength())); + } + } catch (BadLocationException | CoreException e) { + Activator.log(e); + } + } + +} diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/launch/ArduinoHyperlink.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/launch/ArduinoHyperlink.java new file mode 100644 index 00000000000..51927a45cf0 --- /dev/null +++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/launch/ArduinoHyperlink.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.arduino.ui.internal.launch; + +import org.eclipse.cdt.arduino.ui.internal.Activator; +import org.eclipse.core.resources.IMarker; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.console.IHyperlink; +import org.eclipse.ui.ide.IDE; + +public class ArduinoHyperlink implements IHyperlink { + + private final IMarker marker; + + public ArduinoHyperlink(IMarker marker) { + this.marker = marker; + } + + @Override + public void linkEntered() { + } + + @Override + public void linkExited() { + } + + @Override + public void linkActivated() { + IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + try { + IDE.openEditor(page, marker); + } catch (PartInitException e) { + Activator.log(e); + } + } + +} diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/launch/ArduinoLaunchConfigurationTabGroup.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/launch/ArduinoLaunchConfigurationTabGroup.java new file mode 100644 index 00000000000..4dad04b5658 --- /dev/null +++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/launch/ArduinoLaunchConfigurationTabGroup.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.arduino.ui.internal.launch; + +import org.eclipse.debug.ui.AbstractLaunchConfigurationTabGroup; +import org.eclipse.debug.ui.ILaunchConfigurationDialog; +import org.eclipse.debug.ui.ILaunchConfigurationTab; + +public class ArduinoLaunchConfigurationTabGroup extends AbstractLaunchConfigurationTabGroup { + + @Override + public void createTabs(ILaunchConfigurationDialog dialog, String mode) { + setTabs(new ILaunchConfigurationTab[0]); + } + +} diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/launch/ArduinoPatternMatchListener.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/launch/ArduinoPatternMatchListener.java new file mode 100644 index 00000000000..ea222570f14 --- /dev/null +++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/launch/ArduinoPatternMatchListener.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.arduino.ui.internal.launch; + +import org.eclipse.cdt.arduino.core.internal.console.ArduinoConsoleParser; +import org.eclipse.ui.console.IPatternMatchListener; +import org.eclipse.ui.console.TextConsole; + +public abstract class ArduinoPatternMatchListener implements IPatternMatchListener { + + protected final ArduinoConsole arduinoConsole; + protected final ArduinoConsoleParser parser; + + protected TextConsole textConsole; + + public ArduinoPatternMatchListener(ArduinoConsole arduinoConsole, ArduinoConsoleParser parser) { + this.arduinoConsole = arduinoConsole; + this.parser = parser; + } + + @Override + public void connect(TextConsole console) { + this.textConsole = console; + } + + @Override + public void disconnect() { + } + + @Override + public String getPattern() { + return parser.getPattern(); + } + + @Override + public int getCompilerFlags() { + return parser.getCompilerFlags(); + } + + @Override + public String getLineQualifier() { + return parser.getLineQualifier(); + } + +} diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/messages.properties b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/messages.properties index a0c4bb4d5ed..c108275701d 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/messages.properties +++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/messages.properties @@ -1,10 +1,10 @@ -################################################################################ +#****************************************************************************** # Copyright (c) 2015 QNX Software Systems and others. # All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License v1.0 # which accompanies this distribution, and is available at # http://www.eclipse.org/legal/epl-v10.html -################################################################################ +#****************************************************************************** ArduinoLaunchConsole_0=Arduino ArduinoLaunchConsole_1=Start Arduino Console ArduinoLaunchConsole_2=Arduino Console Output @@ -18,10 +18,29 @@ NewArduinoTargetWizardPage_2=Target name: NewArduinoTargetWizardPage_3= NewArduinoTargetWizardPage_4=Serial port: NewArduinoTargetWizardPage_5=Board type: -ArduinoBoardsPreferencePage_desc=Select a board you would like to install and click Install and then \ -OK or Apply to install the SDK and Tools for that board. By doing so you agree to the licenses of the \ -libraries and tools. For more information, see http://arduino.cc. +ArduinoBoardsPreferencePage_desc=NOTE: To install support for an Arduino board, please use the Arduino \ +Platforms preference page to install the platform support for that board. +LibrariesPropertyPage_0=Name +LibrariesPropertyPage_1=Description LibrariesPropertyPage_desc=Select libraries to use in your project and click OK or Apply. \ If necessary the library will be installed. By adding libraries you agree to the licenses of those \ libraries. For more information, see http://arduino.cc -ArduinoPreferencePage_desc=Enter URLs for package_index.json files one per line. \ No newline at end of file +ArduinoPlatformsPreferencePage_0=Select a platform then click a button to install, uninstall, or find more details about the platform. +ArduinoPlatformsPreferencePage_1=Platform +ArduinoPlatformsPreferencePage_10=Information on the licenses can be found at arduino.cc web site. +ArduinoPlatformsPreferencePage_11=Arduino License +ArduinoPlatformsPreferencePage_12=Accept +ArduinoPlatformsPreferencePage_13=Decline +ArduinoPlatformsPreferencePage_14=Installing Arduino Board Platforms +ArduinoPlatformsPreferencePage_15=Installing Arduino Board Platforms +ArduinoPlatformsPreferencePage_2=Installed +ArduinoPlatformsPreferencePage_3=Available +ArduinoPlatformsPreferencePage_4=Install +ArduinoPlatformsPreferencePage_5=Upgrade +ArduinoPlatformsPreferencePage_6=Details +ArduinoPlatformsPreferencePage_7=Install +ArduinoPlatformsPreferencePage_8=Uninstall +ArduinoPlatformsPreferencePage_9=Do you accept the licenses for the Arduino SDK and libraries? +ArduinoPreferencePage_desc=Enter URLs for package_index.json files one per line. +PlatformDetailsDialog_0=Platform: +PlatformDetailsDialog_1=Supports boards:\n diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/preferences/ArduinoBoardsPreferencePage.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/preferences/ArduinoBoardsPreferencePage.java index 65680e8fbe5..488c7d032a7 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/preferences/ArduinoBoardsPreferencePage.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/preferences/ArduinoBoardsPreferencePage.java @@ -7,46 +7,19 @@ *******************************************************************************/ package org.eclipse.cdt.arduino.ui.internal.preferences; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoard; -import org.eclipse.cdt.arduino.core.internal.board.ArduinoManager; -import org.eclipse.cdt.arduino.core.internal.board.ArduinoPlatform; -import org.eclipse.cdt.arduino.ui.internal.Activator; import org.eclipse.cdt.arduino.ui.internal.Messages; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.MultiStatus; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jface.layout.TableColumnLayout; import org.eclipse.jface.preference.PreferencePage; -import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPreferencePage; public class ArduinoBoardsPreferencePage extends PreferencePage implements IWorkbenchPreferencePage { - private Table table; - private Button installButton; - private Set toInstall = new HashSet<>(); - @Override public void init(IWorkbench workbench) { } @@ -63,150 +36,7 @@ public class ArduinoBoardsPreferencePage extends PreferencePage implements IWork desc.setBackground(parent.getBackground()); desc.setText(Messages.ArduinoBoardsPreferencePage_desc); - Composite comp = new Composite(control, SWT.NONE); - GridLayout layout = new GridLayout(2, false); - layout.marginWidth = 0; - comp.setLayout(layout); - comp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - - Composite tableComp = new Composite(comp, SWT.NONE); - tableComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - - table = new Table(tableComp, SWT.SINGLE | SWT.BORDER | SWT.V_SCROLL | SWT.FULL_SELECTION); - table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - table.setHeaderVisible(true); - table.setLinesVisible(true); - - TableColumn packageColumn = new TableColumn(table, SWT.LEAD); - packageColumn.setText("Board"); - - TableColumn platformColumn = new TableColumn(table, SWT.LEAD); - platformColumn.setText("Platform"); - - TableColumn installedColumn = new TableColumn(table, SWT.LEAD); - installedColumn.setText("Installed"); - - TableColumnLayout tableLayout = new TableColumnLayout(); - tableLayout.setColumnData(packageColumn, new ColumnWeightData(5, 150, true)); - tableLayout.setColumnData(platformColumn, new ColumnWeightData(5, 150, true)); - tableLayout.setColumnData(installedColumn, new ColumnWeightData(2, 75, true)); - tableComp.setLayout(tableLayout); - - table.addListener(SWT.Selection, new Listener() { - @Override - public void handleEvent(Event event) { - updateButtons(); - } - }); - - Composite buttonComp = new Composite(comp, SWT.NONE); - buttonComp.setLayout(new GridLayout()); - buttonComp.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false)); - - installButton = new Button(buttonComp, SWT.PUSH); - installButton.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false)); - installButton.setText("Install"); - installButton.addListener(SWT.Selection, new Listener() { - @Override - public void handleEvent(Event event) { - for (TableItem item : table.getSelection()) { - ArduinoBoard board = (ArduinoBoard) item.getData(); - toInstall.add(board); - item.setText(2, "selected"); - updateButtons(); - } - } - }); - - updateTable(); - updateButtons(); - return control; } - private void updateTable() { - if (table == null || table.isDisposed()) { - return; - } - - table.removeAll(); - - try { - List boards = ArduinoManager.instance.getBoards(); - Collections.sort(boards, new Comparator() { - public int compare(ArduinoBoard o1, ArduinoBoard o2) { - return o1.getName().compareTo(o2.getName()); - } - }); - - for (ArduinoBoard board : boards) { - TableItem item = new TableItem(table, SWT.NONE); - item.setData(board); - item.setText(0, board.getName()); - item.setText(1, board.getPlatform().getName()); - String msg; - if (toInstall.contains(board)) { - msg = "selected"; - } else { - msg = board.getPlatform().isInstalled() ? "yes" : "no"; - } - item.setText(2, msg); - } - } catch (CoreException e) { - Activator.log(e); - } - } - - private void updateButtons() { - if (table == null || table.isDisposed()) { - return; - } - - boolean enable = false; - for (TableItem item : table.getSelection()) { - ArduinoBoard board = (ArduinoBoard) item.getData(); - if (toInstall.contains(board)) { - continue; - } - ArduinoPlatform platform = board.getPlatform(); - if (!platform.isInstalled()) { - enable = true; - } - } - installButton.setEnabled(enable); - } - - @Override - public boolean performOk() { - new Job("Installing Arduino Board Platforms") { - @Override - protected IStatus run(IProgressMonitor monitor) { - Set platforms = new HashSet<>(); - for (ArduinoBoard board : toInstall) { - platforms.add(board.getPlatform()); - } - - MultiStatus status = new MultiStatus(Activator.PLUGIN_ID, 0, "Installing Arduino Board Platforms", - null); - for (ArduinoPlatform platform : platforms) { - status.add(platform.install(monitor)); - } - - toInstall.clear(); - - if (table != null && !table.isDisposed()) { - table.getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - updateTable(); - } - }); - } - - return status; - } - }.schedule(); - return true; - } - } diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/preferences/ArduinoPlatformsPreferencePage.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/preferences/ArduinoPlatformsPreferencePage.java new file mode 100644 index 00000000000..bfbceb248b1 --- /dev/null +++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/preferences/ArduinoPlatformsPreferencePage.java @@ -0,0 +1,264 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.arduino.ui.internal.preferences; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +import org.eclipse.cdt.arduino.core.internal.ArduinoPreferences; +import org.eclipse.cdt.arduino.core.internal.board.ArduinoManager; +import org.eclipse.cdt.arduino.core.internal.board.ArduinoPackage; +import org.eclipse.cdt.arduino.core.internal.board.ArduinoPlatform; +import org.eclipse.cdt.arduino.core.internal.board.PackageIndex; +import org.eclipse.cdt.arduino.ui.internal.Activator; +import org.eclipse.cdt.arduino.ui.internal.Messages; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.layout.TableColumnLayout; +import org.eclipse.jface.preference.PreferencePage; +import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; + +public class ArduinoPlatformsPreferencePage extends PreferencePage implements IWorkbenchPreferencePage { + + private Table table; + private Button installButton; + private Button uninstallButton; + private Button detailButton; + + private Collection toInstall = new HashSet<>(); + private Collection toUninstall = new HashSet<>(); + + private static ArduinoManager manager = Activator.getService(ArduinoManager.class); + + @Override + public void init(IWorkbench workbench) { + } + + @Override + protected Control createContents(Composite parent) { + Composite control = new Composite(parent, SWT.NONE); + control.setLayout(new GridLayout()); + + Text desc = new Text(control, SWT.READ_ONLY | SWT.WRAP); + GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, false); + layoutData.widthHint = 500; + desc.setLayoutData(layoutData); + desc.setBackground(parent.getBackground()); + desc.setText(Messages.ArduinoPlatformsPreferencePage_0); + + Composite comp = new Composite(control, SWT.NONE); + GridLayout layout = new GridLayout(2, false); + layout.marginWidth = 0; + comp.setLayout(layout); + comp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + Composite tableComp = new Composite(comp, SWT.NONE); + tableComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + table = new Table(tableComp, SWT.SINGLE | SWT.BORDER | SWT.V_SCROLL | SWT.FULL_SELECTION); + table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + table.setHeaderVisible(true); + table.setLinesVisible(true); + + TableColumn platformColumn = new TableColumn(table, SWT.LEAD); + platformColumn.setText(Messages.ArduinoPlatformsPreferencePage_1); + TableColumn installedColumn = new TableColumn(table, SWT.LEAD); + installedColumn.setText(Messages.ArduinoPlatformsPreferencePage_2); + TableColumn availableColumn = new TableColumn(table, SWT.LEAD); + availableColumn.setText(Messages.ArduinoPlatformsPreferencePage_3); + + TableColumnLayout tableLayout = new TableColumnLayout(); + tableLayout.setColumnData(platformColumn, new ColumnWeightData(5, 150, true)); + tableLayout.setColumnData(installedColumn, new ColumnWeightData(2, 75, true)); + tableLayout.setColumnData(availableColumn, new ColumnWeightData(2, 75, true)); + tableComp.setLayout(tableLayout); + + table.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + TableItem[] selection = table.getSelection(); + if (selection.length > 0) { + TableItem item = selection[0]; + detailButton.setEnabled(true); + ArduinoPlatform aplat = (ArduinoPlatform) item.getData(); + ArduinoPlatform iplat = aplat.getPackage().getInstalledPlatforms().get(aplat.getName()); + if (iplat == null) { + installButton.setEnabled(true); + installButton.setText(Messages.ArduinoPlatformsPreferencePage_4); + uninstallButton.setEnabled(false); + } else { + installButton.setText(Messages.ArduinoPlatformsPreferencePage_5); + if (!aplat.getVersion().equals(iplat.getVersion())) { + // Assuming upgrade if not equal, dangerous + installButton.setEnabled(true); + } else { + installButton.setEnabled(false); + } + uninstallButton.setEnabled(true); + } + } else { + detailButton.setEnabled(false); + installButton.setEnabled(false); + uninstallButton.setEnabled(false); + } + } + }); + + Composite buttonComp = new Composite(comp, SWT.NONE); + buttonComp.setLayout(new GridLayout()); + buttonComp.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false)); + + detailButton = new Button(buttonComp, SWT.PUSH); + detailButton.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false)); + detailButton.setText(Messages.ArduinoPlatformsPreferencePage_6); + detailButton.setEnabled(false); + detailButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + TableItem[] selection = table.getSelection(); + // We are only enabled when there is a selection + ArduinoPlatform platform = (ArduinoPlatform) selection[0].getData(); + PlatformDetailsDialog dialog = new PlatformDetailsDialog(getShell(), platform); + dialog.open(); + } + }); + + installButton = new Button(buttonComp, SWT.PUSH); + installButton.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false)); + installButton.setText(Messages.ArduinoPlatformsPreferencePage_7); + installButton.setEnabled(false); + installButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + TableItem[] selection = table.getSelection(); + if (selection.length > 0) { + TableItem item = selection[0]; + toInstall.add(((ArduinoPlatform) item.getData())); + item.setImage(Activator.getDefault().getImageRegistry().get(Activator.IMG_ADD)); + } + } + }); + + uninstallButton = new Button(buttonComp, SWT.PUSH); + uninstallButton.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false)); + uninstallButton.setText(Messages.ArduinoPlatformsPreferencePage_8); + uninstallButton.setEnabled(false); + uninstallButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + TableItem[] selection = table.getSelection(); + if (selection.length > 0) { + TableItem item = selection[0]; + toUninstall.add(((ArduinoPlatform) item.getData())); + item.setImage(Activator.getDefault().getImageRegistry().get(Activator.IMG_DELETE)); + } + } + }); + + populateTable(); + + return control; + } + + private void populateTable() { + table.removeAll(); + for (PackageIndex packageIndex : manager.getPackageIndices()) { + for (ArduinoPackage pkg : packageIndex.getPackages()) { + Map available = pkg.getAvailablePlatforms(); + Map installed = pkg.getInstalledPlatforms(); + List names = new ArrayList<>(available.keySet()); + Collections.sort(names); + for (String name : names) { + TableItem item = new TableItem(table, SWT.NONE); + item.setText(0, name); + ArduinoPlatform iplat = installed.get(name); + item.setText(1, iplat != null ? iplat.getVersion() : "---"); //$NON-NLS-1$ + ArduinoPlatform aplat = available.get(name); + item.setText(2, aplat.getVersion()); + item.setData(aplat); + } + } + } + } + + @Override + public boolean performOk() { + File acceptedFile = ArduinoPreferences.getArduinoHome().resolve(".accepted").toFile(); //$NON-NLS-1$ + if (!acceptedFile.exists()) { + String message = Messages.ArduinoPlatformsPreferencePage_9 + Messages.ArduinoPlatformsPreferencePage_10; + MessageDialog dialog = new MessageDialog(getShell(), + Messages.ArduinoPlatformsPreferencePage_11, null, message, MessageDialog.QUESTION, new String[] { + Messages.ArduinoPlatformsPreferencePage_12, Messages.ArduinoPlatformsPreferencePage_13 }, + 0); + int rc = dialog.open(); + if (rc == 0) { + try { + acceptedFile.createNewFile(); + } catch (IOException e) { + Activator.log(e); + } + } else { + return false; + } + } + + new Job(Messages.ArduinoPlatformsPreferencePage_14) { + @Override + protected IStatus run(IProgressMonitor monitor) { + MultiStatus status = new MultiStatus(Activator.PLUGIN_ID, 0, Messages.ArduinoPlatformsPreferencePage_15, + null); + + for (ArduinoPlatform platform : toUninstall) { + status.add(platform.uninstall(monitor)); + } + toUninstall.clear(); + + for (ArduinoPlatform platform : toInstall) { + status.add(platform.install(monitor)); + } + toInstall.clear(); + + if (table != null && !table.isDisposed()) { + table.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + populateTable(); + } + }); + } + + return status; + } + }.schedule(); + return true; + } + +} diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/preferences/ArduinoPreferencePage.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/preferences/ArduinoPreferencePage.java index 50f1c781c2d..8aaaf4b7450 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/preferences/ArduinoPreferencePage.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/preferences/ArduinoPreferencePage.java @@ -12,6 +12,7 @@ package org.eclipse.cdt.arduino.ui.internal.preferences; import org.eclipse.cdt.arduino.core.internal.ArduinoPreferences; import org.eclipse.cdt.arduino.core.internal.board.ArduinoManager; +import org.eclipse.cdt.arduino.ui.internal.Activator; import org.eclipse.cdt.arduino.ui.internal.Messages; import org.eclipse.jface.preference.PreferencePage; import org.eclipse.swt.SWT; @@ -43,7 +44,7 @@ public class ArduinoPreferencePage extends PreferencePage implements IWorkbenchP desc.setBackground(parent.getBackground()); desc.setText(Messages.ArduinoPreferencePage_desc); - urlsText = new Text(control, SWT.BORDER); + urlsText = new Text(control, SWT.BORDER | SWT.MULTI); urlsText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); urlsText.setText(ArduinoPreferences.getBoardUrls()); @@ -53,7 +54,7 @@ public class ArduinoPreferencePage extends PreferencePage implements IWorkbenchP @Override public boolean performOk() { ArduinoPreferences.setBoardUrls(urlsText.getText()); - ArduinoManager.instance.loadIndices(); + Activator.getService(ArduinoManager.class).loadIndices(); return true; } diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/preferences/PlatformDetailsDialog.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/preferences/PlatformDetailsDialog.java new file mode 100644 index 00000000000..20037f4333c --- /dev/null +++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/preferences/PlatformDetailsDialog.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.arduino.ui.internal.preferences; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoard; +import org.eclipse.cdt.arduino.core.internal.board.ArduinoPlatform; +import org.eclipse.cdt.arduino.ui.internal.Messages; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +public class PlatformDetailsDialog extends Dialog { + + private final ArduinoPlatform platform; + + protected PlatformDetailsDialog(Shell parentShell, ArduinoPlatform platform) { + super(parentShell); + setShellStyle(getShellStyle() | SWT.RESIZE); + this.platform = platform; + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite control = (Composite) super.createDialogArea(parent); + + Text text = new Text(control, SWT.BORDER | SWT.READ_ONLY | SWT.MULTI | SWT.V_SCROLL); + text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + StringBuilder str = new StringBuilder(); + + str.append(Messages.PlatformDetailsDialog_0); + str.append(platform.getName()); + str.append('\n'); + + str.append(Messages.PlatformDetailsDialog_1); + List boards = platform.getBoards(); + Collections.sort(boards, new Comparator() { + @Override + public int compare(ArduinoBoard o1, ArduinoBoard o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + for (ArduinoBoard board : platform.getBoards()) { + str.append(" "); //$NON-NLS-1$ + str.append(board.getName()); + str.append('\n'); + } + + text.setText(str.toString()); + return control; + } + + @Override + protected void createButtonsForButtonBar(Composite parent) { + createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); + } + +} diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/project/ArduinoPropertyTester.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/project/ArduinoPropertyTester.java new file mode 100644 index 00000000000..cd3d239e24e --- /dev/null +++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/project/ArduinoPropertyTester.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.arduino.ui.internal.project; + +import org.eclipse.cdt.arduino.core.internal.remote.ArduinoRemoteConnection; +import org.eclipse.core.expressions.PropertyTester; +import org.eclipse.remote.core.IRemoteConnection; + +public class ArduinoPropertyTester extends PropertyTester { + + @Override + public boolean test(Object receiver, String property, Object[] args, Object expectedValue) { + if (receiver instanceof IRemoteConnection) { + IRemoteConnection remote = (IRemoteConnection) receiver; + return remote.hasService(ArduinoRemoteConnection.class); + } else { + return false; + } + } + +} diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/project/LibrariesPropertyPage.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/project/LibrariesPropertyPage.java index 2bb05d4ac11..4c0e2de75f2 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/project/LibrariesPropertyPage.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/project/LibrariesPropertyPage.java @@ -9,11 +9,15 @@ package org.eclipse.cdt.arduino.ui.internal.project; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.eclipse.cdt.arduino.core.internal.board.ArduinoLibrary; import org.eclipse.cdt.arduino.core.internal.board.ArduinoManager; +import org.eclipse.cdt.arduino.core.internal.board.ArduinoPlatform; import org.eclipse.cdt.arduino.core.internal.board.LibraryIndex; +import org.eclipse.cdt.arduino.core.internal.build.ArduinoBuildConfiguration; import org.eclipse.cdt.arduino.ui.internal.Activator; import org.eclipse.cdt.arduino.ui.internal.Messages; import org.eclipse.core.resources.IProject; @@ -40,7 +44,9 @@ import org.eclipse.ui.dialogs.PropertyPage; public class LibrariesPropertyPage extends PropertyPage { - private static class ContentProvider implements ITreeContentProvider { + private static ArduinoManager manager = Activator.getService(ArduinoManager.class); + + private class ContentProvider implements ITreeContentProvider { private LibraryIndex index; @Override @@ -55,9 +61,9 @@ public class LibrariesPropertyPage extends PropertyPage { @Override public boolean hasChildren(Object element) { if (element instanceof LibraryIndex) { - return !index.getCategories().isEmpty(); + return true; } else if (element instanceof String) { // category - return !index.getLibraries((String) element).isEmpty(); + return true; } else if (element instanceof ArduinoLibrary) { return false; } else { @@ -68,8 +74,10 @@ public class LibrariesPropertyPage extends PropertyPage { @Override public Object getParent(Object element) { if (element instanceof ArduinoLibrary) { - return ((ArduinoLibrary) element).getCategory(); - } else if (element instanceof String) { + ArduinoLibrary lib = (ArduinoLibrary) element; + String category = lib.getCategory(); + return category != null ? category : LibraryIndex.UNCATEGORIZED; + } else if (element instanceof String || element instanceof ArduinoPlatform) { return index; } else { return null; @@ -78,15 +86,46 @@ public class LibrariesPropertyPage extends PropertyPage { @Override public Object[] getElements(Object inputElement) { - return ((LibraryIndex) inputElement).getCategories().toArray(new String[0]); + Set categories = new HashSet<>(); + categories.addAll(((LibraryIndex) inputElement).getCategories()); + + try { + for (ArduinoLibrary lib : getPlatform().getLibraries()) { + String category = lib.getCategory(); + categories.add(category != null ? category : LibraryIndex.UNCATEGORIZED); + } + } catch (CoreException e) { + Activator.log(e); + } + + return categories.toArray(); } @Override public Object[] getChildren(Object parentElement) { if (parentElement instanceof String) { - return index.getLibraries((String) parentElement).toArray(new ArduinoLibrary[0]); + String category = (String) parentElement; + List libs = new ArrayList<>(); + libs.addAll(index.getLibraries(category)); + try { + for (ArduinoLibrary lib : getPlatform().getLibraries()) { + String cat = lib.getCategory(); + if (cat != null) { + if (cat.equals(category)) { + libs.add(lib); + } + } else if (category.equals(LibraryIndex.UNCATEGORIZED)) { // cat + // == + // null + libs.add(lib); + } + } + } catch (CoreException e) { + Activator.log(e); + } + return libs.toArray(); } else { - return null; + return new Object[0]; } } } @@ -146,6 +185,7 @@ public class LibrariesPropertyPage extends PropertyPage { } } }, true) { + @Override protected TreeViewer doCreateTreeViewer(Composite parent, int style) { return new ContainerCheckedTreeViewer(parent, style); @@ -158,28 +198,36 @@ public class LibrariesPropertyPage extends PropertyPage { Tree tree = viewer.getTree(); tree.setHeaderVisible(true); TreeColumn column1 = new TreeColumn(tree, SWT.LEFT); - column1.setText("Name"); + column1.setText(Messages.LibrariesPropertyPage_0); column1.setWidth(200); TreeColumn column2 = new TreeColumn(tree, SWT.LEFT); - column2.setText("Description"); + column2.setText(Messages.LibrariesPropertyPage_1); column2.setWidth(200); viewer.setContentProvider(new ContentProvider()); viewer.setLabelProvider(new LabelProvider()); try { - viewer.setInput(ArduinoManager.instance.getLibraryIndex()); + viewer.setInput(manager.getLibraryIndex()); // Set the check states for currently selected libraries IProject project = getElement().getAdapter(IProject.class); - Collection libraries = ArduinoManager.instance.getLibraries(project); + Collection libraries = manager.getLibraries(project); for (ArduinoLibrary lib : libraries) { viewer.setChecked(lib, true); } } catch (CoreException e) { Activator.log(e); } - return comp; + + } + + private IProject getProject() { + return getElement().getAdapter(IProject.class); + } + + private ArduinoPlatform getPlatform() throws CoreException { + return getProject().getActiveBuildConfig().getAdapter(ArduinoBuildConfiguration.class).getBoard().getPlatform(); } @Override @@ -194,7 +242,7 @@ public class LibrariesPropertyPage extends PropertyPage { } } try { - ArduinoManager.instance.setLibraries(getElement().getAdapter(IProject.class), libs); + manager.setLibraries(getProject(), libs); } catch (CoreException e) { Activator.log(e); } diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/project/NewArduinoProjectWizard.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/project/NewArduinoProjectWizard.java index ea280faf261..1ad1f0df6d7 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/project/NewArduinoProjectWizard.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/project/NewArduinoProjectWizard.java @@ -33,10 +33,11 @@ public class NewArduinoProjectWizard extends BasicNewProjectResourceWizard { return false; new Job(Messages.NewArduinoProjectWizard_0) { + @Override protected IStatus run(IProgressMonitor monitor) { try { final ArduinoProjectGenerator generator = new ArduinoProjectGenerator(getNewProject()); - generator.setupArduinoProject(monitor); + generator.generate(monitor); getWorkbench().getDisplay().asyncExec(new Runnable() { @Override public void run() { diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/ArduinoLaunchTargetLabelProvider.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/ArduinoLaunchTargetLabelProvider.java deleted file mode 100644 index 65186d4a302..00000000000 --- a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/ArduinoLaunchTargetLabelProvider.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.eclipse.cdt.arduino.ui.internal.remote; - -import org.eclipse.cdt.arduino.core.internal.remote.ArduinoRemoteConnection; -import org.eclipse.cdt.arduino.ui.internal.Activator; -import org.eclipse.jface.viewers.LabelProvider; -import org.eclipse.launchbar.core.target.ILaunchTarget; -import org.eclipse.swt.graphics.Image; - -public class ArduinoLaunchTargetLabelProvider extends LabelProvider { - - @Override - public String getText(Object element) { - if (element instanceof ILaunchTarget) { - return ((ILaunchTarget) element).getName(); - } - return super.getText(element); - } - - @Override - public Image getImage(Object element) { - if (element instanceof ILaunchTarget - && ((ILaunchTarget) element).getTypeId().equals(ArduinoRemoteConnection.TYPE_ID)) { - return Activator.getDefault().getImageRegistry().get(Activator.IMG_ARDUINO); - } - return super.getImage(element); - } - -} diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/ArduinoTargetPropertyPage.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/ArduinoTargetPropertyPage.java index f5bafced6bc..1b848f57268 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/ArduinoTargetPropertyPage.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/ArduinoTargetPropertyPage.java @@ -44,36 +44,24 @@ public class ArduinoTargetPropertyPage extends PropertyPage implements IWorkbenc Composite comp = new Composite(parent, SWT.NONE); comp.setLayout(new GridLayout(2, false)); - IRemoteConnection remoteConnection = (IRemoteConnection) getElement().getAdapter(IRemoteConnection.class); + IRemoteConnection remoteConnection = getElement().getAdapter(IRemoteConnection.class); ArduinoRemoteConnection arduinoRemote = remoteConnection.getService(ArduinoRemoteConnection.class); Label portLabel = new Label(comp, SWT.NONE); portLabel.setText(Messages.ArduinoTargetPropertyPage_0); - portSelector = new Combo(comp, SWT.READ_ONLY); + portSelector = new Combo(comp, SWT.NONE); portSelector.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); String currentPort = arduinoRemote.getPortName(); - int i = 0, portSel = -1; + portSelector.setText(currentPort); try { for (String port : SerialPort.list()) { portSelector.add(port); - if (port.equals(currentPort)) { - portSel = i; - } else { - portSel = portSel < 0 ? 0 : portSel; - } - i++; } } catch (IOException e) { Activator.log(e); } - if (portSel >= 0) { - portSelector.select(portSel); - } else { - setMessage(Messages.ArduinoTargetPropertyPage_1, ERROR); - setValid(false); - } Label boardLabel = new Label(comp, SWT.NONE); boardLabel.setText(Messages.ArduinoTargetPropertyPage_2); @@ -83,9 +71,9 @@ public class ArduinoTargetPropertyPage extends PropertyPage implements IWorkbenc try { ArduinoBoard currentBoard = arduinoRemote.getBoard(); - Collection boardList = ArduinoManager.instance.getBoards(); + Collection boardList = Activator.getService(ArduinoManager.class).getInstalledBoards(); boards = new ArduinoBoard[boardList.size()]; - i = 0; + int i = 0; int boardSel = 0; for (ArduinoBoard board : boardList) { boards[i] = board; @@ -105,7 +93,7 @@ public class ArduinoTargetPropertyPage extends PropertyPage implements IWorkbenc @Override public boolean performOk() { - IRemoteConnection remoteConnection = (IRemoteConnection) getElement().getAdapter(IRemoteConnection.class); + IRemoteConnection remoteConnection = getElement().getAdapter(IRemoteConnection.class); IRemoteConnectionWorkingCopy workingCopy = remoteConnection.getWorkingCopy(); String portName = portSelector.getItem(portSelector.getSelectionIndex()); diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/BoardPropertyControl.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/BoardPropertyControl.java new file mode 100644 index 00000000000..ada2671dfb5 --- /dev/null +++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/BoardPropertyControl.java @@ -0,0 +1,216 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.arduino.ui.internal.remote; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map.Entry; + +import org.eclipse.cdt.arduino.core.internal.HierarchicalProperties; +import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoard; +import org.eclipse.cdt.arduino.core.internal.board.ArduinoManager; +import org.eclipse.cdt.arduino.core.internal.board.ArduinoPackage; +import org.eclipse.cdt.arduino.core.internal.board.ArduinoPlatform; +import org.eclipse.cdt.arduino.core.internal.remote.ArduinoRemoteConnection; +import org.eclipse.cdt.arduino.ui.internal.Activator; +import org.eclipse.cdt.arduino.ui.internal.Messages; +import org.eclipse.cdt.serial.SerialPort; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.remote.core.IRemoteConnectionWorkingCopy; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; + +public class BoardPropertyControl extends Composite { + + private Combo portCombo; + private String[] portNames; + private String portName; + + private Combo boardCombo; + private ArduinoBoard[] boards; + private ArduinoBoard board; + + private List listeners = Collections.synchronizedList(new ArrayList()); + private List menuControls = new ArrayList<>(); + + public BoardPropertyControl(Composite parent, int style) { + super(parent, style); + setLayout(new GridLayout(2, false)); + + Label portLabel = new Label(this, SWT.NONE); + portLabel.setText(Messages.NewArduinoTargetWizardPage_4); + + portCombo = new Combo(this, SWT.NONE); + portCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + try { + portNames = SerialPort.list(); + } catch (IOException e) { + portNames = new String[0]; + Activator.log(e); + } + for (String portName : portNames) { + portCombo.add(portName); + } + if (portNames.length > 0) { + portCombo.select(0); + portName = portNames[0]; + } else { + portName = ""; //$NON-NLS-1$ + } + portCombo.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + portName = portCombo.getText(); + fireSelection(); + } + }); + + Label boardLabel = new Label(this, SWT.NONE); + boardLabel.setText(Messages.ArduinoTargetPropertyPage_2); + + boardCombo = new Combo(this, SWT.READ_ONLY); + boardCombo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + try { + List boardList = Activator.getService(ArduinoManager.class).getInstalledBoards(); + Collections.sort(boardList, new Comparator() { + @Override + public int compare(ArduinoBoard o1, ArduinoBoard o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + boards = boardList.toArray(new ArduinoBoard[boardList.size()]); + + for (ArduinoBoard board : boards) { + boardCombo.add(board.getName()); + } + + boardCombo.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + boardChanged(); + fireSelection(); + } + }); + + if (boards.length > 0) { + // TODO use preference to remember the last selected board + boardCombo.select(0); + board = boards[0]; + updateBoardMenu(); + } + } catch (CoreException e) { + Activator.log(e); + } + } + + public String getPortName() { + return portName; + } + + public ArduinoBoard getSelectedBoard() { + return board; + } + + public void addSelectionListener(SelectionListener listener) { + listeners.add(listener); + } + + private void updateBoardMenu() { + HierarchicalProperties menus = board.getMenus(); + if (menus != null) { + for (Entry menuEntry : menus.getChildren().entrySet()) { + Label label = new Label(this, SWT.NONE); + label.setText(board.getPlatform().getMenuText(menuEntry.getKey()) + ':'); + label.setData(menuEntry.getKey()); + menuControls.add(label); + + Combo combo = new Combo(this, SWT.READ_ONLY); + combo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + menuControls.add(combo); + + List ids = new ArrayList<>(); + for (Entry valueEntry : menuEntry.getValue().getChildren().entrySet()) { + String value = valueEntry.getValue().getValue(); + if (value != null) { + combo.add(value); + ids.add(valueEntry.getKey()); + } + } + combo.setData(ids); + combo.select(0); + } + } + } + + private void boardChanged() { + int index = boardCombo.getSelectionIndex(); + ArduinoBoard newBoard = index < 0 ? null : boards[index]; + if (newBoard != board) { + // Clear out old menus + for (Control control : menuControls) { + control.dispose(); + } + menuControls.clear(); + + board = newBoard; + updateBoardMenu(); + + layout(); + getShell().pack(); + redraw(); + } + } + + private void fireSelection() { + for (SelectionListener listener : listeners) { + Event event = new Event(); + event.widget = this; + listener.widgetSelected(new SelectionEvent(event)); + } + } + + public void apply(IRemoteConnectionWorkingCopy workingCopy) { + workingCopy.setAttribute(ArduinoRemoteConnection.PORT_NAME, portName); + + workingCopy.setAttribute(ArduinoRemoteConnection.BOARD_NAME, board.getName()); + + ArduinoPlatform platform = board.getPlatform(); + workingCopy.setAttribute(ArduinoRemoteConnection.PLATFORM_NAME, platform.getName()); + + ArduinoPackage pkg = platform.getPackage(); + workingCopy.setAttribute(ArduinoRemoteConnection.PACKAGE_NAME, pkg.getName()); + + String key = null; + for (Control control : menuControls) { + if (control instanceof Label) { + key = (String) control.getData(); + } else if (control instanceof Combo) { + Combo combo = (Combo) control; + @SuppressWarnings("unchecked") + String value = ((List) combo.getData()).get(combo.getSelectionIndex()); + + if (key != null) { + workingCopy.setAttribute(ArduinoBoard.MENU_QUALIFIER + key, value); + } + } + } + } + +} diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/NewArduinoTargetWizard.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/NewArduinoTargetWizard.java index 1b8401c90fc..9d07618a432 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/NewArduinoTargetWizard.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/NewArduinoTargetWizard.java @@ -9,9 +9,6 @@ package org.eclipse.cdt.arduino.ui.internal.remote; import java.util.Set; -import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoard; -import org.eclipse.cdt.arduino.core.internal.board.ArduinoPackage; -import org.eclipse.cdt.arduino.core.internal.board.ArduinoPlatform; import org.eclipse.cdt.arduino.core.internal.remote.ArduinoRemoteConnection; import org.eclipse.cdt.arduino.ui.internal.Activator; import org.eclipse.jface.wizard.Wizard; @@ -38,15 +35,7 @@ public class NewArduinoTargetWizard extends Wizard implements IRemoteUIConnectio return false; } - workingCopy.setAttribute(ArduinoRemoteConnection.PORT_NAME, page.portName); - - ArduinoBoard board = page.board; - workingCopy.setAttribute(ArduinoRemoteConnection.BOARD_NAME, board.getName()); - ArduinoPlatform platform = board.getPlatform(); - workingCopy.setAttribute(ArduinoRemoteConnection.PLATFORM_NAME, platform.getName()); - ArduinoPackage pkg = platform.getPackage(); - workingCopy.setAttribute(ArduinoRemoteConnection.PACKAGE_NAME, pkg.getName()); - + page.performFinish(workingCopy); return true; } diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/NewArduinoTargetWizardPage.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/NewArduinoTargetWizardPage.java index ccbb1cba41d..df8e8889145 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/NewArduinoTargetWizardPage.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/NewArduinoTargetWizardPage.java @@ -7,18 +7,9 @@ *******************************************************************************/ package org.eclipse.cdt.arduino.ui.internal.remote; -import java.io.IOException; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoard; -import org.eclipse.cdt.arduino.core.internal.board.ArduinoManager; -import org.eclipse.cdt.arduino.ui.internal.Activator; import org.eclipse.cdt.arduino.ui.internal.Messages; -import org.eclipse.cdt.serial.SerialPort; -import org.eclipse.core.runtime.CoreException; import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.remote.core.IRemoteConnectionWorkingCopy; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; @@ -26,7 +17,6 @@ import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; @@ -36,13 +26,7 @@ public class NewArduinoTargetWizardPage extends WizardPage { String name; private Text nameText; - String portName; - private String[] portNames; - private Combo portCombo; - - ArduinoBoard board; - private ArduinoBoard[] boards; - private Combo boardCombo; + BoardPropertyControl boardControl; public NewArduinoTargetWizardPage() { super("NewArduinoTargetPage"); //$NON-NLS-1$ @@ -53,17 +37,22 @@ public class NewArduinoTargetWizardPage extends WizardPage { @Override public void createControl(Composite parent) { Composite comp = new Composite(parent, SWT.NONE); - comp.setLayout(new GridLayout(2, false)); + comp.setLayout(new GridLayout()); - Label nameLabel = new Label(comp, SWT.NONE); + Composite nameComp = new Composite(comp, SWT.NONE); + nameComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + nameComp.setLayout(new GridLayout(2, false)); + + Label nameLabel = new Label(nameComp, SWT.NONE); nameLabel.setText(Messages.NewArduinoTargetWizardPage_2); - nameText = new Text(comp, SWT.BORDER | SWT.SINGLE); + nameText = new Text(nameComp, SWT.BORDER | SWT.SINGLE); nameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); nameText.setText(Messages.NewArduinoTargetWizardPage_3); nameText.addKeyListener(new KeyListener() { @Override public void keyReleased(KeyEvent e) { + name = nameText.getText(); updateStatus(); } @@ -72,51 +61,9 @@ public class NewArduinoTargetWizardPage extends WizardPage { } }); - Label portLabel = new Label(comp, SWT.NONE); - portLabel.setText(Messages.NewArduinoTargetWizardPage_4); - - portCombo = new Combo(comp, SWT.READ_ONLY); - portCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - try { - portNames = SerialPort.list(); - } catch (IOException e) { - portNames = new String[0]; - Activator.log(e); - } - for (String portName : portNames) { - portCombo.add(portName); - } - portCombo.select(0); - portCombo.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - updateStatus(); - } - }); - - Label boardLabel = new Label(comp, SWT.NONE); - boardLabel.setText(Messages.NewArduinoTargetWizardPage_5); - - boardCombo = new Combo(comp, SWT.READ_ONLY); - boardCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - try { - List boardList = ArduinoManager.instance.getInstalledBoards(); - Collections.sort(boardList, new Comparator() { - @Override - public int compare(ArduinoBoard o1, ArduinoBoard o2) { - return o1.getName().compareTo(o2.getName()); - } - }); - boards = boardList.toArray(new ArduinoBoard[0]); - - for (ArduinoBoard board : boards) { - boardCombo.add(board.getName()); - } - boardCombo.select(0); - } catch (CoreException e) { - Activator.log(e); - } - boardCombo.addSelectionListener(new SelectionAdapter() { + boardControl = new BoardPropertyControl(comp, SWT.NONE); + boardControl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + boardControl.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { updateStatus(); @@ -128,15 +75,12 @@ public class NewArduinoTargetWizardPage extends WizardPage { } private void updateStatus() { - name = nameText.getText(); + setPageComplete(name != null && !name.isEmpty() && boardControl.getPortName() != null + && boardControl.getSelectedBoard() != null); + } - int portIndex = portCombo.getSelectionIndex(); - portName = portIndex < 0 ? null : portNames[portIndex]; - - int boardIndex = boardCombo.getSelectionIndex(); - board = boardIndex < 0 ? null : boards[boardIndex]; - - setPageComplete(!name.isEmpty() && portName != null && board != null); + public void performFinish(IRemoteConnectionWorkingCopy workingCopy) { + boardControl.apply(workingCopy); } }