mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-04-19 12:57:17 +00:00
feat: handle when starting debug session failed (#1809)
If the sketch has not been verified, IDE2 offers the user a verify action. Closes #808 Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
This commit is contained in:
parent
afb02da806
commit
6140ae525c
@ -3,7 +3,12 @@ import { Event, Emitter } from '@theia/core/lib/common/event';
|
||||
import { HostedPluginSupport } from '@theia/plugin-ext/lib/hosted/browser/hosted-plugin';
|
||||
import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
|
||||
import { NotificationCenter } from '../notification-center';
|
||||
import { Board, BoardsService, ExecutableService } from '../../common/protocol';
|
||||
import {
|
||||
Board,
|
||||
BoardsService,
|
||||
ExecutableService,
|
||||
Sketch,
|
||||
} from '../../common/protocol';
|
||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||
import {
|
||||
URI,
|
||||
@ -16,9 +21,8 @@ import { MaybePromise, MenuModelRegistry, nls } from '@theia/core/lib/common';
|
||||
import { CurrentSketch } from '../../common/protocol/sketches-service-client-impl';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
|
||||
import { MainMenuManager } from '../../common/main-menu-manager';
|
||||
|
||||
const COMPILE_FOR_DEBUG_KEY = 'arduino-compile-for-debug';
|
||||
|
||||
@injectable()
|
||||
export class Debug extends SketchContribution {
|
||||
@inject(HostedPluginSupport)
|
||||
@ -36,9 +40,6 @@ export class Debug extends SketchContribution {
|
||||
@inject(BoardsServiceProvider)
|
||||
private readonly boardsServiceProvider: BoardsServiceProvider;
|
||||
|
||||
@inject(MainMenuManager)
|
||||
private readonly mainMenuManager: MainMenuManager;
|
||||
|
||||
/**
|
||||
* If `undefined`, debugging is enabled. Otherwise, the reason why it's disabled.
|
||||
*/
|
||||
@ -203,7 +204,28 @@ export class Debug extends SketchContribution {
|
||||
sketchPath,
|
||||
configPath,
|
||||
};
|
||||
return this.commandService.executeCommand('arduino.debug.start', config);
|
||||
try {
|
||||
await this.commandService.executeCommand('arduino.debug.start', config);
|
||||
} catch (err) {
|
||||
if (await this.isSketchNotVerifiedError(err, sketch)) {
|
||||
const yes = nls.localize('vscode/extensionsUtils/yes', 'Yes');
|
||||
const answer = await this.messageService.error(
|
||||
nls.localize(
|
||||
'arduino/debug/sketchIsNotCompiled',
|
||||
"Sketch '{0}' must be verified before starting a debug session. Please verify the sketch and start debugging again. Do you want to verify the sketch now?",
|
||||
sketch.name
|
||||
),
|
||||
yes
|
||||
);
|
||||
if (answer === yes) {
|
||||
this.commandService.executeCommand('arduino-verify-sketch');
|
||||
}
|
||||
} else {
|
||||
this.messageService.error(
|
||||
err instanceof Error ? err.message : String(err)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get compileForDebug(): boolean {
|
||||
@ -215,7 +237,24 @@ export class Debug extends SketchContribution {
|
||||
const oldState = this.compileForDebug;
|
||||
const newState = !oldState;
|
||||
window.localStorage.setItem(COMPILE_FOR_DEBUG_KEY, String(newState));
|
||||
this.mainMenuManager.update();
|
||||
this.menuManager.update();
|
||||
}
|
||||
|
||||
private async isSketchNotVerifiedError(
|
||||
err: unknown,
|
||||
sketch: Sketch
|
||||
): Promise<boolean> {
|
||||
if (err instanceof Error) {
|
||||
try {
|
||||
const tempBuildPaths = await this.sketchService.tempBuildPath(sketch);
|
||||
return tempBuildPaths.some((tempBuildPath) =>
|
||||
err.message.includes(tempBuildPath)
|
||||
);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
export namespace Debug {
|
||||
|
@ -105,6 +105,17 @@ export interface SketchesService {
|
||||
* Recursively deletes the sketch folder with all its content.
|
||||
*/
|
||||
deleteSketch(sketch: Sketch): Promise<void>;
|
||||
|
||||
/**
|
||||
* This is the JS/TS re-implementation of [`GenBuildPath`](https://github.com/arduino/arduino-cli/blob/c0d4e4407d80aabad81142693513b3306759cfa6/arduino/sketch/sketch.go#L296-L306) of the CLI.
|
||||
* Pass in a sketch and get the build temporary folder filesystem path calculated from the main sketch file location. Can be multiple ones. This method does not check the existence of the sketch.
|
||||
*
|
||||
* The case sensitivity of the drive letter on Windows matters when the CLI calculates the MD5 hash of the temporary build folder.
|
||||
* IDE2 does not know and does not want to rely on how the CLI treats the paths: with lowercase or uppercase drive letters.
|
||||
* Hence, IDE2 has to provide multiple build paths on Windows. This hack will be obsolete when the CLI can provide error codes:
|
||||
* https://github.com/arduino/arduino-cli/issues/1762.
|
||||
*/
|
||||
tempBuildPath(sketch: Sketch): Promise<string[]>;
|
||||
}
|
||||
|
||||
export interface SketchRef {
|
||||
|
@ -13,6 +13,10 @@ export function firstToUpperCase(what: string): string {
|
||||
return what.charAt(0).toUpperCase() + what.slice(1);
|
||||
}
|
||||
|
||||
export function isNullOrUndefined(what: any): what is undefined | null {
|
||||
export function startsWithUpperCase(what: string): boolean {
|
||||
return !!what && what.charAt(0) === firstToUpperCase(what.charAt(0));
|
||||
}
|
||||
|
||||
export function isNullOrUndefined(what: unknown): what is undefined | null {
|
||||
return what === undefined || what === null;
|
||||
}
|
||||
|
@ -4,16 +4,16 @@ import { isWindows, isOSX } from '@theia/core/lib/common/os';
|
||||
import { injectable } from '@theia/core/shared/inversify';
|
||||
import { firstToLowerCase } from '../common/utils';
|
||||
|
||||
const Win32DriveRegex = /^[a-zA-Z]:\\/;
|
||||
export const Win32DriveRegex = /^[a-zA-Z]:\\/;
|
||||
export const TempSketchPrefix = '.arduinoIDE-unsaved';
|
||||
|
||||
@injectable()
|
||||
export class IsTempSketch {
|
||||
// If on macOS, the `temp-dir` lib will make sure there is resolved realpath.
|
||||
// If on Windows, the `C:\Users\KITTAA~1\AppData\Local\Temp` path will be resolved and normalized to `C:\Users\kittaakos\AppData\Local\Temp`.
|
||||
// If on Windows, the `C:\Users\KITTAA~1\AppData\Local\Temp` path will be resolved and normalized to `c:\Users\kittaakos\AppData\Local\Temp`.
|
||||
// Note: VS Code URI normalizes the drive letter. `C:` will be converted into `c:`.
|
||||
// https://github.com/Microsoft/vscode/issues/68325#issuecomment-462239992
|
||||
private readonly tempDirRealpath = isOSX
|
||||
readonly tempDirRealpath = isOSX
|
||||
? tempDir
|
||||
: maybeNormalizeDrive(fs.realpathSync.native(tempDir));
|
||||
|
||||
|
@ -33,9 +33,16 @@ import {
|
||||
IsTempSketch,
|
||||
maybeNormalizeDrive,
|
||||
TempSketchPrefix,
|
||||
Win32DriveRegex,
|
||||
} from './is-temp-sketch';
|
||||
import { join } from 'path';
|
||||
import { ErrnoException } from './utils/errors';
|
||||
import { isWindows } from '@theia/core/lib/common/os';
|
||||
import {
|
||||
firstToLowerCase,
|
||||
firstToUpperCase,
|
||||
startsWithUpperCase,
|
||||
} from '../common/utils';
|
||||
|
||||
const RecentSketches = 'recent-sketches.json';
|
||||
const DefaultIno = `void setup() {
|
||||
@ -566,11 +573,59 @@ export class SketchesServiceImpl
|
||||
return FileUri.create(genBuildPath).toString();
|
||||
}
|
||||
|
||||
async getIdeTempFolderPath(sketch: Sketch): Promise<string> {
|
||||
private async getIdeTempFolderPath(sketch: Sketch): Promise<string> {
|
||||
const sketchPath = FileUri.fsPath(sketch.uri);
|
||||
await fs.readdir(sketchPath); // Validates the sketch folder and rejects if not accessible.
|
||||
const suffix = crypto.createHash('md5').update(sketchPath).digest('hex');
|
||||
return path.join(os.tmpdir(), `arduino-ide2-${suffix}`);
|
||||
return path.join(
|
||||
this.isTempSketch.tempDirRealpath,
|
||||
`arduino-ide2-${suffix}`
|
||||
);
|
||||
}
|
||||
|
||||
async tempBuildPath(sketch: Sketch): Promise<string[]> {
|
||||
const sketchPath = FileUri.fsPath(sketch.uri);
|
||||
const { tempDirRealpath } = this.isTempSketch;
|
||||
const tempBuildPaths = [
|
||||
this.tempBuildPathMD5Hash(tempDirRealpath, sketchPath),
|
||||
];
|
||||
|
||||
// If on Windows, provide both the upper and the lowercase drive letter MD5 hashes. All together four paths are expected:
|
||||
// One of them should match if the sketch is not yet compiled.
|
||||
// https://github.com/arduino/arduino-ide/pull/1809#discussion_r1071031040
|
||||
if (isWindows && Win32DriveRegex.test(tempDirRealpath)) {
|
||||
const toggleFirstCharCasing = (s: string) =>
|
||||
startsWithUpperCase(s) ? firstToLowerCase(s) : firstToUpperCase(s);
|
||||
const otherCaseTempDirRealPath = toggleFirstCharCasing(tempDirRealpath);
|
||||
tempBuildPaths.push(
|
||||
this.tempBuildPathMD5Hash(otherCaseTempDirRealPath, sketchPath)
|
||||
);
|
||||
if (Win32DriveRegex.test(sketchPath)) {
|
||||
const otherCaseSketchPath = toggleFirstCharCasing(sketchPath);
|
||||
tempBuildPaths.push(
|
||||
this.tempBuildPathMD5Hash(tempDirRealpath, otherCaseSketchPath),
|
||||
this.tempBuildPathMD5Hash(
|
||||
otherCaseTempDirRealPath,
|
||||
otherCaseSketchPath
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
return tempBuildPaths;
|
||||
}
|
||||
|
||||
private tempBuildPathMD5Hash(tempFolderPath: string, path: string): string {
|
||||
return join(tempFolderPath, this.tempBuildFolderMD5Hash(path));
|
||||
}
|
||||
|
||||
private tempBuildFolderMD5Hash(path: string): string {
|
||||
const hash = crypto
|
||||
.createHash('md5')
|
||||
.update(path)
|
||||
.digest('hex')
|
||||
.toUpperCase();
|
||||
const folderName = `arduino-sketch-${hash}`;
|
||||
return folderName;
|
||||
}
|
||||
|
||||
async deleteSketch(sketch: Sketch): Promise<void> {
|
||||
|
@ -191,7 +191,8 @@
|
||||
"debugWithMessage": "Debug - {0}",
|
||||
"debuggingNotSupported": "Debugging is not supported by '{0}'",
|
||||
"noPlatformInstalledFor": "Platform is not installed for '{0}'",
|
||||
"optimizeForDebugging": "Optimize for Debugging"
|
||||
"optimizeForDebugging": "Optimize for Debugging",
|
||||
"sketchIsNotCompiled": "Sketch '{0}' must be verified before starting a debug session. Please verify the sketch and start debugging again. Do you want to verify the sketch now?"
|
||||
},
|
||||
"dialog": {
|
||||
"dontAskAgain": "Don't ask again"
|
||||
|
@ -75,7 +75,7 @@
|
||||
"theiaPluginsDir": "plugins",
|
||||
"theiaPlugins": {
|
||||
"vscode-builtin-cpp": "https://open-vsx.org/api/vscode/cpp/1.52.1/file/vscode.cpp-1.52.1.vsix",
|
||||
"vscode-arduino-tools": "https://downloads.arduino.cc/vscode-arduino-tools/vscode-arduino-tools-0.0.2-beta.5.vsix",
|
||||
"vscode-arduino-tools": "https://downloads.arduino.cc/vscode-arduino-tools/vscode-arduino-tools-0.0.2-beta.7.vsix",
|
||||
"vscode-builtin-json": "https://open-vsx.org/api/vscode/json/1.46.1/file/vscode.json-1.46.1.vsix",
|
||||
"vscode-builtin-json-language-features": "https://open-vsx.org/api/vscode/json-language-features/1.46.1/file/vscode.json-language-features-1.46.1.vsix",
|
||||
"cortex-debug": "https://downloads.arduino.cc/marus25.cortex-debug/marus25.cortex-debug-1.5.1.vsix",
|
||||
|
Loading…
x
Reference in New Issue
Block a user