Compare commits

..

1217 Commits

Author SHA1 Message Date
Sampo Silvennoinen
4e0c3c1181 CI: add Node.js 18, 20 & 22 (#2630)
* CI workflow: add Node.js 18, 20 & 22

* CI workflow: pin old Node.js versions to older MacOS

MacOS-latest can run Node versions 6 - 14 anymore. Pin them to MacOS-13 to keep the actions running

* CI: update used GH action versions

* CI: allow failure on Windows

All Windows pipelines currently fail for some integration tests. It seems to be a question of running actual git commands inside a Windows based Github action runner. Reverting it to older Windows runner wont help.
2024-10-13 12:45:04 +02:00
Sampo Silvennoinen
a0d4444324 CI workflow: add Node 16 (#2593)
Adds Node 16 to version matrix for tests

Co-authored-by: Adam Stankiewicz <sheerun@sher.pl>
2022-03-14 16:52:35 +01:00
Adam Stankiewicz
d765b2bb88 Bump to 1.8.14 2022-03-14 16:37:01 +01:00
Adam Stankiewicz
ca23b460b3 Run CI only on node 6+ 2022-03-14 16:31:27 +01:00
Eduardo Freitas
7f26c5b856 Fix bug unauthenticated git protocol in GitHubResolver (#2612)
Co-authored-by: Adam Stankiewicz <sheerun@sher.pl>
2022-03-14 16:23:54 +01:00
Adam Stankiewicz
4b5722f2bd Update README.md 2022-03-10 22:30:29 +01:00
Adam Stankiewicz
557c1cd7f1 Fix mode for bin/bower 2021-11-15 04:10:45 +01:00
Adam Stankiewicz
74560b7308 Fix child process execution 2021-11-15 03:58:38 +01:00
Adam Stankiewicz
2905791817 Fix running bower on non-windows 2021-11-15 03:30:58 +01:00
Adam Stankiewicz
dfdda3fda3 Merge remote-tracking branch 'origin/master' 2021-11-15 03:25:18 +01:00
Adam Stankiewicz
fa36814f64 Bump to 1.8.13 2021-11-15 03:23:11 +01:00
Adam Stankiewicz
f19bc34f84 Make sure correct git/svn binary is always used 2021-11-15 03:22:34 +01:00
Ikko Ashimine
eb8659ea32 Fix typo in Manager.js (#2607)
depdendency -> dependency
2021-10-20 14:58:32 +02:00
Ikko Ashimine
537b9b4558 Fix typo in Project.js (#2597)
propery -> property
2021-06-08 10:05:45 +02:00
Adam Stankiewicz
372fefbf1c Finish fixing linting 2021-01-18 17:34:20 +01:00
Adam Stankiewicz
f6ced09f76 Fix linting 2021-01-18 16:48:23 +01:00
Adam Stankiewicz
f18330b248 Bump to 1.8.12 2021-01-18 16:41:52 +01:00
Adam Stankiewicz
a1b5d93f13 Remove wild .npmignore before publishing, #2591 2021-01-18 16:41:32 +01:00
Adam Stankiewicz
74baec8a60 Bump to 1.8.11 2021-01-18 12:00:36 +01:00
Adam Stankiewicz
771c7d0ac8 Fix packaging node_modules 2021-01-18 12:00:15 +01:00
Adam Stankiewicz
50e98031e5 Fix publish script 2021-01-18 11:31:15 +01:00
Adam Stankiewicz
41126ec03e Update build script for 1.8.10 2021-01-18 11:01:39 +01:00
Adam Stankiewicz
bb563b01c2 Bump to 1.8.10 2021-01-14 18:42:22 +01:00
Adam Stankiewicz
c94f3f6422 Fix production packing 2021-01-14 18:42:06 +01:00
Adam Stankiewicz
ab589e46e9 Bump to 1.8.9 2021-01-14 17:21:29 +01:00
Adam Stankiewicz
341c3772f0 Improve publish script 2021-01-11 23:56:45 +01:00
Adam Stankiewicz
9734497faf Add package-lock.json to gitignores (we use yarn.lock) 2021-01-11 19:31:26 +01:00
dependabot[bot]
87cc6a3c6c Bump tar-fs from 1.15.3 to 1.16.2 (#2576)
Bumps [tar-fs](https://github.com/mafintosh/tar-fs) from 1.15.3 to 1.16.2.
- [Release notes](https://github.com/mafintosh/tar-fs/releases)
- [Commits](https://github.com/mafintosh/tar-fs/compare/v1.15.3...v1.16.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-11 19:18:41 +01:00
dependabot[bot]
2a47ba1a1d Bump ini from 1.3.4 to 1.3.7 (#2589)
Bumps [ini](https://github.com/isaacs/ini) from 1.3.4 to 1.3.7.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.4...v1.3.7)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-11 19:17:13 +01:00
dependabot[bot]
26212e7a67 Bump handlebars from 4.3.0 to 4.5.3 (#2586)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.3.0 to 4.5.3.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/handlebars-lang/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.3.0...v4.5.3)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-11 19:16:10 +01:00
Adam Stankiewicz
7af181f276 Update CONTRIBUTING.md 2020-05-19 10:01:56 +02:00
Adam Stankiewicz
975f6216e5 Update CONTRIBUTING.md 2020-05-19 10:01:23 +02:00
Adam Stankiewicz
d8747d794e Update minimist (#2578) 2020-04-28 14:04:17 +02:00
Adam Stankiewicz
8630604e82 Update mocha (#2577) 2020-04-28 13:19:08 +02:00
Adam Stankiewicz
8f604adf26 Revert "Bump tar-fs from 1.15.3 to 1.16.2 (#2569)"
This reverts commit 3f01228db4.
2020-04-28 12:41:52 +02:00
Satoshi Nakamura
34b4644ca3 Fix typos in changelog (#2574) 2020-04-28 01:11:43 +02:00
dependabot[bot]
3f01228db4 Bump tar-fs from 1.15.3 to 1.16.2 (#2569)
Bumps [tar-fs](https://github.com/mafintosh/tar-fs) from 1.15.3 to 1.16.2.
- [Release notes](https://github.com/mafintosh/tar-fs/releases)
- [Commits](https://github.com/mafintosh/tar-fs/compare/v1.15.3...v1.16.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-04-27 22:10:20 +02:00
Adam Stankiewicz
f5dbab0eac Update yarn.lock 2020-04-27 21:31:30 +02:00
Adam Stankiewicz
26031df67c Prevent errors when expanded env variable does not exist, fixes #2573 2020-04-27 21:29:47 +02:00
Adam Stankiewicz
1226186126 Update dependencies and yarn.lock 2020-04-27 18:05:53 +02:00
Adam Stankiewicz
752d6d42d7 Update deep-extend 2020-04-27 18:03:33 +02:00
Adam Stankiewicz
587f08844b Update yarn.lock 2020-04-27 13:57:27 +02:00
Adam Stankiewicz
6afb7b19ef Fix requires in bower-json 2020-04-27 13:55:22 +02:00
Adam Stankiewicz
6798f961f7 Update yarn.lock 2020-04-27 01:58:42 +02:00
Adam Stankiewicz
f1685ec484 Bump bower-json 2020-04-27 01:57:47 +02:00
Adam Stankiewicz
6682e312ac Vendor ext-name (drop meow dependency) (#2572) 2020-04-26 22:51:21 +02:00
Adam Stankiewicz
b123fed19b Remove coveralls and istanbul 2020-04-26 22:21:06 +02:00
Adam Stankiewicz
f6443b675a Update eslint (#2571) 2020-04-26 22:19:22 +02:00
dependabot[bot]
199e46c94a Bump fstream from 1.0.11 to 1.0.12 (#2568)
Bumps [fstream](https://github.com/npm/fstream) from 1.0.11 to 1.0.12.
- [Release notes](https://github.com/npm/fstream/releases)
- [Commits](https://github.com/npm/fstream/compare/v1.0.11...v1.0.12)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-04-26 20:43:39 +02:00
dependabot[bot]
d3455643d2 Bump is-my-json-valid from 2.16.1 to 2.20.0 (#2570)
Bumps [is-my-json-valid](https://github.com/mafintosh/is-my-json-valid) from 2.16.1 to 2.20.0.
- [Release notes](https://github.com/mafintosh/is-my-json-valid/releases)
- [Commits](https://github.com/mafintosh/is-my-json-valid/compare/v2.16.1...v2.20.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-04-26 20:43:28 +02:00
Adam Stankiewicz
95d5a35f70 Restore yarn.lock 2020-04-26 20:20:59 +02:00
Adam Stankiewicz
7c922f577a Pin chmodr 2020-04-26 20:14:34 +02:00
Adam Stankiewicz
7ae3808b44 Fix linting 2020-04-26 19:57:41 +02:00
Adam Stankiewicz
f7b21d38a8 Fix formatting 2020-04-26 19:52:20 +02:00
Adam Stankiewicz
807eada63f Bump bower-config in bower 2020-04-26 19:48:22 +02:00
Adam Stankiewicz
c1abde9269 Bump bower-config 2020-04-26 19:47:20 +02:00
Adam Stankiewicz
f82a541679 Bump bower-config 2020-04-26 19:42:39 +02:00
Adam Stankiewicz
ce59f15cc9 Apply security fix for minimist, closes #2564 2020-04-26 19:40:42 +02:00
Adam Stankiewicz
845995fccd Allow to run bower with sudo by default, closes #2406 2020-04-26 15:58:38 +02:00
Adam Stankiewicz
ebd99ad866 Update support channels 2020-04-26 15:37:03 +02:00
Adam Stankiewicz
26a37942de Update SECURITY.md 2020-04-25 02:41:14 +02:00
Adam Stankiewicz
390dec6d7f Create SECURITY.md 2020-04-25 02:40:23 +02:00
Adam Stankiewicz
234ee9149d Update travis badges and remove old files 2020-04-25 02:23:19 +02:00
Adam Stankiewicz
bcb1911268 Test subpackages, all node versions, and all platforms (#2554) 2020-04-25 02:14:49 +02:00
Adam Stankiewicz
c18aa260f3 Update sponsor badges 2020-04-20 14:05:09 +02:00
Adam Stankiewicz
9d5f7b7f61 Update README 2020-04-19 15:27:13 +02:00
Tim Gates
71661c6460 docs: Fix simple typo, wheter -> whether (#2563) 2020-04-02 16:50:45 +02:00
dependabot[bot]
67590f7728 Bump handlebars from 4.1.2 to 4.3.0 (#2555)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.1.2 to 4.3.0.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.1.2...v4.3.0)

Signed-off-by: dependabot[bot] <support@github.com>
2020-01-15 16:37:53 +01:00
dependabot[bot]
4e68c23c87 Bump stringstream from 0.0.5 to 0.0.6 (#2553)
Bumps [stringstream](https://github.com/mhart/StringStream) from 0.0.5 to 0.0.6.
- [Release notes](https://github.com/mhart/StringStream/releases)
- [Commits](https://github.com/mhart/StringStream/compare/v0.0.5...v0.0.6)

Signed-off-by: dependabot[bot] <support@github.com>
2019-12-10 12:59:40 +01:00
dependabot[bot]
fcc02c4200 Bump handlebars from 4.0.10 to 4.1.2 (#2552)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.0.10 to 4.1.2.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.0.10...v4.1.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-12-10 12:33:10 +01:00
dependabot[bot]
d24e7be811 Bump mime from 1.4.0 to 1.6.0 (#2551)
Bumps [mime](https://github.com/broofa/node-mime) from 1.4.0 to 1.6.0.
- [Release notes](https://github.com/broofa/node-mime/releases)
- [Changelog](https://github.com/broofa/node-mime/blob/v1.6.0/CHANGELOG.md)
- [Commits](https://github.com/broofa/node-mime/compare/v1.4.0...v1.6.0)

Signed-off-by: dependabot[bot] <support@github.com>
2019-12-10 11:41:29 +01:00
dependabot[bot]
746fd3a669 Bump sshpk from 1.13.1 to 1.16.1 (#2550)
Bumps [sshpk](https://github.com/joyent/node-sshpk) from 1.13.1 to 1.16.1.
- [Release notes](https://github.com/joyent/node-sshpk/releases)
- [Commits](https://github.com/joyent/node-sshpk/compare/v1.13.1...v1.16.1)

Signed-off-by: dependabot[bot] <support@github.com>
2019-12-10 09:35:48 +01:00
dependabot[bot]
031c7731a4 Bump extend from 3.0.1 to 3.0.2 (#2549)
Bumps [extend](https://github.com/justmoon/node-extend) from 3.0.1 to 3.0.2.
- [Release notes](https://github.com/justmoon/node-extend/releases)
- [Changelog](https://github.com/justmoon/node-extend/blob/master/CHANGELOG.md)
- [Commits](https://github.com/justmoon/node-extend/compare/v3.0.1...v3.0.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-12-10 09:35:31 +01:00
Adam Stankiewicz
fa62654b9c Test node 10 and 12 on Windows 2019-12-10 09:26:12 +01:00
Adam Stankiewicz
fd2d448b7e Test node 10 and 12 on CI (#2548) 2019-12-10 08:53:36 +01:00
Adam Stankiewicz
997fb2b298 Create FUNDING.yml 2019-11-25 23:18:17 +01:00
Adam Stankiewicz
9c9f332ea0 Add sponsor slots 2019-08-29 17:19:21 +02:00
Adam Stankiewicz
1861fa4355 Add sponsor slots 2019-08-29 17:18:09 +02:00
Adam Stankiewicz
79a539ffb4 Add sponsor slots 2019-06-26 14:30:21 +02:00
Adam Stankiewicz
0608b26364 Add sponsors slots 2019-06-26 14:28:47 +02:00
Adam Stankiewicz
15e5b9709d Add some slots 2019-06-26 14:26:05 +02:00
Adam Stankiewicz
67741b4bfe Bump to 1.8.8 2019-01-23 22:15:30 +01:00
Adam Stankiewicz
45c6bfa86f Fix .tar.gz extract vulnerability 2019-01-23 22:14:48 +01:00
Adam Stankiewicz
4f68fc7daa Update decompress-zip and bump 2019-01-17 23:35:49 +01:00
Adam Stankiewicz
206046b271 Bump to 1.8.6 2019-01-17 14:44:28 +01:00
Adam Stankiewicz
43894f5149 Bump to 1.8.5 2019-01-17 14:19:04 +01:00
Adam Stankiewicz
6390815c5f Update decompress-zip 2019-01-17 13:03:49 +01:00
Adam Stankiewicz
e8b94ecbd0 Mention parcel 2018-06-23 18:06:56 +02:00
Adam Stankiewicz
51feb8f925 Fix release script 2018-04-19 11:07:03 +02:00
Adam Stankiewicz
1c15deadc0 Bump to 1.8.4 2018-03-28 20:43:29 +02:00
Adam Stankiewicz
2aa1f27367 Update publish script 2018-03-28 20:16:27 +02:00
Adam Stankiewicz
275601601a Bump to 1.8.3 2018-03-28 19:52:42 +02:00
Adam Stankiewicz
c22c09546e Disable testing per commit and update changelog 2018-03-28 19:33:16 +02:00
Adam Stankiewicz
6bc778df32 Format with prettier (#2510) 2018-03-28 19:28:43 +02:00
Adam Stankiewicz
451c60ec20 Do not store resolutions if --save is not used, fixes #2344 (#2508) 2018-03-28 18:15:30 +02:00
Adam Stankiewicz
d6a18ae7ee Revert "Update request version in bower-registry-client #2336"
This reverts commit 1e2c27f338.
2018-03-28 18:09:01 +02:00
Adam Stankiewicz
b62faa19a6 Update request version in bower-registry-client #2336 2018-03-28 18:09:01 +02:00
Adam Stankiewicz
50ee729ea2 Allow to disable shorthand resolver (#2507) 2018-03-28 17:58:56 +02:00
Adam Stankiewicz
bb17839bc2 Allow shallow cloning when source is a ssh protocol (#2506) 2018-03-28 17:37:34 +02:00
Michael Lee
5a6ae540f9 Adding support for Arrays in Environment Variable replacement (#2411) 2018-03-28 17:05:13 +02:00
Max Schaefer
1935716660 Fix issues found by lgtm (#2493) 2018-03-28 15:51:53 +02:00
Adam Stankiewicz
add601795f Update year in licenses one last time, fixes #2476 2018-03-28 15:25:36 +02:00
Adam Stankiewicz
8e34328466 Run tests on all node versions and fix test suite, closes #2495 (#2505) 2018-03-28 15:17:31 +02:00
Michael Kühnel
c3e9c94833 Expose non-interactive option to CLI help (#2404) 2018-03-28 13:20:11 +02:00
Madan
dd19bafa37 docs: highlight "-allow-root" (#2496) 2018-03-28 13:17:55 +02:00
Martin Page
74af42c176 Only replace last @ after (if any) last / with # (#2395) 2018-03-28 13:16:09 +02:00
Guido Bouman
a6308bf8f8 Remove duplicate space setting from .editorconfig. (#2480) 2017-09-26 08:11:42 -05:00
Adam Stankiewicz
e1dc0105d2 Reduce node versions on appveyor 2017-09-26 10:57:16 +02:00
Adam Stankiewicz
ce210e4f16 Install grunt on appveyor 2017-09-26 10:55:11 +02:00
Adam Stankiewicz
e483e9bc2c Reduce tested node versions 2017-09-26 10:48:43 +02:00
Adam Stankiewicz
b0c3859699 Fix a test 2017-09-26 10:37:59 +02:00
Adam Stankiewicz
e6d1b2d82e Try to fix appveyor build 2017-09-26 10:36:09 +02:00
Adam Stankiewicz
d4345bb254 Use Yarn on travis and appveyor 2017-09-14 18:08:22 +02:00
Adam Stankiewicz
975f9bdcdb Lock dependencies 2017-09-14 18:05:08 +02:00
Adam Stankiewicz
a969a9c557 Bump bower-config 2017-09-14 18:04:12 +02:00
Adam Stankiewicz
6500b421ce Migrate bower.herokuapp.com to registry.bower.io 2017-09-13 18:59:52 +02:00
Adam Stankiewicz
0641167b96 Remove opencollective for now to prevent installation issues 2017-09-13 18:55:23 +02:00
yanca018
0d03374dab Update LICENSE (#2475)
Update year to 2017
2017-08-14 12:41:32 +02:00
Xavier Damman
765d8e739d Activating Open Collective (#2450) 2017-05-30 18:15:09 +02:00
Thomas Grainger
0bd318de53 Add yarn and webpack recommendation (#2458) 2017-05-19 20:29:15 +02:00
Juan Olvera
aa6b51edc0 Replace gitter references with discord on documentation (#2453) 2017-04-18 18:12:36 -05:00
Adam Stankiewicz
2c2e5309fd Run tests on node 7 as well 2017-03-22 14:03:31 +01:00
Eugene Kenny
b716bc4e3a Prefer exact versions when dissecting dependencies (#2371) 2016-11-08 09:11:29 +01:00
Adam Stankiewicz
bda400634c Bump to 1.8.0 2016-11-07 10:53:30 +01:00
Adam Stankiewicz
b01243ac3c Fix eslint issues 2016-11-07 10:47:29 +01:00
Adam Stankiewicz
89902a6919 Mark release in changelog 2016-11-07 10:46:10 +01:00
Adam Stankiewicz
80308a41a6 Update changelog 2016-11-07 10:34:39 +01:00
Adam Stankiewicz
47cc2262e1 Download tar archives from https://github when possible (#2263) 2016-11-07 02:33:43 +01:00
Guillermo Ignacio Enriquez Gutierrez
f7c5154490 Fix ssl handling by not setting GIT_SSL_NO_VERIFY=false (#2361) 2016-11-07 01:50:57 +01:00
Ali MoezGholami
cba4b2a4cd Allow for removing components with url instead of name (#2368) 2016-11-07 01:48:41 +01:00
Leo.liang
bdabf6a4e6 Show in warning message location of malformed bower.json (#2357) 2016-11-07 01:29:17 +01:00
GvS
7896224384 Improve handling of non-semver versions in git resolver (#2316) 2016-11-07 01:27:14 +01:00
Johannes Faigle
3209cda975 docs: Update package repository information (#2351) 2016-11-07 01:21:27 +01:00
Vytautas Jakutis
38501a0b93 Fix handling of cached releases pluginResolverFactory (#2356) 2016-11-07 01:19:41 +01:00
Adam Stankiewicz
e60d236b25 Add bower-config changes to changelog 2016-11-06 23:04:07 +01:00
Adam Stankiewicz
044896e708 Bump bower-config to 1.4.0 2016-11-06 23:03:56 +01:00
Adam Stankiewicz
fc4c260de4 Update changelog 2016-11-06 22:56:42 +01:00
Adam Stankiewicz
d405917b4a Remove non-working issue stats 2016-07-05 11:16:26 +02:00
Martin Page
22bbb3fcaf Allow @ to be used as a divider with cli: install and info. (#2322) 2016-07-04 23:31:06 +02:00
Adam Stankiewicz
8b6c8eeaa9 Run tests also on 4.0 and 4.1 2016-06-12 14:22:36 +02:00
Adam Stankiewicz
58ddb59104 Revert "Rename .travis.yml to travis.yml"
This reverts commit 9317bb6e33.
2016-06-12 14:19:04 +02:00
Adam Stankiewicz
f26fe38c30 Fix CI badges 2016-06-12 14:18:29 +02:00
Adam Stankiewicz
9317bb6e33 Rename .travis.yml to travis.yml 2016-06-12 14:04:50 +02:00
Adam Stankiewicz
2693bae8ed Improve appveyor.yml 2016-06-12 14:04:28 +02:00
Adam Stankiewicz
8368539a93 Change appveyor badge to new project
[skip ci]
2016-06-12 01:40:45 +02:00
Adam Stankiewicz
8947400487 Disable deploy in appveyor.yml 2016-06-12 01:19:50 +02:00
Adam Stankiewicz
44eeb60529 Improve appveyor.yml 2016-06-12 01:18:32 +02:00
Adam Stankiewicz
2309cd80c6 Add missing return in promise 2016-06-11 02:49:22 +02:00
Adam Stankiewicz
684ab0c0a6 Simplify travis configuration 2016-06-10 20:48:44 +02:00
Adam Stankiewicz
1f6b32a48e Test node 6 also on appveyor 2016-06-10 17:41:11 +02:00
Adam Stankiewicz
e4f0295ef1 Test node 4, 5, and 6 2016-06-10 17:37:53 +02:00
Adam Stankiewicz
85e39cf190 Try to fix svn tests 2016-06-10 17:24:42 +02:00
Adam Stankiewicz
16c134f0f9 Update devDependencies 2016-06-10 17:14:47 +02:00
Adam Stankiewicz
bcbff32716 Pass through eslint 2016-06-10 16:40:46 +02:00
Adam Stankiewicz
809117ea73 Merge bower-endpoint-parser repository 2016-06-10 14:24:55 +02:00
Adam Stankiewicz
af448ba484 Merge bower-registry-client repository 2016-06-10 13:44:43 +02:00
Adam Stankiewicz
89069784bb Merge bower-logger repository 2016-06-10 13:32:03 +02:00
Adam Stankiewicz
57cc6f7a40 Merge bower-json repository 2016-06-10 13:22:15 +02:00
Adam Stankiewicz
cea728c7bc Merge bower-config repository 2016-06-10 13:18:55 +02:00
Adam Stankiewicz
f6be8e5e28 Improve issue template a little 2016-06-09 20:34:14 +02:00
Ben
c6f7ec36de Add issue template (#2305) 2016-06-09 20:29:26 +02:00
Ben
3235b3c0d3 Fix typo in README 2016-06-02 13:36:10 +02:00
Adam Stankiewicz
6ca5d434a4 [docs] Change info at the top of readme 2016-06-02 12:38:49 +02:00
Evan Bowling
eb27ae8fdc Added integration tests for installing nested components (#1513) (#2297) 2016-05-30 11:16:53 +02:00
Ben
353a399f75 Fix test & build for shorthand resolver 2016-05-10 10:46:07 +02:00
Ben
c718541a4e Merge pull request #2282 from evanjbowling/master
Correct typo in command descriptions, followup for #2280
2016-05-08 20:08:40 +02:00
Evan Bowling
1f4372299a Correct typo in command descriptions, followup for #2280 2016-05-08 11:39:45 -05:00
Adam Stankiewicz
e640d0ec5c Improve search / lookup command descriptions, closes #2280 2016-05-06 11:57:26 +02:00
Ben
2e5acfe076 Remove analytics from example config 2016-05-04 19:55:27 +02:00
Ben
19f3c53c70 Merge pull request #54 from evanjbowling/master
Update README.md to be more descriptive
2016-05-04 08:52:38 +02:00
Evan Bowling
26902aec27 Update README.md to be more descriptive 2016-05-03 22:18:05 -05:00
Ben
08feaf2b0a Merge pull request #2271 from rajzshkr/bower-register-info
info message added for bower register
Closing #2075
2016-04-28 12:46:17 +02:00
Ben
db1ed1c08f Fix build errors #2
Related to the change from git:// to https://
2016-04-28 12:32:13 +02:00
Ben
3c2562ca0e Fix failing tests 2016-04-28 12:23:54 +02:00
Raja Sekar
b1f1b8fae3 info message added for bower register 2016-04-28 15:16:10 +05:30
Ben
f1c874b202 Merge pull request #2270 from rajzshkr/bower-cache
fix for 2264
2016-04-28 07:27:15 +02:00
Raja Sekar
4757e7353f fix for 2264 2016-04-28 10:20:19 +05:30
Adam Stankiewicz
249ac47b9c 1.4.0 2016-04-22 00:35:39 +02:00
Adam Stankiewicz
dc59913098 Change default shorthandResolver from git:// to https:// 2016-04-22 00:35:23 +02:00
Oskar Cieślik
343e6ac8bc Implement postuninstall hooks with tests (#2252) 2016-04-14 15:02:07 +02:00
Adam Stankiewicz
e729829174 Make bower version behavior consistent with spec (#2232) 2016-04-12 19:18:36 +02:00
Oskar Cieślik
40e3ee091b Support single-char repo names and package names (#2249) 2016-04-12 19:15:24 +02:00
Oskar Cieślik
8ee2d78779 Add support for registering package with github's orgname/reponame (#2248) 2016-04-12 18:57:44 +02:00
Oskar Cieślik
7c54812ecf Allow to type the entire version when conflict occured (#2243) 2016-04-10 13:24:29 +02:00
Adam Stankiewicz
3251051d20 Fix tests given the new registry 2016-04-10 13:15:57 +02:00
Adam Stankiewicz
81052830f2 Merge pull request #52 from bamsy/topic-unreachable-code
Remove unreachable code from parse function
2016-04-09 18:18:53 +02:00
Justin Barnes
7b2fd5dcd1 Remove unreachable code from parse function 2016-04-09 09:14:04 -05:00
Adam Stankiewicz
bbc9b35cb1 Update grunt to 1.0.1 2016-04-06 13:45:43 +02:00
Adam Stankiewicz
3aebb34f1d Fix typo in changelog 2016-04-05 13:48:21 +02:00
Adam Stankiewicz
8065e5c64a 1.7.9 2016-04-05 13:44:58 +02:00
Adam Stankiewicz
b8e6f36a91 Add changelog entries for 1.7.9 2016-04-05 13:36:52 +02:00
Adam Stankiewicz
12d41aeb8c Warn instead of erroring for invalida package names, #2233 2016-04-05 13:34:06 +02:00
Adam Stankiewicz
8c624bbda6 0.8.1 2016-04-04 21:45:44 +02:00
Adam Stankiewicz
7ee1686cf4 Add changelog for 0.8.1 2016-04-04 21:45:39 +02:00
Adam Stankiewicz
8e181c1792 Make name validation far less strict 2016-04-04 21:37:50 +02:00
Adam Stankiewicz
9569a8074d Add missing changelog entry, #2233 2016-04-04 20:42:55 +02:00
Adam Stankiewicz
e8e4c8fdbc Fix typo in changelog 2016-04-04 19:20:57 +02:00
Adam Stankiewicz
9e5cd572f8 1.7.8 2016-04-04 19:00:08 +02:00
Adam Stankiewicz
69cd360551 Update changelog 2016-04-04 18:59:44 +02:00
Adam Stankiewicz
4793fc0d1c Bump year in license 2016-04-04 18:38:28 +02:00
Adam Stankiewicz
aaaa9cd530 Don't ask for git credentials in non-interactive session
This is done by setting GIT_TERMINAL_PROMPT variable

- fixes #956
- fixes #1009
2016-04-04 18:17:04 +02:00
Adam Stankiewicz
c2e0dc9d23 Prevent swallowing exceptions with programmatic api, fixes #2187 2016-04-04 17:33:19 +02:00
Adam Stankiewicz
fc4446247c Update graceful-fs to 4.x 2016-04-04 14:26:26 +02:00
Adam Stankiewicz
f4e0b3dfba Update bower-json to 0.8.0 and update tests 2016-04-04 14:18:23 +02:00
Adam Stankiewicz
4d7cdb0556 0.8.0 2016-04-04 14:11:41 +02:00
Adam Stankiewicz
037bbff17e Update changelog 2016-04-04 14:11:37 +02:00
Adam Stankiewicz
f05cd5fb94 Update bower-json to 0.7.1 2016-04-04 13:49:22 +02:00
Adam Stankiewicz
358a73b98e 0.7.1 2016-04-04 13:47:56 +02:00
Adam Stankiewicz
32cbb5a0e8 Update graceful-fs 2016-04-04 13:47:10 +02:00
bamsy
8679ad77ae Fix grammar in contributing file.
- remove trailing whitespace

- "anyway" -> "any way"
2016-04-03 13:18:06 +02:00
Kyle Pollock
1b1d8bdad6 Remove jscs inline error suppression comments.
- jscs is removed from the project.
2016-04-02 14:26:04 +02:00
Kyle Pollock
aecdf3f365 Merge pull request #2229 from bamsy/master
Fix typos/grammar in first paragraph of contributing file.
2016-04-01 20:30:51 -05:00
Justin Barnes
1cf87041cc Fix typos/grammar in first paragraph of contributing file. 2016-04-01 19:36:04 -05:00
Adam Stankiewicz
5116fec1ab Update decompress-zip to 0.2.1 2016-04-01 17:51:46 +02:00
Adam Stankiewicz
8f2668a24d Bump config-store to 2.0.0 2016-04-01 17:36:06 +02:00
Adam Stankiewicz
e7516e4bcb Bump bower-config to 1.3.1 2016-04-01 17:32:50 +02:00
Adam Stankiewicz
3853d1297e Add changelog entry 2016-04-01 17:28:23 +02:00
Adam Stankiewicz
1e398f999b Update dependencies 2016-04-01 17:27:18 +02:00
Adam Stankiewicz
3a0ea968f4 Update graceful-fs dependency 2016-04-01 17:24:12 +02:00
Adam Stankiewicz
7de2e5d601 Remove moduleType from from "bower init" result, fixes #1229 2016-04-01 16:19:51 +02:00
Adam Stankiewicz
b1c45bb586 Resolve pluggable resolvers using cwd and fallback to global module 2016-04-01 14:57:36 +02:00
Adam Stankiewicz
f4cb047e9d Allow to install custom resolver globally, fixes #1919 2016-04-01 03:22:42 +02:00
Adam Stankiewicz
f494ae7ddd [refactor] Fix tests for previous commit 2016-04-01 01:39:09 +02:00
Adam Stankiewicz
44e71267c1 [refactor] Put bower-registry-client instantiation in one place 2016-03-31 22:10:10 +02:00
Adam Stankiewicz
52aa684949 [refactor] Move abbreviations to utils 2016-03-31 19:29:55 +02:00
Adam Stankiewicz
46655b7c4e Final .eslintrc configuration 2016-03-31 19:27:12 +02:00
Adam Stankiewicz
16cde3118a Revert "Merge pull request #2197 from albertinadx/albertinad/fix-scripts-hooks"
This reverts commit 0a81308e98, reversing
changes made to f2884656c0.
2016-03-31 01:36:05 +02:00
Adam Stankiewicz
7c2dfc1146 Fix peerDependency of grunt-exec 2016-03-31 00:55:47 +02:00
Adam Stankiewicz
53eeca97d3 Use eslint instead jscs 2016-03-31 00:27:17 +02:00
Adam Stankiewicz
9201a379d6 Update to grunt 1.0 2016-03-30 22:30:57 +02:00
Adam Stankiewicz
2052ba3eed Remove jshint 2016-03-30 22:12:24 +02:00
Adam Stankiewicz
b32bd8b877 Merge pull request #2225 from echavezNS/master
Reuse the files selected in jshint for jscs
2016-03-28 12:19:38 +02:00
echavezNS
233f685c61 Reuse the files selected in jshint for jscs 2016-03-28 00:39:05 -07:00
Kun Yan
5fe8df2e0a Merge pull request #2224 from kunyan/bugfix/test-case
Fix message unit test error
2016-03-28 14:35:35 +08:00
Kun Yan
a3ae3b66b7 Fix message unit test error 2016-03-28 14:11:02 +08:00
Ben
2000d2f5db Merge pull request #2212 from echavezNS/master
Extend conflict message to be more expressive how to choose an option
2016-03-27 08:01:03 +02:00
echavezNS
84d8d8c57f Typo 2016-03-26 12:39:35 -07:00
echavezNS
f9ea3846e2 Extend conflict message 2016-03-26 01:25:10 -07:00
Yan Kun
8b6c20239e Merge pull request #2208 from kunyan/bugfix/grunt-file-json-error
Fix Gruntfile error
2016-03-20 22:43:33 -05:00
Kun Yan
73171766e7 Fix Gruntfile error 2016-03-21 11:16:51 +08:00
Adam Stankiewicz
88b3655829 Merge pull request #2204 from echavezNS/master
Add jsonPackage for refactoring purposes
2016-03-17 10:00:59 +01:00
Jorge Chavez
3241e8ed62 Add jsonPackage for refactoring purposes 2016-03-16 18:12:43 -07:00
Albertina Durante
0a81308e98 Merge pull request #2197 from albertinadx/albertinad/fix-scripts-hooks
Fix hooks to support shell operators
2016-03-05 21:54:22 -03:00
Albertina Durante
8d76b87d65 Supporting shell operators in hooks scripts.
- Removing module "shell-quote"
- Adding tests for hooks scripts with shell operators
- This fixes issue #1594
2016-03-05 21:50:05 -03:00
Adam Stankiewicz
f2884656c0 Merge pull request #2196 from prometheansacrifice/handlebars-vulnerability
Handlebars vulnerability
2016-03-06 01:17:19 +01:00
Manas
6fff6fa707 Upgrades handlebars to 4.0.5 to address #2195
Adds test for template util methods
Upgrades handlebars
Fixes RangeError due to `length` attribute in rpad helper
2016-03-06 01:37:20 +05:30
Ben
1357f63a1b Merge pull request #2191 from nirajkaushal/master
Update: Copyright Year from 2015 to 2016
2016-02-29 09:23:52 +01:00
Niraj Kaushal
529d702959 Update Copyright Year from 2015 to 2016
This commit will change copyright year from 2015 to current year(2016)
2016-02-29 11:13:06 +05:30
Ben
0155a70457 Merge pull request #2186 from yash14123/master
Changelog is still in 2015
2016-02-24 11:37:21 +01:00
yash14123
a6ca2ae9bb Changelog is still in 2015 2016-02-24 05:34:44 +05:30
Adam Stankiewicz
78e443db0a Merge pull request #2177 from oliamb/eslintrc-indent
[eslint] fix indentation to 4 spaces
2016-02-17 15:59:54 +01:00
Sivakumar Kailasam
5f24eab32d Merge pull request #2175 from sivakumar-kailasam/bowerrc-placeholder-replacement-fix
Replace all occurrences of % character in hook commands.
2016-02-17 13:27:12 +05:30
Olivier Amblet
f4620b28ab [eslint] fix indentation to 4 spaces
Changed the indentation from 2 to 4 spaces in .eslintrc files.
All the code is using this convention and .jscsrc already define 4 as
the right value.
2016-02-16 23:22:46 +01:00
Sivakumar Kailasam
9f4c2384ea Replace all occurrences of % character in hook commands.
Fixes #2174 % character replaced once in .bowerrc scripts
2016-02-15 20:34:01 +05:30
Adam Stankiewicz
e85a5f778f Update opn package to 4.0.0, fixes #2169 2016-02-13 21:41:35 +01:00
Adam Stankiewicz
5283a132bc Add name check that reflects reality 2016-02-10 04:33:26 +01:00
Adam Stankiewicz
db1453f7c0 Add findSync and readSync to the README 2016-02-10 02:55:24 +01:00
Adam Stankiewicz
878a228a7d Fix linting error 2016-02-10 02:44:53 +01:00
Adam Stankiewicz
b33041c3ec [test] Remove unnecessary check 2016-02-10 02:42:33 +01:00
Stefan Grönke
c8a6ff38a0 test validation against all registred packages 2016-02-10 02:38:55 +01:00
Adam Stankiewicz
573b84f7f4 Update bower-json to 0.7.0 2016-02-10 02:34:30 +01:00
Adam Stankiewicz
ef67955c21 Bump to 0.7.0 2016-02-10 02:22:34 +01:00
Adam Stankiewicz
36a14b9b37 Add getIssues function and make validate less restrictive 2016-02-10 01:54:31 +01:00
Adam Stankiewicz
96d986f436 Merge pull request #2161 from blcook223/feature/save-bowerrc-config
add support for save and save-exact in .bowerrc
2016-01-29 12:27:44 +01:00
blcook223
394dd7c8d2 add support for save and save-exact in .bowerrc
The install command now supports designating "save" and "save-exact"
values in .bowerrc. If the `--save` flag is not used, but the config
file sets "save" to true, the command will behave as if the `--save`
option was specified. The same is true of `--save-exact` if
"save-exact" is set to true in `.bowerrc`.

The uninstall command will also behave as if the `--save` flag had
been specified if "save" is set to true in `.bowerrc`.
2016-01-28 21:10:17 -06:00
Adam Stankiewicz
6c67d07cc8 Add missing lib/bin/bower.js file 2016-01-27 15:37:13 +01:00
Adam Stankiewicz
cd7bbab310 Bump to 1.7.7 2016-01-27 15:05:27 +01:00
Adam Stankiewicz
4b4a854ed8 Restore directory structure for published bower
It's because people are depending on internals of bower, like
"bower/lib/renderers/StandardRenderer"

Instead we move templates and bin to lib directory and leave
paths intact. Additionally we alias bin/bower to lib/bin/bower.
2016-01-27 14:47:18 +01:00
Adam Stankiewicz
8194bcb4c6 Revert bin/bower location and bump to 1.7.6 2016-01-27 12:06:48 +01:00
Adam Stankiewicz
e5d478a1cc Bump to 1.7.5 and update changelog 2016-01-26 22:35:22 +01:00
Adam Stankiewicz
bbaaee67a1 Update publishing script to bundle all modules 2016-01-25 22:57:07 +01:00
Adam Stankiewicz
ad27112b58 Do not assume package.json location 2016-01-25 19:40:54 +01:00
Adam Stankiewicz
38c3cee1a7 Perform test on fake .git directory 2016-01-25 19:40:54 +01:00
Adam Stankiewicz
b485c5d3cb Remove bundledDependencies from package.json
bundledDependencies will be filled only just before publish
2016-01-25 19:40:54 +01:00
Adam Stankiewicz
d63047b4ee Merge pull request #2137 from pwielgolaski/#2129
when strictSsl is false set GIT_SSL_NO_VERIFY=true for git command
2016-01-24 18:14:38 +01:00
Piotr Wielgolaski
f0a54d0018 set GIT_SSL_NO_VERIFY for opposite value than strictSsl 2016-01-23 20:29:28 +01:00
Piotr Wielgolaski
1d73764788 when strictSsl is false set GIT_SSL_NO_VERIFY=true for git command
Solves #2129
2016-01-23 14:26:48 +01:00
Adam Stankiewicz
9d2681b0c4 Ignore test files in published package 2016-01-21 13:43:17 +01:00
Adam Stankiewicz
f3330e8612 Update changelog and bump to 1.7.3 2016-01-20 18:23:27 +01:00
Adam Stankiewicz
11996c04b7 Update to fs-write-stream@1.0.8 2016-01-20 14:18:44 +01:00
Adam Stankiewicz
35e73a619a Tolerate failure in covealls reporting 2016-01-20 14:06:48 +01:00
Adam Stankiewicz
fe615fd517 Merge pull request #2150 from bower/feature/analytics
Remove analytics from Bower, fixes #1102
2016-01-20 13:35:55 +01:00
Adam Stankiewicz
3e3b64218d Remove analytics from Bower, fixes #1102
They caused more issues than useful they were.

Instead, we'll focus on fetching statistics from
NPM registry to watch Bower's popularity, and
GitHub stars over time to watch packages' popularity.
2016-01-20 12:30:54 +01:00
Adam Stankiewicz
afe76e57f8 Remove HOOKS.md as they are now properly documented, thanks @dvidsilva! 2016-01-18 22:05:17 +01:00
Adam Stankiewicz
6ee3ef7aa8 Merge pull request #2071 from prometheansacrifice/adding-tests-plugin-resolver
Adds tests for pluginResolverFactory.js
2016-01-18 12:34:50 +01:00
Manas
64db869bd4 Adds tests for pluginResolverFactory.js 2016-01-18 01:22:07 +05:30
Adam Stankiewicz
a4ea05800d Add prepublish script for easy and reliable bower releasing 2016-01-17 00:13:07 +01:00
Adam Stankiewicz
8cf897cd19 Merge pull request #2145 from bower/sjs/use-caret-on-install-save
Use caret on install save
2016-01-12 21:19:55 +00:00
Sam Saccone
d06af7a3d7 Default to ^ operator on --save
This fix brings us inline with how npm installs work and also brings us
more inline with how semver is supposed to be used.

Fixes #2144
2016-01-10 18:28:42 -08:00
Jaime Olmo
d4fd71986e Merge pull request #2140 from jamesxv7/master
Changes to license file and package.json
2016-01-07 20:55:31 -04:00
Jaime Olmo
3154444556 Update CHANGELOG.md
Updated as per 1.7.2 release
2016-01-07 01:59:49 -04:00
Jaime Olmo
24f8b913b9 Update LICENSE
Update license year to 2016.
2016-01-07 01:50:58 -04:00
Jaime Olmo
fe6b6863ea Update package.json
Version updated as per [1.7.2](https://github.com/bower/bower/releases/tag/v1.7.2) release.
2016-01-07 01:49:41 -04:00
Adam Stankiewicz
671c23ad50 Merge pull request #2130 from gronke/enhancement/absolute-paths-1914
support absolute path in .bowerrc directory option
2016-01-05 12:28:09 +01:00
Stefan Grönke
5384fa54b1 refactor, address feedback and add more unit tests 2016-01-05 05:23:19 +01:00
Adam Stankiewicz
4bfa8227d9 Merge pull request #2133 from azbshiri/display-logged-in-username
Display the logged in user's name
2016-01-05 00:32:16 +01:00
Alireza Bashiri
55d78f7928 Display the logged in user's name 2016-01-05 02:24:08 +03:30
Stefan Grönke
2110148830 support absolute path in .bowerrc 'directory' option
fixes #1914
2016-01-04 01:46:53 +01:00
Alireza Bashiri
afc4bfbd42 Revert "Display login message when user login via normal and 2 factor auth mode."
This reverts commit ed881e3f29.
2016-01-04 00:58:03 +03:30
Alireza Bashiri
9c42a008aa Merge pull request #2102 from reavowed/fix-extract-name-clashes
Fix name clashes in package extraction
2016-01-01 12:29:55 +03:30
Alireza Bashiri
67884744c3 Merge pull request #2127 from azbshiri/display-info-message-bower-login
Display login message when user login via bower login
2016-01-01 00:19:01 +03:30
Raja Sekar
ed881e3f29 Display login message when user login via normal and 2 factor auth mode.
Displaying info message when user login via bower login

Login message added for 2 factor authentication also

Fix unreachable code

Fix code quality issues
2015-12-31 23:31:16 +03:30
Vlad Filippov
e6e60d5d5e Merge pull request #2125 from bower/fix-write-stream-regression
Lock fs-write-steam-atomic to 1.0.5
2015-12-30 20:52:29 -05:00
Sam Saccone
d8f166a933 Lock fs-write-steam-atomic to 1.0.5
context: https://github.com/bower/bower/issues/2118#issuecomment-168097858

Fixes #2118
2015-12-30 16:22:54 -08:00
Adam Stankiewicz
bb626d1605 Merge pull request #2122 from kevdez/master
Added the --force docs to the --help command
2015-12-29 10:46:45 +01:00
Kevin H
daa5b8ddf9 Added the --force documentation to the --help command 2015-12-28 21:27:13 -08:00
Adam Stankiewicz
db087dfe13 Log-level is actually loglevel, closes #2112 2015-12-21 06:14:22 +01:00
Adam Stankiewicz
848e401efd Link back to invitation form 2015-12-21 05:18:45 +01:00
Adam Stankiewicz
c17c725057 Merge pull request #48 from mithun/no-env-in-hooks
Ignore hook scripts for environment variable expansion
2015-12-18 10:00:05 +01:00
Mithun Ayachit
2b31f6c07a Ignore hook scripts for environment variable expansion 2015-12-17 20:38:48 -06:00
Iain Monro
3cf597fccf Fix jshint errors
Add missing semicolons to test file.
2015-12-15 15:32:13 +00:00
Vlad Filippov
e2adbc37f1 Merge pull request #2103 from Rogerkael/master
Typo fix resolverFactory.js
2015-12-14 17:21:14 -05:00
Roger Rodriguez Texido
6c3b7dbf58 Fixed typo. 2015-12-14 17:12:30 -05:00
Rob Simpson
d3ab3c1fa7 remove freenode as support option 2015-12-14 12:57:24 -05:00
Iain Monro
b1ba9be7f6 Fix name clashes in package extraction
Prevent extraction failing if a package archive contains a file with
the same name as the archive, or a single directory with a subdirectory
with the same name.
2015-12-14 16:58:02 +00:00
Adam Stankiewicz
1e5122c023 Merge pull request #2092 from Utsav2/gzip
Decompress gzip files
2015-12-13 11:16:33 +01:00
Utsav Shah
4255d7d4a8 Add tests for decoding gzipped files 2015-12-12 18:08:19 -06:00
Utsav Shah
cdf45239f4 Decompress gzip files
Update request lib
2015-12-12 18:08:19 -06:00
Adam Stankiewicz
8b2fad32f6 Revert "Change entry in changelog"
This reverts commit d1ae0b1982.
2015-12-11 21:53:31 +01:00
Adam Stankiewicz
d1ae0b1982 Change entry in changelog 2015-12-11 21:53:00 +01:00
Adam Stankiewicz
87cf578ba8 Update changelog 2015-12-11 21:51:30 +01:00
Adam Stankiewicz
3ead440c7c Update changelog 2015-12-11 21:50:50 +01:00
Adam Stankiewicz
e168c894a2 Bump to 1.7.1 2015-12-11 21:43:21 +01:00
Adam Stankiewicz
75e3661371 Update changelog 2015-12-11 21:42:34 +01:00
Adam Stankiewicz
baf8f7bf6b Fix missing parenthesis 2015-12-11 21:37:08 +01:00
Adam Stankiewicz
88758cd98c Revert "Add bower update --save functionality"
This reverts commit d2ba80e6e9.
2015-12-11 21:33:45 +01:00
Adam Stankiewicz
3bd2d62e67 Revert "Add failing tests for single package updates, optimize older tests"
This reverts commit 6616d09f47.
2015-12-11 21:32:47 +01:00
Adam Stankiewicz
d3eef5772a Revert "Only update packages requested by the user"
This reverts commit e3f402fc66.
2015-12-11 21:25:15 +01:00
Adam Stankiewicz
7c714901d4 Fix test for StandardRenderer 2015-12-11 20:33:54 +01:00
Adam Stankiewicz
7792b6d35d Use coveralls as npm script (fix certain versions of node) 2015-12-11 20:24:40 +01:00
Adam Stankiewicz
2db983dba3 Better formatting of help 2015-12-11 20:16:54 +01:00
Adam Stankiewicz
b9718bb309 Fix search command on no arguments, fixes #2066 2015-12-11 20:15:04 +01:00
Adam Stankiewicz
26f609e614 Ignore for now failing windows build on node 5 2015-12-10 21:25:01 +01:00
Adam Stankiewicz
4c2b56096b Merge pull request #2096 from contolini/readme-clean-up
Readme updates
2015-12-10 17:56:08 +01:00
Chris Contolini
5af929f0be Clean up readme 2015-12-09 20:08:44 -05:00
Adam Stankiewicz
6a18cde782 Merge pull request #33 from bower/paulohp-patch-1
added coveralls badge.
2015-12-09 13:03:21 +01:00
Adam Stankiewicz
32c5538fc5 Merge pull request #46 from bower/paulohp-patch-1
added coveralls badge
2015-12-09 13:03:03 +01:00
Paulo Pires
57478d86c7 added 2015-12-09 03:53:47 -08:00
Paulo Pires
42107e6fea added coveralls badge 2015-12-09 03:52:47 -08:00
Adam Stankiewicz
686e883d87 Merge pull request #2094 from accommodavid/tar-test
Add test for tar archives
2015-12-09 11:34:57 +01:00
Adam Stankiewicz
f2767648e7 Merge pull request #2093 from contolini/hide-prereleases
Hide prerelease versions from `bower info`
2015-12-09 11:33:54 +01:00
Accommodavid
9e4bdd270d Add test for tar archives
Adds a test that checks if dependencies that point to tar archives (not
tar.gz) are handled and extracted correctly. Also removes a test from
`test/commands/install.js` that was duplicated.

Re-add postinstall test
2015-12-09 09:05:13 +01:00
Chris Contolini
7cb88ab49f Add renderer tests for prereleases 2015-12-08 17:59:21 -05:00
Chris Contolini
a532c55dca Hide prereleases when showing package info 2015-12-08 17:59:21 -05:00
Adam Stankiewicz
c559432c19 Properly call coveralls script 2015-12-08 20:05:04 +01:00
Adam Stankiewicz
9aae3b8d7e Merge pull request #45 from paulohp/grunt-travis
added grunt travis script to .travis.yml
2015-12-08 19:54:52 +01:00
Adam Stankiewicz
322c49edf4 Get rid of STRICT_REQUIRE flag for coverage testing 2015-12-08 19:52:10 +01:00
Adam Stankiewicz
34ec39507c Merge pull request #32 from paulohp/sync-functions
added synchronous functions to read and find
2015-12-08 19:20:40 +01:00
Adam Stankiewicz
fe9b27a647 Try to fix appveyor build with npm-env 2015-12-08 19:15:06 +01:00
Paulo Pires
304bb36bbc Added coveralls support
added missing packages

added test coverage files to gitignore

remove unecessary files

added missing coveralls package
2015-12-08 09:48:42 -08:00
Paulo Pires
376a2de600 added synchronous functions to read and find
added .readSync function

Added coverage
2015-12-08 05:33:38 -08:00
Adam Stankiewicz
1605374a25 Properly run code coverage on appveyor 2015-12-08 14:32:05 +01:00
Adam Stankiewicz
ac244a1400 Run coverage on appveyor as well 2015-12-08 14:21:05 +01:00
Adam Stankiewicz
9e58bbca31 Merge pull request #31 from paulohp/coveralls
Added coverage report. 📄
2015-12-08 13:54:36 +01:00
Paulo Pires
027a0694f7 Added coverage 2015-12-08 04:16:44 -08:00
Adam Stankiewicz
d50e50f3b5 Add discord chat link, closes #2088 2015-12-08 11:14:33 +01:00
Adam Stankiewicz
3030469c59 Update update-notifier to 0.6.0 2015-12-08 11:00:51 +01:00
Adam Stankiewicz
977e0ddc52 Update changelog 2015-12-07 20:34:47 +01:00
Adam Stankiewicz
de3e1089da Better formatting of help message 2015-12-07 20:32:33 +01:00
Adam Stankiewicz
7897ad7dba Move bug reports to the top 2015-12-07 16:35:19 +01:00
Adam Stankiewicz
accdab3ece Link bug reports to wiki 2015-12-07 16:34:26 +01:00
David DeSandro
612aaa88eb add help menu for update --save, update --save-dev
Ref #2035
2015-12-07 08:42:17 -05:00
Adam Stankiewicz
338ac99080 Bump to 1.7.0 2015-12-07 13:34:01 +01:00
Adam Stankiewicz
9605bbea5f Bump bower-config to 1.3.0 2015-12-07 13:08:58 +01:00
Adam Stankiewicz
7bc97a1241 Add changelog entry for array notation in env 2015-12-07 11:45:36 +01:00
Adam Stankiewicz
bd2c253f99 Bump to 1.3.0 2015-12-07 11:43:12 +01:00
Adam Stankiewicz
f1efce7d1f Merge pull request #44 from bower/feature/env
Allow for arrays in env fields (includes a test)
2015-12-07 11:39:17 +01:00
Adam Stankiewicz
844cc5a527 Add test for accept array from process env feature 2015-12-07 11:31:09 +01:00
Peng Wang
0e27b6f813 restore spacing and code formating 2015-12-07 11:31:09 +01:00
Adam Stankiewicz
3791aee9d6 Merge pull request #2085 from pertrai1/feature/eslintrc
adding eslintrc for new ruleset option
2015-12-06 15:48:52 +01:00
Rob Simpson
20a223a959 adding eslintrc for new ruleset option 2015-12-06 06:10:13 -05:00
Adam Stankiewicz
9219f54718 Merge pull request #43 from prometheansacrifice/adding-changelog
Adding CHANGELOG.md
2015-12-06 11:27:30 +01:00
Adam Stankiewicz
ea5bd51327 Merge pull request #2083 from prometheansacrifice/updating-changelog
Adds changelog for release 1.7.0
2015-12-06 11:26:26 +01:00
Manas
5a2272cab1 Adds CHANGELOG.md 2015-12-06 01:19:11 +05:30
Manas
b94c20b8da Release 1.7.0 2015-12-05 22:28:18 +05:30
Adam Stankiewicz
b81ba140e3 Bump to 1.6.9 and release 2015-12-04 22:28:09 +01:00
Adam Stankiewicz
4ffdb500b9 Update to npm version of fs-write-stream-atomic 2015-12-04 22:28:09 +01:00
Adam Stankiewicz
609607b096 Merge pull request #42 from mithun/allow-env-vars
Allow the use of environment variables in .bowerrc
2015-12-03 12:30:43 +01:00
Mithun Ayachit
e9657668a9 Allow the use of environment variables in .bowerrc
Similar to npmrc

Expand '~/' to user's home directory
2015-12-03 05:20:23 -06:00
Adam Stankiewicz
1696cde273 Merge pull request #2074 from eppeters/bower-search-prompt-before-listing-all
Prompt before listing all repos when running `bower search` without a query param
2015-12-03 00:21:57 +01:00
Adam Stankiewicz
94ffc35b25 Merge pull request #2070 from contolini/dont-update-all
Only update the packages requested by the user
2015-12-02 23:14:58 +01:00
Edward Peters
5a1e5eb9c7 Make 'bower search' show the help display when a user does not enter a
search term. Keep current behavior when running with config.json
enabled, or in non-interactive mode.

Rewrite bower search tests to cover the different cases of using the
command without a query parameter (interactive w/o config.json,
interactive w/ config.json, and non-interactive)
2015-12-02 17:07:27 -05:00
Chris Contolini
8c1f30b1c8 Format test files to comply with new jscs rules 2015-12-02 14:10:33 -05:00
Chris Contolini
e3f402fc66 Only update packages requested by the user 2015-12-02 14:10:28 -05:00
Chris Contolini
6616d09f47 Add failing tests for single package updates, optimize older tests 2015-12-02 14:10:28 -05:00
Adam Stankiewicz
25ad2ef946 Merge pull request #2076 from prometheansacrifice/instructions-for-squashing-commits
Adds instructions for squashing commits
2015-12-02 13:51:13 +01:00
Manas
ba4a1a9d45 Adds instructions for squashing commits 2015-12-02 13:30:45 +05:30
Adam Stankiewicz
3a37202dc5 Rollback to original fs-write-stream-atomic 2015-12-01 15:58:18 +01:00
Adam Stankiewicz
12258324d3 More code style rules to enforce 2015-11-30 11:06:57 +01:00
Adam Stankiewicz
2adb0b0807 Merge pull request #2063 from AnthonyBobsin/style-guide
Implements jscs to enforce a newly created style guide for the repo.
2015-11-30 10:54:40 +01:00
AnthonyBobsin
19fc84007d Implements jscs to enforce a newly created style guide for the repo. Uses jscs to fix some minor style guide warnings. 2015-11-29 16:22:58 -05:00
Adam Stankiewicz
8fcbd3671d Merge pull request #2062 from contolini/update-save
Add `bower update --save` functionality
2015-11-28 19:29:40 +01:00
Chris Contolini
0eadbef02d Merge branch 'master' into update-save 2015-11-28 08:42:43 -08:00
Adam Stankiewicz
107ad1d3fc Merge pull request #2060 from Utsav2/remove-at
Remove @ in temporary directories
2015-11-28 13:14:30 +01:00
Chris Contolini
d2ba80e6e9 Add bower update --save functionality 2015-11-28 05:40:24 -05:00
Adam Stankiewicz
f18b38cde5 Merge pull request #40 from ryantemple/master
Updated so cwd is set from command line and correct directory tree used
2015-11-28 10:57:22 +01:00
Ryan Temple
e6f1805df0 Added tests 2015-11-27 19:31:24 +00:00
Ryan Temple
4da1b62542 Updated so cwd is set from command line and correct directory tree used 2015-11-27 19:30:08 +00:00
Utsav Shah
852a586d5c Replace temp directory name with md5 hash
Fixes issues with characters like @ interfering with directory name
lookups
2015-11-27 13:17:36 -06:00
Utsav Shah
e8a2d92785 Remove @ in temporary directories 2015-11-27 11:36:14 -06:00
Adam Stankiewicz
50ed13e4ee Release 1.6.8 2015-11-27 15:53:52 +01:00
Adam Stankiewicz
cb9b737b9d Merge pull request #2058 from bower/enotdir-coverage
Add directory test for install command
2015-11-27 15:19:10 +01:00
Adam Stankiewicz
700b46162c Remove minor bumps of node from Travis 2015-11-27 14:47:11 +01:00
Accommodavid
0e1153f610 Add ENOTDIR test for install command 2015-11-27 14:43:22 +01:00
Adam Stankiewicz
8669ed2aac Bump bower-config to 1.2.3 2015-11-27 14:08:50 +01:00
Adam Stankiewicz
6d12ef291b Properly restore env variables if they are undefined 2015-11-27 13:53:36 +01:00
Adam Stankiewicz
ca0a36abcf Make downloader work on all platforms, fixes #2050 2015-11-27 13:45:19 +01:00
Adam Stankiewicz
4c6fdc905f Revert "Fix tests on Windows (cleanup of downloaded files)"
This reverts commit bb7c02b07b.
2015-11-27 00:33:15 +01:00
Adam Stankiewicz
cdbc4a123c Merge pull request #2040 from bower/fix-shallow-host
Fix shallow clone host
2015-11-26 18:25:49 +01:00
Adam Stankiewicz
bb7c02b07b Fix tests on Windows (cleanup of downloaded files) 2015-11-26 18:06:26 +01:00
Adam Stankiewicz
4f42aeabd7 Fix tests for abbreviations on Windows 2015-11-26 16:20:59 +01:00
Adam Stankiewicz
b77517ef64 Remove iojs from versions tested on travis (node 4.0 should be enough) 2015-11-26 14:35:52 +01:00
Adam Stankiewicz
b9c3f750eb Remove npm-shrinkwrap.json (bundledDependencies are enough..) 2015-11-26 14:25:14 +01:00
Adam Stankiewicz
aaecbfab17 evert "Merge pull request #2027 from watilde/patch/supports-tilde"
This reverts commit 2ff53fc448, reversing
changes made to 89286e628b.
2015-11-26 14:23:19 +01:00
Adam Stankiewicz
c4539aa603 Update npm-shrinkwrap.json 2015-11-26 14:01:10 +01:00
Adam Stankiewicz
7f801319bf Merge branch 'release-1.6.6' 2015-11-26 12:37:35 +01:00
Adam Stankiewicz
1a990f4563 Release 1.6.7 2015-11-26 12:31:53 +01:00
Trevor Heins
944a328f30 Merge pull request #2051 from kunyan/improve/2049
Add badge links to readme #2048 #2049
2015-11-26 00:00:46 -05:00
Kun Yan
e11b60d812 Add badge links to readme #2048 #2049
Signed-off-by: Kun Yan <kyan@redhat.com>
2015-11-26 10:38:35 +08:00
Adam Stankiewicz
c91e99b782 Merge pull request #2045 from zzarcon/chore/move_abbreviations_from_index
Move abbreviations to a different file
2015-11-26 00:01:43 +01:00
Hector Leon Zarco Garcia
da8ec1e4ab Move abbreviations to a different file 2015-11-25 23:58:30 +01:00
Adam Stankiewicz
c8d5199815 Merge pull request #33 from adriaanthomas/handle-default-ca
Load custom CA file for "default"
2015-11-25 18:32:44 +01:00
Vlad Filippov
e7868f0fb1 Changelog updates
[skip ci]
2015-11-25 10:54:11 -05:00
Adam Stankiewicz
eca46dbd85 Merge pull request #2042 from paulohp/update-node-version-appveyor
Added major versions (5 and 4) to appveyor
2015-11-25 16:47:13 +01:00
Vlad Filippov
67bd5d026f Bump to 1.6.6 2015-11-25 10:45:42 -05:00
Paulo Pires
51de67cc73 added major versions 5 and 4 to appveyor 2015-11-25 09:33:03 -02:00
Vlad Filippov
3d4f9cd919 Fix shallow clone host 2015-11-24 14:21:27 -05:00
Adam Stankiewicz
cd8d397e63 Merge pull request #38 from bower/revert-36-master
Revert "updated to respect the bowerrc in the cwd passed in as command line argument"
2015-11-24 16:53:09 +01:00
Riyadh Al Nur
5a9c099188 Revert "updated to respect the bowerrc in the cwd passed in as command line argument" 2015-11-24 21:25:11 +06:00
Adam Stankiewicz
2137089a70 Merge pull request #37 from riyadhalnur/update-node-versions-travis
Added newer Node versions to Travis
2015-11-24 13:11:17 +01:00
Riyadh Al Nur
fbd02852a3 Added newer Node versions to Travis
ADDED/UPDATED:
- Updated Travis file to not test against `iojs` anymore
- Added versions 4 and 5 of Node to test against on Travis
2015-11-24 13:11:54 +06:00
Riyadh Al Nur
f2584ade24 Merge pull request #36 from ryantemple/master
updated to respect the bowerrc in the cwd passed in as command line argument
2015-11-24 13:06:05 +06:00
Rob Simpson
2f72cd4b7d Adding contributing link to CONTRIBUTING.md
We now have a section in the wiki for contributors so I added a link to this until all of it can be merged together.
2015-11-24 00:10:47 -05:00
Ryan Temple
50bfd14968 updated to respect the bowerrc in the cwd passed in as command line argument 2015-11-23 22:45:45 +00:00
Adam Stankiewicz
2ff53fc448 Merge pull request #2027 from watilde/patch/supports-tilde
Supports ~/ paths to cwd field in .bowerrc
2015-11-21 16:32:52 +01:00
Daijiro Wachi
42cd2e584f Update npm-shrinkwrap.json to add untildify 2015-11-19 23:46:22 +01:00
Daijiro Wachi
49de3cca62 Add a test case to support ~/ paths to cwd field 2015-11-19 23:31:22 +01:00
Daijiro Wachi
718db0309f Supports ~/ paths to cwd field in .bowerrc
+ Add untildify module
+ Update config.js to convert tilde path to home path

Fixes #1784
2015-11-19 21:36:28 +01:00
Adam Stankiewicz
d867095f50 Merge pull request #34 from kevcenteno/bowerrc-dir-error
Show error if .bowerrc is a directory
2015-11-19 18:17:24 +01:00
kevcenteno
e51bf20e72 Show error if .bowerrc is a directory 2015-11-19 10:35:22 -05:00
Adam Stankiewicz
89286e628b Update to fixed version of fs-write-stream-atomic 2015-11-18 15:06:46 +01:00
Adam Stankiewicz
c8042b4781 Fix tests on node 0.10 by updating nock 2015-11-18 14:50:00 +01:00
Adriaan Thomas
15f8a30cd4 Also load custom CA file for "default" 2015-11-17 13:31:40 +01:00
Adam Stankiewicz
9fdd96c92b Update fs-write-stream-atomic to fork with timing fix
It turned out that removing files synchronously on windows can cause
issues. This commit makes Appveyor build for Windows little better.
2015-11-17 12:13:26 +01:00
Adam Stankiewicz
ce15df27ca Properly destroy read stream for downloads 2015-11-17 12:13:26 +01:00
Rob Simpson
468657bfe2 bug report link fix on readme 2015-11-16 21:27:54 -05:00
Rob Simpson
814180d129 update bug report link to point to wiki 2015-11-16 21:25:48 -05:00
Rob Simpson
93be2fef6d Update README.md 2015-11-16 16:08:04 -05:00
Rob Simpson
3ab71f27ff Update README.md 2015-11-16 16:06:11 -05:00
Adam Stankiewicz
38fa1b6858 Downgrade spawn-sync to 1.0.13 (windows build) 2015-11-15 13:18:33 +01:00
Adam Stankiewicz
c6ed215260 Re-order scripts for appveyor build 2015-11-15 13:15:05 +01:00
Adam Stankiewicz
74eba8d2e8 Move spawn-sync back to devDependencies... 2015-11-15 13:14:28 +01:00
Adam Stankiewicz
5a72dae2c8 Build on both node 0.10 and 0.12 on appveyor 2015-11-15 13:10:10 +01:00
Adam Stankiewicz
6194821643 Skip installing npm and svn for appveyor 2015-11-15 13:06:16 +01:00
Adam Stankiewicz
37aab9c72e Downgrade spawn-sync for appveyor 2015-11-15 13:01:24 +01:00
Adam Stankiewicz
0a0dc8cef9 Update spawn-sync to fix appveyor tests 2015-11-15 12:51:41 +01:00
Adam Stankiewicz
c6d89b79b4 Remove npm-shrinkwrap from devDependencies (issues with npm@3.x) 2015-11-15 12:02:39 +01:00
Adam Stankiewicz
8a435dff27 Update to newest npm in appveyor builds 2015-11-15 11:51:45 +01:00
Michael Robinson
459925eba7 Merge pull request #1972 from pwielgolaski/#1958
fix passing options to request
2015-11-15 22:22:12 +13:00
Adam Stankiewicz
6614a43658 Bump to 1.6.5 2015-11-14 15:56:13 +01:00
Adam Stankiewicz
88fd65ae34 Merge pull request #1988 from faceleg/travis-node-versions
Run travis tests in all versions of node
2015-11-14 15:52:47 +01:00
Adam Stankiewicz
83da088024 Update CONTRIBUTING.md 2015-11-14 15:39:41 +01:00
Piotr Wielgolaski
51a986d0d4 add test for download.js and fix download behavior to not leave temporary files in case of error 2015-11-07 18:26:48 +01:00
Michael Robinson
0aefe8fc0e Be more specific with node version 5 2015-11-05 10:47:39 +13:00
Michael Robinson
2845984169 Use environment vars for node versions because OS X 2015-11-05 10:47:24 +13:00
Michael Robinson
2a91dc5fb1 Updated travis tests to run in supported node versions 2015-11-05 10:43:02 +13:00
Michael Robinson
5eca9274ee Added language to travis.yml 2015-11-05 10:40:44 +13:00
Michael Robinson
d57d81ca85 Run travis tests in all versions of node 2015-11-05 10:38:15 +13:00
Adam Stankiewicz
a5dcf9cc24 Merge pull request #1973 from gronke/remove-insecure-suggestion-from-readme
remove hint to use --allow-root flag from readme
2015-10-26 10:30:59 +01:00
Stefan Grönke
484c8985ed remove hint to use --allow-root flag from readme 2015-10-26 01:14:09 +01:00
Piotr Wielgolaski
931b0a8905 fix passing options to request
options from download need to be pass to request library that make HTTP
request

Also when there is http error stream need to be closed otherwise there
is issue reported that unlink operation is not permitted on Windows
2015-10-24 16:52:22 +02:00
Adam Stankiewicz
bfd1e93325 Install stable version on npm on appveyor 2015-10-24 12:01:59 +02:00
Adam Stankiewicz
bf23751549 Bump to 1.6.4 2015-10-24 11:51:50 +02:00
Adam Stankiewicz
b79034fbb9 Merge pull request #1956 from bower/strip-trailing-slash
strip trailing slash in urlResolver
2015-10-24 11:09:32 +02:00
Adam Stankiewicz
eaa05ac6c1 Merge pull request #1960 from bower/add-user-agent
add User-Agent to downloadd
2015-10-24 11:08:31 +02:00
Adam Stankiewicz
8f0a3d727e Merge pull request #1969 from chrisjons/svn_improvements
use --non-interactive when running svn client
2015-10-24 10:41:21 +02:00
Adam Stankiewicz
b6a524e6b4 Merge pull request #1970 from twalpole/ignore2
fix issue #1962 - ignoredDependenices multiple install run
2015-10-24 10:39:20 +02:00
Thomas Walpole
43d00deb88 fix issue #1962 - ignoredDependenices multiple install run 2015-10-23 11:52:40 -07:00
Christian Jönsson
4836a0cae9 use --non-interactive when running svn client
If there is a problem in connecting to the Subversion server,
e.g. credential or certificate related, the CLI client will pause to
ask the user for input on the console. This is not handled by bower
Subversion Resolver, causing the install process to hang forever
with no message printed to the bower user.

Running the Subversion CLI client with the option --non-interactive
will instead cause the client to exit upon such an error.This is
detected by the bower resolver and the message printed to the user,
making it much easier to investigate and solve the underlying problem.
2015-10-23 13:05:16 +02:00
Adam Stankiewicz
302c4ade51 Leave link only to Support Declaration 2015-10-22 12:19:42 +02:00
Adam Stankiewicz
75d80e014a Mention about Support Declaration and BountySource 2015-10-22 12:15:50 +02:00
Patrick Kettner
0f790f4293 add User-Agent to downloadd 2015-10-20 13:51:50 -07:00
Patrick Kettner
452217e9fa strip trailing slash in urlResolver 2015-10-17 21:48:10 -05:00
Adam Stankiewicz
f66c0cfe5c Update npm to 2.0.0 on travis 2015-10-16 12:05:36 +02:00
Adam Stankiewicz
30898c13d3 Update changelog 2015-10-16 12:01:25 +02:00
Adam Stankiewicz
2330d59ffa Bump to 1.6.3 2015-10-16 11:49:04 +02:00
Adam Stankiewicz
1316be57dc Update bower-config to 1.2.2 2015-10-16 11:46:51 +02:00
Adam Stankiewicz
b7c19695e7 Bump to 1.2.2 2015-10-16 11:38:06 +02:00
Adam Stankiewicz
b85cf2683c Fix registry configuration expanding, closes bower/bower#1950 2015-10-16 11:37:41 +02:00
Adam Stankiewicz
ff0f2a8f83 Use stat instead of lstat for checking if something is directory, fixes #1951 2015-10-16 11:17:03 +02:00
Adam Stankiewicz
7e5184d342 Merge pull request #1954 from scottaddie/master
Replace README file msysgit references with Git for Windows
2015-10-16 11:05:35 +02:00
Scott Addie
8fa1fd55e9 Replace README file msysgit references with Git for Windows 2015-10-15 22:18:30 -05:00
Adam Stankiewicz
52463dea09 Bump and update npm-shrinkwrap.json for bower 1.6.2 2015-10-15 16:15:51 +02:00
Adam Stankiewicz
8cf09f5444 Revert "Bump to 1.6.1 and update npm-shrinkwrap.json"
This reverts commit 20a6190ed8.
2015-10-15 16:12:42 +02:00
Adam Stankiewicz
20a6190ed8 Bump to 1.6.1 and update npm-shrinkwrap.json 2015-10-15 15:56:23 +02:00
Adam Stankiewicz
402a9f3017 Add node-uuid back to npm-shrinkwrap 2015-10-15 14:10:25 +02:00
Adam Stankiewicz
af09872fba Set default bower.config again 2015-10-15 13:50:36 +02:00
Adam Stankiewicz
2311d7dc44 Update npm-shrinkwrap.json with npm-shrinkwrap tool 2015-10-15 13:29:56 +02:00
Adam Stankiewicz
b261bf8a76 Update npm-shrinkwrap.json for bower 1.6.0 2015-10-15 13:13:21 +02:00
Adam Stankiewicz
140c6d963f Update changelog and bump 2015-10-15 13:03:30 +02:00
Adam Stankiewicz
0c5e457359 Merge pull request #1948 from bower/feature/bundle
Shrinkwrap all dependencies and add them to bundledDependencies
2015-10-15 13:01:13 +02:00
Adam Stankiewicz
bfa4295606 Try to use container-based infrastructure on Travis 2015-10-15 12:53:18 +02:00
Adam Stankiewicz
8ac68ede5d Shrinkwrap all dependencies and add them to bundledDependencies 2015-10-15 12:45:38 +02:00
Adam Stankiewicz
a019f887e9 Update chmodr to fix chmod behavior on windows 2015-10-15 11:14:49 +02:00
Adam Stankiewicz
eba2c69308 Update bower-config to fix proxy behavior on windows 2015-10-15 11:14:35 +02:00
Adam Stankiewicz
8df5970300 Bump to 1.2.1 2015-10-14 21:30:26 +02:00
Adam Stankiewicz
db265d471f fix: Setting HTTP_PROXY on Windows (case insensitivity) 2015-10-14 21:30:09 +02:00
Adam Stankiewicz
0bb1536c99 Better manage file handles, properly close streams 2015-10-14 19:31:53 +02:00
Adam Stankiewicz
64eb7d598a Use lstat instead of stat for rimraf util 2015-10-14 17:24:54 +02:00
Adam Stankiewicz
df8e5a16be Fix readdir call on Windows
Sometimes it return ENOENT instead of ENODIR for normal files.

This broke code paths in few places. Also, see:
https://github.com/isaacs/chmodr/pull/8
2015-10-14 16:09:38 +02:00
Adam Stankiewicz
3ce2dd3989 Replace all fs with graceful-fs 2015-10-14 14:31:13 +02:00
Adam Stankiewicz
99105fbb57 Try chmod 777 + rimraf as fallback on rimraf in all places 2015-10-14 12:50:41 +02:00
Adam Stankiewicz
96f1e98859 test: Fix url for js-event-emitter 2015-10-13 17:56:42 +02:00
Adam Stankiewicz
d614b057c9 fix: Set environment variable as string, not number 2015-10-13 17:27:27 +02:00
Adam Stankiewicz
aafe02f3e9 Update bower-registry-client and bower-config 2015-09-28 19:42:35 +02:00
Adam Stankiewicz
0441e16bdb Bump to 1.2.0 2015-09-28 19:37:58 +02:00
Adam Stankiewicz
30a489535e Prevent defaulting cwd to process.cwd() 2015-09-28 19:37:44 +02:00
Adam Stankiewicz
ac88ece259 Bump to 1.0.0 2015-09-28 19:15:26 +02:00
Adam Stankiewicz
9b45c76744 Change ~ ranges to ^ 2015-09-28 19:14:58 +02:00
Adam Stankiewicz
059a5f83b7 Require using explicitly bower-config 2015-09-28 19:14:58 +02:00
Adam Stankiewicz
cf5cd61995 Pass proxy configuration via env variables instead of directly, closes #22 2015-09-28 19:14:58 +02:00
Adam Stankiewicz
a499cc5103 Update bower.json dependency 2015-09-28 19:14:58 +02:00
Adam Stankiewicz
123779bbd1 Remove client-side check for register command, closes bower/registry#23 2015-09-28 18:01:46 +02:00
Adam Stankiewicz
5365c7b428 Disable client-side check for registering git:// endpoints 2015-09-28 17:46:58 +02:00
Adam Stankiewicz
da961a9c42 Pass proxy configuration to request.js via env variables 2015-09-28 17:34:06 +02:00
de Winter, Anton
8ff0e0e2d1 Components that are not installed by bower should be left alone
Rework of commit by @wibblymat for PR #1363
Make compatible with existing tests
Uses fs.readdirSync() (once!) instead of async method.
Added new test
2015-09-28 17:18:36 +02:00
Adam Stankiewicz
ffde6bd228 Remove version generation from "bower init" command, closes #1343 2015-09-28 17:07:29 +02:00
Adam Stankiewicz
bebb4fb33b Fix one more upper case spelling 2015-09-27 19:46:43 +02:00
Adam Stankiewicz
2c243ea5b7 tests: Fix camel casing 2015-09-27 19:42:16 +02:00
JD Isaacks
498fe84b99 Use values from package.json as defaults if exists 2015-09-27 19:39:46 +02:00
Adam Stankiewicz
9b8b66ed83 Merge pull request #1838 from yasinkocak/patch-1
Added keywords tag
2015-09-27 18:22:51 +02:00
Adam Stankiewicz
9cc3dd4c92 Pass certificate for GitHubResolver and UrlResolver, closes #1869 2015-09-27 18:18:11 +02:00
Adam Stankiewicz
bf23d81c9e Update bower-config and fix tests for ignoreDependenies 2015-09-27 18:18:11 +02:00
Adam Stankiewicz
f53100d8d3 Bump version to 1.1.2 2015-09-27 17:08:55 +02:00
Adam Stankiewicz
acbe60cdf1 Perform only camelcase normalization before merging configs 2015-09-27 17:08:42 +02:00
Adam Stankiewicz
4c7f37e0f8 Bump to 1.1.1 2015-09-27 16:41:44 +02:00
Adam Stankiewicz
3ba696937c Merge extra config after normalisation 2015-09-27 16:41:32 +02:00
Adam Stankiewicz
1647994471 Bump to 1.1.0 2015-09-27 16:35:01 +02:00
Adam Stankiewicz
674e09dc56 Allow for overwriting options 2015-09-27 16:34:51 +02:00
Adam Stankiewicz
4c129d470f Bump to 1.0.1 2015-09-27 15:03:33 +02:00
Adam Stankiewicz
c630f01baa Update dependencies 2015-09-27 15:02:48 +02:00
Adam Stankiewicz
6018fc13b2 Bump version to 1.0.0 2015-09-27 14:45:53 +02:00
Adam Stankiewicz
c4fc6cd0e2 Typo in readme 2015-09-27 14:41:54 +02:00
Adam Stankiewicz
eed8735238 Fix formatting in the readme 2015-09-27 14:41:17 +02:00
Adam Stankiewicz
8c0155e8bd Normalize config right away in load method 2015-09-27 14:33:22 +02:00
Adam Stankiewicz
b2d4412e59 Remove unused methods and better document .restore method 2015-09-27 14:14:35 +02:00
John Andersen
4e3e45a88b Support for setting and restoring proxy related env variables 2015-09-27 14:05:17 +02:00
Adam Stankiewicz
af9b386d8a Suport backward-compatible ca certificate embedding 2015-09-27 13:34:17 +02:00
Adriaan Thomas
201b8a3bc6 Load CA file contents instead of keeping the path, so the request library can use it. 2015-09-27 13:34:17 +02:00
Adam Stankiewicz
6e1a994c26 Merge pull request #1922 from pwang2/feature/allow-resolver-passed-via-cli
allow --config.resolvers={required package}
2015-09-27 12:31:37 +02:00
Thomas Walpole
2ccc05cb98 get ignoredDependencies from .bowerrc instead of bower.json 2015-09-27 12:27:39 +02:00
Thomas Walpole
e7d22ffb11 install and update tests for ignoredDependencies 2015-09-27 12:27:39 +02:00
SignalDancer
4805c3615b Allow Ignore For Child Dependencies
Fix for bug #927. Ignore package if name matches specified in bower.json.
Permit fetch if package is explicitly declared in dependencies or devDependencies.
Designed for users who need tighter control of versions due to corporate liscence restrictions or other reasons.

Code Review Comments
2015-09-27 12:27:38 +02:00
Adam Stankiewicz
44a5260050 test: Clear analytics config for test environment 2015-09-27 12:22:40 +02:00
Adam Stankiewicz
d72d01823d Bump inquirer to 0.10, closes #1883 2015-09-27 12:03:25 +02:00
Adam Stankiewicz
1e166189ba Merge pull request #1917 from lukemelia/improve-version-failure-message
Include package name in error info when a version is not found.
2015-09-24 14:17:13 +02:00
Adam Stankiewicz
66310523d1 Bump to 1.5.3 2015-09-24 13:58:05 +02:00
Adam Stankiewicz
87a041a212 Fix --save-exact feature for github endpoints, fixes #1925 2015-09-24 13:34:49 +02:00
Adam Stankiewicz
9c52ec2751 Revert "Auto-sort bower.json dependencies alphabetically, fixes #1373"
This reverts commit 9dd79a8061.
2015-09-24 11:06:55 +02:00
Adam Stankiewicz
9010269236 Merge pull request #1923 from mex/feature/insight-prompt
Bumps Insight to reduce prompt friction
2015-09-18 12:11:36 +02:00
Michael Storgaard
aac254d275 Bumped Insight to reduce prompt friction
- Insight now checks for `process.env.CI` before prompting
 - Insight now times out after 30 seconds of no response to prompt
2015-09-18 11:18:08 +02:00
Peng Wang
889b54f309 allow --config.resolvers={required package} 2015-09-17 16:25:05 -05:00
Luke Melia
5d13ffda09 Include package name in error info when a version is not found.
Prior to this commit, when specifying a package version that cannot
be resolved, but other versions are available, the error message
did not state which what package failed, allowing for confusion.

For example, you might see:

```
bower ENORESTARGET  No tag found that was able to satisfy 1.0.2

Additional error details:
Available versions: 1.0.1, 1.0.0
```

After this change, in the above situation the svn and git resolvers
will produce the following:

```
bower ENORESTARGET  No tag found that was able to satisfy 1.0.2

Additional error details:
Available versions in somelib: 1.0.1, 1.0.0
```
2015-09-12 21:10:01 -04:00
Adam Stankiewicz
31b6d5971c Merge pull request #1819 from bak/init_private
Allow boolean values in bower.json file created by `bower init`
2015-09-11 22:55:52 +02:00
Ben Cullen-Kerney
304b6393d4 Allow whitelisted values in bower.json file created by bower init
A change in the behavior of `mout.lang.isEmpty()` in Mout v0.10.0
introduced a bug in `bower init`, preventing it from including Boolean
values in "bower.json".

This commit explicitly whitelists the types that are used in the
bower.json spec - Object, Array, String, Boolean - as well as Number for
future compatibility.
2015-09-11 12:40:20 -07:00
Sindre Sorhus
490f63a838 modularize the MD5 util function 2015-09-03 11:00:38 +07:00
Adam Stankiewicz
64d990ba10 Add changelog for 1.5.2 2015-08-25 22:37:23 +02:00
Adam Stankiewicz
cb019c405b Bump version to 1.5.2 2015-08-25 22:31:13 +02:00
Adam Stankiewicz
26f80d25be Put smart host detection behind a configuration, fixes #1764 2015-08-25 22:26:26 +02:00
Adam Stankiewicz
fe9a1bb5fc Revert "upgrade to newer semver, fixes #1817,#1845,#1851"
This reverts commit 8744449016.
2015-08-25 17:12:51 +02:00
Adam Stankiewicz
79679f9b08 Revert "Make bower commands work from subdirectories"
This reverts commit 7acafc26d6.
2015-08-25 17:11:48 +02:00
Adam Stankiewicz
5ef5403d69 Update changelog 2015-08-25 11:20:57 +02:00
Adam Stankiewicz
23afb3a129 Bump version to 1.5.1 2015-08-23 16:37:07 +02:00
Adam Stankiewicz
fac08cf835 [test] Recover process.cwd() after running one test 2015-08-23 16:32:45 +02:00
Adam Stankiewicz
dd67cc7de0 If cwd provided explicitly, force using it, fixes #1866 2015-08-23 16:24:36 +02:00
Adam Stankiewicz
8531534241 Merge pull request #1885 from bower/rwjblue-patch-1
Remove `it.only`.
2015-08-23 15:30:38 +02:00
Robert Jackson
0993621bb8 Remove it.only. 2015-08-23 09:26:48 -04:00
Adam Stankiewicz
45fe5c37cc Bump version to 1.5.0 2015-08-23 14:34:30 +02:00
Adam Stankiewicz
35b60d8d89 Merge pull request #1865 from bower/sheerun-patch-1
No longer prefer installing bower as global
2015-08-23 14:30:16 +02:00
Adam Stankiewicz
63b4d37207 Merge pull request #1866 from bower/feature/cwd
Make bower commands work from subdirectories
2015-08-23 14:30:05 +02:00
Adam Stankiewicz
793268ed54 Merge pull request #1871 from bower/1.5.0-preview
Pluggable resolvers
2015-08-23 14:28:25 +02:00
Adam Stankiewicz
a4a05a5413 Make custom resolvers implementation pass through linter 2015-08-23 14:20:09 +02:00
Adam Stankiewicz
821979bab1 Rename options to bower and add "version" to resolvers options 2015-08-23 14:16:23 +02:00
Adam Stankiewicz
69be742619 Improve API for pluggable resolvers 2015-08-23 13:44:00 +02:00
Sindre Sorhus
298982b522 Merge pull request #1879 from bower/sheerun-patch-2
Remove core team section from README
2015-08-18 01:10:43 +07:00
Adam Stankiewicz
9f2b3d1cd4 Merge pull request #1872 from insanehong/add-shorthand-version
Add shorthand for version of options in help.json
2015-08-13 23:14:37 +02:00
Adam Stankiewicz
800119fc92 Remove core team section from README
Instead, use link to contributors page on GitHub
2015-08-13 23:11:44 +02:00
insanehong
725fc26880 Add shorthand for version of options in help.json
"-v" shorthand aleady supported of cli opeion for output version
2015-08-04 13:58:23 +09:00
Adam Stankiewicz
ed27e87540 Fix the tests 2015-08-04 06:40:03 +02:00
Adam Stankiewicz
4fc2b5cf76 Add tests and improve resolver interface 2015-08-04 06:21:06 +02:00
Adam Stankiewicz
749d46930d Mention about issue with node path on Ubuntu 2015-07-29 00:02:12 +02:00
Adam Stankiewicz
7acafc26d6 Make bower commands work from subdirectories 2015-07-28 23:22:44 +02:00
Adam Stankiewicz
2817936b87 No longer prefer installing bower as global
Installing bower locally if perfectly good. It allows to use different version of bower locally.

The next step is to create bower-cli package that can run local bower installation.
2015-07-28 22:22:56 +02:00
Adam Stankiewicz
022c5a8401 Merge pull request #1864 from jodytate/patch-1
change to use a standard three dot ellipsis
2015-07-28 18:16:43 +02:00
jody tate
50fd944a62 change to use a standard three dot ellipsis 2015-07-28 08:19:05 -07:00
Adam Stankiewicz
9c9cd8164b Merge pull request #1852 from ZephyrHealth/fix/update-semver
upgrade to newer semver, fixes #1817,#1845,#1851
2015-07-28 17:00:18 +02:00
Peter Chanthamynavong
8744449016 upgrade to newer semver, fixes #1817,#1845,#1851
Upgrading to latest version of semver to fix (#1817, #1845, #1851).

Possible breaking changes in regards to the way semvers handles pre-releases.

If a version has a prerelease tags (for example, 1.2.3-alpha.3) then it will only be allowed to satisfy comparator sets if at least one comparator with the same [major, minor, patch] tuple also has a prerelease tag.

For example, the range >1.2.3-alpha.0 would be allowed to match the version 1.2.3-alpha.7, but it would not be satisfied by * or 1.2.3. See [semvers](https://github.com/npm/node-semver#prerelease-tags) additional details.
2015-07-23 07:52:14 -05:00
David DeSandro
a23f66d889 Merge pull request #27 from cvrebert/patch-1
0.6.0
2015-07-22 15:31:40 -04:00
Chris Rebert
a1596bb63c 0.6.0 2015-07-13 19:17:20 -07:00
Adam Stankiewicz
ada6fc18d9 Implement initial version of pluggable resolvers 2015-07-09 18:30:26 +03:00
David DeSandro
19af145166 Merge pull request #25 from cvrebert/normalize
Remove non-spec-compliant comma-separated string interpretation of main
2015-07-01 14:14:15 -04:00
David DeSandro
4ed81be0c6 Merge pull request #26 from cvrebert/validate-main
Validate that `main` conforms to the bower.json spec
2015-07-01 08:55:23 -04:00
Chris Rebert
1c62adcdb6 Validate that main conforms to the bower.json spec 2015-06-30 23:16:00 -07:00
Chris Rebert
95f46930a5 Remove non-spec-compliant comma-separated string interpretation of main
See https://github.com/bower/bower.json-spec/#main
2015-06-30 23:04:13 -07:00
Web Artisan
50b0186c06 Added keywords tag
Added keywords tag
2015-06-30 11:40:05 +02:00
Adam Stankiewicz
2c9d847a1d Merge pull request #1836 from blueyed/doc-remove-completion-section
doc: remove section about completion
2015-06-29 23:01:18 +03:00
Daniel Hahler
816cdda6bb doc: remove section about completion
The completion command appears to have been lost during the rewrite
(#1066).  So to avoid confusion it should not be mentioned in the
README.
2015-06-29 12:34:14 +02:00
Adam Stankiewicz
76dd504589 Merge pull request #27 from pdehaan/patch-1
Update license attribute
2015-05-21 12:31:51 +02:00
Peter deHaan
938c69c816 Update license attribute
specifying the type and URL is deprecated:

https://docs.npmjs.com/files/package.json#license
http://npm1k.org/
2015-05-20 16:57:57 -07:00
Sindre Sorhus
d5fc402a89 0.5.0 2015-05-19 22:07:12 +02:00
Sindre Sorhus
065a7a1f1b bump deps 2015-05-19 22:06:59 +02:00
Sindre Sorhus
833f97198e minor package.json tweak 2015-05-19 20:55:20 +02:00
Adam Stankiewicz
293d5cc02b Merge pull request #1802 from pgilad/patch-1
update license attribute
2015-05-19 16:04:24 +02:00
Gilad Peleg
dbb302f22a update license attribute
specifying the type and URL is deprecated:

https://docs.npmjs.com/files/package.json#license
http://npm1k.org/
2015-05-19 13:05:23 +03:00
Sindre Sorhus
ccadffea73 Update package.json 2015-04-28 12:54:04 +07:00
Sindre Sorhus
b3390ce201 use package.json files object to reduce the package size
https://docs.npmjs.com/files/package.json#files
2015-04-28 12:50:37 +07:00
Sindre Sorhus
6039f6c691 minor package.json tweak 2015-04-28 12:50:10 +07:00
Sindre Sorhus
c65cdc8699 use package.json files object to reduce the package size
https://docs.npmjs.com/files/package.json#files
2015-04-28 12:42:26 +07:00
Sindre Sorhus
7603886e04 minor package.json tweak 2015-04-28 12:41:43 +07:00
Sindre Sorhus
406a96e4d1 use package.json files object to reduce the package size
https://docs.npmjs.com/files/package.json#files
2015-04-28 12:40:35 +07:00
Sindre Sorhus
87d21e7968 use package.json files object to reduce the package size
https://docs.npmjs.com/files/package.json#files
2015-04-28 12:34:44 +07:00
insanehong
9dd79a8061 Auto-sort bower.json dependencies alphabetically, fixes #1373 2015-04-14 00:06:13 +02:00
Adam Stankiewicz
a1287416d4 Update changelog for 1.4.1 2015-04-01 00:38:21 -07:00
Adam Stankiewicz
00dc877f0a 1.4.1 2015-04-01 00:35:54 -07:00
Adam Stankiewicz
335081053d Bump bower-config and bower-registry-client versions, fixes #1763 2015-04-01 00:35:00 -07:00
Adam Stankiewicz
7d74d7d8f6 0.3.0 2015-04-01 00:24:38 -07:00
Adam Stankiewicz
e98d8139bc Bump bower-config version (bower/config#25) 2015-04-01 00:24:22 -07:00
Adam Stankiewicz
4af22cfbc0 [test] Replace sync-exec with spawn-sync
sync-exec has performance issue on Windows
2015-03-31 23:39:13 -07:00
Adam Stankiewicz
8a47aab01d Bump to 0.6.1 2015-03-31 22:27:07 -07:00
Adam Stankiewicz
395b208a0c Merge all .bowerrc upwards directory tree, fixes #25 2015-03-31 22:26:39 -07:00
Adam Stankiewicz
ab4f8a0e39 [test] Make synchronous exec work on Windows 2015-03-31 22:00:02 -07:00
Adam Stankiewicz
7e110603b5 [test] Make git helper in tests synchronous 2015-03-31 19:08:37 -07:00
Adam Stankiewicz
94455192ad Use -y flag for Chocolatey as AppVeyor suggests 2015-03-31 18:42:21 -07:00
Adam Stankiewicz
c4ca24a537 Add changelog for 1.4.0 2015-03-31 08:52:55 -07:00
Adam Stankiewicz
ea1f5d1ff0 Bump to 1.4.0 2015-03-30 15:46:30 -07:00
Adam Stankiewicz
77b7355433 Bump npm-config, fixes #1689, fixes #1711 2015-03-30 01:23:20 -07:00
Adam Stankiewicz
f6178c2f75 Bump to 0.6.0 2015-03-30 01:19:35 -07:00
Adam Stankiewicz
f1e04e5629 Merge branch 'kodypeterson-fixes-bower/bower/1689'
Conflicts:
	test/test.js
2015-03-30 01:15:56 -07:00
Adam Stankiewicz
cc913a728a Merge pull request #23 from zanona/npm-config
Allow NPM config variables. Resolve bower/bower#1711
2015-03-30 01:14:02 -07:00
Adam Stankiewicz
e727566741 Revert SvnResolver changes (windows paths in URLs) 2015-03-30 00:49:06 -07:00
Adam Stankiewicz
0f68da4eb8 Add support for two-factor authentication for login 2015-03-30 00:19:05 -07:00
Adam Stankiewicz
1a7abfd3b7 Add tests for login command 2015-03-29 23:31:20 -07:00
Adam Stankiewicz
905c2775d2 Add tests for unregister command 2015-03-29 17:56:04 -07:00
Mat Scales
126da9ee12 Unregister and login commands 2015-03-29 17:56:04 -07:00
Adam Stankiewicz
1080cb71c4 Merge pull request #1759 from nwinkler/Request-dep
Request dep
2015-03-29 14:36:24 -07:00
Nils Winkler
39a295901a Set request version to 2.53.0
This fixes the failing unit tests
2015-03-29 16:38:07 +02:00
Nils Winkler
7e55b0b099 Merge pull request #1 from bower/master
Update
2015-03-29 16:36:27 +02:00
Kody Peterson
f8c179b153 Cleanup 2015-03-27 11:05:41 -04:00
Adam Stankiewicz
b4aa90b402 Merge pull request #1755 from dancrumb/feature/1754
Fixes #1754: The version command in the programmatic API now returns the new version
2015-03-26 18:59:23 -07:00
Kody Peterson
bea46fb879 Children should be source 2015-03-26 14:32:35 -04:00
Kody Peterson
379de05a61 Correct the logic 2015-03-26 14:25:42 -04:00
Dan Rumney
a1ecf8a413 Fixes #1754: The version command in the programmatic API now returns the new version
When users of the programmatic API update the version, they may do so without having to inspect the new contents of the bower.json file to find out the new version.
This is useful in scripts where the tag needs to be pushed programatically; the user can push the new tag explicitly.
2015-03-26 10:03:52 -05:00
Adam Stankiewicz
4d59d266c1 Merge pull request #1628 from nwinkler/detect-smart-git
Automatically detecting smart Git hosts
2015-03-25 19:56:57 -07:00
Kody Peterson
c2f222760a Fixes https://github.com/bower/bower/issues/1689 and actually adds tests and testing ability 2015-03-25 13:42:44 -04:00
Nils Winkler
7e0a2ea4cb Added check for empty remote or no protocol set. 2015-03-24 20:36:15 +01:00
Nils Winkler
912808b672 Added support for caching hosts that support shallow cloning. 2015-03-24 20:22:15 +01:00
Nils Winkler
a352d51711 Using a function reference instead of calling directly from constructor 2015-03-24 17:14:28 +01:00
Nils Winkler
4ad5ed64d7 Automatically detecting _smart Git hosts_.
Added logic to automatically detect smart Git hosts that allow shallow
cloning. This is done by sending an `ls-remote` request to the server
and then evaluating the returned HTTP header fields. For this, Curl
verbose logging is enabled for the `ls-remote` request, since Curl
verbose logging sends the returned HTTP headers to `stderr`.

If the `stderr` output contains the desired header

  Content-Type: application/x-git-upload-pack-advertisement

then the server supports shallow cloning.

This approach uses Git and Curl for the heavy lifting. Instead of
implementing the request to the server using a simple HTTP client, Git
is used, since it takes care of authentication using stored credentials.

The used approach should also work for BitBucket, which only sends the
Content-Type header when a specific user agent is used. Using Git to
make the request enables this behavior.

The function to detect the smart Git host
(`GitRemoteResolver.prototype._supportsShallowCloning`) returns a
promise that is resolved when the server's request is evaluated. The
promise handling required an addition to `GitHubResolver.js` - to always
resolve the promise to `true`, since GitHub supports shallow cloning.

Added test cases to verify the new functionality.
2015-03-24 17:13:18 +01:00
Sam Saccone
3838a3b4fb Merge pull request #1740 from kytwb/master
Fix broken link to npm completion doc
2015-03-13 09:57:33 -04:00
Amine Mouafik
7d748ae15e Fix broken link to npm completion doc 2015-03-13 11:41:36 +07:00
Marcus Zanona
9aef3b7f1d Allow NPM config variables. Resolve bower/bower#1711 2015-03-12 17:42:32 +00:00
Adam Stankiewicz
9dab389b50 Merge pull request #1722 from kant/patch-1
Update year of copyright
2015-03-06 21:05:03 -08:00
Darío Hereñú
260b4adb8c Update year of copyright 2015-03-06 14:30:00 -03:00
Adam Stankiewicz
c93bbbd302 Bump to 0.2.4 2015-03-04 22:38:12 -08:00
Adam Stankiewicz
009e5ce0c8 Better error messages for unregistering 2015-03-04 22:25:46 -08:00
Adam Stankiewicz
61bb4f53c0 Increase timeout for test 2015-03-04 22:25:46 -08:00
Adam Stankiewicz
182d92f9bd test: Fix SvnResolver tests on all platforms 2015-02-28 23:56:17 -08:00
Adam Stankiewicz
61a68a9e38 test: Replace dejavu repo with pure (dejavu moved) 2015-02-28 19:52:40 -08:00
Sindre Sorhus
b6e33d70c8 Update README.md 2015-03-01 02:58:15 +08:00
Sindre Sorhus
7a26bf1a10 bump chalk
https://github.com/sindresorhus/chalk/releases/tag/v1.0.0
2015-02-23 15:07:56 +07:00
Sindre Sorhus
b6dd5e445e minor tweaks 2015-02-08 21:12:31 +07:00
Sindre Sorhus
6f4b77a440 Update .travis.yml 2015-02-08 20:47:09 +07:00
Sindre Sorhus
463584ea10 Update .travis.yml 2015-02-08 20:46:55 +07:00
Sindre Sorhus
fd8d603831 Update .travis.yml 2015-02-08 20:45:29 +07:00
Sindre Sorhus
a1ec83b002 0.2.3 2015-01-22 17:43:09 +08:00
Sindre Sorhus
041d3f2843 minor tweaks 2015-01-22 17:23:36 +08:00
Sindre Sorhus
0b22127906 Merge pull request #19 from tchajed/duplicate-package-error
Change duplicate package status code to 403
2015-01-22 16:46:52 +08:00
Sindre Sorhus
0b0b507827 Merge pull request #20 from masakura/fix-node11-proxy-failed
Fix error bower command behind proxy.
2015-01-22 16:45:12 +08:00
Sindre Sorhus
df1a87eb4e Merge pull request #1672 from therewasaguy/master
Update License Year to 2015
2015-01-21 16:37:52 +08:00
Tomo Masakura
16de289942 Fix error bower command behind proxy. 2015-01-21 13:57:28 +09:00
Jason Sigal
e203b1aa9a Update License Year to 2015
Happy new year!
2015-01-20 17:31:41 -05:00
patrick kettner
02dc97e413 Merge pull request #18 from tmcw/error-message
Adds an error message to errors. Fixes #16
2015-01-13 10:43:04 -08:00
Adam Stankiewicz
f458114c5b Enable OSX Travis build 2015-01-12 17:51:40 +01:00
Paul Irish
8db09d2fed Close #1655 PR: extend mocha timeout to 30s for travis.. 2015-01-12 16:02:05 +08:00
Sindre Sorhus
0ce7053598 bump dev deps 2015-01-12 10:09:33 +08:00
Sindre Sorhus
6a96815c44 bump insight 2015-01-12 10:04:25 +08:00
Sindre Sorhus
d7b0db41f4 bump update-notifier 2015-01-12 08:27:39 +08:00
Adam Stankiewicz
9c9f3e7055 Merge pull request #1654 from bower/alexanderGugel-save-exact
Add --save-exact flag
2015-01-11 17:32:53 +01:00
Alexander Gugel
2f6d680b6c Add --save-exact flag 2015-01-11 17:12:19 +01:00
Adam Stankiewicz
639f7939a3 Add info about Windows git configuration for testing 2015-01-11 03:33:23 +01:00
Adam Stankiewicz
95ce9cbf0c Remove node@0.11 from Windows builds 2015-01-11 03:28:12 +01:00
Adam Stankiewicz
1e0ef941c7 Add link to AppVeyor badge 2015-01-11 03:24:18 +01:00
Adam Stankiewicz
7e5bd64885 Fix AppVeyor badge 2015-01-11 03:15:33 +01:00
Adam Stankiewicz
de023bc6ea Update badges 2015-01-11 03:13:01 +01:00
Adam Stankiewicz
c7df6f50ca Add AppVeyor config for Windows CI 2015-01-11 03:08:43 +01:00
Adam Stankiewicz
df71d251f0 Disable SVN testing for unsuppoted hosts (e.g. AppVeyor) 2015-01-11 03:08:41 +01:00
Adam Stankiewicz
0b9acc18cc Test reading commands arguments 2015-01-10 12:56:15 +01:00
Adam Stankiewicz
58a7de3136 Prevent loading cli module in headless mode 2015-01-10 05:53:21 +01:00
Adam Stankiewicz
5bb77b1e03 [refactor] Prepare command argv readers for testing 2015-01-10 05:49:42 +01:00
Adam Stankiewicz
e351322ce4 More tests for lookup command and little refactor 2015-01-10 04:47:43 +01:00
Adam Stankiewicz
6b53ccc8bd Add tests for init command and fix it
In non-interactive mode error has been thrown in wrong way.
2015-01-09 03:18:53 +01:00
Adam Stankiewicz
33842b6f92 Remove dummy completion command 2015-01-09 02:29:18 +01:00
Adam Stankiewicz
5e747b2cfd Add tests for search and lookup commands 2015-01-09 02:22:05 +01:00
Adam Stankiewicz
3f8de0efb9 Add tests for cache clean command 2015-01-09 01:47:45 +01:00
Adam Stankiewicz
63da3e4595 Add tests for cache list command 2015-01-08 09:44:06 +01:00
Adam Stankiewicz
a04b69dc6a Test and fix link command 2015-01-08 05:09:32 +01:00
Adam Stankiewicz
3be4764d54 Add tests for prune command 2015-01-07 03:32:55 +01:00
Adam Stankiewicz
2d4fec01b1 Refactor some tests to promise style 2015-01-07 02:04:34 +01:00
Adam Stankiewicz
85c50eb542 Inject credentials to ENV for Travis 2015-01-06 20:56:27 +01:00
Adam Stankiewicz
ee62d00c96 Add tests for "version" command 2015-01-06 20:49:17 +01:00
Adam Stankiewicz
52a32f0887 Add tests for JsonRenderer 2015-01-06 17:59:45 +01:00
Adam Stankiewicz
dd30be90ad Fix StandardRenderer tests so they work on Travis 2015-01-06 16:03:58 +01:00
Adam Stankiewicz
4cb027eb73 Add tests for StandardRenderer 2015-01-06 15:56:10 +01:00
Adam Stankiewicz
8e0b8f2faf [test] Force monochrome color for test cases 2015-01-06 03:12:32 +01:00
Adam Stankiewicz
39491b78b1 Test register prompt as on dumb terminal (fixes travis) 2015-01-06 02:24:39 +01:00
Adam Stankiewicz
7c82da8389 Add tests for register command 2015-01-06 02:13:30 +01:00
Adam Stankiewicz
d5c13603a0 Merge pull request #1644 from pkollitsch/typo
Fix for #1639, missing line break in CLI input
2015-01-05 22:45:15 +01:00
Patrick Kollitsch
aad253bfad Fix for #1639, missing line break in CLI input 2015-01-05 12:52:31 +07:00
Adam Stankiewicz
dac055e2ef Add timeout in hope to catch stdout on travis 2015-01-05 06:51:09 +01:00
Adam Stankiewicz
85df5b9983 Add test for bower binary nad standard renderer 2015-01-05 06:47:01 +01:00
Adam Stankiewicz
537cd42097 Add tests for info command 2015-01-05 06:07:01 +01:00
Adam Stankiewicz
9d06fce5f9 Add few more tests for home command 2015-01-05 05:31:12 +01:00
Adam Stankiewicz
c029e1005f Add tests for "bower home" command 2015-01-05 05:19:54 +01:00
Adam Stankiewicz
b245a3d611 Remove unnecessary asserts from list test 2015-01-05 04:00:51 +01:00
Adam Stankiewicz
11d89c4268 fix: Tests helper regression 2015-01-05 03:48:59 +01:00
Adam Stankiewicz
6be84ab93e Add test case for #1584 2015-01-05 03:40:34 +01:00
Adam Stankiewicz
2f2c4d6740 Add tests for help command and fix it 2015-01-05 03:31:28 +01:00
Adam Stankiewicz
703eae72eb Bump to 0.2.2 2015-01-05 01:50:06 +01:00
Adam Stankiewicz
6a629e963c fix: Duplicate package has now 403 error code
According to change in bower/registry#74ae4d34b68df239b8db876a4f871b100ef3c540
2015-01-05 01:47:00 +01:00
Sindre Sorhus
06f4d0c117 package.json - use caret version specifier 2015-01-05 00:01:29 +07:00
Sindre Sorhus
b5e557ffb0 bump decompress-zip 2015-01-05 00:00:05 +07:00
Sindre Sorhus
8bd6c4a335 Merge pull request #1640 from laurelnaiad/update-deps
update package.json dependencies
2015-01-04 23:58:41 +07:00
Sindre Sorhus
29eaff9edc Merge pull request #1614 from joneshf/answer-colon
Remove erroneous colon.
2015-01-04 23:56:01 +07:00
Sindre Sorhus
08afaf7fa5 Merge pull request #1584 from vlajos/typofixes20141102
typo fixes
2015-01-04 23:54:32 +07:00
Daphne Maddox
45bab9fe71 update package.json dependencies
Update dependencies in package.json to (mostly) latest available
versions.

Updating these dependencies removes warnings when bower is installed
as a devDependency in other packages and keep the code fresh.

Methodology:

- `npm install`
- `npm test` (all tests pass)
- `npm-check-updates -u`
- `npm test` (find errors, suspect semver, back off to `~2.3.0` in
package.json)
- `rm -rf node_modules` (and .gitignored files)
- `npm install`
- `npm test` (all pass, deem updated version compatible)
- revert to package.json from `master`
- `npm install` (install the old dependencies)
- switch back to updated package.json
- `npm install` (upgrade dependencies in place)
- `npm test` (all tests still pass, deem upgrades safe)

As to the `semver` dependency, it seems that updating to 4.x requires
handling breaking changes, which is TODO.

Closes #1622
2015-01-03 11:24:21 -08:00
Sindre Sorhus
514eb8f0e3 better homedir detection 2014-12-22 22:56:27 +07:00
Ricardo Polo
a7baa58c22 Close #1620 PR: Showing --no-color in help. Fixes #78 2014-12-10 21:09:27 +07:00
Adam Stankiewicz
e548d8b1a5 Merge pull request #1618 from fracmak/bower_list_tests
Added unit tests of bower.commands.list()
2014-12-05 11:58:49 +01:00
Merrifield, Jay
92ff0fe624 Added unit tests of bower.commands.list() 2014-12-04 23:29:03 -05:00
joneshf
a464f5a88e Remove erroneous colon. 2014-11-29 12:22:58 -08:00
Veres Lajos
962a565d30 typo fixes 2014-11-02 22:40:58 +00:00
Tej Chajed
f242e60c1a Change duplicate package status code to 403
Registry no longer sends 406 so clients would previously just see
"Unknown error: 403 if they tried to register a duplicate package.
2014-11-01 09:08:58 -04:00
Sindre Sorhus
7db50391f2 Merge pull request #1576 from darabos/patch-1
Add extra newline at the end of help-cache.std
2014-10-27 23:07:41 +07:00
Daniel Darabos
8b0d55a729 Add extra newline at the end of help-cache.std
Without this newline, the template is rendered without a newline at the end. So when you run `grunt help cache`, the output does not have a newline at the end and the shell prompt will be printed at the end of the last line.
2014-10-27 14:00:13 +01:00
Sindre Sorhus
de6f341f41 bump to latest chalk 2014-10-16 11:52:46 +02:00
Adam Stankiewicz
c9fb530dbf Merge pull request #1557 from ISNIT0/master
Added return character
2014-10-06 14:38:33 +02:00
ISNIT0
836bcd09ec Added return character
https://github.com/bower/bower/issues/1554
2014-10-06 12:58:04 +01:00
Sindre Sorhus
52a6836872 Merge pull request #1548 from bower/fix/readable
[fix] Ensure extracted files are readable, update tar-fs
2014-09-28 23:40:29 +02:00
Adam Stankiewicz
c00cadb37a [fix] Ensure extracted files are readable, update tar-fs 2014-09-28 18:21:24 +02:00
Adam Stankiewicz
b26c072f0d Bump version to 1.3.12 and update changelog 2014-09-28 17:37:40 +02:00
Adam Stankiewicz
c99482f59d [doc] Explain why env in test/helpers.js is needed 2014-09-28 15:58:59 +02:00
Adam Stankiewicz
4aa0f567c3 Merge pull request #1529 from bower/analytics_fix
fix broken analytics tracking introduced in #1507 & changed default
2014-09-27 09:57:29 +02:00
Ray Shan
4656021902 fix broken analytics tracking introduced in #1507 2014-09-26 22:33:43 +02:00
Adam Stankiewicz
3df6144b77 Downgrade mout to 0.9.0, closes #1525 2014-09-23 20:12:19 +02:00
Ray Shan
6d335abe21 Merge pull request #21 from bower/fix/appdata
Use local appdata for cache, fixes bower/bower#1536
2014-09-23 09:58:17 -07:00
Adam Stankiewicz
179b8a28b4 Use local appdata for cache, fixes bower/bower#1536 2014-09-23 16:43:22 +02:00
Adam Stankiewicz
c620004168 Update tar-fs version, fixes #1537 2014-09-23 16:26:26 +02:00
Sindre Sorhus
893ff3e9d7 Merge pull request #1535 from zhiyelee/linebreak
add linebreak
2014-09-22 11:59:24 +02:00
zhiyelee
eec9a3cb8f add linebreak 2014-09-22 11:23:31 +08:00
Sindre Sorhus
d3c8042102 Merge pull request #1532 from BiAiB/fix-zero-major-dependencies
Fix 0.x dependencies to prevent breaking API updates
2014-09-19 14:14:05 +02:00
Rodolphe Gohard
e590b44c77 Fix 0.x dependencies to prevent breaking API updates
Semver states
> Major version zero (0.y.z) is for initial development.
> Anything may change at any time. The public API should
> not be considered stable.
We already had a case where a tmp package update (0.0.24)
broke bower install. This can happen again with  0.x
dependencies that can introduce breaking API changes
anytime.
2014-09-19 12:04:41 +02:00
Adam Stankiewicz
e97bf479fb Merge pull request #1527 from LaurentGoderre/v1.3.11
Bump and update changelog
2014-09-18 02:26:50 +02:00
Laurent Goderre
fe2f71c9b8 Bump and update changelog 2014-09-17 11:12:17 -04:00
Adam Stankiewicz
ee6c483dd4 Merge pull request #1519 from LaurentGoderre/fix-1518
Fix update command not installing missing packages
2014-09-16 22:39:49 +02:00
Laurent Goderre
e83ab86f1f Added update test cases 2014-09-16 16:23:38 -04:00
Laurent Goderre
ef237fc521 Added the missing install command to the update task
Fixes #1518
2014-09-16 16:23:25 -04:00
Adam Stankiewicz
fd4d68038b Bump and update changelog 2014-09-13 16:39:35 +02:00
Adam Stankiewicz
8e458c21e9 [test] Make sure install ends before running next test 2014-09-13 16:12:06 +02:00
Adam Stankiewicz
4ab36cb3bc [test] Use new temp location per process 2014-09-13 16:04:02 +02:00
Adam Stankiewicz
2d149f3a09 Merge pull request #1507 from bower/fix/skip-prompt
Fix/skip prompt
2014-09-13 01:25:20 +02:00
Adam Stankiewicz
dfd2c7a3d2 Add tests to analytics and fix them 2014-09-12 21:28:44 +02:00
John Schulz
6637762aec "analytics" value in \.bowerrc\ removes need to prompt user 2014-09-12 00:26:41 +02:00
Laurent Goderre
615eba3b40 Update p-throttle to allow displaying the output of hooks
Fixes #1484
2014-09-12 00:04:19 +02:00
Adam Stankiewicz
dc183125fc [test] Show coverage status for master branch 2014-09-08 03:12:36 +02:00
Adam Stankiewicz
c3b69d1201 [test] Provide git credentials for tests on CI 2014-09-08 03:10:02 +02:00
Adam Stankiewicz
3e1a50ab9a [test] Add tests for git repository install 2014-09-08 03:02:57 +02:00
Adam Stankiewicz
7565c71eb2 Warn about unnecessary resolution, #1061 2014-09-08 01:13:55 +02:00
Adam Stankiewicz
d743352bc0 Disable removing unnecessary resolutions, #1061 2014-09-08 01:02:31 +02:00
Sindre Sorhus
75ca72e3a8 Merge pull request #1508 from bower/fix/head-pipe
Prevent error when piping bower output to head, fixes #1396
2014-09-08 00:56:48 +02:00
Adam Stankiewicz
59d26c6825 Prevent error when piping bower output to head, fixes #1396 2014-09-07 23:46:20 +02:00
Adam Stankiewicz
5eed363e10 Merge pull request #1393 from Lukeas14/disable-shallow-clone-except-github
Disable shallow clones for all repos except those from github.com
2014-09-07 23:29:24 +02:00
Sindre Sorhus
49b2fdbde9 Merge pull request #1504 from bower/fix/hook-order
Run posthook after saving bower.json, fixes #1471
2014-09-07 20:06:28 +02:00
Burak Yigit Kaya
623f6e9542 Use tar-fs instead of tar for faster TAR extraction 2014-09-07 19:29:37 +02:00
Adam Stankiewicz
32356f23d3 Run posthook after saving bower.json, fixes #1471 2014-09-07 19:14:30 +02:00
Sindre Sorhus
321ddabfd5 Merge pull request #1502 from bower/fix/bowerrc-cwd
Read .bowerrc from specified cwd, fixes #1301
2014-09-06 18:15:55 +02:00
Sindre Sorhus
bf93a6a1ab make bower list --paths a bit prettier 2014-09-06 17:58:47 +02:00
Sindre Sorhus
91aa5dc6dd bump dependencies 2014-09-06 17:20:32 +02:00
Sindre Sorhus
56ed46b99a Merge pull request #1503 from bower/fix/windows-local-caching
Disable caching for windows absolute path, fixes #1416
2014-09-06 17:08:47 +02:00
Adam Stankiewicz
daaf21a4fe Merge pull request #1495 from mitogh/link-issues
Update the references to the issues and pulls in the CHANGELOG.md file
2014-09-06 14:40:55 +02:00
Adam Stankiewicz
06a8f2afab Read .bowerrc from specified cwd, fixes #1301 2014-09-06 02:38:40 +02:00
Adam Stankiewicz
cc04530c4a Merge pull request #1495 from mitogh/link-issues
Update the references to the issues and pulls in the CHANGELOG.md file
2014-09-04 23:14:21 +02:00
Crisoforo Gaspar Hernandez
0b6f62977a Update the references to the issues and pulls in the CHANGELOG.md file 2014-09-04 14:18:00 -05:00
Ben Schwarz
2a2996c22b Merge pull request #1483 from benschwarz/concurrency-reduction
Back concurrency down to 5 (from 50!)
2014-08-28 22:02:07 +10:00
Ben Schwarz
254aba0995 Back concurrency down to 5 (from 50!) 2014-08-28 20:28:22 +10:00
Ben Schwarz
23a81b3121 Merge pull request #1478 from fsmanuel/expose-version
expose bower version
2014-08-20 08:01:56 -07:00
Manuel Wiedenmann
c4659f816f expose bower version 2014-08-20 14:26:42 +02:00
Tom MacWright
fc13328e2a Adds an error message to errors. Fixes #16
This could be better if it could distinguish between server errors
and actually unknown errors (known unknowns), but that would require
the server to provide JSON errors.
2014-08-19 12:30:04 -04:00
Ben Schwarz
d1427e7d2e Merge pull request #1473 from bower/docs_update
Further simplify readme.md
2014-08-16 09:47:17 +10:00
Ray Shan
5584d1062e Further simplify readme.md 2014-08-15 16:26:23 -07:00
Ray Shan
b3f28fac64 Update README.md 2014-08-12 11:08:42 -07:00
Ray Shan
f65af7a308 Update README.md 2014-08-12 11:06:53 -07:00
Ray Shan
559f50a3e3 Merge pull request #3 from ncthis/patch-1
Fixing minor syntax errors
2014-08-12 11:05:27 -07:00
Sindre Sorhus
18b809314c Update README.md 2014-08-12 11:06:11 +02:00
Sindre Sorhus
aa1f819c0d Merge pull request #20 from rayshan/patch-1
Update README.md w/ npm instructions
2014-08-12 11:04:43 +02:00
Ray Shan
5a8cecf499 Update README.md 2014-08-11 17:56:54 -07:00
Adam Stankiewicz
79f362abee Merge pull request #21 from bower/docs_npm
Update README.md
2014-08-12 00:08:17 +02:00
Ray Shan
42db74b522 Update README.md 2014-08-11 15:03:34 -07:00
Sindre Sorhus
8cb41fe5fb Merge pull request #1464 from thorn0/patch-1
Mention updates in the main help
2014-08-11 18:35:42 +02:00
thorn0
cd893fec15 Mention updates in the main help
See #955. The same was done for `bower list -h`, but not for `bower help` AKA just `bower`.
2014-08-11 17:07:07 +03:00
Adam Stankiewicz
3309e9f53f Merge pull request #19 from stephanebachelier/patch-1
fix typo in README
2014-08-08 17:02:10 +02:00
Stéphane Bachelier
ae3a017143 fix typo in README 2014-08-08 16:59:47 +02:00
Sindre Sorhus
2a01f178da Update changelog 2014-08-06 21:41:46 +02:00
Sindre Sorhus
a069d1e07d 1.3.9 2014-08-06 21:39:31 +02:00
Sindre Sorhus
76fa7f5200 Merge pull request #1434 from pornel/master
Fix "TypeError: Arguments to path.join must be strings" in GitHubResolver
2014-08-06 21:35:41 +02:00
Kornel Lesiński
7a0a86d51c When tmp.js returns cleanup callback along with the tmp dir path, nfcall changes return type to an array 2014-08-06 14:28:04 +01:00
Sindre Sorhus
8e283e43db Merge pull request #1442 from luckysw/master
Added .zip MIME type (e.g. the default served by Windows/IIS)
2014-07-30 08:38:23 -07:00
MadLux
794744d5a3 Added .zip MIME type (e.g. the default served by Windows/IIS) 2014-07-30 11:41:21 +02:00
Sindre Sorhus
5c3e69b045 Merge pull request #1436 from rayshan/bump_insight
analytics - bump insight, supports OS/node/CLI version tracking
2014-07-28 04:16:02 -07:00
Ray Shan
9cbd595cfd analytics - bump insight to 0.4.1, supports OS/node/CLI tool version tracking 2014-07-27 21:42:15 -07:00
Adam Stankiewicz
a5074eca7d [doc] Encourage to always use --save option 2014-07-15 14:11:29 +02:00
Sindre Sorhus
9386b117c1 Merge pull request #1415 from bower/simple-readme
Remove content that can be now be found on bower.io
2014-07-15 01:58:10 +02:00
Sindre Sorhus
7738248230 lock down 0.0.x versions
as `~` causes unexpected and non-semver behaviour on them.

https://github.com/isaacs/node-semver
2014-07-15 01:50:32 +02:00
David DeSandro
85f1f808d3 Remove content that can be now be found on bower.io
+ bower.json
+ custom install directory
+ bower search
+ using bower cache
+ .bowerrc
+ continuous integration server
+ interactive configuration
+ Defining a package
+ maintaining deps
+ consuming a package
+ programmatic api
+ assistance & contribution list

Ref #1371
2014-07-14 17:45:24 -04:00
Ben Schwarz
6dbafa22bb Merge pull request #1412 from chibicode/master
Fix typo on help-uninstall.json
2014-07-13 19:17:16 +10:00
Shu Uesugi
cadcd37681 Fix typo on help-uninstall.json 2014-07-13 16:36:41 +09:00
Paul Irish
a45ea6e1d8 Update changelog 2014-07-11 17:02:35 -07:00
Paul Irish
187f24de81 Bump to 1.3.8 2014-07-11 17:02:35 -07:00
Paul Irish
8df1f48226 Merge pull request #1407 from vladikoff/tmp-dep-fix
Fixes node-tmp update issue
2014-07-11 13:44:04 -07:00
vladikoff
7dbf332a94 Fixes node-tmp update issue 2014-07-11 13:40:58 -07:00
Sindre Sorhus
c09ddf6de1 Merge pull request #1395 from steveyken/master
Fixed typo
2014-07-09 23:48:49 +02:00
Sindre Sorhus
9b5fa99d6a bump update-notifier and simplify 2014-07-09 16:15:47 +02:00
Steve Kenworthy
b9abf32007 Fixed typo 2014-07-09 10:50:43 +08:00
Lucas, Justin
09ecb80625 Disable shallow clones for all repos except github.com 2014-07-08 11:39:14 -07:00
Sindre Sorhus
c4e9a0e340 bump deps 2014-07-05 00:26:46 +02:00
Adam Stankiewicz
b6cf4e1826 Update changelog 2014-07-04 13:02:12 +01:00
Adam Stankiewicz
ecb1619399 Bump to 1.3.7 2014-07-04 12:58:03 +01:00
Vladimir Alaev
83f4b7b699 Fix callstack error when processing installed packages with circular dependencies 2014-07-04 12:53:50 +01:00
insanehong
9b81ddf4d5 It should shows an error when bower install failed, fixes #922
- reason no bower.json in current directory
2014-07-03 15:10:38 +01:00
insanehong
4af17f0e40 Fixed bower list --paths` fails with TypeError, fixes #1383 2014-07-03 15:00:53 +01:00
Adam Stankiewicz
2fbc036e69 Update the changelog 2014-07-02 14:04:01 +01:00
Adam Stankiewicz
d236a12b8f Bump version to 1.3.6 2014-07-02 12:28:48 +01:00
Adam Stankiewicz
232be333ad Add tests for removeIgnores utility 2014-07-02 11:37:56 +01:00
Tim Monks
192e5af797 Add integration tests for bower commands 2014-07-02 11:16:12 +01:00
Tim Monks
deb39b8f34 Publish to coveralls.io from travis 2014-07-02 11:16:10 +01:00
Adam Stankiewicz
197b41d97a Merge pull request #1366 from sheerun/fix/local
[#1356] Disable caching for local resources
2014-07-02 10:31:30 +01:00
Adam Stankiewicz
7b11a57c6f Merge pull request #1365 from sheerun/fix/force
[#931] Make --force always re-run installation
2014-07-02 10:26:50 +01:00
Adam Stankiewicz
eac7945fae Merge pull request #1372 from incompl/master
Add --version to --help
2014-06-27 23:03:35 +01:00
Greg
1177d2263f Add --version to --help 2014-06-27 11:08:09 -04:00
Ben Schwarz
b9478a1f65 Merge pull request #1367 from abutcher/bower-install-save-readme
Add bower install --save/--save-dev blurb to README.md. Closes #1321
2014-06-25 08:03:45 +10:00
Andrew Butcher
025cf91679 README.md --save rewording suggested by @benschwarz for #1321 2014-06-24 09:33:45 -04:00
Adam Stankiewicz
442aa72ccc [fixes 5c839724] Prevent command like "bower info" from crashing on render 2014-06-24 11:39:44 +02:00
Adam Stankiewicz
1c09f9c82d Bump bower-config and endpoint-parser versions 2014-06-24 11:16:07 +02:00
Andrew Butcher
c6d2f633ea Add bower install --save/--save-dev blurb to README.md. Closes #1321 2014-06-24 00:37:57 -04:00
Adam Stankiewicz
17bd60e3e9 [#1356] Disable caching for local resources 2014-06-22 22:05:13 +02:00
Adam Stankiewicz
1d24e82276 [#931] Make --force always re-run installation 2014-06-21 00:33:51 +02:00
Adam Stankiewicz
43d7a11ba8 Bump version to 0.2.2 2014-06-20 23:01:20 +02:00
Adam Stankiewicz
02e12e17d6 Prepend # to ambiguous branch name, fixes bower/bower#1308 2014-06-20 23:00:14 +02:00
Adam Stankiewicz
e42d3d5620 [#1329] Check if pkgMeta is undefined 2014-06-20 21:57:41 +02:00
Thomas Scholtes
5c83972401 Use promise interface for commands
This commit changes the interface of the command functions exported by the
files in `lib/commands`. The functions now return a promise and accept a logger
as the first argument. This has several advantages

* The promise style is consistent with the rest of the code.
* It removes a lot of duplicate code.
* The command factory does not need to proxy the logger object.
2014-06-20 21:14:26 +02:00
Martin Hansen
b8df18481f Ignore does now not apply to any file in main #547 2014-06-20 19:48:00 +02:00
Andrew Eisenberg
1690dd4728 Warn users when installing package with missing properties.
Fix for issue #694. Test case included.
2014-06-20 19:00:19 +02:00
Sindre Sorhus
a86087ed7c Update README.md 2014-06-13 23:32:05 +02:00
Ray Shan
745060f0b5 Close GH-1348: Updated Analytics section of readme.md with link to stats.bower.io. 2014-06-13 23:30:12 +02:00
Sindre Sorhus
0a0a490a38 bump deps 2014-06-10 22:18:26 +02:00
Adam Stankiewicz
4f838685d6 Bump to 0.5.2 2014-06-09 03:28:08 +02:00
Adam Stankiewicz
6339ba09f0 "Merge pull request #18 from mdasberg/master\n\nFix for Overriding .bowerrc with a relative tmp path that breaks downloading of bower modules with ignores" 2014-06-09 03:26:33 +02:00
Adam Stankiewicz
f816a5b0da Bump tmp version to 0.0.23, #988 2014-06-09 03:09:22 +02:00
Adam Stankiewicz
2f02e49716 Always ignore bower.json as said in spec 2014-06-08 18:46:39 +02:00
Mat Scales
a98a0b1ac2 Release 1.3.5 2014-06-06 11:31:37 +01:00
Adam Stankiewicz
034326c984 Add some tests and documentation for #1310 2014-06-05 23:52:48 +02:00
Sergey Tatarintsev
a965b05400 Search compatible versions in fetching packages
Previous version of code reported endpoints that does not have pckMeta
(not downloaded) yet and does not have exactly equal targets as
incompatible. This caused some package to be downloaded multiple times
and caused conflict errors (#1147).

This patch adds proper code for searching compatible version in
currently fetching packages basing on targets.

It also simplifies check for case when we have resolvedVersion and
candidate's target is range.
2014-06-05 19:41:37 +02:00
Sindre Sorhus
23c2e82c97 Merge pull request #18 from shinnn/master
Update dependencies and .jshintrc
2014-06-03 11:22:57 +02:00
Mat Scales
6c2de4a359 1.3.4 2014-06-02 15:22:18 +01:00
Mat Scales
e9588279c8 Updated changelog for v1.3.4 2014-06-02 15:21:04 +01:00
Shinnosuke Watanabe
7138d3518e Fix CI setting to pass the test against Node v0.8 2014-06-02 17:22:49 +09:00
Shinnosuke Watanabe
f852325906 Update graceful-fs and mocha 2014-06-02 14:43:08 +09:00
Shinnosuke Watanabe
3c9082ece3 Update .jshintrc for JSHint v2.5.x 2014-06-02 14:42:43 +09:00
Mat Scales
efe3a78499 Merge pull request #1278 from jfsiii/patch-1
Mirror `npm version` format for git tags
2014-05-27 19:37:53 +01:00
Adam Stankiewicz
98c77ffe18 Bump to 0.2.1 2014-05-21 14:20:25 +02:00
Adam Stankiewicz
31969a4939 Merge pull request #1306 from wibblymat/dependency-loop
Resolve a situation in which the install process gets into an infinite loop
2014-05-21 13:50:03 +02:00
Mischa Dasberg
b95d5f9f23 moved tmp resolve from load to normalize method 2014-05-21 11:02:19 +02:00
Nadeesha Cabral
adf59d78d7 Fixing minor syntax errors 2014-05-21 12:22:13 +05:30
Adam Stankiewicz
904ae3eab7 Merge pull request #9 from geigerzaehler/update-config-version
Use the same version of bower-config as bower
2014-05-21 02:17:33 +02:00
Adam Stankiewicz
44d2309700 Bump version 2014-05-21 00:17:40 +02:00
Adam Stankiewicz
5dd6a3883a Add info about unimplemented features, closes #11 2014-05-20 23:47:47 +02:00
Adam Stankiewicz
7a00c5ac71 Merge pull request #1307 from thomasmulvaney/patch-1
Fixed typo in README.md
2014-05-20 16:33:19 +02:00
Mat Scales
23fbbb5191 Resolve a situation in which the install process gets into an infinite loop 2014-05-20 14:46:41 +01:00
thomasmulvaney
a58b1ccfa5 Update README.md
Fixed sentence which had 'set manually' accidentally repeated.
2014-05-20 15:26:40 +02:00
Mischa Dasberg
5f0a3fe1c1 See: https://github.com/bower/bower/issues/1299 and https://github.com/bower/config/issues/17 2014-05-13 14:25:45 +02:00
Ben Schwarz
37b0a5c04c Merge pull request #1291 from danfinnie/patch-1
Fix Markdown typo in CONTRIBUTING.md
2014-05-12 13:12:38 +10:00
Daniel Finnie
3fb4f60192 Fix Markdown typo in CONTRIBUTING.md 2014-05-11 23:06:46 -04:00
Ben Schwarz
635fa84731 Merge pull request #1284 from niksy/improve-cli-color-output
Improve CLI output for conflicts
2014-05-08 08:14:13 +10:00
Ivan Nikolić
410bf4f0cd Improve CLI output for conflicts
Replace white color with green.
2014-05-07 19:27:44 +02:00
John Schulz
eebe115b78 Mirror npm version format for git tags
See https://github.com/bower/bower/pull/961#issuecomment-33981712 and  https://github.com/bower/bower/pull/961#issuecomment-35591108 for more context.
2014-05-04 15:11:47 -07:00
Sindre Sorhus
70eb9f0678 Merge pull request #1277 from benschwarz/analytics-statement-and-disable
Description of Analytics usage & how to disable
2014-05-04 06:03:26 +02:00
Ben Schwarz
b9de179fe8 Add notes about what analytics are used for, who has access and how to disable 2014-05-04 13:17:10 +10:00
Adam Stankiewicz
ac29e24c1b Allow for short commit SHA, closes #990 2014-04-25 02:09:10 +02:00
Adam Stankiewicz
d83572803d Bump, update changelog, update contributors 2014-04-24 22:35:22 +02:00
Adam Stankiewicz
87faa4f108 Do not cache moving targets like branches, fixes #1242 2014-04-24 20:31:36 +02:00
Sindre Sorhus
ea3a0d64c1 make jshint :) 2014-04-22 16:01:24 +02:00
Sindre Sorhus
8288d2f38b readme improvements 2014-04-22 15:28:29 +02:00
Sindre Sorhus
ff817dad0d various tweaks 2014-04-22 15:16:58 +02:00
Sindre Sorhus
ba554d5f45 use opn instead of open
`open` is buggy on Linux

https://github.com/sindresorhus/opn
2014-04-22 15:07:33 +02:00
Sindre Sorhus
90922a0ce0 bump deps 2014-04-22 15:04:42 +02:00
Sindre Sorhus
a91cb546f9 let npm sort dependencies 2014-04-22 14:57:38 +02:00
Adam Stankiewicz
3cb21d128f Forward all events from wrapped command, fixes #1232 2014-04-18 14:41:27 +02:00
Paul Irish
1b8d5d0648 Merge pull request #1234 from ahmadnassri/svn-export
using 'svn export' for efficiency. Closes #1224
2014-04-14 12:47:02 -07:00
Adam Stankiewicz
03f035cdf0 Merge pull request #1239 from bower/docs/usage
Discourage using bower components statically, closes #1210
2014-04-13 01:55:07 +02:00
Adam Stankiewicz
ac95654409 Discourage using bower components statically, closes #1210 2014-04-13 01:53:12 +02:00
Adam Stankiewicz
ba33bb6aa4 Cache clean and cache list work again, fixes #1232 2014-04-13 01:45:56 +02:00
Sindre Sorhus
2898c0507e Merge pull request #1237 from bower/fix/bower-list
Fix considering extended directory using .bowerrc
2014-04-12 23:41:32 +02:00
Sindre Sorhus
d59edd6cca Merge pull request #1238 from bower/feature/performance
Improve noninteractive loading performance 2x, fixes #1221
2014-04-12 23:33:49 +02:00
Sindre Sorhus
bc3079332c Merge pull request #7 from sheerun/patch-1
perf: Use the same mout version as bower
2014-04-12 23:22:47 +02:00
Sindre Sorhus
3c0395b19f Merge pull request #16 from sheerun/fix/mout
perf: Use only relevant parts of mout
2014-04-12 23:21:41 +02:00
Sindre Sorhus
9e7b591c78 Merge pull request #8 from sheerun/fix/mout
Use only relevant parts of mout
2014-04-12 23:21:18 +02:00
Adam Stankiewicz
b6107a1198 Use only relevant parts of mout 2014-04-12 22:23:12 +02:00
Adam Stankiewicz
2d94018f12 perf: Use only relevant parts of mout 2014-04-12 22:17:56 +02:00
Adam Stankiewicz
42f0268829 perf: Use the same mout version as bower 2014-04-12 22:10:37 +02:00
Adam Stankiewicz
74d568b1e7 Improve noninteractive loading performance 2x, fixes #1221 2014-04-12 21:11:17 +02:00
toshipon
0316fedd4c Fix considering extended directory using .bowerrc 2014-04-12 14:40:45 +02:00
Ahmad Nassri
e8c071304c using 'svn export' for efficiency. Closes #1224 2014-04-11 09:00:41 -04:00
shinnn
4812c380c4 Add a validation for description length
closes #17
2014-04-05 13:06:09 +02:00
Sven Lito
0e833c155a Merge pull request #10 from wibblymat/unregister
Add 'unregister' feature
2014-04-01 17:32:33 +02:00
Mat Scales
9ebb1b17d1 Added tests and fixed code-style 2014-04-01 15:57:08 +01:00
Mat Scales
3397cf053c Removed a debug line 2014-04-01 15:29:35 +01:00
Mat Scales
6e73b5934e Add 'unregister' feature 2014-04-01 13:26:35 +01:00
Thomas Scholtes
a5c49d89d5 Use tilde to match bower-config version 2014-02-27 00:26:34 +01:00
Thomas Scholtes
1f9a92e6ad Use the same version of bower-config as bower
Make loading this package from bower faster. Used `>=` to specify version so it
doesn't break that fast when bower starts using a version `>=0.6.0`.
2014-02-26 15:38:10 +01:00
Sindre Sorhus
6280611aea Merge pull request #13 from geigerzaehler/master
Use same mout version as bower
2014-02-25 21:51:08 +01:00
Thomas Scholtes
20c0e6e12b Use same mout version as bower
We don't need to load mout twice, which takes a lot of time.
2014-02-25 19:53:50 +01:00
reiz
d3ccc73796 Adding validation for package name
Closes #15
2014-01-31 14:54:40 +01:00
Sven Lito
53d3ac570e Merge pull request #7 from clientlab/master
fix a bug
2013-12-26 07:32:13 -08:00
周培公
237022baae add a test.
add a test 'calling the lookup instance method with two registries, and
the first missing', and adjust the test sequence.
2013-12-26 08:08:29 +08:00
周培公
bccfd7bbbb fix a bug. 2013-12-24 15:03:03 +08:00
Sven Lito
597853cd6c bump version 2013-12-11 10:43:50 +00:00
Sven Lito
1bd6568f94 Merge pull request #6 from xiaojue/master
add headers for request to fix userAgent not work.
2013-12-11 02:39:42 -08:00
xiaojue
4b2235aef2 add userAgent test 2013-12-11 18:32:13 +08:00
xiaojue
faf1c26669 add headers for request to fix userAgent not work. 2013-12-11 15:17:08 +08:00
Mat Scales
c385c08e2f Close GH-2: Add checkbox prompt. 2013-12-06 22:11:00 +00:00
André Cruz
ab7e7ac12a Bump version. 2013-09-28 15:11:01 +01:00
Sven Lito
3788e8d7b3 Merge pull request #5 from bower/md5
Append a truncated hash to prevent case issues in case insensitive fs.
2013-09-28 02:15:53 -07:00
André Cruz
041290e1c7 Append a truncated hash to prevent case issues in case insensitive fs. 2013-09-28 00:54:33 +01:00
André Cruz
1099e786df Bump version. 2013-08-29 19:51:13 +01:00
André Cruz
be95169c1b Add DEFAULT_REGISTRY, #6. 2013-08-29 19:50:46 +01:00
André Cruz
a899cb48b3 Bump version. 2013-08-28 08:21:13 +01:00
André Cruz
ed8ac01f07 Do not crash if home is not set. 2013-08-28 08:20:55 +01:00
André Cruz
12cde3ddce Doc typo. 2013-08-21 18:48:21 +01:00
André Cruz
860d70551f Bump version. 2013-08-21 18:46:05 +01:00
André Cruz
6db6fcc414 Small tweaks to last PR. 2013-08-21 18:45:46 +01:00
André Cruz
25c229de73 Merge pull request #9 from alexwhitman/nested-env-vars
Allow nested environment variables using '__'
2013-08-21 10:26:31 -07:00
Alex Whitman
d954a54017 Handle nesting in environment variables
Nested configuration variables can now be specified by environment
variable. Levels are split by '__' (double underscore). Single
underscores are converted to '-'.

`bower_foo__bar-baz` -> `foo.bar-baz`
2013-08-21 11:41:46 +01:00
André Cruz
78bbf1f04f Bump version. 2013-08-20 21:48:55 +01:00
André Cruz
52938202bd Fix target not being added if source does not look like a source. 2013-08-20 21:48:26 +01:00
André Cruz
0f29818030 Bump version. 2013-08-20 01:03:01 +01:00
André Cruz
dd39a25dd0 Update deps. 2013-08-20 01:02:39 +01:00
André Cruz
6ed4be9135 Merge branch 'master' of github.com:bower/logger 2013-08-20 00:42:32 +01:00
André Cruz
02b6a21276 Bump version. 2013-08-20 00:42:17 +01:00
André Cruz
794ca573b8 Trim answers automatically. 2013-08-20 00:41:15 +01:00
André Cruz
032f771996 Simplify. 2013-08-19 09:01:45 +01:00
Andre Cruz
3dfd7a9ab1 Bump version. 2013-08-19 00:57:39 +01:00
Andre Cruz
1713e5e2eb Minor improvement in argv.config parsing. 2013-08-19 00:57:30 +01:00
Andre Cruz
1d7342573b Bump version. 2013-08-19 00:43:41 +01:00
Andre Cruz
64fc295ecc Add prompt(). 2013-08-19 00:43:17 +01:00
Andre Cruz
6b6dc8311a Bump version. 2013-08-18 17:29:00 +01:00
Andre Cruz
b1d8c3c1e3 Interactive is now set to auto (null). 2013-08-18 17:28:35 +01:00
Andre Cruz
71037cb482 Bump version. 2013-08-18 13:08:43 +01:00
Andre Cruz
1f4e5cadd2 Generate a fake user instead of using 'unknown'. 2013-08-18 13:08:15 +01:00
André Cruz
0de9cc82f6 Bump version. 2013-08-16 09:43:39 +01:00
André Cruz
7dba46df9b Temp folder is now suffixed with the user and "bower". 2013-08-16 09:30:40 +01:00
André Cruz
9cb09feb65 Bump version. 2013-08-14 09:10:24 +01:00
André Cruz
fb084fa4cd Cast buffer to string. 2013-08-14 09:10:08 +01:00
André Cruz
846b8fb57e Bump version 2013-08-14 08:36:54 +01:00
Salehen Shovon Rahman
cb649830a0 Close GH-7: Empty .bowerrc files should not throw an error.. 2013-08-14 08:35:00 +01:00
André Cruz
89510f40d3 Bump version. 2013-08-11 18:24:25 +01:00
André Cruz
9f2207eb1f Change git folder to empty (was not being used anyway). 2013-08-11 18:24:13 +01:00
André Cruz
dfb18b305d Bump version. 2013-08-11 14:46:33 +01:00
André Cruz
1606395546 Close GH-12: Ignore component(1) files.. 2013-08-11 14:45:55 +01:00
André Cruz
8dbd79d49b Bump version. 2013-08-07 08:29:40 +01:00
André Cruz
e2c67fa25a Use a known user agent by default when a proxy. 2013-08-07 08:28:50 +01:00
André Cruz
cf85177c7f DRY. 2013-08-06 09:12:13 +01:00
André Cruz
bc4a0f448b Bump version. 2013-08-06 00:02:54 +01:00
André Cruz
14ef86456f Typo. 2013-08-06 00:02:31 +01:00
André Cruz
12efc85baf Bump version. 2013-08-05 23:40:52 +01:00
André Cruz
68124dfdbe Bum version. 2013-08-05 23:39:15 +01:00
André Cruz
ee4158e90b Append the username when using the temporary folder. 2013-08-05 23:38:19 +01:00
André Cruz
0b3b7efccf Minor improvement. 2013-08-05 23:36:11 +01:00
André Cruz
6064269936 Bump version. 2013-08-05 14:22:51 +01:00
André Cruz
d0929896cf Update README. 2013-08-05 14:22:41 +01:00
André Cruz
990e87de1f Tweaks to the last PR. 2013-08-05 14:16:53 +01:00
Nick Heiner
8da47dcd00 Close GH-10: Find .bower.json if it exists. 2013-08-05 14:10:57 +01:00
André Cruz
c63d88d987 Bump version. 2013-08-03 12:44:18 +01:00
André Cruz
c21bde192b Fix failing test. 2013-08-03 12:44:07 +01:00
André Cruz
39f1f8aff5 Improve retry error messages.
Also fixed "undefined" being printed as the url.
2013-08-03 12:38:21 +01:00
André Cruz
8b699c58ae Bump rc version. 2013-08-02 21:12:54 +01:00
André Cruz
743a97c784 Merge branch 'master' of github.com:bower/config 2013-08-02 21:10:39 +01:00
André Cruz
ea7ae5698a Do not set undefined values in array. 2013-08-02 21:10:31 +01:00
André Cruz
3ed9b3ec39 Fix default values being mutated. 2013-08-02 21:10:10 +01:00
André Cruz
e8f3e3b88a Set timeout default value to 30sec. 2013-08-02 21:09:54 +01:00
André Cruz
82d16fbfde Change timeout to 30sec. 2013-08-02 08:25:35 +01:00
André Cruz
766dcd0dd5 Bump version. 2013-07-29 23:14:27 +01:00
André Cruz
87302d6d86 Merge pull request #3 from bower/trim
Add trim to everything.
2013-07-29 15:11:07 -07:00
André Cruz
05b94d1d15 Add more tests and fix stuff. 2013-07-28 18:54:04 +01:00
André Cruz
ed0c93aec3 Add trim to everything. 2013-07-28 18:21:24 +01:00
André Cruz
03b4467173 Update deps. 2013-07-28 03:20:46 +01:00
André Cruz
f027cc6a3e Bump version. 2013-07-28 03:03:56 +01:00
André Cruz
634ce6829a Use bower-config to normalise the config object. 2013-07-28 03:03:39 +01:00
André Cruz
64b5f9af78 Bump to 0.2.0 rc1. 2013-07-28 02:58:08 +01:00
André Cruz
9269fcb8a7 Add normalisation, fixes #5.
Refactor a lot of code.
2013-07-28 02:57:24 +01:00
André Cruz
f0d29cb755 Bump to 0.1.0. 2013-07-27 22:30:51 +01:00
André Cruz
897e0f1ba6 Bump to 0.1.0. 2013-07-27 22:28:56 +01:00
André Cruz
4cfa94d304 Bump to 0.2.0. 2013-07-27 22:26:17 +01:00
André Cruz
5e2abb8a33 Add .file property to errors throw in read(). 2013-07-27 22:21:21 +01:00
Sven Lito
0dc5052e36 Close GH-9: adds grunt. 2013-07-27 20:44:16 +01:00
Sven Lito
774ad1e2ff remove inline jshint rule
this setting is covered by local node:true setting
2013-07-27 20:43:33 +01:00
Sven Lito
52e91cc309 Merge pull request #8 from bower/better-api
Changes to the api.
2013-07-27 12:09:12 -07:00
André Cruz
d3e6274939 Remove unused var. 2013-07-27 11:25:38 +01:00
Sven Lito
ec904eb8a4 adds list tests [#4] 2013-07-26 16:02:42 +01:00
André Cruz
95a09c5463 Fix README typos as suggested. 2013-07-25 23:31:33 +01:00
André Cruz
125fb598d5 Adjust README to the api changes. 2013-07-25 22:19:09 +01:00
André Cruz
f8c13f939c Changes to the api.
- Read now accepts directories and finds the bower json to read inside
- Add normalise and validate methods
- Add options to the parse and read methods to enable/disable normalisation and validation.
2013-07-25 22:06:42 +01:00
André Cruz
c846b24ebb Bump rc. 2013-07-24 09:00:53 +01:00
Sven Lito
85324d9109 Merge pull request #3 from bower/lookup-bug
Fix lookup and list bug for multiple registries.
2013-07-24 00:10:36 -07:00
André Cruz
10b410d46f Fix multiple registries in the list method. 2013-07-23 23:20:56 +01:00
André Cruz
c87fe7c265 Fix lookup bug for multiple registries.
Improve and fix tests.
2013-07-23 22:56:17 +01:00
André Cruz
ce0984573b Fix tests. 2013-07-23 22:55:00 +01:00
André Cruz
b38c3a5035 Add missing dep. 2013-07-23 22:51:24 +01:00
André Cruz
15dca65bd1 Set timeout to 60sec. 2013-07-23 22:50:40 +01:00
André Cruz
e1aa43147d Minor tweaks. 2013-07-23 22:49:58 +01:00
André Cruz
057b18e4be Bump to 0.1.0 2013-07-23 21:01:51 +01:00
André Cruz
d4f2ced6a3 Add paths tests, simply with regexp. 2013-07-23 21:01:30 +01:00
André Cruz
0b6c92fcd2 Merge pull request #2 from redking/master
Endpoints with backslashes should be recognized as sources
2013-07-23 12:57:27 -07:00
Sven Lito
4491e71ee2 Merge pull request #2 from neoziro/fix-registry-search
Fix search in multiple registries
2013-07-23 09:07:23 -07:00
Greg Bergé
d09f78801c fix search in multiple registries 2013-07-23 18:00:21 +02:00
Cormac Flynn
f26ea32897 Endpoints with backslashes should be recognized as sources 2013-07-23 15:41:22 +02:00
André Cruz
86dbea7ddb Update reps. 2013-07-20 23:18:09 +01:00
André Cruz
4221ddbb35 Bump rc. 2013-07-20 22:06:34 +01:00
André Cruz
eeb0c22d90 Integrate logger. 2013-07-20 22:05:36 +01:00
André Cruz
eb801e66ae Remove replay from register. 2013-07-20 22:05:07 +01:00
André Cruz
4d0d4ca6ea README typos. 2013-07-20 20:22:30 +01:00
André Cruz
56cdae67c3 Document log levels 2013-07-20 20:21:00 +01:00
André Cruz
b50017cad4 Initial commit. 2013-07-20 20:18:39 +01:00
André Cruz
c85c38cde3 Bump rc version. 2013-07-20 19:49:41 +01:00
André Cruz
f606eda18d Add replay to requests. 2013-07-20 19:49:13 +01:00
André Cruz
08c9e2dde3 CS. 2013-07-20 19:48:42 +01:00
André Cruz
882bf7b020 Bump rc version. 2013-07-18 19:31:52 +01:00
André Cruz
da4e70bc60 Merge branch 'master' of github.com:bower/endpoint-parser 2013-07-18 19:31:02 +01:00
André Cruz
f75f720c8a Merge branch 'master' of github.com:bower/registry-client 2013-07-18 19:30:44 +01:00
André Cruz
8d3aff5ff1 Update editorconfig. 2013-07-18 19:30:27 +01:00
André Cruz
4e8c9078f7 Update editorconfig. 2013-07-18 19:30:13 +01:00
André Cruz
41e4efcf1f Merge branch 'master' of github.com:bower/config 2013-07-18 19:29:38 +01:00
André Cruz
f55e6138a5 Remove git config. 2013-07-18 19:29:30 +01:00
André Cruz
147e24d835 Update editorconfig. 2013-07-18 19:29:22 +01:00
André Cruz
4a94858ed1 Update editorconfig. 2013-07-18 19:29:11 +01:00
André Cruz
12c90bae04 Another README typo. 2013-07-18 08:13:10 +01:00
André Cruz
6f7f10b2f7 Update README.md 2013-07-16 20:03:16 +01:00
André Cruz
430a2ea2f6 Bump rc. 2013-07-16 19:52:46 +01:00
André Cruz
87569617ae Add spec link. 2013-07-16 19:52:32 +01:00
André Cruz
b17beaccf1 Add timeout config. 2013-07-16 19:52:24 +01:00
Sven Lito
cddba64151 call next instead of done 2013-07-16 16:10:07 +01:00
André Cruz
a006bfeb24 Fix git@ endpoints not being interpreted as sources. 2013-07-16 07:09:20 +01:00
André Cruz
71e1a8666d Add tests and made some changes. 2013-07-15 22:29:23 +01:00
André Cruz
16e7872a82 Typo. 2013-07-15 00:42:47 +01:00
André Cruz
aa4ebb07f8 Fix title. 2013-07-15 00:36:56 +01:00
André Cruz
4366d6a8c7 Fix test script, wtf! 2013-07-15 00:35:59 +01:00
André Cruz
aa76d49234 Improve README. 2013-07-15 00:34:38 +01:00
André Cruz
d9df06644e Initial commit. 2013-07-15 00:30:44 +01:00
André Cruz
554ee01263 Force camelCase. 2013-07-15 00:30:27 +01:00
André Cruz
b3055067d8 Force camelCase. 2013-07-15 00:30:18 +01:00
André Cruz
7f997d4b59 Force camelCase. 2013-07-15 00:30:08 +01:00
André Cruz
d2d959f455 Upgrade deps. 2013-07-14 17:21:45 +01:00
André Cruz
a9e497f878 Upgrade deps. 2013-07-14 17:21:29 +01:00
André Cruz
e423e9ffba Upgrade deps. 2013-07-14 17:21:17 +01:00
André Cruz
ff99fae928 Bump rc version. 2013-07-13 23:07:19 +01:00
André Cruz
3c9983ca12 Merge branch 'master' of github.com:bower/registry-client 2013-07-13 22:35:48 +01:00
André Cruz
d3412e7de6 Stupid typos, I was drunk when I did that. 2013-07-13 22:35:23 +01:00
Sven Lito
2841942899 more cache related tests 2013-07-11 10:33:47 +01:00
André Cruz
415e79b523 Bump rc version. 2013-07-10 20:39:30 +01:00
André Cruz
9a6fdaa42b Do not remove invalid files, throw instead. 2013-07-10 20:39:02 +01:00
Sven Lito
0cdbe998cb [tests] adds cache test 2013-07-10 17:14:24 +01:00
Sven Lito
35b0c49da5 clarify cache docs 2013-07-10 15:46:52 +01:00
Sven Lito
d43c9f006b fix module references 2013-07-10 15:01:18 +01:00
Sven Lito
01a6ae61d2 replace chai with expect.js 2013-07-10 14:53:48 +01:00
André Cruz
4b4b233377 Bump rc version. 2013-07-09 23:38:15 +01:00
André Cruz
ccc9907034 Change from bower_new to bower. 2013-07-09 23:36:15 +01:00
André Cruz
26520abe2b Merge branch 'master' of github.com:bower/json 2013-07-09 21:02:08 +01:00
André Cruz
1397c3248d Bump rc version. 2013-07-09 21:01:53 +01:00
André Cruz
c40dc39b88 Merge branch 'master' of github.com:bower/registry-client 2013-07-09 21:01:33 +01:00
André Cruz
a2753bb27d Bump rc version. 2013-07-09 21:01:19 +01:00
André Cruz
1c5529691b Bump rc version. 2013-07-09 21:00:58 +01:00
André Cruz
8e5bdc6b2b BC change. 2013-07-09 21:00:39 +01:00
André Cruz
39324d6b55 Merge pull request #6 from btford/master
Fix typos.
2013-07-08 11:18:57 -07:00
Brian Ford
b1ad187d1b Fix typos. 2013-07-08 11:12:40 -07:00
Sven Lito
606f15fec5 [tests] basic offline check 2013-07-08 14:23:55 +01:00
André Cruz
09a0eb26d1 Improve sentence. 2013-07-07 03:00:18 +01:00
André Cruz
bf9e8048ff Sort deps. 2013-07-07 02:51:55 +01:00
André Cruz
21ebc226e4 Sort deps. 2013-07-07 02:51:04 +01:00
André Cruz
8e3fef9096 Sort deps. 2013-07-07 02:50:47 +01:00
André Cruz
829dccc1b6 Bump rc version. 2013-07-07 02:38:53 +01:00
André Cruz
a65caa62b3 Add name validation. 2013-07-07 02:38:43 +01:00
André Cruz
ddb6f9c5b4 Merge branch 'master' of github.com:bower/config 2013-07-07 02:26:18 +01:00
André Cruz
e152ab6cf2 Use our own rc implementation. 2013-07-07 02:26:06 +01:00
André Cruz
4085af023a Typo. 2013-07-07 02:25:13 +01:00
André Cruz
686e401368 Add del. 2013-07-07 02:24:54 +01:00
André Cruz
2fdfa64b13 Typo. 2013-07-06 22:42:16 +01:00
André Cruz
f406cfcebb Change from toJson to toObject. 2013-07-06 22:40:37 +01:00
André Cruz
80f35725e6 Require relatively. 2013-07-06 22:31:05 +01:00
André Cruz
6741d99681 Fix rc version and update mocha. 2013-07-06 21:56:53 +01:00
André Cruz
ad4ec14778 Add editor config. 2013-07-06 21:55:53 +01:00
André Cruz
2bf16ad88b Fix rc name and update mocha. 2013-07-06 21:55:43 +01:00
André Cruz
6c56581c15 Typo. 2013-07-06 21:55:16 +01:00
André Cruz
ce89d9fbe0 Initial commit. 2013-07-06 21:53:04 +01:00
André Cruz
e298f74310 Improve sentence. 2013-07-06 14:55:43 +01:00
André Cruz
c550c1373e Merge branch 'master' of github.com:bower/registry-client 2013-07-06 14:39:33 +01:00
André Cruz
6a1bb88c3b Update README. 2013-07-06 14:39:24 +01:00
André Cruz
a585e96fdf Improve clear runtime cache. 2013-07-06 14:39:13 +01:00
Sven Lito
e78ef493a1 [tests] don't test for private methods 2013-07-06 14:28:25 +01:00
André Cruz
c139378694 Add comment. 2013-07-06 14:09:11 +01:00
André Cruz
d0eb3e760f Bump rc version. 2013-07-06 13:55:59 +01:00
André Cruz
9cfa3e5002 Changes to the reset & clear runtime cache.
Minor tweak to the grunt file.
2013-07-06 13:48:53 +01:00
Sven Lito
82278037ec [tests] adds comments and clearCache tests 2013-07-05 13:08:42 +01:00
Sven Lito
0b592f86d0 [tests] tidy up nock call 2013-07-05 12:50:25 +01:00
Sven Lito
ee4e003c2d [tests] fix method call 2013-07-05 12:50:08 +01:00
Sven Lito
b2904bc6fb [tests] mock search endpoint 2013-07-05 12:36:36 +01:00
Sven Lito
67b94cf52e sets nock as npm dependency 2013-07-05 11:53:08 +01:00
Sven Lito
c308d2c9dd adds nock fixture 2013-07-05 11:51:28 +01:00
Sven Lito
e36370b080 removes fixtures 2013-07-05 11:51:15 +01:00
Sven Lito
d0f005a6f1 adjust fixtures path 2013-07-05 10:54:51 +01:00
Sven Lito
a461fa9137 move fixture 2013-07-05 10:54:39 +01:00
Sven Lito
22e969fb59 fix npm module name
meh..
2013-07-05 10:52:25 +01:00
Sven Lito
34527c8395 [tests] fix breaking test 2013-07-05 10:49:53 +01:00
Sven Lito
012f4d68bc [wip] update tests 2013-07-05 10:46:48 +01:00
Sven Lito
724283433a adds lookup method tests 2013-07-04 15:55:10 +01:00
Sven Lito
aea19b93b1 rename client -> registry
because that's what it is right?
2013-07-04 15:11:44 +01:00
Sven Lito
73020a711d tweaking docs 2013-07-04 15:00:15 +01:00
Sven Lito
7e62e671e3 updates testrunner 2013-07-04 14:51:29 +01:00
Sven Lito
2e845ac0ab adds createError tests 2013-07-04 14:51:17 +01:00
Sven Lito
2df41e52ed adds Cache tests 2013-07-04 14:51:09 +01:00
Sven Lito
bf8e93f581 adds search tests 2013-07-04 14:51:03 +01:00
Sven Lito
f5eec3283c adds register tests 2013-07-04 14:50:54 +01:00
Sven Lito
223161c7d6 adds list tests 2013-07-04 14:50:47 +01:00
Sven Lito
b8ba6e4827 adds index tests 2013-07-04 14:50:39 +01:00
Sven Lito
15c8259ac2 adds lookup tests 2013-07-04 14:50:32 +01:00
Sven Lito
720492932f update Client.js tests 2013-07-04 10:40:36 +01:00
Sven Lito
a08a0fb084 add tests to jshint 2013-07-04 10:40:21 +01:00
Sven Lito
827fbaac1f update jshint settings 2013-07-04 10:40:03 +01:00
André Cruz
297224bd31 Merge branch 'master' of github.com:bower/registry-client 2013-07-03 16:20:38 +01:00
André Cruz
9dc835c60c Bump rc version. 2013-07-03 16:18:50 +01:00
André Cruz
67a96bc2f3 Typo ignoring ENOENT errors. 2013-07-03 16:18:22 +01:00
Sven Lito
ff5bf16111 fix file reference 2013-07-02 23:33:52 +01:00
Sven Lito
8d22059462 adds grunt travis setup 2013-07-02 23:26:07 +01:00
Sven Lito
91d144f5f7 Merge branch 'master' of https://github.com/bower/registry-client 2013-07-02 22:51:50 +01:00
Sven Lito
c894b1d335 adds grunt and test runner setup 2013-07-02 22:51:43 +01:00
Sven Lito
d30a7bf6a1 adds .editorconfig 2013-07-02 22:50:26 +01:00
André Cruz
649d5f56c9 Minor doc typo. 2013-07-02 09:41:17 +01:00
André Cruz
36b033c2f7 Switch to graceful-fs. 2013-07-01 20:28:37 +01:00
André Cruz
dc9bce915b Switch to graceful-fs. 2013-07-01 20:28:11 +01:00
André Cruz
c9a7cfafd0 Bump rc version! 2013-06-28 21:59:56 +01:00
André Cruz
9d9585ecba Ignore ENOENT erros when deleting from the cache. 2013-06-28 21:59:24 +01:00
André Cruz
0ebd7e6a58 Small typo in README. 2013-06-24 14:51:54 +01:00
André Cruz
a100abc3b6 Bump rc version. 2013-06-24 14:48:36 +01:00
André Cruz
94f6945d5a Complete README, change cleanRuntimeCache to clearRuntimeCache. 2013-06-24 14:48:20 +01:00
André Cruz
442d771a7a Bump rc version. 2013-06-23 17:44:29 +01:00
André Cruz
242e11eefc Add register. 2013-06-23 17:43:52 +01:00
André Cruz
7fbbae8cd4 Bump (rc3). 2013-06-22 17:05:13 +01:00
André Cruz
b80d96d9c7 Fix tests. 2013-06-22 14:15:35 +01:00
André Cruz
d8e69360b9 Add search command, other fixes/changes.
- Use LRU to prevent huge memory usage when using the module in long-living programs
- Lookup no longer throws when a package is not found (null is returned instead).
- Cache mechanism improvements.
- Misc fixes.
2013-06-22 14:11:11 +01:00
André Cruz
83ae9b66a3 Add license note, misc tweaks. 2013-06-22 14:07:51 +01:00
André Cruz
4ac052c10b Oops. 2013-05-26 13:17:54 +01:00
André Cruz
f1717f8319 Move force and offline options to the constructor. 2013-05-26 13:12:54 +01:00
André Cruz
cb000549bd Small tweaks. 2013-05-26 12:46:45 +01:00
André Cruz
2712aa2ae2 Merge branch 'master' of github.com:bower/json 2013-05-24 22:55:03 +01:00
André Cruz
7dcefa6bee Add repository to package.json and fix URL's, also bump rc version. 2013-05-24 22:54:41 +01:00
André Cruz
70e3528809 Add repository to package.json and bump rc version. 2013-05-24 22:53:52 +01:00
André Cruz
c7780a2708 Try next registry endpoint on 404. 2013-05-24 22:53:17 +01:00
André Cruz
26bab84d04 Fix parse usage in README. 2013-05-19 14:27:36 +02:00
André Cruz
efea6136e7 Merge pull request #2 from badunk/find-readme
Quick fix for bowerJson.find() example
2013-05-19 05:26:42 -07:00
Duncan Wong
c56026c18a quick fix for bowerJson.find() example 2013-05-18 19:26:49 -06:00
André Cruz
1d9504d0f0 Bump rc. 2013-05-17 13:14:53 +01:00
André Cruz
780b1f8acc Fix various bugs. 2013-05-17 13:13:47 +01:00
André Cruz
9b6c5741de Move cache did creation to appropriate class, small pert improvement.. 2013-05-13 11:10:10 +01:00
André Cruz
0742e18edd Oops. 2013-05-11 14:00:11 +01:00
André Cruz
cb59c2489b Change main file. 2013-05-11 13:56:48 +01:00
André Cruz
3158b544d5 Minor lang change. 2013-05-11 13:42:23 +01:00
André Cruz
e80270d1fa Add correct maxAge for the cache entries. 2013-05-11 13:40:59 +01:00
André Cruz
99b37f24bb Slightly different strategy, implement lookup cache. 2013-05-11 13:33:40 +01:00
André Cruz
fdbdcc4130 More doc typos. 2013-05-10 20:01:35 +01:00
André Cruz
08104966b2 Improve doc. 2013-05-10 19:54:30 +01:00
André Cruz
1c99133177 Change package to bower-registry-client.
Some changes to the codebase.
2013-05-10 19:46:52 +01:00
André Cruz
28780dc67e Wrong async usage of doUntil. 2013-05-09 21:15:49 +01:00
André Cruz
423ce54d8a Add empty tests and add cache TODO. 2013-05-09 13:18:59 +01:00
André Cruz
73bab73db6 Initial implementation of lookup. 2013-05-09 13:11:57 +01:00
André Cruz
3e90471fa2 Setup project. 2013-05-07 17:38:53 +01:00
André Cruz
7f2db8a9a7 Setup project. 2013-05-07 17:30:29 +01:00
André Cruz
d5fc147ffd Merge pull request #1 from dylang/human-friendly-error-message
Made the error message more understandable.
2013-05-07 09:29:32 -07:00
André Cruz
77ffd7bbf9 Merge branch 'master' of github.com:bower/bower-json 2013-05-07 17:26:32 +01:00
André Cruz
42775d3477 Improve gitignore. 2013-05-07 17:26:22 +01:00
André Cruz
6932b8c378 Better license format. 2013-05-07 17:26:10 +01:00
Dylan Greene
cff641ef80 add quotes around the path and fix the test 2013-05-06 22:16:52 -04:00
André Cruz
373abf1b24 Update README.md 2013-05-06 23:11:51 +02:00
Dylan Greene
f668596667 Made the error message more understandable. 2013-05-06 17:02:57 -04:00
André Cruz
93e0e815d7 Fix indentation. 2013-05-05 03:03:56 +01:00
André Cruz
05275c8938 Improve README. 2013-05-05 04:02:15 +02:00
André Cruz
19475db7dd Typos. 2013-05-05 04:00:55 +02:00
André Cruz
aa315d7c97 Merge branch 'master' of github.com:bower/bower-json 2013-04-23 23:58:48 +01:00
André Cruz
080b25e30c Update .gitignore. 2013-04-23 23:58:35 +01:00
André Cruz
a7c8c08183 Update README.md 2013-04-23 10:12:47 +02:00
André Cruz
bb98627d2b Made parse async for consistency, tweak error codes. 2013-04-20 12:17:00 +01:00
André Cruz
3060866586 Add test for invalid json. 2013-04-20 11:37:15 +01:00
André Cruz
eacf121f78 Update README. 2013-04-20 11:23:24 +01:00
André Cruz
c39535fdd0 Merge branch 'master' of github.com:bower/bower-json 2013-04-20 11:21:31 +01:00
André Cruz
c3311df2a8 Initial implementation and tests. 2013-04-20 11:20:41 +01:00
André Cruz
5a17314b2c Oops. 2013-04-19 22:00:24 +02:00
André Cruz
07281f050c Change to just bower-json. 2013-04-19 13:58:18 +01:00
André Cruz
9c3757fb0c Doc improv. 2013-04-19 12:33:07 +01:00
André Cruz
f5d5e59040 Typo. 2013-04-19 12:31:04 +01:00
André Cruz
70880c066f Add LICENSE and README. 2013-04-19 12:29:20 +01:00
André Cruz
5508c70f3a Setup module. 2013-04-19 11:19:47 +01:00
262 changed files with 30468 additions and 9448 deletions

View File

@@ -13,3 +13,6 @@ trim_trailing_whitespace = false
[**.std]
insert_final_newline = false
[{package,bower}.json]
indent_size = 2

6
.eslintignore Normal file
View File

@@ -0,0 +1,6 @@
node_modules
test/assets
test/reports
test/sample
test/tmp
packages/bower-logger/test

51
.eslintrc Normal file
View File

@@ -0,0 +1,51 @@
{
"env": {
"node": true,
"mocha": true
},
"rules": {
"no-bitwise": 0,
"curly": 0,
"eqeqeq": 0,
"guard-for-in": 0,
"no-use-before-define": 0,
"no-caller": 2,
"no-new": 2,
"no-plusplus": 0,
"no-undef": 2,
"no-unused-vars": 0,
"strict": 0,
"semi": 0,
"comma-spacing": 2,
"quote-props": [2, "as-needed"],
"quotes": [2, "single", "avoid-escape"],
"no-cond-assign": [ 2, "except-parens" ],
"no-debugger": 2,
"no-dupe-args": 2,
"no-dupe-keys": 2,
"no-duplicate-case": 2,
"no-unreachable": 2,
"valid-typeof": 2,
"no-fallthrough": 2,
"no-ex-assign": 2,
"no-eq-null": 0,
"no-eval": 0,
"no-unused-expressions": 0,
"block-scoped-var": 0,
"no-iterator": 0,
"no-loop-func": 2,
"no-script-url": 0,
"no-shadow": 0,
"no-new-func": 2,
"no-new-wrappers": 2,
"no-invalid-this": 0,
"space-before-blocks": [2, "always"],
"space-before-function-paren": [2, "never"],
"space-infix-ops": 2,
"keyword-spacing": 2,
"new-parens": 2,
"no-multiple-empty-lines": [2, { max: 2}],
"eol-last": 2,
"no-trailing-spaces": 2
}
}

3
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,3 @@
# These are supported funding model platforms
open_collective: bower

44
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,44 @@
<!--
If you are reporting a new issue, make sure that we do not have any duplicates.
You can ensure this by searching the issue list for this repository.
You are welcome to open issues to discuss important general topics concerning Bower.
However for support questions, please consider using http://stackoverflow.com or
asking for help in our Discord channel: https://discordapp.com/invite/0fFM7QF0KpZaDeN9
# BUG REPORT
Use the commands below to provide key information to reproduce:
You do NOT have to include this information if this is a FEATURE REQUEST OR DISCUSSION
For more information about reporting bugs, see:
https://github.com/bower/bower/wiki/Report-a-Bug
-->
**Output of `bower -v && npm -v && node -v`:**
```
(paste your output here)
```
**Additional environment details (proxy, private registry, etc.):**
**Steps to reproduce the issue:**
1.
2.
3.
**Describe the results you received:**
**Describe the results you expected:**
**Additional information:**

88
.github/workflows/nodejs.yml vendored Normal file
View File

@@ -0,0 +1,88 @@
name: build
on:
push:
branches:
- master
pull_request:
branches:
- '**'
jobs:
test:
name: Node v${{ matrix.node-version }} on ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# https://github.com/actions/setup-node/issues/27
node-version: [6.x, 8.x, 10.x, 12.x, 14.x, 16.x, 18.x, 20.x, 22.x]
os: [ubuntu-latest, macOS-latest, windows-latest]
include:
# Pin deprecated Node.js versions on Mac to specific MacOS,
# as later OS architecture wont support them anymore.
- node-version: 6.x
os: macOS-13
- node-version: 8.x
os: macOS-13
- node-version: 10.x
os: macOS-13
- node-version: 12.x
os: macOS-13
- node-version: 14.x
os: macOS-13
exclude:
# Exclude older Node.js versions from macOS-latest
- node-version: 6.x
os: macOS-latest
- node-version: 8.x
os: macOS-latest
- node-version: 10.x
os: macOS-latest
- node-version: 12.x
os: macOS-latest
- node-version: 14.x
os: macOS-latest
runs-on: ${{ matrix.os }}
steps:
- name: Set git config
shell: bash
run: |
git config --global core.autocrlf false
git config --global core.symlinks true
if: runner.os == 'Windows'
- uses: actions/checkout@v4
- name: install
run: yarn && (cd packages/bower-json && yarn link) && yarn link bower-json
- name: lint
run: npm run lint
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: bower tests
run: npm test
env:
CI: true
continue-on-error: ${{ matrix.os == 'windows-latest' }} # Allow failure on Windows
- name: bower-logger tests
run: (cd packages/bower-logger && npm install && npm test)
env:
CI: true
- name: bower-config tests
run: (cd packages/bower-config && npm install && npm test)
env:
CI: true
- name: bower-endpoint-parser tests
run: (cd packages/bower-endpoint-parser && npm install && npm test)
env:
CI: true
- name: bower-json tests
run: (cd packages/bower-json && npm install && npm test)
env:
CI: true
- name: bower-registry-client tests
run: (cd packages/bower-registry-client && npm install && npm test)
env:
CI: true

10
.gitignore vendored
View File

@@ -1,12 +1,16 @@
!lib/bin
/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
/bower_components
/test/sample
!/test/sample/bower.json
/npm-shrinkwrap.json
package-lock.json

View File

@@ -1,62 +0,0 @@
{
"predef": [
"console",
"describe",
"it",
"after",
"afterEach",
"before",
"beforeEach"
],
"indent": 4,
"node": true,
"devel": true,
"bitwise": false,
"curly": false,
"eqeqeq": true,
"forin": false,
"immed": true,
"latedef": false,
"newcap": true,
"noarg": true,
"noempty": false,
"nonew": true,
"plusplus": false,
"regexp": false,
"undef": true,
"unused": "vars",
"quotmark": "single",
"strict": false,
"trailing": true,
"camelcase": true,
"asi": false,
"boss": true,
"debug": false,
"eqnull": true,
"es5": false,
"esnext": false,
"evil": false,
"expr": false,
"funcscope": false,
"globalstrict": false,
"iterator": false,
"lastsemic": false,
"laxbreak": true,
"laxcomma": false,
"loopfunc": true,
"multistr": false,
"onecase": true,
"regexdash": false,
"scripturl": false,
"smarttabs": false,
"shadow": false,
"sub": false,
"supernew": true,
"validthis": false,
"nomen": false,
"white": true
}

4
.prettierignore Normal file
View File

@@ -0,0 +1,4 @@
**/node_modules/**
**/test/assets/**
**/bower_components/**
test/sample

View File

@@ -1,9 +0,0 @@
language: node_js
node_js:
- "0.10"
- "0.11"
matrix:
allow_failures:
- node_js: "0.11"
before_script:
- npm install grunt-cli -g

View File

@@ -1,13 +1,310 @@
# Changelog
## Newer releases
Please see: https://github.com/bower/bower/releases
## 1.8.0 - 2016-11-07
- Download tar archives from GitHub when possible (#2263)
- Change default shorthand resolver for github from `git://` to `https://`
- Fix ssl handling by not setting GIT_SSL_NO_VERIFY=false (#2361)
- Allow for removing components with url instead of name (#2368)
- Show in warning message location of malformed bower.json (#2357)
- Improve handling of non-semver versions in git resolver (#2316)
- Fix handling of cached releases pluginResolverFactory (#2356)
- Allow to type the entire version when conflict occured (#2243)
- Allow `owner/reponame` shorthand for registering components (#2248)
- Allow single-char repo names and package names (#2249)
- Make `bower version` no longer honor `version` in bower.json (#2232)
- Add `postinstall` hook (#2252)
- Allow for `@` instead of `#` for `install` and `info` commands (#2322)
- Upgrade all bundled modules
## 1.7.9 - 2016-04-05
- Show warnings for invalid bower.json fields
- Update bower-json
- Less strict validation on package name (allow spaces, slashes, and "@")
## 1.7.8 - 2016-04-04
- Don't ask for git credentials in non-interactive session, fixes #956 #1009
- Prevent swallowing exceptions with programmatic api, fixes #2187
- Update graceful-fs to 4.x in all dependences, fixes nodejs/node#5213
- Resolve pluggable resolvers using cwd and fallback to global modules, fixes #1919
- Upgrade handlebars to 4.0.5, closes #2195
- Replace all % chatacters in defined scripts, instead of only first one, fixes #2174
- Update opn package to fix issues with "bower open" command on Windows
- Update bower-config
- Do not interpolate environment variables in script hooks, fixes bower/config#47
- Update bower-json
- Validate package name more strictly and allow only latin letters, dots, dashes and underscores
- Add support for "save" and "save-exact" in .bowerrc, #2161
## 1.7.7 - 2016-01-27
Revert locations of all files while still packaging `node_modules`.
It's because people are depending on internals of bower, like
`bower/lib/renderers/StandardRenderer`. We want to preserve this
implicit contract, but we discourage it. The only official way
to use bower programmatically is through `require('bower')`.
## 1.7.6 - 2016-01-27
- Revert location of "bin/bower" as developers are using it directly ([#2157](https://github.com/bower/bower/issues/2157))
Note: Correctly, you should use an alias created in `npm bin --global`.
## 1.7.5 - 2016-01-26
- Remove analytics from Bower, fixes ([#2150](https://github.com/bower/bower/pull/2150))
- Default to ^ operator on `bower install --save` ([#2145](https://github.com/bower/bower/pull/2145))
- Support absolute path in .bowerrc directory option ([#2130](https://github.com/bower/bower/pull/2130))
- Display user's name upon `bower login` command ([#2133](https://github.com/bower/bower/pull/2133))
- Decompress gzip files ([#2092](https://github.com/bower/bower/pull/2092))
- Prevent name clashes in package extraction ([#2102](https://github.com/bower/bower/pull/2102))
- When strictSsl is false, set GIT_SSL_NO_VERIFY=true ([#2129](https://github.com/bower/bower/issues/2129))
- Distribute bower with npm@3 for better Windows support ([#2146](https://github.com/bower/bower/issues/2146))
- Update request to 2.67.0 and fs-write-stream-atomic to 1.0.8
- Documentation improvements
## 1.7.4 - 2016-01-21
Unpublished because of issue with npm distribution:
https://github.com/npm/npm/issues/11227
## 1.7.3 - 2016-01-20
Unpublished because of issue with npm distribution:
https://github.com/npm/npm/issues/11227
## 1.7.2 - 2015-12-31
- Lock "fs-write-stream-atomic" to 1.0.5
## 1.7.1 - 2015-12-11
- Rollback "Add `bower update --save` functionality", it causes issues and needs more testing
- Fix backward-compatibility of `bower search --json` ([#2066](https://github.com/bower/bower/issues/2066))
- Ignore prerelease versions from `bower info` output
- Update update-notifier to 0.6.0
- Better formatting of help messages (https://github.com/bower/bower/commit/de3e1089da80f47ea3667c5ab80d301cddfd8c3e)
- Add help menu for update `--save` and `update --save-dev` (https://github.com/bower/bower/commit/612aaa88eb4d4b268b2d8665c338ac086af3a5b0)
## 1.7.0 - 2015-12-07
- Add `bower update --save` functionality ([#2035](https://github.com/bower/bower/issues/2035))
- `bower search` shows help message when no package name is specified ([#2066](https://github.com/bower/bower/issues/2066))
- Update only those packages that are explicitly requested by the user. Related Issues
- [#256](https://github.com/bower/bower/issues/256)
- [#924](https://github.com/bower/bower/issues/924)
- [#1770](https://github.com/bower/bower/issues/1770)
- Allow for @ in username for SVN on windows ([#1650](https://github.com/bower/bower/issues/1650))
- Update bower config
- Loads the .bowerrc file from the cwd specified on the command line
- Allow the use of environment variables in .bowerrc ([#41](https://github.com/bower/config/issues/41))
- Allow for array notation in ENV variables ([#44](https://github.com/bower/config/issues/44))
## 1.6.9 - 2015-12-04
- Change git version of fs-write-stream-atomic back to npm version ([#2079](https://github.com/bower/bower/issues/2079))
## 1.6.8 - 2015-11-27
- Use fs-write-stream-atomic for downloads
- Improved downloader that properly cleans after itself
- Fix shallow host detection ([#2040](https://github.com/bower/bower/pull/2040))
- Upgrade to ([bower-config#1.2.3](https://github.com/bower/config/releases/tag/1.2.3))
- Properly restore env variables if they are undefined at the beginning
- Properly handle `default` setting for config.ca
- Display proper error if .bowerrc is a directory instead of file
## 1.6.7 - 2015-11-26
- Bundless all the dependencies again
## 1.6.6 - 2015-11-25
- Fixes regression with the published npm version
## 1.6.5 - 2015-10-24
- Updates to tests and documentation
- Fixes passing options when requesting downloads
## 1.6.4 - 2015-10-24
- Fix ignoring dependencies on multiple install run ([#1970](https://github.com/bower/bower/pull/1970))
- Use --non-interactive when running svn client ([#1969](https://github.com/bower/bower/pull/1969))
- Fix downloading of URLs ending with slash ([#1956](https://github.com/bower/bower/pull/1956))
- Add user-agent field for downloads by Bower ([#1960](https://github.com/bower/bower/pull/1960))
## 1.6.3 - 2015-10-16
Fixes regression issues introduced with 1.6.2, specifically:
- Allow for bower_components to be a symlink
- Allow setting custom registry in .bowerrc
## 1.6.2 - 2015-10-15
Fix dependency issues of 1.6.1. First published release of 1.6.x.
## 1.6.1 - 2015-10-15
Fix dependency issues of 1.6.0. Reverted release.
## 1.6.0 - 2015-10-15
- Shrinkwrap all dependencies and add them to bundledDependencies ([#1948](https://github.com/bower/bower/pull/1948))
- Allow for ignoring of child dependencies ([#1394](https://github.com/bower/bower/pull/1394))
- Allow passing `--config.resolvers` through CLI ([#1922](https://github.com/bower/bower/pull/1922))
- Use defaults values from package.json if it exists (bower init) ([#1731](https://github.com/bower/bower/issues/1731))
- Properly use cerificates set in .bowerrc ([#1869](https://github.com/bower/bower/pull/1869))
- Include package name when version conflict occurs ([#1917](https://github.com/bower/bower/pull/1917))
- Add timeout for permission check ([yeoman/insight#35](https://github.com/yeoman/insight/pull/35))
- Close file-handles when possible. Prevents all sorts of permission issues on Windows ([0bb1536](https://github.com/bower/bower/commit/0bb1536c9972e13f3be06bea9a8619632966c664))
- Prevent ENOENT error on Windows when in VM environment ([isaacs/chmodr#8](https://github.com/isaacs/chmodr/pull/8))
Reverted release.
## 1.5.4 - 2015-11-24
- [fix] Lock lru-cache dependency to 2.7.0
## 1.5.3 - 2015-09-24
- Revert auto sorting of bower dependencies, fixes ([#1897](https://github.com/bower/bower/issues/1897))
- Fix --save-exact feature for github endpoints, fixes ([#1925](https://github.com/bower/bower/issues/1925))
- Fix `bower init` to support private flag again ([#1819](https://github.com/bower/bower/pull/1819))
- Bump insight dependency to support prompt timeout ([#1102](https://github.com/bower/bower/issues/1102))
## 1.5.2 - 2015-08-25
- Revert update semver version from 2.x to 5.x, fixes ([#1896](https://github.com/bower/bower/issues/1896))
- Make bower commands work from subdirectories, fixes ([#1893](https://github.com/bower/bower/issues/1893))
- Put auto shallow cloning for git behind a flag, fixes ([#1764](https://github.com/bower/bower/issues/1764))
## 1.5.1 - 2015-08-24
- If cwd provided explicitly, force using it, fixes #1866
## 1.5.0 - 2015-08-24
- Pluggable Resolvers! http://bower.io/docs/pluggable-resolvers/
- Update semver version from 2.x to 5.x ([#1852](https://github.com/bower/bower/issues/1852))
- Auto-sort dependencies alphabetically ([#1381](https://github.com/bower/bower/issues/1381))
- Make bower commands work from subdirectories ([#1866](https://github.com/bower/bower/issues/1866))
- No longer prefer installing bower as global module ([#1865](https://github.com/bower/bower/issues/1865))
## 1.4.2 - 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.

View File

@@ -1,96 +1,34 @@
# Contributing to Bower
Bower is a large community project with many different developers contributing at all levels to the project. We're **actively** looking for more contributors right now. (Jan 2014)
Bower is a large community project with many different developers contributing at all levels to the project. There is more information about [contributing](https://github.com/bower/bower/wiki/Contributor-Guidelines) in the Wiki.
<a name="bugs"></a>
## 🐛 [Bug reports](https://github.com/bower/bower/wiki/Report-a-Bug)
## Casual Involvement
* Improve the bower.io site ([tickets](https://github.com/bower/bower.github.io/issues))
* Move forward [bower.io redesign](https://github.com/bower/bower.github.io/issues/7)
* Attend team meetings
* Comment on issues and drive to resolution
## High-impact Involvement
* Maintaining the bower client.
* [Authoring client tests](https://github.com/bower/bower/issues/801)
* Maintaining the bower client.
* Read [Architecture doc](https://github.com/bower/bower/wiki/Rewrite-architecture)
* Triage, close, fix and resolve [issues](https://github.com/bower/bower/issues)
* Developing the [new registry server](https://github.com/bower/registry/tree/node_rewrite)
* Hooking in to Elastic Search rather than the in-memory search
* Getting bower/registry-client to talk to the new server without breaking backwards compatibility
* DevOps for the server
## Team Meetings
We meet on Monday at 1:00pm PST, 9:00pm UTC in #bower on Freenode. [The meeting notes](http://goo.gl/NJZ1o2).
<hr>
Following these guidelines helps to communicate that you respect the time of
the developers managing and developing this open source project. In return,
they should reciprocate that respect in addressing your issue, assessing
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:
* Please **do not** use the issue tracker for personal support requests. Use
[Stack Overflow](http://stackoverflow.com/questions/tagged/bower), our
[Mailing List](http://groups.google.com/group/twitter-bower)
(twitter-bower@googlegroups.com), or
[#bower](http://webchat.freenode.net/?channels=bower) on Freenode.
[Stack Overflow](http://stackoverflow.com/questions/tagged/bower), or in serious cases
send an e-mail to team@bower.io
* Please **do not** derail or troll issues. Keep the discussion on topic and
respect the opinions of others.
<a name="bugs"></a>
## Bug reports
A bug is a _demonstrable problem_ that is caused by the code in the repository.
Good bug reports are extremely helpful - thank you!
Guidelines for bug reports:
1. **Use the GitHub issue search** &mdash; check if the issue has already been
reported.
2. **Check if the issue has been fixed** &mdash; try to reproduce it using the
latest `master` or development branch in the repository.
3. **Isolate the problem** &mdash; ideally create a [reduced test
case](http://css-tricks.com/6263-reduced-test-cases/).
A good bug report shouldn't leave others needing to chase you up for more
information. Please try to be as detailed as possible in your report. What is
your environment? What steps will reproduce the issue? What OS experiences the
problem? What would you expect to be the outcome? All these details will help
people to fix any potential bugs.
Example:
> Short and descriptive example bug report title
>
> A summary of the issue and the browser/OS environment in which it occurs. If
> suitable, include the steps required to reproduce the bug.
>
> 1. This is the first step
> 2. This is the second step
> 3. Further steps, etc.
>
> `<url>` - a link to the reduced test case
>
> Any other information you want to share that is relevant to the issue being
> reported. This might include the lines of code that you have identified as
> causing the bug, and potential solutions (and your opinions on their
> merits).
<a name="features"></a>
## Feature requests
@@ -174,6 +112,8 @@ included in the project:
force push to your remote feature branch. You may also be asked to squash
commits.
10. If you are asked to squash your commits, then please use `git rebase -i master`. It will ask you to pick your commits - pick the major commits and squash the rest.
**IMPORTANT**: By submitting a patch, you agree to license your work under the
same license as that used by the project.

View File

@@ -1,47 +0,0 @@
module.exports = function (grunt) {
require('load-grunt-tasks')(grunt);
grunt.initConfig({
jshint: {
options: {
jshintrc: '.jshintrc'
},
files: ['Gruntfile.js', 'bin/*', 'lib/**/*.js', 'test/**/*.js', '!test/assets/**/*', '!test/reports/**/*']
},
simplemocha: {
options: {
reporter: 'spec',
timeout: '5000'
},
full: { src: ['test/test.js'] },
short: {
options: {
reporter: 'dot'
},
src: ['test/test.js']
}
},
exec: {
assets: {
command: 'node test/packages.js && node test/packages-svn.js'
},
'assets-force': {
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'
}
},
watch: {
files: ['<%= jshint.files %>'],
tasks: ['jshint', 'simplemocha:short']
}
});
grunt.registerTask('assets', ['exec:assets-force']);
grunt.registerTask('test', ['jshint', 'exec:assets', 'simplemocha:full']);
grunt.registerTask('cover', 'exec:cover');
grunt.registerTask('default', 'test');
};

View File

@@ -1,21 +0,0 @@
# Install and Uninstall Hooks
Bower provides 3 separate hooks that can be used to trigger other automated tools during Bower usage. Importantly, these hooks are intended to allow external tools to help wire up the newly installed components into the parent project and other similar tasks. These hooks are not intended to provide a post-installation build step for component authors. As such, the configuration for these hooks is provided in the `.bowerrc` file in the parent project's directory.
## Configuring
In `.bowerrc` do:
```js
{
"scripts": {
"preinstall": "<your command here>",
"postinstall": "<your command here>",
"preuninstall": "<your command here>"
}
}
```
The value of each script hook may contain a % character. When your script is called, the % will be replaced with a space-separated list of components being installed or uninstalled.
Your script will also include an environment variable `BOWER_PID` containing the PID of the parent Bower process that triggered the script. This can be used to verify that a `preinstall` and `postinstall` steps are part of the same Bower process.

View File

@@ -1,4 +1,4 @@
Copyright (c) 2014 Twitter and other contributors
Copyright (c) 2013-present 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

536
README.md
View File

@@ -1,424 +1,262 @@
# Bower
# Bower - A package manager for the web
[![Build Status](https://secure.travis-ci.org/bower/bower.svg?branch=master)](http://travis-ci.org/bower/bower)
[![Build](https://github.com/bower/bower/workflows/build/badge.svg)](https://github.com/bower/bower/actions?query=branch%3Amaster)
[![Backers on Open Collective](https://opencollective.com/bower/backers/badge.svg)](#backers)
[![Sponsors on Open Collective](https://opencollective.com/bower/sponsors/badge.svg)](#sponsors)
> ..psst! While Bower is maintained, we recommend [yarn](https://yarnpkg.com/) and [webpack](https://webpack.js.org/) or [parcel](https://parceljs.org/) for new front-end projects!
<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.
---
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 a 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
### Never run Bower 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.
Bower is a user command; there is no need to execute it with superuser permissions.
#### 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
option shown below:
[Git for Windows](http://git-for-windows.github.io/) correctly. Be sure to check the
options shown below:
![msysgit](http://f.cl.ly/items/2V2O3i1p3R2F1r2v0a12/mysgit.png)
<img src="https://cloud.githubusercontent.com/assets/10702007/10532690/d2e8991a-7386-11e5-9a57-613c7f92e84e.png" width="534" height="418" alt="Git for Windows" />
<img src="https://cloud.githubusercontent.com/assets/10702007/10532694/dbe8857a-7386-11e5-9bd0-367e97644403.png" width="534" height="418" alt="Git for Windows" />
Note that if you use TortoiseGit and if Bower keeps asking for your SSH
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
### Ubuntu users
To use Bower on Ubuntu, you might need to link `nodejs` executable to `node`:
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
sudo ln -s /usr/bin/nodejs /usr/bin/node
```
## 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).
Bower can be configured using JSON in a `.bowerrc` file. Read over available options at [bower.io/docs/config](http://bower.io/docs/config).
## Consuming a package
## Support
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);
});
```
## 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
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
```
## Contact
Have a question?
You can ask questions on following channels in order:
* [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
* [Issue Tracker](https://github.com/bower/bower/issues)
* team@bower.io
## Contributing
## Contributing to this project
We welcome [contributions](https://github.com/bower/bower/graphs/contributors) of all kinds from anyone. Please take a moment to review the [guidelines for contributing](CONTRIBUTING.md).
Anyone and everyone is welcome to contribute. Please take a moment to
review the [guidelines for contributing](CONTRIBUTING.md).
* [Bug reports](CONTRIBUTING.md#bugs)
* [Bug reports](https://github.com/bower/bower/wiki/Report-a-Bug)
* [Feature requests](CONTRIBUTING.md#features)
* [Pull requests](CONTRIBUTING.md#pull-requests)
## Bower Team
Note that on Windows for tests to pass you need to configure Git before cloning:
### Core team
```
git config --global core.autocrlf input
```
* [@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:
## Backers
[@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)
Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/bower#backer)]
### Bower Alumni
* [@fat](https://github.com/fat)
* [@maccman](https://github.com/maccman)
<a href='https://opencollective.com/bower/tiers/sponsors/1/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/1/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/2/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/2/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/3/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/3/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/4/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/4/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/5/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/5/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/6/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/6/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/7/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/7/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/8/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/8/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/9/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/9/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/10/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/10/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/11/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/11/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/12/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/12/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/13/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/13/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/14/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/14/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/15/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/15/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/16/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/16/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/17/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/17/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/18/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/18/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/19/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/19/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/20/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/20/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/21/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/21/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/22/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/22/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/23/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/23/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/24/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/24/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/25/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/25/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/26/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/26/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/27/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/27/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/28/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/28/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/29/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/29/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/30/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/30/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/31/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/31/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/32/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/32/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/33/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/33/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/34/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/34/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/35/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/35/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/36/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/36/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/37/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/37/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/38/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/38/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/39/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/39/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/40/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/40/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/41/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/41/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/42/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/42/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/43/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/43/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/44/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/44/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/45/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/45/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/46/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/46/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/47/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/47/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/48/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/48/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/49/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/49/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/50/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/50/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/51/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/51/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/52/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/52/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/53/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/53/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/54/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/54/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/55/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/55/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/56/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/56/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/57/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/57/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/58/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/58/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/59/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/59/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/60/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/60/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/61/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/61/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/62/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/62/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/63/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/63/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/64/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/64/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/65/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/65/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/66/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/66/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/67/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/67/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/68/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/68/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/69/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/69/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/70/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/70/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/71/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/71/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/72/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/72/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/73/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/73/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/74/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/74/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/75/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/75/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/76/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/76/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/77/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/77/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/78/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/78/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/79/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/79/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/80/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/80/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/81/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/81/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/82/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/82/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/83/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/83/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/84/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/84/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/85/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/85/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/86/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/86/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/87/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/87/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/88/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/88/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/89/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/89/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/90/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/90/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/91/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/91/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/92/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/92/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/93/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/93/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/94/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/94/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/95/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/95/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/96/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/96/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/97/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/97/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/98/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/98/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/99/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/99/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/100/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/100/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/101/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/101/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/102/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/102/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/103/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/103/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/104/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/104/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/105/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/105/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/106/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/106/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/107/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/107/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/108/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/108/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/109/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/109/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/110/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/110/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/111/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/111/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/112/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/112/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/113/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/113/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/114/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/114/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/115/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/115/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/116/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/116/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/117/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/117/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/118/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/118/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/119/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/119/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/120/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/120/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/121/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/121/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/122/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/122/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/123/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/123/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/124/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/124/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/125/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/125/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/126/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/126/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/127/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/127/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/128/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/128/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/129/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/129/avatar.svg'></a>
<a href='https://opencollective.com/bower/tiers/sponsors/130/website' target='_blank'><img src='https://opencollective.com/bower/tiers/sponsors/130/avatar.svg'></a>
## License
Copyright (c) 2014 Twitter and other contributors
Copyright (c) 2012-present Twitter and [other contributors](https://github.com/bower/bower/graphs/contributors)
Licensed under the MIT License

3
SECURITY.md Normal file
View File

@@ -0,0 +1,3 @@
# Security Policy
For critical security issues, please send an e-mail to team@bower.io instead of filing issue here.

144
bin/bower
View File

@@ -1,145 +1,3 @@
#!/usr/bin/env node
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 bower = require('../lib');
var pkg = require(path.join(__dirname, '..', '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({
version: { type: Boolean, shorthand: 'v' },
help: { type: Boolean, shorthand: 'h' },
'allow-root': { type: Boolean }
});
// Handle print of version
if (options.version) {
process.stdout.write(pkg.version + '\n');
process.exit();
}
// Root check
rootCheck(options, bower.config);
// Set loglevel
if (bower.config.silent) {
loglevel = levels.error;
} else if (bower.config.verbose) {
loglevel = -Infinity;
Q.longStackSupport = true;
} else if (bower.config.quiet) {
loglevel = levels.warn;
} else {
loglevel = levels[bower.config.loglevel] || levels.info;
}
// Get the command to execute
while (options.argv.remain.length) {
command = options.argv.remain.join(' ');
// Alias lookup
if (bower.abbreviations[command]) {
command = bower.abbreviations[command].replace(/\s/g, '.');
break;
}
command = command.replace(/\s/g, '.');
// Direct lookup
if (mout.object.has(bower.commands, command)) {
break;
}
options.argv.remain.pop();
}
// Ask for Insights on first run.
analytics.setup().then(function () {
// Execute the command
commandFunc = command && mout.object.get(bower.commands, command);
command = command && command.replace(/\./g, ' ');
// If no command was specified, show bower help
// Do the same if the command is unknown
if (!commandFunc) {
logger = bower.commands.help();
command = 'help';
// If the user requested help, show the command's help
// Do the same if the actual command is a group of other commands (e.g.: cache)
} else if (options.help || !commandFunc.line) {
logger = bower.commands.help(command);
command = 'help';
// Call the line method
} else {
logger = commandFunc.line(process.argv);
// If the method failed to interpret the process arguments
// show the command help
if (!logger) {
logger = bower.commands.help(command);
command = 'help';
}
}
// Get the renderer and configure it with the executed command
renderer = cli.getRenderer(command, logger.json, bower.config);
logger
.on('end', function (data) {
if (!bower.config.silent && !bower.config.quiet) {
renderer.end(data);
}
})
.on('error', function (err) {
if (levels.error >= loglevel) {
renderer.error(err);
}
process.exit(1);
})
.on('log', function (log) {
if (levels[log.level] >= loglevel) {
renderer.log(log);
}
})
.on('prompt', function (prompt, callback) {
renderer.prompt(prompt)
.then(function (answer) {
callback(answer);
});
});
// Warn if HOME is not SET
if (!osenv.home()) {
logger.warn('no-home', 'HOME not set, user configuration will not be loaded');
}
// Check for newer version of Bower
notifier = updateNotifier({
packageName: pkg.name,
packageVersion: pkg.version
});
if (notifier.update && levels.info >= loglevel) {
renderer.updateNotice(notifier.update);
}
});
require('../lib/bin/bower');

150
lib/bin/bower.js Normal file
View File

@@ -0,0 +1,150 @@
process.bin = process.title = 'bower';
var Q = require('q');
var mout = require('mout');
var Logger = require('bower-logger');
var userHome = require('user-home');
var bower = require('../');
var version = require('../version');
var cli = require('../util/cli');
var rootCheck = require('../util/rootCheck');
var options;
var renderer;
var loglevel;
var command;
var commandFunc;
var logger;
var levels = Logger.LEVELS;
options = cli.readOptions({
version: { type: Boolean, shorthand: 'v' },
help: { type: Boolean, shorthand: 'h' },
'allow-root': { type: Boolean }
});
// Handle print of version
if (options.version) {
process.stdout.write(version + '\n');
process.exit();
}
// Root check
rootCheck(options, bower.config);
// Set loglevel
if (bower.config.silent) {
loglevel = levels.error;
} else if (bower.config.verbose) {
loglevel = -Infinity;
Q.longStackSupport = true;
} else if (bower.config.quiet) {
loglevel = levels.warn;
} else {
loglevel = levels[bower.config.loglevel] || levels.info;
}
// Get the command to execute
while (options.argv.remain.length) {
command = options.argv.remain.join(' ');
// Alias lookup
if (bower.abbreviations[command]) {
command = bower.abbreviations[command].replace(/\s/g, '.');
break;
}
command = command.replace(/\s/g, '.');
// Direct lookup
if (mout.object.has(bower.commands, command)) {
break;
}
options.argv.remain.pop();
}
// Execute the command
commandFunc = command && mout.object.get(bower.commands, command);
command = command && command.replace(/\./g, ' ');
// If no command was specified, show bower help
// Do the same if the command is unknown
if (!commandFunc) {
logger = bower.commands.help();
command = 'help';
// If the user requested help, show the command's help
// Do the same if the actual command is a group of other commands (e.g.: cache)
} else if (options.help || !commandFunc.line) {
logger = bower.commands.help(command);
command = 'help';
// Call the line method
} else {
logger = commandFunc.line(process.argv);
// If the method failed to interpret the process arguments
// show the command help
if (!logger) {
logger = bower.commands.help(command);
command = 'help';
}
}
// Get the renderer and configure it with the executed command
renderer = cli.getRenderer(command, logger.json, bower.config);
function handleLogger(logger, renderer) {
logger
.on('end', function(data) {
if (!bower.config.silent && !bower.config.quiet) {
renderer.end(data);
}
})
.on('error', function(err) {
if (
command !== 'help' &&
(err.code === 'EREADOPTIONS' || err.code === 'EINVFORMAT')
) {
logger = bower.commands.help(command);
renderer = cli.getRenderer('help', logger.json, bower.config);
handleLogger(logger, renderer);
} else {
if (levels.error >= loglevel) {
renderer.error(err);
}
process.exit(1);
}
})
.on('log', function(log) {
if (levels[log.level] >= loglevel) {
renderer.log(log);
}
})
.on('prompt', function(prompt, callback) {
renderer.prompt(prompt).then(function(answer) {
callback(answer);
});
});
}
handleLogger(logger, renderer);
// Warn if HOME is not SET
if (!userHome) {
logger.warn(
'no-home',
'HOME environment variable not set. User config will not be loaded.'
);
}
if (bower.config.interactive) {
var updateNotifier = require('update-notifier');
// Check for newer version of Bower
var notifier = updateNotifier({ pkg: { name: 'bower', version: version } });
if (notifier.update && levels.info >= loglevel) {
notifier.notify();
}
}

View File

@@ -1,22 +1,19 @@
var fs = require('graceful-fs');
var fs = require('../../util/fs');
var path = require('path');
var mout = require('mout');
var Q = require('q');
var rimraf = require('rimraf');
var Logger = require('bower-logger');
var rimraf = require('../../util/rimraf');
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) {
@@ -25,46 +22,37 @@ function clean(endpoints, options, config) {
// Generate decomposed endpoints and names based on the endpoints
if (endpoints) {
decEndpoints = endpoints.map(function (endpoint) {
decEndpoints = endpoints.map(function(endpoint) {
return endpointParser.decompose(endpoint);
});
names = decEndpoints.map(function (decEndpoint) {
names = decEndpoints.map(function(decEndpoint) {
return decEndpoint.name || decEndpoint.source;
});
}
Q.all([
return Q.all([
clearPackages(decEndpoints, config, logger),
clearLinks(names, config, logger),
!names ? clearCompletion(config, logger) : null
])
.spread(function (entries) {
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) {
var repository = new PackageRepository(config, logger);
var repository = new PackageRepository(config, logger);
return repository.list()
.then(function (entries) {
return repository.list().then(function(entries) {
var promises;
// Filter entries according to the specified packages
if (decEndpoints) {
entries = entries.filter(function (entry) {
return !!mout.array.find(decEndpoints, function (decEndpoint) {
entries = entries.filter(function(entry) {
return !!mout.array.find(decEndpoints, function(decEndpoint) {
var entryPkgMeta = entry.pkgMeta;
// Check if name or source match the entry
if (decEndpoint.name !== entryPkgMeta.name &&
if (
decEndpoint.name !== entryPkgMeta.name &&
decEndpoint.source !== entryPkgMeta.name &&
decEndpoint.source !== entryPkgMeta._source
) {
@@ -78,36 +66,47 @@ function clearPackages(decEndpoints, config, logger) {
// If it's a semver target, compare using semver spec
if (semver.validRange(decEndpoint.target)) {
return semver.satisfies(entryPkgMeta.version, decEndpoint.target);
return semver.satisfies(
entryPkgMeta.version,
decEndpoint.target
);
}
// Otherwise, compare against target/release
return decEndpoint.target === entryPkgMeta._target ||
decEndpoint.target === entryPkgMeta._release;
return (
decEndpoint.target === entryPkgMeta._target ||
decEndpoint.target === entryPkgMeta._release
);
});
});
}
promises = entries.map(function (entry) {
return repository.eliminate(entry.pkgMeta)
.then(function () {
logger.info('deleted', 'Cached package ' + entry.pkgMeta.name + ': ' + entry.canonicalDir, {
file: entry.canonicalDir
});
promises = entries.map(function(entry) {
return repository.eliminate(entry.pkgMeta).then(function() {
logger.info(
'deleted',
'Cached package ' +
entry.pkgMeta.name +
': ' +
entry.canonicalDir,
{
file: entry.canonicalDir
}
);
});
});
return Q.all(promises)
.then(function () {
if (!decEndpoints) {
// Ensure that everything is cleaned,
// even invalid packages in the cache
return repository.clear();
}
})
.then(function () {
return entries;
});
.then(function() {
if (!decEndpoints) {
// Ensure that everything is cleaned,
// even invalid packages in the cache
return repository.clear();
}
})
.then(function() {
return entries;
});
});
}
@@ -117,59 +116,59 @@ function clearLinks(names, config, logger) {
// If no names are passed, grab all links
if (!names) {
promise = Q.nfcall(fs.readdir, dir)
.fail(function (err) {
promise = Q.nfcall(fs.readdir, dir).fail(function(err) {
if (err.code === 'ENOENT') {
return [];
}
throw err;
});
// Otherwise use passed ones
// Otherwise use passed ones
} else {
promise = Q.resolve(names);
}
return promise
.then(function (names) {
return promise.then(function(names) {
var promises;
var linksToRemove = [];
// Decide which links to delete
promises = names.map(function (name) {
promises = names.map(function(name) {
var link = path.join(config.storage.links, name);
return Q.nfcall(fs.readlink, link)
.then(function (linkTarget) {
// Link exists, check if it points to a folder
// that still exists
return Q.nfcall(fs.stat, linkTarget)
.then(function (stat) {
// Target is not a folder..
if (!stat.isDirectory()) {
return Q.nfcall(fs.readlink, link).then(
function(linkTarget) {
// Link exists, check if it points to a folder
// that still exists
return (
Q.nfcall(fs.stat, linkTarget)
.then(function(stat) {
// Target is not a folder..
if (!stat.isDirectory()) {
linksToRemove.push(link);
}
})
// Error occurred reading the link
.fail(function() {
linksToRemove.push(link);
})
);
// Ignore if link does not exist
},
function(err) {
if (err.code !== 'ENOENT') {
linksToRemove.push(link);
}
})
// Error occurred reading the link
.fail(function () {
linksToRemove.push(link);
});
// Ignore if link does not exist
}, function (err) {
if (err.code !== 'ENOENT') {
linksToRemove.push(link);
}
});
);
});
return Q.all(promises)
.then(function () {
return Q.all(promises).then(function() {
var promises;
// Remove each link that was declared as invalid
promises = linksToRemove.map(function (link) {
return Q.nfcall(rimraf, link)
.then(function () {
promises = linksToRemove.map(function(link) {
return Q.nfcall(rimraf, link).then(function() {
logger.info('deleted', 'Invalid link: ' + link, {
file: link
});
@@ -181,37 +180,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;

View File

@@ -1,4 +0,0 @@
module.exports = {
clean: require('./clean'),
list: require('./list')
};

View File

@@ -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,41 +13,30 @@ function list(packages, options, config) {
packages = null;
}
repository.list()
.then(function (entries) {
return repository.list().then(function(entries) {
if (packages) {
// Filter entries according to the specified packages
entries = entries.filter(function (entry) {
return !!mout.array.find(packages, function (pkg) {
entries = entries.filter(function(entry) {
return !!mout.array.find(packages, function(pkg) {
return pkg === entry.pkgMeta.name;
});
});
}
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;

View File

@@ -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;

View File

@@ -1,52 +1,41 @@
var Q = require('q');
var path = require('path');
var fs = require('graceful-fs');
var Logger = require('bower-logger');
var cli = require('../util/cli');
var fs = require('../util/fs');
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');
json = path.resolve(
__dirname,
'../templates/json/help-' + name.replace(/\s+/g, '/') + '.json'
);
} else {
json = path.resolve(__dirname, '../../templates/json/help.json');
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;

View File

@@ -1,27 +1,22 @@
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
// If no name is specified, read the project json
// If a name is specified, fetch from the package repository
if (!name) {
promise = project.hasJson()
.then(function (json) {
promise = project.hasJson().then(function(json) {
if (!json) {
throw createError('You are not inside a package', 'ENOENT');
}
@@ -30,47 +25,35 @@ function home(name, config) {
});
} else {
decEndpoint = endpointParser.decompose(name);
promise = project.getPackageRepository().fetch(decEndpoint)
.spread(function (canonicalDir, pkgMeta) {
return pkgMeta;
});
promise = project
.getPackageRepository()
.fetch(decEndpoint)
.spread(function(canonicalDir, pkgMeta) {
return pkgMeta;
});
}
// Get homepage and open it
promise.then(function (pkgMeta) {
return promise.then(function(pkgMeta) {
var homepage = pkgMeta.homepage;
if (!homepage) {
throw createError('No homepage set for ' + pkgMeta.name, 'ENOHOME');
}
open(homepage);
open(homepage, { wait: false });
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;

View File

@@ -1,5 +1,6 @@
var Q = require('q');
var Logger = require('bower-logger');
var config = require('../config');
/**
* Require commands only when called.
@@ -8,50 +9,74 @@ 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) {
function runApi() {
var command = require(id);
var commandArgs = [].slice.call(arguments);
Q.try(function () {
// call require asynchronously
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 (error) {
logger.emit('error', error);
return withLogger(function(logger) {
commandArgs.unshift(logger);
return command.apply(undefined, commandArgs);
});
}
function runFromArgv(argv) {
var commandArgs;
var command = require(id);
commandArgs = command.readOptions(argv);
return withLogger(function(logger) {
commandArgs.unshift(logger);
return command.apply(undefined, commandArgs);
});
}
function withLogger(func) {
var logger = new Logger();
Q.try(func, logger).done(
function() {
config.restore();
var args = [].slice.call(arguments);
args.unshift('end');
logger.emit.apply(logger, args);
},
function(error) {
config.restore();
logger.emit('error', error);
}
);
return logger;
}
function runFromArgv() {
return require(id).line.apply(undefined, arguments);
}
runApi.line = runFromArgv;
command.line = runFromArgv;
return command;
return runApi;
}
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')
};

View File

@@ -1,30 +1,35 @@
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;
}
// handle @ as version divider
var splitParts = endpoint.split('/');
splitParts[splitParts.length - 1] = splitParts[
splitParts.length - 1
].replace('@', '#');
endpoint = splitParts.join('/');
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
])
.spread(function (pkgMeta, versions) {
decEndpoint.target === '*' && !property
? repository.versions(decEndpoint.source)
: null
]).spread(function(pkgMeta, versions) {
if (versions) {
return {
name: decEndpoint.source,
@@ -34,52 +39,35 @@ 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) {
return repository.fetch(decEndpoint)
.spread(function (canonicalDir, pkgMeta) {
pkgMeta = mout.object.filter(pkgMeta, function (value, key) {
return key.charAt(0) !== '_';
return repository
.fetch(decEndpoint)
.spread(function(canonicalDir, pkgMeta) {
pkgMeta = mout.object.filter(pkgMeta, function(value, key) {
return key.charAt(0) !== '_';
});
// Retrieve specific property
if (property) {
pkgMeta = mout.object.get(pkgMeta, property);
}
return pkgMeta;
});
// Retrieve specific property
if (property) {
pkgMeta = mout.object.get(pkgMeta, property);
}
return pkgMeta;
});
}
// -------------------
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;

View File

@@ -1,61 +1,60 @@
var mout = require('mout');
var fs = require('graceful-fs');
var fs = require('../util/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 = config || {};
if (!config.cwd) {
config.cwd = process.cwd();
}
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)
// Fill in defaults
.then(setDefaults.bind(null, config))
// Now prompt user to make changes
.then(promptUser.bind(null, logger))
// Set ignore based on the response
.spread(setIgnore.bind(null, 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;
return (
readJson(project, logger)
// Fill in defaults
.then(setDefaults.bind(null, config))
// Now prompt user to make changes
.then(promptUser.bind(null, logger))
// Set ignore based on the response
.spread(setIgnore.bind(null, config))
// Set dependencies based on the response
.spread(setDependencies.bind(null, project))
// All done!
.spread(saveJson.bind(null, project, logger))
);
}
function readJson(project, logger) {
return project.hasJson()
.then(function (json) {
return project.hasJson().then(function(json) {
if (json) {
logger.warn('existing', 'The existing ' + path.basename(json) + ' file will be used and filled in');
logger.warn(
'existing',
'The existing ' +
path.basename(json) +
' file will be used and filled in'
);
}
return project.getJson();
@@ -64,8 +63,8 @@ function readJson(project, logger) {
function saveJson(project, logger, json) {
// Cleanup empty props (null values, empty strings, objects and arrays)
mout.object.forOwn(json, function (value, key) {
if (value == null || mout.lang.isEmpty(value)) {
mout.object.forOwn(json, function(value, key) {
if (!validConfigValue(value)) {
delete json[key];
}
});
@@ -77,8 +76,7 @@ function saveJson(project, logger, json) {
type: 'confirm',
message: 'Looks good?',
default: true
})
.then(function (good) {
}).then(function(good) {
if (!good) {
return null;
}
@@ -88,6 +86,18 @@ function saveJson(project, logger, json) {
});
}
// Test if value is of a type supported by bower.json[0] - Object, Array, String, Boolean - or a Number
// [0]: https://github.com/bower/bower.json-spec
function validConfigValue(val) {
return (
mout.lang.isObject(val) ||
mout.lang.isArray(val) ||
mout.lang.isString(val) ||
mout.lang.isBoolean(val) ||
mout.lang.isNumber(val)
);
}
function setDefaults(config, json) {
var name;
var promise = Q.resolve();
@@ -97,19 +107,6 @@ function setDefaults(config, json) {
json.name = path.basename(config.cwd);
}
// Version
if (!json.version) {
// Assume latest semver tag if it's a git repo
promise = promise.then(function () {
return GitFsResolver.versions(config.cwd)
.then(function (versions) {
json.version = versions[0] || '0.0.0';
}, function () {
json.version = '0.0.0';
});
});
}
// Main
if (!json.main) {
// Remove '.js' from the end of the package name if it is there
@@ -125,52 +122,70 @@ function setDefaults(config, json) {
// Homepage
if (!json.homepage) {
// Set as GitHub homepage if it's a GitHub repository
promise = promise.then(function () {
promise = promise.then(function() {
return cmd('git', ['config', '--get', 'remote.origin.url'])
.spread(function (stdout) {
var pair;
.spread(function(stdout) {
var pair;
stdout = stdout.trim();
if (!stdout) {
return;
}
stdout = stdout.trim();
if (!stdout) {
return;
}
pair = GitHubResolver.getOrgRepoPair(stdout);
if (pair) {
json.homepage = 'https://github.com/' + pair.org + '/' + pair.repo;
}
})
.fail(function () { });
pair = GitHubResolver.getOrgRepoPair(stdout);
if (pair) {
json.homepage =
'https://github.com/' + pair.org + '/' + pair.repo;
}
})
.fail(function() {});
});
}
if (!json.authors) {
promise = promise.then(function () {
promise = promise.then(function() {
// Get the user name configured in git
return cmd('git', ['config', '--get', '--global', 'user.name'])
.spread(function (stdout) {
var gitEmail;
var gitName = stdout.trim();
return cmd('git', [
'config',
'--get',
'--global',
'user.name'
]).spread(
function(stdout) {
var gitEmail;
var gitName = stdout.trim();
// Abort if no name specified
if (!gitName) {
return;
}
// Abort if no name specified
if (!gitName) {
return;
}
// Get the user email configured in git
return cmd('git', ['config', '--get', '--global', 'user.email'])
.spread(function (stdout) {
gitEmail = stdout.trim();
}, function () {})
.then(function () {
json.authors = gitName;
json.authors += gitEmail ? ' <' + gitEmail + '>' : '';
});
}, function () {});
// Get the user email configured in git
return cmd('git', [
'config',
'--get',
'--global',
'user.email'
])
.spread(
function(stdout) {
gitEmail = stdout.trim();
},
function() {}
)
.then(function() {
json.authors = gitName;
json.authors += gitEmail
? ' <' + gitEmail + '>'
: '';
});
},
function() {}
);
});
}
return promise.then(function () {
return promise.then(function() {
return json;
});
}
@@ -178,86 +193,76 @@ function setDefaults(config, json) {
function promptUser(logger, json) {
var questions = [
{
'name': 'name',
'message': 'name',
'default': json.name,
'type': 'input'
name: 'name',
message: 'name',
default: json.name,
type: 'input'
},
{
'name': 'version',
'message': 'version',
'default': json.version,
'type': 'input'
name: 'description',
message: 'description',
default: json.description,
type: 'input'
},
{
'name': 'description',
'message': 'description',
'default': json.description,
'type': 'input'
name: 'main',
message: 'main file',
default: json.main,
type: 'input'
},
{
'name': 'main',
'message': 'main file',
'default': json.main,
'type': 'input'
name: 'keywords',
message: 'keywords',
default: json.keywords ? json.keywords.toString() : null,
type: 'input'
},
{
'name': 'moduleType',
'message': 'what types of modules does this package expose?',
'type': 'checkbox',
'choices': ['amd', 'es6', 'globals', 'node', 'yui']
name: 'authors',
message: 'authors',
default: json.authors ? json.authors.toString() : null,
type: 'input'
},
{
'name': 'keywords',
'message': 'keywords',
'default': json.keywords ? json.keywords.toString() : null,
'type': 'input'
name: 'license',
message: 'license',
default: json.license || 'MIT',
type: 'input'
},
{
'name': 'authors',
'message': 'authors',
'default': json.authors ? json.authors.toString() : null,
'type': 'input'
name: 'homepage',
message: 'homepage',
default: json.homepage,
type: 'input'
},
{
'name': 'license',
'message': 'license',
'default': json.license || 'MIT',
'type': 'input'
name: 'dependencies',
message: 'set currently installed components as dependencies?',
default:
!mout.object.size(json.dependencies) &&
!mout.object.size(json.devDependencies),
type: 'confirm'
},
{
'name': 'homepage',
'message': 'homepage',
'default': json.homepage,
'type': 'input'
name: 'ignore',
message: 'add commonly ignored files to ignore list?',
default: true,
type: 'confirm'
},
{
'name': 'dependencies',
'message': 'set currently installed components as dependencies?',
'default': !mout.object.size(json.dependencies) && !mout.object.size(json.devDependencies),
'type': 'confirm'
},
{
'name': 'ignore',
'message': 'add commonly ignored files to ignore list?',
'default': true,
'type': 'confirm'
},
{
'name': 'private',
'message': 'would you like to mark this package as private which prevents it from being accidentally published to the registry?',
'default': !!json.private,
'type': 'confirm'
name: 'private',
message:
'would you like to mark this package as private which prevents it from being accidentally published to the registry?',
default: !!json.private,
type: 'confirm'
}
];
return Q.nfcall(logger.prompt.bind(logger), questions)
.then(function (answers) {
return Q.nfcall(logger.prompt.bind(logger), questions).then(function(
answers
) {
json.name = answers.name;
json.version = answers.version;
json.description = answers.description;
json.main = answers.main;
json.moduleType = answers.moduleType;
json.keywords = toArray(answers.keywords);
json.authors = toArray(answers.authors, ',');
json.license = answers.license;
@@ -272,12 +277,12 @@ function toArray(value, splitter) {
var arr = value.split(splitter || /[\s,]/);
// Trim values
arr = arr.map(function (item) {
arr = arr.map(function(item) {
return item.trim();
});
// Filter empty values
arr = arr.filter(function (item) {
arr = arr.filter(function(item) {
return !!item;
});
@@ -301,13 +306,12 @@ function setIgnore(config, json, answers) {
function setDependencies(project, json, answers) {
if (answers.dependencies) {
return project.getTree()
.spread(function (tree, flattened, extraneous) {
return project.getTree().spread(function(tree, flattened, extraneous) {
if (extraneous.length) {
json.dependencies = {};
// Add extraneous as dependencies
extraneous.forEach(function (extra) {
extraneous.forEach(function(extra) {
var jsonEndpoint;
// Skip linked packages
@@ -315,7 +319,9 @@ function setDependencies(project, json, answers) {
return;
}
jsonEndpoint = endpointParser.decomposed2json(extra.endpoint);
jsonEndpoint = endpointParser.decomposed2json(
extra.endpoint
);
mout.object.mixIn(json.dependencies, jsonEndpoint);
});
}
@@ -329,16 +335,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;

View File

@@ -1,61 +1,55 @@
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;
}
project = new Project(config, logger);
tracker = new Tracker(config);
// Convert endpoints to decomposed endpoints
endpoints = endpoints || [];
decEndpoints = endpoints.map(function (endpoint) {
decEndpoints = endpoints.map(function(endpoint) {
// handle @ as version divider
var splitParts = endpoint.split('/');
splitParts[splitParts.length - 1] = splitParts[
splitParts.length - 1
].replace('@', '#');
endpoint = splitParts.join('/');
return endpointParser.decompose(endpoint);
});
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({
'force-latest': { type: Boolean, shorthand: 'F'},
'production': { type: Boolean, shorthand: 'p' },
'save': { type: Boolean, shorthand: 'S' },
'save-dev': { type: Boolean, shorthand: 'D' }
}, argv);
};
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-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;

View File

@@ -1,110 +1,88 @@
var path = require('path');
var rimraf = require('rimraf');
var mout = require('mout');
var rimraf = require('../util/rimraf');
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');
var relativeToBaseDir = require('../util/relativeToBaseDir');
function linkSelf(config) {
function link(logger, name, localName, config) {
if (name) {
return linkTo(logger, name, localName, config);
} else {
return linkSelf(logger, config);
}
}
function linkSelf(logger, config) {
var project;
var logger = new Logger();
config = mout.object.deepFillIn(config || {}, defaultConfig);
config = defaultConfig(config);
project = new Project(config, logger);
project.getJson()
.then(function (json) {
return project.getJson().then(function(json) {
var src = config.cwd;
var dst = path.join(config.storage.links, json.name);
// Delete previous link if any
return Q.nfcall(rimraf, dst)
// Link globally
.then(function () {
return createLink(src, dst);
})
.then(function () {
return {
src: src,
dst: dst
};
});
})
.done(function (result) {
logger.emit('end', result);
}, function (error) {
logger.emit('error', error);
return (
Q.nfcall(rimraf, dst)
// Link globally
.then(function() {
return createLink(src, dst);
})
.then(function() {
return {
src: src,
dst: dst
};
})
);
});
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(relativeToBaseDir(config.cwd)(config.directory), localName);
// Delete destination folder if any
Q.nfcall(rimraf, dst)
// Link locally
.then(function () {
return createLink(src, dst);
})
// Install linked package deps
.then(function () {
return project.update([localName]);
})
.then(function (installed) {
return {
src: src,
dst: dst,
installed: installed
};
})
.done(function (result) {
logger.emit('end', result);
}, function (error) {
logger.emit('error', error);
});
return logger;
return (
Q.nfcall(rimraf, dst)
// Link locally
.then(function() {
return createLink(src, dst);
})
// Install linked package deps
.then(function() {
return project.update([localName]);
})
.then(function(installed) {
return {
src: src,
dst: dst,
installed: installed
};
})
);
}
// -------------------
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;

View File

@@ -1,54 +1,58 @@
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 || {};
// Make relative option true by default when used with paths
if (options.paths && options.relative == null) {
if (options.paths && options.relative == null) {
options.relative = true;
}
config = mout.object.deepFillIn(config || {}, defaultConfig);
config = defaultConfig(config);
project = new Project(config, logger);
project.getTree(options)
.spread(function (tree, flattened) {
var baseDir = path.dirname(path.join(config.cwd, config.directory));
return project.getTree(options).spread(function(tree, flattened) {
// Relativize paths
// Also normalize paths on windows
project.walkTree(tree, function (node) {
if (node.missing) {
return;
}
project.walkTree(
tree,
function(node) {
if (node.missing) {
return;
}
if (options.relative) {
node.canonicalDir = path.relative(baseDir, node.canonicalDir);
}
if (options.paths) {
node.canonicalDir = normalize(node.canonicalDir);
}
}, true);
if (options.relative) {
node.canonicalDir = path.relative(
config.cwd,
node.canonicalDir
);
}
if (options.paths) {
node.canonicalDir = normalize(node.canonicalDir);
}
},
true
);
// Note that we need to to parse the flattened tree because it might
// contain additional packages
mout.object.forOwn(flattened, function (node) {
mout.object.forOwn(flattened, function(node) {
if (node.missing) {
return;
}
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);
@@ -66,20 +70,10 @@ function list(options, config) {
}
// Check for new versions
return checkVersions(project, tree, logger)
.then(function () {
return checkVersions(project, tree, logger).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) {
@@ -88,32 +82,40 @@ function checkVersions(project, tree, logger) {
var repository = project.getPackageRepository();
// Gather all nodes, ignoring linked nodes
project.walkTree(tree, function (node) {
if (!node.linked) {
nodes.push(node);
}
}, true);
project.walkTree(
tree,
function(node) {
if (!node.linked) {
nodes.push(node);
}
},
true
);
if (nodes.length) {
logger.info('check-new', 'Checking for new versions of the project dependencies..');
logger.info(
'check-new',
'Checking for new versions of the project dependencies...'
);
}
// Check for new versions for each node
promises = nodes.map(function (node) {
promises = nodes.map(function(node) {
var target = node.endpoint.target;
return repository.versions(node.endpoint.source)
.then(function (versions) {
node.versions = versions;
return repository
.versions(node.endpoint.source)
.then(function(versions) {
node.versions = versions;
// Do not check if node's target is not a valid semver one
if (versions.length && semver.validRange(target)) {
node.update = {
target: semver.maxSatisfying(versions, target),
latest: semver.maxSatisfying(versions, '*')
};
}
});
// Do not check if node's target is not a valid semver one
if (versions.length && semver.validRange(target)) {
node.update = {
target: semver.maxSatisfying(versions, target),
latest: semver.maxSatisfying(versions, '*')
};
}
});
});
// Set the versions also for the root node
@@ -125,7 +127,7 @@ function checkVersions(project, tree, logger) {
function paths(flattened) {
var ret = {};
mout.object.forOwn(flattened, function (pkg, name) {
mout.object.forOwn(flattened, function(pkg, name) {
var main;
if (pkg.missing) {
@@ -146,7 +148,7 @@ function paths(flattened) {
}
// Concatenate each main entry with the canonical dir
main = main.map(function (part) {
main = main.map(function(part) {
return normalize(path.join(pkg.canonicalDir, part).trim());
});
@@ -164,20 +166,20 @@ 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({
'paths': { type: Boolean, shorthand: 'p' },
'relative': { type: Boolean, shorthand: 'r' }
}, argv);
};
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;

155
lib/commands/login.js Normal file
View File

@@ -0,0 +1,155 @@
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);
logger.info(
'EAUTH',
'Logged in as ' + configstore.get('username'),
{}
);
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);
logger.info(
'EAUTH',
'Logged in as ' + configstore.get('username'),
{}
);
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;

View File

@@ -1,56 +1,37 @@
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 PackageRepository = require('../core/PackageRepository');
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);
config.cache = config.storage.registry;
config = defaultConfig(config);
registryClient = new RegistryClient(config, logger);
var repository = new PackageRepository(config, logger);
var registryClient = repository.getRegistryClient();
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
return !entry ? null : {
name: name,
url: entry && entry.url
};
})
.done(function (result) {
logger.emit('end', result);
}, function (error) {
logger.emit('error', error);
});
return logger;
return Q.nfcall(registryClient.lookup.bind(registryClient), name).then(
function(entry) {
return !entry
? null
: {
name: name,
url: entry.url
};
}
);
}
// -------------------
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;

View File

@@ -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) {
@@ -27,42 +17,44 @@ function clean(project, options, removed) {
// Continually call clean until there is no more extraneous
// dependencies to remove
return project.getTree(options)
.spread(function (tree, flattened, extraneous) {
var names = extraneous.map(function (extra) {
return extra.endpoint.name;
});
return project
.getTree(options)
.spread(function(tree, flattened, extraneous) {
var names = extraneous.map(function(extra) {
return extra.endpoint.name;
});
// Uninstall extraneous
return project.uninstall(names, options)
.then(function (uninstalled) {
// Are we done?
if (!mout.object.size(uninstalled)) {
return removed;
}
// Uninstall extraneous
return project
.uninstall(names, options)
.then(function(uninstalled) {
// Are we done?
if (!mout.object.size(uninstalled)) {
return removed;
}
// Not yet, recurse!
mout.object.mixIn(removed, uninstalled);
return clean(project, options, removed);
// Not yet, recurse!
mout.object.mixIn(removed, uninstalled);
return 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({
'production': { type: Boolean, shorthand: 'p' },
}, argv);
};
var options = cli.readOptions(
{
production: { type: Boolean, shorthand: 'p' }
},
argv
);
prune.completion = function () {
// TODO:
delete options.argv;
return [options];
};
module.exports = prune;

View File

@@ -1,59 +1,51 @@
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, source, config) {
var repository;
var registryClient;
var tracker;
var logger = new Logger();
var force;
var url;
var githubSourceRegex = /^\w[\w-]*\/\w[\w-]*$/;
var getGithubUrl = function(source) {
return 'git@github.com:' + source + '.git';
};
config = mout.object.deepFillIn(config || {}, defaultConfig);
config = defaultConfig(config);
force = config.force;
tracker = new Tracker(config);
name = (name || '').trim();
source = (source || '').trim();
url = source.match(githubSourceRegex) ? getGithubUrl(source) : source;
// 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
// As such, we attempt to convert URLs as necessary
if (config.registry.register === Config.DEFAULT_REGISTRY) {
url = convertUrl(url, logger);
if (!mout.string.startsWith(url, 'git://')) {
return logger.emit('error', createError('The registry only accepts URLs starting with git://', 'EINVFORMAT'));
}
}
tracker.track('register');
// 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) {
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');
throw createError(
'The package you are trying to register is marked as private',
'EPRIV'
);
}
// If non interactive or user forced, bypass confirmation
@@ -64,12 +56,14 @@ function register(name, url, config) {
// 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?',
message:
'Registering a package will make it installable via the registry (' +
chalk.cyan.underline(config.registry.register) +
'), continue?',
default: true
});
})
.then(function (result) {
.then(function(result) {
// If user response was negative, abort
if (!result) {
return;
@@ -83,55 +77,24 @@ function register(name, url, config) {
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);
return Q.nfcall(
registryClient.register.bind(registryClient),
name,
url
);
});
});
return logger;
}
function convertUrl(url, logger) {
var pair;
var newUrl;
if (!mout.string.startsWith(url, 'git://')) {
// Convert GitHub ssh & https to git://
pair = GitHubResolver.getOrgRepoPair(url);
if (pair) {
newUrl = 'git://github.com/' + pair.org + '/' + pair.repo + '.git';
logger.warn('convert', 'Converted ' + url + ' to ' + newUrl);
}
}
return newUrl || url;
}
// -------------------
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;

View File

@@ -1,55 +1,39 @@
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 PackageRepository = require('../core/PackageRepository');
var defaultConfig = require('../config');
var cli = require('../util/cli');
var createError = require('../util/createError');
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.cache = config.storage.registry;
config = defaultConfig(config);
registryClient = new RegistryClient(config, logger);
tracker = new Tracker(config);
tracker.track('search', name);
var repository = new PackageRepository(config, logger);
var registryClient = repository.getRegistryClient();
// If no name was specified, list all packages
if (!name) {
promise = Q.nfcall(registryClient.list.bind(registryClient));
// Otherwise search it
if (name) {
return Q.nfcall(registryClient.search.bind(registryClient), name);
} else {
promise = Q.nfcall(registryClient.search.bind(registryClient), name);
// List all packages when in interactive mode + json enabled, and
// always when in non-interactive mode
if (config.interactive && !config.json) {
throw createError('no parameter to bower search', 'EREADOPTIONS');
}
return Q.nfcall(registryClient.list.bind(registryClient));
}
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 options = cli.readOptions(argv);
var terms = options.argv.remain.slice(1);
search.options = function (argv) {
return cli.readOptions(argv);
};
var name = terms.join(' ');
search.completion = function () {
// TODO:
return [name];
};
module.exports = search;

View File

@@ -1,79 +1,75 @@
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)
.spread(function (tree, flattened) {
return project.getTree(options).spread(function(tree, flattened) {
// Uninstall nodes
return project.uninstall(names, options)
// Clean out non-shared uninstalled dependencies
.then(function (uninstalled) {
var names = Object.keys(uninstalled);
var children = [];
return (
project
.uninstall(names, options)
// Clean out non-shared uninstalled dependencies
.then(function(uninstalled) {
var names = Object.keys(uninstalled);
var children = [];
// Grab the dependencies of packages that were uninstalled
mout.object.forOwn(flattened, function (node) {
if (names.indexOf(node.endpoint.name) !== -1) {
children.push.apply(children, mout.object.keys(node.dependencies));
}
});
// Grab the dependencies of packages that were uninstalled
mout.object.forOwn(flattened, function(node) {
if (names.indexOf(node.endpoint.name) !== -1) {
children.push.apply(
children,
mout.object.keys(node.dependencies)
);
}
});
// 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);
// Clean them!
return clean(project, children, uninstalled);
})
);
});
return logger;
}
function clean(project, names, removed) {
removed = removed || {};
return project.getTree()
.spread(function (tree, flattened) {
return project.getTree().spread(function(tree, flattened) {
var nodes = [];
var dependantsCounter = {};
// Grab the nodes of each specified name
mout.object.forOwn(flattened, function (node) {
mout.object.forOwn(flattened, function(node) {
if (names.indexOf(node.endpoint.name) !== -1) {
nodes.push(node);
}
});
// Walk the down the tree, gathering dependants of the packages
project.walkTree(tree, function (node, nodeName) {
if (names.indexOf(nodeName) !== -1) {
dependantsCounter[nodeName] = dependantsCounter[nodeName] || 0;
dependantsCounter[nodeName] += node.nrDependants;
}
}, true);
project.walkTree(
tree,
function(node, nodeName) {
if (names.indexOf(nodeName) !== -1) {
dependantsCounter[nodeName] =
dependantsCounter[nodeName] || 0;
dependantsCounter[nodeName] += node.nrDependants;
}
},
true
);
// Filter out those that have no dependants
nodes = nodes.filter(function (node) {
nodes = nodes.filter(function(node) {
return !dependantsCounter[node.endpoint.name];
});
@@ -83,52 +79,54 @@ function clean(project, names, removed) {
}
// Grab the nodes after filtering
names = nodes.map(function (node) {
names = nodes.map(function(node) {
return node.endpoint.name;
});
// Uninstall them
return project.uninstall(names)
// Clean out non-shared uninstalled dependencies
.then(function (uninstalled) {
var children;
return (
project
.uninstall(names)
// Clean out non-shared uninstalled dependencies
.then(function(uninstalled) {
var children;
mout.object.mixIn(removed, uninstalled);
mout.object.mixIn(removed, uninstalled);
// Grab the dependencies of packages that were uninstalled
children = [];
nodes.forEach(function (node) {
children.push.apply(children, mout.object.keys(node.dependencies));
});
// Grab the dependencies of packages that were uninstalled
children = [];
nodes.forEach(function(node) {
children.push.apply(
children,
mout.object.keys(node.dependencies)
);
});
// Recurse!
return clean(project, children, removed);
});
// Recurse!
return clean(project, children, removed);
})
);
});
}
// -------------------
uninstall.line = function (argv) {
var options = uninstall.options(argv);
uninstall.readOptions = function(argv) {
var cli = require('../util/cli');
var options = cli.readOptions(
{
save: { type: Boolean, shorthand: 'S' },
'save-dev': { type: Boolean, shorthand: 'D' }
},
argv
);
var names = options.argv.remain.slice(1);
if (!names.length) {
return null;
}
delete options.argv;
return uninstall(names, options);
};
uninstall.options = function (argv) {
return cli.readOptions({
'save': { type: Boolean, shorthand: 'S' },
'save-dev': { type: Boolean, shorthand: 'D' }
}, argv);
};
uninstall.completion = function () {
// TODO:
return [names, options];
};
module.exports = uninstall;

View File

@@ -0,0 +1,90 @@
var chalk = require('chalk');
var Q = require('q');
var defaultConfig = require('../config');
var PackageRepository = require('../core/PackageRepository');
var createError = require('../util/createError');
function unregister(logger, name, config) {
if (!name) {
return;
}
var repository;
var registryClient;
var force;
config = defaultConfig(config);
force = config.force;
// Bypass any cache
config.offline = false;
config.force = true;
// Trim name
name = name.trim();
repository = new PackageRepository(config, logger);
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) {
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;

View File

@@ -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,27 @@ 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({
'force-latest': { type: Boolean, shorthand: 'F' },
'production': { type: Boolean, shorthand: 'p' }
}, argv);
};
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;

View File

@@ -1,140 +1,210 @@
var mout = require('mout');
var semver = require('semver');
var Logger = require('bower-logger');
var which = require('which');
var fs = require('fs');
var which = require('../util/which');
var fs = require('../util/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 execFile = require('../util/childProcess').execFile;
var defaultConfig = require('../config');
var createError = require('../util/createError');
function version(versionArg, options, config) {
var project;
var logger = new Logger();
function version(logger, versionArg, options, config) {
options = options || {};
config = mout.object.deepFillIn(config || {}, defaultConfig);
project = new Project(config, logger);
config = defaultConfig(config);
bump(project, versionArg, options.message)
.done(function () {
logger.emit('end');
}, function (error) {
logger.emit('error', error);
});
return logger;
return bump(logger, config, versionArg, options.message);
}
function bump(project, versionArg, message) {
function bump(logger, config, versionArg, message) {
var cwd = config.cwd || process.cwd();
var newVersion;
var doGitCommit = false;
return checkGit()
.then(function (hasGit) {
doGitCommit = hasGit;
})
.then(project.getJson.bind(project))
.then(function (json) {
newVersion = getNewVersion(json.version, versionArg);
json.version = newVersion;
})
.then(project.saveJson.bind(project))
.then(function () {
if (doGitCommit) {
return gitCommitAndTag(newVersion, message);
}
})
.then(function () {
console.log('v' + newVersion);
});
}
function getNewVersion(currentVersion, versionArg) {
var newVersion = semver.valid(versionArg);
if (!newVersion) {
newVersion = semver.inc(currentVersion, versionArg);
if (!versionArg) {
throw createError('No <version> agrument provided', 'EREADOPTIONS');
}
if (!newVersion) {
throw createError('Invalid version argument: `' + versionArg + '`. Usage: `bower version [<newversion> | major | minor | patch]`', 'EINVALIDVERSION');
}
if (currentVersion === newVersion) {
throw createError('Version not changed', 'EVERSIONNOTCHANGED');
}
return newVersion;
return driver
.check(cwd)
.then(function() {
return Q.all([driver.versions(cwd), driver.currentVersion(cwd)]);
})
.spread(function(versions, currentVersion) {
currentVersion = currentVersion || '0.0.0';
if (semver.valid(versionArg)) {
newVersion = semver.valid(versionArg);
} else {
newVersion = semver.inc(currentVersion, versionArg);
if (!newVersion) {
throw createError(
'Invalid <version> argument: ' + versionArg,
'EINVALIDVERSION',
{ version: versionArg }
);
}
}
newVersion =
currentVersion[0] === 'v' ? 'v' + newVersion : newVersion;
if (versions) {
versions.forEach(function(version) {
if (semver.eq(version, newVersion)) {
throw createError(
'Version exists: ' + newVersion,
'EVERSIONEXISTS',
{ versions: versions, newVersion: newVersion }
);
}
});
}
return driver.bump(cwd, newVersion, message).then(function() {
return {
oldVersion: currentVersion,
newVersion: newVersion
};
});
})
.then(function(result) {
logger.info(
'version',
'Bumped package version from ' +
result.oldVersion +
' to ' +
result.newVersion,
result
);
return result.newVersion;
});
}
function checkGit() {
var gitDir = path.join(process.cwd(), '.git');
return Q.nfcall(fs.stat, gitDir)
.then(function (stat) {
if (stat.isDirectory()) {
return checkGitStatus();
var driver = {
check: function(cwd) {
function checkGit(cwd) {
var gitDir = path.join(cwd, '.git');
return Q.nfcall(fs.stat, gitDir).then(
function(stat) {
if (stat.isDirectory()) {
return checkGitStatus(cwd);
}
return false;
},
function() {
//Ignore not found .git directory
return false;
}
);
}
return false;
}, function () {
//Ignore not found .git directory
return false;
});
}
function checkGitStatus() {
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});
})
.then(function (value) {
var stdout = value[0];
var lines = filterModifiedStatusLines(stdout);
if (lines.length) {
throw createError('Git working directory not clean.\n' + lines.join('\n'), 'EWORKINGDIRECTORYDIRTY');
function checkGitStatus(cwd) {
return Q.nfcall(which, 'git')
.fail(function(err) {
err.code = 'ENOGIT';
throw err;
})
.then(function(gitPath) {
return Q.nfcall(
execFile,
gitPath,
['status', '--porcelain'],
{ env: process.env, cwd: cwd }
);
})
.then(function(value) {
var stdout = value[0];
var lines = filterModifiedStatusLines(stdout);
if (lines.length) {
throw createError(
'Version bump requires clean working directory',
'EWORKINGDIRECTORYDIRTY'
);
}
return true;
});
}
return true;
});
}
function filterModifiedStatusLines(stdout) {
return stdout.trim().split('\n')
.filter(function (line) {
return line.trim() && !line.match(/^\?\? /);
}).map(function (line) {
return line.trim();
});
}
function filterModifiedStatusLines(stdout) {
return stdout
.trim()
.split('\n')
.filter(function(line) {
return line.trim() && !line.match(/^\?\? /);
})
.map(function(line) {
return line.trim();
});
}
function gitCommitAndTag(newVersion, message) {
message = message || 'v' + newVersion;
message = message.replace(/%s/g, newVersion);
return Q.nfcall(execFile, 'git', ['add', 'bower.json'], {env: process.env})
.then(function () {
return Q.nfcall(execFile, 'git', ['commit', '-m', message], {env: process.env});
})
.then(function () {
return Q.nfcall(execFile, 'git', ['tag', newVersion, '-am', message], {env: process.env});
});
}
return checkGit(cwd).then(function(hasGit) {
if (!hasGit) {
throw createError(
'Version bump currently supports only git repositories',
'ENOTGITREPOSITORY'
);
}
});
},
versions: function(cwd) {
return Q.nfcall(execFile, 'git', ['tag'], {
env: process.env,
cwd: cwd
}).then(
function(res) {
var versions = res[0].split(/\r?\n/).filter(semver.valid);
// -------------------
return versions;
},
function() {
return [];
}
);
},
currentVersion: function(cwd) {
return Q.nfcall(execFile, 'git', ['describe', '--abbrev=0', '--tags'], {
env: process.env,
cwd: cwd
}).then(
function(res) {
var version = res[0].split(/\r?\n/).filter(semver.valid)[0];
version.line = function (argv) {
var options = version.options(argv);
return version(options.argv.remain[1], options);
return version;
},
function() {
return undefined;
}
);
},
bump: function(cwd, tag, message) {
message = message || tag;
message = message.replace(/%s/g, tag);
return Q.nfcall(
execFile,
'git',
['commit', '-m', message, '--allow-empty'],
{ env: process.env, cwd: cwd }
).then(function() {
return Q.nfcall(execFile, 'git', ['tag', tag, '-am', message], {
env: process.env,
cwd: cwd
});
});
}
};
version.options = function (argv) {
return cli.readOptions({
'message': { type: String, shorthand: 'm'}
}, argv);
version.readOptions = function(argv) {
var cli = require('../util/cli');
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;

View File

@@ -1,33 +1,63 @@
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 current;
// 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 || {};
return readCachedConfig(config.cwd || process.cwd(), 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, overwrites) {
current = bowerConfig.create(cwd).load(overwrites);
var config = current.toObject();
var configstore = new Configstore('bower-github').all;
object.mixIn(config, configstore);
// 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 restoreConfig() {
if (current) {
current.restore();
}
}
module.exports = config;
function resetCache() {
restoreConfig();
current = undefined;
}
module.exports = defaultConfig;
module.exports.restore = restoreConfig;
module.exports.reset = resetCache;

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,9 @@
var mout = require('mout');
var Q = require('q');
var RegistryClient = require('bower-registry-client');
var ResolveCache = require('./ResolveCache');
var resolverFactory = require('./resolverFactory');
var createError = require('../util/createError');
var RegistryClient = require('bower-registry-client');
function PackageRepository(config, logger) {
var registryOptions;
@@ -14,6 +14,7 @@ function PackageRepository(config, logger) {
// Instantiate the registry
registryOptions = mout.object.deepMixIn({}, this._config);
registryOptions.cache = this._config.storage.registry;
this._registryClient = new RegistryClient(registryOptions, logger);
// Instantiate the resolve cache
@@ -22,7 +23,7 @@ function PackageRepository(config, logger) {
// -----------------
PackageRepository.prototype.fetch = function (decEndpoint) {
PackageRepository.prototype.fetch = function(decEndpoint) {
var logger;
var that = this;
var isTargetable;
@@ -34,129 +35,192 @@ PackageRepository.prototype.fetch = function (decEndpoint) {
// used to fetch
logger = this._logger.geminate();
// Intercept all logs, adding additional information
logger.intercept(function (log) {
logger.intercept(function(log) {
that._extendLog(log, info);
});
// Get the appropriate resolver
return resolverFactory(decEndpoint, this._config, logger, this._registryClient)
// Decide if we retrieve from the cache or not
// Also decide if we validate the cached entry or not
.then(function (resolver) {
info.resolver = resolver;
isTargetable = resolver.constructor.isTargetable;
return (
this._getResolver(decEndpoint, logger)
// Decide if we retrieve from the cache or not
// Also decide if we validate the cached entry or not
.then(function(resolver) {
info.resolver = resolver;
isTargetable = resolver.constructor.isTargetable;
// If force flag is used, bypass cache
if (that._config.force) {
logger.action('resolve', resolver.getSource() + '#' + resolver.getTarget());
return that._resolve(resolver, logger);
}
// Note that we use the resolver methods to query the
// cache because transformations/normalisations can occur
return that._resolveCache.retrieve(resolver.getSource(), resolver.getTarget())
// Decide if we can use the one from the resolve cache
.spread(function (canonicalDir, pkgMeta) {
// If there's no package in the cache
if (!canonicalDir) {
// And the offline flag is passed, error out
if (that._config.offline) {
throw createError('No cached version for ' + resolver.getSource() + '#' + resolver.getTarget(), 'ENOCACHE', {
resolver: resolver
});
if (!resolver.isCacheable()) {
return that._resolve(resolver, logger);
}
// Otherwise, we have to resolve it
logger.info('not-cached', resolver.getSource() + (resolver.getTarget() ? '#' + resolver.getTarget() : ''));
logger.action('resolve', resolver.getSource() + '#' + resolver.getTarget());
return that._resolve(resolver, logger);
}
info.canonicalDir = canonicalDir;
info.pkgMeta = pkgMeta;
logger.info('cached', resolver.getSource() + (pkgMeta._release ? '#' + pkgMeta._release : ''));
// If offline flag is used, use directly the cached one
if (that._config.offline) {
return [canonicalDir, pkgMeta, isTargetable];
}
// Otherwise check for new contents
logger.action('validate', (pkgMeta._release ? pkgMeta._release + ' against ': '') +
resolver.getSource() + (resolver.getTarget() ? '#' + resolver.getTarget() : ''));
return resolver.hasNew(canonicalDir, pkgMeta)
.then(function (hasNew) {
// If there are no new contents, resolve to
// the cached one
if (!hasNew) {
return [canonicalDir, pkgMeta, isTargetable];
// 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);
}
// Otherwise resolve to the newest one
logger.info('new', 'version for ' + resolver.getSource() + '#' + resolver.getTarget());
logger.action('resolve', resolver.getSource() + '#' + resolver.getTarget());
// Note that we use the resolver methods to query the
// cache because transformations/normalisations can occur
return (
that._resolveCache
.retrieve(resolver.getSource(), resolver.getTarget())
// Decide if we can use the one from the resolve cache
.spread(function(canonicalDir, pkgMeta) {
// If there's no package in the cache
if (!canonicalDir) {
// And the offline flag is passed, error out
if (that._config.offline) {
throw createError(
'No cached version for ' +
resolver.getSource() +
'#' +
resolver.getTarget(),
'ENOCACHE',
{
resolver: resolver
}
);
}
return that._resolve(resolver, logger);
});
});
})
// If something went wrong, also extend the error
.fail(function (err) {
that._extendLog(err, info);
throw err;
});
// Otherwise, we have to resolve it
logger.info(
'not-cached',
resolver.getSource() +
(resolver.getTarget()
? '#' + resolver.getTarget()
: '')
);
logger.action(
'resolve',
resolver.getSource() +
'#' +
resolver.getTarget()
);
return that._resolve(resolver, logger);
}
info.canonicalDir = canonicalDir;
info.pkgMeta = pkgMeta;
logger.info(
'cached',
resolver.getSource() +
(pkgMeta._release
? '#' + pkgMeta._release
: '')
);
// If offline flag is used, use directly the cached one
if (that._config.offline) {
return [canonicalDir, pkgMeta, isTargetable];
}
// Otherwise check for new contents
logger.action(
'validate',
(pkgMeta._release
? pkgMeta._release + ' against '
: '') +
resolver.getSource() +
(resolver.getTarget()
? '#' + resolver.getTarget()
: '')
);
return resolver
.hasNew(pkgMeta)
.then(function(hasNew) {
// If there are no new contents, resolve to
// the cached one
if (!hasNew) {
return [
canonicalDir,
pkgMeta,
isTargetable
];
}
// Otherwise resolve to the newest one
logger.info(
'new',
'version for ' +
resolver.getSource() +
'#' +
resolver.getTarget()
);
logger.action(
'resolve',
resolver.getSource() +
'#' +
resolver.getTarget()
);
return that._resolve(resolver, logger);
});
})
);
})
// If something went wrong, also extend the error
.fail(function(err) {
that._extendLog(err, info);
throw err;
})
);
};
PackageRepository.prototype.versions = function (source) {
PackageRepository.prototype.versions = function(source) {
// Resolve the source using the factory because the
// source can actually be a registry name
return resolverFactory.getConstructor(source, this._config, this._registryClient)
.spread(function (ConcreteResolver, source) {
// If offline, resolve using the cached versions
if (this._config.offline) {
return this._resolveCache.versions(source);
}
return this._getResolver({ source: source }).then(
function(resolver) {
// If offline, resolve using the cached versions
if (this._config.offline) {
return this._resolveCache.versions(resolver.getSource());
}
// Otherwise, fetch remotely
return ConcreteResolver.versions(source);
}.bind(this));
// Otherwise, fetch remotely
return resolver.constructor.versions(resolver.getSource());
}.bind(this)
);
};
PackageRepository.prototype.eliminate = function (pkgMeta) {
PackageRepository.prototype.eliminate = function(pkgMeta) {
return Q.all([
this._resolveCache.eliminate(pkgMeta),
Q.nfcall(this._registryClient.clearCache.bind(this._registryClient), pkgMeta.name)
Q.nfcall(
this._registryClient.clearCache.bind(this._registryClient),
pkgMeta.name
)
]);
};
PackageRepository.prototype.clear = function () {
PackageRepository.prototype.clear = function() {
return Q.all([
this._resolveCache.clear(),
Q.nfcall(this._registryClient.clearCache.bind(this._registryClient))
]);
};
PackageRepository.prototype.reset = function () {
PackageRepository.prototype.reset = function() {
this._resolveCache.reset();
this._registryClient.resetCache();
};
PackageRepository.prototype.list = function () {
PackageRepository.prototype.list = function() {
return this._resolveCache.list();
};
PackageRepository.prototype.getRegistryClient = function () {
PackageRepository.prototype.getRegistryClient = function() {
return this._registryClient;
};
PackageRepository.prototype.getResolveCache = function () {
PackageRepository.prototype.getResolveCache = function() {
return this._resolveCache;
};
PackageRepository.clearRuntimeCache = function () {
PackageRepository.clearRuntimeCache = function() {
ResolveCache.clearRuntimeCache();
RegistryClient.clearRuntimeCache();
resolverFactory.clearRuntimeCache();
@@ -164,28 +228,59 @@ PackageRepository.clearRuntimeCache = function () {
// ---------------------
PackageRepository.prototype._resolve = function (resolver, logger) {
// Resolve the resolver
return resolver.resolve()
// Store in the cache
.then(function (canonicalDir) {
return this._resolveCache.store(canonicalDir, resolver.getPkgMeta());
}.bind(this))
// Resolve promise with canonical dir and package meta
.then(function (dir) {
var pkgMeta = resolver.getPkgMeta();
PackageRepository.prototype._getResolver = function(decEndpoint, logger) {
logger = logger || this._logger;
logger.info('resolved', resolver.getSource() + (pkgMeta._release ? '#' + pkgMeta._release : ''));
return [dir, pkgMeta, resolver.constructor.isTargetable()];
}.bind(this));
// Get the appropriate resolver
return resolverFactory(
decEndpoint,
{ config: this._config, logger: logger },
this._registryClient
);
};
PackageRepository.prototype._extendLog = function (log, info) {
PackageRepository.prototype._resolve = function(resolver, logger) {
var that = this;
// Resolve the resolver
return (
resolver
.resolve()
// Store in the cache
.then(function(canonicalDir) {
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()];
})
);
};
PackageRepository.prototype._extendLog = function(log, info) {
log.data = log.data || {};
// Store endpoint info in each log
if (info.decEndpoint) {
log.data.endpoint = mout.object.pick(info.decEndpoint, ['name', 'source', 'target']);
log.data.endpoint = mout.object.pick(info.decEndpoint, [
'name',
'source',
'target'
]);
}
// Store the resolver info in each log

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,15 @@
var fs = require('graceful-fs');
var fs = require('../util/fs');
var path = require('path');
var mout = require('mout');
var Q = require('q');
var mkdirp = require('mkdirp');
var rimraf = require('rimraf');
var rimraf = require('../util/rimraf');
var LRU = require('lru-cache');
var lockFile = require('lockfile');
var md5 = require('md5-hex');
var semver = require('../util/semver');
var readJson = require('../util/readJson');
var copy = require('../util/copy');
var md5 = require('../util/md5');
function ResolveCache(config) {
// TODO: Make some config entries, such as:
@@ -29,7 +29,7 @@ function ResolveCache(config) {
if (!this._cache) {
this._cache = new LRU({
max: 100,
maxAge: 60 * 5 * 1000 // 5 minutes
maxAge: 60 * 5 * 1000 // 5 minutes
});
this.constructor._cache.set(this._dir, this._cache);
}
@@ -40,7 +40,7 @@ function ResolveCache(config) {
// -----------------
ResolveCache.prototype.retrieve = function (source, target) {
ResolveCache.prototype.retrieve = function(source, target) {
var sourceId = md5(source);
var dir = path.join(this._dir, sourceId);
var that = this;
@@ -48,56 +48,57 @@ ResolveCache.prototype.retrieve = function (source, target) {
target = target || '*';
return this._getVersions(sourceId)
.spread(function (versions) {
var suitable;
.spread(function(versions) {
var suitable;
// If target is a semver, find a suitable version
if (semver.validRange(target)) {
suitable = semver.maxSatisfying(versions, target, true);
// If target is a semver, find a suitable version
if (semver.validRange(target)) {
suitable = semver.maxSatisfying(versions, target, true);
if (suitable) {
return suitable;
if (suitable) {
return suitable;
}
}
}
// If target is '*' check if there's a cached '_wildcard'
if (target === '*') {
return mout.array.find(versions, function (version) {
return version === '_wildcard';
// If target is '*' check if there's a cached '_wildcard'
if (target === '*') {
return mout.array.find(versions, function(version) {
return version === '_wildcard';
});
}
// Otherwise check if there's an exact match
return mout.array.find(versions, function(version) {
return version === target;
});
}
})
.then(function(version) {
var canonicalDir;
// Otherwise check if there's an exact match
return mout.array.find(versions, function (version) {
return version === target;
if (!version) {
return [];
}
// Resolve with canonical dir and package meta
canonicalDir = path.join(dir, encodeURIComponent(version));
return that._readPkgMeta(canonicalDir).then(
function(pkgMeta) {
return [canonicalDir, pkgMeta];
},
function() {
// If there was an error, invalidate the in-memory cache,
// delete the cached package and try again
that._cache.del(sourceId);
return Q.nfcall(rimraf, canonicalDir).then(function() {
return that.retrieve(source, target);
});
}
);
});
})
.then(function (version) {
var canonicalDir;
if (!version) {
return [];
}
// Resolve with canonical dir and package meta
canonicalDir = path.join(dir, encodeURIComponent(version));
return that._readPkgMeta(canonicalDir)
.then(function (pkgMeta) {
return [canonicalDir, pkgMeta];
}, function () {
// If there was an error, invalidate the in-memory cache,
// delete the cached package and try again
that._cache.del(sourceId);
return Q.nfcall(rimraf, canonicalDir)
.then(function () {
return that.retrieve(source, target);
});
});
});
};
ResolveCache.prototype.store = function (canonicalDir, pkgMeta) {
ResolveCache.prototype.store = function(canonicalDir, pkgMeta) {
var sourceId;
var release;
var dir;
@@ -108,70 +109,82 @@ ResolveCache.prototype.store = function (canonicalDir, pkgMeta) {
promise = pkgMeta ? Q.resolve(pkgMeta) : this._readPkgMeta(canonicalDir);
return promise
.then(function (pkgMeta) {
sourceId = md5(pkgMeta._source);
release = that._getPkgRelease(pkgMeta);
dir = path.join(that._dir, sourceId, release);
pkgLock = path.join(that._lockDir, sourceId + '-' + release + '.lock');
.then(function(pkgMeta) {
sourceId = md5(pkgMeta._source);
release = that._getPkgRelease(pkgMeta);
dir = path.join(that._dir, sourceId, release);
pkgLock = path.join(
that._lockDir,
sourceId + '-' + release + '.lock'
);
// Check if destination directory exists to prevent issuing lock at all times
return Q.nfcall(fs.stat, dir)
.fail(function (err) {
var lockParams = { wait: 250, retries: 25, stale: 60000 };
return Q.nfcall(lockFile.lock, pkgLock, lockParams).then(function () {
// Ensure other process didn't start copying files before lock was created
return Q.nfcall(fs.stat, dir)
.fail(function (err) {
// If stat fails, it is expected to return ENOENT
if (err.code !== 'ENOENT') {
throw err;
}
// Check if destination directory exists to prevent issuing lock at all times
return Q.nfcall(fs.stat, dir)
.fail(function(err) {
var lockParams = { wait: 250, retries: 25, stale: 60000 };
return Q.nfcall(lockFile.lock, pkgLock, lockParams)
.then(function() {
// Ensure other process didn't start copying files before lock was created
return Q.nfcall(fs.stat, dir).fail(function(err) {
// If stat fails, it is expected to return ENOENT
if (err.code !== 'ENOENT') {
throw err;
}
// Create missing directory and copy files there
return Q.nfcall(mkdirp, path.dirname(dir)).then(function () {
return Q.nfcall(fs.rename, canonicalDir, dir)
.fail(function (err) {
// If error is EXDEV it means that we are trying to rename
// across different drives, so we copy and remove it instead
if (err.code !== 'EXDEV') {
throw err;
}
// Create missing directory and copy files there
return Q.nfcall(mkdirp, path.dirname(dir)).then(
function() {
return Q.nfcall(
fs.rename,
canonicalDir,
dir
).fail(function(err) {
// If error is EXDEV it means that we are trying to rename
// across different drives, so we copy and remove it instead
if (err.code !== 'EXDEV') {
throw err;
}
return copy.copyDir(canonicalDir, dir);
return copy.copyDir(
canonicalDir,
dir
);
});
}
);
});
})
.finally(function() {
lockFile.unlockSync(pkgLock);
});
});
})
.finally(function() {
// Ensure no tmp dir is left on disk.
return Q.nfcall(rimraf, canonicalDir);
});
}).finally(function () {
lockFile.unlockSync(pkgLock);
});
}).finally(function () {
// Ensure no tmp dir is left on disk.
return Q.nfcall(rimraf, canonicalDir);
})
.then(function() {
var versions = that._cache.get(sourceId);
// Add it to the in memory cache
// and sort the versions afterwards
if (versions && versions.indexOf(release) === -1) {
versions.push(release);
that._sortVersions(versions);
}
// Resolve with the final location
return dir;
});
})
.then(function () {
var versions = that._cache.get(sourceId);
// Add it to the in memory cache
// and sort the versions afterwards
if (versions && versions.indexOf(release) === -1) {
versions.push(release);
that._sortVersions(versions);
}
// Resolve with the final location
return dir;
});
};
ResolveCache.prototype.eliminate = function (pkgMeta) {
ResolveCache.prototype.eliminate = function(pkgMeta) {
var sourceId = md5(pkgMeta._source);
var release = this._getPkgRelease(pkgMeta);
var dir = path.join(this._dir, sourceId, release);
var that = this;
return Q.nfcall(rimraf, dir)
.then(function () {
return Q.nfcall(rimraf, dir).then(function() {
var versions = that._cache.get(sourceId) || [];
mout.array.remove(versions, release);
@@ -182,8 +195,7 @@ ResolveCache.prototype.eliminate = function (pkgMeta) {
if (!versions.length) {
that._cache.del(sourceId);
return that._getVersions(sourceId)
.spread(function (versions) {
return that._getVersions(sourceId).spread(function(versions) {
if (!versions.length) {
// Do not keep in-memory cache if it's completely
// empty
@@ -196,125 +208,144 @@ ResolveCache.prototype.eliminate = function (pkgMeta) {
});
};
ResolveCache.prototype.clear = function () {
ResolveCache.prototype.clear = function() {
return Q.nfcall(rimraf, this._dir)
.then(function () {
return Q.nfcall(fs.mkdir, this._dir);
}.bind(this))
.then(function () {
this._cache.reset();
}.bind(this));
.then(
function() {
return Q.nfcall(fs.mkdir, this._dir);
}.bind(this)
)
.then(
function() {
this._cache.reset();
}.bind(this)
);
};
ResolveCache.prototype.reset = function () {
ResolveCache.prototype.reset = function() {
this._cache.reset();
return this;
};
ResolveCache.prototype.versions = function (source) {
ResolveCache.prototype.versions = function(source) {
var sourceId = md5(source);
return this._getVersions(sourceId)
.spread(function (versions) {
return versions.filter(function (version) {
return this._getVersions(sourceId).spread(function(versions) {
return versions.filter(function(version) {
return semver.valid(version);
});
});
};
ResolveCache.prototype.list = function () {
ResolveCache.prototype.list = function() {
var promises;
var dirs = [];
var that = this;
// Get the list of directories
return Q.nfcall(fs.readdir, this._dir)
.then(function (sourceIds) {
promises = sourceIds.map(function (sourceId) {
return Q.nfcall(fs.readdir, path.join(that._dir, sourceId))
.then(function (versions) {
versions.forEach(function (version) {
var dir = path.join(that._dir, sourceId, version);
dirs.push(dir);
return (
Q.nfcall(fs.readdir, this._dir)
.then(function(sourceIds) {
promises = sourceIds.map(function(sourceId) {
return Q.nfcall(
fs.readdir,
path.join(that._dir, sourceId)
).then(
function(versions) {
versions.forEach(function(version) {
var dir = path.join(
that._dir,
sourceId,
version
);
dirs.push(dir);
});
},
function(err) {
// Ignore lurking files, e.g.: .DS_Store if the user
// has navigated throughout the cache
if (err.code === 'ENOTDIR' && err.path) {
return Q.nfcall(rimraf, err.path);
}
throw err;
}
);
});
}, function (err) {
// Ignore lurking files, e.g.: .DS_Store if the user
// has navigated throughout the cache
if (err.code === 'ENOTDIR' && err.path) {
return Q.nfcall(rimraf, err.path);
}
throw err;
});
});
return Q.all(promises);
})
// Read every package meta
.then(function() {
promises = dirs.map(function(dir) {
return that._readPkgMeta(dir).then(
function(pkgMeta) {
return {
canonicalDir: dir,
pkgMeta: pkgMeta
};
},
function() {
// If it fails to read, invalidate the in memory
// cache for the source and delete the entry directory
var sourceId = path.basename(path.dirname(dir));
that._cache.del(sourceId);
return Q.all(promises);
})
// Read every package meta
.then(function () {
promises = dirs.map(function (dir) {
return that._readPkgMeta(dir)
.then(function (pkgMeta) {
return {
canonicalDir: dir,
pkgMeta: pkgMeta
};
}, function () {
// If it fails to read, invalidate the in memory
// cache for the source and delete the entry directory
var sourceId = path.basename(path.dirname(dir));
that._cache.del(sourceId);
return Q.nfcall(rimraf, dir);
}
);
});
return Q.nfcall(rimraf, dir);
});
});
return Q.all(promises);
})
// Sort by name ASC & release ASC
.then(function(entries) {
// Ignore falsy entries due to errors reading
// package metas
entries = entries.filter(function(entry) {
return !!entry;
});
return Q.all(promises);
})
// Sort by name ASC & release ASC
.then(function (entries) {
// Ignore falsy entries due to errors reading
// package metas
entries = entries.filter(function (entry) {
return !!entry;
});
return entries.sort(function(entry1, entry2) {
var pkgMeta1 = entry1.pkgMeta;
var pkgMeta2 = entry2.pkgMeta;
var comp = pkgMeta1.name.localeCompare(pkgMeta2.name);
return entries.sort(function (entry1, entry2) {
var pkgMeta1 = entry1.pkgMeta;
var pkgMeta2 = entry2.pkgMeta;
var comp = pkgMeta1.name.localeCompare(pkgMeta2.name);
// Sort by name
if (comp) {
return comp;
}
// Sort by name
if (comp) {
return comp;
}
// Sort by version
if (pkgMeta1.version && pkgMeta2.version) {
return semver.compare(
pkgMeta1.version,
pkgMeta2.version
);
}
if (pkgMeta1.version) {
return -1;
}
if (pkgMeta2.version) {
return 1;
}
// Sort by version
if (pkgMeta1.version && pkgMeta2.version) {
return semver.compare(pkgMeta1.version, pkgMeta2.version);
}
if (pkgMeta1.version) {
return -1;
}
if (pkgMeta2.version) {
return 1;
}
// Sort by target
return pkgMeta1._target.localeCompare(pkgMeta2._target);
});
});
// Sort by target
return pkgMeta1._target.localeCompare(pkgMeta2._target);
});
})
);
};
// ------------------------
ResolveCache.clearRuntimeCache = function () {
ResolveCache.clearRuntimeCache = function() {
// Note that _cache refers to the static _cache variable
// that holds other caches per dir!
// Do not confuse it with the instance cache
// Clear cache of each directory
this._cache.forEach(function (cache) {
this._cache.forEach(function(cache) {
cache.reset();
});
@@ -324,8 +355,10 @@ ResolveCache.clearRuntimeCache = function () {
// ------------------------
ResolveCache.prototype._getPkgRelease = function (pkgMeta) {
var release = pkgMeta.version || (pkgMeta._target === '*' ? '_wildcard' : pkgMeta._target);
ResolveCache.prototype._getPkgRelease = function(pkgMeta) {
var release =
pkgMeta.version ||
(pkgMeta._target === '*' ? '_wildcard' : pkgMeta._target);
// Encode some dangerous chars such as / and \
release = encodeURIComponent(release);
@@ -333,16 +366,15 @@ ResolveCache.prototype._getPkgRelease = function (pkgMeta) {
return release;
};
ResolveCache.prototype._readPkgMeta = function (dir) {
ResolveCache.prototype._readPkgMeta = function(dir) {
var filename = path.join(dir, '.bower.json');
return readJson(filename)
.spread(function (json) {
return readJson(filename).spread(function(json) {
return json;
});
};
ResolveCache.prototype._getVersions = function (sourceId) {
ResolveCache.prototype._getVersions = function(sourceId) {
var dir;
var versions = this._cache.get(sourceId);
var that = this;
@@ -352,29 +384,31 @@ ResolveCache.prototype._getVersions = function (sourceId) {
}
dir = path.join(this._dir, sourceId);
return Q.nfcall(fs.readdir, dir)
.then(function (versions) {
// Sort and cache in memory
that._sortVersions(versions);
versions = versions.map(decodeURIComponent);
that._cache.set(sourceId, versions);
return [versions, false];
}, function (err) {
// If the directory does not exists, resolve
// as an empty array
if (err.code === 'ENOENT') {
versions = [];
return Q.nfcall(fs.readdir, dir).then(
function(versions) {
// Sort and cache in memory
that._sortVersions(versions);
versions = versions.map(decodeURIComponent);
that._cache.set(sourceId, versions);
return [versions, false];
}
},
function(err) {
// If the directory does not exists, resolve
// as an empty array
if (err.code === 'ENOENT') {
versions = [];
that._cache.set(sourceId, versions);
return [versions, false];
}
throw err;
});
throw err;
}
);
};
ResolveCache.prototype._sortVersions = function (versions) {
ResolveCache.prototype._sortVersions = function(versions) {
// Sort DESC
versions.sort(function (version1, version2) {
versions.sort(function(version1, version2) {
var validSemver1 = semver.valid(version1);
var validSemver2 = semver.valid(version2);
@@ -400,7 +434,7 @@ ResolveCache.prototype._sortVersions = function (versions) {
ResolveCache._cache = new LRU({
max: 5,
maxAge: 60 * 30 * 1000 // 30 minutes
maxAge: 60 * 30 * 1000 // 30 minutes
});
module.exports = ResolveCache;

View File

@@ -1,170 +1,275 @@
var Q = require('q');
var fs = require('graceful-fs');
var fs = require('../util/fs');
var path = require('path');
var mout = require('mout');
var resolvers = require('./resolvers');
var createError = require('../util/createError');
var resolve = require('../util/resolve');
function createInstance(decEndpoint, config, logger, registryClient) {
return getConstructor(decEndpoint.source, config, registryClient)
.spread(function (ConcreteResolver, source, fromRegistry) {
var decEndpointCopy = mout.object.pick(decEndpoint, ['name', 'target']);
var pluginResolverFactory = require('./resolvers/pluginResolverFactory');
decEndpointCopy.source = source;
function createInstance(decEndpoint, options, registryClient) {
decEndpoint = mout.object.pick(decEndpoint, ['name', 'target', 'source']);
// Signal if it was fetched from the registry
if (fromRegistry) {
decEndpoint.registry = true;
// If no name was specified, assume the name from the registry
if (!decEndpointCopy.name) {
decEndpointCopy.name = decEndpoint.name = decEndpoint.source;
}
}
options.version = require('../version');
return new ConcreteResolver(decEndpointCopy, config, logger);
return getConstructor(decEndpoint, options, registryClient).spread(function(
ConcreteResolver,
decEndpoint
) {
return new ConcreteResolver(
decEndpoint,
options.config,
options.logger
);
});
}
function getConstructor(source, config, registryClient) {
var absolutePath,
promise;
function getConstructor(decEndpoint, options, registryClient) {
var source = decEndpoint.source;
var config = options.config;
// Below we try a series of async tests to guess the type of resolver to use
// If a step was unable to guess the resolver, it returns undefined
// If a step can guess the resolver, it returns with constructor of resolver
var promise = Q.resolve();
var addResolver = function(resolverFactory) {
promise = promise.then(function(result) {
if (result === undefined) {
return resolverFactory(decEndpoint, options);
} else {
return result;
}
});
};
// Plugin resolvers.
//
// It requires each resolver defined in config.resolvers and calls
// its "match" to check if given resolves supports given decEndpoint
addResolver(function() {
var selectedResolver;
var resolverNames;
if (Array.isArray(config.resolvers)) {
resolverNames = config.resolvers;
} else if (!!config.resolvers) {
resolverNames = config.resolvers.split(',');
} else {
resolverNames = [];
}
var resolverPromises = resolverNames.map(function(resolverName) {
var resolver = resolvers[resolverName];
if (resolver === undefined) {
var resolverPath = resolve(resolverName, { cwd: config.cwd });
if (resolverPath === undefined) {
throw createError(
'Bower resolver not found: ' + resolverName,
'ENORESOLVER'
);
}
resolver = pluginResolverFactory(
require(resolverPath),
options
);
}
return function() {
if (selectedResolver === undefined) {
var match = resolver.match.bind(resolver);
return Q.fcall(match, source).then(function(result) {
if (result) {
return (selectedResolver = resolver);
}
});
} else {
return selectedResolver;
}
};
});
return resolverPromises
.reduce(Q.when, new Q(undefined))
.then(function(resolver) {
if (resolver) {
return Q.fcall(
resolver.locate.bind(resolver),
decEndpoint.source
).then(function(result) {
if (result && result !== decEndpoint.source) {
decEndpoint.source = result;
decEndpoint.registry = true;
return getConstructor(
decEndpoint,
options,
registryClient
);
} else {
return [resolver, decEndpoint];
}
});
}
});
});
// Git case: git git+ssh, git+http, git+https
// .git at the end (probably ssh shorthand)
// git@ at the start
if (/^git(\+(ssh|https?))?:\/\//i.test(source) || /\.git\/?$/i.test(source) || /^git@/i.test(source)) {
source = source.replace(/^git\+/, '');
return Q.fcall(function () {
addResolver(function() {
if (
/^git(\+(ssh|https?))?:\/\//i.test(source) ||
/\.git\/?$/i.test(source) ||
/^git@/i.test(source)
) {
decEndpoint.source = source.replace(/^git\+/, '');
// If it's a GitHub repository, return the specialized resolver
if (resolvers.GitHub.getOrgRepoPair(source)) {
return [resolvers.GitHub, source];
return [resolvers.GitHub, decEndpoint];
}
return [resolvers.GitRemote, source];
});
}
return [resolvers.GitRemote, decEndpoint];
}
});
// SVN case: svn, svn+ssh, svn+http, svn+https, svn+file
if (/^svn(\+(ssh|https?|file))?:\/\//i.test(source)) {
return Q.fcall(function () {
return [resolvers.Svn, source];
});
}
addResolver(function() {
if (/^svn(\+(ssh|https?|file))?:\/\//i.test(source)) {
return [resolvers.Svn, decEndpoint];
}
});
// URL case
if (/^https?:\/\//i.exec(source)) {
return Q.fcall(function () {
return [resolvers.Url, source];
});
}
// Below we try a series of async tests to guess the type of resolver to use
// If a step was unable to guess the resolver, it throws an error
// If a step was able to guess the resolver, it resolves with a function
// That function returns a promise that will resolve with the concrete type
addResolver(function() {
if (/^https?:\/\//i.exec(source)) {
return [resolvers.Url, decEndpoint];
}
});
// If source is ./ or ../ or an absolute path
absolutePath = path.resolve(config.cwd, source);
if (/^\.\.?[\/\\]/.test(source) || /^~\//.test(source) || path.normalize(source).replace(/[\/\\]+$/, '') === absolutePath) {
promise = Q.nfcall(fs.stat, path.join(absolutePath, '.git'))
.then(function (stats) {
if (stats.isDirectory()) {
return function () {
return Q.resolve([resolvers.GitFs, absolutePath]);
};
}
addResolver(function() {
var absolutePath = path.resolve(config.cwd, source);
throw new Error('Not a Git repository');
})
// If not, check if source is a valid Subversion repository
.fail(function () {
return Q.nfcall(fs.stat, path.join(absolutePath, '.svn'))
.then(function (stats) {
if (stats.isDirectory()) {
return function () {
return Q.resolve([resolvers.Svn, absolutePath]);
};
}
if (
/^\.\.?[\/\\]/.test(source) ||
/^~\//.test(source) ||
path.normalize(source).replace(/[\/\\]+$/, '') === absolutePath
) {
return (
Q.nfcall(fs.stat, path.join(absolutePath, '.git'))
.then(function(stats) {
decEndpoint.source = absolutePath;
throw new Error('Not a Subversion repository');
});
})
// If not, check if source is a valid file/folder
.fail(function () {
return Q.nfcall(fs.stat, absolutePath)
.then(function () {
return function () {
return Q.resolve([resolvers.Fs, absolutePath]);
};
});
});
} else {
promise = Q.reject(new Error('Not an absolute or relative file'));
}
if (stats.isDirectory()) {
return Q.resolve([resolvers.GitFs, decEndpoint]);
}
throw new Error('Not a Git repository');
})
// If not, check if source is a valid Subversion repository
.fail(function() {
return Q.nfcall(
fs.stat,
path.join(absolutePath, '.svn')
).then(function(stats) {
decEndpoint.source = absolutePath;
if (stats.isDirectory()) {
return Q.resolve([resolvers.Svn, decEndpoint]);
}
throw new Error('Not a Subversion repository');
});
})
// If not, check if source is a valid file/folder
.fail(function() {
return Q.nfcall(fs.stat, absolutePath).then(function() {
decEndpoint.source = absolutePath;
return Q.resolve([resolvers.Fs, decEndpoint]);
});
})
);
}
});
return promise
// Check if is a shorthand and expand it
.fail(function (err) {
var parts;
addResolver(function() {
// Check if the shorthandResolver is falsy
if (!config.shorthandResolver) {
return;
}
// Skip ssh and/or URL with auth
if (/[:@]/.test(source)) {
throw err;
return;
}
// Ensure exactly only one "/"
parts = source.split('/');
var parts = source.split('/');
if (parts.length === 2) {
source = mout.string.interpolate(config.shorthandResolver, {
shorthand: source,
owner: parts[0],
package: parts[1]
});
return function () {
return getConstructor(source, config, registryClient);
};
}
throw err;
})
// As last resort, we try the registry
.fail(function (err) {
if (!registryClient) {
throw err;
}
return function () {
return Q.nfcall(registryClient.lookup.bind(registryClient), source)
.then(function (entry) {
if (!entry) {
throw createError('Package ' + source + ' not found', 'ENOTFOUND');
decEndpoint.source = mout.string.interpolate(
config.shorthandResolver,
{
shorthand: source,
owner: parts[0],
package: parts[1]
}
);
// TODO: Handle entry.type.. for now it's only 'alias'
// When we got published packages, this needs to be adjusted
source = entry.url;
return getConstructor(source, config, registryClient)
.spread(function (ConcreteResolver, source) {
return [ConcreteResolver, source, true];
});
});
};
})
// If we got the function, simply call and return
.then(function (func) {
return func();
// Finally throw a meaningful error
}, function () {
throw createError('Could not find appropriate resolver for ' + source, 'ENORESOLVER');
return getConstructor(decEndpoint, options, registryClient);
}
});
// As last resort, we try the registry
addResolver(function() {
if (!registryClient) {
return;
}
return Q.nfcall(
registryClient.lookup.bind(registryClient),
source
).then(function(entry) {
if (!entry) {
throw createError(
'Package ' + source + ' not found',
'ENOTFOUND'
);
}
decEndpoint.registry = true;
if (!decEndpoint.name) {
decEndpoint.name = decEndpoint.source;
}
decEndpoint.source = entry.url;
return getConstructor(decEndpoint, options);
});
});
addResolver(function() {
throw createError(
'Could not find appropriate resolver for ' + source,
'ENORESOLVER'
);
});
return promise;
}
function clearRuntimeCache() {
mout.object.values(resolvers).forEach(function (ConcreteResolver) {
mout.object.values(resolvers).forEach(function(ConcreteResolver) {
ConcreteResolver.clearRuntimeCache();
});
}

View File

@@ -1,5 +1,5 @@
var util = require('util');
var fs = require('graceful-fs');
var fs = require('../../util/fs');
var path = require('path');
var mout = require('mout');
var Q = require('q');
@@ -17,13 +17,19 @@ function FsResolver(decEndpoint, config, logger) {
// If target was specified, simply reject the promise
if (this._target !== '*') {
throw createError('File system sources can\'t resolve targets', 'ENORESTARGET');
throw createError(
"File system sources can't resolve targets",
'ENORESTARGET'
);
}
// If the name was guessed
if (this._guessedName) {
// Remove extension
this._name = this._name.substr(0, this._name.length - path.extname(this._name).length);
this._name = this._name.substr(
0,
this._name.length - path.extname(this._name).length
);
}
}
@@ -32,7 +38,7 @@ mout.object.mixIn(FsResolver, Resolver);
// -----------------
FsResolver.isTargetable = function () {
FsResolver.isTargetable = function() {
return false;
};
@@ -42,19 +48,18 @@ FsResolver.isTargetable = function () {
// TODO: There's room for improvement by using streams if the source
// is an archive file, by piping read stream to the zip extractor
// This will likely increase the complexity of code but might worth it
FsResolver.prototype._resolve = function () {
FsResolver.prototype._resolve = function() {
return this._copy()
.then(this._extract.bind(this))
.then(this._rename.bind(this));
.then(this._extract.bind(this))
.then(this._rename.bind(this));
};
// -----------------
FsResolver.prototype._copy = function () {
FsResolver.prototype._copy = function() {
var that = this;
return Q.nfcall(fs.stat, this._source)
.then(function (stat) {
return Q.nfcall(fs.stat, this._source).then(function(stat) {
var dst;
var copyOpts;
var promise;
@@ -68,22 +73,24 @@ FsResolver.prototype._copy = function () {
// Read the bower.json inside the folder, so that we
// copy only the necessary files if it has ignore specified
promise = that._readJson(that._source)
.then(function (json) {
copyOpts.ignore = json.ignore;
return copy.copyDir(that._source, dst, copyOpts);
})
.then(function () {
// Resolve to null because it's a dir
return;
});
// Else it's a file
promise = that
._readJson(that._source)
.then(function(json) {
copyOpts.ignore = json.ignore;
return copy.copyDir(that._source, dst, copyOpts);
})
.then(function() {
// Resolve to null because it's a dir
return;
});
// Else it's a file
} else {
dst = path.join(that._tempDir, path.basename(that._source));
promise = copy.copyFile(that._source, dst, copyOpts)
.then(function () {
return dst;
});
promise = copy
.copyFile(that._source, dst, copyOpts)
.then(function() {
return dst;
});
}
that._logger.action('copy', that._source, {
@@ -95,7 +102,7 @@ FsResolver.prototype._copy = function () {
});
};
FsResolver.prototype._extract = function (file) {
FsResolver.prototype._extract = function(file) {
if (!file || !extract.canExtract(file)) {
return Q.resolve();
}
@@ -108,30 +115,34 @@ FsResolver.prototype._extract = function (file) {
return extract(file, this._tempDir);
};
FsResolver.prototype._rename = function () {
return Q.nfcall(fs.readdir, this._tempDir)
.then(function (files) {
var file;
var oldPath;
var newPath;
FsResolver.prototype._rename = function() {
return Q.nfcall(fs.readdir, this._tempDir).then(
function(files) {
var file;
var oldPath;
var newPath;
// Remove any OS specific files from the files array
// before checking its length
files = files.filter(junk.isnt);
// Remove any OS specific files from the files array
// before checking its length
files = files.filter(junk.isnt);
// Only rename if there's only one file and it's not the json
if (files.length === 1 && !/^(bower|component)\.json$/.test(files[0])) {
file = files[0];
this._singleFile = 'index' + path.extname(file);
oldPath = path.join(this._tempDir, file);
newPath = path.join(this._tempDir, this._singleFile);
// Only rename if there's only one file and it's not the json
if (
files.length === 1 &&
!/^(bower|component)\.json$/.test(files[0])
) {
file = files[0];
this._singleFile = 'index' + path.extname(file);
oldPath = path.join(this._tempDir, file);
newPath = path.join(this._tempDir, this._singleFile);
return Q.nfcall(fs.rename, oldPath, newPath);
}
}.bind(this));
return Q.nfcall(fs.rename, oldPath, newPath);
}
}.bind(this)
);
};
FsResolver.prototype._savePkgMeta = function (meta) {
FsResolver.prototype._savePkgMeta = function(meta) {
// Store main if is a single file
if (this._singleFile) {
meta.main = this._singleFile;

View File

@@ -19,31 +19,52 @@ mout.object.mixIn(GitFsResolver, GitResolver);
// -----------------
// Override the checkout function to work with the local copy
GitFsResolver.prototype._checkout = function () {
GitFsResolver.prototype._checkout = function() {
var resolution = this._resolution;
// The checkout process could be similar to the GitRemoteResolver by prepending file:// to the source
// But from my performance measures, it's faster to copy the folder and just checkout in there
this._logger.action('checkout', resolution.tag || resolution.branch || resolution.commit, {
resolution: resolution,
to: this._tempDir
});
this._logger.action(
'checkout',
resolution.tag || resolution.branch || resolution.commit,
{
resolution: resolution,
to: this._tempDir
}
);
// Copy files to the temporary directory first
return this._copy()
.then(cmd.bind(cmd, 'git', ['checkout', '-f', resolution.tag || resolution.branch || resolution.commit], { cwd: this._tempDir }))
// Cleanup unstaged files
.then(cmd.bind(cmd, 'git', ['clean', '-f', '-d'], { cwd: this._tempDir }));
return (
this._copy()
.then(
cmd.bind(
cmd,
'git',
[
'checkout',
'-f',
resolution.tag || resolution.branch || resolution.commit
],
{ cwd: this._tempDir }
)
)
// Cleanup unstaged files
.then(
cmd.bind(cmd, 'git', ['clean', '-f', '-d'], {
cwd: this._tempDir
})
)
);
};
GitFsResolver.prototype._copy = function () {
GitFsResolver.prototype._copy = function() {
return copy.copyDir(this._source, this._tempDir);
};
// -----------------
// Grab refs locally
GitFsResolver.refs = function (source) {
GitFsResolver.refs = function(source) {
var value;
// TODO: Normalize source because of the various available protocols?
@@ -52,20 +73,24 @@ GitFsResolver.refs = function (source) {
return Q.resolve(value);
}
value = cmd('git', ['show-ref', '--tags', '--heads'], { cwd : source })
.spread(function (stdout) {
var refs;
value = cmd('git', ['show-ref', '--tags', '--heads'], {
cwd: source
}).spread(
function(stdout) {
var refs;
refs = stdout.toString()
.trim() // Trim trailing and leading spaces
.replace(/[\t ]+/g, ' ') // Standardize spaces (some git versions make tabs, other spaces)
.split(/[\r\n]+/); // Split lines into an array
refs = stdout
.toString()
.trim() // Trim trailing and leading spaces
.replace(/[\t ]+/g, ' ') // Standardize spaces (some git versions make tabs, other spaces)
.split(/[\r\n]+/); // Split lines into an array
// Update the refs with the actual refs
this._cache.refs.set(source, refs);
// Update the refs with the actual refs
this._cache.refs.set(source, refs);
return refs;
}.bind(this));
return refs;
}.bind(this)
);
// Store the promise to be reused until it resolves
// to a specific value

View File

@@ -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');
@@ -28,13 +29,13 @@ function GitHubResolver(decEndpoint, config, logger) {
this._source += '.git';
}
// Check if it's public
this._public = mout.string.startsWith(this._source, 'git://');
// Use https:// rather than git:// (PR #2611)
this._source = this._source.replace('git://', 'https://');
// Use https:// rather than git:// if on a proxy
if (this._config.proxy || this._config.httpsProxy) {
this._source = this._source.replace('git://', 'https://');
}
// Enable shallow clones for GitHub repos
this._shallowClone = function() {
return Q.resolve(true);
};
}
util.inherits(GitHubResolver, GitRemoteResolver);
@@ -42,15 +43,21 @@ mout.object.mixIn(GitHubResolver, GitRemoteResolver);
// -----------------
GitHubResolver.prototype._checkout = function () {
// Only fully works with public repositories and tags
// Could work with https/ssh protocol but not with 100% certainty
if (!this._public || !this._resolution.tag) {
return GitRemoteResolver.prototype._checkout.call(this);
}
GitHubResolver.prototype._checkout = function() {
var msg;
var tarballUrl = 'https://github.com/' + this._org + '/' + this._repo + '/archive/' + this._resolution.tag + '.tar.gz';
var name =
this._resolution.tag ||
this._resolution.branch ||
this._resolution.commit;
var tarballUrl =
'https://github.com/' +
this._org +
'/' +
this._repo +
'/archive/' +
name +
'.tar.gz';
var file = path.join(this._tempDir, 'archive.tar.gz');
var reqHeaders = {};
var that = this;
@@ -66,60 +73,93 @@ GitHubResolver.prototype._checkout = function () {
// Download tarball
return download(tarballUrl, file, {
proxy: this._config.httpsProxy,
ca: this._config.ca.default,
strictSSL: this._config.strictSsl,
timeout: this._config.timeout,
headers: reqHeaders
})
.progress(function (state) {
// Retry?
if (state.retry) {
msg = 'Download of ' + tarballUrl + ' failed with ' + state.error.code + ', ';
msg += 'retrying in ' + (state.delay / 1000).toFixed(1) + 's';
that._logger.debug('error', state.error.message, { error: state.error });
return that._logger.warn('retry', msg);
}
.progress(function(state) {
// Retry?
if (state.retry) {
msg =
'Download of ' +
tarballUrl +
' failed with ' +
state.error.code +
', ';
msg += 'retrying in ' + (state.delay / 1000).toFixed(1) + 's';
that._logger.debug('error', state.error.message, {
error: state.error
});
return that._logger.warn('retry', msg);
}
// Progress
msg = 'received ' + (state.received / 1024 / 1024).toFixed(1) + 'MB';
if (state.total) {
msg += ' of ' + (state.total / 1024 / 1024).toFixed(1) + 'MB downloaded, ';
msg += state.percent + '%';
}
that._logger.info('progress', msg);
})
.then(function () {
// Extract archive
that._logger.action('extract', path.basename(file), {
archive: file,
to: that._tempDir
});
// Progress
msg =
'received ' + (state.received / 1024 / 1024).toFixed(1) + 'MB';
if (state.total) {
msg +=
' of ' +
(state.total / 1024 / 1024).toFixed(1) +
'MB downloaded, ';
msg += state.percent + '%';
}
that._logger.info('progress', msg);
})
.then(
function() {
// Extract archive
that._logger.action('extract', path.basename(file), {
archive: file,
to: that._tempDir
});
return extract(file, that._tempDir)
// Fallback to standard git clone if extraction failed
.fail(function (err) {
msg = 'Decompression of ' + path.basename(file) + ' failed' + (err.code ? ' with ' + err.code : '') + ', ';
msg += 'trying with git..';
that._logger.debug('error', err.message, { error: err });
that._logger.warn('retry', msg);
return (
extract(file, that._tempDir)
// Fallback to standard git clone if extraction failed
.fail(function(err) {
msg =
'Decompression of ' +
path.basename(file) +
' failed' +
(err.code ? ' with ' + err.code : '') +
', ';
msg += 'trying with git..';
that._logger.debug('error', err.message, {
error: err
});
that._logger.warn('retry', msg);
return that._cleanTempDir()
.then(GitRemoteResolver.prototype._checkout.bind(that));
});
// Fallback to standard git clone if download failed
}, function (err) {
msg = 'Download of ' + tarballUrl + ' failed' + (err.code ? ' with ' + err.code : '') + ', ';
msg += 'trying with git..';
that._logger.debug('error', err.message, { error: err });
that._logger.warn('retry', msg);
return that
._cleanTempDir()
.then(
GitRemoteResolver.prototype._checkout.bind(
that
)
);
})
);
// Fallback to standard git clone if download failed
},
function(err) {
msg =
'Download of ' +
tarballUrl +
' failed' +
(err.code ? ' with ' + err.code : '') +
', ';
msg += 'trying with git..';
that._logger.debug('error', err.message, { error: err });
that._logger.warn('retry', msg);
return that._cleanTempDir()
.then(GitRemoteResolver.prototype._checkout.bind(that));
});
return that
._cleanTempDir()
.then(GitRemoteResolver.prototype._checkout.bind(that));
}
);
};
GitHubResolver.prototype._savePkgMeta = function (meta) {
GitHubResolver.prototype._savePkgMeta = function(meta) {
// Set homepage if not defined
if (!meta.homepage) {
meta.homepage = 'https://github.com/' + this._org + '/' + this._repo;
@@ -130,10 +170,12 @@ GitHubResolver.prototype._savePkgMeta = function (meta) {
// ----------------
GitHubResolver.getOrgRepoPair = function (url) {
GitHubResolver.getOrgRepoPair = function(url) {
var match;
match = url.match(/(?:@|:\/\/)github.com[:\/]([^\/\s]+?)\/([^\/\s]+?)(?:\.git)?\/?$/i);
match = url.match(
/(?:@|:\/\/)github.com[:\/]([^\/\s]+?)\/([^\/\s]+?)(?:\.git)?\/?$/i
);
if (!match) {
return null;
}

View File

@@ -19,12 +19,17 @@ function GitRemoteResolver(decEndpoint, config, logger) {
this._name = this._name.slice(0, -4);
}
// Get the host of this source
// Get the remote of this source
if (!/:\/\//.test(this._source)) {
this._host = url.parse('ssh://' + this._source).host;
this._remote = url.parse('ssh://' + this._source);
} else {
this._host = url.parse(this._source).host;
this._remote = url.parse(this._source);
}
this._host = this._remote.host;
// Verify whether the server supports shallow cloning
this._shallowClone = this._supportsShallowCloning;
}
util.inherits(GitRemoteResolver, GitResolver);
@@ -32,33 +37,37 @@ mout.object.mixIn(GitRemoteResolver, GitResolver);
// -----------------
GitRemoteResolver.prototype._checkout = function () {
GitRemoteResolver.prototype._checkout = function() {
var promise;
var timer;
var reporter;
var that = this;
var resolution = this._resolution;
this._logger.action('checkout', resolution.tag || resolution.branch || resolution.commit, {
resolution: resolution,
to: this._tempDir
});
this._logger.action(
'checkout',
resolution.tag || resolution.branch || resolution.commit,
{
resolution: resolution,
to: this._tempDir
}
);
// If resolution is a commit, we need to clone the entire repo and check it out
// Because a commit is not a named ref, there's no better solution
if (resolution.type === 'commit') {
promise = this._slowClone(resolution);
// Otherwise we are checking out a named ref so we can optimize it
// Otherwise we are checking out a named ref so we can optimize it
} else {
promise = this._fastClone(resolution);
}
// Throttle the progress reporter to 1 time each sec
reporter = mout.fn.throttle(function (data) {
reporter = mout.fn.throttle(function(data) {
var lines;
lines = data.split(/[\r\n]+/);
lines.forEach(function (line) {
lines.forEach(function(line) {
if (/\d{1,3}\%/.test(line)) {
// TODO: There are some strange chars that appear once in a while (\u001b[K)
// Trim also those?
@@ -68,99 +77,217 @@ GitRemoteResolver.prototype._checkout = function () {
}, 1000);
// Start reporting progress after a few seconds
timer = setTimeout(function () {
timer = setTimeout(function() {
promise.progress(reporter);
}, 8000);
return promise
// Add additional proxy information to the error if necessary
.fail(function (err) {
that._suggestProxyWorkaround(err);
throw err;
})
// Clear timer at the end
.fin(function () {
clearTimeout(timer);
reporter.cancel();
});
return (
promise
// Add additional proxy information to the error if necessary
.fail(function(err) {
that._suggestProxyWorkaround(err);
throw err;
})
// Clear timer at the end
.fin(function() {
clearTimeout(timer);
reporter.cancel();
})
);
};
GitRemoteResolver.prototype._findResolution = function (target) {
GitRemoteResolver.prototype._findResolution = function(target) {
var that = this;
// Override this function to include a meaningful message related to proxies
// if necessary
return GitResolver.prototype._findResolution.call(this, target)
.fail(function (err) {
that._suggestProxyWorkaround(err);
throw err;
});
return GitResolver.prototype._findResolution
.call(this, target)
.fail(function(err) {
that._suggestProxyWorkaround(err);
throw err;
});
};
// ------------------------------
GitRemoteResolver.prototype._slowClone = function (resolution) {
return cmd('git', ['clone', this._source, this._tempDir, '--progress'])
.then(cmd.bind(cmd, 'git', ['checkout', resolution.commit], { cwd: this._tempDir }));
GitRemoteResolver.prototype._slowClone = function(resolution) {
return cmd('git', [
'clone',
this._source,
this._tempDir,
'--progress'
]).then(
cmd.bind(cmd, 'git', ['checkout', resolution.commit], {
cwd: this._tempDir
})
);
};
GitRemoteResolver.prototype._fastClone = function (resolution) {
GitRemoteResolver.prototype._fastClone = function(resolution) {
var branch,
args,
that = this;
branch = resolution.tag || resolution.branch;
args = ['clone', this._source, '-b', branch, '--progress', '.'];
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;
}
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)
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(that._host)
) {
GitRemoteResolver._noShallow.set(that._host, true);
return that._fastClone(resolution);
args.push('--depth', 1);
}
throw err;
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;
}
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;
}
);
});
};
GitRemoteResolver.prototype._suggestProxyWorkaround = function (err) {
if ((this._config.proxy || this._config.httpsProxy) &&
GitRemoteResolver.prototype._suggestProxyWorkaround = function(err) {
if (
(this._config.proxy || this._config.httpsProxy) &&
mout.string.startsWith(this._source, 'git://') &&
err.code === 'ECMDERR' && err.details
err.code === 'ECMDERR' &&
err.details
) {
err.details = err.details.trim();
err.details += '\n\nWhen under a proxy, you must configure git to use https:// instead of git://.';
err.details += '\nYou can configure it for every endpoint or for this specific host as follows:';
err.details +=
'\n\nWhen under a proxy, you must configure git to use https:// instead of git://.';
err.details +=
'\nYou can configure it for every endpoint or for this specific host as follows:';
err.details += '\ngit config --global url."https://".insteadOf git://';
err.details += '\ngit config --global url."https://' + this._host + '".insteadOf git://' + this._host;
err.details += 'Ignore this suggestion if you already have this configured.';
err.details +=
'\ngit config --global url."https://' +
this._host +
'".insteadOf git://' +
this._host;
err.details +=
'Ignore this suggestion if you already have this configured.';
}
};
// 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);
}
if (
!this._host ||
!this._config.shallowCloneHosts ||
this._config.shallowCloneHosts.indexOf(this._host) === -1
) {
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
GitRemoteResolver.refs = function (source) {
GitRemoteResolver.refs = function(source) {
var value;
// TODO: Normalize source because of the various available protocols?
@@ -170,20 +297,22 @@ GitRemoteResolver.refs = function (source) {
}
// Store the promise in the refs object
value = cmd('git', ['ls-remote', '--tags', '--heads', source])
.spread(function (stdout) {
var refs;
value = cmd('git', ['ls-remote', '--tags', '--heads', source]).spread(
function(stdout) {
var refs;
refs = stdout.toString()
.trim() // Trim trailing and leading spaces
.replace(/[\t ]+/g, ' ') // Standardize spaces (some git versions make tabs, other spaces)
.split(/[\r\n]+/); // Split lines into an array
refs = stdout
.toString()
.trim() // Trim trailing and leading spaces
.replace(/[\t ]+/g, ' ') // Standardize spaces (some git versions make tabs, other spaces)
.split(/[\r\n]+/); // Split lines into an array
// Update the refs with the actual refs
this._cache.refs.set(source, refs);
// Update the refs with the actual refs
this._cache.refs.set(source, refs);
return refs;
}.bind(this));
return refs;
}.bind(this)
);
// Store the promise to be reused until it resolves
// to a specific value
@@ -195,4 +324,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;

View File

@@ -1,16 +1,14 @@
var util = require('util');
var path = require('path');
var Q = require('q');
var chmodr = require('chmodr');
var rimraf = require('rimraf');
var rimraf = require('../../util/rimraf');
var mkdirp = require('mkdirp');
var which = require('which');
var which = require('../../util/which');
var LRU = require('lru-cache');
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 +20,25 @@ 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;
if (!config.strictSsl) {
process.env.GIT_SSL_NO_VERIFY = 'true';
}
if (!config.interactive) {
process.env.GIT_TERMINAL_PROMPT = '0';
if (!process.env.SSH_ASKPASS) {
process.env.SSH_ASKPASS = 'echo';
}
}
Resolver.call(this, decEndpoint, config, logger);
if (!hasGit) {
@@ -41,18 +51,20 @@ mout.object.mixIn(GitResolver, Resolver);
// -----------------
GitResolver.prototype._hasNew = function (canonicalDir, pkgMeta) {
GitResolver.prototype._hasNew = function(pkgMeta) {
var oldResolution = pkgMeta._resolution || {};
return this._findResolution()
.then(function (resolution) {
return this._findResolution().then(function(resolution) {
// Check if resolution types are different
if (oldResolution.type !== resolution.type) {
return true;
}
// If resolved to a version, there is new content if the tags are not equal
if (resolution.type === 'version' && semver.neq(resolution.tag, oldResolution.tag)) {
if (
resolution.type === 'version' &&
semver.neq(resolution.tag, oldResolution.tag)
) {
return true;
}
@@ -61,35 +73,37 @@ GitResolver.prototype._hasNew = function (canonicalDir, pkgMeta) {
});
};
GitResolver.prototype._resolve = function () {
GitResolver.prototype._resolve = function() {
var that = this;
return this._findResolution()
.then(function () {
return that._checkout()
// Always run cleanup after checkout to ensure that .git 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 this._findResolution().then(function() {
return (
that
._checkout()
// Always run cleanup after checkout to ensure that .git 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();
})
);
});
};
// -----------------
// Abstract functions that should be implemented by concrete git resolvers
GitResolver.prototype._checkout = function () {
GitResolver.prototype._checkout = function() {
throw new Error('_checkout not implemented');
};
GitResolver.refs = function (source) {
GitResolver.refs = function(source) {
throw new Error('refs not implemented');
};
// -----------------
GitResolver.prototype._findResolution = function (target) {
GitResolver.prototype._findResolution = function(target) {
var err;
var self = this.constructor;
var that = this;
@@ -98,20 +112,15 @@ GitResolver.prototype._findResolution = function (target) {
// Target is a commit, so it's a stale target (not a moving target)
// There's nothing to do in this case
if ((/^[a-f0-9]{40}$/).test(target)) {
if (/^[a-f0-9]{40}$/.test(target)) {
this._resolution = { type: 'commit', commit: target };
return Q.resolve(this._resolution);
}
// Target is a range/version
if (semver.validRange(target)) {
return self.versions(this._source, true)
.then(function (versions) {
var versionsArr,
version,
index;
versionsArr = versions.map(function (obj) { return obj.version; });
return self.versions(this._source, true).then(function(versions) {
var versionsArr, version, index;
// If there are no tags and target is *,
// fallback to the latest commit on master
@@ -119,102 +128,143 @@ GitResolver.prototype._findResolution = function (target) {
return that._findResolution('master');
}
versionsArr = versions.map(function (obj) { return obj.version; });
versionsArr = versions.map(function(obj) {
return obj.version;
});
// Find a satisfying version, enabling strict match so that pre-releases
// have lower priority over normal ones when target is *
index = semver.maxSatisfyingIndex(versionsArr, target, true);
if (index !== -1) {
version = versions[index];
return that._resolution = { type: 'version', tag: version.tag, commit: version.commit };
return (that._resolution = {
type: 'version',
tag: version.tag,
commit: version.commit
});
}
// Check if there's an exact branch/tag with this name as last resort
return Q.all([
self.branches(that._source),
self.tags(that._source)
])
.spread(function (branches, tags) {
]).spread(function(branches, tags) {
// Use hasOwn because a branch/tag could have a name like "hasOwnProperty"
if (mout.object.hasOwn(tags, target)) {
return that._resolution = { type: 'tag', tag: target, commit: tags[target] };
return (that._resolution = {
type: 'tag',
tag: target,
commit: tags[target]
});
}
if (mout.object.hasOwn(branches, target)) {
return that._resolution = { type: 'branch', branch: target, commit: branches[target] };
return (that._resolution = {
type: 'branch',
branch: target,
commit: branches[target]
});
}
throw createError('No tag found that was able to satisfy ' + target, 'ENORESTARGET', {
details: !versions.length ?
'No versions found in ' + that._source :
'Available versions: ' + versions.map(function (version) { return version.version; }).join(', ')
});
throw createError(
'No tag found that was able to satisfy ' + target,
'ENORESTARGET',
{
details: !versions.length
? 'No versions found in ' + that._source
: 'Available versions in ' +
that._source +
': ' +
versions
.map(function(version) {
return version.version;
})
.join(', ')
}
);
});
});
}
// Otherwise, target is either a tag or a branch
return Q.all([
self.branches(that._source),
self.tags(that._source)
])
.spread(function (branches, tags) {
// Use hasOwn because a branch/tag could have a name like "hasOwnProperty"
if (mout.object.hasOwn(tags, target)) {
return that._resolution = { type: 'tag', tag: target, commit: tags[target] };
return Q.all([self.branches(that._source), self.tags(that._source)]).spread(
function(branches, tags) {
// Use hasOwn because a branch/tag could have a name like "hasOwnProperty"
if (mout.object.hasOwn(tags, target)) {
return (that._resolution = {
type: 'tag',
tag: target,
commit: tags[target]
});
}
if (mout.object.hasOwn(branches, 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);
err = createError(
'Tag/branch ' + target + ' does not exist',
'ENORESTARGET'
);
err.details = !tags.length
? 'No tags found in ' + that._source
: 'Available tags: ' + tags.join(', ');
err.details += '\n';
err.details += !branches.length
? 'No branches found in ' + that._source
: 'Available branches: ' + branches.join(', ');
throw err;
}
if (mout.object.hasOwn(branches, target)) {
return that._resolution = { type: 'branch', branch: target, commit: branches[target] };
}
branches = Object.keys(branches);
tags = Object.keys(tags);
err = createError('Tag/branch ' + target + ' does not exist', 'ENORESTARGET');
err.details = !tags.length ?
'No tags found in ' + that._source :
'Available tags: ' + tags.join(', ');
err.details += '\n';
err.details += !branches.length ?
'No branches found in ' + that._source :
'Available branches: ' + branches.join(', ');
throw err;
});
);
};
GitResolver.prototype._cleanup = function () {
GitResolver.prototype._cleanup = function() {
var gitFolder = path.join(this._tempDir, '.git');
// Remove the .git folder
// Note that on windows, we need to chmod to 0777 before due to a bug in git
// See: https://github.com/isaacs/rimraf/issues/19
if (process.platform === 'win32') {
return Q.nfcall(chmodr, gitFolder, 0777)
.then(function () {
return Q.nfcall(rimraf, gitFolder);
}, function (err) {
// If .git does not exist, chmodr returns ENOENT
// so, we ignore that error code
if (err.code !== 'ENOENT') {
throw err;
}
});
} else {
return Q.nfcall(rimraf, gitFolder);
}
return Q.nfcall(rimraf, gitFolder);
};
GitResolver.prototype._savePkgMeta = function (meta) {
GitResolver.prototype._savePkgMeta = function(meta) {
var version;
if (this._resolution.type === 'version') {
version = semver.clean(this._resolution.tag);
// Warn if the package meta version is different than the resolved one
if (typeof meta.version === 'string' && semver.neq(meta.version, version)) {
this._logger.warn('mismatch', 'Version declared in the json (' + meta.version + ') is different than the resolved one (' + version + ')', {
resolution: this._resolution,
pkgMeta: meta
});
if (
typeof meta.version === 'string' &&
semver.valid(meta.version) &&
semver.neq(meta.version, version)
) {
this._logger.warn(
'mismatch',
'Version declared in the json (' +
meta.version +
') is different than the resolved one (' +
version +
')',
{
resolution: this._resolution,
pkgMeta: meta
}
);
}
// Ensure package meta version is the same as the resolution
@@ -228,9 +278,10 @@ GitResolver.prototype._savePkgMeta = function (meta) {
// Save version/tag/commit in the release
// Note that we can't store branches because _release is supposed to be
// an unique id of this ref.
meta._release = version ||
this._resolution.tag ||
this._resolution.commit.substr(0, 10);
meta._release =
version ||
this._resolution.tag ||
this._resolution.commit.substr(0, 10);
// Save resolution to be used in hasNew later
meta._resolution = this._resolution;
@@ -240,51 +291,56 @@ GitResolver.prototype._savePkgMeta = function (meta) {
// ------------------------------
GitResolver.versions = function (source, extra) {
GitResolver.versions = function(source, extra) {
var value = this._cache.versions.get(source);
if (value) {
return Q.resolve(value)
.then(function () {
var versions = this._cache.versions.get(source);
return Q.resolve(value).then(
function() {
var versions = this._cache.versions.get(source);
// If no extra information was requested,
// resolve simply with the versions
if (!extra) {
versions = versions.map(function (version) {
return version.version;
});
}
// If no extra information was requested,
// resolve simply with the versions
if (!extra) {
versions = versions.map(function(version) {
return version.version;
});
}
return versions;
}.bind(this));
return versions;
}.bind(this)
);
}
value = this.tags(source)
.then(function (tags) {
var tag;
var version;
var versions = [];
value = this.tags(source).then(
function(tags) {
var tag;
var version;
var versions = [];
// For each tag
for (tag in tags) {
version = semver.clean(tag);
if (version) {
versions.push({ version: version, tag: tag, commit: tags[tag] });
// For each tag
for (tag in tags) {
version = semver.clean(tag);
if (version) {
versions.push({
version: version,
tag: tag,
commit: tags[tag]
});
}
}
}
// Sort them by DESC order
versions.sort(function (a, b) {
return semver.rcompare(a.version, b.version);
});
// Sort them by DESC order
versions.sort(function(a, b) {
return semver.rcompare(a.version, b.version);
});
this._cache.versions.set(source, versions);
// Call the function again to keep it DRY
return this.versions(source, extra);
}.bind(this));
this._cache.versions.set(source, versions);
// Call the function again to keep it DRY
return this.versions(source, extra);
}.bind(this)
);
// Store the promise to be reused until it resolves
// to a specific value
@@ -293,30 +349,31 @@ GitResolver.versions = function (source, extra) {
return value;
};
GitResolver.tags = function (source) {
GitResolver.tags = function(source) {
var value = this._cache.tags.get(source);
if (value) {
return Q.resolve(value);
}
value = this.refs(source)
.then(function (refs) {
var tags = {};
value = this.refs(source).then(
function(refs) {
var tags = {};
// For each line in the refs, match only the tags
refs.forEach(function (line) {
var match = line.match(/^([a-f0-9]{40})\s+refs\/tags\/(\S+)/);
// For each line in the refs, match only the tags
refs.forEach(function(line) {
var match = line.match(/^([a-f0-9]{40})\s+refs\/tags\/(\S+)/);
if (match && !mout.string.endsWith(match[2], '^{}')) {
tags[match[2]] = match[1];
}
});
if (match && !mout.string.endsWith(match[2], '^{}')) {
tags[match[2]] = match[1];
}
});
this._cache.tags.set(source, tags);
this._cache.tags.set(source, tags);
return tags;
}.bind(this));
return tags;
}.bind(this)
);
// Store the promise to be reused until it resolves
// to a specific value
@@ -325,32 +382,33 @@ GitResolver.tags = function (source) {
return value;
};
GitResolver.branches = function (source) {
GitResolver.branches = function(source) {
var value = this._cache.branches.get(source);
if (value) {
return Q.resolve(value);
}
value = this.refs(source)
.then(function (refs) {
var branches = {};
value = this.refs(source).then(
function(refs) {
var branches = {};
// For each line in the refs, extract only the heads
// Organize them in an object where keys are branches and values
// the commit hashes
refs.forEach(function (line) {
var match = line.match(/^([a-f0-9]{40})\s+refs\/heads\/(\S+)/);
// For each line in the refs, extract only the heads
// Organize them in an object where keys are branches and values
// the commit hashes
refs.forEach(function(line) {
var match = line.match(/^([a-f0-9]{40})\s+refs\/heads\/(\S+)/);
if (match) {
branches[match[2]] = match[1];
}
});
if (match) {
branches[match[2]] = match[1];
}
});
this._cache.branches.set(source, branches);
this._cache.branches.set(source, branches);
return branches;
}.bind(this));
return branches;
}.bind(this)
);
// Store the promise to be reused until it resolves
// to a specific value
@@ -359,9 +417,9 @@ GitResolver.branches = function (source) {
return value;
};
GitResolver.clearRuntimeCache = function () {
GitResolver.clearRuntimeCache = function() {
// Reset cache for branches, tags, etc
mout.object.forOwn(GitResolver._cache, function (lru) {
mout.object.forOwn(GitResolver._cache, function(lru) {
lru.reset();
});
};

View File

@@ -1,12 +1,13 @@
var fs = require('graceful-fs');
var fs = require('../../util/fs');
var path = require('path');
var Q = require('q');
var tmp = require('tmp');
var mkdirp = require('mkdirp');
var rimraf = require('rimraf');
var rimraf = require('../../util/rimraf');
var readJson = require('../../util/readJson');
var createError = require('../../util/createError');
var removeIgnores = require('../../util/removeIgnores');
var md5 = require('md5-hex');
tmp.setGracefulCleanup();
@@ -23,29 +24,28 @@ function Resolver(decEndpoint, config, logger) {
// -----------------
Resolver.prototype.getSource = function () {
Resolver.prototype.getSource = function() {
return this._source;
};
Resolver.prototype.getName = function () {
Resolver.prototype.getName = function() {
return this._name;
};
Resolver.prototype.getTarget = function () {
Resolver.prototype.getTarget = function() {
return this._target;
};
Resolver.prototype.getTempDir = function () {
Resolver.prototype.getTempDir = function() {
return this._tempDir;
};
Resolver.prototype.getPkgMeta = function () {
Resolver.prototype.getPkgMeta = function() {
return this._pkgMeta;
};
Resolver.prototype.hasNew = function (canonicalDir, pkgMeta) {
Resolver.prototype.hasNew = function(pkgMeta) {
var promise;
var metaFile;
var that = this;
// If already working, error out
@@ -56,31 +56,14 @@ Resolver.prototype.hasNew = function (canonicalDir, pkgMeta) {
this._working = true;
// Avoid reading the package meta if already given
if (pkgMeta) {
promise = this._hasNew(canonicalDir, pkgMeta);
// Otherwise call _hasNew with both the package meta and the canonical dir
} else {
metaFile = path.join(canonicalDir, '.bower.json');
promise = this._hasNew(pkgMeta);
promise = readJson(metaFile)
.spread(function (pkgMeta) {
return that._hasNew(canonicalDir, pkgMeta);
}, function (err) {
that._logger.debug('read-json', 'Failed to read ' + metaFile, {
filename: metaFile,
error: err
});
return true; // Simply resolve to true if there was an error reading the file
});
}
return promise.fin(function () {
return promise.fin(function() {
that._working = false;
});
};
Resolver.prototype.resolve = function () {
Resolver.prototype.resolve = function() {
var that = this;
// If already working, error out
@@ -91,70 +74,104 @@ Resolver.prototype.resolve = function () {
this._working = true;
// Create temporary dir
return this._createTempDir()
// Resolve self
.then(this._resolve.bind(this))
// Read json, generating the package meta
.then(this._readJson.bind(this, null))
// Apply and save package meta
.then(function (meta) {
return that._applyPkgMeta(meta)
.then(that._savePkgMeta.bind(that, meta));
})
.then(function () {
// Resolve with the folder
return that._tempDir;
}, function (err) {
// If something went wrong, unset the temporary dir
that._tempDir = null;
throw err;
})
.fin(function () {
that._working = false;
});
return (
this._createTempDir()
// Resolve self
.then(this._resolve.bind(this))
// Read json, generating the package meta
.then(this._readJson.bind(this, null))
// Apply and save package meta
.then(function(meta) {
return that
._applyPkgMeta(meta)
.then(that._savePkgMeta.bind(that, meta));
})
.then(
function() {
// Resolve with the folder
return that._tempDir;
},
function(err) {
// If something went wrong, unset the temporary dir
that._tempDir = null;
throw err;
}
)
.fin(function() {
that._working = false;
})
);
};
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
Resolver.prototype._resolve = function () {
Resolver.prototype._resolve = function() {
throw new Error('_resolve not implemented');
};
// Abstract functions that can be re-implemented by concrete resolvers
// as necessary
Resolver.prototype._hasNew = function (canonicalDir, pkgMeta) {
Resolver.prototype._hasNew = function(pkgMeta) {
return Q.resolve(true);
};
Resolver.isTargetable = function () {
Resolver.isTargetable = function() {
return true;
};
Resolver.versions = function (source) {
Resolver.versions = function(source) {
return Q.resolve([]);
};
Resolver.clearRuntimeCache = function () {};
Resolver.clearRuntimeCache = function() {};
// -----------------
Resolver.prototype._createTempDir = function () {
Resolver.prototype._createTempDir = function() {
return Q.nfcall(mkdirp, this._config.tmp)
.then(function () {
return Q.nfcall(tmp.dir, {
template: path.join(this._config.tmp, this._name + '-' + process.pid + '-XXXXXX'),
mode: 0777 & ~process.umask(),
unsafeCleanup: true
});
}.bind(this))
.then(function (dir) {
this._tempDir = dir;
return dir;
}.bind(this));
.then(
function() {
return Q.nfcall(tmp.dir, {
template: path.join(
this._config.tmp,
md5(this._name) + '-' + process.pid + '-XXXXXX'
),
mode: 0777 & ~process.umask(),
unsafeCleanup: true
});
}.bind(this)
)
.then(
function(dir) {
// nfcall may return multiple callback arguments as an array
return (this._tempDir = Array.isArray(dir) ? dir[0] : dir);
}.bind(this)
);
};
Resolver.prototype._cleanTempDir = function () {
Resolver.prototype._cleanTempDir = function() {
var tempDir = this._tempDir;
if (!tempDir) {
@@ -163,31 +180,37 @@ Resolver.prototype._cleanTempDir = function () {
// Delete and create folder
return Q.nfcall(rimraf, tempDir)
.then(function () {
return Q.nfcall(mkdirp, tempDir, 0777 & ~process.umask());
})
.then(function () {
return tempDir;
});
.then(function() {
return Q.nfcall(mkdirp, tempDir, 0777 & ~process.umask());
})
.then(function() {
return tempDir;
});
};
Resolver.prototype._readJson = function (dir) {
Resolver.prototype._readJson = function(dir) {
var that = this;
dir = dir || this._tempDir;
return readJson(dir, {
assume: { name: this._name }
})
.spread(function (json, deprecated) {
assume: { name: this._name },
logger: that._logger
}).spread(function(json, deprecated) {
if (deprecated) {
that._logger.warn('deprecated', 'Package ' + that._name + ' is using the deprecated ' + deprecated);
that._logger.warn(
'deprecated',
'Package ' +
that._name +
' is using the deprecated ' +
deprecated
);
}
return json;
});
};
Resolver.prototype._applyPkgMeta = function (meta) {
Resolver.prototype._applyPkgMeta = function(meta) {
// Check if name defined in the json is different
// If so and if the name was "guessed", assume the json name
if (meta.name !== this._name && this._guessedName) {
@@ -201,13 +224,13 @@ Resolver.prototype._applyPkgMeta = function (meta) {
}
// Otherwise remove them from the temp dir
return removeIgnores(this._tempDir, meta.ignore)
.then(function () {
return removeIgnores(this._tempDir, meta).then(function() {
return meta;
});
};
Resolver.prototype._savePkgMeta = function (meta) {
Resolver.prototype._savePkgMeta = function(meta) {
var that = this;
var contents;
// Store original source & target
@@ -217,10 +240,13 @@ Resolver.prototype._savePkgMeta = function (meta) {
// 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 Q.nfcall(
fs.writeFile,
path.join(this._tempDir, '.bower.json'),
contents
).then(function() {
return (that._pkgMeta = meta);
});
};
module.exports = Resolver;

View File

@@ -1,8 +1,6 @@
var util = require('util');
var path = require('path');
var Q = require('q');
var rimraf = require('rimraf');
var which = require('which');
var which = require('../../util/which');
var LRU = require('lru-cache');
var mout = require('mout');
var Resolver = require('./Resolver');
@@ -33,27 +31,29 @@ mout.object.mixIn(SvnResolver, Resolver);
// -----------------
SvnResolver.getSource = function (source) {
SvnResolver.getSource = function(source) {
var uri = this._source || source;
return uri
.replace(/^svn\+(https?|file):\/\//i, '$1://') // Change svn+http or svn+https or svn+file to http(s), file respectively
.replace('svn://', 'http://') // Change svn to http
.replace(/\/+$/, ''); // Remove trailing slashes
.replace(/^svn\+(https?|file):\/\//i, '$1://') // Change svn+http or svn+https or svn+file to http(s), file respectively
.replace('svn://', 'http://') // Change svn to http
.replace(/\/+$/, ''); // Remove trailing slashes
};
SvnResolver.prototype._hasNew = function (canonicalDir, pkgMeta) {
SvnResolver.prototype._hasNew = function(pkgMeta) {
var oldResolution = pkgMeta._resolution || {};
return this._findResolution()
.then(function (resolution) {
return this._findResolution().then(function(resolution) {
// Check if resolution types are different
if (oldResolution.type !== resolution.type) {
return true;
}
// If resolved to a version, there is new content if the tags are not equal
if (resolution.type === 'version' && semver.neq(resolution.tag, oldResolution.tag)) {
if (
resolution.type === 'version' &&
semver.neq(resolution.tag, oldResolution.tag)
) {
return true;
}
@@ -62,24 +62,17 @@ SvnResolver.prototype._hasNew = function (canonicalDir, pkgMeta) {
});
};
SvnResolver.prototype._resolve = function () {
SvnResolver.prototype._resolve = function() {
var that = this;
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 this._findResolution().then(function() {
return that._export();
});
};
// -----------------
SvnResolver.prototype._checkout = function () {
SvnResolver.prototype._export = function() {
var promise;
var timer;
var reporter;
@@ -88,27 +81,56 @@ SvnResolver.prototype._checkout = function () {
this.source = SvnResolver.getSource(this._source);
this._logger.action('checkout', resolution.tag || resolution.branch || resolution.commit, {
resolution: resolution,
to: this._tempDir
});
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',
'--non-interactive',
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',
'--non-interactive',
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',
'--non-interactive',
this._source + '/branches/' + resolution.branch,
this._tempDir
]);
} else {
promise = cmd('svn', ['checkout', this._source + '/tags/' + resolution.tag, this._tempDir]);
promise = cmd('svn', [
'export',
'--force',
'--non-interactive',
this._source + '/tags/' + resolution.tag,
this._tempDir
]);
}
// Throttle the progress reporter to 1 time each sec
reporter = mout.fn.throttle(function (data) {
reporter = mout.fn.throttle(function(data) {
var lines;
lines = data.split(/[\r\n]+/);
lines.forEach(function (line) {
lines.forEach(function(line) {
if (/\d{1,3}\%/.test(line)) {
// TODO: There are some strange chars that appear once in a while (\u001b[K)
// Trim also those?
@@ -118,25 +140,27 @@ SvnResolver.prototype._checkout = function () {
}, 1000);
// Start reporting progress after a few seconds
timer = setTimeout(function () {
timer = setTimeout(function() {
promise.progress(reporter);
}, 8000);
return promise
// Add additional proxy information to the error if necessary
.fail(function (err) {
throw err;
})
// Clear timer at the end
.fin(function () {
clearTimeout(timer);
reporter.cancel();
});
return (
promise
// Add additional proxy information to the error if necessary
.fail(function(err) {
throw err;
})
// Clear timer at the end
.fin(function() {
clearTimeout(timer);
reporter.cancel();
})
);
};
// -----------------
SvnResolver.prototype._findResolution = function (target) {
SvnResolver.prototype._findResolution = function(target) {
var err;
var self = this.constructor;
var that = this;
@@ -147,7 +171,7 @@ SvnResolver.prototype._findResolution = function (target) {
// Target is a revision, so it's a stale target (not a moving target)
// There's nothing to do in this case
if ((/^r\d+/).test(target)) {
if (/^r\d+/.test(target)) {
target = target.split('r');
this._resolution = { type: 'commit', commit: target[1] };
@@ -156,13 +180,12 @@ SvnResolver.prototype._findResolution = function (target) {
// Target is a range/version
if (semver.validRange(target)) {
return self.versions(this._source, true)
.then(function (versions) {
var versionsArr,
version,
index;
return self.versions(this._source, true).then(function(versions) {
var versionsArr, version, index;
versionsArr = versions.map(function (obj) { return obj.version; });
versionsArr = versions.map(function(obj) {
return obj.version;
});
// If there are no tags and target is *,
// fallback to the latest commit on trunk
@@ -170,86 +193,124 @@ SvnResolver.prototype._findResolution = function (target) {
return that._findResolution('trunk');
}
versionsArr = versions.map(function (obj) { return obj.version; });
versionsArr = versions.map(function(obj) {
return obj.version;
});
// Find a satisfying version, enabling strict match so that pre-releases
// have lower priority over normal ones when target is *
index = semver.maxSatisfyingIndex(versionsArr, target, true);
if (index !== -1) {
version = versions[index];
return that._resolution = { type: 'version', tag: version.tag, commit: version.commit };
return (that._resolution = {
type: 'version',
tag: version.tag,
commit: version.commit
});
}
// Check if there's an exact branch/tag with this name as last resort
return Q.all([
self.branches(that._source),
self.tags(that._source)
])
.spread(function (branches, tags) {
]).spread(function(branches, tags) {
// Use hasOwn because a branch/tag could have a name like "hasOwnProperty"
if (mout.object.hasOwn(tags, target)) {
return that._resolution = { type: 'tag', tag: target, commit: tags[target] };
return (that._resolution = {
type: 'tag',
tag: target,
commit: tags[target]
});
}
if (mout.object.hasOwn(branches, target)) {
return that._resolution = { type: 'branch', branch: target, commit: branches[target] };
return (that._resolution = {
type: 'branch',
branch: target,
commit: branches[target]
});
}
throw createError('No tag found that was able to satisfy ' + target, 'ENORESTARGET', {
details: !versions.length ?
'No versions found in ' + that._source :
'Available versions: ' + versions.map(function (version) { return version.version; }).join(', ')
});
throw createError(
'No tag found that was able to satisfy ' + target,
'ENORESTARGET',
{
details: !versions.length
? 'No versions found in ' + that._source
: 'Available versions in ' +
that._source +
': ' +
versions
.map(function(version) {
return version.version;
})
.join(', ')
}
);
});
});
}
// Otherwise, target is either a tag or a branch
return Q.all([
self.branches(that._source),
self.tags(that._source)
])
.spread(function (branches, tags) {
// Use hasOwn because a branch/tag could have a name like "hasOwnProperty"
if (mout.object.hasOwn(tags, target)) {
return that._resolution = { type: 'tag', tag: target, commit: tags[target] };
return Q.all([self.branches(that._source), self.tags(that._source)]).spread(
function(branches, tags) {
// Use hasOwn because a branch/tag could have a name like "hasOwnProperty"
if (mout.object.hasOwn(tags, target)) {
return (that._resolution = {
type: 'tag',
tag: target,
commit: tags[target]
});
}
if (mout.object.hasOwn(branches, target)) {
return (that._resolution = {
type: 'branch',
branch: target,
commit: branches[target]
});
}
branches = Object.keys(branches);
tags = Object.keys(tags);
err = createError(
'target ' + target + ' does not exist',
'ENORESTARGET'
);
err.details = !tags.length
? 'No tags found in ' + that._source
: 'Available tags: ' + tags.join(', ');
err.details += '\n';
err.details += !branches.length
? 'No branches found in ' + that._source
: 'Available branches: ' + branches.join(', ');
throw err;
}
if (mout.object.hasOwn(branches, target)) {
return that._resolution = { type: 'branch', branch: target, commit: branches[target] };
}
branches = Object.keys(branches);
tags = Object.keys(tags);
err = createError('target ' + target + ' does not exist', 'ENORESTARGET');
err.details = !tags.length ?
'No tags found in ' + that._source :
'Available tags: ' + tags.join(', ');
err.details += '\n';
err.details += !branches.length ?
'No branches found in ' + that._source :
'Available branches: ' + branches.join(', ');
throw err;
});
);
};
SvnResolver.prototype._cleanup = function () {
var svnFolder = path.join(this._tempDir, '.svn');
return Q.nfcall(rimraf, svnFolder);
};
SvnResolver.prototype._savePkgMeta = function (meta) {
SvnResolver.prototype._savePkgMeta = function(meta) {
var version;
if (this._resolution.type === 'version') {
version = semver.clean(this._resolution.tag);
// Warn if the package meta version is different than the resolved one
if (typeof meta.version === 'string' && semver.neq(meta.version, version)) {
this._logger.warn('mismatch', 'Version declared in the json (' + meta.version + ') is different than the resolved one (' + version + ')', {
resolution: this._resolution,
pkgMeta: meta
});
if (
typeof meta.version === 'string' &&
semver.neq(meta.version, version)
) {
this._logger.warn(
'mismatch',
'Version declared in the json (' +
meta.version +
') is different than the resolved one (' +
version +
')',
{
resolution: this._resolution,
pkgMeta: meta
}
);
}
// Ensure package meta version is the same as the resolution
@@ -263,9 +324,7 @@ SvnResolver.prototype._savePkgMeta = function (meta) {
// Save version/tag/commit in the release
// Note that we can't store branches because _release is supposed to be
// an unique id of this ref.
meta._release = version ||
this._resolution.tag ||
this._resolution.commit;
meta._release = version || this._resolution.tag || this._resolution.commit;
// Save resolution to be used in hasNew later
meta._resolution = this._resolution;
@@ -275,52 +334,58 @@ SvnResolver.prototype._savePkgMeta = function (meta) {
// ------------------------------
SvnResolver.versions = function (source, extra) {
SvnResolver.versions = function(source, extra) {
source = SvnResolver.getSource(source);
var value = this._cache.versions.get(source);
if (value) {
return Q.resolve(value)
.then(function () {
var versions = this._cache.versions.get(source);
return Q.resolve(value).then(
function() {
var versions = this._cache.versions.get(source);
// If no extra information was requested,
// resolve simply with the versions
if (!extra) {
versions = versions.map(function (version) {
return version.version;
});
}
// If no extra information was requested,
// resolve simply with the versions
if (!extra) {
versions = versions.map(function(version) {
return version.version;
});
}
return versions;
}.bind(this));
return versions;
}.bind(this)
);
}
value = this.tags(source)
.then(function (tags) {
var tag;
var version;
var versions = [];
value = this.tags(source).then(
function(tags) {
var tag;
var version;
var versions = [];
// For each tag
for (tag in tags) {
version = semver.clean(tag);
if (version) {
versions.push({ version: version, tag: tag, commit: tags[tag] });
// For each tag
for (tag in tags) {
version = semver.clean(tag);
if (version) {
versions.push({
version: version,
tag: tag,
commit: tags[tag]
});
}
}
}
// Sort them by DESC order
versions.sort(function (a, b) {
return semver.rcompare(a.version, b.version);
});
// Sort them by DESC order
versions.sort(function(a, b) {
return semver.rcompare(a.version, b.version);
});
this._cache.versions.set(source, versions);
this._cache.versions.set(source, versions);
// Call the function again to keep it DRY
return this.versions(source, extra);
}.bind(this));
// Call the function again to keep it DRY
return this.versions(source, extra);
}.bind(this)
);
// Store the promise to be reused until it resolves
// to a specific value
@@ -329,7 +394,7 @@ SvnResolver.versions = function (source, extra) {
return value;
};
SvnResolver.tags = function (source) {
SvnResolver.tags = function(source) {
source = SvnResolver.getSource(source);
var value = this._cache.tags.get(source);
@@ -338,14 +403,19 @@ SvnResolver.tags = function (source) {
return Q.resolve(value);
}
value = cmd('svn', ['list', source + '/tags', '--verbose'])
.spread(function (stout) {
var tags = SvnResolver.parseSubversionListOutput(stout.toString());
value = cmd('svn', [
'list',
source + '/tags',
'--verbose',
'--non-interactive'
]).spread(
function(stout) {
var tags = SvnResolver.parseSubversionListOutput(stout.toString());
this._cache.tags.set(source, tags);
return tags;
}.bind(this));
this._cache.tags.set(source, tags);
return tags;
}.bind(this)
);
// Store the promise to be reused until it resolves
// to a specific value
@@ -354,7 +424,7 @@ SvnResolver.tags = function (source) {
return value;
};
SvnResolver.branches = function (source) {
SvnResolver.branches = function(source) {
source = SvnResolver.getSource(source);
var value = this._cache.branches.get(source);
@@ -363,17 +433,24 @@ SvnResolver.branches = function (source) {
return Q.resolve(value);
}
value = cmd('svn', ['list', source + '/branches', '--verbose'])
.spread(function (stout) {
var branches = SvnResolver.parseSubversionListOutput(stout.toString());
value = cmd('svn', [
'list',
source + '/branches',
'--verbose',
'--non-interactive'
]).spread(
function(stout) {
var branches = SvnResolver.parseSubversionListOutput(
stout.toString()
);
// trunk is a branch!
branches.trunk = '*';
// trunk is a branch!
branches.trunk = '*';
this._cache.branches.set(source, branches);
return branches;
}.bind(this));
this._cache.branches.set(source, branches);
return branches;
}.bind(this)
);
// Store the promise to be reused until it resolves
// to a specific value
@@ -382,15 +459,12 @@ SvnResolver.branches = function (source) {
return value;
};
SvnResolver.parseSubversionListOutput = function (stout) {
SvnResolver.parseSubversionListOutput = function(stout) {
var entries = {};
var lines = stout
.trim()
.split(/[\r\n]+/);
var lines = stout.trim().split(/[\r\n]+/);
// For each line in the refs, match only the branches
lines.forEach(function (line) {
lines.forEach(function(line) {
var match = line.match(/\s+([0-9]+)\s.+\s([\w.$-]+)\//i);
if (match && match[2] !== '.') {
@@ -401,9 +475,9 @@ SvnResolver.parseSubversionListOutput = function (stout) {
return entries;
};
SvnResolver.clearRuntimeCache = function () {
SvnResolver.clearRuntimeCache = function() {
// Reset cache for branches, tags, etc
mout.object.forOwn(SvnResolver._cache, function (lru) {
mout.object.forOwn(SvnResolver._cache, function(lru) {
lru.reset();
});
};

View File

@@ -1,6 +1,6 @@
var util = require('util');
var path = require('path');
var fs = require('graceful-fs');
var fs = require('../../util/fs');
var url = require('url');
var request = require('request');
var Q = require('q');
@@ -16,7 +16,7 @@ function UrlResolver(decEndpoint, config, logger) {
// If target was specified, error out
if (this._target !== '*') {
throw createError('URL sources can\'t resolve targets', 'ENORESTARGET');
throw createError("URL sources can't resolve targets", 'ENORESTARGET');
}
// If the name was guessed
@@ -24,7 +24,10 @@ function UrlResolver(decEndpoint, config, logger) {
// Remove the ?xxx part
this._name = this._name.replace(/\?.*$/, '');
// Remove extension
this._name = this._name.substr(0, this._name.length - path.extname(this._name).length);
this._name = this._name.substr(
0,
this._name.length - path.extname(this._name).length
);
}
this._remote = url.parse(this._source);
@@ -35,11 +38,11 @@ mout.object.mixIn(UrlResolver, Resolver);
// -----------------
UrlResolver.isTargetable = function () {
UrlResolver.isTargetable = function() {
return false;
};
UrlResolver.prototype._hasNew = function (canonicalDir, pkgMeta) {
UrlResolver.prototype._hasNew = function(pkgMeta) {
var oldCacheHeaders = pkgMeta._cacheHeaders || {};
var reqHeaders = {};
@@ -54,58 +57,78 @@ UrlResolver.prototype._hasNew = function (canonicalDir, pkgMeta) {
}
// Make an HEAD request to the source
return Q.nfcall(request.head, this._source, {
proxy: this._remote.protocol === 'https:' ? this._config.httpsProxy : this._config.proxy,
strictSSL: this._config.strictSsl,
timeout: this._config.timeout,
headers: reqHeaders
})
// Compare new headers with the old ones
.spread(function (response) {
var cacheHeaders;
return (
Q.nfcall(request.head, this._source, {
ca: this._config.ca.default,
strictSSL: this._config.strictSsl,
timeout: this._config.timeout,
headers: reqHeaders
})
// Compare new headers with the old ones
.spread(
function(response) {
var cacheHeaders;
// If the server responded with 303 then the resource
// still has the same ETag
if (response.statusCode === 304) {
return false;
}
// If the server responded with 303 then the resource
// still has the same ETag
if (response.statusCode === 304) {
return false;
}
// If status code is not in the 2xx range,
// then just resolve to true
if (response.statusCode < 200 || response.statusCode >= 300) {
return true;
}
// If status code is not in the 2xx range,
// then just resolve to true
if (
response.statusCode < 200 ||
response.statusCode >= 300
) {
return true;
}
// Fallback to comparing cache headers
cacheHeaders = this._collectCacheHeaders(response);
return !mout.object.equals(oldCacheHeaders, cacheHeaders);
}.bind(this), function () {
// Assume new contents if the request failed
// Note that we do not retry the request using the "request-replay" module
// because it would take too long
return true;
});
// Fallback to comparing cache headers
cacheHeaders = this._collectCacheHeaders(response);
return !mout.object.equals(oldCacheHeaders, cacheHeaders);
}.bind(this),
function() {
// Assume new contents if the request failed
// Note that we do not retry the request using the "request-replay" module
// because it would take too long
return true;
}
)
);
};
// TODO: There's room for improvement by using streams if the URL
// is an archive file, by piping read stream to the zip extractor
// This will likely increase the complexity of code but might worth it
UrlResolver.prototype._resolve = function () {
UrlResolver.prototype._resolve = function() {
// Download
return this._download()
// Parse headers
.spread(this._parseHeaders.bind(this))
// Extract file
.spread(this._extract.bind(this))
// Rename file to index
.then(this._rename.bind(this));
return (
this._download()
// Parse headers
.spread(this._parseHeaders.bind(this))
// Extract file
.spread(this._extract.bind(this))
// Rename file to index
.then(this._rename.bind(this))
);
};
// -----------------
UrlResolver.prototype._download = function () {
var fileName = url.parse(path.basename(this._source)).pathname;
UrlResolver.prototype._parseSourceURL = function(_url) {
return url.parse(path.basename(_url)).pathname;
};
UrlResolver.prototype._download = function() {
var fileName = this._parseSourceURL(this._source);
if (!fileName) {
this._source = this._source.replace(/\/(?=\?|#)/, '');
fileName = this._parseSourceURL(this._source);
}
var file = path.join(this._tempDir, fileName);
var reqHeaders = {};
var that = this;
@@ -121,37 +144,48 @@ UrlResolver.prototype._download = function () {
// Download the file
return download(this._source, file, {
proxy: this._remote.protocol === 'https:' ? this._config.httpsProxy : this._config.proxy,
ca: this._config.ca.default,
strictSSL: this._config.strictSsl,
timeout: this._config.timeout,
headers: reqHeaders
})
.progress(function (state) {
var msg;
.progress(function(state) {
var msg;
// Retry?
if (state.retry) {
msg = 'Download of ' + that._source + ' failed' + (state.error.code ? ' with ' + state.error.code : '') + ', ';
msg += 'retrying in ' + (state.delay / 1000).toFixed(1) + 's';
that._logger.debug('error', state.error.message, { error: state.error });
return that._logger.warn('retry', msg);
}
// Retry?
if (state.retry) {
msg =
'Download of ' +
that._source +
' failed' +
(state.error.code ? ' with ' + state.error.code : '') +
', ';
msg += 'retrying in ' + (state.delay / 1000).toFixed(1) + 's';
that._logger.debug('error', state.error.message, {
error: state.error
});
return that._logger.warn('retry', msg);
}
// Progress
msg = 'received ' + (state.received / 1024 / 1024).toFixed(1) + 'MB';
if (state.total) {
msg += ' of ' + (state.total / 1024 / 1024).toFixed(1) + 'MB downloaded, ';
msg += state.percent + '%';
}
that._logger.info('progress', msg);
})
.then(function (response) {
that._response = response;
return [file, response];
});
// Progress
msg =
'received ' + (state.received / 1024 / 1024).toFixed(1) + 'MB';
if (state.total) {
msg +=
' of ' +
(state.total / 1024 / 1024).toFixed(1) +
'MB downloaded, ';
msg += state.percent + '%';
}
that._logger.info('progress', msg);
})
.then(function(response) {
that._response = response;
return [file, response];
});
};
UrlResolver.prototype._parseHeaders = function (file, response) {
UrlResolver.prototype._parseHeaders = function(file, response) {
var disposition;
var newFile;
var match;
@@ -186,20 +220,19 @@ UrlResolver.prototype._parseHeaders = function (file, response) {
newFile = path.join(this._tempDir, newFile);
return Q.nfcall(fs.rename, file, newFile)
.then(function () {
return Q.nfcall(fs.rename, file, newFile).then(function() {
return [newFile, response];
});
};
UrlResolver.prototype._extract = function (file, response) {
UrlResolver.prototype._extract = function(file, response) {
var mimeType = response.headers['content-type'];
if (mimeType) {
// Clean everything after ; and trim the end result
mimeType = mimeType.split(';')[0].trim();
// Some servers add quotes around the content-type, so we trim that also
mimeType = mout.string.trim(mimeType, ['"', '\'']);
mimeType = mout.string.trim(mimeType, ['"', "'"]);
}
if (!extract.canExtract(file, mimeType)) {
@@ -216,36 +249,42 @@ UrlResolver.prototype._extract = function (file, response) {
});
};
UrlResolver.prototype._rename = function () {
return Q.nfcall(fs.readdir, this._tempDir)
.then(function (files) {
var file;
var oldPath;
var newPath;
UrlResolver.prototype._rename = function() {
return Q.nfcall(fs.readdir, this._tempDir).then(
function(files) {
var file;
var oldPath;
var newPath;
// Remove any OS specific files from the files array
// before checking its length
files = files.filter(junk.isnt);
// Remove any OS specific files from the files array
// before checking its length
files = files.filter(junk.isnt);
// Only rename if there's only one file and it's not the json
if (files.length === 1 && !/^(component|bower)\.json$/.test(files[0])) {
file = files[0];
this._singleFile = 'index' + path.extname(file);
oldPath = path.join(this._tempDir, file);
newPath = path.join(this._tempDir, this._singleFile);
// Only rename if there's only one file and it's not the json
if (
files.length === 1 &&
!/^(component|bower)\.json$/.test(files[0])
) {
file = files[0];
this._singleFile = 'index' + path.extname(file);
oldPath = path.join(this._tempDir, file);
newPath = path.join(this._tempDir, this._singleFile);
return Q.nfcall(fs.rename, oldPath, newPath);
}
}.bind(this));
return Q.nfcall(fs.rename, oldPath, newPath);
}
}.bind(this)
);
};
UrlResolver.prototype._savePkgMeta = function (meta) {
UrlResolver.prototype._savePkgMeta = function(meta) {
// Store collected headers in the package meta
meta._cacheHeaders = this._collectCacheHeaders(this._response);
// Store ETAG under _release
if (meta._cacheHeaders.ETag) {
meta._release = 'e-tag:' + mout.string.trim(meta._cacheHeaders.ETag.substr(0, 10), '"');
meta._release =
'e-tag:' +
mout.string.trim(meta._cacheHeaders.ETag.substr(0, 10), '"');
}
// Store main if is a single file
@@ -256,11 +295,11 @@ UrlResolver.prototype._savePkgMeta = function (meta) {
return Resolver.prototype._savePkgMeta.call(this, meta);
};
UrlResolver.prototype._collectCacheHeaders = function (res) {
UrlResolver.prototype._collectCacheHeaders = function(res) {
var headers = {};
// Collect cache headers
this.constructor._cacheHeaders.forEach(function (name) {
this.constructor._cacheHeaders.forEach(function(name) {
var value = res.headers[name.toLowerCase()];
if (value != null) {

View File

@@ -0,0 +1,385 @@
var Q = require('q');
var path = require('path');
var fs = require('../../util/fs');
var object = require('mout/object');
var semver = require('../../util/semver');
var createError = require('../../util/createError');
var readJson = require('../../util/readJson');
var removeIgnores = require('../../util/removeIgnores');
function pluginResolverFactory(resolverFactory, bower) {
bower = bower || {};
if (typeof resolverFactory !== 'function') {
throw createError(
'Resolver has "' +
typeof resolverFactory +
'" type instead of "function" type.',
'ERESOLERAPI'
);
}
var resolver = resolverFactory(bower);
function maxSatisfyingVersion(versions, target) {
var versionsArr, index;
versionsArr = versions.map(function(obj) {
return obj.version;
});
// Find a satisfying version, enabling strict match so that pre-releases
// have lower priority over normal ones when target is *
index = semver.maxSatisfyingIndex(versionsArr, target, true);
if (index !== -1) {
return versions[index];
}
}
function PluginResolver(decEndpoint) {
this._decEndpoint = decEndpoint;
}
// @private
PluginResolver.prototype.getEndpoint = function() {
return object.merge(this._decEndpoint, {
name: this.getName(),
source: this.getSource(),
target: this.getTarget()
});
};
PluginResolver.prototype.getSource = function() {
return this._decEndpoint.source;
};
PluginResolver.prototype.getTarget = function() {
return this._decEndpoint.target || '*';
};
PluginResolver.prototype.getName = function() {
if (!this._decEndpoint.name && typeof resolver.getName === 'function') {
return resolver.getName.call(resolver, this.getSource());
} else if (!this._decEndpoint.name) {
return path.basename(this.getSource());
} else {
return this._decEndpoint.name;
}
};
PluginResolver.prototype.getPkgMeta = function() {
return this._pkgMeta;
};
// -----------------
// Plugin Resolver is always considered potentially cacheable
// The "resolve" method decides whether to use cached or fetch new version.
PluginResolver.prototype.isCacheable = function() {
return true;
};
// Not only it's always potentially cacheable, but also always potenially new.
// The "resolve" handles logic of re-downloading target if needed.
PluginResolver.prototype.hasNew = function(pkgMeta) {
if (this.hasNewPromise) {
return this.hasNewPromise;
}
this._pkgMeta = pkgMeta;
return (this.hasNewPromise = this.resolve().then(function(result) {
return result !== undefined;
}));
};
PluginResolver.prototype.resolve = function() {
if (this.resolvePromise) {
return this.resolvePromise;
}
var that = this;
return (this.resolvePromise = Q.fcall(function() {
var target = that.getTarget();
// It means that we can accept ranges as targets
if (that.constructor.isTargetable()) {
that._release = target;
if (semver.validRange(target)) {
return Q.fcall(
resolver.releases.bind(resolver),
that.getSource()
).then(function(result) {
if (!result) {
throw createError(
'Resolver did not provide releases of package.'
);
}
var releases = (that._releases = result);
var versions = releases.filter(function(target) {
return semver.clean(target.version);
});
var maxRelease = maxSatisfyingVersion(versions, target);
if (maxRelease) {
that._version = maxRelease.version;
that._release = that._decEndpoint.target =
maxRelease.target;
} else {
throw createError(
'No version found that was able to satisfy ' +
target,
'ENORESTARGET',
{
details: !versions.length
? 'No versions found in ' +
that.getSource()
: 'Available versions: ' +
versions
.map(function(version) {
return version.version;
})
.join(', ')
}
);
}
});
}
} else {
if (semver.validRange(target) && target !== '*') {
return Q.reject(
createError(
'Resolver does not accept version ranges (' +
target +
')'
)
);
}
}
})
.then(function() {
// We pass old _resolution (if hasNew has been called before contents).
// So resolver can decide whether use cached version of contents new one.
if (typeof resolver.fetch !== 'function') {
throw createError(
'Resolver does not implement the "fetch" method.'
);
}
var cached = {};
if (that._releases) {
cached.releases = that._releases;
}
if (that._pkgMeta) {
cached.endpoint = {
name: that._pkgMeta.name,
source: that._pkgMeta._source,
target: that._pkgMeta._target
};
cached.release = that._pkgMeta._release;
cached.version = that._pkgMeta.version;
cached.resolution = that._pkgMeta._resolution || {};
}
return Q.fcall(
resolver.fetch.bind(resolver),
that.getEndpoint(),
cached
);
})
.then(function(result) {
// Empty result means to re-use existing resolution
if (!result) {
return;
} else {
if (!result.tempPath) {
throw createError(
'Resolver did not provide path to extracted contents of package.'
);
}
that._tempDir = result.tempPath;
return that._readJson(that._tempDir).then(function(meta) {
return that
._applyPkgMeta(meta, result)
.then(that._savePkgMeta.bind(that, meta, result))
.then(function() {
return that._tempDir;
});
});
}
}));
};
PluginResolver.prototype._readJson = function(dir) {
var that = this;
return readJson(dir, {
assume: { name: that.getName() },
logger: bower.logger
}).spread(function(json, deprecated) {
if (deprecated) {
bower.logger.warn(
'deprecated',
'Package ' +
that.getName() +
' is using the deprecated ' +
deprecated
);
}
return json;
});
};
PluginResolver.prototype._applyPkgMeta = function(meta, result) {
// Check if name defined in the json is different
// If so and if the name was "guessed", assume the json name
if (meta.name !== this._name) {
this._name = meta.name;
}
// Handle ignore property, deleting all files from the temporary directory
// If no ignores were specified, simply resolve
if (
result.removeIgnores === false ||
!meta.ignore ||
!meta.ignore.length
) {
return Q.resolve(meta);
}
// Otherwise remove them from the temp dir
return removeIgnores(this._tempDir, meta).then(function() {
return meta;
});
};
PluginResolver.prototype._savePkgMeta = function(meta, result) {
var that = this;
meta._source = that.getSource();
meta._target = that.getTarget();
if (result.resolution) {
meta._resolution = result.resolution;
}
if (that._release) {
meta._release = that._release;
}
if (that._version) {
meta.version = that._version;
} else {
delete meta.version;
}
// Stringify contents
var contents = JSON.stringify(meta, null, 2);
return Q.nfcall(
fs.writeFile,
path.join(this._tempDir, '.bower.json'),
contents
).then(function() {
return (that._pkgMeta = meta);
});
};
// It is used only by "bower info". It returns all semver versions.
PluginResolver.versions = function(source) {
return Q.fcall(resolver.releases.bind(resolver), source).then(function(
result
) {
if (!result) {
throw createError(
'Resolver did not provide releases of package.'
);
}
var releases = (this._releases = result);
var versions = releases.map(function(version) {
return semver.clean(version.version);
});
versions = versions.filter(function(version) {
return version;
});
versions.sort(function(a, b) {
return semver.rcompare(a, b);
});
return versions;
});
};
PluginResolver.isTargetable = function() {
// If resolver doesn't define versions function, it's not targetable..
return typeof resolver.releases === 'function';
};
PluginResolver.clearRuntimeCache = function() {
resolver = resolverFactory(bower);
};
PluginResolver.match = function(source) {
if (typeof resolver.match !== 'function') {
throw createError(
'Resolver is missing "match" method.',
'ERESOLVERAPI'
);
}
var match = resolver.match.bind(resolver);
return Q.fcall(match, source).then(function(result) {
if (typeof result !== 'boolean') {
throw createError(
'Resolver\'s "match" method should return a boolean',
'ERESOLVERAPI'
);
}
return result;
});
};
PluginResolver.locate = function(source) {
if (typeof resolver.locate !== 'function') {
return source;
}
return Q.fcall(resolver.locate.bind(resolver), source).then(function(
result
) {
if (typeof result !== 'string') {
throw createError(
'Resolver\'s "locate" method should return a string',
'ERESOLVERAPI'
);
}
return result;
});
};
return PluginResolver;
}
module.exports = pluginResolverFactory;

View File

@@ -3,28 +3,36 @@ var cmd = require('../util/cmd');
var Q = require('q');
var shellquote = require('shell-quote');
var orderByDependencies = function (packages, installed, json) {
var orderByDependencies = function(packages, installed, json) {
var ordered = [];
installed = mout.object.keys(installed);
var depsSatisfied = function (packageName) {
return mout.array.difference(mout.object.keys(packages[packageName].dependencies), installed, ordered).length === 0;
var depsSatisfied = function(packageName) {
return (
mout.array.difference(
mout.object.keys(packages[packageName].dependencies),
installed,
ordered
).length === 0
);
};
var depsFromBowerJson = json && json.dependencies ? mout.object.keys(json.dependencies) : [];
var depsFromBowerJson =
json && json.dependencies ? mout.object.keys(json.dependencies) : [];
var packageNames = mout.object.keys(packages);
//get the list of the packages that are specified in bower.json in that order
//its nice to maintain that order for users
var desiredOrder = mout.array.intersection(depsFromBowerJson, packageNames);
//then add to the end any remaining packages that werent in bower.json
desiredOrder = desiredOrder.concat(mout.array.difference(packageNames, desiredOrder));
desiredOrder = desiredOrder.concat(
mout.array.difference(packageNames, desiredOrder)
);
//the desired order isn't necessarily a correct dependency specific order
//so we ensure that below
var resolvedOne = true;
while (resolvedOne) {
resolvedOne = false;
for (var i = 0; i < desiredOrder.length; i++) {
@@ -43,17 +51,16 @@ var orderByDependencies = function (packages, installed, json) {
//so lets just jam those names on the end
ordered = ordered.concat(desiredOrder);
}
}
return ordered;
};
var run = function (cmdString, action, logger, config) {
var run = function(cmdString, action, logger, config) {
logger.action(action, cmdString);
//pass env + BOWER_PID so callees can identify a preinstall+postinstall from the same bower instance
var env = mout.object.mixIn({ 'BOWER_PID': process.pid }, process.env);
var env = mout.object.mixIn({ BOWER_PID: process.pid }, process.env);
var args = shellquote.parse(cmdString, env);
var cmdName = args[0];
mout.array.remove(args, cmdName); //no rest() in mout
@@ -65,8 +72,8 @@ var run = function (cmdString, action, logger, config) {
var promise = cmd(cmdName, args, options);
promise.progress(function (progress) {
progress.split('\n').forEach(function (line) {
promise.progress(function(progress) {
progress.split('\n').forEach(function(line) {
if (line) {
logger.action(action, line);
}
@@ -76,21 +83,40 @@ var run = function (cmdString, action, logger, config) {
return promise;
};
var hook = function (action, ordered, config, logger, packages, installed, json) {
if (mout.object.keys(packages).length === 0 || !config.scripts || !config.scripts[action]) {
/*jshint newcap: false */
var hook = function(
action,
ordered,
config,
logger,
packages,
installed,
json
) {
if (
mout.object.keys(packages).length === 0 ||
!config.scripts ||
!config.scripts[action]
) {
return Q();
}
var orderedPackages = ordered ? orderByDependencies(packages, installed, json) : mout.object.keys(packages);
var cmdString = mout.string.replace(config.scripts[action], '%', orderedPackages.join(' '));
var orderedPackages = ordered
? orderByDependencies(packages, installed, json)
: mout.object.keys(packages);
var placeholder = new RegExp('%', 'g');
var cmdString = mout.string.replace(
config.scripts[action],
placeholder,
orderedPackages.join(' ')
);
return run(cmdString, action, logger, config);
};
module.exports = {
preuninstall: mout.function.partial(hook, 'preuninstall', false),
postuninstall: mout.function.partial(hook, 'postuninstall', false),
preinstall: mout.function.partial(hook, 'preinstall', true),
postinstall: mout.function.partial(hook, 'postinstall', true),
//only exposed for test
_orderByDependencies: orderByDependencies
};
};

View File

@@ -1,29 +1,6 @@
var abbrev = require('abbrev');
var mout = require('mout');
var commands = require('./commands');
var abbreviations = abbrev(expandNames(commands));
abbreviations.i = 'install';
abbreviations.rm = 'uninstall';
abbreviations.unlink = 'uninstall';
abbreviations.ls = 'list';
function expandNames(obj, prefix, stack) {
prefix = prefix || '';
stack = stack || [];
mout.object.forOwn(obj, function (value, name) {
name = prefix + name;
stack.push(name);
if (typeof value === 'object' && !value.line) {
expandNames(value, name + ' ', stack);
}
});
return stack;
}
var version = require('./version');
var abbreviations = require('./util/abbreviations')(commands);
function clearRuntimeCache() {
// Note that in edge cases, some architecture components instance's
@@ -34,8 +11,9 @@ function clearRuntimeCache() {
}
module.exports = {
version: version,
commands: commands,
config: require('./config'),
config: require('./config')(),
abbreviations: abbreviations,
reset: clearRuntimeCache
};

View File

@@ -7,7 +7,7 @@ function JsonRenderer() {
this._nrLogs = 0;
}
JsonRenderer.prototype.end = function (data) {
JsonRenderer.prototype.end = function(data) {
if (this._nrLogs) {
process.stderr.write(']\n');
}
@@ -17,7 +17,7 @@ JsonRenderer.prototype.end = function (data) {
}
};
JsonRenderer.prototype.error = function (err) {
JsonRenderer.prototype.error = function(err) {
var message = err.message;
var stack;
@@ -31,16 +31,14 @@ JsonRenderer.prototype.error = function (err) {
err.message = message;
// Stack
/*jshint camelcase:false*/
stack = err.fstream_stack || err.stack || 'N/A';
err.stacktrace = (Array.isArray(stack) ? stack.join('\n') : stack);
/*jshint camelcase:true*/
err.stacktrace = Array.isArray(stack) ? stack.join('\n') : stack;
this.log(err);
this.end();
};
JsonRenderer.prototype.log = function (log) {
JsonRenderer.prototype.log = function(log) {
if (!this._nrLogs) {
process.stderr.write('[');
} else {
@@ -51,12 +49,12 @@ JsonRenderer.prototype.log = function (log) {
this._nrLogs++;
};
JsonRenderer.prototype.prompt = function (prompts) {
JsonRenderer.prototype.prompt = function(prompts) {
var promise = Q.resolve();
var answers = {};
var that = this;
prompts.forEach(function (prompt) {
prompts.forEach(function(prompt) {
var opts;
var funcName;
@@ -65,67 +63,68 @@ JsonRenderer.prototype.prompt = function (prompts) {
// Prompt
opts = {
silent: true, // To not mess with JSON output
trim: false, // To allow " " to not assume the default value
default: prompt.default == null ? '' : prompt.default, // If default is null, make it '' so that it does not retry
validator: !prompt.validate ? null : function (value) {
var ret = prompt.validate(value);
silent: true, // To not mess with JSON output
trim: false, // To allow " " to not assume the default value
default: prompt.default == null ? '' : prompt.default, // If default is null, make it '' so that it does not retry
validator: !prompt.validate
? null
: function(value) {
var ret = prompt.validate(value);
if (typeof ret === 'string') {
throw ret;
}
if (typeof ret === 'string') {
throw ret;
}
return value;
},
return value;
}
};
// For now only "input", "confirm" and "password" are supported
switch (prompt.type) {
case 'input':
funcName = 'prompt';
break;
case 'confirm':
case 'password':
funcName = prompt.type;
break;
case 'checkbox':
funcName = 'prompt';
break;
default:
promise = promise.then(function () {
throw createError('Unknown prompt type', 'ENOTSUP');
});
return;
case 'input':
funcName = 'prompt';
break;
case 'confirm':
case 'password':
funcName = prompt.type;
break;
case 'checkbox':
funcName = 'prompt';
break;
default:
promise = promise.then(function() {
throw createError('Unknown prompt type', 'ENOTSUP');
});
return;
}
promise = promise.then(function () {
promise = promise.then(function() {
// Log
prompt.level = 'prompt';
that.log(prompt);
return Q.nfcall(promptly[funcName], '', opts)
.then(function (answer) {
return Q.nfcall(promptly[funcName], '', opts).then(function(
answer
) {
answers[prompt.name] = answer;
});
});
if (prompt.type === 'checkbox') {
promise = promise.then(function () {
promise = promise.then(function() {
answers[prompt.name] = answers[prompt.name].split(',');
});
}
});
return promise.then(function () {
return promise.then(function() {
return answers;
});
};
JsonRenderer.prototype.updateNotice = function () {};
// -------------------------
JsonRenderer.prototype._stringify = function (log) {
JsonRenderer.prototype._stringify = function(log) {
// To json
var str = JSON.stringify(log, null, ' ');
// Remove colors in case some log has colors..

View File

@@ -1,20 +1,19 @@
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'));
var semverUtils = require('semver-utils');
var version = require('../version');
var template = require('../util/template');
function StandardRenderer(command, config) {
this._sizes = {
id: 13, // Id max chars
id: 13, // Id max chars
label: 20, // Label max chars
sumup: 5 // Amount to sum when the label exceeds
sumup: 5 // Amount to sum when the label exceeds
};
this._colors = {
warn: chalk.yellow,
@@ -25,16 +24,26 @@ 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) {
StandardRenderer.prototype.end = function(data) {
var method = '_' + mout.string.camelCase(this._command);
if (this[method]) {
@@ -42,7 +51,7 @@ StandardRenderer.prototype.end = function (data) {
}
};
StandardRenderer.prototype.error = function (err) {
StandardRenderer.prototype.error = function(err) {
var str;
var stack;
@@ -51,37 +60,48 @@ StandardRenderer.prototype.error = function (err) {
err.id = err.code || 'error';
err.level = 'error';
str = this._prefix(err) + ' ' + err.message.replace(/\r?\n/g, ' ').trim() + '\n';
str =
this._prefix(err) +
' ' +
err.message.replace(/\r?\n/g, ' ').trim() +
'\n';
this._write(process.stderr, 'bower ' + str);
// Check if additional details were provided
if (err.details) {
str = chalk.yellow('\nAdditional error details:\n') + err.details.trim() + '\n';
str =
chalk.yellow('\nAdditional error details:\n') +
err.details.trim() +
'\n';
this._write(process.stderr, str);
}
// Print trace if verbose, the error has no code
// or if the error is a node error
if (this._config.verbose || !err.code || err.errno) {
/*jshint camelcase:false*/
stack = err.fstream_stack || err.stack || 'N/A';
str = chalk.yellow('\nStack trace:\n');
str += (Array.isArray(stack) ? stack.join('\n') : stack) + '\n';
str += chalk.yellow('\nConsole trace:\n');
/*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'));
this._write(process.stderr, 'Bower version: ' + pkg.version + '\n');
this._write(process.stderr, 'Node version: ' + process.versions.node + '\n');
this._write(process.stderr, 'OS: ' + os.type() + ' ' + os.release() + ' ' + os.arch() + '\n');
this._write(process.stderr, 'Bower version: ' + version + '\n');
this._write(
process.stderr,
'Node version: ' + process.versions.node + '\n'
);
this._write(
process.stderr,
'OS: ' + os.type() + ' ' + os.release() + ' ' + os.arch() + '\n'
);
}
};
StandardRenderer.prototype.log = function (log) {
StandardRenderer.prototype.log = function(log) {
var method = '_' + mout.string.camelCase(log.id) + 'Log';
this._guessOrigin(log);
@@ -94,31 +114,27 @@ StandardRenderer.prototype.log = function (log) {
}
};
StandardRenderer.prototype.prompt = function (prompts) {
StandardRenderer.prototype.prompt = function(prompts) {
var deferred;
// Strip colors from the prompt if color is disabled
if (!this._config.color) {
prompts.forEach(function (prompt) {
prompts.forEach(function(prompt) {
prompt.message = chalk.stripColor(prompt.message);
});
}
// 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) {
StandardRenderer.prototype._help = function(data) {
var str;
var that = this;
var specific;
@@ -133,56 +149,68 @@ StandardRenderer.prototype._help = function (data) {
if (template.exists(specific)) {
str = template.render(specific, data);
} else {
str = template.render('std/help-generic.std', data);
str = template.render('std/help-generic.std', data);
}
that._write(process.stdout, str);
}
};
StandardRenderer.prototype._install = function (packages) {
StandardRenderer.prototype._install = function(packages) {
var str = '';
mout.object.forOwn(packages, function (pkg) {
var cliTree;
mout.object.forOwn(
packages,
function(pkg) {
var cliTree;
// List only 1 level deep dependencies
mout.object.forOwn(pkg.dependencies, function (dependency) {
dependency.dependencies = {};
});
// Make canonical dir relative
pkg.canonicalDir = path.relative(this._config.cwd, pkg.canonicalDir);
// Signal as root
pkg.root = true;
// List only 1 level deep dependencies
mout.object.forOwn(pkg.dependencies, function(dependency) {
dependency.dependencies = {};
});
// Make canonical dir relative
pkg.canonicalDir = path.relative(
this._config.cwd,
pkg.canonicalDir
);
// Signal as root
pkg.root = true;
cliTree = this._tree2archy(pkg);
str += '\n' + archy(cliTree);
}, this);
cliTree = this._tree2archy(pkg);
str += '\n' + archy(cliTree);
},
this
);
if (str) {
this._write(process.stdout, str);
}
};
StandardRenderer.prototype._update = function (packages) {
StandardRenderer.prototype._update = function(packages) {
this._install(packages);
};
StandardRenderer.prototype._list = function (tree) {
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) {
StandardRenderer.prototype._search = function(results) {
var str = template.render('std/search-results.std', results);
this._write(process.stdout, str);
};
StandardRenderer.prototype._info = function (data) {
StandardRenderer.prototype._info = function(data) {
var str = '';
var pkgMeta = data;
var includeVersions = false;
@@ -201,19 +229,32 @@ StandardRenderer.prototype._info = function (data) {
// Render the versions at the end
if (includeVersions) {
data.hidePreReleases = false;
data.numPreReleases = 0;
// If output isn't verbose, hide prereleases
if (!this._config.verbose) {
data.versions = mout.array.filter(data.versions, function(version) {
version = semverUtils.parse(version);
if (!version.release && !version.build) {
return true;
}
data.numPreReleases++;
});
data.hidePreReleases = !!data.numPreReleases;
}
str += '\n' + template.render('std/info.std', data);
}
this._write(process.stdout, str);
};
StandardRenderer.prototype._lookup = function (data) {
StandardRenderer.prototype._lookup = function(data) {
var str = template.render('std/lookup.std', data);
this._write(process.stdout, str);
};
StandardRenderer.prototype._link = function (data) {
StandardRenderer.prototype._link = function(data) {
this._sizes.id = 4;
this.log({
@@ -228,7 +269,7 @@ StandardRenderer.prototype._link = function (data) {
}
};
StandardRenderer.prototype._register = function (data) {
StandardRenderer.prototype._register = function(data) {
var str;
// If no data passed, it means the user aborted
@@ -240,17 +281,20 @@ StandardRenderer.prototype._register = function (data) {
this._write(process.stdout, str);
};
StandardRenderer.prototype._cacheList = function (entries) {
entries.forEach(function (entry) {
StandardRenderer.prototype._cacheList = function(entries) {
entries.forEach(function(entry) {
var pkgMeta = entry.pkgMeta;
var version = pkgMeta.version || pkgMeta._target;
this._write(process.stdout, pkgMeta.name + '=' + pkgMeta._source + '#' + version + '\n');
this._write(
process.stdout,
pkgMeta.name + '=' + pkgMeta._source + '#' + version + '\n'
);
}, this);
};
// -------------------------
StandardRenderer.prototype._genericLog = function (log) {
StandardRenderer.prototype._genericLog = function(log) {
var stream;
var str;
@@ -264,7 +308,7 @@ StandardRenderer.prototype._genericLog = function (log) {
this._write(stream, 'bower ' + str);
};
StandardRenderer.prototype._checkoutLog = function (log) {
StandardRenderer.prototype._checkoutLog = function(log) {
if (this._compact) {
log.message = log.origin.split('#')[0] + '#' + log.message;
}
@@ -272,7 +316,7 @@ StandardRenderer.prototype._checkoutLog = function (log) {
this._genericLog(log);
};
StandardRenderer.prototype._progressLog = function (log) {
StandardRenderer.prototype._progressLog = function(log) {
if (this._compact) {
log.message = log.origin + ' ' + log.message;
}
@@ -280,7 +324,7 @@ StandardRenderer.prototype._progressLog = function (log) {
this._genericLog(log);
};
StandardRenderer.prototype._extractLog = function (log) {
StandardRenderer.prototype._extractLog = function(log) {
if (this._compact) {
log.message = log.origin + ' ' + log.message;
}
@@ -288,19 +332,23 @@ StandardRenderer.prototype._extractLog = function (log) {
this._genericLog(log);
};
StandardRenderer.prototype._incompatibleLog = function (log) {
StandardRenderer.prototype._incompatibleLog = function(log) {
var str;
var templatePath;
// Generate dependants string for each pick
log.data.picks.forEach(function (pick) {
pick.dependants = pick.dependants.map(function (dependant) {
var release = dependant.pkgMeta._release;
return dependant.endpoint.name + (release ? '#' + release : '');
}).join(', ');
log.data.picks.forEach(function(pick) {
pick.dependants = pick.dependants
.map(function(dependant) {
var release = dependant.pkgMeta._release;
return dependant.endpoint.name + (release ? '#' + release : '');
})
.join(', ');
});
templatePath = log.data.suitable ? 'std/conflict-resolved.std' : 'std/conflict.std';
templatePath = log.data.suitable
? 'std/conflict-resolved.std'
: 'std/conflict.std';
str = template.render(templatePath, log.data);
this._write(process.stdout, '\n');
@@ -308,15 +356,18 @@ StandardRenderer.prototype._incompatibleLog = function (log) {
this._write(process.stdout, '\n');
};
StandardRenderer.prototype._solvedLog = function (log) {
StandardRenderer.prototype._solvedLog = function(log) {
this._incompatibleLog(log);
};
StandardRenderer.prototype._jsonLog = function (log) {
this._write(process.stdout, '\n' + this._highlightJson(log.data.json) + '\n\n');
StandardRenderer.prototype._jsonLog = function(log) {
this._write(
process.stdout,
'\n' + this._highlightJson(log.data.json) + '\n\n'
);
};
StandardRenderer.prototype._cachedEntryLog = function (log) {
StandardRenderer.prototype._cachedEntryLog = function(log) {
if (this._compact) {
log.message = log.origin;
}
@@ -326,7 +377,7 @@ StandardRenderer.prototype._cachedEntryLog = function (log) {
// -------------------------
StandardRenderer.prototype._guessOrigin = function (log) {
StandardRenderer.prototype._guessOrigin = function(log) {
var data = log.data;
if (!data) {
@@ -334,7 +385,8 @@ StandardRenderer.prototype._guessOrigin = function (log) {
}
if (data.endpoint) {
log.origin = data.endpoint.name || (data.registry && data.endpoint.source);
log.origin =
data.endpoint.name || (data.registry && data.endpoint.source);
// Resort to using the resolver name for unnamed endpoints
if (!log.origin && data.resolver) {
@@ -353,7 +405,7 @@ StandardRenderer.prototype._guessOrigin = function (log) {
}
};
StandardRenderer.prototype._prefix = function (log) {
StandardRenderer.prototype._prefix = function(log) {
var label;
var length;
var nrSpaces;
@@ -385,7 +437,7 @@ StandardRenderer.prototype._prefix = function (log) {
return chalk.green(label) + mout.string.repeat(' ', nrSpaces) + idColor(id);
};
StandardRenderer.prototype._write = function (stream, str) {
StandardRenderer.prototype._write = function(stream, str) {
if (!this._config.color) {
str = chalk.stripColor(str);
}
@@ -393,16 +445,18 @@ StandardRenderer.prototype._write = function (stream, str) {
stream.write(str);
};
StandardRenderer.prototype._highlightJson = function (json) {
StandardRenderer.prototype._highlightJson = function(json) {
var cardinal = require('cardinal');
return cardinal.highlight(stringifyObject(json, { indent: ' ' }), {
theme: {
String: {
_default: function (str) {
_default: function(str) {
return chalk.cyan(str);
}
},
Identifier: {
_default: function (str) {
_default: function(str) {
return chalk.green(str);
}
}
@@ -411,9 +465,11 @@ StandardRenderer.prototype._highlightJson = function (json) {
});
};
StandardRenderer.prototype._tree2archy = function (node) {
StandardRenderer.prototype._tree2archy = function(node) {
var dependencies = mout.object.values(node.dependencies);
var version = !node.missing ? node.pkgMeta._release || node.pkgMeta.version : null;
var version = !node.missing
? node.pkgMeta._release || node.pkgMeta.version
: null;
var label = node.endpoint.name + (version ? '#' + version : '');
var update;
@@ -436,7 +492,8 @@ StandardRenderer.prototype._tree2archy = function (node) {
}
if (node.incompatible) {
label += chalk.yellow(' incompatible') + ' with ' + node.endpoint.target;
label +=
chalk.yellow(' incompatible') + ' with ' + node.endpoint.target;
} else if (node.extraneous) {
label += chalk.green(' extraneous');
}
@@ -450,7 +507,7 @@ StandardRenderer.prototype._tree2archy = function (node) {
}
if (node.update.latest !== node.update.target) {
update += (update ? ', ' : '');
update += update ? ', ' : '';
update += 'latest is ' + node.update.latest;
}
@@ -478,7 +535,7 @@ StandardRenderer._wideCommands = [
'register'
];
StandardRenderer._idMappings = {
'mutual': 'conflict',
mutual: 'conflict',
'cached-entry': 'cached'
};

View File

@@ -0,0 +1,13 @@
var chalk = require('chalk');
var templateColors = ['yellow', 'green', 'cyan', 'red', 'white', 'magenta'];
function colors(Handlebars) {
templateColors.forEach(function(color) {
Handlebars.registerHelper(color, function(context) {
return chalk[color](context.fn(this));
});
});
}
module.exports = colors;

View File

@@ -1,9 +1,9 @@
var mout = require('mout');
var leadLinesRegExp = /^\r?\n/;
var multipleLinesRegExp = /\r?\n(\r?\n)+/mg;
var multipleLinesRegExp = /\r?\n(\r?\n)+/gm;
function condense(Handlebars) {
Handlebars.registerHelper('condense', function (context) {
Handlebars.registerHelper('condense', function(context) {
var str = context.fn(this);
// Remove multiple lines

View File

@@ -1,7 +1,7 @@
var mout = require('mout');
function indent(Handlebars) {
Handlebars.registerHelper('indent', function (context) {
Handlebars.registerHelper('indent', function(context) {
var hash = context.hash;
var indentStr = mout.string.repeat(' ', parseInt(hash.level, 10));

View File

@@ -0,0 +1,12 @@
var mout = require('mout');
function rpad(Handlebars) {
Handlebars.registerHelper('rpad', function(context) {
var hash = context.hash;
var minLength = parseInt(hash.minLength, 10);
var chr = hash.char;
return mout.string.rpad(context.fn(this), minLength, chr);
});
}
module.exports = rpad;

View File

@@ -1,5 +1,5 @@
function sum(Handlebars) {
Handlebars.registerHelper('sum', function (val1, val2) {
Handlebars.registerHelper('sum', function(val1, val2) {
return val1 + val2;
});
}

View File

@@ -1,5 +1,5 @@
{
"command": "cache list",
"command": "cache clean",
"description": "Cleans cached packages.",
"usage": [
"cache clean [<options>]",

View File

@@ -1,5 +1,5 @@
{
"command": "cache clean",
"command": "cache list",
"description": "Lists cached packages.",
"usage": [
"cache list [<options>]",

View File

@@ -11,6 +11,11 @@
"flag": "--force-latest",
"description": "Force latest version on conflict"
},
{
"shorthand": "-f",
"flag": "--force",
"description": "If dependencies are installed, it reinstalls all installed components. It also forces installation even when there are non-bower directories with the same name in the components directory. Also bypasses the cache and overwrites to the cache anyway."
},
{
"shorthand": "-h",
"flag": "--help",
@@ -30,6 +35,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"
}
]
}

View 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."
}
]
}

View File

@@ -1,6 +1,6 @@
{
"command": "lookup",
"description": "Looks up a package URL by name.",
"description": "Look up a single package URL by name.",
"usage": [
"lookup <name> [<options>]"
],

View File

@@ -5,6 +5,11 @@
"register <name> <url> [<options>]"
],
"options": [
{
"shorthand": "-f",
"flag": "--force",
"description": "Bypasses confirmation. Bower login is still needed."
},
{
"shorthand": "-h",
"flag": "--help",

View File

@@ -1,8 +1,7 @@
{
"command": "search",
"description": "Finds all packages or a specific package.",
"description": "Search for packages by name.",
"usage": [
"search [<options>]",
"search <name> [<options>]"
],
"options": [

View File

@@ -5,6 +5,11 @@
"uninstall <name> [<name> ..] [<options>]"
],
"options": [
{
"shorthand": "-f",
"flag": "--force",
"description": "Continues uninstallation even after a dependency conflict"
},
{
"shorthand": "-h",
"flag": "--help",
@@ -13,12 +18,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"
}
]
}

View File

@@ -0,0 +1,19 @@
{
"command": "unregister",
"description": "Unregisters a package.",
"usage": [
"unregister <name> [<options>]"
],
"options": [
{
"shorthand": "-f",
"flag": "--force",
"description": "Bypasses confirmation. Bower login is still needed."
},
{
"shorthand": "-h",
"flag": "--help",
"description": "Show this help message"
}
]
}

View File

@@ -19,6 +19,16 @@
"shorthand": "-p",
"flag": "--production",
"description": "Do not install project devDependencies"
},
{
"shorthand": "-S",
"flag": "--save",
"description": "Update dependencies in bower.json"
},
{
"shorthand": "-D",
"flag": "--save-dev",
"description": "Update devDependencies in bower.json"
}
]
}

View File

@@ -0,0 +1,14 @@
{
"command": "version",
"description": "Creates an empty version commit and tag, and fail if the repo is not clean.\n\nThe <version> argument should be a valid semver string, or one of following:\nbuild, patch, minor, major.\n\nIf supplied with --message (shorthand: -m) config option, bower will use it\nas a commit message when creating a version commit. If the message config\ncontains %s then that will be replaced with the resulting version number.\n\nFor example:\n\n bower version patch -m \"Upgrade to %s for reasons\"",
"usage": [
"version [<version> | major | minor | patch]"
],
"options": [
{
"shorthand": "-m",
"flag": "--message",
"description": "Custom git commit and tag message"
}
]
}

View File

@@ -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",
"lookup": "Look up a package URL by name",
"list": "List local packages - and possible updates",
"login": "Authenticate with GitHub and store credentials",
"lookup": "Look up a single package URL by name",
"prune": "Removes local extraneous packages",
"register": "Register a package",
"search": "Search for a package by name",
"search": "Search for packages 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": [
@@ -32,7 +34,7 @@
},
{
"shorthand": "-l",
"flag": "--log-level",
"flag": "--loglevel",
"description": "What level of logs to report"
},
{
@@ -58,6 +60,19 @@
{
"flag": "--allow-root",
"description": "Allows running commands as root"
},
{
"shorthand": "-v",
"flag": "--version",
"description": "Output Bower version"
},
{
"flag": "--no-color",
"description": "Disable colors"
},
{
"flag": "--config.interactive=false",
"description": "Disable prompts"
}
]
}

View File

@@ -0,0 +1,9 @@
{{#yellow}}Please note that,{{/yellow}}
{{#condense}}
{{#each picks}}
{{#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 {{#green}}{{suitable.endpoint.name}}#{{suitable.pkgMeta._release}}{{/green}}
Code incompatibilities may occur.

View File

@@ -1,9 +1,11 @@
{{#yellow}}Unable to find a suitable version for {{name}}, please choose one:{{/yellow}}
{{#yellow}}Unable to find a suitable version for {{name}}, please choose one by typing one of the numbers below:{{/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}}

View File

@@ -11,6 +11,7 @@ Commands:
{{#condense}}
{{#each commands}}
{{#rpad length="23"}}{{@key}}{{/rpad}} {{.}}
{{#rpad minLength="23"}}{{@key}}{{/rpad}} {{.}}
{{/each}}
{{/condense}}
{{#rpad minLength="23"}}{{/rpad}}

View File

@@ -7,11 +7,12 @@ Usage:
{{/each}}
{{/condense}}
Options:
{{#condense}}
{{#each options}}
{{#yellow}}{{#rpad length="23"}}{{#if shorthand}}{{shorthand}}, {{/if}}{{flag}}{{/rpad}}{{/yellow}} {{description}}
{{#yellow}}{{#rpad minLength="23"}}{{#if shorthand}}{{shorthand}}, {{/if}}{{flag}}{{/rpad}}{{/yellow}} {{description}}
{{/each}}
{{/condense}}

View File

@@ -11,7 +11,7 @@ Commands:
{{#condense}}
{{#each commands}}
{{#rpad length="23"}}{{@key}}{{/rpad}} {{.}}
{{#rpad minLength="23"}}{{@key}}{{/rpad}} {{.}}
{{/each}}
{{/condense}}
@@ -19,7 +19,7 @@ Options:
{{#condense}}
{{#each options}}
{{#yellow}}{{#rpad length="23"}}{{#if shorthand}}{{shorthand}}, {{/if}}{{flag}}{{/rpad}}{{/yellow}} {{description}}
{{#yellow}}{{#rpad minLength="23"}}{{#if shorthand}}{{shorthand}}, {{/if}}{{flag}}{{/rpad}}{{/yellow}} {{description}}
{{/each}}
{{/condense}}

View File

@@ -5,6 +5,10 @@
{{/versions}}
{{/condense}}
{{#if hidePreReleases}}
Show {{numPreReleases}} additional prereleases with bower info {{name}} --verbose
{{/if}}
You can request info for a specific version with 'bower info {{name}}#<version>'
{{else}}No versions available.
{{/if}}

View File

@@ -5,3 +5,4 @@
Package not found.
{{/if}}
{{/condense}}

View File

@@ -5,5 +5,6 @@
{{#cyan}}{{{name}}}{{/cyan}} {{{url}}}
{{/.}}
{{/condense}}
{{else}}No results.
{{/if}}
{{/if}}

30
lib/util/abbreviations.js Normal file
View File

@@ -0,0 +1,30 @@
var abbrev = require('abbrev');
var mout = require('mout');
function expandNames(obj, prefix, stack) {
prefix = prefix || '';
stack = stack || [];
mout.object.forOwn(obj, function(value, name) {
name = prefix + name;
stack.push(name);
if (typeof value === 'object' && !value.line) {
expandNames(value, name + ' ', stack);
}
});
return stack;
}
module.exports = function(commands) {
var abbreviations = abbrev(expandNames(commands));
abbreviations.i = 'install';
abbreviations.rm = 'uninstall';
abbreviations.unlink = 'uninstall';
abbreviations.ls = 'list';
return abbreviations;
};

View File

@@ -1,61 +0,0 @@
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;
// Initializes the application-wide insight singleton and asks for the
// permission on the CLI during the first run.
analytics.setup = function setup() {
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);
} else {
deferred.resolve();
}
return deferred.promise;
};
var Tracker = analytics.Tracker = function Tracker(config) {
if (!config.analytics) {
this.track = 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);
};
Tracker.prototype.trackDecomposedEndpoints = function trackDecomposedEndpoints(command, endpoints) {
endpoints.forEach(function (endpoint) {
this.track(command, endpoint.source, endpoint.target);
}.bind(this));
};
Tracker.prototype.trackPackages = function trackPackages(command, packages) {
mout.object.forOwn(packages, function (package) {
var meta = package.pkgMeta;
this.track(command, meta.name, meta.version);
}.bind(this));
};
Tracker.prototype.trackNames = function trackNames(command, names) {
names.forEach(function (name) {
this.track(command, name);
}.bind(this));
};

21
lib/util/childProcess.js Normal file
View File

@@ -0,0 +1,21 @@
var childProcess = require('child_process');
var which = require('./which');
function execFile(cmd, args, opt, cb) {
try {
cmd = which.sync(cmd);
} catch (e) {
cb(e);
}
return childProcess.execFile(cmd, args, opt, cb);
}
function spawn(cmd, args, opt) {
cmd = which.sync(cmd);
return childProcess.spawn(cmd, args, opt);
}
module.exports = {
execFile: execFile,
spawn: spawn
};

View File

@@ -15,10 +15,10 @@ function readOptions(options, argv) {
options = options || {};
}
types = mout.object.map(options, function (option) {
types = mout.object.map(options, function(option) {
return option.type;
});
mout.object.forOwn(options, function (option, name) {
mout.object.forOwn(options, function(option, name) {
shorthands[option.shorthand] = '--' + name;
});
@@ -26,7 +26,7 @@ function readOptions(options, argv) {
// Filter only the specified options because nopt parses every --
// Also make them camel case
mout.object.forOwn(noptOptions, function (value, key) {
mout.object.forOwn(noptOptions, function(value, key) {
if (options[key]) {
parsedOptions[mout.string.camelCase(key)] = value;
}

View File

@@ -1,16 +1,19 @@
var cp = require('child_process');
var cp = require('./childProcess');
var path = require('path');
var Q = require('q');
var mout = require('mout');
var which = require('which');
var which = require('./which');
var PThrottler = require('p-throttler');
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;
@@ -34,17 +37,17 @@ function getWindowsCommand(command) {
try {
fullCommand = which.sync(command);
} catch (err) {
return winWhichCache[command] = command;
return (winWhichCache[command] = command);
}
extension = path.extname(fullCommand).toLowerCase();
// Does it need to be converted?
if (winBatchExtensions.indexOf(extension) === -1) {
return winWhichCache[command] = command;
return (winWhichCache[command] = command);
}
return winWhichCache[command] = fullCommand;
return (winWhichCache[command] = fullCommand);
}
// Executes a shell command, buffering the stdout and stderr
@@ -64,25 +67,25 @@ function executeCmd(command, args, options) {
// Buffer output, reporting progress
process = cp.spawn(command, args, options);
process.stdout.on('data', function (data) {
process.stdout.on('data', function(data) {
data = data.toString();
deferred.notify(data);
stdout += data;
});
process.stderr.on('data', function (data) {
process.stderr.on('data', function(data) {
data = data.toString();
deferred.notify(data);
stderr += data;
});
// If there is an error spawning the command, reject the promise
process.on('error', function (error) {
process.on('error', function(error) {
return deferred.reject(error);
});
// Listen to the close event instead of exit
// They are similar but close ensures that streams are flushed
process.on('close', function (code) {
process.on('close', function(code) {
var fullCommand;
var error;
@@ -96,10 +99,19 @@ 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', {
details: stderr,
exitCode: code
});
error = createError(
'Failed to execute "' +
fullCommand +
'", exit code of #' +
code +
'\n' +
stderr,
'ECMDERR',
{
details: stderr,
exitCode: code
}
);
return deferred.reject(error);
}

View File

@@ -1,6 +1,6 @@
var fstream = require('fstream');
var fstreamIgnore = require('fstream-ignore');
var fs = require('graceful-fs');
var fs = require('./fs');
var Q = require('q');
function copy(reader, writer) {
@@ -26,18 +26,17 @@ function copy(reader, writer) {
deferred = Q.defer();
reader
.on('error', deferred.reject)
// Pipe to writer
.pipe(fstream.Writer(writer))
.on('error', deferred.reject)
.on('close', deferred.resolve);
.on('error', deferred.reject)
// Pipe to writer
.pipe(fstream.Writer(writer))
.on('error', deferred.reject)
.on('close', deferred.resolve);
return deferred.promise;
}
function copyMode(src, dst) {
return Q.nfcall(fs.stat, src)
.then(function (stat) {
return Q.nfcall(fs.stat, src).then(function(stat) {
return Q.nfcall(fs.chmod, dst, stat.mode);
});
}
@@ -68,14 +67,17 @@ function copyFile(src, dst, opts) {
opts = parseOptions(opts);
promise = copy({
path: src,
type: 'File'
}, {
path: dst,
mode: opts.mode,
type: 'File'
});
promise = copy(
{
path: src,
type: 'File'
},
{
path: dst,
mode: opts.mode,
type: 'File'
}
);
if (opts.copyMode) {
promise = promise.then(copyMode.bind(copyMode, src, dst));
@@ -93,15 +95,18 @@ function copyDir(src, dst, opts) {
opts = parseOptions(opts);
promise = copy({
path: src,
type: 'Directory',
ignore: opts.ignore
}, {
path: dst,
mode: opts.mode,
type: 'Directory'
});
promise = copy(
{
path: src,
type: 'Directory',
ignore: opts.ignore
},
{
path: dst,
mode: opts.mode,
type: 'Directory'
}
);
if (opts.copyMode) {
promise = promise.then(copyMode.bind(copyMode, src, dst));

View File

@@ -1,4 +1,4 @@
var fs = require('graceful-fs');
var fs = require('./fs');
var path = require('path');
var Q = require('q');
var mkdirp = require('mkdirp');
@@ -6,52 +6,59 @@ 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
return Q.nfcall(mkdirp, dstDir)
// Check if source exists
.then(function () {
return Q.nfcall(fs.stat, src)
.fail(function (error) {
if (error.code === 'ENOENT') {
throw createError('Failed to create link to ' + path.basename(src), 'ENOENT', {
details: src + ' does not exist or points to a non-existent file'
return (
Q.nfcall(mkdirp, dstDir)
// Check if source exists
.then(function() {
return Q.nfcall(fs.stat, src).fail(function(error) {
if (error.code === 'ENOENT') {
throw createError(
'Failed to create link to ' + path.basename(src),
'ENOENT',
{
details:
src +
' does not exist or points to a non-existent file'
}
);
}
throw error;
});
}
})
// Create symlink
.then(function(stat) {
type = type || (stat.isDirectory() ? 'dir' : 'file');
throw error;
});
})
// 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);
}
return Q.nfcall(fs.symlink, src, dst, type).fail(function(err) {
if (!isWin || err.code !== 'EPERM') {
throw err;
}
return Q.nfcall(fs.symlink, src, dst, type)
.fail(function (err) {
if (!isWin || err.code !== 'EPERM') {
throw err;
}
// Try with type "junction" on Windows
// Junctions behave equally to true symlinks and can be created in
// non elevated terminal (well, not always..)
return Q.nfcall(fs.symlink, src, dst, 'junction')
.fail(function (err) {
throw createError('Unable to create link to ' + path.basename(src), err.code, {
details: err.message.trim() + '\n\nTry running this command in an elevated terminal (run as root/administrator).'
// Try with type "junction" on Windows
// Junctions behave equally to true symlinks and can be created in
// non elevated terminal (well, not always..)
return Q.nfcall(fs.symlink, src, dst, 'junction').fail(
function(err) {
throw createError(
'Unable to create link to ' +
path.basename(src),
err.code,
{
details:
err.message.trim() +
'\n\nTry running this command in an elevated terminal (run as root/administrator).'
}
);
}
);
});
});
});
});
})
);
}
module.exports = createLink;

Some files were not shown because too many files have changed in this diff Show More