Skip to content

feat: upload using programmer by default if board requires it #2500

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions arduino-ide-extension/src/browser/contributions/upload-sketch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ export class UploadSketch extends CoreServiceContribution {
usingProgrammer,
verifyOptions
);

if (!uploadOptions) {
return;
}
Expand All @@ -137,11 +138,37 @@ export class UploadSketch extends CoreServiceContribution {

const uploadResponse = await this.doWithProgress({
progressText: nls.localize('arduino/sketch/uploading', 'Uploading...'),
task: (progressId, coreService, token) =>
coreService.upload({ ...uploadOptions, progressId }, token),
task: async (progressId, coreService, token) => {
try {
return await coreService.upload(
{ ...uploadOptions, progressId },
token
);
} catch (err) {
if (err.code === 4005) {
const uploadWithProgrammerOptions = await this.uploadOptions(
true,
verifyOptions
);
if (uploadWithProgrammerOptions) {
return coreService.upload(
{ ...uploadWithProgrammerOptions, progressId },
token
);
}
} else {
throw err;
}
}
},
keepOutput: true,
cancelable: true,
});

if (!uploadResponse) {
return;
}

// the port update is NOOP if nothing has changed
this.boardsServiceProvider.updateConfig(uploadResponse.portAfterUpload);

Expand Down
5 changes: 5 additions & 0 deletions arduino-ide-extension/src/common/protocol/core-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,18 @@ export namespace CoreError {
Upload: 4002,
UploadUsingProgrammer: 4003,
BurnBootloader: 4004,
UploadRequiresProgrammer: 4005,
};
export const VerifyFailed = declareCoreError(Codes.Verify);
export const UploadFailed = declareCoreError(Codes.Upload);
export const UploadUsingProgrammerFailed = declareCoreError(
Codes.UploadUsingProgrammer
);
export const BurnBootloaderFailed = declareCoreError(Codes.BurnBootloader);
export const UploadRequiresProgrammer = declareCoreError(
Codes.UploadRequiresProgrammer
);

export function is(
error: unknown
): error is ApplicationError<number, ErrorLocation[]> {
Expand Down
15 changes: 14 additions & 1 deletion arduino-ide-extension/src/node/core-service-impl.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ClientReadableStream } from '@grpc/grpc-js';
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';
Expand Down Expand Up @@ -41,6 +41,7 @@ import { Port as RpcPort } from './cli-protocol/cc/arduino/cli/commands/v1/port_
import {
BurnBootloaderRequest,
BurnBootloaderResponse,
ProgrammerIsRequiredForUploadError,
UploadRequest,
UploadResponse,
UploadUsingProgrammerRequest,
Expand Down Expand Up @@ -295,12 +296,24 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
reject(UserAbortApplicationError());
return;
}

if (
ServiceError.isInstanceOf(
error,
ProgrammerIsRequiredForUploadError
)
) {
reject(CoreError.UploadRequiresProgrammer());
return;
}

const message = nls.localize(
'arduino/upload/error',
'{0} error: {1}',
firstToUpperCase(task),
error.details
);

this.sendResponse(error.details, OutputMessage.Severity.Error);
reject(
errorCtor(
Expand Down
44 changes: 42 additions & 2 deletions arduino-ide-extension/src/node/service-error.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,54 @@
import { Metadata, StatusObject } from '@grpc/grpc-js';
import { Status } from './cli-protocol/google/rpc/status_pb';
import { stringToUint8Array } from '../common/utils';
import { ProgrammerIsRequiredForUploadError } from './cli-protocol/cc/arduino/cli/commands/v1/upload_pb';

type ProtoError = typeof ProgrammerIsRequiredForUploadError;
const protoErrorsMap = new Map<string, ProtoError>([
[
'type.googleapis.com/cc.arduino.cli.commands.v1.ProgrammerIsRequiredForUploadError',
ProgrammerIsRequiredForUploadError,
],
// handle other cli defined errors here
]);

export type ServiceError = StatusObject & Error;
export namespace ServiceError {
export function isCancel(arg: unknown): arg is ServiceError & { code: 1 } {
return is(arg) && arg.code === 1; // https://grpc.github.io/grpc/core/md_doc_statuscodes.html
}

export function is(arg: unknown): arg is ServiceError {
return arg instanceof Error && isStatusObjet(arg);
return arg instanceof Error && isStatusObject(arg);
}
function isStatusObjet(arg: unknown): arg is StatusObject {

export function isInstanceOf(arg: unknown, type: unknown): boolean {
if (!isStatusObject(arg)) {
return false;
}

const bin = arg.metadata.get('grpc-status-details-bin')[0];

const uint8Array =
typeof bin === 'string'
? stringToUint8Array(bin)
: new Uint8Array(bin.buffer, bin.byteOffset, bin.byteLength);

const errors = Status.deserializeBinary(uint8Array)
.getDetailsList()
.map((details) => {
const typeUrl = details.getTypeUrl();
const ErrorType = protoErrorsMap.get(typeUrl);
return ErrorType?.deserializeBinary(details.getValue_asU8());
});

return !!errors.find((error) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return error && error instanceof <any>type;
});
}

function isStatusObject(arg: unknown): arg is StatusObject {
if (typeof arg === 'object') {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const any = arg as any;
Expand Down
Loading