Compare commits

..

27 Commits
0.1.0 ... 0.1.2

Author SHA1 Message Date
Akos Kitta
fbebfc7cca Use 0.13.0 CLI. Updated version to 0.1.2.
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-09-14 14:14:37 +02:00
Akos Kitta
c3eb3e4622 arduino/arduino-pro-ide#337: Use bigger min window
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-09-10 10:45:38 +02:00
Akos Kitta
30421f0de4 Enabled file logging for the backend process.
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-09-10 10:45:38 +02:00
Akos Kitta
daa25794ef Better error handling when killing the BE process.
Catch the ESRCH error when terminating non-existing backend process.

Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-09-10 10:45:38 +02:00
Akos Kitta
ec8df37c2d Fixed the output channel registry for extensions.
See: eclipse-theia/theia#8122

Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-09-10 10:45:38 +02:00
Akos Kitta
cb24571eeb Customized channel to cancel the queue on dispose.
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-09-10 10:45:38 +02:00
Akos Kitta
2f8e28b296 Patched the menu ordering. (Workaround for eclipse-theia/theia#8377)
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-09-07 13:42:11 +02:00
Akos Kitta
524fbbdf40 arduino/arduino-pro-ide#336: Fixed 'Save As...'
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-09-07 13:42:11 +02:00
Akos Kitta
7a37aa2e2f ATL-78: Implemented include library.
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-09-07 13:42:11 +02:00
Akos Kitta
56ff86629c ATL-73: Added library examples to the app.
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-09-07 13:42:11 +02:00
Akos Kitta
1c9fcd0cdf ATL-302: Added built-in examples to the app.
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-09-07 13:42:11 +02:00
Akos Kitta
b5d7c3b45d ATL-61: Implemented burn bootloader.
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-09-07 13:42:11 +02:00
Akos Kitta
525e688d70 Use git log as of the body for the GH release.
There is no need to prepend any other info to the release body.

Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-09-04 13:12:41 +02:00
Akos Kitta
d7f4d0c18e Fixed the tag name of the GH releases.
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-09-04 13:12:41 +02:00
Akos Kitta
6ae7404092 ATL-439: Create the GH release in the public repo.
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-09-02 21:05:46 +02:00
Akos Kitta
6b1b9c0524 Use docker://plugins/s3 action for the S3 upload
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-09-02 21:05:46 +02:00
Akos Kitta
717db95c90 ATL-424: Generate a changelog for the nightlies.
Configure generated changelog output from `changelog` job so it can be used in the `release` job of the workflow

It is necessary to define job outputs to make them accessible via the `needs` context in other jobs.

Reference: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idneeds

Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-09-02 21:05:46 +02:00
Akos Kitta
7536c3a485 ATL-423: Can execute the nightly manually.
We consider a build as nightly, if was started by the
CRON job, or was manually triggered from the master
branch.

Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-09-02 21:05:46 +02:00
Akos Kitta
ec7df884ee Merge pull request #143 from bcmi-labs/0.1.1
0.1.1
2020-08-26 16:22:34 +02:00
Akos Kitta
24b6d84d27 Updated the CLI to 0.12.1.
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-08-26 15:23:24 +02:00
Akos Kitta
4435696949 Updated the versions from 0.1.0 to 0.1.1.
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-08-26 15:13:04 +02:00
Akos Kitta
6aa3ff8044 Merge pull request #141 from bcmi-labs/arduino/arduino-pro-ide#311
GH-311: Fixed FS path to URI conversion issue.
2020-08-25 18:10:10 +02:00
Akos Kitta
4b44113f2c GH-311: Fixed FS path to URI conversion issue.
Instead of passing the FS path (`string`) to the `LoadSketch` method,
we have to convert it into a proper URI string.

Closes arduino/arduino-pro-ide#311

Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-08-25 16:03:49 +02:00
Akos Kitta
c6ad0f582a Merge pull request #139 from bcmi-labs/build-on-ubuntu
Added steps to build the app from source
2020-08-24 20:37:27 +02:00
Akos Kitta
4b8b468e53 Added steps to build the app from source
Verified on 18.04.4

Signed-off-by: Akos Kitta <kittaakos@typefox.io>
2020-08-24 18:52:25 +02:00
Akos Kitta
ba319b23d9 Merge pull request #133 from bcmi-labs/per1234/name-snapshot-archive-with-commit
Use short commit hash in "snapshot" build artifact archive filename
2020-08-24 16:43:27 +02:00
per1234
70278fed6f Use short commit hash in "snapshot" build artifact archive filename
When you have multiple snapshot builds on your computer for testing purposes, it's difficult to keep track of which is which. The commit hash is shown by the running application, but it's more convenient to have the installation also identified by its folder name.

Adding the short commit hash to the build archive filename (and thus the extracted folder name) provides a clear identifier for each build.

Before this change, the archive is named like:
arduino-pro-ide_snapshot_Linux_64bit.zip

after:
arduino-pro-ide_0.0.7-snapshot.1b8c510_Linux_64bit.zip
2020-08-24 05:12:10 -07:00
62 changed files with 4102 additions and 542 deletions

View File

@@ -6,6 +6,7 @@ on:
- master
tags:
- '[0-9]+.[0-9]+.[0-9]+*'
workflow_dispatch:
pull_request:
branches:
- master
@@ -58,7 +59,7 @@ jobs:
AC_PASSWORD: ${{ secrets.AC_PASSWORD }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
IS_NIGHTLY: ${{ github.event_name == 'schedule' }}
IS_NIGHTLY: ${{ github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/master') }}
IS_RELEASE: ${{ startsWith(github.ref, 'refs/tags/') }}
run: |
# electron-builder will try to sign during the Windows job if these environment variables are defined
@@ -76,9 +77,51 @@ jobs:
name: build-artifacts
path: electron/build/dist/build-artifacts/
publish:
changelog:
needs: build
if: github.event_name == 'schedule'
runs-on: ubuntu-latest
outputs:
BODY: ${{ steps.changelog.outputs.BODY }}
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0 # To fetch all history for all branches and tags.
- name: Generate Changelog
id: changelog
env:
IS_RELEASE: ${{ startsWith(github.ref, 'refs/tags/') }}
run: |
export LATEST_TAG=$(git describe --abbrev=0)
export GIT_LOG=$(git log --pretty=" - %s [%h]" $LATEST_TAG..HEAD | sed 's/ *$//g')
if [ "$IS_RELEASE" = true ]; then
export BODY=$(echo -e "$GIT_LOG")
else
export LATEST_TAG_WITH_LINK=$(echo "[$LATEST_TAG](https://github.com/arduino/arduino-pro-ide/releases/tag/$LATEST_TAG)")
if [ -z "$GIT_LOG" ]; then
export BODY="There were no changes since version $LATEST_TAG_WITH_LINK."
else
export BODY=$(echo -e "Changes since version $LATEST_TAG_WITH_LINK:\n$GIT_LOG")
fi
fi
echo -e "$BODY"
OUTPUT_SAFE_BODY="${BODY//'%'/'%25'}"
OUTPUT_SAFE_BODY="${OUTPUT_SAFE_BODY//$'\n'/'%0A'}"
OUTPUT_SAFE_BODY="${OUTPUT_SAFE_BODY//$'\r'/'%0D'}"
echo "::set-output name=BODY::$OUTPUT_SAFE_BODY"
echo "$BODY" > CHANGELOG.txt
- name: Upload Changelog [GitHub Actions]
if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/master')
uses: actions/upload-artifact@v2
with:
name: build-artifacts
path: CHANGELOG.txt
publish:
needs: changelog
if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/master')
runs-on: ubuntu-latest
steps:
- name: Download [GitHub Actions]
@@ -88,16 +131,17 @@ jobs:
path: build-artifacts
- name: Publish Nightly [S3]
uses: kittaakos/upload-s3-action@v0.0.1
with:
aws_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws_bucket: ${{ secrets.DOWNLOADS_BUCKET }}
source_dir: build-artifacts/
destination_dir: arduino-pro-ide/nightly/
uses: docker://plugins/s3
env:
PLUGIN_SOURCE: "build-artifacts/*"
PLUGIN_STRIP_PREFIX: "build-artifacts/"
PLUGIN_TARGET: "/arduino-pro-ide/nightly"
PLUGIN_BUCKET: ${{ secrets.DOWNLOADS_BUCKET }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
release:
needs: build
needs: changelog
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
steps:
@@ -107,27 +151,28 @@ jobs:
name: build-artifacts
path: build-artifacts
- name: Create Release [GitHub]
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
- name: Get Tag
id: tag_name
run: |
echo ::set-output name=TAG_NAME::${GITHUB_REF#refs/tags/}
- name: Publish Release [GitHub]
uses: svenstaro/upload-release-action@v1-release
uses: kittaakos/upload-release-action@dev
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
repo_token: ${{ secrets.RELEASE_TOKEN }}
repo_name: arduino/arduino-pro-ide
release_name: ${{ steps.tag_name.outputs.TAG_NAME }}
file: build-artifacts/*
tag: ${{ github.ref }}
file_glob: true
body: ${{ needs.changelog.outputs.BODY }}
- name: Publish Release [S3]
uses: kittaakos/upload-s3-action@v0.0.1
with:
aws_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws_bucket: ${{ secrets.DOWNLOADS_BUCKET }}
source_dir: build-artifacts/
destination_dir: arduino-pro-ide/
uses: docker://plugins/s3
env:
PLUGIN_SOURCE: "build-artifacts/*"
PLUGIN_STRIP_PREFIX: "build-artifacts/"
PLUGIN_TARGET: "/arduino-pro-ide"
PLUGIN_BUCKET: ${{ secrets.DOWNLOADS_BUCKET }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

1
.gitignore vendored
View File

@@ -4,6 +4,7 @@ node_modules/
lib/
downloads/
build/
Examples/
!electron/build/
src-gen/
*webpack.config.js

View File

@@ -1,11 +1,11 @@
{
"name": "arduino-debugger-extension",
"version": "0.1.0",
"version": "0.1.2",
"description": "An extension for debugging Arduino programs",
"license": "MIT",
"dependencies": {
"@theia/debug": "next",
"arduino-ide-extension": "0.1.0",
"arduino-ide-extension": "0.1.2",
"cdt-gdb-adapter": "^0.0.14",
"vscode-debugadapter": "^1.26.0",
"vscode-debugprotocol": "^1.26.0"

View File

@@ -1,13 +1,14 @@
{
"name": "arduino-ide-extension",
"version": "0.1.0",
"version": "0.1.2",
"description": "An extension for Theia building the Arduino IDE",
"license": "MIT",
"scripts": {
"prepare": "yarn download-cli && yarn download-ls && yarn run clean && yarn run build",
"prepare": "yarn download-cli && yarn download-ls && yarn clean && yarn download-examples && yarn build",
"clean": "rimraf lib",
"download-cli": "node ./scripts/download-cli.js",
"download-ls": "node ./scripts/download-ls.js",
"download-examples": "node ./scripts/download-examples.js",
"generate-protocol": "node ./scripts/generate-protocol.js",
"lint": "tslint -c ./tslint.json --project ./tsconfig.json",
"build": "tsc && ncp ./src/node/cli-protocol/ ./lib/node/cli-protocol/ && yarn lint",
@@ -99,7 +100,8 @@
"lib",
"src",
"build",
"data"
"data",
"examples"
],
"theiaExtensions": [
{

View File

@@ -10,7 +10,7 @@
(() => {
const DEFAULT_VERSION = '0.12.0'; // require('moment')().format('YYYYMMDD');
const DEFAULT_VERSION = '0.13.0'; // require('moment')().format('YYYYMMDD');
const path = require('path');
const shell = require('shelljs');

View File

@@ -0,0 +1,23 @@
// @ts-check
(async () => {
const os = require('os');
const path = require('path');
const shell = require('shelljs');
const { v4 } = require('uuid');
const repository = path.join(os.tmpdir(), `${v4()}-arduino-examples`);
if (shell.mkdir('-p', repository).code !== 0) {
shell.exit(1);
}
if (shell.exec(`git clone https://github.com/arduino/arduino.git --depth 1 ${repository}`).code !== 0) {
shell.exit(1);
}
const destination = path.join(__dirname, '..', 'Examples');
shell.mkdir('-p', destination);
shell.cp('-fR', path.join(repository, 'build', 'shared', 'examples', '*'), destination);
})();

View File

@@ -16,7 +16,7 @@
shell.exit(1);
}
if (shell.exec(`git clone https://github.com/arduino/arduino-cli.git ${repository}`).code !== 0) {
if (shell.exec(`git clone --depth 1 https://github.com/arduino/arduino-cli.git ${repository}`).code !== 0) {
shell.exit(1);
}

View File

@@ -12,7 +12,7 @@ import { ArduinoLanguageClientContribution } from './language/arduino-language-c
import { LibraryListWidget } from './library/library-list-widget';
import { ArduinoFrontendContribution } from './arduino-frontend-contribution';
import { ArduinoLanguageGrammarContribution } from './language/arduino-language-grammar-contribution';
import { LibraryService, LibraryServicePath } from '../common/protocol/library-service';
import { LibraryServiceServer, LibraryServiceServerPath } from '../common/protocol/library-service';
import { BoardsService, BoardsServicePath, BoardsServiceClient } from '../common/protocol/boards-service';
import { SketchesService, SketchesServicePath } from '../common/protocol/sketches-service';
import { SketchesServiceClientImpl } from '../common/protocol/sketches-service-client-impl';
@@ -117,6 +117,14 @@ import { EditorWidgetFactory as TheiaEditorWidgetFactory } from '@theia/editor/l
import { EditorWidgetFactory } from './theia/editor/editor-widget-factory';
import { OutputWidget as TheiaOutputWidget } from '@theia/output/lib/browser/output-widget';
import { OutputWidget } from './theia/output/output-widget';
import { BurnBootloader } from './contributions/burn-bootloader';
import { ExamplesServicePath, ExamplesService } from '../common/protocol/examples-service';
import { BuiltInExamples, LibraryExamples } from './contributions/examples';
import { LibraryServiceProvider } from './library/library-service-provider';
import { IncludeLibrary } from './contributions/include-library';
import { OutputChannelManager as TheiaOutputChannelManager } from '@theia/output/lib/common/output-channel';
import { OutputChannelManager } from './theia/output/output-channel';
import { OutputChannelRegistryMainImpl as TheiaOutputChannelRegistryMainImpl, OutputChannelRegistryMainImpl } from './theia/plugin-ext/output-channel-registry-main';
const ElementQueries = require('css-element-queries/src/ElementQueries');
@@ -150,7 +158,9 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(ListItemRenderer).toSelf().inSingletonScope();
// Library service
bind(LibraryService).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, LibraryServicePath)).inSingletonScope();
bind(LibraryServiceProvider).toSelf().inSingletonScope();
bind(LibraryServiceServer).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, LibraryServiceServerPath)).inSingletonScope();
// Library list widget
bind(LibraryListWidget).toSelf();
bindViewContribution(bind, LibraryListWidgetFrontendContribution);
@@ -303,6 +313,10 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
});
bind(OutputWidget).toSelf().inSingletonScope();
rebind(TheiaOutputWidget).toService(OutputWidget);
bind(OutputChannelManager).toSelf().inSingletonScope();
rebind(TheiaOutputChannelManager).toService(OutputChannelManager);
bind(OutputChannelRegistryMainImpl).toSelf().inTransientScope();
rebind(TheiaOutputChannelRegistryMainImpl).toService(OutputChannelRegistryMainImpl);
// Show a disconnected status bar, when the daemon is not available
bind(ApplicationConnectionStatusContribution).toSelf().inSingletonScope();
@@ -346,6 +360,9 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
// File-system extension
bind(FileSystemExt).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, FileSystemExtPath)).inSingletonScope();
// Examples service
bind(ExamplesService).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, ExamplesServicePath)).inSingletonScope();
Contribution.configure(bind, NewSketch);
Contribution.configure(bind, OpenSketch);
Contribution.configure(bind, CloseSketch);
@@ -358,4 +375,8 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
Contribution.configure(bind, QuitApp);
Contribution.configure(bind, SketchControl);
Contribution.configure(bind, Settings);
Contribution.configure(bind, BurnBootloader);
Contribution.configure(bind, BuiltInExamples);
Contribution.configure(bind, LibraryExamples);
Contribution.configure(bind, IncludeLibrary);
});

View File

@@ -27,13 +27,13 @@ export class BoardsDataStore implements FrontendApplicationContribution {
protected readonly onChangedEmitter = new Emitter<void>();
onStart(): void {
this.boardsServiceClient.onBoardsPackageInstalled(async ({ pkg }) => {
const { installedVersion: version } = pkg;
this.boardsServiceClient.onBoardsPackageInstalled(async ({ item }) => {
const { installedVersion: version } = item;
if (!version) {
return;
}
let shouldFireChanged = false;
for (const fqbn of pkg.boards.map(({ fqbn }) => fqbn).filter(notEmpty).filter(fqbn => !!fqbn)) {
for (const fqbn of item.boards.map(({ fqbn }) => fqbn).filter(notEmpty).filter(fqbn => !!fqbn)) {
const key = this.getStorageKey(fqbn, version);
let data = await this.storageService.getData<ConfigOption[] | undefined>(key);
if (!data || !data.length) {

View File

@@ -1,11 +1,20 @@
import { injectable, inject, optional } from 'inversify';
import { injectable, inject } from 'inversify';
import { Emitter } from '@theia/core/lib/common/event';
import { ILogger } from '@theia/core/lib/common/logger';
import { MessageService } from '@theia/core/lib/common/message-service';
import { StorageService } from '@theia/core/lib/browser/storage-service';
import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application';
import { RecursiveRequired } from '../../common/types';
import { BoardsServiceClient, AttachedBoardsChangeEvent, BoardInstalledEvent, Board, Port, BoardUninstalledEvent, BoardsService } from '../../common/protocol';
import {
Port,
Board,
BoardsService,
BoardsPackage,
InstalledEvent,
UninstalledEvent,
BoardsServiceClient,
AttachedBoardsChangeEvent
} from '../../common/protocol';
import { BoardsConfig } from './boards-config';
import { naturalCompare } from '../../common/utils';
import { compareAnything } from '../theia/monaco/comparers';
@@ -21,15 +30,14 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp
@inject(ILogger)
protected logger: ILogger;
@optional()
@inject(MessageService)
protected messageService: MessageService;
@inject(StorageService)
protected storageService: StorageService;
protected readonly onBoardsPackageInstalledEmitter = new Emitter<BoardInstalledEvent>();
protected readonly onBoardsPackageUninstalledEmitter = new Emitter<BoardUninstalledEvent>();
protected readonly onBoardsPackageInstalledEmitter = new Emitter<InstalledEvent<BoardsPackage>>();
protected readonly onBoardsPackageUninstalledEmitter = new Emitter<UninstalledEvent<BoardsPackage>>();
protected readonly onAttachedBoardsChangedEmitter = new Emitter<AttachedBoardsChangeEvent>();
protected readonly onBoardsConfigChangedEmitter = new Emitter<BoardsConfig.Config>();
protected readonly onAvailableBoardsChangedEmitter = new Emitter<AvailableBoard[]>();
@@ -119,13 +127,13 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp
return false;
}
notifyBoardInstalled(event: BoardInstalledEvent): void {
this.logger.info('Board installed: ', JSON.stringify(event));
notifyInstalled(event: InstalledEvent<BoardsPackage>): void {
this.logger.info('Boards package installed: ', JSON.stringify(event));
this.onBoardsPackageInstalledEmitter.fire(event);
const { selectedBoard } = this.boardsConfig;
const { installedVersion, id } = event.pkg;
const { installedVersion, id } = event.item;
if (selectedBoard) {
const installedBoard = event.pkg.boards.find(({ name }) => name === selectedBoard.name);
const installedBoard = event.item.boards.find(({ name }) => name === selectedBoard.name);
if (installedBoard && (!selectedBoard.fqbn || selectedBoard.fqbn === installedBoard.fqbn)) {
this.logger.info(`Board package ${id}[${installedVersion}] was installed. Updating the FQBN of the currently selected ${selectedBoard.name} board. [FQBN: ${installedBoard.fqbn}]`);
this.boardsConfig = {
@@ -136,14 +144,14 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp
}
}
notifyBoardUninstalled(event: BoardUninstalledEvent): void {
this.logger.info('Board uninstalled: ', JSON.stringify(event));
notifyUninstalled(event: UninstalledEvent<BoardsPackage>): void {
this.logger.info('Boards package uninstalled: ', JSON.stringify(event));
this.onBoardsPackageUninstalledEmitter.fire(event);
const { selectedBoard } = this.boardsConfig;
if (selectedBoard && selectedBoard.fqbn) {
const uninstalledBoard = event.pkg.boards.find(({ name }) => name === selectedBoard.name);
const uninstalledBoard = event.item.boards.find(({ name }) => name === selectedBoard.name);
if (uninstalledBoard && uninstalledBoard.fqbn === selectedBoard.fqbn) {
this.logger.info(`Board package ${event.pkg.id} was uninstalled. Discarding the FQBN of the currently selected ${selectedBoard.name} board.`);
this.logger.info(`Board package ${event.item.id} was uninstalled. Discarding the FQBN of the currently selected ${selectedBoard.name} board.`);
const selectedBoardWithoutFqbn = {
name: selectedBoard.name
// No FQBN
@@ -219,7 +227,7 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp
}
if (!config.selectedBoard) {
if (!options.silent && this.messageService) {
if (!options.silent) {
this.messageService.warn('No boards selected.', { timeout: 3000 });
}
return false;
@@ -241,14 +249,14 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp
const { name } = config.selectedBoard;
if (!config.selectedPort) {
if (!options.silent && this.messageService) {
if (!options.silent) {
this.messageService.warn(`No ports selected for board: '${name}'.`, { timeout: 3000 });
}
return false;
}
if (!config.selectedBoard.fqbn) {
if (!options.silent && this.messageService) {
if (!options.silent) {
this.messageService.warn(`The FQBN is not available for the selected board ${name}. Do you have the corresponding core installed?`, { timeout: 3000 });
}
return false;

View File

@@ -0,0 +1,94 @@
import { inject, injectable } from 'inversify';
import { OutputChannelManager } from '@theia/output/lib/common/output-channel';
import { CoreService } from '../../common/protocol';
import { ArduinoMenus } from '../menu/arduino-menus';
import { BoardsDataStore } from '../boards/boards-data-store';
import { MonitorConnection } from '../monitor/monitor-connection';
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
import { SketchContribution, Command, CommandRegistry, MenuModelRegistry } from './contribution';
@injectable()
export class BurnBootloader extends SketchContribution {
@inject(CoreService)
protected readonly coreService: CoreService;
@inject(MonitorConnection)
protected readonly monitorConnection: MonitorConnection;
@inject(BoardsDataStore)
protected readonly boardsDataStore: BoardsDataStore;
@inject(BoardsServiceClientImpl)
protected readonly boardsServiceClientImpl: BoardsServiceClientImpl;
@inject(OutputChannelManager)
protected readonly outputChannelManager: OutputChannelManager;
registerCommands(registry: CommandRegistry): void {
registry.registerCommand(BurnBootloader.Commands.BURN_BOOTLOADER, {
execute: () => this.burnBootloader()
});
}
registerMenus(registry: MenuModelRegistry): void {
registry.registerMenuAction(ArduinoMenus.TOOLS__BOARD_SETTINGS_GROUP, {
commandId: BurnBootloader.Commands.BURN_BOOTLOADER.id,
label: 'Burn Bootloader',
order: 'z99'
});
}
async burnBootloader(): Promise<void> {
const monitorConfig = this.monitorConnection.monitorConfig;
if (monitorConfig) {
await this.monitorConnection.disconnect();
}
try {
const { boardsConfig } = this.boardsServiceClientImpl;
if (!boardsConfig || !boardsConfig.selectedBoard) {
throw new Error('No boards selected. Please select a board.');
}
if (!boardsConfig.selectedBoard.fqbn) {
throw new Error(`No core is installed for the '${boardsConfig.selectedBoard.name}' board. Please install the core.`);
}
const { selectedPort } = boardsConfig;
if (!selectedPort) {
throw new Error('No ports selected. Please select a port.');
}
const port = selectedPort.address;
const [fqbn, { selectedProgrammer: programmer }] = await Promise.all([
this.boardsDataStore.appendConfigToFqbn(boardsConfig.selectedBoard.fqbn),
this.boardsDataStore.getData(boardsConfig.selectedBoard.fqbn)
]);
if (!programmer) {
throw new Error('Programmer is not selected. Please select a programmer from the `Tools` > `Programmer` menu.');
}
this.outputChannelManager.getChannel('Arduino: bootloader').clear();
await this.coreService.burnBootloader({
fqbn,
programmer,
port
});
this.messageService.info('Done burning bootloader.', { timeout: 1000 });
} catch (e) {
this.messageService.error(e.toString());
} finally {
if (monitorConfig) {
await this.monitorConnection.connect(monitorConfig);
}
}
}
}
export namespace BurnBootloader {
export namespace Commands {
export const BURN_BOOTLOADER: Command = {
id: 'arduino-burn-bootloader'
};
}
}

View File

@@ -2,6 +2,7 @@ import { inject, injectable, interfaces } from 'inversify';
import URI from '@theia/core/lib/common/uri';
import { ILogger } from '@theia/core/lib/common/logger';
import { FileSystem } from '@theia/filesystem/lib/common';
import { MaybePromise } from '@theia/core/lib/common/types';
import { LabelProvider } from '@theia/core/lib/browser/label-provider';
import { MessageService } from '@theia/core/lib/common/message-service';
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
@@ -13,11 +14,12 @@ import { Command, CommandRegistry, CommandContribution, CommandService } from '@
import { EditorMode } from '../editor-mode';
import { SketchesServiceClientImpl } from '../../common/protocol/sketches-service-client-impl';
import { SketchesService, ConfigService, FileSystemExt, Sketch } from '../../common/protocol';
import { FrontendApplicationContribution, FrontendApplication } from '@theia/core/lib/browser';
export { Command, CommandRegistry, MenuModelRegistry, KeybindingRegistry, TabBarToolbarRegistry, URI, Sketch, open };
@injectable()
export abstract class Contribution implements CommandContribution, MenuContribution, KeybindingContribution, TabBarToolbarContribution {
export abstract class Contribution implements CommandContribution, MenuContribution, KeybindingContribution, TabBarToolbarContribution, FrontendApplicationContribution {
@inject(ILogger)
protected readonly logger: ILogger;
@@ -37,6 +39,9 @@ export abstract class Contribution implements CommandContribution, MenuContribut
@inject(LabelProvider)
protected readonly labelProvider: LabelProvider;
onStart(app: FrontendApplication): MaybePromise<void> {
}
registerCommands(registry: CommandRegistry): void {
}
@@ -75,11 +80,12 @@ export abstract class SketchContribution extends Contribution {
}
export namespace Contribution {
export function configure<T>(bind: interfaces.Bind, serviceIdentifier: interfaces.ServiceIdentifier<T>): void {
export function configure<T>(bind: interfaces.Bind, serviceIdentifier: typeof Contribution): void {
bind(serviceIdentifier).toSelf().inSingletonScope();
bind(CommandContribution).toService(serviceIdentifier);
bind(MenuContribution).toService(serviceIdentifier);
bind(KeybindingContribution).toService(serviceIdentifier);
bind(TabBarToolbarContribution).toService(serviceIdentifier);
bind(FrontendApplicationContribution).toService(serviceIdentifier);
}
}

View File

@@ -0,0 +1,151 @@
import * as PQueue from 'p-queue';
import { inject, injectable, postConstruct } from 'inversify';
import { MenuPath, SubMenuOptions, CompositeMenuNode } from '@theia/core/lib/common/menu';
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
import { OpenSketch } from './open-sketch';
import { ArduinoMenus } from '../menu/arduino-menus';
import { MainMenuManager } from '../../common/main-menu-manager';
import { LibraryServiceProvider } from '../library/library-service-provider';
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
import { ExamplesService, ExampleContainer } from '../../common/protocol/examples-service';
import { SketchContribution, CommandRegistry, MenuModelRegistry } from './contribution';
@injectable()
export abstract class Examples extends SketchContribution {
@inject(CommandRegistry)
protected readonly commandRegistry: CommandRegistry;
@inject(MenuModelRegistry)
protected readonly menuRegistry: MenuModelRegistry;
@inject(MainMenuManager)
protected readonly menuManager: MainMenuManager;
@inject(ExamplesService)
protected readonly examplesService: ExamplesService;
@inject(BoardsServiceClientImpl)
protected readonly boardsServiceClient: BoardsServiceClientImpl;
protected readonly toDispose = new DisposableCollection();
@postConstruct()
init(): void {
this.boardsServiceClient.onBoardsConfigChanged(({ selectedBoard }) => this.handleBoardChanged(selectedBoard?.fqbn));
}
protected handleBoardChanged(fqbn: string | undefined): void {
// NOOP
}
registerMenus(registry: MenuModelRegistry): void {
try {
// This is a hack the ensures the desired menu ordering! We cannot use https://github.com/eclipse-theia/theia/pull/8377 due to ATL-222.
const index = ArduinoMenus.FILE__EXAMPLES_SUBMENU.length - 1;
const menuId = ArduinoMenus.FILE__EXAMPLES_SUBMENU[index];
const groupPath = index === 0 ? [] : ArduinoMenus.FILE__EXAMPLES_SUBMENU.slice(0, index);
const parent: CompositeMenuNode = (registry as any).findGroup(groupPath);
const examples = new CompositeMenuNode(menuId, '', { order: '4' });
parent.addNode(examples);
} catch (e) {
console.error(e);
console.warn('Could not patch menu ordering.');
}
// Registering the same submenu multiple times has no side-effect.
// TODO: unregister submenu? https://github.com/eclipse-theia/theia/issues/7300
registry.registerSubmenu(ArduinoMenus.FILE__EXAMPLES_SUBMENU, 'Examples', { order: '4' });
}
registerRecursively(
exampleContainer: ExampleContainer,
menuPath: MenuPath,
pushToDispose: DisposableCollection = new DisposableCollection(),
options?: SubMenuOptions): void {
const { label, sketches, children } = exampleContainer;
const submenuPath = [...menuPath, label];
this.menuRegistry.registerSubmenu(submenuPath, label, options);
children.forEach(child => this.registerRecursively(child, submenuPath, pushToDispose));
for (const sketch of sketches) {
const { uri } = sketch;
const commandId = `arduino-open-example-${submenuPath.join(':')}--${uri}`;
const command = { id: commandId };
const handler = {
execute: async () => {
const sketch = await this.sketchService.cloneExample(uri);
this.commandService.executeCommand(OpenSketch.Commands.OPEN_SKETCH.id, sketch);
}
};
pushToDispose.push(this.commandRegistry.registerCommand(command, handler));
this.menuRegistry.registerMenuAction(submenuPath, { commandId, label: sketch.name });
pushToDispose.push(Disposable.create(() => this.menuRegistry.unregisterMenuAction(command)));
}
}
}
@injectable()
export class BuiltInExamples extends Examples {
onStart(): void {
this.register(); // no `await`
}
protected async register() {
let exampleContainers: ExampleContainer[] | undefined;
try {
exampleContainers = await this.examplesService.builtIns();
} catch (e) {
console.error('Could not initialize built-in examples.', e);
this.messageService.error('Could not initialize built-in examples.');
return;
}
this.toDispose.dispose();
for (const container of exampleContainers) {
this.registerRecursively(container, ArduinoMenus.EXAMPLES__BUILT_IN_GROUP, this.toDispose);
}
this.menuManager.update();
}
}
@injectable()
export class LibraryExamples extends Examples {
@inject(LibraryServiceProvider)
protected readonly libraryServiceProvider: LibraryServiceProvider;
protected readonly queue = new PQueue({ autoStart: true, concurrency: 1 });
onStart(): void {
this.register(); // no `await`
this.libraryServiceProvider.onLibraryPackageInstalled(() => this.register());
this.libraryServiceProvider.onLibraryPackageUninstalled(() => this.register());
}
protected handleBoardChanged(fqbn: string | undefined): void {
this.register(fqbn);
}
protected async register(fqbn: string | undefined = this.boardsServiceClient.boardsConfig.selectedBoard?.fqbn) {
return this.queue.add(async () => {
this.toDispose.dispose();
if (!fqbn) {
return;
}
const { user, current, any } = await this.examplesService.installed({ fqbn });
for (const container of user) {
this.registerRecursively(container, ArduinoMenus.EXAMPLES__USER_LIBS_GROUP, this.toDispose);
}
for (const container of current) {
this.registerRecursively(container, ArduinoMenus.EXAMPLES__CURRENT_BOARD_GROUP, this.toDispose);
}
for (const container of any) {
this.registerRecursively(container, ArduinoMenus.EXAMPLES__ANY_BOARD_GROUP, this.toDispose);
}
this.menuManager.update();
});
}
}

View File

@@ -0,0 +1,156 @@
import * as PQueue from 'p-queue';
import { inject, injectable } from 'inversify';
import URI from '@theia/core/lib/common/uri';
import { MonacoEditor } from '@theia/monaco/lib/browser/monaco-editor';
import { EditorManager } from '@theia/editor/lib/browser';
import { MenuModelRegistry, MenuPath } from '@theia/core/lib/common/menu';
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
import { ArduinoMenus } from '../menu/arduino-menus';
import { LibraryPackage, LibraryLocation } from '../../common/protocol';
import { MainMenuManager } from '../../common/main-menu-manager';
import { LibraryListWidget } from '../library/library-list-widget';
import { LibraryServiceProvider } from '../library/library-service-provider';
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
import { SketchContribution, Command, CommandRegistry } from './contribution';
@injectable()
export class IncludeLibrary extends SketchContribution {
@inject(CommandRegistry)
protected readonly commandRegistry: CommandRegistry;
@inject(MenuModelRegistry)
protected readonly menuRegistry: MenuModelRegistry;
@inject(MainMenuManager)
protected readonly mainMenuManager: MainMenuManager;
@inject(EditorManager)
protected readonly editorManager: EditorManager;
@inject(LibraryServiceProvider)
protected readonly libraryServiceProvider: LibraryServiceProvider;
@inject(BoardsServiceClientImpl)
protected readonly boardsServiceClient: BoardsServiceClientImpl;
protected readonly queue = new PQueue({ autoStart: true, concurrency: 1 });
protected readonly toDispose = new DisposableCollection();
onStart(): void {
this.updateMenuActions();
this.boardsServiceClient.onBoardsConfigChanged(() => this.updateMenuActions())
this.libraryServiceProvider.onLibraryPackageInstalled(() => this.updateMenuActions());
this.libraryServiceProvider.onLibraryPackageUninstalled(() => this.updateMenuActions());
}
registerCommands(registry: CommandRegistry): void {
registry.registerCommand(IncludeLibrary.Commands.INCLUDE_LIBRARY, {
execute: async arg => {
if (LibraryPackage.is(arg)) {
this.includeLibrary(arg);
}
}
});
}
protected async updateMenuActions(): Promise<void> {
return this.queue.add(async () => {
this.toDispose.dispose();
this.mainMenuManager.update();
const libraries: LibraryPackage[] = []
const fqbn = this.boardsServiceClient.boardsConfig.selectedBoard?.fqbn;
// Do not show board specific examples, when no board is selected.
if (fqbn) {
libraries.push(...await this.libraryServiceProvider.list({ fqbn }));
}
// `Include Library` submenu
const includeLibMenuPath = [...ArduinoMenus.SKETCH__UTILS_GROUP, '0_include'];
this.menuRegistry.registerSubmenu(includeLibMenuPath, 'Include Library', { order: '1' });
// `Manage Libraries...` group.
this.menuRegistry.registerMenuAction([...includeLibMenuPath, '0_manage'], {
commandId: `${LibraryListWidget.WIDGET_ID}:toggle`,
label: 'Manage Libraries...'
});
this.toDispose.push(Disposable.create(() => this.menuRegistry.unregisterMenuAction({ commandId: `${LibraryListWidget.WIDGET_ID}:toggle` })));
// `Add .ZIP Library...`
// TODO: implement it
// `Arduino libraries`
const packageMenuPath = [...includeLibMenuPath, '2_arduino'];
const userMenuPath = [...includeLibMenuPath, '3_contributed'];
for (const library of libraries) {
this.toDispose.push(this.registerLibrary(library, library.location === LibraryLocation.USER ? userMenuPath : packageMenuPath));
}
this.mainMenuManager.update();
});
}
protected registerLibrary(library: LibraryPackage, menuPath: MenuPath): Disposable {
const commandId = `arduino-include-library--${library.name}:${library.author}`;
const command = { id: commandId };
const handler = { execute: () => this.commandRegistry.executeCommand(IncludeLibrary.Commands.INCLUDE_LIBRARY.id, library) };
const menuAction = { commandId, label: library.name };
this.menuRegistry.registerMenuAction(menuPath, menuAction);
return new DisposableCollection(
this.commandRegistry.registerCommand(command, handler),
Disposable.create(() => this.menuRegistry.unregisterMenuAction(menuAction)),
);
}
protected async includeLibrary(library: LibraryPackage): Promise<void> {
const sketch = await this.sketchServiceClient.currentSketch();
if (!sketch) {
return;
}
// If the current editor is one of the additional files from the sketch, we use that.
// Otherwise, we pick the editor of the main sketch file.
let codeEditor: monaco.editor.IStandaloneCodeEditor | undefined;
const editor = this.editorManager.currentEditor?.editor;
if (editor instanceof MonacoEditor) {
if (sketch.additionalFileUris.some(uri => uri === editor.uri.toString())) {
codeEditor = editor.getControl();
}
}
if (!codeEditor) {
const widget = await this.editorManager.open(new URI(sketch.mainFileUri));
if (widget.editor instanceof MonacoEditor) {
codeEditor = widget.editor.getControl();
}
}
if (!codeEditor) {
return;
}
const textModel = codeEditor.getModel();
if (!textModel) {
return;
}
const cursorState = codeEditor.getSelections() || [];
const eol = textModel.getEOL();
const includes = library.includes.slice();
includes.push(''); // For the trailing new line.
const text = includes.map(include => include ? `#include <${include}>` : eol).join(eol);
textModel.pushStackElement(); // Start a fresh operation.
textModel.pushEditOperations(cursorState, [{
range: new monaco.Range(1, 1, 1, 1),
text,
forceMoveMarkers: true
}], () => cursorState);
textModel.pushStackElement(); // Make it undoable.
}
}
export namespace IncludeLibrary {
export namespace Commands {
export const INCLUDE_LIBRARY: Command = {
id: 'arduino-include-library'
};
}
}

View File

@@ -6,6 +6,8 @@ import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposa
import { ArduinoMenus } from '../menu/arduino-menus';
import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
import { SketchContribution, Sketch, URI, Command, CommandRegistry, MenuModelRegistry, KeybindingRegistry, TabBarToolbarRegistry } from './contribution';
import { ExamplesService } from '../../common/protocol/examples-service';
import { BuiltInExamples } from './examples';
@injectable()
export class OpenSketch extends SketchContribution {
@@ -16,6 +18,12 @@ export class OpenSketch extends SketchContribution {
@inject(ContextMenuRenderer)
protected readonly contextMenuRenderer: ContextMenuRenderer;
@inject(BuiltInExamples)
protected readonly builtInExamples: BuiltInExamples;
@inject(ExamplesService)
protected readonly examplesService: ExamplesService;
protected readonly toDisposeBeforeCreateNewContextMenu = new DisposableCollection();
registerCommands(registry: CommandRegistry): void {
@@ -53,6 +61,14 @@ export class OpenSketch extends SketchContribution {
});
this.toDisposeBeforeCreateNewContextMenu.push(Disposable.create(() => this.menuRegistry.unregisterMenuAction(command)));
}
try {
const containers = await this.examplesService.builtIns();
for (const container of containers) {
this.builtInExamples.registerRecursively(container, ArduinoMenus.OPEN_SKETCH__CONTEXT__EXAMPLES_GROUP, this.toDisposeBeforeCreateNewContextMenu);
}
} catch (e) {
console.error('Error when collecting built-in examples.', e);
}
const options = {
menuPath: ArduinoMenus.OPEN_SKETCH__CONTEXT,
anchor: {

View File

@@ -103,7 +103,7 @@ export class UploadSketch extends SketchContribution {
if (usingProgrammer) {
const programmer = selectedProgrammer;
if (!programmer) {
throw new Error('Programmer is not selected. Please select a programmer.');
throw new Error('Programmer is not selected. Please select a programmer from the `Tools` > `Programmer` menu.');
}
let port: undefined | string = undefined;
// If the port is set by the user, we pass it to the CLI as it might be required.

View File

@@ -1,17 +1,18 @@
import { inject, injectable } from 'inversify';
import { Library, LibraryService } from '../../common/protocol/library-service';
import { LibraryPackage } from '../../common/protocol/library-service';
import { ListWidget } from '../widgets/component-list/list-widget';
import { ListItemRenderer } from '../widgets/component-list/list-item-renderer';
import { LibraryServiceProvider } from './library-service-provider';
@injectable()
export class LibraryListWidget extends ListWidget<Library> {
export class LibraryListWidget extends ListWidget<LibraryPackage> {
static WIDGET_ID = 'library-list-widget';
static WIDGET_LABEL = 'Library Manager';
constructor(
@inject(LibraryService) protected service: LibraryService,
@inject(ListItemRenderer) protected itemRenderer: ListItemRenderer<Library>) {
@inject(LibraryServiceProvider) protected service: LibraryServiceProvider,
@inject(ListItemRenderer) protected itemRenderer: ListItemRenderer<LibraryPackage>) {
super({
id: LibraryListWidget.WIDGET_ID,
@@ -19,7 +20,7 @@ export class LibraryListWidget extends ListWidget<Library> {
iconClass: 'library-tab-icon',
searchable: service,
installable: service,
itemLabel: (item: Library) => item.name,
itemLabel: (item: LibraryPackage) => item.name,
itemRenderer
});
}

View File

@@ -0,0 +1,61 @@
import { inject, injectable, postConstruct } from 'inversify';
import { JsonRpcProxy } from '@theia/core/lib/common/messaging/proxy-factory';
import { Event, Emitter } from '@theia/core/lib/common/event';
import { DisposableCollection } from '@theia/core/lib/common/disposable';
import { Searchable, InstalledEvent, UninstalledEvent } from '../../common/protocol';
import { LibraryPackage, LibraryServiceServer, LibraryService } from '../../common/protocol/library-service';
@injectable()
export class LibraryServiceProvider implements Required<LibraryService> {
@inject(LibraryServiceServer)
protected readonly server: JsonRpcProxy<LibraryServiceServer>;
protected readonly onLibraryPackageInstalledEmitter = new Emitter<InstalledEvent<LibraryPackage>>();
protected readonly onLibraryPackageUninstalledEmitter = new Emitter<UninstalledEvent<LibraryPackage>>();
protected readonly toDispose = new DisposableCollection(
this.onLibraryPackageInstalledEmitter,
this.onLibraryPackageUninstalledEmitter
);
@postConstruct()
protected init(): void {
this.server.setClient({
notifyInstalled: event => this.onLibraryPackageInstalledEmitter.fire(event),
notifyUninstalled: event => this.onLibraryPackageUninstalledEmitter.fire(event)
});
}
get onLibraryPackageInstalled(): Event<InstalledEvent<LibraryPackage>> {
return this.onLibraryPackageInstalledEmitter.event;
}
get onLibraryPackageUninstalled(): Event<InstalledEvent<LibraryPackage>> {
return this.onLibraryPackageUninstalledEmitter.event;
}
// #region remote library service API
async install(options: { item: LibraryPackage; version?: string | undefined; }): Promise<void> {
return this.server.install(options);
}
async list(options: LibraryService.List.Options): Promise<LibraryPackage[]> {
return this.server.list(options);
}
async uninstall(options: { item: LibraryPackage; }): Promise<void> {
return this.server.uninstall(options);
}
async search(options: Searchable.Options): Promise<LibraryPackage[]> {
return this.server.search(options);
}
// #endregion remote API
dispose(): void {
this.toDispose.dispose();
}
}

View File

@@ -12,6 +12,13 @@ export namespace ArduinoMenus {
export const FILE__SETTINGS_GROUP = [...(isOSX ? MAIN_MENU_BAR : CommonMenus.FILE), '2_settings'];
export const FILE__QUIT_GROUP = [...CommonMenus.FILE, '3_quit'];
// -- File / Examples
export const FILE__EXAMPLES_SUBMENU = [...FILE__SKETCH_GROUP, '0_examples'];
export const EXAMPLES__BUILT_IN_GROUP = [...FILE__EXAMPLES_SUBMENU, '0_built_ins'];
export const EXAMPLES__ANY_BOARD_GROUP = [...FILE__EXAMPLES_SUBMENU, '1_any_board'];
export const EXAMPLES__CURRENT_BOARD_GROUP = [...FILE__EXAMPLES_SUBMENU, '2_current_board'];
export const EXAMPLES__USER_LIBS_GROUP = [...FILE__EXAMPLES_SUBMENU, '3_user_libs'];
// -- Edit
// `Copy`, `Copy to Forum`, `Paste`, etc.
// Note: `1_undo` is the first group from Theia, we start with `2`
@@ -30,7 +37,7 @@ export namespace ArduinoMenus {
export const TOOLS = [...MAIN_MENU_BAR, '4_tools'];
// `Auto Format`, `Library Manager...`, `Boards Manager...`
export const TOOLS__MAIN_GROUP = [...TOOLS, '0_main'];
// Core settings, such as `Processor` and `Programmers` for the board.
// Core settings, such as `Processor` and `Programmers` for the board and `Burn Bootloader`
export const TOOLS__BOARD_SETTINGS_GROUP = [...TOOLS, '1_board_settings'];
// Context menu

View File

@@ -0,0 +1,53 @@
import * as PQueue from 'p-queue';
import { injectable } from 'inversify';
import { Deferred } from '@theia/core/lib/common/promise-util';
import { OutputUri } from '@theia/output/lib/common/output-uri';
import { IReference } from '@theia/monaco/lib/browser/monaco-text-model-service';
import { MonacoEditorModel } from '@theia/monaco/lib/browser/monaco-editor-model';
import { OutputChannelManager as TheiaOutputChannelManager, OutputChannel as TheiaOutputChannel } from '@theia/output/lib/common/output-channel';
@injectable()
export class OutputChannelManager extends TheiaOutputChannelManager {
getChannel(name: string): TheiaOutputChannel {
const existing = this.channels.get(name);
if (existing) {
return existing;
}
// We have to register the resource first, because `textModelService#createModelReference` will require it
// right after creating the monaco.editor.ITextModel.
// All `append` and `appendLine` will be deferred until the underlying text-model instantiation.
let resource = this.resources.get(name);
if (!resource) {
const uri = OutputUri.create(name);
const editorModelRef = new Deferred<IReference<MonacoEditorModel>>();
resource = this.createResource({ uri, editorModelRef });
this.resources.set(name, resource);
this.textModelService.createModelReference(uri).then(ref => editorModelRef.resolve(ref));
}
const channel = new OutputChannel(resource, this.preferences);
this.channels.set(name, channel);
this.toDisposeOnChannelDeletion.set(name, this.registerListeners(channel));
this.channelAddedEmitter.fire(channel);
if (!this.selectedChannel) {
this.selectedChannel = channel;
}
return channel;
}
}
export class OutputChannel extends TheiaOutputChannel {
dispose(): void {
super.dispose();
if ((this as any).disposed) {
const textModifyQueue: PQueue = (this as any).textModifyQueue;
textModifyQueue.pause();
textModifyQueue.clear();
}
}
}

View File

@@ -0,0 +1,38 @@
import { injectable, inject } from 'inversify';
import { CommandService } from '@theia/core/lib/common/command';
import { OutputCommands } from '@theia/output/lib/browser/output-commands';
import { PluginInfo } from '@theia/plugin-ext/lib/common/plugin-api-rpc';
import { OutputChannelRegistryMainImpl as TheiaOutputChannelRegistryMainImpl } from '@theia/plugin-ext/lib/main/browser/output-channel-registry-main';
@injectable()
export class OutputChannelRegistryMainImpl extends TheiaOutputChannelRegistryMainImpl {
@inject(CommandService)
protected readonly commandService: CommandService;
$append(name: string, text: string, pluginInfo: PluginInfo): PromiseLike<void> {
this.commandService.executeCommand(OutputCommands.APPEND.id, { name, text });
return Promise.resolve();
}
$clear(name: string): PromiseLike<void> {
this.commandService.executeCommand(OutputCommands.CLEAR.id, { name });
return Promise.resolve();
}
$dispose(name: string): PromiseLike<void> {
this.commandService.executeCommand(OutputCommands.DISPOSE.id, { name });
return Promise.resolve();
}
async $reveal(name: string, preserveFocus: boolean): Promise<void> {
const options = { preserveFocus };
this.commandService.executeCommand(OutputCommands.SHOW.id, { name, options });
}
$close(name: string): PromiseLike<void> {
this.commandService.executeCommand(OutputCommands.HIDE.id, { name });
return Promise.resolve();
}
}

View File

@@ -12,3 +12,15 @@ export interface ArduinoComponent {
readonly installedVersion?: Installable.Version;
}
export namespace ArduinoComponent {
export function is(arg: any): arg is ArduinoComponent {
return !!arg
&& 'name' in arg && typeof arg['name'] === 'string'
&& 'author' in arg && typeof arg['author'] === 'string'
&& 'summary' in arg && typeof arg['summary'] === 'string'
&& 'description' in arg && typeof arg['description'] === 'string'
&& 'installable' in arg && typeof arg['installable'] === 'boolean';
}
}

View File

@@ -2,7 +2,7 @@ import { isWindows, isOSX } from '@theia/core/lib/common/os';
import { JsonRpcServer } from '@theia/core/lib/common/messaging/proxy-factory';
import { naturalCompare } from './../utils';
import { Searchable } from './searchable';
import { Installable } from './installable';
import { Installable, InstallableClient } from './installable';
import { ArduinoComponent } from './arduino-component';
export interface AttachedBoardsChangeEvent {
@@ -45,19 +45,9 @@ export namespace AttachedBoardsChangeEvent {
}
export interface BoardInstalledEvent {
readonly pkg: Readonly<BoardsPackage>;
}
export interface BoardUninstalledEvent {
readonly pkg: Readonly<BoardsPackage>;
}
export const BoardsServiceClient = Symbol('BoardsServiceClient');
export interface BoardsServiceClient {
export interface BoardsServiceClient extends InstallableClient<BoardsPackage> {
notifyAttachedBoardsChanged(event: AttachedBoardsChangeEvent): void;
notifyBoardInstalled(event: BoardInstalledEvent): void
notifyBoardUninstalled(event: BoardUninstalledEvent): void
}
export const BoardsServicePath = '/services/boards-service';
@@ -194,6 +184,11 @@ export interface BoardsPackage extends ArduinoComponent {
readonly id: string;
readonly boards: Board[];
}
export namespace BoardsPackage {
export function equals(left: BoardsPackage, right: BoardsPackage): boolean {
return left.id === right.id;
}
}
export interface Board {
readonly name: string;

View File

@@ -11,6 +11,7 @@ export const CoreService = Symbol('CoreService');
export interface CoreService extends JsonRpcServer<CoreServiceClient> {
compile(options: CoreService.Compile.Options): Promise<void>;
upload(options: CoreService.Upload.Options): Promise<void>;
burnBootloader(options: CoreService.Bootloader.Options): Promise<void>;
}
export namespace CoreService {
@@ -29,4 +30,12 @@ export namespace CoreService {
Compile.Options & Readonly<{ programmer: Programmer, port?: string }>;
}
export namespace Bootloader {
export interface Options {
readonly fqbn: string;
readonly programmer: Programmer;
readonly port: string;
}
}
}

View File

@@ -0,0 +1,14 @@
import { Sketch } from './sketches-service';
export const ExamplesServicePath = '/services/example-service';
export const ExamplesService = Symbol('ExamplesService');
export interface ExamplesService {
builtIns(): Promise<ExampleContainer[]>;
installed(options: { fqbn: string }): Promise<{ user: ExampleContainer[], current: ExampleContainer[], any: ExampleContainer[] }>;
}
export interface ExampleContainer {
readonly label: string;
readonly children: ExampleContainer[];
readonly sketches: Sketch[];
}

View File

@@ -1,6 +1,17 @@
import { naturalCompare } from './../utils';
import { ArduinoComponent } from './arduino-component';
export interface InstalledEvent<T extends ArduinoComponent> {
readonly item: Readonly<T>;
}
export interface UninstalledEvent<T extends ArduinoComponent> {
readonly item: Readonly<T>;
}
export interface InstallableClient<T extends ArduinoComponent> {
notifyInstalled(event: InstalledEvent<T>): void
notifyUninstalled(event: UninstalledEvent<T>): void
}
export interface Installable<T extends ArduinoComponent> {
/**
* If `options.version` is specified, that will be installed. Otherwise, `item.availableVersions[0]`.

View File

@@ -1,13 +1,74 @@
import { JsonRpcServer } from '@theia/core/lib/common/messaging/proxy-factory';
import { Searchable } from './searchable';
import { Installable } from './installable';
import { ArduinoComponent } from './arduino-component';
import { Installable, InstallableClient } from './installable';
export const LibraryServicePath = '/services/library-service';
export const LibraryService = Symbol('LibraryService');
export interface LibraryService extends Installable<Library>, Searchable<Library> {
install(options: { item: Library, version?: Installable.Version }): Promise<void>;
export interface LibraryService extends Installable<LibraryPackage>, Searchable<LibraryPackage> {
install(options: { item: LibraryPackage, version?: Installable.Version }): Promise<void>;
list(options: LibraryService.List.Options): Promise<LibraryPackage[]>;
}
export interface Library extends ArduinoComponent {
readonly builtIn?: boolean;
export const LibraryServiceClient = Symbol('LibraryServiceClient');
export interface LibraryServiceClient extends InstallableClient<LibraryPackage> {
}
export const LibraryServiceServerPath = '/services/library-service-server';
export const LibraryServiceServer = Symbol('LibraryServiceServer');
export interface LibraryServiceServer extends LibraryService, JsonRpcServer<LibraryServiceClient> {
}
export namespace LibraryService {
export namespace List {
export interface Options {
readonly fqbn?: string | undefined;
}
}
}
export enum LibraryLocation {
/**
* In the `libraries` subdirectory of the Arduino IDE installation.
*/
IDE_BUILTIN = 0,
/**
* In the `libraries` subdirectory of the user directory (sketchbook).
*/
USER = 1,
/**
* In the `libraries` subdirectory of a platform.
*/
PLATFORM_BUILTIN = 2,
/**
* When `LibraryLocation` is used in a context where a board is specified, this indicates the library is in the `libraries`
* subdirectory of a platform referenced by the board's platform.
*/
REFERENCED_PLATFORM_BUILTIN = 3
}
export interface LibraryPackage extends ArduinoComponent {
/**
* Same as [`Library#real_name`](https://arduino.github.io/arduino-cli/latest/rpc/commands/#library).
* Should be used for the UI, and `name` is used to uniquely identify a library. It does not have an ID.
*/
readonly label: string;
/**
* An array of string that should be included into the `ino` file if this library is used.
* For example, including `SD` will prepend `#include <SD.h>` to the `ino` file. While including `Bridge`
* requires multiple `#include` declarations: `YunClient`, `YunServer`, `Bridge`, etc.
*/
readonly includes: string[];
readonly exampleUris: string[];
readonly location: LibraryLocation;
readonly installDirUri?: string;
}
export namespace LibraryPackage {
export function is(arg: any): arg is LibraryPackage {
return ArduinoComponent.is(arg) && 'includes' in arg && Array.isArray(arg['includes']);
}
export function equals(left: LibraryPackage, right: LibraryPackage): boolean {
return left.name === right.name && left.author === right.author;
}
}

View File

@@ -22,6 +22,11 @@ export interface SketchesService {
*/
createNewSketch(): Promise<Sketch>;
/**
* Creates a new sketch with existing content. Rejects if `uri` is not pointing to a valid sketch folder.
*/
cloneExample(uri: string): Promise<Sketch>;
isSketchFolder(uri: string): Promise<boolean>;
/**

View File

@@ -7,3 +7,7 @@ export function notEmpty(arg: string | undefined | null): arg is string {
export function firstToLowerCase(what: string): string {
return what.charAt(0).toLowerCase() + what.slice(1);
}
export function firstToUpperCase(what: string): string {
return what.charAt(0).toUpperCase() + what.slice(1);
}

View File

@@ -7,9 +7,9 @@ import { ILogger } from '@theia/core/lib/common/logger';
import { BackendApplicationContribution } from '@theia/core/lib/node/backend-application';
import { LanguageServerContribution } from '@theia/languages/lib/node';
import { ArduinoLanguageServerContribution } from './language/arduino-language-server-contribution';
import { LibraryService, LibraryServicePath } from '../common/protocol/library-service';
import { LibraryServiceServerPath, LibraryServiceServer, LibraryServiceClient } from '../common/protocol/library-service';
import { BoardsService, BoardsServicePath, BoardsServiceClient } from '../common/protocol/boards-service';
import { LibraryServiceImpl } from './library-service-impl';
import { LibraryServiceServerImpl } from './library-service-server-impl';
import { BoardsServiceImpl } from './boards-service-impl';
import { CoreServiceImpl } from './core-service-impl';
import { CoreService, CoreServicePath, CoreServiceClient } from '../common/protocol/core-service';
@@ -35,6 +35,8 @@ import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
import { ArduinoEnvVariablesServer } from './arduino-env-variables-server';
import { NodeFileSystemExt } from './node-filesystem-ext';
import { FileSystemExt, FileSystemExtPath } from '../common/protocol/filesystem-ext';
import { ExamplesServiceImpl } from './examples-service-impl';
import { ExamplesService, ExamplesServicePath } from '../common/protocol/examples-service';
export default new ContainerModule((bind, unbind, isBound, rebind) => {
rebind(EnvVariablesServer).to(ArduinoEnvVariablesServer).inSingletonScope();
@@ -66,25 +68,31 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
})
).inSingletonScope();
// Shared examples service
bind(ExamplesServiceImpl).toSelf().inSingletonScope();
bind(ExamplesService).toService(ExamplesServiceImpl);
bind(ConnectionHandler).toDynamicValue(context => new JsonRpcConnectionHandler(ExamplesServicePath, () => context.container.get(ExamplesService))).inSingletonScope();
// Language server
bind(ArduinoLanguageServerContribution).toSelf().inSingletonScope();
bind(LanguageServerContribution).toService(ArduinoLanguageServerContribution);
// Library service
const libraryServiceConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService }) => {
bind(LibraryServiceImpl).toSelf().inSingletonScope();
bind(LibraryService).toService(LibraryServiceImpl);
bindBackendService(LibraryServicePath, LibraryService);
});
bind(ConnectionContainerModule).toConstantValue(libraryServiceConnectionModule);
bind(LibraryServiceServerImpl).toSelf().inSingletonScope();
bind(LibraryServiceServer).toService(LibraryServiceServerImpl);
bind(ConnectionHandler).toDynamicValue(context =>
new JsonRpcConnectionHandler<LibraryServiceClient>(LibraryServiceServerPath, client => {
const server = context.container.get<LibraryServiceServerImpl>(LibraryServiceServerImpl);
server.setClient(client);
client.onDidCloseConnection(() => server.dispose());
return server;
})
).inSingletonScope();
// Sketches service
const sketchesServiceConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService }) => {
bind(SketchesServiceImpl).toSelf().inSingletonScope();
bind(SketchesService).toService(SketchesServiceImpl);
bindBackendService(SketchesServicePath, SketchesService);
});
bind(ConnectionContainerModule).toConstantValue(sketchesServiceConnectionModule);
// Shred sketches service
bind(SketchesServiceImpl).toSelf().inSingletonScope();
bind(SketchesService).toService(SketchesServiceImpl);
bind(ConnectionHandler).toDynamicValue(context => new JsonRpcConnectionHandler(SketchesServicePath, () => context.container.get(SketchesService))).inSingletonScope();
// Boards service
const boardsServiceConnectionModule = ConnectionContainerModule.create(async ({ bind, bindBackendService }) => {
@@ -190,6 +198,6 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
// File-system extension for mapping paths to URIs
bind(NodeFileSystemExt).toSelf().inSingletonScope();
bind(FileSystemExt).toDynamicValue(context => context.container.get(NodeFileSystemExt));
bind(FileSystemExt).toService(NodeFileSystemExt);
bind(ConnectionHandler).toDynamicValue(context => new JsonRpcConnectionHandler(FileSystemExtPath, () => context.container.get(FileSystemExt))).inSingletonScope();
});

View File

@@ -112,8 +112,8 @@ export class BoardsServiceImpl implements BoardsService {
if (this.discoveryTimer !== undefined) {
clearInterval(this.discoveryTimer);
}
this.logger.info('<<< Disposed boards service.');
this.client = undefined;
this.logger.info('<<< Disposed boards service.');
}
async getAttachedBoards(): Promise<Board[]> {
@@ -370,15 +370,15 @@ export class BoardsServiceImpl implements BoardsService {
}
async install(options: { item: BoardsPackage, version?: Installable.Version }): Promise<void> {
const pkg = options.item;
const version = !!options.version ? options.version : pkg.availableVersions[0];
const item = options.item;
const version = !!options.version ? options.version : item.availableVersions[0];
const coreClient = await this.coreClientProvider.client();
if (!coreClient) {
return;
}
const { client, instance } = coreClient;
const [platform, architecture] = pkg.id.split(':');
const [platform, architecture] = item.id.split(':');
const req = new PlatformInstallReq();
req.setInstance(instance);
@@ -386,7 +386,7 @@ export class BoardsServiceImpl implements BoardsService {
req.setPlatformPackage(platform);
req.setVersion(version);
console.info('Starting board installation', pkg);
console.info('>>> Starting boards package installation...', item);
const resp = client.platformInstall(req);
resp.on('data', (r: PlatformInstallResp) => {
const prog = r.getProgress();
@@ -399,34 +399,34 @@ export class BoardsServiceImpl implements BoardsService {
resp.on('error', reject);
});
if (this.client) {
const packages = await this.search({});
const updatedPackage = packages.find(({ id }) => id === pkg.id) || pkg;
this.client.notifyBoardInstalled({ pkg: updatedPackage });
const items = await this.search({});
const updated = items.find(other => BoardsPackage.equals(other, item)) || item;
this.client.notifyInstalled({ item: updated });
}
console.info('Board installation done', pkg);
console.info('<<< Boards package installation done.', item);
}
async uninstall(options: { item: BoardsPackage }): Promise<void> {
const pkg = options.item;
const item = options.item;
const coreClient = await this.coreClientProvider.client();
if (!coreClient) {
return;
}
const { client, instance } = coreClient;
const [platform, architecture] = pkg.id.split(':');
const [platform, architecture] = item.id.split(':');
const req = new PlatformUninstallReq();
req.setInstance(instance);
req.setArchitecture(architecture);
req.setPlatformPackage(platform);
console.info('Starting board uninstallation', pkg);
console.info('>>> Starting boards package uninstallation...', item);
let logged = false;
const resp = client.platformUninstall(req);
resp.on('data', (_: PlatformUninstallResp) => {
if (!logged) {
this.toolOutputService.append({ tool: 'board uninstall', chunk: `uninstalling ${pkg.id}\n` });
this.toolOutputService.append({ tool: 'board uninstall', chunk: `uninstalling ${item.id}\n` });
logged = true;
}
})
@@ -435,10 +435,10 @@ export class BoardsServiceImpl implements BoardsService {
resp.on('error', reject);
});
if (this.client) {
// Here, unlike at `install` we send out the argument `pkg`. Otherwise, we would not know about the board FQBN.
this.client.notifyBoardUninstalled({ pkg });
// Here, unlike at `install` we send out the argument `item`. Otherwise, we would not know about the board FQBN.
this.client.notifyUninstalled({ item });
}
console.info('Board uninstallation done', pkg);
console.info('<<< Boards package uninstallation done.', item);
}
}

View File

@@ -84,6 +84,11 @@ export class BoardDetailsResp extends jspb.Message {
setIdentificationPrefList(value: Array<IdentificationPref>): BoardDetailsResp;
addIdentificationPref(value?: IdentificationPref, index?: number): IdentificationPref;
clearProgrammersList(): void;
getProgrammersList(): Array<commands_common_pb.Programmer>;
setProgrammersList(value: Array<commands_common_pb.Programmer>): BoardDetailsResp;
addProgrammers(value?: commands_common_pb.Programmer, index?: number): commands_common_pb.Programmer;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): BoardDetailsResp.AsObject;
@@ -109,6 +114,7 @@ export namespace BoardDetailsResp {
toolsdependenciesList: Array<ToolsDependencies.AsObject>,
configOptionsList: Array<ConfigOption.AsObject>,
identificationPrefList: Array<IdentificationPref.AsObject>,
programmersList: Array<commands_common_pb.Programmer.AsObject>,
}
}

View File

@@ -619,7 +619,7 @@ proto.cc.arduino.cli.commands.BoardDetailsReq.prototype.setFqbn = function(value
* @private {!Array<number>}
* @const
*/
proto.cc.arduino.cli.commands.BoardDetailsResp.repeatedFields_ = [10,11,12];
proto.cc.arduino.cli.commands.BoardDetailsResp.repeatedFields_ = [10,11,12,13];
@@ -666,7 +666,9 @@ proto.cc.arduino.cli.commands.BoardDetailsResp.toObject = function(includeInstan
configOptionsList: jspb.Message.toObjectList(msg.getConfigOptionsList(),
proto.cc.arduino.cli.commands.ConfigOption.toObject, includeInstance),
identificationPrefList: jspb.Message.toObjectList(msg.getIdentificationPrefList(),
proto.cc.arduino.cli.commands.IdentificationPref.toObject, includeInstance)
proto.cc.arduino.cli.commands.IdentificationPref.toObject, includeInstance),
programmersList: jspb.Message.toObjectList(msg.getProgrammersList(),
commands_common_pb.Programmer.toObject, includeInstance)
};
if (includeInstance) {
@@ -756,6 +758,11 @@ proto.cc.arduino.cli.commands.BoardDetailsResp.deserializeBinaryFromReader = fun
reader.readMessage(value,proto.cc.arduino.cli.commands.IdentificationPref.deserializeBinaryFromReader);
msg.addIdentificationPref(value);
break;
case 13:
var value = new commands_common_pb.Programmer;
reader.readMessage(value,commands_common_pb.Programmer.deserializeBinaryFromReader);
msg.addProgrammers(value);
break;
default:
reader.skipField();
break;
@@ -874,6 +881,14 @@ proto.cc.arduino.cli.commands.BoardDetailsResp.serializeBinaryToWriter = functio
proto.cc.arduino.cli.commands.IdentificationPref.serializeBinaryToWriter
);
}
f = message.getProgrammersList();
if (f.length > 0) {
writer.writeRepeatedMessage(
13,
f,
commands_common_pb.Programmer.serializeBinaryToWriter
);
}
};
@@ -1191,6 +1206,44 @@ proto.cc.arduino.cli.commands.BoardDetailsResp.prototype.clearIdentificationPref
};
/**
* repeated Programmer programmers = 13;
* @return {!Array<!proto.cc.arduino.cli.commands.Programmer>}
*/
proto.cc.arduino.cli.commands.BoardDetailsResp.prototype.getProgrammersList = function() {
return /** @type{!Array<!proto.cc.arduino.cli.commands.Programmer>} */ (
jspb.Message.getRepeatedWrapperField(this, commands_common_pb.Programmer, 13));
};
/**
* @param {!Array<!proto.cc.arduino.cli.commands.Programmer>} value
* @return {!proto.cc.arduino.cli.commands.BoardDetailsResp} returns this
*/
proto.cc.arduino.cli.commands.BoardDetailsResp.prototype.setProgrammersList = function(value) {
return jspb.Message.setRepeatedWrapperField(this, 13, value);
};
/**
* @param {!proto.cc.arduino.cli.commands.Programmer=} opt_value
* @param {number=} opt_index
* @return {!proto.cc.arduino.cli.commands.Programmer}
*/
proto.cc.arduino.cli.commands.BoardDetailsResp.prototype.addProgrammers = function(opt_value, opt_index) {
return jspb.Message.addToRepeatedWrapperField(this, 13, opt_value, proto.cc.arduino.cli.commands.Programmer, opt_index);
};
/**
* Clears the list making it empty but non-null.
* @return {!proto.cc.arduino.cli.commands.BoardDetailsResp} returns this
*/
proto.cc.arduino.cli.commands.BoardDetailsResp.prototype.clearProgrammersList = function() {
return this.setProgrammersList([]);
};

View File

@@ -20,7 +20,11 @@ interface IArduinoCoreService extends grpc.ServiceDefinition<grpc.UntypedService
rescan: IArduinoCoreService_IRescan;
updateIndex: IArduinoCoreService_IUpdateIndex;
updateLibrariesIndex: IArduinoCoreService_IUpdateLibrariesIndex;
updateCoreLibrariesIndex: IArduinoCoreService_IUpdateCoreLibrariesIndex;
outdated: IArduinoCoreService_IOutdated;
upgrade: IArduinoCoreService_IUpgrade;
version: IArduinoCoreService_IVersion;
loadSketch: IArduinoCoreService_ILoadSketch;
boardDetails: IArduinoCoreService_IBoardDetails;
boardAttach: IArduinoCoreService_IBoardAttach;
boardList: IArduinoCoreService_IBoardList;
@@ -89,6 +93,33 @@ interface IArduinoCoreService_IUpdateLibrariesIndex extends grpc.MethodDefinitio
responseSerialize: grpc.serialize<commands_commands_pb.UpdateLibrariesIndexResp>;
responseDeserialize: grpc.deserialize<commands_commands_pb.UpdateLibrariesIndexResp>;
}
interface IArduinoCoreService_IUpdateCoreLibrariesIndex extends grpc.MethodDefinition<commands_commands_pb.UpdateCoreLibrariesIndexReq, commands_commands_pb.UpdateCoreLibrariesIndexResp> {
path: string; // "/cc.arduino.cli.commands.ArduinoCore/UpdateCoreLibrariesIndex"
requestStream: false;
responseStream: true;
requestSerialize: grpc.serialize<commands_commands_pb.UpdateCoreLibrariesIndexReq>;
requestDeserialize: grpc.deserialize<commands_commands_pb.UpdateCoreLibrariesIndexReq>;
responseSerialize: grpc.serialize<commands_commands_pb.UpdateCoreLibrariesIndexResp>;
responseDeserialize: grpc.deserialize<commands_commands_pb.UpdateCoreLibrariesIndexResp>;
}
interface IArduinoCoreService_IOutdated extends grpc.MethodDefinition<commands_commands_pb.OutdatedReq, commands_commands_pb.OutdatedResp> {
path: string; // "/cc.arduino.cli.commands.ArduinoCore/Outdated"
requestStream: false;
responseStream: false;
requestSerialize: grpc.serialize<commands_commands_pb.OutdatedReq>;
requestDeserialize: grpc.deserialize<commands_commands_pb.OutdatedReq>;
responseSerialize: grpc.serialize<commands_commands_pb.OutdatedResp>;
responseDeserialize: grpc.deserialize<commands_commands_pb.OutdatedResp>;
}
interface IArduinoCoreService_IUpgrade extends grpc.MethodDefinition<commands_commands_pb.UpgradeReq, commands_commands_pb.UpgradeResp> {
path: string; // "/cc.arduino.cli.commands.ArduinoCore/Upgrade"
requestStream: false;
responseStream: true;
requestSerialize: grpc.serialize<commands_commands_pb.UpgradeReq>;
requestDeserialize: grpc.deserialize<commands_commands_pb.UpgradeReq>;
responseSerialize: grpc.serialize<commands_commands_pb.UpgradeResp>;
responseDeserialize: grpc.deserialize<commands_commands_pb.UpgradeResp>;
}
interface IArduinoCoreService_IVersion extends grpc.MethodDefinition<commands_commands_pb.VersionReq, commands_commands_pb.VersionResp> {
path: string; // "/cc.arduino.cli.commands.ArduinoCore/Version"
requestStream: false;
@@ -98,6 +129,15 @@ interface IArduinoCoreService_IVersion extends grpc.MethodDefinition<commands_co
responseSerialize: grpc.serialize<commands_commands_pb.VersionResp>;
responseDeserialize: grpc.deserialize<commands_commands_pb.VersionResp>;
}
interface IArduinoCoreService_ILoadSketch extends grpc.MethodDefinition<commands_commands_pb.LoadSketchReq, commands_commands_pb.LoadSketchResp> {
path: string; // "/cc.arduino.cli.commands.ArduinoCore/LoadSketch"
requestStream: false;
responseStream: false;
requestSerialize: grpc.serialize<commands_commands_pb.LoadSketchReq>;
requestDeserialize: grpc.deserialize<commands_commands_pb.LoadSketchReq>;
responseSerialize: grpc.serialize<commands_commands_pb.LoadSketchResp>;
responseDeserialize: grpc.deserialize<commands_commands_pb.LoadSketchResp>;
}
interface IArduinoCoreService_IBoardDetails extends grpc.MethodDefinition<commands_board_pb.BoardDetailsReq, commands_board_pb.BoardDetailsResp> {
path: string; // "/cc.arduino.cli.commands.ArduinoCore/BoardDetails"
requestStream: false;
@@ -296,7 +336,11 @@ export interface IArduinoCoreServer {
rescan: grpc.handleUnaryCall<commands_commands_pb.RescanReq, commands_commands_pb.RescanResp>;
updateIndex: grpc.handleServerStreamingCall<commands_commands_pb.UpdateIndexReq, commands_commands_pb.UpdateIndexResp>;
updateLibrariesIndex: grpc.handleServerStreamingCall<commands_commands_pb.UpdateLibrariesIndexReq, commands_commands_pb.UpdateLibrariesIndexResp>;
updateCoreLibrariesIndex: grpc.handleServerStreamingCall<commands_commands_pb.UpdateCoreLibrariesIndexReq, commands_commands_pb.UpdateCoreLibrariesIndexResp>;
outdated: grpc.handleUnaryCall<commands_commands_pb.OutdatedReq, commands_commands_pb.OutdatedResp>;
upgrade: grpc.handleServerStreamingCall<commands_commands_pb.UpgradeReq, commands_commands_pb.UpgradeResp>;
version: grpc.handleUnaryCall<commands_commands_pb.VersionReq, commands_commands_pb.VersionResp>;
loadSketch: grpc.handleUnaryCall<commands_commands_pb.LoadSketchReq, commands_commands_pb.LoadSketchResp>;
boardDetails: grpc.handleUnaryCall<commands_board_pb.BoardDetailsReq, commands_board_pb.BoardDetailsResp>;
boardAttach: grpc.handleServerStreamingCall<commands_board_pb.BoardAttachReq, commands_board_pb.BoardAttachResp>;
boardList: grpc.handleUnaryCall<commands_board_pb.BoardListReq, commands_board_pb.BoardListResp>;
@@ -333,9 +377,19 @@ export interface IArduinoCoreClient {
updateIndex(request: commands_commands_pb.UpdateIndexReq, metadata?: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<commands_commands_pb.UpdateIndexResp>;
updateLibrariesIndex(request: commands_commands_pb.UpdateLibrariesIndexReq, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<commands_commands_pb.UpdateLibrariesIndexResp>;
updateLibrariesIndex(request: commands_commands_pb.UpdateLibrariesIndexReq, metadata?: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<commands_commands_pb.UpdateLibrariesIndexResp>;
updateCoreLibrariesIndex(request: commands_commands_pb.UpdateCoreLibrariesIndexReq, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<commands_commands_pb.UpdateCoreLibrariesIndexResp>;
updateCoreLibrariesIndex(request: commands_commands_pb.UpdateCoreLibrariesIndexReq, metadata?: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<commands_commands_pb.UpdateCoreLibrariesIndexResp>;
outdated(request: commands_commands_pb.OutdatedReq, callback: (error: grpc.ServiceError | null, response: commands_commands_pb.OutdatedResp) => void): grpc.ClientUnaryCall;
outdated(request: commands_commands_pb.OutdatedReq, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: commands_commands_pb.OutdatedResp) => void): grpc.ClientUnaryCall;
outdated(request: commands_commands_pb.OutdatedReq, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: commands_commands_pb.OutdatedResp) => void): grpc.ClientUnaryCall;
upgrade(request: commands_commands_pb.UpgradeReq, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<commands_commands_pb.UpgradeResp>;
upgrade(request: commands_commands_pb.UpgradeReq, metadata?: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<commands_commands_pb.UpgradeResp>;
version(request: commands_commands_pb.VersionReq, callback: (error: grpc.ServiceError | null, response: commands_commands_pb.VersionResp) => void): grpc.ClientUnaryCall;
version(request: commands_commands_pb.VersionReq, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: commands_commands_pb.VersionResp) => void): grpc.ClientUnaryCall;
version(request: commands_commands_pb.VersionReq, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: commands_commands_pb.VersionResp) => void): grpc.ClientUnaryCall;
loadSketch(request: commands_commands_pb.LoadSketchReq, callback: (error: grpc.ServiceError | null, response: commands_commands_pb.LoadSketchResp) => void): grpc.ClientUnaryCall;
loadSketch(request: commands_commands_pb.LoadSketchReq, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: commands_commands_pb.LoadSketchResp) => void): grpc.ClientUnaryCall;
loadSketch(request: commands_commands_pb.LoadSketchReq, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: commands_commands_pb.LoadSketchResp) => void): grpc.ClientUnaryCall;
boardDetails(request: commands_board_pb.BoardDetailsReq, callback: (error: grpc.ServiceError | null, response: commands_board_pb.BoardDetailsResp) => void): grpc.ClientUnaryCall;
boardDetails(request: commands_board_pb.BoardDetailsReq, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: commands_board_pb.BoardDetailsResp) => void): grpc.ClientUnaryCall;
boardDetails(request: commands_board_pb.BoardDetailsReq, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: commands_board_pb.BoardDetailsResp) => void): grpc.ClientUnaryCall;
@@ -403,9 +457,19 @@ export class ArduinoCoreClient extends grpc.Client implements IArduinoCoreClient
public updateIndex(request: commands_commands_pb.UpdateIndexReq, metadata?: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<commands_commands_pb.UpdateIndexResp>;
public updateLibrariesIndex(request: commands_commands_pb.UpdateLibrariesIndexReq, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<commands_commands_pb.UpdateLibrariesIndexResp>;
public updateLibrariesIndex(request: commands_commands_pb.UpdateLibrariesIndexReq, metadata?: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<commands_commands_pb.UpdateLibrariesIndexResp>;
public updateCoreLibrariesIndex(request: commands_commands_pb.UpdateCoreLibrariesIndexReq, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<commands_commands_pb.UpdateCoreLibrariesIndexResp>;
public updateCoreLibrariesIndex(request: commands_commands_pb.UpdateCoreLibrariesIndexReq, metadata?: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<commands_commands_pb.UpdateCoreLibrariesIndexResp>;
public outdated(request: commands_commands_pb.OutdatedReq, callback: (error: grpc.ServiceError | null, response: commands_commands_pb.OutdatedResp) => void): grpc.ClientUnaryCall;
public outdated(request: commands_commands_pb.OutdatedReq, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: commands_commands_pb.OutdatedResp) => void): grpc.ClientUnaryCall;
public outdated(request: commands_commands_pb.OutdatedReq, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: commands_commands_pb.OutdatedResp) => void): grpc.ClientUnaryCall;
public upgrade(request: commands_commands_pb.UpgradeReq, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<commands_commands_pb.UpgradeResp>;
public upgrade(request: commands_commands_pb.UpgradeReq, metadata?: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<commands_commands_pb.UpgradeResp>;
public version(request: commands_commands_pb.VersionReq, callback: (error: grpc.ServiceError | null, response: commands_commands_pb.VersionResp) => void): grpc.ClientUnaryCall;
public version(request: commands_commands_pb.VersionReq, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: commands_commands_pb.VersionResp) => void): grpc.ClientUnaryCall;
public version(request: commands_commands_pb.VersionReq, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: commands_commands_pb.VersionResp) => void): grpc.ClientUnaryCall;
public loadSketch(request: commands_commands_pb.LoadSketchReq, callback: (error: grpc.ServiceError | null, response: commands_commands_pb.LoadSketchResp) => void): grpc.ClientUnaryCall;
public loadSketch(request: commands_commands_pb.LoadSketchReq, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: commands_commands_pb.LoadSketchResp) => void): grpc.ClientUnaryCall;
public loadSketch(request: commands_commands_pb.LoadSketchReq, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: commands_commands_pb.LoadSketchResp) => void): grpc.ClientUnaryCall;
public boardDetails(request: commands_board_pb.BoardDetailsReq, callback: (error: grpc.ServiceError | null, response: commands_board_pb.BoardDetailsResp) => void): grpc.ClientUnaryCall;
public boardDetails(request: commands_board_pb.BoardDetailsReq, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: commands_board_pb.BoardDetailsResp) => void): grpc.ClientUnaryCall;
public boardDetails(request: commands_board_pb.BoardDetailsReq, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: commands_board_pb.BoardDetailsResp) => void): grpc.ClientUnaryCall;

View File

@@ -377,6 +377,50 @@ function deserialize_cc_arduino_cli_commands_ListProgrammersAvailableForUploadRe
return commands_upload_pb.ListProgrammersAvailableForUploadResp.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_cc_arduino_cli_commands_LoadSketchReq(arg) {
if (!(arg instanceof commands_commands_pb.LoadSketchReq)) {
throw new Error('Expected argument of type cc.arduino.cli.commands.LoadSketchReq');
}
return Buffer.from(arg.serializeBinary());
}
function deserialize_cc_arduino_cli_commands_LoadSketchReq(buffer_arg) {
return commands_commands_pb.LoadSketchReq.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_cc_arduino_cli_commands_LoadSketchResp(arg) {
if (!(arg instanceof commands_commands_pb.LoadSketchResp)) {
throw new Error('Expected argument of type cc.arduino.cli.commands.LoadSketchResp');
}
return Buffer.from(arg.serializeBinary());
}
function deserialize_cc_arduino_cli_commands_LoadSketchResp(buffer_arg) {
return commands_commands_pb.LoadSketchResp.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_cc_arduino_cli_commands_OutdatedReq(arg) {
if (!(arg instanceof commands_commands_pb.OutdatedReq)) {
throw new Error('Expected argument of type cc.arduino.cli.commands.OutdatedReq');
}
return Buffer.from(arg.serializeBinary());
}
function deserialize_cc_arduino_cli_commands_OutdatedReq(buffer_arg) {
return commands_commands_pb.OutdatedReq.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_cc_arduino_cli_commands_OutdatedResp(arg) {
if (!(arg instanceof commands_commands_pb.OutdatedResp)) {
throw new Error('Expected argument of type cc.arduino.cli.commands.OutdatedResp');
}
return Buffer.from(arg.serializeBinary());
}
function deserialize_cc_arduino_cli_commands_OutdatedResp(buffer_arg) {
return commands_commands_pb.OutdatedResp.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_cc_arduino_cli_commands_PlatformDownloadReq(arg) {
if (!(arg instanceof commands_core_pb.PlatformDownloadReq)) {
throw new Error('Expected argument of type cc.arduino.cli.commands.PlatformDownloadReq');
@@ -531,6 +575,28 @@ function deserialize_cc_arduino_cli_commands_RescanResp(buffer_arg) {
return commands_commands_pb.RescanResp.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_cc_arduino_cli_commands_UpdateCoreLibrariesIndexReq(arg) {
if (!(arg instanceof commands_commands_pb.UpdateCoreLibrariesIndexReq)) {
throw new Error('Expected argument of type cc.arduino.cli.commands.UpdateCoreLibrariesIndexReq');
}
return Buffer.from(arg.serializeBinary());
}
function deserialize_cc_arduino_cli_commands_UpdateCoreLibrariesIndexReq(buffer_arg) {
return commands_commands_pb.UpdateCoreLibrariesIndexReq.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_cc_arduino_cli_commands_UpdateCoreLibrariesIndexResp(arg) {
if (!(arg instanceof commands_commands_pb.UpdateCoreLibrariesIndexResp)) {
throw new Error('Expected argument of type cc.arduino.cli.commands.UpdateCoreLibrariesIndexResp');
}
return Buffer.from(arg.serializeBinary());
}
function deserialize_cc_arduino_cli_commands_UpdateCoreLibrariesIndexResp(buffer_arg) {
return commands_commands_pb.UpdateCoreLibrariesIndexResp.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_cc_arduino_cli_commands_UpdateIndexReq(arg) {
if (!(arg instanceof commands_commands_pb.UpdateIndexReq)) {
throw new Error('Expected argument of type cc.arduino.cli.commands.UpdateIndexReq');
@@ -575,6 +641,28 @@ function deserialize_cc_arduino_cli_commands_UpdateLibrariesIndexResp(buffer_arg
return commands_commands_pb.UpdateLibrariesIndexResp.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_cc_arduino_cli_commands_UpgradeReq(arg) {
if (!(arg instanceof commands_commands_pb.UpgradeReq)) {
throw new Error('Expected argument of type cc.arduino.cli.commands.UpgradeReq');
}
return Buffer.from(arg.serializeBinary());
}
function deserialize_cc_arduino_cli_commands_UpgradeReq(buffer_arg) {
return commands_commands_pb.UpgradeReq.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_cc_arduino_cli_commands_UpgradeResp(arg) {
if (!(arg instanceof commands_commands_pb.UpgradeResp)) {
throw new Error('Expected argument of type cc.arduino.cli.commands.UpgradeResp');
}
return Buffer.from(arg.serializeBinary());
}
function deserialize_cc_arduino_cli_commands_UpgradeResp(buffer_arg) {
return commands_commands_pb.UpgradeResp.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_cc_arduino_cli_commands_UploadReq(arg) {
if (!(arg instanceof commands_upload_pb.UploadReq)) {
throw new Error('Expected argument of type cc.arduino.cli.commands.UploadReq');
@@ -682,6 +770,42 @@ updateLibrariesIndex: {
responseSerialize: serialize_cc_arduino_cli_commands_UpdateLibrariesIndexResp,
responseDeserialize: deserialize_cc_arduino_cli_commands_UpdateLibrariesIndexResp,
},
// Update packages indexes for both Cores and Libraries
updateCoreLibrariesIndex: {
path: '/cc.arduino.cli.commands.ArduinoCore/UpdateCoreLibrariesIndex',
requestStream: false,
responseStream: true,
requestType: commands_commands_pb.UpdateCoreLibrariesIndexReq,
responseType: commands_commands_pb.UpdateCoreLibrariesIndexResp,
requestSerialize: serialize_cc_arduino_cli_commands_UpdateCoreLibrariesIndexReq,
requestDeserialize: deserialize_cc_arduino_cli_commands_UpdateCoreLibrariesIndexReq,
responseSerialize: serialize_cc_arduino_cli_commands_UpdateCoreLibrariesIndexResp,
responseDeserialize: deserialize_cc_arduino_cli_commands_UpdateCoreLibrariesIndexResp,
},
// Outdated returns a message with a list of outdated Cores and Libraries
outdated: {
path: '/cc.arduino.cli.commands.ArduinoCore/Outdated',
requestStream: false,
responseStream: false,
requestType: commands_commands_pb.OutdatedReq,
responseType: commands_commands_pb.OutdatedResp,
requestSerialize: serialize_cc_arduino_cli_commands_OutdatedReq,
requestDeserialize: deserialize_cc_arduino_cli_commands_OutdatedReq,
responseSerialize: serialize_cc_arduino_cli_commands_OutdatedResp,
responseDeserialize: deserialize_cc_arduino_cli_commands_OutdatedResp,
},
// Upgrade both Cores and Libraries
upgrade: {
path: '/cc.arduino.cli.commands.ArduinoCore/Upgrade',
requestStream: false,
responseStream: true,
requestType: commands_commands_pb.UpgradeReq,
responseType: commands_commands_pb.UpgradeResp,
requestSerialize: serialize_cc_arduino_cli_commands_UpgradeReq,
requestDeserialize: deserialize_cc_arduino_cli_commands_UpgradeReq,
responseSerialize: serialize_cc_arduino_cli_commands_UpgradeResp,
responseDeserialize: deserialize_cc_arduino_cli_commands_UpgradeResp,
},
// Get the version of Arduino CLI in use.
version: {
path: '/cc.arduino.cli.commands.ArduinoCore/Version',
@@ -694,6 +818,18 @@ version: {
responseSerialize: serialize_cc_arduino_cli_commands_VersionResp,
responseDeserialize: deserialize_cc_arduino_cli_commands_VersionResp,
},
// Returns all files composing a Sketch
loadSketch: {
path: '/cc.arduino.cli.commands.ArduinoCore/LoadSketch',
requestStream: false,
responseStream: false,
requestType: commands_commands_pb.LoadSketchReq,
responseType: commands_commands_pb.LoadSketchResp,
requestSerialize: serialize_cc_arduino_cli_commands_LoadSketchReq,
requestDeserialize: deserialize_cc_arduino_cli_commands_LoadSketchReq,
responseSerialize: serialize_cc_arduino_cli_commands_LoadSketchResp,
responseDeserialize: deserialize_cc_arduino_cli_commands_LoadSketchResp,
},
// BOARD COMMANDS
// --------------
//
@@ -709,7 +845,7 @@ boardDetails: {
responseSerialize: serialize_cc_arduino_cli_commands_BoardDetailsResp,
responseDeserialize: deserialize_cc_arduino_cli_commands_BoardDetailsResp,
},
// Attach a board to a sketch. When the `fqbn` field of a request is not
// Attach a board to a sketch. When the `fqbn` field of a request is not
// provided, the FQBN of the attached board will be used.
boardAttach: {
path: '/cc.arduino.cli.commands.ArduinoCore/BoardAttach',

View File

@@ -269,6 +269,162 @@ export namespace UpdateLibrariesIndexResp {
}
}
export class UpdateCoreLibrariesIndexReq extends jspb.Message {
hasInstance(): boolean;
clearInstance(): void;
getInstance(): commands_common_pb.Instance | undefined;
setInstance(value?: commands_common_pb.Instance): UpdateCoreLibrariesIndexReq;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): UpdateCoreLibrariesIndexReq.AsObject;
static toObject(includeInstance: boolean, msg: UpdateCoreLibrariesIndexReq): UpdateCoreLibrariesIndexReq.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: UpdateCoreLibrariesIndexReq, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): UpdateCoreLibrariesIndexReq;
static deserializeBinaryFromReader(message: UpdateCoreLibrariesIndexReq, reader: jspb.BinaryReader): UpdateCoreLibrariesIndexReq;
}
export namespace UpdateCoreLibrariesIndexReq {
export type AsObject = {
instance?: commands_common_pb.Instance.AsObject,
}
}
export class UpdateCoreLibrariesIndexResp extends jspb.Message {
hasDownloadProgress(): boolean;
clearDownloadProgress(): void;
getDownloadProgress(): commands_common_pb.DownloadProgress | undefined;
setDownloadProgress(value?: commands_common_pb.DownloadProgress): UpdateCoreLibrariesIndexResp;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): UpdateCoreLibrariesIndexResp.AsObject;
static toObject(includeInstance: boolean, msg: UpdateCoreLibrariesIndexResp): UpdateCoreLibrariesIndexResp.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: UpdateCoreLibrariesIndexResp, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): UpdateCoreLibrariesIndexResp;
static deserializeBinaryFromReader(message: UpdateCoreLibrariesIndexResp, reader: jspb.BinaryReader): UpdateCoreLibrariesIndexResp;
}
export namespace UpdateCoreLibrariesIndexResp {
export type AsObject = {
downloadProgress?: commands_common_pb.DownloadProgress.AsObject,
}
}
export class OutdatedReq extends jspb.Message {
hasInstance(): boolean;
clearInstance(): void;
getInstance(): commands_common_pb.Instance | undefined;
setInstance(value?: commands_common_pb.Instance): OutdatedReq;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): OutdatedReq.AsObject;
static toObject(includeInstance: boolean, msg: OutdatedReq): OutdatedReq.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: OutdatedReq, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): OutdatedReq;
static deserializeBinaryFromReader(message: OutdatedReq, reader: jspb.BinaryReader): OutdatedReq;
}
export namespace OutdatedReq {
export type AsObject = {
instance?: commands_common_pb.Instance.AsObject,
}
}
export class OutdatedResp extends jspb.Message {
clearOutdatedLibraryList(): void;
getOutdatedLibraryList(): Array<commands_lib_pb.InstalledLibrary>;
setOutdatedLibraryList(value: Array<commands_lib_pb.InstalledLibrary>): OutdatedResp;
addOutdatedLibrary(value?: commands_lib_pb.InstalledLibrary, index?: number): commands_lib_pb.InstalledLibrary;
clearOutdatedPlatformList(): void;
getOutdatedPlatformList(): Array<commands_core_pb.Platform>;
setOutdatedPlatformList(value: Array<commands_core_pb.Platform>): OutdatedResp;
addOutdatedPlatform(value?: commands_core_pb.Platform, index?: number): commands_core_pb.Platform;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): OutdatedResp.AsObject;
static toObject(includeInstance: boolean, msg: OutdatedResp): OutdatedResp.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: OutdatedResp, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): OutdatedResp;
static deserializeBinaryFromReader(message: OutdatedResp, reader: jspb.BinaryReader): OutdatedResp;
}
export namespace OutdatedResp {
export type AsObject = {
outdatedLibraryList: Array<commands_lib_pb.InstalledLibrary.AsObject>,
outdatedPlatformList: Array<commands_core_pb.Platform.AsObject>,
}
}
export class UpgradeReq extends jspb.Message {
hasInstance(): boolean;
clearInstance(): void;
getInstance(): commands_common_pb.Instance | undefined;
setInstance(value?: commands_common_pb.Instance): UpgradeReq;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): UpgradeReq.AsObject;
static toObject(includeInstance: boolean, msg: UpgradeReq): UpgradeReq.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: UpgradeReq, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): UpgradeReq;
static deserializeBinaryFromReader(message: UpgradeReq, reader: jspb.BinaryReader): UpgradeReq;
}
export namespace UpgradeReq {
export type AsObject = {
instance?: commands_common_pb.Instance.AsObject,
}
}
export class UpgradeResp extends jspb.Message {
hasProgress(): boolean;
clearProgress(): void;
getProgress(): commands_common_pb.DownloadProgress | undefined;
setProgress(value?: commands_common_pb.DownloadProgress): UpgradeResp;
hasTaskProgress(): boolean;
clearTaskProgress(): void;
getTaskProgress(): commands_common_pb.TaskProgress | undefined;
setTaskProgress(value?: commands_common_pb.TaskProgress): UpgradeResp;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): UpgradeResp.AsObject;
static toObject(includeInstance: boolean, msg: UpgradeResp): UpgradeResp.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: UpgradeResp, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): UpgradeResp;
static deserializeBinaryFromReader(message: UpgradeResp, reader: jspb.BinaryReader): UpgradeResp;
}
export namespace UpgradeResp {
export type AsObject = {
progress?: commands_common_pb.DownloadProgress.AsObject,
taskProgress?: commands_common_pb.TaskProgress.AsObject,
}
}
export class VersionReq extends jspb.Message {
serializeBinary(): Uint8Array;
@@ -306,3 +462,68 @@ export namespace VersionResp {
version: string,
}
}
export class LoadSketchReq extends jspb.Message {
hasInstance(): boolean;
clearInstance(): void;
getInstance(): commands_common_pb.Instance | undefined;
setInstance(value?: commands_common_pb.Instance): LoadSketchReq;
getSketchPath(): string;
setSketchPath(value: string): LoadSketchReq;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): LoadSketchReq.AsObject;
static toObject(includeInstance: boolean, msg: LoadSketchReq): LoadSketchReq.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: LoadSketchReq, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): LoadSketchReq;
static deserializeBinaryFromReader(message: LoadSketchReq, reader: jspb.BinaryReader): LoadSketchReq;
}
export namespace LoadSketchReq {
export type AsObject = {
instance?: commands_common_pb.Instance.AsObject,
sketchPath: string,
}
}
export class LoadSketchResp extends jspb.Message {
getMainFile(): string;
setMainFile(value: string): LoadSketchResp;
getLocationPath(): string;
setLocationPath(value: string): LoadSketchResp;
clearOtherSketchFilesList(): void;
getOtherSketchFilesList(): Array<string>;
setOtherSketchFilesList(value: Array<string>): LoadSketchResp;
addOtherSketchFiles(value: string, index?: number): string;
clearAdditionalFilesList(): void;
getAdditionalFilesList(): Array<string>;
setAdditionalFilesList(value: Array<string>): LoadSketchResp;
addAdditionalFiles(value: string, index?: number): string;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): LoadSketchResp.AsObject;
static toObject(includeInstance: boolean, msg: LoadSketchResp): LoadSketchResp.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: LoadSketchResp, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): LoadSketchResp;
static deserializeBinaryFromReader(message: LoadSketchResp, reader: jspb.BinaryReader): LoadSketchResp;
}
export namespace LoadSketchResp {
export type AsObject = {
mainFile: string,
locationPath: string,
otherSketchFilesList: Array<string>,
additionalFilesList: Array<string>,
}
}

View File

@@ -92,3 +92,32 @@ export namespace TaskProgress {
completed: boolean,
}
}
export class Programmer extends jspb.Message {
getPlatform(): string;
setPlatform(value: string): Programmer;
getId(): string;
setId(value: string): Programmer;
getName(): string;
setName(value: string): Programmer;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): Programmer.AsObject;
static toObject(includeInstance: boolean, msg: Programmer): Programmer.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: Programmer, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): Programmer;
static deserializeBinaryFromReader(message: Programmer, reader: jspb.BinaryReader): Programmer;
}
export namespace Programmer {
export type AsObject = {
platform: string,
id: string,
name: string,
}
}

View File

@@ -14,6 +14,7 @@ var global = Function('return this')();
goog.exportSymbol('proto.cc.arduino.cli.commands.DownloadProgress', null, global);
goog.exportSymbol('proto.cc.arduino.cli.commands.Instance', null, global);
goog.exportSymbol('proto.cc.arduino.cli.commands.Programmer', null, global);
goog.exportSymbol('proto.cc.arduino.cli.commands.TaskProgress', null, global);
/**
* Generated by JsPbCodeGenerator.
@@ -78,6 +79,27 @@ if (goog.DEBUG && !COMPILED) {
*/
proto.cc.arduino.cli.commands.TaskProgress.displayName = 'proto.cc.arduino.cli.commands.TaskProgress';
}
/**
* Generated by JsPbCodeGenerator.
* @param {Array=} opt_data Optional initial data array, typically from a
* server response, or constructed directly in Javascript. The array is used
* in place and becomes part of the constructed object. It is not cloned.
* If no data is provided, the constructed object will be empty, but still
* valid.
* @extends {jspb.Message}
* @constructor
*/
proto.cc.arduino.cli.commands.Programmer = function(opt_data) {
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
};
goog.inherits(proto.cc.arduino.cli.commands.Programmer, jspb.Message);
if (goog.DEBUG && !COMPILED) {
/**
* @public
* @override
*/
proto.cc.arduino.cli.commands.Programmer.displayName = 'proto.cc.arduino.cli.commands.Programmer';
}
@@ -648,4 +670,194 @@ proto.cc.arduino.cli.commands.TaskProgress.prototype.setCompleted = function(val
};
if (jspb.Message.GENERATE_TO_OBJECT) {
/**
* Creates an object representation of this proto.
* Field names that are reserved in JavaScript and will be renamed to pb_name.
* Optional fields that are not set will be set to undefined.
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
* For the list of reserved names please see:
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
* JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @return {!Object}
*/
proto.cc.arduino.cli.commands.Programmer.prototype.toObject = function(opt_includeInstance) {
return proto.cc.arduino.cli.commands.Programmer.toObject(opt_includeInstance, this);
};
/**
* Static version of the {@see toObject} method.
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
* the JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @param {!proto.cc.arduino.cli.commands.Programmer} msg The msg instance to transform.
* @return {!Object}
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.cc.arduino.cli.commands.Programmer.toObject = function(includeInstance, msg) {
var f, obj = {
platform: jspb.Message.getFieldWithDefault(msg, 1, ""),
id: jspb.Message.getFieldWithDefault(msg, 2, ""),
name: jspb.Message.getFieldWithDefault(msg, 3, "")
};
if (includeInstance) {
obj.$jspbMessageInstance = msg;
}
return obj;
};
}
/**
* Deserializes binary data (in protobuf wire format).
* @param {jspb.ByteSource} bytes The bytes to deserialize.
* @return {!proto.cc.arduino.cli.commands.Programmer}
*/
proto.cc.arduino.cli.commands.Programmer.deserializeBinary = function(bytes) {
var reader = new jspb.BinaryReader(bytes);
var msg = new proto.cc.arduino.cli.commands.Programmer;
return proto.cc.arduino.cli.commands.Programmer.deserializeBinaryFromReader(msg, reader);
};
/**
* Deserializes binary data (in protobuf wire format) from the
* given reader into the given message object.
* @param {!proto.cc.arduino.cli.commands.Programmer} msg The message object to deserialize into.
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
* @return {!proto.cc.arduino.cli.commands.Programmer}
*/
proto.cc.arduino.cli.commands.Programmer.deserializeBinaryFromReader = function(msg, reader) {
while (reader.nextField()) {
if (reader.isEndGroup()) {
break;
}
var field = reader.getFieldNumber();
switch (field) {
case 1:
var value = /** @type {string} */ (reader.readString());
msg.setPlatform(value);
break;
case 2:
var value = /** @type {string} */ (reader.readString());
msg.setId(value);
break;
case 3:
var value = /** @type {string} */ (reader.readString());
msg.setName(value);
break;
default:
reader.skipField();
break;
}
}
return msg;
};
/**
* Serializes the message to binary data (in protobuf wire format).
* @return {!Uint8Array}
*/
proto.cc.arduino.cli.commands.Programmer.prototype.serializeBinary = function() {
var writer = new jspb.BinaryWriter();
proto.cc.arduino.cli.commands.Programmer.serializeBinaryToWriter(this, writer);
return writer.getResultBuffer();
};
/**
* Serializes the given message to binary data (in protobuf wire
* format), writing to the given BinaryWriter.
* @param {!proto.cc.arduino.cli.commands.Programmer} message
* @param {!jspb.BinaryWriter} writer
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.cc.arduino.cli.commands.Programmer.serializeBinaryToWriter = function(message, writer) {
var f = undefined;
f = message.getPlatform();
if (f.length > 0) {
writer.writeString(
1,
f
);
}
f = message.getId();
if (f.length > 0) {
writer.writeString(
2,
f
);
}
f = message.getName();
if (f.length > 0) {
writer.writeString(
3,
f
);
}
};
/**
* optional string platform = 1;
* @return {string}
*/
proto.cc.arduino.cli.commands.Programmer.prototype.getPlatform = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
};
/**
* @param {string} value
* @return {!proto.cc.arduino.cli.commands.Programmer} returns this
*/
proto.cc.arduino.cli.commands.Programmer.prototype.setPlatform = function(value) {
return jspb.Message.setProto3StringField(this, 1, value);
};
/**
* optional string id = 2;
* @return {string}
*/
proto.cc.arduino.cli.commands.Programmer.prototype.getId = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
};
/**
* @param {string} value
* @return {!proto.cc.arduino.cli.commands.Programmer} returns this
*/
proto.cc.arduino.cli.commands.Programmer.prototype.setId = function(value) {
return jspb.Message.setProto3StringField(this, 2, value);
};
/**
* optional string name = 3;
* @return {string}
*/
proto.cc.arduino.cli.commands.Programmer.prototype.getName = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, ""));
};
/**
* @param {string} value
* @return {!proto.cc.arduino.cli.commands.Programmer} returns this
*/
proto.cc.arduino.cli.commands.Programmer.prototype.setName = function(value) {
return jspb.Message.setProto3StringField(this, 3, value);
};
goog.object.extend(exports, proto.cc.arduino.cli.commands);

View File

@@ -23,6 +23,9 @@ export class PlatformInstallReq extends jspb.Message {
getVersion(): string;
setVersion(value: string): PlatformInstallReq;
getSkippostinstall(): boolean;
setSkippostinstall(value: boolean): PlatformInstallReq;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): PlatformInstallReq.AsObject;
@@ -40,6 +43,7 @@ export namespace PlatformInstallReq {
platformPackage: string,
architecture: string,
version: string,
skippostinstall: boolean,
}
}
@@ -203,6 +207,9 @@ export class PlatformUpgradeReq extends jspb.Message {
getArchitecture(): string;
setArchitecture(value: string): PlatformUpgradeReq;
getSkippostinstall(): boolean;
setSkippostinstall(value: boolean): PlatformUpgradeReq;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): PlatformUpgradeReq.AsObject;
@@ -219,6 +226,7 @@ export namespace PlatformUpgradeReq {
instance?: commands_common_pb.Instance.AsObject,
platformPackage: string,
architecture: string,
skippostinstall: boolean,
}
}

View File

@@ -357,7 +357,8 @@ proto.cc.arduino.cli.commands.PlatformInstallReq.toObject = function(includeInst
instance: (f = msg.getInstance()) && commands_common_pb.Instance.toObject(includeInstance, f),
platformPackage: jspb.Message.getFieldWithDefault(msg, 2, ""),
architecture: jspb.Message.getFieldWithDefault(msg, 3, ""),
version: jspb.Message.getFieldWithDefault(msg, 4, "")
version: jspb.Message.getFieldWithDefault(msg, 4, ""),
skippostinstall: jspb.Message.getBooleanFieldWithDefault(msg, 5, false)
};
if (includeInstance) {
@@ -411,6 +412,10 @@ proto.cc.arduino.cli.commands.PlatformInstallReq.deserializeBinaryFromReader = f
var value = /** @type {string} */ (reader.readString());
msg.setVersion(value);
break;
case 5:
var value = /** @type {boolean} */ (reader.readBool());
msg.setSkippostinstall(value);
break;
default:
reader.skipField();
break;
@@ -469,6 +474,13 @@ proto.cc.arduino.cli.commands.PlatformInstallReq.serializeBinaryToWriter = funct
f
);
}
f = message.getSkippostinstall();
if (f) {
writer.writeBool(
5,
f
);
}
};
@@ -563,6 +575,24 @@ proto.cc.arduino.cli.commands.PlatformInstallReq.prototype.setVersion = function
};
/**
* optional bool skipPostInstall = 5;
* @return {boolean}
*/
proto.cc.arduino.cli.commands.PlatformInstallReq.prototype.getSkippostinstall = function() {
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 5, false));
};
/**
* @param {boolean} value
* @return {!proto.cc.arduino.cli.commands.PlatformInstallReq} returns this
*/
proto.cc.arduino.cli.commands.PlatformInstallReq.prototype.setSkippostinstall = function(value) {
return jspb.Message.setProto3BooleanField(this, 5, value);
};
@@ -1553,7 +1583,8 @@ proto.cc.arduino.cli.commands.PlatformUpgradeReq.toObject = function(includeInst
var f, obj = {
instance: (f = msg.getInstance()) && commands_common_pb.Instance.toObject(includeInstance, f),
platformPackage: jspb.Message.getFieldWithDefault(msg, 2, ""),
architecture: jspb.Message.getFieldWithDefault(msg, 3, "")
architecture: jspb.Message.getFieldWithDefault(msg, 3, ""),
skippostinstall: jspb.Message.getBooleanFieldWithDefault(msg, 4, false)
};
if (includeInstance) {
@@ -1603,6 +1634,10 @@ proto.cc.arduino.cli.commands.PlatformUpgradeReq.deserializeBinaryFromReader = f
var value = /** @type {string} */ (reader.readString());
msg.setArchitecture(value);
break;
case 4:
var value = /** @type {boolean} */ (reader.readBool());
msg.setSkippostinstall(value);
break;
default:
reader.skipField();
break;
@@ -1654,6 +1689,13 @@ proto.cc.arduino.cli.commands.PlatformUpgradeReq.serializeBinaryToWriter = funct
f
);
}
f = message.getSkippostinstall();
if (f) {
writer.writeBool(
4,
f
);
}
};
@@ -1730,6 +1772,24 @@ proto.cc.arduino.cli.commands.PlatformUpgradeReq.prototype.setArchitecture = fun
};
/**
* optional bool skipPostInstall = 4;
* @return {boolean}
*/
proto.cc.arduino.cli.commands.PlatformUpgradeReq.prototype.getSkippostinstall = function() {
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 4, false));
};
/**
* @param {boolean} value
* @return {!proto.cc.arduino.cli.commands.PlatformUpgradeReq} returns this
*/
proto.cc.arduino.cli.commands.PlatformUpgradeReq.prototype.setSkippostinstall = function(value) {
return jspb.Message.setProto3BooleanField(this, 4, value);
};

View File

@@ -565,6 +565,12 @@ export class LibraryListReq extends jspb.Message {
getUpdatable(): boolean;
setUpdatable(value: boolean): LibraryListReq;
getName(): string;
setName(value: string): LibraryListReq;
getFqbn(): string;
setFqbn(value: string): LibraryListReq;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): LibraryListReq.AsObject;
@@ -581,6 +587,8 @@ export namespace LibraryListReq {
instance?: commands_common_pb.Instance.AsObject,
all: boolean,
updatable: boolean,
name: string,
fqbn: string,
}
}
@@ -713,6 +721,16 @@ export class Library extends jspb.Message {
getLayout(): LibraryLayout;
setLayout(value: LibraryLayout): Library;
clearExamplesList(): void;
getExamplesList(): Array<string>;
setExamplesList(value: Array<string>): Library;
addExamples(value: string, index?: number): string;
clearProvidesIncludesList(): void;
getProvidesIncludesList(): Array<string>;
setProvidesIncludesList(value: Array<string>): Library;
addProvidesIncludes(value: string, index?: number): string;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): Library.AsObject;
@@ -750,6 +768,8 @@ export namespace Library {
propertiesMap: Array<[string, string]>,
location: LibraryLocation,
layout: LibraryLayout,
examplesList: Array<string>,
providesIncludesList: Array<string>,
}
}

View File

@@ -4157,7 +4157,9 @@ proto.cc.arduino.cli.commands.LibraryListReq.toObject = function(includeInstance
var f, obj = {
instance: (f = msg.getInstance()) && commands_common_pb.Instance.toObject(includeInstance, f),
all: jspb.Message.getBooleanFieldWithDefault(msg, 2, false),
updatable: jspb.Message.getBooleanFieldWithDefault(msg, 3, false)
updatable: jspb.Message.getBooleanFieldWithDefault(msg, 3, false),
name: jspb.Message.getFieldWithDefault(msg, 4, ""),
fqbn: jspb.Message.getFieldWithDefault(msg, 5, "")
};
if (includeInstance) {
@@ -4207,6 +4209,14 @@ proto.cc.arduino.cli.commands.LibraryListReq.deserializeBinaryFromReader = funct
var value = /** @type {boolean} */ (reader.readBool());
msg.setUpdatable(value);
break;
case 4:
var value = /** @type {string} */ (reader.readString());
msg.setName(value);
break;
case 5:
var value = /** @type {string} */ (reader.readString());
msg.setFqbn(value);
break;
default:
reader.skipField();
break;
@@ -4258,6 +4268,20 @@ proto.cc.arduino.cli.commands.LibraryListReq.serializeBinaryToWriter = function(
f
);
}
f = message.getName();
if (f.length > 0) {
writer.writeString(
4,
f
);
}
f = message.getFqbn();
if (f.length > 0) {
writer.writeString(
5,
f
);
}
};
@@ -4334,6 +4358,42 @@ proto.cc.arduino.cli.commands.LibraryListReq.prototype.setUpdatable = function(v
};
/**
* optional string name = 4;
* @return {string}
*/
proto.cc.arduino.cli.commands.LibraryListReq.prototype.getName = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, ""));
};
/**
* @param {string} value
* @return {!proto.cc.arduino.cli.commands.LibraryListReq} returns this
*/
proto.cc.arduino.cli.commands.LibraryListReq.prototype.setName = function(value) {
return jspb.Message.setProto3StringField(this, 4, value);
};
/**
* optional string fqbn = 5;
* @return {string}
*/
proto.cc.arduino.cli.commands.LibraryListReq.prototype.getFqbn = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 5, ""));
};
/**
* @param {string} value
* @return {!proto.cc.arduino.cli.commands.LibraryListReq} returns this
*/
proto.cc.arduino.cli.commands.LibraryListReq.prototype.setFqbn = function(value) {
return jspb.Message.setProto3StringField(this, 5, value);
};
/**
* List of repeated fields within this message type.
@@ -4702,7 +4762,7 @@ proto.cc.arduino.cli.commands.InstalledLibrary.prototype.hasRelease = function()
* @private {!Array<number>}
* @const
*/
proto.cc.arduino.cli.commands.Library.repeatedFields_ = [8,9];
proto.cc.arduino.cli.commands.Library.repeatedFields_ = [8,9,26,27];
@@ -4757,7 +4817,9 @@ proto.cc.arduino.cli.commands.Library.toObject = function(includeInstance, msg)
license: jspb.Message.getFieldWithDefault(msg, 22, ""),
propertiesMap: (f = msg.getPropertiesMap()) ? f.toObject(includeInstance, undefined) : [],
location: jspb.Message.getFieldWithDefault(msg, 24, 0),
layout: jspb.Message.getFieldWithDefault(msg, 25, 0)
layout: jspb.Message.getFieldWithDefault(msg, 25, 0),
examplesList: (f = jspb.Message.getRepeatedField(msg, 26)) == null ? undefined : f,
providesIncludesList: (f = jspb.Message.getRepeatedField(msg, 27)) == null ? undefined : f
};
if (includeInstance) {
@@ -4888,6 +4950,14 @@ proto.cc.arduino.cli.commands.Library.deserializeBinaryFromReader = function(msg
var value = /** @type {!proto.cc.arduino.cli.commands.LibraryLayout} */ (reader.readEnum());
msg.setLayout(value);
break;
case 26:
var value = /** @type {string} */ (reader.readString());
msg.addExamples(value);
break;
case 27:
var value = /** @type {string} */ (reader.readString());
msg.addProvidesIncludes(value);
break;
default:
reader.skipField();
break;
@@ -5075,6 +5145,20 @@ proto.cc.arduino.cli.commands.Library.serializeBinaryToWriter = function(message
f
);
}
f = message.getExamplesList();
if (f.length > 0) {
writer.writeRepeatedString(
26,
f
);
}
f = message.getProvidesIncludesList();
if (f.length > 0) {
writer.writeRepeatedString(
27,
f
);
}
};
@@ -5534,6 +5618,80 @@ proto.cc.arduino.cli.commands.Library.prototype.setLayout = function(value) {
};
/**
* repeated string examples = 26;
* @return {!Array<string>}
*/
proto.cc.arduino.cli.commands.Library.prototype.getExamplesList = function() {
return /** @type {!Array<string>} */ (jspb.Message.getRepeatedField(this, 26));
};
/**
* @param {!Array<string>} value
* @return {!proto.cc.arduino.cli.commands.Library} returns this
*/
proto.cc.arduino.cli.commands.Library.prototype.setExamplesList = function(value) {
return jspb.Message.setField(this, 26, value || []);
};
/**
* @param {string} value
* @param {number=} opt_index
* @return {!proto.cc.arduino.cli.commands.Library} returns this
*/
proto.cc.arduino.cli.commands.Library.prototype.addExamples = function(value, opt_index) {
return jspb.Message.addToRepeatedField(this, 26, value, opt_index);
};
/**
* Clears the list making it empty but non-null.
* @return {!proto.cc.arduino.cli.commands.Library} returns this
*/
proto.cc.arduino.cli.commands.Library.prototype.clearExamplesList = function() {
return this.setExamplesList([]);
};
/**
* repeated string provides_includes = 27;
* @return {!Array<string>}
*/
proto.cc.arduino.cli.commands.Library.prototype.getProvidesIncludesList = function() {
return /** @type {!Array<string>} */ (jspb.Message.getRepeatedField(this, 27));
};
/**
* @param {!Array<string>} value
* @return {!proto.cc.arduino.cli.commands.Library} returns this
*/
proto.cc.arduino.cli.commands.Library.prototype.setProvidesIncludesList = function(value) {
return jspb.Message.setField(this, 27, value || []);
};
/**
* @param {string} value
* @param {number=} opt_index
* @return {!proto.cc.arduino.cli.commands.Library} returns this
*/
proto.cc.arduino.cli.commands.Library.prototype.addProvidesIncludes = function(value, opt_index) {
return jspb.Message.addToRepeatedField(this, 27, value, opt_index);
};
/**
* Clears the list making it empty but non-null.
* @return {!proto.cc.arduino.cli.commands.Library} returns this
*/
proto.cc.arduino.cli.commands.Library.prototype.clearProvidesIncludesList = function() {
return this.setProvidesIncludesList([]);
};
/**
* @enum {number}
*/

View File

@@ -195,9 +195,9 @@ export namespace ListProgrammersAvailableForUploadReq {
export class ListProgrammersAvailableForUploadResp extends jspb.Message {
clearProgrammersList(): void;
getProgrammersList(): Array<Programmer>;
setProgrammersList(value: Array<Programmer>): ListProgrammersAvailableForUploadResp;
addProgrammers(value?: Programmer, index?: number): Programmer;
getProgrammersList(): Array<commands_common_pb.Programmer>;
setProgrammersList(value: Array<commands_common_pb.Programmer>): ListProgrammersAvailableForUploadResp;
addProgrammers(value?: commands_common_pb.Programmer, index?: number): commands_common_pb.Programmer;
serializeBinary(): Uint8Array;
@@ -212,35 +212,6 @@ export class ListProgrammersAvailableForUploadResp extends jspb.Message {
export namespace ListProgrammersAvailableForUploadResp {
export type AsObject = {
programmersList: Array<Programmer.AsObject>,
}
}
export class Programmer extends jspb.Message {
getPlatform(): string;
setPlatform(value: string): Programmer;
getId(): string;
setId(value: string): Programmer;
getName(): string;
setName(value: string): Programmer;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): Programmer.AsObject;
static toObject(includeInstance: boolean, msg: Programmer): Programmer.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: Programmer, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): Programmer;
static deserializeBinaryFromReader(message: Programmer, reader: jspb.BinaryReader): Programmer;
}
export namespace Programmer {
export type AsObject = {
platform: string,
id: string,
name: string,
programmersList: Array<commands_common_pb.Programmer.AsObject>,
}
}

View File

@@ -18,7 +18,6 @@ goog.exportSymbol('proto.cc.arduino.cli.commands.BurnBootloaderReq', null, globa
goog.exportSymbol('proto.cc.arduino.cli.commands.BurnBootloaderResp', null, global);
goog.exportSymbol('proto.cc.arduino.cli.commands.ListProgrammersAvailableForUploadReq', null, global);
goog.exportSymbol('proto.cc.arduino.cli.commands.ListProgrammersAvailableForUploadResp', null, global);
goog.exportSymbol('proto.cc.arduino.cli.commands.Programmer', null, global);
goog.exportSymbol('proto.cc.arduino.cli.commands.UploadReq', null, global);
goog.exportSymbol('proto.cc.arduino.cli.commands.UploadResp', null, global);
/**
@@ -147,27 +146,6 @@ if (goog.DEBUG && !COMPILED) {
*/
proto.cc.arduino.cli.commands.ListProgrammersAvailableForUploadResp.displayName = 'proto.cc.arduino.cli.commands.ListProgrammersAvailableForUploadResp';
}
/**
* Generated by JsPbCodeGenerator.
* @param {Array=} opt_data Optional initial data array, typically from a
* server response, or constructed directly in Javascript. The array is used
* in place and becomes part of the constructed object. It is not cloned.
* If no data is provided, the constructed object will be empty, but still
* valid.
* @extends {jspb.Message}
* @constructor
*/
proto.cc.arduino.cli.commands.Programmer = function(opt_data) {
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
};
goog.inherits(proto.cc.arduino.cli.commands.Programmer, jspb.Message);
if (goog.DEBUG && !COMPILED) {
/**
* @public
* @override
*/
proto.cc.arduino.cli.commands.Programmer.displayName = 'proto.cc.arduino.cli.commands.Programmer';
}
@@ -1497,7 +1475,7 @@ proto.cc.arduino.cli.commands.ListProgrammersAvailableForUploadResp.prototype.to
proto.cc.arduino.cli.commands.ListProgrammersAvailableForUploadResp.toObject = function(includeInstance, msg) {
var f, obj = {
programmersList: jspb.Message.toObjectList(msg.getProgrammersList(),
proto.cc.arduino.cli.commands.Programmer.toObject, includeInstance)
commands_common_pb.Programmer.toObject, includeInstance)
};
if (includeInstance) {
@@ -1535,8 +1513,8 @@ proto.cc.arduino.cli.commands.ListProgrammersAvailableForUploadResp.deserializeB
var field = reader.getFieldNumber();
switch (field) {
case 1:
var value = new proto.cc.arduino.cli.commands.Programmer;
reader.readMessage(value,proto.cc.arduino.cli.commands.Programmer.deserializeBinaryFromReader);
var value = new commands_common_pb.Programmer;
reader.readMessage(value,commands_common_pb.Programmer.deserializeBinaryFromReader);
msg.addProgrammers(value);
break;
default:
@@ -1573,7 +1551,7 @@ proto.cc.arduino.cli.commands.ListProgrammersAvailableForUploadResp.serializeBin
writer.writeRepeatedMessage(
1,
f,
proto.cc.arduino.cli.commands.Programmer.serializeBinaryToWriter
commands_common_pb.Programmer.serializeBinaryToWriter
);
}
};
@@ -1585,7 +1563,7 @@ proto.cc.arduino.cli.commands.ListProgrammersAvailableForUploadResp.serializeBin
*/
proto.cc.arduino.cli.commands.ListProgrammersAvailableForUploadResp.prototype.getProgrammersList = function() {
return /** @type{!Array<!proto.cc.arduino.cli.commands.Programmer>} */ (
jspb.Message.getRepeatedWrapperField(this, proto.cc.arduino.cli.commands.Programmer, 1));
jspb.Message.getRepeatedWrapperField(this, commands_common_pb.Programmer, 1));
};
@@ -1617,194 +1595,4 @@ proto.cc.arduino.cli.commands.ListProgrammersAvailableForUploadResp.prototype.cl
};
if (jspb.Message.GENERATE_TO_OBJECT) {
/**
* Creates an object representation of this proto.
* Field names that are reserved in JavaScript and will be renamed to pb_name.
* Optional fields that are not set will be set to undefined.
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
* For the list of reserved names please see:
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
* JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @return {!Object}
*/
proto.cc.arduino.cli.commands.Programmer.prototype.toObject = function(opt_includeInstance) {
return proto.cc.arduino.cli.commands.Programmer.toObject(opt_includeInstance, this);
};
/**
* Static version of the {@see toObject} method.
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
* the JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @param {!proto.cc.arduino.cli.commands.Programmer} msg The msg instance to transform.
* @return {!Object}
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.cc.arduino.cli.commands.Programmer.toObject = function(includeInstance, msg) {
var f, obj = {
platform: jspb.Message.getFieldWithDefault(msg, 1, ""),
id: jspb.Message.getFieldWithDefault(msg, 2, ""),
name: jspb.Message.getFieldWithDefault(msg, 3, "")
};
if (includeInstance) {
obj.$jspbMessageInstance = msg;
}
return obj;
};
}
/**
* Deserializes binary data (in protobuf wire format).
* @param {jspb.ByteSource} bytes The bytes to deserialize.
* @return {!proto.cc.arduino.cli.commands.Programmer}
*/
proto.cc.arduino.cli.commands.Programmer.deserializeBinary = function(bytes) {
var reader = new jspb.BinaryReader(bytes);
var msg = new proto.cc.arduino.cli.commands.Programmer;
return proto.cc.arduino.cli.commands.Programmer.deserializeBinaryFromReader(msg, reader);
};
/**
* Deserializes binary data (in protobuf wire format) from the
* given reader into the given message object.
* @param {!proto.cc.arduino.cli.commands.Programmer} msg The message object to deserialize into.
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
* @return {!proto.cc.arduino.cli.commands.Programmer}
*/
proto.cc.arduino.cli.commands.Programmer.deserializeBinaryFromReader = function(msg, reader) {
while (reader.nextField()) {
if (reader.isEndGroup()) {
break;
}
var field = reader.getFieldNumber();
switch (field) {
case 1:
var value = /** @type {string} */ (reader.readString());
msg.setPlatform(value);
break;
case 2:
var value = /** @type {string} */ (reader.readString());
msg.setId(value);
break;
case 3:
var value = /** @type {string} */ (reader.readString());
msg.setName(value);
break;
default:
reader.skipField();
break;
}
}
return msg;
};
/**
* Serializes the message to binary data (in protobuf wire format).
* @return {!Uint8Array}
*/
proto.cc.arduino.cli.commands.Programmer.prototype.serializeBinary = function() {
var writer = new jspb.BinaryWriter();
proto.cc.arduino.cli.commands.Programmer.serializeBinaryToWriter(this, writer);
return writer.getResultBuffer();
};
/**
* Serializes the given message to binary data (in protobuf wire
* format), writing to the given BinaryWriter.
* @param {!proto.cc.arduino.cli.commands.Programmer} message
* @param {!jspb.BinaryWriter} writer
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.cc.arduino.cli.commands.Programmer.serializeBinaryToWriter = function(message, writer) {
var f = undefined;
f = message.getPlatform();
if (f.length > 0) {
writer.writeString(
1,
f
);
}
f = message.getId();
if (f.length > 0) {
writer.writeString(
2,
f
);
}
f = message.getName();
if (f.length > 0) {
writer.writeString(
3,
f
);
}
};
/**
* optional string platform = 1;
* @return {string}
*/
proto.cc.arduino.cli.commands.Programmer.prototype.getPlatform = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
};
/**
* @param {string} value
* @return {!proto.cc.arduino.cli.commands.Programmer} returns this
*/
proto.cc.arduino.cli.commands.Programmer.prototype.setPlatform = function(value) {
return jspb.Message.setProto3StringField(this, 1, value);
};
/**
* optional string id = 2;
* @return {string}
*/
proto.cc.arduino.cli.commands.Programmer.prototype.getId = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
};
/**
* @param {string} value
* @return {!proto.cc.arduino.cli.commands.Programmer} returns this
*/
proto.cc.arduino.cli.commands.Programmer.prototype.setId = function(value) {
return jspb.Message.setProto3StringField(this, 2, value);
};
/**
* optional string name = 3;
* @return {string}
*/
proto.cc.arduino.cli.commands.Programmer.prototype.getName = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, ""));
};
/**
* @param {string} value
* @return {!proto.cc.arduino.cli.commands.Programmer} returns this
*/
proto.cc.arduino.cli.commands.Programmer.prototype.setName = function(value) {
return jspb.Message.setProto3StringField(this, 3, value);
};
goog.object.extend(exports, proto.cc.arduino.cli.commands);

View File

@@ -43,7 +43,7 @@ function deserialize_cc_arduino_cli_monitor_StreamingOpenResp(buffer_arg) {
}
// Service that abstract a Monitor usage
// Service that abstracts a Monitor usage
var MonitorService = exports['cc.arduino.cli.monitor.Monitor'] = {
// Open a bidirectional monitor stream. This can be used to implement
// something similar to the Arduino IDE's Serial Monitor.

View File

@@ -15,11 +15,16 @@ export class CoreClientProvider extends GrpcClientProvider<CoreClientProvider.Cl
protected readonly toolOutputService: ToolOutputServiceServer;
protected readonly onIndexUpdatedEmitter = new Emitter<void>();
protected readonly onClientReadyEmitter = new Emitter<void>();
get onIndexUpdated(): Event<void> {
return this.onIndexUpdatedEmitter.event;
}
get onClientReady(): Event<void> {
return this.onClientReadyEmitter.event;
}
close(client: CoreClientProvider.Client): void {
client.client.close();
}
@@ -28,10 +33,12 @@ export class CoreClientProvider extends GrpcClientProvider<CoreClientProvider.Cl
if (port && port === this._port) {
// No need to create a new gRPC client, but we have to update the indexes.
if (this._client) {
this.updateIndexes(this._client);
await this.updateIndexes(this._client);
this.onClientReadyEmitter.fire();
}
} else {
return super.reconcileClient(port);
await super.reconcileClient(port);
this.onClientReadyEmitter.fire();
}
}

View File

@@ -6,7 +6,7 @@ import { BoardsService } from '../common/protocol/boards-service';
import { CoreClientProvider } from './core-client-provider';
import * as path from 'path';
import { ToolOutputServiceServer } from '../common/protocol/tool-output-service';
import { UploadReq, UploadResp } from './cli-protocol/commands/upload_pb';
import { UploadReq, UploadResp, BurnBootloaderReq, BurnBootloaderResp } from './cli-protocol/commands/upload_pb';
@injectable()
export class CoreServiceImpl implements CoreService {
@@ -113,9 +113,9 @@ export class CoreServiceImpl implements CoreService {
try {
await new Promise<void>((resolve, reject) => {
result.on('data', (cr: UploadResp) => {
this.toolOutputService.append({ tool: 'upload', chunk: Buffer.from(cr.getOutStream_asU8()).toString() });
this.toolOutputService.append({ tool: 'upload', chunk: Buffer.from(cr.getErrStream_asU8()).toString() });
result.on('data', (resp: UploadResp) => {
this.toolOutputService.append({ tool: 'upload', chunk: Buffer.from(resp.getOutStream_asU8()).toString() });
this.toolOutputService.append({ tool: 'upload', chunk: Buffer.from(resp.getErrStream_asU8()).toString() });
});
result.on('error', error => reject(error));
result.on('end', () => resolve());
@@ -127,6 +127,40 @@ export class CoreServiceImpl implements CoreService {
}
}
async burnBootloader(options: CoreService.Bootloader.Options): Promise<void> {
const coreClient = await this.coreClientProvider.client();
if (!coreClient) {
return;
}
const { fqbn, port, programmer } = options;
if (!fqbn) {
throw new Error('The selected board has no FQBN.');
}
if (!port) {
throw new Error('Port must be specified.');
}
const { client, instance } = coreClient;
const req = new BurnBootloaderReq();
req.setFqbn(fqbn);
req.setPort(port);
req.setProgrammer(programmer.id);
req.setInstance(instance);
const result = client.burnBootloader(req);
try {
await new Promise<void>((resolve, reject) => {
result.on('data', (resp: BurnBootloaderResp) => {
this.toolOutputService.append({ tool: 'bootloader', chunk: Buffer.from(resp.getOutStream_asU8()).toString() });
this.toolOutputService.append({ tool: 'bootloader', chunk: Buffer.from(resp.getErrStream_asU8()).toString() });
});
result.on('error', error => reject(error));
result.on('end', () => resolve());
});
} catch (e) {
this.toolOutputService.append({ tool: 'bootloader', chunk: `Error while burning the bootloader: ${e}\n`, severity: 'error' });
throw e;
}
}
setClient(client: CoreServiceClient | undefined): void {
this.client = client;
}

View File

@@ -0,0 +1,160 @@
import { inject, injectable, postConstruct } from 'inversify';
import { join, basename } from 'path';
import * as fs from './fs-extra';
import { FileUri } from '@theia/core/lib/node/file-uri';
import { notEmpty } from '@theia/core/lib/common/objects';
import { Sketch } from '../common/protocol/sketches-service';
import { SketchesServiceImpl } from './sketches-service-impl';
import { ExamplesService, ExampleContainer } from '../common/protocol/examples-service';
import { LibraryServiceServer, LibraryLocation, LibraryPackage } from '../common/protocol';
import { ConfigServiceImpl } from './config-service-impl';
@injectable()
export class ExamplesServiceImpl implements ExamplesService {
@inject(SketchesServiceImpl)
protected readonly sketchesService: SketchesServiceImpl;
@inject(LibraryServiceServer)
protected readonly libraryService: LibraryServiceServer;
@inject(ConfigServiceImpl)
protected readonly configService: ConfigServiceImpl;
protected _all: ExampleContainer[] | undefined;
@postConstruct()
protected init(): void {
this.builtIns();
}
async builtIns(): Promise<ExampleContainer[]> {
if (this._all) {
return this._all;
}
const exampleRootPath = join(__dirname, '..', '..', 'Examples');
const exampleNames = await fs.readdir(exampleRootPath);
this._all = await Promise.all(exampleNames.map(name => join(exampleRootPath, name)).map(path => this.load(path)));
return this._all;
}
// TODO: decide whether it makes sense to cache them. Keys should be: `fqbn` + version of containing core/library.
async installed({ fqbn }: { fqbn: string }): Promise<{ user: ExampleContainer[], current: ExampleContainer[], any: ExampleContainer[] }> {
const user: ExampleContainer[] = [];
const current: ExampleContainer[] = [];
const any: ExampleContainer[] = [];
if (fqbn) {
const packages = await this.libraryService.list({ fqbn });
for (const pkg of packages) {
const container = await this.tryGroupExamples(pkg);
const { location } = pkg;
if (location === LibraryLocation.USER) {
user.push(container);
} else if (location === LibraryLocation.PLATFORM_BUILTIN || LibraryLocation.REFERENCED_PLATFORM_BUILTIN) {
current.push(container);
} else {
any.push(container);
}
}
}
return { user, current, any };
}
/**
* The CLI provides direct FS paths to the examples so that menus and menu groups cannot be built for the UI by traversing the
* folder hierarchy. This method tries to workaround it by falling back to the `installDirUri` and manually creating the
* location of the examples. Otherwise it creates the example container from the direct examples FS paths.
*/
protected async tryGroupExamples({ label, exampleUris, installDirUri }: LibraryPackage): Promise<ExampleContainer> {
const paths = exampleUris.map(uri => FileUri.fsPath(uri));
if (installDirUri) {
for (const example of ['example', 'Example', 'EXAMPLE', 'examples', 'Examples', 'EXAMPLES']) {
const examplesPath = join(FileUri.fsPath(installDirUri), example);
const exists = await fs.exists(examplesPath);
const isDir = exists && (await fs.lstat(examplesPath)).isDirectory();
if (isDir) {
const fileNames = await fs.readdir(examplesPath);
const children: ExampleContainer[] = [];
const sketches: Sketch[] = [];
for (const fileName of fileNames) {
const subPath = join(examplesPath, fileName);
const subIsDir = (await fs.lstat(subPath)).isDirectory();
if (subIsDir) {
const sketch = await this.tryLoadSketch(subPath);
if (!sketch) {
const container = await this.load(subPath);
if (container.children.length || container.sketches.length) {
children.push(container);
}
} else {
sketches.push(sketch);
}
}
}
return {
label,
children,
sketches
};
}
}
}
const sketches = await Promise.all(paths.map(path => this.tryLoadSketch(path)));
return {
label,
children: [],
sketches: sketches.filter(notEmpty)
};
}
// Built-ins are included inside the IDE.
protected async load(path: string): Promise<ExampleContainer> {
if (!await fs.exists(path)) {
throw new Error('Examples are not available');
}
const stat = await fs.stat(path);
if (!stat.isDirectory) {
throw new Error(`${path} is not a directory.`);
}
const names = await fs.readdir(path);
const sketches: Sketch[] = [];
const children: ExampleContainer[] = [];
for (const p of names.map(name => join(path, name))) {
const stat = await fs.stat(p);
if (stat.isDirectory()) {
const sketch = await this.tryLoadSketch(p);
if (sketch) {
sketches.push(sketch);
} else {
const child = await this.load(p);
children.push(child);
}
}
}
const label = basename(path);
return {
label,
children,
sketches
};
}
protected async group(paths: string[]): Promise<Map<string, fs.Stats>> {
const map = new Map<string, fs.Stats>();
for (const path of paths) {
const stat = await fs.stat(path);
map.set(path, stat);
}
return map;
}
protected async tryLoadSketch(path: string): Promise<Sketch | undefined> {
try {
const sketch = await this.sketchesService.loadSketch(FileUri.create(path).toString());
return sketch;
} catch {
return undefined;
}
}
}

View File

@@ -2,6 +2,7 @@ import * as fs from 'fs';
import { promisify } from 'util';
export const constants = fs.constants;
export type Stats = fs.Stats;
export const existsSync = fs.existsSync;
export const lstatSync = fs.lstatSync;

View File

@@ -1,142 +0,0 @@
import { injectable, inject } from 'inversify';
import { Library, LibraryService } from '../common/protocol/library-service';
import { CoreClientProvider } from './core-client-provider';
import {
LibrarySearchReq,
LibrarySearchResp,
LibraryListReq,
LibraryListResp,
LibraryRelease,
InstalledLibrary,
LibraryInstallReq,
LibraryInstallResp,
LibraryUninstallReq,
LibraryUninstallResp
} from './cli-protocol/commands/lib_pb';
import { ToolOutputServiceServer } from '../common/protocol/tool-output-service';
import { Installable } from '../common/protocol/installable';
@injectable()
export class LibraryServiceImpl implements LibraryService {
@inject(CoreClientProvider)
protected readonly coreClientProvider: CoreClientProvider;
@inject(ToolOutputServiceServer)
protected readonly toolOutputService: ToolOutputServiceServer;
async search(options: { query?: string }): Promise<Library[]> {
const coreClient = await this.coreClientProvider.client();
if (!coreClient) {
return [];
}
const { client, instance } = coreClient;
const listReq = new LibraryListReq();
listReq.setInstance(instance);
const installedLibsResp = await new Promise<LibraryListResp>((resolve, reject) => client.libraryList(listReq, (err, resp) => !!err ? reject(err) : resolve(resp)));
const installedLibs = installedLibsResp.getInstalledLibraryList();
const installedLibsIdx = new Map<string, InstalledLibrary>();
for (const installedLib of installedLibs) {
if (installedLib.hasLibrary()) {
const lib = installedLib.getLibrary();
if (lib) {
installedLibsIdx.set(lib.getRealName(), installedLib);
}
}
}
const req = new LibrarySearchReq();
req.setQuery(options.query || '');
req.setInstance(instance);
const resp = await new Promise<LibrarySearchResp>((resolve, reject) => client.librarySearch(req, (err, resp) => !!err ? reject(err) : resolve(resp)));
const items = resp.getLibrariesList()
.filter(item => !!item.getLatest())
.slice(0, 50)
.map(item => {
// TODO: This seems to contain only the latest item instead of all of the items.
const availableVersions = item.getReleasesMap().getEntryList().map(([key, _]) => key).sort(Installable.Version.COMPARATOR);
let installedVersion: string | undefined;
const installed = installedLibsIdx.get(item.getName());
if (installed) {
installedVersion = installed.getLibrary()!.getVersion();
}
return toLibrary({
name: item.getName(),
installable: true,
installedVersion,
}, item.getLatest()!, availableVersions)
})
return items;
}
async install(options: { item: Library, version?: Installable.Version }): Promise<void> {
const library = options.item;
const version = !!options.version ? options.version : library.availableVersions[0];
const coreClient = await this.coreClientProvider.client();
if (!coreClient) {
return;
}
const { client, instance } = coreClient;
const req = new LibraryInstallReq();
req.setInstance(instance);
req.setName(library.name);
req.setVersion(version);
const resp = client.libraryInstall(req);
resp.on('data', (r: LibraryInstallResp) => {
const prog = r.getProgress();
if (prog) {
this.toolOutputService.append({ tool: 'library', chunk: `downloading ${prog.getFile()}: ${prog.getCompleted()}%\n` });
}
});
await new Promise<void>((resolve, reject) => {
resp.on('end', resolve);
resp.on('error', reject);
});
}
async uninstall(options: { item: Library }): Promise<void> {
const library = options.item;
const coreClient = await this.coreClientProvider.client();
if (!coreClient) {
return;
}
const { client, instance } = coreClient;
const req = new LibraryUninstallReq();
req.setInstance(instance);
req.setName(library.name);
req.setVersion(library.installedVersion!);
let logged = false;
const resp = client.libraryUninstall(req);
resp.on('data', (_: LibraryUninstallResp) => {
if (!logged) {
this.toolOutputService.append({ tool: 'library', chunk: `uninstalling ${library.name}:${library.installedVersion}%\n` });
logged = true;
}
});
await new Promise<void>((resolve, reject) => {
resp.on('end', resolve);
resp.on('error', reject);
});
}
}
function toLibrary(tpl: Partial<Library>, release: LibraryRelease, availableVersions: string[]): Library {
return {
name: '',
installable: false,
...tpl,
author: release.getAuthor(),
availableVersions,
description: release.getSentence(),
moreInfoLink: release.getWebsite(),
summary: release.getParagraph()
}
}

View File

@@ -0,0 +1,231 @@
import { injectable, inject, postConstruct } from 'inversify';
import { LibraryPackage, LibraryServiceClient, LibraryServiceServer } from '../common/protocol/library-service';
import { CoreClientProvider } from './core-client-provider';
import {
LibrarySearchReq,
LibrarySearchResp,
LibraryListReq,
LibraryListResp,
LibraryRelease,
InstalledLibrary,
LibraryInstallReq,
LibraryInstallResp,
LibraryUninstallReq,
LibraryUninstallResp,
Library
} from './cli-protocol/commands/lib_pb';
import { ToolOutputServiceServer } from '../common/protocol/tool-output-service';
import { Installable } from '../common/protocol/installable';
import { ILogger, notEmpty } from '@theia/core';
import { Deferred } from '@theia/core/lib/common/promise-util';
import { FileUri } from '@theia/core/lib/node';
@injectable()
export class LibraryServiceServerImpl implements LibraryServiceServer {
@inject(ILogger)
protected logger: ILogger;
@inject(CoreClientProvider)
protected readonly coreClientProvider: CoreClientProvider;
@inject(ToolOutputServiceServer)
protected readonly toolOutputService: ToolOutputServiceServer;
protected ready = new Deferred<void>();
protected client: LibraryServiceClient | undefined;
@postConstruct()
protected init(): void {
this.coreClientProvider.client().then(client => {
if (client) {
this.ready.resolve();
} else {
this.coreClientProvider.onClientReady(() => this.ready.resolve());
}
})
}
async search(options: { query?: string }): Promise<LibraryPackage[]> {
await this.ready.promise;
const coreClient = await this.coreClientProvider.client();
if (!coreClient) {
return [];
}
const { client, instance } = coreClient;
const listReq = new LibraryListReq();
listReq.setInstance(instance);
const installedLibsResp = await new Promise<LibraryListResp>((resolve, reject) => client.libraryList(listReq, (err, resp) => !!err ? reject(err) : resolve(resp)));
const installedLibs = installedLibsResp.getInstalledLibraryList();
const installedLibsIdx = new Map<string, InstalledLibrary>();
for (const installedLib of installedLibs) {
if (installedLib.hasLibrary()) {
const lib = installedLib.getLibrary();
if (lib) {
installedLibsIdx.set(lib.getRealName(), installedLib);
}
}
}
const req = new LibrarySearchReq();
req.setQuery(options.query || '');
req.setInstance(instance);
const resp = await new Promise<LibrarySearchResp>((resolve, reject) => client.librarySearch(req, (err, resp) => !!err ? reject(err) : resolve(resp)));
const items = resp.getLibrariesList()
.filter(item => !!item.getLatest())
.slice(0, 50)
.map(item => {
// TODO: This seems to contain only the latest item instead of all of the items.
const availableVersions = item.getReleasesMap().getEntryList().map(([key, _]) => key).sort(Installable.Version.COMPARATOR);
let installedVersion: string | undefined;
const installed = installedLibsIdx.get(item.getName());
if (installed) {
installedVersion = installed.getLibrary()!.getVersion();
}
return toLibrary({
name: item.getName(),
installable: true,
installedVersion,
}, item.getLatest()!, availableVersions)
});
return items;
}
async list({ fqbn }: { fqbn?: string | undefined }): Promise<LibraryPackage[]> {
await this.ready.promise;
const coreClient = await this.coreClientProvider.client();
if (!coreClient) {
return [];
}
const { client, instance } = coreClient;
const req = new LibraryListReq();
req.setInstance(instance);
req.setAll(true);
if (fqbn) {
req.setFqbn(fqbn);
}
const resp = await new Promise<LibraryListResp>((resolve, reject) => client.libraryList(req, ((error, resp) => !!error ? reject(error) : resolve(resp))));
return resp.getInstalledLibraryList().map(item => {
const library = item.getLibrary();
if (!library) {
return undefined;
}
const installedVersion = library.getVersion();
return toLibrary({
name: library.getName(),
label: library.getRealName(),
installedVersion,
installable: true,
description: library.getSentence(),
summary: library.getParagraph(),
moreInfoLink: library.getWebsite(),
includes: library.getProvidesIncludesList(),
location: library.getLocation(),
installDirUri: FileUri.create(library.getInstallDir()).toString(),
exampleUris: library.getExamplesList().map(fsPath => FileUri.create(fsPath).toString())
}, library, [library.getVersion()]);
}).filter(notEmpty);
}
async install(options: { item: LibraryPackage, version?: Installable.Version }): Promise<void> {
await this.ready.promise;
const item = options.item;
const version = !!options.version ? options.version : item.availableVersions[0];
const coreClient = await this.coreClientProvider.client();
if (!coreClient) {
return;
}
const { client, instance } = coreClient;
const req = new LibraryInstallReq();
req.setInstance(instance);
req.setName(item.name);
req.setVersion(version);
console.info('>>> Starting library package installation...', item);
const resp = client.libraryInstall(req);
resp.on('data', (r: LibraryInstallResp) => {
const prog = r.getProgress();
if (prog) {
this.toolOutputService.append({ tool: 'library', chunk: `downloading ${prog.getFile()}: ${prog.getCompleted()}%\n` });
}
});
await new Promise<void>((resolve, reject) => {
resp.on('end', resolve);
resp.on('error', reject);
});
if (this.client) {
const items = await this.search({});
const updated = items.find(other => LibraryPackage.equals(other, item)) || item;
this.client.notifyInstalled({ item: updated });
}
console.info('<<< Library package installation done.', item);
}
async uninstall(options: { item: LibraryPackage }): Promise<void> {
const item = options.item;
const coreClient = await this.coreClientProvider.client();
if (!coreClient) {
return;
}
const { client, instance } = coreClient;
const req = new LibraryUninstallReq();
req.setInstance(instance);
req.setName(item.name);
req.setVersion(item.installedVersion!);
console.info('>>> Starting library package uninstallation...', item);
let logged = false;
const resp = client.libraryUninstall(req);
resp.on('data', (_: LibraryUninstallResp) => {
if (!logged) {
this.toolOutputService.append({ tool: 'library', chunk: `uninstalling ${item.name}:${item.installedVersion}%\n` });
logged = true;
}
});
await new Promise<void>((resolve, reject) => {
resp.on('end', resolve);
resp.on('error', reject);
});
if (this.client) {
this.client.notifyUninstalled({ item });
}
console.info('<<< Library package uninstallation done.', item);
}
setClient(client: LibraryServiceClient | undefined): void {
this.client = client;
}
dispose(): void {
this.logger.info('>>> Disposing library service...');
this.client = undefined;
this.logger.info('<<< Disposed library service.');
}
}
function toLibrary(pkg: Partial<LibraryPackage>, lib: LibraryRelease | Library, availableVersions: string[]): LibraryPackage {
return {
name: '',
label: '',
exampleUris: [],
installable: false,
location: 0,
...pkg,
author: lib.getAuthor(),
availableVersions,
includes: lib.getProvidesIncludesList(),
description: lib.getSentence(),
moreInfoLink: lib.getWebsite(),
summary: lib.getParagraph()
}
}

View File

@@ -19,6 +19,8 @@ const MAX_FILESYSTEM_DEPTH = 40;
const WIN32_DRIVE_REGEXP = /^[a-zA-Z]:\\/;
const prefix = '.arduinoProIDE-unsaved';
// TODO: `fs`: use async API
@injectable()
export class SketchesServiceImpl implements SketchesService, BackendApplicationContribution {
@@ -205,6 +207,22 @@ export class SketchesServiceImpl implements SketchesService, BackendApplicationC
}
}
async cloneExample(uri: string): Promise<Sketch> {
const sketch = await this.loadSketch(uri);
const parentPath = await new Promise<string>((resolve, reject) => {
this.temp.mkdir({ prefix }, (err, dirPath) => {
if (err) {
reject(err);
return;
}
resolve(dirPath);
})
});
const destinationUri = FileUri.create(path.join(parentPath, sketch.name)).toString();
const copiedSketchUri = await this.copy(sketch, { destinationUri });
return this.loadSketch(copiedSketchUri);
}
protected async simpleLocalWalk(
root: string,
maxDepth: number,
@@ -258,15 +276,15 @@ export class SketchesServiceImpl implements SketchesService, BackendApplicationC
async createNewSketch(): Promise<Sketch> {
const monthNames = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'];
const today = new Date();
const parent = await new Promise<string>((resolve, reject) => {
this.temp.mkdir({ prefix: '.arduinoProIDE-unsaved' }, (err, dirPath) => {
const parentPath = await new Promise<string>((resolve, reject) => {
this.temp.mkdir({ prefix }, (err, dirPath) => {
if (err) {
reject(err);
return;
}
resolve(dirPath);
})
})
});
});
const sketchBaseName = `sketch_${monthNames[today.getMonth()]}${today.getDate()}`;
const config = await this.configService.getConfiguration();
const user = FileUri.fsPath(config.sketchDirUri);
@@ -286,7 +304,7 @@ export class SketchesServiceImpl implements SketchesService, BackendApplicationC
throw new Error('Cannot create a unique sketch name');
}
const sketchDir = path.join(parent, sketchName)
const sketchDir = path.join(parentPath, sketchName)
const sketchFile = path.join(sketchDir, `${sketchName}.ino`);
await fs.mkdirp(sketchDir);
await fs.writeFile(sketchFile, `void setup() {
@@ -324,7 +342,7 @@ void loop() {
for (let i = 0; i < files.length; i++) {
if (files[i] === basename + '.ino') {
try {
await this.loadSketch(fsPath);
await this.loadSketch(FileUri.create(fsPath).toString());
return true;
} catch { }
}
@@ -346,7 +364,7 @@ void loop() {
temp = firstToLowerCase(temp);
}
}
return sketchPath.indexOf('.arduinoProIDE-unsaved') !== -1 && sketchPath.startsWith(temp);
return sketchPath.indexOf(prefix) !== -1 && sketchPath.startsWith(temp);
}
async copy(sketch: Sketch, { destinationUri }: { destinationUri: string }): Promise<string> {
@@ -364,7 +382,11 @@ void loop() {
}
const newName = path.basename(destination);
try {
await fs.rename(path.join(destination, new URI(sketch.mainFileUri).path.base), path.join(destination, `${newName}.ino`));
const oldPath = path.join(destination, new URI(sketch.mainFileUri).path.base);
const newPath = path.join(destination, `${newName}.ino`);
if (oldPath !== newPath) {
await fs.rename(oldPath, newPath);
}
await this.loadSketch(destinationUri); // Sanity check.
resolve();
} catch (e) {

View File

@@ -7,6 +7,8 @@ import { ILogger } from '@theia/core/lib/common/logger';
import { Deferred } from '@theia/core/lib/common/promise-util';
import { MockLogger } from '@theia/core/lib/common/test/mock-logger';
import { MaybePromise } from '@theia/core/lib/common/types';
import { MessageClient } from '@theia/core/lib/common/message-service-protocol';
import { MessageService } from '@theia/core/lib/common/message-service';
import { StorageService } from '@theia/core/lib/browser/storage-service';
import { DisposableCollection } from '@theia/core/lib/common/disposable';
import { BoardsService, Board, Port, BoardsPackage, BoardDetails, BoardsServiceClient } from '../../common/protocol';
@@ -164,6 +166,8 @@ function init(): Container {
container.bind(MockStorageService).toSelf();
container.bind(StorageService).toService(MockStorageService);
container.bind(BoardsServiceClientImpl).toSelf();
container.bind(MessageClient).toSelf().inSingletonScope();
container.bind(MessageService).toSelf().inSingletonScope();
return container;
}

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "browser-app",
"version": "0.1.0",
"version": "0.1.2",
"license": "MIT",
"dependencies": {
"@theia/core": "next",
@@ -19,8 +19,8 @@
"@theia/process": "next",
"@theia/terminal": "next",
"@theia/workspace": "next",
"arduino-ide-extension": "0.1.0",
"arduino-debugger-extension": "0.1.0"
"arduino-ide-extension": "0.1.2",
"arduino-debugger-extension": "0.1.2"
},
"devDependencies": {
"@theia/cli": "next"

33
docs/internal/Ubuntu.md Normal file
View File

@@ -0,0 +1,33 @@
### Building and start the app from the sources on Ubuntu Linux
Tested and verified on Ubuntu 18.04.4. The source will be checked out to `~/dev/git/arduino-editor`.
```
#!/bin/bash -i
sudo apt update \
&& sudo apt install --no-install-recommends --yes \
git \
gcc \
curl \
make \
python \
pkg-config \
libx11-dev \
libxkbfile-dev \
build-essential \
&& wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash \
&& source ~/.bashrc \
&& nvm install 12.14.1 \
&& nvm use 12.14.1 \
&& nvm alias default 12.14.1 \
&& curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - \
&& echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list \
&& sudo apt update && sudo apt install --no-install-recommends yarn \
&& mkdir -p ~/dev/git/ \
&& rm -rf ~/dev/git/arduino-editor \
&& git clone --depth 1 https://github.com/bcmi-labs/arduino-editor.git ~/dev/git/arduino-editor \
&& yarn --cwd ~/dev/git/arduino-editor \
&& yarn --cwd ~/dev/git/arduino-editor rebuild:electron \
&& yarn --cwd ~/dev/git/arduino-editor/electron-app start
```

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "electron-app",
"version": "0.1.0",
"version": "0.1.2",
"license": "MIT",
"main": "src-gen/frontend/electron-main.js",
"dependencies": {
@@ -21,8 +21,8 @@
"@theia/process": "next",
"@theia/terminal": "next",
"@theia/workspace": "next",
"arduino-ide-extension": "0.1.0",
"arduino-debugger-extension": "0.1.0"
"arduino-ide-extension": "0.1.2",
"arduino-debugger-extension": "0.1.2"
},
"devDependencies": {
"@theia/cli": "next"

View File

@@ -89,8 +89,9 @@ app.on('ready', () => {
title: applicationName,
width: windowState.width,
height: windowState.height,
minWidth: 200,
minHeight: 120,
// Set and use a custom minimum window size: https://github.com/arduino/arduino-pro-ide/issues/337#issuecomment-687017281
minWidth: 900,
minHeight: 800,
x: windowState.x,
y: windowState.y,
isMaximized: windowState.isMaximized,
@@ -286,7 +287,15 @@ app.on('ready', () => {
app.on('quit', () => {
// If we forked the process for the clusters, we need to manually terminate it.
// See: https://github.com/eclipse-theia/theia/issues/835
process.kill(cp.pid);
try {
process.kill(cp.pid);
} catch (e) {
if (e.code === 'ESRCH') {
console.log('Could not terminate the backend process. It was not running.');
return;
}
throw e;
}
});
}
});

View File

@@ -0,0 +1,29 @@
// @ts-check
const { setup, log } = require('node-log-rotate');
setup({
appName: 'Arduino Pro IDE',
maxSize: 10 * 1024 * 1024
});
for (const name of ['log', 'trace', 'info', 'warn', 'error']) {
const original = console[name];
console[name] = (data => {
original(data);
log(data);
}).bind(console);
}
const { BackendApplicationConfigProvider } = require('@theia/core/lib/node/backend-application-config-provider');
const main = require('@theia/core/lib/node/main');
BackendApplicationConfigProvider.set({
"configDirName": ".arduinoProIDE",
"singleInstance": true
});
const serverModule = require('./server');
const serverAddress = main.start(serverModule());
serverAddress.then(function ({ port, address }) {
if (process && process.send) {
process.send({ port, address });
}
});
module.exports = serverAddress;

View File

@@ -4,6 +4,9 @@
"resolutions": {
"**/fs-extra": "^4.0.3"
},
"dependencies": {
"node-log-rotate": "^0.1.5"
},
"devDependencies": {
"@theia/cli": "next",
"cross-env": "^7.0.2",
@@ -19,7 +22,7 @@
"package": "cross-env DEBUG=* && electron-builder --publish=never",
"package:publish": "cross-env DEBUG=* && electron-builder --publish=always",
"download:plugins": "theia download:plugins",
"patch": "ncp ./patch/electron-main.js ./src-gen/frontend/electron-main.js"
"patch": "ncp ./patch/electron-main.js ./src-gen/frontend/electron-main.js && ncp ./patch/main.js ./src-gen/backend/main.js"
},
"engines": {
"node": ">=10.11.0 <13"

View File

@@ -15,7 +15,7 @@ function artifactName() {
} else if (isNightly) {
return `nightly-${timestamp()}`
} else {
return 'snapshot';
return getVersion();
}
})();
const name = 'arduino-pro-ide';

View File

@@ -1,6 +1,6 @@
{
"name": "arduino-editor",
"version": "0.1.0",
"version": "0.1.2",
"description": "Arduino Pro IDE",
"repository": "https://github.com/bcmi-labs/arduino-editor.git",
"author": "Arduino SA",