mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-07-09 20:36:32 +00:00
Prevent overwriting existing libraries and platforms at first IDE start-up (#1169)
* move initialization of libs and platforms into new contribution * use noOverwrite when install built-in libraries and platform * catch errors when installing platforms and libraries at first start-up * arduino-cli version 0.25.0-rc1 * refine platforms and libraries initialization in case of errors * add trailing newline when libraries and platform installation fail * use regex to check error if builtin library dependencies are already installed * rename contribution
This commit is contained in:
parent
46fcc71dd8
commit
73835eced3
@ -155,7 +155,7 @@
|
||||
],
|
||||
"arduino": {
|
||||
"cli": {
|
||||
"version": "0.24.0"
|
||||
"version": "0.25.0-rc1"
|
||||
},
|
||||
"fwuploader": {
|
||||
"version": "2.2.0"
|
||||
|
@ -10,7 +10,6 @@ import {
|
||||
SketchesService,
|
||||
ExecutableService,
|
||||
Sketch,
|
||||
LibraryService,
|
||||
ArduinoDaemon,
|
||||
} from '../common/protocol';
|
||||
import { Mutex } from 'async-mutex';
|
||||
@ -77,7 +76,6 @@ import { IDEUpdater } from '../common/protocol/ide-updater';
|
||||
import { FileSystemFrontendContribution } from '@theia/filesystem/lib/browser/filesystem-frontend-contribution';
|
||||
import { HostedPluginEvents } from './hosted-plugin-events';
|
||||
|
||||
const INIT_LIBS_AND_PACKAGES = 'initializedLibsAndPackages';
|
||||
export const SKIP_IDE_VERSION = 'skipIDEVersion';
|
||||
|
||||
@injectable()
|
||||
@ -98,9 +96,6 @@ export class ArduinoFrontendContribution
|
||||
@inject(BoardsService)
|
||||
private readonly boardsService: BoardsService;
|
||||
|
||||
@inject(LibraryService)
|
||||
private readonly libraryService: LibraryService;
|
||||
|
||||
@inject(BoardsServiceProvider)
|
||||
private readonly boardsServiceClientImpl: BoardsServiceProvider;
|
||||
|
||||
@ -162,27 +157,6 @@ export class ArduinoFrontendContribution
|
||||
|
||||
@postConstruct()
|
||||
protected async init(): Promise<void> {
|
||||
const isFirstStartup = !(await this.localStorageService.getData(
|
||||
INIT_LIBS_AND_PACKAGES
|
||||
));
|
||||
if (isFirstStartup) {
|
||||
await this.localStorageService.setData(INIT_LIBS_AND_PACKAGES, true);
|
||||
const avrPackage = await this.boardsService.getBoardPackage({
|
||||
id: 'arduino:avr',
|
||||
});
|
||||
const builtInLibrary = (
|
||||
await this.libraryService.search({
|
||||
query: 'Arduino_BuiltIn',
|
||||
})
|
||||
)[0];
|
||||
|
||||
!!avrPackage && (await this.boardsService.install({ item: avrPackage }));
|
||||
!!builtInLibrary &&
|
||||
(await this.libraryService.install({
|
||||
item: builtInLibrary,
|
||||
installDependencies: true,
|
||||
}));
|
||||
}
|
||||
if (!window.navigator.onLine) {
|
||||
// tslint:disable-next-line:max-line-length
|
||||
this.messageService.warn(
|
||||
|
@ -304,6 +304,7 @@ import { WidgetManager as TheiaWidgetManager } from '@theia/core/lib/browser/wid
|
||||
import { StartupTask } from './widgets/sketchbook/startup-task';
|
||||
import { IndexesUpdateProgress } from './contributions/indexes-update-progress';
|
||||
import { Daemon } from './contributions/daemon';
|
||||
import { FirstStartupInstaller } from './contributions/first-startup-installer';
|
||||
|
||||
MonacoThemingService.register({
|
||||
id: 'arduino-theme',
|
||||
@ -699,6 +700,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
Contribution.configure(bind, StartupTask);
|
||||
Contribution.configure(bind, IndexesUpdateProgress);
|
||||
Contribution.configure(bind, Daemon);
|
||||
Contribution.configure(bind, FirstStartupInstaller);
|
||||
|
||||
// Disabled the quick-pick customization from Theia when multiple formatters are available.
|
||||
// Use the default VS Code behavior, and pick the first one. In the IDE2, clang-format has `exclusive` selectors.
|
||||
|
@ -0,0 +1,97 @@
|
||||
import { LocalStorageService } from '@theia/core/lib/browser';
|
||||
import { inject, injectable } from '@theia/core/shared/inversify';
|
||||
import { BoardsService, LibraryService } from '../../common/protocol';
|
||||
import { Contribution } from './contribution';
|
||||
|
||||
@injectable()
|
||||
export class FirstStartupInstaller extends Contribution {
|
||||
@inject(LocalStorageService)
|
||||
private readonly localStorageService: LocalStorageService;
|
||||
@inject(BoardsService)
|
||||
private readonly boardsService: BoardsService;
|
||||
@inject(LibraryService)
|
||||
private readonly libraryService: LibraryService;
|
||||
|
||||
override async onReady(): Promise<void> {
|
||||
const isFirstStartup = !(await this.localStorageService.getData(
|
||||
FirstStartupInstaller.INIT_LIBS_AND_PACKAGES
|
||||
));
|
||||
if (isFirstStartup) {
|
||||
const avrPackage = await this.boardsService.getBoardPackage({
|
||||
id: 'arduino:avr',
|
||||
});
|
||||
const builtInLibrary = (
|
||||
await this.libraryService.search({ query: 'Arduino_BuiltIn' })
|
||||
)[0];
|
||||
|
||||
let avrPackageError: Error | undefined;
|
||||
let builtInLibraryError: Error | undefined;
|
||||
|
||||
if (avrPackage) {
|
||||
try {
|
||||
await this.boardsService.install({
|
||||
item: avrPackage,
|
||||
noOverwrite: true, // We don't want to automatically replace custom platforms the user might already have in place
|
||||
});
|
||||
} catch (e) {
|
||||
// There's no error code, I need to parse the error message: https://github.com/arduino/arduino-cli/commit/ffe4232b359fcfa87238d68acf1c3b64a1621f14#diff-10ffbdde46838dd9caa881fd1f2a5326a49f8061f6cfd7c9d430b4875a6b6895R62
|
||||
if (
|
||||
e.message.includes(
|
||||
`Platform ${avrPackage.id}@${avrPackage.installedVersion} already installed`
|
||||
)
|
||||
) {
|
||||
// If arduino:avr installation fails because it's already installed we don't want to retry on next start-up
|
||||
console.error(e);
|
||||
} else {
|
||||
// But if there is any other error (e.g.: no interntet cconnection), we want to retry next time
|
||||
avrPackageError = e;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
avrPackageError = new Error('Could not find platform.');
|
||||
}
|
||||
|
||||
if (builtInLibrary) {
|
||||
try {
|
||||
await this.libraryService.install({
|
||||
item: builtInLibrary,
|
||||
installDependencies: true,
|
||||
noOverwrite: true, // We don't want to automatically replace custom libraries the user might already have in place
|
||||
});
|
||||
} catch (e) {
|
||||
// There's no error code, I need to parse the error message: https://github.com/arduino/arduino-cli/commit/2ea3608453b17b1157f8a1dc892af2e13e40f4f0#diff-1de7569144d4e260f8dde0e0d00a4e2a218c57966d583da1687a70d518986649R95
|
||||
if (/Library (.*) is already installed/.test(e.message)) {
|
||||
// If Arduino_BuiltIn installation fails because it's already installed we don't want to retry on next start-up
|
||||
console.log('error installing core', e);
|
||||
} else {
|
||||
// But if there is any other error (e.g.: no interntet cconnection), we want to retry next time
|
||||
builtInLibraryError = e;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
builtInLibraryError = new Error('Could not find library');
|
||||
}
|
||||
|
||||
if (avrPackageError) {
|
||||
this.messageService.error(
|
||||
`Could not install Arduino AVR platform: ${avrPackageError}`
|
||||
);
|
||||
}
|
||||
if (builtInLibraryError) {
|
||||
this.messageService.error(
|
||||
`Could not install ${builtInLibrary.name} library: ${builtInLibraryError}`
|
||||
);
|
||||
}
|
||||
|
||||
if (!avrPackageError && !builtInLibraryError) {
|
||||
await this.localStorageService.setData(
|
||||
FirstStartupInstaller.INIT_LIBS_AND_PACKAGES,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
export namespace FirstStartupInstaller {
|
||||
export const INIT_LIBS_AND_PACKAGES = 'initializedLibsAndPackages';
|
||||
}
|
@ -17,6 +17,7 @@ export interface Installable<T extends ArduinoComponent> {
|
||||
item: T;
|
||||
progressId?: string;
|
||||
version?: Installable.Version;
|
||||
noOverwrite?: boolean;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
|
@ -16,6 +16,7 @@ export interface LibraryService
|
||||
progressId?: string;
|
||||
version?: Installable.Version;
|
||||
installDependencies?: boolean;
|
||||
noOverwrite?: boolean;
|
||||
}): Promise<void>;
|
||||
installZip(options: {
|
||||
zipUri: string;
|
||||
|
@ -391,6 +391,7 @@ export class BoardsServiceImpl
|
||||
item: BoardsPackage;
|
||||
progressId?: string;
|
||||
version?: Installable.Version;
|
||||
noOverwrite?: boolean;
|
||||
}): Promise<void> {
|
||||
const item = options.item;
|
||||
const version = !!options.version
|
||||
@ -406,6 +407,7 @@ export class BoardsServiceImpl
|
||||
req.setArchitecture(architecture);
|
||||
req.setPlatformPackage(platform);
|
||||
req.setVersion(version);
|
||||
req.setNoOverwrite(Boolean(options.noOverwrite));
|
||||
|
||||
console.info('>>> Starting boards package installation...', item);
|
||||
|
||||
@ -430,7 +432,7 @@ export class BoardsServiceImpl
|
||||
chunk: `Failed to install platform: ${item.id}.\n`,
|
||||
});
|
||||
this.responseService.appendToOutput({
|
||||
chunk: error.toString(),
|
||||
chunk: `${error.toString()}\n`,
|
||||
});
|
||||
reject(error);
|
||||
});
|
||||
|
@ -95,6 +95,9 @@ export class CompileRequest extends jspb.Message {
|
||||
getEncryptKey(): string;
|
||||
setEncryptKey(value: string): CompileRequest;
|
||||
|
||||
getSkipLibrariesDiscovery(): boolean;
|
||||
setSkipLibrariesDiscovery(value: boolean): CompileRequest;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): CompileRequest.AsObject;
|
||||
@ -133,6 +136,7 @@ export namespace CompileRequest {
|
||||
keysKeychain: string,
|
||||
signKey: string,
|
||||
encryptKey: string,
|
||||
skipLibrariesDiscovery: boolean,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,7 +149,8 @@ proto.cc.arduino.cli.commands.v1.CompileRequest.toObject = function(includeInsta
|
||||
libraryList: (f = jspb.Message.getRepeatedField(msg, 24)) == null ? undefined : f,
|
||||
keysKeychain: jspb.Message.getFieldWithDefault(msg, 25, ""),
|
||||
signKey: jspb.Message.getFieldWithDefault(msg, 26, ""),
|
||||
encryptKey: jspb.Message.getFieldWithDefault(msg, 27, "")
|
||||
encryptKey: jspb.Message.getFieldWithDefault(msg, 27, ""),
|
||||
skipLibrariesDiscovery: jspb.Message.getBooleanFieldWithDefault(msg, 28, false)
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
@ -286,6 +287,10 @@ proto.cc.arduino.cli.commands.v1.CompileRequest.deserializeBinaryFromReader = fu
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setEncryptKey(value);
|
||||
break;
|
||||
case 28:
|
||||
var value = /** @type {boolean} */ (reader.readBool());
|
||||
msg.setSkipLibrariesDiscovery(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
@ -482,6 +487,13 @@ proto.cc.arduino.cli.commands.v1.CompileRequest.serializeBinaryToWriter = functi
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getSkipLibrariesDiscovery();
|
||||
if (f) {
|
||||
writer.writeBool(
|
||||
28,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1016,6 +1028,24 @@ proto.cc.arduino.cli.commands.v1.CompileRequest.prototype.setEncryptKey = functi
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional bool skip_libraries_discovery = 28;
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.CompileRequest.prototype.getSkipLibrariesDiscovery = function() {
|
||||
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 28, false));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {boolean} value
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.CompileRequest} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.CompileRequest.prototype.setSkipLibrariesDiscovery = function(value) {
|
||||
return jspb.Message.setProto3BooleanField(this, 28, value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* List of repeated fields within this message type.
|
||||
|
@ -26,6 +26,9 @@ export class PlatformInstallRequest extends jspb.Message {
|
||||
getSkipPostInstall(): boolean;
|
||||
setSkipPostInstall(value: boolean): PlatformInstallRequest;
|
||||
|
||||
getNoOverwrite(): boolean;
|
||||
setNoOverwrite(value: boolean): PlatformInstallRequest;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): PlatformInstallRequest.AsObject;
|
||||
@ -44,6 +47,7 @@ export namespace PlatformInstallRequest {
|
||||
architecture: string,
|
||||
version: string,
|
||||
skipPostInstall: boolean,
|
||||
noOverwrite: boolean,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -339,7 +339,8 @@ proto.cc.arduino.cli.commands.v1.PlatformInstallRequest.toObject = function(incl
|
||||
platformPackage: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||
architecture: jspb.Message.getFieldWithDefault(msg, 3, ""),
|
||||
version: jspb.Message.getFieldWithDefault(msg, 4, ""),
|
||||
skipPostInstall: jspb.Message.getBooleanFieldWithDefault(msg, 5, false)
|
||||
skipPostInstall: jspb.Message.getBooleanFieldWithDefault(msg, 5, false),
|
||||
noOverwrite: jspb.Message.getBooleanFieldWithDefault(msg, 6, false)
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
@ -397,6 +398,10 @@ proto.cc.arduino.cli.commands.v1.PlatformInstallRequest.deserializeBinaryFromRea
|
||||
var value = /** @type {boolean} */ (reader.readBool());
|
||||
msg.setSkipPostInstall(value);
|
||||
break;
|
||||
case 6:
|
||||
var value = /** @type {boolean} */ (reader.readBool());
|
||||
msg.setNoOverwrite(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
@ -462,6 +467,13 @@ proto.cc.arduino.cli.commands.v1.PlatformInstallRequest.serializeBinaryToWriter
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getNoOverwrite();
|
||||
if (f) {
|
||||
writer.writeBool(
|
||||
6,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -574,6 +586,24 @@ proto.cc.arduino.cli.commands.v1.PlatformInstallRequest.prototype.setSkipPostIns
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional bool no_overwrite = 6;
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.PlatformInstallRequest.prototype.getNoOverwrite = function() {
|
||||
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 6, false));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {boolean} value
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.PlatformInstallRequest} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.PlatformInstallRequest.prototype.setNoOverwrite = function(value) {
|
||||
return jspb.Message.setProto3BooleanField(this, 6, value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -79,6 +79,9 @@ export class LibraryInstallRequest extends jspb.Message {
|
||||
getNoDeps(): boolean;
|
||||
setNoDeps(value: boolean): LibraryInstallRequest;
|
||||
|
||||
getNoOverwrite(): boolean;
|
||||
setNoOverwrite(value: boolean): LibraryInstallRequest;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): LibraryInstallRequest.AsObject;
|
||||
@ -96,6 +99,7 @@ export namespace LibraryInstallRequest {
|
||||
name: string,
|
||||
version: string,
|
||||
noDeps: boolean,
|
||||
noOverwrite: boolean,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -967,7 +967,8 @@ proto.cc.arduino.cli.commands.v1.LibraryInstallRequest.toObject = function(inclu
|
||||
instance: (f = msg.getInstance()) && cc_arduino_cli_commands_v1_common_pb.Instance.toObject(includeInstance, f),
|
||||
name: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||
version: jspb.Message.getFieldWithDefault(msg, 3, ""),
|
||||
noDeps: jspb.Message.getBooleanFieldWithDefault(msg, 4, false)
|
||||
noDeps: jspb.Message.getBooleanFieldWithDefault(msg, 4, false),
|
||||
noOverwrite: jspb.Message.getBooleanFieldWithDefault(msg, 5, false)
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
@ -1021,6 +1022,10 @@ proto.cc.arduino.cli.commands.v1.LibraryInstallRequest.deserializeBinaryFromRead
|
||||
var value = /** @type {boolean} */ (reader.readBool());
|
||||
msg.setNoDeps(value);
|
||||
break;
|
||||
case 5:
|
||||
var value = /** @type {boolean} */ (reader.readBool());
|
||||
msg.setNoOverwrite(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
@ -1079,6 +1084,13 @@ proto.cc.arduino.cli.commands.v1.LibraryInstallRequest.serializeBinaryToWriter =
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getNoOverwrite();
|
||||
if (f) {
|
||||
writer.writeBool(
|
||||
5,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1173,6 +1185,24 @@ proto.cc.arduino.cli.commands.v1.LibraryInstallRequest.prototype.setNoDeps = fun
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional bool no_overwrite = 5;
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.LibraryInstallRequest.prototype.getNoOverwrite = function() {
|
||||
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 5, false));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {boolean} value
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.LibraryInstallRequest} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.LibraryInstallRequest.prototype.setNoOverwrite = function(value) {
|
||||
return jspb.Message.setProto3BooleanField(this, 5, value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -252,6 +252,7 @@ export class LibraryServiceImpl
|
||||
progressId?: string;
|
||||
version?: Installable.Version;
|
||||
installDependencies?: boolean;
|
||||
noOverwrite?: boolean;
|
||||
}): Promise<void> {
|
||||
const item = options.item;
|
||||
const version = !!options.version
|
||||
@ -265,6 +266,7 @@ export class LibraryServiceImpl
|
||||
req.setName(item.name);
|
||||
req.setVersion(version);
|
||||
req.setNoDeps(!options.installDependencies);
|
||||
req.setNoOverwrite(Boolean(options.noOverwrite));
|
||||
|
||||
console.info('>>> Starting library package installation...', item);
|
||||
|
||||
@ -291,7 +293,7 @@ export class LibraryServiceImpl
|
||||
}.\n`,
|
||||
});
|
||||
this.responseService.appendToOutput({
|
||||
chunk: error.toString(),
|
||||
chunk: `${error.toString()}\n`,
|
||||
});
|
||||
reject(error);
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user