Skip to content

Commit bbcf9bc

Browse files
Merge pull request #3562 from NativeScript/vladimirov/build-plugin-hooks
fix: Build plugins when path to project has space
2 parents 238eb06 + b7ae6dd commit bbcf9bc

File tree

3 files changed

+66
-32
lines changed

3 files changed

+66
-32
lines changed

lib/definitions/android-plugin-migrator.d.ts

+22
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,25 @@ interface IAndroidPluginBuildService {
1313
buildAar(options: IBuildOptions): Promise<boolean>;
1414
migrateIncludeGradle(options: IBuildOptions): boolean;
1515
}
16+
17+
/**
18+
* Describes data required for building plugin for Android.
19+
* The data can be consumed in the buildAndroidPlugin hook.
20+
*/
21+
interface IBuildAndroidPluginData {
22+
/**
23+
* Directory where the plugin will be build.
24+
* Usually this is the `<project dir>/platforms/tempPlugin/<plugin name>` dir.
25+
*/
26+
pluginDir: string;
27+
28+
/**
29+
* The name of the plugin.
30+
*/
31+
pluginName: string;
32+
33+
/**
34+
* Information about tools that will be used to build the plugin, for example compile SDK version, build tools version, etc.
35+
*/
36+
androidToolsInfo: IAndroidToolsInfoData;
37+
}

lib/services/android-plugin-build-service.ts

+31-24
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
import * as path from "path";
22
import { MANIFEST_FILE_NAME, INCLUDE_GRADLE_NAME, ASSETS_DIR, RESOURCES_DIR } from "../constants";
3-
import { getShortPluginName } from "../common/helpers";
3+
import { getShortPluginName, hook } from "../common/helpers";
44
import { Builder, parseString } from "xml2js";
55
import { ILogger } from "log4js";
66

77
export class AndroidPluginBuildService implements IAndroidPluginBuildService {
88

9-
constructor(private $fs: IFileSystem,
9+
/**
10+
* Required for hooks execution to work.
11+
*/
12+
private get $hooksService(): IHooksService {
13+
return this.$injector.resolve("hooksService");
14+
}
15+
16+
constructor(private $injector: IInjector,
17+
private $fs: IFileSystem,
1018
private $childProcess: IChildProcess,
1119
private $hostInfo: IHostInfo,
1220
private $androidToolsInfo: IAndroidToolsInfo,
@@ -240,30 +248,9 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService {
240248
}
241249

242250
// finally build the plugin
243-
const gradlew = this.$hostInfo.isWindows ? "gradlew.bat" : "./gradlew";
244-
const localArgs = [
245-
gradlew,
246-
"-p",
247-
newPluginDir,
248-
"assembleRelease"
249-
];
250-
251251
this.$androidToolsInfo.validateInfo({ showWarningsAsErrors: true, validateTargetSdk: true });
252-
253252
const androidToolsInfo = this.$androidToolsInfo.getToolsInfo();
254-
const compileSdk = androidToolsInfo.compileSdkVersion;
255-
const buildToolsVersion = androidToolsInfo.buildToolsVersion;
256-
const supportVersion = androidToolsInfo.supportRepositoryVersion;
257-
258-
localArgs.push(`-PcompileSdk=android-${compileSdk}`);
259-
localArgs.push(`-PbuildToolsVersion=${buildToolsVersion}`);
260-
localArgs.push(`-PsupportVersion=${supportVersion}`);
261-
262-
try {
263-
await this.$childProcess.exec(localArgs.join(" "), { cwd: newPluginDir });
264-
} catch (err) {
265-
throw new Error(`Failed to build plugin ${options.pluginName} : \n${err}`);
266-
}
253+
await this.buildPlugin( { pluginDir: newPluginDir, pluginName: options.pluginName, androidToolsInfo });
267254

268255
const finalAarName = `${shortPluginName}-release.aar`;
269256
const pathToBuiltAar = path.join(newPluginDir, "build", "outputs", "aar", finalAarName);
@@ -318,6 +305,26 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService {
318305
return false;
319306
}
320307

308+
@hook("buildAndroidPlugin")
309+
private async buildPlugin(pluginBuildSettings: IBuildAndroidPluginData): Promise<void> {
310+
const gradlew = this.$hostInfo.isWindows ? "gradlew.bat" : "./gradlew";
311+
312+
const localArgs = [
313+
"-p",
314+
pluginBuildSettings.pluginDir,
315+
"assembleRelease",
316+
`-PcompileSdk=android-${pluginBuildSettings.androidToolsInfo.compileSdkVersion}`,
317+
`-PbuildToolsVersion=${pluginBuildSettings.androidToolsInfo.buildToolsVersion}`,
318+
`-PsupportVersion=${pluginBuildSettings.androidToolsInfo.supportRepositoryVersion}`
319+
];
320+
321+
try {
322+
await this.$childProcess.spawnFromEvent(gradlew, localArgs, "close", { cwd: pluginBuildSettings.pluginDir });
323+
} catch (err) {
324+
throw new Error(`Failed to build plugin ${pluginBuildSettings.pluginName} : \n${err}`);
325+
}
326+
}
327+
321328
private validateOptions(options: IBuildOptions): void {
322329
if (!options) {
323330
throw new Error("Android plugin cannot be built without passing an 'options' object.");

test/services/android-plugin-build-service.ts

+13-8
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,15 @@ temp.track();
1212

1313
describe('androiPluginBuildService', () => {
1414

15-
let execCalled = false;
15+
let spawnFromEventCalled = false;
1616
const createTestInjector = (): IInjector => {
1717
const testInjector = new Yok();
1818

1919
testInjector.register("fs", FsLib.FileSystem);
2020
testInjector.register("childProcess", {
21-
exec: () => {
22-
execCalled = true;
21+
spawnFromEvent: async (command: string, args: string[], event: string, options?: any, spawnFromEventOptions?: ISpawnFromEventOptions): Promise<ISpawnResult> => {
22+
spawnFromEventCalled = command.indexOf("gradlew") !== -1;
23+
return null;
2324
}
2425
});
2526
testInjector.register("hostInfo", HostInfo);
@@ -36,6 +37,10 @@ describe('androiPluginBuildService', () => {
3637
testInjector.register("options", {});
3738
testInjector.register("config", {});
3839
testInjector.register("staticConfig", {});
40+
testInjector.register("hooksService", {
41+
executeBeforeHooks: async (commandName: string, hookArguments?: IDictionary<any>): Promise<void> => undefined,
42+
executeAfterHooks: async (commandName: string, hookArguments?: IDictionary<any>): Promise<void> => undefined
43+
});
3944

4045
return testInjector;
4146
};
@@ -107,7 +112,7 @@ dependencies {
107112
});
108113

109114
beforeEach(() => {
110-
execCalled = false;
115+
spawnFromEventCalled = false;
111116
});
112117

113118
describe('builds aar', () => {
@@ -127,7 +132,7 @@ dependencies {
127132
/* intentionally left blank */
128133
}
129134

130-
assert.isTrue(execCalled);
135+
assert.isTrue(spawnFromEventCalled);
131136
});
132137

133138
it('if android manifest is missing', async () => {
@@ -145,7 +150,7 @@ dependencies {
145150
/* intentionally left blank */
146151
}
147152

148-
assert.isTrue(execCalled);
153+
assert.isTrue(spawnFromEventCalled);
149154
});
150155

151156
it('if there is only an android manifest file', async () => {
@@ -163,7 +168,7 @@ dependencies {
163168
/* intentionally left blank */
164169
}
165170

166-
assert.isTrue(execCalled);
171+
assert.isTrue(spawnFromEventCalled);
167172
});
168173
});
169174

@@ -183,7 +188,7 @@ dependencies {
183188
/* intentionally left blank */
184189
}
185190

186-
assert.isFalse(execCalled);
191+
assert.isFalse(spawnFromEventCalled);
187192
});
188193
});
189194

0 commit comments

Comments
 (0)