mirror of
https://github.com/bower/bower.git
synced 2026-04-24 03:00:19 -04:00
Compare commits
238 Commits
feature/de
...
v1.4.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47e5834662 | ||
|
|
a1287416d4 | ||
|
|
00dc877f0a | ||
|
|
335081053d | ||
|
|
4af22cfbc0 | ||
|
|
ab4f8a0e39 | ||
|
|
7e110603b5 | ||
|
|
94455192ad | ||
|
|
c4ca24a537 | ||
|
|
ea1f5d1ff0 | ||
|
|
77b7355433 | ||
|
|
e727566741 | ||
|
|
0f68da4eb8 | ||
|
|
1a7abfd3b7 | ||
|
|
905c2775d2 | ||
|
|
126da9ee12 | ||
|
|
1080cb71c4 | ||
|
|
39a295901a | ||
|
|
7e55b0b099 | ||
|
|
b4aa90b402 | ||
|
|
a1ecf8a413 | ||
|
|
4d59d266c1 | ||
|
|
7e0a2ea4cb | ||
|
|
912808b672 | ||
|
|
a352d51711 | ||
|
|
4ad5ed64d7 | ||
|
|
3838a3b4fb | ||
|
|
7d748ae15e | ||
|
|
9dab389b50 | ||
|
|
260b4adb8c | ||
|
|
182d92f9bd | ||
|
|
61a68a9e38 | ||
|
|
b6e33d70c8 | ||
|
|
7a26bf1a10 | ||
|
|
df1a87eb4e | ||
|
|
e203b1aa9a | ||
|
|
f458114c5b | ||
|
|
8db09d2fed | ||
|
|
0ce7053598 | ||
|
|
6a96815c44 | ||
|
|
d7b0db41f4 | ||
|
|
9c9f3e7055 | ||
|
|
2f6d680b6c | ||
|
|
639f7939a3 | ||
|
|
95ce9cbf0c | ||
|
|
1e0ef941c7 | ||
|
|
7e5bd64885 | ||
|
|
de023bc6ea | ||
|
|
c7df6f50ca | ||
|
|
df71d251f0 | ||
|
|
0b9acc18cc | ||
|
|
58a7de3136 | ||
|
|
5bb77b1e03 | ||
|
|
e351322ce4 | ||
|
|
6b53ccc8bd | ||
|
|
33842b6f92 | ||
|
|
5e747b2cfd | ||
|
|
3f8de0efb9 | ||
|
|
63da3e4595 | ||
|
|
a04b69dc6a | ||
|
|
3be4764d54 | ||
|
|
2d4fec01b1 | ||
|
|
85c50eb542 | ||
|
|
ee62d00c96 | ||
|
|
52a32f0887 | ||
|
|
dd30be90ad | ||
|
|
4cb027eb73 | ||
|
|
8e0b8f2faf | ||
|
|
39491b78b1 | ||
|
|
7c82da8389 | ||
|
|
d5c13603a0 | ||
|
|
aad253bfad | ||
|
|
dac055e2ef | ||
|
|
85df5b9983 | ||
|
|
537cd42097 | ||
|
|
9d06fce5f9 | ||
|
|
c029e1005f | ||
|
|
b245a3d611 | ||
|
|
11d89c4268 | ||
|
|
6be84ab93e | ||
|
|
2f2c4d6740 | ||
|
|
06f4d0c117 | ||
|
|
b5e557ffb0 | ||
|
|
8bd6c4a335 | ||
|
|
29eaff9edc | ||
|
|
08afaf7fa5 | ||
|
|
45bab9fe71 | ||
|
|
514eb8f0e3 | ||
|
|
a7baa58c22 | ||
|
|
e548d8b1a5 | ||
|
|
92ff0fe624 | ||
|
|
a464f5a88e | ||
|
|
962a565d30 | ||
|
|
7db50391f2 | ||
|
|
8b0d55a729 | ||
|
|
de6f341f41 | ||
|
|
c9fb530dbf | ||
|
|
836bcd09ec | ||
|
|
52a6836872 | ||
|
|
c00cadb37a | ||
|
|
b26c072f0d | ||
|
|
c99482f59d | ||
|
|
4aa0f567c3 | ||
|
|
4656021902 | ||
|
|
3df6144b77 | ||
|
|
c620004168 | ||
|
|
893ff3e9d7 | ||
|
|
eec9a3cb8f | ||
|
|
d3c8042102 | ||
|
|
e590b44c77 | ||
|
|
e97bf479fb | ||
|
|
fe2f71c9b8 | ||
|
|
ee6c483dd4 | ||
|
|
e83ab86f1f | ||
|
|
ef237fc521 | ||
|
|
fd4d68038b | ||
|
|
8e458c21e9 | ||
|
|
4ab36cb3bc | ||
|
|
2d149f3a09 | ||
|
|
dfd2c7a3d2 | ||
|
|
6637762aec | ||
|
|
615eba3b40 | ||
|
|
dc183125fc | ||
|
|
c3b69d1201 | ||
|
|
3e1a50ab9a | ||
|
|
7565c71eb2 | ||
|
|
d743352bc0 | ||
|
|
75ca72e3a8 | ||
|
|
59d26c6825 | ||
|
|
5eed363e10 | ||
|
|
49b2fdbde9 | ||
|
|
623f6e9542 | ||
|
|
32356f23d3 | ||
|
|
321ddabfd5 | ||
|
|
bf93a6a1ab | ||
|
|
91aa5dc6dd | ||
|
|
56ed46b99a | ||
|
|
daaf21a4fe | ||
|
|
06a8f2afab | ||
|
|
cc04530c4a | ||
|
|
0b6f62977a | ||
|
|
2a2996c22b | ||
|
|
254aba0995 | ||
|
|
23a81b3121 | ||
|
|
c4659f816f | ||
|
|
d1427e7d2e | ||
|
|
5584d1062e | ||
|
|
8cb41fe5fb | ||
|
|
cd893fec15 | ||
|
|
2a01f178da | ||
|
|
a069d1e07d | ||
|
|
76fa7f5200 | ||
|
|
7a0a86d51c | ||
|
|
8e283e43db | ||
|
|
794744d5a3 | ||
|
|
5c3e69b045 | ||
|
|
9cbd595cfd | ||
|
|
a5074eca7d | ||
|
|
9386b117c1 | ||
|
|
7738248230 | ||
|
|
85f1f808d3 | ||
|
|
6dbafa22bb | ||
|
|
cadcd37681 | ||
|
|
a45ea6e1d8 | ||
|
|
187f24de81 | ||
|
|
8df1f48226 | ||
|
|
7dbf332a94 | ||
|
|
c09ddf6de1 | ||
|
|
9b5fa99d6a | ||
|
|
b9abf32007 | ||
|
|
09ecb80625 | ||
|
|
c4e9a0e340 | ||
|
|
b6cf4e1826 | ||
|
|
ecb1619399 | ||
|
|
83f4b7b699 | ||
|
|
9b81ddf4d5 | ||
|
|
4af17f0e40 | ||
|
|
2fbc036e69 | ||
|
|
d236a12b8f | ||
|
|
232be333ad | ||
|
|
192e5af797 | ||
|
|
deb39b8f34 | ||
|
|
197b41d97a | ||
|
|
7b11a57c6f | ||
|
|
eac7945fae | ||
|
|
1177d2263f | ||
|
|
b9478a1f65 | ||
|
|
025cf91679 | ||
|
|
442aa72ccc | ||
|
|
1c09f9c82d | ||
|
|
c6d2f633ea | ||
|
|
17bd60e3e9 | ||
|
|
1d24e82276 | ||
|
|
e42d3d5620 | ||
|
|
5c83972401 | ||
|
|
b8df18481f | ||
|
|
1690dd4728 | ||
|
|
a86087ed7c | ||
|
|
745060f0b5 | ||
|
|
0a0a490a38 | ||
|
|
f816a5b0da | ||
|
|
2f02e49716 | ||
|
|
a98a0b1ac2 | ||
|
|
034326c984 | ||
|
|
a965b05400 | ||
|
|
6c2de4a359 | ||
|
|
e9588279c8 | ||
|
|
efe3a78499 | ||
|
|
31969a4939 | ||
|
|
7a00c5ac71 | ||
|
|
23fbbb5191 | ||
|
|
a58b1ccfa5 | ||
|
|
37b0a5c04c | ||
|
|
3fb4f60192 | ||
|
|
635fa84731 | ||
|
|
410bf4f0cd | ||
|
|
eebe115b78 | ||
|
|
70eb9f0678 | ||
|
|
b9de179fe8 | ||
|
|
ac29e24c1b | ||
|
|
d83572803d | ||
|
|
87faa4f108 | ||
|
|
ea3a0d64c1 | ||
|
|
8288d2f38b | ||
|
|
ff817dad0d | ||
|
|
ba554d5f45 | ||
|
|
90922a0ce0 | ||
|
|
a91cb546f9 | ||
|
|
3cb21d128f | ||
|
|
1b8d5d0648 | ||
|
|
03f035cdf0 | ||
|
|
ac95654409 | ||
|
|
ba33bb6aa4 | ||
|
|
2898c0507e | ||
|
|
d59edd6cca | ||
|
|
74d568b1e7 | ||
|
|
0316fedd4c | ||
|
|
e8c071304c |
@@ -13,3 +13,7 @@ trim_trailing_whitespace = false
|
||||
|
||||
[**.std]
|
||||
insert_final_newline = false
|
||||
|
||||
[{package,bower}.json]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,11 +1,10 @@
|
||||
/node_modules
|
||||
/npm-debug.log
|
||||
|
||||
/test/assets/temp
|
||||
/test/assets/temp2
|
||||
/test/assets/temp-resolve-cache
|
||||
/test/assets/package-*/
|
||||
/test/assets/temp-*/
|
||||
/test/reports
|
||||
/test/tmp/
|
||||
|
||||
/bower.json
|
||||
/component.json
|
||||
|
||||
30
.travis.yml
30
.travis.yml
@@ -1,9 +1,25 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.10"
|
||||
- "0.11"
|
||||
env:
|
||||
- NODE_VERSION=0.10
|
||||
- NODE_VERSION=0.11
|
||||
|
||||
install:
|
||||
- test $TRAVIS_OS_NAME = "osx" && brew install nvm && source $(brew --prefix nvm)/nvm.sh || test $TRAVIS_OS_NAME = "linux"
|
||||
- nvm install $NODE_VERSION
|
||||
- node --version
|
||||
- npm --version
|
||||
- git --version
|
||||
- svn --version | head -n 1
|
||||
- npm install -g grunt-cli
|
||||
- npm install
|
||||
|
||||
os:
|
||||
- osx
|
||||
- linux
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- node_js: "0.11"
|
||||
before_script:
|
||||
- npm install grunt-cli -g
|
||||
- os: osx
|
||||
- env: "NODE_VERSION=0.11"
|
||||
|
||||
script:
|
||||
- grunt travis
|
||||
|
||||
99
CHANGELOG.md
99
CHANGELOG.md
@@ -1,13 +1,112 @@
|
||||
# Changelog
|
||||
|
||||
## 1.5.4 - 2015-11-24
|
||||
|
||||
- [fix] Lock lru-cache dependency to 2.7.0
|
||||
|
||||
## 1.4.1 - 2015-04-01
|
||||
|
||||
- [fix] Reading .bowerrc upwards directory tree ([#1763](https://github.com/bower/bower/issues/1763))
|
||||
- [fix] Update bower-registry-client so it uses the same bower-config as bower
|
||||
|
||||
## 1.4.0 - 2015-03-30
|
||||
|
||||
- Add login and unregister commands ([#1719](https://github.com/bower/bower/issues/1719))
|
||||
- Automatically detecting smart Git hosts ([#1628](https://github.com/bower/bower/issues/1628))
|
||||
- [bower/config#23] Allow npm config variables ([#1711](https://github.com/bower/bower/issues/1711))
|
||||
- [bower/config#24] Merge .bowerrc files upwards directory tree ([#1689](https://github.com/bower/bower/issues/1689))
|
||||
- Better homedir detection (514eb8f)
|
||||
- Add --save-exact flag ([#1654](https://github.com/bower/bower/issues/1654))
|
||||
- Ensure extracted files are readable (tar-fs) ([#1548](https://github.com/bower/bower/issues/1548))
|
||||
- The version command in the programmatic API now returns the new version ([#1755](https://github.com/bower/bower/issues/1755))
|
||||
- Some minor fixes: #1639, #1620, #1576, #1557, 962a565, a464f5a
|
||||
- Improved Windows support (AppVeyor CI, tests actually passing on Windows)
|
||||
- OSX testing enabled on TravisCI
|
||||
|
||||
It also includes improved test coverage (~60% -> ~85%) and many refactors.
|
||||
|
||||
## 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))
|
||||
|
||||
## 1.3.4 - 2014-06-02
|
||||
|
||||
- Resolve a situation in which the install process gets into an infinite loop ([#1169](https://github.com/bower/bower/issues/1169))
|
||||
- Improved CLI output for conflicts ([#1284](https://github.com/bower/bower/issues/1284))
|
||||
- Changed `bower version` to mirror the tag format of `npm version` ([#1278](https://github.com/bower/bower/issues/1278))
|
||||
- Allow short commit SHAs to be used ([#990](https://github.com/bower/bower/issues/990))
|
||||
|
||||
## 1.3.3 - 2014-04-24
|
||||
|
||||
- Do not cache moving targets like branches ([#1242](https://github.com/bower/bower/issues/1242))
|
||||
- Suppress output if --quiet option is specified ([#1124](https://github.com/bower/bower/pull/1124))
|
||||
- Use "svn export" for efficiency ([#1224](https://github.com/bower/bower/pull/1224))
|
||||
- Prevent loading insights and analytics on CI ([#1221](https://github.com/bower/bower/issues/1221))
|
||||
- Make "bower list" respect custom components directory ([#1237](https://github.com/bower/bower/issues/1237))
|
||||
- Improve non-interactive loading performance 2x ([#1238](https://github.com/bower/bower/issues/1238))
|
||||
- Load commands only on demand, improving performance ([#1232](https://github.com/bower/bower/pull/1232))
|
||||
|
||||
## 1.3.2 - 2014-04-05
|
||||
|
||||
- Added yui moduleType [PR #1129](https://github.com/bower/bower/pull/1129)
|
||||
- Fixes for concurrency issues [PR #1211](https://github.com/bower/bower/pull/1211)
|
||||
- `link` now installs package dependencies [PR #891](https://github.com/bower/bower/pull/891)
|
||||
- Improved conflict installation message [Commit](https://github.com/bower/bower/commit/bea533acf87903d4b411bfbaa7df93f852ef46a3)
|
||||
- Add --production switch to "prune" command [PR #1168](https://github.com/bower/bower/pull/1168)
|
||||
|
||||
|
||||
## 1.3.1 - 2014-03-10
|
||||
|
||||
- No longer ask for permission to gather analytics when running on in a CI environment.
|
||||
|
||||
|
||||
|
||||
@@ -33,8 +33,6 @@ changes, and helping you finalize your pull requests.
|
||||
|
||||
## Using the issue tracker
|
||||
|
||||
*
|
||||
|
||||
The issue tracker is the preferred channel for [bug reports](#bugs),
|
||||
[features requests](#features) and [submitting pull
|
||||
requests](#pull-requests), but please respect the following restrictions:
|
||||
|
||||
25
Gruntfile.js
25
Gruntfile.js
@@ -1,5 +1,5 @@
|
||||
'use strict';
|
||||
module.exports = function (grunt) {
|
||||
|
||||
require('load-grunt-tasks')(grunt);
|
||||
|
||||
grunt.initConfig({
|
||||
@@ -7,14 +7,24 @@ module.exports = function (grunt) {
|
||||
options: {
|
||||
jshintrc: '.jshintrc'
|
||||
},
|
||||
files: ['Gruntfile.js', 'bin/*', 'lib/**/*.js', 'test/**/*.js', '!test/assets/**/*', '!test/reports/**/*']
|
||||
files: [
|
||||
'Gruntfile.js',
|
||||
'bin/*',
|
||||
'lib/**/*.js',
|
||||
'test/**/*.js',
|
||||
'!test/assets/**/*',
|
||||
'!test/reports/**/*',
|
||||
'!test/tmp/**/*'
|
||||
]
|
||||
},
|
||||
simplemocha: {
|
||||
options: {
|
||||
reporter: 'spec',
|
||||
timeout: '5000'
|
||||
timeout: '15000'
|
||||
},
|
||||
full: {
|
||||
src: ['test/test.js']
|
||||
},
|
||||
full: { src: ['test/test.js'] },
|
||||
short: {
|
||||
options: {
|
||||
reporter: 'dot'
|
||||
@@ -30,7 +40,10 @@ module.exports = function (grunt) {
|
||||
command: 'node test/packages.js --force && node test/packages-svn.js --force'
|
||||
},
|
||||
cover: {
|
||||
command: 'node node_modules/istanbul/lib/cli.js cover --dir ./test/reports node_modules/mocha/bin/_mocha -- -R dot test/test.js'
|
||||
command: 'STRICT_REQUIRE=1 node node_modules/istanbul/lib/cli.js cover --dir ./test/reports node_modules/mocha/bin/_mocha -- --timeout 30000 -R dot test/test.js'
|
||||
},
|
||||
coveralls: {
|
||||
command: 'node node_modules/.bin/coveralls < test/reports/lcov.info'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -39,9 +52,9 @@ module.exports = function (grunt) {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
grunt.registerTask('assets', ['exec:assets-force']);
|
||||
grunt.registerTask('test', ['jshint', 'exec:assets', 'simplemocha:full']);
|
||||
grunt.registerTask('cover', 'exec:cover');
|
||||
grunt.registerTask('travis', ['jshint', 'exec:assets', 'exec:cover', 'exec:coveralls']);
|
||||
grunt.registerTask('default', 'test');
|
||||
};
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2014 Twitter and other contributors
|
||||
Copyright (c) 2015 Twitter and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
||||
366
README.md
366
README.md
@@ -1,149 +1,70 @@
|
||||
# Bower
|
||||
|
||||
[](http://travis-ci.org/bower/bower)
|
||||
[](https://travis-ci.org/bower/bower) [](https://ci.appveyor.com/project/sheerun/bower/history) [](https://coveralls.io/r/bower/bower?branch=master)
|
||||
|
||||
<img align="right" height="300" src="http://bower.io/img/bower-logo.png">
|
||||
|
||||
Bower is 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.
|
||||
> A package manager for the web
|
||||
|
||||
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.).
|
||||
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 complete docs on [bower.io](http://bower.io)**
|
||||
|
||||
[View all packages available through Bower's registry](http://bower.io/search/).
|
||||
|
||||
## Install
|
||||
|
||||
## Installing Bower
|
||||
|
||||
Bower depends on [Node](http://nodejs.org/) and [npm](http://npmjs.org/). It's
|
||||
installed globally using npm:
|
||||
|
||||
```
|
||||
npm install -g bower
|
||||
```sh
|
||||
$ npm install -g bower
|
||||
```
|
||||
|
||||
Also make sure that [git](http://git-scm.com/) is installed as some bower
|
||||
Bower depends on [Node.js](http://nodejs.org/) and [npm](http://npmjs.org/). Also make sure that [git](http://git-scm.com/) is installed as some bower
|
||||
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:
|
||||
```sh
|
||||
# install dependencies listed in bower.json
|
||||
$ bower install
|
||||
|
||||
#####Using the dependencies listed in the current directory's bower.json
|
||||
# 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
|
||||
```
|
||||
bower install
|
||||
```
|
||||
##### Using a local or remote package
|
||||
```
|
||||
bower install <package>
|
||||
```
|
||||
##### Using a specific version of a package
|
||||
```
|
||||
bower install <package>#<version>
|
||||
```
|
||||
##### Using a different name and a specific version of a package
|
||||
```
|
||||
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": "public/bower_components"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Finding packages
|
||||
|
||||
To search for packages registered with Bower:
|
||||
|
||||
```
|
||||
bower search [<name>]
|
||||
```
|
||||
|
||||
Using just `bower search` will list all packages in the registry.
|
||||
|
||||
### Using packages
|
||||
|
||||
The easiest approach is to use Bower statically, just reference the package's
|
||||
installed components manually using a `script` tag:
|
||||
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).
|
||||
|
||||
```html
|
||||
<script src="/bower_components/jquery/jquery.js"></script>
|
||||
```
|
||||
|
||||
For more complex projects, you'll probably want to concatenate your scripts or
|
||||
use a module loader. Bower is just a package manager, but there are plenty of
|
||||
other tools -- such as [Sprockets](https://github.com/sstephenson/sprockets)
|
||||
and [RequireJS](http://requirejs.org/) -- that will help you do this.
|
||||
The best approach is to process components installed by bower with build tool (like [Grunt](http://gruntjs.com/) or [gulp](http://gulpjs.com/)), and serve them concatenated or using module loader (like [RequireJS](http://requirejs.org/)).
|
||||
|
||||
### Uninstalling packages
|
||||
|
||||
To uninstall a locally installed package:
|
||||
|
||||
```
|
||||
bower uninstall <package-name>
|
||||
```sh
|
||||
$ 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
|
||||
@@ -156,211 +77,36 @@ 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.
|
||||
```
|
||||
bower install <package-name> --offline
|
||||
```
|
||||
The content of the cache can be listed with:
|
||||
```
|
||||
bower cache list
|
||||
```
|
||||
The cache can be cleaned with:
|
||||
```
|
||||
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 manually set `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:
|
||||
|
||||
```
|
||||
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:
|
||||
|
||||
```
|
||||
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).
|
||||
|
||||
|
||||
## 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)
|
||||
|
||||
_NOTE_: Completion is still not implemented for the 1.0.0 release
|
||||
|
||||
Bower now has an experimental `completion` command that is based on, and works
|
||||
similarly to the [npm completion](https://npmjs.org/doc/completion.html). It is
|
||||
similarly to the [npm completion](https://npmjs.org/doc/cli/completion.html). It is
|
||||
not available for Windows users.
|
||||
|
||||
This command will output a Bash / ZSH script to put into your `~/.bashrc`,
|
||||
`~/.bash_profile`, or `~/.zshrc` file.
|
||||
|
||||
```
|
||||
bower completion >> ~/.bash_profile
|
||||
```sh
|
||||
$ bower completion >> ~/.bash_profile
|
||||
```
|
||||
|
||||
|
||||
## Contact
|
||||
|
||||
Have a question?
|
||||
## Support
|
||||
|
||||
* [StackOverflow](http://stackoverflow.com/questions/tagged/bower)
|
||||
* [Mailinglist](http://groups.google.com/group/twitter-bower) - twitter-bower@googlegroups.com
|
||||
* [\#bower](http://webchat.freenode.net/?channels=bower) on Freenode
|
||||
|
||||
|
||||
## Contributing to this project
|
||||
## Contributing
|
||||
|
||||
Anyone and everyone is welcome to contribute. Please take a moment to
|
||||
We welcome contributions of all kinds from anyone. Please take a moment to
|
||||
review the [guidelines for contributing](CONTRIBUTING.md).
|
||||
|
||||
* [Bug reports](CONTRIBUTING.md#bugs)
|
||||
@@ -368,48 +114,24 @@ review the [guidelines for contributing](CONTRIBUTING.md).
|
||||
* [Pull requests](CONTRIBUTING.md#pull-requests)
|
||||
|
||||
|
||||
Note that on Windows for tests to pass you need to configure Git before cloning:
|
||||
|
||||
```
|
||||
git config --global core.autocrlf input
|
||||
```
|
||||
|
||||
## 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)
|
||||
* [@wibblymat](https://github.com/wibblymat)
|
||||
* [@paulirish](https://github.com/paulirish)
|
||||
* [@benschwarz](https://github.com/benschwarz)
|
||||
* [@sindresorhus](https://github.com/sindresorhus)
|
||||
* [@svnlto](https://github.com/svnlto)
|
||||
|
||||
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)
|
||||
* [@sheerun](https://github.com/sheerun)
|
||||
|
||||
### Bower Alumni
|
||||
|
||||
@@ -419,6 +141,6 @@ Thanks for assistance and contributions:
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) 2014 Twitter and other contributors
|
||||
Copyright (c) 2015 Twitter and other contributors
|
||||
|
||||
Licensed under the MIT License
|
||||
|
||||
40
appveyor.yml
Normal file
40
appveyor.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
# Thanks for Grunt for template of this file!
|
||||
|
||||
# http://www.appveyor.com/docs/appveyor-yml
|
||||
|
||||
# Fix line endings in Windows. (runs before repo cloning)
|
||||
init:
|
||||
- git config --global core.autocrlf input
|
||||
|
||||
# Test against these versions of Node.js.
|
||||
environment:
|
||||
matrix:
|
||||
- nodejs_version: "0.10"
|
||||
# - nodejs_version: "0.11"
|
||||
|
||||
# Allow failing jobs for bleeding-edge Node.js versions.
|
||||
matrix:
|
||||
allow_failures:
|
||||
- nodejs_version: "0.11"
|
||||
|
||||
# Install scripts. (runs after repo cloning)
|
||||
install:
|
||||
# Get the latest stable version of Node 0.STABLE.latest
|
||||
- ps: Install-Product node $env:nodejs_version
|
||||
# Install subversion
|
||||
- choco install svn -y
|
||||
# Install bower
|
||||
- npm install
|
||||
|
||||
# Post-install test scripts.
|
||||
test_script:
|
||||
# Output useful info for debugging.
|
||||
- node --version
|
||||
- npm --version
|
||||
- cmd: npm test
|
||||
|
||||
# Don't actually build.
|
||||
build: off
|
||||
|
||||
# Set build version format here instead of in the admin panel.
|
||||
version: "{build}"
|
||||
31
bin/bower
31
bin/bower
@@ -1,28 +1,24 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
process.bin = process.title = 'bower';
|
||||
|
||||
var Q = require('q');
|
||||
var path = require('path');
|
||||
var mout = require('mout');
|
||||
var updateNotifier = require('update-notifier');
|
||||
var Logger = require('bower-logger');
|
||||
var osenv = require('osenv');
|
||||
var userHome = require('user-home');
|
||||
var bower = require('../lib');
|
||||
var pkg = require(path.join(__dirname, '..', 'package.json'));
|
||||
var pkg = require('../package.json');
|
||||
var cli = require('../lib/util/cli');
|
||||
var rootCheck = require('../lib/util/rootCheck');
|
||||
var analytics = require('../lib/util/analytics');
|
||||
|
||||
// --------
|
||||
|
||||
var options;
|
||||
var renderer;
|
||||
var loglevel;
|
||||
var command;
|
||||
var commandFunc;
|
||||
var logger;
|
||||
var notifier;
|
||||
var levels = Logger.LEVELS;
|
||||
|
||||
options = cli.readOptions({
|
||||
@@ -73,7 +69,7 @@ while (options.argv.remain.length) {
|
||||
}
|
||||
|
||||
// Ask for Insights on first run.
|
||||
analytics.setup().then(function () {
|
||||
analytics.setup(bower.config).then(function () {
|
||||
// Execute the command
|
||||
commandFunc = command && mout.object.get(bower.commands, command);
|
||||
command = command && command.replace(/\./g, ' ');
|
||||
@@ -129,17 +125,18 @@ analytics.setup().then(function () {
|
||||
});
|
||||
|
||||
// Warn if HOME is not SET
|
||||
if (!osenv.home()) {
|
||||
logger.warn('no-home', 'HOME not set, user configuration will not be loaded');
|
||||
if (!userHome) {
|
||||
logger.warn('no-home', 'HOME environment variable not set. User config will not be loaded.');
|
||||
}
|
||||
|
||||
// Check for newer version of Bower
|
||||
notifier = updateNotifier({
|
||||
packageName: pkg.name,
|
||||
packageVersion: pkg.version
|
||||
});
|
||||
if (bower.config.interactive) {
|
||||
var updateNotifier = require('update-notifier');
|
||||
|
||||
if (notifier.update && levels.info >= loglevel) {
|
||||
renderer.updateNotice(notifier.update);
|
||||
// Check for newer version of Bower
|
||||
var notifier = updateNotifier({pkg: pkg});
|
||||
|
||||
if (notifier.update && levels.info >= loglevel) {
|
||||
notifier.notify();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
52
lib/commands/cache/clean.js
vendored
52
lib/commands/cache/clean.js
vendored
@@ -3,20 +3,17 @@ var path = require('path');
|
||||
var mout = require('mout');
|
||||
var Q = require('q');
|
||||
var rimraf = require('rimraf');
|
||||
var Logger = require('bower-logger');
|
||||
var endpointParser = require('bower-endpoint-parser');
|
||||
var PackageRepository = require('../../core/PackageRepository');
|
||||
var semver = require('../../util/semver');
|
||||
var cli = require('../../util/cli');
|
||||
var defaultConfig = require('../../config');
|
||||
|
||||
function clean(endpoints, options, config) {
|
||||
var logger = new Logger();
|
||||
function clean(logger, endpoints, options, config) {
|
||||
var decEndpoints;
|
||||
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) {
|
||||
@@ -33,21 +30,13 @@ function clean(endpoints, options, config) {
|
||||
});
|
||||
}
|
||||
|
||||
Q.all([
|
||||
return Q.all([
|
||||
clearPackages(decEndpoints, config, logger),
|
||||
clearLinks(names, config, logger),
|
||||
!names ? clearCompletion(config, logger) : null
|
||||
clearLinks(names, config, logger)
|
||||
])
|
||||
.spread(function (entries) {
|
||||
return entries;
|
||||
})
|
||||
.done(function (entries) {
|
||||
logger.emit('end', entries);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
function clearPackages(decEndpoints, config, logger) {
|
||||
@@ -181,37 +170,16 @@ function clearLinks(names, config, logger) {
|
||||
});
|
||||
}
|
||||
|
||||
function clearCompletion(config, logger) {
|
||||
var dir = config.storage.completion;
|
||||
|
||||
return Q.nfcall(fs.stat, dir)
|
||||
.then(function () {
|
||||
return Q.nfcall(rimraf, dir)
|
||||
.then(function () {
|
||||
logger.info('deleted', 'Completion cache', {
|
||||
file: dir
|
||||
});
|
||||
});
|
||||
}, function (error) {
|
||||
if (error.code !== 'ENOENT') {
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
clean.line = function (argv) {
|
||||
var options = clean.options(argv);
|
||||
return clean(options.argv.remain.slice(2), options);
|
||||
};
|
||||
clean.readOptions = function (argv) {
|
||||
var cli = require('../../util/cli');
|
||||
var options = cli.readOptions(argv);
|
||||
var endpoints = options.argv.remain.slice(2);
|
||||
|
||||
clean.options = function (argv) {
|
||||
return cli.readOptions(argv);
|
||||
};
|
||||
delete options.argv;
|
||||
|
||||
clean.completion = function () {
|
||||
// TODO:
|
||||
return [endpoints, options];
|
||||
};
|
||||
|
||||
module.exports = clean;
|
||||
|
||||
4
lib/commands/cache/index.js
vendored
4
lib/commands/cache/index.js
vendored
@@ -1,4 +0,0 @@
|
||||
module.exports = {
|
||||
clean: require('./clean'),
|
||||
list: require('./list')
|
||||
};
|
||||
31
lib/commands/cache/list.js
vendored
31
lib/commands/cache/list.js
vendored
@@ -1,14 +1,11 @@
|
||||
var mout = require('mout');
|
||||
var Logger = require('bower-logger');
|
||||
var PackageRepository = require('../../core/PackageRepository');
|
||||
var cli = require('../../util/cli');
|
||||
var defaultConfig = require('../../config');
|
||||
|
||||
function list(packages, options, config) {
|
||||
function list(logger, packages, options, config) {
|
||||
var repository;
|
||||
var logger = new Logger();
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
repository = new PackageRepository(config, logger);
|
||||
|
||||
// If packages is an empty array, null them
|
||||
@@ -16,7 +13,7 @@ function list(packages, options, config) {
|
||||
packages = null;
|
||||
}
|
||||
|
||||
repository.list()
|
||||
return repository.list()
|
||||
.then(function (entries) {
|
||||
if (packages) {
|
||||
// Filter entries according to the specified packages
|
||||
@@ -28,29 +25,19 @@ function list(packages, options, config) {
|
||||
}
|
||||
|
||||
return entries;
|
||||
})
|
||||
.done(function (entries) {
|
||||
logger.emit('end', entries);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
list.line = function (argv) {
|
||||
var options = list.options(argv);
|
||||
return list(options.argv.remain.slice(2), options);
|
||||
};
|
||||
list.readOptions = function (argv) {
|
||||
var cli = require('../../util/cli');
|
||||
var options = cli.readOptions(argv);
|
||||
var packages = options.argv.remain.slice(2);
|
||||
|
||||
list.options = function (argv) {
|
||||
return cli.readOptions(argv);
|
||||
};
|
||||
delete options.argv;
|
||||
|
||||
list.completion = function () {
|
||||
// TODO:
|
||||
return [packages, options];
|
||||
};
|
||||
|
||||
module.exports = list;
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
var Logger = require('bower-logger');
|
||||
var cli = require('../util/cli');
|
||||
|
||||
function completion(config) {
|
||||
var logger = new Logger();
|
||||
|
||||
process.nextTick(function () {
|
||||
logger.emit('end');
|
||||
});
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
completion.line = function (argv) {
|
||||
var options = completion.options(argv);
|
||||
var name = options.argv.remain[1];
|
||||
|
||||
return completion(name);
|
||||
};
|
||||
|
||||
completion.options = function (argv) {
|
||||
return cli.readOptions(argv);
|
||||
};
|
||||
|
||||
completion.completion = function () {
|
||||
// TODO:
|
||||
};
|
||||
|
||||
module.exports = completion;
|
||||
@@ -1,12 +1,10 @@
|
||||
var Q = require('q');
|
||||
var path = require('path');
|
||||
var fs = require('graceful-fs');
|
||||
var Logger = require('bower-logger');
|
||||
var cli = require('../util/cli');
|
||||
var createError = require('../util/createError');
|
||||
|
||||
function help(name) {
|
||||
function help(logger, name, config) {
|
||||
var json;
|
||||
var logger = new Logger();
|
||||
|
||||
if (name) {
|
||||
json = path.resolve(__dirname, '../../templates/json/help-' + name.replace(/\s+/g, '/') + '.json');
|
||||
@@ -14,39 +12,28 @@ function help(name) {
|
||||
json = path.resolve(__dirname, '../../templates/json/help.json');
|
||||
}
|
||||
|
||||
fs.exists(json, function (exists) {
|
||||
return Q.promise(function (resolve) {
|
||||
fs.exists(json, resolve);
|
||||
})
|
||||
.then(function (exists) {
|
||||
if (!exists) {
|
||||
return logger.emit('error', createError('Unknown command: ' + name, 'EUNKOWNCMD', {
|
||||
throw createError('Unknown command: ' + name, 'EUNKNOWNCMD', {
|
||||
command: name
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
json = require(json);
|
||||
} catch (error) {
|
||||
return logger.emit('error', error);
|
||||
}
|
||||
|
||||
logger.emit('end', json);
|
||||
return require(json);
|
||||
});
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
help.line = function (argv) {
|
||||
var options = help.options(argv);
|
||||
help.readOptions = function (argv) {
|
||||
var cli = require('../util/cli');
|
||||
var options = cli.readOptions(argv);
|
||||
var name = options.argv.remain.slice(1).join(' ');
|
||||
|
||||
return help(options.argv.remain.slice(1).join(' '));
|
||||
};
|
||||
|
||||
help.options = function (argv) {
|
||||
return cli.readOptions(argv);
|
||||
};
|
||||
|
||||
help.completion = function () {
|
||||
// TODO
|
||||
return [name];
|
||||
};
|
||||
|
||||
module.exports = help;
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
var mout = require('mout');
|
||||
var Logger = require('bower-logger');
|
||||
var Project = require('../core/Project');
|
||||
var open = require('open');
|
||||
var open = require('opn');
|
||||
var endpointParser = require('bower-endpoint-parser');
|
||||
var cli = require('../util/cli');
|
||||
var createError = require('../util/createError');
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function home(name, config) {
|
||||
function home(logger, name, config) {
|
||||
var project;
|
||||
var promise;
|
||||
var decEndpoint;
|
||||
var logger = new Logger();
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
project = new Project(config, logger);
|
||||
|
||||
// Get the package meta
|
||||
@@ -37,7 +33,7 @@ function home(name, config) {
|
||||
}
|
||||
|
||||
// Get homepage and open it
|
||||
promise.then(function (pkgMeta) {
|
||||
return promise.then(function (pkgMeta) {
|
||||
var homepage = pkgMeta.homepage;
|
||||
|
||||
if (!homepage) {
|
||||
@@ -46,31 +42,17 @@ function home(name, config) {
|
||||
|
||||
open(homepage);
|
||||
return homepage;
|
||||
})
|
||||
.done(function (homepage) {
|
||||
logger.emit('end', homepage);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
home.line = function (argv) {
|
||||
var options = home.options(argv);
|
||||
home.readOptions = function (argv) {
|
||||
var cli = require('../util/cli');
|
||||
var options = cli.readOptions(argv);
|
||||
var name = options.argv.remain[1];
|
||||
|
||||
return home(name);
|
||||
};
|
||||
|
||||
home.options = function (argv) {
|
||||
return cli.readOptions(argv);
|
||||
};
|
||||
|
||||
home.completion = function () {
|
||||
// TODO:
|
||||
return [name];
|
||||
};
|
||||
|
||||
module.exports = home;
|
||||
|
||||
@@ -8,19 +8,39 @@ var Logger = require('bower-logger');
|
||||
* a command function. The difference is that `cmd = commandFactory()` and `cmd()`
|
||||
* return as soon as possible and load and execute the command asynchronously.
|
||||
*/
|
||||
function lazyRequire(id) {
|
||||
function command() {
|
||||
var logger = new Logger();
|
||||
var commandArgs = arguments;
|
||||
function commandFactory(id) {
|
||||
if (process.env.STRICT_REQUIRE) {
|
||||
require(id);
|
||||
}
|
||||
|
||||
Q.try(function () {
|
||||
// call require asynchronously
|
||||
function command() {
|
||||
var commandArgs = [].slice.call(arguments);
|
||||
|
||||
return withLogger(function (logger) {
|
||||
commandArgs.unshift(logger);
|
||||
return require(id).apply(undefined, commandArgs);
|
||||
})
|
||||
.done(function (commandLogger) {
|
||||
// forward to exposed logger
|
||||
commandLogger.on('end', logger.emit.bind(logger, 'end'));
|
||||
commandLogger.on('error', logger.emit.bind(logger, 'error'));
|
||||
});
|
||||
}
|
||||
|
||||
function runFromArgv(argv) {
|
||||
return withLogger(function (logger) {
|
||||
var command = require(id);
|
||||
|
||||
var commandArgs = command.readOptions(argv);
|
||||
commandArgs.unshift(logger);
|
||||
|
||||
return command.apply(undefined, commandArgs);
|
||||
});
|
||||
}
|
||||
|
||||
function withLogger(func) {
|
||||
var logger = new Logger();
|
||||
|
||||
Q.try(func, logger)
|
||||
.done(function () {
|
||||
var args = [].slice.call(arguments);
|
||||
args.unshift('end');
|
||||
logger.emit.apply(logger, args);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
@@ -28,30 +48,31 @@ function lazyRequire(id) {
|
||||
return logger;
|
||||
}
|
||||
|
||||
function runFromArgv() {
|
||||
return require(id).line.apply(undefined, arguments);
|
||||
}
|
||||
|
||||
command.line = runFromArgv;
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
cache: lazyRequire('./cache'),
|
||||
completion: lazyRequire('./completion'),
|
||||
help: lazyRequire('./help'),
|
||||
home: lazyRequire('./home'),
|
||||
info: lazyRequire('./info'),
|
||||
init: lazyRequire('./init'),
|
||||
install: lazyRequire('./install'),
|
||||
link: lazyRequire('./link'),
|
||||
list: lazyRequire('./list'),
|
||||
lookup: lazyRequire('./lookup'),
|
||||
prune: lazyRequire('./prune'),
|
||||
register: lazyRequire('./register'),
|
||||
search: lazyRequire('./search'),
|
||||
update: lazyRequire('./update'),
|
||||
uninstall: lazyRequire('./uninstall'),
|
||||
version: lazyRequire('./version')
|
||||
cache: {
|
||||
clean: commandFactory('./cache/clean'),
|
||||
list: commandFactory('./cache/list'),
|
||||
},
|
||||
help: commandFactory('./help'),
|
||||
home: commandFactory('./home'),
|
||||
info: commandFactory('./info'),
|
||||
init: commandFactory('./init'),
|
||||
install: commandFactory('./install'),
|
||||
link: commandFactory('./link'),
|
||||
list: commandFactory('./list'),
|
||||
login: commandFactory('./login'),
|
||||
lookup: commandFactory('./lookup'),
|
||||
prune: commandFactory('./prune'),
|
||||
register: commandFactory('./register'),
|
||||
search: commandFactory('./search'),
|
||||
update: commandFactory('./update'),
|
||||
uninstall: commandFactory('./uninstall'),
|
||||
unregister: commandFactory('./unregister'),
|
||||
version: commandFactory('./version')
|
||||
};
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
var mout = require('mout');
|
||||
var Q = require('q');
|
||||
var Logger = require('bower-logger');
|
||||
var endpointParser = require('bower-endpoint-parser');
|
||||
var PackageRepository = require('../core/PackageRepository');
|
||||
var cli = require('../util/cli');
|
||||
var Tracker = require('../util/analytics').Tracker;
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function info(endpoint, property, config) {
|
||||
function info(logger, endpoint, property, config) {
|
||||
if (!endpoint) {
|
||||
return;
|
||||
}
|
||||
|
||||
var repository;
|
||||
var decEndpoint;
|
||||
var tracker;
|
||||
var logger = new Logger();
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
repository = new PackageRepository(config, logger);
|
||||
tracker = new Tracker(config);
|
||||
|
||||
decEndpoint = endpointParser.decompose(endpoint);
|
||||
tracker.trackDecomposedEndpoints('info', [decEndpoint]);
|
||||
|
||||
Q.all([
|
||||
return Q.all([
|
||||
getPkgMeta(repository, decEndpoint, property),
|
||||
decEndpoint.target === '*' && !property ? repository.versions(decEndpoint.source) : null
|
||||
])
|
||||
@@ -34,14 +35,7 @@ function info(endpoint, property, config) {
|
||||
}
|
||||
|
||||
return pkgMeta;
|
||||
})
|
||||
.done(function (result) {
|
||||
logger.emit('end', result);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
function getPkgMeta(repository, decEndpoint, property) {
|
||||
@@ -62,24 +56,13 @@ function getPkgMeta(repository, decEndpoint, property) {
|
||||
|
||||
// -------------------
|
||||
|
||||
info.line = function (argv) {
|
||||
var options = info.options(argv);
|
||||
info.readOptions = function (argv) {
|
||||
var cli = require('../util/cli');
|
||||
var options = cli.readOptions(argv);
|
||||
var pkg = options.argv.remain[1];
|
||||
var property = options.argv.remain[2];
|
||||
|
||||
if (!pkg) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return info(pkg, property);
|
||||
};
|
||||
|
||||
info.options = function (argv) {
|
||||
return cli.readOptions(argv);
|
||||
};
|
||||
|
||||
info.completion = function () {
|
||||
// TODO:
|
||||
return [pkg, property];
|
||||
};
|
||||
|
||||
module.exports = info;
|
||||
|
||||
@@ -2,36 +2,30 @@ var mout = require('mout');
|
||||
var fs = require('graceful-fs');
|
||||
var path = require('path');
|
||||
var Q = require('q');
|
||||
var Logger = require('bower-logger');
|
||||
var endpointParser = require('bower-endpoint-parser');
|
||||
var Project = require('../core/Project');
|
||||
var defaultConfig = require('../config');
|
||||
var GitHubResolver = require('../core/resolvers/GitHubResolver');
|
||||
var GitFsResolver = require('../core/resolvers/GitFsResolver');
|
||||
var cli = require('../util/cli');
|
||||
var cmd = require('../util/cmd');
|
||||
var createError = require('../util/createError');
|
||||
|
||||
function init(config) {
|
||||
function init(logger, config) {
|
||||
var project;
|
||||
var logger = new Logger();
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
|
||||
// This command requires interactive to be enabled
|
||||
if (!config.interactive) {
|
||||
process.nextTick(function () {
|
||||
logger.emit('error', createError('Register requires an interactive shell', 'ENOINT', {
|
||||
details: 'Note that you can manually force an interactive shell with --config.interactive'
|
||||
}));
|
||||
throw createError('Register requires an interactive shell', 'ENOINT', {
|
||||
details: 'Note that you can manually force an interactive shell with --config.interactive'
|
||||
});
|
||||
return logger;
|
||||
}
|
||||
|
||||
project = new Project(config, logger);
|
||||
|
||||
// Start with existing JSON details
|
||||
readJson(project, logger)
|
||||
return readJson(project, logger)
|
||||
// Fill in defaults
|
||||
.then(setDefaults.bind(null, config))
|
||||
// Now prompt user to make changes
|
||||
@@ -41,14 +35,7 @@ function init(config) {
|
||||
// Set dependencies based on the response
|
||||
.spread(setDependencies.bind(null, project))
|
||||
// All done!
|
||||
.spread(saveJson.bind(null, project, logger))
|
||||
.done(function (json) {
|
||||
logger.emit('end', json);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
|
||||
return logger;
|
||||
.spread(saveJson.bind(null, project, logger));
|
||||
}
|
||||
|
||||
function readJson(project, logger) {
|
||||
@@ -329,16 +316,8 @@ function setDependencies(project, json, answers) {
|
||||
|
||||
// -------------------
|
||||
|
||||
init.line = function () {
|
||||
return init();
|
||||
};
|
||||
|
||||
init.options = function (argv) {
|
||||
return cli.readOptions(argv);
|
||||
};
|
||||
|
||||
init.completion = function () {
|
||||
// TODO:
|
||||
init.readOptions = function (argv) {
|
||||
return [];
|
||||
};
|
||||
|
||||
module.exports = init;
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
var mout = require('mout');
|
||||
var Logger = require('bower-logger');
|
||||
var endpointParser = require('bower-endpoint-parser');
|
||||
var Project = require('../core/Project');
|
||||
var cli = require('../util/cli');
|
||||
var Tracker = require('../util/analytics').Tracker;
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function install(endpoints, options, config) {
|
||||
function install(logger, endpoints, options, config) {
|
||||
var project;
|
||||
var decEndpoints;
|
||||
var tracker;
|
||||
var logger = new Logger();
|
||||
|
||||
options = options || {};
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
if (options.save === undefined) {
|
||||
options.save = config.defaultSave;
|
||||
}
|
||||
@@ -27,35 +23,27 @@ function install(endpoints, options, config) {
|
||||
});
|
||||
tracker.trackDecomposedEndpoints('install', decEndpoints);
|
||||
|
||||
project.install(decEndpoints, options)
|
||||
.done(function (installed) {
|
||||
tracker.trackPackages('installed', installed);
|
||||
logger.emit('end', installed);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
|
||||
return logger;
|
||||
return project.install(decEndpoints, options, config);
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
install.line = function (argv) {
|
||||
var options = install.options(argv);
|
||||
return install(options.argv.remain.slice(1), options);
|
||||
};
|
||||
install.readOptions = function (argv) {
|
||||
var cli = require('../util/cli');
|
||||
|
||||
install.options = function (argv) {
|
||||
return cli.readOptions({
|
||||
var options = cli.readOptions({
|
||||
'force-latest': { type: Boolean, shorthand: 'F'},
|
||||
'production': { type: Boolean, shorthand: 'p' },
|
||||
'save': { type: Boolean, shorthand: 'S' },
|
||||
'save-dev': { type: Boolean, shorthand: 'D' }
|
||||
'save-dev': { type: Boolean, shorthand: 'D' },
|
||||
'save-exact': { type: Boolean, shorthand: 'E' }
|
||||
}, argv);
|
||||
};
|
||||
|
||||
install.completion = function () {
|
||||
// TODO:
|
||||
var packages = options.argv.remain.slice(1);
|
||||
|
||||
delete options.argv;
|
||||
|
||||
return [packages, options];
|
||||
};
|
||||
|
||||
module.exports = install;
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
var path = require('path');
|
||||
var rimraf = require('rimraf');
|
||||
var mout = require('mout');
|
||||
var Q = require('q');
|
||||
var Logger = require('bower-logger');
|
||||
var Project = require('../core/Project');
|
||||
var createLink = require('../util/createLink');
|
||||
var cli = require('../util/cli');
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function linkSelf(config) {
|
||||
var project;
|
||||
var logger = new Logger();
|
||||
function link(logger, name, localName, config) {
|
||||
if (name) {
|
||||
return linkTo(logger, name, localName, config);
|
||||
} else {
|
||||
return linkSelf(logger, config);
|
||||
}
|
||||
}
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
function linkSelf(logger, config) {
|
||||
var project;
|
||||
|
||||
config = defaultConfig(config);
|
||||
project = new Project(config, logger);
|
||||
|
||||
project.getJson()
|
||||
return project.getJson()
|
||||
.then(function (json) {
|
||||
var src = config.cwd;
|
||||
var dst = path.join(config.storage.links, json.name);
|
||||
@@ -32,30 +36,23 @@ function linkSelf(config) {
|
||||
dst: dst
|
||||
};
|
||||
});
|
||||
})
|
||||
.done(function (result) {
|
||||
logger.emit('end', result);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
function linkTo(name, localName, config) {
|
||||
function linkTo(logger, name, localName, config) {
|
||||
var src;
|
||||
var dst;
|
||||
var logger = new Logger();
|
||||
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);
|
||||
dst = path.join(process.cwd(), config.directory, localName);
|
||||
dst = path.join(config.cwd, config.directory, localName);
|
||||
|
||||
// Delete destination folder if any
|
||||
Q.nfcall(rimraf, dst)
|
||||
return Q.nfcall(rimraf, dst)
|
||||
// Link locally
|
||||
.then(function () {
|
||||
return createLink(src, dst);
|
||||
@@ -70,41 +67,18 @@ function linkTo(name, localName, config) {
|
||||
dst: dst,
|
||||
installed: installed
|
||||
};
|
||||
})
|
||||
.done(function (result) {
|
||||
logger.emit('end', result);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
var link = {
|
||||
linkTo: linkTo,
|
||||
linkSelf: linkSelf
|
||||
};
|
||||
|
||||
link.line = function (argv) {
|
||||
var options = link.options(argv);
|
||||
link.readOptions = function (argv) {
|
||||
var cli = require('../util/cli');
|
||||
var options = cli.readOptions(argv);
|
||||
var name = options.argv.remain[1];
|
||||
var localName = options.argv.remain[2];
|
||||
|
||||
if (name) {
|
||||
return linkTo(name, localName);
|
||||
}
|
||||
|
||||
return linkSelf();
|
||||
};
|
||||
|
||||
link.options = function (argv) {
|
||||
return cli.readOptions(argv);
|
||||
};
|
||||
|
||||
link.completion = function () {
|
||||
// TODO:
|
||||
return [name, localName];
|
||||
};
|
||||
|
||||
module.exports = link;
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
var path = require('path');
|
||||
var mout = require('mout');
|
||||
var Q = require('q');
|
||||
var Logger = require('bower-logger');
|
||||
var Project = require('../core/Project');
|
||||
var semver = require('../util/semver');
|
||||
var cli = require('../util/cli');
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function list(options, config) {
|
||||
function list(logger, options, config) {
|
||||
var project;
|
||||
var logger = new Logger();
|
||||
|
||||
options = options || {};
|
||||
|
||||
@@ -18,13 +15,11 @@ function list(options, config) {
|
||||
options.relative = true;
|
||||
}
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
project = new Project(config, logger);
|
||||
|
||||
project.getTree(options)
|
||||
return project.getTree(options)
|
||||
.spread(function (tree, flattened) {
|
||||
var baseDir = path.dirname(path.join(config.cwd, config.directory));
|
||||
|
||||
// Relativize paths
|
||||
// Also normalize paths on windows
|
||||
project.walkTree(tree, function (node) {
|
||||
@@ -33,7 +28,7 @@ function list(options, config) {
|
||||
}
|
||||
|
||||
if (options.relative) {
|
||||
node.canonicalDir = path.relative(baseDir, node.canonicalDir);
|
||||
node.canonicalDir = path.relative(config.cwd, node.canonicalDir);
|
||||
}
|
||||
if (options.paths) {
|
||||
node.canonicalDir = normalize(node.canonicalDir);
|
||||
@@ -48,7 +43,7 @@ function list(options, config) {
|
||||
}
|
||||
|
||||
if (options.relative) {
|
||||
node.canonicalDir = path.relative(baseDir, node.canonicalDir);
|
||||
node.canonicalDir = path.relative(config.cwd, node.canonicalDir);
|
||||
}
|
||||
if (options.paths) {
|
||||
node.canonicalDir = normalize(node.canonicalDir);
|
||||
@@ -70,16 +65,7 @@ function list(options, config) {
|
||||
.then(function () {
|
||||
return tree;
|
||||
});
|
||||
})
|
||||
.done(function (value) {
|
||||
logger.emit('end', value);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
|
||||
logger.json = !!options.paths;
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
function checkVersions(project, tree, logger) {
|
||||
@@ -164,20 +150,17 @@ function normalize(src) {
|
||||
|
||||
// -------------------
|
||||
|
||||
list.line = function (argv) {
|
||||
var options = list.options(argv);
|
||||
return list(options);
|
||||
};
|
||||
list.readOptions = function (argv) {
|
||||
var cli = require('../util/cli');
|
||||
|
||||
list.options = function (argv) {
|
||||
return cli.readOptions({
|
||||
var options = cli.readOptions({
|
||||
'paths': { type: Boolean, shorthand: 'p' },
|
||||
'relative': { type: Boolean, shorthand: 'r' }
|
||||
}, argv);
|
||||
};
|
||||
|
||||
list.completion = function () {
|
||||
// TODO:
|
||||
delete options.argv;
|
||||
|
||||
return [options];
|
||||
};
|
||||
|
||||
module.exports = list;
|
||||
|
||||
123
lib/commands/login.js
Normal file
123
lib/commands/login.js
Normal file
@@ -0,0 +1,123 @@
|
||||
var Configstore = require('configstore');
|
||||
var GitHub = require('github');
|
||||
var Q = require('q');
|
||||
|
||||
var createError = require('../util/createError');
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function login(logger, options, config) {
|
||||
var configstore = new Configstore('bower-github');
|
||||
|
||||
config = defaultConfig(config);
|
||||
|
||||
var promise;
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (options.token) {
|
||||
promise = Q.resolve({ token: options.token });
|
||||
} else {
|
||||
// This command requires interactive to be enabled
|
||||
if (!config.interactive) {
|
||||
logger.emit('error', createError('Login requires an interactive shell', 'ENOINT', {
|
||||
details: 'Note that you can manually force an interactive shell with --config.interactive'
|
||||
}));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var questions = [
|
||||
{
|
||||
'name': 'username',
|
||||
'message': 'Username',
|
||||
'type': 'input',
|
||||
'default': configstore.get('username')
|
||||
},
|
||||
{
|
||||
'name': 'password',
|
||||
'message': 'Password',
|
||||
'type': 'password'
|
||||
}
|
||||
];
|
||||
|
||||
var github = new GitHub({
|
||||
version: '3.0.0'
|
||||
});
|
||||
|
||||
promise = Q.nfcall(logger.prompt.bind(logger), questions)
|
||||
.then(function (answers) {
|
||||
configstore.set('username', answers.username);
|
||||
|
||||
github.authenticate({
|
||||
type: 'basic',
|
||||
username: answers.username,
|
||||
password: answers.password
|
||||
});
|
||||
|
||||
return Q.ninvoke(github.authorization, 'create', {
|
||||
scopes: ['user', 'repo'],
|
||||
note: 'Bower command line client (' + (new Date()).toISOString() + ')'
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return promise.then(function (result) {
|
||||
configstore.set('accessToken', result.token);
|
||||
|
||||
return result;
|
||||
}, function (error) {
|
||||
var message;
|
||||
|
||||
try {
|
||||
message = JSON.parse(error.message).message;
|
||||
} catch (e) {
|
||||
message = 'Authorization failed';
|
||||
}
|
||||
|
||||
var questions = [
|
||||
{
|
||||
'name': 'otpcode',
|
||||
'message': 'Two-Factor Auth Code',
|
||||
'type': 'input'
|
||||
}
|
||||
];
|
||||
|
||||
if (message === 'Must specify two-factor authentication OTP code.') {
|
||||
return Q.nfcall(logger.prompt.bind(logger), questions)
|
||||
.then(function (answers) {
|
||||
return Q.ninvoke(github.authorization, 'create', {
|
||||
scopes: ['user', 'repo'],
|
||||
note: 'Bower command line client (' + (new Date()).toISOString() + ')',
|
||||
headers: {
|
||||
'X-GitHub-OTP': answers.otpcode
|
||||
}
|
||||
});
|
||||
})
|
||||
.then(function (result) {
|
||||
configstore.set('accessToken', result.token);
|
||||
|
||||
return result;
|
||||
}, function () {
|
||||
logger.emit('error', createError(message, 'EAUTH'));
|
||||
});
|
||||
} else {
|
||||
logger.emit('error', createError(message, 'EAUTH'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
login.readOptions = function (argv) {
|
||||
var cli = require('../util/cli');
|
||||
|
||||
var options = cli.readOptions({
|
||||
token: { type: String, shorthand: 't' },
|
||||
}, argv);
|
||||
|
||||
delete options.argv;
|
||||
|
||||
return [options];
|
||||
};
|
||||
|
||||
module.exports = login;
|
||||
@@ -1,20 +1,20 @@
|
||||
var mout = require('mout');
|
||||
var Q = require('q');
|
||||
var Logger = require('bower-logger');
|
||||
var RegistryClient = require('bower-registry-client');
|
||||
var cli = require('../util/cli');
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function lookup(name, config) {
|
||||
var registryClient;
|
||||
var logger = new Logger();
|
||||
function lookup(logger, name, config) {
|
||||
if (!name) {
|
||||
return new Q(null);
|
||||
}
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
var registryClient;
|
||||
|
||||
config = defaultConfig(config);
|
||||
config.cache = config.storage.registry;
|
||||
|
||||
registryClient = new RegistryClient(config, logger);
|
||||
|
||||
Q.nfcall(registryClient.lookup.bind(registryClient), name)
|
||||
return Q.nfcall(registryClient.lookup.bind(registryClient), name)
|
||||
.then(function (entry) {
|
||||
// TODO: Handle entry.type.. for now it's only 'alias'
|
||||
// When we got published packages, this needs to be adjusted
|
||||
@@ -22,35 +22,17 @@ function lookup(name, config) {
|
||||
name: name,
|
||||
url: entry && entry.url
|
||||
};
|
||||
})
|
||||
.done(function (result) {
|
||||
logger.emit('end', result);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
lookup.line = function (argv) {
|
||||
var options = lookup.options(argv);
|
||||
lookup.readOptions = function (argv) {
|
||||
var cli = require('../util/cli');
|
||||
var options = cli.readOptions(argv);
|
||||
var name = options.argv.remain[1];
|
||||
|
||||
if (!name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return lookup(name);
|
||||
};
|
||||
|
||||
lookup.options = function (argv) {
|
||||
return cli.readOptions(argv);
|
||||
};
|
||||
|
||||
lookup.completion = function () {
|
||||
// TODO:
|
||||
return [name];
|
||||
};
|
||||
|
||||
module.exports = lookup;
|
||||
|
||||
@@ -1,25 +1,15 @@
|
||||
var mout = require('mout');
|
||||
var Logger = require('bower-logger');
|
||||
var Project = require('../core/Project');
|
||||
var cli = require('../util/cli');
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function prune(options, config) {
|
||||
function prune(logger, options, config) {
|
||||
var project;
|
||||
var logger = new Logger();
|
||||
|
||||
options = options || {};
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
project = new Project(config, logger);
|
||||
|
||||
clean(project, options)
|
||||
.done(function (removed) {
|
||||
logger.emit('end', removed);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
|
||||
return logger;
|
||||
return clean(project, options);
|
||||
}
|
||||
|
||||
function clean(project, options, removed) {
|
||||
@@ -50,19 +40,16 @@ function clean(project, options, removed) {
|
||||
|
||||
// -------------------
|
||||
|
||||
prune.line = function (argv) {
|
||||
var options = prune.options(argv);
|
||||
return prune(options);
|
||||
};
|
||||
prune.readOptions = function (argv) {
|
||||
var cli = require('../util/cli');
|
||||
|
||||
prune.options = function (argv) {
|
||||
return cli.readOptions({
|
||||
var options = cli.readOptions({
|
||||
'production': { type: Boolean, shorthand: 'p' },
|
||||
}, argv);
|
||||
};
|
||||
|
||||
prune.completion = function () {
|
||||
// TODO:
|
||||
delete options.argv;
|
||||
|
||||
return [options];
|
||||
};
|
||||
|
||||
module.exports = prune;
|
||||
|
||||
@@ -2,37 +2,33 @@ var mout = require('mout');
|
||||
var Q = require('q');
|
||||
var chalk = require('chalk');
|
||||
var PackageRepository = require('../core/PackageRepository');
|
||||
var Logger = require('bower-logger');
|
||||
var Config = require('bower-config');
|
||||
var Tracker = require('../util/analytics').Tracker;
|
||||
var cli = require('../util/cli');
|
||||
var createError = require('../util/createError');
|
||||
var defaultConfig = require('../config');
|
||||
var GitHubResolver = require('../core/resolvers/GitHubResolver');
|
||||
|
||||
function register(name, url, config) {
|
||||
function register(logger, name, url, config) {
|
||||
var repository;
|
||||
var registryClient;
|
||||
var tracker;
|
||||
var logger = new Logger();
|
||||
var force;
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
force = config.force;
|
||||
tracker = new Tracker(config);
|
||||
|
||||
name = (name || '').trim();
|
||||
url = (url || '').trim();
|
||||
|
||||
// Bypass any cache
|
||||
config.offline = false;
|
||||
config.force = true;
|
||||
|
||||
// Trim name
|
||||
name = name.trim();
|
||||
|
||||
process.nextTick(function () {
|
||||
// Verify name
|
||||
// TODO: Verify with the new spec regexp?
|
||||
if (!name) {
|
||||
return logger.emit('error', createError('Please type a name', 'EINVNAME'));
|
||||
return Q.try(function () {
|
||||
// Verify name and url
|
||||
if (!name || !url) {
|
||||
throw createError('Usage: bower register <name> <url>', 'EINVFORMAT');
|
||||
}
|
||||
|
||||
// The public registry only allows git:// endpoints
|
||||
@@ -41,7 +37,7 @@ function register(name, url, config) {
|
||||
url = convertUrl(url, logger);
|
||||
|
||||
if (!mout.string.startsWith(url, 'git://')) {
|
||||
return logger.emit('error', createError('The registry only accepts URLs starting with git://', 'EINVFORMAT'));
|
||||
throw createError('The registry only accepts URLs starting with git://', 'EINVFORMAT');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,50 +46,42 @@ function register(name, url, config) {
|
||||
// Attempt to resolve the package referenced by the URL to ensure
|
||||
// everything is ok before registering
|
||||
repository = new PackageRepository(config, logger);
|
||||
repository.fetch({ name: name, source: url, target: '*' })
|
||||
.spread(function (canonicalDir, pkgMeta) {
|
||||
if (pkgMeta.private) {
|
||||
throw createError('The package you are trying to register is marked as private', 'EPRIV');
|
||||
}
|
||||
return repository.fetch({ name: name, source: url, target: '*' });
|
||||
})
|
||||
.spread(function (canonicalDir, pkgMeta) {
|
||||
if (pkgMeta.private) {
|
||||
throw createError('The package you are trying to register is marked as private', 'EPRIV');
|
||||
}
|
||||
|
||||
// If non interactive or user forced, bypass confirmation
|
||||
if (!config.interactive || force) {
|
||||
return true;
|
||||
}
|
||||
// If non interactive or user forced, bypass confirmation
|
||||
if (!config.interactive || force) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Confirm if the user really wants to register
|
||||
return Q.nfcall(logger.prompt.bind(logger), {
|
||||
type: 'confirm',
|
||||
message: 'Registering a package will make it installable via the registry (' +
|
||||
chalk.cyan.underline(config.registry.register) + '), continue?',
|
||||
default: true
|
||||
});
|
||||
})
|
||||
.then(function (result) {
|
||||
// If user response was negative, abort
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Register
|
||||
registryClient = repository.getRegistryClient();
|
||||
|
||||
logger.action('register', url, {
|
||||
name: name,
|
||||
url: url
|
||||
});
|
||||
|
||||
return Q.nfcall(registryClient.register.bind(registryClient), name, url);
|
||||
})
|
||||
.done(function (result) {
|
||||
tracker.track('registered');
|
||||
logger.emit('end', result);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
// Confirm if the user really wants to register
|
||||
return Q.nfcall(logger.prompt.bind(logger), {
|
||||
type: 'confirm',
|
||||
message: 'Registering a package will make it installable via the registry (' +
|
||||
chalk.cyan.underline(config.registry.register) + '), continue?',
|
||||
default: true
|
||||
});
|
||||
});
|
||||
})
|
||||
.then(function (result) {
|
||||
// If user response was negative, abort
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
return logger;
|
||||
// Register
|
||||
registryClient = repository.getRegistryClient();
|
||||
|
||||
logger.action('register', url, {
|
||||
name: name,
|
||||
url: url
|
||||
});
|
||||
|
||||
return Q.nfcall(registryClient.register.bind(registryClient), name, url);
|
||||
});
|
||||
}
|
||||
|
||||
function convertUrl(url, logger) {
|
||||
@@ -114,24 +102,14 @@ function convertUrl(url, logger) {
|
||||
|
||||
// -------------------
|
||||
|
||||
register.line = function (argv) {
|
||||
var options = register.options(argv);
|
||||
register.readOptions = function (argv) {
|
||||
var cli = require('../util/cli');
|
||||
|
||||
var options = cli.readOptions(argv);
|
||||
var name = options.argv.remain[1];
|
||||
var url = options.argv.remain[2];
|
||||
|
||||
if (!name || !url) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return register(name, url);
|
||||
};
|
||||
|
||||
register.options = function (argv) {
|
||||
return cli.readOptions(argv);
|
||||
};
|
||||
|
||||
register.completion = function () {
|
||||
// TODO:
|
||||
return [name, url];
|
||||
};
|
||||
|
||||
module.exports = register;
|
||||
|
||||
@@ -1,18 +1,13 @@
|
||||
var mout = require('mout');
|
||||
var Q = require('q');
|
||||
var Logger = require('bower-logger');
|
||||
var RegistryClient = require('bower-registry-client');
|
||||
var cli = require('../util/cli');
|
||||
var Tracker = require('../util/analytics').Tracker;
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function search(name, config) {
|
||||
function search(logger, name, config) {
|
||||
var registryClient;
|
||||
var promise;
|
||||
var tracker;
|
||||
var logger = new Logger();
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
config.cache = config.storage.registry;
|
||||
|
||||
registryClient = new RegistryClient(config, logger);
|
||||
@@ -21,35 +16,21 @@ function search(name, config) {
|
||||
|
||||
// If no name was specified, list all packages
|
||||
if (!name) {
|
||||
promise = Q.nfcall(registryClient.list.bind(registryClient));
|
||||
return Q.nfcall(registryClient.list.bind(registryClient));
|
||||
// Otherwise search it
|
||||
} else {
|
||||
promise = Q.nfcall(registryClient.search.bind(registryClient), name);
|
||||
return Q.nfcall(registryClient.search.bind(registryClient), name);
|
||||
}
|
||||
|
||||
promise
|
||||
.done(function (results) {
|
||||
logger.emit('end', results);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
search.line = function (argv) {
|
||||
var options = search.options(argv);
|
||||
return search(options.argv.remain.slice(1).join(' '), options);
|
||||
};
|
||||
search.readOptions = function (argv) {
|
||||
var cli = require('../util/cli');
|
||||
var options = cli.readOptions(argv);
|
||||
var name = options.argv.remain.slice(1).join(' ');
|
||||
|
||||
search.options = function (argv) {
|
||||
return cli.readOptions(argv);
|
||||
};
|
||||
|
||||
search.completion = function () {
|
||||
// TODO:
|
||||
return [name];
|
||||
};
|
||||
|
||||
module.exports = search;
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
var mout = require('mout');
|
||||
var Logger = require('bower-logger');
|
||||
var Q = require('q');
|
||||
var Project = require('../core/Project');
|
||||
var cli = require('../util/cli');
|
||||
var Tracker = require('../util/analytics').Tracker;
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function uninstall(names, options, config) {
|
||||
function uninstall(logger, names, options, config) {
|
||||
if (!names.length) {
|
||||
return new Q();
|
||||
}
|
||||
|
||||
var project;
|
||||
var tracker;
|
||||
var logger = new Logger();
|
||||
|
||||
options = options || {};
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
project = new Project(config, logger);
|
||||
tracker = new Tracker(config);
|
||||
|
||||
tracker.trackNames('uninstall', names);
|
||||
|
||||
project.getTree(options)
|
||||
return project.getTree(options)
|
||||
.spread(function (tree, flattened) {
|
||||
// Uninstall nodes
|
||||
return project.uninstall(names, options)
|
||||
@@ -37,15 +38,7 @@ function uninstall(names, options, config) {
|
||||
// Clean them!
|
||||
return clean(project, children, uninstalled);
|
||||
});
|
||||
})
|
||||
.done(function (uninstalled) {
|
||||
logger.emit('end', uninstalled);
|
||||
tracker.trackNames('uninstalled', Object.keys(uninstalled));
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
function clean(project, names, removed) {
|
||||
@@ -109,26 +102,19 @@ function clean(project, names, removed) {
|
||||
|
||||
// -------------------
|
||||
|
||||
uninstall.line = function (argv) {
|
||||
var options = uninstall.options(argv);
|
||||
var names = options.argv.remain.slice(1);
|
||||
uninstall.readOptions = function (argv) {
|
||||
var cli = require('../util/cli');
|
||||
|
||||
if (!names.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return uninstall(names, options);
|
||||
};
|
||||
|
||||
uninstall.options = function (argv) {
|
||||
return cli.readOptions({
|
||||
var options = cli.readOptions({
|
||||
'save': { type: Boolean, shorthand: 'S' },
|
||||
'save-dev': { type: Boolean, shorthand: 'D' }
|
||||
}, argv);
|
||||
};
|
||||
|
||||
uninstall.completion = function () {
|
||||
// TODO:
|
||||
var names = options.argv.remain.slice(1);
|
||||
|
||||
delete options.argv;
|
||||
|
||||
return [names, options];
|
||||
};
|
||||
|
||||
module.exports = uninstall;
|
||||
|
||||
85
lib/commands/unregister.js
Normal file
85
lib/commands/unregister.js
Normal file
@@ -0,0 +1,85 @@
|
||||
var chalk = require('chalk');
|
||||
var Q = require('q');
|
||||
|
||||
var defaultConfig = require('../config');
|
||||
var PackageRepository = require('../core/PackageRepository');
|
||||
var Tracker = require('../util/analytics').Tracker;
|
||||
var createError = require('../util/createError');
|
||||
|
||||
function unregister(logger, name, config) {
|
||||
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
|
||||
var repository;
|
||||
var registryClient;
|
||||
var tracker;
|
||||
var force;
|
||||
|
||||
config = defaultConfig(config);
|
||||
force = config.force;
|
||||
tracker = new Tracker(config);
|
||||
|
||||
// Bypass any cache
|
||||
config.offline = false;
|
||||
config.force = true;
|
||||
|
||||
// Trim name
|
||||
name = name.trim();
|
||||
|
||||
repository = new PackageRepository(config, logger);
|
||||
|
||||
tracker.track('unregister');
|
||||
|
||||
if (!config.accessToken) {
|
||||
return logger.emit('error',
|
||||
createError('Use "bower login" with collaborator credentials', 'EFORBIDDEN')
|
||||
);
|
||||
}
|
||||
|
||||
return Q.resolve()
|
||||
.then(function () {
|
||||
// If non interactive or user forced, bypass confirmation
|
||||
if (!config.interactive || force) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Q.nfcall(logger.prompt.bind(logger), {
|
||||
type: 'confirm',
|
||||
message: 'You are about to remove component "' + chalk.cyan.underline(name) + '" from the bower registry (' + chalk.cyan.underline(config.registry.register) + '). It is generally considered bad behavior to remove versions of a library that others are depending on. Are you really sure?',
|
||||
default: false
|
||||
});
|
||||
})
|
||||
.then(function (result) {
|
||||
// If user response was negative, abort
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
registryClient = repository.getRegistryClient();
|
||||
|
||||
logger.action('unregister', name, { name: name });
|
||||
|
||||
return Q.nfcall(registryClient.unregister.bind(registryClient), name);
|
||||
})
|
||||
.then(function (result) {
|
||||
tracker.track('unregistered');
|
||||
logger.info('Package unregistered', name);
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
unregister.readOptions = function (argv) {
|
||||
var cli = require('../util/cli');
|
||||
|
||||
var options = cli.readOptions(argv);
|
||||
var name = options.argv.remain[1];
|
||||
|
||||
return [name];
|
||||
};
|
||||
|
||||
module.exports = unregister;
|
||||
@@ -1,15 +1,11 @@
|
||||
var mout = require('mout');
|
||||
var Logger = require('bower-logger');
|
||||
var Project = require('../core/Project');
|
||||
var cli = require('../util/cli');
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function update(names, options, config) {
|
||||
function update(logger, names, options, config) {
|
||||
var project;
|
||||
var logger = new Logger();
|
||||
|
||||
options = options || {};
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config = defaultConfig(config);
|
||||
project = new Project(config, logger);
|
||||
|
||||
// If names is an empty array, null them
|
||||
@@ -17,32 +13,24 @@ function update(names, options, config) {
|
||||
names = null;
|
||||
}
|
||||
|
||||
project.update(names, options)
|
||||
.done(function (installed) {
|
||||
logger.emit('end', installed);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
|
||||
return logger;
|
||||
return project.update(names, options);
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
update.line = function (argv) {
|
||||
var options = update.options(argv);
|
||||
return update(options.argv.remain.slice(1), options);
|
||||
};
|
||||
update.readOptions = function (argv) {
|
||||
var cli = require('../util/cli');
|
||||
|
||||
update.options = function (argv) {
|
||||
return cli.readOptions({
|
||||
var options = cli.readOptions({
|
||||
'force-latest': { type: Boolean, shorthand: 'F' },
|
||||
'production': { type: Boolean, shorthand: 'p' }
|
||||
}, argv);
|
||||
};
|
||||
|
||||
update.completion = function () {
|
||||
// TODO:
|
||||
var names = options.argv.remain.slice(1);
|
||||
|
||||
delete options.argv;
|
||||
|
||||
return [names, options];
|
||||
};
|
||||
|
||||
module.exports = update;
|
||||
|
||||
@@ -1,38 +1,29 @@
|
||||
var mout = require('mout');
|
||||
var semver = require('semver');
|
||||
var Logger = require('bower-logger');
|
||||
var which = require('which');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var Q = require('q');
|
||||
var execFile = require('child_process').execFile;
|
||||
var Project = require('../core/Project');
|
||||
var cli = require('../util/cli');
|
||||
var defaultConfig = require('../config');
|
||||
var createError = require('../util/createError');
|
||||
|
||||
function version(versionArg, options, config) {
|
||||
function version(logger, versionArg, options, config) {
|
||||
var project;
|
||||
var logger = new Logger();
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
options = options || {};
|
||||
config = defaultConfig(config);
|
||||
project = new Project(config, logger);
|
||||
|
||||
bump(project, versionArg, options.message)
|
||||
.done(function () {
|
||||
logger.emit('end');
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
|
||||
return logger;
|
||||
return bump(project, versionArg, options.message);
|
||||
}
|
||||
|
||||
function bump(project, versionArg, message) {
|
||||
var cwd = project._config.cwd || process.cwd();
|
||||
var newVersion;
|
||||
var doGitCommit = false;
|
||||
|
||||
return checkGit()
|
||||
return checkGit(cwd)
|
||||
.then(function (hasGit) {
|
||||
doGitCommit = hasGit;
|
||||
})
|
||||
@@ -44,11 +35,12 @@ function bump(project, versionArg, message) {
|
||||
.then(project.saveJson.bind(project))
|
||||
.then(function () {
|
||||
if (doGitCommit) {
|
||||
return gitCommitAndTag(newVersion, message);
|
||||
return gitCommitAndTag(cwd, newVersion, message);
|
||||
}
|
||||
})
|
||||
.then(function () {
|
||||
console.log('v' + newVersion);
|
||||
return newVersion;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -66,12 +58,12 @@ function getNewVersion(currentVersion, versionArg) {
|
||||
return newVersion;
|
||||
}
|
||||
|
||||
function checkGit() {
|
||||
var gitDir = path.join(process.cwd(), '.git');
|
||||
function checkGit(cwd) {
|
||||
var gitDir = path.join(cwd, '.git');
|
||||
return Q.nfcall(fs.stat, gitDir)
|
||||
.then(function (stat) {
|
||||
if (stat.isDirectory()) {
|
||||
return checkGitStatus();
|
||||
return checkGitStatus(cwd);
|
||||
}
|
||||
return false;
|
||||
}, function () {
|
||||
@@ -80,14 +72,14 @@ function checkGit() {
|
||||
});
|
||||
}
|
||||
|
||||
function checkGitStatus() {
|
||||
function checkGitStatus(cwd) {
|
||||
return Q.nfcall(which, 'git')
|
||||
.fail(function (err) {
|
||||
err.code = 'ENOGIT';
|
||||
throw err;
|
||||
})
|
||||
.then(function () {
|
||||
return Q.nfcall(execFile, 'git', ['status', '--porcelain'], {env: process.env});
|
||||
return Q.nfcall(execFile, 'git', ['status', '--porcelain'], {env: process.env, cwd: cwd});
|
||||
})
|
||||
.then(function (value) {
|
||||
var stdout = value[0];
|
||||
@@ -108,33 +100,29 @@ function filterModifiedStatusLines(stdout) {
|
||||
});
|
||||
}
|
||||
|
||||
function gitCommitAndTag(newVersion, message) {
|
||||
message = message || 'v' + newVersion;
|
||||
function gitCommitAndTag(cwd, newVersion, message) {
|
||||
var tag = 'v' + newVersion;
|
||||
message = message || tag;
|
||||
message = message.replace(/%s/g, newVersion);
|
||||
return Q.nfcall(execFile, 'git', ['add', 'bower.json'], {env: process.env})
|
||||
return Q.nfcall(execFile, 'git', ['add', 'bower.json'], {env: process.env, cwd: cwd})
|
||||
.then(function () {
|
||||
return Q.nfcall(execFile, 'git', ['commit', '-m', message], {env: process.env});
|
||||
return Q.nfcall(execFile, 'git', ['commit', '-m', message], {env: process.env, cwd: cwd});
|
||||
})
|
||||
.then(function () {
|
||||
return Q.nfcall(execFile, 'git', ['tag', newVersion, '-am', message], {env: process.env});
|
||||
return Q.nfcall(execFile, 'git', ['tag', tag, '-am', message], {env: process.env, cwd: cwd});
|
||||
});
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
version.line = function (argv) {
|
||||
var options = version.options(argv);
|
||||
return version(options.argv.remain[1], options);
|
||||
};
|
||||
version.readOptions = function (argv) {
|
||||
var cli = require('../util/cli');
|
||||
|
||||
version.options = function (argv) {
|
||||
return cli.readOptions({
|
||||
var options = cli.readOptions({
|
||||
'message': { type: String, shorthand: 'm'}
|
||||
}, argv);
|
||||
|
||||
return [options.argv.remain[1], options];
|
||||
};
|
||||
|
||||
version.completion = function () {
|
||||
// TODO:
|
||||
};
|
||||
|
||||
module.exports = version;
|
||||
module.exports = version;
|
||||
|
||||
@@ -1,33 +1,62 @@
|
||||
var tty = require('tty');
|
||||
var mout = require('mout');
|
||||
var config = require('bower-config').read();
|
||||
var cli = require('./util/cli');
|
||||
var object = require('mout').object;
|
||||
var bowerConfig = require('bower-config');
|
||||
var Configstore = require('configstore');
|
||||
|
||||
// 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);
|
||||
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 && !process.env.CI;
|
||||
function readCachedConfig(cwd) {
|
||||
if (cachedConfigs[cwd]) {
|
||||
return cachedConfigs[cwd];
|
||||
}
|
||||
|
||||
var config = cachedConfigs[cwd] = bowerConfig.read(cwd);
|
||||
var configstore = new Configstore('bower-github').all;
|
||||
|
||||
object.mixIn(config, configstore);
|
||||
|
||||
// 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
|
||||
if (process.bin === 'bower') {
|
||||
var cli = require('./util/cli');
|
||||
|
||||
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,7 +9,6 @@ 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) {
|
||||
@@ -110,6 +109,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;
|
||||
@@ -126,9 +159,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 = [];
|
||||
|
||||
@@ -170,9 +200,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
|
||||
@@ -191,13 +218,7 @@ 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);
|
||||
@@ -550,13 +571,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
|
||||
@@ -565,12 +584,8 @@ Manager.prototype._dissect = function () {
|
||||
var installedMeta = this._installed[name];
|
||||
var dst;
|
||||
|
||||
// Analyse a few props
|
||||
if (installedMeta &&
|
||||
installedMeta._target === decEndpoint.target &&
|
||||
installedMeta._originalSource === decEndpoint.source &&
|
||||
installedMeta._release === decEndpoint.pkgMeta._release
|
||||
) {
|
||||
// Skip linked dependencies
|
||||
if (decEndpoint.linked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -580,6 +595,15 @@ Manager.prototype._dissect = function () {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Analyse a few props
|
||||
if (installedMeta &&
|
||||
installedMeta._target === decEndpoint.target &&
|
||||
installedMeta._originalSource === decEndpoint.source &&
|
||||
installedMeta._release === decEndpoint.pkgMeta._release
|
||||
) {
|
||||
return this._config.force;
|
||||
}
|
||||
|
||||
return true;
|
||||
}, this);
|
||||
}.bind(this))
|
||||
@@ -751,7 +775,7 @@ Manager.prototype._electSuitable = function (name, semvers, nonSemvers) {
|
||||
choices = picks.map(function (pick, index) { return index + 1; });
|
||||
return Q.nfcall(this._logger.prompt.bind(this._logger), {
|
||||
type: 'input',
|
||||
message: 'Answer:',
|
||||
message: 'Answer',
|
||||
validate: function (choice) {
|
||||
choice = Number(mout.string.trim(choice.trim(), '!'));
|
||||
|
||||
@@ -798,10 +822,28 @@ Manager.prototype._storeResolution = function (pick) {
|
||||
this._resolutions[name] = resolution;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if some endpoint is compatible with already resolved target.
|
||||
*
|
||||
* It is used in two situations:
|
||||
* * checks if resolved component matches dependency constraint
|
||||
* * checks if not resolved component matches already fetched component
|
||||
*
|
||||
* If candidate matches already resolved component, it won't be downloaded.
|
||||
*
|
||||
* @param {Endpoint} candidate endpoint
|
||||
* @param {Endpoint} resolved endpoint
|
||||
*
|
||||
* @return {Boolean}
|
||||
*/
|
||||
Manager.prototype._areCompatible = function (candidate, resolved) {
|
||||
var resolvedVersion;
|
||||
var highestCandidate;
|
||||
var highestResolved;
|
||||
var candidateIsRange = semver.validRange(candidate.target);
|
||||
var resolvedIsRange = semver.validRange(resolved.target);
|
||||
var candidateIsVersion = semver.valid(candidate.target);
|
||||
var resolvedIsVersion = semver.valid(resolved.target);
|
||||
|
||||
// Check if targets are equal
|
||||
if (candidate.target === resolved.target) {
|
||||
@@ -809,30 +851,77 @@ Manager.prototype._areCompatible = function (candidate, resolved) {
|
||||
}
|
||||
|
||||
resolvedVersion = resolved.pkgMeta && resolved.pkgMeta.version;
|
||||
// If there is no pkgMeta, resolvedVersion is downloading now
|
||||
// Check based on target requirements
|
||||
if (!resolvedVersion) {
|
||||
// If one of the targets is range and other is version,
|
||||
// check version against the range
|
||||
if (candidateIsVersion && resolvedIsRange) {
|
||||
return semver.satisfies(candidate.target, resolved.target);
|
||||
}
|
||||
|
||||
if (resolvedIsVersion && candidateIsRange) {
|
||||
return semver.satisfies(resolved.target, candidate.target);
|
||||
}
|
||||
|
||||
if (resolvedIsVersion && candidateIsVersion) {
|
||||
return semver.eq(resolved.target, candidate.target);
|
||||
}
|
||||
|
||||
// If both targets are range, check that both have same
|
||||
// higher cap
|
||||
if (resolvedIsRange && candidateIsRange) {
|
||||
highestCandidate =
|
||||
this._getCap(semver.toComparators(candidate.target), 'highest');
|
||||
highestResolved =
|
||||
this._getCap(semver.toComparators(resolved.target), 'highest');
|
||||
|
||||
// This never happens, but you can't be sure without tests
|
||||
if (!highestResolved.version || !highestCandidate.version) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return semver.eq(highestCandidate.version, highestResolved.version) &&
|
||||
highestCandidate.comparator === highestResolved.comparator;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// If target is a version, compare against the resolved version
|
||||
if (semver.valid(candidate.target)) {
|
||||
if (candidateIsVersion) {
|
||||
return semver.eq(candidate.target, resolvedVersion);
|
||||
}
|
||||
|
||||
// If target is a range, check if the max versions of the range are the same
|
||||
// and if the resolved version satisfies the candidate target
|
||||
if (semver.validRange(candidate.target) && semver.validRange(resolved.target)) {
|
||||
highestCandidate = this._getCap(semver.toComparators(candidate.target), 'highest');
|
||||
highestResolved = this._getCap(semver.toComparators(resolved.target), 'highest');
|
||||
|
||||
return highestCandidate.version && highestResolved.version &&
|
||||
semver.eq(highestCandidate.version, highestResolved.version) &&
|
||||
highestCandidate.comparator === highestResolved.comparator &&
|
||||
semver.satisfies(resolvedVersion, candidate.target);
|
||||
// If target is a range, check if resolved version satisfies it
|
||||
if (candidateIsRange) {
|
||||
return semver.satisfies(resolvedVersion, candidate.target);
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets highest/lowest version from set of comparators.
|
||||
*
|
||||
* The only thing that matters for this function is version number.
|
||||
* Returned comparator is splitted to comparator and version parts.
|
||||
*
|
||||
* It is used to receive lowest / highest bound of toComparators result:
|
||||
* semver.toComparators('~0.1.1') // => [ [ '>=0.1.1-0', '<0.2.0-0' ] ]
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* _getCap([['>=2.1.1-0', '<2.2.0-0'], '<3.2.0'], 'highest')
|
||||
* // => { comparator: '<', version: '3.2.0' }
|
||||
*
|
||||
* _getCap([['>=2.1.1-0', '<2.2.0-0'], '<3.2.0'], 'lowest')
|
||||
* // => { comparator: '>=', version: '2.1.1-0' }
|
||||
*
|
||||
* @param {Array.<Array|string>} comparators
|
||||
* @param {string} side, 'highest' (default) or 'lowest'
|
||||
*
|
||||
* @return {{ comparator: string, version: string }}
|
||||
*/
|
||||
Manager.prototype._getCap = function (comparators, side) {
|
||||
var matches;
|
||||
var candidate;
|
||||
@@ -868,6 +957,23 @@ Manager.prototype._getCap = function (comparators, side) {
|
||||
return cap;
|
||||
};
|
||||
|
||||
/**
|
||||
* Filters out unique endpoints, comparing by name and then source.
|
||||
*
|
||||
* It leaves last matching endpoint.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* manager._uniquify([
|
||||
* { name: 'foo', source: 'google.com' },
|
||||
* { name: 'foo', source: 'facebook.com' }
|
||||
* ]);
|
||||
* // => { name: 'foo', source: 'facebook.com' }
|
||||
*
|
||||
* @param {Array.<Endpoint>} decEndpoints
|
||||
* @return {Array.<Endpoint>} Filtered elements of decEndpoints
|
||||
*
|
||||
*/
|
||||
Manager.prototype._uniquify = function (decEndpoints) {
|
||||
var length = decEndpoints.length;
|
||||
|
||||
|
||||
@@ -46,7 +46,11 @@ PackageRepository.prototype.fetch = function (decEndpoint) {
|
||||
info.resolver = resolver;
|
||||
isTargetable = resolver.constructor.isTargetable;
|
||||
|
||||
// If force flag is used, bypass cache
|
||||
if (!resolver.isCacheable()) {
|
||||
return that._resolve(resolver, logger);
|
||||
}
|
||||
|
||||
// If force flag is used, bypass cache, but write to cache anyway
|
||||
if (that._config.force) {
|
||||
logger.action('resolve', resolver.getSource() + '#' + resolver.getTarget());
|
||||
return that._resolve(resolver, logger);
|
||||
@@ -165,19 +169,25 @@ PackageRepository.clearRuntimeCache = function () {
|
||||
// ---------------------
|
||||
|
||||
PackageRepository.prototype._resolve = function (resolver, logger) {
|
||||
var that = this;
|
||||
|
||||
// Resolve the resolver
|
||||
return resolver.resolve()
|
||||
// Store in the cache
|
||||
.then(function (canonicalDir) {
|
||||
return this._resolveCache.store(canonicalDir, resolver.getPkgMeta());
|
||||
}.bind(this))
|
||||
if (!resolver.isCacheable()) {
|
||||
return canonicalDir;
|
||||
}
|
||||
|
||||
return that._resolveCache.store(canonicalDir, resolver.getPkgMeta());
|
||||
})
|
||||
// Resolve promise with canonical dir and package meta
|
||||
.then(function (dir) {
|
||||
var pkgMeta = resolver.getPkgMeta();
|
||||
|
||||
logger.info('resolved', resolver.getSource() + (pkgMeta._release ? '#' + pkgMeta._release : ''));
|
||||
return [dir, pkgMeta, resolver.constructor.isTargetable()];
|
||||
}.bind(this));
|
||||
});
|
||||
};
|
||||
|
||||
PackageRepository.prototype._extendLog = function (log, info) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -29,7 +29,7 @@ function Project(config, logger) {
|
||||
|
||||
// -----------------
|
||||
|
||||
Project.prototype.install = function (decEndpoints, options) {
|
||||
Project.prototype.install = function (decEndpoints, options, config) {
|
||||
var that = this;
|
||||
var targets = [];
|
||||
var resolved = {};
|
||||
@@ -41,21 +41,28 @@ Project.prototype.install = function (decEndpoints, options) {
|
||||
}
|
||||
|
||||
this._options = options || {};
|
||||
this._config = config || {};
|
||||
this._working = true;
|
||||
|
||||
// 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.missing || node.different) {
|
||||
targets.push(node);
|
||||
} else if (node.incompatible) {
|
||||
if (node.incompatible) {
|
||||
incompatibles.push(node);
|
||||
} else if (node.missing || node.different || that._config.force) {
|
||||
targets.push(node);
|
||||
} else {
|
||||
resolved[name] = node;
|
||||
}
|
||||
});
|
||||
}, true);
|
||||
|
||||
// Add decomposed endpoints as targets
|
||||
decEndpoints = decEndpoints || [];
|
||||
@@ -71,6 +78,12 @@ Project.prototype.install = function (decEndpoints, 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) {
|
||||
// Handle save and saveDev options
|
||||
if (that._options.save || that._options.saveDev) {
|
||||
@@ -80,6 +93,10 @@ Project.prototype.install = function (decEndpoints, options) {
|
||||
|
||||
jsonEndpoint = endpointParser.decomposed2json(decEndpoint);
|
||||
|
||||
if (that._options.saveExact) {
|
||||
jsonEndpoint[decEndpoint.name] = decEndpoint.pkgMeta.version;
|
||||
}
|
||||
|
||||
if (that._options.save) {
|
||||
that._json.dependencies = mout.object.mixIn(that._json.dependencies || {}, jsonEndpoint);
|
||||
}
|
||||
@@ -93,7 +110,9 @@ Project.prototype.install = function (decEndpoints, options) {
|
||||
// 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 () {
|
||||
@@ -174,11 +193,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;
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
@@ -462,7 +489,8 @@ Project.prototype._analyse = function () {
|
||||
var isSaved = jsonCopy.dependencies[key] || jsonCopy.devDependencies[key];
|
||||
|
||||
// The _direct propery is saved by the manager when .newly is specified
|
||||
if (!isSaved && pkgMeta._direct) {
|
||||
// It may happen pkgMeta is undefined if package is uninstalled
|
||||
if (!isSaved && pkgMeta && pkgMeta._direct) {
|
||||
decEndpoint.extraneous = true;
|
||||
|
||||
if (decEndpoint.linked) {
|
||||
@@ -521,9 +549,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 () {
|
||||
@@ -728,7 +754,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
|
||||
@@ -738,10 +764,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) {
|
||||
@@ -788,15 +815,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);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
var util = require('util');
|
||||
var path = require('path');
|
||||
var mout = require('mout');
|
||||
var Q = require('q');
|
||||
var GitRemoteResolver = require('./GitRemoteResolver');
|
||||
var download = require('../../util/download');
|
||||
var extract = require('../../util/extract');
|
||||
@@ -35,6 +36,11 @@ 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 = function() {
|
||||
return Q.resolve(true);
|
||||
};
|
||||
}
|
||||
|
||||
util.inherits(GitHubResolver, GitRemoteResolver);
|
||||
|
||||
@@ -25,6 +25,11 @@ function GitRemoteResolver(decEndpoint, config, logger) {
|
||||
} else {
|
||||
this._host = url.parse(this._source).host;
|
||||
}
|
||||
|
||||
this._remote = url.parse(this._source);
|
||||
|
||||
// Verify whether the server supports shallow cloning
|
||||
this._shallowClone = this._supportsShallowCloning;
|
||||
}
|
||||
|
||||
util.inherits(GitRemoteResolver, GitResolver);
|
||||
@@ -112,34 +117,36 @@ GitRemoteResolver.prototype._fastClone = function (resolution) {
|
||||
branch = resolution.tag || resolution.branch;
|
||||
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)) {
|
||||
args.push('--depth', 1);
|
||||
}
|
||||
|
||||
return cmd('git', args, { cwd: this._tempDir })
|
||||
.spread(function (stdout, stderr) {
|
||||
// Only after 1.7.10 --branch accepts tags
|
||||
// Detect those cases and inform the user to update git otherwise it's
|
||||
// a lot slower than newer versions
|
||||
if (!/branch .+? not found/i.test(stderr)) {
|
||||
return;
|
||||
return this._shallowClone().then(function (shallowCloningSupported) {
|
||||
// If the host does not support shallow clones, we don't use --depth=1
|
||||
if (shallowCloningSupported && !GitRemoteResolver._noShallow.get(this._host)) {
|
||||
args.push('--depth', 1);
|
||||
}
|
||||
|
||||
that._logger.warn('old-git', 'It seems you are using an old version of git, it will be slower and propitious to errors!');
|
||||
return cmd('git', ['checkout', resolution.commit], { cwd: that._tempDir });
|
||||
}, function (err) {
|
||||
// Some git servers do not support shallow clones
|
||||
// When that happens, we mark this host and try again
|
||||
if (!GitRemoteResolver._noShallow.has(that._source) &&
|
||||
err.details &&
|
||||
/(rpc failed|shallow|--depth)/i.test(err.details)
|
||||
) {
|
||||
GitRemoteResolver._noShallow.set(that._host, true);
|
||||
return that._fastClone(resolution);
|
||||
}
|
||||
return cmd('git', args, { cwd: that._tempDir })
|
||||
.spread(function (stdout, stderr) {
|
||||
// Only after 1.7.10 --branch accepts tags
|
||||
// Detect those cases and inform the user to update git otherwise it's
|
||||
// a lot slower than newer versions
|
||||
if (!/branch .+? not found/i.test(stderr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw err;
|
||||
that._logger.warn('old-git', 'It seems you are using an old version of git, it will be slower and propitious to errors!');
|
||||
return cmd('git', ['checkout', resolution.commit], { cwd: that._tempDir });
|
||||
}, function (err) {
|
||||
// Some git servers do not support shallow clones
|
||||
// When that happens, we mark this host and try again
|
||||
if (!GitRemoteResolver._noShallow.has(that._source) &&
|
||||
err.details &&
|
||||
/(rpc failed|shallow|--depth)/i.test(err.details)
|
||||
) {
|
||||
GitRemoteResolver._noShallow.set(that._host, true);
|
||||
return that._fastClone(resolution);
|
||||
}
|
||||
|
||||
throw err;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@@ -157,6 +164,74 @@ GitRemoteResolver.prototype._suggestProxyWorkaround = function (err) {
|
||||
}
|
||||
};
|
||||
|
||||
// Verifies whether the server supports shallow cloning.
|
||||
// This is done according to the rules found in the following links:
|
||||
// * https://github.com/dimitri/el-get/pull/1921/files
|
||||
// * http://stackoverflow.com/questions/9270488/is-it-possible-to-detect-whether-a-http-git-remote-is-smart-or-dumb
|
||||
//
|
||||
// Summary of the rules:
|
||||
// * Protocols like ssh or git always support shallow cloning
|
||||
// * HTTP-based protocols can be verified by sending a HEAD or GET request to the URI (appended to the URL of the Git repo):
|
||||
// /info/refs?service=git-upload-pack
|
||||
// * If the server responds with a 'Content-Type' header of 'application/x-git-upload-pack-advertisement',
|
||||
// the server supports shallow cloning ("smart server")
|
||||
// * If the server responds with a different content type, the server does not support shallow cloning ("dumb server")
|
||||
// * Instead of doing the HEAD or GET request using an HTTP client, we're letting Git and Curl do the heavy lifting.
|
||||
// Calling Git with the GIT_CURL_VERBOSE=2 env variable will provide the Git and Curl output, which includes
|
||||
// the content type. This has the advantage that Git will take care of using stored credentials and any additional
|
||||
// negotiation that needs to take place.
|
||||
//
|
||||
// The above should cover most cases, including BitBucket.
|
||||
GitRemoteResolver.prototype._supportsShallowCloning = function () {
|
||||
var value = true;
|
||||
|
||||
// Verify that the remote could be parsed and that a protocol is set
|
||||
// This case is unlikely, but let's still cover it.
|
||||
if (this._remote == null || this._remote.protocol == null) {
|
||||
return Q.resolve(false);
|
||||
}
|
||||
|
||||
// Check for protocol - the remote check for hosts supporting shallow cloning is only required for
|
||||
// HTTP or HTTPS, not for Git or SSH.
|
||||
// Also check for hosts that have been checked in a previous request and have been found to support
|
||||
// shallow cloning.
|
||||
if (mout.string.startsWith(this._remote.protocol, 'http')
|
||||
&& !GitRemoteResolver._canShallow.get(this._host)) {
|
||||
// Provide GIT_CURL_VERBOSE=2 environment variable to capture curl output.
|
||||
// Calling ls-remote includes a call to the git-upload-pack service, which returns the content type in the response.
|
||||
var processEnv = mout.object.merge(process.env, { 'GIT_CURL_VERBOSE': 2 });
|
||||
|
||||
value = cmd('git', ['ls-remote', '--heads', this._source], {
|
||||
env: processEnv
|
||||
})
|
||||
.spread(function (stdout, stderr) {
|
||||
// Check stderr for content-type, ignore stdout
|
||||
var isSmartServer;
|
||||
|
||||
// If the content type is 'x-git', then the server supports shallow cloning
|
||||
isSmartServer = mout.string.contains(stderr,
|
||||
'Content-Type: application/x-git-upload-pack-advertisement');
|
||||
|
||||
this._logger.debug('detect-smart-git', 'Smart Git host detected: ' + isSmartServer);
|
||||
|
||||
if (isSmartServer) {
|
||||
// Cache this host
|
||||
GitRemoteResolver._canShallow.set(this._host, true);
|
||||
}
|
||||
|
||||
return isSmartServer;
|
||||
}.bind(this));
|
||||
}
|
||||
else {
|
||||
// One of the following cases:
|
||||
// * A non-HTTP/HTTPS protocol
|
||||
// * A host that has been checked before and that supports shallow cloning
|
||||
return Q.resolve(true);
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
// ------------------------------
|
||||
|
||||
// Grab refs remotely
|
||||
@@ -195,4 +270,7 @@ GitRemoteResolver.refs = function (source) {
|
||||
// Store hosts that do not support shallow clones here
|
||||
GitRemoteResolver._noShallow = new LRU({ max: 50, maxAge: 5 * 60 * 1000 });
|
||||
|
||||
// Store hosts that support shallow clones here
|
||||
GitRemoteResolver._canShallow = new LRU({ max: 50, maxAge: 5 * 60 * 1000 });
|
||||
|
||||
module.exports = GitRemoteResolver;
|
||||
|
||||
@@ -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) {
|
||||
@@ -165,6 +164,18 @@ GitResolver.prototype._findResolution = function (target) {
|
||||
return that._resolution = { type: 'branch', branch: target, commit: branches[target] };
|
||||
}
|
||||
|
||||
if ((/^[a-f0-9]{4,40}$/).test(target)) {
|
||||
if (target.length < 12) {
|
||||
that._logger.warn(
|
||||
'short-sha',
|
||||
'Consider using longer commit SHA to avoid conflicts'
|
||||
);
|
||||
}
|
||||
|
||||
that._resolution = { type: 'commit', commit: target };
|
||||
return that._resolution;
|
||||
}
|
||||
|
||||
branches = Object.keys(branches);
|
||||
tags = Object.keys(tags);
|
||||
|
||||
|
||||
@@ -114,6 +114,26 @@ Resolver.prototype.resolve = function () {
|
||||
});
|
||||
};
|
||||
|
||||
Resolver.prototype.isCacheable = function () {
|
||||
// Bypass cache for local dependencies
|
||||
if (this._source &&
|
||||
/^(?:file:[\/\\]{2}|[A-Z]:)?\.?\.?[\/\\]/.test(this._source)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We don't want to cache moving targets like branches
|
||||
if (this._pkgMeta &&
|
||||
this._pkgMeta._resolution &&
|
||||
this._pkgMeta._resolution.type === 'branch')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
// -----------------
|
||||
|
||||
// Abstract functions that must be implemented by concrete resolvers
|
||||
@@ -149,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));
|
||||
};
|
||||
|
||||
@@ -201,26 +221,36 @@ Resolver.prototype._applyPkgMeta = function (meta) {
|
||||
}
|
||||
|
||||
// Otherwise remove them from the temp dir
|
||||
return removeIgnores(this._tempDir, meta.ignore)
|
||||
return removeIgnores(this._tempDir, meta)
|
||||
.then(function () {
|
||||
return meta;
|
||||
});
|
||||
};
|
||||
|
||||
Resolver.prototype._savePkgMeta = function (meta) {
|
||||
var that = this;
|
||||
var contents;
|
||||
|
||||
// Store original source & target
|
||||
meta._source = this._source;
|
||||
meta._target = this._target;
|
||||
|
||||
['main', 'ignore'].forEach(function (attr) {
|
||||
if (meta[attr]) return;
|
||||
|
||||
that._logger.log(
|
||||
'warn', 'invalid-meta',
|
||||
(meta.name || 'component') + ' is missing "' + attr + '" entry in bower.json'
|
||||
);
|
||||
});
|
||||
|
||||
// Stringify contents
|
||||
contents = JSON.stringify(meta, null, 2);
|
||||
|
||||
return Q.nfcall(fs.writeFile, path.join(this._tempDir, '.bower.json'), contents)
|
||||
.then(function () {
|
||||
return this._pkgMeta = meta;
|
||||
}.bind(this));
|
||||
return that._pkgMeta = meta;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = Resolver;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
var util = require('util');
|
||||
var path = require('path');
|
||||
var Q = require('q');
|
||||
var rimraf = require('rimraf');
|
||||
var which = require('which');
|
||||
var LRU = require('lru-cache');
|
||||
var mout = require('mout');
|
||||
@@ -67,19 +65,13 @@ SvnResolver.prototype._resolve = function () {
|
||||
|
||||
return this._findResolution()
|
||||
.then(function () {
|
||||
return that._checkout()
|
||||
// Always run cleanup after checkout to ensure that .svn is removed!
|
||||
// If it's not removed, problems might arise when the "tmp" module attempts
|
||||
// to delete the temporary folder
|
||||
.fin(function () {
|
||||
return that._cleanup();
|
||||
});
|
||||
return that._export();
|
||||
});
|
||||
};
|
||||
|
||||
// -----------------
|
||||
|
||||
SvnResolver.prototype._checkout = function () {
|
||||
SvnResolver.prototype._export = function () {
|
||||
var promise;
|
||||
var timer;
|
||||
var reporter;
|
||||
@@ -88,19 +80,19 @@ SvnResolver.prototype._checkout = function () {
|
||||
|
||||
this.source = SvnResolver.getSource(this._source);
|
||||
|
||||
this._logger.action('checkout', resolution.tag || resolution.branch || resolution.commit, {
|
||||
this._logger.action('export', resolution.tag || resolution.branch || resolution.commit, {
|
||||
resolution: resolution,
|
||||
to: this._tempDir
|
||||
});
|
||||
|
||||
if (resolution.type === 'commit') {
|
||||
promise = cmd('svn', ['checkout', this._source + '/trunk', '-r' + resolution.commit, this._tempDir]);
|
||||
promise = cmd('svn', ['export', '--force', this._source + '/trunk', '-r' + resolution.commit, this._tempDir]);
|
||||
} else if (resolution.type === 'branch' && resolution.branch === 'trunk') {
|
||||
promise = cmd('svn', ['checkout', this._source + '/trunk', this._tempDir]);
|
||||
promise = cmd('svn', ['export', '--force', this._source + '/trunk', this._tempDir]);
|
||||
} else if (resolution.type === 'branch') {
|
||||
promise = cmd('svn', ['checkout', this._source + '/branches/' + resolution.branch, this._tempDir]);
|
||||
promise = cmd('svn', ['export', '--force', this._source + '/branches/' + resolution.branch, this._tempDir]);
|
||||
} else {
|
||||
promise = cmd('svn', ['checkout', this._source + '/tags/' + resolution.tag, this._tempDir]);
|
||||
promise = cmd('svn', ['export', '--force', this._source + '/tags/' + resolution.tag, this._tempDir]);
|
||||
}
|
||||
|
||||
// Throttle the progress reporter to 1 time each sec
|
||||
@@ -232,12 +224,6 @@ SvnResolver.prototype._findResolution = function (target) {
|
||||
});
|
||||
};
|
||||
|
||||
SvnResolver.prototype._cleanup = function () {
|
||||
var svnFolder = path.join(this._tempDir, '.svn');
|
||||
|
||||
return Q.nfcall(rimraf, svnFolder);
|
||||
};
|
||||
|
||||
SvnResolver.prototype._savePkgMeta = function (meta) {
|
||||
var version;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
var cardinal = require('cardinal');
|
||||
var chalk = require('chalk');
|
||||
var path = require('path');
|
||||
var mout = require('mout');
|
||||
var archy = require('archy');
|
||||
var Q = require('q');
|
||||
var inquirer = require('inquirer');
|
||||
var stringifyObject = require('stringify-object');
|
||||
var os = require('os');
|
||||
var pkg = require(path.join(__dirname, '../..', 'package.json'));
|
||||
@@ -25,13 +23,23 @@ function StandardRenderer(command, config) {
|
||||
};
|
||||
|
||||
this._command = command;
|
||||
this._config = config;
|
||||
this._config = config || {};
|
||||
|
||||
if (this.constructor._wideCommands.indexOf(command) === -1) {
|
||||
this._compact = true;
|
||||
} 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) {
|
||||
@@ -71,7 +79,7 @@ StandardRenderer.prototype.error = function (err) {
|
||||
/*jshint camelcase:true*/
|
||||
|
||||
this._write(process.stderr, str);
|
||||
console.trace();
|
||||
this._write(process.stderr, new Error().stack);
|
||||
|
||||
// Print bower version, node version and system info.
|
||||
this._write(process.stderr, chalk.yellow('\nSystem info:\n'));
|
||||
@@ -106,16 +114,12 @@ StandardRenderer.prototype.prompt = function (prompts) {
|
||||
|
||||
// Prompt
|
||||
deferred = Q.defer();
|
||||
var inquirer = require('inquirer');
|
||||
inquirer.prompt(prompts, deferred.resolve);
|
||||
|
||||
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) {
|
||||
@@ -171,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) {
|
||||
@@ -394,6 +402,8 @@ StandardRenderer.prototype._write = function (stream, str) {
|
||||
};
|
||||
|
||||
StandardRenderer.prototype._highlightJson = function (json) {
|
||||
var cardinal = require('cardinal');
|
||||
|
||||
return cardinal.highlight(stringifyObject(json, { indent: ' ' }), {
|
||||
theme: {
|
||||
String: {
|
||||
|
||||
@@ -1,43 +1,95 @@
|
||||
var Q = require('q');
|
||||
var Insight = require('insight');
|
||||
var mout = require('mout');
|
||||
var config = require('../config');
|
||||
var pkg = require('../../package.json');
|
||||
|
||||
var analytics = module.exports;
|
||||
|
||||
var insight;
|
||||
|
||||
var enableAnalytics = false;
|
||||
|
||||
// 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');
|
||||
insight = new Insight({
|
||||
trackingCode: 'UA-43531210-1',
|
||||
pkg: require('../../package.json')
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Initializes the application-wide insight singleton and asks for the
|
||||
// permission on the CLI during the first run.
|
||||
analytics.setup = function setup() {
|
||||
//
|
||||
// This method is called only from bin/bower. Programmatic API skips it.
|
||||
analytics.setup = function setup (config) {
|
||||
var deferred = Q.defer();
|
||||
insight = new Insight({
|
||||
trackingCode: 'UA-43531210-1',
|
||||
packageName: pkg.name,
|
||||
packageVersion: pkg.version
|
||||
});
|
||||
|
||||
// Display the ask prompt only if it hasn't been answered before
|
||||
// and the current session is looking to configure the analytics.
|
||||
if (insight.optOut === undefined && config.analytics) {
|
||||
insight.askPermission(null, deferred.resolve);
|
||||
// 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 {
|
||||
// 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;
|
||||
@@ -96,7 +99,7 @@ function executeCmd(command, args, options) {
|
||||
fullCommand += args.length ? ' ' + args.join(' ') : '';
|
||||
|
||||
// Build the error instance
|
||||
error = createError('Failed to execute "' + fullCommand + '", exit code of #' + code, 'ECMDERR', {
|
||||
error = createError('Failed to execute "' + fullCommand + '", exit code of #' + code + '\n' + stderr, 'ECMDERR', {
|
||||
details: stderr,
|
||||
exitCode: code
|
||||
});
|
||||
|
||||
@@ -6,9 +6,7 @@ var createError = require('./createError');
|
||||
|
||||
var isWin = process.platform === 'win32';
|
||||
|
||||
function createLink(src, dst, options) {
|
||||
options = options || {};
|
||||
|
||||
function createLink(src, dst, type) {
|
||||
var dstDir = path.dirname(dst);
|
||||
|
||||
// Create directory
|
||||
@@ -28,12 +26,7 @@ function createLink(src, dst, options) {
|
||||
})
|
||||
// Create symlink
|
||||
.then(function (stat) {
|
||||
var type = options.type || (stat.isDirectory() ? 'dir' : 'file');
|
||||
if (options.relative && !isWin) {
|
||||
src = path.relative(path.dirname(dst), src);
|
||||
} else {
|
||||
src = path.resolve(src);
|
||||
}
|
||||
type = type || (stat.isDirectory() ? 'dir' : 'file');
|
||||
|
||||
return Q.nfcall(fs.symlink, src, dst, type)
|
||||
.fail(function (err) {
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
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,13 @@ 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
|
||||
dmode: 0555, // Ensure dirs are readable
|
||||
fmode: 0444 // Ensure files are readable
|
||||
}))
|
||||
.on('error', deferred.reject)
|
||||
.on('close', deferred.resolve.bind(deferred, dst));
|
||||
.on('finish', deferred.resolve.bind(deferred, dst));
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
@@ -68,13 +69,13 @@ 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
|
||||
dmode: 0555, // Ensure dirs are readable
|
||||
fmode: 0444 // Ensure files are readable
|
||||
}))
|
||||
.on('error', deferred.reject)
|
||||
.on('close', deferred.resolve.bind(deferred, dst));
|
||||
.on('finish', deferred.resolve.bind(deferred, dst));
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
@@ -93,6 +94,10 @@ function extractGz(archive, dst) {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function isSymlink(entry) {
|
||||
return entry.type === 'SymbolicLink';
|
||||
}
|
||||
|
||||
function filterSymlinks(entry) {
|
||||
return entry.type !== 'SymbolicLink';
|
||||
}
|
||||
|
||||
@@ -4,19 +4,26 @@ var fstreamIgnore = require('fstream-ignore');
|
||||
var mout = require('mout');
|
||||
var Q = require('q');
|
||||
|
||||
function removeIgnores(dir, ignore) {
|
||||
function removeIgnores(dir, meta) {
|
||||
var reader;
|
||||
var applyIgnores;
|
||||
var deferred = Q.defer();
|
||||
var ignored = [];
|
||||
var nonIgnored = [];
|
||||
var nonIgnored = ['bower.json'];
|
||||
|
||||
// Don't ignore main files
|
||||
nonIgnored = nonIgnored.concat(meta.main || []);
|
||||
|
||||
nonIgnored = nonIgnored.map(function (file) {
|
||||
return path.join(dir, file);
|
||||
});
|
||||
|
||||
reader = fstreamIgnore({
|
||||
path: dir,
|
||||
type: 'Directory'
|
||||
});
|
||||
|
||||
reader.addIgnoreRules(ignore);
|
||||
reader.addIgnoreRules(meta.ignore || []);
|
||||
|
||||
// Monkey patch applyIgnores such that we get hold of all ignored files
|
||||
applyIgnores = reader.applyIgnores;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
'use strict';
|
||||
var isRoot = require('is-root');
|
||||
var createError = require('./createError');
|
||||
var cli = require('./cli');
|
||||
|
||||
var renderer;
|
||||
|
||||
@@ -23,6 +22,7 @@ https://gist.github.com/isaacs/579814\n\n\
|
||||
You can however run a command with sudo using --allow-root option';
|
||||
|
||||
if (isRoot()) {
|
||||
var cli = require('./cli');
|
||||
renderer = cli.getRenderer('', false, config);
|
||||
renderer.error(createError('Cannot be run with sudo', 'ESUDO', { details : errorMsg }));
|
||||
process.exit(1);
|
||||
|
||||
121
package.json
121
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "bower",
|
||||
"version": "1.3.2",
|
||||
"description": "The browser package manager.",
|
||||
"version": "1.4.2",
|
||||
"description": "The browser package manager",
|
||||
"author": "Twitter",
|
||||
"licenses": [
|
||||
{
|
||||
@@ -9,70 +9,75 @@
|
||||
"url": "https://github.com/bower/bower/blob/master/LICENSE"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/bower/bower.git"
|
||||
},
|
||||
"repository": "bower/bower",
|
||||
"main": "lib",
|
||||
"homepage": "http://bower.io",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"abbrev": "~1.0.4",
|
||||
"archy": "0.0.2",
|
||||
"bower-config": "~0.5.0",
|
||||
"bower-endpoint-parser": "~0.2.0",
|
||||
"bower-json": "~0.4.0",
|
||||
"bower-logger": "~0.2.2",
|
||||
"bower-registry-client": "~0.1.4",
|
||||
"cardinal": "~0.4.0",
|
||||
"chalk": "~0.4.0",
|
||||
"chmodr": "~0.1.0",
|
||||
"decompress-zip": "~0.0.3",
|
||||
"fstream": "~0.1.22",
|
||||
"fstream-ignore": "~0.0.6",
|
||||
"glob": "~3.2.9",
|
||||
"graceful-fs": "~2.0.0",
|
||||
"handlebars": "~1.3.0",
|
||||
"inquirer": "~0.4.0",
|
||||
"junk": "~0.2.2",
|
||||
"mkdirp": "~0.3.5",
|
||||
"mout": "~0.9.1",
|
||||
"nopt": "~2.1.2",
|
||||
"lru-cache": "~2.5.0",
|
||||
"open": "~0.0.3",
|
||||
"osenv": "~0.0.3",
|
||||
"promptly": "~0.2.0",
|
||||
"q": "~1.0.1",
|
||||
"request": "~2.33.0",
|
||||
"request-progress": "~0.3.0",
|
||||
"retry": "~0.6.0",
|
||||
"rimraf": "~2.2.0",
|
||||
"semver": "~2.2.1",
|
||||
"stringify-object": "~0.2.0",
|
||||
"tar": "~0.1.17",
|
||||
"tmp": "~0.0.20",
|
||||
"update-notifier": "~0.1.3",
|
||||
"which": "~1.0.5",
|
||||
"p-throttler": "~0.0.1",
|
||||
"insight": "~0.3.0",
|
||||
"is-root": "~0.1.0",
|
||||
"shell-quote": "~1.4.1",
|
||||
"lockfile": "~0.4.2"
|
||||
"abbrev": "^1.0.5",
|
||||
"archy": "1.0.0",
|
||||
"bower-config": "^0.6.1",
|
||||
"bower-endpoint-parser": "^0.2.2",
|
||||
"bower-json": "^0.4.0",
|
||||
"bower-logger": "^0.2.2",
|
||||
"bower-registry-client": "^0.3.0",
|
||||
"cardinal": "0.4.4",
|
||||
"chalk": "^1.0.0",
|
||||
"chmodr": "0.1.0",
|
||||
"configstore": "^0.3.2",
|
||||
"decompress-zip": "^0.1.0",
|
||||
"fstream": "^1.0.3",
|
||||
"fstream-ignore": "^1.0.2",
|
||||
"github": "^0.2.3",
|
||||
"glob": "^4.3.2",
|
||||
"graceful-fs": "^3.0.5",
|
||||
"handlebars": "^2.0.0",
|
||||
"inquirer": "0.8.0",
|
||||
"insight": "^0.5.0",
|
||||
"is-root": "^1.0.0",
|
||||
"junk": "^1.0.0",
|
||||
"lockfile": "^1.0.0",
|
||||
"lru-cache": "2.7.0",
|
||||
"mkdirp": "0.5.0",
|
||||
"mout": "^0.11.0",
|
||||
"nopt": "^3.0.1",
|
||||
"opn": "^1.0.1",
|
||||
"p-throttler": "0.1.1",
|
||||
"promptly": "0.2.0",
|
||||
"q": "^1.1.2",
|
||||
"request": "2.53.0",
|
||||
"request-progress": "0.3.1",
|
||||
"retry": "0.6.1",
|
||||
"rimraf": "^2.2.8",
|
||||
"semver": "^2.3.0",
|
||||
"shell-quote": "^1.4.2",
|
||||
"stringify-object": "^1.0.0",
|
||||
"tar-fs": "^1.4.1",
|
||||
"tmp": "0.0.24",
|
||||
"update-notifier": "^0.3.0",
|
||||
"user-home": "^1.1.0",
|
||||
"which": "^1.0.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"expect.js": "~0.2.0",
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-simple-mocha": "~0.4.0",
|
||||
"grunt-contrib-watch": "~0.5.3",
|
||||
"grunt-contrib-jshint": "~0.8.0",
|
||||
"grunt-exec": "~0.4.2",
|
||||
"mocha": "~1.18",
|
||||
"nock": "~0.27.2",
|
||||
"istanbul": "~0.2.4",
|
||||
"proxyquire": "~0.5.3",
|
||||
"load-grunt-tasks": "~0.3.0"
|
||||
"chai": "^1.10.0",
|
||||
"coveralls": "^2.11.2",
|
||||
"expect.js": "^0.3.1",
|
||||
"grunt": "^0.4.5",
|
||||
"grunt-cli": "^0.1.13",
|
||||
"grunt-contrib-jshint": "^0.10.0",
|
||||
"grunt-contrib-watch": "^0.6.1",
|
||||
"grunt-exec": "^0.4.6",
|
||||
"grunt-simple-mocha": "^0.4.0",
|
||||
"istanbul": "^0.3.5",
|
||||
"load-grunt-tasks": "^2.0.0",
|
||||
"mocha": "^2.1.0",
|
||||
"multiline": "^1.0.2",
|
||||
"nock": "^0.56.0",
|
||||
"node-uuid": "^1.4.2",
|
||||
"proxyquire": "^1.3.0",
|
||||
"spawn-sync": "^1.0.5"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "grunt test"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"command": "cache list",
|
||||
"command": "cache clean",
|
||||
"description": "Cleans cached packages.",
|
||||
"usage": [
|
||||
"cache clean [<options>]",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"command": "cache clean",
|
||||
"command": "cache list",
|
||||
"description": "Lists cached packages.",
|
||||
"usage": [
|
||||
"cache list [<options>]",
|
||||
|
||||
@@ -30,6 +30,11 @@
|
||||
"shorthand": "-D",
|
||||
"flag": "--save-dev",
|
||||
"description": "Save installed packages into the project's bower.json devDependencies"
|
||||
},
|
||||
{
|
||||
"shorthand": "-E",
|
||||
"flag": "--save-exact",
|
||||
"description": "Configure installed packages with an exact version rather than semver"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
19
templates/json/help-login.json
Normal file
19
templates/json/help-login.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"command": "login",
|
||||
"description": "Authenticate with GitHub and store credentials to be used later.",
|
||||
"usage": [
|
||||
"login [<options>]"
|
||||
],
|
||||
"options": [
|
||||
{
|
||||
"shorthand": "-h",
|
||||
"flag": "--help",
|
||||
"description": "Show this help message"
|
||||
},
|
||||
{
|
||||
"shorthand": "-t",
|
||||
"flag": "--token",
|
||||
"description": "Pass an existing GitHub auth token rather than prompting for username and password."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
14
templates/json/help-unregister.json
Normal file
14
templates/json/help-unregister.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"command": "unregister",
|
||||
"description": "Unregisters a package.",
|
||||
"usage": [
|
||||
"unregister <name> [<options>]"
|
||||
],
|
||||
"options": [
|
||||
{
|
||||
"shorthand": "-h",
|
||||
"flag": "--help",
|
||||
"description": "Show this help message"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -10,13 +10,15 @@
|
||||
"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",
|
||||
"login": "Authenticate with GitHub and store credentials",
|
||||
"lookup": "Look up a package URL by name",
|
||||
"prune": "Removes local extraneous packages",
|
||||
"register": "Register a package",
|
||||
"search": "Search for a package by name",
|
||||
"update": "Update a local package",
|
||||
"uninstall": "Remove a local package",
|
||||
"unregister": "Remove a package from the registry",
|
||||
"version": "Bump a package version"
|
||||
},
|
||||
"options": [
|
||||
@@ -58,6 +60,14 @@
|
||||
{
|
||||
"flag": "--allow-root",
|
||||
"description": "Allows running commands as root"
|
||||
},
|
||||
{
|
||||
"flag": "--version",
|
||||
"description": "Output Bower version"
|
||||
},
|
||||
{
|
||||
"flag": "--no-color",
|
||||
"description": "Disable colors"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{{#yellow}}Please note that,{{/yellow}}
|
||||
{{#condense}}
|
||||
{{#each picks}}
|
||||
{{#if dependants}}{{#white}}{{dependants}}{{/white}}{{else}}none{{/if}} depends on {{#cyan}}{{endpoint.name}}#{{endpoint.target}}{{/cyan}}{{#if pkgMeta._release}} which resolved to {{#white}}{{endpoint.name}}#{{pkgMeta._release}}{{/white}}{{/if}}
|
||||
{{#if dependants}}{{#green}}{{dependants}}{{/green}}{{else}}none{{/if}} depends on {{#cyan}}{{endpoint.name}}#{{endpoint.target}}{{/cyan}}{{#if pkgMeta._release}} which resolved to {{#green}}{{endpoint.name}}#{{pkgMeta._release}}{{/green}}{{/if}}
|
||||
{{/each}}
|
||||
{{/condense}}
|
||||
|
||||
Resort to using {{#cyan}}{{suitable.endpoint.name}}#{{resolution}}{{/cyan}} which resolved to {{#white}}{{suitable.endpoint.name}}#{{suitable.pkgMeta._release}}{{/white}}
|
||||
Resort to using {{#cyan}}{{suitable.endpoint.name}}#{{resolution}}{{/cyan}} which resolved to {{#green}}{{suitable.endpoint.name}}#{{suitable.pkgMeta._release}}{{/green}}
|
||||
Code incompatibilities may occur.
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
{{#yellow}}Unable to find a suitable version for {{name}}, please choose one:{{/yellow}}
|
||||
{{#condense}}
|
||||
{{#each picks}}
|
||||
{{#magenta}}{{sum @index 1}}){{/magenta}} {{#cyan}}{{endpoint.name}}#{{endpoint.target}}{{/cyan}}{{#if pkgMeta._release}} which resolved to {{#white}}{{pkgMeta._release}}{{/white}}{{/if}}{{#if dependants}} and is required by {{#white}}{{dependants}}{{/white}} {{/if}}
|
||||
{{#magenta}}{{sum @index 1}}){{/magenta}} {{#cyan}}{{endpoint.name}}#{{endpoint.target}}{{/cyan}}{{#if pkgMeta._release}} which resolved to {{#green}}{{pkgMeta._release}}{{/green}}{{/if}}{{#if dependants}} and is required by {{#green}}{{dependants}}{{/green}}{{/if}}
|
||||
{{/each}}
|
||||
{{/condense}}
|
||||
|
||||
{{#unless saveResolutions}}
|
||||
|
||||
Prefix the choice with ! to persist it to bower.json
|
||||
{{/unless}}
|
||||
{{/unless}}
|
||||
|
||||
@@ -14,3 +14,4 @@ Commands:
|
||||
{{#rpad length="23"}}{{@key}}{{/rpad}} {{.}}
|
||||
{{/each}}
|
||||
{{/condense}}
|
||||
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -1,51 +1,51 @@
|
||||
[
|
||||
{
|
||||
"canonicalDir": "/test/assets/temp-resolve-cache/3668e6529b32a6d3e8931a68474e909d/0.2.0",
|
||||
"canonicalDir": "/test/tmp/temp-resolve-cache/3668e6529b32a6d3e8931a68474e909d/0.2.0",
|
||||
"pkgMeta": {
|
||||
"name": "abc",
|
||||
"version": "0.2.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"canonicalDir": "/test/assets/temp-resolve-cache/77008abea14f06f199c2f481362b48d9/0.0.1",
|
||||
"canonicalDir": "/test/tmp/temp-resolve-cache/77008abea14f06f199c2f481362b48d9/0.0.1",
|
||||
"pkgMeta": {
|
||||
"name": "foo",
|
||||
"version": "0.0.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"canonicalDir": "/test/assets/temp-resolve-cache/77008abea14f06f199c2f481362b48d9/0.1.0",
|
||||
"canonicalDir": "/test/tmp/temp-resolve-cache/77008abea14f06f199c2f481362b48d9/0.1.0",
|
||||
"pkgMeta": {
|
||||
"name": "foo",
|
||||
"version": "0.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"canonicalDir": "/test/assets/temp-resolve-cache/3668e6529b32a6d3e8931a68474e909d/0.2.1",
|
||||
"canonicalDir": "/test/tmp/temp-resolve-cache/3668e6529b32a6d3e8931a68474e909d/0.2.1",
|
||||
"pkgMeta": {
|
||||
"name": "foo",
|
||||
"version": "0.2.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"canonicalDir": "/test/assets/temp-resolve-cache/77008abea14f06f199c2f481362b48d9/aa",
|
||||
"canonicalDir": "/test/tmp/temp-resolve-cache/77008abea14f06f199c2f481362b48d9/aa",
|
||||
"pkgMeta": {
|
||||
"name": "foo",
|
||||
"_target": "aa"
|
||||
}
|
||||
},
|
||||
{
|
||||
"canonicalDir": "/test/assets/temp-resolve-cache/77008abea14f06f199c2f481362b48d9/bar",
|
||||
"canonicalDir": "/test/tmp/temp-resolve-cache/77008abea14f06f199c2f481362b48d9/bar",
|
||||
"pkgMeta": {
|
||||
"name": "foo",
|
||||
"_target": "bar"
|
||||
}
|
||||
},
|
||||
{
|
||||
"canonicalDir": "/test/assets/temp-resolve-cache/77008abea14f06f199c2f481362b48d9/foo",
|
||||
"canonicalDir": "/test/tmp/temp-resolve-cache/77008abea14f06f199c2f481362b48d9/foo",
|
||||
"pkgMeta": {
|
||||
"name": "foo",
|
||||
"_target": "foo"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@@ -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
|
||||
|
||||
31
test/commands/bower.js
Normal file
31
test/commands/bower.js
Normal file
@@ -0,0 +1,31 @@
|
||||
var expect = require('expect.js');
|
||||
var helpers = require('../helpers');
|
||||
|
||||
describe('bower', function () {
|
||||
|
||||
var oldStdout;
|
||||
var text;
|
||||
|
||||
before(function() {
|
||||
oldStdout = process.stdout.write;
|
||||
text = '';
|
||||
|
||||
process.stdout.write = function(args) {
|
||||
text += args;
|
||||
};
|
||||
});
|
||||
|
||||
it('runs bower installation', function (done) {
|
||||
helpers.require('bin/bower');
|
||||
|
||||
setTimeout(function() {
|
||||
done();
|
||||
}, 250);
|
||||
});
|
||||
|
||||
after(function() {
|
||||
process.stdout.write = oldStdout;
|
||||
expect(text).to.contain('Usage:');
|
||||
expect(text).to.contain('Commands:');
|
||||
});
|
||||
});
|
||||
89
test/commands/cache/clean.js
vendored
Normal file
89
test/commands/cache/clean.js
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
var expect = require('expect.js');
|
||||
var helpers = require('../../helpers');
|
||||
|
||||
var cacheClean = helpers.command('cache/clean');
|
||||
var md5 = helpers.require('lib/util/md5');
|
||||
var object = require('mout/object');
|
||||
|
||||
describe('bower cache clean', function () {
|
||||
|
||||
// Because directory names are required to be mp5 of _source
|
||||
var cacheFilesFactory = function (spec) {
|
||||
var files = {};
|
||||
|
||||
object.map(spec, function(bowerJson) {
|
||||
bowerJson._source = bowerJson.name + '/' + bowerJson.version;
|
||||
var path = md5(bowerJson._source) + '/' + bowerJson.version + '/.bower.json';
|
||||
files[path] = bowerJson;
|
||||
});
|
||||
|
||||
return files;
|
||||
};
|
||||
|
||||
|
||||
var cacheFiles = cacheFilesFactory([
|
||||
{
|
||||
name: 'angular',
|
||||
version: '1.3.8'
|
||||
},
|
||||
{
|
||||
name: 'angular',
|
||||
version: '1.3.9'
|
||||
},
|
||||
{
|
||||
name: 'jquery',
|
||||
version: '1.0.0'
|
||||
}
|
||||
]);
|
||||
|
||||
var cacheDir = new helpers.TempDir(cacheFiles);
|
||||
|
||||
it('correctly reads arguments', function() {
|
||||
expect(cacheClean.readOptions(['jquery', 'angular']))
|
||||
.to.eql([['jquery', 'angular'], {}]);
|
||||
});
|
||||
|
||||
it('removes all cache', function () {
|
||||
cacheDir.prepare();
|
||||
|
||||
return helpers.run(cacheClean, [undefined, {}, {
|
||||
storage: {
|
||||
packages: cacheDir.path
|
||||
}
|
||||
}]).spread(function(result) {
|
||||
object.map(cacheFiles, function (_, cacheFile) {
|
||||
expect(cacheDir.exists(cacheFile)).to.be(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('removes single package', function () {
|
||||
cacheDir.prepare();
|
||||
|
||||
return helpers.run(cacheClean, [['angular'], {}, {
|
||||
storage: {
|
||||
packages: cacheDir.path
|
||||
}
|
||||
}]).spread(function(result) {
|
||||
var paths = Object.keys(cacheFiles);
|
||||
expect(cacheDir.exists(paths[0])).to.be(false);
|
||||
expect(cacheDir.exists(paths[1])).to.be(false);
|
||||
expect(cacheDir.exists(paths[2])).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('removes single package package version', function () {
|
||||
cacheDir.prepare();
|
||||
|
||||
return helpers.run(cacheClean, [['angular#1.3.8'], {}, {
|
||||
storage: {
|
||||
packages: cacheDir.path
|
||||
}
|
||||
}]).spread(function(result) {
|
||||
var paths = Object.keys(cacheFiles);
|
||||
expect(cacheDir.exists(paths[0])).to.be(false);
|
||||
expect(cacheDir.exists(paths[1])).to.be(true);
|
||||
expect(cacheDir.exists(paths[2])).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
60
test/commands/cache/list.js
vendored
Normal file
60
test/commands/cache/list.js
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
var expect = require('expect.js');
|
||||
var helpers = require('../../helpers');
|
||||
|
||||
var cacheList = helpers.command('cache/list');
|
||||
|
||||
describe('bower cache list', function () {
|
||||
|
||||
var cacheDir = new helpers.TempDir({
|
||||
'87323d6d4e48be291a9616a033d4cc6c/1.3.8/.bower.json': {
|
||||
name: 'angular',
|
||||
version: '1.3.8'
|
||||
},
|
||||
'87323d6d4e48be291a9616a033d4cc6c/1.3.9/.bower.json': {
|
||||
name: 'angular',
|
||||
version: '1.3.9'
|
||||
},
|
||||
'9eaed103d6a7e78d91f673cfad796850/1.0.0/.bower.json': {
|
||||
name: 'jquery',
|
||||
version: '1.0.0'
|
||||
}
|
||||
});
|
||||
|
||||
it('correctly reads arguments', function() {
|
||||
expect(cacheList.readOptions(['jquery', 'angular']))
|
||||
.to.eql([['jquery', 'angular'], {}]);
|
||||
});
|
||||
|
||||
it('lists packages from cache', function () {
|
||||
cacheDir.prepare();
|
||||
|
||||
return helpers.run(cacheList, [undefined, {}, {
|
||||
storage: {
|
||||
packages: cacheDir.path
|
||||
}
|
||||
}]).spread(function(result) {
|
||||
expect(result[0].canonicalDir)
|
||||
.to.be(cacheDir.getPath('87323d6d4e48be291a9616a033d4cc6c/1.3.8'));
|
||||
expect(result[0].pkgMeta.version).to.be('1.3.8');
|
||||
expect(result[1].pkgMeta.version).to.be('1.3.9');
|
||||
expect(result[2].pkgMeta.version).to.be('1.0.0');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('lists selected package names', function () {
|
||||
cacheDir.prepare();
|
||||
|
||||
return helpers.run(cacheList, [['angular'], {}, {
|
||||
storage: {
|
||||
packages: cacheDir.path
|
||||
}
|
||||
}]).spread(function(result) {
|
||||
expect(result[0].canonicalDir)
|
||||
.to.be(cacheDir.getPath('87323d6d4e48be291a9616a033d4cc6c/1.3.8'));
|
||||
expect(result[0].pkgMeta.version).to.be('1.3.8');
|
||||
expect(result[1].pkgMeta.version).to.be('1.3.9');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
43
test/commands/help.js
Normal file
43
test/commands/help.js
Normal file
@@ -0,0 +1,43 @@
|
||||
var expect = require('expect.js');
|
||||
var helpers = require('../helpers');
|
||||
var help = helpers.command('help');
|
||||
|
||||
describe('bower help', function () {
|
||||
|
||||
it('correctly reads arguments', function() {
|
||||
expect(help.readOptions(['foo'])).to.eql(['foo']);
|
||||
});
|
||||
|
||||
it('shows general help', function () {
|
||||
return helpers.run(help).spread(function(result) {
|
||||
expect(result.usage[0]).to.be.a('string');
|
||||
expect(result.commands).to.be.a('object');
|
||||
expect(result.options).to.be.a('object');
|
||||
});
|
||||
});
|
||||
|
||||
var commands = [
|
||||
'home', 'info', 'init', 'install',
|
||||
'link', 'list', 'lookup', 'prune', 'register',
|
||||
'search', 'update', 'uninstall', 'version',
|
||||
'cache list', 'cache clean'
|
||||
];
|
||||
|
||||
commands.forEach(function(command) {
|
||||
it('shows help for ' + command + ' command', function() {
|
||||
return helpers.run(help, [command]).spread(function(result) {
|
||||
expect(result.command).to.be(command);
|
||||
expect(result.description).to.be.a('string');
|
||||
expect(result.usage[0]).to.be.a('string');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('displays error for non-existing command', function() {
|
||||
return helpers.run(help, ['fuu']).fail(function(e) {
|
||||
expect(e.message).to.be('Unknown command: fuu');
|
||||
expect(e.command).to.be('fuu');
|
||||
expect(e.code).to.be('EUNKNOWNCMD');
|
||||
});
|
||||
});
|
||||
});
|
||||
59
test/commands/home.js
Normal file
59
test/commands/home.js
Normal file
@@ -0,0 +1,59 @@
|
||||
var Q = require('q');
|
||||
var expect = require('expect.js');
|
||||
var helpers = require('../helpers');
|
||||
|
||||
var home = helpers.command('home');
|
||||
|
||||
describe('bower home', function () {
|
||||
|
||||
it('correctly reads arguments', function() {
|
||||
expect(home.readOptions(['foo'])).to.eql(['foo']);
|
||||
});
|
||||
|
||||
var package = new helpers.TempDir({
|
||||
'bower.json': {
|
||||
name: 'package',
|
||||
homepage: 'http://bower.io'
|
||||
}
|
||||
});
|
||||
|
||||
var wrongPackage = new helpers.TempDir({
|
||||
'bower.json': {
|
||||
name: 'package'
|
||||
}
|
||||
});
|
||||
|
||||
it('opens repository home page in web browser', function () {
|
||||
package.prepare();
|
||||
|
||||
return Q.Promise(function(resolve) {
|
||||
var home = helpers.command('home', { opn: resolve });
|
||||
helpers.run(home, [package.path]);
|
||||
}).then(function(url) {
|
||||
expect(url).to.be('http://bower.io');
|
||||
});
|
||||
});
|
||||
|
||||
it('opens home page of current repository', function () {
|
||||
package.prepare();
|
||||
|
||||
return Q.Promise(function(resolve) {
|
||||
var home = helpers.command('home', { opn: resolve });
|
||||
helpers.run(home, [undefined, { cwd: package.path }]);
|
||||
}).then(function(url) {
|
||||
expect(url).to.be('http://bower.io');
|
||||
});
|
||||
});
|
||||
|
||||
it('errors if no homepage is set', function () {
|
||||
wrongPackage.prepare();
|
||||
|
||||
return Q.Promise(function(resolve) {
|
||||
var home = helpers.command('home', { opn: resolve });
|
||||
helpers.run(home, [wrongPackage.path]).fail(resolve);
|
||||
}).then(function(reason) {
|
||||
expect(reason.message).to.be('No homepage set for package');
|
||||
expect(reason.code).to.be('ENOHOME');
|
||||
});
|
||||
});
|
||||
});
|
||||
21
test/commands/index.js
Normal file
21
test/commands/index.js
Normal file
@@ -0,0 +1,21 @@
|
||||
describe('integration tests', function () {
|
||||
require('./cache/list');
|
||||
require('./cache/clean');
|
||||
require('./help');
|
||||
require('./home');
|
||||
require('./info');
|
||||
require('./init');
|
||||
require('./install');
|
||||
require('./list');
|
||||
require('./link');
|
||||
require('./lookup');
|
||||
require('./prune');
|
||||
require('./register');
|
||||
require('./search');
|
||||
require('./uninstall');
|
||||
require('./update');
|
||||
require('./version');
|
||||
|
||||
// run last because it changes defaults
|
||||
require('./bower');
|
||||
});
|
||||
52
test/commands/info.js
Normal file
52
test/commands/info.js
Normal file
@@ -0,0 +1,52 @@
|
||||
var expect = require('expect.js');
|
||||
|
||||
var helpers = require('../helpers');
|
||||
var info = helpers.command('info');
|
||||
|
||||
describe('bower info', function () {
|
||||
|
||||
it('correctly reads arguments', function() {
|
||||
expect(info.readOptions(['pkg', 'property']))
|
||||
.to.eql(['pkg', 'property']);
|
||||
});
|
||||
|
||||
var meta = {
|
||||
name: 'package',
|
||||
version: '0.1.2',
|
||||
homepage: 'http://bower.io',
|
||||
description: 'Hello world!'
|
||||
};
|
||||
|
||||
var meta2 = {
|
||||
name: 'package',
|
||||
version: '0.1.3',
|
||||
homepage: 'http://bower.io',
|
||||
description: 'Hello world! Hello!'
|
||||
};
|
||||
|
||||
var package = new helpers.TempDir({
|
||||
'0.1.2': { 'bower.json': meta },
|
||||
'0.1.3': { 'bower.json': meta2 }
|
||||
});
|
||||
|
||||
it('just returns if not package is specified', function () {
|
||||
return helpers.run(info).spread(function(results) {
|
||||
expect(results).to.be(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
it('shows info about given package', function () {
|
||||
package.prepareGit({});
|
||||
|
||||
return helpers.run(info, [package.path]).spread(function(results) {
|
||||
expect(results).to.eql({
|
||||
'latest': meta2,
|
||||
'name': package.path,
|
||||
'versions': [
|
||||
'0.1.3',
|
||||
'0.1.2'
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
85
test/commands/init.js
Normal file
85
test/commands/init.js
Normal file
@@ -0,0 +1,85 @@
|
||||
var expect = require('expect.js');
|
||||
var helpers = require('../helpers');
|
||||
|
||||
var init = helpers.command('init');
|
||||
|
||||
describe('bower init', function () {
|
||||
|
||||
var package = new helpers.TempDir();
|
||||
|
||||
it('correctly reads arguments', function() {
|
||||
expect(init.readOptions([]))
|
||||
.to.eql([]);
|
||||
});
|
||||
|
||||
it('generates bower.json file', function () {
|
||||
package.prepare();
|
||||
|
||||
var logger = init({
|
||||
cwd: package.path,
|
||||
interactive: true
|
||||
});
|
||||
|
||||
return helpers.expectEvent(logger, 'prompt')
|
||||
.spread(function (prompt, answer) {
|
||||
answer({
|
||||
name: 'test-name',
|
||||
version: 'test-version',
|
||||
description: 'test-description',
|
||||
moduleType: 'test-moduleType',
|
||||
keywords: 'test-keyword',
|
||||
authors: 'test-author',
|
||||
license: 'test-license',
|
||||
homepage: 'test-homepage',
|
||||
private: true
|
||||
});
|
||||
|
||||
return helpers.expectEvent(logger, 'prompt');
|
||||
})
|
||||
.spread(function (prompt, answer) {
|
||||
answer({ prompt: true });
|
||||
return helpers.expectEvent(logger, 'end');
|
||||
})
|
||||
.then(function () {
|
||||
expect(package.readJson('bower.json')).to.eql({
|
||||
name: 'test-name',
|
||||
version: 'test-version',
|
||||
homepage: 'test-homepage',
|
||||
authors: [ 'test-author' ],
|
||||
description: 'test-description',
|
||||
moduleType: 'test-moduleType',
|
||||
keywords: [ 'test-keyword' ],
|
||||
license: 'test-license'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('errors on non-interactive mode', function () {
|
||||
package.prepare();
|
||||
|
||||
return helpers.run(init, { cwd: package.path }).then(
|
||||
function () { throw 'should fail'; },
|
||||
function (reason) {
|
||||
expect(reason.message).to.be('Register requires an interactive shell');
|
||||
expect(reason.code).to.be('ENOINT');
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('warns about existing bower.json', function () {
|
||||
package.prepare({
|
||||
'bower.json': {
|
||||
name: 'foobar'
|
||||
}
|
||||
});
|
||||
|
||||
var logger = init({ cwd: package.path, interactive: true });
|
||||
|
||||
return helpers.expectEvent(logger, 'log').spread(function(event) {
|
||||
expect(event.level).to.be('warn');
|
||||
expect(event.message).to.be(
|
||||
'The existing bower.json file will be used and filled in'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
276
test/commands/install.js
Normal file
276
test/commands/install.js
Normal file
@@ -0,0 +1,276 @@
|
||||
var expect = require('expect.js');
|
||||
var helpers = require('../helpers');
|
||||
|
||||
describe('bower install', function () {
|
||||
|
||||
var tempDir = new helpers.TempDir();
|
||||
|
||||
var install = helpers.command('install', { cwd: tempDir.path });
|
||||
|
||||
it('correctly reads arguments', function() {
|
||||
expect(install.readOptions(['jquery', 'angular', '-F', '-p', '-S', '-D', '-E']))
|
||||
.to.eql([['jquery', 'angular'], {
|
||||
forceLatest: true,
|
||||
production: true,
|
||||
save: true,
|
||||
saveDev: true,
|
||||
saveExact: true
|
||||
}]);
|
||||
});
|
||||
|
||||
it('correctly reads long arguments', function() {
|
||||
expect(install.readOptions([
|
||||
'jquery', 'angular',
|
||||
'--force-latest', '--production', '--save', '--save-dev', '--save-exact'
|
||||
])).to.eql([['jquery', 'angular'], {
|
||||
forceLatest: true,
|
||||
production: true,
|
||||
save: true,
|
||||
saveDev: true,
|
||||
saveExact: true
|
||||
}]);
|
||||
});
|
||||
|
||||
var package = new helpers.TempDir({
|
||||
'bower.json': {
|
||||
name: 'package'
|
||||
}
|
||||
}).prepare();
|
||||
|
||||
var gitPackage = new helpers.TempDir();
|
||||
|
||||
it('writes to bower.json if --save flag is used', function () {
|
||||
package.prepare();
|
||||
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test'
|
||||
}
|
||||
});
|
||||
|
||||
return helpers.run(install, [[package.path], { save: true }]).then(function() {
|
||||
expect(tempDir.read('bower.json')).to.contain('dependencies');
|
||||
});
|
||||
});
|
||||
|
||||
it('writes an exact version number to dependencies in bower.json if --save --save-exact flags are used', function () {
|
||||
package.prepare({
|
||||
'bower.json': {
|
||||
version: '1.2.3'
|
||||
}
|
||||
});
|
||||
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test'
|
||||
}
|
||||
});
|
||||
|
||||
return helpers.run(install, [
|
||||
[package.path],
|
||||
{ saveExact: true, save: true }
|
||||
]).then(function() {
|
||||
expect(tempDir.readJson('bower.json').dependencies.package).to.equal('1.2.3');
|
||||
});
|
||||
});
|
||||
|
||||
it('writes an exact version number to devDependencies in bower.json if --save-dev --save-exact flags are used', function () {
|
||||
package.prepare({
|
||||
'bower.json': {
|
||||
version: '0.1.0'
|
||||
}
|
||||
});
|
||||
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test'
|
||||
}
|
||||
});
|
||||
|
||||
return helpers.run(install, [
|
||||
[package.path],
|
||||
{ saveExact: true, saveDev: true }
|
||||
]).then(function() {
|
||||
expect(tempDir.readJson('bower.json').devDependencies.package).to.equal('0.1.0');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('does not write to bower.json if only --save-exact flag is used', function() {
|
||||
package.prepare({
|
||||
'bower.json': {
|
||||
version: '1.2.3'
|
||||
}
|
||||
});
|
||||
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test'
|
||||
}
|
||||
});
|
||||
|
||||
return helpers.run(install, [[package.path], { saveExact: true }]).then(function() {
|
||||
expect(tempDir.read('bower.json')).to.not.contain('dependencies');
|
||||
expect(tempDir.read('bower.json')).to.not.contain('devDependencies');
|
||||
});
|
||||
});
|
||||
|
||||
it('reads .bowerrc from cwd', function () {
|
||||
package.prepare({ foo: 'bar' });
|
||||
|
||||
tempDir.prepare({
|
||||
'.bowerrc': { directory: 'assets' },
|
||||
'bower.json': {
|
||||
name: 'test',
|
||||
dependencies: {
|
||||
package: package.path
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return helpers.run(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: 'node -e \'require("fs").writeFileSync("preinstall.txt", "%")\''
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return helpers.run(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: 'node -e \'require("fs").writeFileSync("postinstall.txt", "%")\''
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return helpers.run(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: 'node -e \'require("fs").writeFileSync("hooks.txt", "%")\'',
|
||||
preinstall: 'node -e \'require("fs").writeFileSync("hooks.txt", "%")\''
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return helpers.run(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: 'node -e \'var fs = require("fs"); fs.writeFileSync("hook.txt", fs.readFileSync("bower.json"));\''
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return helpers.run(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: 'node -e \'process.stdout.write("foobar")\''
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var lastAction = null;
|
||||
|
||||
helpers.run(install).logger.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 () {
|
||||
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'
|
||||
}
|
||||
});
|
||||
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test',
|
||||
dependencies: {
|
||||
package: gitPackage.path + '#1.0.0'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return helpers.run(install).then(function() {
|
||||
expect(tempDir.read('bower_components/package/version.txt')).to.contain('1.0.0');
|
||||
});
|
||||
});
|
||||
});
|
||||
110
test/commands/link.js
Normal file
110
test/commands/link.js
Normal file
@@ -0,0 +1,110 @@
|
||||
var expect = require('expect.js');
|
||||
var helpers = require('../helpers');
|
||||
|
||||
var link = helpers.command('link');
|
||||
|
||||
describe('bower link', function () {
|
||||
|
||||
var package = new helpers.TempDir({
|
||||
'bower.json': {
|
||||
name: 'package',
|
||||
},
|
||||
'index.js': 'Hello World!'
|
||||
});
|
||||
|
||||
var otherPackage = new helpers.TempDir({
|
||||
'bower.json': {
|
||||
name: 'package2',
|
||||
},
|
||||
'index.js': 'Welcome World!'
|
||||
});
|
||||
|
||||
var linksDir = new helpers.TempDir();
|
||||
|
||||
beforeEach(function() {
|
||||
package.prepare();
|
||||
otherPackage.prepare();
|
||||
linksDir.prepare();
|
||||
});
|
||||
|
||||
it('correctly reads arguments', function() {
|
||||
expect(link.readOptions(['jquery', 'angular']))
|
||||
.to.eql(['jquery', 'angular']);
|
||||
});
|
||||
|
||||
it('creates self link', function () {
|
||||
return helpers.run(link, [undefined, undefined,
|
||||
{
|
||||
cwd: package.path,
|
||||
storage: {
|
||||
links: linksDir.path
|
||||
}
|
||||
}
|
||||
]).then(function() {
|
||||
expect(linksDir.read('package/index.js'))
|
||||
.to.be('Hello World!');
|
||||
});
|
||||
});
|
||||
|
||||
it('creates inter-link', function () {
|
||||
return helpers.run(link, [undefined, undefined,
|
||||
{
|
||||
cwd: package.path,
|
||||
storage: {
|
||||
links: linksDir.path
|
||||
}
|
||||
}
|
||||
]).then(function () {
|
||||
return helpers.run(link, ['package', undefined,
|
||||
{
|
||||
cwd: otherPackage.path,
|
||||
storage: {
|
||||
links: linksDir.path
|
||||
}
|
||||
}
|
||||
]);
|
||||
}).then(function() {
|
||||
expect(otherPackage.read('bower_components/package/index.js'))
|
||||
.to.be('Hello World!');
|
||||
});
|
||||
});
|
||||
|
||||
it('creates inter-link with custom local name', function () {
|
||||
return helpers.run(link, [undefined, undefined,
|
||||
{
|
||||
cwd: package.path,
|
||||
storage: {
|
||||
links: linksDir.path
|
||||
}
|
||||
}
|
||||
]).then(function () {
|
||||
return helpers.run(link, ['package', 'local',
|
||||
{
|
||||
cwd: otherPackage.path,
|
||||
storage: {
|
||||
links: linksDir.path
|
||||
}
|
||||
}
|
||||
]);
|
||||
}).then(function() {
|
||||
expect(otherPackage.read('bower_components/local/index.js'))
|
||||
.to.be('Hello World!');
|
||||
});
|
||||
});
|
||||
|
||||
it('errors on unexising package', function () {
|
||||
return helpers.run(link, ['package', 'local',
|
||||
{
|
||||
cwd: otherPackage.path,
|
||||
storage: {
|
||||
links: linksDir.path
|
||||
}
|
||||
}
|
||||
]).then(function() {
|
||||
throw 'Should fail creating a link!';
|
||||
}).fail(function(reason) {
|
||||
expect(reason.code).to.be('ENOENT');
|
||||
expect(reason.message).to.be('Failed to create link to package');
|
||||
});
|
||||
});
|
||||
});
|
||||
256
test/commands/list.js
Normal file
256
test/commands/list.js
Normal file
@@ -0,0 +1,256 @@
|
||||
var expect = require('expect.js');
|
||||
var object = require('mout').object;
|
||||
var path = require('path');
|
||||
|
||||
var helpers = require('../helpers');
|
||||
|
||||
var commands = {
|
||||
install: helpers.command('install'),
|
||||
list: helpers.command('list')
|
||||
};
|
||||
|
||||
describe('bower list', function () {
|
||||
|
||||
var tempDir = new helpers.TempDir();
|
||||
|
||||
var gitPackage = new helpers.TempDir();
|
||||
|
||||
var install = function(packages, options, config) {
|
||||
config = object.merge(config || {}, {
|
||||
cwd: tempDir.path
|
||||
});
|
||||
|
||||
return helpers.run(commands.install, [packages, options, config]);
|
||||
};
|
||||
|
||||
var list = function(options, config) {
|
||||
config = object.merge(config || {}, {
|
||||
cwd: tempDir.path
|
||||
});
|
||||
|
||||
return helpers.run(commands.list, [options, config]);
|
||||
};
|
||||
|
||||
it('correctly reads arguments', function() {
|
||||
expect(commands.list.readOptions(['-p', '-r']))
|
||||
.to.eql([{
|
||||
paths: true,
|
||||
relative: true
|
||||
}]);
|
||||
});
|
||||
|
||||
it('correctly reads long arguments', function() {
|
||||
expect(commands.list.readOptions(['--paths', '--relative']))
|
||||
.to.eql([{
|
||||
paths: true,
|
||||
relative: true
|
||||
}]);
|
||||
});
|
||||
|
||||
it('lists no packages when nothing installed', function () {
|
||||
tempDir.prepare();
|
||||
|
||||
return list().spread(function(results) {
|
||||
expect(results).to.be.an(Object);
|
||||
expect(results.canonicalDir).to.equal(tempDir.path);
|
||||
expect(results.pkgMeta.dependencies).to.eql({});
|
||||
expect(results.pkgMeta.devDependencies).to.eql({});
|
||||
expect(results.dependencies).to.eql({});
|
||||
expect(results.nrDependants).to.eql(0);
|
||||
expect(results.versions).to.eql([]);
|
||||
});
|
||||
});
|
||||
|
||||
it('lists 1 dependency when 1 local package installed', function () {
|
||||
|
||||
var package = new helpers.TempDir({
|
||||
'bower.json': {
|
||||
name: 'package',
|
||||
main: 'test.txt'
|
||||
}
|
||||
}).prepare();
|
||||
package.prepare();
|
||||
|
||||
return install([package.path]).then(function() {
|
||||
return list().spread(function(results) {
|
||||
expect(results).to.be.an(Object);
|
||||
expect(results.canonicalDir).to.equal(tempDir.path);
|
||||
expect(results.pkgMeta.dependencies).to.eql({
|
||||
package: package.path + '#*'
|
||||
});
|
||||
expect(results.pkgMeta.devDependencies).to.eql({});
|
||||
expect(results.dependencies.package).to.be.an(Object);
|
||||
expect(results.dependencies.package.pkgMeta).to.be.an(Object);
|
||||
expect(results.dependencies.package.pkgMeta.main).to.equal('test.txt');
|
||||
expect(results.dependencies.package.canonicalDir).to.equal(
|
||||
path.join(tempDir.path, 'bower_components/package')
|
||||
);
|
||||
expect(results.dependencies.package.dependencies).to.eql({});
|
||||
expect(results.dependencies.package.nrDependants).to.equal(1);
|
||||
expect(results.dependencies.package.versions).to.eql([]);
|
||||
expect(results.nrDependants).to.equal(0);
|
||||
expect(results.versions).to.eql([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('lists 1 dependency with relative paths when 1 local package installed', function () {
|
||||
|
||||
var package = new helpers.TempDir({
|
||||
'bower.json': {
|
||||
name: 'package',
|
||||
main: 'test.txt'
|
||||
}
|
||||
}).prepare();
|
||||
package.prepare();
|
||||
|
||||
return install([package.path]).then(function() {
|
||||
return list({relative: true}).spread(function(results) {
|
||||
expect(results).to.be.an(Object);
|
||||
expect(results.canonicalDir).to.equal(tempDir.path);
|
||||
expect(results.dependencies).to.be.an(Object);
|
||||
expect(results.dependencies.package).to.be.an(Object);
|
||||
expect(results.dependencies.package.pkgMeta).to.be.an(Object);
|
||||
expect(results.dependencies.package.pkgMeta.main).to.equal('test.txt');
|
||||
expect(results.pkgMeta.dependencies).to.eql({
|
||||
package: package.path + '#*'
|
||||
});
|
||||
expect(results.dependencies.package.canonicalDir).to.equal(
|
||||
path.normalize('bower_components/package')
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('lists 1 dependency with 1 source relative source mapping when 1 local package installed', function () {
|
||||
|
||||
var package = new helpers.TempDir({
|
||||
'bower.json': {
|
||||
name: 'package',
|
||||
main: 'test.txt'
|
||||
}
|
||||
}).prepare();
|
||||
package.prepare();
|
||||
|
||||
return install([package.path]).then(function() {
|
||||
return list({paths: true}).spread(function(results) {
|
||||
expect(results).to.be.an(Object);
|
||||
expect(results.package).to.equal(
|
||||
'bower_components/package/test.txt'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('lists 1 dependency with 2 source relative source mapping when 1 local package installed', function () {
|
||||
|
||||
var package = new helpers.TempDir({
|
||||
'bower.json': {
|
||||
name: 'package',
|
||||
main: ['test.txt', 'test2.txt']
|
||||
}
|
||||
}).prepare();
|
||||
package.prepare();
|
||||
|
||||
return install([package.path]).then(function() {
|
||||
return list({paths: true}).spread(function(results) {
|
||||
expect(results).to.be.an(Object);
|
||||
expect(results.package).to.be.an(Object);
|
||||
expect(results.package).to.eql([
|
||||
'bower_components/package/test.txt',
|
||||
'bower_components/package/test2.txt'
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('lists 1 dependency when 1 git package installed', function () {
|
||||
gitPackage.prepareGit({
|
||||
'1.0.0': {
|
||||
'bower.json': {
|
||||
name: 'package',
|
||||
main: 'test.txt'
|
||||
},
|
||||
'version.txt': '1.0.0'
|
||||
},
|
||||
'1.0.1': {
|
||||
'bower.json': {
|
||||
name: 'package',
|
||||
main: 'test2.txt'
|
||||
},
|
||||
'version.txt': '1.0.1'
|
||||
}
|
||||
});
|
||||
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test',
|
||||
dependencies: {
|
||||
package: gitPackage.path + '#1.0.0'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return install().then(function() {
|
||||
return list().spread(function(results) {
|
||||
expect(results).to.be.an(Object);
|
||||
expect(results.canonicalDir).to.equal(tempDir.path);
|
||||
expect(results.pkgMeta.dependencies).to.eql({
|
||||
package: gitPackage.path + '#1.0.0'
|
||||
});
|
||||
expect(results.pkgMeta.devDependencies).to.eql({});
|
||||
expect(results.dependencies.package).to.be.an(Object);
|
||||
expect(results.dependencies.package.pkgMeta).to.be.an(Object);
|
||||
expect(results.dependencies.package.pkgMeta.main).to.equal('test.txt');
|
||||
expect(results.dependencies.package.canonicalDir).to.equal(
|
||||
path.join(tempDir.path, 'bower_components/package')
|
||||
);
|
||||
expect(results.dependencies.package.dependencies).to.eql({});
|
||||
expect(results.dependencies.package.nrDependants).to.equal(1);
|
||||
expect(results.dependencies.package.versions).to.eql(['1.0.1', '1.0.0']);
|
||||
expect(results.nrDependants).to.equal(0);
|
||||
expect(results.versions).to.eql([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('lists 1 dependency with relative paths when 1 git package installed', function () {
|
||||
gitPackage.prepareGit({
|
||||
'1.0.0': {
|
||||
'bower.json': {
|
||||
name: 'package',
|
||||
main: 'test.txt'
|
||||
},
|
||||
'version.txt': '1.0.0'
|
||||
},
|
||||
'1.0.1': {
|
||||
'bower.json': {
|
||||
name: 'package',
|
||||
main: 'test2.txt'
|
||||
},
|
||||
'version.txt': '1.0.1'
|
||||
}
|
||||
});
|
||||
|
||||
tempDir.prepare({
|
||||
'bower.json': {
|
||||
name: 'test',
|
||||
dependencies: {
|
||||
package: gitPackage.path + '#1.0.0'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return install().then(function() {
|
||||
return list({relative: true}).spread(function(results) {
|
||||
expect(results.canonicalDir).to.equal(tempDir.path);
|
||||
expect(results.pkgMeta.dependencies).to.eql({
|
||||
package: gitPackage.path + '#1.0.0'
|
||||
});
|
||||
expect(results.dependencies.package.canonicalDir).to.equal(
|
||||
path.normalize('bower_components/package')
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
187
test/commands/login.js
Normal file
187
test/commands/login.js
Normal file
@@ -0,0 +1,187 @@
|
||||
var expect = require('expect.js');
|
||||
var helpers = require('../helpers');
|
||||
|
||||
var fakeGitHub = function (authenticate) {
|
||||
function FakeGitHub() { }
|
||||
|
||||
var _creds;
|
||||
|
||||
FakeGitHub.prototype.authenticate = function (creds) {
|
||||
_creds = creds;
|
||||
};
|
||||
|
||||
FakeGitHub.prototype.authorization = {
|
||||
create: function (options, cb) {
|
||||
if (_creds.password === 'validpassword') {
|
||||
cb(null, { token: 'faketoken' });
|
||||
} else if (_creds.password === 'withtwofactor') {
|
||||
if (options.headers && options.headers['X-GitHub-OTP'] === '123456') {
|
||||
cb(null, { token: 'faketwoauthtoken' });
|
||||
} else {
|
||||
cb({ code: 401, message: '{ "message": "Must specify two-factor authentication OTP code." }' });
|
||||
}
|
||||
} else {
|
||||
cb({ code: 401, message: 'Bad credentials' });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return FakeGitHub;
|
||||
};
|
||||
|
||||
var fakeConfigstore = function (set, get) {
|
||||
function FakeConfigstore() { }
|
||||
|
||||
FakeConfigstore.prototype.set = set;
|
||||
FakeConfigstore.prototype.get = get;
|
||||
|
||||
return FakeConfigstore;
|
||||
};
|
||||
|
||||
var login = helpers.command('login');
|
||||
|
||||
var loginFactory = function (options) {
|
||||
return helpers.command('login', {
|
||||
'github': fakeGitHub(),
|
||||
'configstore': fakeConfigstore(
|
||||
options.set || function () { return true; },
|
||||
options.get || function () { return true; }
|
||||
)
|
||||
});
|
||||
};
|
||||
|
||||
describe('bower login', function () {
|
||||
|
||||
it('correctly reads arguments', function() {
|
||||
expect(login.readOptions(['--token', 'foobar']))
|
||||
.to.eql([{ token: 'foobar' }]);
|
||||
});
|
||||
|
||||
it('fails if run in non-interactive shell without token passed', function () {
|
||||
return helpers.run(login, []).fail(function(reason) {
|
||||
expect(reason.message).to.be('Login requires an interactive shell');
|
||||
expect(reason.code).to.be('ENOINT');
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds if run in non-interactive shell with token passed', function () {
|
||||
return helpers.run(login, [{ token: 'foobar' }]);
|
||||
});
|
||||
|
||||
it('succeeds if provided password is valid', function () {
|
||||
var login = loginFactory({});
|
||||
|
||||
var logger = login({}, { interactive: true });
|
||||
|
||||
logger.once('prompt', function (prompt, answer) {
|
||||
answer({
|
||||
username: 'user',
|
||||
password: 'validpassword'
|
||||
});
|
||||
});
|
||||
|
||||
return helpers.expectEvent(logger, 'end')
|
||||
.spread(function(options) {
|
||||
expect(options.token).to.be('faketoken');
|
||||
});
|
||||
});
|
||||
|
||||
it('supports two-factor authorization', function () {
|
||||
var login = loginFactory({});
|
||||
|
||||
var logger = login({}, { interactive: true });
|
||||
|
||||
logger.once('prompt', function (prompt, answer) {
|
||||
logger.once('prompt', function (prompt, answer) {
|
||||
answer({
|
||||
otpcode: '123456'
|
||||
});
|
||||
});
|
||||
|
||||
answer({
|
||||
username: 'user',
|
||||
password: 'withtwofactor'
|
||||
});
|
||||
});
|
||||
|
||||
return helpers.expectEvent(logger, 'end')
|
||||
.spread(function(options) {
|
||||
expect(options.token).to.be('faketwoauthtoken');
|
||||
});
|
||||
});
|
||||
|
||||
it('fails if provided password is invalid', function () {
|
||||
var login = loginFactory({});
|
||||
|
||||
var logger = login({}, { interactive: true });
|
||||
|
||||
logger.once('prompt', function (prompt, answer) {
|
||||
answer({
|
||||
username: 'user',
|
||||
password: 'invalidpassword'
|
||||
});
|
||||
});
|
||||
|
||||
return helpers.expectEvent(logger, 'error').spread(function (error) {
|
||||
expect(error.code).to.be('EAUTH');
|
||||
expect(error.message).to.be('Authorization failed');
|
||||
});
|
||||
});
|
||||
|
||||
it('uses username stored in config as default username', function () {
|
||||
var login = loginFactory({
|
||||
get: function (key) {
|
||||
if (key === 'username') {
|
||||
return 'savedusername';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var logger = login({}, { interactive: true });
|
||||
|
||||
return helpers.expectEvent(logger, 'prompt')
|
||||
.spread(function (prompt, answer) {
|
||||
expect(prompt[0].default).to.be('savedusername');
|
||||
});
|
||||
});
|
||||
|
||||
it('saves username in config', function (done) {
|
||||
var login = loginFactory({
|
||||
set: function (key, value) {
|
||||
if(key === 'username') {
|
||||
expect(value).to.be('user');
|
||||
done();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var logger = login({}, { interactive: true });
|
||||
|
||||
logger.once('prompt', function (prompt, answer) {
|
||||
answer({
|
||||
username: 'user',
|
||||
password: 'validpassword'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('saves received token in accessToken config', function (done) {
|
||||
var login = loginFactory({
|
||||
set: function (key, value) {
|
||||
if(key === 'accessToken') {
|
||||
expect(value).to.be('faketoken');
|
||||
done();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var logger = login({}, { interactive: true });
|
||||
|
||||
logger.once('prompt', function (prompt, answer) {
|
||||
answer({
|
||||
username: 'user',
|
||||
password: 'validpassword'
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
55
test/commands/lookup.js
Normal file
55
test/commands/lookup.js
Normal file
@@ -0,0 +1,55 @@
|
||||
var expect = require('expect.js');
|
||||
var helpers = require('../helpers');
|
||||
|
||||
var lookup = helpers.command('lookup');
|
||||
|
||||
describe('bower lookup', function () {
|
||||
|
||||
var lookupWithResult = function (response) {
|
||||
return helpers.command('lookup', {
|
||||
'bower-registry-client': function() {
|
||||
return {
|
||||
lookup: function(query, callback) {
|
||||
if (query in response) {
|
||||
callback(null, response[query]);
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
it('correctly reads arguments', function() {
|
||||
expect(lookup.readOptions(['jquery']))
|
||||
.to.eql(['jquery']);
|
||||
});
|
||||
|
||||
it('lookups package by name', function () {
|
||||
var lookup = lookupWithResult({ jquery: { url: 'http://jquery.org' } });
|
||||
|
||||
return helpers.run(lookup, ['jquery']).spread(function(result) {
|
||||
expect(result).to.eql({
|
||||
name: 'jquery',
|
||||
url: 'http://jquery.org'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('returns null if no package is found', function () {
|
||||
var lookup = lookupWithResult({ jquery: { url: 'http://jquery.org' } });
|
||||
|
||||
return helpers.run(lookup, ['foobar']).spread(function(result) {
|
||||
expect(result).to.eql(null);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns null if called without argument', function () {
|
||||
var lookup = lookupWithResult({ jquery: { url: 'http://jquery.org' } });
|
||||
|
||||
return helpers.run(lookup, []).spread(function(result) {
|
||||
expect(result).to.eql(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
65
test/commands/prune.js
Normal file
65
test/commands/prune.js
Normal file
@@ -0,0 +1,65 @@
|
||||
var expect = require('expect.js');
|
||||
var helpers = require('../helpers');
|
||||
|
||||
var prune = helpers.command('prune');
|
||||
|
||||
describe('bower home', function () {
|
||||
|
||||
var package = new helpers.TempDir({
|
||||
'bower.json': {
|
||||
name: 'package',
|
||||
dependencies: {
|
||||
jquery: '*'
|
||||
}
|
||||
},
|
||||
'bower_components/jquery/jquery.js': 'jquery source'
|
||||
});
|
||||
|
||||
it('correctly reads arguments', function() {
|
||||
expect(prune.readOptions(['-p']))
|
||||
.to.eql([{ production: true }]);
|
||||
});
|
||||
|
||||
it('correctly reads long arguments', function() {
|
||||
expect(prune.readOptions(['--production']))
|
||||
.to.eql([{ production: true }]);
|
||||
});
|
||||
|
||||
it('removes extraneous packages', function () {
|
||||
package.prepare({
|
||||
'bower_components/angular/angular.js': 'angular source',
|
||||
'bower_components/angular/.bower.json': { name: 'angular' }
|
||||
});
|
||||
|
||||
return helpers.run(prune, [{}, { cwd: package.path }]).then(function() {
|
||||
expect(package.exists('bower_components/angular/angular.js'))
|
||||
.to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('leaves non-bower packages', function () {
|
||||
package.prepare({
|
||||
'bower_components/angular/angular.js': 'angular source'
|
||||
});
|
||||
|
||||
return helpers.run(prune, [{}, { cwd: package.path }]).then(function() {
|
||||
expect(package.exists('bower_components/angular/angular.js'))
|
||||
.to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('deals with custom directory', function () {
|
||||
package.prepare({
|
||||
'.bowerrc': { directory: 'components' },
|
||||
'bower_components/angular/.bower.json': { name: 'angular' },
|
||||
'bower_components/angular/angular.js': 'angular source',
|
||||
'components/angular/.bower.json': { name: 'angular' },
|
||||
'components/angular/angular.js': 'angular source'
|
||||
});
|
||||
|
||||
return helpers.run(prune, [{}, { cwd: package.path }]).then(function() {
|
||||
expect(package.exists('components/angular/angular.js')).to.be(false);
|
||||
expect(package.exists('bower_components/angular/angular.js')).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
125
test/commands/register.js
Normal file
125
test/commands/register.js
Normal file
@@ -0,0 +1,125 @@
|
||||
var Q = require('q');
|
||||
var expect = require('expect.js');
|
||||
var helpers = require('../helpers');
|
||||
|
||||
var register = helpers.command('register');
|
||||
|
||||
var fakeRepositoryFactory = function (canonicalDir, pkgMeta) {
|
||||
function FakeRepository() { }
|
||||
|
||||
FakeRepository.prototype.fetch = function() {
|
||||
return Q.fcall(function () {
|
||||
return [canonicalDir, pkgMeta];
|
||||
});
|
||||
};
|
||||
|
||||
FakeRepository.prototype.getRegistryClient = function() {
|
||||
return {
|
||||
register: function (name, url, cb) {
|
||||
cb(null, { name: name, url: url });
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return FakeRepository;
|
||||
};
|
||||
|
||||
var register = helpers.command('register');
|
||||
|
||||
var registerFactory = function (canonicalDir, pkgMeta) {
|
||||
return helpers.command('register', {
|
||||
'../core/PackageRepository': fakeRepositoryFactory(
|
||||
canonicalDir, pkgMeta
|
||||
)
|
||||
});
|
||||
};
|
||||
|
||||
describe('bower register', function () {
|
||||
|
||||
var package = new helpers.TempDir({
|
||||
'bower.json': {
|
||||
name: 'package'
|
||||
}
|
||||
});
|
||||
|
||||
it('correctly reads arguments', function() {
|
||||
expect(register.readOptions(['jquery', 'url']))
|
||||
.to.eql(['jquery', 'url']);
|
||||
});
|
||||
|
||||
it('errors if name is not provided', function () {
|
||||
return helpers.run(register).fail(function(reason) {
|
||||
expect(reason.message).to.be('Usage: bower register <name> <url>');
|
||||
expect(reason.code).to.be('EINVFORMAT');
|
||||
});
|
||||
});
|
||||
|
||||
it('errors if url is not provided', function () {
|
||||
return helpers.run(register, ['some-name'])
|
||||
.fail(function(reason) {
|
||||
expect(reason.message).to.be('Usage: bower register <name> <url>');
|
||||
expect(reason.code).to.be('EINVFORMAT');
|
||||
});
|
||||
});
|
||||
|
||||
it('errors if url is not correct', function () {
|
||||
return helpers.run(register, ['some-name', 'url'])
|
||||
.fail(function(reason) {
|
||||
expect(reason.message).to.be('The registry only accepts URLs starting with git://');
|
||||
expect(reason.code).to.be('EINVFORMAT');
|
||||
});
|
||||
});
|
||||
|
||||
it('errors if trying to register private package', function () {
|
||||
package.prepare({ 'bower.json': { private: true } });
|
||||
|
||||
var register = registerFactory(package.path, package.meta());
|
||||
return helpers.run(register, ['some-name', 'git://fake-url.git'])
|
||||
.fail(function(reason) {
|
||||
expect(reason.message).to.be('The package you are trying to register is marked as private');
|
||||
expect(reason.code).to.be('EPRIV');
|
||||
});
|
||||
});
|
||||
|
||||
it('should call registry client with name and url', function () {
|
||||
package.prepare();
|
||||
|
||||
var register = registerFactory(package.path, package.meta());
|
||||
return helpers.run(register, ['some-name', 'git://fake-url.git'])
|
||||
.spread(function(result) {
|
||||
expect(result).to.eql({
|
||||
// Result from register action on stub
|
||||
name: 'some-name', url: 'git://fake-url.git'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should confirm in interactive mode', function () {
|
||||
package.prepare();
|
||||
|
||||
var register = registerFactory(package.path, package.meta());
|
||||
|
||||
var promise = helpers.run(register,
|
||||
['some-name', 'git://fake-url.git', { interactive: true }]
|
||||
);
|
||||
|
||||
return helpers.expectEvent(promise.logger, 'confirm')
|
||||
.spread(function(e) {
|
||||
expect(e.type).to.be('confirm');
|
||||
expect(e.message).to.be('Registering a package will make it installable via the registry (https://bower.herokuapp.com), continue?');
|
||||
expect(e.default).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should skip confirming when forcing', function () {
|
||||
package.prepare();
|
||||
|
||||
var register = registerFactory(package.path, package.meta());
|
||||
|
||||
return helpers.run(register,
|
||||
['some-name', 'git://fake-url.git',
|
||||
{ interactive: true, force: true }
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
44
test/commands/search.js
Normal file
44
test/commands/search.js
Normal file
@@ -0,0 +1,44 @@
|
||||
var Q = require('q');
|
||||
var expect = require('expect.js');
|
||||
var helpers = require('../helpers');
|
||||
|
||||
var search = helpers.command('search');
|
||||
|
||||
describe('bower search', function () {
|
||||
|
||||
it('correctly reads arguments', function() {
|
||||
expect(search.readOptions(['jquery']))
|
||||
.to.eql(['jquery']);
|
||||
});
|
||||
|
||||
it('searches for single repository', function () {
|
||||
return Q.Promise(function(resolve) {
|
||||
var search = helpers.command('search', {
|
||||
'bower-registry-client': function() {
|
||||
return {
|
||||
search: resolve
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
helpers.run(search, ['jquery'], {});
|
||||
}).then(function(query) {
|
||||
expect(query).to.be('jquery');
|
||||
});
|
||||
});
|
||||
|
||||
it('lists all repositories if no query given', function () {
|
||||
return Q.Promise(function(resolve) {
|
||||
var search = helpers.command('search', {
|
||||
'bower-registry-client': function() {
|
||||
return {
|
||||
list: resolve
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
helpers.run(search, [], {});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
56
test/commands/uninstall.js
Normal file
56
test/commands/uninstall.js
Normal file
@@ -0,0 +1,56 @@
|
||||
var path = require('path');
|
||||
var expect = require('expect.js');
|
||||
var fs = require('fs');
|
||||
|
||||
var helpers = require('../helpers');
|
||||
var uninstall = helpers.command('uninstall');
|
||||
|
||||
describe('bower uninstall', function () {
|
||||
|
||||
var tempDir = new helpers.TempDir({
|
||||
'bower.json': {
|
||||
name: 'hello-world',
|
||||
dependencies: {
|
||||
'underscore': '*'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
beforeEach(function() {
|
||||
tempDir.prepare();
|
||||
});
|
||||
|
||||
var bowerJsonPath = path.join(tempDir.path, 'bower.json');
|
||||
|
||||
function bowerJson() {
|
||||
return JSON.parse(fs.readFileSync(bowerJsonPath));
|
||||
}
|
||||
|
||||
var config = {
|
||||
cwd: tempDir.path,
|
||||
interactive: true
|
||||
};
|
||||
|
||||
it('correctly reads arguments', function() {
|
||||
expect(uninstall.readOptions(['jquery', '-S', '-D']))
|
||||
.to.eql([['jquery'], { save: true, saveDev: true }]);
|
||||
});
|
||||
|
||||
it('correctly reads long arguments', function() {
|
||||
expect(uninstall.readOptions(['jquery', '--save', '--save-dev']))
|
||||
.to.eql([['jquery'], { save: true, saveDev: true }]);
|
||||
});
|
||||
|
||||
it('does not remove anything from dependencies by default', function () {
|
||||
return helpers.run(uninstall, [['underscore'], undefined, config]).then(function () {
|
||||
expect(bowerJson().dependencies).to.eql({ 'underscore': '*' });
|
||||
});
|
||||
});
|
||||
|
||||
it('removes dependency from bower.json if --save flag is used', function () {
|
||||
return helpers.run(uninstall, [['underscore'], {save: true}, config]).then(function () {
|
||||
expect(bowerJson().dependencies).to.eql({});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
79
test/commands/unregister.js
Normal file
79
test/commands/unregister.js
Normal file
@@ -0,0 +1,79 @@
|
||||
var expect = require('expect.js');
|
||||
var helpers = require('../helpers');
|
||||
|
||||
var fakeRepositoryFactory = function () {
|
||||
function FakeRepository() { }
|
||||
|
||||
FakeRepository.prototype.getRegistryClient = function() {
|
||||
return {
|
||||
unregister: function (name, cb) {
|
||||
cb(null, { name: name });
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return FakeRepository;
|
||||
};
|
||||
|
||||
var unregister = helpers.command('unregister');
|
||||
|
||||
var unregisterFactory = function () {
|
||||
return helpers.command('unregister', {
|
||||
'../core/PackageRepository': fakeRepositoryFactory()
|
||||
});
|
||||
};
|
||||
|
||||
describe('bower unregister', function () {
|
||||
|
||||
it('correctly reads arguments', function() {
|
||||
expect(unregister.readOptions(['jquery']))
|
||||
.to.eql(['jquery']);
|
||||
});
|
||||
|
||||
it('errors if name is not provided', function () {
|
||||
return helpers.run(unregister).fail(function(reason) {
|
||||
expect(reason.message).to.be('Usage: bower unregister <name> <url>');
|
||||
expect(reason.code).to.be('EINVFORMAT');
|
||||
});
|
||||
});
|
||||
|
||||
it('should call registry client with name', function () {
|
||||
var unregister = unregisterFactory();
|
||||
|
||||
return helpers.run(unregister, ['some-name'])
|
||||
.spread(function(result) {
|
||||
expect(result).to.eql({
|
||||
// Result from register action on stub
|
||||
name: 'some-name'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should confirm in interactive mode', function () {
|
||||
var register = unregisterFactory();
|
||||
|
||||
var promise = helpers.run(register,
|
||||
['some-name', {
|
||||
interactive: true,
|
||||
registry: { register: 'http://localhost' }
|
||||
}]
|
||||
);
|
||||
|
||||
return helpers.expectEvent(promise.logger, 'confirm')
|
||||
.spread(function(e) {
|
||||
expect(e.type).to.be('confirm');
|
||||
expect(e.message).to.be('You are about to remove component "some-name" from the bower registry (http://localhost). It is generally considered bad behavior to remove versions of a library that others are depending on. Are you really sure?');
|
||||
expect(e.default).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('should skip confirming when forcing', function () {
|
||||
var register = unregisterFactory();
|
||||
|
||||
return helpers.run(register,
|
||||
['some-name',
|
||||
{ interactive: true, force: true }
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
247
test/commands/update.js
Normal file
247
test/commands/update.js
Normal file
@@ -0,0 +1,247 @@
|
||||
var expect = require('expect.js');
|
||||
var object = require('mout').object;
|
||||
|
||||
var helpers = require('../helpers');
|
||||
var updateCmd = helpers.command('update');
|
||||
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('correctly reads arguments', function() {
|
||||
expect(updateCmd.readOptions(['jquery', '-F', '-p']))
|
||||
.to.eql([['jquery'], { forceLatest: true, production: true }]);
|
||||
});
|
||||
|
||||
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: 'node -e \'require("fs").writeFileSync("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: 'node -e \'require("fs").writeFileSync("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: 'node -e \'require("fs").writeFileSync("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: 'node -e \'require("fs").writeFileSync("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: {
|
||||
preinstall: 'node -e \'require("fs").writeFileSync("preinstall.txt", "%")\'',
|
||||
postinstall: 'node -e \'require("fs").writeFileSync("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');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
89
test/commands/version.js
Normal file
89
test/commands/version.js
Normal file
@@ -0,0 +1,89 @@
|
||||
var expect = require('expect.js');
|
||||
|
||||
var helpers = require('../helpers');
|
||||
var version = helpers.require('lib/commands').version;
|
||||
|
||||
describe('bower list', function () {
|
||||
|
||||
var package = new helpers.TempDir({
|
||||
'bower.json': {
|
||||
name: 'foobar',
|
||||
version: '0.0.0'
|
||||
}
|
||||
});
|
||||
|
||||
var gitPackage = new helpers.TempDir({
|
||||
'v0.0.0': {
|
||||
'bower.json': {
|
||||
name: 'foobar',
|
||||
version: '0.0.0'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('bumps patch version', function() {
|
||||
package.prepare();
|
||||
|
||||
return helpers.run(version, ['patch', {}, { cwd: package.path }]).then(function() {
|
||||
expect(package.readJson('bower.json').version).to.be('0.0.1');
|
||||
});
|
||||
});
|
||||
|
||||
it('bumps minor version', function() {
|
||||
package.prepare();
|
||||
|
||||
return helpers.run(version, ['minor', {}, { cwd: package.path }]).then(function() {
|
||||
expect(package.readJson('bower.json').version).to.be('0.1.0');
|
||||
});
|
||||
});
|
||||
|
||||
it('bumps major version', function() {
|
||||
package.prepare();
|
||||
|
||||
return helpers.run(version, ['major', {}, { cwd: package.path }]).then(function() {
|
||||
expect(package.readJson('bower.json').version).to.be('1.0.0');
|
||||
});
|
||||
});
|
||||
|
||||
it('changes version', function() {
|
||||
package.prepare();
|
||||
|
||||
return helpers.run(version, ['1.2.3', {}, { cwd: package.path }]).then(function() {
|
||||
expect(package.readJson('bower.json').version).to.be('1.2.3');
|
||||
});
|
||||
});
|
||||
|
||||
it('returns the new version', function() {
|
||||
package.prepare();
|
||||
|
||||
return helpers.run(version, ['major', {}, { cwd: package.path }]).then(function(results) {
|
||||
expect(results[0]).to.be('1.0.0');
|
||||
});
|
||||
});
|
||||
|
||||
it('bumps patch version, create commit, and tag', function() {
|
||||
gitPackage.prepareGit();
|
||||
|
||||
return helpers.run(version, ['patch', {}, { cwd: gitPackage.path }]).then(function() {
|
||||
expect(gitPackage.readJson('bower.json').version).to.be('0.0.1');
|
||||
|
||||
var tags = gitPackage.git('tag');
|
||||
expect(tags).to.be('v0.0.0\nv0.0.1\n');
|
||||
var message = gitPackage.git('log', '--pretty=format:%s', '-n1');
|
||||
expect(message).to.be('v0.0.1');
|
||||
});
|
||||
});
|
||||
|
||||
it('bumps with custom commit message', function() {
|
||||
gitPackage.prepareGit();
|
||||
|
||||
return helpers.run(version, ['patch', { message: 'Bumping %s, because what'}, { cwd: gitPackage.path }]).then(function() {
|
||||
expect(gitPackage.readJson('bower.json').version).to.be('0.0.1');
|
||||
|
||||
var tags = gitPackage.git('tag');
|
||||
expect(tags).to.be('v0.0.0\nv0.0.1\n');
|
||||
var message = gitPackage.git('log', '--pretty=format:%s', '-n1');
|
||||
expect(message).to.be('Bumping 0.0.1, because what');
|
||||
});
|
||||
});
|
||||
});
|
||||
270
test/core/Manager.js
Normal file
270
test/core/Manager.js
Normal file
@@ -0,0 +1,270 @@
|
||||
var expect = require('expect.js');
|
||||
var path = require('path');
|
||||
var rimraf = require('rimraf');
|
||||
var Logger = require('bower-logger');
|
||||
var Manager = require('../../lib/core/Manager');
|
||||
var defaultConfig = require('../../lib/config');
|
||||
|
||||
describe('Manager', function () {
|
||||
var manager;
|
||||
|
||||
var packagesCacheDir =
|
||||
path.join(__dirname, '../assets/temp-resolve-cache');
|
||||
|
||||
var registryCacheDir =
|
||||
path.join(__dirname, '../assets/temp-registry-cache');
|
||||
|
||||
after(function () {
|
||||
rimraf.sync(registryCacheDir);
|
||||
rimraf.sync(packagesCacheDir);
|
||||
});
|
||||
|
||||
beforeEach(function (next) {
|
||||
var logger = new Logger();
|
||||
|
||||
var config = defaultConfig({
|
||||
storage: {
|
||||
packages: packagesCacheDir,
|
||||
registry: registryCacheDir
|
||||
}
|
||||
});
|
||||
|
||||
manager = new Manager(config, logger);
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
|
||||
describe('_areCompatible', function () {
|
||||
describe('resolved is being fetched', function() {
|
||||
|
||||
it('accepts endpoints with same targets', function () {
|
||||
expect(manager._areCompatible(
|
||||
{ name: 'foo', target: 'xxx' },
|
||||
{ name: 'bar', target: 'xxx' }
|
||||
)).to.be(true);
|
||||
});
|
||||
|
||||
it('rejects endpoints with different targets', function () {
|
||||
expect(manager._areCompatible(
|
||||
{ name: 'foo', target: 'xxx' },
|
||||
{ name: 'bar', target: 'yyy' }
|
||||
)).to.be(false);
|
||||
});
|
||||
|
||||
it('accepts with version and matching range', function () {
|
||||
expect(manager._areCompatible(
|
||||
{ name: 'foo', target: '0.1.2' },
|
||||
{ name: 'bar', target: '~0.1.0' }
|
||||
)).to.be(true);
|
||||
});
|
||||
|
||||
it('rejects with version and non-matching range', function () {
|
||||
expect(manager._areCompatible(
|
||||
{ name: 'foo', target: '0.1.2' },
|
||||
{ name: 'bar', target: '~0.1.3' }
|
||||
)).to.be(false);
|
||||
});
|
||||
|
||||
it('accepts with matching range and version', function () {
|
||||
expect(manager._areCompatible(
|
||||
{ name: 'foo', target: '~0.1.0' },
|
||||
{ name: 'bar', target: '0.1.2' }
|
||||
)).to.be(true);
|
||||
});
|
||||
|
||||
it('accepts with non-matching range and version', function () {
|
||||
expect(manager._areCompatible(
|
||||
{ name: 'foo', target: '~0.1.3' },
|
||||
{ name: 'bar', target: '0.1.2' }
|
||||
)).to.be(false);
|
||||
});
|
||||
|
||||
it('accepts with matching ranges', function () {
|
||||
expect(manager._areCompatible(
|
||||
{ name: 'foo', target: '~0.1.0' },
|
||||
{ name: 'bar', target: '~0.1.3' }
|
||||
)).to.be(true);
|
||||
});
|
||||
|
||||
it('rejects with non-matching ranges', function () {
|
||||
expect(manager._areCompatible(
|
||||
{ name: 'foo', target: '~0.1.0' },
|
||||
{ name: 'bar', target: '~0.2.3' }
|
||||
)).to.be(false);
|
||||
});
|
||||
|
||||
it('rejects with non-matching ranges', function () {
|
||||
expect(manager._areCompatible(
|
||||
{ name: 'foo', target: '~0.1.0' },
|
||||
{ name: 'bar', target: 'xxx' }
|
||||
)).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolved is already fetched', function () {
|
||||
var resolved = {
|
||||
name: 'foo',
|
||||
target: '~1.2.1',
|
||||
pkgMeta: {
|
||||
version: '1.2.3'
|
||||
}
|
||||
};
|
||||
|
||||
it('accepts if the same version as resolved', function () {
|
||||
expect(manager._areCompatible(
|
||||
{ name: 'foo', target: '1.2.3' },
|
||||
resolved
|
||||
)).to.be(true);
|
||||
});
|
||||
|
||||
it('rejects if different version than resolved', function () {
|
||||
expect(manager._areCompatible(
|
||||
{ name: 'foo', target: '1.2.4' },
|
||||
resolved
|
||||
)).to.be(false);
|
||||
});
|
||||
|
||||
it('accepts if range matches resolved version', function () {
|
||||
expect(manager._areCompatible(
|
||||
{ name: 'foo', target: '~1.2.1' },
|
||||
resolved
|
||||
)).to.be(true);
|
||||
});
|
||||
|
||||
it('rejects if range does not match', function () {
|
||||
expect(manager._areCompatible(
|
||||
{ name: 'foo', target: '~1.2.4' },
|
||||
resolved
|
||||
)).to.be(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('_getCap', function () {
|
||||
it('finds highest bound', function () {
|
||||
var highest = manager._getCap(
|
||||
[['2.1.1-0', '<2.2.0-0'], '<3.2.0'],
|
||||
'highest'
|
||||
);
|
||||
|
||||
expect(highest).to.eql({
|
||||
version: '3.2.0',
|
||||
comparator: '<'
|
||||
});
|
||||
});
|
||||
|
||||
it('finds lowest bound', function () {
|
||||
var highest = manager._getCap(
|
||||
[['2.1.1-0', '<2.2.0-0'], '<3.2.0'],
|
||||
'lowest'
|
||||
);
|
||||
|
||||
expect(highest).to.eql({
|
||||
version: '2.1.1-0',
|
||||
comparator: ''
|
||||
});
|
||||
});
|
||||
|
||||
it('defaults to highest bound', function () {
|
||||
var highest = manager._getCap(
|
||||
['1.0.0', '2.0.0']
|
||||
);
|
||||
|
||||
expect(highest).to.eql({
|
||||
version: '2.0.0',
|
||||
comparator: ''
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('ignores non-semver elements', function () {
|
||||
var highest = manager._getCap(
|
||||
['0.9', '>1.0.1', ['<1.0.0', 'lol']]
|
||||
);
|
||||
|
||||
expect(highest).to.eql({
|
||||
version: '1.0.1',
|
||||
comparator: '>'
|
||||
});
|
||||
});
|
||||
|
||||
it('returns empty object if cap is not found', function () {
|
||||
var highest = manager._getCap(
|
||||
['0.9'] // Not a semver
|
||||
);
|
||||
|
||||
expect(highest).to.eql({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('_uniquify', function () {
|
||||
|
||||
it('leaves last unique element', function () {
|
||||
var unique = manager._uniquify([
|
||||
{ name: 'foo', id: 1 },
|
||||
{ name: 'foo', id: 2 }
|
||||
]);
|
||||
expect(unique).to.eql([
|
||||
{ name: 'foo', id: 2 }
|
||||
]);
|
||||
});
|
||||
|
||||
it('compares by name first', function () {
|
||||
var unique = manager._uniquify([
|
||||
{ name: 'foo', source: 'google.com' },
|
||||
{ name: 'foo', source: 'facebook.com' }
|
||||
]);
|
||||
|
||||
expect(unique).to.eql([
|
||||
{ name: 'foo', source: 'facebook.com' }
|
||||
]);
|
||||
});
|
||||
|
||||
it('compares by source if name is not available', function () {
|
||||
var unique = manager._uniquify([
|
||||
{ source: 'facebook.com' },
|
||||
{ source: 'facebook.com' }
|
||||
]);
|
||||
|
||||
expect(unique).to.eql([
|
||||
{ source: 'facebook.com' }
|
||||
]);
|
||||
});
|
||||
|
||||
it('leaves different targets intact', function() {
|
||||
var unique = manager._uniquify([
|
||||
{ source: 'facebook.com', target: 'a1b2c3' },
|
||||
{ source: 'facebook.com', target: 'ffffff' }
|
||||
]);
|
||||
|
||||
expect(unique).to.eql([
|
||||
{ source: 'facebook.com', target: 'a1b2c3' },
|
||||
{ source: 'facebook.com', target: 'ffffff' }
|
||||
]);
|
||||
});
|
||||
|
||||
it('removes if same targets', function() {
|
||||
var unique = manager._uniquify([
|
||||
{ source: 'facebook.com', target: 'ffffff' },
|
||||
{ source: 'facebook.com', target: 'ffffff' }
|
||||
]);
|
||||
|
||||
expect(unique).to.eql([
|
||||
{ source: 'facebook.com', target: 'ffffff' }
|
||||
]);
|
||||
});
|
||||
|
||||
it('ignores other fields', function() {
|
||||
var unique = manager._uniquify([
|
||||
{ source: 'facebook.com', foo: 12 },
|
||||
{ source: 'facebook.com', bar: 13 }
|
||||
]);
|
||||
|
||||
expect(unique).to.eql([
|
||||
{ source: 'facebook.com', bar: 13 }
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -11,6 +11,7 @@ var defaultConfig = require('../../lib/config');
|
||||
var ResolveCache = require('../../lib/core/ResolveCache');
|
||||
var resolvers = require('../../lib/core/resolvers');
|
||||
var copy = require('../../lib/util/copy');
|
||||
var helpers = require('../helpers');
|
||||
|
||||
describe('PackageRepository', function () {
|
||||
var packageRepository;
|
||||
@@ -18,10 +19,12 @@ describe('PackageRepository', function () {
|
||||
var resolverFactoryHook;
|
||||
var resolverFactoryClearHook;
|
||||
var testPackage = path.resolve(__dirname, '../assets/package-a');
|
||||
var tempPackage = path.resolve(__dirname, '../assets/temp');
|
||||
var packagesCacheDir = path.join(__dirname, '../assets/temp-resolve-cache');
|
||||
var registryCacheDir = path.join(__dirname, '../assets/temp-registry-cache');
|
||||
var mockSource = 'file://' + testPackage;
|
||||
var tempPackage = path.resolve(__dirname, '../tmp/temp-package');
|
||||
var packagesCacheDir = path.join(__dirname, '../tmp/temp-resolve-cache');
|
||||
var registryCacheDir = path.join(__dirname, '../tmp/temp-registry-cache');
|
||||
var mockSource = helpers.localSource(testPackage);
|
||||
|
||||
var forceCaching = true;
|
||||
|
||||
after(function () {
|
||||
rimraf.sync(registryCacheDir);
|
||||
@@ -34,7 +37,7 @@ describe('PackageRepository', function () {
|
||||
var logger = new Logger();
|
||||
|
||||
// Config
|
||||
config = mout.object.deepMixIn({}, defaultConfig, {
|
||||
config = defaultConfig({
|
||||
storage: {
|
||||
packages: packagesCacheDir,
|
||||
registry: registryCacheDir
|
||||
@@ -51,12 +54,20 @@ describe('PackageRepository', function () {
|
||||
decEndpoint.source = mockSource;
|
||||
|
||||
resolver = new resolvers.GitRemote(decEndpoint, _config, _logger);
|
||||
|
||||
if (forceCaching) {
|
||||
// Force to use cache even for local resources
|
||||
resolver.isCacheable = function () {
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
resolverFactoryHook(resolver);
|
||||
|
||||
return Q.resolve(resolver);
|
||||
}
|
||||
resolverFactory.getConstructor = function () {
|
||||
return Q.resolve([resolvers.GitRemote, 'file://' + testPackage, false]);
|
||||
return Q.resolve([resolvers.GitRemote, helpers.localSource(testPackage), false]);
|
||||
};
|
||||
resolverFactory.clearRuntimeCache = function () {
|
||||
resolverFactoryClearHook();
|
||||
@@ -140,7 +151,7 @@ describe('PackageRepository', function () {
|
||||
});
|
||||
|
||||
it('should attempt to retrieve a resolved package from the resolve package', function (next) {
|
||||
var called;
|
||||
var called = false;
|
||||
var originalRetrieve = packageRepository._resolveCache.retrieve;
|
||||
|
||||
packageRepository._resolveCache.retrieve = function (source) {
|
||||
@@ -161,6 +172,31 @@ describe('PackageRepository', function () {
|
||||
.done();
|
||||
});
|
||||
|
||||
it('should avoid using cache for local resources', function (next) {
|
||||
forceCaching = false;
|
||||
|
||||
var called = false;
|
||||
var originalRetrieve = packageRepository._resolveCache.retrieve;
|
||||
|
||||
packageRepository._resolveCache.retrieve = function (source) {
|
||||
called = true;
|
||||
expect(source).to.be(mockSource);
|
||||
return originalRetrieve.apply(this, arguments);
|
||||
};
|
||||
|
||||
packageRepository.fetch({ name: '', source: helpers.localSource(testPackage), target: '~0.1.0' })
|
||||
.spread(function (canonicalDir, pkgMeta) {
|
||||
expect(called).to.be(false);
|
||||
expect(fs.existsSync(canonicalDir)).to.be(true);
|
||||
expect(pkgMeta).to.be.an('object');
|
||||
expect(pkgMeta.name).to.be('package-a');
|
||||
expect(pkgMeta.version).to.be('0.1.1');
|
||||
forceCaching = true;
|
||||
next();
|
||||
})
|
||||
.done();
|
||||
});
|
||||
|
||||
it('should just call the resolver resolve method if no appropriate package was found in the resolve cache', function (next) {
|
||||
var called = [];
|
||||
|
||||
|
||||
@@ -14,16 +14,16 @@ var md5 = require('../../lib/util/md5');
|
||||
describe('ResolveCache', function () {
|
||||
var resolveCache;
|
||||
var testPackage = path.resolve(__dirname, '../assets/package-a');
|
||||
var tempPackage = path.resolve(__dirname, '../assets/temp');
|
||||
var tempPackage2 = path.resolve(__dirname, '../assets/temp2');
|
||||
var cacheDir = path.join(__dirname, '../assets/temp-resolve-cache');
|
||||
var tempPackage = path.resolve(__dirname, '../tmp/temp-package');
|
||||
var tempPackage2 = path.resolve(__dirname, '../tmp/temp2-package');
|
||||
var cacheDir = path.join(__dirname, '../tmp/temp-resolve-cache');
|
||||
|
||||
before(function (next) {
|
||||
// Delete cache folder
|
||||
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
|
||||
}
|
||||
@@ -908,7 +908,6 @@ describe('ResolveCache', function () {
|
||||
expect(entries).to.be.an('array');
|
||||
|
||||
expectedJson = fs.readFileSync(path.join(__dirname, '../assets/resolve-cache/list-json-1.json'));
|
||||
expectedJson = expectedJson.toString();
|
||||
|
||||
mout.object.forOwn(entries, function (entry) {
|
||||
// Trim absolute bower path from json
|
||||
@@ -917,8 +916,7 @@ describe('ResolveCache', function () {
|
||||
entry.canonicalDir = entry.canonicalDir.replace(/\\/g, '/');
|
||||
});
|
||||
|
||||
json = JSON.stringify(entries, null, ' ');
|
||||
expect(json).to.equal(expectedJson);
|
||||
expect(entries).to.eql(JSON.parse(expectedJson));
|
||||
|
||||
next();
|
||||
})
|
||||
|
||||
@@ -10,13 +10,14 @@ var Logger = require('bower-logger');
|
||||
var resolverFactory = require('../../lib/core/resolverFactory');
|
||||
var resolvers = require('../../lib/core/resolvers');
|
||||
var defaultConfig = require('../../lib/config');
|
||||
var helpers = require('../helpers');
|
||||
|
||||
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();
|
||||
@@ -30,11 +31,11 @@ describe('resolverFactory', function () {
|
||||
});
|
||||
|
||||
after(function (next) {
|
||||
rimraf('dejavu', next);
|
||||
rimraf('pure', next);
|
||||
});
|
||||
|
||||
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) {
|
||||
@@ -339,7 +340,9 @@ describe('resolverFactory', function () {
|
||||
.done();
|
||||
});
|
||||
|
||||
it('should recognize svn remote endpoints correctly', function (next) {
|
||||
if (!helpers.hasSvn())
|
||||
describe.skip('should recognize svn remote endpoints correctly', function() {});
|
||||
else it('should recognize svn remote endpoints correctly', function (next) {
|
||||
var promise = Q.resolve();
|
||||
var endpoints;
|
||||
|
||||
@@ -421,7 +424,7 @@ describe('resolverFactory', function () {
|
||||
var endpoints;
|
||||
var temp;
|
||||
|
||||
tempSource = path.resolve(__dirname, '../assets/tmp');
|
||||
tempSource = path.resolve(__dirname, '../tmp/tmp');
|
||||
mkdirp.sync(tempSource);
|
||||
fs.writeFileSync(path.join(tempSource, '.git'), 'foo');
|
||||
fs.writeFileSync(path.join(tempSource, 'file.with.multiple.dots'), 'foo');
|
||||
@@ -431,7 +434,7 @@ describe('resolverFactory', function () {
|
||||
// Absolute path to folder with .git file
|
||||
endpoints[tempSource] = tempSource;
|
||||
// Relative path to folder with .git file
|
||||
endpoints[__dirname + '/../assets/tmp'] = tempSource;
|
||||
endpoints[__dirname + '/../tmp/tmp'] = tempSource;
|
||||
|
||||
// Absolute path to folder
|
||||
temp = path.resolve(__dirname, '../assets/test-temp-dir');
|
||||
@@ -524,31 +527,31 @@ describe('resolverFactory', function () {
|
||||
});
|
||||
|
||||
it('should recognize registry endpoints correctly', function (next) {
|
||||
// Create a 'dejavu' file at the root to prevent regressions of #666
|
||||
fs.writeFileSync('dejavu', 'foo');
|
||||
// Create a 'pure' file at the root to prevent regressions of #666
|
||||
fs.writeFileSync('pure', 'foo');
|
||||
|
||||
callFactory({ source: 'dejavu' })
|
||||
callFactory({ source: 'pure' })
|
||||
.then(function (resolver) {
|
||||
expect(resolver).to.be.a(resolvers.GitRemote);
|
||||
expect(resolver.getSource()).to.equal('git://github.com/IndigoUnited/dejavu.git');
|
||||
expect(resolver.getSource()).to.equal('git://github.com/yui/pure-release.git');
|
||||
expect(resolver.getTarget()).to.equal('*');
|
||||
})
|
||||
.then(function () {
|
||||
// Test with name
|
||||
return callFactory({ source: 'dejavu', name: 'foo' })
|
||||
return callFactory({ source: 'pure', name: 'foo' })
|
||||
.then(function (resolver) {
|
||||
expect(resolver).to.be.a(resolvers.GitRemote);
|
||||
expect(resolver.getSource()).to.equal('git://github.com/IndigoUnited/dejavu.git');
|
||||
expect(resolver.getSource()).to.equal('git://github.com/yui/pure-release.git');
|
||||
expect(resolver.getName()).to.equal('foo');
|
||||
expect(resolver.getTarget()).to.equal('*');
|
||||
});
|
||||
})
|
||||
.then(function () {
|
||||
// Test with target
|
||||
return callFactory({ source: 'dejavu', target: '~2.0.0' })
|
||||
return callFactory({ source: 'pure', target: '~0.4.0' })
|
||||
.then(function (resolver) {
|
||||
expect(resolver).to.be.a(resolvers.GitRemote);
|
||||
expect(resolver.getTarget()).to.equal('~2.0.0');
|
||||
expect(resolver.getTarget()).to.equal('~0.4.0');
|
||||
|
||||
next();
|
||||
});
|
||||
@@ -571,7 +574,7 @@ describe('resolverFactory', function () {
|
||||
});
|
||||
|
||||
it('should set registry to true on the decomposed endpoint if fetched from the registry', function (next) {
|
||||
var decEndpoint = { source: 'dejavu' };
|
||||
var decEndpoint = { source: 'pure' };
|
||||
|
||||
callFactory(decEndpoint)
|
||||
.then(function () {
|
||||
@@ -584,14 +587,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 +617,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) {
|
||||
|
||||
@@ -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 () {
|
||||
@@ -82,7 +82,7 @@ describe('FsResolver', function () {
|
||||
it('should resolve always to true (for now..)', function (next) {
|
||||
var resolver = create(testPackage);
|
||||
|
||||
tempSource = path.resolve(__dirname, '../../assets/tmp');
|
||||
tempSource = path.resolve(__dirname, '../../tmp/tmp');
|
||||
mkdirp.sync(tempSource);
|
||||
fs.writeFileSync(path.join(tempSource, '.bower.json'), JSON.stringify({
|
||||
name: 'test'
|
||||
@@ -161,7 +161,7 @@ describe('FsResolver', function () {
|
||||
it('should rename to index if source is a folder with just one file in it', function (next) {
|
||||
var resolver;
|
||||
|
||||
tempSource = path.resolve(__dirname, '../../assets/tmp');
|
||||
tempSource = path.resolve(__dirname, '../../tmp/tmp');
|
||||
|
||||
mkdirp.sync(tempSource);
|
||||
resolver = create(tempSource);
|
||||
@@ -181,7 +181,7 @@ describe('FsResolver', function () {
|
||||
it('should not rename to index if source is a folder with just bower.json/component.json file in it', function (next) {
|
||||
var resolver;
|
||||
|
||||
tempSource = path.resolve(__dirname, '../../assets/tmp');
|
||||
tempSource = path.resolve(__dirname, '../../tmp/tmp');
|
||||
|
||||
mkdirp.sync(tempSource);
|
||||
resolver = create(tempSource);
|
||||
@@ -235,7 +235,7 @@ describe('FsResolver', function () {
|
||||
var mode0777;
|
||||
var resolver;
|
||||
|
||||
tempSource = path.resolve(__dirname, '../../assets/temp');
|
||||
tempSource = path.resolve(__dirname, '../../tmp/temp-source');
|
||||
resolver = create(tempSource);
|
||||
|
||||
copy.copyFile(path.join(testPackage, 'foo'), tempSource)
|
||||
|
||||
@@ -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 () {
|
||||
@@ -78,6 +70,8 @@ describe('GitHub', function () {
|
||||
});
|
||||
|
||||
it('should retry using the GitRemoteResolver mechanism if download failed', function (next) {
|
||||
this.timeout(20000);
|
||||
|
||||
var resolver;
|
||||
var retried;
|
||||
|
||||
@@ -108,6 +102,8 @@ describe('GitHub', function () {
|
||||
});
|
||||
|
||||
it('should retry using the GitRemoteResolver mechanism if extraction failed', function (next) {
|
||||
this.timeout(20000);
|
||||
|
||||
var resolver;
|
||||
var retried;
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@ var expect = require('expect.js');
|
||||
var path = require('path');
|
||||
var fs = require('graceful-fs');
|
||||
var Logger = require('bower-logger');
|
||||
var helpers = require('../../helpers');
|
||||
var Q = require('q');
|
||||
var mout = require('mout');
|
||||
var multiline = require('multiline').stripIndent;
|
||||
var GitRemoteResolver = require('../../../lib/core/resolvers/GitRemoteResolver');
|
||||
var defaultConfig = require('../../../lib/config');
|
||||
|
||||
@@ -21,12 +25,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 () {
|
||||
@@ -106,6 +110,92 @@ describe('GitRemoteResolver', function () {
|
||||
.done();
|
||||
});
|
||||
|
||||
describe('shallow cloning', function () {
|
||||
var gitRemoteResolverFactory;
|
||||
|
||||
beforeEach(function () {
|
||||
gitRemoteResolverFactory = function (handler) {
|
||||
return helpers.require('lib/core/resolvers/GitRemoteResolver', {
|
||||
'../../util/cmd': handler
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
it('should add --depth=1 when shallow cloning is supported', function (next) {
|
||||
var testSource = 'http://foo/bar.git';
|
||||
|
||||
var MyGitRemoteResolver = gitRemoteResolverFactory(function (cmd, args) {
|
||||
// The first git call fetches the tags for the provided source
|
||||
if (mout.array.equals(args, ['ls-remote', '--tags', '--heads', testSource])) {
|
||||
// Return list of commits, including one tag.
|
||||
// The tag will be used for the clone call.
|
||||
return Q.all([multiline(function () {/*
|
||||
e4655d250f2a3f64ef2d712f25dafa60652bb93e refs/heads/some-branch
|
||||
0a7daf646d4fd743b6ef701d63bdbe20eee422de refs/tags/0.0.1
|
||||
*/
|
||||
})]);
|
||||
}
|
||||
else if (args[0] === 'clone') {
|
||||
// Verify parameters of the clone call.
|
||||
// In this case, the arguments need to contain "--depth 1".
|
||||
expect(args).to.eql(['clone', 'http://foo/bar.git', '-b', '0.0.1', '--progress', '.', '--depth', 1]);
|
||||
|
||||
// In this case, only the stderr content is evaluated. Everything's fine as long as it
|
||||
// does not contain any error description.
|
||||
return Q.all(['stdout', 'stderr']);
|
||||
}
|
||||
});
|
||||
|
||||
// Mock the call, return true for this test.
|
||||
MyGitRemoteResolver.prototype._supportsShallowCloning = function () {
|
||||
return Q.resolve(true);
|
||||
};
|
||||
|
||||
var resolver = new MyGitRemoteResolver({ source: testSource }, defaultConfig(), logger);
|
||||
|
||||
resolver.resolve().then(function () {
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not add --depth=1 when shallow cloning is not supported', function (next) {
|
||||
var testSource = 'http://foo/bar.git';
|
||||
|
||||
var MyGitRemoteResolver = gitRemoteResolverFactory(function (cmd, args) {
|
||||
// The first git call fetches the tags for the provided source
|
||||
if (mout.array.equals(args, ['ls-remote', '--tags', '--heads', testSource])) {
|
||||
// Return list of commits, including one tag.
|
||||
// The tag will be used for the clone call.
|
||||
return Q.all([multiline(function () {/*
|
||||
e4655d250f2a3f64ef2d712f25dafa60652bb93e refs/heads/some-branch
|
||||
0a7daf646d4fd743b6ef701d63bdbe20eee422de refs/tags/0.0.1
|
||||
*/
|
||||
})]);
|
||||
}
|
||||
else if (args[0] === 'clone') {
|
||||
// Verify parameters of the clone call.
|
||||
// In this case, the arguments should not contain "--depth 1".
|
||||
expect(args).to.eql(['clone', 'http://foo/bar.git', '-b', '0.0.1', '--progress', '.']);
|
||||
|
||||
// In this case, only the stderr content is evaluated. Everything's fine as long as it
|
||||
// does not contain any error description.
|
||||
return Q.all(['stdout', 'stderr']);
|
||||
}
|
||||
});
|
||||
|
||||
// Mock the call, return false for this test.
|
||||
MyGitRemoteResolver.prototype._supportsShallowCloning = function () {
|
||||
return Q.resolve(false);
|
||||
};
|
||||
|
||||
var resolver = new MyGitRemoteResolver({ source: testSource }, defaultConfig(), logger);
|
||||
|
||||
resolver.resolve().then(function () {
|
||||
next();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it.skip('should handle gracefully servers that do not support --depth=1');
|
||||
it.skip('should report progress when it takes too long to clone');
|
||||
});
|
||||
@@ -162,4 +252,251 @@ describe('GitRemoteResolver', function () {
|
||||
.done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#_supportsShallowCloning', function () {
|
||||
var gitRemoteResolverFactory;
|
||||
|
||||
beforeEach(function () {
|
||||
gitRemoteResolverFactory = function (handler) {
|
||||
return helpers.require('lib/core/resolvers/GitRemoteResolver', {
|
||||
'../../util/cmd': handler
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
function createCmdHandlerFn (testSource, stderr) {
|
||||
return function (cmd, args, options) {
|
||||
expect(cmd).to.be('git');
|
||||
expect(args).to.eql([ 'ls-remote', '--heads', testSource ]);
|
||||
expect(options.env.GIT_CURL_VERBOSE).to.be(2);
|
||||
|
||||
return Q.all(['stdout', stderr]);
|
||||
};
|
||||
}
|
||||
|
||||
it('should call ls-remote when using http protocol', function (next) {
|
||||
var testSource = 'http://foo/bar.git';
|
||||
|
||||
var MyGitRemoteResolver = gitRemoteResolverFactory(
|
||||
createCmdHandlerFn(testSource, multiline(function () {/*
|
||||
foo: bar
|
||||
Content-Type: none
|
||||
1234: 5678
|
||||
*/}))
|
||||
);
|
||||
|
||||
var resolver = new MyGitRemoteResolver({ source: testSource }, defaultConfig(), logger);
|
||||
|
||||
resolver._shallowClone().then(function (shallowCloningSupported) {
|
||||
expect(shallowCloningSupported).to.be(false);
|
||||
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
it('should call ls-remote when using https protocol', function (next) {
|
||||
var testSource = 'https://foo/bar.git';
|
||||
|
||||
var MyGitRemoteResolver = gitRemoteResolverFactory(
|
||||
createCmdHandlerFn(testSource, multiline(function () {/*
|
||||
foo: bar
|
||||
Content-Type: none
|
||||
1234: 5678
|
||||
*/}))
|
||||
);
|
||||
|
||||
var resolver = new MyGitRemoteResolver({ source: testSource }, defaultConfig(), logger);
|
||||
|
||||
resolver._shallowClone().then(function (shallowCloningSupported) {
|
||||
expect(shallowCloningSupported).to.be(false);
|
||||
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
it('should evaluate to false when the URL can not be parsed', function (next) {
|
||||
var testSource = 'grmblfjx///:::.git';
|
||||
|
||||
var MyGitRemoteResolver = gitRemoteResolverFactory(
|
||||
createCmdHandlerFn(testSource, multiline(function () {/*
|
||||
foo: bar
|
||||
Content-Type: none
|
||||
1234: 5678
|
||||
*/}))
|
||||
);
|
||||
|
||||
var resolver = new MyGitRemoteResolver({ source: testSource }, defaultConfig(), logger);
|
||||
|
||||
resolver._shallowClone().then(function (shallowCloningSupported) {
|
||||
expect(shallowCloningSupported).to.be(false);
|
||||
|
||||
next();
|
||||
}, function (err) {
|
||||
next(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('should evaluate to true when the smart content type is returned', function (next) {
|
||||
var testSource = 'https://foo/bar.git';
|
||||
|
||||
var MyGitRemoteResolver = gitRemoteResolverFactory(
|
||||
createCmdHandlerFn(testSource, multiline(function () {/*
|
||||
foo: bar
|
||||
Content-Type: application/x-git-upload-pack-advertisement
|
||||
1234: 5678
|
||||
*/}))
|
||||
);
|
||||
|
||||
var resolver = new MyGitRemoteResolver({ source: testSource }, defaultConfig(), logger);
|
||||
|
||||
resolver._shallowClone().then(function (shallowCloningSupported) {
|
||||
expect(shallowCloningSupported).to.be(true);
|
||||
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
it('should cache hosts that support shallow cloning', function (next) {
|
||||
var testSource = 'https://foo/bar.git';
|
||||
|
||||
var counter = 0;
|
||||
|
||||
var MyGitRemoteResolver = gitRemoteResolverFactory(
|
||||
function (cmd, args, options) {
|
||||
counter++;
|
||||
|
||||
if (counter === 1) {
|
||||
expect(cmd).to.be('git');
|
||||
expect(args).to.eql([ 'ls-remote', '--heads', testSource ]);
|
||||
expect(options.env.GIT_CURL_VERBOSE).to.be(2);
|
||||
|
||||
return Q.all(['stdout', multiline(function () {/*
|
||||
foo: bar
|
||||
Content-Type: application/x-git-upload-pack-advertisement
|
||||
1234: 5678
|
||||
*/
|
||||
})]);
|
||||
}
|
||||
else {
|
||||
return Q.reject(new Error('More calls than expected'));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
var resolver = new MyGitRemoteResolver({ source: testSource }, defaultConfig(), logger);
|
||||
|
||||
resolver._shallowClone().then(function (shallowCloningSupported) {
|
||||
expect(shallowCloningSupported).to.be(true);
|
||||
|
||||
var resolver2 = new MyGitRemoteResolver({ source: testSource }, defaultConfig(), logger);
|
||||
|
||||
resolver2._shallowClone().then(function (shallowCloningSupported) {
|
||||
expect(shallowCloningSupported).to.be(true);
|
||||
|
||||
next();
|
||||
}, function(err) {
|
||||
next(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should cache hosts that support shallow cloning across multiple repos', function (next) {
|
||||
var testSource1 = 'https://foo/bar.git';
|
||||
var testSource2 = 'https://foo/barbaz.git';
|
||||
|
||||
var counter = 0;
|
||||
|
||||
var MyGitRemoteResolver = gitRemoteResolverFactory(
|
||||
function (cmd, args, options) {
|
||||
counter++;
|
||||
|
||||
if (counter === 1) {
|
||||
expect(cmd).to.be('git');
|
||||
expect(args).to.eql([ 'ls-remote', '--heads', testSource1 ]);
|
||||
expect(options.env.GIT_CURL_VERBOSE).to.be(2);
|
||||
|
||||
return Q.all(['stdout', multiline(function () {/*
|
||||
foo: bar
|
||||
Content-Type: application/x-git-upload-pack-advertisement
|
||||
1234: 5678
|
||||
*/
|
||||
})]);
|
||||
}
|
||||
else {
|
||||
return Q.reject(new Error('More calls than expected'));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
var resolver = new MyGitRemoteResolver({ source: testSource1 }, defaultConfig(), logger);
|
||||
|
||||
resolver._shallowClone().then(function (shallowCloningSupported) {
|
||||
expect(shallowCloningSupported).to.be(true);
|
||||
|
||||
var resolver2 = new MyGitRemoteResolver({ source: testSource2 }, defaultConfig(), logger);
|
||||
|
||||
resolver2._shallowClone().then(function (shallowCloningSupported) {
|
||||
expect(shallowCloningSupported).to.be(true);
|
||||
|
||||
next();
|
||||
}, function(err) {
|
||||
next(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should run separate checks for separate hosts ', function (next) {
|
||||
var testSource1 = 'https://foo/bar.git';
|
||||
var testSource2 = 'https://foo.bar.baz/barbaz.git';
|
||||
|
||||
var counter = 0;
|
||||
|
||||
var MyGitRemoteResolver = gitRemoteResolverFactory(
|
||||
function (cmd, args, options) {
|
||||
counter++;
|
||||
|
||||
if (counter === 1) {
|
||||
expect(cmd).to.be('git');
|
||||
expect(args).to.eql([ 'ls-remote', '--heads', testSource1 ]);
|
||||
expect(options.env.GIT_CURL_VERBOSE).to.be(2);
|
||||
|
||||
return Q.all(['stdout', multiline(function () {/*
|
||||
foo: bar
|
||||
Content-Type: application/x-git-upload-pack-advertisement
|
||||
1234: 5678
|
||||
*/
|
||||
})]);
|
||||
}
|
||||
else {
|
||||
expect(cmd).to.be('git');
|
||||
expect(args).to.eql([ 'ls-remote', '--heads', testSource2 ]);
|
||||
expect(options.env.GIT_CURL_VERBOSE).to.be(2);
|
||||
|
||||
return Q.all(['stdout', multiline(function () {/*
|
||||
foo: barbaz
|
||||
Content-Type: application/x-git-upload-pack-advertisement
|
||||
1234: 5678
|
||||
*/
|
||||
})]);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
var resolver = new MyGitRemoteResolver({ source: testSource1 }, defaultConfig(), logger);
|
||||
|
||||
resolver._shallowClone().then(function (shallowCloningSupported) {
|
||||
expect(shallowCloningSupported).to.be(true);
|
||||
|
||||
var resolver2 = new MyGitRemoteResolver({ source: testSource2 }, defaultConfig(), logger);
|
||||
|
||||
resolver2._shallowClone().then(function (shallowCloningSupported) {
|
||||
expect(shallowCloningSupported).to.be(true);
|
||||
|
||||
next();
|
||||
}, function(err) {
|
||||
next(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,7 +13,7 @@ var GitResolver = require('../../../lib/core/resolvers/GitResolver');
|
||||
var defaultConfig = require('../../../lib/config');
|
||||
|
||||
describe('GitResolver', function () {
|
||||
var tempDir = path.resolve(__dirname, '../../assets/tmp');
|
||||
var tempDir = path.resolve(__dirname, '../../tmp/tmp');
|
||||
var originalrefs = GitResolver.refs;
|
||||
var logger;
|
||||
|
||||
@@ -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 () {
|
||||
@@ -750,6 +750,27 @@ describe('GitResolver', function () {
|
||||
.done();
|
||||
});
|
||||
|
||||
it('should resolve to the specified short commit', function (next) {
|
||||
var resolver;
|
||||
|
||||
GitResolver.refs = function () {
|
||||
return Q.resolve([
|
||||
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa refs/heads/master'
|
||||
]);
|
||||
};
|
||||
|
||||
resolver = create('foo');
|
||||
resolver._findResolution('bbbbbbb')
|
||||
.then(function (resolution) {
|
||||
expect(resolution).to.eql({
|
||||
type: 'commit',
|
||||
commit: 'bbbbbbb'
|
||||
});
|
||||
next();
|
||||
})
|
||||
.done();
|
||||
});
|
||||
|
||||
it('should resolve to the specified tag if it exists', function (next) {
|
||||
var resolver;
|
||||
|
||||
|
||||
@@ -13,10 +13,11 @@ var Resolver = require('../../../lib/core/resolvers/Resolver');
|
||||
var defaultConfig = require('../../../lib/config');
|
||||
|
||||
describe('Resolver', function () {
|
||||
var tempDir = path.resolve(__dirname, '../../assets/tmp');
|
||||
var tempDir = path.resolve(__dirname, '../../tmp/tmp');
|
||||
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();
|
||||
@@ -676,7 +677,7 @@ describe('Resolver', function () {
|
||||
.done();
|
||||
});
|
||||
|
||||
it('should remove files that match the ignore patterns', function (next) {
|
||||
it('should remove files that match the ignore patterns excluding main files', function (next) {
|
||||
var resolver = create({ source: 'foo', name: 'foo' });
|
||||
|
||||
mkdirp.sync(tempDir);
|
||||
@@ -701,6 +702,8 @@ describe('Resolver', function () {
|
||||
expect(fs.existsSync(path.join(tempDir, 'foo'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(tempDir, 'baz'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(tempDir, 'test'))).to.be(false);
|
||||
expect(fs.existsSync(path.join(tempDir, 'bower.json'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(tempDir, 'main.js'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(tempDir, 'more/docs'))).to.be(false);
|
||||
expect(fs.existsSync(path.join(tempDir, 'more/assets'))).to.be(false);
|
||||
next();
|
||||
@@ -784,6 +787,32 @@ describe('Resolver', function () {
|
||||
})
|
||||
.done();
|
||||
});
|
||||
|
||||
it('should warn user for missing attributes in bower.json', function (next) {
|
||||
var resolver = create('fooooo');
|
||||
resolver._tempDir = tempDir;
|
||||
var notifiedCount = 0;
|
||||
logger.on('log', function (log) {
|
||||
notifiedCount ++;
|
||||
expect(log).to.be.an('object');
|
||||
expect(log.level).to.be('warn');
|
||||
if (notifiedCount === 1) {
|
||||
expect(log.message).to.contain('bar is missing "main" entry in bower.json');
|
||||
} else {
|
||||
expect(log.message).to.contain('bar is missing "ignore" entry in bower.json');
|
||||
}
|
||||
});
|
||||
resolver._savePkgMeta({ name: 'bar' });
|
||||
expect(notifiedCount).to.be(2);
|
||||
|
||||
resolver._savePkgMeta({ name: 'bar', main: 'foo' });
|
||||
expect(notifiedCount).to.be(3);
|
||||
|
||||
// should not warn again
|
||||
resolver._savePkgMeta({ name: 'bar', main: 'flart', ignore: 'blat' });
|
||||
expect(notifiedCount).to.be(3);
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isTargetable', function () {
|
||||
@@ -803,5 +832,43 @@ describe('Resolver', function () {
|
||||
})
|
||||
.done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#isCacheable', function () {
|
||||
it('caches for normal name', function () {
|
||||
var resolver = new Resolver({ source: 'foo' });
|
||||
expect(resolver.isCacheable()).to.be(true);
|
||||
});
|
||||
|
||||
it('does not cache for absolute paths', function () {
|
||||
var resolver = new Resolver({ source: '/foo' });
|
||||
expect(resolver.isCacheable()).to.be(false);
|
||||
});
|
||||
|
||||
it('does not cache for relative paths', function () {
|
||||
var resolver = new Resolver({ source: './foo' });
|
||||
expect(resolver.isCacheable()).to.be(false);
|
||||
});
|
||||
|
||||
it('does not cache for parent paths', function () {
|
||||
var resolver = new Resolver({ source: '../foo' });
|
||||
expect(resolver.isCacheable()).to.be(false);
|
||||
});
|
||||
|
||||
it('does not cache for file:/// prefix', function () {
|
||||
var resolver = new Resolver({ source: 'file:///foo' });
|
||||
expect(resolver.isCacheable()).to.be(false);
|
||||
});
|
||||
|
||||
it('does not cache for windows paths', function () {
|
||||
var resolver = new Resolver({ source: '..\\foo' });
|
||||
expect(resolver.isCacheable()).to.be(false);
|
||||
});
|
||||
|
||||
it('does not cache for windows absolute paths', function () {
|
||||
var resolver = new Resolver({ source: 'C:\\foo' });
|
||||
expect(resolver.isCacheable()).to.be(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,20 +2,20 @@ var expect = require('expect.js');
|
||||
var util = require('util');
|
||||
var path = require('path');
|
||||
var fs = require('graceful-fs');
|
||||
var chmodr = require('chmodr');
|
||||
var rimraf = require('rimraf');
|
||||
var mkdirp = require('mkdirp');
|
||||
var Q = require('q');
|
||||
var mout = require('mout');
|
||||
var Logger = require('bower-logger');
|
||||
var copy = require('../../../lib/util/copy');
|
||||
var SvnResolver = require('../../../lib/core/resolvers/SvnResolver');
|
||||
var defaultConfig = require('../../../lib/config');
|
||||
var helpers = require('../../helpers');
|
||||
|
||||
describe('SvnResolver', function () {
|
||||
var tempDir = path.resolve(__dirname, '../../assets/tmp');
|
||||
if (!helpers.hasSvn()) describe.skip('SvnResolver', function() {});
|
||||
else describe('SvnResolver', function () {
|
||||
var tempDir = path.resolve(__dirname, '../../tmp/tmp');
|
||||
var testPackage = path.resolve(__dirname, '../../assets/package-svn/repo');
|
||||
var testPackageAdmin = path.resolve(__dirname, '../../assets/package-svn/admin');
|
||||
// var testPackageAdmin = path.resolve(__dirname, '../../assets/package-svn/admin');
|
||||
var originaltags = SvnResolver.tags;
|
||||
var logger;
|
||||
|
||||
@@ -32,12 +32,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 () {
|
||||
@@ -271,35 +271,24 @@ describe('SvnResolver', function () {
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
DummyResolver.prototype._checkout = function () {
|
||||
this._stack.push('before _checkout');
|
||||
DummyResolver.prototype._export = function () {
|
||||
this._stack.push('before _export');
|
||||
return Q.resolve()
|
||||
.then(function (val) {
|
||||
this._stack.push('after _checkout');
|
||||
this._stack.push('after _export');
|
||||
return val;
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
DummyResolver.prototype._cleanup = function () {
|
||||
this._stack.push('before _cleanup');
|
||||
return SvnResolver.prototype._cleanup.apply(this, arguments)
|
||||
.then(function (val) {
|
||||
this._stack.push('after _cleanup');
|
||||
return val;
|
||||
}.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 () {
|
||||
expect(resolver.getStack()).to.eql([
|
||||
'before _findResolution',
|
||||
'after _findResolution',
|
||||
'before _checkout',
|
||||
'after _checkout',
|
||||
'before _cleanup',
|
||||
'after _cleanup'
|
||||
'before _export',
|
||||
'after _export'
|
||||
]);
|
||||
next();
|
||||
})
|
||||
@@ -608,87 +597,6 @@ describe('SvnResolver', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('._cleanup', function () {
|
||||
beforeEach(function () {
|
||||
mkdirp.sync(tempDir);
|
||||
});
|
||||
|
||||
afterEach(function (next) {
|
||||
clearResolverRuntimeCache();
|
||||
// Need to chmodr before removing..at least on windows
|
||||
// because .svn has some read only files
|
||||
chmodr(tempDir, 0777, function () {
|
||||
rimraf(tempDir, next);
|
||||
});
|
||||
});
|
||||
|
||||
it('should remove the .svn folder from the temp dir', function (next) {
|
||||
var resolver = create('foo');
|
||||
var dst = path.join(tempDir, '.svn');
|
||||
|
||||
this.timeout(30000); // Give some time to copy
|
||||
|
||||
// Copy .svn folder to the tempDir
|
||||
copy.copyDir(path.resolve(__dirname, '../../assets/package-svn/repo/.svn'), dst, {
|
||||
mode: 0777
|
||||
})
|
||||
.then(function () {
|
||||
resolver._tempDir = tempDir;
|
||||
|
||||
return resolver._cleanup()
|
||||
.then(function () {
|
||||
expect(fs.existsSync(dst)).to.be(false);
|
||||
next();
|
||||
});
|
||||
})
|
||||
.done();
|
||||
});
|
||||
|
||||
it('should not fail if .svn does not exist for some reason', function (next) {
|
||||
var resolver = create('foo');
|
||||
var dst = path.join(tempDir, '.svn');
|
||||
|
||||
resolver._tempDir = tempDir;
|
||||
|
||||
resolver._cleanup()
|
||||
.then(function () {
|
||||
expect(fs.existsSync(dst)).to.be(false);
|
||||
next();
|
||||
})
|
||||
.done();
|
||||
});
|
||||
|
||||
it('should sill run even if _checkout fails for some reason', function (next) {
|
||||
var resolver = create('foo');
|
||||
var called = false;
|
||||
|
||||
SvnResolver.tags = function () {
|
||||
return Q.resolve({
|
||||
'1.0.0': 1
|
||||
});
|
||||
};
|
||||
|
||||
resolver._tempDir = tempDir;
|
||||
resolver._checkout = function () {
|
||||
return Q.reject(new Error('Some error'));
|
||||
};
|
||||
|
||||
resolver._cleanup = function () {
|
||||
called = true;
|
||||
return SvnResolver.prototype._cleanup.apply(this, arguments);
|
||||
};
|
||||
|
||||
resolver.resolve()
|
||||
.then(function () {
|
||||
next(new Error('Should have failed'));
|
||||
}, function () {
|
||||
expect(called).to.be(true);
|
||||
next();
|
||||
})
|
||||
.done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('._savePkgMeta', function () {
|
||||
before(function () {
|
||||
mkdirp.sync(tempDir);
|
||||
@@ -1094,17 +1002,18 @@ describe('SvnResolver', function () {
|
||||
it('should guess the name from the path', function () {
|
||||
var resolver;
|
||||
|
||||
resolver = create('file://' + testPackage);
|
||||
resolver = create(helpers.localSource(testPackage));
|
||||
expect(resolver.getName()).to.equal('repo');
|
||||
|
||||
resolver = create('svn+http://yii.googlecode.com/svn');
|
||||
expect(resolver.getName()).to.equal('svn');
|
||||
});
|
||||
});
|
||||
|
||||
describe('.resolve', function () {
|
||||
|
||||
it('should checkout correctly if resolution is a tag', function (next) {
|
||||
var resolver = create({ source: 'file://' + testPackageAdmin, target: '0.0.1' });
|
||||
it('should export correctly if resolution is a tag', function (next) {
|
||||
var resolver = create({ source: testPackage, target: '0.0.1' });
|
||||
|
||||
resolver.resolve()
|
||||
.then(function (dir) {
|
||||
@@ -1119,8 +1028,8 @@ describe('SvnResolver', function () {
|
||||
.done();
|
||||
});
|
||||
|
||||
it('should checkout correctly if resolution is a commit', function (next) {
|
||||
var resolver = create({ source: 'file://' + testPackageAdmin, target: 'r1' });
|
||||
it('should export correctly if resolution is a commit', function (next) {
|
||||
var resolver = create({ source: testPackage, target: 'r1' });
|
||||
|
||||
resolver.resolve()
|
||||
.then(function (dir) {
|
||||
@@ -1136,8 +1045,4 @@ describe('SvnResolver', function () {
|
||||
.done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
@@ -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');
|
||||
@@ -13,7 +12,7 @@ var defaultConfig = require('../../../lib/config');
|
||||
|
||||
describe('UrlResolver', function () {
|
||||
var testPackage = path.resolve(__dirname, '../../assets/package-a');
|
||||
var tempDir = path.resolve(__dirname, '../../assets/tmp');
|
||||
var tempDir = path.resolve(__dirname, '../../tmp/tmp');
|
||||
var logger;
|
||||
|
||||
before(function (next) {
|
||||
@@ -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 () {
|
||||
|
||||
@@ -8,16 +8,26 @@ var scripts = require('../../lib/core/scripts.js');
|
||||
|
||||
describe('scripts', function () {
|
||||
|
||||
var tempDir = path.join(__dirname, '../assets/temp-scripts');
|
||||
var tempDir = path.join(__dirname, '../tmp/temp-scripts');
|
||||
var packageName = 'package-zip';
|
||||
var packageDir = path.join('..', packageName + '.zip');
|
||||
var packageDir = path.join(__dirname, '../assets/' + packageName + '.zip');
|
||||
|
||||
// We cannot use pure touch, because Windows
|
||||
var touch = function (file) {
|
||||
return 'node -e "var fs = require(\'fs\'); fs.closeSync(fs.openSync(\'' + file + '\', \'w\'));"';
|
||||
};
|
||||
|
||||
// We cannot use pure touch, because Windows
|
||||
var touchWithPid = function (file) {
|
||||
return 'node -e "var fs = require(\'fs\'); fs.closeSync(fs.openSync(process.env.BOWER_PID + \'' + file + '\', \'w\'));"';
|
||||
};
|
||||
|
||||
var config = {
|
||||
cwd: tempDir,
|
||||
scripts: {
|
||||
preinstall: 'touch preinstall_%',
|
||||
postinstall: 'touch postinstall_%',
|
||||
preuninstall: 'touch preuninstall_%'
|
||||
preinstall: touch('preinstall_%'),
|
||||
postinstall: touch('postinstall_%'),
|
||||
preuninstall: touch('preuninstall_%')
|
||||
}
|
||||
};
|
||||
|
||||
@@ -112,7 +122,7 @@ describe('scripts', function () {
|
||||
|
||||
it('should process scripts with quotes and vars in the cmd properly.', function (next) {
|
||||
|
||||
config.scripts.preinstall = 'touch "$BOWER_PID %"';
|
||||
config.scripts.preinstall = touchWithPid(' %');
|
||||
|
||||
bower.commands
|
||||
.install([packageDir], undefined, config)
|
||||
@@ -125,4 +135,4 @@ describe('scripts', function () {
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user