Skip to content

Commit 73835ec

Browse files
author
Alberto Iannaccone
authored
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
1 parent 46fcc71 commit 73835ec

14 files changed

+213
-32
lines changed

Diff for: arduino-ide-extension/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@
155155
],
156156
"arduino": {
157157
"cli": {
158-
"version": "0.24.0"
158+
"version": "0.25.0-rc1"
159159
},
160160
"fwuploader": {
161161
"version": "2.2.0"

Diff for: arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx

-26
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010
SketchesService,
1111
ExecutableService,
1212
Sketch,
13-
LibraryService,
1413
ArduinoDaemon,
1514
} from '../common/protocol';
1615
import { Mutex } from 'async-mutex';
@@ -77,7 +76,6 @@ import { IDEUpdater } from '../common/protocol/ide-updater';
7776
import { FileSystemFrontendContribution } from '@theia/filesystem/lib/browser/filesystem-frontend-contribution';
7877
import { HostedPluginEvents } from './hosted-plugin-events';
7978

80-
const INIT_LIBS_AND_PACKAGES = 'initializedLibsAndPackages';
8179
export const SKIP_IDE_VERSION = 'skipIDEVersion';
8280

8381
@injectable()
@@ -98,9 +96,6 @@ export class ArduinoFrontendContribution
9896
@inject(BoardsService)
9997
private readonly boardsService: BoardsService;
10098

101-
@inject(LibraryService)
102-
private readonly libraryService: LibraryService;
103-
10499
@inject(BoardsServiceProvider)
105100
private readonly boardsServiceClientImpl: BoardsServiceProvider;
106101

@@ -162,27 +157,6 @@ export class ArduinoFrontendContribution
162157

163158
@postConstruct()
164159
protected async init(): Promise<void> {
165-
const isFirstStartup = !(await this.localStorageService.getData(
166-
INIT_LIBS_AND_PACKAGES
167-
));
168-
if (isFirstStartup) {
169-
await this.localStorageService.setData(INIT_LIBS_AND_PACKAGES, true);
170-
const avrPackage = await this.boardsService.getBoardPackage({
171-
id: 'arduino:avr',
172-
});
173-
const builtInLibrary = (
174-
await this.libraryService.search({
175-
query: 'Arduino_BuiltIn',
176-
})
177-
)[0];
178-
179-
!!avrPackage && (await this.boardsService.install({ item: avrPackage }));
180-
!!builtInLibrary &&
181-
(await this.libraryService.install({
182-
item: builtInLibrary,
183-
installDependencies: true,
184-
}));
185-
}
186160
if (!window.navigator.onLine) {
187161
// tslint:disable-next-line:max-line-length
188162
this.messageService.warn(

Diff for: arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts

+2
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ import { WidgetManager as TheiaWidgetManager } from '@theia/core/lib/browser/wid
304304
import { StartupTask } from './widgets/sketchbook/startup-task';
305305
import { IndexesUpdateProgress } from './contributions/indexes-update-progress';
306306
import { Daemon } from './contributions/daemon';
307+
import { FirstStartupInstaller } from './contributions/first-startup-installer';
307308

308309
MonacoThemingService.register({
309310
id: 'arduino-theme',
@@ -699,6 +700,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
699700
Contribution.configure(bind, StartupTask);
700701
Contribution.configure(bind, IndexesUpdateProgress);
701702
Contribution.configure(bind, Daemon);
703+
Contribution.configure(bind, FirstStartupInstaller);
702704

703705
// Disabled the quick-pick customization from Theia when multiple formatters are available.
704706
// Use the default VS Code behavior, and pick the first one. In the IDE2, clang-format has `exclusive` selectors.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { LocalStorageService } from '@theia/core/lib/browser';
2+
import { inject, injectable } from '@theia/core/shared/inversify';
3+
import { BoardsService, LibraryService } from '../../common/protocol';
4+
import { Contribution } from './contribution';
5+
6+
@injectable()
7+
export class FirstStartupInstaller extends Contribution {
8+
@inject(LocalStorageService)
9+
private readonly localStorageService: LocalStorageService;
10+
@inject(BoardsService)
11+
private readonly boardsService: BoardsService;
12+
@inject(LibraryService)
13+
private readonly libraryService: LibraryService;
14+
15+
override async onReady(): Promise<void> {
16+
const isFirstStartup = !(await this.localStorageService.getData(
17+
FirstStartupInstaller.INIT_LIBS_AND_PACKAGES
18+
));
19+
if (isFirstStartup) {
20+
const avrPackage = await this.boardsService.getBoardPackage({
21+
id: 'arduino:avr',
22+
});
23+
const builtInLibrary = (
24+
await this.libraryService.search({ query: 'Arduino_BuiltIn' })
25+
)[0];
26+
27+
let avrPackageError: Error | undefined;
28+
let builtInLibraryError: Error | undefined;
29+
30+
if (avrPackage) {
31+
try {
32+
await this.boardsService.install({
33+
item: avrPackage,
34+
noOverwrite: true, // We don't want to automatically replace custom platforms the user might already have in place
35+
});
36+
} catch (e) {
37+
// There's no error code, I need to parse the error message: https://github.com/arduino/arduino-cli/commit/ffe4232b359fcfa87238d68acf1c3b64a1621f14#diff-10ffbdde46838dd9caa881fd1f2a5326a49f8061f6cfd7c9d430b4875a6b6895R62
38+
if (
39+
e.message.includes(
40+
`Platform ${avrPackage.id}@${avrPackage.installedVersion} already installed`
41+
)
42+
) {
43+
// If arduino:avr installation fails because it's already installed we don't want to retry on next start-up
44+
console.error(e);
45+
} else {
46+
// But if there is any other error (e.g.: no interntet cconnection), we want to retry next time
47+
avrPackageError = e;
48+
}
49+
}
50+
} else {
51+
avrPackageError = new Error('Could not find platform.');
52+
}
53+
54+
if (builtInLibrary) {
55+
try {
56+
await this.libraryService.install({
57+
item: builtInLibrary,
58+
installDependencies: true,
59+
noOverwrite: true, // We don't want to automatically replace custom libraries the user might already have in place
60+
});
61+
} catch (e) {
62+
// There's no error code, I need to parse the error message: https://github.com/arduino/arduino-cli/commit/2ea3608453b17b1157f8a1dc892af2e13e40f4f0#diff-1de7569144d4e260f8dde0e0d00a4e2a218c57966d583da1687a70d518986649R95
63+
if (/Library (.*) is already installed/.test(e.message)) {
64+
// If Arduino_BuiltIn installation fails because it's already installed we don't want to retry on next start-up
65+
console.log('error installing core', e);
66+
} else {
67+
// But if there is any other error (e.g.: no interntet cconnection), we want to retry next time
68+
builtInLibraryError = e;
69+
}
70+
}
71+
} else {
72+
builtInLibraryError = new Error('Could not find library');
73+
}
74+
75+
if (avrPackageError) {
76+
this.messageService.error(
77+
`Could not install Arduino AVR platform: ${avrPackageError}`
78+
);
79+
}
80+
if (builtInLibraryError) {
81+
this.messageService.error(
82+
`Could not install ${builtInLibrary.name} library: ${builtInLibraryError}`
83+
);
84+
}
85+
86+
if (!avrPackageError && !builtInLibraryError) {
87+
await this.localStorageService.setData(
88+
FirstStartupInstaller.INIT_LIBS_AND_PACKAGES,
89+
true
90+
);
91+
}
92+
}
93+
}
94+
}
95+
export namespace FirstStartupInstaller {
96+
export const INIT_LIBS_AND_PACKAGES = 'initializedLibsAndPackages';
97+
}

Diff for: arduino-ide-extension/src/common/protocol/installable.ts

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export interface Installable<T extends ArduinoComponent> {
1717
item: T;
1818
progressId?: string;
1919
version?: Installable.Version;
20+
noOverwrite?: boolean;
2021
}): Promise<void>;
2122

2223
/**

Diff for: arduino-ide-extension/src/common/protocol/library-service.ts

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export interface LibraryService
1616
progressId?: string;
1717
version?: Installable.Version;
1818
installDependencies?: boolean;
19+
noOverwrite?: boolean;
1920
}): Promise<void>;
2021
installZip(options: {
2122
zipUri: string;

Diff for: arduino-ide-extension/src/node/boards-service-impl.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@ export class BoardsServiceImpl
391391
item: BoardsPackage;
392392
progressId?: string;
393393
version?: Installable.Version;
394+
noOverwrite?: boolean;
394395
}): Promise<void> {
395396
const item = options.item;
396397
const version = !!options.version
@@ -406,6 +407,7 @@ export class BoardsServiceImpl
406407
req.setArchitecture(architecture);
407408
req.setPlatformPackage(platform);
408409
req.setVersion(version);
410+
req.setNoOverwrite(Boolean(options.noOverwrite));
409411

410412
console.info('>>> Starting boards package installation...', item);
411413

@@ -430,7 +432,7 @@ export class BoardsServiceImpl
430432
chunk: `Failed to install platform: ${item.id}.\n`,
431433
});
432434
this.responseService.appendToOutput({
433-
chunk: error.toString(),
435+
chunk: `${error.toString()}\n`,
434436
});
435437
reject(error);
436438
});

Diff for: arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/compile_pb.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ export class CompileRequest extends jspb.Message {
9595
getEncryptKey(): string;
9696
setEncryptKey(value: string): CompileRequest;
9797

98+
getSkipLibrariesDiscovery(): boolean;
99+
setSkipLibrariesDiscovery(value: boolean): CompileRequest;
100+
98101

99102
serializeBinary(): Uint8Array;
100103
toObject(includeInstance?: boolean): CompileRequest.AsObject;
@@ -133,6 +136,7 @@ export namespace CompileRequest {
133136
keysKeychain: string,
134137
signKey: string,
135138
encryptKey: string,
139+
skipLibrariesDiscovery: boolean,
136140
}
137141
}
138142

Diff for: arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/compile_pb.js

+31-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@ proto.cc.arduino.cli.commands.v1.CompileRequest.toObject = function(includeInsta
149149
libraryList: (f = jspb.Message.getRepeatedField(msg, 24)) == null ? undefined : f,
150150
keysKeychain: jspb.Message.getFieldWithDefault(msg, 25, ""),
151151
signKey: jspb.Message.getFieldWithDefault(msg, 26, ""),
152-
encryptKey: jspb.Message.getFieldWithDefault(msg, 27, "")
152+
encryptKey: jspb.Message.getFieldWithDefault(msg, 27, ""),
153+
skipLibrariesDiscovery: jspb.Message.getBooleanFieldWithDefault(msg, 28, false)
153154
};
154155

155156
if (includeInstance) {
@@ -286,6 +287,10 @@ proto.cc.arduino.cli.commands.v1.CompileRequest.deserializeBinaryFromReader = fu
286287
var value = /** @type {string} */ (reader.readString());
287288
msg.setEncryptKey(value);
288289
break;
290+
case 28:
291+
var value = /** @type {boolean} */ (reader.readBool());
292+
msg.setSkipLibrariesDiscovery(value);
293+
break;
289294
default:
290295
reader.skipField();
291296
break;
@@ -482,6 +487,13 @@ proto.cc.arduino.cli.commands.v1.CompileRequest.serializeBinaryToWriter = functi
482487
f
483488
);
484489
}
490+
f = message.getSkipLibrariesDiscovery();
491+
if (f) {
492+
writer.writeBool(
493+
28,
494+
f
495+
);
496+
}
485497
};
486498

487499

@@ -1016,6 +1028,24 @@ proto.cc.arduino.cli.commands.v1.CompileRequest.prototype.setEncryptKey = functi
10161028
};
10171029

10181030

1031+
/**
1032+
* optional bool skip_libraries_discovery = 28;
1033+
* @return {boolean}
1034+
*/
1035+
proto.cc.arduino.cli.commands.v1.CompileRequest.prototype.getSkipLibrariesDiscovery = function() {
1036+
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 28, false));
1037+
};
1038+
1039+
1040+
/**
1041+
* @param {boolean} value
1042+
* @return {!proto.cc.arduino.cli.commands.v1.CompileRequest} returns this
1043+
*/
1044+
proto.cc.arduino.cli.commands.v1.CompileRequest.prototype.setSkipLibrariesDiscovery = function(value) {
1045+
return jspb.Message.setProto3BooleanField(this, 28, value);
1046+
};
1047+
1048+
10191049

10201050
/**
10211051
* List of repeated fields within this message type.

Diff for: arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/core_pb.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ export class PlatformInstallRequest extends jspb.Message {
2626
getSkipPostInstall(): boolean;
2727
setSkipPostInstall(value: boolean): PlatformInstallRequest;
2828

29+
getNoOverwrite(): boolean;
30+
setNoOverwrite(value: boolean): PlatformInstallRequest;
31+
2932

3033
serializeBinary(): Uint8Array;
3134
toObject(includeInstance?: boolean): PlatformInstallRequest.AsObject;
@@ -44,6 +47,7 @@ export namespace PlatformInstallRequest {
4447
architecture: string,
4548
version: string,
4649
skipPostInstall: boolean,
50+
noOverwrite: boolean,
4751
}
4852
}
4953

Diff for: arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/core_pb.js

+31-1
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,8 @@ proto.cc.arduino.cli.commands.v1.PlatformInstallRequest.toObject = function(incl
339339
platformPackage: jspb.Message.getFieldWithDefault(msg, 2, ""),
340340
architecture: jspb.Message.getFieldWithDefault(msg, 3, ""),
341341
version: jspb.Message.getFieldWithDefault(msg, 4, ""),
342-
skipPostInstall: jspb.Message.getBooleanFieldWithDefault(msg, 5, false)
342+
skipPostInstall: jspb.Message.getBooleanFieldWithDefault(msg, 5, false),
343+
noOverwrite: jspb.Message.getBooleanFieldWithDefault(msg, 6, false)
343344
};
344345

345346
if (includeInstance) {
@@ -397,6 +398,10 @@ proto.cc.arduino.cli.commands.v1.PlatformInstallRequest.deserializeBinaryFromRea
397398
var value = /** @type {boolean} */ (reader.readBool());
398399
msg.setSkipPostInstall(value);
399400
break;
401+
case 6:
402+
var value = /** @type {boolean} */ (reader.readBool());
403+
msg.setNoOverwrite(value);
404+
break;
400405
default:
401406
reader.skipField();
402407
break;
@@ -462,6 +467,13 @@ proto.cc.arduino.cli.commands.v1.PlatformInstallRequest.serializeBinaryToWriter
462467
f
463468
);
464469
}
470+
f = message.getNoOverwrite();
471+
if (f) {
472+
writer.writeBool(
473+
6,
474+
f
475+
);
476+
}
465477
};
466478

467479

@@ -574,6 +586,24 @@ proto.cc.arduino.cli.commands.v1.PlatformInstallRequest.prototype.setSkipPostIns
574586
};
575587

576588

589+
/**
590+
* optional bool no_overwrite = 6;
591+
* @return {boolean}
592+
*/
593+
proto.cc.arduino.cli.commands.v1.PlatformInstallRequest.prototype.getNoOverwrite = function() {
594+
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 6, false));
595+
};
596+
597+
598+
/**
599+
* @param {boolean} value
600+
* @return {!proto.cc.arduino.cli.commands.v1.PlatformInstallRequest} returns this
601+
*/
602+
proto.cc.arduino.cli.commands.v1.PlatformInstallRequest.prototype.setNoOverwrite = function(value) {
603+
return jspb.Message.setProto3BooleanField(this, 6, value);
604+
};
605+
606+
577607

578608

579609

Diff for: arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/lib_pb.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ export class LibraryInstallRequest extends jspb.Message {
7979
getNoDeps(): boolean;
8080
setNoDeps(value: boolean): LibraryInstallRequest;
8181

82+
getNoOverwrite(): boolean;
83+
setNoOverwrite(value: boolean): LibraryInstallRequest;
84+
8285

8386
serializeBinary(): Uint8Array;
8487
toObject(includeInstance?: boolean): LibraryInstallRequest.AsObject;
@@ -96,6 +99,7 @@ export namespace LibraryInstallRequest {
9699
name: string,
97100
version: string,
98101
noDeps: boolean,
102+
noOverwrite: boolean,
99103
}
100104
}
101105

0 commit comments

Comments
 (0)