You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by er...@apache.org on 2025/07/15 05:43:10 UTC

(cordova-common) branch master updated: feat: Support finding an unprefixed Info.plist file (#212)

This is an automated email from the ASF dual-hosted git repository.

erisu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cordova-common.git


The following commit(s) were added to refs/heads/master by this push:
     new 30206cd  feat: Support finding an unprefixed Info.plist file (#212)
30206cd is described below

commit 30206cdc2642758f20291450ac05d8b08836d61f
Author: Darryl Pogue <da...@dpogue.ca>
AuthorDate: Mon Jul 14 22:43:06 2025 -0700

    feat: Support finding an unprefixed Info.plist file (#212)
    
    Co-authored-by: Norman Breau <no...@nbsolutions.ca>
---
 package-lock.json                        | 55 -------------------
 package.json                             |  1 -
 spec/ConfigChanges/ConfigChanges.spec.js |  2 +-
 spec/ConfigChanges/ConfigFile.spec.js    | 42 ++++++++-------
 src/ConfigChanges/ConfigFile.js          | 93 ++++++++++++++++++--------------
 5 files changed, 76 insertions(+), 117 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index 6aa062a..d426883 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,7 +18,6 @@
         "fast-glob": "^3.3.3",
         "plist": "^3.1.0",
         "q": "^1.5.1",
-        "read-chunk": "^3.2.0",
         "strip-bom": "^4.0.0"
       },
       "devDependencies": {
@@ -3239,15 +3238,6 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/p-finally": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
-      "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=4"
-      }
-    },
     "node_modules/p-limit": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -3280,15 +3270,6 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/p-try": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
-      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/package-json-from-dist": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
@@ -3374,15 +3355,6 @@
         "url": "https://github.com/sponsors/jonschlinkert"
       }
     },
-    "node_modules/pify": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
-      "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/plist": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz",
@@ -3458,19 +3430,6 @@
       ],
       "license": "MIT"
     },
-    "node_modules/read-chunk": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-3.2.0.tgz",
-      "integrity": "sha512-CEjy9LCzhmD7nUpJ1oVOE6s/hBkejlcJEgLQHVnQznOSilOPb+kpKktlLfFDK3/WP43+F80xkUTM2VOkYoSYvQ==",
-      "license": "MIT",
-      "dependencies": {
-        "pify": "^4.0.1",
-        "with-open-file": "^0.1.6"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/reflect.getprototypeof": {
       "version": "1.0.10",
       "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
@@ -4630,20 +4589,6 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/with-open-file": {
-      "version": "0.1.7",
-      "resolved": "https://registry.npmjs.org/with-open-file/-/with-open-file-0.1.7.tgz",
-      "integrity": "sha512-ecJS2/oHtESJ1t3ZfMI3B7KIDKyfN0O16miWxdn30zdh66Yd3LsRFebXZXq6GU4xfxLf6nVxp9kIqElb5fqczA==",
-      "license": "MIT",
-      "dependencies": {
-        "p-finally": "^1.0.0",
-        "p-try": "^2.1.0",
-        "pify": "^4.0.1"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/word-wrap": {
       "version": "1.2.5",
       "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
diff --git a/package.json b/package.json
index eae4271..fcbe238 100644
--- a/package.json
+++ b/package.json
@@ -26,7 +26,6 @@
     "fast-glob": "^3.3.3",
     "plist": "^3.1.0",
     "q": "^1.5.1",
-    "read-chunk": "^3.2.0",
     "strip-bom": "^4.0.0"
   },
   "devDependencies": {
diff --git a/spec/ConfigChanges/ConfigChanges.spec.js b/spec/ConfigChanges/ConfigChanges.spec.js
index 6085591..ccaee9f 100644
--- a/spec/ConfigChanges/ConfigChanges.spec.js
+++ b/spec/ConfigChanges/ConfigChanges.spec.js
@@ -508,7 +508,7 @@ describe('config-changes module', function () {
 
                 const munger = new configChanges.PlatformMunger('ios', temp, platformJson, pluginInfoProvider);
                 munger.process(plugins_dir);
-                expect(spy).toHaveBeenCalledWith(path.join(temp, 'SampleApp', 'SampleApp-Info.plist'), 'utf8');
+                expect(spy).toHaveBeenCalledWith(path.join(temp, 'SampleApp', 'SampleApp-Info.plist'));
             });
 
             it('Test 026 : should move successfully installed plugins from queue to installed plugins section, and include/retain vars if applicable', function () {
diff --git a/spec/ConfigChanges/ConfigFile.spec.js b/spec/ConfigChanges/ConfigFile.spec.js
index c5e7958..1aa60a6 100644
--- a/spec/ConfigChanges/ConfigFile.spec.js
+++ b/spec/ConfigChanges/ConfigFile.spec.js
@@ -15,17 +15,11 @@
     under the License.
 */
 
-const rewire = require('rewire');
 const fs = require('node:fs');
 const path = require('node:path');
-const readChunk = require('read-chunk');
+const ConfigFile = require('../../src/ConfigChanges/ConfigFile');
 
 describe('ConfigFile tests', function () {
-    let ConfigFile;
-    beforeEach(() => {
-        ConfigFile = rewire('../../src/ConfigChanges/ConfigFile');
-    });
-
     describe('instance methods', () => {
         describe('save', () => {
             it('calls fs.writeFileSync', function () {
@@ -37,18 +31,6 @@ describe('ConfigFile tests', function () {
     });
 
     describe('static methods', () => {
-        describe('isBinaryPlist', () => {
-            it('should return false if not binary', function () {
-                spyOn(readChunk, 'sync').and.returnValue('not bplist');
-                expect(ConfigFile.isBinaryPlist('someFile')).toBe(false);
-            });
-
-            it('should return true if binary', function () {
-                spyOn(readChunk, 'sync').and.returnValue('bplist');
-                expect(ConfigFile.isBinaryPlist('someFile')).toBe(true);
-            });
-        });
-
         describe('getIOSProjectname', () => {
             it('should throw error', function () {
                 expect(function () { ConfigFile.getIOSProjectname('some/project/name'); }).toThrow();
@@ -78,6 +60,11 @@ describe('ConfigFile tests', function () {
                 expect(ConfigFile.resolveConfigFilePath('project_dir', 'android', 'strings.xml')).toBe(stringsPath);
             });
 
+            it('should return android values xml file path', function () {
+                const resPath = path.join(projectDir, 'res', 'values', 'colors.xml');
+                expect(ConfigFile.resolveConfigFilePath('project_dir', 'android', path.join('res', 'values', 'colors.xml'))).toBe(resPath);
+            });
+
             it('should return ios config.xml file path', function () {
                 spyOn(ConfigFile, 'getIOSProjectname').and.returnValue('iospath');
                 const configPath = path.join('project_dir', 'iospath', 'config.xml');
@@ -106,7 +93,7 @@ describe('ConfigFile tests', function () {
                 const projName = 'XXX';
                 const expectedPlistPath = `${projName}${path.sep}${projName}-Info.plist`;
 
-                ConfigFile.__set__('getIOSProjectname', () => projName);
+                spyOn(ConfigFile, 'getIOSProjectname').and.returnValue(projName);
                 spyOn(require('fast-glob'), 'sync').and.returnValue([
                     `AAA/${projName}-Info.plist`,
                     `Pods/Target Support Files/Pods-${projName}/Info.plist`,
@@ -116,6 +103,21 @@ describe('ConfigFile tests', function () {
 
                 expect(ConfigFile.resolveConfigFilePath('', 'ios', '*-Info.plist')).toBe(expectedPlistPath);
             });
+
+            it('should return Info.plist file', function () {
+                const projName = 'XXX';
+                const expectedPlistPath = path.join(projName, 'Info.plist');
+
+                spyOn(ConfigFile, 'getIOSProjectname').and.returnValue(projName);
+                spyOn(require('fast-glob'), 'sync').and.returnValue([
+                    'AAA/Info.plist',
+                    `Pods/Target Support Files/Pods-${projName}/Info.plist`,
+                    `Pods/Target Support Files/Pods-${projName}/Pods-${projName}-Info.plist`,
+                    expectedPlistPath
+                ]);
+
+                expect(ConfigFile.resolveConfigFilePath('', 'ios', '*-Info.plist')).toBe(expectedPlistPath);
+            });
         });
     });
 });
diff --git a/src/ConfigChanges/ConfigFile.js b/src/ConfigChanges/ConfigFile.js
index bc2673c..dfbf299 100644
--- a/src/ConfigChanges/ConfigFile.js
+++ b/src/ConfigChanges/ConfigFile.js
@@ -16,7 +16,6 @@
 
 const fs = require('node:fs');
 const path = require('node:path');
-const readChunk = require('read-chunk');
 
 // Use delay loading to ensure plist and other node modules to not get loaded
 // on Android, Windows platforms
@@ -29,6 +28,9 @@ const modules = {
     get xml_helpers () { return require('../util/xml-helpers'); }
 };
 
+// Cache of project folder paths to Xcode project names
+const xcodeprojMap = new Map();
+
 /******************************************************************************
 * ConfigFile class
 *
@@ -73,13 +75,13 @@ class ConfigFile {
         } else {
             // plist file
             this.type = 'plist';
-            // TODO: isBinaryPlist() reads the file and then parse re-reads it again.
-            //       We always write out text plist, not binary.
-            //       Do we still need to support binary plist?
-            //       If yes, use plist.parseStringSync() and read the file once.
-            this.data = isBinaryPlist(filepath)
-                ? modules.bplist.parseBuffer(fs.readFileSync(filepath))[0]
-                : modules.plist.parse(fs.readFileSync(filepath, 'utf8'));
+
+            const fileData = fs.readFileSync(filepath);
+            if (fileData.toString('utf8', 0, 6) === 'bplist') {
+                this.data = modules.bplist.parseBuffer(fileData)[0];
+            } else {
+                this.data = modules.plist.parse(fileData.toString('utf8'));
+            }
         }
     }
 
@@ -154,11 +156,34 @@ class ConfigFile {
 
         this.is_changed = true;
     }
+
+    // Find out the real name of an iOS project
+    //
+    // This caches the project name for a given directory path, assuming that
+    // it won't change over the course of a single Cordova command invocation
+    static getIOSProjectname (project_dir) {
+        if (xcodeprojMap.has(project_dir)) {
+            return xcodeprojMap.get(project_dir);
+        }
+
+        const matches = modules.glob.sync('*.xcodeproj', { cwd: project_dir, onlyDirectories: true });
+
+        if (matches.length !== 1) {
+            const msg = matches.length === 0
+                ? 'Does not appear to be an xcode project, no xcode project file'
+                : 'There are multiple *.xcodeproj dirs';
+
+            throw new Error(`${msg} in ${project_dir}`);
+        }
+
+        const projectName = path.basename(matches[0], '.xcodeproj');
+        xcodeprojMap.set(project_dir, projectName);
+        return projectName;
+    }
 }
 
 // Some config-file target attributes are not qualified with a full leading directory, or contain wildcards.
 // Resolve to a real path in this function.
-// TODO: getIOSProjectname is slow because of glob, try to avoid calling it several times per project.
 function resolveConfigFilePath (project_dir, platform, file) {
     let filepath = path.join(project_dir, file);
     let matches;
@@ -167,20 +192,32 @@ function resolveConfigFilePath (project_dir, platform, file) {
 
     if (file.includes('*')) {
         // handle wildcards in targets using glob.
-        matches = modules.glob.sync(`**/${file}`, {
+        matches = modules.glob.sync(`**/${file.replace('*-Info.plist', '*Info.plist')}`, {
             fs,
             cwd: project_dir,
             absolute: true
         }).map(path.normalize);
 
-        if (matches.length) filepath = matches[0];
+        if (matches.length) {
+            filepath = matches[0];
+        }
 
-        // [CB-5989] multiple Info.plist files may exist. default to $PROJECT_NAME-Info.plist
+        // [CB-5989] multiple Info.plist files may exist. default to Info.plist then $PROJECT_NAME-Info.plist
         if (matches.length > 1 && file.includes('-Info.plist')) {
-            const projName = getIOSProjectname(project_dir);
+            const projName = ConfigFile.getIOSProjectname(project_dir);
+
+            // Try to find a unprefix Info.plist file first
+            let plistPath = path.join(project_dir, projName, 'Info.plist');
+            if (matches.includes(plistPath)) {
+                return plistPath;
+            }
+
+            // Then try to find one prefixed with the project name
             const plistName = `${projName}-Info.plist`;
-            const plistPath = path.join(project_dir, projName, plistName);
-            if (matches.includes(plistPath)) return plistPath;
+            plistPath = path.join(project_dir, projName, plistName);
+            if (matches.includes(plistPath)) {
+                return plistPath;
+            }
         }
         return filepath;
     }
@@ -216,7 +253,7 @@ function resolveConfigFilePath (project_dir, platform, file) {
         if (platform === 'ios' || platform === 'osx') {
             filepath = path.join(
                 project_dir,
-                module.exports.getIOSProjectname(project_dir),
+                ConfigFile.getIOSProjectname(project_dir),
                 'config.xml'
             );
         } else {
@@ -235,29 +272,5 @@ function resolveConfigFilePath (project_dir, platform, file) {
     return filepath;
 }
 
-// Find out the real name of an iOS or OSX project
-// TODO: glob is slow, need a better way or caching, or avoid using more than once.
-function getIOSProjectname (project_dir) {
-    const matches = modules.glob.sync('*.xcodeproj', { cwd: project_dir, onlyDirectories: true });
-
-    if (matches.length !== 1) {
-        const msg = matches.length === 0
-            ? 'Does not appear to be an xcode project, no xcode project file'
-            : 'There are multiple *.xcodeproj dirs';
-
-        throw new Error(`${msg} in ${project_dir}`);
-    }
-
-    return path.basename(matches[0], '.xcodeproj');
-}
-
-// determine if a plist file is binary
-// i.e. they start with the magic header "bplist"
-function isBinaryPlist (filename) {
-    return readChunk.sync(filename, 0, 6).toString() === 'bplist';
-}
-
 module.exports = ConfigFile;
-module.exports.isBinaryPlist = isBinaryPlist;
-module.exports.getIOSProjectname = getIOSProjectname;
 module.exports.resolveConfigFilePath = resolveConfigFilePath;


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org