First stop towards compile/verify

This commit is contained in:
Christian Weichel 2019-05-06 19:58:36 +02:00
parent c48d80b137
commit cc79d53dc4
12 changed files with 145 additions and 31 deletions

View File

@ -11,6 +11,7 @@ import { ArduinoCommands } from './arduino-commands';
import { ConnectedBoards } from './components/connected-boards';
import { CoreService } from '../common/protocol/core-service';
import { WorkspaceServiceExt } from './workspace-service-ext';
import { ToolOutputServiceClient } from '../common/protocol/tool-output-service';
@injectable()
@ -28,6 +29,9 @@ export class ArduinoFrontendContribution extends DefaultFrontendApplicationContr
@inject(WorkspaceServiceExt)
protected readonly workspaceServiceExt: WorkspaceServiceExt;
@inject(ToolOutputServiceClient)
protected readonly toolOutputServiceClient: ToolOutputServiceClient;
@postConstruct()
protected async init(): Promise<void> {
// This is a hack. Otherwise, the backend services won't bind.

View File

@ -17,8 +17,11 @@ import { BoardsListWidget } from './boards/boards-list-widget';
import { BoardsListWidgetFrontendContribution } from './boards/boards-widget-frontend-contribution';
import { WorkspaceServiceExt, WorkspaceServiceExtPath } from './workspace-service-ext';
import { WorkspaceServiceExtImpl } from './workspace-service-ext-impl';
import { ToolOutputServiceClient } from '../common/protocol/tool-output-service';
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) => {
// 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))
.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
bind(WorkspaceServiceExt).to(WorkspaceServiceExtImpl).inSingletonScope().onActivation(({ container }, workspaceServiceExt) => {
WebSocketConnectionProvider.createProxy(container, WorkspaceServiceExtPath, workspaceServiceExt);

View File

@ -52,6 +52,7 @@
padding: 4px;
font-size: 10px;
font-weight: bold;
max-height: calc(1em + 4px);
}
.component-list-item .footer {

View File

@ -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);
}
}

View File

@ -1,7 +1,7 @@
export const CoreServicePath = '/services/core-service';
export const CoreService = Symbol('CoreService');
export interface CoreService {
compile(options: CoreService.Compile.Options): Promise<string>;
compile(options: CoreService.Compile.Options): Promise<void>;
upload(): Promise<void>;
}

View File

@ -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";
}

View File

@ -12,6 +12,9 @@ import { ConnectionContainerModule } from '@theia/core/lib/node/messaging/connec
import { WorkspaceServiceExtPath, WorkspaceServiceExt } from '../browser/workspace-service-ext';
import { CoreClientProviderImpl } from './core-client-provider-impl';
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) => {
bind(ArduinoDaemon).toSelf().inSingletonScope();
@ -51,6 +54,17 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
});
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.
// So that we can access the workspace roots of the frontend.
const workspaceServiceExtConnectionModule = ConnectionContainerModule.create(({ bindFrontendService }) => {

View File

@ -6,6 +6,7 @@ import { ILogger } from '@theia/core/lib/common/logger';
import { BackendApplicationContribution } from '@theia/core/lib/node';
import { Deferred } from '@theia/core/lib/common/promise-util';
import { DaemonLog } from './daemon-log';
import { ToolOutputServiceServer } from '../common/protocol/tool-output-service';
const EXECUTABLE_PATH = resolve(join(__dirname, '..', '..', 'build', `arduino-cli.${os.platform()}`))
@ -16,6 +17,9 @@ export class ArduinoDaemon implements BackendApplicationContribution {
@named('daemon')
protected readonly logger: ILogger
@inject(ToolOutputServiceServer)
protected readonly toolOutputService: ToolOutputServiceServer;
protected isReady = new Deferred<boolean>();
async onStart() {
@ -28,10 +32,16 @@ export class ArduinoDaemon implements BackendApplicationContribution {
console.log(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) {
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) {
daemon.on('exit', (code, signal) => DaemonLog.log(this.logger, `Daemon exited with code: ${code}. Signal was: ${signal}.`));

View File

@ -66,10 +66,10 @@ export class BoardsServiceImpl implements BoardsService {
const [ platform, boardName ] = board.id.split(":");
const req = new PlatformInstallReq();
req.setInstance(instance);
req.setArchitecture(boardName);
req.setPlatformPackage(platform);
req.setVersion(board.availableVersions[0]);
req.setInstance(instance);
console.info("Starting board installation", board);
const resp = client.platformInstall(req);

View File

@ -84,6 +84,24 @@ export class CoreClientProviderImpl implements CoreClientProvider {
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!!!
// `updateResp.on('data'` is called only when running, for instance, `compile`. It does not run eagerly.
// await new Promise<void>((resolve, reject) => {

View File

@ -1,11 +1,11 @@
import { inject, injectable } from 'inversify';
import { FileSystem } from '@theia/filesystem/lib/common/filesystem';
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 { CoreClientProvider } from './core-client-provider';
import { PlatformInstallReq } from './cli-protocol/core_pb';
import { LibraryInstallReq } from './cli-protocol/lib_pb';
import * as path from 'path';
import { ToolOutputServiceServer } from '../common/protocol/tool-output-service';
@injectable()
export class CoreServiceImpl implements CoreService {
@ -19,13 +19,17 @@ export class CoreServiceImpl implements CoreService {
@inject(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);
const { uri } = options;
const sketchpath = await this.fileSystem.getFsPath(options.uri);
if (!sketchpath) {
const sketchFilePath = await this.fileSystem.getFsPath(options.uri);
if (!sketchFilePath) {
throw new Error(`Cannot resolve filesystem path for URI: ${uri}.`);
}
const sketchpath = path.dirname(sketchFilePath);
const { client, instance } = await this.coreClientProvider.getClient(uri);
// 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
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();
compilerReq.setInstance(instance);
compilerReq.setSketchpath(sketchpath);
compilerReq.setFqbn('arduino:samd'/*boards.current.name*/);
compilerReq.setFqbn('arduino:avr:uno'/*boards.current.name*/);
// request.setShowproperties(false);
// request.setPreprocess(false);
compilerReq.setPreprocess(false);
// request.setBuildcachepath('');
// request.setBuildpath('');
// compilerReq.setBuildpath('/tmp/build');
// compilerReq.setShowproperties(true);
// request.setBuildpropertiesList([]);
// request.setWarnings('none');
// request.setVerbose(true);
// request.setQuiet(false);
compilerReq.setVerbose(true);
compilerReq.setQuiet(false);
// request.setVidpid('');
// request.setExportfile('');
const result = client.compile(compilerReq);
return new Promise<string>((resolve, reject) => {
const chunks: Buffer[] = [];
result.on('data', (chunk: Buffer) => chunks.push(chunk));
return new Promise<void>((resolve, reject) => {
result.on('data', (cr: CompileResp) => {
this.toolOutputService.publishNewOutput("compile", new Buffer(cr.getOutStream_asU8()).toString());
console.error(cr.getErrStream().toString());
});
result.on('error', error => reject(error));
result.on('end', () => resolve(Buffer.concat(chunks).toString('utf8').trim()))
result.on('end', () => resolve());
});
}

View 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 = [];
}
}