Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

plugman

Package Overview
Dependencies
Maintainers
5
Versions
91
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

plugman - npm Package Compare versions

Comparing version 0.6.1 to 0.6.2

spec/plugins/shared-deps-multi-child/plugin.xml

23

main.js

@@ -34,7 +34,4 @@ #!/usr/bin/env node

, 'uninstall' : Boolean
, 'fetch' : Boolean
, 'list' : Boolean
, 'v' : Boolean
, 'debug' : Boolean
, 'prepare' : Boolean
, 'plugins': path

@@ -65,15 +62,2 @@ , 'link': Boolean

}
else if (cli_opts.list) {
plugins.listAllPlugins(function(plugins) {
for(var i = 0, j = plugins.length ; i < j ; i++) {
console.log(plugins[i].value.name, '-', plugins[i].value.description);
}
});
}
else if (cli_opts.prepare && cli_opts.project) {
plugman.prepare(cli_opts.project, cli_opts.platform, plugins_dir);
}
else if (cli_opts.fetch) {
plugman.fetch(cli_opts.plugin, plugins_dir, cli_opts.link);
}
else if (!cli_opts.platform || !cli_opts.project || !cli_opts.plugin) {

@@ -100,10 +84,5 @@ printUsage();

console.log('Usage\n---------');
console.log('Fetch a plugin:\n\t' + package.name + ' --fetch --plugin <directory|git-url|name> [--plugins_dir <directory>]\n');
console.log('Install an already fetched plugin:\n\t' + package.name + ' --platform <'+ platforms +'> --project <directory> --plugin <name> [--plugins_dir <directory>]\n');
console.log('Install a plugin (will call fetch if cannot be found):\n\t' + package.name + ' --platform <'+ platforms +'> --project <directory> --plugin <name> [--plugins_dir <directory>] [--variable <name>=<value>]\n');
console.log('Uninstall a plugin:\n\t' + package.name + ' --uninstall --platform <'+ platforms +'> --project <directory> --plugin <name> [--plugins_dir <directory>]\n');
console.log('List plugins:\n\t' + package.name + ' --list [--plugins_dir <directory>]\n');
console.log('Prepare project:\n\t' + package.name + ' --prepare --platform <ios|android|bb10> --project <directory> [--plugins_dir <directory>]');
console.log('\n\t--plugins_dir defaults to <project>/cordova/plugins, but can be any directory containing a subdirectory for each plugin');
}

@@ -5,3 +5,3 @@ {

"description": "install/uninstall Cordova plugins",
"version": "0.6.1",
"version": "0.6.2",
"repository": {

@@ -8,0 +8,0 @@ "type": "git",

@@ -7,3 +7,6 @@ # plugman

## Quickstart
npm install -g plugman
## Design Goals

@@ -19,5 +22,4 @@

plugman --fetch --plugin <directory|git-url|name> [--plugins_dir <directory>]
plugman --install --platform <ios|android|bb10> --project <directory> --plugin <name|url> [--plugins_dir <directory>]
plugman --install --platform <ios|android|bb10> --project <directory> --plugin <name|url> [--plugins_dir <directory>] [--variable <name>=<value> [--variable <name>=<value> ...]]
plugman --uninstall --platform <ios|android|bb10> --project <directory> --plugin <name> [--plugins_dir <directory>]
plugman --remove --plugin <name> [--plugins_dir <directory>]
plugman --list [--plugins_dir <directory>]

@@ -29,11 +31,13 @@ plugman --prepare --platform <ios|android|bb10> --project <directory> [--plugins_dir <directory>]

* `--uninstall`: Uninstalls an already-`--install`'ed plugin from a cordova project
* `--remove`: Removes a `--fetch`'ed plugin
* `--list`: Lists all `--fetch`'ed plugins
* `--prepare`: Based on all installed plugins, will set up properly injecting plugin JavaScript code and setting up permissions properly. Implicitly called after `--install` and `--uninstall` commands. See below for more details.
`--plugins_dir` defaults to `<project>/cordova/plugins`, but can be any directory containing a subdirectory for each fetched plugin
Other parameters:
Note that `--fetch` and `--remove` deal with the local cache of the plugin's files and don't care about platforms, while `--install` and `--uninstall` require specifying the target platform and the location of the project, and actually do installation of plugin code and assets.
* `--plugins_dir` defaults to `<project>/cordova/plugins`, but can be any directory containing a subdirectory for each fetched plugin.
* `--variable` allows to specify certain variables at install time, necessary for certain plugins requiring API keys or other custom, user-defined parameters.
Note that `--fetch` deals with the local cache of the plugin's files (in the `--plugins_dir` location) and doesn't care about platforms, while `--install` and `--uninstall` require specifying the target platform and the location of the project, and actually do installation of plugin code and assets.
### Supported Platforms

@@ -47,3 +51,4 @@

The plugins found [https://github.com/MobileChromeApps/chrome-cordova/plugins](here) are maintained actively by a contributor to plugman, and should serve as good examples.
- Google has a [https://github.com/MobileChromeApps/chrome-cordova/plugins](bunch of plugins) which are maintained actively by a contributor to plugman
- Adobe maintains plugins for its Build cloud service, which are open sourced and [available on GitHub](https://github.com/phonegap-build)

@@ -92,3 +97,3 @@ ## Development

Last edited April 17 2013.
Last edited May 2 2013.

@@ -181,6 +186,4 @@ The `plugin.xml` file is an XML document in the plugins namespace -

All assets tags require both a `src` attribute and a `target` attribute.
All assets tags require both a `src` attribute and a `target` attribute. Web-only plugins would contains mainly &lt;asset&gt; elements. &lt;asset&gt; elements can also be nested under &lt;platform&gt; elements, to specify platform-specific web assets (see below).
Web-only plugins would contains mainly &lt;asset&gt; elements.
#### src (required)

@@ -191,3 +194,3 @@

If a file does not exist at the source location, plugman will stop/reverse the installation process and notify the user, and exit with a non-zero code.
If a file does not exist at the specified `src` location, plugman will stop/reverse the installation process and notify the user, and exit with a non-zero code.

@@ -236,3 +239,5 @@ #### target (required)

&lt;js-module&gt; elements can also be nested under &lt;platform&gt;, to declare platform-specific JavaScript module bindings.
### &lt;platform&gt;

@@ -306,2 +311,4 @@

Two file types that have been tested for modification with this element are `xml` and `plist` files.
The `config-file` element only allows for appending

@@ -311,12 +318,23 @@ new children into an XML document. The children are XML literals that are the

Example:
Example for XML:
<config-file target="AndroidManifest.xml" parent="/manifest/application">
<activity android:name="com.foo.Foo"
android:label="@string/app_name">
<intent-filter>
</intent-filter>
<activity android:name="com.foo.Foo" android:label="@string/app_name">
<intent-filter>
</intent-filter>
</activity>
</config-file>
Example for plist:
<config-file target="*-Info.plist" parent="CFBundleURLTypes">
<array>
<dict>
<key>PackageName</key>
<string>$PACKAGE_NAME</string>
</dict>
</array>
</config-file>
#### target

@@ -327,9 +345,14 @@

If this file does not exist, the tool should stop/reverse the installation process, warn the user, and exit with a non-zero code.
The target can include a wildcard (`*`) element. In this case, plugman will recursively search through the project directory structure and use the first match.
On iOS, the location of configuration files relative to the project directory root is not known. Specifying a target of `config.xml` will resolve to `cordova-ios-project/MyAppName/config.xml`.
If the specified file does not exist, the tool will ignore the configuration change and continue installation.
#### parent
An absolute XPath selector pointing to the parent of the elements to be added to
the config file.
An XPath selector pointing to the parent of the elements to be added to the config file. If absolute selectors are used, you can use a wildcard (`*`) to specify the root element, e.g. `/*/plugins`.
For plist files, the parent is used to determine under what parent key should the specified XML be inserted.
If the selector does not resolve to a child of the specified document, the tool should stop/reverse the installation process, warn the user, and exit with a non-zero code.

@@ -339,3 +362,3 @@

This is OUTDATED as it only applies to cordova-ios 2.2.0 and below. Use &lt;config-file&gt; tag (same as Android) for newer versions of Cordova.
This is OUTDATED as it only applies to cordova-ios 2.2.0 and below. Use &lt;config-file&gt; tag for newer versions of Cordova.

@@ -345,4 +368,3 @@ Example:

<config-file target="config.xml" parent="/cordova/plugins">
<plugin name="ChildBrowser"
value="ChildBrowserCommand"/>
<plugin name="ChildBrowser" value="ChildBrowserCommand"/>
</config-file>

@@ -353,4 +375,3 @@

<plugins-plist key="Foo"
string="CDVFoo" />
<plugins-plist key="Foo" string="CDVFoo" />

@@ -361,3 +382,3 @@

Like source files, but specifically for platforms that distinguish between
source files, headers, and resources (iOS)
source files, headers, and resources (iOS).

@@ -423,9 +444,9 @@ Examples:

<info>
You need to install **Google Play Services** from the `Android Extras` section using the Android SDK manager (run `android`).
<info>
You need to install **Google Play Services** from the `Android Extras` section using the Android SDK manager (run `android`).
You need to add the following line to your `local.properties`
android.library.reference.1=PATH_TO_ANDROID_SDK/sdk/extras/google/google_play_services/libproject/google-play-services_lib
</info>
You need to add the following line to your `local.properties`
android.library.reference.1=PATH_TO_ANDROID_SDK/sdk/extras/google/google_play_services/libproject/google-play-services_lib
</info>

@@ -473,30 +494,8 @@ ## Variables

## Project Directory Structure
TODO: show how the foo plugin example from above will have its files placed in a cordova project after running plugman
## Authors
* Andrew Lunny
* Fil Maj
* Mike Reinstein
* Anis Kadri
* Braden Shepherdson
* Tim Kim
## Contributors
* Michael Brooks
See the package.json file for attribution notes.
## License
Apache
## TODO
These apply to plugman as well as cordova-cli. Keep the two in step, they both have `future` branches.
These are in rough order of priority, most urgent at the top.
* Fix all the tests, including the www-only tests, which expect the old `www` platform that has been removed. Note that most of the tests will need some rewiring because of the separation of `--fetch` and `--install`. [CB-2814](http://issues.cordova.io/2814). Assigned to Tim.
* Implement a `cordova watch` a la `grunt watch` that will re-run `cordova prepare` every time the installed plugins change (including those installed with `--link`). This is definitely a stretch goal, but it would be awesome. Not assigned but tracked at [CB-2819](http://issues.cordova.io/2819).
Apache License 2.0

@@ -25,6 +25,6 @@ var fetch = require('../src/fetch'),

});
it('should copy locally-available plugin to plugins directory when specified with a trailing slash', function() {
fetch(test_plugin+'/', temp, false);
expect(fs.existsSync(copied_plugin_path)).toBe(true);
});
// it('should copy locally-available plugin to plugins directory when specified with a trailing slash', function() {
// fetch(test_plugin+'/', temp, false);
// expect(fs.existsSync(copied_plugin_path)).toBe(true);
// });
it('should create a symlink if used with `link` param', function() {

@@ -46,17 +46,3 @@ fetch(test_plugin, temp, true);

});
it('should call getPluginInfo and clonePluginRepo for names', function() {
var s1 = spyOn(plugins, 'getPluginInfo').andCallFake(function(plugin_name, callback) {
callback(null, {url:"https://github.com/imhotep/ChildBrowser.git"});
});
var s2 = spyOn(plugins, 'clonePluginGitRepo');
fetch("ChildBrowser", temp, false, null);
expect(s1).toHaveBeenCalled();
expect(s2).toHaveBeenCalledWith('https://github.com/imhotep/ChildBrowser.git', temp, null);
});
it('should throw if used with name and `link` param', function() {
expect(function() {
fetch('ChildBrowser', temp, true);
}).toThrow();
});
});
});

@@ -33,2 +33,3 @@ var install = require('../src/install'),

describe('success', function() {

@@ -56,3 +57,3 @@ var android_installer;

expect(transactions.length).toEqual(3);
expect(transactions.length).toEqual(1);
expect(transactions[0].tag).toBe('source-file');

@@ -69,2 +70,5 @@ });

describe('failure', function() {
describe('should revert web assets if an install error occurs', function() {
});
it('should throw if platform is unrecognized', function() {

@@ -71,0 +75,0 @@ expect(function() {

@@ -8,2 +8,3 @@ var ios = require('../../src/platforms/ios'),

os = require('osenv'),
common = require('../../src/platforms/common'),
xcode = require('xcode'),

@@ -199,3 +200,3 @@ plist = require('plist'),

});
it('should call into xcodeproj\'s addHeaderFile appropriately when element a no target-dir', function() {
it('should call into xcodeproj\'s addHeaderFile appropriately when element a target-dir', function() {
var headers = copyArray(valid_headers).filter(function(s) { return s.attrib['target-dir'] != undefined});

@@ -277,41 +278,41 @@ var spy = jasmine.createSpy();

});
describe('of <asset> elements', function() {
beforeEach(function() {
shell.cp('-rf', ios_config_xml_project, temp);
});
it('should throw if asset src cannot be found', function() {
var assets = copyArray(invalid_assets);
expect(function() {
ios.install(assets, faulty_id, temp, faultyplugin, {});
}).toThrow('"' + path.resolve(faultyplugin, 'www/main.js') + '" not found!');
});
it('should throw if asset target already exists', function() {
var assets = copyArray(valid_assets);
var target = path.join(temp, 'www', 'dummyplugin.js');
fs.writeFileSync(target, 'some bs', 'utf-8');
expect(function() {
ios.install(assets, dummy_id, temp, dummyplugin, {});
}).toThrow('"'+ target + '" already exists!');
});
it('should cp the file and directory to the right target location', function() {
var assets = copyArray(valid_assets);
var spy_cp = spyOn(shell, 'cp').andCallThrough();
var spy_mkdir = spyOn(shell, 'mkdir').andCallThrough();
ios.install(assets, dummy_id, temp, dummyplugin, {});
expect(spy_mkdir).toHaveBeenCalledWith('-p', path.join(temp, 'www'));
expect(spy_cp).toHaveBeenCalledWith(path.join(dummyplugin, 'www', 'dummyplugin.js'), path.join(temp, 'www', 'dummyplugin.js'));
expect(spy_cp).toHaveBeenCalledWith('-R', path.join(dummyplugin, 'www', 'dummyplugin/*'), path.join(temp, 'www', 'dummyplugin'));
// make sure the file and directory are properly copies
expect(fs.existsSync(path.join(temp, 'www', 'dummyplugin.js'))).toBe(true);
expect(fs.statSync(path.join(temp, 'www', 'dummyplugin.js')).isFile()).toBe(true);
expect(fs.existsSync(path.join(temp, 'www', 'dummyplugin'))).toBe(true);
expect(fs.statSync(path.join(temp, 'www', 'dummyplugin')).isDirectory()).toBe(true);
expect(fs.existsSync(path.join(temp, 'www', 'dummyplugin', 'image.jpg'))).toBe(true);
expect(fs.statSync(path.join(temp, 'www', 'dummyplugin', 'image.jpg')).isFile()).toBe(true);
});
});
// TODO move this shit to install/uninstall
// describe('of <asset> elements', function() {
// beforeEach(function() {
// shell.cp('-rf', ios_config_xml_project, temp);
// });
// it('should throw if asset src cannot be found', function() {
// var assets = copyArray(invalid_assets);
// expect(function() {
// ios.install(assets, faulty_id, temp, faultyplugin, {});
// }).toThrow('"' + path.resolve(faultyplugin, 'www/main.js') + '" not found!');
// });
// it('should throw if asset target already exists', function() {
// var assets = copyArray(valid_assets);
// var target = path.join(temp, 'www', 'dummyplugin.js');
// fs.writeFileSync(target, 'some bs', 'utf-8');
// expect(function() {
// ios.install(assets, dummy_id, temp, dummyplugin, {});
// }).toThrow('"'+ target + '" already exists!');
// });
// it('should cp the file and directory to the right target location', function() {
// var assets = copyArray(valid_assets);
// var spy_cp = spyOn(shell, 'cp').andCallThrough();
// var spy_mkdir = spyOn(shell, 'mkdir').andCallThrough();
// ios.install(assets, dummy_id, temp, dummyplugin, {});
// expect(spy_mkdir).toHaveBeenCalledWith('-p', path.join(temp, 'www'));
// expect(spy_cp).toHaveBeenCalledWith(path.join(dummyplugin, 'www', 'dummyplugin.js'), path.join(temp, 'www', 'dummyplugin.js'));
// expect(spy_cp).toHaveBeenCalledWith('-R', path.join(dummyplugin, 'www', 'dummyplugin/*'), path.join(temp, 'www', 'dummyplugin'));
//
// // make sure the file and directory are properly copies
// expect(fs.existsSync(path.join(temp, 'www', 'dummyplugin.js'))).toBe(true);
// expect(fs.statSync(path.join(temp, 'www', 'dummyplugin.js')).isFile()).toBe(true);
//
// expect(fs.existsSync(path.join(temp, 'www', 'dummyplugin'))).toBe(true);
// expect(fs.statSync(path.join(temp, 'www', 'dummyplugin')).isDirectory()).toBe(true);
//
// expect(fs.existsSync(path.join(temp, 'www', 'dummyplugin', 'image.jpg'))).toBe(true);
// expect(fs.statSync(path.join(temp, 'www', 'dummyplugin', 'image.jpg')).isFile()).toBe(true);
// });
// });

@@ -362,28 +363,59 @@ describe('of <framework> elements', function() {

describe('of <source-file> elements', function() {
it('should call into xcodeproj\'s removeSourceFile appropriately when element has no target-dir');
it('should call into xcodeproj\'s removeSourceFile appropriately when element a no target-dir');
it('should rm the file from the right target location when element has a target-dir');
it('should rm the file from the right target location when element has no target-dir');
});
describe('of <plugins-plist> elements', function() {
it('should only be used in an applicably old cordova-ios project');
it('should not be used in an applicably old cordova-ios project');
it('should remove the <plugin> element in applicably new cordova-ios projects with old-style plugins using only <plugins-plist> elements', function() {
it('should call into xcodeproj\'s removeSourceFile appropriately when element has no target-dir', function(){
var source = copyArray(valid_source).filter(function(s) { return s.attrib['target-dir'] == undefined});
shell.cp('-rf', ios_config_xml_project, temp);
var spy = jasmine.createSpy();
spyOn(xcode, 'project').andReturn({
parseSync:function(){},
writeSync:function(){},
removeSourceFile:spy
});
ios.uninstall(source, dummy_id, temp, dummyplugin);
expect(spy).toHaveBeenCalledWith(path.join('Plugins', 'DummyPluginCommand.m'));
});
it('should call into xcodeproj\'s removeSourceFile appropriately when element a target-dir', function(){
var source = copyArray(valid_source).filter(function(s) { return s.attrib['target-dir'] != undefined});
shell.cp('-rf', ios_config_xml_project, temp);
var spy = spyOn(shell, 'rm');
ios.uninstall(source, dummy_id, temp, dummyplugin);
expect(spy).toHaveBeenCalledWith('-rf', path.join(temp, 'SampleApp', 'Plugins', 'targetDir', 'TargetDirTest.m'));
});
it('should rm the file from the right target location when element has no target-dir', function(){
var source = copyArray(valid_source).filter(function(s) { return s.attrib['target-dir'] == undefined});
shell.cp('-rf', ios_config_xml_project, temp);
var spy = spyOn(shell, 'rm');
ios.uninstall(source, dummy_id, temp, dummyplugin);
expect(spy).toHaveBeenCalledWith('-rf', path.join(temp, 'SampleApp', 'Plugins', 'DummyPluginCommand.m'));
});
it('should rm the file from the right target location when element has a target-dir', function(){
var source = copyArray(valid_source).filter(function(s) { return s.attrib['target-dir'] != undefined});
shell.cp('-rf', ios_config_xml_project, temp);
var spy = spyOn(shell, 'rm');
ios.uninstall(source, dummy_id, temp, dummyplugin);
expect(spy).toHaveBeenCalledWith('-rf', path.join(temp, 'SampleApp', 'Plugins', 'targetDir', 'TargetDirTest.m'));
});
});
describe('of <config-file> elements', function() {
it('should only be used in applicably new cordova-ios projects');
it('should remove any applicable <plugin> elements in applicably new cordova-ios projects with old-style plugins using only <plugins-plist> elements');
it('should call xml_helpers\' pruneXML');
it('should write the new config file out after successfully pruning');
});
describe('of <asset> elements', function() {
it('should call rm on specified asset', function() {
beforeEach(function() {
shell.cp('-rf', ios_config_xml_project, temp);
});
it('should call rm on specified asset',function(){
var config = copyArray(valid_assets);
var spy = spyOn(common, 'removeFile');
ios.uninstall(config, dummy_id, temp, dummyplugin);
expect(spy).toHaveBeenCalledWith(path.join(temp, 'www'), 'dummyplugin.js');
expect(spy).toHaveBeenCalledWith(path.join(temp, 'www'), 'dummyplugin');
});
it('should call rm on the www/plugins/<plugin_id> folder', function() {
it('should call rm on the www/plugins/<plugin_id> folder',function(){
var config = copyArray(valid_assets);
var spy = spyOn(common, 'removeFile');
ios.uninstall(config, dummy_id, temp, dummyplugin);
expect(spy).toHaveBeenCalledWith(path.join(temp, 'www', 'plugins'), dummy_id);
});

@@ -393,16 +425,81 @@ });

describe('of <header-file> elements', function() {
it('should call into xcodeproj\'s removeHeaderFile appropriately when element has no target-dir');
it('should call into xcodeproj\'s removeHeaderFile appropriately when element a no target-dir');
it('should rm the file from the right target location');
beforeEach(function() {
shell.cp('-rf', ios_config_xml_project, temp);
});
it('should call into xcodeproj\'s removeHeaderFile appropriately when element has no target-dir', function(){
var headers = copyArray(valid_headers).filter(function(s) { return s.attrib['target-dir'] == undefined});
var spy = jasmine.createSpy();
spyOn(xcode, 'project').andReturn({
parseSync:function(){},
writeSync:function(){},
removeHeaderFile:spy
});
ios.uninstall(headers, dummy_id, temp, dummyplugin);
expect(spy).toHaveBeenCalledWith(path.join('Plugins', 'DummyPluginCommand.h'));
});
it('should call into xcodeproj\'s removeHeaderFile appropriately when element a target-dir', function(){
var headers = copyArray(valid_headers).filter(function(s) { return s.attrib['target-dir'] != undefined});
var spy = jasmine.createSpy();
spyOn(xcode, 'project').andReturn({
parseSync:function(){},
writeSync:function(){},
removeHeaderFile:spy
});
ios.uninstall(headers, dummy_id, temp, dummyplugin);
expect(spy).toHaveBeenCalledWith(path.join('Plugins', 'targetDir', 'TargetDirTest.h'));
});
it('should rm the file from the right target location', function(){
var headers = copyArray(valid_headers).filter(function(s) { return s.attrib['target-dir'] != undefined});
var spy = spyOn(shell, 'rm');
ios.uninstall(headers, dummy_id, temp, dummyplugin);
expect(spy).toHaveBeenCalledWith('-rf', path.join(temp, 'SampleApp', 'Plugins', 'targetDir', 'TargetDirTest.h'));
});
});
describe('of <resource-file> elements', function() {
it('should call into xcodeproj\'s removeResourceFile');
it('should rm the file from the right target location');
beforeEach(function() {
shell.cp('-rf', ios_config_xml_project, temp);
});
it('should call into xcodeproj\'s removeResourceFile', function(){
var resources = copyArray(valid_resources);
var spy = jasmine.createSpy();
spyOn(xcode, 'project').andReturn({
parseSync:function(){},
writeSync:function(){},
removeResourceFile:spy
});
ios.uninstall(resources, dummy_id, temp, dummyplugin);
expect(spy).toHaveBeenCalledWith(path.join('Resources', 'DummyPlugin.bundle'));
});
it('should rm the file from the right target location', function(){
var resources = copyArray(valid_resources);
var spy = spyOn(shell, 'rm');
ios.uninstall(resources, dummy_id, temp, dummyplugin);
expect(spy).toHaveBeenCalledWith('-rf', path.join(temp, 'SampleApp', 'Resources', 'DummyPlugin.bundle'));
});
});
describe('of <framework> elements', function() {
it('should call into xcodeproj\'s removeFramework');
beforeEach(function() {
shell.cp('-rf', ios_config_xml_project, temp);
});
it('should call into xcodeproj\'s removeFramework' ,function() {
var frameworks = copyArray(valid_frameworks).filter(function(f) { return f.attrib.weak == undefined; });
var spy = jasmine.createSpy();
spyOn(xcode, 'project').andReturn({
parseSync:function(){},
writeSync:function(){},
removeFramework:spy
});
ios.uninstall(frameworks, dummy_id, temp, dummyplugin);
expect(spy).toHaveBeenCalledWith(path.join('src', 'ios', 'libsqlite3.dylib'));
});
});
});
});

@@ -47,3 +47,3 @@ var uninstall = require('../src/uninstall'),

expect(transactions.length).toEqual(6);
expect(transactions.length).toEqual(1);
expect(transactions[0].tag).toBe('source-file');

@@ -73,11 +73,6 @@ });

install('android', temp, 'DummyPlugin', plugins_dir, {});
// make uninstall fail by removing a js asset
shell.rm(path.join(temp, 'assets', 'www', 'dummyplugin.js'));
var s = spyOn(android, 'install');
// destroy android manifest /manifest/application so pruneXML fails
var manifest_path = path.join(temp, 'AndroidManifest.xml');
var manifest = xml_helpers.parseElementtreeSync(manifest_path);
var app_el = manifest.find('application');
manifest.getroot().remove(0, app_el);
var output = manifest.write({indent:4});
fs.writeFileSync(manifest_path, output);
uninstall('android', temp, 'DummyPlugin', plugins_dir, {});

@@ -84,0 +79,0 @@ var executed_txs = s.mostRecentCall.args[0];

@@ -11,6 +11,9 @@ var configChanges = require('../../src/util/config-changes'),

dummyplugin = path.join(__dirname, '..', 'plugins', 'DummyPlugin'),
cbplugin = path.join(__dirname, '..', 'plugins', 'ChildBrowser'),
childrenplugin = path.join(__dirname, '..', 'plugins', 'multiple-children'),
shareddepsplugin = path.join(__dirname, '..', 'plugins', 'shared-deps-multi-child'),
configplugin = path.join(__dirname, '..', 'plugins', 'ConfigTestPlugin'),
varplugin = path.join(__dirname, '..', 'plugins', 'VariablePlugin'),
android_two_project = path.join(__dirname, '..', 'projects', 'android_two', '*'),
android_two_no_perms_project = path.join(__dirname, '..', 'projects', 'android_two_no_perms', '*'),
ios_plist_project = path.join(__dirname, '..', 'projects', 'ios-plist', '*'),

@@ -135,3 +138,3 @@ ios_config_xml = path.join(__dirname, '..', 'projects', 'ios-config-xml', '*'),

xdescribe('save_platform_json method', function() {
describe('save_platform_json method', function() {
it('should write out specified json', function() {

@@ -148,4 +151,5 @@ var filepath = path.join(plugins_dir, 'android.json');

it('should return a flat config heirarchy for simple, one-off config changes', function() {
shell.cp('-rf', android_two_project, temp);
var xml;
var munge = configChanges.generate_plugin_config_munge(dummyplugin, 'android');
var munge = configChanges.generate_plugin_config_munge(dummyplugin, 'android', temp, {});
expect(munge['AndroidManifest.xml']).toBeDefined();

@@ -168,3 +172,4 @@ expect(munge['AndroidManifest.xml']['/manifest/application']).toBeDefined();

it('should split out multiple children of config-file elements into individual leaves', function() {
var munge = configChanges.generate_plugin_config_munge(childrenplugin, 'android');
shell.cp('-rf', android_two_project, temp);
var munge = configChanges.generate_plugin_config_munge(childrenplugin, 'android', temp, {});
expect(munge['AndroidManifest.xml']).toBeDefined();

@@ -177,8 +182,9 @@ expect(munge['AndroidManifest.xml']['/manifest']).toBeDefined();

expect(munge['AndroidManifest.xml']['/manifest']['<uses-permission android:name="android.permission.WAKE_LOCK" />']).toBeDefined();
expect(munge['AndroidManifest.xml']['/manifest']['<permission android:name="$PACKAGE_NAME.permission.C2D_MESSAGE" android:protectionLevel="signature" />']).toBeDefined();
expect(munge['AndroidManifest.xml']['/manifest']['<uses-permission android:name="$PACKAGE_NAME.permission.C2D_MESSAGE" />']).toBeDefined();
expect(munge['AndroidManifest.xml']['/manifest']['<permission android:name="com.alunny.childapp.permission.C2D_MESSAGE" android:protectionLevel="signature" />']).toBeDefined();
expect(munge['AndroidManifest.xml']['/manifest']['<uses-permission android:name="com.alunny.childapp.permission.C2D_MESSAGE" />']).toBeDefined();
expect(munge['AndroidManifest.xml']['/manifest']['<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />']).toBeDefined();
});
it('should not use xml comments as config munge leaves', function() {
var munge = configChanges.generate_plugin_config_munge(childrenplugin, 'android');
shell.cp('-rf', android_two_project, temp);
var munge = configChanges.generate_plugin_config_munge(childrenplugin, 'android', temp, {});
expect(munge['AndroidManifest.xml']['/manifest']['<!--library-->']).not.toBeDefined();

@@ -188,11 +194,32 @@ expect(munge['AndroidManifest.xml']['/manifest']['<!-- GCM connects to Google Services. -->']).not.toBeDefined();

it('should increment config heirarchy leaves if dfferent config-file elements target the same file + selector + xml', function() {
var munge = configChanges.generate_plugin_config_munge(configplugin, 'android');
shell.cp('-rf', android_two_project, temp);
var munge = configChanges.generate_plugin_config_munge(configplugin, 'android', temp, {});
expect(munge['res/xml/config.xml']['/widget']['<poop />']).toEqual(2);
});
it('should take into account interpolation variables', function() {
var munge = configChanges.generate_plugin_config_munge(childrenplugin, 'android', {PACKAGE_NAME:'ca.filmaj.plugins'});
shell.cp('-rf', android_two_project, temp);
var munge = configChanges.generate_plugin_config_munge(childrenplugin, 'android', temp, {PACKAGE_NAME:'ca.filmaj.plugins'});
expect(munge['AndroidManifest.xml']['/manifest']['<uses-permission android:name="ca.filmaj.plugins.permission.C2D_MESSAGE" />']).toBeDefined();
});
it('should create munges for platform-agnostic config.xml changes', function() {
shell.cp('-rf', android_two_project, temp);
var munge = configChanges.generate_plugin_config_munge(dummyplugin, 'android', temp, {});
expect(munge['config.xml']['/*']['<access origin="build.phonegap.com" />']).toBeDefined();
expect(munge['config.xml']['/*']['<access origin="s3.amazonaws.com" />']).toBeDefined();
});
it('should automatically add on ios bundle identifier as PACKAGE_NAME variable for ios config munges', function() {
shell.cp('-rf', ios_config_xml, temp);
var munge = configChanges.generate_plugin_config_munge(varplugin, 'ios', temp, {});
var expected_xml = '<cfbundleid>com.example.friendstring</cfbundleid>';
expect(munge['config.xml']['/widget'][expected_xml]).toBeDefined();
});
it('should automatically add on app java identifier as PACKAGE_NAME variable for android config munges', function() {
shell.cp('-rf', android_two_project, temp);
var munge = configChanges.generate_plugin_config_munge(varplugin, 'android', temp, {});
var expected_xml = '<package>com.alunny.childapp</package>';
expect(munge['AndroidManifest.xml']['/manifest'][expected_xml]).toBeDefined();
});
it('should special case plugins-plist elements into own property', function() {
var munge = configChanges.generate_plugin_config_munge(dummyplugin, 'ios', {});
shell.cp('-rf', ios_config_xml, temp);
var munge = configChanges.generate_plugin_config_munge(dummyplugin, 'ios', temp, {});
expect(munge['plugins-plist']).toBeDefined();

@@ -214,3 +241,3 @@ expect(munge['plugins-plist']['com.phonegap.plugins.dummyplugin']).toEqual('DummyPluginCommand');

configChanges.process(plugins_dir, temp, 'android');
expect(spy).toHaveBeenCalledWith(path.join(plugins_dir, 'DummyPlugin'), 'android', {});
expect(spy).toHaveBeenCalledWith(path.join(plugins_dir, 'DummyPlugin'), 'android', temp, {});
});

@@ -242,5 +269,7 @@ it('should get a reference to existing config munge by calling get_platform_json', function() {

configChanges.process(plugins_dir, temp, 'android');
expect(spy.calls.length).toEqual(2);
expect(spy.argsForCall[0][2]).toEqual('/manifest/application');
expect(spy.argsForCall[1][2]).toEqual('/cordova/plugins');
expect(spy.calls.length).toEqual(4);
expect(spy.argsForCall[0][2]).toEqual('/*');
expect(spy.argsForCall[1][2]).toEqual('/*');
expect(spy.argsForCall[2][2]).toEqual('/manifest/application');
expect(spy.argsForCall[3][2]).toEqual('/cordova/plugins');
});

@@ -250,5 +279,3 @@ it('should not call graftXML for a config munge that already exists from another plugin', function() {

shell.cp('-rf', configplugin, plugins_dir);
var cfg = configChanges.get_platform_json(plugins_dir, 'android');
cfg.prepare_queue.installed = [{'plugin':'ConfigTestPlugin', 'vars':{}}];
configChanges.save_platform_json(cfg, plugins_dir, 'android');
configChanges.add_installed_plugin_to_prepare_queue(plugins_dir, 'ConfigTestPlugin', 'android', {});

@@ -261,5 +288,3 @@ var spy = spyOn(xml_helpers, 'graftXML').andReturn(true);

shell.cp('-rf', android_two_project, temp);
var cfg = configChanges.get_platform_json(plugins_dir, 'android');
cfg.prepare_queue.installed = [{'plugin':'DummyPlugin', 'vars':{}}];
configChanges.save_platform_json(cfg, plugins_dir, 'android');
configChanges.add_installed_plugin_to_prepare_queue(plugins_dir, 'DummyPlugin', 'android', {});

@@ -271,7 +296,15 @@ var spy = spyOn(fs, 'readFileSync').andCallThrough();

});
it('should resolve wildcard config-file targets to the project, if applicable', function() {
shell.cp('-rf', ios_config_xml, temp);
shell.cp('-rf', cbplugin, plugins_dir);
configChanges.add_installed_plugin_to_prepare_queue(plugins_dir, 'ChildBrowser', 'ios', {});
var spy = spyOn(fs, 'readFileSync').andCallThrough();
configChanges.process(plugins_dir, temp, 'ios');
expect(spy).toHaveBeenCalledWith(path.join(temp, 'SampleApp', 'SampleApp-Info.plist'), 'utf8');
});
it('should move successfully installed plugins from queue to installed plugins section, and include/retain vars if applicable', function() {
shell.cp('-rf', android_two_project, temp);
shell.cp('-rf', varplugin, plugins_dir);
var cfg = configChanges.get_platform_json(plugins_dir, 'android');
cfg.prepare_queue.installed = [{'plugin':'VariablePlugin', 'vars':{"API_KEY":"hi"}}];
configChanges.save_platform_json(cfg, plugins_dir, 'android');
configChanges.add_installed_plugin_to_prepare_queue(plugins_dir, 'VariablePlugin', 'android', {"API_KEY":"hi"});

@@ -288,5 +321,3 @@ configChanges.process(plugins_dir, temp, 'android');

shell.cp('-rf', varplugin, plugins_dir);
var cfg = configChanges.get_platform_json(plugins_dir, 'android');
cfg.prepare_queue.installed = [{'plugin':'VariablePlugin', 'vars':{"API_KEY":"hi"}}];
configChanges.save_platform_json(cfg, plugins_dir, 'android');
configChanges.add_installed_plugin_to_prepare_queue(plugins_dir, 'VariablePlugin', 'android', {"API_KEY":"hi"});

@@ -314,14 +345,103 @@ var spy = spyOn(configChanges, 'save_platform_json');

it('should call pruneXML for every config munge it completely removes from the app (every leaf that is decremented to 0)', function() {
shell.cp('-rf', android_two_project, temp);
// Run through an "install"
configChanges.add_installed_plugin_to_prepare_queue(plugins_dir, 'DummyPlugin', 'android', {});
configChanges.process(plugins_dir, temp, 'android');
// Now set up an uninstall and make sure prunexml is called properly
configChanges.add_uninstalled_plugin_to_prepare_queue(plugins_dir, 'DummyPlugin', 'android');
var spy = spyOn(xml_helpers, 'pruneXML').andReturn(true);
configChanges.process(plugins_dir, temp, 'android');
expect(spy.calls.length).toEqual(4);
expect(spy.argsForCall[0][2]).toEqual('/*');
expect(spy.argsForCall[1][2]).toEqual('/*');
expect(spy.argsForCall[2][2]).toEqual('/manifest/application');
expect(spy.argsForCall[3][2]).toEqual('/cordova/plugins');
});
it('should call pruneXML with variables to interpolate if applicable', function() {
it('should generate a config munge that interpolates variables into config changes, if applicable', function() {
shell.cp('-rf', android_two_project, temp);
shell.cp('-rf', varplugin, plugins_dir);
// Run through an "install"
configChanges.add_installed_plugin_to_prepare_queue(plugins_dir, 'VariablePlugin', 'android', {"API_KEY":"canucks"});
configChanges.process(plugins_dir, temp, 'android');
// Now set up an uninstall and make sure prunexml is called properly
configChanges.add_uninstalled_plugin_to_prepare_queue(plugins_dir, 'VariablePlugin', 'android');
var spy = spyOn(configChanges, 'generate_plugin_config_munge').andReturn({});
configChanges.process(plugins_dir, temp, 'android');
var munge_params = spy.mostRecentCall.args;
expect(munge_params[0]).toEqual(path.join(plugins_dir, 'VariablePlugin'));
expect(munge_params[1]).toEqual('android');
expect(munge_params[2]).toEqual(temp);
expect(munge_params[3]['API_KEY']).toEqual('canucks');
});
it('should not call pruneXML for a config munge that another plugin depends on', function() {
shell.cp('-rf', android_two_no_perms_project, temp);
shell.cp('-rf', childrenplugin, plugins_dir);
shell.cp('-rf', shareddepsplugin, plugins_dir);
// Run through and "install" two plugins (they share a permission for INTERNET)
configChanges.add_installed_plugin_to_prepare_queue(plugins_dir, 'multiple-children', 'android', {});
configChanges.add_installed_plugin_to_prepare_queue(plugins_dir, 'shared-deps-multi-child', 'android', {});
configChanges.process(plugins_dir, temp, 'android');
// Now set up an uninstall for multi-child plugin
configChanges.add_uninstalled_plugin_to_prepare_queue(plugins_dir, 'multiple-children', 'android');
configChanges.process(plugins_dir, temp, 'android');
var am_xml = new et.ElementTree(et.XML(fs.readFileSync(path.join(temp, 'AndroidManifest.xml'), 'utf-8')));
var permission = am_xml.find('./uses-permission');
expect(permission).toBeDefined();
expect(permission.attrib['android:name']).toEqual('android.permission.INTERNET');
});
it('should not call pruneXML for a config munge targeting a config file that does not exist', function() {
shell.cp('-rf', android_two_project, temp);
// install a plugin
configChanges.add_installed_plugin_to_prepare_queue(plugins_dir, 'DummyPlugin', 'android', {});
configChanges.process(plugins_dir, temp, 'android');
// set up an uninstall for the same plugin
configChanges.add_uninstalled_plugin_to_prepare_queue(plugins_dir, 'DummyPlugin', 'android', {});
var spy = spyOn(fs, 'readFileSync').andCallThrough();
configChanges.process(plugins_dir, temp, 'android');
expect(spy).not.toHaveBeenCalledWith(path.join(temp, 'res', 'xml', 'plugins.xml'), 'utf-8');
});
it('should remove uninstalled plugins from installed plugins list', function() {
shell.cp('-rf', android_two_project, temp);
shell.cp('-rf', varplugin, plugins_dir);
// install the var plugin
configChanges.add_installed_plugin_to_prepare_queue(plugins_dir, 'VariablePlugin', 'android', {"API_KEY":"eat my shorts"});
configChanges.process(plugins_dir, temp, 'android');
// queue up an uninstall for the same plugin
configChanges.add_uninstalled_plugin_to_prepare_queue(plugins_dir, 'VariablePlugin', 'android');
configChanges.process(plugins_dir, temp, 'android');
var cfg = configChanges.get_platform_json(plugins_dir, 'android');
expect(cfg.prepare_queue.uninstalled.length).toEqual(0);
expect(cfg.installed_plugins['com.adobe.vars']).not.toBeDefined();
});
it('should only parse + remove plist plugin entries in applicably old ios projects', function() {
shell.cp('-rf', ios_plist_project, temp);
// install plugin
configChanges.add_installed_plugin_to_prepare_queue(plugins_dir, 'DummyPlugin', 'ios', {});
configChanges.process(plugins_dir, temp, 'ios');
// set up an uninstall
configChanges.add_uninstalled_plugin_to_prepare_queue(plugins_dir, 'DummyPlugin', 'ios');
var spy = spyOn(plist, 'parseFileSync').andReturn({Plugins:{}});
configChanges.process(plugins_dir, temp, 'ios');
expect(spy).toHaveBeenCalledWith(path.join(temp, 'SampleApp', 'PhoneGap.plist'));
});
it('should save changes to global config munge after completing an uninstall', function() {
shell.cp('-rf', android_two_project, temp);
shell.cp('-rf', varplugin, plugins_dir);
// install a plugin
configChanges.add_installed_plugin_to_prepare_queue(plugins_dir, 'VariablePlugin', 'android', {"API_KEY":"eat my shorts"});
configChanges.process(plugins_dir, temp, 'android');
// set up an uninstall for the plugin
configChanges.add_uninstalled_plugin_to_prepare_queue(plugins_dir, 'VariablePlugin', 'android');
var spy = spyOn(configChanges, 'save_platform_json');
configChanges.process(plugins_dir, temp, 'android');
expect(spy).toHaveBeenCalled();
});

@@ -328,0 +448,0 @@ });

@@ -30,24 +30,2 @@ #!/usr/bin/env node

describe('server', function(){
it('should receive the correct request when searching for a plugin', function(){
var mySpy = spyOn(http, 'get').andCallThrough();
// this clears the timeout in plugins.js
var spyTimeout = spyOn(global, 'setTimeout');
plugins.getPluginInfo('ChildBrowser', function() {});
expect(mySpy).toHaveBeenCalled();
expect(mySpy.argsForCall[0][0]).toBe('http://plugins.cordova.io/cordova_plugins/_design/cordova_plugins/_view/by_name?key="ChildBrowser"');
});
it('should receive the correct request when searching for a list of plugins', function(){
var mySpy = spyOn(http, 'get').andCallThrough();
// this clears the timeout in plugins.js
var spyTimeout = spyOn(global, 'setTimeout');
plugins.listAllPlugins(function(){});
expect(mySpy).toHaveBeenCalled();
expect(mySpy.argsForCall[0][0]).toBe('http://plugins.cordova.io/cordova_plugins/_design/cordova_plugins/_view/by_name');
});
it('should be able to receive the correct git clone arguments', function(){

@@ -54,0 +32,0 @@ var mySpy = spyOn(plugins, 'clonePluginGitRepo');

@@ -34,40 +34,96 @@ /*

describe('xml-helpers', function(){
it('should return false for different tags', function(){
expect(xml_helpers.equalNodes(usesNetworkOne, title)).toBe(false);
describe('equalNodes', function() {
it('should return false for different tags', function(){
expect(xml_helpers.equalNodes(usesNetworkOne, title)).toBe(false);
});
it('should return true for identical tags', function(){
expect(xml_helpers.equalNodes(usesNetworkOne, usesNetworkTwo)).toBe(true);
});
it('should return false for different attributes', function(){
expect(xml_helpers.equalNodes(usesNetworkOne, usesReceive)).toBe(false);
});
it('should distinguish between text', function(){
expect(xml_helpers.equalNodes(helloTagOne, goodbyeTag)).toBe(false);
});
it('should ignore whitespace in text', function(){
expect(xml_helpers.equalNodes(helloTagOne, helloTagTwo)).toBe(true);
});
describe('should compare children', function(){
it('by child quantity', function(){
var one = et.XML('<i><b>o</b></i>'),
two = et.XML('<i><b>o</b><u></u></i>');
expect(xml_helpers.equalNodes(one, two)).toBe(false);
});
it('by child equality', function(){
var one = et.XML('<i><b>o</b></i>'),
two = et.XML('<i><u></u></i>'),
uno = et.XML('<i>\n<b>o</b>\n</i>');
expect(xml_helpers.equalNodes(one, uno)).toBe(true);
expect(xml_helpers.equalNodes(one, two)).toBe(false);
});
});
});
describe('pruneXML', function() {
var config_xml;
it('should return true for identical tags', function(){
expect(xml_helpers.equalNodes(usesNetworkOne, usesNetworkTwo)).toBe(true);
});
it('should return false for different attributes', function(){
expect(xml_helpers.equalNodes(usesNetworkOne, usesReceive)).toBe(false);
});
it('should distinguish between text', function(){
expect(xml_helpers.equalNodes(helloTagOne, goodbyeTag)).toBe(false);
});
it('should ignore whitespace in text', function(){
expect(xml_helpers.equalNodes(helloTagOne, helloTagTwo)).toBe(true);
});
describe('should compare children', function(){
it('by child quantity', function(){
var one = et.XML('<i><b>o</b></i>'),
two = et.XML('<i><b>o</b><u></u></i>');
expect(xml_helpers.equalNodes(one, two)).toBe(false);
beforeEach(function() {
config_xml = xml_helpers.parseElementtreeSync(path.join(__dirname, '..', 'projects', 'android_two', 'res', 'xml', 'config.xml'));
});
it('by child equality', function(){
var one = et.XML('<i><b>o</b></i>'),
two = et.XML('<i><u></u></i>'),
uno = et.XML('<i>\n<b>o</b>\n</i>');
expect(xml_helpers.equalNodes(one, uno)).toBe(true);
expect(xml_helpers.equalNodes(one, two)).toBe(false);
it('should remove any children that match the specified selector', function() {
var children = config_xml.findall('plugins/plugin');
xml_helpers.pruneXML(config_xml, children, 'plugins');
expect(config_xml.find('plugins').getchildren().length).toEqual(0);
});
});
it('should do nothing if the children cannot be found', function() {
var children = [title];
xml_helpers.pruneXML(config_xml, children, 'plugins');
expect(config_xml.find('plugins').getchildren().length).toEqual(17);
});
it('should be able to handle absolute selectors', function() {
var children = config_xml.findall('plugins/plugin');
xml_helpers.pruneXML(config_xml, children, '/cordova/plugins');
expect(config_xml.find('plugins').getchildren().length).toEqual(0);
});
it('should be able to handle absolute selectors with wildcards', function() {
var children = config_xml.findall('plugins/plugin');
xml_helpers.pruneXML(config_xml, children, '/*/plugins');
expect(config_xml.find('plugins').getchildren().length).toEqual(0);
});
});
describe('graftXML', function() {
var config_xml, plugin_xml;
beforeEach(function() {
config_xml = xml_helpers.parseElementtreeSync(path.join(__dirname, '..', 'projects', 'android_two', 'res', 'xml', 'config.xml'));
plugin_xml = xml_helpers.parseElementtreeSync(path.join(__dirname, '..', 'plugins', 'ChildBrowser', 'plugin.xml'));
});
it('should add children to the specified selector', function() {
var children = plugin_xml.find('config-file').getchildren();
xml_helpers.graftXML(config_xml, children, 'plugins');
expect(config_xml.find('plugins').getchildren().length).toEqual(19);
});
it('should be able to handle absolute selectors', function() {
var children = plugin_xml.find('config-file').getchildren();
xml_helpers.graftXML(config_xml, children, '/cordova');
expect(config_xml.findall('access').length).toEqual(3);
});
it('should be able to handle absolute selectors with wildcards', function() {
var children = plugin_xml.find('config-file').getchildren();
xml_helpers.graftXML(config_xml, children, '/*');
expect(config_xml.findall('access').length).toEqual(3);
});
});
});

@@ -19,12 +19,2 @@ var shell = require('shelljs'),

}
} else if(!fs.existsSync(plugin_dir)) {
if (link) {
var err = new Error('--link is not supported for name installations');
if (callback) callback(err);
else throw err;
} else {
plugins.getPluginInfo(plugin_dir, function(err, plugin_info) {
plugins.clonePluginGitRepo(plugin_info.url, plugins_dir, callback);
});
}
} else {

@@ -38,4 +28,3 @@ // Copy from the local filesystem.

} else {
// XXX if you don't path.resolve(plugin_dir) and plugin_dir has a trailing slash shelljs shits itself.
shell.cp('-R', path.resolve(plugin_dir), plugins_dir); // Yes, not dest.
shell.cp('-R', plugin_dir, plugins_dir); // Yes, not dest.
}

@@ -42,0 +31,0 @@

@@ -83,4 +83,2 @@ var path = require('path'),

}
// TODO: handle asset elements
// TODO: if plugin does not have platform tag but has platform-agnostic config changes, should we queue it up?

@@ -92,4 +90,3 @@ var platformTag = plugin_et.find('./platform[@name="'+platform+'"]');

// should call prepare probably!
require('./../plugman').prepare(project_dir, platform, plugins_dir);
if (callback) callback();
finalizeInstall(project_dir, plugins_dir, platform, plugin_basename, filtered_variables, callback);
return;

@@ -109,8 +106,36 @@ }

txs = txs.concat(sourceFiles, headerFiles, resourceFiles, frameworks, assets);
// asset installation
var installedAssets = [];
var common = require('./platforms/common');
try {
for(var i = 0, j = assets.length ; i < j ; i++) {
var src = assets[i].attrib['src'],
target = assets[i].attrib['target'];
common.copyFile(plugin_dir, src, handler.www_dir(project_dir), target);
installedAssets.push(assets[i]);
}
} catch(err) {
var issue = 'asset installation failed\n'+err.stack+'\n';
try {
// removing assets and reverting install
for(var i = 0, j = installedAssets.length ; i < j ; i++) {
common.removeFile(handler.www_dir(project_dir), installedAssets[i].target);
}
common.removeFileF(path.resolve(handler.www_dir(project_dir), 'plugins', plugin_id));
issue += 'but successfully reverted\n';
} catch(err2) {
issue += 'and reversion failed :(\n' + err2.stack;
}
var error = new Error(issue);
if (callback) callback(error);
else throw error;
}
txs = txs.concat(sourceFiles, headerFiles, resourceFiles, frameworks);
// pass platform-specific transactions into install
handler.install(txs, plugin_id, project_dir, plugin_dir, filtered_variables, function(err) {
if (err) {
// FAIL
// TODO revert assets at this point too
if (err. transactions) {

@@ -134,8 +159,4 @@ handler.uninstall(err.transactions.executed, plugin_id, project_dir, plugin_dir, function(superr) {

} else {
// WIN!
// queue up the plugin so prepare knows what to do.
config_changes.add_installed_plugin_to_prepare_queue(plugins_dir, path.basename(plugin_dir), platform, filtered_variables);
// call prepare after a successful install
require('./../plugman').prepare(project_dir, platform, plugins_dir);
// Log out plugin INFO element contents in case additional install steps are necessary

@@ -146,5 +167,15 @@ var info = platformTag.findall('./info');

}
if (callback) callback();
finalizeInstall(project_dir, plugins_dir, platform, plugin_basename, filtered_variables, callback);
}
});
}
function finalizeInstall(project_dir, plugins_dir, platform, plugin_name, variables, callback) {
// queue up the plugin so prepare knows what to do.
config_changes.add_installed_plugin_to_prepare_queue(plugins_dir, plugin_name, platform, variables);
// call prepare after a successful install
require('./../plugman').prepare(project_dir, platform, plugins_dir);
if (callback) callback();
}

@@ -37,2 +37,10 @@ /*

return path.join(project_dir, 'assets', 'www');
},
// reads the package name out of the Android Manifest file
// @param string project_dir the absolute path to the directory containing the project
// @return string the name of the package
package_name:function (project_dir) {
var mDoc = xml_helpers.parseElementtreeSync(path.join(project_dir, 'AndroidManifest.xml'));
return mDoc._root.attrib['package'];
}

@@ -42,3 +50,2 @@ };

function handlePlugin(action, plugin_id, txs, project_dir, plugin_dir, variables, callback) {
var PACKAGE_NAME = androidPackageName(project_dir);
variables = variables || {};

@@ -69,24 +76,2 @@

break;
case 'config-file':
// Only modify config files that exist.
var config_file = path.resolve(project_dir, mod.attrib['target']);
if (fs.existsSync(config_file)) {
var xmlDoc = xml_helpers.parseElementtreeSync(config_file);
var selector = mod.attrib["parent"];
var children = mod.findall('*');
if (action == 'install') {
if (!xml_helpers.graftXML(xmlDoc, children, selector)) {
throw new Error('failed to add config-file children to "' + selector + '" to "'+ config_file + '"');
}
} else {
if (!xml_helpers.pruneXML(xmlDoc, children, selector)) {
throw new Error('failed to remove config-file children from "' + selector + '" from "' + config_file + '"');
}
}
var output = xmlDoc.write({indent: 4});
fs.writeFileSync(config_file, output);
}
break;
case 'asset':

@@ -119,20 +104,3 @@ var src = mod.attrib['src'];

if (action == 'install') {
variables['PACKAGE_NAME'] = androidPackageName(project_dir);
var config_filename = path.resolve(project_dir, 'res', 'xml', 'config.xml');
if (!fs.existsSync(config_filename)) config_filename = path.resolve(project_dir, 'res', 'xml', 'plugins.xml');
plugins_module.searchAndReplace(config_filename, variables);
plugins_module.searchAndReplace(path.resolve(project_dir, 'AndroidManifest.xml'), variables);
}
if (callback) callback();
}
// reads the package name out of the Android Manifest file
// @param string project_dir the absolute path to the directory containing the project
// @return string the name of the package
function androidPackageName(project_dir) {
var mDoc = xml_helpers.parseElementtreeSync(path.resolve(project_dir, 'AndroidManifest.xml'));
return mDoc._root.attrib['package'];
}

@@ -37,2 +37,7 @@ /*

return path.join(project_dir, 'www');
},
package_name:function(project_dir) {
var config_path = path.join(module.exports.www_dir(project_dir), 'config.xml');
var widget_doc = new et.ElementTree(et.XML(fs.readFileSync(config_path, 'utf-8')));
return widget_doc._root.attrib['id'];
}

@@ -56,24 +61,2 @@ };

break;
case 'config-file':
// Only modify config files that exist.
var config_file = path.resolve(project_dir, mod.attrib['target']);
if (fs.existsSync(config_file)) {
var xmlDoc = xml_helpers.parseElementtreeSync(config_file);
var selector = mod.attrib["parent"];
var children = mod.findall('*');
if (action == 'install') {
if (!xml_helpers.graftXML(xmlDoc, children, selector)) {
throw new Error('failed to add config-file children to "' + filename + '"');
}
} else {
if (!xml_helpers.pruneXML(xmlDoc, children, selector)) {
throw new Error('failed to remove config-file children from "' + filename + '"');
}
}
var output = xmlDoc.write({indent: 4});
fs.writeFileSync(config_file, output);
}
break;
case 'asset':

@@ -80,0 +63,0 @@ var src = mod.attrib['src'];

@@ -42,2 +42,6 @@ /*

return path.join(project_dir, 'www');
},
package_name:function(project_dir) {
var plist_file = glob.sync(path.join(project_dir, '**', '*-Info.plist'))[0];
return plist.parseFileSync(plist_file).CFBundleIdentifier;
}

@@ -102,3 +106,2 @@ };

var destFile = path.resolve(targetDir, path.basename(src));
if (action == 'install') {

@@ -111,87 +114,10 @@ if (!fs.existsSync(srcFile)) throw new Error('cannot find "' + srcFile + '" ios <source-file>');

} else {
xcodeproj.removeSourceFile(path.join('Plugins', path.basename(src)));
xcodeproj.removeSourceFile(path.join('Plugins', path.relative(pluginsDir, destFile)));
shell.rm('-rf', destFile);
// TODO: is this right, should we check if dir is empty?
shell.rm('-rf', targetDir);
}
break;
case 'plugins-plist':
var name = mod.attrib.key;
var value = mod.attrib.string;
// Tack on stuff into plist if this is an old-style project
if (path.extname(config_file) == '.plist') {
// determine if this is a binary or ascii plist and choose the parser
// TODO: this is temporary until binary support is added to node-plist
var pl = (isBinaryPlist(config_file) ? bplist : plist);
var plistObj = pl.parseFileSync(config_file);
if (action == 'install') {
// TODO: move to prepare?
// add hosts to whitelist (ExternalHosts) in plist
/*
hosts && hosts.forEach(function(host) {
plistObj.ExternalHosts.push(host.attrib['origin']);
});
*/
// add plugin to plist
plistObj.Plugins[name] = value;
} else {
delete plistObj.Plugins[name];
if(fs.existsSync(targetDir) && fs.readdirSync(targetDir).length>0){
shell.rm('-rf', targetDir);
}
// write out plist
fs.writeFileSync(config_file, plist.build(plistObj));
} else {
// If it's a config.xml-based project, we should still add/remove plugin entry to config.xml
var xmlDoc = xml_helpers.parseElementtreeSync(config_file);
var pluginsEl = xmlDoc.find('plugins');
// Only add if it's not already there.
if (pluginsEl.findall('./plugin[@name="' + name + '"]').length === 0) {
if ( action == 'install') {
var new_plugin = new et.Element('plugin');
new_plugin.attrib.name = name;
new_plugin.attrib.value = value;
pluginsEl.append(new_plugin);
} else {
var culprit = pluginsEl.find("plugin[@name='"+name+"']");
pluginsEl.remove(0, culprit);
}
var output = xmlDoc.write({indent: 4});
fs.writeFileSync(config_file, output);
}
}
break;
case 'config-file':
// Only use config file appropriate for the current cordova-ios project
if (mod.attrib['target'] == config_filename) {
// edit configuration files
var xmlDoc = xml_helpers.parseElementtreeSync(config_file);
var selector = mod.attrib["parent"],
children = mod.findall('*');
if( action == 'install') {
// Throw error if plugin was already added.
if (children.length == 1 && children[0].tag.toLowerCase() == 'plugin' && (xmlDoc.find('plugins').findall('./plugin[@name="' + children[0].attrib.name + '"]').length === 1)
||(xmlDoc.find('plugins').findall('./plugin[@value="' + children[0].attrib.value + '"]').length === 1)){
throw new Error('faild to add '+children[0].attrib.name+' to config.xml because it already exists');
}
if (!xml_helpers.graftXML(xmlDoc, children, selector)) {
throw new Error('failed to add config-file children to xpath "' + selector + '" in "' + config_file + '" because xpath selector could not be resolved.');
}
} else {
// Ignore if plugin was already removed.
if (children.length == 1 && children[0].tag.toLowerCase() == 'plugin' && xmlDoc.find('plugins').findall('./plugin[@name="' + children[0].attrib.name + '"]').length === 0) break;
if (!xml_helpers.pruneXML(xmlDoc, children, selector)) {
throw new Error('failed to remove config-file children from "' + selector + '" from "' + config_path + '"');
}
}
var output = xmlDoc.write({indent: 4});
fs.writeFileSync(config_file, output);
}
break;
case 'asset':

@@ -204,3 +130,3 @@ var src = mod.attrib['src'];

common.removeFile(module.exports.www_dir(project_dir), target);
common.removeFile(path.resolve(module.exports.www_dir(project_dir), 'plugins', plugin_id));
common.removeFile(path.join(module.exports.www_dir(project_dir), 'plugins'), plugin_id);
}

@@ -221,3 +147,3 @@ break;

// TODO: doesnt preserve-dirs affect what the originally-added path to xcodeproj (see above) affect how we should call remove too?
xcodeproj.removeHeaderFile(path.join('Plugins', path.basename(src)));
xcodeproj.removeHeaderFile(path.join('Plugins', path.relative(pluginsDir, destFile)));
shell.rm('-rf', destFile);

@@ -254,3 +180,3 @@ // TODO: again.. is this right? same as source-file

default:
throw new Error('Unrecognized plugin.xml element/action in android installer: ' + mod.tag);
throw new Error('Unrecognized plugin.xml element/action in ios installer: ' + mod.tag);
break;

@@ -270,12 +196,5 @@ }

}
// write out xcodeproj file
fs.writeFileSync(pbxPath, xcodeproj.writeSync());
if (action == 'install') {
variables['PACKAGE_NAME'] = plist.parseFileSync(projectPListPath).CFBundleIdentifier;
searchAndReplace(pbxPath, variables);
searchAndReplace(projectPListPath, variables);
searchAndReplace(config_file, variables);
}
if (callback) callback();

@@ -282,0 +201,0 @@ }

@@ -35,6 +35,3 @@ var path = require('path'),

// TODO: remove any asset elements
var platformTag = plugin_et.find('./platform[@name="'+platform+'"]');
var platformTag = plugin_et.find('./platform[@name="'+platform+'"]');
if (!platformTag) {

@@ -56,9 +53,34 @@ // Either this plugin doesn't support this platform, or it's a JS-only plugin.

assets = platformTag.findall('./asset'),
frameworks = platformTag.findall('./framework'),
pluginsPlist = platformTag.findall('./plugins-plist'),
configChanges = platformTag.findall('./config-file');
frameworks = platformTag.findall('./framework');
assets = assets.concat(plugin_et.findall('./asset'));
txs = txs.concat(sourceFiles, headerFiles, resourceFiles, frameworks, configChanges, assets, pluginsPlist);
// asset uninstallation
var uninstalledAssets = [];
var common = require('./platforms/common');
try {
for(var i = 0, j = assets.length ; i < j ; i++) {
common.removeFile(handler.www_dir(project_dir), assets[i].attrib['target']);
uninstalledAssets.push(assets[i]);
}
common.removeFileF(path.resolve(handler.www_dir(project_dir), 'plugins', plugin_id));
} catch(err) {
var issue = 'asset uninstallation failed\n'+err.stack+'\n';
try {
// adding assets back
for(var i = 0, j = uninstalledAssets.length ; i < j ; i++) {
var src = uninstalledAssets[i].attrib['src'],
target = uninstalledAssets[i].attrib['target'];
common.copyFile(plugin_dir, src, handler.www_dir(project_dir), target);
}
issue += 'but successfully reverted\n';
} catch(err2) {
issue += 'and reversion failed :(\n' + err2.stack;
}
var error = new Error(issue);
if (callback) callback(error);
else throw error;
}
txs = txs.concat(sourceFiles, headerFiles, resourceFiles, frameworks);
// pass platform-specific transactions into uninstall

@@ -68,2 +90,3 @@ handler.uninstall(txs, plugin_id, project_dir, plugin_dir, function(err) {

// FAIL
// TODO revert assets here too
if (err. transactions) {

@@ -70,0 +93,0 @@ handler.install(err.transactions.executed, plugin_id, project_dir, plugin_dir, cli_variables, function(superr) {

@@ -27,3 +27,4 @@ /*

platforms = require('./../platforms'),
xml_helpers = require('./../util/xml-helpers');
xml_helpers = require('./../util/xml-helpers'),
plist_helpers = require('./../util/plist-helpers');

@@ -72,5 +73,12 @@ function checkPlatform(platform) {

},
generate_plugin_config_munge:function(plugin_dir, platform, vars) {
generate_plugin_config_munge:function(plugin_dir, platform, project_dir, vars) {
checkPlatform(platform);
vars = vars || {};
var platform_handler = platforms[platform];
// Add PACKAGE_NAME variable into vars
if (!vars['PACKAGE_NAME']) {
vars['PACKAGE_NAME'] = platform_handler.package_name(project_dir);
}
var munge = {};

@@ -80,23 +88,31 @@ var plugin_xml = new et.ElementTree(et.XML(fs.readFileSync(path.join(plugin_dir, 'plugin.xml'), 'utf-8')));

var platformTag = plugin_xml.find('platform[@name="' + platform + '"]');
var changes = platformTag.findall('config-file');
// note down plugins-plist munges in special section of munge obj
var plugins_plist = platformTag.findall('plugins-plist');
plugins_plist.forEach(function(pl) {
if (!munge['plugins-plist']) {
munge['plugins-plist'] = {};
}
var key = pl.attrib['key'];
var value = pl.attrib['string'];
if (!munge['plugins-plist'][key]) {
munge['plugins-plist'][key] = value;
}
});
var changes = [];
// add platform-agnostic config changes
changes = changes.concat(plugin_xml.findall('config-file'));
if (platformTag) {
// add platform-specific config changes if they exist
changes = changes.concat(platformTag.findall('config-file'));
// note down plugins-plist munges in special section of munge obj
var plugins_plist = platformTag.findall('plugins-plist');
plugins_plist.forEach(function(pl) {
if (!munge['plugins-plist']) {
munge['plugins-plist'] = {};
}
var key = pl.attrib['key'];
var value = pl.attrib['string'];
if (!munge['plugins-plist'][key]) {
munge['plugins-plist'][key] = value;
}
});
}
changes.forEach(function(change) {
var target = change.attrib['target'];
var parent = change.attrib['parent'];
if (!munge[target]) {
munge[target] = {};
}
if (!munge[target][change.attrib['parent']]) {
munge[target][change.attrib['parent']] = {};
if (!munge[target][parent]) {
munge[target][parent] = {};
}

@@ -113,6 +129,6 @@ var xmls = change.getchildren();

// 2. add into munge
if (!munge[target][change.attrib['parent']][stringified]) {
munge[target][change.attrib['parent']][stringified] = 0;
if (!munge[target][parent][stringified]) {
munge[target][parent][stringified] = 0;
}
munge[target][change.attrib['parent']][stringified] += 1;
munge[target][parent][stringified] += 1;
});

@@ -130,6 +146,6 @@ });

var plugin_id = u.id;
var plugin_vars = platform_config.installed_plugins[plugin_id].vars;
var plugin_vars = platform_config.installed_plugins[plugin_id];
// get config munge, aka how did this plugin change various config files
var config_munge = module.exports.generate_plugin_config_munge(plugin_dir, platform, plugin_vars);
var config_munge = module.exports.generate_plugin_config_munge(plugin_dir, platform, project_dir, plugin_vars);
// global munge looks at all plugins' changes to config files

@@ -170,10 +186,21 @@ var global_munge = platform_config.config_munge;

if (fs.existsSync(filepath)) {
var doc = new et.ElementTree(et.XML(fs.readFileSync(filepath, 'utf-8')));
var xml_to_prune = [new et.ElementTree(et.XML(xml_child)).getroot()];
if (xml_helpers.pruneXML(doc, xml_to_prune, selector)) {
// were good, write out the file!
fs.writeFileSync(filepath, doc.write(), 'utf-8');
if (path.extname(filepath) == '.xml') {
var xml_to_prune = [et.XML(xml_child)];
var doc = new et.ElementTree(et.XML(fs.readFileSync(filepath, 'utf-8')));
if (xml_helpers.pruneXML(doc, xml_to_prune, selector)) {
// were good, write out the file!
fs.writeFileSync(filepath, doc.write(), 'utf-8');
} else {
// uh oh
throw new Error('pruning xml at selector "' + selector + '" from "' + filepath + '" during config uninstall went bad :(');
}
} else {
// uh oh
throw new Error('pruning xml during config uninstall went bad :(');
// plist file
var pl = (isBinaryPlist(filepath) ? bplist : plist);
var plistObj = pl.parseFileSync(filepath);
if (plist_helpers.prunePLIST(plistObj, xml_child, selector)) {
fs.writeFileSync(filepath, plist.build(plistObj));
} else {
throw new Error('grafting to plist "' + filepath + '" during config install went bad :(');
}
}

@@ -205,3 +232,3 @@ }

// get config munge, aka how should this plugin change various config files
var config_munge = module.exports.generate_plugin_config_munge(plugin_dir, platform, plugin_vars);
var config_munge = module.exports.generate_plugin_config_munge(plugin_dir, platform, project_dir, plugin_vars);
// global munge looks at all plugins' changes to config files

@@ -246,10 +273,22 @@ var global_munge = platform_config.config_munge;

if (fs.existsSync(filepath)) {
var doc = new et.ElementTree(et.XML(fs.readFileSync(filepath, 'utf-8')));
var xml_to_graft = [new et.ElementTree(et.XML(xml_child)).getroot()];
if (xml_helpers.graftXML(doc, xml_to_graft, selector)) {
// were good, write out the file!
fs.writeFileSync(filepath, doc.write(), 'utf-8');
// look at ext and do proper config change based on file type
if (path.extname(filepath) == '.xml') {
var xml_to_graft = [et.XML(xml_child)];
var doc = new et.ElementTree(et.XML(fs.readFileSync(filepath, 'utf-8')));
if (xml_helpers.graftXML(doc, xml_to_graft, selector)) {
// were good, write out the file!
fs.writeFileSync(filepath, doc.write(), 'utf-8');
} else {
// uh oh
throw new Error('grafting xml at selector "' + selector + '" from "' + filepath + '" during config install went bad :(');
}
} else {
// uh oh
throw new Error('grafting xml during config install went bad :(');
// plist file
var pl = (isBinaryPlist(filepath) ? bplist : plist);
var plistObj = pl.parseFileSync(filepath);
if (plist_helpers.graftPLIST(plistObj, xml_child, selector)) {
fs.writeFileSync(filepath, plist.build(plistObj));
} else {
throw new Error('grafting to plist "' + filepath + '" during config install went bad :(');
}
}

@@ -265,3 +304,3 @@ }

// Move to installed_plugins
platform_config.installed_plugins[plugin_id] = plugin_vars;
platform_config.installed_plugins[plugin_id] = plugin_vars || {};
});

@@ -286,8 +325,17 @@

// Some config-file target attributes are not qualified with a full leading directory, or contain wildcards. resolve to a real path in this function
function resolveConfigFilePath(project_dir, platform, file) {
var filepath = path.join(project_dir, file);
if (platform == 'ios' && file == 'config.xml') {
filepath = glob.sync(path.join(project_dir, '**', 'config.xml'))[0];
if (file.indexOf('*') > -1) {
// handle wildcards in targets using glob.
var matches = glob.sync(path.join(project_dir, '**', file));
if (matches.length) filepath = matches[0];
} else {
// special-case config.xml target that is just "config.xml". this should be resolved to the real location of the file.
if (file == 'config.xml') {
var matches = glob.sync(path.join(project_dir, '**', 'config.xml'));
if (matches.length) filepath = matches[0];
}
}
return filepath;
}

@@ -26,23 +26,22 @@ /*

// adds node to doc at selector
exports.graftPLIST = function (doc, nodes, selector) {
var text = et.tostring(nodes, { xml_declaration: false });
obj = plist.parseStringSync("<plist>"+text+"</plist>");
module.exports = {
graftPLIST:function (doc, xml, selector) {
var obj = plist.parseStringSync("<plist>"+xml+"</plist>");
var node = doc[selector];
if (node && Array.isArray(node) && Array.isArray(obj))
doc[selector] = node.concat(obj);
else
doc[selector] = obj;
var node = doc[selector];
if (node && Array.isArray(node) && Array.isArray(obj))
doc[selector] = node.concat(obj);
else
doc[selector] = obj;
return true;
}
return true;
},
// removes node from doc at selector
prunePLIST:function(doc, xml, selector) {
var obj = plist.parseStringSync("<plist>"+xml+"</plist>");
pruneOBJECT(doc, selector, obj);
// removes node from doc at selector
exports.prunePLIST = function(doc, nodes, selector) {
var text = et.tostring(nodes, { xml_declaration: false }),
obj = plist.parseStringSync("<plist>"+text+"</plist>");
pruneOBJECT(doc, selector, obj);
return true;
return true;
}
}

@@ -91,2 +90,1 @@

};

@@ -22,8 +22,7 @@ #!/usr/bin/env node

var http = require('http'),
osenv = require('osenv'),
os = require('os'),
path = require('path'),
fs = require('fs'),
util = require('util'),
shell = require('shelljs'),
remote = require(path.join(__dirname, '..', '..', 'config', 'remote'));
shell = require('shelljs');

@@ -33,47 +32,2 @@ module.exports = {

// Fetches plugin information from remote server
getPluginInfo:function(plugin_name, callback) {
var responded = false;
http.get(remote.url + util.format(remote.query_path, plugin_name), function(res) {
var str = '';
res.on('data', function (chunk) {
str += chunk;
});
res.on('end', function () {
responded = true;
var response, plugin_info;
if((response = JSON.parse(str)).rows.length == 1) {
plugin_info = response.rows[0].value;
callback(null, plugin_info);
} else {
callback("Could not find information on "+plugin_name+" plugin");
}
});
}).on('error', function(e) {
callback(e);
});
setTimeout(function() {
if (!responded) {
console.log('timed out');
callback('timed out')
}
}, 3000);
},
listAllPlugins:function(success, error) {
http.get(remote.url + remote.list_path, function(res) {
var str = '';
res.on('data', function (chunk) {
str += chunk;
});
res.on('end', function () {
var plugins = (JSON.parse(str)).rows;
success(plugins);
});
}).on('error', function(e) {
console.log("Got error: " + e.message);
error(e.message);
});
},
clonePluginGitRepo:function(plugin_git_url, plugins_dir, callback) {

@@ -85,11 +39,4 @@ if(!shell.which('git')) {

}
// use osenv to get a temp directory in a portable way
var lastSlash = plugin_git_url.lastIndexOf('/');
var basename = plugin_git_url.substring(lastSlash+1);
var dotGitIndex = basename.lastIndexOf('.git');
if (dotGitIndex >= 0) {
basename = basename.substring(0, dotGitIndex);
}
var plugin_dir = path.join(plugins_dir, basename);
var plugin_dir = path.join(plugins_dir, path.basename(plugin_git_url).replace(path.extname(plugin_git_url), ''));

@@ -111,18 +58,4 @@ // trash it if it already exists (something went wrong before probably)

});
}
// TODO add method for archives and other formats
// extractArchive:function(plugin_dir) {
// }
// TODO add method to publish plugin from cli
// publishPlugin:function(plugin_dir) {
// }
// TODO add method to unpublish plugin from cli
// unpublishPlugin:function(plugin_dir) {
// }
},
};

@@ -76,24 +76,5 @@ /*

graftXML: function(doc, nodes, selector) {
var ROOT = /^\/([^\/]*)/
, ABSOLUTE = /^\/([^\/]*)\/(.*)/
, parent, tagName, subSelector;
var parent = resolveParent(doc, selector);
if (!parent) return false;
// handle absolute selector (which elementtree doesn't like)
if (ROOT.test(selector)) {
tagName = selector.match(ROOT)[1];
if (tagName === doc._root.tag) {
parent = doc._root;
// could be an absolute path, but not selecting the root
if (ABSOLUTE.test(selector)) {
subSelector = selector.match(ABSOLUTE)[2];
parent = parent.find(subSelector)
}
} else {
return false;
}
} else {
parent = doc.find(selector)
}
nodes.forEach(function (node) {

@@ -111,23 +92,5 @@ // check if child is unique first

pruneXML: function(doc, nodes, selector) {
var ROOT = /^\/([^\/]*)/
, ABSOLUTE = /^\/([^\/]*)\/(.*)/
, parent, tagName, subSelector;
var parent = resolveParent(doc, selector);
if (!parent) return false;
// handle absolute selector (which elementtree doesn't like)
if (ROOT.test(selector)) {
tagName = selector.match(ROOT)[1];
if (tagName === doc._root.tag) {
parent = doc._root;
// could be an absolute path, but not selecting the root
if (ABSOLUTE.test(selector)) {
subSelector = selector.match(ABSOLUTE)[2];
parent = parent.find(subSelector)
}
} else {
return false;
}
} else {
parent = doc.find(selector)
}
nodes.forEach(function (node) {

@@ -156,3 +119,3 @@ var matchingKid = null;

for (i = 0, j = matchingKids.length ; i < j ; i++) {
if (exports.equalNodes(node, matchingKids[i])) {
if (module.exports.equalNodes(node, matchingKids[i])) {
return matchingKids[i];

@@ -180,1 +143,26 @@ }

var ROOT = /^\/([^\/]*)/,
ABSOLUTE = /^\/([^\/]*)\/(.*)/;
function resolveParent(doc, selector) {
var parent, tagName, subSelector;
// handle absolute selector (which elementtree doesn't like)
if (ROOT.test(selector)) {
tagName = selector.match(ROOT)[1];
// test for wildcard "any-tag" root selector
if (tagName == '*' || tagName === doc._root.tag) {
parent = doc._root;
// could be an absolute path, but not selecting the root
if (ABSOLUTE.test(selector)) {
subSelector = selector.match(ABSOLUTE)[2];
parent = parent.find(subSelector)
}
} else {
return false;
}
} else {
parent = doc.find(selector)
}
return parent;
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc