Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
shinnn committed Oct 3, 2015
0 parents commit 8eba343
Show file tree
Hide file tree
Showing 10 changed files with 357 additions and 0 deletions.
12 changes: 12 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
root = true

[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
coverage
node_modules
Gemfile.lock
26 changes: 26 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
os:
- linux
- osx
git:
depth: 1
branches:
except: /^v\d/
language: ruby
rvm: 2.2.2
before_install: >-
if [[ $TRAVIS_OS_NAME == osx ]];
then rm -rf ~/.nvm &&
git clone --depth 1 https://github.com/creationix/nvm.git ~/.nvm &&
source ~/.nvm/nvm.sh;
fi;
before_script:
- nvm install stable
- npm install
- pod --version
- if [[ $TRAVIS_OS_NAME != osx ]]; then pod setup; fi;
script: npm run-script coverage
after_script:
- npm install istanbul-coveralls
- node node_modules/.bin/istanbul-coveralls
notifications:
email: false
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
source 'https://rubygems.org'
gem 'cocoapods'
20 changes: 20 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
The MIT License (MIT)

Copyright (c) 2015 Shinnosuke Watanabe

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
78 changes: 78 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# exec-pod-callback

[![NPM version](https://img.shields.io/npm/v/exec-pod-callback.svg)](https://www.npmjs.com/package/exec-pod-callback)
[![Build Status](https://travis-ci.org/shinnn/exec-pod-callback.svg?branch=master)](https://travis-ci.org/shinnn/exec-pod-callback)
[![Coverage Status](https://img.shields.io/coveralls/shinnn/exec-pod-callback.svg)](https://coveralls.io/r/shinnn/exec-pod-callback)
[![Dependency Status](https://david-dm.org/shinnn/exec-pod-callback.svg)](https://david-dm.org/shinnn/exec-pod-callback)
[![devDependency Status](https://david-dm.org/shinnn/exec-pod-callback/dev-status.svg)](https://david-dm.org/shinnn/exec-pod-callback#info=devDependencies)

[Callback](http://thenodeway.io/posts/understanding-error-first-callbacks/)-style version of [exec-pod]:

> Run a `pod` subcommand and buffer the output
```javascript
const execPodCallback = require('exec-pod-callback');

execPodCallback('search', ['AWS'], (err, stdout, stderr) => {
stdout; //=> '-> AWSAPIGateway (2.2.7)\n Amazon Web Services SDK for iOS ...'
});
```

## Installation

[Use npm](https://docs.npmjs.com/cli/install):

```
npm install exec-pod-callback
```

and make sure [`cocoapods`](https://rubygems.org/gems/cocoapods/versions/0.39.0) is [installed](https://guides.cocoapods.org/using/getting-started.html#installation).

## API

```javascript
const execPodCallback = require('exec-pod-callback');
```

### execPodCallback(*subcommand* [, *args*, *options*, *cb*])

*subcommand*: `String` (one of the `pod` [subcommands](https://guides.cocoapods.org/terminal/commands.html) to run e.g. `install`)
*args*: `Array` of strings (arguments passed to the command)
*options*: `Object`
*cb*: `Function` (callback function which takes three arguments: `error`, `stdout`, `stderr`)
Return: [ChildProcess](https://nodejs.org/api/child_process.html#child_process_class_childprocess) instance

It runs the given `pod` subcommand and passes buffered [`stdout`](https://nodejs.org/api/child_process.html#child_process_child_stdout)/[`stderr`](https://nodejs.org/api/child_process.html#child_process_child_stderr) values to the callback function.

```javascript
execPodCallback('install', ['AFNetworking'], {bundleExec: true}, (err, stdout, stderr) => {
if (err) {
throw err;
}

stdout; //=> 'Updating spec repo `master` ... '
});
```

#### Options

All [`child_process#execFile`](https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options) options and [`bundleExec`](#optionsbundleexec) option are available.

##### options.bundleExec

Type: `Boolean`
Default: `false`

`true` runs the `pod` command with [`bundle exec`](http://bundler.io/man/bundle-exec.1.html), instead of using globally installed `pod`.

## Related project

* [exec-pod][exec-pod] ([Promises/A+](https://promisesaplus.com/) version)

## License

Copyright (c) 2015 [Shinnosuke Watanabe](https://github.com/shinnn)

Licensed under [the MIT License](./LICENSE).

[exec-pod]: https://github.com/shinnn/exec-pod
58 changes: 58 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*!
* exec-pod-callback | MIT (c) Shinnosuke Watanabe
* https://github.com/shinnn/exec-pod-callback
*/
const execFileSubcommand = require('execfile-subcommand');

module.exports = function execPodCallback(subcommand, args, options, cb) {
'use strict';

if (typeof subcommand !== 'string') {
throw new TypeError(
String(subcommand) +
' is not a string. Expected one of the `pod` subcommands (e.g. `install`).'
);
}

if (subcommand === '') {
throw new Error('Expected one of the `pod` subcommands (e.g. `outdated`), but received an empty string.');
}

if (cb === undefined) {
if (options === undefined) {
cb = args;
args = [];
options = {};
} else {
cb = options;

if (Array.isArray(args)) {
options = {};
} else {
options = args || {};
args = [];
}
}
} else {
options = options || {};
}

if (options.bundleExec !== undefined && typeof options.bundleExec !== 'boolean') {
throw new TypeError(
String(options.bundleExec) +
' is not Boolean. `bundleExec` option must be Boolean (`false` by default).'
);
}

let cmd;

if (options.bundleExec) {
cmd = 'bundle';
args.unshift('pod', subcommand);
subcommand = 'exec';
} else {
cmd = 'pod';
}

return execFileSubcommand(cmd, subcommand, args, options, cb);
};
57 changes: 57 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"name": "exec-pod-callback",
"version": "1.0.0",
"description": "Callback-style version of exec-pod",
"repository": "shinnn/exec-pod-callback",
"author": "Shinnosuke Watanabe (https://github.com/shinnn)",
"scripts": {
"pretest": "eslint --config @shinnn/node index.js test.js",
"test": "node --strong_mode --harmony_rest_parameters --throw-deprecation --track-heap-objects test.js",
"coverage": "node --strong_mode node_modules/.bin/istanbul cover test.js"
},
"license": "MIT",
"files": [
"index.js"
],
"keywords": [
"cocoapods",
"pod",
"pods",
"init",
"install",
"update",
"outdated",
"search",
"list",
"try",
"create",
"lint",
"cat",
"which",
"edit",
"add-user",
"info",
"me",
"push",
"register",
"remove-owner",
"repo",
"setup",
"lib",
"child",
"process",
"cp",
"command",
"run",
"exec"
],
"dependencies": {
"execfile-subcommand": "^1.0.1"
},
"devDependencies": {
"@shinnn/eslint-config-node": "^1.0.1",
"eslint": "^1.8.0",
"istanbul": "^0.4.0",
"tape": "^4.2.2"
}
}
100 changes: 100 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
'use strict';

const execPodCallback = require('.');
const test = require('tape');

test('execPodCallback()', t => {
t.plan(17);

t.equal(execPodCallback.name, 'execPodCallback', 'should have a function name.');

execPodCallback('try', (err, stdout, stderr) => {
t.equal(err.cmd, 'pod try', 'should pass an error to the callback when the command fails.');
t.ok(/A Pod name or URL is required\./.test(stdout), 'should pass error messages to `stderr` argument.');
t.strictEqual(stderr, '', 'should not pass error messages to `stderr` argument.');
});

execPodCallback('search', ['AFNetworking'], (err, stdout) => {
t.strictEqual(
err,
null,
'should not pass any errors to the callback when it successfully runs the command.'
);
t.ok(
/https:\/\/github.com\/AFNetworking\/AFNetworking/.test(stdout),
'should pass the result to `stdout` argument.'
);
});

execPodCallback('search', ['AFNetworking'], {maxBuffer: 1}, err => {
t.equal(
err.message,
'stdout maxBuffer exceeded.',
'should accept child_process#execFile options.'
);
});

execPodCallback('insta1l', ['123'], {bundleExec: true}, err => {
t.equal(
err.cmd,
'bundle exec pod insta1l 123',
'should run the command in a bundler context when `bundleExec` option is enabled.'
);
});

execPodCallback('search', null, {maxBuffer: -1}, err => {
t.equal(
err.cmd,
'pod search',
'should accept child_process#execFile options.'
);
});

execPodCallback('foobarbazqux', null, (err, stdout) => {
t.equal(
err.cmd,
'pod foobarbazqux',
'should fail when the subcommand is not valid.'
);
t.ok(
/Unknown command: `foobarbazqux`/.test(stdout),
'should output "Unknown command" message when the subcommand is not valid.'
);
});

execPodCallback('search', ['.+/', '--verbose'], null, (err, stdout) => {
t.equal(
err.cmd,
'pod search .+/ --verbose',
'should fail when it tries to search Pods with invlid characters.'
);
t.ok(
/<main>/.test(stdout),
'should output verbose messages when `--verbose` flag is enabled.'
);
});

t.throws(
() => execPodCallback(1, t.fail),
/TypeError.*1 is not a string\. Expected one of the `pod` subcommands \(e\.g\. `install`\)\./,
'should throw a type error when the first argument is not a string.'
);

t.throws(
() => execPodCallback('', t.fail),
/Error.*Expected one of the `pod` subcommands \(e\.g\. `outdated`\), but received an empty string\./,
'should throw an error when the first argument is an empty string.'
);

t.throws(
() => execPodCallback('outdated', 1, {}, t.fail),
/TypeError.*1 is not an array\. Expected a list of arguments to be passed to `pod outdated` command\./,
'should throw a type error when a `args` argument takes a truthy value but it\'s not an array.'
);

t.throws(
() => execPodCallback('outdated', [], {bundleExec: 1}, t.fail),
/TypeError.*1 is not Boolean\. `bundleExec` option must be Boolean \(`false` by default\)\./,
'should throw a type error when `bundleExec` option is not Boolean.'
);
});

0 comments on commit 8eba343

Please sign in to comment.