From a9681bd833bc8632312a2019acc19badc2272cb0 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 21 Nov 2019 11:24:25 +0100 Subject: [PATCH] Added arduino-cli daemon startup and some basic control code --- app/src/processing/app/Base.java | 2 + .../src/cc/arduino/cli/ArduinoCore.java | 129 ++++++++++++++++++ .../cc/arduino/cli/ArduinoCoreInstance.java | 128 +++++++++++++++++ .../src/processing/app/BaseNoGui.java | 17 +++ 4 files changed, 276 insertions(+) create mode 100644 arduino-core/src/cc/arduino/cli/ArduinoCore.java create mode 100644 arduino-core/src/cc/arduino/cli/ArduinoCoreInstance.java diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 63ecd8501..ef2d19770 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -240,6 +240,8 @@ public class Base { } } + BaseNoGui.initArduinoCoreService(); + SplashScreenHelper splash; if (parser.isGuiMode()) { // Setup all notification widgets diff --git a/arduino-core/src/cc/arduino/cli/ArduinoCore.java b/arduino-core/src/cc/arduino/cli/ArduinoCore.java new file mode 100644 index 000000000..4b92a7d29 --- /dev/null +++ b/arduino-core/src/cc/arduino/cli/ArduinoCore.java @@ -0,0 +1,129 @@ +/* + * This file is part of Arduino. + * + * Copyright 2019 Arduino LLC (http://www.arduino.cc/) + * + * Arduino is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.cli; + +import java.io.File; +import java.io.IOException; +import java.util.Iterator; + +import cc.arduino.cli.commands.ArduinoCoreGrpc; +import cc.arduino.cli.commands.ArduinoCoreGrpc.ArduinoCoreBlockingStub; +import cc.arduino.cli.commands.Commands.Configuration; +import cc.arduino.cli.commands.Commands.InitReq; +import cc.arduino.cli.commands.Commands.InitResp; +import cc.arduino.cli.commands.Common.Instance; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import processing.app.BaseNoGui; +import processing.app.debug.MessageSiphon; +import processing.app.helpers.ProcessUtils; + +public class ArduinoCore { + + private Process cliProcess; + private ArduinoCoreBlockingStub blocking; + // private ArduinoCoreStub async; + + public ArduinoCore() throws IOException { + String cliPath = BaseNoGui.getContentFile("arduino-cli").getAbsolutePath(); + cliProcess = ProcessUtils.exec(new String[] { cliPath, "daemon" }); + new MessageSiphon(cliProcess.getInputStream(), (msg) -> { + System.out.println("CLI> " + msg); + }); + new MessageSiphon(cliProcess.getErrorStream(), (msg) -> { + System.err.println("CLI> " + msg); + }); + + // TODO: Do a better job managing the arduino-cli process + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + if (!cliProcess.isAlive()) { + int res; + try { + res = cliProcess.waitFor(); + throw new IOException( + "Arduino server terminated with return code " + res); + } catch (InterruptedException e) { + } + throw new IOException("Arduino server terminated"); + } + + ManagedChannel channel = ManagedChannelBuilder // + .forAddress("127.0.0.1", 50051) // + .usePlaintext() // + .build(); + + blocking = ArduinoCoreGrpc.newBlockingStub(channel); + // async = ArduinoCoreGrpc.newStub(channel); + } + + public ArduinoCoreInstance init(File dataDir, File sketchbookDir) { + InitReq req = InitReq.newBuilder() + .setConfiguration(Configuration.newBuilder() // + .setDataDir(dataDir.getAbsolutePath()) // + .setSketchbookDir(sketchbookDir.getAbsolutePath())) + .build(); + Iterator resp = blocking.init(req); + Instance instance = null; + while (resp.hasNext()) { + InitResp r = resp.next(); + if (r.hasTaskProgress()) { + System.out.println(r.getTaskProgress()); + } + if (r.hasDownloadProgress()) { + System.out.println(r.getDownloadProgress()); + } + if (r.getInstance() != null) { + if (!r.getLibrariesIndexError().isEmpty()) { + System.err.println(r.getLibrariesIndexError()); + } + r.getPlatformsIndexErrorsList().forEach(System.err::println); + instance = r.getInstance(); + } + } + return new ArduinoCoreInstance(instance, blocking); + } + + public static void main(String[] args) { + try { + ArduinoCore core = new ArduinoCore(); + ArduinoCoreInstance instance = core.init(new File("/mnt/ramdisk"), + new File("/mnt/ramdisk/sketchbook")); + instance.boardDetails("arduino:samd:mkr1000"); + instance.compile("arduino:samd:mkr1000", + "/home/megabug/Arduino/alloc_check"); + } catch (Throwable e) { + e.printStackTrace(); + } + System.exit(0); + } +} diff --git a/arduino-core/src/cc/arduino/cli/ArduinoCoreInstance.java b/arduino-core/src/cc/arduino/cli/ArduinoCoreInstance.java new file mode 100644 index 000000000..a00fe5191 --- /dev/null +++ b/arduino-core/src/cc/arduino/cli/ArduinoCoreInstance.java @@ -0,0 +1,128 @@ +/* + * This file is part of Arduino. + * + * Copyright 2019 Arduino LLC (http://www.arduino.cc/) + * + * Arduino is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.cli; + +import java.util.Iterator; +import java.util.List; + +import com.google.protobuf.ByteString; + +import cc.arduino.cli.commands.Board.BoardDetailsReq; +import cc.arduino.cli.commands.Board.BoardDetailsResp; +import cc.arduino.cli.commands.Commands.DestroyReq; +import cc.arduino.cli.commands.Commands.RescanReq; +import cc.arduino.cli.commands.Common.Instance; +import cc.arduino.cli.commands.Compile.CompileReq; +import cc.arduino.cli.commands.Compile.CompileResp; +import cc.arduino.cli.commands.Lib.LibrarySearchReq; +import cc.arduino.cli.commands.Lib.LibrarySearchResp; +import cc.arduino.cli.commands.Lib.SearchedLibrary; +import io.grpc.StatusException; +import io.grpc.StatusRuntimeException; +import cc.arduino.cli.commands.ArduinoCoreGrpc.ArduinoCoreBlockingStub; + +public class ArduinoCoreInstance { + + private Instance instance; + private ArduinoCoreBlockingStub stub; + + public ArduinoCoreInstance(Instance instance, + ArduinoCoreBlockingStub blocking) { + this.instance = instance; + this.stub = blocking; + } + + public void boardDetails(String fqbn) throws StatusException { + try { + BoardDetailsReq req = BoardDetailsReq.newBuilder() // + .setFqbn(fqbn) // + .setInstance(instance) // + .build(); + BoardDetailsResp resp = stub.boardDetails(req); + System.out.println(resp.getName()); + } catch (StatusRuntimeException e) { + throw e.getStatus().asException(); + } + } + + public void compile(String fqbn, String sketchPath) throws StatusException { + try { + CompileReq req = CompileReq.newBuilder() // + .setInstance(instance) // + .setFqbn(fqbn) // + .setSketchPath(sketchPath) // + .setVerbose(true) // + .build(); + Iterator stream = stub.compile(req); + while (stream.hasNext()) { + CompileResp resp = stream.next(); + ByteString out = resp.getOutStream(); + if (out != null) + System.out.print(out.toStringUtf8()); + } + } catch (StatusRuntimeException e) { + throw e.getStatus().asException(); + } + } + + public void rescan() throws StatusException { + try { + stub.rescan(RescanReq.newBuilder() // + .setInstance(instance) // + .build()); + } catch (StatusRuntimeException e) { + throw e.getStatus().asException(); + } + } + + public void destroy() throws StatusException { + try { + stub.destroy(DestroyReq.newBuilder() // + .setInstance(instance).build()); + } catch (StatusRuntimeException e) { + throw e.getStatus().asException(); + } + } + + // Lib functions + + public List searchLibrary(String query) + throws StatusException { + try { + LibrarySearchResp resp = stub.librarySearch(LibrarySearchReq.newBuilder() // + .setInstance(instance) // + .setQuery(query) // + .build()); + return resp.getLibrariesList(); + } catch (StatusRuntimeException e) { + throw e.getStatus().asException(); + } + } +} diff --git a/arduino-core/src/processing/app/BaseNoGui.java b/arduino-core/src/processing/app/BaseNoGui.java index 438771b86..00c1b7385 100644 --- a/arduino-core/src/processing/app/BaseNoGui.java +++ b/arduino-core/src/processing/app/BaseNoGui.java @@ -1,6 +1,8 @@ package processing.app; import cc.arduino.Constants; +import cc.arduino.cli.ArduinoCore; +import cc.arduino.cli.ArduinoCoreInstance; import cc.arduino.contributions.GPGDetachedSignatureVerifier; import cc.arduino.contributions.VersionComparator; import cc.arduino.contributions.libraries.LibrariesIndexer; @@ -105,6 +107,21 @@ public class BaseNoGui { private static File buildCache; + private static ArduinoCoreInstance arduinoCoreInstance; + + public static void initArduinoCoreService() { + try { + ArduinoCore core = new ArduinoCore(); + arduinoCoreInstance = core.init(getSettingsFolder(), getSketchbookFolder()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static ArduinoCoreInstance getArduinoCoreService() { + return arduinoCoreInstance; + } + // Returns a File object for the given pathname. If the pathname // is not absolute, it is interpreted relative to the current // directory when starting the IDE (which is not the same as the