mirror of
https://github.com/bower/bower.git
synced 2026-04-24 03:00:19 -04:00
Compare commits
2053 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
965a53db21 | ||
|
|
1334ff67ae | ||
|
|
afb27f446a | ||
|
|
fe011b8462 | ||
|
|
096fc3da0d | ||
|
|
8b6c8eeaa9 | ||
|
|
58ddb59104 | ||
|
|
f26fe38c30 | ||
|
|
9317bb6e33 | ||
|
|
2693bae8ed | ||
|
|
8368539a93 | ||
|
|
8947400487 | ||
|
|
44eeb60529 | ||
|
|
2309cd80c6 | ||
|
|
684ab0c0a6 | ||
|
|
1f6b32a48e | ||
|
|
e4f0295ef1 | ||
|
|
85e39cf190 | ||
|
|
16c134f0f9 | ||
|
|
bcbff32716 | ||
|
|
809117ea73 | ||
|
|
af448ba484 | ||
|
|
89069784bb | ||
|
|
57cc6f7a40 | ||
|
|
cea728c7bc | ||
|
|
f6be8e5e28 | ||
|
|
c6f7ec36de | ||
|
|
3235b3c0d3 | ||
|
|
6ca5d434a4 | ||
|
|
eb27ae8fdc | ||
|
|
353a399f75 | ||
|
|
c718541a4e | ||
|
|
1f4372299a | ||
|
|
e640d0ec5c | ||
|
|
2e5acfe076 | ||
|
|
19f3c53c70 | ||
|
|
26902aec27 | ||
|
|
08feaf2b0a | ||
|
|
db1ed1c08f | ||
|
|
3c2562ca0e | ||
|
|
b1f1b8fae3 | ||
|
|
f1c874b202 | ||
|
|
4757e7353f | ||
|
|
249ac47b9c | ||
|
|
dc59913098 | ||
|
|
343e6ac8bc | ||
|
|
e729829174 | ||
|
|
40e3ee091b | ||
|
|
8ee2d78779 | ||
|
|
7c54812ecf | ||
|
|
3251051d20 | ||
|
|
81052830f2 | ||
|
|
7b2fd5dcd1 | ||
|
|
bbc9b35cb1 | ||
|
|
3aebb34f1d | ||
|
|
8065e5c64a | ||
|
|
b8e6f36a91 | ||
|
|
12d41aeb8c | ||
|
|
8c624bbda6 | ||
|
|
7ee1686cf4 | ||
|
|
8e181c1792 | ||
|
|
9569a8074d | ||
|
|
e8e4c8fdbc | ||
|
|
9e5cd572f8 | ||
|
|
69cd360551 | ||
|
|
4793fc0d1c | ||
|
|
aaaa9cd530 | ||
|
|
c2e0dc9d23 | ||
|
|
fc4446247c | ||
|
|
f4e0b3dfba | ||
|
|
4d7cdb0556 | ||
|
|
037bbff17e | ||
|
|
f05cd5fb94 | ||
|
|
358a73b98e | ||
|
|
32cbb5a0e8 | ||
|
|
8679ad77ae | ||
|
|
1b1d8bdad6 | ||
|
|
aecdf3f365 | ||
|
|
1cf87041cc | ||
|
|
5116fec1ab | ||
|
|
8f2668a24d | ||
|
|
e7516e4bcb | ||
|
|
3853d1297e | ||
|
|
1e398f999b | ||
|
|
3a0ea968f4 | ||
|
|
7de2e5d601 | ||
|
|
b1c45bb586 | ||
|
|
f4cb047e9d | ||
|
|
f494ae7ddd | ||
|
|
44e71267c1 | ||
|
|
52aa684949 | ||
|
|
46655b7c4e | ||
|
|
16cde3118a | ||
|
|
7c2dfc1146 | ||
|
|
53eeca97d3 | ||
|
|
9201a379d6 | ||
|
|
2052ba3eed | ||
|
|
b32bd8b877 | ||
|
|
233f685c61 | ||
|
|
5fe8df2e0a | ||
|
|
a3ae3b66b7 | ||
|
|
2000d2f5db | ||
|
|
84d8d8c57f | ||
|
|
f9ea3846e2 | ||
|
|
8b6c20239e | ||
|
|
73171766e7 | ||
|
|
88b3655829 | ||
|
|
3241e8ed62 | ||
|
|
0a81308e98 | ||
|
|
8d76b87d65 | ||
|
|
f2884656c0 | ||
|
|
6fff6fa707 | ||
|
|
1357f63a1b | ||
|
|
529d702959 | ||
|
|
0155a70457 | ||
|
|
a6ca2ae9bb | ||
|
|
78e443db0a | ||
|
|
5f24eab32d | ||
|
|
f4620b28ab | ||
|
|
9f4c2384ea | ||
|
|
e85a5f778f | ||
|
|
5283a132bc | ||
|
|
db1453f7c0 | ||
|
|
878a228a7d | ||
|
|
b33041c3ec | ||
|
|
c8a6ff38a0 | ||
|
|
573b84f7f4 | ||
|
|
ef67955c21 | ||
|
|
36a14b9b37 | ||
|
|
96d986f436 | ||
|
|
394dd7c8d2 | ||
|
|
6c67d07cc8 | ||
|
|
cd7bbab310 | ||
|
|
4b4a854ed8 | ||
|
|
8194bcb4c6 | ||
|
|
e5d478a1cc | ||
|
|
bbaaee67a1 | ||
|
|
ad27112b58 | ||
|
|
38c3cee1a7 | ||
|
|
b485c5d3cb | ||
|
|
d63047b4ee | ||
|
|
f0a54d0018 | ||
|
|
1d73764788 | ||
|
|
9d2681b0c4 | ||
|
|
f3330e8612 | ||
|
|
11996c04b7 | ||
|
|
35e73a619a | ||
|
|
fe615fd517 | ||
|
|
3e3b64218d | ||
|
|
afe76e57f8 | ||
|
|
6ee3ef7aa8 | ||
|
|
64db869bd4 | ||
|
|
a4ea05800d | ||
|
|
8cf897cd19 | ||
|
|
d06af7a3d7 | ||
|
|
d4fd71986e | ||
|
|
3154444556 | ||
|
|
24f8b913b9 | ||
|
|
fe6b6863ea | ||
|
|
671c23ad50 | ||
|
|
5384fa54b1 | ||
|
|
4bfa8227d9 | ||
|
|
55d78f7928 | ||
|
|
2110148830 | ||
|
|
afc4bfbd42 | ||
|
|
9c42a008aa | ||
|
|
67884744c3 | ||
|
|
ed881e3f29 | ||
|
|
e6e60d5d5e | ||
|
|
d8f166a933 | ||
|
|
bb626d1605 | ||
|
|
daa5b8ddf9 | ||
|
|
db087dfe13 | ||
|
|
848e401efd | ||
|
|
c17c725057 | ||
|
|
2b31f6c07a | ||
|
|
3cf597fccf | ||
|
|
e2adbc37f1 | ||
|
|
6c3b7dbf58 | ||
|
|
d3ab3c1fa7 | ||
|
|
b1ba9be7f6 | ||
|
|
1e5122c023 | ||
|
|
4255d7d4a8 | ||
|
|
cdf45239f4 | ||
|
|
8b2fad32f6 | ||
|
|
d1ae0b1982 | ||
|
|
87cf578ba8 | ||
|
|
3ead440c7c | ||
|
|
e168c894a2 | ||
|
|
75e3661371 | ||
|
|
baf8f7bf6b | ||
|
|
88758cd98c | ||
|
|
3bd2d62e67 | ||
|
|
d3eef5772a | ||
|
|
7c714901d4 | ||
|
|
7792b6d35d | ||
|
|
2db983dba3 | ||
|
|
b9718bb309 | ||
|
|
26f609e614 | ||
|
|
4c2b56096b | ||
|
|
5af929f0be | ||
|
|
6a18cde782 | ||
|
|
32c5538fc5 | ||
|
|
57478d86c7 | ||
|
|
42107e6fea | ||
|
|
686e883d87 | ||
|
|
f2767648e7 | ||
|
|
9e4bdd270d | ||
|
|
7cb88ab49f | ||
|
|
a532c55dca | ||
|
|
c559432c19 | ||
|
|
9aae3b8d7e | ||
|
|
322c49edf4 | ||
|
|
34ec39507c | ||
|
|
fe9b27a647 | ||
|
|
304bb36bbc | ||
|
|
376a2de600 | ||
|
|
1605374a25 | ||
|
|
ac244a1400 | ||
|
|
9e58bbca31 | ||
|
|
027a0694f7 | ||
|
|
d50e50f3b5 | ||
|
|
3030469c59 | ||
|
|
977e0ddc52 | ||
|
|
de3e1089da | ||
|
|
7897ad7dba | ||
|
|
accdab3ece | ||
|
|
612aaa88eb | ||
|
|
338ac99080 | ||
|
|
9605bbea5f | ||
|
|
7bc97a1241 | ||
|
|
bd2c253f99 | ||
|
|
f1efce7d1f | ||
|
|
844cc5a527 | ||
|
|
0e27b6f813 | ||
|
|
3791aee9d6 | ||
|
|
20a223a959 | ||
|
|
9219f54718 | ||
|
|
ea5bd51327 | ||
|
|
5a2272cab1 | ||
|
|
b94c20b8da | ||
|
|
b81ba140e3 | ||
|
|
4ffdb500b9 | ||
|
|
609607b096 | ||
|
|
e9657668a9 | ||
|
|
1696cde273 | ||
|
|
94ffc35b25 | ||
|
|
5a1e5eb9c7 | ||
|
|
8c1f30b1c8 | ||
|
|
e3f402fc66 | ||
|
|
6616d09f47 | ||
|
|
25ad2ef946 | ||
|
|
ba4a1a9d45 | ||
|
|
3a37202dc5 | ||
|
|
12258324d3 | ||
|
|
2adb0b0807 | ||
|
|
19fc84007d | ||
|
|
8fcbd3671d | ||
|
|
0eadbef02d | ||
|
|
107ad1d3fc | ||
|
|
d2ba80e6e9 | ||
|
|
f18b38cde5 | ||
|
|
e6f1805df0 | ||
|
|
4da1b62542 | ||
|
|
852a586d5c | ||
|
|
e8a2d92785 | ||
|
|
50ed13e4ee | ||
|
|
cb9b737b9d | ||
|
|
700b46162c | ||
|
|
0e1153f610 | ||
|
|
8669ed2aac | ||
|
|
6d12ef291b | ||
|
|
ca0a36abcf | ||
|
|
4c6fdc905f | ||
|
|
cdbc4a123c | ||
|
|
bb7c02b07b | ||
|
|
4f42aeabd7 | ||
|
|
b77517ef64 | ||
|
|
b9c3f750eb | ||
|
|
aaecbfab17 | ||
|
|
c4539aa603 | ||
|
|
7f801319bf | ||
|
|
1a990f4563 | ||
|
|
944a328f30 | ||
|
|
e11b60d812 | ||
|
|
c91e99b782 | ||
|
|
da8ec1e4ab | ||
|
|
c8d5199815 | ||
|
|
e7868f0fb1 | ||
|
|
eca46dbd85 | ||
|
|
67bd5d026f | ||
|
|
51de67cc73 | ||
|
|
3d4f9cd919 | ||
|
|
cd8d397e63 | ||
|
|
5a9c099188 | ||
|
|
2137089a70 | ||
|
|
fbd02852a3 | ||
|
|
f2584ade24 | ||
|
|
2f72cd4b7d | ||
|
|
50bfd14968 | ||
|
|
2ff53fc448 | ||
|
|
42cd2e584f | ||
|
|
49de3cca62 | ||
|
|
718db0309f | ||
|
|
d867095f50 | ||
|
|
e51bf20e72 | ||
|
|
89286e628b | ||
|
|
c8042b4781 | ||
|
|
15f8a30cd4 | ||
|
|
9fdd96c92b | ||
|
|
ce15df27ca | ||
|
|
468657bfe2 | ||
|
|
814180d129 | ||
|
|
93be2fef6d | ||
|
|
3ab71f27ff | ||
|
|
38fa1b6858 | ||
|
|
c6ed215260 | ||
|
|
74eba8d2e8 | ||
|
|
5a72dae2c8 | ||
|
|
6194821643 | ||
|
|
37aab9c72e | ||
|
|
0a0dc8cef9 | ||
|
|
c6d89b79b4 | ||
|
|
8a435dff27 | ||
|
|
459925eba7 | ||
|
|
6614a43658 | ||
|
|
88fd65ae34 | ||
|
|
83da088024 | ||
|
|
51a986d0d4 | ||
|
|
0aefe8fc0e | ||
|
|
2845984169 | ||
|
|
2a91dc5fb1 | ||
|
|
5eca9274ee | ||
|
|
d57d81ca85 | ||
|
|
a5dcf9cc24 | ||
|
|
484c8985ed | ||
|
|
931b0a8905 | ||
|
|
bfd1e93325 | ||
|
|
bf23751549 | ||
|
|
b79034fbb9 | ||
|
|
eaa05ac6c1 | ||
|
|
8f0a3d727e | ||
|
|
b6a524e6b4 | ||
|
|
43d00deb88 | ||
|
|
4836a0cae9 | ||
|
|
302c4ade51 | ||
|
|
75d80e014a | ||
|
|
0f790f4293 | ||
|
|
452217e9fa | ||
|
|
f66c0cfe5c | ||
|
|
30898c13d3 | ||
|
|
2330d59ffa | ||
|
|
1316be57dc | ||
|
|
b7c19695e7 | ||
|
|
b85cf2683c | ||
|
|
ff0f2a8f83 | ||
|
|
7e5184d342 | ||
|
|
8fa1fd55e9 | ||
|
|
52463dea09 | ||
|
|
8cf09f5444 | ||
|
|
20a6190ed8 | ||
|
|
402a9f3017 | ||
|
|
af09872fba | ||
|
|
2311d7dc44 | ||
|
|
b261bf8a76 | ||
|
|
140c6d963f | ||
|
|
0c5e457359 | ||
|
|
bfa4295606 | ||
|
|
8ac68ede5d | ||
|
|
a019f887e9 | ||
|
|
eba2c69308 | ||
|
|
8df5970300 | ||
|
|
db265d471f | ||
|
|
0bb1536c99 | ||
|
|
64eb7d598a | ||
|
|
df8e5a16be | ||
|
|
3ce2dd3989 | ||
|
|
99105fbb57 | ||
|
|
96f1e98859 | ||
|
|
d614b057c9 | ||
|
|
aafe02f3e9 | ||
|
|
0441e16bdb | ||
|
|
30a489535e | ||
|
|
ac88ece259 | ||
|
|
9b45c76744 | ||
|
|
059a5f83b7 | ||
|
|
cf5cd61995 | ||
|
|
a499cc5103 | ||
|
|
123779bbd1 | ||
|
|
5365c7b428 | ||
|
|
da961a9c42 | ||
|
|
8ff0e0e2d1 | ||
|
|
ffde6bd228 | ||
|
|
bebb4fb33b | ||
|
|
2c243ea5b7 | ||
|
|
498fe84b99 | ||
|
|
9b8b66ed83 | ||
|
|
9cc3dd4c92 | ||
|
|
bf23d81c9e | ||
|
|
f53100d8d3 | ||
|
|
acbe60cdf1 | ||
|
|
4c7f37e0f8 | ||
|
|
3ba696937c | ||
|
|
1647994471 | ||
|
|
674e09dc56 | ||
|
|
4c129d470f | ||
|
|
c630f01baa | ||
|
|
6018fc13b2 | ||
|
|
c4fc6cd0e2 | ||
|
|
eed8735238 | ||
|
|
8c0155e8bd | ||
|
|
b2d4412e59 | ||
|
|
4e3e45a88b | ||
|
|
af9b386d8a | ||
|
|
201b8a3bc6 | ||
|
|
6e1a994c26 | ||
|
|
2ccc05cb98 | ||
|
|
e7d22ffb11 | ||
|
|
4805c3615b | ||
|
|
44a5260050 | ||
|
|
d72d01823d | ||
|
|
1e166189ba | ||
|
|
66310523d1 | ||
|
|
87a041a212 | ||
|
|
9c52ec2751 | ||
|
|
9010269236 | ||
|
|
aac254d275 | ||
|
|
889b54f309 | ||
|
|
5d13ffda09 | ||
|
|
31b6d5971c | ||
|
|
304b6393d4 | ||
|
|
490f63a838 | ||
|
|
64d990ba10 | ||
|
|
cb019c405b | ||
|
|
26f80d25be | ||
|
|
fe9a1bb5fc | ||
|
|
79679f9b08 | ||
|
|
5ef5403d69 | ||
|
|
23afb3a129 | ||
|
|
fac08cf835 | ||
|
|
dd67cc7de0 | ||
|
|
8531534241 | ||
|
|
0993621bb8 | ||
|
|
45fe5c37cc | ||
|
|
35b60d8d89 | ||
|
|
63b4d37207 | ||
|
|
793268ed54 | ||
|
|
a4a05a5413 | ||
|
|
821979bab1 | ||
|
|
69be742619 | ||
|
|
298982b522 | ||
|
|
9f2b3d1cd4 | ||
|
|
800119fc92 | ||
|
|
725fc26880 | ||
|
|
ed27e87540 | ||
|
|
4fc2b5cf76 | ||
|
|
749d46930d | ||
|
|
7acafc26d6 | ||
|
|
2817936b87 | ||
|
|
022c5a8401 | ||
|
|
50fd944a62 | ||
|
|
9c9cd8164b | ||
|
|
8744449016 | ||
|
|
a23f66d889 | ||
|
|
a1596bb63c | ||
|
|
ada6fc18d9 | ||
|
|
19af145166 | ||
|
|
4ed81be0c6 | ||
|
|
1c62adcdb6 | ||
|
|
95f46930a5 | ||
|
|
50b0186c06 | ||
|
|
2c9d847a1d | ||
|
|
816cdda6bb | ||
|
|
76dd504589 | ||
|
|
938c69c816 | ||
|
|
d5fc402a89 | ||
|
|
065a7a1f1b | ||
|
|
833f97198e | ||
|
|
293d5cc02b | ||
|
|
dbb302f22a | ||
|
|
ccadffea73 | ||
|
|
b3390ce201 | ||
|
|
6039f6c691 | ||
|
|
c65cdc8699 | ||
|
|
7603886e04 | ||
|
|
406a96e4d1 | ||
|
|
87d21e7968 | ||
|
|
9dd79a8061 | ||
|
|
a1287416d4 | ||
|
|
00dc877f0a | ||
|
|
335081053d | ||
|
|
7d74d7d8f6 | ||
|
|
e98d8139bc | ||
|
|
4af22cfbc0 | ||
|
|
8a47aab01d | ||
|
|
395b208a0c | ||
|
|
ab4f8a0e39 | ||
|
|
7e110603b5 | ||
|
|
94455192ad | ||
|
|
c4ca24a537 | ||
|
|
ea1f5d1ff0 | ||
|
|
77b7355433 | ||
|
|
f6178c2f75 | ||
|
|
f1e04e5629 | ||
|
|
cc913a728a | ||
|
|
e727566741 | ||
|
|
0f68da4eb8 | ||
|
|
1a7abfd3b7 | ||
|
|
905c2775d2 | ||
|
|
126da9ee12 | ||
|
|
1080cb71c4 | ||
|
|
39a295901a | ||
|
|
7e55b0b099 | ||
|
|
f8c179b153 | ||
|
|
b4aa90b402 | ||
|
|
bea46fb879 | ||
|
|
379de05a61 | ||
|
|
a1ecf8a413 | ||
|
|
4d59d266c1 | ||
|
|
c2f222760a | ||
|
|
7e0a2ea4cb | ||
|
|
912808b672 | ||
|
|
a352d51711 | ||
|
|
4ad5ed64d7 | ||
|
|
3838a3b4fb | ||
|
|
7d748ae15e | ||
|
|
9aef3b7f1d | ||
|
|
9dab389b50 | ||
|
|
260b4adb8c | ||
|
|
c93bbbd302 | ||
|
|
009e5ce0c8 | ||
|
|
61bb4f53c0 | ||
|
|
182d92f9bd | ||
|
|
61a68a9e38 | ||
|
|
b6e33d70c8 | ||
|
|
7a26bf1a10 | ||
|
|
b6dd5e445e | ||
|
|
6f4b77a440 | ||
|
|
463584ea10 | ||
|
|
fd8d603831 | ||
|
|
a1ec83b002 | ||
|
|
041d3f2843 | ||
|
|
0b22127906 | ||
|
|
0b0b507827 | ||
|
|
df1a87eb4e | ||
|
|
16de289942 | ||
|
|
e203b1aa9a | ||
|
|
02dc97e413 | ||
|
|
f458114c5b | ||
|
|
8db09d2fed | ||
|
|
0ce7053598 | ||
|
|
6a96815c44 | ||
|
|
d7b0db41f4 | ||
|
|
9c9f3e7055 | ||
|
|
2f6d680b6c | ||
|
|
639f7939a3 | ||
|
|
95ce9cbf0c | ||
|
|
1e0ef941c7 | ||
|
|
7e5bd64885 | ||
|
|
de023bc6ea | ||
|
|
c7df6f50ca | ||
|
|
df71d251f0 | ||
|
|
0b9acc18cc | ||
|
|
58a7de3136 | ||
|
|
5bb77b1e03 | ||
|
|
e351322ce4 | ||
|
|
6b53ccc8bd | ||
|
|
33842b6f92 | ||
|
|
5e747b2cfd | ||
|
|
3f8de0efb9 | ||
|
|
63da3e4595 | ||
|
|
a04b69dc6a | ||
|
|
3be4764d54 | ||
|
|
2d4fec01b1 | ||
|
|
85c50eb542 | ||
|
|
ee62d00c96 | ||
|
|
52a32f0887 | ||
|
|
dd30be90ad | ||
|
|
4cb027eb73 | ||
|
|
8e0b8f2faf | ||
|
|
39491b78b1 | ||
|
|
7c82da8389 | ||
|
|
d5c13603a0 | ||
|
|
aad253bfad | ||
|
|
dac055e2ef | ||
|
|
85df5b9983 | ||
|
|
537cd42097 | ||
|
|
9d06fce5f9 | ||
|
|
c029e1005f | ||
|
|
b245a3d611 | ||
|
|
11d89c4268 | ||
|
|
6be84ab93e | ||
|
|
2f2c4d6740 | ||
|
|
703eae72eb | ||
|
|
6a629e963c | ||
|
|
06f4d0c117 | ||
|
|
b5e557ffb0 | ||
|
|
8bd6c4a335 | ||
|
|
29eaff9edc | ||
|
|
08afaf7fa5 | ||
|
|
45bab9fe71 | ||
|
|
514eb8f0e3 | ||
|
|
a7baa58c22 | ||
|
|
e548d8b1a5 | ||
|
|
92ff0fe624 | ||
|
|
a464f5a88e | ||
|
|
962a565d30 | ||
|
|
f242e60c1a | ||
|
|
7db50391f2 | ||
|
|
8b0d55a729 | ||
|
|
de6f341f41 | ||
|
|
c9fb530dbf | ||
|
|
836bcd09ec | ||
|
|
52a6836872 | ||
|
|
c00cadb37a | ||
|
|
b26c072f0d | ||
|
|
c99482f59d | ||
|
|
4aa0f567c3 | ||
|
|
4656021902 | ||
|
|
3df6144b77 | ||
|
|
6d335abe21 | ||
|
|
179b8a28b4 | ||
|
|
c620004168 | ||
|
|
893ff3e9d7 | ||
|
|
eec9a3cb8f | ||
|
|
d3c8042102 | ||
|
|
e590b44c77 | ||
|
|
e97bf479fb | ||
|
|
fe2f71c9b8 | ||
|
|
ee6c483dd4 | ||
|
|
e83ab86f1f | ||
|
|
ef237fc521 | ||
|
|
fd4d68038b | ||
|
|
8e458c21e9 | ||
|
|
4ab36cb3bc | ||
|
|
2d149f3a09 | ||
|
|
dfd2c7a3d2 | ||
|
|
6637762aec | ||
|
|
615eba3b40 | ||
|
|
dc183125fc | ||
|
|
c3b69d1201 | ||
|
|
3e1a50ab9a | ||
|
|
7565c71eb2 | ||
|
|
d743352bc0 | ||
|
|
75ca72e3a8 | ||
|
|
59d26c6825 | ||
|
|
5eed363e10 | ||
|
|
49b2fdbde9 | ||
|
|
623f6e9542 | ||
|
|
32356f23d3 | ||
|
|
321ddabfd5 | ||
|
|
bf93a6a1ab | ||
|
|
91aa5dc6dd | ||
|
|
56ed46b99a | ||
|
|
daaf21a4fe | ||
|
|
06a8f2afab | ||
|
|
cc04530c4a | ||
|
|
0b6f62977a | ||
|
|
2a2996c22b | ||
|
|
254aba0995 | ||
|
|
23a81b3121 | ||
|
|
c4659f816f | ||
|
|
fc13328e2a | ||
|
|
d1427e7d2e | ||
|
|
5584d1062e | ||
|
|
b3f28fac64 | ||
|
|
f65af7a308 | ||
|
|
559f50a3e3 | ||
|
|
18b809314c | ||
|
|
aa1f819c0d | ||
|
|
5a8cecf499 | ||
|
|
79f362abee | ||
|
|
42db74b522 | ||
|
|
8cb41fe5fb | ||
|
|
cd893fec15 | ||
|
|
3309e9f53f | ||
|
|
ae3a017143 | ||
|
|
2a01f178da | ||
|
|
a069d1e07d | ||
|
|
76fa7f5200 | ||
|
|
7a0a86d51c | ||
|
|
8e283e43db | ||
|
|
794744d5a3 | ||
|
|
5c3e69b045 | ||
|
|
9cbd595cfd | ||
|
|
a5074eca7d | ||
|
|
9386b117c1 | ||
|
|
7738248230 | ||
|
|
85f1f808d3 | ||
|
|
6dbafa22bb | ||
|
|
cadcd37681 | ||
|
|
a45ea6e1d8 | ||
|
|
187f24de81 | ||
|
|
8df1f48226 | ||
|
|
7dbf332a94 | ||
|
|
c09ddf6de1 | ||
|
|
9b5fa99d6a | ||
|
|
b9abf32007 | ||
|
|
09ecb80625 | ||
|
|
c4e9a0e340 | ||
|
|
b6cf4e1826 | ||
|
|
ecb1619399 | ||
|
|
83f4b7b699 | ||
|
|
9b81ddf4d5 | ||
|
|
4af17f0e40 | ||
|
|
2fbc036e69 | ||
|
|
d236a12b8f | ||
|
|
232be333ad | ||
|
|
192e5af797 | ||
|
|
deb39b8f34 | ||
|
|
197b41d97a | ||
|
|
7b11a57c6f | ||
|
|
eac7945fae | ||
|
|
1177d2263f | ||
|
|
b9478a1f65 | ||
|
|
025cf91679 | ||
|
|
442aa72ccc | ||
|
|
1c09f9c82d | ||
|
|
c6d2f633ea | ||
|
|
17bd60e3e9 | ||
|
|
1d24e82276 | ||
|
|
43d7a11ba8 | ||
|
|
02e12e17d6 | ||
|
|
e42d3d5620 | ||
|
|
5c83972401 | ||
|
|
b8df18481f | ||
|
|
1690dd4728 | ||
|
|
a86087ed7c | ||
|
|
745060f0b5 | ||
|
|
0a0a490a38 | ||
|
|
4f838685d6 | ||
|
|
6339ba09f0 | ||
|
|
f816a5b0da | ||
|
|
2f02e49716 | ||
|
|
a98a0b1ac2 | ||
|
|
034326c984 | ||
|
|
a965b05400 | ||
|
|
23c2e82c97 | ||
|
|
6c2de4a359 | ||
|
|
e9588279c8 | ||
|
|
7138d3518e | ||
|
|
f852325906 | ||
|
|
3c9082ece3 | ||
|
|
efe3a78499 | ||
|
|
98c77ffe18 | ||
|
|
31969a4939 | ||
|
|
b95d5f9f23 | ||
|
|
adf59d78d7 | ||
|
|
904ae3eab7 | ||
|
|
44d2309700 | ||
|
|
5dd6a3883a | ||
|
|
7a00c5ac71 | ||
|
|
23fbbb5191 | ||
|
|
a58b1ccfa5 | ||
|
|
5f0a3fe1c1 | ||
|
|
37b0a5c04c | ||
|
|
3fb4f60192 | ||
|
|
635fa84731 | ||
|
|
410bf4f0cd | ||
|
|
eebe115b78 | ||
|
|
70eb9f0678 | ||
|
|
b9de179fe8 | ||
|
|
ac29e24c1b | ||
|
|
d83572803d | ||
|
|
87faa4f108 | ||
|
|
ea3a0d64c1 | ||
|
|
8288d2f38b | ||
|
|
ff817dad0d | ||
|
|
ba554d5f45 | ||
|
|
90922a0ce0 | ||
|
|
a91cb546f9 | ||
|
|
3cb21d128f | ||
|
|
1b8d5d0648 | ||
|
|
03f035cdf0 | ||
|
|
ac95654409 | ||
|
|
ba33bb6aa4 | ||
|
|
2898c0507e | ||
|
|
d59edd6cca | ||
|
|
bc3079332c | ||
|
|
3c0395b19f | ||
|
|
9e7b591c78 | ||
|
|
b6107a1198 | ||
|
|
2d94018f12 | ||
|
|
42f0268829 | ||
|
|
74d568b1e7 | ||
|
|
0316fedd4c | ||
|
|
5247d93d7b | ||
|
|
bda5312917 | ||
|
|
e8c071304c | ||
|
|
4e155caae9 | ||
|
|
aedb7e44ba | ||
|
|
c58109c1b4 | ||
|
|
2167c7b6d4 | ||
|
|
22eef989f6 | ||
|
|
edf387363d | ||
|
|
14ffb7443f | ||
|
|
c21ba1e64c | ||
|
|
46b8069c6d | ||
|
|
2fb697f452 | ||
|
|
73f3293314 | ||
|
|
53fc25550b | ||
|
|
961d1775e5 | ||
|
|
bdaa359d11 | ||
|
|
a90cc018dd | ||
|
|
e06f784d35 | ||
|
|
5ce1b6a4c1 | ||
|
|
86d579a7ae | ||
|
|
d031ab5ceb | ||
|
|
dcf7230494 | ||
|
|
20aca45b39 | ||
|
|
4812c380c4 | ||
|
|
98ea43eca9 | ||
|
|
cd541c7a20 | ||
|
|
5a5cf31aba | ||
|
|
3074711828 | ||
|
|
aa97c928e9 | ||
|
|
5b4d6f2fee | ||
|
|
0e833c155a | ||
|
|
9ebb1b17d1 | ||
|
|
3397cf053c | ||
|
|
6e73b5934e | ||
|
|
7120ad5014 | ||
|
|
6286cfac28 | ||
|
|
1af09da2aa | ||
|
|
bea533acf8 | ||
|
|
5316c2479e | ||
|
|
9895f8c71e | ||
|
|
9749a398c0 | ||
|
|
2883a278ee | ||
|
|
6bbb9ec956 | ||
|
|
630556f7fe | ||
|
|
32a79c4fa1 | ||
|
|
eabfee6890 | ||
|
|
6b9b283149 | ||
|
|
a19ad6663c | ||
|
|
dfae97a8d7 | ||
|
|
93d03434eb | ||
|
|
76fcd341f6 | ||
|
|
cea53ddd1f | ||
|
|
cfc061c960 | ||
|
|
09bc1784e4 | ||
|
|
b723cf92e7 | ||
|
|
3d7b9f60da | ||
|
|
b049bdb33f | ||
|
|
a5c49d89d5 | ||
|
|
1f9a92e6ad | ||
|
|
6280611aea | ||
|
|
20c0e6e12b | ||
|
|
9aa6c2bd9f | ||
|
|
4450cce0e9 | ||
|
|
523cd421b3 | ||
|
|
88dbbe7bc3 | ||
|
|
cc63a633b5 | ||
|
|
72578e49dd | ||
|
|
83f1edb9da | ||
|
|
8016bd4e1f | ||
|
|
cb8b25da53 | ||
|
|
c517b98bae | ||
|
|
d66876a9c9 | ||
|
|
ad31df09fb | ||
|
|
1831e507fe | ||
|
|
b12a58632d | ||
|
|
8442373be9 | ||
|
|
0f7a9e5a74 | ||
|
|
74bce91db8 | ||
|
|
469b74ffb3 | ||
|
|
5dd0775737 | ||
|
|
33ed5402f4 | ||
|
|
aa655dadc4 | ||
|
|
0828025450 | ||
|
|
d9db3b695c | ||
|
|
c3e6199ecf | ||
|
|
926b9e0bfd | ||
|
|
05ba2ee2f2 | ||
|
|
cd865e0a0a | ||
|
|
08af876e01 | ||
|
|
a33fb05946 | ||
|
|
de52fa564b | ||
|
|
8e13d406d4 | ||
|
|
504f738cff | ||
|
|
fde7965bc9 | ||
|
|
d3ccc73796 | ||
|
|
a1154bf383 | ||
|
|
c9cf6d157b | ||
|
|
ef2f637d01 | ||
|
|
d130c73e77 | ||
|
|
3ecc389e66 | ||
|
|
3dbddfba41 | ||
|
|
e6cb497d1a | ||
|
|
703ac13185 | ||
|
|
a3e1c86953 | ||
|
|
3d64222655 | ||
|
|
5eb29fa99c | ||
|
|
84a24b76c7 | ||
|
|
89c2a64008 | ||
|
|
c1f992b11f | ||
|
|
ea60442fd6 | ||
|
|
d78c5fd7c2 | ||
|
|
3b98e4962a | ||
|
|
f739a1141d | ||
|
|
c498e9437e | ||
|
|
9f9a7c6b38 | ||
|
|
e3d2949c46 | ||
|
|
53f563ec08 | ||
|
|
d27c36c70c | ||
|
|
820834111b | ||
|
|
0c7b09c237 | ||
|
|
6eb8bb6241 | ||
|
|
ce0b18045b | ||
|
|
10d2d566a3 | ||
|
|
9c404185e8 | ||
|
|
3044c16ce1 | ||
|
|
729ef0190e | ||
|
|
3aab16f6db | ||
|
|
0682882ac1 | ||
|
|
da46cd78a3 | ||
|
|
f3cca3483d | ||
|
|
40dbb0ffaf | ||
|
|
53d3ac570e | ||
|
|
237022baae | ||
|
|
b11ef97b7d | ||
|
|
bccfd7bbbb | ||
|
|
634ed4a341 | ||
|
|
52aa87c145 | ||
|
|
597853cd6c | ||
|
|
1bd6568f94 | ||
|
|
4b2235aef2 | ||
|
|
faf1c26669 | ||
|
|
3aea5fb704 | ||
|
|
ea559592b5 | ||
|
|
c385c08e2f | ||
|
|
a74b925173 | ||
|
|
e84f71cd37 | ||
|
|
bc6428536c | ||
|
|
1c47a0e1a0 | ||
|
|
4d3e2f4fd3 | ||
|
|
a3430f7ce6 | ||
|
|
247b7ee1ab | ||
|
|
58eafce947 | ||
|
|
ed25cf9d23 | ||
|
|
8992c74d32 | ||
|
|
01f56c515b | ||
|
|
864d3a3b2f | ||
|
|
d68d2a4b18 | ||
|
|
d24da615b3 | ||
|
|
84c693ad22 | ||
|
|
747cbc1442 | ||
|
|
722cc54338 | ||
|
|
21abf0d215 | ||
|
|
83cb1b05d9 | ||
|
|
83d4c04646 | ||
|
|
0a7f601dec | ||
|
|
1d079c0879 | ||
|
|
3df4b5b28f | ||
|
|
14dc86e9ea | ||
|
|
b64d8bfab3 | ||
|
|
b41c8ad364 | ||
|
|
03c6709254 | ||
|
|
7a6fb46841 | ||
|
|
5b43407388 | ||
|
|
0e05301588 | ||
|
|
7a501164a9 | ||
|
|
b632984874 | ||
|
|
94407079bf | ||
|
|
57ab7ee6f2 | ||
|
|
62cf372d81 | ||
|
|
d3991ee672 | ||
|
|
b4603069bf | ||
|
|
60c522a696 | ||
|
|
99b0c8974b | ||
|
|
6ae2c8497f | ||
|
|
01b7509e61 | ||
|
|
194a09f21d | ||
|
|
3207365e3a | ||
|
|
b87b8ea931 | ||
|
|
58d21ddc15 | ||
|
|
80c1fee406 | ||
|
|
a595c1ceaf | ||
|
|
cc9c440614 | ||
|
|
37425713ba | ||
|
|
8e76d67bdf | ||
|
|
ab7e7ac12a | ||
|
|
99cb553cbd | ||
|
|
dcc396234c | ||
|
|
3788e8d7b3 | ||
|
|
715de1b18c | ||
|
|
7c2384cb94 | ||
|
|
5b1dd15749 | ||
|
|
041290e1c7 | ||
|
|
1f8417041d | ||
|
|
7ecd70a90b | ||
|
|
6d85ae8e8e | ||
|
|
f405877a16 | ||
|
|
d22c6f9d66 | ||
|
|
c87f0495c0 | ||
|
|
15fbf44948 | ||
|
|
10963bd808 | ||
|
|
0866c93573 | ||
|
|
48e475c9f6 | ||
|
|
2c5ab19374 | ||
|
|
9d50c31d2c | ||
|
|
b8b03c88e4 | ||
|
|
a65f57e0f5 | ||
|
|
491027b048 | ||
|
|
5e1971a951 | ||
|
|
1099e786df | ||
|
|
be95169c1b | ||
|
|
f64f672b20 | ||
|
|
7c0a5d60ef | ||
|
|
1f7bd9fd47 | ||
|
|
2a7c3eb2e6 | ||
|
|
32aeba2bb8 | ||
|
|
20e376c214 | ||
|
|
a0c1552726 | ||
|
|
46783e32d5 | ||
|
|
2eafac3ff6 | ||
|
|
9bd85b7023 | ||
|
|
eb9dcce30b | ||
|
|
a899cb48b3 | ||
|
|
ed8ac01f07 | ||
|
|
742ef58d89 | ||
|
|
c98bef5fc7 | ||
|
|
23044b3758 | ||
|
|
107ce78b12 | ||
|
|
5f81b8f0c1 | ||
|
|
83d75e704b | ||
|
|
a860e3eaf7 | ||
|
|
3d84bcc7ad | ||
|
|
c31504220d | ||
|
|
f8501cf7f4 | ||
|
|
81ef5a1dd2 | ||
|
|
29ec793386 | ||
|
|
187457df13 | ||
|
|
2eea214a42 | ||
|
|
639c2290b7 | ||
|
|
3044dcd3af | ||
|
|
3d64b16227 | ||
|
|
7bd22a5103 | ||
|
|
12cde3ddce | ||
|
|
860d70551f | ||
|
|
6db6fcc414 | ||
|
|
25c229de73 | ||
|
|
d954a54017 | ||
|
|
dcdd8cb3db | ||
|
|
e93c5f8265 | ||
|
|
77be4520dc | ||
|
|
cf76bcb2aa | ||
|
|
b272a61eac | ||
|
|
4ed5f278f8 | ||
|
|
6a16850960 | ||
|
|
78bbf1f04f | ||
|
|
52938202bd | ||
|
|
0eac8bb96e | ||
|
|
46ae1e759c | ||
|
|
e0c1308c2a | ||
|
|
0f29818030 | ||
|
|
dd39a25dd0 | ||
|
|
430dc04b09 | ||
|
|
39209f3bda | ||
|
|
0eaa43c05d | ||
|
|
6ed4be9135 | ||
|
|
02b6a21276 | ||
|
|
794ca573b8 | ||
|
|
5eadd36107 | ||
|
|
c6a370309d | ||
|
|
13e2514830 | ||
|
|
0b8be97fb5 | ||
|
|
c327dcb255 | ||
|
|
1b505cc0e6 | ||
|
|
032f771996 | ||
|
|
35d83d2306 | ||
|
|
dd23feb5ea | ||
|
|
e21d7bd000 | ||
|
|
d18cfa7b59 | ||
|
|
eca956cf80 | ||
|
|
587cc5acdd | ||
|
|
b5e9a4c191 | ||
|
|
3ced03ca7f | ||
|
|
9fa08fee99 | ||
|
|
3dfd7a9ab1 | ||
|
|
1713e5e2eb | ||
|
|
1d7342573b | ||
|
|
64fc295ecc | ||
|
|
12baabcc89 | ||
|
|
13839e9384 | ||
|
|
6b6dc8311a | ||
|
|
b1d8c3c1e3 | ||
|
|
d42a564de8 | ||
|
|
71d083a552 | ||
|
|
cf802c368d | ||
|
|
71037cb482 | ||
|
|
1f4e5cadd2 | ||
|
|
72e6e61970 | ||
|
|
4402b80ec9 | ||
|
|
3f0dbef7ea | ||
|
|
1ee8abf098 | ||
|
|
55eb1e2290 | ||
|
|
906990d9b5 | ||
|
|
518f3d2a8f | ||
|
|
6ba6ea0084 | ||
|
|
01c499d73f | ||
|
|
0de9cc82f6 | ||
|
|
7dba46df9b | ||
|
|
7621a71359 | ||
|
|
17f72f0ae2 | ||
|
|
47094ef046 | ||
|
|
6e28e79b29 | ||
|
|
463b258409 | ||
|
|
49d4c96ddf | ||
|
|
197d3e9d36 | ||
|
|
adcc368238 | ||
|
|
eff97c4d28 | ||
|
|
d2aeed7a0c | ||
|
|
9cb09feb65 | ||
|
|
fb084fa4cd | ||
|
|
846b8fb57e | ||
|
|
cb649830a0 | ||
|
|
bf4266c2e3 | ||
|
|
814a0f9016 | ||
|
|
098753520f | ||
|
|
43ae12f63b | ||
|
|
46937bbb87 | ||
|
|
5bf0c768f7 | ||
|
|
f124fd4c23 | ||
|
|
ff49d24743 | ||
|
|
99ca255aad | ||
|
|
d1a63b6fe0 | ||
|
|
3530a33fe7 | ||
|
|
d08efcfe3c | ||
|
|
337c0f2d0a | ||
|
|
1acf4a53d3 | ||
|
|
a2b0fb7d82 | ||
|
|
088c488e2d | ||
|
|
64ef934a3c | ||
|
|
39b690e96a | ||
|
|
08fc86698d | ||
|
|
89510f40d3 | ||
|
|
9f2207eb1f | ||
|
|
7bacf8c425 | ||
|
|
896672c4f4 | ||
|
|
a6552d7d54 | ||
|
|
cacef7b316 | ||
|
|
7a8642db94 | ||
|
|
2b8e0fdf06 | ||
|
|
dfb18b305d | ||
|
|
1606395546 | ||
|
|
abe4264a13 | ||
|
|
60d9bfb2b8 | ||
|
|
9141b3020f | ||
|
|
367c3c3e95 | ||
|
|
41a3903ac9 | ||
|
|
146d6ac538 | ||
|
|
fce93e16ae | ||
|
|
fb12fc03bf | ||
|
|
9c49b097c8 | ||
|
|
524e83fca4 | ||
|
|
f5999e84a2 | ||
|
|
ee2640bc43 | ||
|
|
2b93aa000c | ||
|
|
9c4b30b65c | ||
|
|
160dc5c470 | ||
|
|
bbe2896de2 | ||
|
|
673f641283 | ||
|
|
36d8d308f2 | ||
|
|
3482dd2a6b | ||
|
|
9cee8b7b78 | ||
|
|
4ae1b5e04d | ||
|
|
a34c8dc502 | ||
|
|
b42c1ddbbc | ||
|
|
9cc4860050 | ||
|
|
58921f7422 | ||
|
|
8dbd79d49b | ||
|
|
e2c67fa25a | ||
|
|
f332de8ba9 | ||
|
|
8dce9a6f66 | ||
|
|
1c616115b9 | ||
|
|
a97375552f | ||
|
|
1cf99d757a | ||
|
|
e84e94a8d1 | ||
|
|
cf85177c7f | ||
|
|
2b334774ce | ||
|
|
bc4a0f448b | ||
|
|
14ef86456f | ||
|
|
b083422321 | ||
|
|
12efc85baf | ||
|
|
68124dfdbe | ||
|
|
ee4158e90b | ||
|
|
0b3b7efccf | ||
|
|
b282d02a77 | ||
|
|
e07c813320 | ||
|
|
b76a00b6fe | ||
|
|
77e077d658 | ||
|
|
1cec48c065 | ||
|
|
30fa7f5a7f | ||
|
|
83edff6b26 | ||
|
|
fd58a5fe06 | ||
|
|
6064269936 | ||
|
|
d0929896cf | ||
|
|
990e87de1f | ||
|
|
8da47dcd00 | ||
|
|
15957bc9ac | ||
|
|
59f87bdffe | ||
|
|
ee31e93f98 | ||
|
|
d3f3d17536 | ||
|
|
88c1045180 | ||
|
|
2c06feb6a1 | ||
|
|
5b4fb961af | ||
|
|
3995ec0ff7 | ||
|
|
d2144905db | ||
|
|
b29c9c28fa | ||
|
|
aa2e68d1ad | ||
|
|
85b2ec93c8 | ||
|
|
c63d88d987 | ||
|
|
c21bde192b | ||
|
|
39f1f8aff5 | ||
|
|
3f8fcbf4e3 | ||
|
|
24cabf19af | ||
|
|
ae04f71e55 | ||
|
|
c56f0db891 | ||
|
|
ebf2765f2f | ||
|
|
8dac95d86d | ||
|
|
6125c0423f | ||
|
|
f3d1638131 | ||
|
|
8b699c58ae | ||
|
|
743a97c784 | ||
|
|
ea7ae5698a | ||
|
|
3ed9b3ec39 | ||
|
|
e8f3e3b88a | ||
|
|
82d16fbfde | ||
|
|
73c2e885e9 | ||
|
|
2e615e7570 | ||
|
|
d0f90546f3 | ||
|
|
22091cf272 | ||
|
|
f2f3fa4c9c | ||
|
|
0ab2ce9cf6 | ||
|
|
1b1424fe2f | ||
|
|
ee31c44ff1 | ||
|
|
e64af6b11b | ||
|
|
d6045931a5 | ||
|
|
9f99d5d42a | ||
|
|
327703871b | ||
|
|
b456f71b64 | ||
|
|
9576b8a8e9 | ||
|
|
e0037c7eaf | ||
|
|
59c5caa395 | ||
|
|
e4a35594ba | ||
|
|
5f44d1f2cf | ||
|
|
489c6f6730 | ||
|
|
c66afdf434 | ||
|
|
d62f5142cc | ||
|
|
5d4007918c | ||
|
|
5b49b5c535 | ||
|
|
7bd19e39a7 | ||
|
|
5037aed3ae | ||
|
|
c00bacb790 | ||
|
|
5672019203 | ||
|
|
7cb5da9971 | ||
|
|
62672bc4c8 | ||
|
|
705d62be18 | ||
|
|
d237522e8c | ||
|
|
44308fa026 | ||
|
|
766dcd0dd5 | ||
|
|
87302d6d86 | ||
|
|
aae19206a0 | ||
|
|
212c4c3a71 | ||
|
|
e1a443177e | ||
|
|
1210ea821a | ||
|
|
9721381383 | ||
|
|
5ea9a1d715 | ||
|
|
83f00d720e | ||
|
|
ee76fe584e | ||
|
|
063453b744 | ||
|
|
05b94d1d15 | ||
|
|
ed0c93aec3 | ||
|
|
3a0cb8b35c | ||
|
|
f0ed7f22db | ||
|
|
ac91f07d22 | ||
|
|
d5a7a691a2 | ||
|
|
229b23b350 | ||
|
|
18ee9518ec | ||
|
|
43e0328722 | ||
|
|
12cf93ddd8 | ||
|
|
03b4467173 | ||
|
|
45a5ac28f2 | ||
|
|
635eec013c | ||
|
|
679b9217e0 | ||
|
|
39f3571383 | ||
|
|
f027cc6a3e | ||
|
|
634ce6829a | ||
|
|
64b5f9af78 | ||
|
|
9269fcb8a7 | ||
|
|
571b34c990 | ||
|
|
f0d29cb755 | ||
|
|
897e0f1ba6 | ||
|
|
4cfa94d304 | ||
|
|
5e2abb8a33 | ||
|
|
0dc5052e36 | ||
|
|
774ad1e2ff | ||
|
|
52e91cc309 | ||
|
|
38fb72ece9 | ||
|
|
fcbefa218b | ||
|
|
c06b9d696e | ||
|
|
d3e6274939 | ||
|
|
ec904eb8a4 | ||
|
|
68c5e996d6 | ||
|
|
95a09c5463 | ||
|
|
125fb598d5 | ||
|
|
f8c13f939c | ||
|
|
e55e08339a | ||
|
|
ec86260eb5 | ||
|
|
adee5cec2b | ||
|
|
c846b24ebb | ||
|
|
85324d9109 | ||
|
|
10b410d46f | ||
|
|
c87fe7c265 | ||
|
|
ce0984573b | ||
|
|
b38c3a5035 | ||
|
|
15dca65bd1 | ||
|
|
e1aa43147d | ||
|
|
057b18e4be | ||
|
|
d4f2ced6a3 | ||
|
|
0b6c92fcd2 | ||
|
|
4491e71ee2 | ||
|
|
d09f78801c | ||
|
|
f26ea32897 | ||
|
|
6b7f6aee22 | ||
|
|
514fd0730c | ||
|
|
854596fb04 | ||
|
|
cf6b8f752b | ||
|
|
702f36be0d | ||
|
|
c738bc1e96 | ||
|
|
6c1c13ed11 | ||
|
|
d1b39cce2b | ||
|
|
5e67622374 | ||
|
|
90e95bbd76 | ||
|
|
6deaacadea | ||
|
|
2ae4003f7d | ||
|
|
dd951d5350 | ||
|
|
c86d0230ba | ||
|
|
79345691b8 | ||
|
|
2763cf37f7 | ||
|
|
66cfe050e0 | ||
|
|
e6b1595cde | ||
|
|
3b376a3d3d | ||
|
|
5ed04d97dd | ||
|
|
1e724af838 | ||
|
|
aec00821e5 | ||
|
|
bf1542c35b | ||
|
|
5a6d27cc19 | ||
|
|
2d83abbb85 | ||
|
|
a9afa42f52 | ||
|
|
a37f1c5dcb | ||
|
|
ecac2bd084 | ||
|
|
01aec3760c | ||
|
|
33cac4832f | ||
|
|
41b246903f | ||
|
|
4148e0c7a9 | ||
|
|
729bdd9c68 | ||
|
|
1f2d8d6340 | ||
|
|
de3cf327d4 | ||
|
|
fa3da880ea | ||
|
|
5dea57ddd5 | ||
|
|
caa59cbb62 | ||
|
|
51e32f72de | ||
|
|
32089aefce | ||
|
|
048bc53bd0 | ||
|
|
69e1d04638 | ||
|
|
de4c7a04c3 | ||
|
|
2c79181c05 | ||
|
|
5b37ec0de5 | ||
|
|
86dbea7ddb | ||
|
|
c49e7e181b | ||
|
|
b0dbbc51df | ||
|
|
91779a67fb | ||
|
|
1fe6cde934 | ||
|
|
3b8d00095e | ||
|
|
4221ddbb35 | ||
|
|
eeb0c22d90 | ||
|
|
eb801e66ae | ||
|
|
3fdf639bb4 | ||
|
|
4061ef65e4 | ||
|
|
0cf8af00b3 | ||
|
|
4d0d4ca6ea | ||
|
|
56cdae67c3 | ||
|
|
b50017cad4 | ||
|
|
62c616f197 | ||
|
|
fcfeda9f39 | ||
|
|
c85c38cde3 | ||
|
|
f606eda18d | ||
|
|
08c9e2dde3 | ||
|
|
dd965e03c5 | ||
|
|
3e3f5faacc | ||
|
|
7e41cd0d32 | ||
|
|
882bf7b020 | ||
|
|
da4e70bc60 | ||
|
|
f75f720c8a | ||
|
|
8d3aff5ff1 | ||
|
|
4e8c9078f7 | ||
|
|
41e4efcf1f | ||
|
|
f55e6138a5 | ||
|
|
147e24d835 | ||
|
|
4a94858ed1 | ||
|
|
e1d77e12b9 | ||
|
|
8e51d1eaf3 | ||
|
|
738835088b | ||
|
|
823b287eda | ||
|
|
a2c195e844 | ||
|
|
5a5503ab34 | ||
|
|
6e037a4d46 | ||
|
|
14597f74f4 | ||
|
|
fabf2479ec | ||
|
|
12c90bae04 | ||
|
|
37904db9cd | ||
|
|
499d9da75f | ||
|
|
198d612b87 | ||
|
|
e7667ba34b | ||
|
|
861ef7313b | ||
|
|
0291ffb951 | ||
|
|
93a7f9f3b8 | ||
|
|
62337e34a3 | ||
|
|
a24b70de75 | ||
|
|
6f7f10b2f7 | ||
|
|
bd7579fa65 | ||
|
|
430a2ea2f6 | ||
|
|
87569617ae | ||
|
|
b17beaccf1 | ||
|
|
cddba64151 | ||
|
|
ed3a18529a | ||
|
|
06bffb9cee | ||
|
|
a6e4ff83f0 | ||
|
|
a73025d20b | ||
|
|
0085ebb756 | ||
|
|
5d5f23cddc | ||
|
|
761c947e25 | ||
|
|
ec33766803 | ||
|
|
6daf891c5c | ||
|
|
9b04553fc8 | ||
|
|
a006bfeb24 | ||
|
|
71e1a8666d | ||
|
|
820c7e660a | ||
|
|
e94cb6a4b6 | ||
|
|
16e7872a82 | ||
|
|
aa4ebb07f8 | ||
|
|
4366d6a8c7 | ||
|
|
aa76d49234 | ||
|
|
d9df06644e | ||
|
|
554ee01263 | ||
|
|
b3055067d8 | ||
|
|
7f997d4b59 | ||
|
|
07717b2d08 | ||
|
|
7d2162b2d2 | ||
|
|
d15fa0cfb3 | ||
|
|
d2d959f455 | ||
|
|
a9e497f878 | ||
|
|
e423e9ffba | ||
|
|
3b8b52d222 | ||
|
|
b9514692fe | ||
|
|
73592f76ba | ||
|
|
47f0f1fab8 | ||
|
|
bb3a5620d3 | ||
|
|
268a1475f0 | ||
|
|
a46dad9fde | ||
|
|
3f7bf15cdb | ||
|
|
ed9f883301 | ||
|
|
2386d46609 | ||
|
|
0da1dbdc14 | ||
|
|
dba635aac5 | ||
|
|
e1ca49c082 | ||
|
|
a47d5f4f12 | ||
|
|
e809133c25 | ||
|
|
4e39979852 | ||
|
|
ff99fae928 | ||
|
|
2e0353c725 | ||
|
|
3c9983ca12 | ||
|
|
d3412e7de6 | ||
|
|
908fa55674 | ||
|
|
4a26332133 | ||
|
|
6c17c5a3a2 | ||
|
|
1e6f54f055 | ||
|
|
59da873adf | ||
|
|
fb4b1827db | ||
|
|
2e2263ed58 | ||
|
|
ac18199295 | ||
|
|
4a954853f2 | ||
|
|
1973f1a1de | ||
|
|
d36a448aff | ||
|
|
29aa481d2d | ||
|
|
5c276c34ea | ||
|
|
1d2b654021 | ||
|
|
bdfb0bb14f | ||
|
|
6eeb03f159 | ||
|
|
f806416b84 | ||
|
|
7e64e60625 | ||
|
|
a44d4bccc2 | ||
|
|
b8c3e95068 | ||
|
|
85e55f3be2 | ||
|
|
eaee9e0e49 | ||
|
|
e232c42fc5 | ||
|
|
c7c043c898 | ||
|
|
57b718ff32 | ||
|
|
f2775c18a1 | ||
|
|
d1001aea1a | ||
|
|
39e33f3538 | ||
|
|
a786fa534a | ||
|
|
2a0831ab5a | ||
|
|
c6b61b0838 | ||
|
|
e73e480939 | ||
|
|
e5d53b4964 | ||
|
|
1521fde0bd | ||
|
|
eee0e81e6b | ||
|
|
c7be3d73b9 | ||
|
|
8574d50eaa | ||
|
|
2841942899 | ||
|
|
eb33c9ec81 | ||
|
|
56679d2a8e | ||
|
|
415e79b523 | ||
|
|
9a6fdaa42b | ||
|
|
ff54168a10 | ||
|
|
b2acd5fa75 | ||
|
|
33d0f1fd94 | ||
|
|
bb4f09316a | ||
|
|
b5976dc2ff | ||
|
|
47824ec1ac | ||
|
|
9223b089b1 | ||
|
|
6da9a1285c | ||
|
|
3b90e24ff8 | ||
|
|
93da60c03b | ||
|
|
a3e501a355 | ||
|
|
0cdbe998cb | ||
|
|
35b0c49da5 | ||
|
|
d43c9f006b | ||
|
|
01a6ae61d2 | ||
|
|
a25d9e7aa7 | ||
|
|
440020726f | ||
|
|
36ad643a5f | ||
|
|
2b6800f01b | ||
|
|
b7cb3ee89f | ||
|
|
c9490b9ef8 | ||
|
|
87210a3c15 | ||
|
|
a314d33dea | ||
|
|
4c305b7532 | ||
|
|
19cd6a1bdf | ||
|
|
dbd276dd9c | ||
|
|
28913e3a72 | ||
|
|
d0465eccf1 | ||
|
|
3aedec3e2d | ||
|
|
f931d60ac1 | ||
|
|
4b4b233377 | ||
|
|
ccc9907034 | ||
|
|
7c8146128e | ||
|
|
6c506ba556 | ||
|
|
5a7baa0a3b | ||
|
|
26520abe2b | ||
|
|
1397c3248d | ||
|
|
c40dc39b88 | ||
|
|
a2753bb27d | ||
|
|
1c5529691b | ||
|
|
8e5bdc6b2b | ||
|
|
c5342e4a15 | ||
|
|
47a1cce5fa | ||
|
|
ef60fcb9ec | ||
|
|
b45a1bd913 | ||
|
|
9a8a0932d0 | ||
|
|
ccd06ee534 | ||
|
|
5f5e33027a | ||
|
|
3fbdfa1583 | ||
|
|
624bc1de56 | ||
|
|
597100d108 | ||
|
|
418f97dbba | ||
|
|
6a38671e3c | ||
|
|
4f8542c133 | ||
|
|
0f2d49b2d6 | ||
|
|
39324d6b55 | ||
|
|
b1ad187d1b | ||
|
|
606f15fec5 | ||
|
|
34a2f1ad65 | ||
|
|
ce20fb535d | ||
|
|
bfe8323753 | ||
|
|
f2b86ad3ed | ||
|
|
42b498654b | ||
|
|
888a4e1c0e | ||
|
|
09a0eb26d1 | ||
|
|
bf9e8048ff | ||
|
|
1c6d2864b6 | ||
|
|
21ebc226e4 | ||
|
|
8e3fef9096 | ||
|
|
829dccc1b6 | ||
|
|
a65caa62b3 | ||
|
|
ddb6f9c5b4 | ||
|
|
e152ab6cf2 | ||
|
|
4085af023a | ||
|
|
686e401368 | ||
|
|
8ec079945a | ||
|
|
4d8dbefc85 | ||
|
|
746c05081d | ||
|
|
2fdfa64b13 | ||
|
|
f406cfcebb | ||
|
|
80f35725e6 | ||
|
|
6741d99681 | ||
|
|
ad4ec14778 | ||
|
|
2bf16ad88b | ||
|
|
6c56581c15 | ||
|
|
ce89d9fbe0 | ||
|
|
9517191e35 | ||
|
|
e298f74310 | ||
|
|
c550c1373e | ||
|
|
6a1bb88c3b | ||
|
|
a585e96fdf | ||
|
|
e78ef493a1 | ||
|
|
c139378694 | ||
|
|
e51827bfcd | ||
|
|
d0eb3e760f | ||
|
|
9cfa3e5002 | ||
|
|
bb76621b7f | ||
|
|
c6746f6f77 | ||
|
|
714d453aa0 | ||
|
|
915c8d7afa | ||
|
|
1bf51a047e | ||
|
|
a7b2fe14b9 | ||
|
|
82278037ec | ||
|
|
0b592f86d0 | ||
|
|
ee4e003c2d | ||
|
|
b2904bc6fb | ||
|
|
67b94cf52e | ||
|
|
c308d2c9dd | ||
|
|
e36370b080 | ||
|
|
d0f005a6f1 | ||
|
|
a461fa9137 | ||
|
|
22e969fb59 | ||
|
|
34527c8395 | ||
|
|
012f4d68bc | ||
|
|
da8d0f3265 | ||
|
|
9b57d18143 | ||
|
|
9f0ac51e06 | ||
|
|
74b9e51cf7 | ||
|
|
ec4d8d7f9c | ||
|
|
011a19772d | ||
|
|
d8cef76592 | ||
|
|
856b0f4469 | ||
|
|
ca76d41f9a | ||
|
|
f7ba6e1121 | ||
|
|
df19dbc0de | ||
|
|
3b3e64e752 | ||
|
|
724283433a | ||
|
|
aea19b93b1 | ||
|
|
73020a711d | ||
|
|
7e62e671e3 | ||
|
|
2e845ac0ab | ||
|
|
2df41e52ed | ||
|
|
bf8e93f581 | ||
|
|
f5eec3283c | ||
|
|
223161c7d6 | ||
|
|
b8ba6e4827 | ||
|
|
15c8259ac2 | ||
|
|
720492932f | ||
|
|
a08a0fb084 | ||
|
|
827fbaac1f | ||
|
|
0de3175775 | ||
|
|
008b807803 | ||
|
|
08b53410b4 | ||
|
|
ce06b2cb18 | ||
|
|
d4d5a04487 | ||
|
|
297224bd31 | ||
|
|
9dc835c60c | ||
|
|
67a96bc2f3 | ||
|
|
92d98c8d59 | ||
|
|
7becb19da4 | ||
|
|
deee654426 | ||
|
|
552fd52bd5 | ||
|
|
f58fb3e556 | ||
|
|
ff5bf16111 | ||
|
|
8d22059462 | ||
|
|
91d144f5f7 | ||
|
|
c894b1d335 | ||
|
|
d30a7bf6a1 | ||
|
|
7f18cbf7d5 | ||
|
|
e7741b3d1f | ||
|
|
561bc42259 | ||
|
|
649d5f56c9 | ||
|
|
3e4ca5ceb9 | ||
|
|
81b53112c1 | ||
|
|
fe1a635c14 | ||
|
|
521e6033a2 | ||
|
|
36b033c2f7 | ||
|
|
dc9bce915b | ||
|
|
37a0e733ad | ||
|
|
b3005eeec7 | ||
|
|
b21bfda7f6 | ||
|
|
a2f9662a99 | ||
|
|
274254b12e | ||
|
|
087e17511c | ||
|
|
139e868cce | ||
|
|
b6ec84e94d | ||
|
|
2b09392261 | ||
|
|
2132384736 | ||
|
|
8798f467e1 | ||
|
|
c9a7cfafd0 | ||
|
|
9d9585ecba | ||
|
|
3204bcb7a0 | ||
|
|
645a5206ec | ||
|
|
28baf4de5e | ||
|
|
04ddcd9489 | ||
|
|
a82f392cac | ||
|
|
15d308864c | ||
|
|
9af3a0d725 | ||
|
|
d2494fb97d | ||
|
|
c32ef61d3a | ||
|
|
6020d06038 | ||
|
|
b2b1b1cb47 | ||
|
|
023a605cad | ||
|
|
a61e31f646 | ||
|
|
0361436a66 | ||
|
|
c800670f39 | ||
|
|
7fa42cbdd3 | ||
|
|
f3f39e283e | ||
|
|
c9e1159c42 | ||
|
|
f9f8f7aebd | ||
|
|
ee3941b86a | ||
|
|
f9499e4b2f | ||
|
|
0ebd7e6a58 | ||
|
|
a100abc3b6 | ||
|
|
94f6945d5a | ||
|
|
870d57bfa5 | ||
|
|
a02f26f0eb | ||
|
|
442d771a7a | ||
|
|
242e11eefc | ||
|
|
97edd21784 | ||
|
|
17f793a4bb | ||
|
|
2f16e17ed5 | ||
|
|
27ae79f50d | ||
|
|
eb18c0a505 | ||
|
|
103d1adc46 | ||
|
|
db661f124f | ||
|
|
4c3802878a | ||
|
|
23e560b638 | ||
|
|
b82a2ee735 | ||
|
|
7fbbae8cd4 | ||
|
|
83b6820458 | ||
|
|
b80d96d9c7 | ||
|
|
d8e69360b9 | ||
|
|
83ae9b66a3 | ||
|
|
3a7b4fd404 | ||
|
|
578557f3d7 | ||
|
|
92b7668067 | ||
|
|
95f9170736 | ||
|
|
52be2230cb | ||
|
|
4738150c55 | ||
|
|
88b4847ba9 | ||
|
|
f532eb708e | ||
|
|
94a24b3f57 | ||
|
|
62fadc8200 | ||
|
|
1370625568 | ||
|
|
8eed440840 | ||
|
|
1aed2b9a43 | ||
|
|
6ec31cc7f9 | ||
|
|
6d3b3e6de2 | ||
|
|
10fd2b5b5a | ||
|
|
d020acca22 | ||
|
|
e704733743 | ||
|
|
79522194f1 | ||
|
|
aadc9e64d8 | ||
|
|
2eea258b9b | ||
|
|
796e019f12 | ||
|
|
036bd999fd | ||
|
|
1fdb5373c9 | ||
|
|
0ebe5ff55a | ||
|
|
ef610ab7de | ||
|
|
68454492e9 | ||
|
|
4593b652c4 | ||
|
|
2670915583 | ||
|
|
8239226208 | ||
|
|
49be1638ba | ||
|
|
e188047cfb | ||
|
|
afd01cc40c | ||
|
|
2d0c0d2aad | ||
|
|
e811236973 | ||
|
|
12078f07c6 | ||
|
|
c9ef3fa1d7 | ||
|
|
0a724e5a73 | ||
|
|
2c9e4aacf2 | ||
|
|
41486d44ee | ||
|
|
7fb326245e | ||
|
|
542645d876 | ||
|
|
9a5cf69251 | ||
|
|
b322633e8b | ||
|
|
487cd384a5 | ||
|
|
0b0055e0e2 | ||
|
|
57a9b313c4 | ||
|
|
81e8b0eb18 | ||
|
|
26da7d5e81 | ||
|
|
76b85ed554 | ||
|
|
4064fedf55 | ||
|
|
a27ad2e353 | ||
|
|
13aa3914ac | ||
|
|
20ba998383 | ||
|
|
3cf56ff7d5 | ||
|
|
70a4ab863d | ||
|
|
d62ccfd234 | ||
|
|
4d6bcf27e9 | ||
|
|
130e417451 | ||
|
|
e6f2d9de86 | ||
|
|
415a1bffac | ||
|
|
798895d78d | ||
|
|
454436905c | ||
|
|
005b3356f2 | ||
|
|
4ac052c10b | ||
|
|
f1717f8319 | ||
|
|
cb000549bd | ||
|
|
c8d4d39068 | ||
|
|
8539298008 | ||
|
|
f7395b7d7c | ||
|
|
86758dcb70 | ||
|
|
f7c3b7c664 | ||
|
|
616d1a2c88 | ||
|
|
9f2b02d98e | ||
|
|
fc193b2d24 | ||
|
|
01d8d0dbec | ||
|
|
2712aa2ae2 | ||
|
|
7dcefa6bee | ||
|
|
70e3528809 | ||
|
|
c7780a2708 | ||
|
|
784d458e62 | ||
|
|
03c6614aed | ||
|
|
26f33b9581 | ||
|
|
0ba66d4d47 | ||
|
|
5bc0b24913 | ||
|
|
da87fd7747 | ||
|
|
49b1608af8 | ||
|
|
8bc6d7af8c | ||
|
|
479690f011 | ||
|
|
2510f21c81 | ||
|
|
d6e55dffb0 | ||
|
|
7df0e22664 | ||
|
|
8939fe0b83 | ||
|
|
c4cbfd352e | ||
|
|
aea39080d6 | ||
|
|
ecacdfaf49 | ||
|
|
d8719ede12 | ||
|
|
11834a4186 | ||
|
|
81381fac75 | ||
|
|
9fa91aab36 | ||
|
|
2897b66a1c | ||
|
|
ef77ac11ef | ||
|
|
382c857a4b | ||
|
|
c4bfbd3f94 | ||
|
|
f4c1a125e7 | ||
|
|
010e47634b | ||
|
|
086fda5f24 | ||
|
|
27b39c29b8 | ||
|
|
680ac9825a | ||
|
|
cfb3d14028 | ||
|
|
9f6bf62efc | ||
|
|
60ecceafec | ||
|
|
7b0b53a96d | ||
|
|
87d0e1d886 | ||
|
|
e84bc3754f | ||
|
|
26bab84d04 | ||
|
|
efea6136e7 | ||
|
|
c56026c18a | ||
|
|
1d9504d0f0 | ||
|
|
780b1f8acc | ||
|
|
b369fa2c7b | ||
|
|
7c96eb0819 | ||
|
|
febc3b7936 | ||
|
|
1e511dd655 | ||
|
|
e479e84bde | ||
|
|
19e3a2ecc4 | ||
|
|
d2290d509f | ||
|
|
9b6c5741de | ||
|
|
e09a3b8cbf | ||
|
|
0742e18edd | ||
|
|
cb59c2489b | ||
|
|
3158b544d5 | ||
|
|
e80270d1fa | ||
|
|
99b37f24bb | ||
|
|
fdbdcc4130 | ||
|
|
08104966b2 | ||
|
|
1c99133177 | ||
|
|
28780dc67e | ||
|
|
423ce54d8a | ||
|
|
73bab73db6 | ||
|
|
3e90471fa2 | ||
|
|
7f2db8a9a7 | ||
|
|
d5fc147ffd | ||
|
|
77ffd7bbf9 | ||
|
|
42775d3477 | ||
|
|
6932b8c378 | ||
|
|
cff641ef80 | ||
|
|
373abf1b24 | ||
|
|
f668596667 | ||
|
|
adf14f79e0 | ||
|
|
cd31799c4c | ||
|
|
93e0e815d7 | ||
|
|
05275c8938 | ||
|
|
19475db7dd | ||
|
|
63c005a3de | ||
|
|
4e984f5532 | ||
|
|
5cb79a4c1a | ||
|
|
083cb9cc9a | ||
|
|
f25903905c | ||
|
|
16216147bc | ||
|
|
8069e5568b | ||
|
|
0682df3801 | ||
|
|
b0800c7e38 | ||
|
|
e5c4391900 | ||
|
|
e33e7446ee | ||
|
|
f8c3e6adf3 | ||
|
|
de0eca7890 | ||
|
|
20ca17fcac | ||
|
|
6cbd1963bf | ||
|
|
2d292000a8 | ||
|
|
6e75f94505 | ||
|
|
e748bcb291 | ||
|
|
409a8c2a77 | ||
|
|
4cc09e49ac | ||
|
|
665b5363e3 | ||
|
|
5a05f40428 | ||
|
|
007b3644be | ||
|
|
93eba6ef68 | ||
|
|
0c7e593370 | ||
|
|
6b7df8fd50 | ||
|
|
4919b9cb48 | ||
|
|
3f81e0ab82 | ||
|
|
96f2e150a1 | ||
|
|
a38af3a31c | ||
|
|
f29023f11d | ||
|
|
3a93600195 | ||
|
|
974373dc40 | ||
|
|
36aacba237 | ||
|
|
2530c577dc | ||
|
|
54b7920697 | ||
|
|
9ead37845e | ||
|
|
bff9141a4f | ||
|
|
f11b2f6782 | ||
|
|
b5054a7a7f | ||
|
|
bf61ed6310 | ||
|
|
e52756bf9f | ||
|
|
421dbc28bd | ||
|
|
561a5b2b2e | ||
|
|
2bfdd033eb | ||
|
|
938ae7dc8e | ||
|
|
3f7bd98174 | ||
|
|
dc67e8bbde | ||
|
|
d0cef987fe | ||
|
|
af4131bb4d | ||
|
|
d6e0638cd9 | ||
|
|
030b6f9720 | ||
|
|
d9634030d4 | ||
|
|
79f5502b8e | ||
|
|
179781dfee | ||
|
|
413fd61900 | ||
|
|
9f605cae29 | ||
|
|
c557279607 | ||
|
|
aa315d7c97 | ||
|
|
080b25e30c | ||
|
|
75920e0a09 | ||
|
|
f46ec05a3a | ||
|
|
a87969d85f | ||
|
|
3231ac15c9 | ||
|
|
627c75b6b9 | ||
|
|
823a845752 | ||
|
|
f28ac0c037 | ||
|
|
727e02b816 | ||
|
|
a7c8c08183 | ||
|
|
b872f90365 | ||
|
|
8c3446fb1f | ||
|
|
504222b564 | ||
|
|
108fcd5691 | ||
|
|
e78dc4892f | ||
|
|
5cce1af3d7 | ||
|
|
92156e0520 | ||
|
|
9c13e48b62 | ||
|
|
bfc840d1a7 | ||
|
|
8bc7349635 | ||
|
|
ddbfc5c57a | ||
|
|
b1e97266e3 | ||
|
|
bb8c456a04 | ||
|
|
c5c9387226 | ||
|
|
ee6ff7daaa | ||
|
|
29c93d2b0d | ||
|
|
bb98627d2b | ||
|
|
3060866586 | ||
|
|
eacf121f78 | ||
|
|
c39535fdd0 | ||
|
|
c3311df2a8 | ||
|
|
99af52ac2f | ||
|
|
5a17314b2c | ||
|
|
05d974578d | ||
|
|
0d585a4d98 | ||
|
|
b968b4a9a4 | ||
|
|
07281f050c | ||
|
|
9c3757fb0c | ||
|
|
f5d5e59040 | ||
|
|
70880c066f | ||
|
|
5508c70f3a | ||
|
|
f100982b04 | ||
|
|
c8db2a85c6 | ||
|
|
3b086d130f | ||
|
|
cb8394fb07 | ||
|
|
a401f19ca1 | ||
|
|
444fd41d58 | ||
|
|
e3ccc6d558 | ||
|
|
8ed20e35ca | ||
|
|
bd16b485be | ||
|
|
9783de7464 | ||
|
|
9139fa7ec4 | ||
|
|
ba45539375 | ||
|
|
bb99abdebd | ||
|
|
89878dddf6 | ||
|
|
075ac9e280 | ||
|
|
d43f65366b | ||
|
|
052ab2d9bc | ||
|
|
74f7c93a6d | ||
|
|
36c3cac484 | ||
|
|
2fc014af03 | ||
|
|
8abd010d08 | ||
|
|
c117ef3000 | ||
|
|
543407920d | ||
|
|
3dbdb541ed | ||
|
|
8f24858af8 | ||
|
|
f2667bfcae | ||
|
|
4bbafe13e6 | ||
|
|
f33bac5b59 | ||
|
|
85d2a33620 | ||
|
|
643f4fddf9 | ||
|
|
8ec8118d39 | ||
|
|
dcabf2738a | ||
|
|
a4fbe65259 | ||
|
|
83d76a0781 | ||
|
|
59fbc308b0 | ||
|
|
7266410840 | ||
|
|
e4312ed5cc | ||
|
|
1642a7714f | ||
|
|
c62be68bda | ||
|
|
a1befc78e0 | ||
|
|
fdb8e0e2e5 | ||
|
|
7b803d855f | ||
|
|
3116fde51c | ||
|
|
714c542da9 | ||
|
|
1c7e272ac3 | ||
|
|
31f66c7142 | ||
|
|
5e1d49cc7e | ||
|
|
495a72d167 | ||
|
|
e0eabb8d71 | ||
|
|
4c2c804d0d | ||
|
|
733c375afe | ||
|
|
5dce6e416e | ||
|
|
201bf29429 | ||
|
|
408417bbda | ||
|
|
3d8c8a36dd | ||
|
|
ca1b9d35dd | ||
|
|
2841bfe819 | ||
|
|
1694b10690 |
19
.editorconfig
Normal file
19
.editorconfig
Normal file
@@ -0,0 +1,19 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[**.std]
|
||||
insert_final_newline = false
|
||||
|
||||
[{package,bower}.json]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
52
.eslintrc
Normal file
52
.eslintrc
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"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, "consistent", { "keywords": true }],
|
||||
"quotes": [2, "single", "avoid-escape"],
|
||||
"indent": [2, 4],
|
||||
"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, {"anonymous": "always", "named": "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
|
||||
}
|
||||
}
|
||||
44
.github/ISSUE_TEMPLATE.md
vendored
Normal file
44
.github/ISSUE_TEMPLATE.md
vendored
Normal 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:**
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,3 +1,2 @@
|
||||
node_modules
|
||||
components
|
||||
.DS_Store
|
||||
npm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
31
.travis.yml
31
.travis.yml
@@ -1,4 +1,33 @@
|
||||
sudo: false
|
||||
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- "0.10"
|
||||
- "0.8"
|
||||
- "0.11"
|
||||
- "0.12"
|
||||
- "4.0"
|
||||
- "4.1"
|
||||
- "4.2"
|
||||
- "5"
|
||||
- "6"
|
||||
|
||||
install:
|
||||
- node --version
|
||||
- npm --version
|
||||
- git --version
|
||||
- svn --version | head -n 1
|
||||
- npm install
|
||||
|
||||
os:
|
||||
- osx
|
||||
- linux
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- os: osx
|
||||
- env: "NODE_VERSION=0.11"
|
||||
|
||||
script:
|
||||
- npm test
|
||||
|
||||
503
CHANGELOG.md
503
CHANGELOG.md
@@ -1,10 +1,509 @@
|
||||
# Changelog
|
||||
|
||||
## 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.
|
||||
|
||||
|
||||
## 1.3.0 - 2014-03-10
|
||||
|
||||
- **Removed support for node 0.8.** It may still work but we will no longer fix bugs for older versions of node.
|
||||
- Add **Bower Insight** for opt-in analytics integration to help improve tool and gain insight on community trends
|
||||
- Old overview of [Insight](https://github.com/yeoman/yeoman/wiki/Insight), [Issue #260](https://github.com/bower/bower/issues/260)
|
||||
- Reporting to GA. Public Dashboard is in progress.
|
||||
- [Turn off interactive mode](https://github.com/bower/bower/issues/1162) if you run Bower in a CI environment
|
||||
- Add `moduleType` property to bower init ([#934](https://github.com/bower/bower/pull/934))
|
||||
- Fix prune command to log only after cleanup is completed ([#1023](https://github.com/bower/bower/issues/1023))
|
||||
- Fix git resolver to ignore pre-release versions ([#1017](https://github.com/bower/bower/issues/1017))
|
||||
- Fix shorthand flag for `save` option on `uninstall` command ([#1031](https://github.com/bower/bower/pull/1031))
|
||||
- Add `bower version` command ([#961](https://github.com/bower/bower/pull/961))
|
||||
- Add .bowerrc option to use `--save` by default when using `bower install` command ([#1074](https://github.com/bower/bower/pull/1074))
|
||||
- Fix git resolver caching ([#1083](https://github.com/bower/bower/issues/1083))
|
||||
- Fix reading versions from cache directory ([#1076](https://github.com/bower/bower/pull/1076))
|
||||
- Add svn support ([#1055](https://github.com/bower/bower/pull/1055))
|
||||
- Allow circular dependencies to be installed ([#1104](https://github.com/bower/bower/pull/1104))
|
||||
- Add scripts/hooks support ([#718](https://github.com/bower/bower/pull/718))
|
||||
|
||||
_NOTE_: It's advisable that users use `--config.interactive=false` on automated scripts.
|
||||
|
||||
|
||||
## 1.2.8 - 2013-12-02
|
||||
- Fix absolute paths ending with / not going through the FsResolver, ([#898](https://github.com/bower/bower/issues/898))
|
||||
- Allow query string parameters in package URLs
|
||||
- Swapped 'unzip' module for 'decompress-zip', and some other small unzipping fixes([#873](https://github.com/bower/bower/issues/873), [#896](https://github.com/bower/bower/issues/896))
|
||||
- Allow the root-check to be overridden when calling bower programmatically.
|
||||
- Fixed some bugs relating to packages with a very large dependency tree
|
||||
- Fix a bug caused by a recent change to semver
|
||||
|
||||
|
||||
## 1.2.7 - 2013-09-29
|
||||
|
||||
- Do not swallow sync errors when using the programmatic API ([#849](https://github.com/bower/bower/issues/849))
|
||||
- Fix resolutions not being saved if `--force-latest` is specified ([#861](https://github.com/bower/bower/issues/861))
|
||||
- Fix `bower register` warning about URL conversion, even if no conversion occurred
|
||||
- Fix `bower update` not correctly catching up branch commits
|
||||
- Add configured directory in `.bowerrc` to the ignores in `bower init` ([#854](https://github.com/bower/bower/issues/854))
|
||||
- Fix some case sensitive issues with data stored in registry cache (e.g.: jquery/jQuery, [#859](https://github.com/bower/bower/issues/859))
|
||||
- Fix bower not checking out a tag if it looks like a semver (e.g.: 1.0, [#872](https://github.com/bower/bower/issues/872))
|
||||
- Fix install & update commands printing the wrong versions in some cases ([#879](https://github.com/bower/bower/issues/879))
|
||||
- Give priority to mime type headers when deciding if a package need to be extracted, except if it is `octet-stream`
|
||||
|
||||
_NOTE_: It's advisable that users run `bower cache clean`.
|
||||
|
||||
|
||||
## 1.2.6 - 2013-09-04
|
||||
|
||||
- Bower now reports download progress even for servers that do not respond with `content-length` header.
|
||||
- Do not translate endpoints when registering a package to a private registry server ([#832](https://github.com/bower/bower/issues/832))
|
||||
- Detect corrupted downloads by comparing downloaded bytes with `content-length` header if possible; this fixes Bower silently failing on unstable networks ([#824](https://github.com/bower/bower/issues/824) and [#792](https://github.com/bower/bower/issues/792))
|
||||
- Fix quotes in fields causing Bower to crash in the `init` command ([#841](https://github.com/bower/bower/issues/841))
|
||||
|
||||
|
||||
## 1.2.5 - 2013-08-28
|
||||
|
||||
- Fix persistent conflict resolutions not working correctly for branches ([#818](https://github.com/bower/bower/issues/818))
|
||||
- Fix Bower failing to run if HOME is not set ([#826](https://github.com/bower/bower/issues/826))
|
||||
- Bower now prints a warning if HOME is not set ([#827](https://github.com/bower/bower/issues/827))
|
||||
- Fix progress message being fired after completion of long running `git clone` commands
|
||||
- Other minor improvements
|
||||
|
||||
|
||||
## 1.2.4 - 2013-08-23
|
||||
|
||||
- Fix ignored nested folders not being correctly handled in some cases ([#814](https://github.com/bower/bower/issues/814))
|
||||
|
||||
|
||||
## 1.2.3 - 2013-08-22
|
||||
|
||||
- Fix read of environment variables that map to config properties with dashes and also support nested ones ([#8@bower-config](https://github.com/bower/config/issues/8))
|
||||
- Fix `bower info <package> <property>` printing the available versions (it shouldn't!)
|
||||
- Fix interactive shell not being correctly detected in node `0.8.x` ([#802](https://github.com/bower/bower/issues/802))
|
||||
- Fix `extraneous` flag in the `list` command being incorrectly set for saved dev dependencies in some cases
|
||||
- Fix linked dependencies not being read in `bower list` on Windows ([#813](https://github.com/bower/bower/issues/813))
|
||||
- Fix update notice not working with `--json`
|
||||
|
||||
|
||||
## 1.2.2 - 2013-08-20
|
||||
|
||||
- Standardize prompt behaviour with and without `--json`
|
||||
- Improve detection of `git` servers that do not support shallow clones ([#805](https://github.com/bower/bower/issues/805))
|
||||
- Ignore remote tags (tags ending with ^{})
|
||||
- Fix bower not saving the correct endpoint in some edge cases ([#806](https://github.com/bower/bower/issues/806))
|
||||
|
||||
|
||||
## 1.2.1 - 2013-08-19
|
||||
|
||||
- Fix bower throwing on non-semver targets ([#800](https://github.com/bower/bower/issues/800))
|
||||
|
||||
|
||||
## 1.2.0 - 2013-08-19
|
||||
|
||||
- __Bower no longer installs a pre-release version by default, that is, if no version/range is specified__ ([#782](https://github.com/bower/bower/issues/782))
|
||||
- __`bower info <package>` will now show the latest `<package>` information along with the available versions__ ([#759](https://github.com/bower/bower/issues/759))
|
||||
- __`bower link` no longer requires an elevated user on Windows in most cases__ ([#472](https://github.com/bower/bower/issues/472))
|
||||
- __Init command now prompts for the whole `bower.json` spec properties, filling in default values for `author` and `homepage` based on `git` settings__ ([#693](https://github.com/bower/bower/issues/693))
|
||||
- Changes to endpoint sources in `bower.json` are now catched up by `bower install` and `bower update` ([#788](https://github.com/bower/bower/issues/788))
|
||||
- Allow semver ranges in `bower cache clean`, e.g. `bower cache clean jquery#<2.0.0` ([#688](https://github.com/bower/bower/issues/688))
|
||||
- Normalize `bower list --paths` on Windows ([#279](https://github.com/bower/bower/issues/279))
|
||||
- Multiple mains are now correctly outputted as an array in `bower list --paths` ([#784](https://github.com/bower/bower/issues/784))
|
||||
- Add `--relative` option to `bower list --json` so that Bower outputs relative paths instead of absolute ([#714](https://github.com/bower/bower/issues/714))
|
||||
- `bower list --paths` now outputs relative paths by default; can be turned off with `--no-relative` ([#785](https://github.com/bower/bower/issues/785))
|
||||
- Bower no longer fails if `symlinks` to files are present in the `bower_components` folder ([#783](https://github.com/bower/bower/issues/783) and [#791](https://github.com/bower/bower/issues/791))
|
||||
- Disable git templates/hooks when running `git` ([#761](https://github.com/bower/bower/issues/761))
|
||||
- Add instructions to setup git workaround for proxies when execution of `git` fails ([#250](https://github.com/bower/bower/issues/250))
|
||||
- Ignore `component.json` if it looks like a component(1) file ([#556](https://github.com/bower/bower/issues/556))
|
||||
- Fix multi-user usage on bower when it creates temporary directories to hold some files
|
||||
- Fix prompting causing an invalid JSON output when running commands with `--json`
|
||||
- When running Bower commands programmatically, prompting is now disabled by default (see the updated programmatic [usage](https://github.com/bower/bower#programmatic-api) for more info)
|
||||
- Other minor improvements and fixes
|
||||
|
||||
Fix for `#788` requires installed components to be re-installed.
|
||||
|
||||
|
||||
## 1.1.2 - 2013-08-10
|
||||
|
||||
- Detect and fallback if the git server does not support `--depth=1` when cloning ([#747](https://github.com/bower/bower/issues/747))
|
||||
|
||||
|
||||
## 1.1.1 - 2013-08-08
|
||||
|
||||
- Fix silent fail when spawning child processes in some edge cases ([#722](https://github.com/bower/bower/issues/722))
|
||||
- Fix `home` command not guessing the correct URL for `GitHub` ssh endpoints (requires `bower cache-clean`)
|
||||
- Fix bower not correctly filtering packages with symlinks in some cases ([#730](https://github.com/bower/bower/issues/730))
|
||||
- Fix multi-user usage on bower when it falls back to create a `/tmp/bower` folder ([#743](https://github.com/bower/bower/issues/743))
|
||||
- Bower now sends a fake user agent when behind a proxy by default, so that corporate proxies do not block requests ([#698](https://github.com/bower/bower/issues/698))
|
||||
- Bower now translates GitHub public `git://` URLs to `git@` when behind a proxy ([#731](https://github.com/bower/bower/issues/731))
|
||||
- Minor improvements to the CLI output on small terminals
|
||||
- Minor programmatic usage improvements
|
||||
- Minor help usage fixes
|
||||
|
||||
|
||||
## 1.1.0 - 2013-08-03
|
||||
|
||||
- __Fix `--save` and `--save-dev` not working correctly for the uninstall command in some situations__
|
||||
- __Attempting to register a package that declares `"private": true` in `bower.json` will result in an error ([#162](https://github.com/bower/bower/issues/162))__
|
||||
- __Fix retry strategy on download error that was causing some strange I/O errors__ ([#699](https://github.com/bower/bower/issues/699) and [#704](https://github.com/bower/bower/issues/704))
|
||||
- __`bower prune` now clears pruned packages dependencies if they are also extraneous__ ([#708](https://github.com/bower/bower/issues/708))
|
||||
- __`bower uninstall` now uninstalls uninstalled packages dependencies if they are not shared ([#609](https://github.com/bower/bower/issues/609))__
|
||||
- Fix `bower list` display the `incompatible` label even if they are compatible ([#710](https://github.com/bower/bower/issues/710))
|
||||
- Fix `bower cache clean` not working correctly when `package#non-semver` is specified
|
||||
- Implement no operation `completion` command to prevent weird output when hitting tab ([#691](https://github.com/bower/bower/issues/691))
|
||||
- Fix `bower info --help` ([#703](https://github.com/bower/bower/issues/703))
|
||||
- Add colorized output for `bower info <package>#<version>` ([#571](https://github.com/bower/bower/issues/571))
|
||||
- Added `bower ls` as an alias to `bower list`
|
||||
- Fix regression: do not create a json file when saving is required, warn instead
|
||||
- Ignore linked packages when reading dependencies in `bower init` ([#709](https://github.com/bower/bower/issues/709))
|
||||
- `bower list` is now able to (partially) reconstruct the dependency tree, even for dependencies not declared in `bower.json` ([#622](https://github.com/bower/bower/issues/622))
|
||||
|
||||
|
||||
## 1.0.3 - 2013-07-30
|
||||
|
||||
- Fix some changes not being saved to bower.json ([#685](https://github.com/bower/bower/issues/685))
|
||||
- Fix `bower info <package> <property>` not showing information related to property of the latest version of that package ([#684](https://github.com/bower/bower/issues/684))
|
||||
|
||||
|
||||
## 1.0.2 - 2013-07-30
|
||||
|
||||
- Fix severe bug originated from a wrong merge that caused conflict messages to not show up correctly
|
||||
|
||||
|
||||
## 1.0.1 - 2013-07-29
|
||||
|
||||
- Fix `bower register` going ahead even if the answer was `no` ([#644](https://github.com/bower/bower/issues/644))
|
||||
- Fix local endpoints with backslashes on Windows ([#2@endpoint-parser](https://github.com/bower/endpoint-parser/pull/2))
|
||||
- Fix usage of multiple registries in the registry-client ([#3@registry-client](https://github.com/bower/registry-client/pull/3) and [#2@registry-client](https://github.com/bower/registry-client/pull/2))
|
||||
- File extensions now have more priority than mime types when deciding if extraction is necessary ([#657](https://github.com/bower/bower/pull/657))
|
||||
- Fix `Bower` not working when calling `.bat`/`.cmd` commands on Windows; it affected people using `Git portable` ([#626](https://github.com/bower/bower/issues/626))
|
||||
- Fix `bower list --paths` not resolving all files to absolute paths when the `main` property contained multiple files ([660](https://github.com/bower/bower/issues/660))
|
||||
- Fix `Bower` renaming `bower.json` and `component.json` files to `index.json` when it was the only file in the folder ([#674](https://github.com/bower/bower/issues/674))
|
||||
- Ignore symlinks when copying/extracting since they are not portable, specially across different hard-drives ([#665](https://github.com/bower/bower/issues/665))
|
||||
- Local file/dir endpoints are now exclusively referenced by an absolute path or relative path starting with `.` ([#666](https://github.com/bower/bower/issues/666))
|
||||
- Linked packages `bower.json` files are now parsed, making `bower list` account linked packages dependencies ([#659](https://github.com/bower/bower/issues/659))
|
||||
- Bower now fails to run with sudo unless `--allow-root` is passed ([#498](https://github.com/bower/bower/issues/498))
|
||||
- Add additional system information such as node version, bower version, OS version when an error occurs ([#670](https://github.com/bower/bower/issues/670))
|
||||
- `bower install` no longer overwrites `linked` packages unless it needs to ([#593](https://github.com/bower/bower/issues/593)).
|
||||
- All endpoint parts are now trimmed so that the Manager can better detect similar endpoints ([#3@endpoint-parser](https://github.com/bower/endpoint-parser/pull/3))
|
||||
- `bower register` now shows the server that will be used ([#647](https://github.com/bower/endpoint-parser/pull/647))
|
||||
|
||||
|
||||
## 1.0.0 - 2013-07-23
|
||||
|
||||
Total rewrite of bower.
|
||||
The list bellow highlights the most important stuff.
|
||||
For a complete list of changes that this rewrite and release brings please read: https://github.com/bower/bower/wiki/Rewrite-state
|
||||
|
||||
|
||||
- Clear architecture and separation of concerns
|
||||
- Much much faster
|
||||
- `--json` output for all commands
|
||||
- `--offline` usage for all commands, except `register`
|
||||
- Proper `install` and `update` commands, similar to `npm` in behaviour
|
||||
- Named endpoints when installing, e.g. `bower install backbone-amd=backbone#~1.0.0`
|
||||
- New interactive conflict resolution strategy
|
||||
- Prevent human errors when using `register`
|
||||
- New `home` command, similar to `npm`
|
||||
- New `cache list` command
|
||||
- New `prune` command
|
||||
- Many many general bug fixes
|
||||
|
||||
Non-backwards compatible changes:
|
||||
|
||||
- The value of the `json` property from .bowerrc is no longer used
|
||||
- `--map` and `--sources` from the list command were removed, use `--json` instead
|
||||
- Programmatic usage changed, specially the commands interface
|
||||
|
||||
Users upgrading from `bower-canary` and `bower@~0.x.x` should do a `bower cache clean`.
|
||||
Additionally you may remove the `~/.bower` folder manually since it's no longer used.
|
||||
On Windows the folder is located in `AppData/bower`.
|
||||
|
||||
|
||||
## 0.10.0 - 2013-07-02
|
||||
|
||||
- __Allow specific commits to be targeted__ ([#275](https://github.com/bower/bower/issues/275))
|
||||
- __Change bower default folder from `components` to `bower_components`__ ([#434](https://github.com/bower/bower/issues/434))
|
||||
- __Support semver pre-releases and builds ([#188](https://github.com/bower/bower/issues/188))
|
||||
- __Support semver pre-releases and builds__ ([#188](https://github.com/bower/bower/issues/188))
|
||||
- Use `Content-Type` and `Content-Disposition` to guess file types, such as zip files ([#454](https://github.com/bower/bower/pull/454))
|
||||
- Fix bower failing silently when using an invalid version value in the bower.json file ([#439](https://github.com/bower/bower/issues/439))
|
||||
- Fix bower slowness when downloading after redirects ([#437](https://github.com/bower/bower/issues/437))
|
||||
@@ -123,7 +622,7 @@ _NOTE_: The `components` folder will still be used if already created, making it
|
||||
|
||||
## 0.6.1 - 2012-11-22
|
||||
- Fix uninstall when the project component.json has no deps saved ([#153](https://github.com/bower/bower/issues/153))
|
||||
- Fix uncaught errors when using file writter (they are now caught and reported)
|
||||
- Fix uncaught errors when using file writer (they are now caught and reported)
|
||||
- Fix temporary directories not being deleted when an exception occurs ([#153](https://github.com/bower/bower/issues/140))
|
||||
|
||||
## 0.6.0 - 2012-11-21
|
||||
|
||||
@@ -1,13 +1,26 @@
|
||||
# Contributing to Bower
|
||||
|
||||
Please take a moment to review this document in order to make the contribution
|
||||
process easy and effective for everyone involved.
|
||||
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. If you're interested in becoming a Bower maintainer or supporting in any way, please fill the following form: http://goo.gl/forms/P1ndzCNoiG. There is more information about [contributing](https://github.com/bower/bower/wiki/Contributor-Guidelines) in the Wiki.
|
||||
|
||||
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.
|
||||
<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))
|
||||
* Comment on issues and drive to resolution
|
||||
|
||||
## High-impact Involvement
|
||||
|
||||
* 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)
|
||||
|
||||
## Team Meetings
|
||||
|
||||
We communicate through a channel on slack: https://gitter.im/bower
|
||||
|
||||
If you'd like to attend the meetings, please fill the [support form](http://goo.gl/forms/P1ndzCNoiG), and you'll get an invite.
|
||||
|
||||
## Using the issue tracker
|
||||
|
||||
@@ -16,7 +29,8 @@ The issue tracker is the preferred channel for [bug reports](#bugs),
|
||||
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
|
||||
[Stack Overflow](http://stackoverflow.com/questions/tagged/bower)
|
||||
[Gitter Channel](https://gitter.im/bower/bower)
|
||||
[Mailing List](http://groups.google.com/group/twitter-bower)
|
||||
(twitter-bower@googlegroups.com), or
|
||||
[#bower](http://webchat.freenode.net/?channels=bower) on Freenode.
|
||||
@@ -24,49 +38,6 @@ requests](#pull-requests), but please respect the following restrictions:
|
||||
* 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** — check if the issue has already been
|
||||
reported.
|
||||
|
||||
2. **Check if the issue has been fixed** — try to reproduce it using the
|
||||
latest `master` or development branch in the repository.
|
||||
|
||||
3. **Isolate the problem** — 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
|
||||
|
||||
@@ -150,6 +121,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.
|
||||
|
||||
|
||||
7
Makefile
7
Makefile
@@ -1,7 +0,0 @@
|
||||
test: node_modules
|
||||
./node_modules/.bin/mocha -R spec -t 10000
|
||||
|
||||
node_modules: package.json
|
||||
npm install
|
||||
|
||||
.PHONY: test
|
||||
372
README.md
372
README.md
@@ -1,364 +1,126 @@
|
||||
# BOWER [](http://travis-ci.org/bower/bower)
|
||||
# Bower - A package manager for the web
|
||||
|
||||
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 needs your help. If you're willing to help, please say hello to team@bower.io or [donate](https://salt.bountysource.com/teams/bower)
|
||||
|
||||
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.).
|
||||
[](https://travis-ci.org/bower/bower)
|
||||
[](https://ci.appveyor.com/project/bower/bower)
|
||||
[](https://coveralls.io/r/bower/bower?branch=master)
|
||||
[](https://discord.gg/0fFM7QF0KpZRh2cY)
|
||||
[](http://issuestats.com/github/bower/bower)
|
||||
[](http://issuestats.com/github/bower/bower)
|
||||
|
||||
[View all packages available through Bower's registry](http://sindresorhus.com/bower-components/).
|
||||
<img align="right" height="300" src="http://bower.io/img/bower-logo.png">
|
||||
|
||||
---
|
||||
|
||||
## Installing Bower
|
||||
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 depends on [Node](http://nodejs.org/) and [npm](http://npmjs.org/). It's
|
||||
installed globally using npm:
|
||||
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
|
||||
|
||||
```sh
|
||||
$ npm install -g bower
|
||||
```
|
||||
npm install -g 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
|
||||
|
||||
```bash
|
||||
# Using the dependencies listed in the current directory's bower.json
|
||||
bower install
|
||||
# Using a local or remote package
|
||||
bower install <package>
|
||||
# Using a specific Git-tagged version from a remote package
|
||||
bower install <package>#<version>
|
||||
# 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
|
||||
```
|
||||
|
||||
Where `<package>` can be any one of the following:
|
||||
|
||||
* A name that maps to a package registered with Bower, e.g, `jquery`. ‡
|
||||
* A remote Git endpoint, e.g., `git://github.com/someone/some-package.git`. Can be
|
||||
public or private. ‡
|
||||
* A local Git endpoint, i.e., a folder that's a Git repository. ‡
|
||||
* A shorthand endpoint, e.g., `someone/some-package` (defaults to GitHub). ‡
|
||||
* A URL to a file, including `zip` and `tar` files. It's contents will be
|
||||
extracted.
|
||||
|
||||
‡ These types of `<package>` make Git tags available. You can specify a
|
||||
[semver](http://semver.org/) tag to fetch a specific release, and lock the
|
||||
package to that version.
|
||||
|
||||
All package contents are installed in the `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.
|
||||
|
||||
### 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/index.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.
|
||||
|
||||
### 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).
|
||||
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>
|
||||
```
|
||||
|
||||
### prezto and oh-my-zsh users
|
||||
|
||||
## Configuration
|
||||
On `prezto` or `oh-my-zsh`, do not forget to `alias bower='noglob bower'` or `bower install jquery\#1.9.1`
|
||||
|
||||
Bower can be configured using JSON in a `.bowerrc` file.
|
||||
### Never run Bower with sudo
|
||||
|
||||
Global configuration is handled by creating a `.bowerrc` in your home directory
|
||||
(i.e., `~/.bowerrc`). Local configuration is handled by creating a `.bowerrc`
|
||||
in your project's directory, allowing you to version a project-specific Bower
|
||||
configuration with the rest of your code base.
|
||||
Bower is a user command; there is no need to execute it with superuser permissions.
|
||||
|
||||
Bower will combine the local and global configurations (with local settings
|
||||
taking precedence).
|
||||
|
||||
The `.bowerrc` defines several options:
|
||||
|
||||
* `directory`: Set the default directory to install packaged components into.
|
||||
* `endpoint`: Set a custom registry endpoint.
|
||||
* `json`: Set the default JSON file for Bower to use when resolving dependencies.
|
||||
* `searchpath`: An array of additional URLs pointing to read-only Bower registries.
|
||||
* `shorthand_resolver`: Define a custom template for shorthand package names.
|
||||
|
||||
```json
|
||||
{
|
||||
"directory": "bower_components",
|
||||
"endpoint": "https://bower.mycompany.com",
|
||||
"json": "bower.json",
|
||||
"searchpath": [
|
||||
"https://bower.herokuapp.com"
|
||||
],
|
||||
"shorthand_resolver": "git://example.com/{{{ organization }}}/{{{ package }}}.git"
|
||||
}
|
||||
```
|
||||
|
||||
The `searchpath` array is useful if your organization wishes to maintain a
|
||||
private registry of packages while also taking advantage of public Bower
|
||||
registries. If a package is not found at your private endpoint, Bower will
|
||||
consult the registries specified in the `searchpath` array.
|
||||
|
||||
The `shorthand_resolver` key provides support for defining a custom template
|
||||
which Bower uses when constructing a URL for a given shorthand. For example, if
|
||||
a shorthand of `twitter/flight` or `twitter/flight#v1.0.0` is specified in the
|
||||
package manifest, the following data can be referenced from within the
|
||||
`.bowerrc` as part of the `shorthand_resolver` template:
|
||||
|
||||
* `endpoint`: `twitter/flight`
|
||||
* `organization`: `twitter`
|
||||
* `package`: `flight`
|
||||
|
||||
**N.B.** To run your own Bower Endpoint for custom packages that are behind a
|
||||
firewall, you can use a simple implementation of the [Bower Registry](https://github.com/bower/registry).
|
||||
|
||||
|
||||
## Defining a package
|
||||
|
||||
You must create a JSON file -- `bower.json` by default -- 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` defines several options:
|
||||
|
||||
* `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.
|
||||
* `devDependencies` [hash]: Development dependencies.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-project",
|
||||
"version": "1.0.0",
|
||||
"main": "path/to/main.css",
|
||||
"ignore": [
|
||||
".jshintrc",
|
||||
"**/*.txt"
|
||||
],
|
||||
"dependencies": {
|
||||
"<name>": "<version>",
|
||||
"<name>": "<folder>",
|
||||
"<name>": "<package>"
|
||||
},
|
||||
"devDependencies": {
|
||||
"<test-framework-name>": "<version>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Consuming a package
|
||||
|
||||
Bower also makes available a source mapping. This can be used by build tools to
|
||||
easily consume Bower packages.
|
||||
|
||||
If you pass the `--map` option to Bower's `list` command, it will generate JSON
|
||||
with dependency objects. Alternatively, you can pass the `--paths` option to
|
||||
the `list` command to get a simple path-to-name mapping:
|
||||
|
||||
```json
|
||||
{
|
||||
"backbone": "bower_components/backbone/index.js",
|
||||
"jquery": "bower_components/jquery/index.js",
|
||||
"underscore": "bower_components/underscore/index.js"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 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(paths, options)
|
||||
.on('end', function (data) {
|
||||
if (data) {
|
||||
console.log(data);
|
||||
}
|
||||
});
|
||||
|
||||
bower.commands
|
||||
.search('jquery', {})
|
||||
.on('packages', function (packages) {
|
||||
// `packages` is a list of packages returned by searching for 'jquery'
|
||||
});
|
||||
```
|
||||
|
||||
Commands emit four types of events: `data`, `end`, `result`, and `error`.
|
||||
|
||||
`error` will only be emitted if something goes wrong. Not all commands emit all
|
||||
events; for a detailed look, check out the code in `lib/commands`.
|
||||
|
||||
`data` is typically a colorized string, ready to show to an end user. `search`
|
||||
and `lookup` emit `packages` and `package`, respectively. Those events contain
|
||||
a JSON representation of the result of the command.
|
||||
|
||||
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).
|
||||
|
||||
For the install command, there is an additional `package` event that is emitted
|
||||
for each installed/uninstalled package.
|
||||
|
||||
|
||||
## Completion (experimental)
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
|
||||
## A note for Windows users
|
||||
### Windows users
|
||||
|
||||
To use Bower on Windows, you must install
|
||||
[msysgit](http://code.google.com/p/msysgit/) 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:
|
||||
|
||||

|
||||
<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.
|
||||
|
||||
### Ubuntu users
|
||||
|
||||
## Contact
|
||||
To use Bower on Ubuntu, you might need to link `nodejs` executable to `node`:
|
||||
|
||||
Have a question?
|
||||
```
|
||||
sudo ln -s /usr/bin/nodejs /usr/bin/node
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Bower can be configured using JSON in a `.bowerrc` file. Read over available options at [bower.io/docs/config](http://bower.io/docs/config).
|
||||
|
||||
|
||||
## Support
|
||||
|
||||
* [Discord chat](https://discord.gg/0fFM7QF0KpZRh2cY)
|
||||
* [StackOverflow](http://stackoverflow.com/questions/tagged/bower)
|
||||
* [Mailinglist](http://groups.google.com/group/twitter-bower) - twitter-bower@googlegroups.com
|
||||
* [\#bower](http://webchat.freenode.net/?channels=bower) on Freenode
|
||||
|
||||
## Contributing
|
||||
|
||||
## 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)
|
||||
|
||||
|
||||
## Authors
|
||||
|
||||
* [@fat](https://github.com/fat)
|
||||
* [@maccman](https://github.com/maccman)
|
||||
* [@satazor](https://github.com/satazor)
|
||||
|
||||
Thanks for assistance and contributions:
|
||||
|
||||
* [@addyosmani](https://github.com/addyosmani)
|
||||
* [@angus-c](https://github.com/angus-c)
|
||||
* [@borismus](https://github.com/borismus)
|
||||
* [@carsonmcdonald](https://github/@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)
|
||||
* [@marcelombc](https://github.com/marcelombc)
|
||||
* [@mklabs](https://github.com/mklabs)
|
||||
* [@paulirish](https://github.com/paulirish)
|
||||
* [@richo](https://github.com/richo)
|
||||
* [@rvagg](https://github.com/rvagg)
|
||||
* [@sindresorhus](https://github.com/sindresorhus)
|
||||
* [@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)
|
||||
* [@wibblymat](https://github.com/wibblymat)
|
||||
* [@wycats](https://github.com/wycats)
|
||||
Note that on Windows for tests to pass you need to configure Git before cloning:
|
||||
|
||||
```
|
||||
git config --global core.autocrlf input
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2012 Twitter, Inc.
|
||||
Copyright (c) 2016 Twitter and [other contributors](https://github.com/bower/bower/graphs/contributors)
|
||||
|
||||
Licensed under the MIT License
|
||||
|
||||
45
appveyor.yml
Normal file
45
appveyor.yml
Normal file
@@ -0,0 +1,45 @@
|
||||
# http://www.appveyor.com/docs/appveyor-yml
|
||||
|
||||
# Set build version format here instead of in the admin panel.
|
||||
version: "{build}"
|
||||
|
||||
# Fix line endings in Windows. (runs before repo cloning)
|
||||
init:
|
||||
- git config --global core.autocrlf input
|
||||
|
||||
# Test against these versions of Node.js.
|
||||
environment:
|
||||
matrix:
|
||||
- nodejs_version: "0.10"
|
||||
- nodejs_version: "0.12"
|
||||
- nodejs_version: "4.0"
|
||||
- nodejs_version: "4.1"
|
||||
- nodejs_version: "4.2"
|
||||
- nodejs_version: "5"
|
||||
- nodejs_version: "6"
|
||||
|
||||
# Finish on first failed build
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
||||
# Install node, display versions, install dependencies
|
||||
install:
|
||||
- ps: Install-Product node $env:nodejs_version
|
||||
- node --version && npm --version
|
||||
- git --version && svn --version
|
||||
- npm install
|
||||
|
||||
# Post-install test scripts.
|
||||
test_script:
|
||||
- cmd: npm test
|
||||
|
||||
# Make clone much faster
|
||||
shallow_clone: true
|
||||
|
||||
# Disable Visual Studio build and deploy
|
||||
build: off
|
||||
deploy: off
|
||||
|
||||
# Cache node modules, and refresh if package.json changes
|
||||
cache:
|
||||
- node_modules -> package.json
|
||||
81
bin/bower
81
bin/bower
@@ -1,81 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var semver = require('semver');
|
||||
var nopt = require('nopt');
|
||||
var path = require('path');
|
||||
var pkg = require(path.join(__dirname, '..', 'package.json'));
|
||||
var updateNotifier = require('update-notifier');
|
||||
|
||||
var template = require('../lib/util/template');
|
||||
var bower = require('../lib');
|
||||
|
||||
var command;
|
||||
var options;
|
||||
var shorthand;
|
||||
var input = process.argv;
|
||||
var nodeVer = process.version;
|
||||
var reqVer = pkg.engines.node;
|
||||
var errors = [];
|
||||
var notifier = updateNotifier({ packageName: pkg.name, packageVersion: pkg.version });
|
||||
|
||||
if (notifier.update) {
|
||||
process.stderr.write(template('update-notice', notifier.update, true));
|
||||
}
|
||||
|
||||
process.title = 'bower';
|
||||
|
||||
if (reqVer && !semver.satisfies(nodeVer, reqVer)) {
|
||||
throw new Error('Required: node ' + reqVer);
|
||||
}
|
||||
|
||||
options = {
|
||||
version: Boolean,
|
||||
quiet: Boolean,
|
||||
silent: Boolean
|
||||
};
|
||||
shorthand = {
|
||||
'v': ['--version'],
|
||||
'q': ['--quiet'],
|
||||
's': ['--silent']
|
||||
};
|
||||
options = nopt(options, shorthand, process.argv);
|
||||
|
||||
bower.version = pkg.version;
|
||||
|
||||
if (options.version) return console.log(bower.version);
|
||||
|
||||
command = options.argv.remain && options.argv.remain.shift();
|
||||
command = bower.abbreviations[command];
|
||||
|
||||
if (command) bower.command = command;
|
||||
|
||||
if (options.silent) {
|
||||
options.quiet = true;
|
||||
}
|
||||
|
||||
// Temporarory fix for #22 #320 #187
|
||||
var errStatusHandler = function () {
|
||||
process.removeListener('exit', errStatusHandler);
|
||||
process.exit(errors.length ? 1 : 0);
|
||||
};
|
||||
process.on('exit', errStatusHandler);
|
||||
|
||||
bower.commands[bower.command || 'help'].line(input)
|
||||
.on('data', function (data) {
|
||||
if (data && !options.quiet) process.stdout.write(data);
|
||||
})
|
||||
.on('end', function (data) {
|
||||
if (data && !options.quiet) process.stdout.write(data);
|
||||
})
|
||||
.on('warn', function (warning) {
|
||||
if (!options.silent) {
|
||||
process.stderr.write(template('warn', { message: warning }, true));
|
||||
}
|
||||
})
|
||||
.on('error', function (err) {
|
||||
if (options.verbose) throw err;
|
||||
if (!options.silent) {
|
||||
process.stdout.write(template('error', { message: err.message }, true));
|
||||
}
|
||||
errors.push(err);
|
||||
});
|
||||
10
lerna.json
Normal file
10
lerna.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"lerna": "2.0.0-beta.23",
|
||||
"version": "independent",
|
||||
"publishConfig": {
|
||||
"ignore": [
|
||||
"ignored-file",
|
||||
"*.md"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: CacheClean API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var async = require('async');
|
||||
var nopt = require('nopt');
|
||||
var rimraf = require('rimraf');
|
||||
var path = require('path');
|
||||
var glob = require('glob');
|
||||
var fs = require('fs');
|
||||
var _ = require('lodash');
|
||||
|
||||
var help = require('./help');
|
||||
var config = require('../core/config');
|
||||
var template = require('../util/template');
|
||||
var fileExists = require('../util/file-exists');
|
||||
|
||||
var optionTypes = { help: Boolean };
|
||||
var shorthand = { 'h': ['--help'] };
|
||||
|
||||
var processCachedPackage = function (emitter, pkg, next) {
|
||||
removeCachedPackage(pkg, function (err, exists) {
|
||||
if (err) {
|
||||
emitter.emit('error', err);
|
||||
return next();
|
||||
}
|
||||
|
||||
if (exists) {
|
||||
template('action', { name: 'cache cleared', shizzle: pkg })
|
||||
.on('data', emitter.emit.bind(emitter, 'data'));
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
};
|
||||
|
||||
var removeCachedPackage = function (pkg, next) {
|
||||
var folder = path.join(config.cache, pkg);
|
||||
|
||||
fileExists(folder, function (exists) {
|
||||
if (!exists) return next(null, false);
|
||||
rimraf(folder, function (err) {
|
||||
if (err) return next(err);
|
||||
next(null, true);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var processLinkedPackage = function (emitter, pkg, next) {
|
||||
checkAndRemoveLinkToPackage(pkg, function (err, removed) {
|
||||
if (err) {
|
||||
emitter.emit('error', err);
|
||||
return next();
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
template('action', { name: 'link cleared', shizzle: pkg })
|
||||
.on('data', emitter.emit.bind(emitter, 'data'));
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
};
|
||||
|
||||
var checkAndRemoveLinkToPackage = function (pkg, next) {
|
||||
var folder = path.join(config.links, pkg);
|
||||
|
||||
fs.readlink(folder, function (err, linkString) {
|
||||
if (err && err.code === 'ENOENT') return next();
|
||||
|
||||
fileExists(linkString, function (exists) {
|
||||
if (!exists) {
|
||||
return rimraf(folder, function (err) {
|
||||
if (err) return next(err);
|
||||
next(null, true);
|
||||
});
|
||||
}
|
||||
|
||||
next(null, false);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = function (pkgs) {
|
||||
var emitter = new Emitter;
|
||||
|
||||
async.parallel({
|
||||
cache: function (next) {
|
||||
if (!pkgs || !pkgs.length) {
|
||||
glob('./*', { cwd: config.cache }, function (err, dirs) {
|
||||
if (err) {
|
||||
emitter.emit('error', err);
|
||||
return next();
|
||||
}
|
||||
|
||||
var pkgs = dirs.map(function (dir) { return dir.replace(/^\.\//, ''); });
|
||||
async.forEach(pkgs, processCachedPackage.bind(this, emitter), next);
|
||||
});
|
||||
} else {
|
||||
pkgs = _.uniq(pkgs);
|
||||
async.forEach(pkgs, processCachedPackage.bind(this, emitter), next);
|
||||
}
|
||||
},
|
||||
links: function (next) {
|
||||
if (!pkgs || !pkgs.length) {
|
||||
glob('./*', { cwd: config.links }, function (err, dirs) {
|
||||
if (err) {
|
||||
emitter.emit('error', err);
|
||||
return next();
|
||||
}
|
||||
|
||||
var pkgs = dirs.map(function (dir) { return dir.replace(/^\.\//, ''); });
|
||||
async.forEach(pkgs, processLinkedPackage.bind(this, emitter), next);
|
||||
});
|
||||
} else {
|
||||
pkgs = _.uniq(pkgs);
|
||||
async.forEach(pkgs, processLinkedPackage.bind(this, emitter), next);
|
||||
}
|
||||
},
|
||||
completion: function (next) {
|
||||
// Do not run completion cache if packages where passed
|
||||
if (pkgs && pkgs.length) return next();
|
||||
|
||||
rimraf(config.completion, function (err) {
|
||||
if (err) {
|
||||
emitter.emit('error', err);
|
||||
return next();
|
||||
}
|
||||
|
||||
template('action', { name: 'completion cleared', shizzle: 'completion cache' })
|
||||
.on('data', emitter.emit.bind(emitter, 'data'));
|
||||
|
||||
next();
|
||||
});
|
||||
}
|
||||
}, emitter.emit.bind(emitter, 'end'));
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
var pkgs = options.argv.remain.slice(1);
|
||||
|
||||
if (options.help) return help('cache-clean');
|
||||
return module.exports(pkgs);
|
||||
};
|
||||
|
||||
module.exports.completion = function (opts, cb) {
|
||||
glob('./*', { cwd: config.cache }, function (err, dirs) {
|
||||
if (err) return cb(err);
|
||||
dirs = dirs.map(function (dir) {
|
||||
return dir.replace(/^\.\//, '');
|
||||
});
|
||||
cb(null, dirs);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.completion.options = shorthand;
|
||||
@@ -1,112 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Completion API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var path = require('path');
|
||||
var nopt = require('nopt');
|
||||
var mkdirp = require('mkdirp');
|
||||
|
||||
var template = require('../util/template');
|
||||
var complete = require('../util/completion');
|
||||
var config = require('../core/config');
|
||||
var help = require('./help');
|
||||
|
||||
var optionTypes = { help: Boolean };
|
||||
var shorthand = { 'h': ['--help'] };
|
||||
|
||||
module.exports = function (argv, env) {
|
||||
env = env || process.env;
|
||||
|
||||
var emitter = new Emitter;
|
||||
var commands = require('../commands');
|
||||
|
||||
// top level flags
|
||||
var flags = ['--no-color', '--help', '--version'];
|
||||
|
||||
var done = function done() {
|
||||
process.nextTick(function () {
|
||||
emitter.emit('end');
|
||||
});
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
// if the COMP_* isn't in the env, then just dump the script.
|
||||
if (!env.COMP_CWORD) {
|
||||
template('completion').on('data', emitter.emit.bind(emitter, 'end'));
|
||||
return emitter;
|
||||
}
|
||||
|
||||
// parse environment and arguments, returns a hash of completion config.
|
||||
var opts = complete(argv, env);
|
||||
|
||||
// if only one word, complete the list of command or top level flags
|
||||
if (opts.w === 1) {
|
||||
if (opts.word.charAt(0) === '-') complete.log(flags, opts);
|
||||
else complete.log(Object.keys(commands), opts);
|
||||
return done();
|
||||
}
|
||||
|
||||
// try to find the bower command. first thing after all the configs.
|
||||
var parsed = opts.conf = nopt({}, {}, opts.partialWords, 0);
|
||||
var cmd = parsed.argv.remain[0];
|
||||
|
||||
// unable to find a command, complete the lisf of commands
|
||||
if (!cmd) {
|
||||
complete.log(Object.keys(commands), opts);
|
||||
return done();
|
||||
}
|
||||
|
||||
// if words[0] is a bower command, then complete on it.
|
||||
cmd = commands[cmd];
|
||||
|
||||
if (cmd && cmd.completion) {
|
||||
// prior to that, ensure the completion cache directory is created first
|
||||
mkdirp(path.join(config.completion), function (err) {
|
||||
if (err) return emitter.emit('error', err);
|
||||
|
||||
var options = cmd.completion.options;
|
||||
if (options && opts.word.charAt(0) === '-') {
|
||||
complete.log(Object.keys(options).map(function (option) {
|
||||
return opts.word.charAt(1) === '-' ? options[option][0] : '-' + option;
|
||||
}), opts);
|
||||
return done();
|
||||
}
|
||||
|
||||
cmd.completion(opts, function (err, data) {
|
||||
if (err) return emitter.emit('error', err);
|
||||
|
||||
// completing options, then append top level flags
|
||||
if (opts.word.charAt(0) === '-') data = data.concat(flags);
|
||||
|
||||
complete.log(data, opts);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
return emitter;
|
||||
}
|
||||
|
||||
// otherwise, do nothing
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var emitter = new Emitter;
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
|
||||
if (options.help) return help('completion');
|
||||
|
||||
module.exports(options.argv.remain.slice(2), process.env)
|
||||
.on('data', emitter.emit.bind(emitter, 'data'))
|
||||
.on('error', emitter.emit.bind(emitter, 'error'))
|
||||
.on('end', emitter.emit.bind(emitter, 'end'));
|
||||
|
||||
return emitter;
|
||||
};
|
||||
@@ -1,52 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Help API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var events = require('events');
|
||||
var nopt = require('nopt');
|
||||
var _ = require('lodash');
|
||||
|
||||
var template = require('../util/template');
|
||||
var config = require('../core/config');
|
||||
|
||||
module.exports = function (name) {
|
||||
var context = {};
|
||||
var emitter = new events.EventEmitter;
|
||||
var commands = require('../commands');
|
||||
|
||||
// Aliases
|
||||
// At the moment we just have the ls, but we might have more
|
||||
switch (name) {
|
||||
case 'ls':
|
||||
name = 'list';
|
||||
break;
|
||||
}
|
||||
|
||||
var validCommand = !!(name && commands[name]);
|
||||
var templateName = validCommand ? 'help-' + name : 'help';
|
||||
|
||||
if (!validCommand) context = {
|
||||
commands: Object.keys(commands).sort().join(', ')
|
||||
}
|
||||
|
||||
_.extend(context, config);
|
||||
|
||||
template(templateName, context)
|
||||
.on('data', emitter.emit.bind(emitter, 'end'));
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt({}, {}, argv);
|
||||
var paths = options.argv.remain.slice(1);
|
||||
return module.exports(paths[0]);
|
||||
};
|
||||
|
||||
module.exports.completion = function (opts, cb) {
|
||||
return cb(null, Object.keys(require('../commands')));
|
||||
};
|
||||
@@ -1,24 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Public Commands List
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
module.exports = {
|
||||
'help': require('./help'),
|
||||
'install': require('./install'),
|
||||
'list': require('./list'),
|
||||
'ls': require('./list'),
|
||||
'uninstall': require('./uninstall'),
|
||||
'update': require('./update'),
|
||||
'link': require('./link'),
|
||||
'lookup': require('./lookup'),
|
||||
'info': require('./info'),
|
||||
'init': require('./init'),
|
||||
'register': require('./register'),
|
||||
'search': require('./search'),
|
||||
'cache-clean': require('./cache-clean'),
|
||||
'completion': require('./completion')
|
||||
};
|
||||
@@ -1,50 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Lookup API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var nopt = require('nopt');
|
||||
|
||||
var template = require('../util/template');
|
||||
var source = require('../core/source');
|
||||
var install = require('./install');
|
||||
var help = require('./help');
|
||||
|
||||
var optionTypes = { help: Boolean };
|
||||
var shorthand = { 'h': ['--help'] };
|
||||
|
||||
module.exports = function (name) {
|
||||
var emitter = new Emitter;
|
||||
|
||||
if (name) {
|
||||
source.info(name, function (err, result) {
|
||||
if (err) return emitter.emit('error', err);
|
||||
emitter.emit('end', result);
|
||||
});
|
||||
}
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var emitter = new Emitter;
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
var names = options.argv.remain.slice(1);
|
||||
|
||||
if (options.help || !names.length) return help('info');
|
||||
|
||||
module.exports(names[0])
|
||||
.on('error', emitter.emit.bind(emitter, 'error'))
|
||||
.on('end', function (data) {
|
||||
template('info', data).on('data', emitter.emit.bind(emitter, 'end'));
|
||||
});
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.completion = install.completion;
|
||||
module.exports.completion.options = shorthand;
|
||||
@@ -1,150 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Init API
|
||||
// ==========================================
|
||||
// Copyright 2013 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var util = require('util');
|
||||
|
||||
var nopt = require('nopt');
|
||||
var promptly = require('promptly');
|
||||
var _ = require('lodash');
|
||||
|
||||
var help = require('./help');
|
||||
var Manager = require('../core/manager');
|
||||
var config = require('../core/config');
|
||||
|
||||
var optionTypes = { help: Boolean };
|
||||
var shorthand = { 'h': ['--help'] };
|
||||
|
||||
var commonIgnore = ['**/.*', 'node_modules', 'components', 'bower_components', 'test', 'tests'];
|
||||
|
||||
var Init = function () {
|
||||
Manager.call(this);
|
||||
};
|
||||
|
||||
util.inherits(Init, Manager);
|
||||
|
||||
Init.prototype.getDependenciesJSON = function () {
|
||||
var dependencies = Object.keys(this.dependencies);
|
||||
var remaining = dependencies.length;
|
||||
var json = {};
|
||||
|
||||
dependencies.forEach(function (name) {
|
||||
var pkg = this.dependencies[name][0];
|
||||
|
||||
pkg.on('loadJSON', function () {
|
||||
// TODO: use fetch endpoint here
|
||||
json[pkg.name] = pkg.commit ? '*' : '~' + pkg.version;
|
||||
remaining -= 1;
|
||||
if (remaining === 0) {
|
||||
this.manager.emit('loadDependencies', json);
|
||||
}
|
||||
}).loadJSON();
|
||||
}, this);
|
||||
|
||||
if (remaining === 0) {
|
||||
this.emit('loadDependencies', json);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Init.prototype.getMain = function (name) {
|
||||
name = path.basename(name, '.js');
|
||||
if (fs.existsSync(path.join(process.cwd(), 'index.js'))) {
|
||||
return 'index.js';
|
||||
} else if (fs.existsSync(path.join(process.cwd(), name + '.js'))) {
|
||||
return name + '.js';
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
Init.prototype.showPrompt = function (question, cb) {
|
||||
var prompt = question.prompt + ': [' + (question.yesno ? 'y' : question.value) + ']';
|
||||
if (question.yesno) {
|
||||
promptly.confirm(prompt, {'default': 'y'}, cb);
|
||||
} else {
|
||||
promptly.prompt(prompt, {'default': question.value}, cb);
|
||||
}
|
||||
this.emit('prompt', prompt);
|
||||
};
|
||||
|
||||
Init.prototype.prompts = function (dependencies) {
|
||||
var main = this.json.main || this.getMain(this.json.name) || '';
|
||||
|
||||
var questions = _.compact([
|
||||
{key: 'name', prompt: 'name', value: this.json.name, yesno: false},
|
||||
{key: 'version', prompt: 'version', value: this.json.version, yesno: false},
|
||||
{key: 'main', prompt: 'main file', value: main, yesno: false},
|
||||
_.size(dependencies) ? {key: 'dependencies', prompt: 'add current components as dependencies? (y/n)', value: dependencies, yesno: true} : null,
|
||||
{key: 'ignore', prompt: 'add commonly ignored files to ignore list? (y/n)', value: commonIgnore, yesno: true}
|
||||
]);
|
||||
var index = 0;
|
||||
var question = questions[index];
|
||||
|
||||
var cb = function (err, value) {
|
||||
if (question.yesno) {
|
||||
if (value) {
|
||||
this.json[question.key] = question.value;
|
||||
}
|
||||
} else if (value) {
|
||||
this.json[question.key] = value;
|
||||
}
|
||||
index += 1;
|
||||
if (index < questions.length) {
|
||||
question = questions[index];
|
||||
this.showPrompt(question, cb);
|
||||
} else {
|
||||
this.emit('prompts');
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
this.showPrompt(question, cb);
|
||||
};
|
||||
|
||||
Init.prototype.save = function (data) {
|
||||
fs.writeFileSync(path.join(this.cwd, config.json), JSON.stringify(data, null, 2));
|
||||
};
|
||||
|
||||
module.exports = function () {
|
||||
var init = new Init();
|
||||
|
||||
init
|
||||
.on('resolveLocal', init.loadJSON.bind(init))
|
||||
.on('loadJSON', init.getDependenciesJSON.bind(init))
|
||||
.on('loadDependencies', init.prompts.bind(init))
|
||||
.on('prompts', function () {
|
||||
init.save(init.json);
|
||||
init.emit('end');
|
||||
})
|
||||
.resolveLocal();
|
||||
|
||||
return init;
|
||||
};
|
||||
|
||||
module.exports.Init = Init; // Purely for testing
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
if (options.help) return help('init');
|
||||
return module.exports();
|
||||
};
|
||||
|
||||
module.exports.completion = function (opts, cb) {
|
||||
var word = opts.word;
|
||||
|
||||
// completing options?
|
||||
if (word.charAt(0) === '-') {
|
||||
return cb(null, Object.keys(optionTypes).map(function (option) {
|
||||
return '--' + option;
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Install API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var nopt = require('nopt');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
var Manager = require('../core/manager');
|
||||
var config = require('../core/config');
|
||||
var source = require('../core/source');
|
||||
var save = require('../util/save');
|
||||
var help = require('./help');
|
||||
|
||||
var optionTypes = { help: Boolean, save: Boolean, 'save-dev': Boolean, force: Boolean, 'force-latest': Boolean, production: Boolean };
|
||||
var shorthand = { 'h': ['--help'], 'S': ['--save'], 'D': ['--save-dev'], 'f': ['--force'], 'F': ['--force-latest'], 'p': ['--production'] };
|
||||
|
||||
module.exports = function (paths, options) {
|
||||
options = options || {};
|
||||
|
||||
var emitter = new Emitter;
|
||||
var manager = new Manager(paths, {
|
||||
force: options.force,
|
||||
forceLatest: options['force-latest'],
|
||||
production: options.production
|
||||
});
|
||||
|
||||
manager
|
||||
.on('data', emitter.emit.bind(emitter, 'data'))
|
||||
.on('warn', emitter.emit.bind(emitter, 'warn'))
|
||||
.on('error', emitter.emit.bind(emitter, 'error'))
|
||||
.on('resolve', function (resolved) {
|
||||
// Handle save/save-dev
|
||||
if (resolved && (options.save || options['save-dev'])) {
|
||||
save(manager, paths, !options.save, emitter.emit.bind(emitter, 'end'));
|
||||
} else {
|
||||
emitter.emit('end');
|
||||
}
|
||||
})
|
||||
.resolve();
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
var paths = options.argv.remain.slice(1);
|
||||
|
||||
if (options.help) return help('install');
|
||||
return module.exports(paths, options);
|
||||
};
|
||||
|
||||
module.exports.completion = function (opts, cb) {
|
||||
var cache = path.join(config.completion, 'install.json');
|
||||
var done = function done(err, results) {
|
||||
if (err) return cb(err);
|
||||
var names = results.map(function (pkg) {
|
||||
return pkg.name;
|
||||
});
|
||||
|
||||
return cb(null, names);
|
||||
};
|
||||
|
||||
fs.readFile(cache, function (err, body) {
|
||||
if (!err) return done(null, JSON.parse(body));
|
||||
|
||||
// expected error, do the first request and cache the results
|
||||
source.all(function (err, results) {
|
||||
if (err) return cb(err);
|
||||
fs.writeFile(cache, JSON.stringify(results, null, 2), function (err) {
|
||||
done(err, results);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.completion.options = shorthand;
|
||||
@@ -1,121 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Link API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var nopt = require('nopt');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var mkdirp = require('mkdirp');
|
||||
var rimraf = require('rimraf');
|
||||
|
||||
var Manager = require('../core/manager');
|
||||
var help = require('./help');
|
||||
var template = require('../util/template');
|
||||
var config = require('../core/config');
|
||||
var isRepo = require('../util/is-repo');
|
||||
|
||||
var optionTypes = { help: Boolean };
|
||||
var shorthand = { 'h': ['--help'] };
|
||||
|
||||
function linkSelf(emitter) {
|
||||
var manager = new Manager;
|
||||
|
||||
manager
|
||||
.on('error', emitter.emit.bind('error'))
|
||||
.once('loadJSON', function () {
|
||||
var destPath = path.join(config.links, manager.name);
|
||||
var srcPath = process.cwd();
|
||||
|
||||
deleteLink(destPath, function (err) {
|
||||
if (err) return emitter.emit('error', err);
|
||||
|
||||
createLink(srcPath, destPath, function (err) {
|
||||
if (err) return emitter.emit('error', err);
|
||||
|
||||
template('link', { src: srcPath, dest: destPath })
|
||||
.on('data', emitter.emit.bind(emitter, 'end'));
|
||||
});
|
||||
});
|
||||
}).loadJSON();
|
||||
}
|
||||
|
||||
function linkTo(name, emitter) {
|
||||
var destPath = path.join(process.cwd(), config.directory, name);
|
||||
var srcPath = path.join(config.links, name);
|
||||
|
||||
deleteLink(destPath, function (err) {
|
||||
if (err) return emitter.emit('error', err);
|
||||
|
||||
createLink(srcPath, destPath, function (err) {
|
||||
if (err) return emitter.emit('error', err);
|
||||
|
||||
template('link', { src: srcPath, dest: destPath })
|
||||
.on('data', emitter.emit.bind(emitter, 'end'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function deleteLink(dest, callback) {
|
||||
// Delete symlink if already present
|
||||
// Beware that if the target is a git repo, we can't proceed
|
||||
isRepo(dest, function (is) {
|
||||
if (is) return callback(new Error(dest + ' is a local repository, please remove it manually'));
|
||||
|
||||
fs.lstat(dest, function (err) {
|
||||
if (!err || err.code !== 'ENOENT') rimraf(dest, callback);
|
||||
else callback();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function createLink(src, dest, callback) {
|
||||
var destDir = path.dirname(dest);
|
||||
|
||||
// Create directory
|
||||
mkdirp(destDir, function (err) {
|
||||
if (err) return callback(err);
|
||||
|
||||
fs.lstat(src, function (err) {
|
||||
if (err && err.code === 'ENOENT') {
|
||||
return callback(new Error('Attempting to link an unknown package: ' + path.basename(src)));
|
||||
}
|
||||
|
||||
// Create symlink
|
||||
fs.symlink(src, dest, 'dir', function (err) {
|
||||
callback(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = function (name) {
|
||||
var emitter = new Emitter;
|
||||
|
||||
if (!name) linkSelf(emitter);
|
||||
else linkTo(name, emitter);
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
var name = options.argv.remain[1];
|
||||
|
||||
if (options.help) return help('link');
|
||||
return module.exports(name);
|
||||
};
|
||||
|
||||
module.exports.completion = function (opts, cb) {
|
||||
fs.readdir(config.links, function (err, dirs) {
|
||||
// ignore ENOENT, ~/.bower/links not created yet
|
||||
if (err && err.code === 'ENOENT') return cb(null, []);
|
||||
cb(err, dirs);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.completion.options = shorthand;
|
||||
@@ -1,245 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: List API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var archy = require('archy');
|
||||
var nopt = require('nopt');
|
||||
var path = require('path');
|
||||
var _ = require('lodash');
|
||||
|
||||
var template = require('../util/template');
|
||||
var Manager = require('../core/manager');
|
||||
var Package = require('../core/package');
|
||||
var config = require('../core/config');
|
||||
var help = require('./help');
|
||||
var fallback = require('../util/fallback');
|
||||
|
||||
var shorthand = { 'h': ['--help'], 'o': ['--offline'] };
|
||||
var optionTypes = { help: Boolean, paths: Boolean, map: Boolean, offline: Boolean, sources: Boolean };
|
||||
|
||||
var getTree = function (packages, subPackages, result) {
|
||||
result = result || {};
|
||||
|
||||
_.each(subPackages || packages, function (pkg) {
|
||||
|
||||
result[pkg.name] = {};
|
||||
|
||||
Object.keys(pkg.json.dependencies || {}).forEach(function (name) {
|
||||
result[pkg.name][name] = {};
|
||||
});
|
||||
|
||||
var subPackages = {};
|
||||
|
||||
Object.keys(pkg.json.dependencies || {}).forEach(function (name) {
|
||||
subPackages[name] = packages[name] || new Package(name, null);
|
||||
});
|
||||
|
||||
getTree(packages, subPackages, result[pkg.name]);
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
var generatePath = function (name, main) {
|
||||
if (typeof main === 'string') {
|
||||
return path.join(config.directory, name, main);
|
||||
} else if (_.isArray(main)) {
|
||||
main = main.map(function (main) { return generatePath(name, main); });
|
||||
return main.length === 1 ? main[0] : main;
|
||||
}
|
||||
};
|
||||
|
||||
var mainTypes = ['main', 'scripts', 'styles', 'templates', 'images'];
|
||||
|
||||
var buildSource = function (pkg, shallow) {
|
||||
var result = {};
|
||||
|
||||
if (pkg) {
|
||||
mainTypes.forEach(function (type) {
|
||||
if (pkg.json[type]) result[type] = generatePath(pkg.name, pkg.json[type]);
|
||||
});
|
||||
}
|
||||
|
||||
if (shallow) {
|
||||
result.main = getMain(result) || generatePath(pkg.name, '');
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
var getMain = function (source) {
|
||||
for (var i = 0, len = mainTypes.length; i < len; i += 1) {
|
||||
var type = mainTypes[i];
|
||||
if (source[type]) {
|
||||
return source[type];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var shallowTree = function (packages, tree) {
|
||||
var result = {};
|
||||
|
||||
Object.keys(tree).forEach(function (packageName) {
|
||||
result[packageName] = buildSource(packages[packageName], true).main;
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
var deepTree = function (packages, tree) {
|
||||
|
||||
var result = {};
|
||||
|
||||
Object.keys(tree).forEach(function (packageName) {
|
||||
|
||||
result[packageName] = {};
|
||||
result[packageName].source = buildSource(packages[packageName]);
|
||||
|
||||
if (Object.keys(tree[packageName]).length) {
|
||||
result[packageName].dependencies = deepTree(packages, tree[packageName]);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
var getNodes = function (packages, tree) {
|
||||
return Object.keys(tree).map(function (key) {
|
||||
var version = packages[key] ? packages[key].version || '' : null;
|
||||
var upgrade;
|
||||
|
||||
if (version && packages[key].tags.indexOf(version)) {
|
||||
upgrade = packages[key].tags[0];
|
||||
}
|
||||
|
||||
if (Object.keys(tree[key]).length) {
|
||||
return {
|
||||
label: template('tree-branch', { 'package': key, version: version, upgrade: upgrade }, true),
|
||||
nodes: getNodes(packages, tree[key])
|
||||
};
|
||||
} else {
|
||||
return template('tree-branch', { 'package': key, version: version, upgrade: upgrade }, true);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var getDependencySrcs = function (list) {
|
||||
var srcs = [];
|
||||
var dependency, main;
|
||||
for (var name in list) {
|
||||
dependency = list[name];
|
||||
main = dependency.source && getMain(dependency.source);
|
||||
|
||||
if (dependency.dependencies) {
|
||||
var depSrcs = getDependencySrcs(dependency.dependencies);
|
||||
srcs.push.apply(srcs, depSrcs);
|
||||
}
|
||||
|
||||
// add main sources to srcs
|
||||
if (main) {
|
||||
if (Array.isArray(main)) {
|
||||
srcs.push.apply(srcs, main);
|
||||
} else {
|
||||
srcs.push(main);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return srcs;
|
||||
};
|
||||
|
||||
var organizeSources = function (tree) {
|
||||
// flat source filepaths
|
||||
var srcs = getDependencySrcs(tree);
|
||||
// remove duplicates, organize by file extension
|
||||
var sources = {};
|
||||
|
||||
srcs.forEach(function (src) {
|
||||
var ext = path.extname(src);
|
||||
sources[ext] = sources[ext] || [];
|
||||
if (sources[ext].indexOf(src) === -1) {
|
||||
sources[ext].push(src);
|
||||
}
|
||||
});
|
||||
|
||||
return sources;
|
||||
};
|
||||
|
||||
module.exports = function (options) {
|
||||
var manager = new Manager;
|
||||
var emitter = new Emitter;
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (options.sources) {
|
||||
options.map = true;
|
||||
}
|
||||
|
||||
var emitOut = function (obj) {
|
||||
// make JSON pretty if started from command line
|
||||
var output = options.argv ? JSON.stringify(obj, null, 2) : obj;
|
||||
emitter.emit('data', output);
|
||||
};
|
||||
manager
|
||||
.on('data', emitter.emit.bind(emitter, 'data'))
|
||||
.on('error', emitter.emit.bind(emitter, 'error'))
|
||||
.on('list', function (packages) {
|
||||
var tree = getTree(packages);
|
||||
var rootLabel;
|
||||
|
||||
if (!options.paths && !options.map) {
|
||||
return fallback(process.cwd(), [config.json, 'bower.json', 'component.json'], function (name) {
|
||||
try {
|
||||
if (name == null) throw new Error('No json');
|
||||
rootLabel = require(path.join(process.cwd(), name)).name;
|
||||
} catch (e) {
|
||||
rootLabel = path.basename(process.cwd());
|
||||
}
|
||||
|
||||
emitter.emit('data', archy({
|
||||
label: rootLabel,
|
||||
nodes: getNodes(packages, tree)
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
tree = options.paths ? shallowTree(packages, tree) : deepTree(packages, tree);
|
||||
|
||||
if (options.sources) {
|
||||
// with map, organize it and emit
|
||||
var sources = organizeSources(tree);
|
||||
emitOut(sources);
|
||||
} else {
|
||||
emitOut(tree);
|
||||
}
|
||||
|
||||
})
|
||||
.list(options);
|
||||
|
||||
return emitter;
|
||||
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
if (options.help) return help('list');
|
||||
return module.exports(options);
|
||||
};
|
||||
|
||||
module.exports.completion = function (opts, cb) {
|
||||
if (!/^-/.test(opts.word)) return cb(null, []);
|
||||
|
||||
var results = Object.keys(optionTypes).map(function (option) {
|
||||
return '--' + option;
|
||||
});
|
||||
|
||||
cb(null, results);
|
||||
};
|
||||
|
||||
module.exports.completion.options = shorthand;
|
||||
@@ -1,64 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Lookup API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var nopt = require('nopt');
|
||||
|
||||
var template = require('../util/template');
|
||||
var source = require('../core/source');
|
||||
var install = require('./install');
|
||||
var help = require('./help');
|
||||
|
||||
var optionTypes = { help: Boolean };
|
||||
var shorthand = { 'h': ['--help'] };
|
||||
|
||||
module.exports = function (name) {
|
||||
var emitter = new Emitter;
|
||||
|
||||
source.lookup(name, function (err, url) {
|
||||
if (err) {
|
||||
source.search(name, function (err, packages) {
|
||||
if (packages.length) {
|
||||
template('suggestions', { packages: packages, name: name })
|
||||
.on('data', function (data) {
|
||||
emitter.emit('data', data);
|
||||
emitter.emit('end');
|
||||
});
|
||||
} else {
|
||||
template('warning-missing', {name: name})
|
||||
.on('data', function (data) {
|
||||
emitter.emit('data', data);
|
||||
emitter.emit('end');
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
var result = { name: name, url: url };
|
||||
emitter.emit('package', result);
|
||||
|
||||
template('lookup', result)
|
||||
.on('data', function (data) {
|
||||
emitter.emit('data', data);
|
||||
emitter.emit('end');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
var names = options.argv.remain.slice(1);
|
||||
|
||||
if (options.help || !names.length) return help('lookup');
|
||||
return module.exports(names[0]);
|
||||
};
|
||||
|
||||
module.exports.completion = install.completion;
|
||||
module.exports.completion.options = shorthand;
|
||||
@@ -1,66 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Lookup API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var nopt = require('nopt');
|
||||
var readline = require('readline');
|
||||
|
||||
var template = require('../util/template');
|
||||
var source = require('../core/source');
|
||||
var help = require('./help');
|
||||
|
||||
var optionTypes = { help: Boolean };
|
||||
var shorthand = { 'h': ['--help'], '-s': ['--silent'] };
|
||||
|
||||
var register = function (name, url, emitter) {
|
||||
source.register(name, url, function (err) {
|
||||
if (err) return emitter.emit('error', err);
|
||||
|
||||
template('register', {name: name, url: url})
|
||||
.on('data', emitter.emit.bind(emitter, 'data'));
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = function (name, url, options) {
|
||||
var emitter = new Emitter;
|
||||
|
||||
if (options.silent) register(name, url, emitter);
|
||||
else {
|
||||
var rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
||||
|
||||
console.log('Registering a package will make it visible and installable via the registry.');
|
||||
rl.question('Proceed (y/n)? ', function (res) {
|
||||
rl.close();
|
||||
|
||||
res = res.toLowerCase();
|
||||
|
||||
if (res === 'y' || res === 'yes') register(name, url, emitter);
|
||||
});
|
||||
}
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
var args = options.argv.remain.slice(1);
|
||||
|
||||
if (options.help || args.length !== 2) return help('register');
|
||||
return module.exports(args[0], args[1], options);
|
||||
};
|
||||
|
||||
module.exports.completion = function (opts, cb) {
|
||||
var word = opts.word;
|
||||
|
||||
// completing options?
|
||||
if (word.charAt(0) === '-') {
|
||||
return cb(null, Object.keys(optionTypes).map(function (option) {
|
||||
return '--' + option;
|
||||
}));
|
||||
}
|
||||
};
|
||||
@@ -1,61 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Lookup API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var nopt = require('nopt');
|
||||
|
||||
var template = require('../util/template');
|
||||
var source = require('../core/source');
|
||||
var install = require('./install');
|
||||
var help = require('./help');
|
||||
|
||||
var optionTypes = { help: Boolean };
|
||||
var shorthand = { 'h': ['--help'] };
|
||||
|
||||
module.exports = function (name) {
|
||||
var emitter = new Emitter;
|
||||
|
||||
var callback = function (err, results) {
|
||||
if (err) return emitter.emit('error', err);
|
||||
|
||||
emitter.emit('packages', results);
|
||||
|
||||
if (results.length) {
|
||||
template('search', {results: results})
|
||||
.on('data', function (data) {
|
||||
emitter.emit('data', data);
|
||||
emitter.emit('end');
|
||||
});
|
||||
} else {
|
||||
template('search-empty', {results: results})
|
||||
.on('data', function (data) {
|
||||
emitter.emit('data', data);
|
||||
emitter.emit('end');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (name) {
|
||||
source.search(name, callback);
|
||||
} else {
|
||||
source.all(callback);
|
||||
}
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
var names = options.argv.remain.slice(1);
|
||||
|
||||
if (options.help) return help('search');
|
||||
return module.exports(names[0]);
|
||||
};
|
||||
|
||||
module.exports.completion = install.completion;
|
||||
module.exports.completion.options = shorthand;
|
||||
@@ -1,206 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Uninstall API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var async = require('async');
|
||||
var nopt = require('nopt');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var _ = require('lodash');
|
||||
|
||||
var template = require('../util/template');
|
||||
var Manager = require('../core/manager');
|
||||
var config = require('../core/config');
|
||||
var help = require('./help');
|
||||
|
||||
var optionTypes = { help: Boolean, force: Boolean, save: Boolean };
|
||||
var shorthand = { 'h': ['--help'], 'S': ['--save'], 'D': ['--save-dev'], 'f': ['--force'] };
|
||||
|
||||
module.exports = function (names, options) {
|
||||
var packages, uninstallables, packagesCount = {};
|
||||
var emitter = new Emitter;
|
||||
var manager = new Manager;
|
||||
var jsonDeps;
|
||||
var newLine;
|
||||
|
||||
options = options || {};
|
||||
|
||||
manager.on('data', emitter.emit.bind(emitter, 'data'));
|
||||
manager.on('error', emitter.emit.bind(emitter, 'error'));
|
||||
|
||||
var resolveLocal = function () {
|
||||
jsonDeps = manager.json.dependencies || {};
|
||||
packages = _.flatten(_.values(manager.dependencies));
|
||||
uninstallables = packages.filter(function (pkg) {
|
||||
return _.include(names, pkg.name);
|
||||
});
|
||||
async.forEach(packages, function (pkg, next) {
|
||||
pkg.once('loadJSON', next).loadJSON();
|
||||
}, function () {
|
||||
if (showWarnings(options.force) && !options.force) return;
|
||||
expandUninstallabes(options.force);
|
||||
uninstall();
|
||||
});
|
||||
};
|
||||
|
||||
var showWarnings = function (force) {
|
||||
var foundConflicts = false;
|
||||
|
||||
packages.forEach(function (pkg) {
|
||||
if (!pkg.json.dependencies) return;
|
||||
if (containsPkg(uninstallables, pkg)) return;
|
||||
|
||||
var conflicts = _.intersection(
|
||||
Object.keys(pkg.json.dependencies),
|
||||
_.pluck(uninstallables, 'name')
|
||||
);
|
||||
|
||||
if (conflicts.length) {
|
||||
foundConflicts = true;
|
||||
if (!force) {
|
||||
conflicts.forEach(function (conflictName) {
|
||||
emitter.emit('data', template('warning-uninstall', { packageName: pkg.name, conflictName: conflictName }, true));
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (foundConflicts && !force) {
|
||||
emitter.emit('data', template('warn', { message: 'To proceed, run uninstall with the --force flag'}, true));
|
||||
}
|
||||
|
||||
return foundConflicts;
|
||||
};
|
||||
|
||||
var expandUninstallabes = function (force) {
|
||||
var x,
|
||||
pkg,
|
||||
forcedUninstallables = {};
|
||||
|
||||
// Direct JSON deps have a count of 1
|
||||
for (var key in jsonDeps) {
|
||||
packagesCount[key] = 1;
|
||||
}
|
||||
|
||||
// Count all packages
|
||||
count(packages, packagesCount);
|
||||
|
||||
if (force) {
|
||||
uninstallables.forEach(function (pkg) {
|
||||
forcedUninstallables[pkg.name] = true;
|
||||
});
|
||||
}
|
||||
|
||||
// Expand the uninstallables deps and nested deps
|
||||
// Also update the count accordingly
|
||||
for (x = uninstallables.length - 1; x >= 0; x -= 1) {
|
||||
parseUninstallableDeps(uninstallables[x]);
|
||||
}
|
||||
|
||||
// Foreach uninstallable, check if it is really to be removed by reading the final count
|
||||
// If the final count is greater than 0, then it is a shared dep
|
||||
// In that case, we remove it from the uninstallables unless it's forced to be uninstalled
|
||||
for (x = uninstallables.length - 1; x >= 0; x -= 1) {
|
||||
pkg = uninstallables[x];
|
||||
if (packagesCount[pkg.name] > 0 && !forcedUninstallables[pkg.name]) uninstallables.splice(x, 1);
|
||||
}
|
||||
};
|
||||
|
||||
var count = function (packages, counts, nested) {
|
||||
packages.forEach(function (pkg) {
|
||||
counts[pkg.name] = (counts[pkg.name] || 0);
|
||||
if (nested) counts[pkg.name] += 1;
|
||||
|
||||
if (pkg.json.dependencies) {
|
||||
for (var key in pkg.json.dependencies) {
|
||||
count(manager.dependencies[key], counts, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var parseUninstallableDeps = function (pkg) {
|
||||
if (!containsPkg(uninstallables, pkg)) uninstallables.push(pkg);
|
||||
packagesCount[pkg.name] -= 1;
|
||||
|
||||
if (pkg.json.dependencies) {
|
||||
for (var key in pkg.json.dependencies) {
|
||||
parseUninstallableDeps(manager.dependencies[key][0]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var containsPkg = function (packages, pkg) {
|
||||
for (var x = packages.length - 1; x >= 0; x -= 1) {
|
||||
if (packages[x].name === pkg.name) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
var uninstall = function () {
|
||||
async.forEach(uninstallables, function (pkg, next) {
|
||||
pkg.on('uninstall', function () {
|
||||
emitter.emit('package', pkg);
|
||||
next();
|
||||
}).uninstall();
|
||||
}, function () {
|
||||
// Finally save
|
||||
if (options.save || options['save-dev']) save(!options.save);
|
||||
emitter.emit('end');
|
||||
});
|
||||
};
|
||||
|
||||
var save = function (dev) {
|
||||
var key = dev ? 'devDependencies' : 'dependencies';
|
||||
var contents;
|
||||
|
||||
if (manager.json[key]) {
|
||||
names.forEach(function (name) {
|
||||
delete manager.json[key][name];
|
||||
});
|
||||
|
||||
contents = JSON.stringify(manager.json, null, 2) + (newLine ? '\n' : '');
|
||||
fs.writeFileSync(path.join(manager.cwd, config.json), contents);
|
||||
}
|
||||
};
|
||||
|
||||
manager.on('loadJSON', function (hasNewLine) {
|
||||
newLine = hasNewLine;
|
||||
manager.on('resolveLocal', resolveLocal).resolveLocal();
|
||||
}).loadJSON();
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
var names = options.argv.remain.slice(1);
|
||||
|
||||
if (options.help || !names.length) return help('uninstall');
|
||||
return module.exports(names, options);
|
||||
};
|
||||
|
||||
module.exports.completion = function (opts, cb) {
|
||||
var word = opts.word;
|
||||
|
||||
// completing options?
|
||||
if (opts.words[0] === 'uninstall' && word.charAt(0) === '-') {
|
||||
return cb(null, Object.keys(optionTypes).map(function (option) {
|
||||
return '--' + option;
|
||||
}));
|
||||
}
|
||||
|
||||
fs.readdir(config.directory, function (err, dirs) {
|
||||
// ignore ENOENT, ./bower_components not created yet
|
||||
if (err && err.code === 'ENOENT') return cb(null, []);
|
||||
cb(err, dirs);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.completion.options = shorthand;
|
||||
@@ -1,110 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Update API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var async = require('async');
|
||||
var nopt = require('nopt');
|
||||
var _ = require('lodash');
|
||||
|
||||
var Manager = require('../core/manager');
|
||||
var help = require('./help');
|
||||
var uninstall = require('./uninstall');
|
||||
var save = require('../util/save');
|
||||
|
||||
var optionTypes = { help: Boolean, save: Boolean, force: Boolean, 'force-latest': Boolean };
|
||||
var shorthand = { 'h': ['--help'], 'S': ['--save'], 'f': ['--force'], 'F': ['--force-latest'] };
|
||||
|
||||
module.exports = function (names, options) {
|
||||
options = options || {};
|
||||
|
||||
var emitter = new Emitter;
|
||||
var manager = new Manager([], {
|
||||
force: options.force,
|
||||
forceLatest: options['force-latest']
|
||||
});
|
||||
|
||||
manager.on('data', emitter.emit.bind(emitter, 'data'));
|
||||
manager.on('error', emitter.emit.bind(emitter, 'error'));
|
||||
|
||||
var install = function (err, array) {
|
||||
var mappings = {},
|
||||
endpoints = [],
|
||||
name,
|
||||
info,
|
||||
length,
|
||||
x;
|
||||
|
||||
length = names.length;
|
||||
if (length) {
|
||||
for (x = 0; x < length; x += 1) {
|
||||
name = names[x];
|
||||
info = _.find(array, function (info) { return info.name === name; });
|
||||
if (!info) {
|
||||
return emitter.emit('error', new Error('Package ' + name + ' is not installed'));
|
||||
}
|
||||
|
||||
endpoints.push(info.endpoint);
|
||||
mappings[info.endpoint] = info.name;
|
||||
}
|
||||
} else {
|
||||
array.forEach(function (info) {
|
||||
endpoints.push(info.endpoint);
|
||||
mappings[info.endpoint] = info.name;
|
||||
});
|
||||
}
|
||||
|
||||
options.endpointNames = mappings;
|
||||
|
||||
// By default the manager will guess the name of the package from the url
|
||||
// But this leads to problems when the package name does not match the one in the url
|
||||
// So the manager now has an option (endpointNames) to deal with this
|
||||
manager = new Manager(endpoints, options);
|
||||
manager
|
||||
.on('data', emitter.emit.bind(emitter, 'data'))
|
||||
.on('warn', emitter.emit.bind(emitter, 'warn'))
|
||||
.on('error', emitter.emit.bind(emitter, 'error'))
|
||||
.on('resolve', function (resolved) {
|
||||
// Handle save
|
||||
if (resolved && options.save) save(manager, null, false, emitter.emit.bind(emitter, 'end'));
|
||||
else emitter.emit('end');
|
||||
})
|
||||
.resolve();
|
||||
};
|
||||
|
||||
manager.once('resolveLocal', function () {
|
||||
async.map(_.values(manager.dependencies), function (pkgs, next) {
|
||||
var pkg = pkgs[0];
|
||||
pkg.once('loadJSON', function () {
|
||||
var endpointInfo = pkg.readEndpoint();
|
||||
if (!endpointInfo) return next();
|
||||
|
||||
// Add tag only if the endpoint is a repository
|
||||
var endpoint = endpointInfo.endpoint;
|
||||
var json = pkg.json;
|
||||
if (!json.commit && (endpointInfo.type === 'git' || endpointInfo.type === 'local-repo')) {
|
||||
endpoint += '#' + ((!names || names.indexOf(pkg.name) > -1) ? '~' : '') + pkg.version;
|
||||
}
|
||||
|
||||
next(null, { name: pkg.name, endpoint: endpoint });
|
||||
}).loadJSON();
|
||||
}, install);
|
||||
}).resolveLocal();
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
if (options.help) return help('update');
|
||||
|
||||
var paths = options.argv.remain.slice(1);
|
||||
return module.exports(paths, options);
|
||||
};
|
||||
|
||||
module.exports.completion = uninstall.completion;
|
||||
module.exports.completion.options = shorthand;
|
||||
@@ -1,75 +0,0 @@
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var _ = require('lodash');
|
||||
var tmp = require('tmp');
|
||||
var mkdirp = require('mkdirp');
|
||||
var zlib = require('zlib');
|
||||
|
||||
var fileExists = require('../util/file-exists').sync;
|
||||
|
||||
// This forces the default chunk size to something small in an attempt
|
||||
// to avoid issue #314
|
||||
zlib.Z_DEFAULT_CHUNK = 1024 * 8;
|
||||
|
||||
var temp = process.env.TMPDIR
|
||||
|| process.env.TMP
|
||||
|| process.env.TEMP
|
||||
|| process.platform === 'win32' ? 'c:\\windows\\temp' : '/tmp';
|
||||
|
||||
var home = (process.platform === 'win32'
|
||||
? process.env.USERPROFILE
|
||||
: process.env.HOME) || temp;
|
||||
|
||||
var roaming = process.platform === 'win32'
|
||||
? path.resolve(process.env.APPDATA || home || temp)
|
||||
: path.resolve(home || temp);
|
||||
|
||||
var folder = process.platform === 'win32'
|
||||
? 'bower'
|
||||
: '.bower';
|
||||
|
||||
var proxy = process.env.HTTPS_PROXY
|
||||
|| process.env.https_proxy
|
||||
|| process.env.HTTP_PROXY
|
||||
|| process.env.http_proxy;
|
||||
|
||||
// Bower Config
|
||||
var config;
|
||||
try {
|
||||
config = require('rc') ('bower', {
|
||||
cache : path.join(roaming, folder, 'cache'),
|
||||
links : path.join(roaming, folder, 'links'),
|
||||
completion : path.join(roaming, folder, 'completion'),
|
||||
git_template : path.join(roaming, folder, 'git_template'),
|
||||
json : 'bower.json',
|
||||
endpoint : 'https://bower.herokuapp.com',
|
||||
directory : !fileExists('bower_components') && fileExists('components') ? 'components' : 'bower_components',
|
||||
proxy : proxy,
|
||||
shorthand_resolver : 'git://github.com/{{{ endpoint }}}.git'
|
||||
});
|
||||
} catch (e) {
|
||||
throw new Error('Unable to parse global .bowerrc file: ' + e.message);
|
||||
}
|
||||
|
||||
// If there is a local .bowerrc file, merge it
|
||||
var localFile = path.join(process.cwd(), '.bowerrc');
|
||||
if (fileExists(localFile)) {
|
||||
try {
|
||||
_.extend(config, JSON.parse(fs.readFileSync(localFile)));
|
||||
} catch (e) {
|
||||
throw new Error('Unable to parse local .bowerrc file: ' + e.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that we have our git template directory
|
||||
try {
|
||||
mkdirp.sync(config.git_template);
|
||||
} catch (e) {
|
||||
throw new Error('Unable to create git_template directory: ' + e.message);
|
||||
}
|
||||
|
||||
// Configure tmp package to use graceful degradation
|
||||
// If an uncaught exception occurs, the temporary directories will be deleted nevertheless
|
||||
tmp.setGracefulCleanup();
|
||||
|
||||
module.exports = config;
|
||||
@@ -1,384 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Manager Object Definition
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
// Events:
|
||||
// - install: fired when everything is installed
|
||||
// - package: fired for each installed packaged
|
||||
// - resolve: fired when deps resolved (with a true/false indicating success or error)
|
||||
// - error: fired on all errors
|
||||
// - data: fired when trying to output data
|
||||
// - warn: fired when a discouraged but not fatal situation arises
|
||||
// - end: fired when finished installing
|
||||
// ==========================================
|
||||
|
||||
var events = require('events');
|
||||
var semver = require('semver');
|
||||
var async = require('async');
|
||||
var path = require('path');
|
||||
var glob = require('glob');
|
||||
var fs = require('fs');
|
||||
var _ = require('lodash');
|
||||
|
||||
var Package = require('./package');
|
||||
var UnitWork = require('./unit_work');
|
||||
var config = require('./config');
|
||||
var fallback = require('../util/fallback');
|
||||
var template = require('../util/template');
|
||||
var prune = require('../util/prune');
|
||||
|
||||
// read local dependencies (with versions)
|
||||
// read json dependencies (resolving along the way into temp dir)
|
||||
// merge local dependencies with json dependencies
|
||||
// prune and move dependencies into local directory
|
||||
|
||||
var Manager = function (endpoints, opts) {
|
||||
this.dependencies = {};
|
||||
this.cwd = process.cwd();
|
||||
this.endpoints = endpoints || [];
|
||||
this.unitWork = new UnitWork;
|
||||
this.opts = opts || {};
|
||||
this.errors = [];
|
||||
};
|
||||
|
||||
Manager.prototype = Object.create(events.EventEmitter.prototype);
|
||||
Manager.prototype.constructor = Manager;
|
||||
|
||||
Manager.prototype.loadJSON = function () {
|
||||
fallback(this.cwd, [config.json, 'component.json'], function (file) {
|
||||
if (file !== null) {
|
||||
if (file !== config.json) {
|
||||
this.emit('warn', 'Using deprecated "component.json". Please use "bower.json" instead');
|
||||
}
|
||||
|
||||
return this.readJSON(path.join(this.cwd, file));
|
||||
}
|
||||
|
||||
this.createJSON();
|
||||
return this.emit('loadJSON');
|
||||
}.bind(this));
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Manager.prototype.resolve = function () {
|
||||
var resolved = function () {
|
||||
// If there is errors, report them
|
||||
if (this.errors.length) return this.reportErrors();
|
||||
// If there is an error while pruning (conflict) then abort installation
|
||||
if (!this.prune()) return this.emit('resolve', false);
|
||||
// Otherwise all is fine, so we install
|
||||
this.once('install', this.emit.bind(this, 'resolve', true)).install();
|
||||
}.bind(this);
|
||||
|
||||
// Resolve locally first
|
||||
this.once('resolveLocal', function () {
|
||||
if (this.endpoints.length) {
|
||||
// TODO: When resolving specific endpoints we need to restore all the local
|
||||
// packages and their hierarchy (all from the local folder)
|
||||
// If something goes wrong, simply do resolveFromJSON before
|
||||
// calling resolved() (slower)
|
||||
// This will solve issue #200
|
||||
this.once('resolveEndpoints', resolved).resolveEndpoints();
|
||||
} else {
|
||||
this.once('resolveFromJson', resolved).resolveFromJson();
|
||||
}
|
||||
}).resolveLocal();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Manager.prototype.resolveLocal = function () {
|
||||
glob('./' + config.directory + '/*', function (err, dirs) {
|
||||
if (err) return this.emit('error', err);
|
||||
dirs.forEach(function (dir) {
|
||||
var name = path.basename(dir);
|
||||
var pkg = new Package(name, dir, this);
|
||||
|
||||
this.dependencies[name] = [];
|
||||
this.dependencies[name].push(pkg);
|
||||
|
||||
this.gatherPackageErrors(pkg);
|
||||
}.bind(this));
|
||||
this.emit('resolveLocal');
|
||||
}.bind(this));
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Manager.prototype.resolveEndpoints = function () {
|
||||
var endpointNames = this.opts.endpointNames || {};
|
||||
|
||||
async.forEach(this.endpoints, function (endpoint, next) {
|
||||
var name = endpointNames[endpoint];
|
||||
var pkg = new Package(name, endpoint, this);
|
||||
var errorNext;
|
||||
|
||||
pkg.root = true;
|
||||
this.dependencies[name] = this.dependencies[name] || [];
|
||||
this.dependencies[name].push(pkg);
|
||||
|
||||
this.gatherPackageErrors(pkg);
|
||||
pkg.once('error', errorNext = next.bind(next, null));
|
||||
pkg.once('resolve', function () {
|
||||
pkg.removeListener('error', errorNext);
|
||||
next();
|
||||
}).resolve();
|
||||
}.bind(this), this.emit.bind(this, 'resolveEndpoints'));
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Manager.prototype.resolveFromJson = function () {
|
||||
this.once('loadJSON', function () {
|
||||
var dependencies = this.json.dependencies || {};
|
||||
|
||||
// add devDependencies
|
||||
if (!this.opts.production && this.json.devDependencies) {
|
||||
dependencies = _.extend({}, dependencies, this.json.devDependencies);
|
||||
}
|
||||
|
||||
async.forEach(Object.keys(dependencies), function (name, next) {
|
||||
var endpoint = dependencies[name];
|
||||
|
||||
if (!endpoint) {
|
||||
// The version for the dependency in the JSON is falsy.
|
||||
return this.emit('error', new Error('The version for ' + name + ' is blank in ' + config.json));
|
||||
}
|
||||
|
||||
var pkg = new Package(name, endpoint, this);
|
||||
var errorNext;
|
||||
|
||||
pkg.root = true;
|
||||
|
||||
this.gatherPackageErrors(pkg);
|
||||
|
||||
pkg.once('error', errorNext = next.bind(next, null));
|
||||
pkg.once('resolve', function () {
|
||||
pkg.removeListener('error', errorNext);
|
||||
|
||||
this.dependencies[pkg.name] = this.dependencies[pkg.name] || [];
|
||||
this.dependencies[pkg.name].push(pkg);
|
||||
|
||||
next();
|
||||
}.bind(this)).resolve();
|
||||
}.bind(this), this.emit.bind(this, 'resolveFromJson'));
|
||||
}.bind(this)).loadJSON();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// Private
|
||||
Manager.prototype.createJSON = function () {
|
||||
// If the json does not exist, assume one
|
||||
this.json = {
|
||||
name: path.basename(this.cwd),
|
||||
version: '0.0.0'
|
||||
},
|
||||
this.name = this.json.name;
|
||||
this.version = this.json.version;
|
||||
};
|
||||
|
||||
Manager.prototype.readJSON = function (filename) {
|
||||
fs.readFile(filename, 'utf8', function (err, json) {
|
||||
if (err) return this.emit('error', err);
|
||||
try {
|
||||
this.json = JSON.parse(json);
|
||||
} catch (e) {
|
||||
return this.emit('error', new Error('There was an error while reading the ' + config.json + ': ' + e.message));
|
||||
}
|
||||
this.name = this.json.name;
|
||||
this.version = this.json.version;
|
||||
this.emit('loadJSON', json.slice(-1) === '\n');
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Manager.prototype.getDeepDependencies = function () {
|
||||
var result = {};
|
||||
|
||||
for (var name in this.dependencies) {
|
||||
this.dependencies[name].forEach(function (pkg) {
|
||||
result[pkg.name] = result[pkg.name] || [];
|
||||
result[pkg.name].push(pkg);
|
||||
pkg.getDeepDependencies().forEach(function (pkg) {
|
||||
result[pkg.name] = result[pkg.name] || [];
|
||||
result[pkg.name].push(pkg);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
Manager.prototype.prune = function () {
|
||||
var result = prune(this.getDeepDependencies(), this.opts.forceLatest);
|
||||
var name;
|
||||
|
||||
// If there is conflicted deps, print them and fail
|
||||
if (result.conflicted) {
|
||||
for (name in result.conflicted) {
|
||||
this.reportConflicts(name, result.conflicted[name]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
this.dependencies = {};
|
||||
|
||||
// If there is conflicted deps but they where forcebly resolved
|
||||
// Print a warning about them
|
||||
if (result.forceblyResolved) {
|
||||
for (name in result.forceblyResolved) {
|
||||
this.reportForceblyResolved(name, result.forceblyResolved[name]);
|
||||
this.dependencies[name] = result.forceblyResolved[name];
|
||||
this.dependencies[name][0].root = true;
|
||||
}
|
||||
}
|
||||
|
||||
_.extend(this.dependencies, result.resolved);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
Manager.prototype.gatherPackageErrors = function (pkg) {
|
||||
pkg.on('error', function (err, origin) {
|
||||
pkg = origin || pkg;
|
||||
|
||||
// If the error message starts with the package name, strip it
|
||||
if (!err.message.indexOf(pkg.name + ' ')) {
|
||||
err.message = err.message.substr(pkg.name.length + 1);
|
||||
}
|
||||
|
||||
this.errors.push({ pkg: pkg, error: err });
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Manager.prototype.install = function () {
|
||||
async.forEach(Object.keys(this.dependencies), function (name, next) {
|
||||
var pkg = this.dependencies[name][0];
|
||||
pkg.once('install', function () {
|
||||
this.emit('package', pkg);
|
||||
next();
|
||||
}.bind(this)).install();
|
||||
pkg.once('error', next);
|
||||
}.bind(this), function () {
|
||||
if (this.errors.length) this.reportErrors();
|
||||
return this.emit('install');
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Manager.prototype.muteDependencies = function () {
|
||||
for (var name in this.dependencies) {
|
||||
this.dependencies[name].forEach(function (pkg) {
|
||||
pkg.removeAllListeners();
|
||||
pkg.on('error', function () {});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Manager.prototype.reportErrors = function () {
|
||||
this.muteDependencies();
|
||||
template('error-summary', { errors: this.errors }).on('data', function (data) {
|
||||
this.emit('data', data);
|
||||
this.emit('resolve', false);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Manager.prototype.reportConflicts = function (name, packages) {
|
||||
var versions = [];
|
||||
var requirements = [];
|
||||
|
||||
packages = packages.filter(function (pkg) { return !!pkg.version; });
|
||||
packages.forEach(function (pkg) {
|
||||
requirements.push({ pkg: pkg, tag: pkg.originalTag || '~' + pkg.version });
|
||||
versions.push((pkg.originalTag || '~' + pkg.version).white);
|
||||
});
|
||||
|
||||
this.emit('error', new Error('No resolvable version for ' + name));
|
||||
this.emit('data', template('conflict', {
|
||||
name: name,
|
||||
requirements: requirements,
|
||||
json: config.json,
|
||||
versions: versions.slice(0, -1).join(', ') + ' or ' + versions[versions.length - 1]
|
||||
}, true));
|
||||
};
|
||||
|
||||
Manager.prototype.reportForceblyResolved = function (name, packages) {
|
||||
var requirements = [];
|
||||
|
||||
packages = packages.filter(function (pkg) { return !!pkg.version; });
|
||||
packages.forEach(function (pkg) {
|
||||
requirements.push({ pkg: pkg, tag: pkg.originalTag || '~' + pkg.version });
|
||||
});
|
||||
|
||||
this.emit('data', template('resolved-conflict', {
|
||||
name: name,
|
||||
requirements: requirements,
|
||||
json: config.json,
|
||||
resolvedTo: packages[0].version,
|
||||
forceLatest: this.opts.forceLatest
|
||||
}, true));
|
||||
};
|
||||
|
||||
|
||||
// ----- list ----- //
|
||||
|
||||
// Used in list command
|
||||
// TODO: not sure if this belongs here.. maybe move it to the list command?
|
||||
Manager.prototype.list = function (options) {
|
||||
options = options || {};
|
||||
// If the user passed the paths or map options, we don't need to fetch versions
|
||||
this._isCheckingVersions = !options.offline && !options.paths && !options.map && options.argv;
|
||||
this.once('resolveLocal', this.getDependencyList.bind(this))
|
||||
.resolveLocal();
|
||||
};
|
||||
|
||||
Manager.prototype.getDependencyList = function () {
|
||||
|
||||
var packages = {};
|
||||
var values;
|
||||
var checkVersions = this._isCheckingVersions;
|
||||
|
||||
Object.keys(this.dependencies).forEach(function (key) {
|
||||
packages[key] = this.dependencies[key][0];
|
||||
}.bind(this));
|
||||
|
||||
values = _.values(packages);
|
||||
|
||||
// Do not proceed if no values
|
||||
if (!values.length) {
|
||||
return packages;
|
||||
}
|
||||
|
||||
if (checkVersions) {
|
||||
template('action', { name: 'discover', shizzle: 'Please wait while newer package versions are being discovered' })
|
||||
.on('data', this.emit.bind(this, 'data'));
|
||||
}
|
||||
|
||||
// Load JSON and get version for each package
|
||||
async.forEach(values, function (pkg, next) {
|
||||
pkg.once('loadJSON', function () {
|
||||
// Only check versions if not offline and it's a repo
|
||||
var fetchVersions = checkVersions &&
|
||||
pkg.json.repository &&
|
||||
(pkg.json.repository.type === 'git' || pkg.json.repository.type === 'local-repo');
|
||||
|
||||
if (fetchVersions) {
|
||||
pkg.once('versions', function (versions) {
|
||||
pkg.tags = versions.map(function (ver) {
|
||||
return semver.valid(ver) ? semver.clean(ver) : ver;
|
||||
});
|
||||
next();
|
||||
}).versions();
|
||||
} else {
|
||||
pkg.tags = [];
|
||||
next();
|
||||
}
|
||||
}).loadJSON();
|
||||
}.bind(this), this.emit.bind(this, 'list', packages));
|
||||
};
|
||||
|
||||
module.exports = Manager;
|
||||
@@ -1,974 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Package Object Definition
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
// Events:
|
||||
// - install: fired when package installed
|
||||
// - resolve: fired when deps resolved
|
||||
// - error: fired on all errors
|
||||
// - data: fired when trying to output data
|
||||
// ==========================================
|
||||
|
||||
var fstream = require('fstream');
|
||||
var mkdirp = require('mkdirp');
|
||||
var events = require('events');
|
||||
var rimraf = require('rimraf');
|
||||
var semver = require('semver');
|
||||
var async = require('async');
|
||||
var https = require('https');
|
||||
var http = require('http');
|
||||
var path = require('path');
|
||||
var glob = require('glob');
|
||||
var url = require('url');
|
||||
var tmp = require('tmp');
|
||||
var fs = require('fs');
|
||||
var crypto = require('crypto');
|
||||
var unzip = require('unzip');
|
||||
var tar = require('tar');
|
||||
var _ = require('lodash');
|
||||
var hogan = require('hogan.js');
|
||||
var which = require('which').sync;
|
||||
|
||||
var config = require('./config');
|
||||
var source = require('./source');
|
||||
var template = require('../util/template');
|
||||
var readJSON = require('../util/read-json');
|
||||
var fileExists = require('../util/file-exists');
|
||||
var fallback = require('../util/fallback');
|
||||
var isRepo = require('../util/is-repo');
|
||||
var git = require('../util/git-cmd');
|
||||
var UnitWork = require('./unit_work');
|
||||
|
||||
var hasGit;
|
||||
|
||||
// Check if git is installed
|
||||
try {
|
||||
which('git');
|
||||
hasGit = true;
|
||||
} catch (ex) {
|
||||
hasGit = false;
|
||||
}
|
||||
|
||||
var Package = function (name, endpoint, manager) {
|
||||
this.dependencies = {};
|
||||
this.json = {};
|
||||
this.name = name;
|
||||
this.manager = manager;
|
||||
this.unitWork = manager ? manager.unitWork : new UnitWork;
|
||||
this.opts = manager ? manager.opts : {};
|
||||
this.explicitName = true;
|
||||
|
||||
var split;
|
||||
|
||||
if (endpoint) {
|
||||
if (/^(.*\.git)$/.exec(endpoint)) {
|
||||
this.gitUrl = RegExp.$1.replace(/^git\+/, '');
|
||||
this.tag = false;
|
||||
|
||||
} else if (/^(.*\.git)#(.*)$/.exec(endpoint)) {
|
||||
this.tag = RegExp.$2;
|
||||
this.gitUrl = RegExp.$1.replace(/^git\+/, '');
|
||||
|
||||
} else if (/^(?:(git):|git\+(https?):)\/\/([^#]+)#?(.*)$/.exec(endpoint)) {
|
||||
this.gitUrl = (RegExp.$1 || RegExp.$2) + '://' + RegExp.$3;
|
||||
this.tag = RegExp.$4;
|
||||
|
||||
} else if (semver.validRange(endpoint)) {
|
||||
this.tag = endpoint;
|
||||
this.explicitName = false;
|
||||
|
||||
} else if (/^[\.\/~]\.?[^.]*\.(js|css)/.test(endpoint) && fs.statSync(endpoint).isFile()) {
|
||||
this.path = path.resolve(endpoint);
|
||||
this.assetType = path.extname(endpoint);
|
||||
|
||||
} else if (/^https?:\/\//.exec(endpoint)) {
|
||||
this.assetUrl = endpoint;
|
||||
this.assetType = path.extname(endpoint);
|
||||
|
||||
} else if (fileExists.sync((split = endpoint.split('#', 2))[0]) && fs.statSync(split[0]).isDirectory()) {
|
||||
this.path = path.resolve(split[0]);
|
||||
this.tag = split[1];
|
||||
|
||||
} else if (/^[\.\/~]/.test(endpoint)) {
|
||||
this.path = path.resolve(endpoint);
|
||||
|
||||
} else if (endpoint.split('/').length === 2) {
|
||||
this.gitUrl = this.resolveShorthand(config.shorthand_resolver, (split = endpoint.split('#', 2))[0]);
|
||||
this.tag = split[1];
|
||||
this.shorthand = endpoint;
|
||||
|
||||
} else {
|
||||
split = endpoint.split('#', 2);
|
||||
this.tag = split[1];
|
||||
}
|
||||
|
||||
// Guess names
|
||||
if (!this.name) {
|
||||
this.name = this.guessName(split && split[0]);
|
||||
this.explicitName = false;
|
||||
} else {
|
||||
this.explicitName = true;
|
||||
}
|
||||
|
||||
this.cacheName = this.name;
|
||||
|
||||
// Store a reference to the original tag & original path
|
||||
// This is because the tag & paths can get rewritten later
|
||||
if (this.tag) this.originalTag = this.tag;
|
||||
if (this.path) this.originalPath = endpoint;
|
||||
if (this.assetUrl) this.originalAssetUrl = this.assetUrl;
|
||||
|
||||
// The id is an unique id that describes this package
|
||||
this.id = crypto.createHash('md5').update(this.name + '%' + this.tag + '%' + this.gitUrl + '%' + this.path + '%' + this.assetUrl).digest('hex');
|
||||
|
||||
// Generate a resource id
|
||||
if (this.gitUrl) this.generateResourceId();
|
||||
}
|
||||
|
||||
if (this.manager) {
|
||||
this.on('data', this.manager.emit.bind(this.manager, 'data'));
|
||||
this.on('warn', this.manager.emit.bind(this.manager, 'warn'));
|
||||
this.on('error', function (err, origin) {
|
||||
// Unlock the unit of work automatically on error (only if the error is from this package)
|
||||
if (!origin && this.unitWork.isLocked(this.cacheName)) this.unitWork.unlock(this.cacheName, this);
|
||||
// Propagate the error event to the parent package/manager
|
||||
this.manager.emit('error', err, origin || this);
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
// Cache a self bound function
|
||||
this.waitUnlock = this.waitUnlock.bind(this);
|
||||
|
||||
this.setMaxListeners(30); // Increase the number of listeners because a package can have more than the default 10 dependencies
|
||||
};
|
||||
|
||||
Package.prototype = Object.create(events.EventEmitter.prototype);
|
||||
|
||||
Package.prototype.constructor = Package;
|
||||
|
||||
Package.prototype.resolve = function () {
|
||||
// If this.cacheName is not defined then this.generateResourceId() fail
|
||||
// Which in turn makes this.resolve() fail
|
||||
// So there is no point in continuing because we can't do anything useful.
|
||||
// This happens when no endpoint is given to new Package()
|
||||
if (!this.cacheName) {
|
||||
return this.emit('error', new Error('Could not determine an endpoint or version for ' + this.name));
|
||||
}
|
||||
|
||||
// Ensure that nobody is resolving the same dep at the same time
|
||||
// If there is, we wait for the unlock event
|
||||
if (this.unitWork.isLocked(this.cacheName)) return this.unitWork.on('unlock', this.waitUnlock);
|
||||
|
||||
var data = this.unitWork.retrieve(this.cacheName);
|
||||
if (data) {
|
||||
// Check if this exact package is the last resolved one
|
||||
// If so, we copy the resolved result and we don't need to do anything else
|
||||
if (data.id === this.id) {
|
||||
this.unserialize(data);
|
||||
this.emit('resolve');
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
// If not, we lock and resolve it
|
||||
this.unitWork.lock(this.cacheName, this);
|
||||
|
||||
if (this.assetUrl) {
|
||||
this.download();
|
||||
} else if (this.gitUrl) {
|
||||
this.clone();
|
||||
} else if (this.path) {
|
||||
this.copy();
|
||||
} else {
|
||||
this.once('lookup', this.clone).lookup();
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Package.prototype.lookup = function () {
|
||||
source.lookup(this.name, function (err, url) {
|
||||
if (err) return this.emit('error', err);
|
||||
this.lookedUp = true;
|
||||
this.gitUrl = url;
|
||||
this.generateResourceId();
|
||||
this.emit('lookup');
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Package.prototype.install = function () {
|
||||
// Only print the installing action if this package has been resolved
|
||||
if (this.unitWork.retrieve(this.cacheName)) {
|
||||
template('action', { name: 'installing', shizzle: this.name + (this.version ? '#' + this.version : '') })
|
||||
.on('data', this.emit.bind(this, 'data'));
|
||||
}
|
||||
|
||||
var localPath = this.localPath;
|
||||
|
||||
if (path.resolve(this.path) === localPath) {
|
||||
this.emit('install');
|
||||
return this;
|
||||
}
|
||||
|
||||
// Remove stuff from the local path (if any)
|
||||
// Rename path to the local path
|
||||
// Beware that if the local path exists and is a git repository, the process is aborted
|
||||
isRepo(localPath, function (is) {
|
||||
if (is) {
|
||||
var err = new Error('Local path is a local repository');
|
||||
err.details = 'To avoid losing work, please remove ' + localPath + ' manually.';
|
||||
return this.emit('error', err, this);
|
||||
}
|
||||
|
||||
mkdirp(path.dirname(localPath), function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
rimraf(localPath, function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
return fs.rename(this.path, localPath, function (err) {
|
||||
if (!err) return this.cleanUpLocal();
|
||||
|
||||
var writter = fstream.Writer({
|
||||
type: 'Directory',
|
||||
path: localPath
|
||||
});
|
||||
writter
|
||||
.on('error', this.emit.bind(this, 'error'))
|
||||
.on('end', rimraf.bind(this, this.path, this.cleanUpLocal.bind(this)));
|
||||
|
||||
fstream.Reader(this.path)
|
||||
.on('error', this.emit.bind(this, 'error'))
|
||||
.pipe(writter);
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Package.prototype.cleanUpLocal = function () {
|
||||
this.once('readLocalConfig', function () {
|
||||
this.json.name = this.name;
|
||||
this.json.version = this.commit ? '0.0.0' : this.version || '0.0.0';
|
||||
|
||||
// Detect commit and save it in the json for later use
|
||||
if (this.commit) this.json.commit = this.commit;
|
||||
else delete this.json.commit;
|
||||
|
||||
if (this.gitUrl) this.json.repository = { type: 'git', url: this.gitUrl };
|
||||
else if (this.gitPath) this.json.repository = { type: 'local-repo', path: this.originalPath };
|
||||
else if (this.originalPath) this.json.repository = { type: 'local', path: this.originalPath };
|
||||
else if (this.assetUrl) this.json = this.generateAssetJSON();
|
||||
|
||||
var jsonStr = JSON.stringify(this.json, null, 2);
|
||||
|
||||
// Save json file
|
||||
async.parallel({
|
||||
'local': function (next) {
|
||||
fs.writeFile(path.join(this.localPath, this.localConfig.json), jsonStr, next);
|
||||
}.bind(this),
|
||||
'git-path': function (next) {
|
||||
if (!this.gitPath) return next();
|
||||
fileExists(this.gitPath, function (exists) {
|
||||
if (!exists) return next();
|
||||
fs.writeFile(path.join(this.gitPath, this.localConfig.json), jsonStr, next);
|
||||
}.bind(this));
|
||||
}.bind(this)
|
||||
}, function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
this.removeLocalPaths();
|
||||
}.bind(this));
|
||||
|
||||
}.bind(this)).readLocalConfig();
|
||||
};
|
||||
|
||||
// finish clean up local by removing .git/ and any ignored files
|
||||
Package.prototype.removeLocalPaths = function () {
|
||||
var removePatterns = ['.git'];
|
||||
if (this.json.ignore) {
|
||||
removePatterns.push.apply(removePatterns, this.json.ignore);
|
||||
}
|
||||
|
||||
var removePaths = [];
|
||||
|
||||
// 3: done
|
||||
var pathsRemoved = function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
this.emit('install');
|
||||
}.bind(this);
|
||||
|
||||
// 2: trigger after paths have been globbed
|
||||
var rimrafPaths = function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
async.forEach(removePaths, function (removePath, next) {
|
||||
// rimraf all the paths
|
||||
rimraf(path.join(this.localPath, removePath), next);
|
||||
}.bind(this), pathsRemoved);
|
||||
}.bind(this);
|
||||
|
||||
// 1: get paths
|
||||
var globOpts = { dot: true, cwd: this.localPath };
|
||||
async.forEach(removePatterns, function (removePattern, next) {
|
||||
// glob path for file path pattern matching
|
||||
glob(removePattern, globOpts, function (err, globPaths) {
|
||||
if (err) return next(err);
|
||||
removePaths.push.apply(removePaths, globPaths);
|
||||
next();
|
||||
}.bind(this));
|
||||
}.bind(this), rimrafPaths);
|
||||
};
|
||||
|
||||
Package.prototype.generateAssetJSON = function () {
|
||||
return {
|
||||
name: this.name,
|
||||
main: this.assetType !== '.zip' && this.assetType !== '.tar' ? 'index' + this.assetType : '',
|
||||
version: '0.0.0',
|
||||
repository: { type: 'asset', url: this.originalAssetUrl }
|
||||
};
|
||||
};
|
||||
|
||||
Package.prototype.uninstall = function () {
|
||||
template('action', { name: 'uninstalling', shizzle: this.path })
|
||||
.on('data', this.emit.bind(this, 'data'));
|
||||
rimraf(this.path, function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
this.emit('uninstall');
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
// Private
|
||||
Package.prototype.guessName = function (fallback) {
|
||||
if (this.gitUrl) return path.basename(this.gitUrl).replace(/(\.git)?(#.*)?$/, '');
|
||||
if (this.path) return path.basename(this.path, this.assetType);
|
||||
if (this.assetUrl) return path.basename(this.assetUrl, this.assetType);
|
||||
return fallback;
|
||||
};
|
||||
|
||||
Package.prototype.findJSON = function () {
|
||||
fallback(this.path, [config.json, 'bower.json', 'component.json'], function (name) {
|
||||
if (name) {
|
||||
if (name === 'component.json') {
|
||||
this.emit('warn', 'Package ' + this.name + ' is still using the deprecated "component.json" file');
|
||||
}
|
||||
this.localConfig.json = name;
|
||||
}
|
||||
this.emit('readLocalConfig');
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Package.prototype.readLocalConfig = function () {
|
||||
if (this.localConfig) return this.emit('readLocalConfig');
|
||||
|
||||
fs.readFile(path.join(this.path, '.bowerrc'), function (err, file) {
|
||||
// If the local .bowerrc file do not exists then we check if the
|
||||
// json specific in the config exists (if not, we fallback to bower.json)
|
||||
if (err) {
|
||||
this.localConfig = { json: config.json };
|
||||
this.findJSON();
|
||||
} else {
|
||||
// If the local .bowerrc file exists, we read it and check if a custom json file
|
||||
// is defined. If not, we check if the global config json file exists (if not, we fallback to bower.json)
|
||||
try {
|
||||
this.localConfig = JSON.parse(file);
|
||||
} catch (e) {
|
||||
return this.emit('error', new Error('Unable to parse local .bowerrc file: ' + e.message));
|
||||
}
|
||||
|
||||
if (!this.localConfig.json) {
|
||||
this.localConfig.json = config.json;
|
||||
return this.findJSON();
|
||||
}
|
||||
|
||||
this.emit('readLocalConfig');
|
||||
}
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Package.prototype.loadJSON = function () {
|
||||
if (!this.path || this.assetUrl) return this.emit('loadJSON');
|
||||
|
||||
this.once('readLocalConfig', function () {
|
||||
var jsonFile = path.join(this.path, this.localConfig.json);
|
||||
fileExists(jsonFile, function (exists) {
|
||||
// If the json does not exists, we attempt to get the version
|
||||
if (!exists) {
|
||||
return this.once('describeTag', function (tag) {
|
||||
tag = semver.clean(tag);
|
||||
if (!tag) this.version = this.tag;
|
||||
else {
|
||||
this.version = tag;
|
||||
if (!this.tag) this.tag = this.version;
|
||||
}
|
||||
|
||||
this.emit('loadJSON');
|
||||
}.bind(this)).describeTag();
|
||||
}
|
||||
|
||||
readJSON(jsonFile, function (err, json) {
|
||||
if (err) {
|
||||
err.details = 'An error was caught when reading the ' + this.localConfig.json + ': ' + err.message;
|
||||
return this.emit('error', err);
|
||||
}
|
||||
|
||||
this.json = json;
|
||||
this.version = this.commit || json.commit || json.version;
|
||||
this.commit = this.commit || json.commit;
|
||||
// Only overwrite the name if not already set
|
||||
// This is because some packages have different names declared in the registry and the json
|
||||
if (!this.name || !this.explicitName) {
|
||||
this.name = json.name;
|
||||
}
|
||||
|
||||
// Read the endpoint from the json to ensure it is set correctly
|
||||
this.readEndpoint();
|
||||
|
||||
// Detect if the tag mismatches the json.version
|
||||
// This is very often to happen because developers tag their new releases but forget to update the json accordingly
|
||||
var cleanedTag;
|
||||
if (this.tag && (cleanedTag = semver.clean(this.tag)) && cleanedTag !== this.version) {
|
||||
// Only print the warning once
|
||||
if (!this.unitWork.retrieve('mismatch#' + this.cacheName + '_' + cleanedTag)) {
|
||||
template('warning-mismatch', { name: this.cacheName, json: this.localConfig.json, tag: cleanedTag, version: this.version || 'N/A' })
|
||||
.on('data', this.emit.bind(this, 'data'));
|
||||
this.unitWork.store('mismatch#' + this.cacheName + '_' + cleanedTag, true);
|
||||
}
|
||||
// Assume the tag
|
||||
this.version = cleanedTag;
|
||||
}
|
||||
|
||||
this.emit('loadJSON');
|
||||
}.bind(this), this);
|
||||
}.bind(this));
|
||||
}.bind(this)).readLocalConfig();
|
||||
};
|
||||
|
||||
Package.prototype.getAssetType = function (headers) {
|
||||
var assetType;
|
||||
var matches;
|
||||
var contentType = headers['content-type'];
|
||||
var contentDisposition = headers['content-disposition'];
|
||||
|
||||
if (contentType) {
|
||||
contentType = contentType.split(';')[0].trim();
|
||||
switch (contentType.toLowerCase()) {
|
||||
case 'application/zip':
|
||||
assetType = '.zip';
|
||||
break;
|
||||
case 'application/x-tar':
|
||||
assetType = '.tar';
|
||||
break;
|
||||
case 'application/x-tgz':
|
||||
assetType = '.tar.gz';
|
||||
break;
|
||||
case 'application/x-gzip':
|
||||
assetType = '.gz';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!assetType && contentDisposition) {
|
||||
matches = contentDisposition.match(/filename="?(.+?)"?$/i);
|
||||
if (matches && matches[1]) {
|
||||
if (/\.tar\.gz$/.test(matches[1])) {
|
||||
assetType = '.tar.gz';
|
||||
} else {
|
||||
assetType = path.extname(matches[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return assetType;
|
||||
};
|
||||
|
||||
Package.prototype.download = function () {
|
||||
template('action', { name: 'downloading', shizzle: this.assetUrl })
|
||||
.on('data', this.emit.bind(this, 'data'));
|
||||
|
||||
var src;
|
||||
|
||||
if (config.proxy) {
|
||||
src = url.parse(config.proxy);
|
||||
src.path = this.assetUrl;
|
||||
} else {
|
||||
src = url.parse(this.assetUrl);
|
||||
}
|
||||
|
||||
src.agent = false;
|
||||
|
||||
tmp.dir({
|
||||
prefix: 'bower-' + this.name + '-',
|
||||
mode: parseInt('0777', 8) & (~process.umask()),
|
||||
unsafeCleanup: true
|
||||
}, function (err, tmpPath) {
|
||||
if (err) return this.emit('error', err);
|
||||
|
||||
var req = src.protocol === 'https:' ? https : http;
|
||||
req.get(src, function (res) {
|
||||
// If assetUrl results in a redirect we update the assetUrl to the redirect to url
|
||||
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
||||
template('action', { name: 'redirect detected', shizzle: res.headers.location})
|
||||
.on('data', this.emit.bind(this, 'data'));
|
||||
this.assetUrl = res.headers.location;
|
||||
return this.download();
|
||||
}
|
||||
|
||||
// Detect not OK status codes
|
||||
if (res.statusCode < 200 || res.statusCode >= 300) {
|
||||
return this.emit('error', new Error(res.statusCode + ' status code for ' + this.assetUrl));
|
||||
}
|
||||
|
||||
this.assetType = this.getAssetType(res.headers) || this.assetType;
|
||||
|
||||
var file = fs.createWriteStream(path.join((this.path = tmpPath), 'index' + this.assetType));
|
||||
res.on('data', function (data) {
|
||||
file.write(data);
|
||||
});
|
||||
|
||||
res.on('end', function () {
|
||||
file.end();
|
||||
|
||||
var next = function () {
|
||||
this.once('loadJSON', this.saveUnit).loadJSON();
|
||||
}.bind(this);
|
||||
|
||||
if (this.assetType === '.zip' || this.assetType === '.tar') return this.once('extract', next).extract();
|
||||
|
||||
if (this.assetType === '.gz') this.emit('warn', 'gz package type not yet supported');
|
||||
else if (this.assetType === '.tar.gz') this.emit('warn', 'tar.gz package type not yet supported');
|
||||
next();
|
||||
}.bind(this));
|
||||
}.bind(this)).on('error', this.emit.bind(this, 'error'));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Package.prototype.extract = function () {
|
||||
var file = path.join(this.path, 'index' + this.assetType);
|
||||
template('action', { name: 'extracting', shizzle: file }).on('data', this.emit.bind(this, 'data'));
|
||||
|
||||
fs.createReadStream(file).pipe(this.assetType === '.zip' ? unzip.Extract({ path: this.path }) : tar.Extract({ path: this.path }))
|
||||
.on('error', this.emit.bind(this, 'error'))
|
||||
.on('close', function () {
|
||||
// Delete zip
|
||||
fs.unlink(file, function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
|
||||
// If we extracted only a folder, move all the files within it to the original path
|
||||
fs.readdir(this.path, function (err, files) {
|
||||
if (err) return this.emit('error', err);
|
||||
|
||||
if (files.length !== 1) return this.emit('extract');
|
||||
|
||||
var dir = path.join(this.path, files[0]);
|
||||
fs.stat(dir, function (err, stat) {
|
||||
if (err) return this.emit('error', err);
|
||||
if (!stat.isDirectory()) return this.emit('extract');
|
||||
|
||||
fs.readdir(dir, function (err, files) {
|
||||
if (err) return this.emit('error', err);
|
||||
|
||||
async.forEachSeries(files, function (file, next) {
|
||||
fs.rename(path.join(dir, file), path.join(this.path, file), next);
|
||||
}.bind(this), function (err) {
|
||||
if (err) return this.emit('error');
|
||||
|
||||
fs.rmdir(dir, function (err) {
|
||||
if (err) return this.emit('error');
|
||||
this.emit('extract');
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Package.prototype.copy = function () {
|
||||
template('action', { name: 'copying', shizzle: this.path }).on('data', this.emit.bind(this, 'data'));
|
||||
|
||||
tmp.dir({
|
||||
prefix: 'bower-' + this.name + '-',
|
||||
unsafeCleanup: true
|
||||
}, function (err, tmpPath) {
|
||||
if (err) return this.emit('error', err);
|
||||
|
||||
fs.stat(this.path, function (err, stats) {
|
||||
if (err) return this.emit('error', err);
|
||||
|
||||
// Copy file permission for directory
|
||||
fs.chmod(tmpPath, stats.mode, function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
|
||||
if (this.assetType) {
|
||||
return fs.readFile(this.path, function (err, data) {
|
||||
fs.writeFile(path.join((this.path = tmpPath), 'index' + this.assetType), data, function () {
|
||||
this.once('loadJSON', this.saveUnit).loadJSON();
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
this.once('loadJSON', function () {
|
||||
if (this.gitUrl) return this.saveUnit();
|
||||
|
||||
// Check if the copied directory is a git repository and is a local endpoint
|
||||
// If so, treat it like a repository.
|
||||
fileExists(path.join(this.path, '.git'), function (exists) {
|
||||
if (!exists) return this.saveUnit();
|
||||
|
||||
this.gitPath = this.path;
|
||||
this.once('loadJSON', this.saveUnit.bind(this)).checkout();
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
|
||||
var writter = fstream.Writer({
|
||||
type: 'Directory',
|
||||
path: tmpPath
|
||||
})
|
||||
.on('error', this.emit.bind(this, 'error'))
|
||||
.on('end', this.loadJSON.bind(this));
|
||||
|
||||
fstream.Reader(this.path)
|
||||
.on('error', this.emit.bind(this, 'error'))
|
||||
.pipe(writter);
|
||||
|
||||
this.path = tmpPath;
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Package.prototype.getDeepDependencies = function (result) {
|
||||
result = result || [];
|
||||
for (var name in this.dependencies) {
|
||||
result.push(this.dependencies[name]);
|
||||
this.dependencies[name].getDeepDependencies(result);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
Package.prototype.saveUnit = function () {
|
||||
this.unitWork.store(this.cacheName, this.serialize(), this);
|
||||
this.unitWork.unlock(this.cacheName, this);
|
||||
this.addDependencies();
|
||||
};
|
||||
|
||||
Package.prototype.addDependencies = function () {
|
||||
var dependencies = this.json.dependencies || {};
|
||||
var callbacks = Object.keys(dependencies).map(function (name) {
|
||||
return function (callback) {
|
||||
var endpoint = dependencies[name];
|
||||
var pkg = new Package(name, endpoint, this);
|
||||
pkg.once('resolve', function () {
|
||||
this.dependencies[pkg.name] = pkg;
|
||||
callback();
|
||||
}.bind(this)).resolve();
|
||||
}.bind(this);
|
||||
}.bind(this));
|
||||
|
||||
async.parallel(callbacks, function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
this.emit('resolve');
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Package.prototype.exists = function (callback) {
|
||||
fileExists(this.localPath, callback);
|
||||
};
|
||||
|
||||
Package.prototype.clone = function () {
|
||||
if (!hasGit) {
|
||||
return this.emit('error', new Error('git is not installed or not on the PATH'));
|
||||
}
|
||||
|
||||
template('action', { name: 'cloning', shizzle: this.gitUrl }).on('data', this.emit.bind(this, 'data'));
|
||||
this.path = this.gitPath;
|
||||
this.once('cache', function () {
|
||||
this.once('loadJSON', this.copy.bind(this)).checkout();
|
||||
}.bind(this)).cache();
|
||||
};
|
||||
|
||||
Package.prototype.cache = function () {
|
||||
// If the force options is true, we need to erase from the cache
|
||||
// Be aware that a similar package might already flushed it
|
||||
// To prevent that we check the unit of work storage
|
||||
if (this.opts.force && !this.unitWork.retrieve('flushed#' + this.cacheName + '_' + this.resourceId)) {
|
||||
rimraf(this.path, function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
this.unitWork.store('flushed#' + this.cacheName + '_' + this.resourceId, true);
|
||||
this.cache();
|
||||
}.bind(this));
|
||||
return this;
|
||||
}
|
||||
|
||||
mkdirp(config.cache, function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
fileExists(this.path, function (exists) {
|
||||
if (exists) {
|
||||
template('action', { name: 'cached', shizzle: this.gitUrl }).on('data', this.emit.bind(this, 'data'));
|
||||
return this.emit('cache');
|
||||
}
|
||||
template('action', { name: 'caching', shizzle: this.gitUrl }).on('data', this.emit.bind(this, 'data'));
|
||||
var url = this.gitUrl;
|
||||
if (config.proxy) {
|
||||
url = url.replace(/^git:/, 'https:');
|
||||
}
|
||||
|
||||
mkdirp(this.path, function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
|
||||
var cp = git(['clone', url, this.path], null, this);
|
||||
cp.on('close', function (code) {
|
||||
if (code) return;
|
||||
this.emit('cache');
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Package.prototype.checkout = function () {
|
||||
template('action', { name: 'fetching', shizzle: this.name })
|
||||
.on('data', this.emit.bind(this, 'data'));
|
||||
|
||||
var doCheckout = function () {
|
||||
template('action', {
|
||||
name: 'checking out',
|
||||
shizzle: this.name + '#' + this.tag
|
||||
}).on('data', this.emit.bind(this, 'data'));
|
||||
|
||||
// Checkout the tag
|
||||
git([ 'checkout', this.tag, '-f'], { cwd: this.path }, this).on('close', function (code) {
|
||||
if (code) return;
|
||||
// Ensure that checkout the tag as it is, removing all untracked files
|
||||
git(['clean', '-f', '-d'], { cwd: this.path }, this).on('close', function (code) {
|
||||
if (code) return;
|
||||
this.emit('checkout');
|
||||
this.loadJSON();
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this);
|
||||
|
||||
if (this.tag && !semver.validRange(this.tag)) {
|
||||
// We might have a commit. Check that this is a valid commit SHA
|
||||
return this.validCommit(this.tag, function (isValid) {
|
||||
if (!isValid) {
|
||||
return this.emit('error', new Error('Tag ' + this.tag + ' is not a valid semver range/version or a valid commit hash'));
|
||||
}
|
||||
doCheckout();
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
this.once('versions', function (versions) {
|
||||
if (!versions.length) {
|
||||
this.emit('checkout');
|
||||
this.loadJSON();
|
||||
}
|
||||
|
||||
// If tag is specified, try to satisfy it
|
||||
if (this.tag) {
|
||||
versions = versions.filter(function (version) {
|
||||
return semver.satisfies(version, this.tag);
|
||||
}.bind(this));
|
||||
|
||||
if (!versions.length) {
|
||||
var error = new Error('Could not find tag satisfying: ' + this.name + '#' + this.tag);
|
||||
error.details = 'The tag ' + this.tag + ' could not be found within the repository';
|
||||
return this.emit('error', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Use latest version
|
||||
this.tag = versions[0];
|
||||
if (!semver.valid(this.tag)) this.commit = this.tag; // If the version is not valid, then its a commit
|
||||
|
||||
if (this.tag) {
|
||||
doCheckout();
|
||||
}
|
||||
}).versions();
|
||||
};
|
||||
|
||||
Package.prototype.validCommit = function (hash, callback) {
|
||||
var emitter = new events.EventEmitter();
|
||||
var cp = git(['branch', '-q', '--contains', hash], { cwd: this.gitPath }, emitter);
|
||||
cp.on('close', function (code) {
|
||||
if (code) callback(false);
|
||||
callback(true);
|
||||
});
|
||||
emitter.on('error', function () {
|
||||
callback(false);
|
||||
});
|
||||
};
|
||||
|
||||
Package.prototype.describeTag = function () {
|
||||
var cp = git(['describe', '--always', '--tag'], { cwd: this.gitPath || this.path, ignoreCodes: [128] }, this);
|
||||
var tag = '';
|
||||
|
||||
cp.stdout.setEncoding('utf8');
|
||||
cp.stdout.on('data', function (data) {
|
||||
tag += data;
|
||||
});
|
||||
|
||||
cp.on('close', function (code) {
|
||||
if (code === 128) tag = 'unspecified'; // Not a git repo
|
||||
this.emit('describeTag', tag.replace(/\n$/, ''));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Package.prototype.versions = function () {
|
||||
this.once('fetch', function () {
|
||||
var cp = git(['tag'], { cwd: this.gitPath }, this);
|
||||
|
||||
var versions = '';
|
||||
|
||||
cp.stdout.setEncoding('utf8');
|
||||
cp.stdout.on('data', function (data) {
|
||||
versions += data;
|
||||
});
|
||||
|
||||
cp.on('close', function (code) {
|
||||
if (code) return;
|
||||
versions = versions.split('\n');
|
||||
versions = versions.filter(function (ver) {
|
||||
return semver.valid(ver);
|
||||
});
|
||||
versions = versions.sort(function (a, b) {
|
||||
return semver.gt(a, b) ? -1 : 1;
|
||||
});
|
||||
|
||||
if (versions.length) return this.emit('versions', versions);
|
||||
|
||||
// If there is no versions tagged in the repo
|
||||
// then we grab the hash of the last commit
|
||||
versions = '';
|
||||
cp = git(['log', '-n', 1, '--format=%H'], { cwd: this.gitPath }, this);
|
||||
|
||||
cp.stdout.setEncoding('utf8');
|
||||
cp.stdout.on('data', function (data) {
|
||||
versions += data;
|
||||
});
|
||||
cp.on('close', function (code) {
|
||||
if (code) return;
|
||||
versions = _.compact(versions.split('\n'));
|
||||
this.emit('versions', versions);
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this)).fetch();
|
||||
};
|
||||
|
||||
Package.prototype.fetch = function () {
|
||||
fileExists(this.gitPath, function (exists) {
|
||||
if (!exists) return this.emit('error', new Error('Unable to fetch package ' + this.name + ' (if the cache was deleted, run install again)'));
|
||||
|
||||
var cp = git(['fetch', '--prune'], { cwd: this.gitPath }, this);
|
||||
cp.on('close', function (code) {
|
||||
if (code) return;
|
||||
cp = git(['reset', '--hard', this.gitUrl ? 'origin/HEAD' : 'HEAD'], { cwd: this.gitPath }, this);
|
||||
cp.on('close', function (code) {
|
||||
if (code) return;
|
||||
this.emit('fetch');
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Package.prototype.readEndpoint = function (replace) {
|
||||
if (!this.json.repository) return;
|
||||
|
||||
if (this.json.repository.type === 'git') {
|
||||
if (replace || !this.gitUrl) {
|
||||
this.gitUrl = this.json.repository.url;
|
||||
this.generateResourceId();
|
||||
}
|
||||
return { type: 'git', endpoint: this.gitUrl };
|
||||
}
|
||||
if (this.json.repository.type === 'local-repo') {
|
||||
if (replace || !this.gitPath) {
|
||||
this.gitPath = path.resolve(this.json.repository.path);
|
||||
}
|
||||
return { type: 'local', endpoint: this.path };
|
||||
}
|
||||
if (this.json.repository.type === 'local') {
|
||||
if (replace || !this.originalPath) {
|
||||
this.originalPath = this.path = path.resolve(this.json.repository.path);
|
||||
}
|
||||
return { type: 'local', endpoint: this.originalPath };
|
||||
}
|
||||
if (this.json.repository.type === 'asset') {
|
||||
if (replace || !this.assetUrl) {
|
||||
this.originalAssetUrl = this.assetUrl = this.json.repository.url;
|
||||
this.assetType = path.extname(this.assetUrl);
|
||||
}
|
||||
return { type: 'asset', endpoint: this.originalAssetUrl };
|
||||
}
|
||||
};
|
||||
|
||||
Package.prototype.waitUnlock = function (cacheName) {
|
||||
if (this.cacheName === cacheName) {
|
||||
this.unitWork.removeListener('unlock', this.waitUnlock);
|
||||
this.resolve();
|
||||
}
|
||||
};
|
||||
|
||||
Package.prototype.serialize = function () {
|
||||
return {
|
||||
id: this.id,
|
||||
resourceId: this.resourceId,
|
||||
path: this.path,
|
||||
originalPath: this.originalPath,
|
||||
tag: this.tag,
|
||||
originalTag: this.originalTag,
|
||||
commit: this.commit,
|
||||
assetUrl: this.assetUrl,
|
||||
originalAssetUrl: this.originalAssetUrl,
|
||||
assetType: this.assetType,
|
||||
lookedUp: this.lookedUp,
|
||||
json: this.json,
|
||||
gitUrl: this.gitUrl,
|
||||
gitPath: this.gitPath,
|
||||
dependencies: this.dependencies,
|
||||
localConfig: this.localConfig
|
||||
};
|
||||
};
|
||||
|
||||
Package.prototype.unserialize = function (obj) {
|
||||
for (var key in obj) {
|
||||
this[key] = obj[key];
|
||||
}
|
||||
|
||||
this.version = this.tag;
|
||||
};
|
||||
|
||||
Package.prototype.generateResourceId = function () {
|
||||
this.resourceId = crypto.createHash('md5').update(this.gitUrl).digest('hex');
|
||||
this.gitPath = path.join(config.cache, this.cacheName, this.resourceId);
|
||||
|
||||
// If we are not in the middle of the resolve process and if the cache folder
|
||||
// does not exists, try guessing it again from the new gitUrl
|
||||
if (!this.unitWork.isLocked(this.cacheName) && !fs.existsSync(this.gitPath)) {
|
||||
this.cacheName = this.guessName(this.cacheName);
|
||||
this.gitPath = path.join(config.cache, this.cacheName, this.resourceId);
|
||||
}
|
||||
};
|
||||
|
||||
Package.prototype.resolveShorthand = function (shorthand, path) {
|
||||
shorthand = hogan.compile(shorthand);
|
||||
|
||||
var parts = path.split('/');
|
||||
|
||||
return shorthand.render({
|
||||
organization: parts[0],
|
||||
package: parts[1],
|
||||
endpoint: path
|
||||
});
|
||||
};
|
||||
|
||||
Object.defineProperty(Package.prototype, 'localPath', {
|
||||
get: function () {
|
||||
return path.join(process.cwd(), config.directory, this.name);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Package;
|
||||
@@ -1,158 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Source Api
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var request = require('request');
|
||||
var config = require('./config');
|
||||
|
||||
var endpoint = config.endpoint + '/packages';
|
||||
|
||||
if (config.proxy) {
|
||||
request = request.defaults({ proxy: config.proxy, timeout: 5000 });
|
||||
}
|
||||
|
||||
|
||||
// allow for searchpath endpoints to be used for search and lookup
|
||||
var endpoints = [];
|
||||
endpoints.push(endpoint);
|
||||
if (config.searchpath) {
|
||||
for (var i = 0; i < config.searchpath.length; i += 1) {
|
||||
endpoints.push(config.searchpath[i] + '/packages');
|
||||
}
|
||||
}
|
||||
|
||||
exports.lookup = function (name, callback, targetEndpoints) {
|
||||
if (!targetEndpoints) {
|
||||
targetEndpoints = endpoints;
|
||||
}
|
||||
|
||||
// walk all endpoints to find the first matching component
|
||||
var f = function (i) {
|
||||
var endpoint = targetEndpoints[i];
|
||||
request.get(endpoint + '/' + encodeURIComponent(name), function (err, response, body) {
|
||||
if (err || (response.statusCode !== 200 && response.statusCode !== 404)) {
|
||||
return callback(err || new Error(name + ' failed to look up for endpoint: ' + endpoint));
|
||||
}
|
||||
|
||||
if (response && response.statusCode !== 404) {
|
||||
callback(err, body && JSON.parse(body).url);
|
||||
} else {
|
||||
if (i + 1 < targetEndpoints.length) f(i + 1);
|
||||
else return callback(new Error(name + ' not found'));
|
||||
}
|
||||
});
|
||||
};
|
||||
f(0);
|
||||
};
|
||||
|
||||
exports.register = function (name, url, callback) {
|
||||
var body = {name: name, url: url};
|
||||
|
||||
request.post({url: endpoint, form: body}, function (err, response) {
|
||||
if (err) return callback(err);
|
||||
|
||||
if (response.statusCode === 406) {
|
||||
return callback(new Error('Duplicate package'));
|
||||
}
|
||||
|
||||
if (response.statusCode === 400) {
|
||||
return callback(new Error('Incorrect format'));
|
||||
}
|
||||
|
||||
if (response.statusCode !== 201) {
|
||||
return callback(new Error('Unknown error: ' + response.statusCode));
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
};
|
||||
|
||||
exports.search = function (name, callback, targetEndpoints) {
|
||||
if (!targetEndpoints) {
|
||||
targetEndpoints = endpoints;
|
||||
}
|
||||
|
||||
// walk all endpoints to produced federated search results
|
||||
var f = function (i, map, results) {
|
||||
var endpoint = targetEndpoints[i];
|
||||
|
||||
request.get(endpoint + '/search/' + encodeURIComponent(name), function (err, response, body) {
|
||||
if (err || (response.statusCode !== 200 && response.statusCode !== 404)) {
|
||||
return callback(err || new Error(name + ' failed to look up for endpoint: ' + endpoint));
|
||||
}
|
||||
|
||||
if (response && response.statusCode !== 404) {
|
||||
var array = body && JSON.parse(body);
|
||||
for (var x = 0; x < array.length; x += 1) {
|
||||
var pkgName = array[x].name;
|
||||
if (!map[pkgName]) {
|
||||
map[pkgName] = pkgName;
|
||||
results.push({ name: pkgName, url: array[x].url, endpoint: array[x].endpoint });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i + 1 < targetEndpoints.length) f(i + 1, map, results);
|
||||
else return callback(null, results);
|
||||
});
|
||||
};
|
||||
|
||||
f(0, {}, []);
|
||||
};
|
||||
|
||||
exports.info = function (name, callback) {
|
||||
exports.lookup(name, function (err, url) {
|
||||
if (err) return callback(err);
|
||||
|
||||
var Package = require('./package');
|
||||
var pkg = new Package(name, url);
|
||||
|
||||
pkg.once('error', function (err) {
|
||||
pkg.removeAllListeners();
|
||||
callback(err);
|
||||
});
|
||||
pkg.once('resolve', function () {
|
||||
pkg.once('versions', function (versions) {
|
||||
pkg.removeAllListeners();
|
||||
callback(null, { pkg: pkg, versions: versions });
|
||||
}).versions();
|
||||
}).resolve();
|
||||
});
|
||||
};
|
||||
|
||||
exports.all = function (callback, targetEndpoints) {
|
||||
if (!targetEndpoints) {
|
||||
targetEndpoints = endpoints;
|
||||
}
|
||||
|
||||
// walk all endpoints to produced federated search results
|
||||
var f = function (i, map, results) {
|
||||
var endpoint = targetEndpoints[i];
|
||||
|
||||
request.get(endpoint, function (err, response, body) {
|
||||
if (err || (response.statusCode !== 200 && response.statusCode !== 404)) {
|
||||
return callback(err || new Error('Failed to look up endpoint: ' + endpoint));
|
||||
}
|
||||
|
||||
if (response && response.statusCode !== 404) {
|
||||
var array = body && JSON.parse(body);
|
||||
for (var x = 0; x < array.length; x += 1) {
|
||||
var pkgName = array[x].name;
|
||||
if (!map[pkgName]) {
|
||||
map[pkgName] = pkgName;
|
||||
results.push({ name: pkgName, url: array[x].url, endpoint: array[x].endpoint });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i + 1 < targetEndpoints.length) f(i + 1, map, results);
|
||||
else return callback(null, results);
|
||||
});
|
||||
};
|
||||
|
||||
f(0, {}, []);
|
||||
};
|
||||
@@ -1,64 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Package Object Definition
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
// Events:
|
||||
// - lock: fired when a lock write over a key is acquired
|
||||
// - unlock: fired when an unlock write over a key is acquired
|
||||
// ==========================================
|
||||
|
||||
var events = require('events');
|
||||
|
||||
var UnitWork = function () {
|
||||
this.locks = [];
|
||||
this.data = [];
|
||||
|
||||
this.setMaxListeners(100); // Increase the number of listeners because this is a central storage
|
||||
};
|
||||
|
||||
UnitWork.prototype = Object.create(events.EventEmitter.prototype);
|
||||
|
||||
UnitWork.prototype.constructor = UnitWork;
|
||||
|
||||
UnitWork.prototype.lock = function (key, owner) {
|
||||
if (this.locks[key]) throw new Error('A write lock for "' + key + '" was already acquired.');
|
||||
if (!owner) throw new Error('A lock requires an owner.');
|
||||
this.locks[key] = owner;
|
||||
|
||||
return this.emit('lock', key);
|
||||
};
|
||||
|
||||
UnitWork.prototype.unlock = function (key, owner) {
|
||||
if (!owner) throw new Error('A write lock requires an owner.');
|
||||
if (this.locks[key]) {
|
||||
if (this.locks[key] !== owner) throw new Error('Lock owner for "' + key + '" mismatch.');
|
||||
delete this.locks[key];
|
||||
this.emit('unlock', key);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
UnitWork.prototype.isLocked = function (key) {
|
||||
return !!this.locks[key];
|
||||
};
|
||||
|
||||
UnitWork.prototype.store = function (key, data, owner) {
|
||||
if (this.locks[key] && owner !== this.locks[key]) throw new Error('A write lock for "' + key + '" is acquired therefore only its owner can write to it.');
|
||||
this.data[key] = data;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
UnitWork.prototype.retrieve = function (key) {
|
||||
return this.data[key];
|
||||
};
|
||||
|
||||
UnitWork.prototype.keys = function () {
|
||||
return Object.keys(this.data);
|
||||
};
|
||||
|
||||
module.exports = UnitWork;
|
||||
20
lib/index.js
20
lib/index.js
@@ -1,20 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Public API Definition
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var abbrev = require('abbrev');
|
||||
var commands = require('./commands');
|
||||
|
||||
var abbreviations = abbrev(Object.keys(commands));
|
||||
abbreviations.i = 'install';
|
||||
abbreviations.rm = 'uninstall';
|
||||
|
||||
module.exports = {
|
||||
commands: commands,
|
||||
abbreviations: abbreviations,
|
||||
config: require('./core/config')
|
||||
};
|
||||
@@ -1,65 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: completion
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
// This module exposes a simple helper to parse the environment variables in
|
||||
// case of a tab completion command. It parses the provided `argv` (nopt's
|
||||
// remain arguments after `--`) and `env` (should be process.env)
|
||||
//
|
||||
// It is inspired and based off Isaac's work on npm.
|
||||
|
||||
module.exports = function (argv, env) {
|
||||
var opts = {};
|
||||
|
||||
// w is the words number, based on the cursor position
|
||||
opts.w = +env.COMP_CWORD;
|
||||
|
||||
// words is the escaped sequence of words following `bower`
|
||||
opts.words = argv.map(function (word) {
|
||||
return word.charAt(0) === '"' ?
|
||||
word.replace(/^"|"$/g, '') :
|
||||
word.replace(/\\ /g, ' ');
|
||||
});
|
||||
|
||||
// word is a shortcut to the last word in the line
|
||||
opts.word = opts.words[opts.w - 1];
|
||||
|
||||
// line is the sequence of tab completed words.
|
||||
opts.line = env.COMP_LINE;
|
||||
|
||||
// point is the cursor position in the line
|
||||
opts.point = +env.COMP_POINT;
|
||||
|
||||
// length is the whole line's length.
|
||||
opts.length = opts.line.length;
|
||||
|
||||
// partialLine is the line ignoring the sequence of characters after
|
||||
// cursor position, ie. tabbing at: bower install j|qu
|
||||
// gives back a partialLine: bower install j
|
||||
opts.partialLine = opts.line.slice(0, opts.point);
|
||||
|
||||
// partialWords is only returning the words based on cursor position,
|
||||
// ie tabbing at: bower install ze|pto backbone
|
||||
// gives back a partialWords array: ['install', 'zepto']
|
||||
opts.partialWords = opts.words.slice(0, opts.w);
|
||||
|
||||
return opts;
|
||||
};
|
||||
|
||||
module.exports.log = function (arr, opts) {
|
||||
arr = Array.isArray(arr) ? arr : [arr];
|
||||
arr.filter(module.exports.abbrev(opts)).forEach(function (word) {
|
||||
console.log(word);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.abbrev = function abbrev(opts) {
|
||||
var word = opts.word.replace(/\./g, '\\.');
|
||||
return function (it) {
|
||||
return new RegExp('^' + word).test(it);
|
||||
};
|
||||
};
|
||||
@@ -1,32 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: fallback
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
// A function that takes a list of files and returns the first one that exists
|
||||
// If none exists, return null
|
||||
|
||||
var fileExists = require('./file-exists');
|
||||
var path = require('path');
|
||||
|
||||
var fallback = function (baseDir, files, callback) {
|
||||
if (!Array.isArray(files) || files.length === 0) {
|
||||
return callback(null);
|
||||
}
|
||||
|
||||
var file = files.shift();
|
||||
|
||||
fileExists(path.join(baseDir, file), function (exists) {
|
||||
if (!exists) {
|
||||
return fallback(baseDir, files, callback);
|
||||
} else {
|
||||
return callback(file);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = fallback;
|
||||
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: file-exists
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var fs = require('fs');
|
||||
|
||||
// This module exposes a version of fs.exists and fs.existsSync with a correct behaviour
|
||||
// See: https://github.com/joyent/node/pull/2603
|
||||
|
||||
module.exports = function (path, callback) {
|
||||
fs.stat(path, function (error) {
|
||||
callback(!error || error.code !== 'ENOENT');
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.sync = function (path) {
|
||||
try {
|
||||
return !!fs.statSync(path);
|
||||
} catch (e) {
|
||||
return e.code !== 'ENOENT';
|
||||
}
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: git-cmd
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
// Extension of the spawn command, that only executes git commands
|
||||
// If a git command fails with code 128 in the cache, that directory
|
||||
// will be deleted to prevent more issues
|
||||
|
||||
var path = require('path');
|
||||
var spawn = require('./spawn');
|
||||
var rimraf = require('rimraf');
|
||||
var config = require('../core/config');
|
||||
|
||||
module.exports = function (args, options, emitter) {
|
||||
process.env.GIT_TEMPLATE_DIR = config.git_template;
|
||||
var cp = spawn('git', args, options, emitter);
|
||||
var cwd = options ? options.cwd || process.cwd() : process.cwd();
|
||||
var isTmp = path.normalize(cwd).indexOf(config.cache) === 0;
|
||||
|
||||
cp.on('exit', function (code) {
|
||||
if (code === 128 && isTmp) rimraf.sync(cwd);
|
||||
});
|
||||
|
||||
return cp;
|
||||
};
|
||||
@@ -1,27 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Hogan.js renderWithColors extension
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var colors = require('colors');
|
||||
var hogan = require('hogan.js');
|
||||
var _ = require('lodash');
|
||||
var nopt = require('nopt');
|
||||
|
||||
module.exports = hogan.Template.prototype.renderWithColors = function (context, partials, indent) {
|
||||
if (nopt(process.argv).color === false) {
|
||||
colors.mode = 'none';
|
||||
}
|
||||
|
||||
context = _.extend({
|
||||
yellow : function (s) { return s.yellow; },
|
||||
green : function (s) { return s.green; },
|
||||
cyan : function (s) { return s.cyan; },
|
||||
red : function (s) { return s.red; },
|
||||
white : function (s) { return s.white; }
|
||||
}, context);
|
||||
return this.ri([context], partials || {}, indent);
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: is-repo
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var fileExists = require('./file-exists');
|
||||
|
||||
// This module checks if a path is a local repository
|
||||
// If the repository is a link, it will be falsy
|
||||
module.exports = function (dir, callback) {
|
||||
fileExists(path.join(dir, '.git'), function (exists) {
|
||||
if (!exists) return callback(false);
|
||||
fs.lstat(dir, function (err, stat) {
|
||||
if (err) return callback(false);
|
||||
callback(!stat.isSymbolicLink());
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -1,111 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: prune
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var semver = require('semver');
|
||||
var sort = require('stable');
|
||||
|
||||
var versionRequirements = function (dependencyMap) {
|
||||
var result = {};
|
||||
|
||||
for (var name in dependencyMap) {
|
||||
dependencyMap[name].forEach(function (pkg) {
|
||||
result[name] = result[name] || [];
|
||||
if (pkg.originalTag && result[name].indexOf(pkg.originalTag) === -1) {
|
||||
result[name].push(pkg.originalTag);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
var validVersions = function (versions, dependency) {
|
||||
if (!versions || !versions.length) return true;
|
||||
|
||||
// If a non resolved dependency is passed, we simply ignore it
|
||||
if (!dependency.version) return false;
|
||||
|
||||
if (!semver.valid(dependency.version)) {
|
||||
throw new Error('Invalid semver version ' + dependency.version + ' specified in ' + dependency.name);
|
||||
}
|
||||
|
||||
return versions.every(function (version) {
|
||||
return semver.satisfies(dependency.version, version);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = function (dependencyMap, forceLatest) {
|
||||
// generate version requirements
|
||||
// compare dependency map with version requirements
|
||||
// check for conflicts
|
||||
// select best version
|
||||
// return an object with the resolved deps, conflict deps and forcebly resolved ones
|
||||
|
||||
var resolved = {};
|
||||
var conflicted = null;
|
||||
var forceblyResolved = null;
|
||||
var versionMap = versionRequirements(dependencyMap);
|
||||
|
||||
var sortFunc = function (a, b) {
|
||||
if (a.version && b.version) {
|
||||
if (semver.gt(a.version, b.version)) return -1;
|
||||
if (semver.lt(a.version, b.version)) return 1;
|
||||
}
|
||||
if (a.version) {
|
||||
return -1;
|
||||
}
|
||||
if (b.version) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// If the comparison determines that both packages are equal, do not give priority to local ones
|
||||
if (a.path === a.localPath && b.path !== b.localPath) return 1;
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Note that bellow we use a stable sort algorithm
|
||||
// This is because if two packages are equal, the initial order should be respected
|
||||
|
||||
for (var name in dependencyMap) {
|
||||
var matches = dependencyMap[name].filter(validVersions.bind(this, versionMap[name]));
|
||||
if (!matches.length) {
|
||||
// No resolvable dependency
|
||||
// We resolve to the latest package if the forceLatest is true
|
||||
// Otherwise, check if any of those are root packages
|
||||
// If so, we assume that as the resolver (with a warning)
|
||||
// Otherwise there's a conflict
|
||||
if (forceLatest) {
|
||||
forceblyResolved = forceblyResolved || {};
|
||||
forceblyResolved[name] = sort(dependencyMap[name], sortFunc);
|
||||
continue;
|
||||
}
|
||||
|
||||
matches = dependencyMap[name].filter(function (pkg) { return !!pkg.root; });
|
||||
if (matches.length) {
|
||||
forceblyResolved = forceblyResolved || {};
|
||||
forceblyResolved[name] = dependencyMap[name].sort(function (a, b) {
|
||||
if (a.root && b.root) return sortFunc(a, b);
|
||||
if (a.root) return -1;
|
||||
if (b.root) return 1;
|
||||
return sortFunc(a, b);
|
||||
});
|
||||
} else {
|
||||
conflicted = conflicted || {};
|
||||
conflicted[name] = dependencyMap[name];
|
||||
}
|
||||
} else {
|
||||
resolved[name] = [ sort(matches, sortFunc)[0] ];
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
resolved: resolved,
|
||||
conflicted: conflicted,
|
||||
forceblyResolved: forceblyResolved
|
||||
};
|
||||
};
|
||||
@@ -1,25 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: read-json.js - with logging fun
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var readJSON = require('read-package-json');
|
||||
var template = require('./template');
|
||||
|
||||
var read = module.exports = function (path, cb, obj) {
|
||||
readJSON.log = {
|
||||
info: function () {},
|
||||
verbose: function () {},
|
||||
warn: function (what, name, shizzle) {
|
||||
if (read.showWarnings) {
|
||||
template('warn', { name: name.replace(/@/, '#'), shizzle: shizzle })
|
||||
.on('data', obj.emit.bind(obj, 'data'));
|
||||
}
|
||||
}
|
||||
};
|
||||
readJSON.cache.reset();
|
||||
readJSON(path, cb);
|
||||
};
|
||||
100
lib/util/save.js
100
lib/util/save.js
@@ -1,100 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: save
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var semver = require('semver');
|
||||
|
||||
var _ = require('lodash');
|
||||
|
||||
var config = require('../core/config');
|
||||
|
||||
function save(manager, paths, dev, cb) {
|
||||
// If there is specific paths to save, redirect to the appropriate function
|
||||
if (paths && paths.length) return savePkgs.apply(savePkgs, arguments);
|
||||
|
||||
manager.on('loadJSON', function (newLine) {
|
||||
manager.json.dependencies = manager.json.dependencies || {};
|
||||
manager.json.devDependencies = manager.json.devDependencies || {};
|
||||
|
||||
// Only include the root packages
|
||||
for (var name in manager.dependencies) {
|
||||
var curr = manager.dependencies[name][0];
|
||||
if (curr.root) {
|
||||
addDependency(manager.json, curr, !!manager.json.devDependencies[name]);
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup dependencies from the json if empty
|
||||
if (!Object.keys(manager.json.dependencies).length) {
|
||||
delete manager.json.dependencies;
|
||||
}
|
||||
|
||||
// Cleanup dependencies if empty
|
||||
if (!Object.keys(manager.json.devDependencies).length) {
|
||||
delete manager.json.devDependencies;
|
||||
}
|
||||
|
||||
// Finally save the modified json
|
||||
var contents = JSON.stringify(manager.json, null, 2) + (newLine ? '\n' : '');
|
||||
fs.writeFile(path.join(manager.cwd, config.json), contents, cb);
|
||||
}).loadJSON();
|
||||
}
|
||||
|
||||
function savePkgs(manager, paths, dev, cb) {
|
||||
manager.on('loadJSON', function (newLine) {
|
||||
// Find the package names that match the paths
|
||||
var names = _.compact(paths.map(function (endpoint) {
|
||||
endpoint = endpoint.split('#')[0];
|
||||
|
||||
return _.find(Object.keys(manager.dependencies), function (key) {
|
||||
var dep = manager.dependencies[key][0];
|
||||
|
||||
if (dep.name === endpoint) return true;
|
||||
if (dep.cacheName === endpoint) return true;
|
||||
if (dep.shorthand === endpoint) return true;
|
||||
|
||||
var fetchedEndpoint = dep.readEndpoint();
|
||||
return fetchedEndpoint && fetchedEndpoint.endpoint === endpoint;
|
||||
});
|
||||
}));
|
||||
|
||||
var key = dev ? 'devDependencies' : 'dependencies';
|
||||
manager.json[key] = manager.json[key] || {};
|
||||
|
||||
// Save each of them
|
||||
// Only include the root packages
|
||||
names.forEach(function (name) {
|
||||
addDependency(manager.json, manager.dependencies[name][0], dev);
|
||||
});
|
||||
|
||||
// Finally save the modified json
|
||||
var contents = JSON.stringify(manager.json, null, 2) + (newLine ? '\n' : '');
|
||||
fs.writeFile(path.join(manager.cwd, config.json), contents, cb);
|
||||
}).loadJSON();
|
||||
}
|
||||
|
||||
function addDependency(json, pkg, dev) {
|
||||
var path;
|
||||
var tag;
|
||||
var key = dev ? 'devDependencies' : 'dependencies';
|
||||
|
||||
if (pkg.lookedUp) {
|
||||
tag = pkg.originalTag || '~' + pkg.version;
|
||||
} else {
|
||||
path = (pkg.shorthand || pkg.gitUrl || pkg.originalAssetUrl || pkg.originalPath || '');
|
||||
tag = pkg.originalTag || '~' + pkg.version;
|
||||
}
|
||||
|
||||
// If the tag is not valid (e.g.: a commit), null it
|
||||
if (!semver.valid(tag) && !semver.validRange(tag)) tag = null;
|
||||
|
||||
json[key][pkg.name] = path ? path + (tag ? '#' + tag : '') : tag || 'latest';
|
||||
}
|
||||
|
||||
module.exports = save;
|
||||
@@ -1,36 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: spawn
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var spawn = require('child_process').spawn;
|
||||
|
||||
// This module is similar to child-process spawn
|
||||
// but automatically handles errors
|
||||
// When an error occurs, it emits the error event containing the details of the error
|
||||
// It also removes all the listeners of the command
|
||||
|
||||
module.exports = function (command, args, options, emitter) {
|
||||
var cp = spawn(command, args, options);
|
||||
var stderr = '';
|
||||
|
||||
cp.stderr.on('data', function (data) {
|
||||
stderr += data;
|
||||
});
|
||||
|
||||
cp.on('exit', function (code) {
|
||||
if (code && (!options || !options.ignoreCodes || options.ignoreCodes.indexOf(code) === -1)) {
|
||||
cp.removeAllListeners();
|
||||
var err = new Error('status code of ' + command + ': ' + code);
|
||||
err.details = stderr;
|
||||
err.command = command;
|
||||
err.code = code;
|
||||
emitter.emit('error', err);
|
||||
}
|
||||
});
|
||||
|
||||
return cp;
|
||||
};
|
||||
@@ -1,41 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Hogan Renderer w/ template cache
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var events = require('events');
|
||||
var hogan = require('hogan.js');
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
|
||||
require('../util/hogan-colors');
|
||||
|
||||
var templates = {};
|
||||
|
||||
module.exports = function (name, context, sync) {
|
||||
var emitter = new events.EventEmitter;
|
||||
|
||||
var templateName = name + '.mustache';
|
||||
var templatePath = path.join(__dirname, '../../templates/', templateName);
|
||||
|
||||
if (sync) {
|
||||
if (!templates[templatePath]) templates[templatePath] = fs.readFileSync(templatePath, 'utf-8');
|
||||
return hogan.compile(templates[templatePath]).renderWithColors(context);
|
||||
} else if (templates[templatePath]) {
|
||||
process.nextTick(function () {
|
||||
emitter.emit('data', hogan.compile(templates[templatePath]).renderWithColors(context));
|
||||
});
|
||||
} else {
|
||||
fs.readFile(templatePath, 'utf-8', function (err, file) {
|
||||
if (err) return emitter.emit('error', err);
|
||||
|
||||
templates[templatePath] = file;
|
||||
emitter.emit('data', hogan.compile(file).renderWithColors(context));
|
||||
});
|
||||
}
|
||||
|
||||
return emitter;
|
||||
};
|
||||
58
package.json
58
package.json
@@ -1,56 +1,10 @@
|
||||
{
|
||||
"name": "bower",
|
||||
"description": "The browser package manager.",
|
||||
"version": "0.10.0",
|
||||
"author": "Twitter",
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT",
|
||||
"url": "https://github.com/bower/bower/blob/master/LICENSE"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bower/bower"
|
||||
},
|
||||
"main": "lib",
|
||||
"homepage": "http://bower.io/",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"abbrev": "~1.0.4",
|
||||
"archy": "~0.0.2",
|
||||
"async": "~0.2.5",
|
||||
"colors": "~0.6.0-1",
|
||||
"fstream": "~0.1.19",
|
||||
"glob": "~3.1.14",
|
||||
"hogan.js": "~2.0.0",
|
||||
"lodash": "~1.0.1",
|
||||
"mkdirp": "~0.3.4",
|
||||
"nopt": "~2.0.0",
|
||||
"promptly": "~0.1.0",
|
||||
"rc": "~0.3.0",
|
||||
"read-package-json": "~0.1.8",
|
||||
"request": "~2.11.4",
|
||||
"rimraf": "~2.0.3",
|
||||
"semver": "~2.0.7",
|
||||
"stable": "~0.1.2",
|
||||
"tar": "~0.1.13",
|
||||
"tmp": "~0.0.20",
|
||||
"unzip": "0.1.7",
|
||||
"update-notifier": "~0.1.3",
|
||||
"which": "~1.0.5"
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"lerna": "2.0.0-beta.23"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "mocha --reporter spec --timeout 40000"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "~1.8.1",
|
||||
"nock": "~0.17.3"
|
||||
},
|
||||
"bin": {
|
||||
"bower": "bin/bower"
|
||||
},
|
||||
"preferGlobal": true
|
||||
"postinstall": "lerna bootstrap",
|
||||
"test": "lerna run test"
|
||||
}
|
||||
}
|
||||
|
||||
12
packages/bower-config/.editorconfig
Normal file
12
packages/bower-config/.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
7
packages/bower-config/.gitignore
vendored
Normal file
7
packages/bower-config/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
node_modules
|
||||
npm-debug.log
|
||||
|
||||
test/assets/github-test-package
|
||||
test/assets/github-test-package-copy
|
||||
test/assets/temp
|
||||
test/reports
|
||||
@@ -9,7 +9,7 @@
|
||||
"beforeEach"
|
||||
],
|
||||
|
||||
"indent": 2,
|
||||
"indent": 4,
|
||||
"node": true,
|
||||
"devel": true,
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"noarg": true,
|
||||
"noempty": false,
|
||||
"nonew": true,
|
||||
"plusplus": true,
|
||||
"plusplus": false,
|
||||
"regexp": false,
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
@@ -32,7 +32,7 @@
|
||||
"trailing": true,
|
||||
|
||||
"asi": false,
|
||||
"boss": false,
|
||||
"boss": true,
|
||||
"debug": false,
|
||||
"eqnull": true,
|
||||
"es5": false,
|
||||
@@ -57,6 +57,5 @@
|
||||
"validthis": false,
|
||||
|
||||
"nomen": false,
|
||||
"onevar": false,
|
||||
"white": true
|
||||
}
|
||||
9
packages/bower-config/.travis.yml
Normal file
9
packages/bower-config/.travis.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
sudo: false
|
||||
language: node_js
|
||||
node_js:
|
||||
- '5'
|
||||
- '4'
|
||||
- '0.12'
|
||||
- '0.10'
|
||||
script:
|
||||
- grunt travis
|
||||
103
packages/bower-config/CHANGELOG.md
Normal file
103
packages/bower-config/CHANGELOG.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# Changelog
|
||||
|
||||
## 1.4.0
|
||||
|
||||
- Change default shorthand resolver from git:// to https://
|
||||
|
||||
## 1.3.1
|
||||
|
||||
- Ignore hook scripts for environment variable expansion
|
||||
|
||||
## 1.3.0 - 2015-12-07
|
||||
|
||||
- Allow the use of environment variables in .bowerrc. Fixes [#41](https://github.com/bower/config/issues/41)
|
||||
- Loads the .bowerrc file from the cwd specified on the command line. Fixes [bower/bower#1993](https://github.com/bower/bower/issues/1993)
|
||||
- Allwow for array notation in ENV variables [#44](https://github.com/bower/config/issues/44)
|
||||
|
||||
## 1.2.3 - 2015-11-27
|
||||
|
||||
- Restores env variables if they are undefined at the beginning
|
||||
- Handles default setting for config.ca. Together with [bower/bower PR #1972](https://github.com/bower/bower/pull/1972), fixes downloading with `strict-ssl` using custom CA
|
||||
- Displays an error message if .bowerrc is a directory instead of file. Fixes [bower/bower#2022](https://github.com/bower/bower/issues/2022)
|
||||
|
||||
## 1.2.2 - 2015-10-16
|
||||
- Fixes registry configurartion expanding [bower/bower#1950](https://github.com/bower/bower/issues/1950)
|
||||
|
||||
## 1.2.1 - 2015-10-15
|
||||
- Fixes case insenstivity HTTP_PROXY setting issue on Windows
|
||||
|
||||
## 1.2.0 - 2015-09-28
|
||||
- Prevent defaulting cwd to process.cwd()
|
||||
|
||||
## 1.1.2 - 2015-09-27
|
||||
- Performs only camel case normalisation before merging
|
||||
|
||||
## 1.1.1 - 2015-09-27
|
||||
- Fix: Merge extra options after camel-case normalisation, instead of before it
|
||||
|
||||
## 1.1.0 - 2015-09-27
|
||||
- Allow for overwriting options with .load(overwrites) / .read(cwd, overwrites)
|
||||
|
||||
## 1.0.1 - 2015-09-27
|
||||
- Update dependencies and relax "mout" version range
|
||||
- Most significant changes:
|
||||
- graceful-fs updated from 2.x version to 4.x
|
||||
- osenv updated to from 0.0.x to 0.1.x, [tmp location changed](https://github.com/npm/osenv/commit/d6eddbc026538b09026b1dbd60fbc081a8c67e03)
|
||||
|
||||
## 1.0.0 - 2015-09-27
|
||||
- Support for no-proxy configuration variable
|
||||
- Overwrite HTTP_PROXY, HTTPS_PROXY, and NO_PROXY env variables in load method
|
||||
- Normalise paths to certificates with contents of them, [#28](https://github.com/bower/config/pull/28)
|
||||
|
||||
## 0.6.1 - 2015-04-1
|
||||
- Fixes merging .bowerrc files upward directory tree. [#25](https://github.com/bower/config/issues/25)
|
||||
|
||||
## 0.6.0 - 2015-03-30
|
||||
- Merge .bowerrc files upward directory tree (fixes [bower/bower#1689](https://github.com/bower/bower/issues/1689)) [#24](https://github.com/bower/config/pull/24)
|
||||
- Allow NPM config variables (resolves [bower/bower#1711](https://github.com/bower/bower/issues/1711)) [#23](https://github.com/bower/config/pull/23)
|
||||
|
||||
## 0.5.2 - 2014-06-09
|
||||
- Fixes downloading of bower modules with ignores when .bowerrc is overridden with a relative tmp path. [#17](https://github.com/bower/config/issues/17) [bower/bower#1299](https://github.com/bower/bower/issues/1299)
|
||||
|
||||
## 0.5.1 - 2014-05-21
|
||||
- [perf] Uses the same mout version as bower
|
||||
- [perf] Uses only relevant parts of mout. Related [bower/bower#1134](https://github.com/bower/bower/pull/1134)
|
||||
|
||||
## 0.5.0 - 2013-08-30
|
||||
- Adds a DEFAULT_REGISTRY key to the Config class that exposes the bower registry UR. [#6](https://github.com/bower/config/issues/6)
|
||||
|
||||
## 0.4.5 - 2013-08-28
|
||||
- Fixes crashing when home is not set
|
||||
|
||||
## 0.4.4 - 2013-08-21
|
||||
- Supports nested environment variables [#8](https://github.com/bower/config/issues/8)
|
||||
|
||||
## 0.4.3 - 2013-08-19
|
||||
- Improvement in argv.config parsing
|
||||
|
||||
## 0.4.2 - 2013-08-18
|
||||
- Sets interative to auto
|
||||
|
||||
## 0.4.1 - 2013-08-18
|
||||
- Generates a fake user instead of using 'unknown'
|
||||
|
||||
## 0.4.0 - 2013-08-16
|
||||
- Suffixes temp folder with the user and 'bower'
|
||||
|
||||
## 0.3.5 - 2013-08-14
|
||||
- Casts buffer to string
|
||||
|
||||
## 0.3.4 - 2013-08-11
|
||||
- Empty .bowerrc files no longer throw an error.
|
||||
|
||||
## 0.3.3 - 2013-08-11
|
||||
- Changes git folder to empty (was not being used anyway)
|
||||
|
||||
## 0.3.2 - 2013-08-07
|
||||
- Uses a known user agent by default when a proxy.
|
||||
|
||||
## 0.3.1 - 2013-08-06
|
||||
- Fixes Typo
|
||||
|
||||
## 0.3.0 - 2013-08-06
|
||||
- Appends the username when using the temporary folder.
|
||||
47
packages/bower-config/Gruntfile.js
Normal file
47
packages/bower-config/Gruntfile.js
Normal file
@@ -0,0 +1,47 @@
|
||||
'use strict';
|
||||
module.exports = function (grunt) {
|
||||
require('load-grunt-tasks')(grunt);
|
||||
|
||||
grunt.initConfig({
|
||||
simplemocha: {
|
||||
options: {
|
||||
reporter: 'spec',
|
||||
timeout: '10000'
|
||||
},
|
||||
full: {
|
||||
src: ['test/test.js']
|
||||
},
|
||||
short: {
|
||||
options: {
|
||||
reporter: 'dot'
|
||||
},
|
||||
src: ['test/test.js']
|
||||
}
|
||||
},
|
||||
exec: {
|
||||
cover: {
|
||||
command: 'STRICT_REQUIRE=1 node node_modules/istanbul/lib/cli.js cover --dir ./test/reports node_modules/mocha/bin/_mocha -- --timeout 30000 -R dot test/test.js'
|
||||
},
|
||||
coveralls: {
|
||||
command: 'node node_modules/.bin/coveralls < test/reports/lcov.info'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
files: [
|
||||
'Gruntfile.js',
|
||||
'bin/*',
|
||||
'lib/**/*.js',
|
||||
'test/**/*.js',
|
||||
'!test/assets/**/*',
|
||||
'!test/reports/**/*',
|
||||
'!test/tmp/**/*'
|
||||
],
|
||||
tasks: ['simplemocha:short']
|
||||
}
|
||||
});
|
||||
|
||||
grunt.registerTask('test', ['simplemocha:full']);
|
||||
grunt.registerTask('cover', 'exec:cover');
|
||||
grunt.registerTask('travis', ['exec:cover', 'exec:coveralls']);
|
||||
grunt.registerTask('default', 'test');
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2012–2013 Twitter, Inc. and other contributors
|
||||
Copyright (c) 2012 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
|
||||
76
packages/bower-config/README.md
Normal file
76
packages/bower-config/README.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# bower-config [](http://travis-ci.org/bower/config)[](https://coveralls.io/github/bower/config?branch=master)
|
||||
|
||||
> The Bower config (`.bowerrc`) reader and writer.
|
||||
|
||||
[Bower](http://bower.io/) can be configured using JSON in a `.bowerrc` file. For example:
|
||||
|
||||
{
|
||||
"directory": "app/components/",
|
||||
"timeout": 120000,
|
||||
"registry": {
|
||||
"search": [
|
||||
"http://localhost:8000",
|
||||
"https://bower.herokuapp.com"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
View the complete [.bowerrc specification](http://bower.io/docs/config/#bowerrc-specification) on the website for more details. Both the `bower.json` and `.bowerrc` specifications are maintained at [github.com/bower/spec](https://github.com/bower/spec).
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
$ npm install --save bower-config
|
||||
```
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
#### .load(overwrites)
|
||||
|
||||
Loads the bower configuration from the configuration files.
|
||||
|
||||
Configuration is overwritten (after camelcase normalisation) with `overwrites` argument.
|
||||
|
||||
This method overwrites following environment variables:
|
||||
|
||||
- `HTTP_PROXY` with `proxy` configuration variable
|
||||
- `HTTPS_PROXY` with `https-proxy` configuration variable
|
||||
- `NO_PROXY` with `no-proxy` configuration variable
|
||||
|
||||
It also clears `http_proxy`, `https_proxy`, and `no_proxy` environment variables.
|
||||
|
||||
To restore those variables you can use `restore` method.
|
||||
|
||||
#### restore()
|
||||
|
||||
Restores environment variables overwritten by `.load` method.
|
||||
|
||||
#### .toObject()
|
||||
|
||||
Returns a deep copy of the underlying configuration object.
|
||||
The returned configuration is normalised.
|
||||
The object keys will be camelCase.
|
||||
|
||||
|
||||
#### #create(cwd)
|
||||
|
||||
Obtains a instance where `cwd` is the current working directory (defaults to `process.cwd`);
|
||||
|
||||
```js
|
||||
var config = require('bower-config').create();
|
||||
// You can also specify a working directory
|
||||
var config2 = require('bower-config').create('./some/path');
|
||||
```
|
||||
|
||||
#### #read(cwd, overrides)
|
||||
|
||||
Alias for:
|
||||
|
||||
```js
|
||||
var configObject = (new Config(cwd)).load(overrides).toJson();
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Released under the [MIT License](http://www.opensource.org/licenses/mit-license.php).
|
||||
109
packages/bower-config/lib/Config.js
Normal file
109
packages/bower-config/lib/Config.js
Normal file
@@ -0,0 +1,109 @@
|
||||
var lang = require('mout/lang');
|
||||
var object = require('mout/object');
|
||||
var rc = require('./util/rc');
|
||||
var expand = require('./util/expand');
|
||||
var EnvProxy = require('./util/proxy');
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
|
||||
function Config(cwd) {
|
||||
this._cwd = cwd;
|
||||
this._proxy = new EnvProxy();
|
||||
this._config = {};
|
||||
}
|
||||
|
||||
Config.prototype.load = function (overwrites) {
|
||||
this._config = rc('bower', this._cwd);
|
||||
|
||||
this._config = object.merge(
|
||||
expand(this._config || {}),
|
||||
expand(overwrites || {})
|
||||
);
|
||||
|
||||
this._config = normalise(this._config);
|
||||
|
||||
this._proxy.set(this._config);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Config.prototype.restore = function () {
|
||||
this._proxy.restore();
|
||||
};
|
||||
|
||||
function readCertFile(path) {
|
||||
path = path || '';
|
||||
|
||||
var sep = '-----END CERTIFICATE-----';
|
||||
|
||||
var certificates;
|
||||
|
||||
if (path.indexOf(sep) === -1) {
|
||||
certificates = fs.readFileSync(path, { encoding: 'utf8' });
|
||||
} else {
|
||||
certificates = path;
|
||||
}
|
||||
|
||||
return certificates.
|
||||
split(sep).
|
||||
filter(function(s) { return !s.match(/^\s*$/); }).
|
||||
map(function(s) { return s + sep; });
|
||||
}
|
||||
|
||||
function loadCAs(caConfig) {
|
||||
// If a ca file path has been specified, expand that here to the file's
|
||||
// contents. As a user can specify these individually, we must load them
|
||||
// one by one.
|
||||
for (var p in caConfig) {
|
||||
if (caConfig.hasOwnProperty(p)) {
|
||||
var prop = caConfig[p];
|
||||
if (Array.isArray(prop)) {
|
||||
caConfig[p] = prop.map(function(s) {
|
||||
return readCertFile(s);
|
||||
});
|
||||
} else if (prop) {
|
||||
caConfig[p] = readCertFile(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Config.prototype.toObject = function () {
|
||||
return lang.deepClone(this._config);
|
||||
};
|
||||
|
||||
Config.create = function (cwd) {
|
||||
return new Config(cwd);
|
||||
};
|
||||
|
||||
Config.read = function (cwd, overrides) {
|
||||
var config = Config.create(cwd);
|
||||
return config.load(overrides).toObject();
|
||||
};
|
||||
|
||||
function normalise(config) {
|
||||
config = expand(config);
|
||||
|
||||
// Some backwards compatible things..
|
||||
if (config.shorthandResolver) {
|
||||
config.shorthandResolver = config.shorthandResolver
|
||||
.replace(/\{\{\{/g, '{{')
|
||||
.replace(/\}\}\}/g, '}}');
|
||||
}
|
||||
|
||||
// Ensure that every registry endpoint does not end with /
|
||||
config.registry.search = config.registry.search.map(function (url) {
|
||||
return url.replace(/\/+$/, '');
|
||||
});
|
||||
config.registry.register = config.registry.register.replace(/\/+$/, '');
|
||||
config.registry.publish = config.registry.publish.replace(/\/+$/, '');
|
||||
config.tmp = path.resolve(config.tmp);
|
||||
|
||||
loadCAs(config.ca);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
Config.DEFAULT_REGISTRY = require('./util/defaults').registry;
|
||||
|
||||
module.exports = Config;
|
||||
45
packages/bower-config/lib/util/defaults.js
Normal file
45
packages/bower-config/lib/util/defaults.js
Normal file
@@ -0,0 +1,45 @@
|
||||
var path = require('path');
|
||||
var paths = require('./paths');
|
||||
|
||||
// Guess proxy defined in the env
|
||||
var proxy = process.env.HTTP_PROXY
|
||||
|| process.env.http_proxy
|
||||
|| null;
|
||||
|
||||
var httpsProxy = process.env.HTTPS_PROXY
|
||||
|| process.env.https_proxy
|
||||
|| proxy;
|
||||
|
||||
var noProxy = process.env.NO_PROXY
|
||||
|| process.env.no_proxy;
|
||||
|
||||
// Use a well known user agent (in this case, curl) when using a proxy,
|
||||
// to avoid potential filtering on many corporate proxies with blank or unknown agents
|
||||
var userAgent = !proxy && !httpsProxy
|
||||
? 'node/' + process.version + ' ' + process.platform + ' ' + process.arch
|
||||
: 'curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5';
|
||||
|
||||
var defaults = {
|
||||
'directory': 'bower_components',
|
||||
'registry': 'https://bower.herokuapp.com',
|
||||
'shorthand-resolver': 'https://github.com/{{owner}}/{{package}}.git',
|
||||
'tmp': paths.tmp,
|
||||
'proxy': proxy,
|
||||
'https-proxy': httpsProxy,
|
||||
'no-proxy': noProxy,
|
||||
'timeout': 30000,
|
||||
'ca': { search: [] },
|
||||
'strict-ssl': true,
|
||||
'user-agent': userAgent,
|
||||
'color': true,
|
||||
'interactive': null,
|
||||
'storage': {
|
||||
packages: path.join(paths.cache, 'packages'),
|
||||
links: path.join(paths.data, 'links'),
|
||||
completion: path.join(paths.data, 'completion'),
|
||||
registry: path.join(paths.cache, 'registry'),
|
||||
empty: path.join(paths.data, 'empty') // Empty dir, used in GIT_TEMPLATE_DIR among others
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = defaults;
|
||||
126
packages/bower-config/lib/util/expand.js
Normal file
126
packages/bower-config/lib/util/expand.js
Normal file
@@ -0,0 +1,126 @@
|
||||
var object = require('mout/object');
|
||||
var lang = require('mout/lang');
|
||||
var string = require('mout/string');
|
||||
|
||||
function camelCase(config) {
|
||||
var camelCased = {};
|
||||
|
||||
// Camel case
|
||||
object.forOwn(config, function (value, key) {
|
||||
// Ignore null values
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
key = string.camelCase(key.replace(/_/g, '-'));
|
||||
camelCased[key] = lang.isPlainObject(value) ? camelCase(value) : value;
|
||||
});
|
||||
|
||||
return camelCased;
|
||||
}
|
||||
|
||||
// Function to replace ${VAR} - style variables
|
||||
// with values set in the environment
|
||||
// This function expects to be passed a string
|
||||
function doEnvReplaceStr (f) {
|
||||
|
||||
// Un-tildify
|
||||
var untildify = require('untildify');
|
||||
f = untildify(f);
|
||||
|
||||
// replace any ${ENV} values with the appropriate environ.
|
||||
var envExpr = /(\\*)\$\{([^}]+)\}/g;
|
||||
return f.replace(envExpr, function (orig, esc, name) {
|
||||
esc = esc.length && esc.length % 2;
|
||||
if (esc) return orig;
|
||||
if (undefined === process.env[name]) {
|
||||
throw new Error('Environment variable used in .bowerrc is not defined: ' + orig);
|
||||
}
|
||||
|
||||
return process.env[name];
|
||||
});
|
||||
}
|
||||
|
||||
function envReplace(config) {
|
||||
var envReplaced = {};
|
||||
|
||||
object.forOwn(config, function (value, key) {
|
||||
|
||||
// Ignore null values
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore 'scripts'
|
||||
// These hooks run within the shell
|
||||
// environment variable expansion is not required
|
||||
if ( key === 'scripts' && lang.isPlainObject(value) ){
|
||||
envReplaced[key] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform variable replacements based on var type
|
||||
if ( lang.isPlainObject(value) ) {
|
||||
envReplaced[key] = envReplace(value);
|
||||
}
|
||||
else if ( lang.isString(value) ) {
|
||||
envReplaced[key] = doEnvReplaceStr(value);
|
||||
}
|
||||
else {
|
||||
envReplaced[key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
return envReplaced;
|
||||
}
|
||||
|
||||
function expand(config) {
|
||||
config = camelCase(config);
|
||||
config = envReplace(config);
|
||||
|
||||
if (typeof config.registry === 'string') {
|
||||
config.registry = {
|
||||
default: config.registry,
|
||||
search: [config.registry],
|
||||
register: config.registry,
|
||||
publish: config.registry
|
||||
};
|
||||
} else if (typeof config.registry === 'object') {
|
||||
config.registry.default = config.registry.default || 'https://bower.herokuapp.com';
|
||||
|
||||
config.registry = {
|
||||
default: config.registry.default,
|
||||
search: config.registry.search || config.registry.default,
|
||||
register: config.registry.register || config.registry.default,
|
||||
publish: config.registry.publish || config.registry.default
|
||||
};
|
||||
|
||||
if (config.registry.search && !Array.isArray(config.registry.search)) {
|
||||
config.registry.search = [config.registry.search];
|
||||
}
|
||||
}
|
||||
|
||||
// CA
|
||||
if (typeof config.ca === 'string') {
|
||||
config.ca = {
|
||||
default: config.ca,
|
||||
search: [config.ca],
|
||||
register: config.ca,
|
||||
publish: config.ca
|
||||
};
|
||||
} else if (typeof config.ca === 'object') {
|
||||
if (config.ca.search && !Array.isArray(config.ca.search)) {
|
||||
config.ca.search = [config.ca.search];
|
||||
}
|
||||
|
||||
if (config.ca.default) {
|
||||
config.ca.search = config.ca.search || config.ca.default;
|
||||
config.ca.register = config.ca.register || config.ca.default;
|
||||
config.ca.publish = config.ca.publish || config.ca.default;
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
module.exports = expand;
|
||||
44
packages/bower-config/lib/util/paths.js
Normal file
44
packages/bower-config/lib/util/paths.js
Normal file
@@ -0,0 +1,44 @@
|
||||
var os = require('os');
|
||||
var path = require('path');
|
||||
var osenv = require('osenv');
|
||||
var crypto = require('crypto');
|
||||
|
||||
function generateFakeUser() {
|
||||
var uid = process.pid + '-' + Date.now() + '-' + Math.floor(Math.random() * 1000000);
|
||||
return crypto.createHash('md5').update(uid).digest('hex');
|
||||
}
|
||||
|
||||
// Assume XDG defaults
|
||||
// See: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
var paths = {
|
||||
config: process.env.XDG_CONFIG_HOME,
|
||||
data: process.env.XDG_DATA_HOME,
|
||||
cache: process.env.XDG_CACHE_HOME
|
||||
};
|
||||
|
||||
// Guess some needed properties based on the user OS
|
||||
var user = (osenv.user() || generateFakeUser()).replace(/\\/g, '-');
|
||||
var tmp = path.join(os.tmpdir ? os.tmpdir() : os.tmpDir(), user);
|
||||
var home = osenv.home();
|
||||
var base;
|
||||
|
||||
// Fallbacks for windows
|
||||
if (process.platform === 'win32') {
|
||||
base = path.resolve(process.env.LOCALAPPDATA || home || tmp);
|
||||
base = path.join(base, 'bower');
|
||||
|
||||
paths.config = paths.config || path.join(base, 'config');
|
||||
paths.data = paths.data || path.join(base, 'data');
|
||||
paths.cache = paths.cache || path.join(base, 'cache');
|
||||
// Fallbacks for other operating systems
|
||||
} else {
|
||||
base = path.resolve(home || tmp);
|
||||
|
||||
paths.config = paths.config || path.join(base, '.config/bower');
|
||||
paths.data = paths.data || path.join(base, '.local/share/bower');
|
||||
paths.cache = paths.cache || path.join(base, '.cache/bower');
|
||||
}
|
||||
|
||||
paths.tmp = path.resolve(path.join(tmp, 'bower'));
|
||||
|
||||
module.exports = paths;
|
||||
79
packages/bower-config/lib/util/proxy.js
Normal file
79
packages/bower-config/lib/util/proxy.js
Normal file
@@ -0,0 +1,79 @@
|
||||
// EnvProxy uses the proxy vaiables passed to it in set and sets the
|
||||
// process.env uppercase proxy variables to them with the ability
|
||||
// to restore the original values later
|
||||
var EnvProxy = function() {
|
||||
this.restoreFrom = {};
|
||||
};
|
||||
|
||||
EnvProxy.prototype.set = function (config) {
|
||||
this.config = config;
|
||||
|
||||
// Override environment defaults if proxy config options are set
|
||||
// This will make requests.js follow the proxies in config
|
||||
if (Object.prototype.hasOwnProperty.call(config, 'noProxy')) {
|
||||
this.restoreFrom.NO_PROXY = process.env.NO_PROXY;
|
||||
this.restoreFrom.no_proxy = process.env.no_proxy;
|
||||
delete process.env.no_proxy;
|
||||
process.env.NO_PROXY = config.noProxy;
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(config, 'proxy')) {
|
||||
this.restoreFrom.HTTP_PROXY = process.env.HTTP_PROXY;
|
||||
this.restoreFrom.http_proxy = process.env.http_proxy;
|
||||
delete process.env.http_proxy;
|
||||
process.env.HTTP_PROXY = config.proxy;
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(config, 'httpsProxy')) {
|
||||
this.restoreFrom.HTTPS_PROXY = process.env.HTTPS_PROXY;
|
||||
this.restoreFrom.https_proxy = process.env.https_proxy;
|
||||
delete process.env.https_proxy;
|
||||
process.env.HTTPS_PROXY = config.httpsProxy;
|
||||
}
|
||||
};
|
||||
|
||||
EnvProxy.prototype.restore = function () {
|
||||
if (Object.prototype.hasOwnProperty.call(this.config, 'noProxy')) {
|
||||
if (this.restoreFrom.NO_PROXY !== undefined) {
|
||||
process.env.NO_PROXY = this.restoreFrom.NO_PROXY;
|
||||
} else {
|
||||
delete process.env.NO_PROXY;
|
||||
}
|
||||
|
||||
if (this.restoreFrom.no_proxy !== undefined) {
|
||||
process.env.no_proxy = this.restoreFrom.no_proxy;
|
||||
} else {
|
||||
delete process.env.no_proxy;
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.config, 'proxy')) {
|
||||
if (this.restoreFrom.HTTP_PROXY !== undefined) {
|
||||
process.env.HTTP_PROXY = this.restoreFrom.HTTP_PROXY;
|
||||
} else {
|
||||
delete process.env.HTTP_PROXY;
|
||||
}
|
||||
|
||||
if (this.restoreFrom.http_proxy !== undefined) {
|
||||
process.env.http_proxy = this.restoreFrom.http_proxy;
|
||||
} else {
|
||||
delete process.env.http_proxy;
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.config, 'httpsProxy')) {
|
||||
if (this.restoreFrom.HTTPS_PROXY !== undefined) {
|
||||
process.env.HTTPS_PROXY = this.restoreFrom.HTTPS_PROXY;
|
||||
} else {
|
||||
delete process.env.HTTPS_PROXY;
|
||||
}
|
||||
|
||||
if (this.restoreFrom.https_proxy !== undefined) {
|
||||
process.env.https_proxy = this.restoreFrom.https_proxy;
|
||||
} else {
|
||||
delete process.env.https_proxy;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = EnvProxy;
|
||||
158
packages/bower-config/lib/util/rc.js
Normal file
158
packages/bower-config/lib/util/rc.js
Normal file
@@ -0,0 +1,158 @@
|
||||
var path = require('path');
|
||||
var fs = require('graceful-fs');
|
||||
var optimist = require('optimist');
|
||||
var osenv = require('osenv');
|
||||
var object = require('mout/object');
|
||||
var string = require('mout/string');
|
||||
var paths = require('./paths');
|
||||
var defaults = require('./defaults');
|
||||
|
||||
var win = process.platform === 'win32';
|
||||
var home = osenv.home();
|
||||
|
||||
function rc(name, cwd, argv) {
|
||||
var argvConfig;
|
||||
|
||||
argv = argv || optimist.argv;
|
||||
|
||||
// Parse --config.foo=false
|
||||
argvConfig = object.map(argv.config || {}, function (value) {
|
||||
return value === 'false' ? false : value;
|
||||
});
|
||||
|
||||
// If we have specified a cwd then use this as the base for getting config.
|
||||
cwd = argvConfig.cwd ? argvConfig.cwd : cwd;
|
||||
|
||||
if (cwd) {
|
||||
return object.deepMixIn.apply(null, [
|
||||
{},
|
||||
defaults,
|
||||
{ cwd: cwd },
|
||||
win ? {} : json(path.join('/etc', name + 'rc')),
|
||||
!home ? {} : json(path.join(home, '.' + name + 'rc')),
|
||||
json(path.join(paths.config, name + 'rc')),
|
||||
json(find('.' + name + 'rc', cwd)),
|
||||
env('npm_package_config_' + name + '_'),
|
||||
env(name + '_'),
|
||||
argvConfig
|
||||
]);
|
||||
} else {
|
||||
return object.deepMixIn.apply(null, [
|
||||
{},
|
||||
defaults,
|
||||
win ? {} : json(path.join('/etc', name + 'rc')),
|
||||
!home ? {} : json(path.join(home, '.' + name + 'rc')),
|
||||
json(path.join(paths.config, name + 'rc')),
|
||||
env('npm_package_config_' + name + '_'),
|
||||
env(name + '_'),
|
||||
argvConfig
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
function parse(content, file) {
|
||||
var error;
|
||||
|
||||
if (!content.trim().length) {
|
||||
return {};
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(content);
|
||||
} catch (e) {
|
||||
if (file) {
|
||||
error = new Error('Unable to parse ' + file + ': ' + e.message);
|
||||
} else {
|
||||
error = new Error('Unable to parse rc config: ' + e.message);
|
||||
}
|
||||
|
||||
error.details = content;
|
||||
error.code = 'EMALFORMED';
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function json(file) {
|
||||
var content = {};
|
||||
if (!Array.isArray(file)) {
|
||||
try {
|
||||
content = fs.readFileSync(file).toString();
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return parse(content, file);
|
||||
} else {
|
||||
// This is multiple json files
|
||||
file.forEach(function(filename) {
|
||||
if (fs.statSync(filename).isDirectory()) {
|
||||
var error;
|
||||
error = new Error(filename + ' should not be a directory');
|
||||
error.code = 'EFILEISDIR';
|
||||
throw error;
|
||||
}
|
||||
var json = fs.readFileSync(filename).toString();
|
||||
json = parse(json, filename);
|
||||
content = object.merge(content, json);
|
||||
});
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
function env(prefix) {
|
||||
var obj = {};
|
||||
var prefixLength = prefix.length;
|
||||
|
||||
prefix = prefix.toLowerCase();
|
||||
|
||||
object.forOwn(process.env, function (value, key) {
|
||||
key = key.toLowerCase();
|
||||
|
||||
if (string.startsWith(key, prefix)) {
|
||||
var parsedKey = key
|
||||
.substr(prefixLength)
|
||||
.replace(/__/g, '.') // __ is used for nesting
|
||||
.replace(/_/g, '-'); // _ is used as a - separator
|
||||
|
||||
//use a convention patern to accept array from process.env
|
||||
//e.g. export bower_registry__search='["http://abc.com","http://def.com"]'
|
||||
var match = /\[([^\]]*)\]/g.exec(value);
|
||||
var targetValue;
|
||||
if (!match || match.length === 0) {
|
||||
targetValue = value;
|
||||
} else {
|
||||
targetValue = match[1].split(',')
|
||||
.map(function(m) {
|
||||
return m.trim();
|
||||
});
|
||||
}
|
||||
object.set(obj, parsedKey, targetValue);
|
||||
}
|
||||
});
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function find(filename, dir) {
|
||||
var files = [];
|
||||
|
||||
var walk = function (filename, dir) {
|
||||
var file = path.join(dir, filename);
|
||||
var parent = path.dirname(dir);
|
||||
|
||||
if (fs.existsSync(file)) {
|
||||
files.push(file);
|
||||
}
|
||||
|
||||
if (parent !== dir) {
|
||||
walk(filename, parent);
|
||||
}
|
||||
};
|
||||
|
||||
walk(filename, dir);
|
||||
files.reverse();
|
||||
return files;
|
||||
}
|
||||
|
||||
module.exports = rc;
|
||||
45
packages/bower-config/package.json
Normal file
45
packages/bower-config/package.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "bower-config",
|
||||
"version": "1.4.0",
|
||||
"description": "The Bower config reader and writer.",
|
||||
"author": "Twitter",
|
||||
"license": "MIT",
|
||||
"repository": "bower/config",
|
||||
"main": "lib/Config",
|
||||
"homepage": "http://bower.io",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.1.3",
|
||||
"mout": "^1.0.0",
|
||||
"optimist": "^0.6.1",
|
||||
"osenv": "^0.1.3",
|
||||
"untildify": "^2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"coveralls": "^2.11.4",
|
||||
"expect.js": "^0.3.1",
|
||||
"glob": "^4.5.3",
|
||||
"grunt": "^0.4.5",
|
||||
"grunt-cli": "^0.1.13",
|
||||
"grunt-contrib-jshint": "^0.10.0",
|
||||
"grunt-contrib-watch": "^0.6.1",
|
||||
"grunt-coveralls": "^1.0.0",
|
||||
"grunt-exec": "^0.4.6",
|
||||
"grunt-simple-mocha": "^0.4.0",
|
||||
"istanbul": "^0.4.1",
|
||||
"load-grunt-tasks": "^2.0.0",
|
||||
"mkdirp": "^0.5.0",
|
||||
"mocha": "~1.12.0",
|
||||
"node-uuid": "^1.4.3",
|
||||
"q": "^1.2.0",
|
||||
"rimraf": "^2.3.2"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "grunt test"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"ca": "Equifax Secure CA\n=================\n-----BEGIN CERTIFICATE-----\nMIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE\nChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5\nMB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT\nB0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB\nnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR\nfM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW\n8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG\nA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE\nCxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG\nA1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS\nspXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB\nAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961\nzgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB\nBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95\n70+sB3c4\n-----END CERTIFICATE-----\n\nGlobalSign Root CA\n==================\n-----BEGIN CERTIFICATE-----\nMIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx\nGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds\nb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV\nBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD\nVQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa\nDuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc\nTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb\nKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP\nc1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX\ngzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\nHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF\nAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj\nY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG\nj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH\nhm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC\nX4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\n-----END CERTIFICATE-----"
|
||||
}
|
||||
3
packages/bower-config/test/assets/custom-ca/.bowerrc
Normal file
3
packages/bower-config/test/assets/custom-ca/.bowerrc
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"ca": "test/assets/custom-ca/ca-bundle.crt"
|
||||
}
|
||||
40
packages/bower-config/test/assets/custom-ca/ca-bundle.crt
Normal file
40
packages/bower-config/test/assets/custom-ca/ca-bundle.crt
Normal file
@@ -0,0 +1,40 @@
|
||||
Equifax Secure CA
|
||||
=================
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE
|
||||
ChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
|
||||
MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT
|
||||
B0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB
|
||||
nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR
|
||||
fM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW
|
||||
8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG
|
||||
A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE
|
||||
CxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG
|
||||
A1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS
|
||||
spXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB
|
||||
Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961
|
||||
zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB
|
||||
BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95
|
||||
70+sB3c4
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
GlobalSign Root CA
|
||||
==================
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx
|
||||
GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds
|
||||
b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV
|
||||
BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD
|
||||
VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa
|
||||
DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc
|
||||
THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb
|
||||
Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP
|
||||
c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX
|
||||
gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
|
||||
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF
|
||||
AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj
|
||||
Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG
|
||||
j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH
|
||||
hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC
|
||||
X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"scripts" : {
|
||||
"postinstall" : "${_myshellvar}"
|
||||
},
|
||||
"storage" : {
|
||||
"packages" : "${_BOWERRC_MY_PACKAGES}",
|
||||
"registry" : "~/.bower-test/registry"
|
||||
},
|
||||
"tmp" : "${_BOWERRC_MY_TMP}"
|
||||
}
|
||||
5
packages/bower-config/test/assets/env-variables/.bowerrc
Normal file
5
packages/bower-config/test/assets/env-variables/.bowerrc
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"proxy": "http://HTTP_PROXY",
|
||||
"https-proxy": "http://HTTPS_PROXY",
|
||||
"no-proxy": "google.com"
|
||||
}
|
||||
126
packages/bower-config/test/helpers.js
Normal file
126
packages/bower-config/test/helpers.js
Normal file
@@ -0,0 +1,126 @@
|
||||
var Q = require('q');
|
||||
var mkdirp = require('mkdirp');
|
||||
var rimraf = require('rimraf');
|
||||
var uuid = require('node-uuid');
|
||||
var object = require('mout/object');
|
||||
var fs = require('fs');
|
||||
var glob = require('glob');
|
||||
var os = require('os');
|
||||
var path = require('path');
|
||||
|
||||
// For better promise errors
|
||||
Q.longStackSupport = true;
|
||||
|
||||
var tmpLocation = path.join(
|
||||
os.tmpdir ? os.tmpdir() : os.tmpDir(),
|
||||
'bower-config-tests',
|
||||
uuid.v4().slice(0, 8)
|
||||
);
|
||||
|
||||
after(function () {
|
||||
rimraf.sync(tmpLocation);
|
||||
});
|
||||
|
||||
exports.TempDir = (function() {
|
||||
function TempDir (defaults) {
|
||||
this.path = path.join(tmpLocation, uuid.v4());
|
||||
this.defaults = defaults;
|
||||
}
|
||||
|
||||
TempDir.prototype.create = function (files, defaults) {
|
||||
var that = this;
|
||||
|
||||
defaults = defaults || this.defaults || {};
|
||||
files = object.merge(files || {}, defaults);
|
||||
|
||||
this.meta = function(tag) {
|
||||
if (tag) {
|
||||
return files[tag]['bower.json'];
|
||||
} else {
|
||||
return files['bower.json'];
|
||||
}
|
||||
};
|
||||
|
||||
if (files) {
|
||||
object.forOwn(files, function (contents, filepath) {
|
||||
if (typeof contents === 'object') {
|
||||
contents = JSON.stringify(contents, null, ' ') + '\n';
|
||||
}
|
||||
|
||||
var fullPath = path.join(that.path, filepath);
|
||||
mkdirp.sync(path.dirname(fullPath));
|
||||
fs.writeFileSync(fullPath, contents);
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
TempDir.prototype.prepare = function (files) {
|
||||
rimraf.sync(this.path);
|
||||
mkdirp.sync(this.path);
|
||||
this.create(files);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// TODO: Rewrite to synchronous form
|
||||
TempDir.prototype.prepareGit = function (revisions) {
|
||||
var that = this;
|
||||
|
||||
revisions = object.merge(revisions || {}, this.defaults);
|
||||
|
||||
rimraf.sync(that.path);
|
||||
|
||||
mkdirp.sync(that.path);
|
||||
|
||||
var promise = new Q();
|
||||
|
||||
object.forOwn(revisions, function (files, tag) {
|
||||
promise = promise.then(function () {
|
||||
return that.git('init');
|
||||
}).then(function () {
|
||||
that.glob('./!(.git)').map(function (removePath) {
|
||||
var fullPath = path.join(that.path, removePath);
|
||||
|
||||
rimraf.sync(fullPath);
|
||||
});
|
||||
|
||||
that.create(files, {});
|
||||
}).then(function () {
|
||||
return that.git('add', '-A');
|
||||
}).then(function () {
|
||||
return that.git('commit', '-m"commit"');
|
||||
}).then(function () {
|
||||
return that.git('tag', tag);
|
||||
});
|
||||
});
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
TempDir.prototype.glob = function (pattern) {
|
||||
return glob.sync(pattern, {
|
||||
cwd: this.path,
|
||||
dot: true
|
||||
});
|
||||
};
|
||||
|
||||
TempDir.prototype.getPath = function (name) {
|
||||
return path.join(this.path, name);
|
||||
};
|
||||
|
||||
TempDir.prototype.read = function (name) {
|
||||
return fs.readFileSync(this.getPath(name), 'utf8');
|
||||
};
|
||||
|
||||
TempDir.prototype.readJson = function (name) {
|
||||
return JSON.parse(this.read(name));
|
||||
};
|
||||
|
||||
TempDir.prototype.exists = function (name) {
|
||||
return fs.existsSync(path.join(this.path, name));
|
||||
};
|
||||
|
||||
return TempDir;
|
||||
})();
|
||||
245
packages/bower-config/test/test.js
Normal file
245
packages/bower-config/test/test.js
Normal file
@@ -0,0 +1,245 @@
|
||||
var assert = require('assert');
|
||||
var path = require('path');
|
||||
|
||||
describe('NPM Config on package.json', function () {
|
||||
beforeEach(function () {
|
||||
delete process.env.npm_package_config_bower_directory;
|
||||
delete process.env.npm_package_config_bower_colors;
|
||||
delete process.env.npm_package_config_bower_resolvers;
|
||||
});
|
||||
|
||||
it('defaults registry entries to default registry', function () {
|
||||
var config = require('../lib/Config').read(null, {});
|
||||
|
||||
assert.deepEqual(config.registry, {
|
||||
'default': 'https://bower.herokuapp.com',
|
||||
'search': [
|
||||
'https://bower.herokuapp.com'
|
||||
],
|
||||
'register': 'https://bower.herokuapp.com',
|
||||
'publish': 'https://bower.herokuapp.com'
|
||||
});
|
||||
});
|
||||
|
||||
it('can change default registry', function () {
|
||||
var config = require('../lib/Config').read(null, { registry: 'https://foobar' });
|
||||
|
||||
assert.deepEqual(config.registry, {
|
||||
'default': 'https://foobar',
|
||||
'search': [
|
||||
'https://foobar',
|
||||
],
|
||||
'register': 'https://foobar',
|
||||
'publish': 'https://foobar'
|
||||
});
|
||||
});
|
||||
|
||||
it('can override single entries in registry configuration', function () {
|
||||
var config = require('../lib/Config').read(null, { registry: { search: 'https://foobar' } });
|
||||
|
||||
assert.deepEqual(config.registry, {
|
||||
'default': 'https://bower.herokuapp.com',
|
||||
'search': [
|
||||
'https://foobar',
|
||||
],
|
||||
'register': 'https://bower.herokuapp.com',
|
||||
'publish': 'https://bower.herokuapp.com'
|
||||
});
|
||||
});
|
||||
|
||||
it('can override single entries in registry configuration and defaults', function () {
|
||||
var config = require('../lib/Config').read(null, { registry: { default: 'https://fizfuz', search: 'https://foobar' } });
|
||||
|
||||
assert.deepEqual(config.registry, {
|
||||
'default': 'https://fizfuz',
|
||||
'search': [
|
||||
'https://foobar',
|
||||
],
|
||||
'register': 'https://fizfuz',
|
||||
'publish': 'https://fizfuz'
|
||||
});
|
||||
});
|
||||
|
||||
it('allows for not providing cwd', function () {
|
||||
var config = require('../lib/Config').read();
|
||||
|
||||
config.tmp = '/foo/bar';
|
||||
config.userAgent = 'firefox';
|
||||
delete config.storage;
|
||||
|
||||
assert.deepEqual(config, {
|
||||
'directory': 'bower_components',
|
||||
'registry': {
|
||||
'default': 'https://bower.herokuapp.com',
|
||||
'search': [
|
||||
'https://bower.herokuapp.com'
|
||||
],
|
||||
'register': 'https://bower.herokuapp.com',
|
||||
'publish': 'https://bower.herokuapp.com'
|
||||
},
|
||||
'shorthandResolver': 'https://github.com/{{owner}}/{{package}}.git',
|
||||
'tmp': '/foo/bar',
|
||||
'timeout': 30000,
|
||||
'ca': {
|
||||
'search': []
|
||||
},
|
||||
'strictSsl': true,
|
||||
'userAgent': 'firefox',
|
||||
'color': true
|
||||
});
|
||||
});
|
||||
|
||||
function assertCAContents(caData, name) {
|
||||
var r = /-----BEGIN CERTIFICATE-----[a-zA-Z0-9+\/=\n\r]+-----END CERTIFICATE-----/;
|
||||
|
||||
assert(caData, name + ' should be set');
|
||||
assert(Array.isArray(caData), name + ' should be an array');
|
||||
assert.equal(2, caData.length);
|
||||
caData.forEach(function(c, i) {
|
||||
assert(c.match(r),
|
||||
name + '[' + i + '] should contain a certificate. Given: ' + JSON.stringify(c));
|
||||
});
|
||||
}
|
||||
|
||||
describe('Setting process.env.npm_package_config', function () {
|
||||
process.env.npm_package_config_bower_directory = 'npm-path';
|
||||
process.env.npm_package_config_bower_colors = 'false';
|
||||
process.env.npm_package_config_bower_resolvers = '[foo,bar,baz]';
|
||||
|
||||
var config = require('../lib/Config').read();
|
||||
|
||||
it('should return "npm-path" for "bower_directory"', function () {
|
||||
assert.equal('npm-path', config.directory);
|
||||
});
|
||||
it('should return "false" for "bower_colors"', function () {
|
||||
assert.equal('false', config.colors);
|
||||
});
|
||||
it('should expand array "false" for "bower_resolvers"', function () {
|
||||
assert.deepEqual(['foo', 'bar', 'baz'], config.resolvers);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Specifying custom CA', function() {
|
||||
|
||||
it('should read the CA file', function() {
|
||||
var config = require('../lib/Config')
|
||||
.read(path.resolve('test/assets/custom-ca'));
|
||||
|
||||
['register', 'publish', 'default'].forEach(function (p) {
|
||||
assertCAContents(config.ca[p], 'config.ca.' + p);
|
||||
});
|
||||
|
||||
assert(Array.isArray(config.ca.search),
|
||||
'ca property search should be an array');
|
||||
|
||||
config.ca.search.forEach(function(c, i) {
|
||||
assertCAContents(c, 'config.ca.search[' + i + ']');
|
||||
});
|
||||
});
|
||||
|
||||
it('should backward-support certificate inside .bowerrc', function() {
|
||||
var config = require('../lib/Config')
|
||||
.read(path.resolve('test/assets/custom-ca-embed'));
|
||||
|
||||
['register', 'publish', 'default'].forEach(function (p) {
|
||||
assertCAContents(config.ca[p], 'config.ca.' + p);
|
||||
});
|
||||
|
||||
assert(Array.isArray(config.ca.search),
|
||||
'ca property search should be an array');
|
||||
config.ca.search.forEach(function(c, i) {
|
||||
assertCAContents(c, 'config.ca.search[' + i + ']');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('setting ENV variables', function () {
|
||||
beforeEach(function () {
|
||||
delete process.env.no_proxy;
|
||||
delete process.env.http_proxy;
|
||||
delete process.env.https_proxy;
|
||||
delete process.env.NO_PROXY;
|
||||
delete process.env.HTTP_PROXY;
|
||||
delete process.env.HTTPS_PROXY;
|
||||
});
|
||||
|
||||
it('sets env variables', function () {
|
||||
require('../lib/Config').read('test/assets/env-variables');
|
||||
|
||||
assert.equal(process.env.HTTP_PROXY, 'http://HTTP_PROXY');
|
||||
assert.equal(process.env.HTTPS_PROXY, 'http://HTTPS_PROXY');
|
||||
assert.equal(process.env.NO_PROXY, 'google.com');
|
||||
|
||||
assert.equal(process.env.http_proxy, undefined);
|
||||
assert.equal(process.env.https_proxy, undefined);
|
||||
assert.equal(process.env.no_proxy, undefined);
|
||||
});
|
||||
|
||||
it('restores env variables', function () {
|
||||
process.env.HTTP_PROXY = 'a';
|
||||
process.env.HTTPS_PROXY = 'b';
|
||||
process.env.NO_PROXY = 'c';
|
||||
process.env.http_proxy = 'd';
|
||||
process.env.https_proxy = 'e';
|
||||
process.env.no_proxy = 'f';
|
||||
|
||||
var config = require('../lib/Config').create('test/assets/env-variables').load();
|
||||
config.restore();
|
||||
|
||||
assert.equal(process.env.HTTP_PROXY, 'a');
|
||||
assert.equal(process.env.HTTPS_PROXY, 'b');
|
||||
assert.equal(process.env.NO_PROXY, 'c');
|
||||
|
||||
assert.equal(process.env.http_proxy, 'd');
|
||||
assert.equal(process.env.https_proxy, 'e');
|
||||
assert.equal(process.env.no_proxy, 'f');
|
||||
});
|
||||
|
||||
it('restores env variables if they are undefined', function () {
|
||||
var config = require('../lib/Config').create('test/assets/env-variables').load();
|
||||
config.restore();
|
||||
|
||||
assert.equal(process.env.HTTP_PROXY, undefined);
|
||||
assert.equal(process.env.HTTPS_PROXY, undefined);
|
||||
assert.equal(process.env.NO_PROXY, undefined);
|
||||
|
||||
assert.equal(process.env.http_proxy, undefined);
|
||||
assert.equal(process.env.https_proxy, undefined);
|
||||
assert.equal(process.env.no_proxy, undefined);
|
||||
});
|
||||
|
||||
it('allows for overriding options', function () {
|
||||
require('../lib/Config').read('test/assets/env-variables', {
|
||||
httpsProxy: 'http://other-proxy.local'
|
||||
});
|
||||
|
||||
assert.equal(process.env.HTTP_PROXY, 'http://HTTP_PROXY');
|
||||
assert.equal(process.env.HTTPS_PROXY, 'http://other-proxy.local');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Allow ${ENV} variables in .bowerrc', function() {
|
||||
|
||||
it('sets values from process.env', function() {
|
||||
process.env._BOWERRC_MY_PACKAGES = 'a';
|
||||
process.env._BOWERRC_MY_TMP = '/tmp/b';
|
||||
|
||||
var config = require('../lib/Config').read('test/assets/env-variables-values');
|
||||
assert.equal('a', config.storage.packages);
|
||||
assert.equal('/tmp/b', config.tmp);
|
||||
assert.equal('${_myshellvar}', config.scripts.postinstall);
|
||||
});
|
||||
});
|
||||
|
||||
describe('untildify paths in .bowerrc', function() {
|
||||
|
||||
it('resolve ~/ in .bowerrc', function() {
|
||||
var config = require('../lib/Config').read('test/assets/env-variables-values');
|
||||
var untildify = require('untildify');
|
||||
|
||||
assert.equal(untildify('~/.bower-test/registry') , config.storage.registry);
|
||||
});
|
||||
});
|
||||
|
||||
require('./util/index');
|
||||
3
packages/bower-config/test/util/index.js
Normal file
3
packages/bower-config/test/util/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
describe('util', function () {
|
||||
require('./rc');
|
||||
});
|
||||
84
packages/bower-config/test/util/rc.js
Normal file
84
packages/bower-config/test/util/rc.js
Normal file
@@ -0,0 +1,84 @@
|
||||
var expect = require('expect.js');
|
||||
var helpers = require('../helpers');
|
||||
|
||||
describe('rc', function() {
|
||||
var tempDir = new helpers.TempDir();
|
||||
var tempDirBowerrc = new helpers.TempDir();
|
||||
|
||||
var rc = require('../../lib/util/rc');
|
||||
|
||||
tempDir.prepare({
|
||||
'.bowerrc': {
|
||||
key: 'value'
|
||||
},
|
||||
'child/.bowerrc': {
|
||||
key2: 'value2'
|
||||
},
|
||||
'child2/.bowerrc': {
|
||||
key: 'valueShouldBeOverwriteParent'
|
||||
},
|
||||
'child3/bower.json': {
|
||||
name: 'without-bowerrc'
|
||||
},
|
||||
'other_dir/.bowerrc': {
|
||||
key: 'othervalue'
|
||||
}
|
||||
});
|
||||
|
||||
tempDirBowerrc.prepare({
|
||||
'.bowerrc/foo': {
|
||||
key: 'bar'
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
it('correctly reads .bowerrc files', function() {
|
||||
var config = rc('bower', tempDir.path);
|
||||
|
||||
expect(config.key).to.eql('value');
|
||||
expect(config.key2).to.eql(undefined);
|
||||
});
|
||||
|
||||
it('correctly reads .bowerrc files from child', function() {
|
||||
var config = rc('bower', tempDir.path + '/child/');
|
||||
|
||||
expect(config.key).to.eql('value');
|
||||
expect(config.key2).to.eql('value2');
|
||||
});
|
||||
|
||||
it('correctly reads .bowerrc files from child2', function() {
|
||||
var config = rc('bower', tempDir.path + '/child2/');
|
||||
|
||||
expect(config.key).to.eql('valueShouldBeOverwriteParent');
|
||||
expect(config.key2).to.eql(undefined);
|
||||
});
|
||||
|
||||
it('correctly reads .bowerrc files from child3', function() {
|
||||
var config = rc('bower', tempDir.path + '/child3/');
|
||||
|
||||
expect(config.key).to.eql('value');
|
||||
expect(config.key2).to.eql(undefined);
|
||||
});
|
||||
|
||||
it('loads the .bowerrc file from the cwd specified on the command line', function(){
|
||||
var argv = {
|
||||
'config': {
|
||||
'cwd': tempDir.path + '/other_dir/'
|
||||
}
|
||||
};
|
||||
|
||||
var config = rc('bower', tempDir.path, argv);
|
||||
|
||||
expect(config.key).to.eql('othervalue');
|
||||
|
||||
});
|
||||
|
||||
it('throws an easy to understand error if .bowerrc is a dir', function() {
|
||||
// Gotta wrap this to catch the error
|
||||
var config = function () {
|
||||
rc('bower', tempDirBowerrc.path);
|
||||
};
|
||||
|
||||
expect(config).to.throwError(/should not be a directory/);
|
||||
});
|
||||
});
|
||||
12
packages/bower-endpoint-parser/.editorconfig
Normal file
12
packages/bower-endpoint-parser/.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
2
packages/bower-endpoint-parser/.gitignore
vendored
Normal file
2
packages/bower-endpoint-parser/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/node_modules
|
||||
/npm-debug.*
|
||||
61
packages/bower-endpoint-parser/.jshintrc
Normal file
61
packages/bower-endpoint-parser/.jshintrc
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"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": true,
|
||||
"quotmark": "single",
|
||||
"strict": false,
|
||||
"trailing": true,
|
||||
"camelcase": true,
|
||||
|
||||
"asi": false,
|
||||
"boss": true,
|
||||
"debug": false,
|
||||
"eqnull": true,
|
||||
"esnext": false,
|
||||
"evil": false,
|
||||
"expr": true,
|
||||
"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
packages/bower-endpoint-parser/.travis.yml
Normal file
4
packages/bower-endpoint-parser/.travis.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.10"
|
||||
- "0.8"
|
||||
19
packages/bower-endpoint-parser/LICENSE
Normal file
19
packages/bower-endpoint-parser/LICENSE
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2012 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
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
102
packages/bower-endpoint-parser/README.md
Normal file
102
packages/bower-endpoint-parser/README.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# endpoint-parser [](http://travis-ci.org/bower/endpoint-parser)
|
||||
|
||||
Little module that helps with endpoints parsing.
|
||||
|
||||
|
||||
## API
|
||||
|
||||
### .decompose(endpoint)
|
||||
|
||||
Decomposes a endpoint into `name`, `source` and `target`.
|
||||
|
||||
```js
|
||||
var endpointParser = require('bower-endpoint-parser');
|
||||
|
||||
endpointParser.decompose('jquery#~2.0.0');
|
||||
// { name: '', source: 'jquery', target: '~2.0.0' }
|
||||
|
||||
endpointParser.decompose('backbone=backbone-amd#~1.0.0');
|
||||
// { name: 'backbone', source: 'backbone-amd', target: '~1.0.0' }
|
||||
|
||||
endpointParser.decompose('http://twitter.github.io/bootstrap/assets/bootstrap.zip');
|
||||
// { name: '', source: 'http://twitter.github.io/bootstrap/assets/bootstrap', target: '*' }
|
||||
|
||||
endpointParser.decompose('bootstrap=http://twitter.github.io/bootstrap/assets/bootstrap.zip');
|
||||
// { name: 'bootstrap', source: 'http://twitter.github.io/bootstrap/assets/bootstrap', target: '*' }
|
||||
```
|
||||
|
||||
### .compose(decEndpoint)
|
||||
|
||||
Inverse of `decompose()`.
|
||||
Takes a decomposed endpoint and composes it back into a string.
|
||||
|
||||
```js
|
||||
var endpointParser = require('bower-endpoint-parser');
|
||||
|
||||
endpointParser.compose({ name: '', source: 'jquery', target: '~2.0.0' });
|
||||
// jquery#~2.0.0
|
||||
|
||||
endpointParser.compose({ name: 'backbone', source: 'backbone-amd', target: '~1.0.0' });
|
||||
// backbone=backbone-amd#~1.0.0
|
||||
|
||||
endpointParser.compose({ name: '', source: 'http://twitter.github.io/bootstrap/assets/bootstrap', target: '*' });
|
||||
// http://twitter.github.io/bootstrap/assets/bootstrap.zip
|
||||
|
||||
endpointParser.compose({ name: 'bootstrap', source: 'http://twitter.github.io/bootstrap/assets/bootstrap', target: '*' });
|
||||
// bootstrap=http://twitter.github.io/bootstrap/assets/bootstrap.zip
|
||||
```
|
||||
|
||||
### .json2decomposed(key, value)
|
||||
|
||||
Similar to `decompose()` but specially designed to be used when parsing `bower.json` dependencies.
|
||||
For instance, in a `bower.json` like this:
|
||||
|
||||
```js
|
||||
{
|
||||
"name": "foo",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"jquery": "~1.9.1",
|
||||
"backbone": "backbone-amd#~1.0.0",
|
||||
"bootstrap": "http://twitter.github.io/bootstrap/assets/bootstrap"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You would call `json2decomposed` like so:
|
||||
|
||||
```js
|
||||
endpointParser.json2decomposed('jquery', '~1.9.1');
|
||||
// { name: 'jquery', source: 'jquery', target: '~1.9.1' }
|
||||
|
||||
endpointParser.json2decomposed('backbone', 'backbone-amd#~1.0.0');
|
||||
// { name: 'backbone', source: 'backbone-amd', target: '~1.0.0' }
|
||||
|
||||
endpointParser.json2decomposed('bootstrap', 'http://twitter.github.io/bootstrap/assets/bootstrap');
|
||||
// { name: 'bootstrap', source: 'http://twitter.github.io/bootstrap/assets/bootstrap', target: '*' }
|
||||
```
|
||||
|
||||
### .decomposed2json(decEndpoint)
|
||||
|
||||
Inverse of `json2decomposed()`.
|
||||
Takes a decomposed endpoint and composes it to be saved to `bower.json`.
|
||||
|
||||
```js
|
||||
var endpointParser = require('bower-endpoint-parser');
|
||||
|
||||
endpointParser.decomposed2json({ name: 'jquery', source: 'jquery', target: '~2.0.0' });
|
||||
// { jquery: '~2.0.0' }
|
||||
|
||||
endpointParser.decomposed2json({ name: 'backbone', source: 'backbone-amd', target: '~1.0.0' });
|
||||
// { backbone: 'backbone-amd#~2.0.0' }
|
||||
|
||||
endpointParser.decomposed2json({ name: 'bootstrap', source: 'http://twitter.github.io/bootstrap/assets/bootstrap', target: '*' });
|
||||
// { bootstrap: 'http://twitter.github.io/bootstrap/assets/bootstrap' }
|
||||
```
|
||||
|
||||
This function throws an exception if the `name` from the decomposed endpoint is empty.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Released under the [MIT License](http://www.opensource.org/licenses/mit-license.php).
|
||||
128
packages/bower-endpoint-parser/index.js
Normal file
128
packages/bower-endpoint-parser/index.js
Normal file
@@ -0,0 +1,128 @@
|
||||
function decompose(endpoint) {
|
||||
// Note that we allow spaces in targets and sources but they are trimmed
|
||||
var regExp = /^(?:([\w\-]|(?:[\w\.\-]+[\w\-])?)=)?([^\|#]+)(?:#(.*))?$/;
|
||||
var matches = endpoint.match(regExp);
|
||||
var target;
|
||||
var error;
|
||||
|
||||
if (!matches) {
|
||||
error = new Error('Invalid endpoint: ' + endpoint);
|
||||
error.code = 'EINVEND';
|
||||
throw error;
|
||||
}
|
||||
|
||||
target = trim(matches[3]);
|
||||
|
||||
return {
|
||||
name: trim(matches[1]),
|
||||
source: trim(matches[2]),
|
||||
target: isWildcard(target) ? '*' : target
|
||||
};
|
||||
}
|
||||
|
||||
function compose(decEndpoint) {
|
||||
var name = trim(decEndpoint.name);
|
||||
var source = trim(decEndpoint.source);
|
||||
var target = trim(decEndpoint.target);
|
||||
var composed = '';
|
||||
|
||||
if (name) {
|
||||
composed += name + '=';
|
||||
}
|
||||
|
||||
composed += source;
|
||||
|
||||
if (!isWildcard(target)) {
|
||||
composed += '#' + target;
|
||||
}
|
||||
|
||||
return composed;
|
||||
}
|
||||
|
||||
function json2decomposed(key, value) {
|
||||
var endpoint;
|
||||
var split;
|
||||
var error;
|
||||
|
||||
key = trim(key);
|
||||
value = trim(value);
|
||||
|
||||
if (!key) {
|
||||
error = new Error('The key must be specified');
|
||||
error.code = 'EINVEND';
|
||||
throw error;
|
||||
}
|
||||
|
||||
endpoint = key + '=';
|
||||
split = value.split('#').map(trim);
|
||||
|
||||
// If # was found, the source was specified
|
||||
if (split.length > 1) {
|
||||
endpoint += (split[0] || key) + '#' + split[1];
|
||||
// Check if value looks like a source
|
||||
} else if (isSource(value)) {
|
||||
endpoint += value + '#*';
|
||||
// Otherwise use the key as the source
|
||||
} else {
|
||||
endpoint += key + '#' + split[0];
|
||||
}
|
||||
|
||||
return decompose(endpoint);
|
||||
}
|
||||
|
||||
function decomposed2json(decEndpoint) {
|
||||
var error;
|
||||
var name = trim(decEndpoint.name);
|
||||
var source = trim(decEndpoint.source);
|
||||
var target = trim(decEndpoint.target);
|
||||
var value = '';
|
||||
var ret = {};
|
||||
|
||||
if (!name) {
|
||||
error = new Error('Decomposed endpoint must have a name');
|
||||
error.code = 'EINVEND';
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Add source only if different than the name
|
||||
if (source !== name) {
|
||||
value += source;
|
||||
}
|
||||
|
||||
// If value is empty, we append the target always
|
||||
if (!value) {
|
||||
if (isWildcard(target)) {
|
||||
value += '*';
|
||||
} else {
|
||||
if (target.indexOf('/') !== -1) {
|
||||
value += '#' + target;
|
||||
} else {
|
||||
value += target;
|
||||
}
|
||||
}
|
||||
// Otherwise append only if not a wildcard or source does not look like a source
|
||||
} else if (!isWildcard(target) || !isSource(source)) {
|
||||
value += '#' + (target || '*');
|
||||
}
|
||||
|
||||
ret[name] = value;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
function trim(str) {
|
||||
return str ? str.trim() : '';
|
||||
}
|
||||
|
||||
function isWildcard(target) {
|
||||
return !target || target === '*' || target === 'latest';
|
||||
}
|
||||
|
||||
function isSource(value) {
|
||||
return (/[\/\\@]/).test(value);
|
||||
}
|
||||
|
||||
module.exports.decompose = decompose;
|
||||
module.exports.compose = compose;
|
||||
module.exports.json2decomposed = json2decomposed;
|
||||
module.exports.decomposed2json = decomposed2json;
|
||||
28
packages/bower-endpoint-parser/package.json
Normal file
28
packages/bower-endpoint-parser/package.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "bower-endpoint-parser",
|
||||
"version": "0.2.2",
|
||||
"description": "Little module that helps with endpoints parsing.",
|
||||
"author": "Twitter",
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT",
|
||||
"url": "https://github.com/bower/endpoint-parser/blob/master/LICENSE"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/bower/endpoint-parser.git"
|
||||
},
|
||||
"main": "index.js",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"expect.js": "~0.2.0",
|
||||
"mocha": "~1.12.0",
|
||||
"mout": "~0.9.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "mocha -R spec"
|
||||
}
|
||||
}
|
||||
263
packages/bower-endpoint-parser/test/test.js
Normal file
263
packages/bower-endpoint-parser/test/test.js
Normal file
@@ -0,0 +1,263 @@
|
||||
var expect = require('expect.js');
|
||||
var lang = require('mout/lang');
|
||||
var object = require('mout/object');
|
||||
var endpointParser = require('../');
|
||||
|
||||
describe('endpoint-parser', function () {
|
||||
describe('.decompose', function () {
|
||||
it('should decompose endpoints correctly', function () {
|
||||
var suite = {
|
||||
'jquery#~2.0.0': { name: '', source: 'jquery', target: '~2.0.0' },
|
||||
'jquery#*': { name: '', source: 'jquery', target: '*' },
|
||||
'jquery#latest': { name: '', source: 'jquery', target: '*' },
|
||||
'jquery#3dc50c62fe2d2d01afc58e7ad42236a35acff4d8': { name: '', source: 'jquery', target: '3dc50c62fe2d2d01afc58e7ad42236a35acff4d8' },
|
||||
'jquery#master': { name: '', source: 'jquery', target: 'master' },
|
||||
'backbone=backbone-amd#~1.0.0': { name: 'backbone', source: 'backbone-amd', target: '~1.0.0' },
|
||||
'backbone=backbone-amd#latest': { name: 'backbone', source: 'backbone-amd', target: '*' },
|
||||
'backbone=backbone-amd#*': { name: 'backbone', source: 'backbone-amd', target: '*' },
|
||||
'http://twitter.github.io/bootstrap/assets/bootstrap.zip': { name: '', source: 'http://twitter.github.io/bootstrap/assets/bootstrap.zip', target: '*' },
|
||||
'bootstrap=http://twitter.github.io/bootstrap/assets/bootstrap.zip': { name: 'bootstrap', source: 'http://twitter.github.io/bootstrap/assets/bootstrap.zip', target: '*' },
|
||||
'bootstrap=http://twitter.github.io/bootstrap/assets/bootstrap.zip#latest': { name: 'bootstrap', source: 'http://twitter.github.io/bootstrap/assets/bootstrap.zip', target: '*' }
|
||||
};
|
||||
|
||||
object.forOwn(suite, function (decEndpoint, endpoint) {
|
||||
expect(endpointParser.decompose(endpoint)).to.eql(decEndpoint);
|
||||
});
|
||||
});
|
||||
|
||||
it('should trim sources and targets', function () {
|
||||
var decEndpoint = endpointParser.decompose('foo= source # ~1.0.2 ');
|
||||
expect(decEndpoint.source).to.equal('source');
|
||||
expect(decEndpoint.target).to.equal('~1.0.2');
|
||||
|
||||
decEndpoint = endpointParser.decompose('foo= source # latest');
|
||||
expect(decEndpoint.source).to.equal('source');
|
||||
expect(decEndpoint.target).to.equal('*');
|
||||
|
||||
decEndpoint = endpointParser.decompose('foo= source # *');
|
||||
expect(decEndpoint.source).to.equal('source');
|
||||
expect(decEndpoint.target).to.equal('*');
|
||||
});
|
||||
});
|
||||
|
||||
describe('.compose', function () {
|
||||
it('should compose endpoints correctly', function () {
|
||||
var suite = {
|
||||
'jquery#~2.0.0': { name: '', source: 'jquery', target: '~2.0.0' },
|
||||
'jquery': [{ name: '', source: 'jquery', target: '*' }, { name: '', source: 'jquery', target: 'latest' }, { name: '', source: 'jquery', target: '' }],
|
||||
'jquery#3dc50c62fe2d2d01afc58e7ad42236a35acff4d8': { name: '', source: 'jquery', target: '3dc50c62fe2d2d01afc58e7ad42236a35acff4d8' },
|
||||
'jquery#master': { name: '', source: 'jquery', target: 'master' },
|
||||
'backbone=backbone-amd#~1.0.0': { name: 'backbone', source: 'backbone-amd', target: '~1.0.0' },
|
||||
'backbone=backbone-amd': [{ name: 'backbone', source: 'backbone-amd', target: '*' }, { name: 'backbone', source: 'backbone-amd', target: '*' }, { name: 'backbone', source: 'backbone-amd', target: '' }],
|
||||
'http://twitter.github.io/bootstrap/assets/bootstrap.zip': { name: '', source: 'http://twitter.github.io/bootstrap/assets/bootstrap.zip', target: '*' },
|
||||
'bootstrap=http://twitter.github.io/bootstrap/assets/bootstrap.zip': { name: 'bootstrap', source: 'http://twitter.github.io/bootstrap/assets/bootstrap.zip', target: '*' }
|
||||
};
|
||||
|
||||
object.forOwn(suite, function (decEndpoints, endpoint) {
|
||||
decEndpoints = lang.toArray(decEndpoints);
|
||||
decEndpoints.forEach(function (decEndpoint) {
|
||||
expect(endpointParser.compose(decEndpoint)).to.equal(endpoint);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should trim values', function () {
|
||||
expect(endpointParser.compose({
|
||||
name: ' foo ',
|
||||
source: ' bar ',
|
||||
target: ' ~1.0.2 '
|
||||
})).to.equal('foo=bar#~1.0.2');
|
||||
|
||||
expect(endpointParser.compose({
|
||||
name: ' foo ',
|
||||
source: ' foo ',
|
||||
target: ' ~1.0.2 '
|
||||
})).to.equal('foo=foo#~1.0.2');
|
||||
|
||||
expect(endpointParser.compose({
|
||||
name: ' foo ',
|
||||
source: ' foo ',
|
||||
target: ' * '
|
||||
})).to.equal('foo=foo');
|
||||
|
||||
expect(endpointParser.compose({
|
||||
name: ' foo ',
|
||||
source: ' foo ',
|
||||
target: ' * '
|
||||
})).to.equal('foo=foo');
|
||||
|
||||
expect(endpointParser.compose({
|
||||
name: ' ',
|
||||
source: ' foo ',
|
||||
target: ''
|
||||
})).to.equal('foo');
|
||||
});
|
||||
});
|
||||
|
||||
describe('.json2decomposed', function () {
|
||||
var expected = [
|
||||
{ name: 'jquery', source: 'jquery', target: '~1.9.1' },
|
||||
{ name: 'foo', source: 'foo', target: '*' },
|
||||
{ name: 'bar', source: 'bar', target: '*' },
|
||||
{ name: 'baz', source: 'baz', target: '~0.2.0' },
|
||||
{ name: 'backbone', source: 'backbone-amd', target: '~1.0.0' },
|
||||
{ name: 'backbone2', source: 'backbone=backbone-amd', target: '~1.0.0' },
|
||||
{ name: 'bootstrap', source: 'http://twitter.github.io/bootstrap/assets/bootstrap', target: '*' },
|
||||
{ name: 'bootstrap2', source: 'http://twitter.github.io/bootstrap/assets/bootstrap', target: '*' },
|
||||
{ name: 'ssh', source: 'git@example.com', target: '*' },
|
||||
{ name: 'git', source: 'git://example.com', target: '*' },
|
||||
{ name: 'path', source: '/foo', target: '*' },
|
||||
{ name: 'winpath', source: 'c:\\foo', target: '*' }
|
||||
];
|
||||
|
||||
it('should decompose json endpoints correctly', function () {
|
||||
var dependencies = {
|
||||
jquery: '~1.9.1',
|
||||
foo: 'latest',
|
||||
bar: '*',
|
||||
baz: '#~0.2.0',
|
||||
backbone: 'backbone-amd#~1.0.0',
|
||||
backbone2: 'backbone=backbone-amd#~1.0.0',
|
||||
bootstrap: 'http://twitter.github.io/bootstrap/assets/bootstrap',
|
||||
bootstrap2: 'http://twitter.github.io/bootstrap/assets/bootstrap#*',
|
||||
ssh: 'git@example.com',
|
||||
git: 'git://example.com',
|
||||
path: '/foo',
|
||||
winpath: 'c:\\foo'
|
||||
};
|
||||
var x = 0;
|
||||
|
||||
object.forOwn(dependencies, function (value, key) {
|
||||
expect(endpointParser.json2decomposed(key, value)).to.eql(expected[x]);
|
||||
x += 1;
|
||||
});
|
||||
});
|
||||
|
||||
it('should trim values', function () {
|
||||
var dependencies = {
|
||||
' jquery ': ' ~1.9.1 ',
|
||||
' foo ': ' latest ',
|
||||
' bar ': ' * ',
|
||||
' baz ': '# ~0.2.0 ',
|
||||
' backbone ': ' backbone-amd#~1.0.0 ',
|
||||
' backbone2 ': ' backbone=backbone-amd # ~1.0.0 ',
|
||||
' bootstrap ': ' http://twitter.github.io/bootstrap/assets/bootstrap',
|
||||
' bootstrap2 ': ' http://twitter.github.io/bootstrap/assets/bootstrap # *',
|
||||
' ssh ': ' git@example.com ',
|
||||
' git ': ' git://example.com ',
|
||||
' path ': ' /foo ',
|
||||
' winpath ': ' c:\\foo '
|
||||
};
|
||||
var x = 0;
|
||||
|
||||
object.forOwn(dependencies, function (value, key) {
|
||||
expect(endpointParser.json2decomposed(key, value)).to.eql(expected[x]);
|
||||
x += 1;
|
||||
});
|
||||
});
|
||||
|
||||
it('should error out if key is not specified', function () {
|
||||
try {
|
||||
endpointParser.json2decomposed(null);
|
||||
throw new Error('Should have failed');
|
||||
} catch (e) {
|
||||
expect(e.code).to.equal('EINVEND');
|
||||
expect(e.message).to.contain('key must be specified');
|
||||
}
|
||||
|
||||
try {
|
||||
endpointParser.json2decomposed('');
|
||||
throw new Error('Should have failed');
|
||||
} catch (e) {
|
||||
expect(e.code).to.equal('EINVEND');
|
||||
expect(e.message).to.contain('key must be specified');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('.decomposed2json', function () {
|
||||
var expected = [
|
||||
{ jquery: '~1.9.1' },
|
||||
{ foo: '*' },
|
||||
{ bar: '*' },
|
||||
{ baz: '*' },
|
||||
{ jqueryx: 'jquery#~1.9.1' },
|
||||
{ jqueryy: 'jquery-x#*' },
|
||||
{ jqueryy: 'jquery-x#*' },
|
||||
{ backbone: 'backbone-amd#~1.0.0' },
|
||||
{ backbone : 'backbone=backbone-amd#~1.0.0' },
|
||||
{ bootstrap: 'http://twitter.github.io/bootstrap/assets/bootstrap' },
|
||||
{ bootstrap: 'http://twitter.github.io/bootstrap/assets/bootstrap' },
|
||||
{ ssh: 'git@example.com' },
|
||||
{ git: 'git://example.com' },
|
||||
{ ckeditor: '#full/4.3.3' }
|
||||
];
|
||||
|
||||
it('should compose endpoints to json correctly', function () {
|
||||
var decEndpoints = [
|
||||
{ name: 'jquery', source: 'jquery', target: '~1.9.1' },
|
||||
{ name: 'foo', source: 'foo', target: 'latest' },
|
||||
{ name: 'bar', source: 'bar', target: '*' },
|
||||
{ name: 'baz', source: 'baz', target: '' },
|
||||
{ name: 'jqueryx', source: 'jquery', target: '~1.9.1' },
|
||||
{ name: 'jqueryy', source: 'jquery-x', target: '' },
|
||||
{ name: 'jqueryy', source: 'jquery-x', target: '*' },
|
||||
{ name: 'backbone', source: 'backbone-amd', target: '~1.0.0' },
|
||||
{ name: 'backbone', source: 'backbone=backbone-amd', target: '~1.0.0' },
|
||||
{ name: 'bootstrap', source: 'http://twitter.github.io/bootstrap/assets/bootstrap', target: '' },
|
||||
{ name: 'bootstrap', source: 'http://twitter.github.io/bootstrap/assets/bootstrap', target: '*' },
|
||||
{ name: 'ssh', source: 'git@example.com', target: '*' },
|
||||
{ name: 'git', source: 'git://example.com', target: '*' },
|
||||
{ name: 'ckeditor', source: 'ckeditor', target: 'full/4.3.3' }
|
||||
];
|
||||
var x = 0;
|
||||
|
||||
decEndpoints.forEach(function (decEndpoint) {
|
||||
expect(endpointParser.decomposed2json(decEndpoint)).to.eql(expected[x]);
|
||||
x += 1;
|
||||
});
|
||||
});
|
||||
|
||||
it('should trim values', function () {
|
||||
var decEndpoints = [
|
||||
{ name: ' jquery ', source: ' jquery ', target: ' ~1.9.1 ' },
|
||||
{ name: 'foo', source: ' foo', target: ' latest ' },
|
||||
{ name: 'bar', source: 'bar ', target: ' * ' },
|
||||
{ name: 'baz ', source: 'baz', target: ' ' },
|
||||
{ name: ' jqueryx ', source: ' jquery ', target: ' ~1.9.1 ' },
|
||||
{ name: ' jqueryy ', source: ' jquery-x ', target: ' ' },
|
||||
{ name: ' jqueryy ', source: ' jquery-x ', target: ' * ' },
|
||||
{ name: ' backbone ', source: ' backbone-amd ', target: ' ~1.0.0 ' },
|
||||
{ name: ' backbone ', source: ' backbone=backbone-amd ', target: ' ~1.0.0 ' },
|
||||
{ name: ' bootstrap ', source: ' http://twitter.github.io/bootstrap/assets/bootstrap ', target: ' ' },
|
||||
{ name: ' bootstrap ', source: ' http://twitter.github.io/bootstrap/assets/bootstrap ', target: ' * ' },
|
||||
{ name: ' ssh ', source: ' git@example.com ', target: ' * ' },
|
||||
{ name: ' git ', source: ' git://example.com ', target: ' * ' }
|
||||
];
|
||||
var x = 0;
|
||||
|
||||
decEndpoints.forEach(function (decEndpoint) {
|
||||
expect(endpointParser.decomposed2json(decEndpoint)).to.eql(expected[x]);
|
||||
x += 1;
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error if name is empty', function () {
|
||||
try {
|
||||
endpointParser.decomposed2json({ name: '', source: 'jquery', target: '*' });
|
||||
throw new Error('Should have failed');
|
||||
} catch (e) {
|
||||
expect(e.code).to.equal('EINVEND');
|
||||
expect(e.message).to.contain('must have a name');
|
||||
}
|
||||
|
||||
try {
|
||||
endpointParser.decomposed2json({ name: ' ', source: 'jquery', target: '*' });
|
||||
throw new Error('Should have failed');
|
||||
} catch (e) {
|
||||
expect(e.code).to.equal('EINVEND');
|
||||
expect(e.message).to.contain('must have a name');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
12
packages/bower-json/.editorconfig
Normal file
12
packages/bower-json/.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
4
packages/bower-json/.gitignore
vendored
Normal file
4
packages/bower-json/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
/node_modules
|
||||
/npm-debug.*
|
||||
|
||||
/test/reports
|
||||
48
packages/bower-json/.jshintrc
Normal file
48
packages/bower-json/.jshintrc
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"indent": 4,
|
||||
"node": true,
|
||||
"devel": true,
|
||||
"mocha": 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": true,
|
||||
"quotmark": "single",
|
||||
"strict": false,
|
||||
"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,
|
||||
"shadow": false,
|
||||
"sub": false,
|
||||
"supernew": true,
|
||||
"validthis": false
|
||||
}
|
||||
10
packages/bower-json/.travis.yml
Normal file
10
packages/bower-json/.travis.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
sudo: false
|
||||
language: node_js
|
||||
node_js:
|
||||
- '5'
|
||||
- '4'
|
||||
- '0.12'
|
||||
- '0.10'
|
||||
|
||||
script:
|
||||
- grunt travis
|
||||
17
packages/bower-json/CHANGELOG.md
Normal file
17
packages/bower-json/CHANGELOG.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# 0.8.1
|
||||
|
||||
- Revert strict name validations and allow @, spaces and slashes
|
||||
|
||||
# 0.8.0
|
||||
|
||||
- Update graceful-fs to 4.x
|
||||
- Add name validations that reflect what's happening in registry
|
||||
|
||||
# 0.7.1
|
||||
|
||||
- Unpublished
|
||||
|
||||
# 0.7.0
|
||||
|
||||
- Add getIssues function to retrieve all errors and warnings
|
||||
- Add readSync and findSync functions for synchronous read
|
||||
60
packages/bower-json/Gruntfile.js
Normal file
60
packages/bower-json/Gruntfile.js
Normal file
@@ -0,0 +1,60 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function (grunt) {
|
||||
require('load-grunt-tasks')(grunt);
|
||||
// Project configuration.
|
||||
grunt.initConfig({
|
||||
|
||||
jshint: {
|
||||
files: [
|
||||
'Gruntfile.js',
|
||||
'lib/**/*.js',
|
||||
'test/**/*.js',
|
||||
'!test/reports/**/*'
|
||||
],
|
||||
options: {
|
||||
jshintrc: '.jshintrc'
|
||||
}
|
||||
},
|
||||
|
||||
simplemocha: {
|
||||
options: {
|
||||
reporter: 'spec'
|
||||
},
|
||||
full: { src: ['test/test.js'] },
|
||||
short: {
|
||||
options: {
|
||||
reporter: 'dot'
|
||||
},
|
||||
src: ['test/test.js']
|
||||
},
|
||||
build: {
|
||||
options: {
|
||||
reporter: 'tap'
|
||||
},
|
||||
src: ['test/test.js']
|
||||
}
|
||||
},
|
||||
|
||||
exec: {
|
||||
cover: {
|
||||
command: 'STRICT_REQUIRE=1 node node_modules/istanbul/lib/cli.js cover --dir ./test/reports node_modules/mocha/bin/_mocha -- --timeout 30000 -R dot test/test.js'
|
||||
},
|
||||
coveralls: {
|
||||
command: 'node node_modules/.bin/coveralls < test/reports/lcov.info'
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
watch: {
|
||||
files: ['<%= jshint.files %>'],
|
||||
tasks: ['jshint', 'simplemocha:short']
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Default task.
|
||||
grunt.registerTask('test', ['simplemocha:full']);
|
||||
grunt.registerTask('default', ['jshint', 'test']);
|
||||
grunt.registerTask('travis', ['jshint', 'exec:cover', 'exec:coveralls']);
|
||||
};
|
||||
19
packages/bower-json/LICENSE
Normal file
19
packages/bower-json/LICENSE
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2016 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
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
159
packages/bower-json/README.md
Normal file
159
packages/bower-json/README.md
Normal file
@@ -0,0 +1,159 @@
|
||||
# bower-json [](http://travis-ci.org/bower/json) [](https://coveralls.io/github/bower/json?branch=master)
|
||||
|
||||
Read `bower.json` files with semantics, normalisation, defaults and validation.
|
||||
|
||||
Install via [npm](https://www.npmjs.org/package/bower-json): `npm install --save bower-json`
|
||||
|
||||
## Usage
|
||||
|
||||
#### .read(file, options, callback)
|
||||
#### .readSync(file, options)
|
||||
|
||||
Reads `file` and applies normalisation, defaults and validation according to the `bower.json` spec.
|
||||
If the passed `file` does not exist, the callback is called with `error.code` equal to `ENOENT`.
|
||||
If the passed `file` contents are not valid JSON, the callback is called with `error.code` equal to `EMALFORMED`.
|
||||
If the `json` does not comply with the `bower.json` spec, the callback is called with `error.code` equal to `EINVALID`.
|
||||
|
||||
If `file` is a directory, `find()` will be used to search for the json file.
|
||||
The `options` argument is optional and can be omitted. These options will be passed to `parse` method.
|
||||
|
||||
|
||||
```js
|
||||
var bowerJson = require('bower-json');
|
||||
|
||||
// Can also be used by simply calling bowerJson()
|
||||
bowerJson.read('/path/to/bower.json', function (err, json) {
|
||||
if (err) {
|
||||
console.error('There was an error reading the file');
|
||||
console.error(err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('JSON: ', json);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
#### .parse(json, options)
|
||||
|
||||
Parses an object. Useful when you want to apply normalisation and validation directly to an object.
|
||||
If the `json` does not comply with the `bower.json` spec, an error is thrown with `error.code` equal to `EINVALID`.
|
||||
|
||||
The `options` arguments is optional and can be omitted. Available options:
|
||||
|
||||
- validate: Apply validation, defaults to `true`
|
||||
- normalize: Apply normalisation, defaults to `false`
|
||||
- clone: clone, use and return the passed in `json` object instead of using it directly, defaults to `false`
|
||||
|
||||
|
||||
```js
|
||||
var bowerJson = require('bower-json');
|
||||
|
||||
var json = {
|
||||
name: 'my-package',
|
||||
version: '0.0.1'
|
||||
};
|
||||
|
||||
try {
|
||||
bowerJson.parse(json);
|
||||
} catch (err) {
|
||||
console.error('There was an error parsing the object');
|
||||
console.error(err.message);
|
||||
}
|
||||
```
|
||||
|
||||
#### .getIssues(json) - DEPRECATED
|
||||
|
||||
Validates the passed `json` object.
|
||||
|
||||
Returns an object with errors and warnings of this bower.json contents.
|
||||
|
||||
```js
|
||||
var bowerJson = require('bower-json');
|
||||
|
||||
var json = {
|
||||
name: 'myPackage',
|
||||
version: '0.0.1',
|
||||
main: {}
|
||||
};
|
||||
|
||||
var issues = bowerJson.getIssues(json);
|
||||
|
||||
expect(issues).toEqual({
|
||||
errors: ['The "main" field has to be either an Array or a String'],
|
||||
warnings: ['The "name" must be lowercase']
|
||||
});
|
||||
|
||||
#### .validate(json)
|
||||
|
||||
Validates the passed `json` object.
|
||||
|
||||
Throws an error with `error.code` equal to `EINVALID` if it does not comply with the spec.
|
||||
|
||||
```js
|
||||
var bowerJson = require('bower-json');
|
||||
|
||||
var json = {
|
||||
name: 'myPackage',
|
||||
version: '0.0.1'
|
||||
};
|
||||
|
||||
try {
|
||||
bowerJson.validate(json);
|
||||
} catch (err) {
|
||||
console.error('There was an error validating the object');
|
||||
console.error(err.message);
|
||||
}
|
||||
```
|
||||
|
||||
#### .normalize(json)
|
||||
|
||||
```js
|
||||
var bowerJson = require('bower-json');
|
||||
|
||||
var json = {
|
||||
name: 'my-package',
|
||||
version: '0.0.1',
|
||||
main: 'foo.js,bar.js'
|
||||
};
|
||||
|
||||
bowerJson.normalize(json);
|
||||
json.main // ['foo.js', 'bar.js']
|
||||
```
|
||||
|
||||
|
||||
#### .find(folder, callback)
|
||||
#### .findSync(folder)
|
||||
|
||||
Finds the `json` filename inside a folder.
|
||||
Checks if a `bower.json` exists, falling back to `component.json` (deprecated) and `.bower.json`.
|
||||
If no file was found, the callback is called with a `error.code` of `ENOENT`.
|
||||
|
||||
```js
|
||||
var bowerJson = require('bower-json');
|
||||
|
||||
bowerJson.find('/path/to/folder', function (err, filename) {
|
||||
if (err) {
|
||||
console.error('There is no json file in the folder');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Filename: ', filename);
|
||||
|
||||
// Now that we got the filename, we can read its contents
|
||||
bowerJson.read(filename, function (err, json) {
|
||||
if (err) {
|
||||
console.error('There was an error reading the file');
|
||||
console.error(err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('JSON: ', json);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Released under the [MIT License](http://www.opensource.org/licenses/mit-license.php).
|
||||
297
packages/bower-json/lib/json.js
Normal file
297
packages/bower-json/lib/json.js
Normal file
@@ -0,0 +1,297 @@
|
||||
var fs = require('graceful-fs');
|
||||
var path = require('path');
|
||||
var deepExtend = require('deep-extend');
|
||||
var isAsset = require('./util/isAsset');
|
||||
var isComponent = require('./util/isComponent');
|
||||
var createError = require('./util/createError');
|
||||
|
||||
var possibleJsons = ['bower.json', 'component.json', '.bower.json'];
|
||||
|
||||
function read(file, options, callback) {
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
// Check if file is a directory
|
||||
fs.stat(file, function (err, stat) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// It's a directory, so we find the json inside it
|
||||
if (stat.isDirectory()) {
|
||||
return find(file, function (err, file) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
read(file, options, callback);
|
||||
});
|
||||
}
|
||||
|
||||
// Otherwise read it
|
||||
fs.readFile(file, function (err, contents) {
|
||||
var json;
|
||||
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
try {
|
||||
json = JSON.parse(contents.toString());
|
||||
} catch (err) {
|
||||
err.file = path.resolve(file);
|
||||
err.code = 'EMALFORMED';
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// Parse it
|
||||
try {
|
||||
json = parse(json, options);
|
||||
} catch (err) {
|
||||
err.file = path.resolve(file);
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
callback(null, json, file);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function readSync(file, options) {
|
||||
var stat;
|
||||
var filename;
|
||||
var contents;
|
||||
var json;
|
||||
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
try {
|
||||
stat = fs.statSync(file);
|
||||
} catch (err) {
|
||||
return err;
|
||||
}
|
||||
if (stat.isDirectory()) {
|
||||
filename = findSync(file);
|
||||
return readSync(filename);
|
||||
}
|
||||
|
||||
contents = fs.readFileSync(file);
|
||||
|
||||
try {
|
||||
json = JSON.parse(contents.toString());
|
||||
} catch (err) {
|
||||
err.file = path.resolve(file);
|
||||
err.code = 'EMALFORMED';
|
||||
return err;
|
||||
}
|
||||
|
||||
try {
|
||||
json = parse(json, options);
|
||||
} catch (err) {
|
||||
err.file = path.resolve(file);
|
||||
return err;
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
function parse(json, options) {
|
||||
options = deepExtend({
|
||||
normalize: false,
|
||||
validate: true,
|
||||
clone: false
|
||||
}, options || {});
|
||||
|
||||
// Clone
|
||||
if (options.clone) {
|
||||
json = deepExtend({}, json);
|
||||
}
|
||||
|
||||
// Validate
|
||||
if (options.validate) {
|
||||
validate(json);
|
||||
}
|
||||
|
||||
// Normalize
|
||||
if (options.normalize) {
|
||||
normalize(json);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
// This function implements:
|
||||
//
|
||||
// https://github.com/bower/bower.json-spec
|
||||
function getIssues(json) {
|
||||
// For things that shouldn't happen
|
||||
var errors = [];
|
||||
|
||||
// For things that happen but they shoudn't
|
||||
var warnings = [];
|
||||
|
||||
if (!json.name) {
|
||||
errors.push('No "name" property set');
|
||||
} else {
|
||||
if (!/^[a-zA-Z0-9_@][a-zA-Z0-9_@\.\- \/]*$/.test(json.name)) {
|
||||
errors.push('Name must be lowercase, can contain digits, dots, dashes, "@" or spaces');
|
||||
}
|
||||
|
||||
if (json.name.length > 50) {
|
||||
warnings.push('The "name" is too long, the limit is 50 characters');
|
||||
}
|
||||
|
||||
if (!/^[a-z0-9_][a-z0-9_\.\-]*$/.test(json.name)) {
|
||||
warnings.push('The "name" is recommended to be lowercase, can contain digits, dots, dashes');
|
||||
}
|
||||
|
||||
if (/^[\.-]/.test(json.name)) {
|
||||
warnings.push('The "name" cannot start with dot or dash');
|
||||
}
|
||||
|
||||
if (/[\.-]$/.test(json.name)) {
|
||||
warnings.push('The "name" cannot end with dot or dash');
|
||||
}
|
||||
}
|
||||
|
||||
if (json.description && json.description.length > 140) {
|
||||
warnings.push('The "description" is too long, the limit is 140 characters');
|
||||
}
|
||||
|
||||
if (json.main !== undefined) {
|
||||
var main = json.main;
|
||||
if (typeof main === 'string') {
|
||||
main = [main];
|
||||
}
|
||||
if (!(main instanceof Array)) {
|
||||
errors.push('The "main" field has to be either an Array or a String');
|
||||
} else {
|
||||
var ext2files = {};
|
||||
main.forEach(function (filename) {
|
||||
if (typeof filename !== 'string') {
|
||||
errors.push('The "main" Array has to contain only Strings');
|
||||
}
|
||||
if (/[*]/.test(filename)) {
|
||||
warnings.push('The "main" field cannot contain globs (example: "*.js")');
|
||||
}
|
||||
if (/[.]min[.][^/]+$/.test(filename)) {
|
||||
warnings.push('The "main" field cannot contain minified files');
|
||||
}
|
||||
if (isAsset(filename)) {
|
||||
warnings.push('The "main" field cannot contain font, image, audio, or video files');
|
||||
}
|
||||
var ext = path.extname(filename);
|
||||
if (ext.length >= 2) {
|
||||
var files = ext2files[ext];
|
||||
if (!files) {
|
||||
files = ext2files[ext] = [];
|
||||
}
|
||||
files.push(filename);
|
||||
}
|
||||
});
|
||||
Object.keys(ext2files).forEach(function (ext) {
|
||||
var files = ext2files[ext];
|
||||
if (files.length > 1) {
|
||||
warnings.push('The "main" field has to contain only 1 file per filetype; found multiple ' + ext + ' files: ' + JSON.stringify(files));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
errors: errors,
|
||||
warnings: warnings
|
||||
};
|
||||
}
|
||||
|
||||
// For backward compatibility, it throws first error
|
||||
function validate(json) {
|
||||
var issues = getIssues(json);
|
||||
|
||||
if (issues.errors && issues.errors.length > 0) {
|
||||
throw createError(issues.errors[0], 'EINVALID');
|
||||
}
|
||||
}
|
||||
|
||||
function normalize(json) {
|
||||
if (typeof json.main === 'string') {
|
||||
json.main = [json.main];
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
function find(folder, files, callback) {
|
||||
var err;
|
||||
var file;
|
||||
|
||||
if (typeof files === 'function') {
|
||||
callback = files;
|
||||
files = possibleJsons;
|
||||
}
|
||||
|
||||
if (!files.length) {
|
||||
err = createError('None of ' + possibleJsons.join(', ') + ' were found in ' + folder, 'ENOENT');
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
file = path.resolve(path.join(folder, files[0]));
|
||||
fs.exists(file, function (exists) {
|
||||
if (!exists) {
|
||||
return find(folder, files.slice(1), callback);
|
||||
}
|
||||
|
||||
if (files[0] !== 'component.json') {
|
||||
return callback(null, file);
|
||||
}
|
||||
|
||||
// If the file is component.json, check it it's a component(1) file
|
||||
// If it is, we ignore it and keep searching
|
||||
isComponent(file, function (is) {
|
||||
if (is) {
|
||||
return find(folder, files.slice(1), callback);
|
||||
}
|
||||
|
||||
callback(null, file);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function findSync(folder, files) {
|
||||
var file;
|
||||
var exists;
|
||||
|
||||
if (files === undefined) {
|
||||
files = possibleJsons;
|
||||
}
|
||||
|
||||
if (!files.length) {
|
||||
return createError('None of ' + possibleJsons.join(', ') + ' were found in ' + folder, 'ENOENT');
|
||||
}
|
||||
|
||||
file = path.resolve(path.join(folder, files[0]));
|
||||
try{
|
||||
exists = fs.statSync(file);
|
||||
}
|
||||
catch (err) {
|
||||
exists = false;
|
||||
}
|
||||
if (exists && exists.isFile()) {
|
||||
return file;
|
||||
} else {
|
||||
return findSync(folder, files.slice(1));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = read;
|
||||
module.exports.read = read;
|
||||
module.exports.readSync = readSync;
|
||||
module.exports.parse = parse;
|
||||
module.exports.getIssues = getIssues;
|
||||
module.exports.validate = validate;
|
||||
module.exports.normalize = normalize;
|
||||
module.exports.find = find;
|
||||
module.exports.findSync = findSync;
|
||||
8
packages/bower-json/lib/util/createError.js
Normal file
8
packages/bower-json/lib/util/createError.js
Normal file
@@ -0,0 +1,8 @@
|
||||
function createError(msg, code) {
|
||||
var err = new Error(msg);
|
||||
err.code = code;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
module.exports = createError;
|
||||
12
packages/bower-json/lib/util/isAsset.js
Normal file
12
packages/bower-json/lib/util/isAsset.js
Normal file
@@ -0,0 +1,12 @@
|
||||
var extName = require('ext-name');
|
||||
|
||||
function isAsset(filename) {
|
||||
var info = extName(filename);
|
||||
|
||||
return info && info.mime && (
|
||||
/^((image)|(audio)|(video)|(font))\//.test(info.mime) ||
|
||||
/application\/((x[-]font[-])|(font[-]woff(\d?))|(vnd[.]ms[-]fontobject))/.test(info.mime)
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = isAsset;
|
||||
41
packages/bower-json/lib/util/isComponent.js
Normal file
41
packages/bower-json/lib/util/isComponent.js
Normal file
@@ -0,0 +1,41 @@
|
||||
var fs = require('graceful-fs');
|
||||
var intersect = require('intersect');
|
||||
|
||||
// Function to check if a file is a component(1) file
|
||||
function isComponent(file, callback) {
|
||||
fs.readFile(file, function (err, contents) {
|
||||
var json;
|
||||
var keys;
|
||||
var common;
|
||||
|
||||
// If an error occurs while reading the file, we ignore it
|
||||
if (err) {
|
||||
return callback(false);
|
||||
}
|
||||
|
||||
try {
|
||||
json = JSON.parse(contents.toString());
|
||||
} catch (err) {
|
||||
return callback(false);
|
||||
}
|
||||
|
||||
// Attempt to find specific things from the component(1) spec
|
||||
// Note that we don't parse the dependencies property because at any point
|
||||
// we can allow / to specify directories
|
||||
// Bellow only some clearly not ambiguous properties are checked
|
||||
keys = Object.keys(json);
|
||||
common = intersect(keys, [
|
||||
'repo',
|
||||
'development',
|
||||
'local',
|
||||
'remotes',
|
||||
'paths',
|
||||
'demo'
|
||||
]);
|
||||
|
||||
// If none were found, than it's a valid component.json bower file
|
||||
callback(common.length ? true : false);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = isComponent;
|
||||
40
packages/bower-json/package.json
Normal file
40
packages/bower-json/package.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "bower-json",
|
||||
"version": "0.8.1",
|
||||
"description": "Read bower.json files with semantics, normalisation, defaults and validation",
|
||||
"author": "Twitter",
|
||||
"license": "MIT",
|
||||
"repository": "bower/json",
|
||||
"main": "lib/json",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"deep-extend": "^0.4.0",
|
||||
"ext-name": "^3.0.0",
|
||||
"graceful-fs": "^4.1.3",
|
||||
"intersect": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"coveralls": "^2.11.2",
|
||||
"expect.js": "^0.3.1",
|
||||
"grunt": "^0.4.4",
|
||||
"grunt-cli": "^0.1.13",
|
||||
"grunt-contrib-jshint": "^0.11.2",
|
||||
"grunt-contrib-watch": "^0.6.1",
|
||||
"grunt-coveralls": "^1.0.0",
|
||||
"grunt-exec": "^0.4.6",
|
||||
"grunt-simple-mocha": "^0.4.0",
|
||||
"istanbul": "^0.3.5",
|
||||
"load-grunt-tasks": "^3.3.0",
|
||||
"mocha": "*",
|
||||
"request": "^2.64.0",
|
||||
"underscore.string": "^3.0.3"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "grunt test"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
5
packages/bower-json/test/pkg-bower-json/bower.json
Normal file
5
packages/bower-json/test/pkg-bower-json/bower.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "some-pkg",
|
||||
"version": "0.0.0",
|
||||
"main": "foo.js"
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "route",
|
||||
"repo": "apily/route",
|
||||
"version": "0.0.1",
|
||||
"description": "Route component",
|
||||
"keywords": ["router", "route"],
|
||||
"scripts": ["index.js"],
|
||||
"dependencies": {},
|
||||
"development": {
|
||||
"component/assert": "*",
|
||||
"visionmedia/mocha": "*"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "some-pkg",
|
||||
"version": "0.0.0"
|
||||
}
|
||||
5
packages/bower-json/test/pkg-dot-bower-json/.bower.json
Normal file
5
packages/bower-json/test/pkg-dot-bower-json/.bower.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "some-installed-pkg",
|
||||
"version": "0.0.1",
|
||||
"main": "bar.js"
|
||||
}
|
||||
497
packages/bower-json/test/test.js
Normal file
497
packages/bower-json/test/test.js
Normal file
@@ -0,0 +1,497 @@
|
||||
var path = require('path');
|
||||
var expect = require('expect.js');
|
||||
var _s = require('underscore.string');
|
||||
var bowerJson = require('../lib/json');
|
||||
var request = require('request');
|
||||
|
||||
describe('.find', function () {
|
||||
it('should find the bower.json file', function (done) {
|
||||
bowerJson.find(__dirname + '/pkg-bower-json', function (err, file) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
expect(file).to.equal(path.resolve(__dirname + '/pkg-bower-json/bower.json'));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fallback to the component.json file', function (done) {
|
||||
bowerJson.find(__dirname + '/pkg-component-json', function (err, file) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
expect(file).to.equal(path.resolve(__dirname + '/pkg-component-json/component.json'));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not fallback to the component.json file if it\'s a component(1) file', function (done) {
|
||||
bowerJson.find(__dirname + '/pkg-component(1)-json', function (err) {
|
||||
expect(err).to.be.an(Error);
|
||||
expect(err.code).to.equal('ENOENT');
|
||||
expect(err.message).to.equal('None of bower.json, component.json, .bower.json were found in ' + __dirname + '/pkg-component(1)-json');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fallback to the .bower.json file', function (done) {
|
||||
bowerJson.find(__dirname + '/pkg-dot-bower-json', function (err, file) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
expect(file).to.equal(path.resolve(__dirname + '/pkg-dot-bower-json/.bower.json'));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should error if no component.json / bower.json / .bower.json is found', function (done) {
|
||||
bowerJson.find(__dirname, function (err) {
|
||||
expect(err).to.be.an(Error);
|
||||
expect(err.code).to.equal('ENOENT');
|
||||
expect(err.message).to.equal('None of bower.json, component.json, .bower.json were found in ' + __dirname);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.findSync', function () {
|
||||
|
||||
it('should find the bower.json file', function (done) {
|
||||
var file = bowerJson.findSync(__dirname + '/pkg-bower-json');
|
||||
|
||||
expect(file).to.equal(path.resolve(__dirname + '/pkg-bower-json/bower.json'));
|
||||
done();
|
||||
});
|
||||
|
||||
it('should fallback to the component.json file', function (done) {
|
||||
var file = bowerJson.findSync(__dirname + '/pkg-component-json');
|
||||
|
||||
expect(file).to.equal(path.resolve(__dirname + '/pkg-component-json/component.json'));
|
||||
done();
|
||||
});
|
||||
|
||||
it('should fallback to the .bower.json file', function (done) {
|
||||
var file = bowerJson.findSync(__dirname + '/pkg-dot-bower-json');
|
||||
|
||||
expect(file).to.equal(path.resolve(__dirname + '/pkg-dot-bower-json/.bower.json'));
|
||||
done();
|
||||
});
|
||||
|
||||
it('should error if no component.json / bower.json / .bower.json is found', function (done) {
|
||||
var err = bowerJson.findSync(__dirname);
|
||||
expect(err).to.be.an(Error);
|
||||
expect(err.code).to.equal('ENOENT');
|
||||
expect(err.message).to.equal('None of bower.json, component.json, .bower.json were found in ' + __dirname);
|
||||
done();
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
describe('.read', function () {
|
||||
it('should give error if file does not exists', function (done) {
|
||||
bowerJson.read(__dirname + '/willneverexist', function (err) {
|
||||
expect(err).to.be.an(Error);
|
||||
expect(err.code).to.equal('ENOENT');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should give error if when reading an invalid json', function (done) {
|
||||
bowerJson.read(__dirname + '/pkg-bower-json-malformed/bower.json', function (err) {
|
||||
expect(err).to.be.an(Error);
|
||||
expect(err.code).to.equal('EMALFORMED');
|
||||
expect(err.file).to.equal(path.resolve(__dirname + '/pkg-bower-json-malformed/bower.json'));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should read the file and give an object', function (done) {
|
||||
bowerJson.read(__dirname + '/pkg-bower-json/bower.json', function (err, json) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
expect(json).to.be.an('object');
|
||||
expect(json.name).to.equal('some-pkg');
|
||||
expect(json.version).to.equal('0.0.0');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should give the json file that was read', function (done) {
|
||||
bowerJson.read(__dirname + '/pkg-bower-json', function (err, json, file) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
|
||||
expect(file).to.equal(__dirname + '/pkg-bower-json/bower.json');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should find for a json file if a directory is given', function (done) {
|
||||
bowerJson.read(__dirname + '/pkg-component-json', function (err, json, file) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
expect(json).to.be.an('object');
|
||||
expect(json.name).to.equal('some-pkg');
|
||||
expect(json.version).to.equal('0.0.0');
|
||||
expect(file).to.equal(path.resolve(__dirname + '/pkg-component-json/component.json'));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should validate the returned object unless validate is false', function (done) {
|
||||
bowerJson.read(__dirname + '/pkg-bower-json-invalid/bower.json', function (err) {
|
||||
expect(err).to.be.an(Error);
|
||||
expect(err.message).to.contain('name');
|
||||
expect(err.file).to.equal(path.resolve(__dirname + '/pkg-bower-json-invalid/bower.json'));
|
||||
|
||||
bowerJson.read(__dirname + '/pkg-bower-json-invalid/bower.json', { validate: false }, function (err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should normalize the returned object if normalize is true', function (done) {
|
||||
bowerJson.read(__dirname + '/pkg-bower-json/bower.json', function (err, json) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
expect(json.main).to.equal('foo.js');
|
||||
|
||||
bowerJson.read(__dirname + '/pkg-bower-json/bower.json', { normalize: true }, function (err, json) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
expect(json.main).to.eql(['foo.js']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.readSync', function () {
|
||||
it('should give error if file does not exists', function (done) {
|
||||
var err = bowerJson.readSync(__dirname + '/willneverexist');
|
||||
expect(err).to.be.an(Error);
|
||||
expect(err.code).to.equal('ENOENT');
|
||||
done();
|
||||
});
|
||||
|
||||
it('should give error if when reading an invalid json', function (done) {
|
||||
var err = bowerJson.readSync(__dirname + '/pkg-bower-json-malformed/bower.json');
|
||||
expect(err).to.be.an(Error);
|
||||
expect(err.code).to.equal('EMALFORMED');
|
||||
expect(err.file).to.equal(path.resolve(__dirname + '/pkg-bower-json-malformed/bower.json'));
|
||||
done();
|
||||
});
|
||||
|
||||
it('should read the file and give an object', function (done) {
|
||||
var json = bowerJson.readSync(__dirname + '/pkg-bower-json/bower.json');
|
||||
|
||||
expect(json).to.be.an('object');
|
||||
expect(json.name).to.equal('some-pkg');
|
||||
expect(json.version).to.equal('0.0.0');
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should find for a json file if a directory is given', function (done) {
|
||||
var json = bowerJson.readSync(__dirname + '/pkg-component-json');
|
||||
|
||||
expect(json).to.be.an('object');
|
||||
expect(json.name).to.equal('some-pkg');
|
||||
expect(json.version).to.equal('0.0.0');
|
||||
done();
|
||||
});
|
||||
|
||||
it('should validate the returned object unless validate is false', function (done) {
|
||||
var err = bowerJson.readSync(__dirname + '/pkg-bower-json-invalid/bower.json');
|
||||
expect(err).to.be.an(Error);
|
||||
expect(err.message).to.contain('name');
|
||||
expect(err.file).to.equal(path.resolve(__dirname + '/pkg-bower-json-invalid/bower.json'));
|
||||
|
||||
err = bowerJson.readSync(__dirname + '/pkg-bower-json-invalid/bower.json', { validate: false });
|
||||
expect(err).to.not.be.an(Error);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should normalize the returned object if normalize is true', function (done) {
|
||||
var json = bowerJson.readSync(__dirname + '/pkg-bower-json/bower.json');
|
||||
expect(json.main).to.equal('foo.js');
|
||||
|
||||
json = bowerJson.readSync(__dirname + '/pkg-bower-json/bower.json', { normalize: true });
|
||||
|
||||
expect(json.main).to.eql(['foo.js']);
|
||||
done();
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
describe('.parse', function () {
|
||||
it('should return the same object, unless clone is true', function () {
|
||||
var json = { name: 'foo' };
|
||||
|
||||
expect(bowerJson.parse(json)).to.equal(json);
|
||||
expect(bowerJson.parse(json, { clone: true })).to.not.equal(json);
|
||||
expect(bowerJson.parse(json, { clone: true })).to.eql(json);
|
||||
});
|
||||
|
||||
it('should validate the passed object, unless validate is false', function () {
|
||||
expect(function () {
|
||||
bowerJson.parse({});
|
||||
}).to.throwException(/name/);
|
||||
|
||||
expect(function () {
|
||||
bowerJson.parse({}, { validate: false });
|
||||
}).to.not.throwException();
|
||||
});
|
||||
|
||||
it('should not normalize the passed object unless normalize is true', function () {
|
||||
var json = { name: 'foo', main: 'foo.js' };
|
||||
|
||||
bowerJson.parse(json);
|
||||
expect(json.main).to.eql('foo.js');
|
||||
|
||||
bowerJson.parse(json, { normalize: true });
|
||||
expect(json.main).to.eql(['foo.js']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getIssues', function () {
|
||||
it('should print no errors even for weird package names', function () {
|
||||
var json = { name: '@gruNt/my dependency' };
|
||||
|
||||
expect(bowerJson.getIssues(json).errors).to.be.empty();
|
||||
});
|
||||
|
||||
it('should validate the name length', function () {
|
||||
var json = { name: 'a_123456789_123456789_123456789_123456789_123456789_z' };
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "name" is too long, the limit is 50 characters'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate the name is lowercase', function () {
|
||||
var json = { name: 'gruNt' };
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "name" is recommended to be lowercase, can contain digits, dots, dashes'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate the name starts with lowercase', function () {
|
||||
var json = { name: '-runt' };
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "name" cannot start with dot or dash'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate the name starts with lowercase', function () {
|
||||
var json = { name: '.grunt' };
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "name" cannot start with dot or dash'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate the name ends with lowercase', function () {
|
||||
var json = { name: 'grun-' };
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "name" cannot end with dot or dash'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate the name ends with lowercase', function () {
|
||||
var json = { name: 'grun.' };
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "name" cannot end with dot or dash'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate the name is valid', function () {
|
||||
var json = { name: 'gru.n-t' };
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.eql([]);
|
||||
});
|
||||
|
||||
it('should validate the description length', function () {
|
||||
var json = {
|
||||
name: 'foo',
|
||||
description: _s.repeat('æ', 141)
|
||||
};
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "description" is too long, the limit is 140 characters'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate the description is valid', function () {
|
||||
var json = {
|
||||
name: 'foo',
|
||||
description: _s.repeat('æ', 140)
|
||||
};
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.eql([]);
|
||||
});
|
||||
|
||||
it('should validate that main does not contain globs', function () {
|
||||
var json = {
|
||||
name: 'foo',
|
||||
main: ['js/*.js']
|
||||
};
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "main" field cannot contain globs (example: "*.js")'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate that main does not contain minified files', function () {
|
||||
var json = {
|
||||
name: 'foo',
|
||||
main: ['foo.min.css']
|
||||
};
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "main" field cannot contain minified files'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate that main does not contain fonts', function () {
|
||||
var json = {
|
||||
name: 'foo',
|
||||
main: ['foo.woff']
|
||||
};
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "main" field cannot contain font, image, audio, or video files'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate that main does not contain images', function () {
|
||||
var json = {
|
||||
name: 'foo',
|
||||
main: ['foo.png']
|
||||
};
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "main" field cannot contain font, image, audio, or video files'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate that main does not contain multiple files of the same filetype', function () {
|
||||
var json = {
|
||||
name: 'foo',
|
||||
main: ['foo.js', 'bar.js']
|
||||
};
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "main" field has to contain only 1 file per filetype; found multiple .js files: ["foo.js","bar.js"]'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.validate', function () {
|
||||
it('should validate the name property', function () {
|
||||
expect(function () {
|
||||
bowerJson.validate({});
|
||||
}).to.throwException(/name/);
|
||||
});
|
||||
|
||||
it('should validate the type of main', function () {
|
||||
var json = {
|
||||
name: 'foo',
|
||||
main: {}
|
||||
};
|
||||
expect(function () {
|
||||
bowerJson.validate(json);
|
||||
}).to.throwException();
|
||||
});
|
||||
it('should validate the type of items of an Array main', function () {
|
||||
var json = {
|
||||
name: 'foo',
|
||||
main: [{}]
|
||||
};
|
||||
expect(function () {
|
||||
bowerJson.validate(json);
|
||||
}).to.throwException();
|
||||
});
|
||||
});
|
||||
|
||||
describe('.normalize', function () {
|
||||
it('should normalize the main property', function () {
|
||||
var json = { name: 'foo', main: 'foo.js' };
|
||||
|
||||
bowerJson.normalize(json);
|
||||
expect(json.main).to.eql(['foo.js']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('packages from bower registry', function () {
|
||||
|
||||
var packageList,
|
||||
packageListUrl = 'http://bower.herokuapp.com/packages';
|
||||
|
||||
this.timeout(60000);
|
||||
|
||||
it('can be downloaded from online source ' + packageListUrl, function(done) {
|
||||
request({
|
||||
url: packageListUrl,
|
||||
json: true
|
||||
}, function(error, response, body) {
|
||||
|
||||
if(error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
expect(body).to.be.an('array');
|
||||
expect(body).to.not.be.empty();
|
||||
packageList = body;
|
||||
|
||||
done();
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
it('should validate each listed package', function (done) {
|
||||
|
||||
expect(packageList).to.be.an('array');
|
||||
|
||||
var invalidPackageCount = 0;
|
||||
|
||||
packageList.forEach(function(package) {
|
||||
try {
|
||||
bowerJson.validate(package);
|
||||
} catch(e) {
|
||||
invalidPackageCount++;
|
||||
console.error('validation of "' + package.name + '" failed: ' + e.message);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if(invalidPackageCount) {
|
||||
throw new Error(invalidPackageCount + '/' + packageList.length + ' package names do not validate');
|
||||
}
|
||||
|
||||
done();
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
12
packages/bower-logger/.editorconfig
Normal file
12
packages/bower-logger/.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
2
packages/bower-logger/.gitignore
vendored
Normal file
2
packages/bower-logger/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/node_modules
|
||||
/npm-debug.*
|
||||
@@ -1,20 +1,24 @@
|
||||
{
|
||||
"predef": [
|
||||
"console",
|
||||
"module",
|
||||
"define",
|
||||
"self"
|
||||
"describe",
|
||||
"it",
|
||||
"after",
|
||||
"afterEach",
|
||||
"before",
|
||||
"beforeEach"
|
||||
],
|
||||
|
||||
"browser": true,
|
||||
"indent": 4,
|
||||
"node": true,
|
||||
"devel": true,
|
||||
|
||||
"bitwise": false,
|
||||
"curly": false,
|
||||
"eqeqeq": false,
|
||||
"eqeqeq": true,
|
||||
"forin": false,
|
||||
"immed": true,
|
||||
"latedef": true,
|
||||
"latedef": false,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"noempty": false,
|
||||
@@ -22,11 +26,14 @@
|
||||
"plusplus": false,
|
||||
"regexp": false,
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
"quotmark": "single",
|
||||
"strict": false,
|
||||
"trailing": true,
|
||||
"camelcase": true,
|
||||
|
||||
"asi": false,
|
||||
"boss": false,
|
||||
"boss": true,
|
||||
"debug": false,
|
||||
"eqnull": true,
|
||||
"es5": false,
|
||||
@@ -37,9 +44,9 @@
|
||||
"globalstrict": false,
|
||||
"iterator": false,
|
||||
"lastsemic": false,
|
||||
"laxbreak": false,
|
||||
"laxbreak": true,
|
||||
"laxcomma": false,
|
||||
"loopfunc": false,
|
||||
"loopfunc": true,
|
||||
"multistr": false,
|
||||
"onecase": true,
|
||||
"regexdash": false,
|
||||
@@ -47,12 +54,9 @@
|
||||
"smarttabs": false,
|
||||
"shadow": false,
|
||||
"sub": false,
|
||||
"supernew": false,
|
||||
"supernew": true,
|
||||
"validthis": false,
|
||||
|
||||
"nomen": false,
|
||||
"onevar": false,
|
||||
"white": true,
|
||||
|
||||
"mootools": true
|
||||
"white": true
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user