Skip to content

Commit b615149

Browse files
Expose loadExtension to fix double loading of packages (#2868)
* Expose loadExtension to fix double loading of packages In case you install extension, the method automatically loads it. However calling `loadExtensions` after that loads it again, so our `$injector` fails. In order to fix this, remove the loading from the `installExtension` method and expose `loadExtension(name)` method. So in the future in case someone wants to load a new an extension after calling `loadExtensions`, they'll be able to use the new method. * Update ios-device-lib Update `ios-device-lib` to 0.4.3. The new version includes a fix for long living processes where detaching iOS device causes a huge memory consuption and core dump.
1 parent a1867c8 commit b615149

File tree

7 files changed

+77
-38
lines changed

7 files changed

+77
-38
lines changed

PublicAPI.md

+27-2
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,12 @@ interface IExtensionData {
9494
```
9595
9696
### installExtension
97-
Installs specified extension and loads it in the current process, so the functionality that it adds can be used immediately.
97+
Installs specified extension.
9898
9999
* Definition:
100100
```TypeScript
101101
/**
102-
* Installs and loads specified extension.
102+
* Installs a specified extension.
103103
* @param {string} extensionName Name of the extension to be installed. It may contain version as well, i.e. myPackage, myPackage@1.0.0, myPackage.tgz, https://github.com/myOrganization/myPackage/tarball/master, https://github.com/myOrganization/myPackage etc.
104104
* @returns {Promise<IExtensionData>} Information about installed extensions.
105105
*/
@@ -180,6 +180,31 @@ for (let promise of loadExtensionsPromises) {
180180
}
181181
```
182182
183+
### loadExtension
184+
Loads a specified extension.
185+
186+
* Definition
187+
```TypeScript
188+
/**
189+
* Loads a single extension, so its methods and commands can be used from CLI.
190+
* @param {string} extensionName Name of the extension to be installed. It may contain version as well, i.e. myPackage, myPackage@1.0.0
191+
* A Promise is returned. It will be rejected in case the extension cannot be loaded.
192+
* @returns {Promise<IExtensionData>} Promise, resolved with IExtensionData.
193+
*/
194+
loadExtension(extensionName: string): Promise<IExtensionData>;
195+
```
196+
197+
* Usage:
198+
```JavaScript
199+
tns.extensibilityService.loadExtension("my-extension")
200+
.then(extensionData => console.log(`Loaded extension: ${extensionData.extensionName}.`),
201+
err => {
202+
console.log(`Failed to load extension: ${err.extensionName}`);
203+
console.log(err);
204+
});
205+
}
206+
```
207+
183208
## settingsService
184209
`settingsService` module provides a way to configure various settings.
185210

lib/commands/extensibility/install-extension.ts

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ export class InstallExtensionCommand implements ICommand {
66
public async execute(args: string[]): Promise<void> {
77
const extensionData = await this.$extensibilityService.installExtension(args[0]);
88
this.$logger.info(`Successfully installed extension ${extensionData.extensionName}.`);
9+
10+
await this.$extensibilityService.loadExtension(extensionData.extensionName);
11+
this.$logger.info(`Successfully loaded extension ${extensionData.extensionName}.`);
912
}
1013

1114
allowedParameters: ICommandParameter[] = [this.$stringParameterBuilder.createMandatoryParameter("You have to provide a valid name for extension that you want to install.")];

lib/definitions/extensibility.d.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ interface IExtensionData {
1313
*/
1414
interface IExtensibilityService {
1515
/**
16-
* Installs and loads specified extension.
16+
* Installs a specified extension.
1717
* @param {string} extensionName Name of the extension to be installed. It may contain version as well, i.e. myPackage, myPackage@1.0.0,
1818
* myPackage.tgz, https://github.com/myOrganization/myPackage/tarball/master, https://github.com/myOrganization/myPackage, etc.
1919
* @returns {Promise<IExtensionData>} Information about installed extensions.
@@ -35,6 +35,14 @@ interface IExtensibilityService {
3535
*/
3636
loadExtensions(): Promise<IExtensionData>[];
3737

38+
/**
39+
* Loads a single extension, so its methods and commands can be used from CLI.
40+
* @param {string} extensionName Name of the extension to be installed. It may contain version as well, i.e. myPackage, myPackage@1.0.0
41+
* A Promise is returned. It will be rejected in case the extension cannot be loaded.
42+
* @returns {Promise<IExtensionData>} Promise, resolved with IExtensionData.
43+
*/
44+
loadExtension(extensionName: string): Promise<IExtensionData>;
45+
3846
/**
3947
* Gets information about installed dependencies - names and versions.
4048
* @returns {IStringDictionary}

lib/services/extensibility-service.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export class ExtensibilityService implements IExtensibilityService {
3535
const installResultInfo = await this.$npm.install(packageName, this.pathToExtensions, npmOpts);
3636
this.$logger.trace(`Finished installation of extension '${extensionName}'. Trying to load it now.`);
3737

38-
return await this.loadExtension(installResultInfo.name);
38+
return { extensionName: installResultInfo.name };
3939
}
4040

4141
@exported("extensibilityService")
@@ -74,7 +74,8 @@ export class ExtensibilityService implements IExtensibilityService {
7474
return null;
7575
}
7676

77-
private async loadExtension(extensionName: string): Promise<IExtensionData> {
77+
@exported("extensibilityService")
78+
public async loadExtension(extensionName: string): Promise<IExtensionData> {
7879
try {
7980
await this.assertExtensionIsInstalled(extensionName);
8081

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
"glob": "^7.0.3",
4343
"iconv-lite": "0.4.11",
4444
"inquirer": "0.9.0",
45-
"ios-device-lib": "0.4.2",
45+
"ios-device-lib": "0.4.3",
4646
"ios-mobileprovision-finder": "1.0.9",
4747
"ios-sim-portable": "~3.0.0",
4848
"lockfile": "1.0.1",

test/nativescript-cli-lib.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ describe("nativescript-cli-lib", () => {
1919
localBuildService: ["build"],
2020
deviceLogProvider: null,
2121
npm: ["install", "uninstall", "view", "search"],
22-
extensibilityService: ["loadExtensions", "getInstalledExtensions", "installExtension", "uninstallExtension"],
22+
extensibilityService: ["loadExtensions", "loadExtension", "getInstalledExtensions", "installExtension", "uninstallExtension"],
2323
analyticsService: ["startEqatecMonitor"],
2424
debugService: ["debug"]
2525
};

test/services/extensibility-service.ts

+33-31
Original file line numberDiff line numberDiff line change
@@ -136,37 +136,6 @@ describe("extensibilityService", () => {
136136
const actualResult = await extensibilityService.installExtension(extensionName);
137137
assert.deepEqual(actualResult, { extensionName });
138138
});
139-
140-
it("throws error that has extensionName property when unable to load extension", async () => {
141-
const expectedErrorMessage = "Require failed";
142-
143-
const extensionName = "extension1";
144-
const testInjector = getTestInjector();
145-
const fs: IFileSystem = testInjector.resolve("fs");
146-
fs.exists = (pathToCheck: string): boolean => path.basename(pathToCheck) !== extensionName;
147-
148-
fs.readDirectory = (dir: string): string[] => [extensionName];
149-
150-
const npm: INodePackageManager = testInjector.resolve("npm");
151-
npm.install = async (packageName: string, pathToSave: string, config?: any): Promise<any> => ({ name: extensionName });
152-
153-
const requireService: IRequireService = testInjector.resolve("requireService");
154-
requireService.require = (pathToRequire: string) => {
155-
throw new Error(expectedErrorMessage);
156-
};
157-
158-
const extensibilityService: IExtensibilityService = testInjector.resolve(ExtensibilityService);
159-
let isErrorRaised = false;
160-
try {
161-
await extensibilityService.installExtension(extensionName);
162-
} catch (err) {
163-
isErrorRaised = true;
164-
assert.deepEqual(err.message, `Unable to load extension ${extensionName}. You will not be able to use the functionality that it adds.`);
165-
assert.deepEqual(err.extensionName, extensionName);
166-
}
167-
168-
assert.isTrue(isErrorRaised);
169-
});
170139
});
171140

172141
describe("loadExtensions", () => {
@@ -609,4 +578,37 @@ describe("extensibilityService", () => {
609578
assert.deepEqual(extensibilityService.getInstalledExtensions(), dependencies);
610579
});
611580
});
581+
582+
describe("loadExtension", () => {
583+
it("throws error that has extensionName property when unable to load extension", async () => {
584+
const expectedErrorMessage = "Require failed";
585+
586+
const extensionName = "extension1";
587+
const testInjector = getTestInjector();
588+
const fs: IFileSystem = testInjector.resolve("fs");
589+
fs.exists = (pathToCheck: string): boolean => path.basename(pathToCheck) !== extensionName;
590+
591+
fs.readDirectory = (dir: string): string[] => [extensionName];
592+
593+
const npm: INodePackageManager = testInjector.resolve("npm");
594+
npm.install = async (packageName: string, pathToSave: string, config?: any): Promise<any> => ({ name: extensionName });
595+
596+
const requireService: IRequireService = testInjector.resolve("requireService");
597+
requireService.require = (pathToRequire: string) => {
598+
throw new Error(expectedErrorMessage);
599+
};
600+
601+
const extensibilityService: IExtensibilityService = testInjector.resolve(ExtensibilityService);
602+
let isErrorRaised = false;
603+
try {
604+
await extensibilityService.loadExtension(extensionName);
605+
} catch (err) {
606+
isErrorRaised = true;
607+
assert.deepEqual(err.message, `Unable to load extension ${extensionName}. You will not be able to use the functionality that it adds.`);
608+
assert.deepEqual(err.extensionName, extensionName);
609+
}
610+
611+
assert.isTrue(isErrorRaised);
612+
});
613+
});
612614
});

0 commit comments

Comments
 (0)