mirror of
https://github.com/bower/bower.git
synced 2026-04-24 03:00:19 -04:00
Compare commits
61 Commits
travis-mod
...
bitbucket-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0a204d806 | ||
|
|
202e52739e | ||
|
|
db7e9f54f0 | ||
|
|
8c63554e02 | ||
|
|
1a2b5a4718 | ||
|
|
636aae971e | ||
|
|
e7556b0e90 | ||
|
|
7a35c0e050 | ||
|
|
37815a624d | ||
|
|
f0fe4ab56b | ||
|
|
e5d7c241bd | ||
|
|
bfa76a3862 | ||
|
|
3f60ffbc4c | ||
|
|
65b536f374 | ||
|
|
6f3109d8a1 | ||
|
|
1b147abfef | ||
|
|
a954ca22ad | ||
|
|
e88a3f6729 | ||
|
|
5a223f7f90 | ||
|
|
f05bf58c43 | ||
|
|
5b9665587a | ||
|
|
1bd451f613 | ||
|
|
1bb0d8f823 | ||
|
|
ec4538eaf3 | ||
|
|
cd22a2d0c9 | ||
|
|
138d846ecc | ||
|
|
eae912b8db | ||
|
|
afec75972c | ||
|
|
60a45edccf | ||
|
|
95c89dbcc5 | ||
|
|
84393d1c26 | ||
|
|
b0db186ac6 | ||
|
|
3b2a571efe | ||
|
|
b9f7303151 | ||
|
|
09e8e3f51d | ||
|
|
71a17ddf4f | ||
|
|
fffcf3e4f2 | ||
|
|
8b78888f67 | ||
|
|
be1a0d121b | ||
|
|
cc0d261c4c | ||
|
|
dd0bded77a | ||
|
|
466f2f6c5c | ||
|
|
66894f5654 | ||
|
|
ca612dafc6 | ||
|
|
e1c68201a5 | ||
|
|
12ebb505d9 | ||
|
|
3facaa95bd | ||
|
|
91042387eb | ||
|
|
2dd301657c | ||
|
|
b9e6eff899 | ||
|
|
d118151c89 | ||
|
|
f90e36a60a | ||
|
|
1818bc9a10 | ||
|
|
3ff14aa939 | ||
|
|
23cbaddb5f | ||
|
|
850de576b9 | ||
|
|
978d8f2727 | ||
|
|
2a6bd40c58 | ||
|
|
0ebda41fa8 | ||
|
|
48f7af12a6 | ||
|
|
98e4847732 |
@@ -5,7 +5,5 @@ node_js:
|
||||
matrix:
|
||||
allow_failures:
|
||||
- node_js: '0.11'
|
||||
before_script:
|
||||
- npm install -g grunt-cli
|
||||
script:
|
||||
- grunt travis
|
||||
|
||||
51
CHANGELOG.md
51
CHANGELOG.md
@@ -1,5 +1,56 @@
|
||||
# Changelog
|
||||
|
||||
## 1.3.12 - 2014-09-28
|
||||
|
||||
- [stability] Fix versions for unstable dependencies ([#1532](https://github.com/bower/bower/pull/1532))
|
||||
- [fix] Update tar-fs to support old tar format ([#1537](https://github.com/bower/bower/issues/1537))
|
||||
- [fix] Make analytics work again ([#1529](https://github.com/bower/bower/pull/1529))
|
||||
- [fix] Always disable analytics for non-interactive mode ([#1529](https://github.com/bower/bower/pull/1529))
|
||||
- [fix] Bower init can create private packages again ([#1522](https://github.com/bower/bower/issues/1522))
|
||||
- [fix] Show again missing newline for bower search output ([#1538](https://github.com/bower/bower/issues/1538))
|
||||
|
||||
## 1.3.11 - 2014-09-17
|
||||
|
||||
- [fix] Restore install missing dependencies on update ([1519](https://github.com/bower/bower/pull/1519))
|
||||
|
||||
## 1.3.10 - 2014-09-13
|
||||
|
||||
- [fix] Back down concurrency from 50 to 5 ([#1483](https://github.com/bower/bower/pull/1483))
|
||||
- [fix] Read .bowerrc from specified cwd ([#1301](https://github.com/bower/bower/pull/1301))
|
||||
- [fix] Disable shallow clones except those from GitHub ([#1393](https://github.com/bower/bower/pull/1393))
|
||||
- [fix] Expose bower version ([#1478](https://github.com/bower/bower/pull/1478))
|
||||
- [fix] Bump dependencies, including "request" ([#1467](https://github.com/bower/bower/pull/1467))
|
||||
- [fix] Prevent an error when piping bower output to head ([#1508](https://github.com/bower/bower/pull/1508))
|
||||
- [fix] Disable removing unnecessary resolutions ([#1061](https://github.com/bower/bower/pull/1061))
|
||||
- [fix] Display the output of hooks again ([#1484](https://github.com/bower/bower/issues/1484))
|
||||
- [fix] analytics: true in .bowerrc prevents user prompt ([#1470](https://github.com/bower/bower/pull/1470))
|
||||
- [perf] Use `tar-fs` instead of `tar` for faster TAR extraction ([#1490](https://github.com/bower/bower/pull/1490))
|
||||
|
||||
## 1.3.9 - 2014-08-06
|
||||
|
||||
- [fix] Handle `tmp` sometimes returning an array ([#1434](https://github.com/bower/bower/pull/1434))
|
||||
|
||||
## 1.3.8 - 2014-7-11
|
||||
|
||||
- [fix] Lock down `tmp` package dep ([#1403](https://github.com/bower/bower/pull/1403), [#1407](https://github.com/bower/bower/pull/1407))
|
||||
|
||||
## 1.3.7 - 2014-07-04
|
||||
|
||||
- [fix] callstack error when processing installed packages with circular dependencies ([#1349](https://github.com/bower/bower/issues/1349))
|
||||
- [fix] Prevent bower list --paths` failing with TypeError ([#1383](https://github.com/bower/bower/issues/1383))
|
||||
- "bower install" fails if there's no bower.json in current directory ([#922](https://github.com/bower/bower/issues/922))
|
||||
|
||||
## 1.3.6 - 2014-07-02
|
||||
|
||||
- [fix] Make --force always re-run installation ([#931](https://github.com/bower/bower/issues/931))
|
||||
- [fix] Disable caching for local resources ([#1356](https://github.com/bower/bower/issues/1356))
|
||||
- [fix] Emit errors instead throwing them when using bower.commands API ([#1297](https://github.com/bower/bower/issues/1297))
|
||||
- [fix] Main files and bower.json are never ignored ([#547](https://github.com/bower/bower/issues/547))
|
||||
- [fix] Check if pkgMeta is undefined during uninstall command ([#1329](https://github.com/bower/bower/issues/1329))
|
||||
- [fix] Make custom tmp dir and ignores play well with each other ([#1299](https://github.com/bower/bower/issues/1299))
|
||||
- Warn users when installing package with missing properties ([#694](https://github.com/bower/bower/issues/694))
|
||||
|
||||
|
||||
## 1.3.5 - 2014-06-06
|
||||
- Search compatible versions in fetching packages ([#1147](https://github.com/bower/bower/issues/1147))
|
||||
|
||||
|
||||
337
README.md
337
README.md
@@ -1,17 +1,18 @@
|
||||
# Bower
|
||||
|
||||
[](https://travis-ci.org/bower/bower) [](https://coveralls.io/r/bower/bower?branch=feature%2Fintegration)
|
||||
[](https://travis-ci.org/bower/bower) [](https://coveralls.io/r/bower/bower?branch=master)
|
||||
|
||||
<img align="right" height="300" src="http://bower.io/img/bower-logo.png">
|
||||
|
||||
> A package manager for the web
|
||||
|
||||
It offers a generic, unopinionated solution to the problem of **front-end package management**, while exposing the package dependency model via an API that can be consumed by a more opinionated build stack. There are no system wide dependencies, no dependencies are shared between different apps, and the dependency tree is flat.
|
||||
Bower offers a generic, unopinionated solution to the problem of **front-end package management**, while exposing the package dependency model via an API that can be consumed by a more opinionated build stack. There are no system wide dependencies, no dependencies are shared between different apps, and the dependency tree is flat.
|
||||
|
||||
Bower runs over Git, and is package-agnostic. A packaged component can be made up of any type of asset, and use any type of transport (e.g., AMD, CommonJS, etc.).
|
||||
|
||||
[View all packages available through Bower's registry](http://bower.io/search/).
|
||||
**View complete docs on [bower.io](http://bower.io)**
|
||||
|
||||
[View all packages available through Bower's registry](http://bower.io/search/).
|
||||
|
||||
## Install
|
||||
|
||||
@@ -25,92 +26,21 @@ packages require it to be fetched and installed.
|
||||
|
||||
## Usage
|
||||
|
||||
Much more information is available via `bower help` once it's installed. This
|
||||
is just enough to get you started.
|
||||
See complete command line reference at [bower.io/docs/api/](http://bower.io/docs/api/)
|
||||
|
||||
### Installing packages and dependencies
|
||||
|
||||
Bower offers several ways to install packages:
|
||||
|
||||
##### Using the dependencies listed in the current directory's bower.json
|
||||
|
||||
```sh
|
||||
# install dependencies listed in bower.json
|
||||
$ bower install
|
||||
|
||||
# install a package and add it to bower.json
|
||||
$ bower install <package> --save
|
||||
|
||||
# install specific version of a package and add it to bower.json
|
||||
$ bower install <package>#<version> --save
|
||||
```
|
||||
|
||||
##### Using a local or remote package
|
||||
|
||||
```sh
|
||||
$ bower install <package>
|
||||
```
|
||||
|
||||
##### Using a specific version of a package
|
||||
|
||||
```sh
|
||||
$ bower install <package>#<version>
|
||||
```
|
||||
|
||||
##### Using a different name and a specific version of a package
|
||||
|
||||
```sh
|
||||
$ bower install <name>=<package>#<version>
|
||||
```
|
||||
|
||||
Where `<package>` can be any one of the following:
|
||||
|
||||
* A name that maps to a package registered with Bower, e.g, `jquery`. ‡
|
||||
* A public remote Git endpoint, e.g., `git://github.com/someone/some-package.git`. ‡
|
||||
* A private Git repository, e.g., `https://github.com/someone/some-package.git`. If the protocol is https, a prompt will ask for the credentials. ssh can also be used, e.g., `git@github.com:someone/some-package.git` and can authenticate with the user's ssh public/private keys. ‡
|
||||
* A local endpoint, i.e., a folder that's a Git repository. ‡
|
||||
* A public remote Subversion endpoint, e.g., `svn+http://package.googlecode.com/svn/`. ‡
|
||||
* A private Subversion repository, e.g., `svn+ssh://package.googlecode.com/svn/` or `svn+https://package.googlecode.com/svn/`. ‡
|
||||
* A local endpoint, i.e., a folder that's an Subversion repository, e.g., `svn+file:///path/to/svn/`. ‡
|
||||
* A shorthand endpoint, e.g., `someone/some-package` (defaults to GitHub). ‡
|
||||
* A URL to a file, including `zip` and `tar` files. Its contents will be
|
||||
extracted.
|
||||
|
||||
‡ These types of `<package>` might have versions available. You can specify a
|
||||
[semver](http://semver.org/) compatible version to fetch a specific release, and lock the
|
||||
package to that version. You can also specify a [range](https://github.com/isaacs/node-semver#ranges) of versions.
|
||||
|
||||
If you are using a package that is a git endpoint, you may use any tag, commit SHA,
|
||||
or branch name as a version. For example: `<package>#<sha>`. Using branches is not
|
||||
recommended because the HEAD does not reference a fixed commit SHA.
|
||||
|
||||
If you are using a package that is a subversion endpoint, you may use any tag, revision number,
|
||||
or branch name as a version. For example: `<package>#<revision>`.
|
||||
|
||||
All package contents are installed in the `bower_components` directory by default.
|
||||
You should **never** directly modify the contents of this directory.
|
||||
|
||||
Using `bower list` will show all the packages that are installed locally.
|
||||
|
||||
**N.B.** If you aren't authoring a package that is intended to be consumed by
|
||||
others (e.g., you're building a web app), you should always [check installed
|
||||
packages into source control](http://addyosmani.com/blog/checking-in-front-end-dependencies/).
|
||||
|
||||
|
||||
### Custom install directory
|
||||
|
||||
A custom install location can be set in a `.bowerrc` file using the `directory` property. The .bowerrc file should be a sibling of your project's bower.json.
|
||||
|
||||
```json
|
||||
{
|
||||
"directory": "app/components"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Finding packages
|
||||
|
||||
To search for packages registered with Bower:
|
||||
|
||||
```sh
|
||||
$ bower search [<name>]
|
||||
```
|
||||
|
||||
Using just `bower search` will list all packages in the registry.
|
||||
|
||||
### Using packages
|
||||
|
||||
We discourage using bower components statically for performance and security reasons (if component has an `upload.php` file that is not ignored, that can be easily exploited to do malicious stuff).
|
||||
@@ -125,17 +55,16 @@ To uninstall a locally installed package:
|
||||
$ bower uninstall <package-name>
|
||||
```
|
||||
|
||||
|
||||
#### Warning
|
||||
### prezto and oh-my-zsh users
|
||||
|
||||
On `prezto` or `oh-my-zsh`, do not forget to `alias bower='noglob bower'` or `bower install jquery\#1.9.1`
|
||||
|
||||
#### Running commands with sudo
|
||||
### Running commands with sudo
|
||||
|
||||
Bower is a user command, there is no need to execute it with superuser permissions.
|
||||
However, if you still want to run commands with sudo, use `--allow-root` option.
|
||||
|
||||
#### A note for Windows users
|
||||
### Windows users
|
||||
|
||||
To use Bower on Windows, you must install
|
||||
[msysgit](http://msysgit.github.io/) correctly. Be sure to check the
|
||||
@@ -148,196 +77,9 @@ password, you should add the following environment variable: `GIT_SSH -
|
||||
C:\Program Files\TortoiseGit\bin\TortoisePlink.exe`. Adjust the `TortoisePlink`
|
||||
path if needed.
|
||||
|
||||
### Using bower's cache
|
||||
|
||||
Bower supports installing packages from its local cache (without internet connection), if the packages were installed before.
|
||||
|
||||
```sh
|
||||
$ bower install <package-name> --offline
|
||||
```
|
||||
|
||||
The content of the cache can be listed with:
|
||||
|
||||
```sh
|
||||
$ bower cache list
|
||||
```
|
||||
|
||||
The cache can be cleaned with:
|
||||
|
||||
```sh
|
||||
$ bower cache clean
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Bower can be configured using JSON in a `.bowerrc` file.
|
||||
|
||||
The current spec can be read
|
||||
[here](https://docs.google.com/document/d/1APq7oA9tNao1UYWyOm8dKqlRP2blVkROYLZ2fLIjtWc/edit#heading=h.4pzytc1f9j8k)
|
||||
in the `Configuration` section.
|
||||
|
||||
## Running on a continuous integration server
|
||||
|
||||
Bower will skip some interactive and analytics operations if it finds a `CI` environmental variable set to `true`. You will find that the `CI` variable is already set for you on many continuous integration servers, e.g., [CircleCI](https://circleci.com/docs/environment-variables#basics) and [Travis-CI](http://docs.travis-ci.com/user/ci-environment/#Environment-variables).
|
||||
|
||||
You may try to set the `CI` variable manually before running your Bower commands. On Mac or Linux, `export CI=true` and on Windows `set CI=true`
|
||||
|
||||
### Interactive configuration
|
||||
|
||||
If for some reason you are unable to set the `CI` environment variable, you can alternately use the `--config.interactive=false` flag. (`bower install --config.interactive=false`)
|
||||
|
||||
## Defining a package
|
||||
|
||||
You must create a `bower.json` in your project's root, and specify all of its
|
||||
dependencies. This is similar to Node's `package.json`, or Ruby's `Gemfile`,
|
||||
and is useful for locking down a project's dependencies.
|
||||
|
||||
*NOTE:* In versions of Bower before 0.9.0 the package metadata file was called
|
||||
`component.json` rather than `bower.json`. This has changed to avoid a name
|
||||
clash with another tool. You can still use `component.json` for now but it is
|
||||
deprecated and the automatic fallback is likely to be removed in an upcoming
|
||||
release.
|
||||
|
||||
You can interactively create a `bower.json` with the following command:
|
||||
|
||||
```sh
|
||||
$ bower init
|
||||
```
|
||||
|
||||
The `bower.json` ([spec](https://github.com/bower/bower.json-spec)) defines several options, including:
|
||||
|
||||
* `name` (required): The name of your package.
|
||||
* `version`: A semantic version number (see [semver](http://semver.org/)).
|
||||
* `main` [string|array]: The primary endpoints of your package.
|
||||
* `ignore` [array]: An array of paths not needed in production that you want
|
||||
Bower to ignore when installing your package.
|
||||
* `dependencies` [hash]: Packages your package depends upon in production.
|
||||
Note that you can specify [ranges](https://github.com/isaacs/node-semver#ranges)
|
||||
of versions for your dependencies.
|
||||
* `devDependencies` [hash]: Development dependencies.
|
||||
* `private` [boolean]: Set to true if you want to keep the package private and
|
||||
do not want to register the package in future.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-project",
|
||||
"description": "My project does XYZ...",
|
||||
"version": "1.0.0",
|
||||
"main": "path/to/main.css",
|
||||
"ignore": [
|
||||
".jshintrc",
|
||||
"**/*.txt"
|
||||
],
|
||||
"dependencies": {
|
||||
"<name>": "<version>",
|
||||
"<name>": "<folder>",
|
||||
"<name>": "<package>"
|
||||
},
|
||||
"devDependencies": {
|
||||
"<test-framework-name>": "<version>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Registering packages
|
||||
|
||||
To register a new package:
|
||||
|
||||
* There **must** be a valid manifest JSON in the current working directory.
|
||||
* Your package should use [semver](http://semver.org/) Git tags.
|
||||
* Your package **must** be available at a Git endpoint (e.g., GitHub); remember
|
||||
to push your Git tags!
|
||||
|
||||
Then use the following command:
|
||||
|
||||
```sh
|
||||
$ bower register <my-package-name> <git-endpoint>
|
||||
```
|
||||
|
||||
The Bower registry does not have authentication or user management at this point
|
||||
in time. It's on a first come, first served basis. Think of it like a URL
|
||||
shortener. Now anyone can run `bower install <my-package-name>`, and get your
|
||||
library installed.
|
||||
|
||||
There is no direct way to unregister a package yet. For now, you can [request a
|
||||
package be unregistered](https://github.com/bower/bower/issues/120).
|
||||
|
||||
|
||||
### Maintaining dependencies
|
||||
|
||||
Using `bower install pkgName --save` will add `pkgName` to your project's
|
||||
bower.json `"depenencies"` array.
|
||||
|
||||
Similarly, using `bower install pkgName --save-dev` will add `pkgName` to your
|
||||
project's bower.json `"devDependencies"` array.
|
||||
|
||||
|
||||
## Consuming a package
|
||||
|
||||
Bower also makes available a source mapping. This can be used by build tools to
|
||||
easily consume Bower packages.
|
||||
|
||||
If you pass the `--paths` option to Bower's `list` command, you will get a
|
||||
simple name-to-path mapping:
|
||||
|
||||
```json
|
||||
{
|
||||
"backbone": "bower_components/backbone/index.js",
|
||||
"jquery": "bower_components/jquery/index.js",
|
||||
"underscore": "bower_components/underscore/index.js"
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively, every command supports the `--json` option that makes bower
|
||||
output JSON. Command result is outputted to `stdout` and error/logs to
|
||||
`stderr`.
|
||||
|
||||
|
||||
## Programmatic API
|
||||
|
||||
Bower provides a powerful, programmatic API. All commands can be accessed
|
||||
through the `bower.commands` object.
|
||||
|
||||
```js
|
||||
var bower = require('bower');
|
||||
|
||||
bower.commands
|
||||
.install(['jquery'], { save: true }, { /* custom config */ })
|
||||
.on('end', function (installed) {
|
||||
console.log(installed);
|
||||
});
|
||||
|
||||
bower.commands
|
||||
.search('jquery', {})
|
||||
.on('end', function (results) {
|
||||
console.log(results);
|
||||
});
|
||||
```
|
||||
|
||||
Commands emit four types of events: `log`, `prompt`, `end`, `error`.
|
||||
|
||||
* `log` is emitted to report the state/progress of the command.
|
||||
* `prompt` is emitted whenever the user needs to be prompted.
|
||||
* `error` will only be emitted if something goes wrong.
|
||||
* `end` is emitted when the command successfully ends.
|
||||
|
||||
For a better of idea how this works, you may want to check out [our bin
|
||||
file](https://github.com/bower/bower/blob/master/bin/bower).
|
||||
|
||||
When using bower programmatically, prompting is disabled by default. Though you can enable it when calling commands with `interactive: true` in the config.
|
||||
This requires you to listen for the `prompt` event and handle the prompting yourself. The easiest way is to use the [inquirer](https://npmjs.org/package/inquirer) npm module like so:
|
||||
|
||||
```js
|
||||
var inquirer = require('inquirer');
|
||||
|
||||
bower.commands
|
||||
.install(['jquery'], { save: true }, { interactive: true })
|
||||
// ..
|
||||
.on('prompt', function (prompts, callback) {
|
||||
inquirer.prompt(prompts, callback);
|
||||
});
|
||||
```
|
||||
|
||||
Bower can be configured using JSON in a `.bowerrc` file. Read over available options at [bower.io/docs/config](http://bower.io/docs/config).
|
||||
|
||||
## Completion (experimental)
|
||||
|
||||
@@ -354,19 +96,6 @@ This command will output a Bash / ZSH script to put into your `~/.bashrc`,
|
||||
$ bower completion >> ~/.bash_profile
|
||||
```
|
||||
|
||||
## Analytics
|
||||
|
||||
Bower can collect anonymous usage statistics. This allows the community to improve Bower and publicly display insights into CLI usage and packages at [stats.bower.io](http://stats.bower.io).
|
||||
|
||||
Data is tracked using Google Analytics and instrumented via [Insight](https://github.com/yeoman/insight). It is made available to all bower team members. Tracking is opt-in upon initial usage. If you'd prefer to disable analytics altogether, you can manually opt-out, or create either a local, or global `.bowerrc` file with:
|
||||
|
||||
```json
|
||||
{
|
||||
"analytics": false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Support
|
||||
|
||||
@@ -387,6 +116,8 @@ review the [guidelines for contributing](CONTRIBUTING.md).
|
||||
|
||||
## Bower Team
|
||||
|
||||
Bower is made by lots of people across the globe, contributions large and small. Our thanks to everyone who has played a part.
|
||||
|
||||
### Core team
|
||||
|
||||
* [@satazor](https://github.com/satazor)
|
||||
@@ -397,38 +128,6 @@ review the [guidelines for contributing](CONTRIBUTING.md).
|
||||
* [@svnlto](https://github.com/svnlto)
|
||||
* [@sheerun](https://github.com/sheerun)
|
||||
|
||||
Thanks for assistance and contributions:
|
||||
|
||||
[@addyosmani](https://github.com/addyosmani),
|
||||
[@ahmadnassri](https://github.com/ahmadnassri),
|
||||
[@angus-c](https://github.com/angus-c),
|
||||
[@borismus](https://github.com/borismus),
|
||||
[@carsonmcdonald](https://github.com/carsonmcdonald),
|
||||
[@chriseppstein](https://github.com/chriseppstein),
|
||||
[@danwrong](https://github.com/danwrong),
|
||||
[@davidmaxwaterman](https://github.com/davidmaxwaterman),
|
||||
[@desandro](https://github.com/desandro),
|
||||
[@hemanth](https://github.com/hemanth),
|
||||
[@isaacs](https://github.com/isaacs),
|
||||
[@josh](https://github.com/josh),
|
||||
[@jrburke](https://github.com/jrburke),
|
||||
[@kennethklee](https://github.com/kennethklee),
|
||||
[@marcelombc](https://github.com/marcelombc),
|
||||
[@marcooliveira](https://github.com/marcooliveira),
|
||||
[@mklabs](https://github.com/mklabs),
|
||||
[@MrDHat](https://github.com/MrDHat),
|
||||
[@necolas](https://github.com/necolas),
|
||||
[@richo](https://github.com/richo),
|
||||
[@rvagg](https://github.com/rvagg),
|
||||
[@ryanflorence](https://github.com/ryanflorence),
|
||||
[@SlexAxton](https://github.com/SlexAxton),
|
||||
[@sstephenson](https://github.com/sstephenson),
|
||||
[@tomdale](https://github.com/tomdale),
|
||||
[@uzquiano](https://github.com/uzquiano),
|
||||
[@visionmedia](https://github.com/visionmedia),
|
||||
[@wagenet](https://github.com/wagenet),
|
||||
[@wycats](https://github.com/wycats)
|
||||
|
||||
### Bower Alumni
|
||||
|
||||
* [@fat](https://github.com/fat)
|
||||
|
||||
@@ -19,7 +19,6 @@ var loglevel;
|
||||
var command;
|
||||
var commandFunc;
|
||||
var logger;
|
||||
var notifier;
|
||||
var levels = Logger.LEVELS;
|
||||
|
||||
options = cli.readOptions({
|
||||
@@ -134,13 +133,13 @@ analytics.setup(bower.config).then(function () {
|
||||
var updateNotifier = require('update-notifier');
|
||||
|
||||
// Check for newer version of Bower
|
||||
notifier = updateNotifier({
|
||||
var notifier = updateNotifier({
|
||||
packageName: pkg.name,
|
||||
packageVersion: pkg.version
|
||||
});
|
||||
|
||||
if (notifier.update && levels.info >= loglevel) {
|
||||
renderer.updateNotice(notifier.update);
|
||||
notifier.notify();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
2
lib/commands/cache/clean.js
vendored
2
lib/commands/cache/clean.js
vendored
@@ -14,7 +14,7 @@ function clean(logger, endpoints, options, config) {
|
||||
var names;
|
||||
|
||||
options = options || {};
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
|
||||
// If endpoints is an empty array, null them
|
||||
if (endpoints && !endpoints.length) {
|
||||
|
||||
2
lib/commands/cache/list.js
vendored
2
lib/commands/cache/list.js
vendored
@@ -6,7 +6,7 @@ var defaultConfig = require('../../config');
|
||||
function list(logger, packages, options, config) {
|
||||
var repository;
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
repository = new PackageRepository(config, logger);
|
||||
|
||||
// If packages is an empty array, null them
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
var mout = require('mout');
|
||||
var Project = require('../core/Project');
|
||||
var open = require('opn');
|
||||
var endpointParser = require('bower-endpoint-parser');
|
||||
@@ -11,7 +10,7 @@ function home(logger, name, config) {
|
||||
var promise;
|
||||
var decEndpoint;
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
project = new Project(config, logger);
|
||||
|
||||
// Get the package meta
|
||||
|
||||
@@ -11,7 +11,7 @@ function info(logger, endpoint, property, config) {
|
||||
var decEndpoint;
|
||||
var tracker;
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
repository = new PackageRepository(config, logger);
|
||||
tracker = new Tracker(config);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ var endpointParser = require('bower-endpoint-parser');
|
||||
var Project = require('../core/Project');
|
||||
var defaultConfig = require('../config');
|
||||
var GitHubResolver = require('../core/resolvers/GitHubResolver');
|
||||
var BitBucketResolver = require('../core/resolvers/BitBucketResolver');
|
||||
var GitFsResolver = require('../core/resolvers/GitFsResolver');
|
||||
var cli = require('../util/cli');
|
||||
var cmd = require('../util/cmd');
|
||||
@@ -14,7 +15,7 @@ var createError = require('../util/createError');
|
||||
function init(logger, config) {
|
||||
var project;
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
|
||||
// This command requires interactive to be enabled
|
||||
if (!config.interactive) {
|
||||
@@ -115,7 +116,7 @@ function setDefaults(config, json) {
|
||||
|
||||
// Homepage
|
||||
if (!json.homepage) {
|
||||
// Set as GitHub homepage if it's a GitHub repository
|
||||
// Set as GitHub/Bitbucket homepage if it's a GitHub/Bitbucket repository
|
||||
promise = promise.then(function () {
|
||||
return cmd('git', ['config', '--get', 'remote.origin.url'])
|
||||
.spread(function (stdout) {
|
||||
@@ -130,6 +131,11 @@ function setDefaults(config, json) {
|
||||
if (pair) {
|
||||
json.homepage = 'https://github.com/' + pair.org + '/' + pair.repo;
|
||||
}
|
||||
|
||||
pair = BitBucketResolver.getOrgRepoPair(stdout);
|
||||
if (pair) {
|
||||
json.homepage = 'https://bitbucket.org/' + pair.org + '/' + pair.repo;
|
||||
}
|
||||
})
|
||||
.fail(function () { });
|
||||
});
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
var mout = require('mout');
|
||||
var endpointParser = require('bower-endpoint-parser');
|
||||
var Project = require('../core/Project');
|
||||
var cli = require('../util/cli');
|
||||
@@ -11,7 +10,7 @@ function install(logger, endpoints, options, config) {
|
||||
var tracker;
|
||||
|
||||
options = options || {};
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
if (options.save === undefined) {
|
||||
options.save = config.defaultSave;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
var path = require('path');
|
||||
var rimraf = require('rimraf');
|
||||
var mout = require('mout');
|
||||
var Q = require('q');
|
||||
var Project = require('../core/Project');
|
||||
var createLink = require('../util/createLink');
|
||||
@@ -18,7 +17,7 @@ function link(logger, name, localName) {
|
||||
function linkSelf(logger, config) {
|
||||
var project;
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
project = new Project(config, logger);
|
||||
|
||||
return project.getJson()
|
||||
@@ -44,9 +43,10 @@ function linkSelf(logger, config) {
|
||||
function linkTo(logger, name, localName, config) {
|
||||
var src;
|
||||
var dst;
|
||||
var project = new Project(config, logger);
|
||||
var project;
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
project = new Project(config, logger);
|
||||
|
||||
localName = localName || name;
|
||||
src = path.join(config.storage.links, name);
|
||||
|
||||
@@ -16,11 +16,9 @@ function list(logger, options, config) {
|
||||
options.relative = true;
|
||||
}
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
project = new Project(config, logger);
|
||||
|
||||
logger.json = !!options.paths;
|
||||
|
||||
return project.getTree(options)
|
||||
.spread(function (tree, flattened) {
|
||||
// Relativize paths
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
var mout = require('mout');
|
||||
var Q = require('q');
|
||||
var RegistryClient = require('bower-registry-client');
|
||||
var cli = require('../util/cli');
|
||||
@@ -7,7 +6,7 @@ var defaultConfig = require('../config');
|
||||
function lookup(logger, name, config) {
|
||||
var registryClient;
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
config.cache = config.storage.registry;
|
||||
|
||||
registryClient = new RegistryClient(config, logger);
|
||||
|
||||
@@ -7,7 +7,7 @@ function prune(logger, options, config) {
|
||||
var project;
|
||||
|
||||
options = options || {};
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
project = new Project(config, logger);
|
||||
|
||||
return clean(project, options);
|
||||
|
||||
@@ -8,6 +8,7 @@ var cli = require('../util/cli');
|
||||
var createError = require('../util/createError');
|
||||
var defaultConfig = require('../config');
|
||||
var GitHubResolver = require('../core/resolvers/GitHubResolver');
|
||||
var BitBucketResolver = require('../core/resolvers/BitBucketResolver');
|
||||
|
||||
function register(logger, name, url, config) {
|
||||
var repository;
|
||||
@@ -15,7 +16,7 @@ function register(logger, name, url, config) {
|
||||
var tracker;
|
||||
var force;
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
force = config.force;
|
||||
tracker = new Tracker(config);
|
||||
|
||||
@@ -91,12 +92,18 @@ function convertUrl(url, logger) {
|
||||
var newUrl;
|
||||
|
||||
if (!mout.string.startsWith(url, 'git://')) {
|
||||
// Convert GitHub ssh & https to git://
|
||||
// Convert GitHub/Bitbucket ssh & https to git://
|
||||
pair = GitHubResolver.getOrgRepoPair(url);
|
||||
if (pair) {
|
||||
newUrl = 'git://github.com/' + pair.org + '/' + pair.repo + '.git';
|
||||
logger.warn('convert', 'Converted ' + url + ' to ' + newUrl);
|
||||
}
|
||||
|
||||
pair = BitBucketResolver.getOrgRepoPair(url);
|
||||
if (pair) {
|
||||
newUrl = 'git://bitbucket.org/' + pair.org + '/' + pair.repo + '.git';
|
||||
logger.warn('convert', 'Converted ' + url + ' to ' + newUrl);
|
||||
}
|
||||
}
|
||||
|
||||
return newUrl || url;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
var mout = require('mout');
|
||||
var Q = require('q');
|
||||
var RegistryClient = require('bower-registry-client');
|
||||
var cli = require('../util/cli');
|
||||
@@ -9,7 +8,7 @@ function search(logger, name, config) {
|
||||
var registryClient;
|
||||
var tracker;
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
config.cache = config.storage.registry;
|
||||
|
||||
registryClient = new RegistryClient(config, logger);
|
||||
|
||||
@@ -10,7 +10,7 @@ function uninstall(logger, names, options, config) {
|
||||
var tracker;
|
||||
|
||||
options = options || {};
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
project = new Project(config, logger);
|
||||
tracker = new Tracker(config);
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
var mout = require('mout');
|
||||
var Project = require('../core/Project');
|
||||
var cli = require('../util/cli');
|
||||
var defaultConfig = require('../config');
|
||||
@@ -7,7 +6,7 @@ function update(logger, names, options, config) {
|
||||
var project;
|
||||
|
||||
options = options || {};
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
project = new Project(config, logger);
|
||||
|
||||
// If names is an empty array, null them
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
var mout = require('mout');
|
||||
var semver = require('semver');
|
||||
var which = require('which');
|
||||
var fs = require('fs');
|
||||
@@ -13,7 +12,7 @@ var createError = require('../util/createError');
|
||||
function version(logger, versionArg, options, config) {
|
||||
var project;
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
project = new Project(config, logger);
|
||||
|
||||
return bump(project, versionArg, options.message);
|
||||
|
||||
@@ -1,37 +1,55 @@
|
||||
var tty = require('tty');
|
||||
var mout = require('mout');
|
||||
var config = require('bower-config').read();
|
||||
var object = require('mout').object;
|
||||
var bowerConfig = require('bower-config');
|
||||
var cli = require('./util/cli');
|
||||
|
||||
// Delete the json attribute because it is no longer supported
|
||||
// and conflicts with --json
|
||||
delete config.json;
|
||||
var cachedConfigs = {};
|
||||
|
||||
// If interactive is auto (null), guess its value
|
||||
if (config.interactive == null) {
|
||||
config.interactive = (
|
||||
process.bin === 'bower' &&
|
||||
tty.isatty(1) &&
|
||||
!process.env.CI
|
||||
);
|
||||
function defaultConfig(config) {
|
||||
config = config || {};
|
||||
|
||||
var cachedConfig = readCachedConfig(config.cwd || process.cwd());
|
||||
|
||||
return object.merge(cachedConfig, config);
|
||||
}
|
||||
|
||||
// If `analytics` hasn't been explicitly set, we disable
|
||||
// it when ran programatically.
|
||||
if (config.analytics == null) {
|
||||
// Don't enable analytics on CI server unless explicitly configured.
|
||||
config.analytics = config.interactive;
|
||||
function readCachedConfig(cwd) {
|
||||
if (cachedConfigs[cwd]) {
|
||||
return cachedConfigs[cwd];
|
||||
}
|
||||
|
||||
var config = cachedConfigs[cwd] = bowerConfig.read(cwd);
|
||||
|
||||
// Delete the json attribute because it is no longer supported
|
||||
// and conflicts with --json
|
||||
delete config.json;
|
||||
|
||||
// If interactive is auto (null), guess its value
|
||||
if (config.interactive == null) {
|
||||
config.interactive = (
|
||||
process.bin === 'bower' &&
|
||||
tty.isatty(1) &&
|
||||
!process.env.CI
|
||||
);
|
||||
}
|
||||
|
||||
// Merge common CLI options into the config
|
||||
object.mixIn(config, cli.readOptions({
|
||||
force: { type: Boolean, shorthand: 'f' },
|
||||
offline: { type: Boolean, shorthand: 'o' },
|
||||
verbose: { type: Boolean, shorthand: 'V' },
|
||||
quiet: { type: Boolean, shorthand: 'q' },
|
||||
loglevel: { type: String, shorthand: 'l' },
|
||||
json: { type: Boolean, shorthand: 'j' },
|
||||
silent: { type: Boolean, shorthand: 's' }
|
||||
}));
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
// Merge common CLI options into the config
|
||||
mout.object.mixIn(config, cli.readOptions({
|
||||
force: { type: Boolean, shorthand: 'f' },
|
||||
offline: { type: Boolean, shorthand: 'o' },
|
||||
verbose: { type: Boolean, shorthand: 'V' },
|
||||
quiet: { type: Boolean, shorthand: 'q' },
|
||||
loglevel: { type: String, shorthand: 'l' },
|
||||
json: { type: Boolean, shorthand: 'j' },
|
||||
silent: { type: Boolean, shorthand: 's' }
|
||||
}));
|
||||
function resetCache () {
|
||||
cachedConfigs = {};
|
||||
}
|
||||
|
||||
module.exports = config;
|
||||
module.exports = defaultConfig;
|
||||
module.exports.reset = resetCache;
|
||||
|
||||
@@ -9,6 +9,7 @@ var PackageRepository = require('./PackageRepository');
|
||||
var semver = require('../util/semver');
|
||||
var copy = require('../util/copy');
|
||||
var createError = require('../util/createError');
|
||||
var dependencyLinker = require('../util/dependencyLinker');
|
||||
var scripts = require('./scripts');
|
||||
|
||||
function Manager(config, logger) {
|
||||
@@ -109,6 +110,40 @@ Manager.prototype.resolve = function () {
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Manager.prototype.preinstall = function (json) {
|
||||
var that = this;
|
||||
var componentsDir = path.join(this._config.cwd, this._config.directory);
|
||||
|
||||
// If nothing to install, skip the code bellow
|
||||
if (mout.lang.isEmpty(that._dissected)) {
|
||||
return Q.resolve({});
|
||||
}
|
||||
|
||||
return Q.nfcall(mkdirp, componentsDir)
|
||||
.then(function () {
|
||||
return scripts.preinstall(
|
||||
that._config, that._logger, that._dissected, that._installed, json
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
Manager.prototype.postinstall = function (json) {
|
||||
var that = this;
|
||||
var componentsDir = path.join(this._config.cwd, this._config.directory);
|
||||
|
||||
// If nothing to install, skip the code bellow
|
||||
if (mout.lang.isEmpty(that._dissected)) {
|
||||
return Q.resolve({});
|
||||
}
|
||||
|
||||
return Q.nfcall(mkdirp, componentsDir)
|
||||
.then(function () {
|
||||
return scripts.postinstall(
|
||||
that._config, that._logger, that._dissected, that._installed, json
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
Manager.prototype.install = function (json) {
|
||||
var componentsDir;
|
||||
var that = this;
|
||||
@@ -125,9 +160,6 @@ Manager.prototype.install = function (json) {
|
||||
|
||||
componentsDir = path.join(this._config.cwd, this._config.directory);
|
||||
return Q.nfcall(mkdirp, componentsDir)
|
||||
.then(function () {
|
||||
return scripts.preinstall(that._config, that._logger, that._dissected, that._installed, json);
|
||||
})
|
||||
.then(function () {
|
||||
var promises = [];
|
||||
|
||||
@@ -169,9 +201,6 @@ Manager.prototype.install = function (json) {
|
||||
|
||||
return Q.all(promises);
|
||||
})
|
||||
.then(function () {
|
||||
return scripts.postinstall(that._config, that._logger, that._dissected, that._installed, json);
|
||||
})
|
||||
.then(function () {
|
||||
// Sync up dissected dependencies and dependants
|
||||
// See: https://github.com/bower/bower/issues/879
|
||||
@@ -190,7 +219,13 @@ Manager.prototype.install = function (json) {
|
||||
return dissected;
|
||||
}, this);
|
||||
}, that);
|
||||
|
||||
})
|
||||
.then(function () {
|
||||
// Create symlinks for sub-dependencies
|
||||
var flattened = mout.object.mixIn({}, that._installed, that._dissected);
|
||||
return dependencyLinker.link(flattened, that._config, that._logger);
|
||||
})
|
||||
.then(function () {
|
||||
// Resolve with meaningful data
|
||||
return mout.object.map(that._dissected, function (decEndpoint) {
|
||||
return this.toData(decEndpoint);
|
||||
@@ -543,13 +578,11 @@ Manager.prototype._dissect = function () {
|
||||
return;
|
||||
}
|
||||
|
||||
this._logger.info('resolution', 'Removed unnecessary ' + name + '#' + resolution + ' resolution', {
|
||||
this._logger.warn('extra-resolution', 'Unnecessary resolution: ' + name + '#' + resolution, {
|
||||
name: name,
|
||||
resolution: resolution,
|
||||
action: 'delete'
|
||||
});
|
||||
|
||||
delete this._resolutions[name];
|
||||
}, this);
|
||||
|
||||
// Filter only packages that need to be installed
|
||||
|
||||
@@ -20,7 +20,7 @@ function Project(config, logger) {
|
||||
// on config and logger
|
||||
// The reason behind it is that users can likely use this component
|
||||
// directly if commands do not fulfil their needs
|
||||
this._config = config || defaultConfig;
|
||||
this._config = defaultConfig(config);
|
||||
this._logger = logger || new Logger();
|
||||
this._manager = new Manager(this._config, this._logger);
|
||||
|
||||
@@ -47,6 +47,12 @@ Project.prototype.install = function (decEndpoints, options, config) {
|
||||
// Analyse the project
|
||||
return this._analyse()
|
||||
.spread(function (json, tree) {
|
||||
// It shows an error when issuing `bower install`
|
||||
// and no bower.json is present in current directory
|
||||
if(!that._jsonFile && decEndpoints.length === 0 ) {
|
||||
throw createError('No bower.json present', 'ENOENT');
|
||||
}
|
||||
|
||||
// Recover tree
|
||||
that.walkTree(tree, function (node, name) {
|
||||
if (node.incompatible) {
|
||||
@@ -72,6 +78,12 @@ Project.prototype.install = function (decEndpoints, options, config) {
|
||||
// Bootstrap the process
|
||||
return that._bootstrap(targets, resolved, incompatibles);
|
||||
})
|
||||
.then(function () {
|
||||
return that._manager.preinstall(that._json);
|
||||
})
|
||||
.then(function () {
|
||||
return that._manager.install(that._json);
|
||||
})
|
||||
.then(function (installed) {
|
||||
// Handle save and saveDev options
|
||||
if (that._options.save || that._options.saveDev) {
|
||||
@@ -94,7 +106,9 @@ Project.prototype.install = function (decEndpoints, options, config) {
|
||||
// Save JSON, might contain changes to dependencies and resolutions
|
||||
return that.saveJson()
|
||||
.then(function () {
|
||||
return installed;
|
||||
return that._manager.postinstall(that._json).then(function () {
|
||||
return installed;
|
||||
});
|
||||
});
|
||||
})
|
||||
.fin(function () {
|
||||
@@ -175,11 +189,19 @@ Project.prototype.update = function (names, options) {
|
||||
|
||||
// Bootstrap the process
|
||||
return that._bootstrap(targets, resolved, incompatibles)
|
||||
.then(function () {
|
||||
return that._manager.preinstall(that._json);
|
||||
})
|
||||
.then(function () {
|
||||
return that._manager.install(that._json);
|
||||
})
|
||||
.then(function (installed) {
|
||||
// Save JSON, might contain changes to resolutions
|
||||
return that.saveJson()
|
||||
.then(function () {
|
||||
return installed;
|
||||
return that._manager.postinstall(that._json).then(function () {
|
||||
return installed;
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
@@ -523,9 +545,7 @@ Project.prototype._bootstrap = function (targets, resolved, incompatibles) {
|
||||
if (!mout.object.size(this._json.resolutions)) {
|
||||
delete this._json.resolutions;
|
||||
}
|
||||
}.bind(this))
|
||||
// Install resolved ones
|
||||
.then(this._manager.install.bind(this._manager, this._json));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Project.prototype._readJson = function () {
|
||||
@@ -730,7 +750,7 @@ Project.prototype._removePackages = function (packages) {
|
||||
});
|
||||
};
|
||||
|
||||
Project.prototype._restoreNode = function (node, flattened, jsonKey) {
|
||||
Project.prototype._restoreNode = function (node, flattened, jsonKey, processed) {
|
||||
var deps;
|
||||
|
||||
// Do not restore if the node is missing
|
||||
@@ -740,10 +760,11 @@ Project.prototype._restoreNode = function (node, flattened, jsonKey) {
|
||||
|
||||
node.dependencies = node.dependencies || {};
|
||||
node.dependants = node.dependants || {};
|
||||
processed = processed || {};
|
||||
|
||||
// Only process deps that are not yet processed
|
||||
deps = mout.object.filter(node.pkgMeta[jsonKey], function (value, key) {
|
||||
return !node.dependencies[key];
|
||||
return !processed[node.name + ':' + key];
|
||||
});
|
||||
|
||||
mout.object.forOwn(deps, function (value, key) {
|
||||
@@ -790,15 +811,17 @@ Project.prototype._restoreNode = function (node, flattened, jsonKey) {
|
||||
|
||||
// Cross reference
|
||||
node.dependencies[key] = restored;
|
||||
processed[node.name + ':' + key] = true;
|
||||
|
||||
restored.dependants = restored.dependants || {};
|
||||
restored.dependants[node.name] = mout.object.mixIn({}, node); // We need to clone due to shared objects in the manager!
|
||||
|
||||
// Call restore for this dependency
|
||||
this._restoreNode(restored, flattened, 'dependencies');
|
||||
this._restoreNode(restored, flattened, 'dependencies', processed);
|
||||
|
||||
// Do the same for the incompatible local package
|
||||
if (local && restored !== local) {
|
||||
this._restoreNode(local, flattened, 'dependencies');
|
||||
this._restoreNode(local, flattened, 'dependencies', processed);
|
||||
}
|
||||
}, this);
|
||||
};
|
||||
|
||||
@@ -41,6 +41,11 @@ function getConstructor(source, config, registryClient) {
|
||||
return [resolvers.GitHub, source];
|
||||
}
|
||||
|
||||
// If it's a BitBucket repository, return the specialized resolver
|
||||
if (resolvers.BitBucket.getOrgRepoPair(source)) {
|
||||
return [resolvers.BitBucket, source];
|
||||
}
|
||||
|
||||
return [resolvers.GitRemote, source];
|
||||
});
|
||||
}
|
||||
|
||||
150
lib/core/resolvers/BitBucketResolver.js
Normal file
150
lib/core/resolvers/BitBucketResolver.js
Normal file
@@ -0,0 +1,150 @@
|
||||
var util = require('util');
|
||||
var path = require('path');
|
||||
var mout = require('mout');
|
||||
var GitRemoteResolver = require('./GitRemoteResolver');
|
||||
var download = require('../../util/download');
|
||||
var extract = require('../../util/extract');
|
||||
var createError = require('../../util/createError');
|
||||
|
||||
function BitBucketResolver(decEndpoint, config, logger) {
|
||||
var pair;
|
||||
|
||||
GitRemoteResolver.call(this, decEndpoint, config, logger);
|
||||
|
||||
// Grab the org/repo
|
||||
// /xxxxx/yyyyy.git or :xxxxx/yyyyy.git (.git is optional)
|
||||
pair = BitBucketResolver.getOrgRepoPair(this._source);
|
||||
if (!pair) {
|
||||
throw createError('Invalid BitBucket URL', 'EINVEND', {
|
||||
details: this._source + ' does not seem to be a valid BitBucket URL'
|
||||
});
|
||||
}
|
||||
|
||||
this._org = pair.org;
|
||||
this._repo = pair.repo;
|
||||
|
||||
// Ensure trailing for all protocols
|
||||
if (!mout.string.endsWith(this._source, '.git')) {
|
||||
this._source += '.git';
|
||||
}
|
||||
|
||||
// Check if it's public
|
||||
this._public = mout.string.startsWith(this._source, 'git://');
|
||||
|
||||
// Use https:// rather than git:// if on a proxy
|
||||
if (this._config.proxy || this._config.httpsProxy) {
|
||||
this._source = this._source.replace('git://', 'https://');
|
||||
}
|
||||
|
||||
// Enable shallow clones for BitBucket repos
|
||||
this._shallowClone = true;
|
||||
}
|
||||
|
||||
util.inherits(BitBucketResolver, GitRemoteResolver);
|
||||
mout.object.mixIn(BitBucketResolver, GitRemoteResolver);
|
||||
|
||||
// -----------------
|
||||
|
||||
BitBucketResolver.prototype._checkout = function () {
|
||||
// Only fully works with public repositories and tags
|
||||
// Could work with https/ssh protocol but not with 100% certainty
|
||||
if (!this._public || !this._resolution.tag) {
|
||||
return GitRemoteResolver.prototype._checkout.call(this);
|
||||
}
|
||||
|
||||
var msg;
|
||||
var tarballUrl = 'https://bitbucket.org/' + this._org + '/' + this._repo + '/get/' + this._resolution.tag + '.tar.gz';
|
||||
var file = path.join(this._tempDir, 'archive.tar.gz');
|
||||
var reqHeaders = {};
|
||||
var that = this;
|
||||
|
||||
if (this._config.userAgent) {
|
||||
reqHeaders['User-Agent'] = this._config.userAgent;
|
||||
}
|
||||
|
||||
this._logger.action('download', tarballUrl, {
|
||||
url: that._source,
|
||||
to: file
|
||||
});
|
||||
|
||||
// Download tarball
|
||||
return download(tarballUrl, file, {
|
||||
proxy: this._config.httpsProxy,
|
||||
strictSSL: this._config.strictSsl,
|
||||
timeout: this._config.timeout,
|
||||
headers: reqHeaders
|
||||
})
|
||||
.progress(function (state) {
|
||||
// Retry?
|
||||
if (state.retry) {
|
||||
msg = 'Download of ' + tarballUrl + ' failed with ' + state.error.code + ', ';
|
||||
msg += 'retrying in ' + (state.delay / 1000).toFixed(1) + 's';
|
||||
that._logger.debug('error', state.error.message, { error: state.error });
|
||||
return that._logger.warn('retry', msg);
|
||||
}
|
||||
|
||||
// Progress
|
||||
msg = 'received ' + (state.received / 1024 / 1024).toFixed(1) + 'MB';
|
||||
if (state.total) {
|
||||
msg += ' of ' + (state.total / 1024 / 1024).toFixed(1) + 'MB downloaded, ';
|
||||
msg += state.percent + '%';
|
||||
}
|
||||
that._logger.info('progress', msg);
|
||||
})
|
||||
.then(function () {
|
||||
// Extract archive
|
||||
that._logger.action('extract', path.basename(file), {
|
||||
archive: file,
|
||||
to: that._tempDir
|
||||
});
|
||||
|
||||
return extract(file, that._tempDir)
|
||||
// Fallback to standard git clone if extraction failed
|
||||
.fail(function (err) {
|
||||
msg = 'Decompression of ' + path.basename(file) + ' failed' + (err.code ? ' with ' + err.code : '') + ', ';
|
||||
msg += 'trying with git..';
|
||||
that._logger.debug('error', err.message, { error: err });
|
||||
that._logger.warn('retry', msg);
|
||||
|
||||
return that._cleanTempDir()
|
||||
.then(GitRemoteResolver.prototype._checkout.bind(that));
|
||||
});
|
||||
// Fallback to standard git clone if download failed
|
||||
}, function (err) {
|
||||
msg = 'Download of ' + tarballUrl + ' failed' + (err.code ? ' with ' + err.code : '') + ', ';
|
||||
msg += 'trying with git..';
|
||||
that._logger.debug('error', err.message, { error: err });
|
||||
that._logger.warn('retry', msg);
|
||||
|
||||
return that._cleanTempDir()
|
||||
.then(GitRemoteResolver.prototype._checkout.bind(that));
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
BitBucketResolver.prototype._savePkgMeta = function (meta) {
|
||||
// Set homepage if not defined
|
||||
if (!meta.homepage) {
|
||||
meta.homepage = 'https://bitbucket.org/' + this._org + '/' + this._repo;
|
||||
}
|
||||
|
||||
return GitRemoteResolver.prototype._savePkgMeta.call(this, meta);
|
||||
};
|
||||
|
||||
// ----------------
|
||||
|
||||
BitBucketResolver.getOrgRepoPair = function (url) {
|
||||
var match;
|
||||
|
||||
match = url.match(/(?:@|:\/\/)bitbucket.org[:\/]([^\/\s]+?)\/([^\/\s]+?)(?:\.git)?\/?$/i);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
org: match[1],
|
||||
repo: match[2]
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = BitBucketResolver;
|
||||
@@ -35,6 +35,9 @@ function GitHubResolver(decEndpoint, config, logger) {
|
||||
if (this._config.proxy || this._config.httpsProxy) {
|
||||
this._source = this._source.replace('git://', 'https://');
|
||||
}
|
||||
|
||||
// Enable shallow clones for GitHub repos
|
||||
this._shallowClone = true;
|
||||
}
|
||||
|
||||
util.inherits(GitHubResolver, GitRemoteResolver);
|
||||
|
||||
@@ -25,6 +25,9 @@ function GitRemoteResolver(decEndpoint, config, logger) {
|
||||
} else {
|
||||
this._host = url.parse(this._source).host;
|
||||
}
|
||||
|
||||
// Disable shallow clones
|
||||
this._shallowClone = false;
|
||||
}
|
||||
|
||||
util.inherits(GitRemoteResolver, GitResolver);
|
||||
@@ -113,7 +116,7 @@ GitRemoteResolver.prototype._fastClone = function (resolution) {
|
||||
args = ['clone', this._source, '-b', branch, '--progress', '.'];
|
||||
|
||||
// If the host does not support shallow clones, we don't use --depth=1
|
||||
if (!GitRemoteResolver._noShallow.get(this._host)) {
|
||||
if (this._shallowClone && !GitRemoteResolver._noShallow.get(this._host)) {
|
||||
args.push('--depth', 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ var mout = require('mout');
|
||||
var Resolver = require('./Resolver');
|
||||
var semver = require('../../util/semver');
|
||||
var createError = require('../../util/createError');
|
||||
var defaultConfig = require('../../config');
|
||||
|
||||
var hasGit;
|
||||
|
||||
@@ -22,13 +21,13 @@ try {
|
||||
hasGit = false;
|
||||
}
|
||||
|
||||
// Set template dir to the empty directory so that user templates are not run
|
||||
// This environment variable is not multiple config aware but it's not documented
|
||||
// anyway
|
||||
mkdirp.sync(defaultConfig.storage.empty);
|
||||
process.env.GIT_TEMPLATE_DIR = defaultConfig.storage.empty;
|
||||
|
||||
function GitResolver(decEndpoint, config, logger) {
|
||||
// Set template dir to the empty directory so that user templates are not run
|
||||
// This environment variable is not multiple config aware but it's not documented
|
||||
// anyway
|
||||
mkdirp.sync(config.storage.empty);
|
||||
process.env.GIT_TEMPLATE_DIR = config.storage.empty;
|
||||
|
||||
Resolver.call(this, decEndpoint, config, logger);
|
||||
|
||||
if (!hasGit) {
|
||||
|
||||
@@ -169,8 +169,8 @@ Resolver.prototype._createTempDir = function () {
|
||||
});
|
||||
}.bind(this))
|
||||
.then(function (dir) {
|
||||
this._tempDir = dir;
|
||||
return dir;
|
||||
// nfcall may return multiple callback arguments as an array
|
||||
return this._tempDir = Array.isArray(dir) ? dir[0] : dir;
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ module.exports = {
|
||||
GitFs: require('./GitFsResolver'),
|
||||
GitRemote: require('./GitRemoteResolver'),
|
||||
GitHub: require('./GitHubResolver'),
|
||||
BitBucket: require('./BitBucketResolver'),
|
||||
Svn: require('./SvnResolver'),
|
||||
Fs: require('./FsResolver'),
|
||||
Url: require('./UrlResolver')
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
var abbrev = require('abbrev');
|
||||
var mout = require('mout');
|
||||
var commands = require('./commands');
|
||||
var pkg = require('../package.json');
|
||||
|
||||
var abbreviations = abbrev(expandNames(commands));
|
||||
abbreviations.i = 'install';
|
||||
@@ -34,8 +35,9 @@ function clearRuntimeCache() {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
version: pkg.version,
|
||||
commands: commands,
|
||||
config: require('./config'),
|
||||
config: require('./config')(),
|
||||
abbreviations: abbreviations,
|
||||
reset: clearRuntimeCache
|
||||
};
|
||||
|
||||
@@ -121,8 +121,6 @@ JsonRenderer.prototype.prompt = function (prompts) {
|
||||
});
|
||||
};
|
||||
|
||||
JsonRenderer.prototype.updateNotice = function () {};
|
||||
|
||||
// -------------------------
|
||||
|
||||
JsonRenderer.prototype._stringify = function (log) {
|
||||
|
||||
@@ -30,6 +30,16 @@ function StandardRenderer(command, config) {
|
||||
} else {
|
||||
this._compact = process.stdout.columns < 120;
|
||||
}
|
||||
|
||||
var exitOnPipeError = function (err) {
|
||||
if (err.code === 'EPIPE') {
|
||||
process.exit(0);
|
||||
}
|
||||
};
|
||||
|
||||
// It happens when piping command to "head" util
|
||||
process.stdout.on('error', exitOnPipeError);
|
||||
process.stderr.on('error', exitOnPipeError);
|
||||
}
|
||||
|
||||
StandardRenderer.prototype.end = function (data) {
|
||||
@@ -110,11 +120,6 @@ StandardRenderer.prototype.prompt = function (prompts) {
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
StandardRenderer.prototype.updateNotice = function (data) {
|
||||
var str = template.render('std/update-notice.std', data);
|
||||
this._write(process.stderr, str);
|
||||
};
|
||||
|
||||
// -------------------------
|
||||
|
||||
StandardRenderer.prototype._help = function (data) {
|
||||
@@ -170,10 +175,14 @@ StandardRenderer.prototype._update = function (packages) {
|
||||
StandardRenderer.prototype._list = function (tree) {
|
||||
var cliTree;
|
||||
|
||||
tree.root = true;
|
||||
cliTree = this._tree2archy(tree);
|
||||
if (tree.pkgMeta) {
|
||||
tree.root = true;
|
||||
cliTree = archy(this._tree2archy(tree));
|
||||
} else {
|
||||
cliTree = stringifyObject(tree, { indent: ' ' }).replace(/[{}]/g, '') + '\n';
|
||||
}
|
||||
|
||||
this._write(process.stdout, archy(cliTree));
|
||||
this._write(process.stdout, cliTree);
|
||||
};
|
||||
|
||||
StandardRenderer.prototype._search = function (results) {
|
||||
|
||||
@@ -2,47 +2,96 @@ var Q = require('q');
|
||||
var mout = require('mout');
|
||||
|
||||
var analytics = module.exports;
|
||||
|
||||
var insight;
|
||||
|
||||
// Initializes the application-wide insight singleton and asks for the
|
||||
// permission on the CLI during the first run.
|
||||
analytics.setup = function setup(config) {
|
||||
var deferred = Q.defer();
|
||||
var enableAnalytics = false;
|
||||
|
||||
// Display the ask prompt only if it hasn't been answered before
|
||||
// and the current session is looking to configure the analytics.
|
||||
if (config.analytics) {
|
||||
// Insight takes long to load, and often causes problems
|
||||
// in non-interactive environment, so we load it lazily
|
||||
//
|
||||
// Insight is used in two cases:
|
||||
//
|
||||
// 1. Read insight configuration (whether track user actions)
|
||||
// 2. Track user actions (Tracker.track method)
|
||||
//
|
||||
// We don't want to instantiate Insight in non-interactive mode
|
||||
// because it takes time to read config and configstore has concurrency issues:
|
||||
//
|
||||
// https://github.com/yeoman/configstore/issues/20
|
||||
function ensureInsight () {
|
||||
if (!insight) {
|
||||
var Insight = require('insight');
|
||||
var pkg = require('../../package.json');
|
||||
|
||||
insight = new Insight({
|
||||
trackingCode: 'UA-43531210-1',
|
||||
packageName: pkg.name,
|
||||
packageVersion: pkg.version
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (insight.optOut === undefined) {
|
||||
insight.askPermission(null, deferred.resolve);
|
||||
// Initializes the application-wide insight singleton and asks for the
|
||||
// permission on the CLI during the first run.
|
||||
//
|
||||
// This method is called only from bin/bower. Programmatic API skips it.
|
||||
analytics.setup = function setup (config) {
|
||||
var deferred = Q.defer();
|
||||
|
||||
// No need for asking if analytics is set in bower config
|
||||
if (config.analytics === undefined) {
|
||||
ensureInsight();
|
||||
|
||||
// For non-interactive call from bin/bower we disable analytics
|
||||
if (config.interactive) {
|
||||
if (insight.optOut !== undefined) {
|
||||
deferred.resolve(!insight.optOut);
|
||||
} else {
|
||||
insight.askPermission(null, function(err, optIn) {
|
||||
// optIn callback param was exactly opposite before 0.4.3
|
||||
// so we force at least insight@0.4.3 in package.json
|
||||
deferred.resolve(optIn);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
deferred.resolve();
|
||||
// no specified value, no stored value, and can't prompt for one
|
||||
// most likely CI environment; defaults to false to reduce data noise
|
||||
deferred.resolve(false);
|
||||
}
|
||||
} else {
|
||||
deferred.resolve();
|
||||
// use the specified value
|
||||
deferred.resolve(config.analytics);
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
return deferred.promise.then(function (enabled) {
|
||||
enableAnalytics = enabled;
|
||||
|
||||
return enabled;
|
||||
});
|
||||
};
|
||||
|
||||
var Tracker = analytics.Tracker = function Tracker(config) {
|
||||
if (!config.analytics) {
|
||||
this.track = function noop() {};
|
||||
function analyticsEnabled () {
|
||||
// Allow for overriding analytics default
|
||||
if (config && config.analytics !== undefined) {
|
||||
return config.analytics;
|
||||
}
|
||||
|
||||
// TODO: let bower pass this variable from bin/bower instead closure
|
||||
return enableAnalytics;
|
||||
}
|
||||
|
||||
if (analyticsEnabled()) {
|
||||
ensureInsight();
|
||||
} else {
|
||||
this.track = function noop () {};
|
||||
this.trackDecomposedEndpoints = function noop () {};
|
||||
this.trackPackages = function noop () {};
|
||||
this.trackNames = function noop () {};
|
||||
}
|
||||
};
|
||||
|
||||
Tracker.prototype.track = function track() {
|
||||
if (!insight) {
|
||||
throw new Error('You must call analytics.setup() prior to tracking.');
|
||||
}
|
||||
insight.track.apply(insight, arguments);
|
||||
};
|
||||
|
||||
|
||||
@@ -8,9 +8,12 @@ var createError = require('./createError');
|
||||
|
||||
// The concurrency limit here is kind of magic. You don't really gain a lot from
|
||||
// having a large number of commands spawned at once, so it isn't super
|
||||
// important for this number to be large. However, it would still be nice to
|
||||
// *know* how high this number can be, rather than having to guess low.
|
||||
var throttler = new PThrottler(50);
|
||||
// important for this number to be large. Reports have shown that much more than 5
|
||||
// or 10 cause issues for corporate networks, private repos or situations where
|
||||
// internet bandwidth is limited. We're running with a concurrency of 5 until
|
||||
// 1.4.X is released, at which time we'll move to what was discussed in #1262
|
||||
// https://github.com/bower/bower/pull/1262
|
||||
var throttler = new PThrottler(5);
|
||||
|
||||
var winBatchExtensions;
|
||||
var winWhichCache;
|
||||
|
||||
@@ -6,7 +6,9 @@ var createError = require('./createError');
|
||||
|
||||
var isWin = process.platform === 'win32';
|
||||
|
||||
function createLink(src, dst, type) {
|
||||
function createLink(src, dst, options) {
|
||||
options = options || {};
|
||||
|
||||
var dstDir = path.dirname(dst);
|
||||
|
||||
// Create directory
|
||||
@@ -26,7 +28,12 @@ function createLink(src, dst, type) {
|
||||
})
|
||||
// Create symlink
|
||||
.then(function (stat) {
|
||||
type = type || (stat.isDirectory() ? 'dir' : 'file');
|
||||
var type = options.type || (stat.isDirectory() ? 'dir' : 'file');
|
||||
if (options.relative && !isWin) {
|
||||
src = path.relative(path.dirname(dst), src);
|
||||
} else {
|
||||
src = path.resolve(src);
|
||||
}
|
||||
|
||||
return Q.nfcall(fs.symlink, src, dst, type)
|
||||
.fail(function (err) {
|
||||
|
||||
39
lib/util/dependencyLinker.js
Normal file
39
lib/util/dependencyLinker.js
Normal file
@@ -0,0 +1,39 @@
|
||||
var Q = require('q');
|
||||
var Config = require('bower-config');
|
||||
var createLink = require('../util/createLink');
|
||||
var readJson = require('../util/readJson');
|
||||
var path = require('path');
|
||||
var fs = require('graceful-fs');
|
||||
|
||||
module.exports.link = function (packages, config, logger) {
|
||||
var rootComponentsDir = path.join(config.cwd, config.directory);
|
||||
|
||||
// create links for new packages and make sure that existing
|
||||
// ones has all dependencies linked
|
||||
var promises = Object.keys(packages).map(function (depName) {
|
||||
var dep = packages[depName];
|
||||
var depPath = dep.canonicalDir || path.join(rootComponentsDir, dep.name);
|
||||
var conf = Config.read(depPath);
|
||||
var componentsDir = path.join(conf.cwd, conf.directory);
|
||||
|
||||
return readJson(depPath)
|
||||
.spread(function (json, deprecated, assumed) {
|
||||
if (json.dependencies) {
|
||||
return Q.all(Object.keys(json.dependencies || {}).map(function (d) {
|
||||
var dst = path.join(componentsDir, d);
|
||||
var src = path.join(rootComponentsDir, d);
|
||||
|
||||
return Q.nfcall(fs.stat, dst)
|
||||
.fail(function () {
|
||||
logger.info('dep-link', d, {
|
||||
name: json.name + '#' + d
|
||||
});
|
||||
return createLink(src, dst, {relative: true});
|
||||
});
|
||||
}));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return Q.all(promises);
|
||||
};
|
||||
@@ -2,7 +2,7 @@ var path = require('path');
|
||||
var fs = require('graceful-fs');
|
||||
var zlib = require('zlib');
|
||||
var DecompressZip = require('decompress-zip');
|
||||
var tar = require('tar');
|
||||
var tar = require('tar-fs');
|
||||
var Q = require('q');
|
||||
var mout = require('mout');
|
||||
var junk = require('junk');
|
||||
@@ -23,6 +23,7 @@ extractors = {
|
||||
'.gz': extractGz,
|
||||
'application/zip': extractZip,
|
||||
'application/x-zip': extractZip,
|
||||
'application/x-zip-compressed': extractZip,
|
||||
'application/x-tar': extractTar,
|
||||
'application/x-tgz': extractTarGz,
|
||||
'application/x-gzip': extractGz
|
||||
@@ -50,13 +51,11 @@ function extractTar(archive, dst) {
|
||||
|
||||
fs.createReadStream(archive)
|
||||
.on('error', deferred.reject)
|
||||
.pipe(tar.Extract({
|
||||
path: dst,
|
||||
follow: false, // Do not follow symlinks (#699)
|
||||
filter: filterSymlinks // Filter symlink files
|
||||
.pipe(tar.extract(dst, {
|
||||
ignore: isSymlink // Filter symlink files
|
||||
}))
|
||||
.on('error', deferred.reject)
|
||||
.on('close', deferred.resolve.bind(deferred, dst));
|
||||
.on('finish', deferred.resolve.bind(deferred, dst));
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
@@ -68,13 +67,11 @@ function extractTarGz(archive, dst) {
|
||||
.on('error', deferred.reject)
|
||||
.pipe(zlib.createGunzip())
|
||||
.on('error', deferred.reject)
|
||||
.pipe(tar.Extract({
|
||||
path: dst,
|
||||
follow: false, // Do not follow symlinks (#699)
|
||||
filter: filterSymlinks // Filter symlink files
|
||||
.pipe(tar.extract(dst, {
|
||||
ignore: isSymlink // Filter symlink files
|
||||
}))
|
||||
.on('error', deferred.reject)
|
||||
.on('close', deferred.resolve.bind(deferred, dst));
|
||||
.on('finish', deferred.resolve.bind(deferred, dst));
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
@@ -93,6 +90,10 @@ function extractGz(archive, dst) {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function isSymlink(entry) {
|
||||
return entry.type === 'SymbolicLink';
|
||||
}
|
||||
|
||||
function filterSymlinks(entry) {
|
||||
return entry.type !== 'SymbolicLink';
|
||||
}
|
||||
|
||||
69
package.json
69
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bower",
|
||||
"version": "1.3.5",
|
||||
"version": "1.3.12",
|
||||
"description": "The browser package manager",
|
||||
"author": "Twitter",
|
||||
"licenses": [
|
||||
@@ -17,61 +17,62 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"abbrev": "~1.0.4",
|
||||
"archy": "~0.0.2",
|
||||
"archy": "0.0.2",
|
||||
"bower-config": "~0.5.2",
|
||||
"bower-endpoint-parser": "~0.2.2",
|
||||
"bower-json": "~0.4.0",
|
||||
"bower-logger": "~0.2.2",
|
||||
"bower-registry-client": "~0.2.0",
|
||||
"cardinal": "~0.4.0",
|
||||
"chalk": "~0.4.0",
|
||||
"chmodr": "~0.1.0",
|
||||
"decompress-zip": "~0.0.6",
|
||||
"fstream": "~0.1.22",
|
||||
"fstream-ignore": "~0.0.6",
|
||||
"cardinal": "0.4.0",
|
||||
"chalk": "0.5.0",
|
||||
"chmodr": "0.1.0",
|
||||
"decompress-zip": "0.0.8",
|
||||
"fstream": "~1.0.2",
|
||||
"fstream-ignore": "~1.0.1",
|
||||
"glob": "~4.0.2",
|
||||
"graceful-fs": "~3.0.1",
|
||||
"handlebars": "~1.3.0",
|
||||
"inquirer": "~0.5.1",
|
||||
"insight": "~0.3.0",
|
||||
"is-root": "~0.1.0",
|
||||
"junk": "~0.3.0",
|
||||
"lockfile": "~0.4.2",
|
||||
"handlebars": "~2.0.0",
|
||||
"inquirer": "0.7.1",
|
||||
"insight": "0.4.3",
|
||||
"is-root": "~1.0.0",
|
||||
"junk": "~1.0.0",
|
||||
"lockfile": "~1.0.0",
|
||||
"lru-cache": "~2.5.0",
|
||||
"mkdirp": "~0.5.0",
|
||||
"mout": "~0.9.1",
|
||||
"mkdirp": "0.5.0",
|
||||
"mout": "~0.9.0",
|
||||
"nopt": "~3.0.0",
|
||||
"opn": "~0.1.1",
|
||||
"osenv": "~0.1.0",
|
||||
"p-throttler": "~0.0.1",
|
||||
"promptly": "~0.2.0",
|
||||
"opn": "~1.0.0",
|
||||
"osenv": "0.1.0",
|
||||
"p-throttler": "0.1.0",
|
||||
"promptly": "0.2.0",
|
||||
"q": "~1.0.1",
|
||||
"request": "~2.36.0",
|
||||
"request-progress": "~0.3.0",
|
||||
"retry": "~0.6.0",
|
||||
"request": "~2.42.0",
|
||||
"request-progress": "0.3.0",
|
||||
"retry": "0.6.0",
|
||||
"rimraf": "~2.2.0",
|
||||
"semver": "~2.3.0",
|
||||
"shell-quote": "~1.4.1",
|
||||
"stringify-object": "~0.2.0",
|
||||
"tar": "~0.1.17",
|
||||
"tmp": "~0.0.23",
|
||||
"update-notifier": "~0.1.8",
|
||||
"stringify-object": "~1.0.0",
|
||||
"tar-fs": "0.5.2",
|
||||
"tmp": "0.0.23",
|
||||
"update-notifier": "0.2.0",
|
||||
"which": "~1.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"coveralls": "~2.11.0",
|
||||
"expect.js": "~0.3.1",
|
||||
"grunt": "~0.4.4",
|
||||
"grunt-cli": "^0.1.13",
|
||||
"grunt-contrib-jshint": "~0.10.0",
|
||||
"grunt-contrib-watch": "~0.6.1",
|
||||
"grunt-exec": "~0.4.2",
|
||||
"grunt-simple-mocha": "~0.4.0",
|
||||
"istanbul": "~0.2.4",
|
||||
"load-grunt-tasks": "~0.4.0",
|
||||
"mocha": "~1.20.1",
|
||||
"nock": "~0.34.1",
|
||||
"proxyquire": "~1.0.1",
|
||||
"coveralls": "~2.10.0",
|
||||
"node-uuid": "~1.4.1"
|
||||
"istanbul": "~0.3.2",
|
||||
"load-grunt-tasks": "~0.6.0",
|
||||
"mocha": "~1.21.4",
|
||||
"nock": "~0.46.0",
|
||||
"node-uuid": "~1.4.1",
|
||||
"proxyquire": "~1.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "grunt test"
|
||||
|
||||
@@ -13,12 +13,12 @@
|
||||
{
|
||||
"shorthand": "-S",
|
||||
"flag": "--save",
|
||||
"description": "Save installed packages into the project's bower.json dependencies"
|
||||
"description": "Remove uninstalled packages from the project's bower.json dependencies"
|
||||
},
|
||||
{
|
||||
"shorthand": "-D",
|
||||
"flag": "--save-dev",
|
||||
"description": "Save installed packages into the project's bower.json devDependencies"
|
||||
"description": "Remove uninstalled packages from the project's bower.json devDependencies"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"init": "Interactively create a bower.json file",
|
||||
"install": "Install a package locally",
|
||||
"link": "Symlink a package folder",
|
||||
"list": "List local packages",
|
||||
"list": "List local packages - and possible updates",
|
||||
"lookup": "Look up a package URL by name",
|
||||
"prune": "Removes local extraneous packages",
|
||||
"register": "Register a package",
|
||||
|
||||
@@ -5,3 +5,4 @@
|
||||
Package not found.
|
||||
{{/if}}
|
||||
{{/condense}}
|
||||
|
||||
|
||||
@@ -5,5 +5,6 @@
|
||||
{{#cyan}}{{{name}}}{{/cyan}} {{{url}}}
|
||||
{{/.}}
|
||||
{{/condense}}
|
||||
|
||||
{{else}}No results.
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{{#red}}-----------------------------------------{{/red}}
|
||||
Update available: {{#yellow}}{{latest}}{{/yellow}} {{#cyan}}(current: {{current}}){{/cyan}}
|
||||
Run {{#yellow}}npm update -g {{name}}{{/yellow}} to update
|
||||
{{#red}}-----------------------------------------{{/red}}
|
||||
|
||||
@@ -4,7 +4,7 @@ var Logger = require('bower-logger');
|
||||
var Resolver = require('../../../lib/core/resolvers/Resolver');
|
||||
var defaultConfig = require('../../../lib/config');
|
||||
|
||||
var resolver = new Resolver({ source: 'foo' }, defaultConfig, new Logger());
|
||||
var resolver = new Resolver({ source: 'foo' }, defaultConfig(), new Logger());
|
||||
resolver._createTempDir()
|
||||
.then(function (dir) {
|
||||
// Need to write something to prevent tmp to automatically
|
||||
|
||||
@@ -4,7 +4,7 @@ var Logger = require('bower-logger');
|
||||
var Resolver = require('../../../lib/core/resolvers/Resolver');
|
||||
var defaultConfig = require('../../../lib/config');
|
||||
|
||||
var resolver = new Resolver({ source: 'foo' }, defaultConfig, new Logger());
|
||||
var resolver = new Resolver({ source: 'foo' }, defaultConfig(), new Logger());
|
||||
resolver._createTempDir()
|
||||
.then(function (dir) {
|
||||
// Need to write something to prevent tmp to automatically
|
||||
|
||||
@@ -2,4 +2,5 @@ describe('integration tests', function () {
|
||||
require('./init');
|
||||
require('./install');
|
||||
require('./uninstall');
|
||||
require('./update');
|
||||
});
|
||||
|
||||
@@ -7,15 +7,17 @@ var bower = helpers.require('lib/index');
|
||||
|
||||
describe('bower init', function () {
|
||||
|
||||
var tempDir = helpers.createTmpDir();
|
||||
var bowerJsonPath = path.join(tempDir, 'bower.json');
|
||||
var tempDir = new helpers.TempDir();
|
||||
var bowerJsonPath = path.join(tempDir.path, 'bower.json');
|
||||
|
||||
var config = {
|
||||
cwd: tempDir,
|
||||
cwd: tempDir.path,
|
||||
interactive: true
|
||||
};
|
||||
|
||||
it('generates bower.json file', function () {
|
||||
tempDir.prepare();
|
||||
|
||||
var logger = bower.commands.init(config);
|
||||
|
||||
return helpers.expectEvent(logger, 'prompt')
|
||||
|
||||
@@ -1,47 +1,205 @@
|
||||
var path = require('path');
|
||||
var expect = require('expect.js');
|
||||
var fs = require('fs');
|
||||
var object = require('mout').object;
|
||||
|
||||
var helpers = require('../helpers');
|
||||
var bower = helpers.require('lib/index');
|
||||
var commands = helpers.require('lib/index').commands;
|
||||
|
||||
describe('bower install', function () {
|
||||
|
||||
var tempDir = helpers.createTmpDir();
|
||||
var bowerJsonPath = path.join(tempDir, 'bower_components', 'underscore', 'bower.json');
|
||||
var tempDir = new helpers.TempDir();
|
||||
|
||||
function bowerJson() {
|
||||
return JSON.parse(fs.readFileSync(bowerJsonPath));
|
||||
}
|
||||
var package = new helpers.TempDir({
|
||||
'bower.json': {
|
||||
name: 'package'
|
||||
}
|
||||
}).prepare();
|
||||
|
||||
var config = {
|
||||
cwd: tempDir,
|
||||
interactive: true
|
||||
var gitPackage = new helpers.TempDir();
|
||||
|
||||
var installLogger = function(packages, options, config) {
|
||||
config = object.merge(config || {}, {
|
||||
cwd: tempDir.path
|
||||
});
|
||||
|
||||
return commands.install(packages, options, config);
|
||||
};
|
||||
|
||||
it('does nothing if no bower.json is present', function () {
|
||||
var logger = bower.commands.install([], undefined, config);
|
||||
var install = function(packages, options, config) {
|
||||
var logger = installLogger(packages, options, config);
|
||||
|
||||
return helpers.expectEvent(logger, 'end');
|
||||
});
|
||||
};
|
||||
|
||||
it.skip('installs a package', function () {
|
||||
this.timeout(10000);
|
||||
var logger = bower.commands.install(['underscore'], undefined, config);
|
||||
it('writes to bower.json if --save flag is used', function () {
|
||||
package.prepare();
|
||||
|
||||
return helpers.expectEvent(logger, 'end')
|
||||
.then(function () {
|
||||
expect(bowerJson()).to.have.key('name');
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test'
|
||||
}
|
||||
});
|
||||
|
||||
return install([package.path], { save: true }).then(function() {
|
||||
expect(tempDir.read('bower.json')).to.contain('dependencies');
|
||||
});
|
||||
});
|
||||
|
||||
it.skip('installs package with --save flag', function () {
|
||||
var logger = bower.commands.install(['underscore'], {save: true}, config);
|
||||
it('reads .bowerrc from cwd', function () {
|
||||
package.prepare({ foo: 'bar' });
|
||||
|
||||
return helpers.expectEvent(logger, 'end')
|
||||
.then(function () {
|
||||
expect(bowerJson()).to.have.key('name');
|
||||
tempDir.prepare({
|
||||
'.bowerrc': { directory: 'assets' },
|
||||
'bower.json': {
|
||||
name: 'test',
|
||||
dependencies: {
|
||||
package: package.path
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return install().then(function() {
|
||||
expect(tempDir.read('assets/package/foo')).to.be('bar');
|
||||
});
|
||||
});
|
||||
|
||||
it('runs preinstall hook', function () {
|
||||
package.prepare();
|
||||
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test',
|
||||
dependencies: {
|
||||
package: package.path
|
||||
}
|
||||
},
|
||||
'.bowerrc': {
|
||||
scripts: {
|
||||
preinstall: 'bash -c "echo -n % > preinstall.txt"'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return install().then(function() {
|
||||
expect(tempDir.read('preinstall.txt')).to.be('package');
|
||||
});
|
||||
});
|
||||
|
||||
it('runs preinstall hook', function () {
|
||||
package.prepare();
|
||||
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test',
|
||||
dependencies: {
|
||||
package: package.path
|
||||
}
|
||||
},
|
||||
'.bowerrc': {
|
||||
scripts: {
|
||||
postinstall: 'bash -c "echo -n % > postinstall.txt"'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return install().then(function() {
|
||||
expect(tempDir.read('postinstall.txt')).to.be('package');
|
||||
});
|
||||
});
|
||||
|
||||
// To be discussed, but that's the implementation now
|
||||
it('does not run hooks if nothing is installed', function () {
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test'
|
||||
},
|
||||
'.bowerrc': {
|
||||
scripts: {
|
||||
postinstall: 'bash -c "echo -n % > hooks.txt"',
|
||||
preinstall: 'bash -c "echo -n % > hooks.txt"'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return install().then(function() {
|
||||
expect(tempDir.exists('hooks.txt')).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('runs postinstall after bower.json is written', function () {
|
||||
package.prepare();
|
||||
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test'
|
||||
},
|
||||
'.bowerrc': {
|
||||
scripts: {
|
||||
postinstall: 'bash -c "cat bower.json > hook.txt"',
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return install([package.path], { save: true }).then(function() {
|
||||
expect(tempDir.read('hook.txt')).to.contain('dependencies');
|
||||
});
|
||||
});
|
||||
|
||||
it('display the output of hook scripts', function (next) {
|
||||
package.prepare();
|
||||
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test',
|
||||
dependencies: {
|
||||
package: package.path
|
||||
}
|
||||
},
|
||||
'.bowerrc': {
|
||||
scripts: {
|
||||
postinstall: 'bash -c "echo foobar"'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var lastAction = null;
|
||||
|
||||
installLogger().intercept(function (log) {
|
||||
if (log.level === 'action') {
|
||||
lastAction = log;
|
||||
}
|
||||
}).on('end', function () {
|
||||
expect(lastAction.message).to.be('foobar');
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
it('works for git repositories', function () {
|
||||
return gitPackage.prepareGit({
|
||||
'1.0.0': {
|
||||
'bower.json': {
|
||||
name: 'package'
|
||||
},
|
||||
'version.txt': '1.0.0'
|
||||
},
|
||||
'1.0.1': {
|
||||
'bower.json': {
|
||||
name: 'package'
|
||||
},
|
||||
'version.txt': '1.0.1'
|
||||
}
|
||||
}).then(function() {
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test',
|
||||
dependencies: {
|
||||
package: gitPackage.path + '#1.0.0'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return install().then(function() {
|
||||
expect(tempDir.read('bower_components/package/version.txt')).to.contain('1.0.0');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ var bower = helpers.require('lib/index');
|
||||
|
||||
describe('bower uninstall', function () {
|
||||
|
||||
var tempDir = helpers.createTmpDir({
|
||||
var tempDir = new helpers.TempDir({
|
||||
'bower.json': {
|
||||
name: 'hello-world',
|
||||
dependencies: {
|
||||
@@ -16,14 +16,18 @@ describe('bower uninstall', function () {
|
||||
}
|
||||
});
|
||||
|
||||
var bowerJsonPath = path.join(tempDir, 'bower.json');
|
||||
beforeEach(function() {
|
||||
tempDir.prepare();
|
||||
});
|
||||
|
||||
var bowerJsonPath = path.join(tempDir.path, 'bower.json');
|
||||
|
||||
function bowerJson() {
|
||||
return JSON.parse(fs.readFileSync(bowerJsonPath));
|
||||
}
|
||||
|
||||
var config = {
|
||||
cwd: tempDir,
|
||||
cwd: tempDir.path,
|
||||
interactive: true
|
||||
};
|
||||
|
||||
|
||||
239
test/commands/update.js
Normal file
239
test/commands/update.js
Normal file
@@ -0,0 +1,239 @@
|
||||
var expect = require('expect.js');
|
||||
var object = require('mout').object;
|
||||
|
||||
var helpers = require('../helpers');
|
||||
var commands = helpers.require('lib/index').commands;
|
||||
|
||||
describe('bower update', function () {
|
||||
|
||||
var tempDir = new helpers.TempDir();
|
||||
|
||||
var gitPackage = new helpers.TempDir();
|
||||
gitPackage.prepareGit({
|
||||
'1.0.0': {
|
||||
'bower.json': {
|
||||
name: 'package'
|
||||
},
|
||||
'version.txt': '1.0.0'
|
||||
},
|
||||
'1.0.1': {
|
||||
'bower.json': {
|
||||
name: 'package'
|
||||
},
|
||||
'version.txt': '1.0.1'
|
||||
}
|
||||
});
|
||||
|
||||
var package = new helpers.TempDir({
|
||||
'bower.json': {
|
||||
name: 'package'
|
||||
}
|
||||
}).prepare();
|
||||
|
||||
var updateLogger = function(packages, options, config) {
|
||||
config = object.merge(config || {}, {
|
||||
cwd: tempDir.path
|
||||
});
|
||||
|
||||
return commands.update(packages, options, config);
|
||||
};
|
||||
|
||||
var update = function(packages, options, config) {
|
||||
var logger = updateLogger(packages, options, config);
|
||||
|
||||
return helpers.expectEvent(logger, 'end');
|
||||
};
|
||||
|
||||
var install = function(packages, options, config) {
|
||||
config = object.merge(config || {}, {
|
||||
cwd: tempDir.path
|
||||
});
|
||||
|
||||
var logger = commands.install(
|
||||
packages, options, config
|
||||
);
|
||||
|
||||
return helpers.expectEvent(logger, 'end');
|
||||
};
|
||||
|
||||
it('install missing packages', function () {
|
||||
package.prepare();
|
||||
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test',
|
||||
dependencies: {
|
||||
package: package.path
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return update().then(function() {
|
||||
expect(tempDir.exists('bower_components/package/bower.json')).to.equal(true);
|
||||
expect(tempDir.read('bower_components/package/bower.json')).to.contain('"name": "package"');
|
||||
});
|
||||
});
|
||||
|
||||
it('runs preinstall hook when installing missing package', function () {
|
||||
package.prepare();
|
||||
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test',
|
||||
dependencies: {
|
||||
package: package.path
|
||||
}
|
||||
},
|
||||
'.bowerrc': {
|
||||
scripts: {
|
||||
preinstall: 'bash -c "echo -n % > preinstall.txt"'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return update().then(function() {
|
||||
expect(tempDir.read('preinstall.txt')).to.be('package');
|
||||
});
|
||||
});
|
||||
|
||||
it('runs postinstall hook when installing missing package', function () {
|
||||
package.prepare();
|
||||
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test',
|
||||
dependencies: {
|
||||
package: package.path
|
||||
}
|
||||
},
|
||||
'.bowerrc': {
|
||||
scripts: {
|
||||
postinstall: 'bash -c "echo -n % > postinstall.txt"'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return update().then(function() {
|
||||
expect(tempDir.read('postinstall.txt')).to.be('package');
|
||||
});
|
||||
});
|
||||
|
||||
it('doesn\'t runs postinstall when no package is update', function () {
|
||||
package.prepare();
|
||||
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test',
|
||||
dependencies: {
|
||||
package: package.path
|
||||
}
|
||||
},
|
||||
'.bowerrc': {
|
||||
scripts: {
|
||||
postinstall: 'bash -c "echo -n % > postinstall.txt"'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return install().then(function() {
|
||||
tempDir.prepare();
|
||||
|
||||
return update().then(function() {
|
||||
expect(tempDir.exists('postinstall.txt')).to.be(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('updates a package', function () {
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test',
|
||||
dependencies: {
|
||||
package: gitPackage.path + '#1.0.0'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return install().then(function() {
|
||||
|
||||
expect(tempDir.read('bower_components/package/version.txt')).to.contain('1.0.0');
|
||||
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test',
|
||||
dependencies: {
|
||||
package: gitPackage.path + '#1.0.1'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return update().then(function() {
|
||||
expect(tempDir.read('bower_components/package/version.txt')).to.contain('1.0.1');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('runs preinstall hook when updating a package', function () {
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test',
|
||||
dependencies: {
|
||||
package: gitPackage.path + '#1.0.0'
|
||||
}
|
||||
},
|
||||
'.bowerrc': {
|
||||
scripts: {
|
||||
preinstall: 'bash -c "echo -n % > preinstall.txt"'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return install().then(function() {
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test',
|
||||
dependencies: {
|
||||
package: gitPackage.path + '#1.0.1'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
expect(tempDir.exists('preinstall.txt')).to.be(false);
|
||||
return update().then(function() {
|
||||
expect(tempDir.read('preinstall.txt')).to.be('package');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('runs postinstall hook when updating a package', function () {
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test',
|
||||
dependencies: {
|
||||
package: gitPackage.path + '#1.0.0'
|
||||
}
|
||||
},
|
||||
'.bowerrc': {
|
||||
scripts: {
|
||||
postinstall: 'bash -c "echo -n % > postinstall.txt"'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return install().then(function() {
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test',
|
||||
dependencies: {
|
||||
package: gitPackage.path + '#1.0.1'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
expect(tempDir.exists('postinstall.txt')).to.be(false);
|
||||
return update().then(function() {
|
||||
expect(tempDir.read('postinstall.txt')).to.be('package');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,5 @@
|
||||
var expect = require('expect.js');
|
||||
var path = require('path');
|
||||
var mout = require('mout');
|
||||
var rimraf = require('rimraf');
|
||||
var Logger = require('bower-logger');
|
||||
var Manager = require('../../lib/core/Manager');
|
||||
@@ -23,7 +22,7 @@ describe('Manager', function () {
|
||||
beforeEach(function (next) {
|
||||
var logger = new Logger();
|
||||
|
||||
var config = mout.object.deepMixIn({}, defaultConfig, {
|
||||
var config = defaultConfig({
|
||||
storage: {
|
||||
packages: packagesCacheDir,
|
||||
registry: registryCacheDir
|
||||
|
||||
@@ -35,7 +35,7 @@ describe('PackageRepository', function () {
|
||||
var logger = new Logger();
|
||||
|
||||
// Config
|
||||
config = mout.object.deepMixIn({}, defaultConfig, {
|
||||
config = defaultConfig({
|
||||
storage: {
|
||||
packages: packagesCacheDir,
|
||||
registry: registryCacheDir
|
||||
|
||||
@@ -23,7 +23,7 @@ describe('ResolveCache', function () {
|
||||
rimraf.sync(cacheDir);
|
||||
|
||||
// Instantiate resolver cache
|
||||
resolveCache = new ResolveCache(mout.object.deepMixIn(defaultConfig, {
|
||||
resolveCache = new ResolveCache(defaultConfig({
|
||||
storage: {
|
||||
packages: cacheDir
|
||||
}
|
||||
@@ -55,7 +55,7 @@ describe('ResolveCache', function () {
|
||||
});
|
||||
|
||||
function initialize(cacheDir) {
|
||||
return new ResolveCache(mout.object.deepMixIn(defaultConfig, {
|
||||
return new ResolveCache(defaultConfig({
|
||||
storage: {
|
||||
packages: cacheDir
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@ var defaultConfig = require('../../lib/config');
|
||||
describe('resolverFactory', function () {
|
||||
var tempSource;
|
||||
var logger = new Logger();
|
||||
var registryClient = new RegistryClient(mout.object.fillIn({
|
||||
cache: defaultConfig._registry
|
||||
}, defaultConfig));
|
||||
var registryClient = new RegistryClient(defaultConfig({
|
||||
cache: defaultConfig()._registry
|
||||
}));
|
||||
|
||||
afterEach(function (next) {
|
||||
logger.removeAllListeners();
|
||||
@@ -34,7 +34,7 @@ describe('resolverFactory', function () {
|
||||
});
|
||||
|
||||
function callFactory(decEndpoint, config) {
|
||||
return resolverFactory(decEndpoint, config || defaultConfig, logger, registryClient);
|
||||
return resolverFactory(decEndpoint, defaultConfig(config), logger, registryClient);
|
||||
}
|
||||
|
||||
it('should recognize git remote endpoints correctly', function (next) {
|
||||
@@ -584,14 +584,12 @@ describe('resolverFactory', function () {
|
||||
it('should use the configured shorthand resolver', function (next) {
|
||||
callFactory({ source: 'bower/bower' })
|
||||
.then(function (resolver) {
|
||||
var config;
|
||||
var config = {
|
||||
shorthandResolver: 'git://bower.io/{{owner}}/{{package}}/{{shorthand}}'
|
||||
};
|
||||
|
||||
expect(resolver.getSource()).to.equal('git://github.com/bower/bower.git');
|
||||
|
||||
config = mout.object.fillIn({
|
||||
shorthandResolver: 'git://bower.io/{{owner}}/{{package}}/{{shorthand}}'
|
||||
}, defaultConfig);
|
||||
|
||||
return callFactory({ source: 'IndigoUnited/promptly' }, config);
|
||||
})
|
||||
.then(function (resolver) {
|
||||
@@ -616,7 +614,7 @@ describe('resolverFactory', function () {
|
||||
|
||||
|
||||
it('should error out if there\'s no suitable resolver for a given source', function (next) {
|
||||
resolverFactory({ source: 'some-package-that-will-never-exist' }, defaultConfig, logger)
|
||||
resolverFactory({ source: 'some-package-that-will-never-exist' }, defaultConfig(), logger)
|
||||
.then(function () {
|
||||
throw new Error('Should have failed');
|
||||
}, function (err) {
|
||||
|
||||
171
test/core/resolvers/bitBucketResolver.js
Normal file
171
test/core/resolvers/bitBucketResolver.js
Normal file
@@ -0,0 +1,171 @@
|
||||
var path = require('path');
|
||||
var nock = require('nock');
|
||||
var fs = require('graceful-fs');
|
||||
var expect = require('expect.js');
|
||||
var Logger = require('bower-logger');
|
||||
var GitRemoteResolver = require('../../../lib/core/resolvers/GitRemoteResolver');
|
||||
var BitBucketResolver = require('../../../lib/core/resolvers/BitBucketResolver');
|
||||
var defaultConfig = require('../../../lib/config');
|
||||
|
||||
describe('BitBucket', function () {
|
||||
var logger;
|
||||
var testPackage = path.resolve(__dirname, '../../assets/package-a');
|
||||
|
||||
before(function () {
|
||||
logger = new Logger();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
// Clean nocks
|
||||
nock.cleanAll();
|
||||
|
||||
logger.removeAllListeners();
|
||||
});
|
||||
|
||||
function create(decEndpoint) {
|
||||
if (typeof decEndpoint === 'string') {
|
||||
decEndpoint = { source: decEndpoint };
|
||||
}
|
||||
|
||||
return new BitBucketResolver(decEndpoint, defaultConfig({ strictSsl: false }), logger);
|
||||
}
|
||||
|
||||
describe('.constructor', function () {
|
||||
it.skip('should throw an error on invalid BitBucket URLs');
|
||||
|
||||
it('should ensure .git in the source', function () {
|
||||
var resolver;
|
||||
|
||||
resolver = create('git://bitbucket.org/drublic/bower-test');
|
||||
expect(resolver.getSource()).to.equal('git://bitbucket.org/drublic/bower-test.git');
|
||||
|
||||
resolver = create('git://bitbucket.org/drublic/bower-test.git');
|
||||
expect(resolver.getSource()).to.equal('git://bitbucket.org/drublic/bower-test.git');
|
||||
|
||||
resolver = create('git://bitbucket.org/drublic/bower-test.git/');
|
||||
expect(resolver.getSource()).to.equal('git://bitbucket.org/drublic/bower-test.git');
|
||||
});
|
||||
});
|
||||
|
||||
describe('.resolve', function () {
|
||||
|
||||
this.timeout(10000); // Give some time to execute
|
||||
|
||||
it('should download and extract the .tar.gz archive from bitbucket.org', function (next) {
|
||||
var resolver;
|
||||
|
||||
nock('https://bitbucket.org')
|
||||
.get('/drublic/bower-test/get/0.1.0.tar.gz')
|
||||
.replyWithFile(200, path.resolve(__dirname, '../../assets/package-tar.tar.gz'));
|
||||
|
||||
resolver = create({ source: 'https://bitbucket.org/drublic/bower-test.git', target: '0.1.0' });
|
||||
resolver.resolve()
|
||||
.then(function (dir) {
|
||||
expect(fs.existsSync(path.join(dir, 'foo'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(dir, 'bar'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(dir, 'bar'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(dir, '.bower.json'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(dir, 'README.md'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(dir, 'package-tar.tar.gz'))).to.be(false);
|
||||
expect(fs.existsSync(path.join(dir, 'package-tar.tar'))).to.be(false);
|
||||
next();
|
||||
})
|
||||
.done();
|
||||
});
|
||||
|
||||
it('should retry using the GitRemoteResolver mechanism if download failed', function (next) {
|
||||
var resolver;
|
||||
var retried;
|
||||
|
||||
nock('https://bitbucket.org')
|
||||
.get('/drublic/bower-test/get/0.1.0.tar.gz')
|
||||
.reply(200, 'this is not a valid tar');
|
||||
|
||||
logger.on('log', function (entry) {
|
||||
if (entry.level === 'warn' && entry.id === 'retry') {
|
||||
retried = true;
|
||||
}
|
||||
});
|
||||
|
||||
resolver = create({ source: 'git://bitbucket.org/drublic/bower-test.git', target: '0.1.0' });
|
||||
|
||||
// Monkey patch source to file://
|
||||
resolver._source = 'file://' + testPackage;
|
||||
|
||||
resolver.resolve()
|
||||
.then(function (dir) {
|
||||
expect(retried).to.be(true);
|
||||
expect(fs.existsSync(path.join(dir, 'foo'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(dir, 'bar'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(dir, 'baz'))).to.be(true);
|
||||
next();
|
||||
})
|
||||
.done();
|
||||
});
|
||||
|
||||
it('should retry using the GitRemoteResolver mechanism if extraction failed', function (next) {
|
||||
var resolver;
|
||||
var retried;
|
||||
|
||||
nock('https://bitbucket.org')
|
||||
.get('/drublic/bower-test/get/0.1.0.tar.gz')
|
||||
.reply(500);
|
||||
|
||||
logger.on('log', function (entry) {
|
||||
if (entry.level === 'warn' && entry.id === 'retry') {
|
||||
retried = true;
|
||||
}
|
||||
});
|
||||
|
||||
resolver = create({ source: 'git://bitbucket.org/drublic/bower-test.git', target: '0.1.0' });
|
||||
|
||||
// Monkey patch source to file://
|
||||
resolver._source = 'file://' + testPackage;
|
||||
|
||||
resolver.resolve()
|
||||
.then(function (dir) {
|
||||
expect(retried).to.be(true);
|
||||
expect(fs.existsSync(path.join(dir, 'foo'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(dir, 'bar'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(dir, 'baz'))).to.be(true);
|
||||
next();
|
||||
})
|
||||
.done();
|
||||
});
|
||||
|
||||
it('should fallback to the GitRemoteResolver mechanism if resolution is not a tag', function (next) {
|
||||
var resolver = create({ source: 'git://bitbucket.org/drublic/bower-test.git', target: '2af02ac6ddeaac1c2f4bead8d6287ce54269c039' });
|
||||
var originalCheckout = GitRemoteResolver.prototype._checkout;
|
||||
var called;
|
||||
|
||||
GitRemoteResolver.prototype._checkout = function () {
|
||||
called = true;
|
||||
return originalCheckout.apply(this, arguments);
|
||||
};
|
||||
|
||||
// Monkey patch source to file://
|
||||
resolver._source = 'file://' + testPackage;
|
||||
|
||||
resolver.resolve()
|
||||
.then(function (dir) {
|
||||
expect(fs.existsSync(path.join(dir, 'foo'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(dir, 'bar'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(dir, 'baz'))).to.be(true);
|
||||
expect(called).to.be(true);
|
||||
next();
|
||||
})
|
||||
.fin(function () {
|
||||
GitRemoteResolver.prototype._checkout = originalCheckout;
|
||||
})
|
||||
.done();
|
||||
});
|
||||
|
||||
it.skip('it should error out if the status code is not within 200-299');
|
||||
|
||||
it.skip('should report progress if it takes too long to download');
|
||||
});
|
||||
|
||||
describe('._savePkgMeta', function () {
|
||||
it.skip('should guess the homepage if not already set');
|
||||
});
|
||||
});
|
||||
@@ -35,12 +35,12 @@ describe('FsResolver', function () {
|
||||
}
|
||||
});
|
||||
|
||||
function create(decEndpoint, config) {
|
||||
function create(decEndpoint) {
|
||||
if (typeof decEndpoint === 'string') {
|
||||
decEndpoint = { source: decEndpoint };
|
||||
}
|
||||
|
||||
return new FsResolver(decEndpoint, config || defaultConfig, logger);
|
||||
return new FsResolver(decEndpoint, defaultConfig(), logger);
|
||||
}
|
||||
|
||||
describe('.constructor', function () {
|
||||
|
||||
@@ -33,12 +33,12 @@ describe('GitFsResolver', function () {
|
||||
GitFsResolver.clearRuntimeCache();
|
||||
}
|
||||
|
||||
function create(decEndpoint, config) {
|
||||
function create(decEndpoint) {
|
||||
if (typeof decEndpoint === 'string') {
|
||||
decEndpoint = { source: decEndpoint };
|
||||
}
|
||||
|
||||
return new GitFsResolver(decEndpoint, config || defaultConfig, logger);
|
||||
return new GitFsResolver(decEndpoint, defaultConfig(), logger);
|
||||
}
|
||||
|
||||
describe('.constructor', function () {
|
||||
|
||||
@@ -15,27 +15,19 @@ describe('GitHub', function () {
|
||||
logger = new Logger();
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
// Turn off strict ssl because it gives problems with nock
|
||||
defaultConfig.strictSsl = false;
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
// Clean nocks
|
||||
nock.cleanAll();
|
||||
|
||||
logger.removeAllListeners();
|
||||
|
||||
// Enable strict ssl back again
|
||||
defaultConfig.strictSsl = true;
|
||||
});
|
||||
|
||||
function create(decEndpoint, config) {
|
||||
function create(decEndpoint) {
|
||||
if (typeof decEndpoint === 'string') {
|
||||
decEndpoint = { source: decEndpoint };
|
||||
}
|
||||
|
||||
return new GitHubResolver(decEndpoint, config || defaultConfig, logger);
|
||||
return new GitHubResolver(decEndpoint, defaultConfig({ strictSsl: false }), logger);
|
||||
}
|
||||
|
||||
describe('.constructor', function () {
|
||||
|
||||
@@ -21,12 +21,12 @@ describe('GitRemoteResolver', function () {
|
||||
GitRemoteResolver.clearRuntimeCache();
|
||||
}
|
||||
|
||||
function create(decEndpoint, config) {
|
||||
function create(decEndpoint) {
|
||||
if (typeof decEndpoint === 'string') {
|
||||
decEndpoint = { source: decEndpoint };
|
||||
}
|
||||
|
||||
return new GitRemoteResolver(decEndpoint, config || defaultConfig, logger);
|
||||
return new GitRemoteResolver(decEndpoint, defaultConfig(), logger);
|
||||
}
|
||||
|
||||
describe('.constructor', function () {
|
||||
|
||||
@@ -30,12 +30,12 @@ describe('GitResolver', function () {
|
||||
GitResolver.clearRuntimeCache();
|
||||
}
|
||||
|
||||
function create(decEndpoint, config) {
|
||||
function create(decEndpoint) {
|
||||
if (typeof decEndpoint === 'string') {
|
||||
decEndpoint = { source: decEndpoint };
|
||||
}
|
||||
|
||||
return new GitResolver(decEndpoint, config || defaultConfig, logger);
|
||||
return new GitResolver(decEndpoint, defaultConfig(), logger);
|
||||
}
|
||||
|
||||
describe('misc', function () {
|
||||
@@ -334,7 +334,7 @@ describe('GitResolver', function () {
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
resolver = new DummyResolver({ source: 'foo', target: 'master' }, defaultConfig, logger);
|
||||
resolver = new DummyResolver({ source: 'foo', target: 'master' }, defaultConfig(), logger);
|
||||
|
||||
resolver.resolve()
|
||||
.then(function () {
|
||||
|
||||
@@ -17,6 +17,7 @@ describe('Resolver', function () {
|
||||
var testPackage = path.resolve(__dirname, '../../assets/package-a');
|
||||
var logger;
|
||||
var dirMode0777;
|
||||
var config = defaultConfig();
|
||||
|
||||
before(function () {
|
||||
var stat;
|
||||
@@ -33,12 +34,12 @@ describe('Resolver', function () {
|
||||
logger.removeAllListeners();
|
||||
});
|
||||
|
||||
function create(decEndpoint, config) {
|
||||
function create(decEndpoint) {
|
||||
if (typeof decEndpoint === 'string') {
|
||||
decEndpoint = { source: decEndpoint };
|
||||
}
|
||||
|
||||
return new Resolver(decEndpoint, config || defaultConfig, logger);
|
||||
return new Resolver(decEndpoint, config, logger);
|
||||
}
|
||||
|
||||
describe('.getSource', function () {
|
||||
@@ -333,7 +334,7 @@ describe('Resolver', function () {
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
resolver = new DummyResolver({ source: 'foo'}, defaultConfig, logger);
|
||||
resolver = new DummyResolver({ source: 'foo'}, config, logger);
|
||||
|
||||
resolver.resolve()
|
||||
.then(function () {
|
||||
@@ -461,7 +462,7 @@ describe('Resolver', function () {
|
||||
osTempDir = path.resolve(tmp.tmpdir);
|
||||
|
||||
expect(dir.indexOf(osTempDir)).to.be(0);
|
||||
expect(dir.indexOf(defaultConfig.tmp)).to.be(0);
|
||||
expect(dir.indexOf(config.tmp)).to.be(0);
|
||||
|
||||
expect(path.basename(dirname)).to.equal('bower');
|
||||
expect(path.dirname(path.dirname(dirname))).to.equal(osTempDir);
|
||||
@@ -487,13 +488,13 @@ describe('Resolver', function () {
|
||||
it('should remove the folder after execution', function (next) {
|
||||
this.timeout(15000); // Give some time to execute
|
||||
|
||||
rimraf(defaultConfig.tmp, function (err) {
|
||||
rimraf(config.tmp, function (err) {
|
||||
if (err) return next(err);
|
||||
|
||||
cmd('node', ['test/assets/test-temp-dir/test.js'], { cwd: path.resolve(__dirname, '../../..') })
|
||||
.then(function () {
|
||||
expect(fs.existsSync(defaultConfig.tmp)).to.be(true);
|
||||
expect(fs.readdirSync(defaultConfig.tmp)).to.eql([]);
|
||||
expect(fs.existsSync(config.tmp)).to.be(true);
|
||||
expect(fs.readdirSync(config.tmp)).to.eql([]);
|
||||
next();
|
||||
}, function (err) {
|
||||
next(new Error(err.details));
|
||||
@@ -503,15 +504,15 @@ describe('Resolver', function () {
|
||||
});
|
||||
|
||||
it('should remove the folder on an uncaught exception', function (next) {
|
||||
rimraf(defaultConfig.tmp, function (err) {
|
||||
rimraf(config.tmp, function (err) {
|
||||
if (err) return next(err);
|
||||
|
||||
cmd('node', ['test/assets/test-temp-dir/test-exception.js'], { cwd: path.resolve(__dirname, '../../..') })
|
||||
.then(function () {
|
||||
next(new Error('The command should have failed'));
|
||||
}, function () {
|
||||
expect(fs.existsSync(defaultConfig.tmp)).to.be(true);
|
||||
expect(fs.readdirSync(defaultConfig.tmp)).to.eql([]);
|
||||
expect(fs.existsSync(config.tmp)).to.be(true);
|
||||
expect(fs.readdirSync(config.tmp)).to.eql([]);
|
||||
next();
|
||||
})
|
||||
.done();
|
||||
|
||||
@@ -30,12 +30,12 @@ describe('SvnResolver', function () {
|
||||
SvnResolver.clearRuntimeCache();
|
||||
}
|
||||
|
||||
function create(decEndpoint, config) {
|
||||
function create(decEndpoint) {
|
||||
if (typeof decEndpoint === 'string') {
|
||||
decEndpoint = { source: decEndpoint };
|
||||
}
|
||||
|
||||
return new SvnResolver(decEndpoint, config || defaultConfig, logger);
|
||||
return new SvnResolver(decEndpoint, defaultConfig(), logger);
|
||||
}
|
||||
|
||||
describe('misc', function () {
|
||||
@@ -278,7 +278,7 @@ describe('SvnResolver', function () {
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
resolver = new DummyResolver({ source: 'foo', target: '1.0.0' }, defaultConfig, logger);
|
||||
resolver = new DummyResolver({ source: 'foo', target: '1.0.0' }, defaultConfig(), logger);
|
||||
|
||||
resolver.resolve()
|
||||
.then(function () {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
var expect = require('expect.js');
|
||||
var path = require('path');
|
||||
var fs = require('graceful-fs');
|
||||
var path = require('path');
|
||||
var nock = require('nock');
|
||||
var Q = require('q');
|
||||
var rimraf = require('rimraf');
|
||||
@@ -31,12 +30,12 @@ describe('UrlResolver', function () {
|
||||
nock.cleanAll();
|
||||
});
|
||||
|
||||
function create(decEndpoint, config) {
|
||||
function create(decEndpoint) {
|
||||
if (typeof decEndpoint === 'string') {
|
||||
decEndpoint = { source: decEndpoint };
|
||||
}
|
||||
|
||||
return new UrlResolver(decEndpoint, config || defaultConfig, logger);
|
||||
return new UrlResolver(decEndpoint, defaultConfig(), logger);
|
||||
}
|
||||
|
||||
describe('.constructor', function () {
|
||||
|
||||
125
test/helpers.js
125
test/helpers.js
@@ -5,41 +5,142 @@ var rimraf = require('rimraf');
|
||||
var uuid = require('node-uuid');
|
||||
var object = require('mout/object');
|
||||
var fs = require('fs');
|
||||
var glob = require('glob');
|
||||
var os = require('os');
|
||||
var cmd = require('../lib/util/cmd');
|
||||
var config = require('../lib/config');
|
||||
|
||||
// Those are needed for Travis or not configured git environment
|
||||
var env = {
|
||||
'GIT_AUTHOR_DATE': 'Sun Apr 7 22:13:13 2013 +0000',
|
||||
'GIT_AUTHOR_NAME': 'André Cruz',
|
||||
'GIT_AUTHOR_EMAIL': 'amdfcruz@gmail.com',
|
||||
'GIT_COMMITTER_DATE': 'Sun Apr 7 22:13:13 2013 +0000',
|
||||
'GIT_COMMITTER_NAME': 'André Cruz',
|
||||
'GIT_COMMITTER_EMAIL': 'amdfcruz@gmail.com'
|
||||
};
|
||||
|
||||
// Preserve the original environment
|
||||
object.mixIn(env, process.env);
|
||||
|
||||
var tmpLocation = path.join(
|
||||
os.tmpdir ? os.tmpdir() : os.tmpDir(),
|
||||
'bower-tests',
|
||||
uuid.v4().slice(0, 8)
|
||||
);
|
||||
|
||||
exports.require = function (name) {
|
||||
return require(path.join(__dirname, '../', name));
|
||||
};
|
||||
|
||||
exports.createTmpDir = function (files) {
|
||||
var tempDir = path.join(__dirname, 'tmp/' + uuid.v4());
|
||||
// We need to reset cache because tests are reusing temp directories
|
||||
beforeEach(function () {
|
||||
config.reset();
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
mkdirp.sync(tempDir);
|
||||
after(function () {
|
||||
rimraf.sync(tmpLocation);
|
||||
});
|
||||
|
||||
exports.TempDir = (function() {
|
||||
function TempDir (defaults) {
|
||||
this.path = path.join(tmpLocation, uuid.v4());
|
||||
this.defaults = defaults;
|
||||
}
|
||||
|
||||
TempDir.prototype.create = function (files) {
|
||||
var that = this;
|
||||
|
||||
files = object.merge(files || {}, this.defaults);
|
||||
|
||||
if (files) {
|
||||
object.forOwn(files, function (contents, filepath) {
|
||||
if (typeof contents === 'object') {
|
||||
contents = JSON.stringify(contents, null, ' ');
|
||||
contents = JSON.stringify(contents, null, ' ') + '\n';
|
||||
}
|
||||
|
||||
var fullPath = path.join(tempDir, filepath);
|
||||
var fullPath = path.join(that.path, filepath);
|
||||
mkdirp.sync(path.dirname(fullPath));
|
||||
fs.writeFileSync(fullPath, contents);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
rimraf.sync(tempDir);
|
||||
});
|
||||
return this;
|
||||
};
|
||||
|
||||
return tempDir;
|
||||
};
|
||||
TempDir.prototype.prepare = function (files) {
|
||||
rimraf.sync(this.path);
|
||||
mkdirp.sync(this.path);
|
||||
this.create(files);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// TODO: Rewrite to synchronous form
|
||||
TempDir.prototype.prepareGit = function (revisions) {
|
||||
var that = this;
|
||||
|
||||
revisions = object.merge(revisions || {}, this.defaults);
|
||||
|
||||
rimraf.sync(that.path);
|
||||
|
||||
mkdirp.sync(that.path);
|
||||
|
||||
var promise = new Q();
|
||||
|
||||
object.forOwn(revisions, function (files, tag) {
|
||||
promise = promise.then(function () {
|
||||
return that.git('init');
|
||||
}).then(function () {
|
||||
that.glob('./!(.git)').map(function (removePath) {
|
||||
var fullPath = path.join(that.path, removePath);
|
||||
|
||||
rimraf.sync(fullPath);
|
||||
});
|
||||
|
||||
that.create(files);
|
||||
}).then(function () {
|
||||
return that.git('add', '-A');
|
||||
}).then(function () {
|
||||
return that.git('commit', '-m"commit"');
|
||||
}).then(function () {
|
||||
return that.git('tag', tag);
|
||||
});
|
||||
});
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
TempDir.prototype.glob = function (pattern) {
|
||||
return glob.sync(pattern, {
|
||||
cwd: this.path,
|
||||
dot: true
|
||||
});
|
||||
};
|
||||
|
||||
TempDir.prototype.read = function (name) {
|
||||
return fs.readFileSync(path.join(this.path, name), 'utf8');
|
||||
};
|
||||
|
||||
TempDir.prototype.git = function () {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
|
||||
return cmd('git', args, { cwd: this.path, env: env });
|
||||
};
|
||||
|
||||
TempDir.prototype.exists = function (name) {
|
||||
return fs.existsSync(path.join(this.path, name));
|
||||
};
|
||||
|
||||
return TempDir;
|
||||
})();
|
||||
|
||||
exports.expectEvent = function (emitter, eventName) {
|
||||
var deferred = Q.defer();
|
||||
|
||||
emitter.once(eventName, function () {
|
||||
deferred.resolve(arguments);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@ require('./core/resolvers/gitResolver');
|
||||
require('./core/resolvers/gitFsResolver');
|
||||
require('./core/resolvers/gitRemoteResolver');
|
||||
require('./core/resolvers/gitHubResolver');
|
||||
require('./core/resolvers/bitBucketResolver');
|
||||
require('./core/resolvers/svnResolver');
|
||||
require('./core/resolverFactory');
|
||||
require('./core/resolveCache');
|
||||
|
||||
124
test/util/analytics.js
Normal file
124
test/util/analytics.js
Normal file
@@ -0,0 +1,124 @@
|
||||
var expect = require('expect.js');
|
||||
var proxyquire = require('proxyquire');
|
||||
var object = require('mout').object;
|
||||
|
||||
describe('analytics', function () {
|
||||
|
||||
var mockAnalytics = function(stubs, promptResponse) {
|
||||
return proxyquire('../../lib/util/analytics', {
|
||||
insight: function () {
|
||||
return object.merge(stubs || {}, {
|
||||
askPermission: function (message, callback) {
|
||||
callback(undefined, promptResponse);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
describe('#setup', function () {
|
||||
it('leaves analytics enabled if provided', function () {
|
||||
return mockAnalytics()
|
||||
.setup({ analytics: true })
|
||||
.then(function (enabled) {
|
||||
expect(enabled).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('leaves analytics disabled if provided', function () {
|
||||
return mockAnalytics()
|
||||
.setup({ analytics: false })
|
||||
.then(function (enabled) {
|
||||
expect(enabled).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('disables analytics for non-interactive mode', function () {
|
||||
return mockAnalytics()
|
||||
.setup({ interactive: false })
|
||||
.then(function (enabled) {
|
||||
expect(enabled).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('disables if insight.optOut is true and interactive', function () {
|
||||
return mockAnalytics({ optOut: true })
|
||||
.setup({ interactive: true })
|
||||
.then(function (enabled) {
|
||||
expect(enabled).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('enables if insight.optOut is false and interactive', function () {
|
||||
return mockAnalytics({ optOut: false })
|
||||
.setup({ interactive: true })
|
||||
.then(function (enabled) {
|
||||
expect(enabled).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('disables if insight.optOut is false and non-interactive', function () {
|
||||
return mockAnalytics({ optOut: false })
|
||||
.setup({ interactive: false })
|
||||
.then(function (enabled) {
|
||||
expect(enabled).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('enables if interactive insights return true from prompt', function () {
|
||||
return mockAnalytics({ optOut: undefined }, true)
|
||||
.setup({ interactive: true })
|
||||
.then(function (enabled) {
|
||||
expect(enabled).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('disables if interactive insights return false from prompt', function () {
|
||||
return mockAnalytics({ optOut: undefined }, false)
|
||||
.setup({ interactive: true })
|
||||
.then(function (enabled) {
|
||||
expect(enabled).to.be(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Tracker', function (next) {
|
||||
it('tracks if analytics = true', function(next) {
|
||||
var analytics = mockAnalytics({
|
||||
track: function (arg) {
|
||||
expect(arg).to.be('foo');
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
new analytics.Tracker({ analytics: true }).track('foo');
|
||||
});
|
||||
|
||||
it('does not track if analytics = false', function () {
|
||||
var analytics = mockAnalytics({
|
||||
track: function (arg) {
|
||||
throw new Error();
|
||||
}
|
||||
});
|
||||
|
||||
expect(function () {
|
||||
new analytics.Tracker({ analytics: false }).track('foo');
|
||||
}).to.not.throwError();
|
||||
});
|
||||
|
||||
it('tracks if analytics = undefined and setup returns true', function(next) {
|
||||
var analytics = mockAnalytics({
|
||||
track: function (arg) {
|
||||
expect(arg).to.be('foo');
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
analytics
|
||||
.setup({ analytics: true })
|
||||
.then(function () {
|
||||
new analytics.Tracker({}).track('foo');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,3 +1,4 @@
|
||||
describe('util', function () {
|
||||
require('./removeIgnores');
|
||||
require('./analytics');
|
||||
});
|
||||
|
||||
@@ -7,13 +7,15 @@ var removeIgnores = require('../../lib/util/removeIgnores');
|
||||
|
||||
describe('removeIgnores', function () {
|
||||
|
||||
var tempDir = helpers.createTmpDir({
|
||||
var tempDir = new helpers.TempDir({
|
||||
'bower.json': {},
|
||||
'index.js': 'Not to ignore',
|
||||
'node_modules/underscore/index.js': 'Should be ignored'
|
||||
});
|
||||
|
||||
var ignoreTest = function(dir, meta, leftovers) {
|
||||
tempDir.prepare();
|
||||
|
||||
var deferred = Q.defer();
|
||||
|
||||
removeIgnores(dir, meta).then(function() {
|
||||
@@ -27,42 +29,42 @@ describe('removeIgnores', function () {
|
||||
};
|
||||
|
||||
it('removes all files in directory', function () {
|
||||
return ignoreTest(tempDir,
|
||||
return ignoreTest(tempDir.path,
|
||||
{ ignore: [ 'node_modules/**/*' ] },
|
||||
[ 'bower.json', 'index.js' ]
|
||||
);
|
||||
});
|
||||
|
||||
it('removes whole directory', function () {
|
||||
return ignoreTest(tempDir,
|
||||
return ignoreTest(tempDir.path,
|
||||
{ ignore: [ 'node_modules/' ] },
|
||||
[ 'bower.json', 'index.js' ]
|
||||
);
|
||||
});
|
||||
|
||||
it('removes whole directory (no ending slash)', function () {
|
||||
return ignoreTest(tempDir,
|
||||
return ignoreTest(tempDir.path,
|
||||
{ ignore: [ 'node_modules' ] },
|
||||
[ 'bower.json', 'index.js' ]
|
||||
);
|
||||
});
|
||||
|
||||
it('removes all but one file', function() {
|
||||
return ignoreTest(tempDir,
|
||||
return ignoreTest(tempDir.path,
|
||||
{ ignore: [ '**/*', '!bower.json' ] },
|
||||
[ 'bower.json' ]
|
||||
);
|
||||
});
|
||||
|
||||
it('refuses to ignore bower.json', function() {
|
||||
return ignoreTest(tempDir,
|
||||
return ignoreTest(tempDir.path,
|
||||
{ ignore: [ '**/*', '!index.js' ] },
|
||||
[ 'bower.json', 'index.js' ]
|
||||
);
|
||||
});
|
||||
|
||||
it('removes all but one file deep down the tree', function() {
|
||||
return ignoreTest(tempDir,
|
||||
return ignoreTest(tempDir.path,
|
||||
{ ignore: [ '**/*', '!node_modules/underscore/index.js' ] },
|
||||
[
|
||||
'bower.json',
|
||||
|
||||
Reference in New Issue
Block a user