mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-06-07 04:36:33 +00:00
First stop towards compile/verify
This commit is contained in:
parent
c48d80b137
commit
cc79d53dc4
@ -11,6 +11,7 @@ import { ArduinoCommands } from './arduino-commands';
|
|||||||
import { ConnectedBoards } from './components/connected-boards';
|
import { ConnectedBoards } from './components/connected-boards';
|
||||||
import { CoreService } from '../common/protocol/core-service';
|
import { CoreService } from '../common/protocol/core-service';
|
||||||
import { WorkspaceServiceExt } from './workspace-service-ext';
|
import { WorkspaceServiceExt } from './workspace-service-ext';
|
||||||
|
import { ToolOutputServiceClient } from '../common/protocol/tool-output-service';
|
||||||
|
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
@ -28,6 +29,9 @@ export class ArduinoFrontendContribution extends DefaultFrontendApplicationContr
|
|||||||
@inject(WorkspaceServiceExt)
|
@inject(WorkspaceServiceExt)
|
||||||
protected readonly workspaceServiceExt: WorkspaceServiceExt;
|
protected readonly workspaceServiceExt: WorkspaceServiceExt;
|
||||||
|
|
||||||
|
@inject(ToolOutputServiceClient)
|
||||||
|
protected readonly toolOutputServiceClient: ToolOutputServiceClient;
|
||||||
|
|
||||||
@postConstruct()
|
@postConstruct()
|
||||||
protected async init(): Promise<void> {
|
protected async init(): Promise<void> {
|
||||||
// This is a hack. Otherwise, the backend services won't bind.
|
// This is a hack. Otherwise, the backend services won't bind.
|
||||||
|
@ -17,8 +17,11 @@ import { BoardsListWidget } from './boards/boards-list-widget';
|
|||||||
import { BoardsListWidgetFrontendContribution } from './boards/boards-widget-frontend-contribution';
|
import { BoardsListWidgetFrontendContribution } from './boards/boards-widget-frontend-contribution';
|
||||||
import { WorkspaceServiceExt, WorkspaceServiceExtPath } from './workspace-service-ext';
|
import { WorkspaceServiceExt, WorkspaceServiceExtPath } from './workspace-service-ext';
|
||||||
import { WorkspaceServiceExtImpl } from './workspace-service-ext-impl';
|
import { WorkspaceServiceExtImpl } from './workspace-service-ext-impl';
|
||||||
|
import { ToolOutputServiceClient } from '../common/protocol/tool-output-service';
|
||||||
|
|
||||||
import '../../src/browser/style/index.css';
|
import '../../src/browser/style/index.css';
|
||||||
|
import { ToolOutputService } from '../common/protocol/tool-output-service';
|
||||||
|
import { ToolOutputServiceClientImpl } from './tool-output/client-service-impl';
|
||||||
|
|
||||||
export default new ContainerModule((bind: interfaces.Bind, unbind: interfaces.Unbind, isBound: interfaces.IsBound, rebind: interfaces.Rebind) => {
|
export default new ContainerModule((bind: interfaces.Bind, unbind: interfaces.Unbind, isBound: interfaces.IsBound, rebind: interfaces.Rebind) => {
|
||||||
// Commands and toolbar items
|
// Commands and toolbar items
|
||||||
@ -58,6 +61,14 @@ export default new ContainerModule((bind: interfaces.Bind, unbind: interfaces.Un
|
|||||||
.toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, CoreServicePath))
|
.toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, CoreServicePath))
|
||||||
.inSingletonScope();
|
.inSingletonScope();
|
||||||
|
|
||||||
|
// Tool output service client
|
||||||
|
bind(ToolOutputServiceClientImpl).toSelf().inSingletonScope();
|
||||||
|
bind(ToolOutputServiceClient).toDynamicValue(context => {
|
||||||
|
const client = context.container.get(ToolOutputServiceClientImpl);
|
||||||
|
WebSocketConnectionProvider.createProxy(context.container, ToolOutputService.SERVICE_PATH, client);
|
||||||
|
return client;
|
||||||
|
}).inSingletonScope();
|
||||||
|
|
||||||
// The workspace service extension
|
// The workspace service extension
|
||||||
bind(WorkspaceServiceExt).to(WorkspaceServiceExtImpl).inSingletonScope().onActivation(({ container }, workspaceServiceExt) => {
|
bind(WorkspaceServiceExt).to(WorkspaceServiceExtImpl).inSingletonScope().onActivation(({ container }, workspaceServiceExt) => {
|
||||||
WebSocketConnectionProvider.createProxy(container, WorkspaceServiceExtPath, workspaceServiceExt);
|
WebSocketConnectionProvider.createProxy(container, WorkspaceServiceExtPath, workspaceServiceExt);
|
||||||
|
@ -52,6 +52,7 @@
|
|||||||
padding: 4px;
|
padding: 4px;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
max-height: calc(1em + 4px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.component-list-item .footer {
|
.component-list-item .footer {
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
import { ToolOutputServiceClient } from "../../common/protocol/tool-output-service";
|
||||||
|
import { injectable, inject } from "inversify";
|
||||||
|
import { OutputChannelManager } from "@theia/output/lib/common/output-channel";
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
export class ToolOutputServiceClientImpl implements ToolOutputServiceClient {
|
||||||
|
|
||||||
|
@inject(OutputChannelManager)
|
||||||
|
protected readonly outputChannelManager: OutputChannelManager;
|
||||||
|
|
||||||
|
onNewOutput(tool: string, chunk: string): void {
|
||||||
|
const channel = this.outputChannelManager.getChannel(`Arduino: ${tool}`);
|
||||||
|
channel.append(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
export const CoreServicePath = '/services/core-service';
|
export const CoreServicePath = '/services/core-service';
|
||||||
export const CoreService = Symbol('CoreService');
|
export const CoreService = Symbol('CoreService');
|
||||||
export interface CoreService {
|
export interface CoreService {
|
||||||
compile(options: CoreService.Compile.Options): Promise<string>;
|
compile(options: CoreService.Compile.Options): Promise<void>;
|
||||||
upload(): Promise<void>;
|
upload(): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
import { JsonRpcServer } from "@theia/core";
|
||||||
|
|
||||||
|
export const ToolOutputServiceServer = Symbol("ToolOutputServiceServer");
|
||||||
|
export interface ToolOutputServiceServer extends JsonRpcServer<ToolOutputServiceClient> {
|
||||||
|
publishNewOutput(tool: string, chunk: string): void;
|
||||||
|
disposeClient(client: ToolOutputServiceClient): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ToolOutputServiceClient = Symbol("ToolOutputServiceClient");
|
||||||
|
export interface ToolOutputServiceClient {
|
||||||
|
onNewOutput(tool: string, chunk: string): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace ToolOutputService {
|
||||||
|
export const SERVICE_PATH = "/tool-output-service";
|
||||||
|
}
|
@ -12,6 +12,9 @@ import { ConnectionContainerModule } from '@theia/core/lib/node/messaging/connec
|
|||||||
import { WorkspaceServiceExtPath, WorkspaceServiceExt } from '../browser/workspace-service-ext';
|
import { WorkspaceServiceExtPath, WorkspaceServiceExt } from '../browser/workspace-service-ext';
|
||||||
import { CoreClientProviderImpl } from './core-client-provider-impl';
|
import { CoreClientProviderImpl } from './core-client-provider-impl';
|
||||||
import { CoreClientProviderPath, CoreClientProvider } from './core-client-provider';
|
import { CoreClientProviderPath, CoreClientProvider } from './core-client-provider';
|
||||||
|
import { ToolOutputService, ToolOutputServiceClient, ToolOutputServiceServer } from '../common/protocol/tool-output-service';
|
||||||
|
import { ConnectionHandler, JsonRpcConnectionHandler } from '@theia/core';
|
||||||
|
import { ToolOutputServiceServerImpl } from './tool-output-service-impl';
|
||||||
|
|
||||||
export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||||
bind(ArduinoDaemon).toSelf().inSingletonScope();
|
bind(ArduinoDaemon).toSelf().inSingletonScope();
|
||||||
@ -51,6 +54,17 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
|||||||
});
|
});
|
||||||
bind(ConnectionContainerModule).toConstantValue(connectionConnectionModule);
|
bind(ConnectionContainerModule).toConstantValue(connectionConnectionModule);
|
||||||
|
|
||||||
|
// Tool output service -> feedback from the daemon, compile and flash
|
||||||
|
bind(ToolOutputServiceServer).to(ToolOutputServiceServerImpl).inSingletonScope();
|
||||||
|
bind(ConnectionHandler).toDynamicValue(context =>
|
||||||
|
new JsonRpcConnectionHandler<ToolOutputServiceClient>(ToolOutputService.SERVICE_PATH, client => {
|
||||||
|
const server = context.container.get<ToolOutputServiceServer>(ToolOutputServiceServer);
|
||||||
|
server.setClient(client);
|
||||||
|
client.onDidCloseConnection(() => server.disposeClient(client));
|
||||||
|
return server;
|
||||||
|
})
|
||||||
|
).inSingletonScope();
|
||||||
|
|
||||||
// Bind the workspace service extension to the backend per Theia connection.
|
// Bind the workspace service extension to the backend per Theia connection.
|
||||||
// So that we can access the workspace roots of the frontend.
|
// So that we can access the workspace roots of the frontend.
|
||||||
const workspaceServiceExtConnectionModule = ConnectionContainerModule.create(({ bindFrontendService }) => {
|
const workspaceServiceExtConnectionModule = ConnectionContainerModule.create(({ bindFrontendService }) => {
|
||||||
|
@ -6,6 +6,7 @@ import { ILogger } from '@theia/core/lib/common/logger';
|
|||||||
import { BackendApplicationContribution } from '@theia/core/lib/node';
|
import { BackendApplicationContribution } from '@theia/core/lib/node';
|
||||||
import { Deferred } from '@theia/core/lib/common/promise-util';
|
import { Deferred } from '@theia/core/lib/common/promise-util';
|
||||||
import { DaemonLog } from './daemon-log';
|
import { DaemonLog } from './daemon-log';
|
||||||
|
import { ToolOutputServiceServer } from '../common/protocol/tool-output-service';
|
||||||
|
|
||||||
const EXECUTABLE_PATH = resolve(join(__dirname, '..', '..', 'build', `arduino-cli.${os.platform()}`))
|
const EXECUTABLE_PATH = resolve(join(__dirname, '..', '..', 'build', `arduino-cli.${os.platform()}`))
|
||||||
|
|
||||||
@ -16,6 +17,9 @@ export class ArduinoDaemon implements BackendApplicationContribution {
|
|||||||
@named('daemon')
|
@named('daemon')
|
||||||
protected readonly logger: ILogger
|
protected readonly logger: ILogger
|
||||||
|
|
||||||
|
@inject(ToolOutputServiceServer)
|
||||||
|
protected readonly toolOutputService: ToolOutputServiceServer;
|
||||||
|
|
||||||
protected isReady = new Deferred<boolean>();
|
protected isReady = new Deferred<boolean>();
|
||||||
|
|
||||||
async onStart() {
|
async onStart() {
|
||||||
@ -28,10 +32,16 @@ export class ArduinoDaemon implements BackendApplicationContribution {
|
|||||||
console.log(stdout);
|
console.log(stdout);
|
||||||
});
|
});
|
||||||
if (daemon.stdout) {
|
if (daemon.stdout) {
|
||||||
daemon.stdout.on('data', data => DaemonLog.log(this.logger, data.toString()));
|
daemon.stdout.on('data', data => {
|
||||||
|
this.toolOutputService.publishNewOutput("daeomn", data.toString());
|
||||||
|
DaemonLog.log(this.logger, data.toString());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (daemon.stderr) {
|
if (daemon.stderr) {
|
||||||
daemon.stderr.on('data', data => DaemonLog.log(this.logger, data.toString()));
|
daemon.stderr.on('data', data => {
|
||||||
|
this.toolOutputService.publishNewOutput("daeomn error", data.toString());
|
||||||
|
DaemonLog.log(this.logger, data.toString());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (daemon.stderr) {
|
if (daemon.stderr) {
|
||||||
daemon.on('exit', (code, signal) => DaemonLog.log(this.logger, `Daemon exited with code: ${code}. Signal was: ${signal}.`));
|
daemon.on('exit', (code, signal) => DaemonLog.log(this.logger, `Daemon exited with code: ${code}. Signal was: ${signal}.`));
|
||||||
|
@ -66,10 +66,10 @@ export class BoardsServiceImpl implements BoardsService {
|
|||||||
const [ platform, boardName ] = board.id.split(":");
|
const [ platform, boardName ] = board.id.split(":");
|
||||||
|
|
||||||
const req = new PlatformInstallReq();
|
const req = new PlatformInstallReq();
|
||||||
|
req.setInstance(instance);
|
||||||
req.setArchitecture(boardName);
|
req.setArchitecture(boardName);
|
||||||
req.setPlatformPackage(platform);
|
req.setPlatformPackage(platform);
|
||||||
req.setVersion(board.availableVersions[0]);
|
req.setVersion(board.availableVersions[0]);
|
||||||
req.setInstance(instance);
|
|
||||||
|
|
||||||
console.info("Starting board installation", board);
|
console.info("Starting board installation", board);
|
||||||
const resp = client.platformInstall(req);
|
const resp = client.platformInstall(req);
|
||||||
|
@ -84,6 +84,24 @@ export class CoreClientProviderImpl implements CoreClientProvider {
|
|||||||
updateResp.on('end', resolve);
|
updateResp.on('end', resolve);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// {
|
||||||
|
// const installBuiltinPkgReq = new PlatformInstallReq();
|
||||||
|
// installBuiltinPkgReq.setInstance(instance);
|
||||||
|
// installBuiltinPkgReq.setPlatformPackage("builtin");
|
||||||
|
// const resp = client.platformInstall(installBuiltinPkgReq);
|
||||||
|
// resp.on('data', (r: PlatformInstallResp) => {
|
||||||
|
// const prog = r.getProgress();
|
||||||
|
// if (prog) {
|
||||||
|
// console.info(`downloading ${prog.getFile()}: ${prog.getCompleted()}%`)
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// await new Promise<void>((resolve, reject) => {
|
||||||
|
// resp.on('end', resolve);
|
||||||
|
// resp.on('error', reject);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
// TODO: revisit this!!!
|
// TODO: revisit this!!!
|
||||||
// `updateResp.on('data'` is called only when running, for instance, `compile`. It does not run eagerly.
|
// `updateResp.on('data'` is called only when running, for instance, `compile`. It does not run eagerly.
|
||||||
// await new Promise<void>((resolve, reject) => {
|
// await new Promise<void>((resolve, reject) => {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { inject, injectable } from 'inversify';
|
import { inject, injectable } from 'inversify';
|
||||||
import { FileSystem } from '@theia/filesystem/lib/common/filesystem';
|
import { FileSystem } from '@theia/filesystem/lib/common/filesystem';
|
||||||
import { CoreService } from '../common/protocol/core-service';
|
import { CoreService } from '../common/protocol/core-service';
|
||||||
import { CompileReq } from './cli-protocol/compile_pb';
|
import { CompileReq, CompileResp } from './cli-protocol/compile_pb';
|
||||||
import { BoardsService } from '../common/protocol/boards-service';
|
import { BoardsService } from '../common/protocol/boards-service';
|
||||||
import { CoreClientProvider } from './core-client-provider';
|
import { CoreClientProvider } from './core-client-provider';
|
||||||
import { PlatformInstallReq } from './cli-protocol/core_pb';
|
import * as path from 'path';
|
||||||
import { LibraryInstallReq } from './cli-protocol/lib_pb';
|
import { ToolOutputServiceServer } from '../common/protocol/tool-output-service';
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class CoreServiceImpl implements CoreService {
|
export class CoreServiceImpl implements CoreService {
|
||||||
@ -19,13 +19,17 @@ export class CoreServiceImpl implements CoreService {
|
|||||||
@inject(BoardsService)
|
@inject(BoardsService)
|
||||||
protected readonly boardsService: BoardsService;
|
protected readonly boardsService: BoardsService;
|
||||||
|
|
||||||
async compile(options: CoreService.Compile.Options): Promise<string> {
|
@inject(ToolOutputServiceServer)
|
||||||
|
protected readonly toolOutputService: ToolOutputServiceServer;
|
||||||
|
|
||||||
|
async compile(options: CoreService.Compile.Options): Promise<void> {
|
||||||
console.log('compile', options);
|
console.log('compile', options);
|
||||||
const { uri } = options;
|
const { uri } = options;
|
||||||
const sketchpath = await this.fileSystem.getFsPath(options.uri);
|
const sketchFilePath = await this.fileSystem.getFsPath(options.uri);
|
||||||
if (!sketchpath) {
|
if (!sketchFilePath) {
|
||||||
throw new Error(`Cannot resolve filesystem path for URI: ${uri}.`);
|
throw new Error(`Cannot resolve filesystem path for URI: ${uri}.`);
|
||||||
}
|
}
|
||||||
|
const sketchpath = path.dirname(sketchFilePath);
|
||||||
|
|
||||||
const { client, instance } = await this.coreClientProvider.getClient(uri);
|
const { client, instance } = await this.coreClientProvider.getClient(uri);
|
||||||
// const boards = await this.boardsService.connectedBoards();
|
// const boards = await this.boardsService.connectedBoards();
|
||||||
@ -34,38 +38,30 @@ export class CoreServiceImpl implements CoreService {
|
|||||||
// }
|
// }
|
||||||
// https://github.com/cmaglie/arduino-cli/blob/bd5e78701e7546787649d3cca6b21c5d22d0e438/cli/compile/compile.go#L78-L88
|
// https://github.com/cmaglie/arduino-cli/blob/bd5e78701e7546787649d3cca6b21c5d22d0e438/cli/compile/compile.go#L78-L88
|
||||||
|
|
||||||
const installLibReq = new LibraryInstallReq();
|
|
||||||
installLibReq.setInstance(instance);
|
|
||||||
installLibReq.setName('arduino:samd');
|
|
||||||
const installResp = client.libraryInstall(installLibReq);
|
|
||||||
const xxx = await new Promise<string>((resolve, reject) => {
|
|
||||||
const chunks: Buffer[] = [];
|
|
||||||
installResp.on('data', (chunk: Buffer) => chunks.push(chunk));
|
|
||||||
installResp.on('error', error => reject(error));
|
|
||||||
installResp.on('end', () => resolve(Buffer.concat(chunks).toString('utf8').trim()))
|
|
||||||
});
|
|
||||||
console.log('xxx', xxx);
|
|
||||||
|
|
||||||
const compilerReq = new CompileReq();
|
const compilerReq = new CompileReq();
|
||||||
compilerReq.setInstance(instance);
|
compilerReq.setInstance(instance);
|
||||||
compilerReq.setSketchpath(sketchpath);
|
compilerReq.setSketchpath(sketchpath);
|
||||||
compilerReq.setFqbn('arduino:samd'/*boards.current.name*/);
|
compilerReq.setFqbn('arduino:avr:uno'/*boards.current.name*/);
|
||||||
// request.setShowproperties(false);
|
// request.setShowproperties(false);
|
||||||
// request.setPreprocess(false);
|
compilerReq.setPreprocess(false);
|
||||||
// request.setBuildcachepath('');
|
// request.setBuildcachepath('');
|
||||||
// request.setBuildpath('');
|
// compilerReq.setBuildpath('/tmp/build');
|
||||||
|
// compilerReq.setShowproperties(true);
|
||||||
// request.setBuildpropertiesList([]);
|
// request.setBuildpropertiesList([]);
|
||||||
// request.setWarnings('none');
|
// request.setWarnings('none');
|
||||||
// request.setVerbose(true);
|
compilerReq.setVerbose(true);
|
||||||
// request.setQuiet(false);
|
compilerReq.setQuiet(false);
|
||||||
// request.setVidpid('');
|
// request.setVidpid('');
|
||||||
// request.setExportfile('');
|
// request.setExportfile('');
|
||||||
|
|
||||||
const result = client.compile(compilerReq);
|
const result = client.compile(compilerReq);
|
||||||
return new Promise<string>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
const chunks: Buffer[] = [];
|
result.on('data', (cr: CompileResp) => {
|
||||||
result.on('data', (chunk: Buffer) => chunks.push(chunk));
|
this.toolOutputService.publishNewOutput("compile", new Buffer(cr.getOutStream_asU8()).toString());
|
||||||
|
console.error(cr.getErrStream().toString());
|
||||||
|
});
|
||||||
result.on('error', error => reject(error));
|
result.on('error', error => reject(error));
|
||||||
result.on('end', () => resolve(Buffer.concat(chunks).toString('utf8').trim()))
|
result.on('end', () => resolve());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
28
arduino-ide-extension/src/node/tool-output-service-impl.ts
Normal file
28
arduino-ide-extension/src/node/tool-output-service-impl.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { injectable } from "inversify";
|
||||||
|
import { ToolOutputServiceServer, ToolOutputServiceClient } from "../common/protocol/tool-output-service";
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
export class ToolOutputServiceServerImpl implements ToolOutputServiceServer {
|
||||||
|
protected clients: ToolOutputServiceClient[] = [];
|
||||||
|
|
||||||
|
publishNewOutput(tool: string, chunk: string): void {
|
||||||
|
this.clients.forEach(c => c.onNewOutput(tool, chunk));
|
||||||
|
}
|
||||||
|
|
||||||
|
setClient(client: ToolOutputServiceClient | undefined): void {
|
||||||
|
if (!client) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.clients.push(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
disposeClient(client: ToolOutputServiceClient): void {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(): void {
|
||||||
|
this.clients = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user