Skip to content

Commit b0cf146

Browse files
Merge pull request #5166 from NativeScript/vladimirov/fix-pod-prepare
fix: prepare of pods should work on case-sensitive systems
2 parents 998940f + affc727 commit b0cf146

File tree

6 files changed

+80
-110
lines changed

6 files changed

+80
-110
lines changed

lib/controllers/preview-app-controller.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export class PreviewAppController extends EventEmitter implements IPreviewAppCon
138138
@performanceLog()
139139
private async handlePrepareReadyEvent(data: IPreviewAppLiveSyncData, currentPrepareData: IFilesChangeEventData) {
140140
const { hmrData, files, platform } = currentPrepareData;
141-
const platformHmrData = _.cloneDeep(hmrData);
141+
const platformHmrData = _.cloneDeep(hmrData) || <IPlatformHmrData>{};
142142
const connectedDevices = this.$previewDevicesService.getDevicesForPlatform(platform);
143143
if (!connectedDevices || !connectedDevices.length) {
144144
this.$logger.warn(`Unable to find any connected devices for platform '${platform}'. In order to execute live sync, open your Preview app and optionally re-scan the QR code using the Playground app.`);

lib/definitions/plugins.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ interface IBasePluginData {
3535
}
3636

3737
interface IPluginData extends INodeModuleData {
38-
platformsDataService: IPluginPlatformsData;
38+
platformsData: IPluginPlatformsData;
3939
/* Gets all plugin variables from plugin */
4040
pluginVariables: IDictionary<IPluginVariableData>;
4141
pluginPlatformsFolderPath(platform: string): string;

lib/services/plugins-service.ts

+6-7
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,8 @@ export class PluginsService implements IPluginsService {
115115
}
116116
}
117117

118-
public async preparePluginNativeCode({pluginData, platform, projectData}: IPreparePluginNativeCodeData): Promise<void> {
118+
public async preparePluginNativeCode({ pluginData, platform, projectData }: IPreparePluginNativeCodeData): Promise<void> {
119119
const platformData = this.$platformsDataService.getPlatformData(platform, projectData);
120-
pluginData.pluginPlatformsFolderPath = (_platform: string) => path.join(pluginData.fullPath, "platforms", _platform.toLowerCase());
121120

122121
const pluginPlatformsFolderPath = pluginData.pluginPlatformsFolderPath(platform);
123122
if (this.$fs.exists(pluginPlatformsFolderPath)) {
@@ -213,18 +212,18 @@ export class PluginsService implements IPluginsService {
213212
pluginData.version = cacheData.version;
214213
pluginData.fullPath = cacheData.directory || path.dirname(this.getPackageJsonFilePathForModule(cacheData.name, projectDir));
215214
pluginData.isPlugin = !!cacheData.nativescript || !!cacheData.moduleInfo;
216-
pluginData.pluginPlatformsFolderPath = (platform: string) => path.join(pluginData.fullPath, "platforms", platform);
215+
pluginData.pluginPlatformsFolderPath = (platform: string) => path.join(pluginData.fullPath, "platforms", platform.toLowerCase());
217216
const data = cacheData.nativescript || cacheData.moduleInfo;
218217

219218
if (pluginData.isPlugin) {
220-
pluginData.platformsDataService = data.platforms;
219+
pluginData.platformsData = data.platforms;
221220
pluginData.pluginVariables = data.variables;
222221
}
223222

224223
return pluginData;
225224
}
226225

227-
private removeDependencyFromPackageJsonContent(dependency: string, packageJsonContent: Object): {hasModifiedPackageJson: boolean, packageJsonContent: Object} {
226+
private removeDependencyFromPackageJsonContent(dependency: string, packageJsonContent: Object): { hasModifiedPackageJson: boolean, packageJsonContent: Object } {
228227
let hasModifiedPackageJson = false;
229228

230229
if (packageJsonContent.devDependencies && packageJsonContent.devDependencies[dependency]) {
@@ -260,7 +259,7 @@ export class PluginsService implements IPluginsService {
260259

261260
private getPackageJsonFilePathForModule(moduleName: string, projectDir: string): string {
262261
const pathToJsonFile = require.resolve(`${moduleName}/package.json`, {
263-
paths: [projectDir]
262+
paths: [projectDir]
264263
});
265264
return pathToJsonFile;
266265
}
@@ -333,7 +332,7 @@ export class PluginsService implements IPluginsService {
333332
let isValid = true;
334333

335334
const installedFrameworkVersion = this.getInstalledFrameworkVersion(platform, projectData);
336-
const pluginPlatformsData = pluginData.platformsDataService;
335+
const pluginPlatformsData = pluginData.platformsData;
337336
if (pluginPlatformsData) {
338337
const versionRequiredByPlugin = (<any>pluginPlatformsData)[platform];
339338
if (!versionRequiredByPlugin) {

test/ios-project-service.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -879,8 +879,9 @@ describe("handleNativeDependenciesChange", () => {
879879
it("ensure the correct order of pod install and merging pod's xcconfig file", async () => {
880880
const executedCocoapodsMethods: string[] = [];
881881
const projectPodfilePath = "my/test/project/platforms/ios/Podfile";
882+
const dir = temp.mkdirSync("myTestProjectPath");
882883

883-
const testInjector = createTestInjector("myTestProjectPath", "myTestProjectName");
884+
const testInjector = createTestInjector(dir, "myTestProjectName");
884885
const iOSProjectService = testInjector.resolve("iOSProjectService");
885886
const projectData = testInjector.resolve("projectData");
886887

test/plugins-service.ts

+68-99
Original file line numberDiff line numberDiff line change
@@ -207,31 +207,6 @@ async function addPluginWhenExpectingToFail(testInjector: IInjector, plugin: str
207207
assert.isTrue(isErrorThrown);
208208
}
209209

210-
function createAndroidManifestFile(projectFolder: string, fs: IFileSystem): void {
211-
const manifest = `
212-
<?xml version="1.0" encoding="UTF-8"?>
213-
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.basiccontactables" android:versionCode="1" android:versionName="1.0" >
214-
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
215-
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
216-
<uses-permission android:name="android.permission.INTERNET"/>
217-
<application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/Theme.Sample" >
218-
<activity android:name="com.example.android.basiccontactables.MainActivity" android:label="@string/app_name" android:launchMode="singleTop">
219-
<meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />
220-
<intent-filter>
221-
<action android:name="android.intent.action.SEARCH" />
222-
</intent-filter>
223-
<intent-filter>
224-
<action android:name="android.intent.action.MAIN" />
225-
</intent-filter>
226-
</activity>
227-
</application>
228-
</manifest>`;
229-
230-
fs.createDirectory(path.join(projectFolder, "platforms"));
231-
fs.createDirectory(path.join(projectFolder, "platforms", "android"));
232-
fs.writeFile(path.join(projectFolder, "platforms", "android", "AndroidManifest.xml"), manifest);
233-
}
234-
235210
describe("Plugins service", () => {
236211
let testInjector: IInjector;
237212
const commands = ["add", "install"];
@@ -505,76 +480,6 @@ describe("Plugins service", () => {
505480
});
506481
});
507482

508-
describe("merge xmls tests", () => {
509-
beforeEach(() => {
510-
testInjector = createTestInjector();
511-
testInjector.registerCommand("plugin|add", AddPluginCommand);
512-
});
513-
it("fails if the plugin contains incorrect xml", async () => {
514-
const pluginName = "mySamplePlugin";
515-
const projectFolder = createProjectFile(testInjector);
516-
const pluginFolderPath = path.join(projectFolder, pluginName);
517-
const pluginJsonData: IDependencyData = {
518-
name: pluginName,
519-
nativescript: {
520-
platforms: {
521-
android: "0.10.0"
522-
}
523-
},
524-
depth: 0,
525-
directory: "some dir"
526-
};
527-
const fs = testInjector.resolve("fs");
528-
fs.writeJson(path.join(pluginFolderPath, "package.json"), pluginJsonData);
529-
530-
// Adds AndroidManifest.xml file in platforms/android folder
531-
createAndroidManifestFile(projectFolder, fs);
532-
533-
// Mock plugins service
534-
const pluginsService: IPluginsService = testInjector.resolve("pluginsService");
535-
pluginsService.getAllInstalledPlugins = async (pData: IProjectData) => {
536-
return <any[]>[{ name: "" }];
537-
};
538-
539-
const appDestinationDirectoryPath = path.join(projectFolder, "platforms", "android");
540-
541-
// Mock platformsDataService
542-
const platformsDataService = testInjector.resolve("platformsDataService");
543-
platformsDataService.getPlatformData = (platform: string) => {
544-
return {
545-
appDestinationDirectoryPath: appDestinationDirectoryPath,
546-
frameworkPackageName: "tns-android",
547-
configurationFileName: "AndroidManifest.xml",
548-
normalizedPlatformName: "Android",
549-
platformProjectService: {
550-
preparePluginNativeCode: (pluginData: IPluginData) => Promise.resolve()
551-
}
552-
};
553-
};
554-
555-
// Ensure the pluginDestinationPath folder exists
556-
const pluginPlatformsDirPath = path.join(projectFolder, "node_modules", pluginName, "platforms", "android");
557-
const projectData: IProjectData = testInjector.resolve("projectData");
558-
projectData.initializeProjectData();
559-
fs.ensureDirectoryExists(pluginPlatformsDirPath);
560-
561-
// Creates invalid plugin's AndroidManifest.xml file
562-
const xml = '<?xml version="1.0" encoding="UTF-8"?>' +
563-
'<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.basiccontactables" android:versionCode="1" android:versionName="1.0" >' +
564-
'<uses-permission android:name="android.permission.READ_CONTACTS"/>';
565-
const pluginConfigurationFilePath = path.join(pluginPlatformsDirPath, "AndroidManifest.xml");
566-
fs.writeFile(pluginConfigurationFilePath, xml);
567-
568-
// Expected error message. The assertion happens in mockBeginCommand
569-
const expectedErrorMessage = `Exception: Invalid xml file ${pluginConfigurationFilePath}. Additional technical information: element parse error: Exception: Invalid xml file ` +
570-
`${pluginConfigurationFilePath}. Additional technical information: unclosed xml attribute` +
571-
`\n@#[line:1,col:39].` +
572-
`\n@#[line:1,col:39].`;
573-
mockBeginCommand(testInjector, expectedErrorMessage);
574-
await pluginsService.preparePluginNativeCode({pluginData: pluginsService.convertToPluginData(pluginJsonData, projectData.projectDir), platform: "android", projectData});
575-
});
576-
});
577-
578483
describe("preparePluginNativeCode", () => {
579484
const setupTest = (opts: { hasChangesInShasums?: boolean, newPluginHashes?: IStringDictionary, buildDataFileExists?: boolean, hasPluginPlatformsDir?: boolean }): any => {
580485
const testData: any = {
@@ -599,7 +504,8 @@ describe("Plugins service", () => {
599504
const pluginHashes = opts.newPluginHashes || { "file1": "hash1" };
600505
const samplePluginData: IPluginData = <any>{
601506
fullPath: "plugin_full_path",
602-
name: "plugin_name"
507+
name: "plugin_name",
508+
pluginPlatformsFolderPath: (_platform: string) => path.join("plugin_dir", "platforms", _platform.toLowerCase())
603509
};
604510

605511
unitTestsInjector.register("filesHashService", {
@@ -646,22 +552,85 @@ describe("Plugins service", () => {
646552

647553
it("does not prepare the files when plugin does not have platforms dir", async () => {
648554
const testData = setupTest({ hasPluginPlatformsDir: false });
649-
await testData.pluginsService.preparePluginNativeCode({pluginData: testData.pluginData, platform, projectData});
555+
await testData.pluginsService.preparePluginNativeCode({ pluginData: testData.pluginData, platform, projectData });
650556
assert.isFalse(testData.isPreparePluginNativeCodeCalled);
651557
});
652558

653559
it("prepares the files when plugin has platforms dir and has not been built before", async () => {
654560
const newPluginHashes = { "file": "hash" };
655561
const testData = setupTest({ newPluginHashes, hasPluginPlatformsDir: true });
656-
await testData.pluginsService.preparePluginNativeCode({pluginData: testData.pluginData, platform, projectData});
562+
await testData.pluginsService.preparePluginNativeCode({ pluginData: testData.pluginData, platform, projectData });
657563
assert.isTrue(testData.isPreparePluginNativeCodeCalled);
658564
assert.deepEqual(testData.dataPassedToWriteJson, { [testData.pluginData.name]: newPluginHashes });
659565
});
660566

661567
it("does not prepare the files when plugin has platforms dir and files have not changed since then", async () => {
662568
const testData = setupTest({ hasChangesInShasums: false, buildDataFileExists: true, hasPluginPlatformsDir: true });
663-
await testData.pluginsService.preparePluginNativeCode({pluginData: testData.pluginData, platform, projectData});
569+
await testData.pluginsService.preparePluginNativeCode({ pluginData: testData.pluginData, platform, projectData });
664570
assert.isFalse(testData.isPreparePluginNativeCodeCalled);
665571
});
666572
});
573+
574+
describe("convertToPluginData", () => {
575+
const createUnitTestsInjector = () => {
576+
const unitTestsInjector = new Yok();
577+
unitTestsInjector.register("platformsDataService", {});
578+
unitTestsInjector.register("filesHashService", {});
579+
unitTestsInjector.register("fs", {});
580+
unitTestsInjector.register("packageManager", {});
581+
unitTestsInjector.register("options", {});
582+
unitTestsInjector.register("logger", {});
583+
unitTestsInjector.register("errors", {});
584+
unitTestsInjector.register("injector", unitTestsInjector);
585+
unitTestsInjector.register("mobileHelper", MobileHelper);
586+
unitTestsInjector.register("devicePlatformsConstants", DevicePlatformsConstants);
587+
unitTestsInjector.register("nodeModulesDependenciesBuilder", {});
588+
return unitTestsInjector;
589+
};
590+
591+
const pluginDir = "pluginDir";
592+
const dataFromPluginPackageJson = {
593+
name: "name",
594+
version: "1.0.0",
595+
directory: pluginDir,
596+
nativescript: {
597+
platforms: {
598+
ios: "6.0.0",
599+
android: "6.0.0"
600+
}
601+
}
602+
};
603+
604+
it("returns correct pluginData", () => {
605+
const unitTestsInjector = createUnitTestsInjector();
606+
const pluginsService: PluginsService = unitTestsInjector.resolve(PluginsService);
607+
const pluginData = pluginsService.convertToPluginData(dataFromPluginPackageJson, "my project dir");
608+
// Remove the comparison of a function
609+
delete pluginData["pluginPlatformsFolderPath"];
610+
assert.deepEqual(pluginData, <any>{
611+
name: "name",
612+
version: "1.0.0",
613+
fullPath: pluginDir,
614+
isPlugin: true,
615+
platformsData: { android: "6.0.0", ios: "6.0.0" },
616+
pluginVariables: undefined
617+
});
618+
});
619+
620+
it("always returns lowercased platform in the path to plugins dir", () => {
621+
const unitTestsInjector = createUnitTestsInjector();
622+
const pluginsService: PluginsService = unitTestsInjector.resolve(PluginsService);
623+
const pluginData = pluginsService.convertToPluginData(dataFromPluginPackageJson, "my project dir");
624+
625+
const expectediOSPath = path.join(pluginDir, "platforms", "ios");
626+
const expectedAndroidPath = path.join(pluginDir, "platforms", "android");
627+
assert.equal(pluginData.pluginPlatformsFolderPath("iOS"), expectediOSPath);
628+
assert.equal(pluginData.pluginPlatformsFolderPath("ios"), expectediOSPath);
629+
assert.equal(pluginData.pluginPlatformsFolderPath("IOS"), expectediOSPath);
630+
631+
assert.equal(pluginData.pluginPlatformsFolderPath("Android"), expectedAndroidPath);
632+
assert.equal(pluginData.pluginPlatformsFolderPath("android"), expectedAndroidPath);
633+
assert.equal(pluginData.pluginPlatformsFolderPath("ANDROID"), expectedAndroidPath);
634+
});
635+
});
667636
});

test/services/playground/preview-app-livesync-service.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ function createTestInjector(options?: {
171171
mapFilePath: (filePath: string) => path.join(path.join(platformsDirPath, "app"), path.relative(path.join(projectDirPath, "app"), filePath))
172172
});
173173
injector.register("previewDevicesService", {
174-
getConnectedDevices: () => [deviceMockData]
174+
getConnectedDevices: () => [deviceMockData],
175+
getDevicesForPlatform: (platform: string): Device[] => [deviceMockData]
175176
});
176177
injector.register("previewAppFilesService", PreviewAppFilesService);
177178
injector.register("previewQrCodeService", {

0 commit comments

Comments
 (0)