Skip to content

Commit 7f3d735

Browse files
authored
Fix an error when importing extensions with dependencies (#9007)
1 parent f9998ee commit 7f3d735

4 files changed

Lines changed: 91 additions & 14 deletions

File tree

newIDE/app/src/AiGeneration/UseEnsureExtensionInstalled.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ export const useEnsureExtensionInstalled = ({
6161
extensionShortHeadersByNameToUse,
6262
extensionName
6363
);
64+
if (!extensionShortHeader) {
65+
throw new Error(
66+
'Unable to find extension ' + extensionName + ' in the registry.'
67+
);
68+
}
6469
const extensionShortHeaders: Array<ExtensionShortHeader> = [
6570
extensionShortHeader,
6671
];

newIDE/app/src/AssetStore/ExtensionStore/InstallExtension.js

Lines changed: 64 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export type RequiredExtensionInstallation = {|
4141
breakingChangesExtensionShortHeaders: Array<ExtensionShortHeader>,
4242
incompatibleWithIdeExtensionShortHeaders: Array<ExtensionShortHeader>,
4343
safeToUpdateExtensions: Array<ExtensionShortHeader>,
44+
unknownExtensionDependencies: Array<ExtensionDependency>,
4445
isGDevelopUpdateNeeded: boolean,
4546
|};
4647

@@ -78,13 +79,8 @@ export const getExtensionHeader = (
7879
[name: string]: ExtensionShortHeader,
7980
},
8081
extensionName: string
81-
): ExtensionShortHeader => {
82+
): ExtensionShortHeader | null => {
8283
const extensionShortHeader = extensionShortHeadersByName[extensionName];
83-
if (!extensionShortHeader) {
84-
throw new Error(
85-
'Unable to find extension ' + extensionName + ' in the registry.'
86-
);
87-
}
8884
return extensionShortHeader;
8985
};
9086

@@ -94,12 +90,14 @@ type CheckRequiredExtensionsArgs = {|
9490
extensionShortHeadersByName: {
9591
[name: string]: ExtensionShortHeader,
9692
},
93+
shouldAllowUnknownExtension?: boolean,
9794
|};
9895

9996
export const checkRequiredExtensionsUpdate = async ({
10097
requiredExtensions,
10198
project,
10299
extensionShortHeadersByName,
100+
shouldAllowUnknownExtension,
103101
}: CheckRequiredExtensionsArgs): Promise<RequiredExtensionInstallation> => {
104102
if (requiredExtensions.length === 0) {
105103
return {
@@ -109,17 +107,26 @@ export const checkRequiredExtensionsUpdate = async ({
109107
breakingChangesExtensionShortHeaders: [],
110108
incompatibleWithIdeExtensionShortHeaders: [],
111109
safeToUpdateExtensions: [],
110+
unknownExtensionDependencies: [],
112111
isGDevelopUpdateNeeded: false,
113112
};
114113
}
115114

116-
const requiredExtensionShortHeaders = requiredExtensions.map(
117-
requiredExtension =>
118-
getExtensionHeader(
119-
extensionShortHeadersByName,
120-
requiredExtension.extensionName
121-
)
122-
);
115+
const requiredExtensionShortHeaders: Array<ExtensionShortHeader> = [];
116+
const unknownExtensionDependencies: Array<ExtensionDependency> = [];
117+
for (const requiredExtension of requiredExtensions) {
118+
const extensionShortHeader = getExtensionHeader(
119+
extensionShortHeadersByName,
120+
requiredExtension.extensionName
121+
);
122+
if (extensionShortHeader) {
123+
requiredExtensionShortHeaders.push(extensionShortHeader);
124+
} else if (
125+
!project.hasEventsFunctionsExtensionNamed(requiredExtension.extensionName)
126+
) {
127+
unknownExtensionDependencies.push(requiredExtension);
128+
}
129+
}
123130

124131
// Add extensions dependencies
125132
for (let i = 0; i < requiredExtensionShortHeaders.length; i++) {
@@ -139,10 +146,28 @@ export const checkRequiredExtensionsUpdate = async ({
139146
extensionShortHeadersByName,
140147
requiredExtension.extensionName
141148
);
142-
requiredExtensionShortHeaders.push(extensionShortHeader);
149+
if (extensionShortHeader) {
150+
requiredExtensionShortHeaders.push(extensionShortHeader);
151+
} else if (
152+
!project.hasEventsFunctionsExtensionNamed(
153+
requiredExtension.extensionName
154+
)
155+
) {
156+
unknownExtensionDependencies.push(requiredExtension);
157+
}
143158
}
144159
}
145160

161+
if (!shouldAllowUnknownExtension && unknownExtensionDependencies.length > 0) {
162+
throw new Error(
163+
'Unable to find extension ' +
164+
unknownExtensionDependencies
165+
.map(dependency => dependency.extensionName)
166+
.join(', ') +
167+
' in the registry.'
168+
);
169+
}
170+
146171
const incompatibleWithIdeExtensionShortHeaders = requiredExtensionShortHeaders.filter(
147172
requiredExtensionShortHeader =>
148173
!isCompatibleWithGDevelopVersion(
@@ -197,6 +222,7 @@ export const checkRequiredExtensionsUpdate = async ({
197222
breakingChangesExtensionShortHeaders,
198223
incompatibleWithIdeExtensionShortHeaders,
199224
safeToUpdateExtensions,
225+
unknownExtensionDependencies,
200226
isGDevelopUpdateNeeded,
201227
};
202228
};
@@ -526,6 +552,11 @@ export const addSerializedExtensionsToProject = async (
526552
return;
527553
};
528554

555+
const formatDependency = (dependency: ExtensionDependency) =>
556+
dependency.extensionVersion.length > 0
557+
? dependency.extensionName + '-' + dependency.extensionVersion
558+
: dependency.extensionName;
559+
529560
/**
530561
* Open a dialog to choose an extension and install it in the project.
531562
*/
@@ -637,8 +668,27 @@ export const useImportExtension = (): (({
637668
requiredExtensions,
638669
project,
639670
extensionShortHeadersByName,
671+
shouldAllowUnknownExtension: importedExtensionNames.length > 0,
640672
}
641673
);
674+
if (
675+
requiredExtensionInstallation.unknownExtensionDependencies.length > 0
676+
) {
677+
if (skipUserPrompts) {
678+
throw new Error(
679+
'The extension cannot be imported because it has unknown dependencies: ' +
680+
requiredExtensionInstallation.unknownExtensionDependencies
681+
.map(formatDependency)
682+
.join(', ')
683+
);
684+
}
685+
await showAlert({
686+
title: t`Missing dependencies`,
687+
message: t`The extension cannot be imported because it has unknown dependencies: ${requiredExtensionInstallation.unknownExtensionDependencies
688+
.map(formatDependency)
689+
.join(', ')}`,
690+
});
691+
}
642692
const isNotImportedExtension = (
643693
extensionShortHeader: ExtensionShortHeader
644694
) => !importedExtensionNames.includes(extensionShortHeader.name);

newIDE/app/src/AssetStore/InstallAsset.spec.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,7 @@ describe('InstallAsset', () => {
431431
breakingChangesExtensionShortHeaders: [],
432432
incompatibleWithIdeExtensionShortHeaders: [],
433433
safeToUpdateExtensions: [],
434+
unknownExtensionDependencies: [],
434435
isGDevelopUpdateNeeded: false,
435436
});
436437
});
@@ -463,6 +464,7 @@ describe('InstallAsset', () => {
463464
breakingChangesExtensionShortHeaders: [],
464465
incompatibleWithIdeExtensionShortHeaders: [],
465466
safeToUpdateExtensions: [],
467+
unknownExtensionDependencies: [],
466468
isGDevelopUpdateNeeded: false,
467469
});
468470
});
@@ -495,6 +497,7 @@ describe('InstallAsset', () => {
495497
breakingChangesExtensionShortHeaders: [],
496498
incompatibleWithIdeExtensionShortHeaders: [],
497499
safeToUpdateExtensions: [buttonV2ExtensionShortHeader],
500+
unknownExtensionDependencies: [],
498501
isGDevelopUpdateNeeded: false,
499502
});
500503
});
@@ -529,6 +532,7 @@ describe('InstallAsset', () => {
529532
],
530533
incompatibleWithIdeExtensionShortHeaders: [],
531534
safeToUpdateExtensions: [],
535+
unknownExtensionDependencies: [],
532536
isGDevelopUpdateNeeded: false,
533537
});
534538
});
@@ -568,6 +572,7 @@ describe('InstallAsset', () => {
568572
incompatibleButtonV4ExtensionShortHeader,
569573
],
570574
safeToUpdateExtensions: [],
575+
unknownExtensionDependencies: [],
571576
isGDevelopUpdateNeeded: false,
572577
});
573578
});
@@ -602,6 +607,7 @@ describe('InstallAsset', () => {
602607
incompatibleFlashExtensionShortHeader,
603608
],
604609
safeToUpdateExtensions: [],
610+
unknownExtensionDependencies: [],
605611
isGDevelopUpdateNeeded: true,
606612
});
607613
});
@@ -665,6 +671,7 @@ describe('InstallAsset', () => {
665671
breakingChangesExtensionShortHeaders: [],
666672
incompatibleWithIdeExtensionShortHeaders: [],
667673
safeToUpdateExtensions: [],
674+
unknownExtensionDependencies: [],
668675
isGDevelopUpdateNeeded: false,
669676
});
670677
});
@@ -700,6 +707,7 @@ describe('InstallAsset', () => {
700707
breakingChangesExtensionShortHeaders: [],
701708
incompatibleWithIdeExtensionShortHeaders: [],
702709
safeToUpdateExtensions: [],
710+
unknownExtensionDependencies: [],
703711
isGDevelopUpdateNeeded: false,
704712
});
705713
});
@@ -735,6 +743,7 @@ describe('InstallAsset', () => {
735743
breakingChangesExtensionShortHeaders: [],
736744
incompatibleWithIdeExtensionShortHeaders: [],
737745
safeToUpdateExtensions: [buttonV2ExtensionShortHeader],
746+
unknownExtensionDependencies: [],
738747
isGDevelopUpdateNeeded: false,
739748
});
740749
});
@@ -772,6 +781,7 @@ describe('InstallAsset', () => {
772781
],
773782
incompatibleWithIdeExtensionShortHeaders: [],
774783
safeToUpdateExtensions: [],
784+
unknownExtensionDependencies: [],
775785
isGDevelopUpdateNeeded: false,
776786
});
777787
});
@@ -813,6 +823,7 @@ describe('InstallAsset', () => {
813823
incompatibleButtonV4ExtensionShortHeader,
814824
],
815825
safeToUpdateExtensions: [],
826+
unknownExtensionDependencies: [],
816827
isGDevelopUpdateNeeded: true,
817828
});
818829
});
@@ -851,6 +862,7 @@ describe('InstallAsset', () => {
851862
incompatibleFlashExtensionShortHeader,
852863
],
853864
safeToUpdateExtensions: [],
865+
unknownExtensionDependencies: [],
854866
isGDevelopUpdateNeeded: true,
855867
});
856868
});
@@ -1001,6 +1013,7 @@ describe('InstallAsset', () => {
10011013
breakingChangesExtensionShortHeaders: [],
10021014
incompatibleWithIdeExtensionShortHeaders: [],
10031015
safeToUpdateExtensions: [],
1016+
unknownExtensionDependencies: [],
10041017
isGDevelopUpdateNeeded: false,
10051018
},
10061019
shouldUpdateExtension: true,
@@ -1039,6 +1052,7 @@ describe('InstallAsset', () => {
10391052
breakingChangesExtensionShortHeaders: [],
10401053
incompatibleWithIdeExtensionShortHeaders: [],
10411054
safeToUpdateExtensions: [],
1055+
unknownExtensionDependencies: [],
10421056
isGDevelopUpdateNeeded: false,
10431057
},
10441058
shouldUpdateExtension: true,
@@ -1082,6 +1096,7 @@ describe('InstallAsset', () => {
10821096
breakingChangesExtensionShortHeaders: [],
10831097
incompatibleWithIdeExtensionShortHeaders: [],
10841098
safeToUpdateExtensions: [],
1099+
unknownExtensionDependencies: [],
10851100
isGDevelopUpdateNeeded: false,
10861101
},
10871102
shouldUpdateExtension: true,

newIDE/app/src/BehaviorsEditor/NewBehaviorDialog.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,13 @@ export default function NewBehaviorDialog({
227227
extensionShortHeadersByName,
228228
behaviorShortHeader.extensionName
229229
);
230+
if (!extensionShortHeader) {
231+
throw new Error(
232+
'Unable to find extension ' +
233+
behaviorShortHeader.extensionName +
234+
' in the registry.'
235+
);
236+
}
230237
if (
231238
!requiredExtensionInstallation.missingExtensionShortHeaders.includes(
232239
extensionShortHeader

0 commit comments

Comments
 (0)