123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494 |
- /**
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
- */
-
- /*
- A class for holidng the information currently stored in plugin.xml
- It should also be able to answer questions like whether the plugin
- is compatible with a given engine version.
-
- TODO (kamrik): refactor this to not use sync functions and return promises.
- */
-
- var path = require('path');
- var fs = require('fs-extra');
- var xml_helpers = require('../util/xml-helpers');
- var CordovaError = require('../CordovaError/CordovaError');
-
- function PluginInfo (dirname) {
- var self = this;
-
- // METHODS
- // Defined inside the constructor to avoid the "this" binding problems.
-
- // <preference> tag
- // Example: <preference name="API_KEY" />
- // Used to require a variable to be specified via --variable when installing the plugin.
- // returns { key : default | null}
- self.getPreferences = getPreferences;
- function getPreferences (platform) {
- return _getTags(self._et, 'preference', platform, _parsePreference)
- .reduce(function (preferences, pref) {
- preferences[pref.preference] = pref.default;
- return preferences;
- }, {});
- }
-
- function _parsePreference (prefTag) {
- var name = prefTag.attrib.name.toUpperCase();
- var def = prefTag.attrib.default || null;
- return { preference: name, default: def };
- }
-
- // <asset>
- self.getAssets = getAssets;
- function getAssets (platform) {
- var assets = _getTags(self._et, 'asset', platform, _parseAsset);
- return assets;
- }
-
- function _parseAsset (tag) {
- var src = tag.attrib.src;
- var target = tag.attrib.target;
-
- if (!src || !target) {
- var msg =
- 'Malformed <asset> tag. Both "src" and "target" attributes'
- + 'must be specified in\n'
- + self.filepath
- ;
- throw new Error(msg);
- }
-
- var asset = {
- itemType: 'asset',
- src: src,
- target: target
- };
- return asset;
- }
-
- // <dependency>
- // Example:
- // <dependency id="com.plugin.id"
- // url="https://github.com/myuser/someplugin"
- // commit="428931ada3891801"
- // subdir="some/path/here" />
- self.getDependencies = getDependencies;
- function getDependencies (platform) {
- var deps = _getTags(
- self._et,
- 'dependency',
- platform,
- _parseDependency
- );
- return deps;
- }
-
- function _parseDependency (tag) {
- var dep =
- { id: tag.attrib.id,
- version: tag.attrib.version || '',
- url: tag.attrib.url || '',
- subdir: tag.attrib.subdir || '',
- commit: tag.attrib.commit
- };
-
- dep.git_ref = dep.commit;
-
- if (!dep.id) {
- var msg =
- '<dependency> tag is missing id attribute in '
- + self.filepath
- ;
- throw new CordovaError(msg);
- }
- return dep;
- }
-
- // <config-file> tag
- self.getConfigFiles = getConfigFiles;
- function getConfigFiles (platform) {
- var configFiles = _getTags(self._et, 'config-file', platform, _parseConfigFile);
- return configFiles;
- }
-
- function _parseConfigFile (tag) {
- var configFile =
- { target: tag.attrib['target'],
- parent: tag.attrib['parent'],
- after: tag.attrib['after'],
- xmls: tag.getchildren(),
- // To support demuxing via versions
- versions: tag.attrib['versions'],
- deviceTarget: tag.attrib['device-target']
- };
- return configFile;
- }
-
- self.getEditConfigs = getEditConfigs;
- function getEditConfigs (platform) {
- var editConfigs = _getTags(self._et, 'edit-config', platform, _parseEditConfigs);
- return editConfigs;
- }
-
- function _parseEditConfigs (tag) {
- var editConfig =
- { file: tag.attrib['file'],
- target: tag.attrib['target'],
- mode: tag.attrib['mode'],
- xmls: tag.getchildren()
- };
- return editConfig;
- }
-
- // <info> tags, both global and within a <platform>
- // TODO (kamrik): Do we ever use <info> under <platform>? Example wanted.
- self.getInfo = getInfo;
- function getInfo (platform) {
- var infos = _getTags(
- self._et,
- 'info',
- platform,
- function (elem) { return elem.text; }
- );
- // Filter out any undefined or empty strings.
- infos = infos.filter(Boolean);
- return infos;
- }
-
- // <source-file>
- // Examples:
- // <source-file src="src/ios/someLib.a" framework="true" />
- // <source-file src="src/ios/someLib.a" compiler-flags="-fno-objc-arc" />
- self.getSourceFiles = getSourceFiles;
- function getSourceFiles (platform) {
- var sourceFiles = _getTagsInPlatform(self._et, 'source-file', platform, _parseSourceFile);
- return sourceFiles;
- }
-
- function _parseSourceFile (tag) {
- return {
- itemType: 'source-file',
- src: tag.attrib.src,
- framework: isStrTrue(tag.attrib.framework),
- weak: isStrTrue(tag.attrib.weak),
- compilerFlags: tag.attrib['compiler-flags'],
- targetDir: tag.attrib['target-dir']
- };
- }
-
- // <header-file>
- // Example:
- // <header-file src="CDVFoo.h" />
- self.getHeaderFiles = getHeaderFiles;
- function getHeaderFiles (platform) {
- var headerFiles = _getTagsInPlatform(self._et, 'header-file', platform, function (tag) {
- return {
- itemType: 'header-file',
- src: tag.attrib.src,
- targetDir: tag.attrib['target-dir'],
- type: tag.attrib['type']
- };
- });
- return headerFiles;
- }
-
- // <resource-file>
- // Example:
- // <resource-file src="FooPluginStrings.xml" target="res/values/FooPluginStrings.xml" device-target="win" arch="x86" versions=">=8.1" />
- self.getResourceFiles = getResourceFiles;
- function getResourceFiles (platform) {
- var resourceFiles = _getTagsInPlatform(self._et, 'resource-file', platform, function (tag) {
- return {
- itemType: 'resource-file',
- src: tag.attrib.src,
- target: tag.attrib.target,
- versions: tag.attrib.versions,
- deviceTarget: tag.attrib['device-target'],
- arch: tag.attrib.arch,
- reference: tag.attrib.reference
- };
- });
- return resourceFiles;
- }
-
- // <lib-file>
- // Example:
- // <lib-file src="src/BlackBerry10/native/device/libfoo.so" arch="device" />
- self.getLibFiles = getLibFiles;
- function getLibFiles (platform) {
- var libFiles = _getTagsInPlatform(self._et, 'lib-file', platform, function (tag) {
- return {
- itemType: 'lib-file',
- src: tag.attrib.src,
- arch: tag.attrib.arch,
- Include: tag.attrib.Include,
- versions: tag.attrib.versions,
- deviceTarget: tag.attrib['device-target'] || tag.attrib.target
- };
- });
- return libFiles;
- }
-
- // <podspec>
- // Example:
- // <podspec>
- // <config>
- // <source url="https://github.com/brightcove/BrightcoveSpecs.git" />
- // <source url="https://github.com/CocoaPods/Specs.git"/>
- // </config>
- // <pods use-frameworks="true" inhibit-all-warnings="true">
- // <pod name="PromiseKit" />
- // <pod name="Foobar1" spec="~> 2.0.0" />
- // <pod name="Foobar2" git="git@github.com:hoge/foobar1.git" />
- // <pod name="Foobar3" git="git@github.com:hoge/foobar2.git" branch="next" />
- // <pod name="Foobar4" swift-version="4.1" />
- // <pod name="Foobar5" swift-version="3.0" />
- // </pods>
- // </podspec>
- self.getPodSpecs = getPodSpecs;
- function getPodSpecs (platform) {
- var podSpecs = _getTagsInPlatform(self._et, 'podspec', platform, function (tag) {
- var declarations = null;
- var sources = null;
- var libraries = null;
- var config = tag.find('config');
- var pods = tag.find('pods');
- if (config != null) {
- sources = config.findall('source').map(function (t) {
- return {
- url: t.attrib.url
- };
- }).reduce(function (acc, val) {
- return Object.assign({}, acc, { [val.url]: { source: val.url } });
- }, {});
- }
- if (pods != null) {
- declarations = Object.keys(pods.attrib).reduce(function (acc, key) {
- return pods.attrib[key] === undefined ? acc : Object.assign({}, acc, { [key]: pods.attrib[key] });
- }, {});
- libraries = pods.findall('pod').map(function (t) {
- return Object.keys(t.attrib).reduce(function (acc, key) {
- return t.attrib[key] === undefined ? acc : Object.assign({}, acc, { [key]: t.attrib[key] });
- }, {});
- }).reduce(function (acc, val) {
- return Object.assign({}, acc, { [val.name]: val });
- }, {});
- }
- return {
- declarations: declarations,
- sources: sources,
- libraries: libraries
- };
- });
- return podSpecs;
- }
-
- // <hook>
- // Example:
- // <hook type="before_build" src="scripts/beforeBuild.js" />
- self.getHookScripts = getHookScripts;
- function getHookScripts (hook, platforms) {
- var scriptElements = self._et.findall('./hook');
-
- if (platforms) {
- platforms.forEach(function (platform) {
- scriptElements = scriptElements.concat(self._et.findall('./platform[@name="' + platform + '"]/hook'));
- });
- }
-
- function filterScriptByHookType (el) {
- return el.attrib.src && el.attrib.type && el.attrib.type.toLowerCase() === hook;
- }
-
- return scriptElements.filter(filterScriptByHookType);
- }
-
- self.getJsModules = getJsModules;
- function getJsModules (platform) {
- var modules = _getTags(self._et, 'js-module', platform, _parseJsModule);
- return modules;
- }
-
- function _parseJsModule (tag) {
- var ret = {
- itemType: 'js-module',
- name: tag.attrib.name,
- src: tag.attrib.src,
- clobbers: tag.findall('clobbers').map(function (tag) { return { target: tag.attrib.target }; }),
- merges: tag.findall('merges').map(function (tag) { return { target: tag.attrib.target }; }),
- runs: tag.findall('runs').length > 0
- };
-
- return ret;
- }
-
- self.getEngines = function () {
- return self._et.findall('engines/engine').map(function (n) {
- return {
- name: n.attrib.name,
- version: n.attrib.version,
- platform: n.attrib.platform,
- scriptSrc: n.attrib.scriptSrc
- };
- });
- };
-
- self.getPlatforms = function () {
- return self._et.findall('platform').map(function (n) {
- return { name: n.attrib.name };
- });
- };
-
- self.getPlatformsArray = function () {
- return self._et.findall('platform').map(function (n) {
- return n.attrib.name;
- });
- };
-
- self.getFrameworks = function (platform, options) {
- return _getTags(self._et, 'framework', platform, function (el) {
- var src = el.attrib.src;
- if (options) {
- var vars = options.cli_variables || {};
-
- if (Object.keys(vars).length === 0) {
- // get variable defaults from plugin.xml for removal
- vars = self.getPreferences(platform);
- }
- var regExp;
- // Iterate over plugin variables.
- // Replace them in framework src if they exist
- Object.keys(vars).forEach(function (name) {
- if (vars[name]) {
- regExp = new RegExp('\\$' + name, 'g');
- src = src.replace(regExp, vars[name]);
- }
- });
- }
- var ret = {
- itemType: 'framework',
- type: el.attrib.type,
- parent: el.attrib.parent,
- custom: isStrTrue(el.attrib.custom),
- embed: isStrTrue(el.attrib.embed),
- src: src,
- spec: el.attrib.spec,
- weak: isStrTrue(el.attrib.weak),
- versions: el.attrib.versions,
- targetDir: el.attrib['target-dir'],
- deviceTarget: el.attrib['device-target'] || el.attrib.target,
- arch: el.attrib.arch,
- implementation: el.attrib.implementation
- };
- return ret;
- });
- };
-
- self.getFilesAndFrameworks = getFilesAndFrameworks;
- function getFilesAndFrameworks (platform, options) {
- // Please avoid changing the order of the calls below, files will be
- // installed in this order.
- var items = [].concat(
- self.getSourceFiles(platform),
- self.getHeaderFiles(platform),
- self.getResourceFiles(platform),
- self.getFrameworks(platform, options),
- self.getLibFiles(platform)
- );
- return items;
- }
- /// // End of PluginInfo methods /////
-
- /// // PluginInfo Constructor logic /////
- self.filepath = path.join(dirname, 'plugin.xml');
- if (!fs.existsSync(self.filepath)) {
- throw new CordovaError('Cannot find plugin.xml for plugin "' + path.basename(dirname) + '". Please try adding it again.');
- }
-
- self.dir = dirname;
- var et = self._et = xml_helpers.parseElementtreeSync(self.filepath);
- var pelem = et.getroot();
- self.id = pelem.attrib.id;
- self.version = pelem.attrib.version;
-
- // Optional fields
- self.name = pelem.findtext('name');
- self.description = pelem.findtext('description');
- self.license = pelem.findtext('license');
- self.repo = pelem.findtext('repo');
- self.issue = pelem.findtext('issue');
- self.keywords = pelem.findtext('keywords');
- self.info = pelem.findtext('info');
- if (self.keywords) {
- self.keywords = self.keywords.split(',').map(function (s) { return s.trim(); });
- }
- self.getKeywordsAndPlatforms = function () {
- var ret = self.keywords || [];
- return ret.concat('ecosystem:cordova').concat(addCordova(self.getPlatformsArray()));
- };
- } // End of PluginInfo constructor.
-
- // Helper function used to prefix every element of an array with cordova-
- // Useful when we want to modify platforms to be cordova-platform
- function addCordova (someArray) {
- var newArray = someArray.map(function (element) {
- return 'cordova-' + element;
- });
- return newArray;
- }
-
- // Helper function used by most of the getSomething methods of PluginInfo.
- // Get all elements of a given name. Both in root and in platform sections
- // for the given platform. If transform is given and is a function, it is
- // applied to each element.
- function _getTags (pelem, tag, platform, transform) {
- var platformTag = pelem.find('./platform[@name="' + platform + '"]');
- var tagsInRoot = pelem.findall(tag);
- tagsInRoot = tagsInRoot || [];
- var tagsInPlatform = platformTag ? platformTag.findall(tag) : [];
- var tags = tagsInRoot.concat(tagsInPlatform);
- if (typeof transform === 'function') {
- tags = tags.map(transform);
- }
- return tags;
- }
-
- // Same as _getTags() but only looks inside a platform section.
- function _getTagsInPlatform (pelem, tag, platform, transform) {
- var platformTag = pelem.find('./platform[@name="' + platform + '"]');
- var tags = platformTag ? platformTag.findall(tag) : [];
- if (typeof transform === 'function') {
- tags = tags.map(transform);
- }
- return tags;
- }
-
- // Check if x is a string 'true'.
- function isStrTrue (x) {
- return String(x).toLowerCase() === 'true';
- }
-
- module.exports = PluginInfo;
- // Backwards compat:
- PluginInfo.PluginInfo = PluginInfo;
- PluginInfo.loadPluginsDir = function (dir) {
- var PluginInfoProvider = require('./PluginInfoProvider');
- return new PluginInfoProvider().getAllWithinSearchPath(dir);
- };
|