mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-07-09 12:26:34 +00:00
feat: cancelable verify+upload
Closes arduino/arduino-ide#1199 Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
This commit is contained in:
parent
347e3d8118
commit
2a325a5b74
@ -37,11 +37,15 @@ export class BurnBootloader extends CoreServiceContribution {
|
|||||||
'arduino/bootloader/burningBootloader',
|
'arduino/bootloader/burningBootloader',
|
||||||
'Burning bootloader...'
|
'Burning bootloader...'
|
||||||
),
|
),
|
||||||
task: (progressId, coreService) =>
|
task: (progressId, coreService, token) =>
|
||||||
coreService.burnBootloader({
|
coreService.burnBootloader(
|
||||||
...options,
|
{
|
||||||
progressId,
|
...options,
|
||||||
}),
|
progressId,
|
||||||
|
},
|
||||||
|
token
|
||||||
|
),
|
||||||
|
cancelable: true,
|
||||||
});
|
});
|
||||||
this.messageService.info(
|
this.messageService.info(
|
||||||
nls.localize(
|
nls.localize(
|
||||||
|
@ -1,83 +1,89 @@
|
|||||||
|
import { ClipboardService } from '@theia/core/lib/browser/clipboard-service';
|
||||||
|
import {
|
||||||
|
FrontendApplication,
|
||||||
|
FrontendApplicationContribution,
|
||||||
|
} from '@theia/core/lib/browser/frontend-application';
|
||||||
|
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
|
||||||
|
import {
|
||||||
|
KeybindingContribution,
|
||||||
|
KeybindingRegistry,
|
||||||
|
} from '@theia/core/lib/browser/keybinding';
|
||||||
|
import { LabelProvider } from '@theia/core/lib/browser/label-provider';
|
||||||
|
import { OpenerService, open } from '@theia/core/lib/browser/opener-service';
|
||||||
|
import { Saveable } from '@theia/core/lib/browser/saveable';
|
||||||
|
import { ApplicationShell } from '@theia/core/lib/browser/shell/application-shell';
|
||||||
|
import {
|
||||||
|
TabBarToolbarContribution,
|
||||||
|
TabBarToolbarRegistry,
|
||||||
|
} from '@theia/core/lib/browser/shell/tab-bar-toolbar';
|
||||||
|
import { CancellationToken } from '@theia/core/lib/common/cancellation';
|
||||||
|
import {
|
||||||
|
Command,
|
||||||
|
CommandContribution,
|
||||||
|
CommandRegistry,
|
||||||
|
CommandService,
|
||||||
|
} from '@theia/core/lib/common/command';
|
||||||
|
import {
|
||||||
|
Disposable,
|
||||||
|
DisposableCollection,
|
||||||
|
} from '@theia/core/lib/common/disposable';
|
||||||
|
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
|
||||||
|
import { ILogger } from '@theia/core/lib/common/logger';
|
||||||
|
import {
|
||||||
|
MenuContribution,
|
||||||
|
MenuModelRegistry,
|
||||||
|
} from '@theia/core/lib/common/menu';
|
||||||
|
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||||
|
import { MessageType } from '@theia/core/lib/common/message-service-protocol';
|
||||||
|
import { nls } from '@theia/core/lib/common/nls';
|
||||||
|
import { MaybePromise, isObject } from '@theia/core/lib/common/types';
|
||||||
|
import URI from '@theia/core/lib/common/uri';
|
||||||
import {
|
import {
|
||||||
inject,
|
inject,
|
||||||
injectable,
|
injectable,
|
||||||
interfaces,
|
interfaces,
|
||||||
postConstruct,
|
postConstruct,
|
||||||
} from '@theia/core/shared/inversify';
|
} from '@theia/core/shared/inversify';
|
||||||
import URI from '@theia/core/lib/common/uri';
|
|
||||||
import { ILogger } from '@theia/core/lib/common/logger';
|
|
||||||
import {
|
|
||||||
Disposable,
|
|
||||||
DisposableCollection,
|
|
||||||
} from '@theia/core/lib/common/disposable';
|
|
||||||
import { Saveable } from '@theia/core/lib/browser/saveable';
|
|
||||||
import { FileService } from '@theia/filesystem/lib/browser/file-service';
|
|
||||||
import { MaybePromise } from '@theia/core/lib/common/types';
|
|
||||||
import { LabelProvider } from '@theia/core/lib/browser/label-provider';
|
|
||||||
import { EditorManager } from '@theia/editor/lib/browser/editor-manager';
|
import { EditorManager } from '@theia/editor/lib/browser/editor-manager';
|
||||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
import { FileService } from '@theia/filesystem/lib/browser/file-service';
|
||||||
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
|
import { NotificationManager } from '@theia/messages/lib/browser/notifications-manager';
|
||||||
import { open, OpenerService } from '@theia/core/lib/browser/opener-service';
|
import { OutputChannelSeverity } from '@theia/output/lib/browser/output-channel';
|
||||||
|
import { MainMenuManager } from '../../common/main-menu-manager';
|
||||||
|
import { userAbort } from '../../common/nls';
|
||||||
import {
|
import {
|
||||||
MenuModelRegistry,
|
CoreError,
|
||||||
MenuContribution,
|
CoreService,
|
||||||
} from '@theia/core/lib/common/menu';
|
FileSystemExt,
|
||||||
|
ResponseServiceClient,
|
||||||
|
Sketch,
|
||||||
|
SketchesService,
|
||||||
|
} from '../../common/protocol';
|
||||||
import {
|
import {
|
||||||
KeybindingRegistry,
|
ExecuteWithProgress,
|
||||||
KeybindingContribution,
|
UserAbortApplicationError,
|
||||||
} from '@theia/core/lib/browser/keybinding';
|
} from '../../common/protocol/progressible';
|
||||||
import {
|
import { ArduinoPreferences } from '../arduino-preferences';
|
||||||
TabBarToolbarContribution,
|
import { BoardsDataStore } from '../boards/boards-data-store';
|
||||||
TabBarToolbarRegistry,
|
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||||
} from '@theia/core/lib/browser/shell/tab-bar-toolbar';
|
import { ConfigServiceClient } from '../config/config-service-client';
|
||||||
import {
|
import { DialogService } from '../dialog-service';
|
||||||
FrontendApplicationContribution,
|
|
||||||
FrontendApplication,
|
|
||||||
} from '@theia/core/lib/browser/frontend-application';
|
|
||||||
import {
|
|
||||||
Command,
|
|
||||||
CommandRegistry,
|
|
||||||
CommandContribution,
|
|
||||||
CommandService,
|
|
||||||
} from '@theia/core/lib/common/command';
|
|
||||||
import { SettingsService } from '../dialogs/settings/settings';
|
import { SettingsService } from '../dialogs/settings/settings';
|
||||||
import {
|
import {
|
||||||
CurrentSketch,
|
CurrentSketch,
|
||||||
SketchesServiceClientImpl,
|
SketchesServiceClientImpl,
|
||||||
} from '../sketches-service-client-impl';
|
} from '../sketches-service-client-impl';
|
||||||
import {
|
|
||||||
SketchesService,
|
|
||||||
FileSystemExt,
|
|
||||||
Sketch,
|
|
||||||
CoreService,
|
|
||||||
CoreError,
|
|
||||||
ResponseServiceClient,
|
|
||||||
} from '../../common/protocol';
|
|
||||||
import { ArduinoPreferences } from '../arduino-preferences';
|
|
||||||
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
|
|
||||||
import { nls } from '@theia/core';
|
|
||||||
import { OutputChannelManager } from '../theia/output/output-channel';
|
|
||||||
import { ClipboardService } from '@theia/core/lib/browser/clipboard-service';
|
|
||||||
import { ExecuteWithProgress } from '../../common/protocol/progressible';
|
|
||||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
|
||||||
import { BoardsDataStore } from '../boards/boards-data-store';
|
|
||||||
import { NotificationManager } from '@theia/messages/lib/browser/notifications-manager';
|
|
||||||
import { MessageType } from '@theia/core/lib/common/message-service-protocol';
|
|
||||||
import { WorkspaceService } from '../theia/workspace/workspace-service';
|
|
||||||
import { MainMenuManager } from '../../common/main-menu-manager';
|
|
||||||
import { ConfigServiceClient } from '../config/config-service-client';
|
|
||||||
import { ApplicationShell } from '@theia/core/lib/browser/shell/application-shell';
|
|
||||||
import { DialogService } from '../dialog-service';
|
|
||||||
import { ApplicationConnectionStatusContribution } from '../theia/core/connection-status-service';
|
import { ApplicationConnectionStatusContribution } from '../theia/core/connection-status-service';
|
||||||
|
import { OutputChannelManager } from '../theia/output/output-channel';
|
||||||
|
import { WorkspaceService } from '../theia/workspace/workspace-service';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Command,
|
Command,
|
||||||
CommandRegistry,
|
CommandRegistry,
|
||||||
MenuModelRegistry,
|
|
||||||
KeybindingRegistry,
|
KeybindingRegistry,
|
||||||
|
MenuModelRegistry,
|
||||||
|
Sketch,
|
||||||
TabBarToolbarRegistry,
|
TabBarToolbarRegistry,
|
||||||
URI,
|
URI,
|
||||||
Sketch,
|
|
||||||
open,
|
open,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -247,6 +253,12 @@ export abstract class CoreServiceContribution extends SketchContribution {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected handleError(error: unknown): void {
|
protected handleError(error: unknown): void {
|
||||||
|
if (isObject(error) && UserAbortApplicationError.is(error)) {
|
||||||
|
this.outputChannelManager
|
||||||
|
.getChannel('Arduino')
|
||||||
|
.appendLine(userAbort, OutputChannelSeverity.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.tryToastErrorMessage(error);
|
this.tryToastErrorMessage(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,7 +305,13 @@ export abstract class CoreServiceContribution extends SketchContribution {
|
|||||||
protected async doWithProgress<T>(options: {
|
protected async doWithProgress<T>(options: {
|
||||||
progressText: string;
|
progressText: string;
|
||||||
keepOutput?: boolean;
|
keepOutput?: boolean;
|
||||||
task: (progressId: string, coreService: CoreService) => Promise<T>;
|
task: (
|
||||||
|
progressId: string,
|
||||||
|
coreService: CoreService,
|
||||||
|
cancellationToken?: CancellationToken
|
||||||
|
) => Promise<T>;
|
||||||
|
// false by default
|
||||||
|
cancelable?: boolean;
|
||||||
}): Promise<T> {
|
}): Promise<T> {
|
||||||
const toDisposeOnComplete = new DisposableCollection(
|
const toDisposeOnComplete = new DisposableCollection(
|
||||||
this.maybeActivateMonitorWidget()
|
this.maybeActivateMonitorWidget()
|
||||||
@ -306,8 +324,10 @@ export abstract class CoreServiceContribution extends SketchContribution {
|
|||||||
messageService: this.messageService,
|
messageService: this.messageService,
|
||||||
responseService: this.responseService,
|
responseService: this.responseService,
|
||||||
progressText,
|
progressText,
|
||||||
run: ({ progressId }) => task(progressId, this.coreService),
|
run: ({ progressId, cancellationToken }) =>
|
||||||
|
task(progressId, this.coreService, cancellationToken),
|
||||||
keepOutput,
|
keepOutput,
|
||||||
|
cancelable: options.cancelable,
|
||||||
});
|
});
|
||||||
toDisposeOnComplete.dispose();
|
toDisposeOnComplete.dispose();
|
||||||
return result;
|
return result;
|
||||||
|
@ -136,9 +136,10 @@ export class UploadSketch extends CoreServiceContribution {
|
|||||||
|
|
||||||
const uploadResponse = await this.doWithProgress({
|
const uploadResponse = await this.doWithProgress({
|
||||||
progressText: nls.localize('arduino/sketch/uploading', 'Uploading...'),
|
progressText: nls.localize('arduino/sketch/uploading', 'Uploading...'),
|
||||||
task: (progressId, coreService) =>
|
task: (progressId, coreService, token) =>
|
||||||
coreService.upload({ ...uploadOptions, progressId }),
|
coreService.upload({ ...uploadOptions, progressId }, token),
|
||||||
keepOutput: true,
|
keepOutput: true,
|
||||||
|
cancelable: true,
|
||||||
});
|
});
|
||||||
// the port update is NOOP if nothing has changed
|
// the port update is NOOP if nothing has changed
|
||||||
this.boardsServiceProvider.updateConfig(uploadResponse.portAfterUpload);
|
this.boardsServiceProvider.updateConfig(uploadResponse.portAfterUpload);
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
||||||
import { Emitter } from '@theia/core/lib/common/event';
|
import { Emitter } from '@theia/core/lib/common/event';
|
||||||
|
import { nls } from '@theia/core/lib/common/nls';
|
||||||
|
import { inject, injectable } from '@theia/core/shared/inversify';
|
||||||
|
import type { CoreService } from '../../common/protocol';
|
||||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||||
|
import { CurrentSketch } from '../sketches-service-client-impl';
|
||||||
import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
|
import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
|
||||||
import {
|
import {
|
||||||
CoreServiceContribution,
|
|
||||||
Command,
|
Command,
|
||||||
CommandRegistry,
|
CommandRegistry,
|
||||||
MenuModelRegistry,
|
CoreServiceContribution,
|
||||||
KeybindingRegistry,
|
KeybindingRegistry,
|
||||||
|
MenuModelRegistry,
|
||||||
TabBarToolbarRegistry,
|
TabBarToolbarRegistry,
|
||||||
} from './contribution';
|
} from './contribution';
|
||||||
import { nls } from '@theia/core/lib/common';
|
|
||||||
import { CurrentSketch } from '../sketches-service-client-impl';
|
|
||||||
import { CoreService } from '../../common/protocol';
|
|
||||||
import { CoreErrorHandler } from './core-error-handler';
|
import { CoreErrorHandler } from './core-error-handler';
|
||||||
|
|
||||||
export interface VerifySketchParams {
|
export interface VerifySketchParams {
|
||||||
@ -131,11 +131,15 @@ export class VerifySketch extends CoreServiceContribution {
|
|||||||
'arduino/sketch/compile',
|
'arduino/sketch/compile',
|
||||||
'Compiling sketch...'
|
'Compiling sketch...'
|
||||||
),
|
),
|
||||||
task: (progressId, coreService) =>
|
task: (progressId, coreService, token) =>
|
||||||
coreService.compile({
|
coreService.compile(
|
||||||
...options,
|
{
|
||||||
progressId,
|
...options,
|
||||||
}),
|
progressId,
|
||||||
|
},
|
||||||
|
token
|
||||||
|
),
|
||||||
|
cancelable: true,
|
||||||
});
|
});
|
||||||
this.messageService.info(
|
this.messageService.info(
|
||||||
nls.localize('arduino/sketch/doneCompiling', 'Done compiling.'),
|
nls.localize('arduino/sketch/doneCompiling', 'Done compiling.'),
|
||||||
|
@ -12,15 +12,13 @@ import {
|
|||||||
LibrarySearch,
|
LibrarySearch,
|
||||||
LibraryService,
|
LibraryService,
|
||||||
} from '../../common/protocol/library-service';
|
} from '../../common/protocol/library-service';
|
||||||
import {
|
import { ListWidget } from '../widgets/component-list/list-widget';
|
||||||
ListWidget,
|
|
||||||
UserAbortError,
|
|
||||||
} from '../widgets/component-list/list-widget';
|
|
||||||
import { Installable } from '../../common/protocol';
|
import { Installable } from '../../common/protocol';
|
||||||
import { ListItemRenderer } from '../widgets/component-list/list-item-renderer';
|
import { ListItemRenderer } from '../widgets/component-list/list-item-renderer';
|
||||||
import { nls } from '@theia/core/lib/common';
|
import { nls } from '@theia/core/lib/common';
|
||||||
import { LibraryFilterRenderer } from '../widgets/component-list/filter-renderer';
|
import { LibraryFilterRenderer } from '../widgets/component-list/filter-renderer';
|
||||||
import { findChildTheiaButton, splitByBoldTag } from '../utils/dom';
|
import { findChildTheiaButton, splitByBoldTag } from '../utils/dom';
|
||||||
|
import { UserAbortError } from '../../common/protocol/progressible';
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class LibraryListWidget extends ListWidget<
|
export class LibraryListWidget extends ListWidget<
|
||||||
|
@ -2,7 +2,7 @@ import React from '@theia/core/shared/react';
|
|||||||
import type { ArduinoComponent } from '../../../common/protocol/arduino-component';
|
import type { ArduinoComponent } from '../../../common/protocol/arduino-component';
|
||||||
import { Installable } from '../../../common/protocol/installable';
|
import { Installable } from '../../../common/protocol/installable';
|
||||||
import type { ListItemRenderer } from './list-item-renderer';
|
import type { ListItemRenderer } from './list-item-renderer';
|
||||||
import { UserAbortError } from './list-widget';
|
import { UserAbortError } from '../../../common/protocol/progressible';
|
||||||
|
|
||||||
export class ComponentListItem<
|
export class ComponentListItem<
|
||||||
T extends ArduinoComponent
|
T extends ArduinoComponent
|
||||||
|
@ -5,7 +5,10 @@ import { CommandService } from '@theia/core/lib/common/command';
|
|||||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||||
import { ConfirmDialog } from '@theia/core/lib/browser/dialogs';
|
import { ConfirmDialog } from '@theia/core/lib/browser/dialogs';
|
||||||
import { Searchable } from '../../../common/protocol/searchable';
|
import { Searchable } from '../../../common/protocol/searchable';
|
||||||
import { ExecuteWithProgress } from '../../../common/protocol/progressible';
|
import {
|
||||||
|
ExecuteWithProgress,
|
||||||
|
UserAbortError,
|
||||||
|
} from '../../../common/protocol/progressible';
|
||||||
import {
|
import {
|
||||||
Installable,
|
Installable,
|
||||||
libraryInstallFailed,
|
libraryInstallFailed,
|
||||||
@ -13,7 +16,7 @@ import {
|
|||||||
} from '../../../common/protocol/installable';
|
} from '../../../common/protocol/installable';
|
||||||
import { ArduinoComponent } from '../../../common/protocol/arduino-component';
|
import { ArduinoComponent } from '../../../common/protocol/arduino-component';
|
||||||
import { SearchBar } from './search-bar';
|
import { SearchBar } from './search-bar';
|
||||||
import { ListWidget, UserAbortError } from './list-widget';
|
import { ListWidget } from './list-widget';
|
||||||
import { ComponentList } from './component-list';
|
import { ComponentList } from './component-list';
|
||||||
import { ListItemRenderer } from './list-item-renderer';
|
import { ListItemRenderer } from './list-item-renderer';
|
||||||
import {
|
import {
|
||||||
|
@ -192,10 +192,3 @@ export namespace ListWidget {
|
|||||||
readonly defaultSearchOptions: S;
|
readonly defaultSearchOptions: S;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UserAbortError extends Error {
|
|
||||||
constructor(message = 'User abort') {
|
|
||||||
super(message);
|
|
||||||
Object.setPrototypeOf(this, UserAbortError.prototype);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -39,3 +39,5 @@ export const noSketchOpened = nls.localize(
|
|||||||
'arduino/common/noSketchOpened',
|
'arduino/common/noSketchOpened',
|
||||||
'No sketch opened'
|
'No sketch opened'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const userAbort = nls.localize('arduino/common/userAbort', 'User abort');
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { ApplicationError } from '@theia/core/lib/common/application-error';
|
import { ApplicationError } from '@theia/core/lib/common/application-error';
|
||||||
|
import type { CancellationToken } from '@theia/core/lib/common/cancellation';
|
||||||
import { nls } from '@theia/core/lib/common/nls';
|
import { nls } from '@theia/core/lib/common/nls';
|
||||||
import type {
|
import type {
|
||||||
Location,
|
Location,
|
||||||
@ -7,7 +8,7 @@ import type {
|
|||||||
} from '@theia/core/shared/vscode-languageserver-protocol';
|
} from '@theia/core/shared/vscode-languageserver-protocol';
|
||||||
import type { CompileSummary as ApiCompileSummary } from 'vscode-arduino-api';
|
import type { CompileSummary as ApiCompileSummary } from 'vscode-arduino-api';
|
||||||
import type { BoardUserField, Installable } from '../../common/protocol/';
|
import type { BoardUserField, Installable } from '../../common/protocol/';
|
||||||
import { isPortIdentifier, PortIdentifier, Programmer } from './boards-service';
|
import { PortIdentifier, Programmer, isPortIdentifier } from './boards-service';
|
||||||
import type { IndexUpdateSummary } from './notification-service';
|
import type { IndexUpdateSummary } from './notification-service';
|
||||||
import type { Sketch } from './sketches-service';
|
import type { Sketch } from './sketches-service';
|
||||||
|
|
||||||
@ -162,9 +163,18 @@ export function isUploadResponse(arg: unknown): arg is UploadResponse {
|
|||||||
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.Options.Compile): Promise<void>;
|
compile(
|
||||||
upload(options: CoreService.Options.Upload): Promise<UploadResponse>;
|
options: CoreService.Options.Compile,
|
||||||
burnBootloader(options: CoreService.Options.Bootloader): Promise<void>;
|
cancellationToken?: CancellationToken
|
||||||
|
): Promise<void>;
|
||||||
|
upload(
|
||||||
|
options: CoreService.Options.Upload,
|
||||||
|
cancellationToken?: CancellationToken
|
||||||
|
): Promise<UploadResponse>;
|
||||||
|
burnBootloader(
|
||||||
|
options: CoreService.Options.Bootloader,
|
||||||
|
cancellationToken?: CancellationToken
|
||||||
|
): Promise<void>;
|
||||||
/**
|
/**
|
||||||
* Refreshes the underling core gRPC client for the Arduino CLI.
|
* Refreshes the underling core gRPC client for the Arduino CLI.
|
||||||
*/
|
*/
|
||||||
|
@ -1,22 +1,48 @@
|
|||||||
|
import { ApplicationError } from '@theia/core/lib/common/application-error';
|
||||||
import type { CancellationToken } from '@theia/core/lib/common/cancellation';
|
import type { CancellationToken } from '@theia/core/lib/common/cancellation';
|
||||||
import { CancellationTokenSource } from '@theia/core/lib/common/cancellation';
|
import { CancellationTokenSource } from '@theia/core/lib/common/cancellation';
|
||||||
import type { MessageService } from '@theia/core/lib/common/message-service';
|
import type { MessageService } from '@theia/core/lib/common/message-service';
|
||||||
import type { Progress } from '@theia/core/lib/common/message-service-protocol';
|
import type { Progress } from '@theia/core/lib/common/message-service-protocol';
|
||||||
|
import { userAbort } from '../nls';
|
||||||
import type { ResponseServiceClient } from './response-service';
|
import type { ResponseServiceClient } from './response-service';
|
||||||
|
|
||||||
|
export const UserAbortApplicationError = ApplicationError.declare(
|
||||||
|
9999,
|
||||||
|
(message: string, uri: string) => {
|
||||||
|
return {
|
||||||
|
message,
|
||||||
|
data: { uri },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export class UserAbortError extends Error {
|
||||||
|
constructor() {
|
||||||
|
super(userAbort);
|
||||||
|
Object.setPrototypeOf(this, UserAbortError.prototype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export namespace ExecuteWithProgress {
|
export namespace ExecuteWithProgress {
|
||||||
export async function doWithProgress<T>(options: {
|
export async function doWithProgress<T>(options: {
|
||||||
run: ({ progressId }: { progressId: string }) => Promise<T>;
|
run: ({
|
||||||
|
progressId,
|
||||||
|
cancellationToken,
|
||||||
|
}: {
|
||||||
|
progressId: string;
|
||||||
|
cancellationToken?: CancellationToken;
|
||||||
|
}) => Promise<T>;
|
||||||
messageService: MessageService;
|
messageService: MessageService;
|
||||||
responseService: ResponseServiceClient;
|
responseService: ResponseServiceClient;
|
||||||
progressText: string;
|
progressText: string;
|
||||||
keepOutput?: boolean;
|
keepOutput?: boolean;
|
||||||
|
cancelable?: boolean;
|
||||||
}): Promise<T> {
|
}): Promise<T> {
|
||||||
return withProgress(
|
return withProgress(
|
||||||
options.progressText,
|
options.progressText,
|
||||||
options.messageService,
|
options.messageService,
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
async (progress, _token) => {
|
async (progress, token) => {
|
||||||
const progressId = progress.id;
|
const progressId = progress.id;
|
||||||
const toDispose = options.responseService.onProgressDidChange(
|
const toDispose = options.responseService.onProgressDidChange(
|
||||||
(progressMessage) => {
|
(progressMessage) => {
|
||||||
@ -30,24 +56,29 @@ export namespace ExecuteWithProgress {
|
|||||||
if (!options.keepOutput) {
|
if (!options.keepOutput) {
|
||||||
options.responseService.clearOutput();
|
options.responseService.clearOutput();
|
||||||
}
|
}
|
||||||
const result = await options.run({ progressId });
|
const result = await options.run({
|
||||||
|
progressId,
|
||||||
|
cancellationToken: token,
|
||||||
|
});
|
||||||
return result;
|
return result;
|
||||||
} finally {
|
} finally {
|
||||||
toDispose.dispose();
|
toDispose.dispose();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
options.cancelable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function withProgress<T>(
|
export async function withProgress<T>(
|
||||||
text: string,
|
text: string,
|
||||||
messageService: MessageService,
|
messageService: MessageService,
|
||||||
cb: (progress: Progress, token: CancellationToken) => Promise<T>
|
cb: (progress: Progress, token: CancellationToken) => Promise<T>,
|
||||||
|
cancelable = false
|
||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
const cancellationSource = new CancellationTokenSource();
|
const cancellationSource = new CancellationTokenSource();
|
||||||
const { token } = cancellationSource;
|
const { token } = cancellationSource;
|
||||||
const progress = await messageService.showProgress(
|
const progress = await messageService.showProgress(
|
||||||
{ text, options: { cancelable: false } },
|
{ text, options: { cancelable } },
|
||||||
() => cancellationSource.cancel()
|
() => cancellationSource.cancel()
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
|
@ -1,22 +1,44 @@
|
|||||||
|
import type { ClientReadableStream } from '@grpc/grpc-js';
|
||||||
|
import { ApplicationError } from '@theia/core/lib/common/application-error';
|
||||||
|
import type { CancellationToken } from '@theia/core/lib/common/cancellation';
|
||||||
|
import { CommandService } from '@theia/core/lib/common/command';
|
||||||
|
import {
|
||||||
|
Disposable,
|
||||||
|
DisposableCollection,
|
||||||
|
} from '@theia/core/lib/common/disposable';
|
||||||
|
import { nls } from '@theia/core/lib/common/nls';
|
||||||
|
import type { Mutable } from '@theia/core/lib/common/types';
|
||||||
import { FileUri } from '@theia/core/lib/node/file-uri';
|
import { FileUri } from '@theia/core/lib/node/file-uri';
|
||||||
import { inject, injectable } from '@theia/core/shared/inversify';
|
import { inject, injectable } from '@theia/core/shared/inversify';
|
||||||
import { relative } from 'node:path';
|
|
||||||
import * as jspb from 'google-protobuf';
|
import * as jspb from 'google-protobuf';
|
||||||
import { BoolValue } from 'google-protobuf/google/protobuf/wrappers_pb';
|
import { BoolValue } from 'google-protobuf/google/protobuf/wrappers_pb';
|
||||||
import type { ClientReadableStream } from '@grpc/grpc-js';
|
import path from 'node:path';
|
||||||
|
import {
|
||||||
|
UploadResponse as ApiUploadResponse,
|
||||||
|
OutputMessage,
|
||||||
|
Port,
|
||||||
|
PortIdentifier,
|
||||||
|
resolveDetectedPort,
|
||||||
|
} from '../common/protocol';
|
||||||
import {
|
import {
|
||||||
CompilerWarnings,
|
|
||||||
CoreService,
|
|
||||||
CoreError,
|
|
||||||
CompileSummary,
|
CompileSummary,
|
||||||
|
CompilerWarnings,
|
||||||
|
CoreError,
|
||||||
|
CoreService,
|
||||||
isCompileSummary,
|
isCompileSummary,
|
||||||
isUploadResponse,
|
isUploadResponse,
|
||||||
} from '../common/protocol/core-service';
|
} from '../common/protocol/core-service';
|
||||||
|
import { ResponseService } from '../common/protocol/response-service';
|
||||||
|
import { firstToUpperCase, notEmpty } from '../common/utils';
|
||||||
|
import { BoardDiscovery, createApiPort } from './board-discovery';
|
||||||
|
import { tryParseError } from './cli-error-parser';
|
||||||
|
import { ArduinoCoreServiceClient } from './cli-protocol/cc/arduino/cli/commands/v1/commands_grpc_pb';
|
||||||
|
import { Instance } from './cli-protocol/cc/arduino/cli/commands/v1/common_pb';
|
||||||
import {
|
import {
|
||||||
CompileRequest,
|
CompileRequest,
|
||||||
CompileResponse,
|
CompileResponse,
|
||||||
} from './cli-protocol/cc/arduino/cli/commands/v1/compile_pb';
|
} from './cli-protocol/cc/arduino/cli/commands/v1/compile_pb';
|
||||||
import { CoreClientAware } from './core-client-provider';
|
import { Port as RpcPort } from './cli-protocol/cc/arduino/cli/commands/v1/port_pb';
|
||||||
import {
|
import {
|
||||||
BurnBootloaderRequest,
|
BurnBootloaderRequest,
|
||||||
BurnBootloaderResponse,
|
BurnBootloaderResponse,
|
||||||
@ -25,26 +47,13 @@ import {
|
|||||||
UploadUsingProgrammerRequest,
|
UploadUsingProgrammerRequest,
|
||||||
UploadUsingProgrammerResponse,
|
UploadUsingProgrammerResponse,
|
||||||
} from './cli-protocol/cc/arduino/cli/commands/v1/upload_pb';
|
} from './cli-protocol/cc/arduino/cli/commands/v1/upload_pb';
|
||||||
import { ResponseService } from '../common/protocol/response-service';
|
import { CoreClientAware } from './core-client-provider';
|
||||||
import {
|
|
||||||
resolveDetectedPort,
|
|
||||||
OutputMessage,
|
|
||||||
PortIdentifier,
|
|
||||||
Port,
|
|
||||||
UploadResponse as ApiUploadResponse,
|
|
||||||
} from '../common/protocol';
|
|
||||||
import { ArduinoCoreServiceClient } from './cli-protocol/cc/arduino/cli/commands/v1/commands_grpc_pb';
|
|
||||||
import { Port as RpcPort } from './cli-protocol/cc/arduino/cli/commands/v1/port_pb';
|
|
||||||
import { ApplicationError, CommandService, Disposable, nls } from '@theia/core';
|
|
||||||
import { MonitorManager } from './monitor-manager';
|
|
||||||
import { AutoFlushingBuffer } from './utils/buffers';
|
|
||||||
import { tryParseError } from './cli-error-parser';
|
|
||||||
import { Instance } from './cli-protocol/cc/arduino/cli/commands/v1/common_pb';
|
|
||||||
import { firstToUpperCase, notEmpty } from '../common/utils';
|
|
||||||
import { ServiceError } from './service-error';
|
|
||||||
import { ExecuteWithProgress, ProgressResponse } from './grpc-progressible';
|
import { ExecuteWithProgress, ProgressResponse } from './grpc-progressible';
|
||||||
import type { Mutable } from '@theia/core/lib/common/types';
|
import { MonitorManager } from './monitor-manager';
|
||||||
import { BoardDiscovery, createApiPort } from './board-discovery';
|
import { ServiceError } from './service-error';
|
||||||
|
import { AutoFlushingBuffer } from './utils/buffers';
|
||||||
|
import { userAbort } from '../common/nls';
|
||||||
|
import { UserAbortApplicationError } from '../common/protocol/progressible';
|
||||||
|
|
||||||
namespace Uploadable {
|
namespace Uploadable {
|
||||||
export type Request = UploadRequest | UploadUsingProgrammerRequest;
|
export type Request = UploadRequest | UploadUsingProgrammerRequest;
|
||||||
@ -64,9 +73,13 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
|||||||
@inject(BoardDiscovery)
|
@inject(BoardDiscovery)
|
||||||
private readonly boardDiscovery: BoardDiscovery;
|
private readonly boardDiscovery: BoardDiscovery;
|
||||||
|
|
||||||
async compile(options: CoreService.Options.Compile): Promise<void> {
|
async compile(
|
||||||
|
options: CoreService.Options.Compile,
|
||||||
|
cancellationToken?: CancellationToken
|
||||||
|
): Promise<void> {
|
||||||
const coreClient = await this.coreClient;
|
const coreClient = await this.coreClient;
|
||||||
const { client, instance } = coreClient;
|
const { client, instance } = coreClient;
|
||||||
|
const request = this.compileRequest(options, instance);
|
||||||
const compileSummary = <CompileSummaryFragment>{};
|
const compileSummary = <CompileSummaryFragment>{};
|
||||||
const progressHandler = this.createProgressHandler(options);
|
const progressHandler = this.createProgressHandler(options);
|
||||||
const compileSummaryHandler = (response: CompileResponse) =>
|
const compileSummaryHandler = (response: CompileResponse) =>
|
||||||
@ -75,10 +88,15 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
|||||||
progressHandler,
|
progressHandler,
|
||||||
compileSummaryHandler
|
compileSummaryHandler
|
||||||
);
|
);
|
||||||
const request = this.compileRequest(options, instance);
|
const toDisposeOnFinally = new DisposableCollection(handler);
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
client
|
const call = client.compile(request);
|
||||||
.compile(request)
|
if (cancellationToken) {
|
||||||
|
toDisposeOnFinally.push(
|
||||||
|
cancellationToken.onCancellationRequested(() => call.cancel())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
call
|
||||||
.on('data', handler.onData)
|
.on('data', handler.onData)
|
||||||
.on('error', (error) => {
|
.on('error', (error) => {
|
||||||
if (!ServiceError.is(error)) {
|
if (!ServiceError.is(error)) {
|
||||||
@ -87,30 +105,39 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
|||||||
error
|
error
|
||||||
);
|
);
|
||||||
reject(error);
|
reject(error);
|
||||||
} else {
|
return;
|
||||||
const compilerErrors = tryParseError({
|
|
||||||
content: handler.content,
|
|
||||||
sketch: options.sketch,
|
|
||||||
});
|
|
||||||
const message = nls.localize(
|
|
||||||
'arduino/compile/error',
|
|
||||||
'Compilation error: {0}',
|
|
||||||
compilerErrors
|
|
||||||
.map(({ message }) => message)
|
|
||||||
.filter(notEmpty)
|
|
||||||
.shift() ?? error.details
|
|
||||||
);
|
|
||||||
this.sendResponse(
|
|
||||||
error.details + '\n\n' + message,
|
|
||||||
OutputMessage.Severity.Error
|
|
||||||
);
|
|
||||||
reject(CoreError.VerifyFailed(message, compilerErrors));
|
|
||||||
}
|
}
|
||||||
|
if (ServiceError.isCancel(error)) {
|
||||||
|
console.log(userAbort);
|
||||||
|
reject(UserAbortApplicationError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const compilerErrors = tryParseError({
|
||||||
|
content: handler.content,
|
||||||
|
sketch: options.sketch,
|
||||||
|
});
|
||||||
|
const message = nls.localize(
|
||||||
|
'arduino/compile/error',
|
||||||
|
'Compilation error: {0}',
|
||||||
|
compilerErrors
|
||||||
|
.map(({ message }) => message)
|
||||||
|
.filter(notEmpty)
|
||||||
|
.shift() ?? error.details
|
||||||
|
);
|
||||||
|
this.sendResponse(
|
||||||
|
error.details + '\n\n' + message,
|
||||||
|
OutputMessage.Severity.Error
|
||||||
|
);
|
||||||
|
reject(CoreError.VerifyFailed(message, compilerErrors));
|
||||||
})
|
})
|
||||||
.on('end', resolve);
|
.on('end', resolve);
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
handler.dispose();
|
toDisposeOnFinally.dispose();
|
||||||
if (!isCompileSummary(compileSummary)) {
|
if (!isCompileSummary(compileSummary)) {
|
||||||
|
if (cancellationToken && cancellationToken.isCancellationRequested) {
|
||||||
|
// NOOP
|
||||||
|
return;
|
||||||
|
}
|
||||||
console.error(
|
console.error(
|
||||||
`Have not received the full compile summary from the CLI while running the compilation. ${JSON.stringify(
|
`Have not received the full compile summary from the CLI while running the compilation. ${JSON.stringify(
|
||||||
compileSummary
|
compileSummary
|
||||||
@ -176,7 +203,10 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
|||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
upload(options: CoreService.Options.Upload): Promise<ApiUploadResponse> {
|
upload(
|
||||||
|
options: CoreService.Options.Upload,
|
||||||
|
cancellationToken?: CancellationToken
|
||||||
|
): Promise<ApiUploadResponse> {
|
||||||
const { usingProgrammer } = options;
|
const { usingProgrammer } = options;
|
||||||
return this.doUpload(
|
return this.doUpload(
|
||||||
options,
|
options,
|
||||||
@ -190,7 +220,8 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
|||||||
usingProgrammer
|
usingProgrammer
|
||||||
? CoreError.UploadUsingProgrammerFailed
|
? CoreError.UploadUsingProgrammerFailed
|
||||||
: CoreError.UploadFailed,
|
: CoreError.UploadFailed,
|
||||||
`upload${usingProgrammer ? ' using programmer' : ''}`
|
`upload${usingProgrammer ? ' using programmer' : ''}`,
|
||||||
|
cancellationToken
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +235,8 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
|||||||
client: ArduinoCoreServiceClient
|
client: ArduinoCoreServiceClient
|
||||||
) => (request: REQ) => ClientReadableStream<RESP>,
|
) => (request: REQ) => ClientReadableStream<RESP>,
|
||||||
errorCtor: ApplicationError.Constructor<number, CoreError.ErrorLocation[]>,
|
errorCtor: ApplicationError.Constructor<number, CoreError.ErrorLocation[]>,
|
||||||
task: string
|
task: string,
|
||||||
|
cancellationToken?: CancellationToken
|
||||||
): Promise<ApiUploadResponse> {
|
): Promise<ApiUploadResponse> {
|
||||||
const portBeforeUpload = options.port;
|
const portBeforeUpload = options.port;
|
||||||
const uploadResponseFragment: Mutable<Partial<ApiUploadResponse>> = {
|
const uploadResponseFragment: Mutable<Partial<ApiUploadResponse>> = {
|
||||||
@ -241,33 +273,47 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
|||||||
progressHandler,
|
progressHandler,
|
||||||
updateUploadResponseFragmentHandler
|
updateUploadResponseFragmentHandler
|
||||||
);
|
);
|
||||||
|
const toDisposeOnFinally = new DisposableCollection(handler);
|
||||||
const grpcCall = responseFactory(client);
|
const grpcCall = responseFactory(client);
|
||||||
return this.notifyUploadWillStart(options).then(() =>
|
return this.notifyUploadWillStart(options).then(() =>
|
||||||
new Promise<ApiUploadResponse>((resolve, reject) => {
|
new Promise<ApiUploadResponse>((resolve, reject) => {
|
||||||
grpcCall(this.initUploadRequest(request, options, instance))
|
const call = grpcCall(
|
||||||
|
this.initUploadRequest(request, options, instance)
|
||||||
|
);
|
||||||
|
if (cancellationToken) {
|
||||||
|
toDisposeOnFinally.push(
|
||||||
|
cancellationToken.onCancellationRequested(() => call.cancel())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
call
|
||||||
.on('data', handler.onData)
|
.on('data', handler.onData)
|
||||||
.on('error', (error) => {
|
.on('error', (error) => {
|
||||||
if (!ServiceError.is(error)) {
|
if (!ServiceError.is(error)) {
|
||||||
console.error(`Unexpected error occurred while ${task}.`, error);
|
console.error(`Unexpected error occurred while ${task}.`, error);
|
||||||
reject(error);
|
reject(error);
|
||||||
} else {
|
return;
|
||||||
const message = nls.localize(
|
|
||||||
'arduino/upload/error',
|
|
||||||
'{0} error: {1}',
|
|
||||||
firstToUpperCase(task),
|
|
||||||
error.details
|
|
||||||
);
|
|
||||||
this.sendResponse(error.details, OutputMessage.Severity.Error);
|
|
||||||
reject(
|
|
||||||
errorCtor(
|
|
||||||
message,
|
|
||||||
tryParseError({
|
|
||||||
content: handler.content,
|
|
||||||
sketch: options.sketch,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
if (ServiceError.isCancel(error)) {
|
||||||
|
console.log(userAbort);
|
||||||
|
reject(UserAbortApplicationError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const message = nls.localize(
|
||||||
|
'arduino/upload/error',
|
||||||
|
'{0} error: {1}',
|
||||||
|
firstToUpperCase(task),
|
||||||
|
error.details
|
||||||
|
);
|
||||||
|
this.sendResponse(error.details, OutputMessage.Severity.Error);
|
||||||
|
reject(
|
||||||
|
errorCtor(
|
||||||
|
message,
|
||||||
|
tryParseError({
|
||||||
|
content: handler.content,
|
||||||
|
sketch: options.sketch,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.on('end', () => {
|
.on('end', () => {
|
||||||
if (isUploadResponse(uploadResponseFragment)) {
|
if (isUploadResponse(uploadResponseFragment)) {
|
||||||
@ -285,7 +331,7 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}).finally(async () => {
|
}).finally(async () => {
|
||||||
handler.dispose();
|
toDisposeOnFinally.dispose();
|
||||||
await this.notifyUploadDidFinish(
|
await this.notifyUploadDidFinish(
|
||||||
Object.assign(options, {
|
Object.assign(options, {
|
||||||
afterPort: uploadResponseFragment.portAfterUpload,
|
afterPort: uploadResponseFragment.portAfterUpload,
|
||||||
@ -320,16 +366,25 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
|||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
async burnBootloader(options: CoreService.Options.Bootloader): Promise<void> {
|
async burnBootloader(
|
||||||
|
options: CoreService.Options.Bootloader,
|
||||||
|
cancellationToken?: CancellationToken
|
||||||
|
): Promise<void> {
|
||||||
const coreClient = await this.coreClient;
|
const coreClient = await this.coreClient;
|
||||||
const { client, instance } = coreClient;
|
const { client, instance } = coreClient;
|
||||||
const progressHandler = this.createProgressHandler(options);
|
const progressHandler = this.createProgressHandler(options);
|
||||||
const handler = this.createOnDataHandler(progressHandler);
|
const handler = this.createOnDataHandler(progressHandler);
|
||||||
const request = this.burnBootloaderRequest(options, instance);
|
const request = this.burnBootloaderRequest(options, instance);
|
||||||
|
const toDisposeOnFinally = new DisposableCollection(handler);
|
||||||
return this.notifyUploadWillStart(options).then(() =>
|
return this.notifyUploadWillStart(options).then(() =>
|
||||||
new Promise<void>((resolve, reject) => {
|
new Promise<void>((resolve, reject) => {
|
||||||
client
|
const call = client.burnBootloader(request);
|
||||||
.burnBootloader(request)
|
if (cancellationToken) {
|
||||||
|
toDisposeOnFinally.push(
|
||||||
|
cancellationToken.onCancellationRequested(() => call.cancel())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
call
|
||||||
.on('data', handler.onData)
|
.on('data', handler.onData)
|
||||||
.on('error', (error) => {
|
.on('error', (error) => {
|
||||||
if (!ServiceError.is(error)) {
|
if (!ServiceError.is(error)) {
|
||||||
@ -338,23 +393,28 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
|||||||
error
|
error
|
||||||
);
|
);
|
||||||
reject(error);
|
reject(error);
|
||||||
} else {
|
return;
|
||||||
this.sendResponse(error.details, OutputMessage.Severity.Error);
|
|
||||||
reject(
|
|
||||||
CoreError.BurnBootloaderFailed(
|
|
||||||
nls.localize(
|
|
||||||
'arduino/burnBootloader/error',
|
|
||||||
'Error while burning the bootloader: {0}',
|
|
||||||
error.details
|
|
||||||
),
|
|
||||||
tryParseError({ content: handler.content })
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
if (ServiceError.isCancel(error)) {
|
||||||
|
console.log(userAbort);
|
||||||
|
reject(UserAbortApplicationError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.sendResponse(error.details, OutputMessage.Severity.Error);
|
||||||
|
reject(
|
||||||
|
CoreError.BurnBootloaderFailed(
|
||||||
|
nls.localize(
|
||||||
|
'arduino/burnBootloader/error',
|
||||||
|
'Error while burning the bootloader: {0}',
|
||||||
|
error.details
|
||||||
|
),
|
||||||
|
tryParseError({ content: handler.content })
|
||||||
|
)
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.on('end', resolve);
|
.on('end', resolve);
|
||||||
}).finally(async () => {
|
}).finally(async () => {
|
||||||
handler.dispose();
|
toDisposeOnFinally.dispose();
|
||||||
await this.notifyUploadDidFinish(
|
await this.notifyUploadDidFinish(
|
||||||
Object.assign(options, { afterPort: options.port })
|
Object.assign(options, { afterPort: options.port })
|
||||||
);
|
);
|
||||||
@ -463,7 +523,7 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
|||||||
for (const uri of Object.keys(options.sourceOverride)) {
|
for (const uri of Object.keys(options.sourceOverride)) {
|
||||||
const content = options.sourceOverride[uri];
|
const content = options.sourceOverride[uri];
|
||||||
if (content) {
|
if (content) {
|
||||||
const relativePath = relative(sketchPath, FileUri.fsPath(uri));
|
const relativePath = path.relative(sketchPath, FileUri.fsPath(uri));
|
||||||
req.getSourceOverrideMap().set(relativePath, content);
|
req.getSourceOverrideMap().set(relativePath, content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,8 @@
|
|||||||
"serialMonitor": "Serial Monitor",
|
"serialMonitor": "Serial Monitor",
|
||||||
"type": "Type",
|
"type": "Type",
|
||||||
"unknown": "Unknown",
|
"unknown": "Unknown",
|
||||||
"updateable": "Updatable"
|
"updateable": "Updatable",
|
||||||
|
"userAbort": "User abort"
|
||||||
},
|
},
|
||||||
"compile": {
|
"compile": {
|
||||||
"error": "Compilation error: {0}"
|
"error": "Compilation error: {0}"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user