mirror of
https://github.com/balena-io/balena-cli.git
synced 2025-06-24 18:45:07 +00:00
Compare commits
583 Commits
Author | SHA1 | Date | |
---|---|---|---|
6beb6ff44e | |||
c2cd10f6a7 | |||
4d3769def8 | |||
42bfb3b0cc | |||
d9c2717fe4 | |||
8e93577f90 | |||
5b7e1b656e | |||
4a05ce3f53 | |||
61574a8522 | |||
9400d4027a | |||
b5ec49dda1 | |||
1c66efb4fa | |||
68fca3d030 | |||
325304aebe | |||
a50cf5b198 | |||
1b7aeeafc1 | |||
6e3c2ef168 | |||
d9b4753690 | |||
ca40d7ca65 | |||
4aa8362be9 | |||
d68b61a913 | |||
20969ef249 | |||
469d35fcc1 | |||
e9b8c38eeb | |||
d4c44bf350 | |||
2d8cf7c479 | |||
ca6e715bfa | |||
3a839c947e | |||
9896de3c34 | |||
03d7520de2 | |||
4fc8b130f8 | |||
c5692f8b13 | |||
85561b5d50 | |||
88c0833ae2 | |||
7df78a0c9e | |||
30663b0301 | |||
4ffba0ed56 | |||
a522c70f92 | |||
f295837840 | |||
091ae8eb03 | |||
6405c6bb6f | |||
797122ce37 | |||
f81db5a775 | |||
0f84aea47d | |||
84ed20d3ec | |||
9870727e36 | |||
db3de2137b | |||
92c6af91ca | |||
d578f62dca | |||
d4527220c3 | |||
d5797124f5 | |||
654c3c627d | |||
3953b00e77 | |||
13f33da280 | |||
356d2ef6b2 | |||
36a8179e0c | |||
aedb9c732f | |||
c3bd433532 | |||
d72750de65 | |||
ccd8e73c4e | |||
6c677fe8cd | |||
eaa1a798c5 | |||
da1b446b3b | |||
18b4509fef | |||
35bba04b16 | |||
dd382158dd | |||
40f015de93 | |||
bee523828a | |||
474635401a | |||
a8c30bb395 | |||
9e00fdaf31 | |||
5f83c870ed | |||
5d89533afc | |||
a346c3f043 | |||
de0649c980 | |||
b7300deab7 | |||
70b2ba3ab9 | |||
8cbf792786 | |||
bca9a7f51f | |||
4bf079377b | |||
ebefd816b6 | |||
fb1ef0df63 | |||
4489b1daa0 | |||
96f0b5fbd6 | |||
f6897ad41f | |||
69e031da28 | |||
c61a7ef94a | |||
65bc22c02c | |||
1d55ea4dcf | |||
add30b33a1 | |||
999120e711 | |||
67ce0f7f2d | |||
4645ad06bc | |||
612437ae58 | |||
35a821b904 | |||
e4359834d6 | |||
ef7e39450c | |||
c3a5998d5c | |||
78ab2af8ba | |||
11354de596 | |||
86cac606e4 | |||
9b052c9aa5 | |||
8d709aea7d | |||
70ea8dd1a3 | |||
11c0d2a847 | |||
301b8a6ba3 | |||
acb0aa445c | |||
a90d578c85 | |||
d859228aa9 | |||
2be105d329 | |||
6d48fcfd6f | |||
551a315432 | |||
351dfdb892 | |||
dc6727fbf1 | |||
af88e48c39 | |||
9cfce68489 | |||
8393ff647c | |||
63122a5f51 | |||
0ad4598575 | |||
b71c28cec0 | |||
b0ab23dad4 | |||
de9297c351 | |||
26e3cb7957 | |||
bb78a3ca09 | |||
210680c9c9 | |||
6810eb31fd | |||
f5b6df483d | |||
7d0da7adc0 | |||
785f2b4ef5 | |||
b668a8c7d0 | |||
2e247faae4 | |||
3997a61b78 | |||
8ef27f0525 | |||
20855be968 | |||
800d13e3cd | |||
abc8399260 | |||
9ad2ba1131 | |||
0f8d6a98e3 | |||
81af8c74b4 | |||
16ab74294f | |||
f8bcc9d1ea | |||
9a89e3c3ca | |||
359c37f259 | |||
1ba5697986 | |||
647ed1e7aa | |||
b881e23c1c | |||
ae8621dc81 | |||
e08c3752f9 | |||
65646d1206 | |||
e42d3e8c4c | |||
a4642f6184 | |||
038c871911 | |||
f52dd2976f | |||
d079a57da4 | |||
43697a3476 | |||
b893bd1e39 | |||
c3b5a768e1 | |||
111ea44b40 | |||
d1b25c17b6 | |||
ba318f2939 | |||
7ac0291c53 | |||
f64676ab98 | |||
d522cbe1ca | |||
4fc7a4e436 | |||
79f2b4f0d5 | |||
880a7b1e25 | |||
89c5bb3080 | |||
a71fb8ca4d | |||
3b35aed3bf | |||
0bc3b9460f | |||
5509a3e9fd | |||
f84d0d0980 | |||
c866f6e46c | |||
3192f9d2ef | |||
de83a06db8 | |||
9260c8dce2 | |||
bea5f22732 | |||
363f12f81b | |||
1cbd33679f | |||
e962371b59 | |||
77a3d4d6f6 | |||
fc5fe6cf68 | |||
f921488e8c | |||
8fe08642f5 | |||
822632718f | |||
f66cd00646 | |||
5498e45a35 | |||
38479b3191 | |||
965fd8fc19 | |||
7a4f551a47 | |||
303fd74012 | |||
6a7d1b0c70 | |||
c1e6a28640 | |||
ec72f93480 | |||
8913fb515b | |||
6f91ff898f | |||
aa949103f6 | |||
14bd4ad74e | |||
f2507daa09 | |||
ff81c1e514 | |||
7ce92b47a0 | |||
bde5cc65da | |||
ec9347c3a4 | |||
ceb8dada1d | |||
f4186acf80 | |||
05ce54eac1 | |||
d28ecf3230 | |||
8562f723c5 | |||
f6d2043747 | |||
485818f3b5 | |||
ec28bd9c9e | |||
ad68dcf692 | |||
0b7e2a2c8c | |||
b6ebd0631a | |||
7ace4bdfa6 | |||
1cfbd4197d | |||
b2425d2c0e | |||
0ba914236a | |||
71ee0a6cf7 | |||
4326ad4d9c | |||
055bac6ff4 | |||
58713dc291 | |||
adf4aef517 | |||
a17bb2cc09 | |||
48d620f7cd | |||
fa7b104762 | |||
faf2fa167f | |||
ad1e68427c | |||
e9147f0f6f | |||
cddf630907 | |||
494a286cae | |||
e5e871ddcd | |||
5a3166e3de | |||
3149464c7a | |||
97d9b7816f | |||
ec77437080 | |||
d65882639a | |||
f8470287c1 | |||
3cc41ed62a | |||
445e37ccaf | |||
ed6427c541 | |||
90be01b05d | |||
1124293b9a | |||
0e804fdfd8 | |||
0443a35f2b | |||
3a148217e0 | |||
79d1892b66 | |||
0e06ac464f | |||
5ae83d8337 | |||
8694ee2c59 | |||
8234f7675a | |||
15cb0c4889 | |||
a3ebd9827f | |||
30d84f015a | |||
686414b03d | |||
6377618c12 | |||
f17e9c97b8 | |||
21fcdfaff6 | |||
4072edcced | |||
d704c10197 | |||
dea2a7f055 | |||
7e6eb4b9e4 | |||
61474fba5c | |||
42256384be | |||
e25f232fe5 | |||
f6d8f12ba2 | |||
d2b9e6fd8c | |||
cf7effacc0 | |||
1eb7aba293 | |||
21e916679c | |||
d574743c21 | |||
d8a2b82662 | |||
f4ebd890df | |||
b0be5de83a | |||
ba21ddd010 | |||
eecd7a0fd8 | |||
eb4c2f62a7 | |||
dc1e5e6512 | |||
adc0b183cd | |||
828b4f73d1 | |||
82a0761f49 | |||
904b9f07fb | |||
3c0acaa7da | |||
64c8420c9d | |||
26e3dc1aa7 | |||
3bc22a7b7c | |||
7e5b2695fe | |||
79afa79fd9 | |||
cdaaddb826 | |||
ec5f6a7cd8 | |||
72f34031a9 | |||
dc257b5cab | |||
4bdcd3d2ee | |||
b0650530cc | |||
454669ada2 | |||
a65975596e | |||
91f878cfc0 | |||
8c3e832cdc | |||
a5c670902d | |||
14be1d5f9f | |||
41d6d5c670 | |||
a090e6c21d | |||
d78c1ffa47 | |||
5808d20d88 | |||
7f4065e3da | |||
07daa51051 | |||
d10d4ce185 | |||
7f763e7881 | |||
5de0f66d7a | |||
354921ca92 | |||
fb28cc7d2f | |||
7cf89a9bf6 | |||
a3cbc549d8 | |||
1c48328347 | |||
9b69fe3c3c | |||
dc513a08f6 | |||
fcc44949a7 | |||
006764af66 | |||
b879d3f9ea | |||
7f4863da86 | |||
ba6f50d171 | |||
a803d4f646 | |||
85d940df66 | |||
6f9535ca34 | |||
019e2ac357 | |||
433916e18a | |||
f19588032f | |||
0595452c3d | |||
d6305df48e | |||
f7084580b2 | |||
3dd5f5858a | |||
02a06e1e7c | |||
50daf8ef73 | |||
fd5a34a1c4 | |||
51fda13684 | |||
a698b25fda | |||
89bd861d8e | |||
e5b7aae4ae | |||
031168ceed | |||
09a5788902 | |||
713664d103 | |||
f63391acf9 | |||
79ee4302ec | |||
9adda22921 | |||
25311f2a18 | |||
70c060b124 | |||
7a8a3c851b | |||
1096b2d212 | |||
ee286c5690 | |||
1da1d2e6fc | |||
64be9f936d | |||
30f24333c0 | |||
30f6a78282 | |||
8c9a0e0ff1 | |||
8268bbf700 | |||
e712e2f266 | |||
0807b6a2d9 | |||
83382cc8f7 | |||
8401aaeae2 | |||
abf5740950 | |||
606777508d | |||
e9ec6c67b2 | |||
69566f7fc3 | |||
6e4b299c7d | |||
ef35ebf79d | |||
1bc78edf71 | |||
d5204a09f7 | |||
4647aa70c0 | |||
2e8ec3ac64 | |||
25c6246e9f | |||
5408938007 | |||
50cb04b6f7 | |||
09fe4b11ad | |||
4157f21e06 | |||
4900230881 | |||
e60c0605e5 | |||
085781fa18 | |||
08ad8bd5d7 | |||
3d36e5f5d3 | |||
57319f26a6 | |||
11033683fd | |||
e5166c6c8e | |||
5c96663d1e | |||
ffb48c8669 | |||
12145a2393 | |||
f379866c1c | |||
dc030f4cd1 | |||
b726a2d778 | |||
a715ec9dc1 | |||
d24b871964 | |||
bd0c4e6034 | |||
95637e5608 | |||
93b394ed76 | |||
b515e427ff | |||
26b1acf5ef | |||
f31eb7c2b5 | |||
d423a6ea24 | |||
4211333e4e | |||
f220e380a7 | |||
9564b4e478 | |||
e2125b8ce9 | |||
0bb0e6ea4b | |||
cf512cc01b | |||
fe3e68c3af | |||
0bbfbe36c7 | |||
d6ae689593 | |||
5b5d1be52f | |||
cb808869dd | |||
64d83dccfb | |||
122253bb25 | |||
1d53db2854 | |||
30dc5ea1ea | |||
58c7ff1f1b | |||
57b9d634be | |||
6fb25dea88 | |||
10478e389a | |||
46fa4ee2a2 | |||
a7cefe44bf | |||
3d03585318 | |||
076c3428ee | |||
9d4ac46985 | |||
24edb867fa | |||
e926ac46c9 | |||
9ffd657dbb | |||
aa3cb39551 | |||
0acbdac66f | |||
5619bdbb67 | |||
381e63bfc9 | |||
e779347ff2 | |||
8fa906dd48 | |||
7e5ecd634d | |||
29cf4c1e89 | |||
73736abdea | |||
9ab411bade | |||
ef33156de7 | |||
6d8fd6e547 | |||
bab90a8bf2 | |||
43f0288c6c | |||
47e6371e2e | |||
5e400ed335 | |||
56a78b57af | |||
2bfeb7f42c | |||
37e0f12f89 | |||
fdd0e4a966 | |||
38df7e0038 | |||
e9efb78280 | |||
0424d7b640 | |||
2b80c7c91f | |||
142e2c0a65 | |||
1ed9ae7d60 | |||
329bf25dbd | |||
e18ffba183 | |||
ae3f0b429d | |||
34736c4e9b | |||
806678ee5f | |||
1e70401bdd | |||
3c7615f20d | |||
054d5e4879 | |||
b04ed43bed | |||
c2bbb952c5 | |||
63a9e1859b | |||
68ef069e6a | |||
72d4b21cb4 | |||
e8b931680d | |||
218b407f30 | |||
773cc27145 | |||
1c76e2e15b | |||
e466cfd6ff | |||
992b04d521 | |||
5c16c86871 | |||
78af9bbb10 | |||
b78c48d89f | |||
1f8c610bb0 | |||
d220728380 | |||
db58e9986c | |||
2a5e66eca6 | |||
e7e8ec296c | |||
80e69c56d0 | |||
ce3c6aecff | |||
300f76ba83 | |||
a4e8a38bf4 | |||
9bb04f43a8 | |||
9b0c08bd46 | |||
679d48e86e | |||
4b6bf60531 | |||
d8ce6648e2 | |||
402bc2d3a8 | |||
f3e193be0f | |||
f5b461612b | |||
d2514a3fc3 | |||
2019f9fdeb | |||
656f3e5cd9 | |||
741acfbba3 | |||
4b7eca02a0 | |||
c7788a80e1 | |||
08648894e3 | |||
4c5d5697bc | |||
c758a5b9ea | |||
2af54e2e28 | |||
cf9b23b987 | |||
f8380ec8e6 | |||
cd3245a631 | |||
144a155208 | |||
7f7ca13001 | |||
361e149063 | |||
fab85b381a | |||
faecf103bf | |||
a0f8c1aa8c | |||
24726b575d | |||
688b89a099 | |||
2e39110cc0 | |||
193cedae26 | |||
3d1f023ef5 | |||
9bb51d7146 | |||
84900aa588 | |||
b2bce3c4ac | |||
8c11620a42 | |||
7c1e0ac2e9 | |||
9a3c844336 | |||
69039d21c2 | |||
34c9cdd8bb | |||
0a8b30e824 | |||
ea5b521262 | |||
3bc71577b5 | |||
0fb24162fc | |||
d0d63f5bbb | |||
8041905144 | |||
37d96e238d | |||
ae8c941bfe | |||
4c16835ca4 | |||
7bd8922a4e | |||
42b2e2fcf0 | |||
f7256e9927 | |||
85444a5a6a | |||
ac115c7ea3 | |||
3c2a440553 | |||
b29ce3ee04 | |||
2b4394f3ce | |||
60f704eaa9 | |||
caa4fcf754 | |||
c4d1e4244e | |||
a6dc155028 | |||
9c65d11e66 | |||
26f50e7a74 | |||
e4773da1d7 | |||
dfd8086f63 | |||
ec513c61ad | |||
a96ab487ba | |||
cd28c985ce | |||
727af42ad4 | |||
e96d411f3e | |||
4a7d3d5945 | |||
03f05305cf | |||
af6e9ef85d | |||
8533a4a303 | |||
85f9234c74 | |||
064afd6705 | |||
978ff91f87 | |||
5cebbce7bb | |||
1cd0f02db5 | |||
77695bb505 | |||
4e4428fdbb | |||
6e978d74dd | |||
58974af77b | |||
11a0eae7a0 | |||
2a4ba895e5 | |||
19c019076e | |||
dfa18d3cb3 | |||
782c92885d | |||
a14dfa6cf1 | |||
f3b6f9d117 | |||
63b2b3feb6 | |||
9237dd25ac | |||
df9c4ce2fd | |||
fa5a7abbbf | |||
cd8bb7882e | |||
3c0378142a | |||
a524bffaa2 | |||
4b3decbe03 | |||
fa258a84cc | |||
5efa7309be | |||
6e6a01c33c | |||
94ce15bc2c |
2
.gitignore
vendored
2
.gitignore
vendored
@ -32,3 +32,5 @@ bin/node
|
||||
release/build
|
||||
|
||||
npm-shrinkwrap.json
|
||||
.resinconf
|
||||
resinrc.yml
|
||||
|
5
.hound.yml
Normal file
5
.hound.yml
Normal file
@ -0,0 +1,5 @@
|
||||
coffee_script:
|
||||
config_file: coffeelint.json
|
||||
|
||||
javascript:
|
||||
enabled: false
|
4
.npmignore
Normal file
4
.npmignore
Normal file
@ -0,0 +1,4 @@
|
||||
tests
|
||||
doc
|
||||
lib
|
||||
extras
|
@ -1,4 +0,0 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.11"
|
||||
- "0.10"
|
227
CHANGELOG.md
Normal file
227
CHANGELOG.md
Normal file
@ -0,0 +1,227 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [4.0.0] - 2016-04-26
|
||||
|
||||
### Added
|
||||
|
||||
- Implement `resin ssh` command
|
||||
|
||||
### Changed
|
||||
|
||||
- `resin sync` no longer supports the `exec after rsync` feature
|
||||
- Upgraded `resin-sync` and `resin-settings-client`
|
||||
|
||||
## [3.0.2] - 2016-04-08
|
||||
|
||||
### Changed
|
||||
|
||||
- Fix `os configure` command not working with shorter uuids.
|
||||
|
||||
## [3.0.1] - 2016-03-29
|
||||
|
||||
### Changed
|
||||
|
||||
- Log Mixpanel events based on the matching command signature.
|
||||
|
||||
## [3.0.0] - 2016-03-28
|
||||
|
||||
### Added
|
||||
|
||||
- Implement `config inject` command.
|
||||
- Document the case where `EACCES` is thrown during login because of an expired token.
|
||||
- Integrate `resin-plugin-sync` as a build-in command.
|
||||
|
||||
### Changed
|
||||
|
||||
- Allow `config generate` to generate a `config.json` for an application.
|
||||
- Force update alert to always be shown.
|
||||
- Only throw "Invalid 2FA code" if we're sure that's the cause during `login`.
|
||||
|
||||
## [2.7.0] - 2016-03-07
|
||||
|
||||
### Added
|
||||
|
||||
- Implement `config generate` command.
|
||||
- Implement `device reboot` command.
|
||||
|
||||
## [2.6.2] - 2016-02-19
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove debugging statement in `quickstart`.
|
||||
|
||||
## [2.6.1] - 2016-02-12
|
||||
|
||||
### Added
|
||||
|
||||
- Documented corrupted image MBR error.
|
||||
- Show parser device status in `device` command.
|
||||
- Show id a device is online in `devices` command.
|
||||
- Make use of static images.
|
||||
|
||||
### Changed
|
||||
|
||||
- Improve analytics.
|
||||
- Improve `quickstart` messages.
|
||||
- Fix `device` example.
|
||||
|
||||
## [2.6.0] - 2016-01-21
|
||||
|
||||
### Added
|
||||
|
||||
- Add support for credential-based authentication.
|
||||
- Redirect users to GitHub and Gitter in case of errors.
|
||||
- Add Resin.io ASCII art header on `login`.
|
||||
- Print an informative next-steps message after `login`.
|
||||
- Print informative verbose help to `resin help`.
|
||||
- Support for shorter uuids in all commands.
|
||||
|
||||
### Changed
|
||||
|
||||
- Change license to Apache 2.0.
|
||||
- Don't make `device init` a primary command.
|
||||
- Stop instructing users to run `quickstart` as root.
|
||||
- Make `login` command purely interactive.
|
||||
- Handle authentication in `quickstart` if user is not logged in.
|
||||
- Redirect to `signup` from `login` if user doesn't have an account.
|
||||
- Make sure to remove registered device resource in case of errors in `quickstart`.
|
||||
- Upgrade Resin SDK to v5.0.1.
|
||||
- Upgrade Resin Image Manager to v3.2.6.
|
||||
- Make `devices` output shorter uuids.
|
||||
|
||||
## [2.5.0] - 2015-12-11
|
||||
|
||||
### Added
|
||||
|
||||
- Show device id in `resin devices`.
|
||||
- Add helpful instructions after `resin quickstart`.
|
||||
- Add timestamp to `resin logs` lines.
|
||||
|
||||
### Changed
|
||||
|
||||
- Lazy load command actions dependencies for performance reasons.
|
||||
|
||||
## [2.4.0] - 2015-12-01
|
||||
|
||||
### Added
|
||||
|
||||
- Show device types when selecting applications.
|
||||
- Automatic token exchange login with the web dashboard.
|
||||
|
||||
### Changed
|
||||
|
||||
- Simplify download output messages.
|
||||
|
||||
## [2.3.0] - 2015-11-20
|
||||
|
||||
### Added
|
||||
|
||||
- Implement `settings` command.
|
||||
- Handle Windows elevation automatically.
|
||||
|
||||
### Changed
|
||||
|
||||
- Show uuids in `devices` command.
|
||||
- Clarify resin url in `login` and `whoami`.
|
||||
|
||||
## [2.2.0] - 2015-11-12
|
||||
|
||||
### Added
|
||||
|
||||
- Implement `device move` command.
|
||||
|
||||
## [2.1.0] - 2015-11-11
|
||||
|
||||
### Added
|
||||
|
||||
- Implement `config read` command.
|
||||
- Implement `config write` command.
|
||||
|
||||
### Changed
|
||||
|
||||
- Clarify the need of computer password during `sudo` in `os initialize`.
|
||||
|
||||
## [2.0.1] - 2015-10-26
|
||||
|
||||
### Changed
|
||||
|
||||
- Fix critical error when elevating permissions.
|
||||
|
||||
## [2.0.0] - 2015-10-26
|
||||
|
||||
### Added
|
||||
|
||||
- Add `drive` option to `os initialize`.
|
||||
- Add application name length validation.
|
||||
- Allow passing a custom uuid to `device register`.
|
||||
- Add `advanced` option in `device init`.
|
||||
- Implement user/password login form with 2FA support.
|
||||
|
||||
### Changed
|
||||
|
||||
- Clarify the need for admin privileges on update.
|
||||
- Fix non working `yes` option in `os initialize`.
|
||||
- Fix non working `type` option in `app create`.
|
||||
- Take device type as an option in `os initialize`.
|
||||
- Improve the way the update notifier is shown.
|
||||
- Ignore advanced configuration options by default.
|
||||
- Fix `device info` shadowing other command help pages.
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove login with token functionality.
|
||||
- Remove project directory creation logic in `device init`.
|
||||
- Remove `app associate` command.
|
||||
|
||||
## [1.1.0] - 2015-10-13
|
||||
|
||||
### Added
|
||||
|
||||
- Implement `os download` command.
|
||||
- Implement `os configure` command.
|
||||
- Implement `os initialize` command.
|
||||
- Implement `device register` command.
|
||||
- Add TROUBLESHOOTING guide.
|
||||
- Add a dynamic widget for selecting connected drives.
|
||||
|
||||
### Changed
|
||||
|
||||
- Make sure temporary files are removed on failures in `device init`.
|
||||
- Prompt to select application if running `device init` with no arguments.
|
||||
- Only use admin privileges in `os initialize` to avoid the cache directory to belong to `root`.
|
||||
- Separate help output per relevance.
|
||||
- Only print primary command help by default.
|
||||
- Print plugin warnings in red as the rest of the errors.
|
||||
- Shorten the length of device await message.
|
||||
- Upgrade Resin SDK to v3.0.0.
|
||||
- Check that a directory is a `git` repository before attempting to run `git` operations on it.
|
||||
- Improve plugin scanning mechanism.
|
||||
- Fix `EPERM` issue in Windows after a successfull `device init`.
|
||||
- Fix SDCard burning issues in Windows 10.
|
||||
- Fix plugins not being loaded in Windows 10.
|
||||
- Fix bug when listing the available drives in Windows when the user name contains spaces.
|
||||
- Fix an edge case that caused drives to be scanned incorrectly in OS X.
|
||||
- Fix operating system not being detected correctly when initializing a device.
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove outdated information from README.
|
||||
|
||||
[3.0.2]: https://github.com/resin-io/resin-cli/compare/v3.0.1...v3.0.2
|
||||
[3.0.1]: https://github.com/resin-io/resin-cli/compare/v3.0.0...v3.0.1
|
||||
[3.0.0]: https://github.com/resin-io/resin-cli/compare/v2.7.0...v3.0.0
|
||||
[2.7.0]: https://github.com/resin-io/resin-cli/compare/v2.6.2...v2.7.0
|
||||
[2.6.2]: https://github.com/resin-io/resin-cli/compare/v2.6.1...v2.6.2
|
||||
[2.6.1]: https://github.com/resin-io/resin-cli/compare/v2.6.0...v2.6.1
|
||||
[2.6.0]: https://github.com/resin-io/resin-cli/compare/v2.5.0...v2.6.0
|
||||
[2.5.0]: https://github.com/resin-io/resin-cli/compare/v2.4.0...v2.5.0
|
||||
[2.4.0]: https://github.com/resin-io/resin-cli/compare/v2.3.0...v2.4.0
|
||||
[2.3.0]: https://github.com/resin-io/resin-cli/compare/v2.2.0...v2.3.0
|
||||
[2.2.0]: https://github.com/resin-io/resin-cli/compare/v2.1.0...v2.2.0
|
||||
[2.1.0]: https://github.com/resin-io/resin-cli/compare/v2.0.1...v2.1.0
|
||||
[2.0.1]: https://github.com/resin-io/resin-cli/compare/v2.0.0...v2.0.1
|
||||
[2.0.0]: https://github.com/resin-io/resin-cli/compare/v1.1.0...v2.0.0
|
||||
[1.1.0]: https://github.com/resin-io/resin-cli/compare/v1.0.0...v1.1.0
|
190
LICENSE
190
LICENSE
@ -1,21 +1,177 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2014 Resin.io, Inc. https://resin.io
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
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:
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
1. Definitions.
|
||||
|
||||
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.
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
82
README.md
82
README.md
@ -1,65 +1,77 @@
|
||||
# Resin CLI
|
||||
Resin CLI
|
||||
=========
|
||||
|
||||
> The official Resin CLI tool.
|
||||
|
||||
[](http://badge.fury.io/js/resin-cli)
|
||||
[](https://david-dm.org/resin-io/resin-cli.png)
|
||||
[](https://travis-ci.org/resin-io/resin-cli)
|
||||
[](https://david-dm.org/resin-io/resin-cli)
|
||||
[](https://gitter.im/resin-io/chat)
|
||||
|
||||
The official Resin CLI tool.
|
||||
Requisites
|
||||
----------
|
||||
|
||||
## Installing
|
||||
- [NodeJS](https://nodejs.org) (at least v0.10)
|
||||
- [Git](https://git-scm.com)
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
### Installing
|
||||
|
||||
This might require elevated privileges in some environments.
|
||||
|
||||
```sh
|
||||
$ npm install -g resin-cli
|
||||
$ npm install --global --production resin-cli
|
||||
```
|
||||
|
||||
### Running locally
|
||||
### List available commands
|
||||
|
||||
```sh
|
||||
$ ./bin/resin
|
||||
$ resin help
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
||||
You can run the [Mocha](http://mochajs.org/) test suite, you can do:
|
||||
### Run the quickstart wizard
|
||||
|
||||
```sh
|
||||
$ gulp test
|
||||
$ resin quickstart
|
||||
```
|
||||
|
||||
## Development mode
|
||||
Plugins
|
||||
-------
|
||||
|
||||
The following command will watch for any changes and will run a linter and the whole test suite:
|
||||
The Resin CLI can be extended with plugins to automate laborious tasks and overall provide a better experience when working with Resin.io. Check the [plugin development tutorial](https://github.com/resin-io/resin-plugin-hello) to learn how to build your own!
|
||||
|
||||
```sh
|
||||
$ gulp watch
|
||||
```
|
||||
FAQ
|
||||
---
|
||||
|
||||
If you set `DEBUG` environment variable, errors will print with a stack trace:
|
||||
### Where is my configuration file?
|
||||
|
||||
```sh
|
||||
$ DEBUG=true resin ...
|
||||
```
|
||||
The per-user configuration file lives in `$HOME/.resinrc.yml` or `%UserProfile%\_resinrc.yml`, in Unix based operating systems and Windows respectively.
|
||||
|
||||
## Documentation
|
||||
The Resin CLI also attempts to read a `resinrc.yml` file in the current directory, which takes precedence over the per-user configuration file.
|
||||
|
||||
You can renegerate the documentation with:
|
||||
### How do I point the Resin CLI to staging?
|
||||
|
||||
```sh
|
||||
$ npm run-script doc
|
||||
```
|
||||
The easiest way is to set the `RESINRC_RESIN_URL=resinstaging.io` environment variable.
|
||||
|
||||
## Manual pages
|
||||
Alternatively, you can edit your configuration file and set `resinUrl: resinstaging.io` to persist this setting.
|
||||
|
||||
UNIX manual pages reside in `man/`
|
||||
### How do I make the Resin CLI persist data in another directory?
|
||||
|
||||
You can regenerate UNIX `roff` manual pages from markdown with:
|
||||
The Resin CLI persists your session token, as well as cached images in `$HOME/.resin` or `%UserProfile%\_resin`.
|
||||
|
||||
```sh
|
||||
$ gulp man
|
||||
```
|
||||
Pointing the Resin CLI to persist data in another location is necessary in certain environments, like a server, where there is no home directory, or a device running Resin OS, which erases all data after a restart.
|
||||
|
||||
If you add a new `man` page, remember to add the generated filename to the `man` array in `package.json`.
|
||||
You can accomplish this by setting `RESINRC_DATA_DIRECTORY=/opt/resin` or adding `dataDirectory: /opt/resin` to your configuration file, replacing `/opt/resin` with your desired directory.
|
||||
|
||||
## Caveats
|
||||
Support
|
||||
-------
|
||||
|
||||
- Some interactive widgets don't work on [Cygwin](https://cygwin.com/). If you're running Windows, it's preferrable that you use `cmd.exe`, as `Cygwin` is [not official supported by Node.js](https://github.com/chjj/blessed/issues/56#issuecomment-42671945).
|
||||
If you're having any problem, check our [troubleshooting guide](https://github.com/resin-io/resin-cli/blob/master/TROUBLESHOOTING.md) and if your problem is not addressed there, please [raise an issue](https://github.com/resin-io/resin-cli/issues/new) on GitHub and the Resin.io team will be happy to help.
|
||||
|
||||
You can also get in touch with us at our public [Gitter chat channel](https://gitter.im/resin-io/chat).
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
The project is licensed under the Apache 2.0 license.
|
||||
|
59
TROUBLESHOOTING.md
Normal file
59
TROUBLESHOOTING.md
Normal file
@ -0,0 +1,59 @@
|
||||
Troubleshooting
|
||||
===============
|
||||
|
||||
This document contains common issues related to the Resin CLI, and how to fix them.
|
||||
|
||||
### After burning to an sdcard, my device doesn't boot
|
||||
|
||||
- The downloaded image is not complete (download was interrupted).
|
||||
|
||||
Please clean the cache (`%HOME/.resin/cache` or `C:\Users\<user>\_resin\cache`) and run the command again. In the future, the CLI will check that the image is not complete and clean the cache for you.
|
||||
|
||||
### I get a permission error when burning to an sdcard
|
||||
|
||||
- The SDCard is locked.
|
||||
|
||||
### I get EINVAL errors on Cygwin
|
||||
|
||||
The errors look something like this:
|
||||
|
||||
```
|
||||
net.js:156
|
||||
this._handle.open(options.fd);
|
||||
^
|
||||
Error: EINVAL, invalid argument
|
||||
at new Socket (net.js:156:18)
|
||||
at process.stdin (node.js:664:19)
|
||||
at Object.Interface.createInterface (C:\cygwin\home\Juan Cruz Viotti\Projects\resin-cli\node_modules\inquirer\node_modules\readline2\index.js:31:43)
|
||||
at PromptUI.UI (C:\cygwin\home\Juan Cruz Viotti\Projects\resin-cli\node_modules\inquirer\lib\ui\baseUI.js:23:40)
|
||||
at new PromptUI (C:\cygwin\home\Juan Cruz Viotti\Projects\resin-cli\node_modules\inquirer\lib\ui\prompt.js:26:8)
|
||||
at Object.promptModule [as prompt] (C:\cygwin\home\Juan Cruz Viotti\Projects\resin-cli\node_modules\inquirer\lib\inquirer.js:27:14)
|
||||
```
|
||||
|
||||
- Some interactive widgets don't work on `Cygwin`. If you're running Windows, it's preferrable that you use `cmd.exe`, as `Cygwin` is [not official supported by Node.js](https://github.com/chjj/blessed/issues/56#issuecomment-42671945).
|
||||
|
||||
### I get `Invalid MBR boot signature` when configuring a device
|
||||
|
||||
This error, accompanied with something like: `Expected 0xAA55, but saw 0x29FE` usually indicates a corrupted device operating system image in the cache, due to bad a internet connection during the download process.
|
||||
|
||||
Try clearing the cache with the following command and trying again:
|
||||
|
||||
```sh
|
||||
$ rm -rf $HOME/.resin/cache
|
||||
```
|
||||
|
||||
Or in Windows:
|
||||
|
||||
```sh
|
||||
> del /s /q %UserProfile%\_resin\cache
|
||||
```
|
||||
|
||||
### I get `EACCES: permission denied` when logging in
|
||||
|
||||
The Resin CLI stores the session token in `$HOME/.resin` or `C:\Users\<user>\_resin` in UNIX based operating systems and Windows respectively. This error usually indicates that the user doesn't have permissions over that directory, which can happen if you ran the Resin CLI as `root`, and thus the directory got owned by him.
|
||||
|
||||
Try resetting the ownership by running:
|
||||
|
||||
```sh
|
||||
$ sudo chown -R <user> $HOME/.resin
|
||||
```
|
@ -1,16 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var os = require('../build/actions/os');
|
||||
var errors = require('../build/errors');
|
||||
|
||||
// TODO: Do some error handling when image or device are incorrect
|
||||
|
||||
os.install.action({
|
||||
image: process.argv[2],
|
||||
device: process.argv[3]
|
||||
}, {
|
||||
yes: true,
|
||||
fromScript: true
|
||||
}, function(error) {
|
||||
return errors.handle(error);
|
||||
});
|
@ -1,20 +1,25 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var _, async, commandOptions, path, resin, vcs, visuals;
|
||||
|
||||
path = require('path');
|
||||
|
||||
_ = require('lodash-contrib');
|
||||
|
||||
async = require('async');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
visuals = require('resin-cli-visuals');
|
||||
var commandOptions;
|
||||
|
||||
commandOptions = require('./command-options');
|
||||
|
||||
vcs = require('resin-vcs');
|
||||
|
||||
exports.create = {
|
||||
signature: 'app create <name>',
|
||||
description: 'create an application',
|
||||
@ -28,129 +33,82 @@
|
||||
}
|
||||
],
|
||||
permission: 'user',
|
||||
primary: true,
|
||||
action: function(params, options, done) {
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
if (options.type != null) {
|
||||
return callback(null, options.type);
|
||||
}
|
||||
return resin.models.device.getSupportedDeviceTypes(function(error, deviceTypes) {
|
||||
if (error != null) {
|
||||
return callback(error);
|
||||
}
|
||||
return visuals.widgets.select('Select a type', deviceTypes, callback);
|
||||
});
|
||||
}, function(type, callback) {
|
||||
return resin.models.application.create(params.name, type, callback);
|
||||
var patterns, resin;
|
||||
resin = require('resin-sdk');
|
||||
patterns = require('../utils/patterns');
|
||||
return resin.models.application.has(params.name).then(function(hasApplication) {
|
||||
if (hasApplication) {
|
||||
throw new Error('You already have an application with that name!');
|
||||
}
|
||||
], done);
|
||||
}).then(function() {
|
||||
return options.type || patterns.selectDeviceType();
|
||||
}).then(function(deviceType) {
|
||||
return resin.models.application.create(params.name, deviceType);
|
||||
}).then(function(application) {
|
||||
return console.info("Application created: " + application.app_name + " (" + application.device_type + ", id " + application.id + ")");
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.list = {
|
||||
signature: 'apps',
|
||||
description: 'list all applications',
|
||||
help: 'Use this command to list all your applications.\n\nNotice this command only shows the most important bits of information for each app.\nIf you want detailed information, use resin app <id> instead.\n\nExamples:\n\n $ resin apps',
|
||||
help: 'Use this command to list all your applications.\n\nNotice this command only shows the most important bits of information for each app.\nIf you want detailed information, use resin app <name> instead.\n\nExamples:\n\n $ resin apps',
|
||||
permission: 'user',
|
||||
primary: true,
|
||||
action: function(params, options, done) {
|
||||
return resin.models.application.getAll(function(error, applications) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
console.log(visuals.widgets.table.horizontal(applications, ['id', 'app_name', 'device_type', 'online_devices', 'devices_length']));
|
||||
return done();
|
||||
});
|
||||
var resin, visuals;
|
||||
resin = require('resin-sdk');
|
||||
visuals = require('resin-cli-visuals');
|
||||
return resin.models.application.getAll().then(function(applications) {
|
||||
return console.log(visuals.table.horizontal(applications, ['id', 'app_name', 'device_type', 'online_devices', 'devices_length']));
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.info = {
|
||||
signature: 'app <id>',
|
||||
signature: 'app <name>',
|
||||
description: 'list a single application',
|
||||
help: 'Use this command to show detailed information for a single application.\n\nExamples:\n\n $ resin app 91',
|
||||
help: 'Use this command to show detailed information for a single application.\n\nExamples:\n\n $ resin app MyApp',
|
||||
permission: 'user',
|
||||
primary: true,
|
||||
action: function(params, options, done) {
|
||||
return resin.models.application.get(params.id, function(error, application) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
console.log(visuals.widgets.table.vertical(application, ['id', 'app_name', 'device_type', 'git_repository', 'commit']));
|
||||
return done();
|
||||
});
|
||||
var resin, visuals;
|
||||
resin = require('resin-sdk');
|
||||
visuals = require('resin-cli-visuals');
|
||||
return resin.models.application.get(params.name).then(function(application) {
|
||||
return console.log(visuals.table.vertical(application, ["$" + application.app_name + "$", 'id', 'device_type', 'git_repository', 'commit']));
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.restart = {
|
||||
signature: 'app restart <id>',
|
||||
signature: 'app restart <name>',
|
||||
description: 'restart an application',
|
||||
help: 'Use this command to restart all devices that belongs to a certain application.\n\nExamples:\n\n $ resin app restart 91',
|
||||
help: 'Use this command to restart all devices that belongs to a certain application.\n\nExamples:\n\n $ resin app restart MyApp',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.models.application.restart(params.id, done);
|
||||
var resin;
|
||||
resin = require('resin-sdk');
|
||||
return resin.models.application.restart(params.name).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.remove = {
|
||||
signature: 'app rm <id>',
|
||||
signature: 'app rm <name>',
|
||||
description: 'remove an application',
|
||||
help: 'Use this command to remove a resin.io application.\n\nNotice this command asks for confirmation interactively.\nYou can avoid this by passing the `--yes` boolean option.\n\nExamples:\n\n $ resin app rm 91\n $ resin app rm 91 --yes',
|
||||
help: 'Use this command to remove a resin.io application.\n\nNotice this command asks for confirmation interactively.\nYou can avoid this by passing the `--yes` boolean option.\n\nExamples:\n\n $ resin app rm MyApp\n $ resin app rm MyApp --yes',
|
||||
options: [commandOptions.yes],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return visuals.patterns.remove('application', options.yes, function(callback) {
|
||||
return resin.models.application.remove(params.id, callback);
|
||||
}, done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.associate = {
|
||||
signature: 'app associate <id>',
|
||||
description: 'associate a resin project',
|
||||
help: 'Use this command to associate a project directory with a resin application.\n\nThis command adds a \'resin\' git remote to the directory and runs git init if necessary.\n\nExamples:\n\n $ resin app associate 91\n $ resin app associate 91 --project my/app/directory',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
var currentDirectory;
|
||||
currentDirectory = process.cwd();
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
return vcs.initialize(currentDirectory, callback);
|
||||
}, function(callback) {
|
||||
return resin.models.application.get(params.id, callback);
|
||||
}, function(application, callback) {
|
||||
return vcs.addRemote(currentDirectory, application.git_repository, callback);
|
||||
}
|
||||
], function(error, remoteUrl) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
console.info("git repository added: " + remoteUrl);
|
||||
return done(null, remoteUrl);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.init = {
|
||||
signature: 'init',
|
||||
description: 'init an application',
|
||||
help: 'Use this command to initialise a directory as a resin application.\n\nThis command performs the following steps:\n - Create a resin.io application.\n - Initialize the current directory as a git repository.\n - Add the corresponding git remote to the application.\n\nExamples:\n\n $ resin init\n $ resin init --project my/app/directory',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
var currentDirectory;
|
||||
currentDirectory = process.cwd();
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
var currentDirectoryBasename;
|
||||
currentDirectoryBasename = path.basename(currentDirectory);
|
||||
return visuals.widgets.ask('What is the name of your application?', currentDirectoryBasename, callback);
|
||||
}, function(applicationName, callback) {
|
||||
return exports.create.action({
|
||||
name: applicationName
|
||||
}, options, callback);
|
||||
}, function(applicationId, callback) {
|
||||
return exports.associate.action({
|
||||
id: applicationId
|
||||
}, options, callback);
|
||||
}
|
||||
], done);
|
||||
var patterns, resin;
|
||||
resin = require('resin-sdk');
|
||||
patterns = require('../utils/patterns');
|
||||
return patterns.confirm(options.yes, 'Are you sure you want to delete the application?').then(function() {
|
||||
return resin.models.application.remove(params.name);
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,55 +1,98 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var _, async, resin, url, visuals;
|
||||
|
||||
_ = require('lodash-contrib');
|
||||
|
||||
url = require('url');
|
||||
|
||||
async = require('async');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
visuals = require('resin-cli-visuals');
|
||||
|
||||
exports.login = {
|
||||
signature: 'login',
|
||||
description: 'login to resin.io',
|
||||
help: 'Use this command to login to your resin.io account.\nYou need to login before you can use most of the commands this tool provides.\n\nYou can pass your credentials as `--username` and `--password` options, or you can omit the\ncredentials, in which case the tool will present you with an interactive login form.\n\nExamples:\n\n $ resin login --username <username> --password <password>\n $ resin login',
|
||||
help: 'Use this command to login to your resin.io account.\n\nThis command will prompt you to login using the following login types:\n\n- Web authorization: open your web browser and prompt you to authorize the CLI\nfrom the dashboard.\n\n- Credentials: using email/password and 2FA.\n\n- Token: using the authentication token from the preferences page.\n\nExamples:\n\n $ resin login\n $ resin login --web\n $ resin login --token "..."\n $ resin login --credentials\n $ resin login --credentials --email johndoe@gmail.com --password secret',
|
||||
options: [
|
||||
{
|
||||
signature: 'username',
|
||||
parameter: 'username',
|
||||
description: 'user name',
|
||||
alias: 'u'
|
||||
signature: 'token',
|
||||
description: 'auth token',
|
||||
parameter: 'token',
|
||||
alias: 't'
|
||||
}, {
|
||||
signature: 'web',
|
||||
description: 'web-based login',
|
||||
boolean: true,
|
||||
alias: 'w'
|
||||
}, {
|
||||
signature: 'credentials',
|
||||
description: 'credential-based login',
|
||||
boolean: true,
|
||||
alias: 'c'
|
||||
}, {
|
||||
signature: 'email',
|
||||
parameter: 'email',
|
||||
description: 'email',
|
||||
alias: ['e', 'u']
|
||||
}, {
|
||||
signature: 'password',
|
||||
parameter: 'password',
|
||||
description: 'user password',
|
||||
description: 'password',
|
||||
alias: 'p'
|
||||
}
|
||||
],
|
||||
primary: true,
|
||||
action: function(params, options, done) {
|
||||
var hasOptionCredentials;
|
||||
hasOptionCredentials = !_.isEmpty(options);
|
||||
if (hasOptionCredentials) {
|
||||
if (!options.username) {
|
||||
return done(new Error('Missing username'));
|
||||
var Promise, _, auth, capitano, form, login, messages, patterns, resin;
|
||||
_ = require('lodash');
|
||||
Promise = require('bluebird');
|
||||
capitano = Promise.promisifyAll(require('capitano'));
|
||||
resin = require('resin-sdk');
|
||||
auth = require('resin-cli-auth');
|
||||
form = require('resin-cli-form');
|
||||
patterns = require('../utils/patterns');
|
||||
messages = require('../utils/messages');
|
||||
login = function(options) {
|
||||
if (options.token != null) {
|
||||
return Promise["try"](function() {
|
||||
if (_.isString(options.token)) {
|
||||
return options.token;
|
||||
}
|
||||
return form.ask({
|
||||
message: 'Token (from the preferences page)',
|
||||
name: 'token',
|
||||
type: 'input'
|
||||
});
|
||||
}).then(resin.auth.loginWithToken);
|
||||
} else if (options.credentials) {
|
||||
return patterns.authenticate(options);
|
||||
} else if (options.web) {
|
||||
console.info('Connecting to the web dashboard');
|
||||
return auth.login();
|
||||
}
|
||||
if (!options.password) {
|
||||
return done(new Error('Missing password'));
|
||||
}
|
||||
}
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
if (hasOptionCredentials) {
|
||||
return callback(null, options);
|
||||
} else {
|
||||
return visuals.widgets.login(callback);
|
||||
return patterns.askLoginType().then(function(loginType) {
|
||||
if (loginType === 'register') {
|
||||
return capitano.runAsync('signup');
|
||||
}
|
||||
}, function(credentials, callback) {
|
||||
return resin.auth.login(credentials, callback);
|
||||
}
|
||||
], done);
|
||||
options[loginType] = true;
|
||||
return login(options);
|
||||
});
|
||||
};
|
||||
return resin.settings.get('resinUrl').then(function(resinUrl) {
|
||||
console.log(messages.resinAsciiArt);
|
||||
console.log("\nLogging in to " + resinUrl);
|
||||
return login(options);
|
||||
}).then(resin.auth.whoami).tap(function(username) {
|
||||
console.info("Successfully logged in as: " + username);
|
||||
return console.info("\nNow what?\n\n" + messages.gettingStarted + "\n\nFind out about more super powers by running:\n\n $ resin help\n\n" + messages.reachingOut);
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
@ -59,75 +102,61 @@
|
||||
help: 'Use this command to logout from your resin.io account.o\n\nExamples:\n\n $ resin logout',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.auth.logout(done);
|
||||
var resin;
|
||||
resin = require('resin-sdk');
|
||||
return resin.auth.logout().nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.signup = {
|
||||
signature: 'signup',
|
||||
description: 'signup to resin.io',
|
||||
help: 'Use this command to signup for a resin.io account.\n\nIf signup is successful, you\'ll be logged in to your new user automatically.\n\nExamples:\n\n $ resin signup\n Email: me@mycompany.com\n Username: johndoe\n Password: ***********\n\n $ resin signup --email me@mycompany.com --username johndoe --password ***********\n\n $ resin whoami\n johndoe',
|
||||
options: [
|
||||
{
|
||||
signature: 'email',
|
||||
parameter: 'email',
|
||||
description: 'user email',
|
||||
alias: 'e'
|
||||
}, {
|
||||
signature: 'username',
|
||||
parameter: 'username',
|
||||
description: 'user name',
|
||||
alias: 'u'
|
||||
}, {
|
||||
signature: 'password',
|
||||
parameter: 'user password',
|
||||
description: 'user password',
|
||||
alias: 'p'
|
||||
}
|
||||
],
|
||||
help: 'Use this command to signup for a resin.io account.\n\nIf signup is successful, you\'ll be logged in to your new user automatically.\n\nExamples:\n\n $ resin signup\n Email: me@mycompany.com\n Username: johndoe\n Password: ***********\n\n $ resin whoami\n johndoe',
|
||||
action: function(params, options, done) {
|
||||
var hasOptionCredentials;
|
||||
hasOptionCredentials = !_.isEmpty(options);
|
||||
if (hasOptionCredentials) {
|
||||
if (options.email == null) {
|
||||
return done(new Error('Missing email'));
|
||||
}
|
||||
if (options.username == null) {
|
||||
return done(new Error('Missing username'));
|
||||
}
|
||||
if (options.password == null) {
|
||||
return done(new Error('Missing password'));
|
||||
}
|
||||
}
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
if (hasOptionCredentials) {
|
||||
return callback(null, options);
|
||||
var form, resin, validation;
|
||||
resin = require('resin-sdk');
|
||||
form = require('resin-cli-form');
|
||||
validation = require('../utils/validation');
|
||||
return resin.settings.get('resinUrl').then(function(resinUrl) {
|
||||
console.log("\nRegistering to " + resinUrl);
|
||||
return form.run([
|
||||
{
|
||||
message: 'Email:',
|
||||
name: 'email',
|
||||
type: 'input',
|
||||
validate: validation.validateEmail
|
||||
}, {
|
||||
message: 'Username:',
|
||||
name: 'username',
|
||||
type: 'input'
|
||||
}, {
|
||||
message: 'Password:',
|
||||
name: 'password',
|
||||
type: 'password',
|
||||
validate: validation.validatePassword
|
||||
}
|
||||
return visuals.widgets.register(callback);
|
||||
}, function(credentials, callback) {
|
||||
return resin.auth.register(credentials, function(error, token) {
|
||||
return callback(error, credentials);
|
||||
});
|
||||
}, function(credentials, callback) {
|
||||
return resin.auth.login(credentials, callback);
|
||||
}
|
||||
], done);
|
||||
]);
|
||||
}).then(resin.auth.register).then(resin.auth.loginWithToken).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.whoami = {
|
||||
signature: 'whoami',
|
||||
description: 'get current username',
|
||||
help: 'Use this command to find out the current logged in username.\n\nExamples:\n\n $ resin whoami',
|
||||
description: 'get current username and email address',
|
||||
help: 'Use this command to find out the current logged in username and email address.\n\nExamples:\n\n $ resin whoami',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.auth.whoami(function(error, username) {
|
||||
if (username == null) {
|
||||
return done(new Error('Username not found'));
|
||||
}
|
||||
return console.log(username);
|
||||
});
|
||||
var Promise, resin, visuals;
|
||||
Promise = require('bluebird');
|
||||
resin = require('resin-sdk');
|
||||
visuals = require('resin-cli-visuals');
|
||||
return Promise.props({
|
||||
username: resin.auth.whoami(),
|
||||
email: resin.auth.getEmail(),
|
||||
url: resin.settings.get('resinUrl')
|
||||
}).then(function(results) {
|
||||
return console.log(visuals.table.vertical(results, ['$account information$', 'username', 'email', 'url']));
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,3 +1,20 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var _;
|
||||
|
||||
@ -13,7 +30,7 @@
|
||||
exports.optionalApplication = {
|
||||
signature: 'application',
|
||||
parameter: 'application',
|
||||
description: 'application id',
|
||||
description: 'application name',
|
||||
alias: ['a', 'app']
|
||||
};
|
||||
|
||||
@ -21,6 +38,20 @@
|
||||
required: 'You have to specify an application'
|
||||
}, exports.optionalApplication);
|
||||
|
||||
exports.optionalDevice = {
|
||||
signature: 'device',
|
||||
parameter: 'device',
|
||||
description: 'device uuid',
|
||||
alias: 'd'
|
||||
};
|
||||
|
||||
exports.booleanDevice = {
|
||||
signature: 'device',
|
||||
description: 'device',
|
||||
boolean: true,
|
||||
alias: 'd'
|
||||
};
|
||||
|
||||
exports.network = {
|
||||
signature: 'network',
|
||||
parameter: 'network',
|
||||
|
241
build/actions/config.js
Normal file
241
build/actions/config.js
Normal file
@ -0,0 +1,241 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var commandOptions;
|
||||
|
||||
commandOptions = require('./command-options');
|
||||
|
||||
exports.read = {
|
||||
signature: 'config read',
|
||||
description: 'read a device configuration',
|
||||
help: 'Use this command to read the config.json file from a provisioned device\n\nExamples:\n\n $ resin config read --type raspberry-pi\n $ resin config read --type raspberry-pi --drive /dev/disk2',
|
||||
options: [
|
||||
{
|
||||
signature: 'type',
|
||||
description: 'device type',
|
||||
parameter: 'type',
|
||||
alias: 't',
|
||||
required: 'You have to specify a device type'
|
||||
}, {
|
||||
signature: 'drive',
|
||||
description: 'drive',
|
||||
parameter: 'drive',
|
||||
alias: 'd'
|
||||
}
|
||||
],
|
||||
permission: 'user',
|
||||
root: true,
|
||||
action: function(params, options, done) {
|
||||
var Promise, config, prettyjson, umount, visuals;
|
||||
Promise = require('bluebird');
|
||||
config = require('resin-config-json');
|
||||
visuals = require('resin-cli-visuals');
|
||||
umount = Promise.promisifyAll(require('umount'));
|
||||
prettyjson = require('prettyjson');
|
||||
return Promise["try"](function() {
|
||||
return options.drive || visuals.drive('Select the device drive');
|
||||
}).tap(umount.umountAsync).then(function(drive) {
|
||||
return config.read(drive, options.type);
|
||||
}).tap(function(configJSON) {
|
||||
return console.info(prettyjson.render(configJSON));
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.write = {
|
||||
signature: 'config write <key> <value>',
|
||||
description: 'write a device configuration',
|
||||
help: 'Use this command to write the config.json file of a provisioned device\n\nExamples:\n\n $ resin config write --type raspberry-pi username johndoe\n $ resin config write --type raspberry-pi --drive /dev/disk2 username johndoe\n $ resin config write --type raspberry-pi files.network/settings "..."',
|
||||
options: [
|
||||
{
|
||||
signature: 'type',
|
||||
description: 'device type',
|
||||
parameter: 'type',
|
||||
alias: 't',
|
||||
required: 'You have to specify a device type'
|
||||
}, {
|
||||
signature: 'drive',
|
||||
description: 'drive',
|
||||
parameter: 'drive',
|
||||
alias: 'd'
|
||||
}
|
||||
],
|
||||
permission: 'user',
|
||||
root: true,
|
||||
action: function(params, options, done) {
|
||||
var Promise, _, config, umount, visuals;
|
||||
Promise = require('bluebird');
|
||||
_ = require('lodash');
|
||||
config = require('resin-config-json');
|
||||
visuals = require('resin-cli-visuals');
|
||||
umount = Promise.promisifyAll(require('umount'));
|
||||
return Promise["try"](function() {
|
||||
return options.drive || visuals.drive('Select the device drive');
|
||||
}).tap(umount.umountAsync).then(function(drive) {
|
||||
return config.read(drive, options.type).then(function(configJSON) {
|
||||
console.info("Setting " + params.key + " to " + params.value);
|
||||
_.set(configJSON, params.key, params.value);
|
||||
return configJSON;
|
||||
}).tap(function() {
|
||||
return umount.umountAsync(drive);
|
||||
}).then(function(configJSON) {
|
||||
return config.write(drive, options.type, configJSON);
|
||||
});
|
||||
}).tap(function() {
|
||||
return console.info('Done');
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.inject = {
|
||||
signature: 'config inject <file>',
|
||||
description: 'inject a device configuration file',
|
||||
help: 'Use this command to inject a config.json file to a provisioned device\n\nExamples:\n\n $ resin config inject my/config.json --type raspberry-pi\n $ resin config inject my/config.json --type raspberry-pi --drive /dev/disk2',
|
||||
options: [
|
||||
{
|
||||
signature: 'type',
|
||||
description: 'device type',
|
||||
parameter: 'type',
|
||||
alias: 't',
|
||||
required: 'You have to specify a device type'
|
||||
}, {
|
||||
signature: 'drive',
|
||||
description: 'drive',
|
||||
parameter: 'drive',
|
||||
alias: 'd'
|
||||
}
|
||||
],
|
||||
permission: 'user',
|
||||
root: true,
|
||||
action: function(params, options, done) {
|
||||
var Promise, config, fs, umount, visuals;
|
||||
Promise = require('bluebird');
|
||||
config = require('resin-config-json');
|
||||
visuals = require('resin-cli-visuals');
|
||||
umount = Promise.promisifyAll(require('umount'));
|
||||
fs = Promise.promisifyAll(require('fs'));
|
||||
return Promise["try"](function() {
|
||||
return options.drive || visuals.drive('Select the device drive');
|
||||
}).tap(umount.umountAsync).then(function(drive) {
|
||||
return fs.readFileAsync(params.file, 'utf8').then(JSON.parse).then(function(configJSON) {
|
||||
return config.write(drive, options.type, configJSON);
|
||||
});
|
||||
}).tap(function() {
|
||||
return console.info('Done');
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.reconfigure = {
|
||||
signature: 'config reconfigure',
|
||||
description: 'reconfigure a provisioned device',
|
||||
help: 'Use this command to reconfigure a provisioned device\n\nExamples:\n\n $ resin config reconfigure --type raspberry-pi\n $ resin config reconfigure --type raspberry-pi --advanced\n $ resin config reconfigure --type raspberry-pi --drive /dev/disk2',
|
||||
options: [
|
||||
{
|
||||
signature: 'type',
|
||||
description: 'device type',
|
||||
parameter: 'type',
|
||||
alias: 't',
|
||||
required: 'You have to specify a device type'
|
||||
}, {
|
||||
signature: 'drive',
|
||||
description: 'drive',
|
||||
parameter: 'drive',
|
||||
alias: 'd'
|
||||
}, {
|
||||
signature: 'advanced',
|
||||
description: 'show advanced commands',
|
||||
boolean: true,
|
||||
alias: 'v'
|
||||
}
|
||||
],
|
||||
permission: 'user',
|
||||
root: true,
|
||||
action: function(params, options, done) {
|
||||
var Promise, capitano, config, umount, visuals;
|
||||
Promise = require('bluebird');
|
||||
config = require('resin-config-json');
|
||||
visuals = require('resin-cli-visuals');
|
||||
capitano = Promise.promisifyAll(require('capitano'));
|
||||
umount = Promise.promisifyAll(require('umount'));
|
||||
return Promise["try"](function() {
|
||||
return options.drive || visuals.drive('Select the device drive');
|
||||
}).tap(umount.umountAsync).then(function(drive) {
|
||||
return config.read(drive, options.type).get('uuid').tap(function() {
|
||||
return umount.umountAsync(drive);
|
||||
}).then(function(uuid) {
|
||||
var configureCommand;
|
||||
configureCommand = "os configure " + drive + " " + uuid;
|
||||
if (options.advanced) {
|
||||
configureCommand += ' --advanced';
|
||||
}
|
||||
return capitano.runAsync(configureCommand);
|
||||
});
|
||||
}).then(function() {
|
||||
return console.info('Done');
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.generate = {
|
||||
signature: 'config generate',
|
||||
description: 'generate a config.json file',
|
||||
help: 'Use this command to generate a config.json for a device or application\n\nExamples:\n\n $ resin config generate --device 7cf02a6\n $ resin config generate --device 7cf02a6 --output config.json\n $ resin config generate --app MyApp\n $ resin config generate --app MyApp --output config.json',
|
||||
options: [
|
||||
commandOptions.optionalApplication, commandOptions.optionalDevice, {
|
||||
signature: 'output',
|
||||
description: 'output',
|
||||
parameter: 'output',
|
||||
alias: 'o'
|
||||
}
|
||||
],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
var Promise, _, deviceConfig, form, fs, prettyjson, resin;
|
||||
Promise = require('bluebird');
|
||||
fs = Promise.promisifyAll(require('fs'));
|
||||
resin = require('resin-sdk');
|
||||
_ = require('lodash');
|
||||
form = require('resin-cli-form');
|
||||
deviceConfig = require('resin-device-config');
|
||||
prettyjson = require('prettyjson');
|
||||
if ((options.device == null) && (options.application == null)) {
|
||||
throw new Error('You have to pass either a device or an application.\n\nSee the help page for examples:\n\n $ resin help config generate');
|
||||
}
|
||||
return Promise["try"](function() {
|
||||
if (options.device != null) {
|
||||
return resin.models.device.get(options.device);
|
||||
}
|
||||
return resin.models.application.get(options.application);
|
||||
}).then(function(resource) {
|
||||
return resin.models.device.getManifestBySlug(resource.device_type).get('options').then(form.run).then(function(answers) {
|
||||
if (resource.uuid != null) {
|
||||
return deviceConfig.getByDevice(resource.uuid, answers);
|
||||
}
|
||||
return deviceConfig.getByApplication(resource.app_name, answers);
|
||||
});
|
||||
}).then(function(config) {
|
||||
if (options.output != null) {
|
||||
return fs.writeFileAsync(options.output, JSON.stringify(config));
|
||||
}
|
||||
return console.log(prettyjson.render(config));
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
@ -1,147 +1,245 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var _, async, commandOptions, osAction, path, resin, vcs, visuals;
|
||||
|
||||
_ = require('lodash-contrib');
|
||||
|
||||
path = require('path');
|
||||
|
||||
async = require('async');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
visuals = require('resin-cli-visuals');
|
||||
|
||||
vcs = require('resin-vcs');
|
||||
var commandOptions;
|
||||
|
||||
commandOptions = require('./command-options');
|
||||
|
||||
osAction = require('./os');
|
||||
|
||||
exports.list = {
|
||||
signature: 'devices',
|
||||
description: 'list all devices',
|
||||
help: 'Use this command to list all devices that belong to a certain application.\n\nExamples:\n\n $ resin devices --application 91',
|
||||
options: [commandOptions.application],
|
||||
help: 'Use this command to list all devices that belong to you.\n\nYou can filter the devices by application by using the `--application` option.\n\nExamples:\n\n $ resin devices\n $ resin devices --application MyApp\n $ resin devices --app MyApp\n $ resin devices -a MyApp',
|
||||
options: [commandOptions.optionalApplication],
|
||||
permission: 'user',
|
||||
primary: true,
|
||||
action: function(params, options, done) {
|
||||
return resin.models.device.getAllByApplication(options.application, function(error, devices) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
var Promise, _, resin, visuals;
|
||||
Promise = require('bluebird');
|
||||
_ = require('lodash');
|
||||
resin = require('resin-sdk');
|
||||
visuals = require('resin-cli-visuals');
|
||||
return Promise["try"](function() {
|
||||
if (options.application != null) {
|
||||
return resin.models.device.getAllByApplication(options.application);
|
||||
}
|
||||
console.log(visuals.widgets.table.horizontal(devices, ['id', 'name', 'device_type', 'is_online', 'application_name', 'status', 'last_seen']));
|
||||
return done();
|
||||
});
|
||||
return resin.models.device.getAll();
|
||||
}).tap(function(devices) {
|
||||
devices = _.map(devices, function(device) {
|
||||
device.uuid = device.uuid.slice(0, 7);
|
||||
return device;
|
||||
});
|
||||
return console.log(visuals.table.horizontal(devices, ['id', 'uuid', 'name', 'device_type', 'application_name', 'status', 'is_online']));
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.info = {
|
||||
signature: 'device <id>',
|
||||
signature: 'device <uuid>',
|
||||
description: 'list a single device',
|
||||
help: 'Use this command to show information about a single device.\n\nExamples:\n\n $ resin device 317',
|
||||
help: 'Use this command to show information about a single device.\n\nExamples:\n\n $ resin device 7cf02a6',
|
||||
permission: 'user',
|
||||
primary: true,
|
||||
action: function(params, options, done) {
|
||||
return resin.models.device.get(params.id, function(error, device) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
console.log(visuals.widgets.table.vertical(device, ['id', 'name', 'device_type', 'is_online', 'ip_address', 'application_name', 'status', 'last_seen', 'uuid', 'commit', 'supervisor_version', 'is_web_accessible', 'note']));
|
||||
return done();
|
||||
});
|
||||
var resin, visuals;
|
||||
resin = require('resin-sdk');
|
||||
visuals = require('resin-cli-visuals');
|
||||
return resin.models.device.get(params.uuid).then(function(device) {
|
||||
return resin.models.device.getStatus(device).then(function(status) {
|
||||
device.status = status;
|
||||
return console.log(visuals.table.vertical(device, ["$" + device.name + "$", 'id', 'device_type', 'status', 'is_online', 'ip_address', 'application_name', 'last_seen', 'uuid', 'commit', 'supervisor_version', 'is_web_accessible', 'note']));
|
||||
});
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.register = {
|
||||
signature: 'device register <application>',
|
||||
description: 'register a device',
|
||||
help: 'Use this command to register a device to an application.\n\nExamples:\n\n $ resin device register MyApp',
|
||||
permission: 'user',
|
||||
options: [
|
||||
{
|
||||
signature: 'uuid',
|
||||
description: 'custom uuid',
|
||||
parameter: 'uuid',
|
||||
alias: 'u'
|
||||
}
|
||||
],
|
||||
action: function(params, options, done) {
|
||||
var Promise, resin;
|
||||
Promise = require('bluebird');
|
||||
resin = require('resin-sdk');
|
||||
return resin.models.application.get(params.application).then(function(application) {
|
||||
return Promise["try"](function() {
|
||||
return options.uuid || resin.models.device.generateUUID();
|
||||
}).then(function(uuid) {
|
||||
console.info("Registering to " + application.app_name + ": " + uuid);
|
||||
return resin.models.device.register(application.app_name, uuid);
|
||||
});
|
||||
}).get('uuid').nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.remove = {
|
||||
signature: 'device rm <id>',
|
||||
signature: 'device rm <uuid>',
|
||||
description: 'remove a device',
|
||||
help: 'Use this command to remove a device from resin.io.\n\nNotice this command asks for confirmation interactively.\nYou can avoid this by passing the `--yes` boolean option.\n\nExamples:\n\n $ resin device rm 317\n $ resin device rm 317 --yes',
|
||||
help: 'Use this command to remove a device from resin.io.\n\nNotice this command asks for confirmation interactively.\nYou can avoid this by passing the `--yes` boolean option.\n\nExamples:\n\n $ resin device rm 7cf02a6\n $ resin device rm 7cf02a6 --yes',
|
||||
options: [commandOptions.yes],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return visuals.patterns.remove('device', options.yes, function(callback) {
|
||||
return resin.models.device.remove(params.id, callback);
|
||||
}, done);
|
||||
var patterns, resin;
|
||||
resin = require('resin-sdk');
|
||||
patterns = require('../utils/patterns');
|
||||
return patterns.confirm(options.yes, 'Are you sure you want to delete the device?').then(function() {
|
||||
return resin.models.device.remove(params.uuid);
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.identify = {
|
||||
signature: 'device identify <uuid>',
|
||||
description: 'identify a device with a UUID',
|
||||
help: 'Use this command to identify a device.\n\nIn the Raspberry Pi, the ACT led is blinked several times.\n\nExamples:\n\n $ resin device identify 23c73a12e3527df55c60b9ce647640c1b7da1b32d71e6a39849ac0f00db828',
|
||||
help: 'Use this command to identify a device.\n\nIn the Raspberry Pi, the ACT led is blinked several times.\n\nExamples:\n\n $ resin device identify 23c73a1',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.models.device.identify(params.uuid, done);
|
||||
var resin;
|
||||
resin = require('resin-sdk');
|
||||
return resin.models.device.identify(params.uuid).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.reboot = {
|
||||
signature: 'device reboot <uuid>',
|
||||
description: 'restart a device',
|
||||
help: 'Use this command to remotely reboot a device\n\nExamples:\n\n $ resin device reboot 23c73a1',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
var resin;
|
||||
resin = require('resin-sdk');
|
||||
return resin.models.device.reboot(params.uuid).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.rename = {
|
||||
signature: 'device rename <id> [name]',
|
||||
signature: 'device rename <uuid> [newName]',
|
||||
description: 'rename a resin device',
|
||||
help: 'Use this command to rename a device.\n\nIf you omit the name, you\'ll get asked for it interactively.\n\nExamples:\n\n $ resin device rename 317 MyPi\n $ resin device rename 317',
|
||||
help: 'Use this command to rename a device.\n\nIf you omit the name, you\'ll get asked for it interactively.\n\nExamples:\n\n $ resin device rename 7cf02a6\n $ resin device rename 7cf02a6 MyPi',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
if (!_.isEmpty(params.name)) {
|
||||
return callback(null, params.name);
|
||||
}
|
||||
return visuals.widgets.ask('How do you want to name this device?', null, callback);
|
||||
}, function(name, callback) {
|
||||
return resin.models.device.rename(params.id, name, callback);
|
||||
var Promise, _, form, resin;
|
||||
Promise = require('bluebird');
|
||||
_ = require('lodash');
|
||||
resin = require('resin-sdk');
|
||||
form = require('resin-cli-form');
|
||||
return Promise["try"](function() {
|
||||
if (!_.isEmpty(params.newName)) {
|
||||
return params.newName;
|
||||
}
|
||||
], done);
|
||||
return form.ask({
|
||||
message: 'How do you want to name this device?',
|
||||
type: 'input'
|
||||
});
|
||||
}).then(_.partial(resin.models.device.rename, params.uuid)).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.supported = {
|
||||
signature: 'devices supported',
|
||||
description: 'list all supported devices',
|
||||
help: 'Use this command to get the list of all supported devices\n\nExamples:\n\n $ resin devices supported',
|
||||
exports.move = {
|
||||
signature: 'device move <uuid>',
|
||||
description: 'move a device to another application',
|
||||
help: 'Use this command to move a device to another application you own.\n\nIf you omit the application, you\'ll get asked for it interactively.\n\nExamples:\n\n $ resin device move 7cf02a6\n $ resin device move 7cf02a6 --application MyNewApp',
|
||||
permission: 'user',
|
||||
options: [commandOptions.optionalApplication],
|
||||
action: function(params, options, done) {
|
||||
return resin.models.device.getSupportedDeviceTypes(function(error, devices) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
_.each(devices, _.unary(console.log));
|
||||
return done();
|
||||
});
|
||||
var _, patterns, resin;
|
||||
resin = require('resin-sdk');
|
||||
_ = require('lodash');
|
||||
patterns = require('../utils/patterns');
|
||||
return resin.models.device.get(params.uuid).then(function(device) {
|
||||
return options.application || patterns.selectApplication(function(application) {
|
||||
return _.all([application.device_type === device.device_type, device.application_name !== application.app_name]);
|
||||
});
|
||||
}).tap(function(application) {
|
||||
return resin.models.device.move(params.uuid, application);
|
||||
}).then(function(application) {
|
||||
return console.info(params.uuid + " was moved to " + application);
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.init = {
|
||||
signature: 'device init [device]',
|
||||
signature: 'device init',
|
||||
description: 'initialise a device with resin os',
|
||||
help: 'Use this command to download the OS image of a certain application and write it to an SD Card.\n\nNote that this command requires admin privileges.\n\nIf `device` is omitted, you will be prompted to select a device interactively.\n\nNotice this command asks for confirmation interactively.\nYou can avoid this by passing the `--yes` boolean option.\n\nYou can quiet the progress bar by passing the `--quiet` boolean option.\n\nYou may have to unmount the device before attempting this operation.\n\nYou need to configure the network type and other settings:\n\nEthernet:\n You can setup the device OS to use ethernet by setting the `--network` option to "ethernet".\n\nWifi:\n You can setup the device OS to use wifi by setting the `--network` option to "wifi".\n If you set "network" to "wifi", you will need to specify the `--ssid` and `--key` option as well.\n\nYou can omit network related options to be asked about them interactively.\n\nExamples:\n\n $ resin device init --application 91\n $ resin device init --application 91 --network ethernet\n $ resin device init /dev/disk2 --application 91 --network wifi --ssid MyNetwork --key secret',
|
||||
options: [commandOptions.optionalApplication, commandOptions.network, commandOptions.wifiSsid, commandOptions.wifiKey],
|
||||
help: 'Use this command to download the OS image of a certain application and write it to an SD Card.\n\nNotice this command may ask for confirmation interactively.\nYou can avoid this by passing the `--yes` boolean option.\n\nExamples:\n\n $ resin device init\n $ resin device init --application MyApp',
|
||||
options: [
|
||||
commandOptions.optionalApplication, commandOptions.yes, {
|
||||
signature: 'advanced',
|
||||
description: 'enable advanced configuration',
|
||||
boolean: true,
|
||||
alias: 'v'
|
||||
}
|
||||
],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
params.id = options.application;
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
if (options.application != null) {
|
||||
return callback(null, options.application);
|
||||
}
|
||||
return vcs.getApplicationId(process.cwd(), callback);
|
||||
}, function(applicationId, callback) {
|
||||
params.id = applicationId;
|
||||
if (params.device != null) {
|
||||
return callback(null, params.device);
|
||||
}
|
||||
return visuals.patterns.selectDrive(callback);
|
||||
}, function(device, callback) {
|
||||
params.device = device;
|
||||
return visuals.patterns.confirm(options.yes, "This will completely erase " + params.device + ". Are you sure you want to continue?", callback);
|
||||
}, function(confirmed, callback) {
|
||||
if (!confirmed) {
|
||||
return done();
|
||||
}
|
||||
options.yes = confirmed;
|
||||
return osAction.download.action(params, options, callback);
|
||||
}, function(outputFile, callback) {
|
||||
params.image = outputFile;
|
||||
return osAction.install.action(params, options, callback);
|
||||
var Promise, capitano, helpers, patterns, resin, rimraf, tmp;
|
||||
Promise = require('bluebird');
|
||||
capitano = Promise.promisifyAll(require('capitano'));
|
||||
rimraf = Promise.promisify(require('rimraf'));
|
||||
tmp = Promise.promisifyAll(require('tmp'));
|
||||
tmp.setGracefulCleanup();
|
||||
resin = require('resin-sdk');
|
||||
helpers = require('../utils/helpers');
|
||||
patterns = require('../utils/patterns');
|
||||
return Promise["try"](function() {
|
||||
if (options.application != null) {
|
||||
return options.application;
|
||||
}
|
||||
], done);
|
||||
return patterns.selectApplication();
|
||||
}).then(resin.models.application.get).then(function(application) {
|
||||
var download;
|
||||
download = function() {
|
||||
return tmp.tmpNameAsync().then(function(temporalPath) {
|
||||
return capitano.runAsync("os download " + application.device_type + " --output " + temporalPath);
|
||||
}).disposer(function(temporalPath) {
|
||||
return rimraf(temporalPath);
|
||||
});
|
||||
};
|
||||
return Promise.using(download(), function(temporalPath) {
|
||||
return capitano.runAsync("device register " + application.app_name).then(resin.models.device.get).tap(function(device) {
|
||||
var configure;
|
||||
configure = "os configure " + temporalPath + " " + device.uuid;
|
||||
if (options.advanced) {
|
||||
configure += ' --advanced';
|
||||
}
|
||||
return capitano.runAsync(configure).then(function() {
|
||||
var message;
|
||||
message = 'Initializing a device requires administrative permissions\ngiven that we need to access raw devices directly.\n';
|
||||
return helpers.sudo(['os', 'initialize', temporalPath, '--type', application.device_type], message);
|
||||
})["catch"](function(error) {
|
||||
return resin.models.device.remove(device.uuid)["finally"](function() {
|
||||
throw error;
|
||||
});
|
||||
});
|
||||
});
|
||||
}).then(function(device) {
|
||||
console.log('Done');
|
||||
return device.uuid;
|
||||
});
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,33 +0,0 @@
|
||||
(function() {
|
||||
var _, async, drivelist, visuals;
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
async = require('async');
|
||||
|
||||
visuals = require('resin-cli-visuals');
|
||||
|
||||
drivelist = require('drivelist');
|
||||
|
||||
exports.list = {
|
||||
signature: 'drives',
|
||||
description: 'list available drives',
|
||||
help: 'Use this command to list all drives that are connected to your machine.\n\nExamples:\n\n $ resin drives',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return drivelist.list(function(error, drives) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
return async.reject(drives, drivelist.isSystem, function(removableDrives) {
|
||||
if (_.isEmpty(removableDrives)) {
|
||||
return done(new Error('No removable devices available'));
|
||||
}
|
||||
console.log(visuals.widgets.table.horizontal(removableDrives, ['device', 'description', 'size']));
|
||||
return done();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
87
build/actions/enter.js
Normal file
87
build/actions/enter.js
Normal file
@ -0,0 +1,87 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var getSubShellCommand;
|
||||
|
||||
getSubShellCommand = function(command) {
|
||||
var os;
|
||||
os = require('os');
|
||||
if (os.platform() === 'win32') {
|
||||
return {
|
||||
program: 'sh',
|
||||
args: ['-c', command]
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
program: '/bin/sh',
|
||||
args: ['-c', command]
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
signature: 'enter <uuid>',
|
||||
description: '(beta) get a shell into the running app container of a device',
|
||||
help: 'Use this command to get a shell into the running application container of\nyour device.\n\nExamples:\n\n $ resin enter 7cf02a6\n $ resin enter 7cf02a6 --port 8080',
|
||||
permission: 'user',
|
||||
primary: true,
|
||||
options: [
|
||||
{
|
||||
signature: 'port',
|
||||
parameter: 'port',
|
||||
description: 'ssh port',
|
||||
alias: 't'
|
||||
}
|
||||
],
|
||||
action: function(params, options, done) {
|
||||
var Promise, child_process, resin, settings;
|
||||
child_process = require('child_process');
|
||||
Promise = require('bluebird');
|
||||
resin = require('resin-sdk');
|
||||
settings = require('resin-settings-client');
|
||||
if (options.port == null) {
|
||||
options.port = 22;
|
||||
}
|
||||
console.info("Connecting with: " + params.uuid);
|
||||
return Promise.props({
|
||||
isOnline: resin.models.device.isOnline(params.uuid),
|
||||
username: resin.auth.whoami(),
|
||||
uuid: resin.models.device.get(params.uuid).get('uuid'),
|
||||
containerId: resin.models.device.getApplicationInfo(params.uuid).get('containerId')
|
||||
}).then(function(arg) {
|
||||
var containerId, isOnline, username, uuid;
|
||||
isOnline = arg.isOnline, username = arg.username, uuid = arg.uuid, containerId = arg.containerId;
|
||||
if (!isOnline) {
|
||||
throw new Error('Device is not online');
|
||||
}
|
||||
if (containerId == null) {
|
||||
throw new Error('Did not find running application container');
|
||||
}
|
||||
return Promise["try"](function() {
|
||||
var command, spawn, subShellCommand;
|
||||
command = "ssh -t -p " + options.port + " " + username + "@" + (settings.get('proxyUrl')) + " enter " + uuid + " " + containerId;
|
||||
subShellCommand = getSubShellCommand(command);
|
||||
return spawn = child_process.spawn(subShellCommand.program, subShellCommand.args, {
|
||||
stdio: 'inherit'
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
@ -1,20 +1,31 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var _, commandOptions, resin, visuals;
|
||||
|
||||
_ = require('lodash-contrib');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
visuals = require('resin-cli-visuals');
|
||||
var commandOptions;
|
||||
|
||||
commandOptions = require('./command-options');
|
||||
|
||||
exports.list = {
|
||||
signature: 'envs',
|
||||
description: 'list all environment variables',
|
||||
help: 'Use this command to list all environment variables for a particular application.\nNotice we will support per-device environment variables soon.\n\nThis command lists all custom environment variables set on the devices running\nthe application. If you want to see all environment variables, including private\nones used by resin, use the verbose option.\n\nExample:\n\n $ resin envs --application 91\n $ resin envs --application 91 --verbose',
|
||||
help: 'Use this command to list all environment variables for\na particular application or device.\n\nThis command lists all custom environment variables.\nIf you want to see all environment variables, including private\nones used by resin, use the verbose option.\n\nExample:\n\n $ resin envs --application MyApp\n $ resin envs --application MyApp --verbose\n $ resin envs --device 7cf02a6',
|
||||
options: [
|
||||
commandOptions.application, {
|
||||
commandOptions.optionalApplication, commandOptions.optionalDevice, {
|
||||
signature: 'verbose',
|
||||
description: 'show private environment variables',
|
||||
boolean: true,
|
||||
@ -23,58 +34,100 @@
|
||||
],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.models.environmentVariables.getAllByApplication(options.application, function(error, environmentVariables) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
var Promise, _, resin, visuals;
|
||||
Promise = require('bluebird');
|
||||
_ = require('lodash');
|
||||
resin = require('resin-sdk');
|
||||
visuals = require('resin-cli-visuals');
|
||||
return Promise["try"](function() {
|
||||
if (options.application != null) {
|
||||
return resin.models.environmentVariables.getAllByApplication(options.application);
|
||||
} else if (options.device != null) {
|
||||
return resin.models.environmentVariables.device.getAll(options.device);
|
||||
} else {
|
||||
throw new Error('You must specify an application or device');
|
||||
}
|
||||
}).tap(function(environmentVariables) {
|
||||
var isSystemVariable;
|
||||
if (_.isEmpty(environmentVariables)) {
|
||||
throw new Error('No environment variables found');
|
||||
}
|
||||
if (!options.verbose) {
|
||||
environmentVariables = _.reject(environmentVariables, resin.models.environmentVariables.isSystemVariable);
|
||||
isSystemVariable = resin.models.environmentVariables.isSystemVariable;
|
||||
environmentVariables = _.reject(environmentVariables, isSystemVariable);
|
||||
}
|
||||
console.log(visuals.widgets.table.horizontal(environmentVariables, ['id', 'name', 'value']));
|
||||
return done();
|
||||
});
|
||||
return console.log(visuals.table.horizontal(environmentVariables, ['id', 'name', 'value']));
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.remove = {
|
||||
signature: 'env rm <id>',
|
||||
description: 'remove an environment variable',
|
||||
help: 'Use this command to remove an environment variable from an application.\n\nDon\'t remove resin specific variables, as things might not work as expected.\n\nNotice this command asks for confirmation interactively.\nYou can avoid this by passing the `--yes` boolean option.\n\nExamples:\n\n $ resin env rm 215\n $ resin env rm 215 --yes',
|
||||
options: [commandOptions.yes],
|
||||
help: 'Use this command to remove an environment variable from an application.\n\nDon\'t remove resin specific variables, as things might not work as expected.\n\nNotice this command asks for confirmation interactively.\nYou can avoid this by passing the `--yes` boolean option.\n\nIf you want to eliminate a device environment variable, pass the `--device` boolean option.\n\nExamples:\n\n $ resin env rm 215\n $ resin env rm 215 --yes\n $ resin env rm 215 --device',
|
||||
options: [commandOptions.yes, commandOptions.booleanDevice],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return visuals.patterns.remove('environment variable', options.yes, function(callback) {
|
||||
return resin.models.environmentVariables.remove(params.id, callback);
|
||||
}, done);
|
||||
var patterns, resin;
|
||||
resin = require('resin-sdk');
|
||||
patterns = require('../utils/patterns');
|
||||
return patterns.confirm(options.yes, 'Are you sure you want to delete the environment variable?').then(function() {
|
||||
if (options.device) {
|
||||
return resin.models.environmentVariables.device.remove(params.id);
|
||||
} else {
|
||||
return resin.models.environmentVariables.remove(params.id);
|
||||
}
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.add = {
|
||||
signature: 'env add <key> [value]',
|
||||
description: 'add an environment variable',
|
||||
help: 'Use this command to add an enviroment variable to an application.\n\nYou need to pass the `--application` option.\n\nIf value is omitted, the tool will attempt to use the variable\'s value\nas defined in your host machine.\n\nIf the value is grabbed from the environment, a warning message will be printed.\nUse `--quiet` to remove it.\n\nExamples:\n\n $ resin env add EDITOR vim -a 91\n $ resin env add TERM -a 91',
|
||||
options: [commandOptions.application],
|
||||
help: 'Use this command to add an enviroment variable to an application.\n\nIf value is omitted, the tool will attempt to use the variable\'s value\nas defined in your host machine.\n\nUse the `--device` option if you want to assign the environment variable\nto a specific device.\n\nIf the value is grabbed from the environment, a warning message will be printed.\nUse `--quiet` to remove it.\n\nExamples:\n\n $ resin env add EDITOR vim --application MyApp\n $ resin env add TERM --application MyApp\n $ resin env add EDITOR vim --device 7cf02a6',
|
||||
options: [commandOptions.optionalApplication, commandOptions.optionalDevice],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
if (params.value == null) {
|
||||
params.value = process.env[params.key];
|
||||
var Promise, resin;
|
||||
Promise = require('bluebird');
|
||||
resin = require('resin-sdk');
|
||||
return Promise["try"](function() {
|
||||
if (params.value == null) {
|
||||
return done(new Error("Environment value not found for key: " + params.key));
|
||||
} else {
|
||||
console.info("Warning: using " + params.key + "=" + params.value + " from host environment");
|
||||
params.value = process.env[params.key];
|
||||
if (params.value == null) {
|
||||
throw new Error("Environment value not found for key: " + params.key);
|
||||
} else {
|
||||
console.info("Warning: using " + params.key + "=" + params.value + " from host environment");
|
||||
}
|
||||
}
|
||||
}
|
||||
return resin.models.environmentVariables.create(options.application, params.key, params.value, done);
|
||||
if (options.application != null) {
|
||||
return resin.models.environmentVariables.create(options.application, params.key, params.value);
|
||||
} else if (options.device != null) {
|
||||
return resin.models.environmentVariables.device.create(options.device, params.key, params.value);
|
||||
} else {
|
||||
throw new Error('You must specify an application or device');
|
||||
}
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.rename = {
|
||||
signature: 'env rename <id> <value>',
|
||||
description: 'rename an environment variable',
|
||||
help: 'Use this command to rename an enviroment variable from an application.\n\nExamples:\n\n $ resin env rename 376 emacs',
|
||||
help: 'Use this command to rename an enviroment variable from an application.\n\nPass the `--device` boolean option if you want to rename a device environment variable.\n\nExamples:\n\n $ resin env rename 376 emacs\n $ resin env rename 376 emacs --device',
|
||||
permission: 'user',
|
||||
options: [commandOptions.booleanDevice],
|
||||
action: function(params, options, done) {
|
||||
return resin.models.environmentVariables.update(params.id, params.value, done);
|
||||
var Promise, resin;
|
||||
Promise = require('bluebird');
|
||||
resin = require('resin-sdk');
|
||||
return Promise["try"](function() {
|
||||
if (options.device) {
|
||||
return resin.models.environmentVariables.device.update(params.id, params.value);
|
||||
} else {
|
||||
return resin.models.environmentVariables.update(params.id, params.value);
|
||||
}
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,78 +0,0 @@
|
||||
(function() {
|
||||
var _, async, examplesData, fs, path, resin, vcs, visuals;
|
||||
|
||||
async = require('async');
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
path = require('path');
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
visuals = require('resin-cli-visuals');
|
||||
|
||||
vcs = require('resin-vcs');
|
||||
|
||||
examplesData = require('../data/examples.json');
|
||||
|
||||
exports.list = {
|
||||
signature: 'examples',
|
||||
description: 'list all example applications',
|
||||
help: 'Use this command to list available example applications from resin.io\n\nExample:\n\n $ resin examples',
|
||||
permission: 'user',
|
||||
action: function() {
|
||||
examplesData = _.map(examplesData, function(example, index) {
|
||||
example.id = index + 1;
|
||||
return example;
|
||||
});
|
||||
examplesData = _.map(examplesData, function(example) {
|
||||
if (example.author == null) {
|
||||
example.author = 'Unknown';
|
||||
}
|
||||
return example;
|
||||
});
|
||||
return console.log(visuals.widgets.table.horizontal(examplesData, ['id', 'display_name', 'repository', 'author']));
|
||||
}
|
||||
};
|
||||
|
||||
exports.info = {
|
||||
signature: 'example <id>',
|
||||
description: 'list a single example application',
|
||||
help: 'Use this command to show information of a single example application\n\nExample:\n\n $ resin example 3',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
var example, id;
|
||||
id = params.id - 1;
|
||||
example = examplesData[id];
|
||||
if (example == null) {
|
||||
return done(new Error("Unknown example: " + id));
|
||||
}
|
||||
example.id = id;
|
||||
if (example.author == null) {
|
||||
example.author = 'Unknown';
|
||||
}
|
||||
console.log(visuals.widgets.table.vertical(example, ['id', 'display_name', 'description', 'author', 'repository']));
|
||||
return done();
|
||||
}
|
||||
};
|
||||
|
||||
exports.clone = {
|
||||
signature: 'example clone <id>',
|
||||
description: 'clone an example application',
|
||||
help: 'Use this command to clone an example application to the current directory\n\nThis command outputs information about the cloning process.\nUse `--quiet` to remove that output.\n\nExample:\n\n $ resin example clone 3',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
var currentDirectory, example;
|
||||
example = examplesData[params.id - 1];
|
||||
if (example == null) {
|
||||
return done(new Error("Unknown example: " + id));
|
||||
}
|
||||
currentDirectory = process.cwd();
|
||||
console.info("Cloning " + example.display_name + " to " + currentDirectory);
|
||||
return vcs.clone(example.repository, currentDirectory, done);
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
@ -1,125 +1,101 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var PADDING_INITIAL, PADDING_MIDDLE, _, addAlias, addOptionPrefix, buildHelpString, buildOptionSignatureHelp, capitano, command, general, getCommandHelp, getFieldMaxLength, getOptionHelp, getOptionsParsedSignatures, resin;
|
||||
var _, capitano, columnify, command, general, indent, messages, parse, print;
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
_.str = require('underscore.string');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
capitano = require('capitano');
|
||||
|
||||
PADDING_INITIAL = ' ';
|
||||
columnify = require('columnify');
|
||||
|
||||
PADDING_MIDDLE = '\t';
|
||||
messages = require('../utils/messages');
|
||||
|
||||
getFieldMaxLength = function(array, field) {
|
||||
return _.max(_.map(array, function(item) {
|
||||
return item[field].toString().length;
|
||||
}));
|
||||
};
|
||||
|
||||
buildHelpString = function(firstColumn, secondColumn) {
|
||||
var result;
|
||||
result = "" + PADDING_INITIAL + firstColumn;
|
||||
result += "" + PADDING_MIDDLE + secondColumn;
|
||||
return result;
|
||||
};
|
||||
|
||||
addOptionPrefix = function(option) {
|
||||
if (option.length <= 0) {
|
||||
return;
|
||||
}
|
||||
if (option.length === 1) {
|
||||
return "-" + option;
|
||||
} else {
|
||||
return "--" + option;
|
||||
}
|
||||
};
|
||||
|
||||
addAlias = function(alias) {
|
||||
return ", " + (addOptionPrefix(alias));
|
||||
};
|
||||
|
||||
buildOptionSignatureHelp = function(option) {
|
||||
var alias, i, len, ref, result;
|
||||
result = addOptionPrefix(option.signature.toString());
|
||||
if (_.isString(option.alias)) {
|
||||
result += addAlias(option.alias);
|
||||
} else if (_.isArray(option.alias)) {
|
||||
ref = option.alias;
|
||||
for (i = 0, len = ref.length; i < len; i++) {
|
||||
alias = ref[i];
|
||||
result += addAlias(alias);
|
||||
parse = function(object) {
|
||||
return _.object(_.map(object, function(item) {
|
||||
var signature;
|
||||
if (item.alias != null) {
|
||||
signature = item.toString();
|
||||
} else {
|
||||
signature = item.signature.toString();
|
||||
}
|
||||
}
|
||||
if (option.parameter != null) {
|
||||
result += " <" + option.parameter + ">";
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
getCommandHelp = function(command) {
|
||||
var commandSignature, maxSignatureLength;
|
||||
maxSignatureLength = getFieldMaxLength(capitano.state.commands, 'signature');
|
||||
commandSignature = _.str.rpad(command.signature.toString(), maxSignatureLength, ' ');
|
||||
return buildHelpString(commandSignature, command.description);
|
||||
};
|
||||
|
||||
getOptionsParsedSignatures = function(optionsHelp) {
|
||||
var maxLength;
|
||||
maxLength = _.max(_.map(optionsHelp, function(signature) {
|
||||
return signature.length;
|
||||
return [signature, item.description];
|
||||
}));
|
||||
return _.map(optionsHelp, function(signature) {
|
||||
return _.str.rpad(signature, maxLength, ' ');
|
||||
};
|
||||
|
||||
indent = function(text) {
|
||||
text = _.map(_.str.lines(text), function(line) {
|
||||
return ' ' + line;
|
||||
});
|
||||
return text.join('\n');
|
||||
};
|
||||
|
||||
getOptionHelp = function(option, maxLength) {
|
||||
var result;
|
||||
result = PADDING_INITIAL;
|
||||
result += _.str.rpad(option.signature, maxLength, ' ');
|
||||
result += PADDING_MIDDLE;
|
||||
result += option.description;
|
||||
return result;
|
||||
print = function(data) {
|
||||
return console.log(indent(columnify(data, {
|
||||
showHeaders: false,
|
||||
minWidth: 35
|
||||
})));
|
||||
};
|
||||
|
||||
general = function() {
|
||||
var command, i, j, len, len1, option, optionSignatureMaxLength, options, ref;
|
||||
general = function(params, options, done) {
|
||||
var commands, groupedCommands;
|
||||
console.log('Usage: resin [COMMAND] [OPTIONS]\n');
|
||||
console.log('Commands:\n');
|
||||
ref = capitano.state.commands;
|
||||
for (i = 0, len = ref.length; i < len; i++) {
|
||||
command = ref[i];
|
||||
if (command.isWildcard()) {
|
||||
continue;
|
||||
}
|
||||
console.log(getCommandHelp(command));
|
||||
}
|
||||
console.log('\nGlobal Options:\n');
|
||||
options = _.map(capitano.state.globalOptions, function(option) {
|
||||
option.signature = buildOptionSignatureHelp(option);
|
||||
return option;
|
||||
console.log(messages.gettingStarted + "\n");
|
||||
console.log(messages.reachingOut);
|
||||
console.log('\nPrimary commands:\n');
|
||||
commands = _.reject(capitano.state.commands, function(command) {
|
||||
return command.isWildcard();
|
||||
});
|
||||
optionSignatureMaxLength = _.max(_.map(options, function(option) {
|
||||
return option.signature.length;
|
||||
}));
|
||||
for (j = 0, len1 = options.length; j < len1; j++) {
|
||||
option = options[j];
|
||||
console.log(getOptionHelp(option, optionSignatureMaxLength));
|
||||
groupedCommands = _.groupBy(commands, function(command) {
|
||||
if (command.plugin) {
|
||||
return 'plugins';
|
||||
} else if (command.primary) {
|
||||
return 'primary';
|
||||
}
|
||||
return 'secondary';
|
||||
});
|
||||
print(parse(groupedCommands.primary));
|
||||
if (options.verbose) {
|
||||
if (!_.isEmpty(groupedCommands.plugins)) {
|
||||
console.log('\nInstalled plugins:\n');
|
||||
print(parse(groupedCommands.plugins));
|
||||
}
|
||||
console.log('\nAdditional commands:\n');
|
||||
print(parse(groupedCommands.secondary));
|
||||
} else {
|
||||
console.log('\nRun `resin help --verbose` to list additional commands');
|
||||
}
|
||||
return console.log();
|
||||
if (!_.isEmpty(capitano.state.globalOptions)) {
|
||||
console.log('\nGlobal Options:\n');
|
||||
print(parse(capitano.state.globalOptions));
|
||||
}
|
||||
return done();
|
||||
};
|
||||
|
||||
command = function(params, options, done) {
|
||||
return capitano.state.getMatchCommand(params.command, function(error, command) {
|
||||
var i, len, option, optionSignatureMaxLength;
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
if ((command == null) || command.isWildcard()) {
|
||||
return capitano.defaults.actions.commandNotFound(params.command);
|
||||
return done(new Error("Command not found: " + params.command));
|
||||
}
|
||||
console.log("Usage: " + command.signature);
|
||||
if (command.help != null) {
|
||||
@ -129,18 +105,7 @@
|
||||
}
|
||||
if (!_.isEmpty(command.options)) {
|
||||
console.log('\nOptions:\n');
|
||||
options = _.map(command.options, function(option) {
|
||||
option.signature = buildOptionSignatureHelp(option);
|
||||
return option;
|
||||
});
|
||||
optionSignatureMaxLength = _.max(_.map(options, function(option) {
|
||||
return option.signature.toString().length;
|
||||
}));
|
||||
for (i = 0, len = options.length; i < len; i++) {
|
||||
option = options[i];
|
||||
console.log(getOptionHelp(option, optionSignatureMaxLength));
|
||||
}
|
||||
console.log();
|
||||
print(parse(command.options));
|
||||
}
|
||||
return done();
|
||||
});
|
||||
@ -150,6 +115,15 @@
|
||||
signature: 'help [command...]',
|
||||
description: 'show help',
|
||||
help: 'Get detailed help for an specific command.\n\nExamples:\n\n $ resin help apps\n $ resin help os download',
|
||||
primary: true,
|
||||
options: [
|
||||
{
|
||||
signature: 'verbose',
|
||||
description: 'show additional commands',
|
||||
boolean: true,
|
||||
alias: 'v'
|
||||
}
|
||||
],
|
||||
action: function(params, options, done) {
|
||||
if (params.command != null) {
|
||||
return command(params, options, done);
|
||||
|
@ -1,20 +1,37 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
module.exports = {
|
||||
wizard: require('./wizard'),
|
||||
app: require('./app'),
|
||||
info: require('./info'),
|
||||
auth: require('./auth'),
|
||||
drive: require('./drive'),
|
||||
device: require('./device'),
|
||||
env: require('./environment-variables'),
|
||||
keys: require('./keys'),
|
||||
logs: require('./logs'),
|
||||
notes: require('./notes'),
|
||||
preferences: require('./preferences'),
|
||||
os: require('./os'),
|
||||
help: require('./help'),
|
||||
examples: require('./examples'),
|
||||
plugin: require('./plugin'),
|
||||
update: require('./update')
|
||||
os: require('./os'),
|
||||
settings: require('./settings'),
|
||||
config: require('./config'),
|
||||
sync: require('./sync'),
|
||||
ssh: require('./ssh')
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
@ -1,15 +1,30 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var packageJSON;
|
||||
|
||||
packageJSON = require('../../package.json');
|
||||
|
||||
exports.version = {
|
||||
signature: 'version',
|
||||
description: 'output the version number',
|
||||
help: 'Display the Resin CLI, as well as the bundled NodeJS version.',
|
||||
action: function() {
|
||||
console.log(packageJSON.name + ": " + packageJSON.version);
|
||||
return console.log("node: " + process.version);
|
||||
help: 'Display the Resin CLI version.',
|
||||
action: function(params, options, done) {
|
||||
var packageJSON;
|
||||
packageJSON = require('../../package.json');
|
||||
console.log(packageJSON.version);
|
||||
return done();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,19 +1,22 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var _, async, capitano, commandOptions, fs, resin, visuals;
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
_.str = require('underscore.string');
|
||||
|
||||
async = require('async');
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
capitano = require('capitano');
|
||||
|
||||
visuals = require('resin-cli-visuals');
|
||||
var commandOptions;
|
||||
|
||||
commandOptions = require('./command-options');
|
||||
|
||||
@ -23,13 +26,12 @@
|
||||
help: 'Use this command to list all your SSH keys.\n\nExamples:\n\n $ resin keys',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.models.key.getAll(function(error, keys) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
console.log(visuals.widgets.table.horizontal(keys, ['id', 'title']));
|
||||
return done();
|
||||
});
|
||||
var resin, visuals;
|
||||
resin = require('resin-sdk');
|
||||
visuals = require('resin-cli-visuals');
|
||||
return resin.models.key.getAll().then(function(keys) {
|
||||
return console.log(visuals.table.horizontal(keys, ['id', 'title']));
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
@ -39,16 +41,13 @@
|
||||
help: 'Use this command to show information about a single SSH key.\n\nExamples:\n\n $ resin key 17',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.models.key.get(params.id, function(error, key) {
|
||||
var sshKeyWidth;
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
sshKeyWidth = resin.settings.get('sshKeyWidth');
|
||||
key.public_key = '\n' + visuals.helpers.chop(key.public_key, sshKeyWidth);
|
||||
console.log(visuals.widgets.table.vertical(key, ['id', 'title', 'public_key']));
|
||||
return done();
|
||||
});
|
||||
var resin, visuals;
|
||||
resin = require('resin-sdk');
|
||||
visuals = require('resin-cli-visuals');
|
||||
return resin.models.key.get(params.id).then(function(key) {
|
||||
console.log(visuals.table.vertical(key, ['id', 'title']));
|
||||
return console.log('\n' + key.public_key);
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
@ -59,9 +58,12 @@
|
||||
options: [commandOptions.yes],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return visuals.patterns.remove('key', options.yes, function(callback) {
|
||||
return resin.models.key.remove(params.id, callback);
|
||||
}, done);
|
||||
var patterns, resin;
|
||||
resin = require('resin-sdk');
|
||||
patterns = require('../utils/patterns');
|
||||
return patterns.confirm(options.yes, 'Are you sure you want to delete the key?').then(function() {
|
||||
return resin.models.key.remove(params.id);
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
@ -71,21 +73,24 @@
|
||||
help: 'Use this command to associate a new SSH key with your account.\n\nIf `path` is omitted, the command will attempt\nto read the SSH key from stdin.\n\nExamples:\n\n $ resin key add Main ~/.ssh/id_rsa.pub\n $ cat ~/.ssh/id_rsa.pub | resin key add Main',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
if (params.path != null) {
|
||||
return fs.readFile(params.path, {
|
||||
encoding: 'utf8'
|
||||
}, callback);
|
||||
} else {
|
||||
return capitano.utils.getStdin(function(data) {
|
||||
return callback(null, data);
|
||||
});
|
||||
}
|
||||
}, function(key, callback) {
|
||||
return resin.models.key.create(params.name, key, callback);
|
||||
var Promise, _, capitano, fs, resin;
|
||||
_ = require('lodash');
|
||||
Promise = require('bluebird');
|
||||
fs = Promise.promisifyAll(require('fs'));
|
||||
capitano = require('capitano');
|
||||
resin = require('resin-sdk');
|
||||
return Promise["try"](function() {
|
||||
if (params.path != null) {
|
||||
return fs.readFileAsync(params.path, {
|
||||
encoding: 'utf8'
|
||||
});
|
||||
}
|
||||
], done);
|
||||
return Promise.fromNode(function(callback) {
|
||||
return capitano.utils.getStdin(function(data) {
|
||||
return callback(null, data);
|
||||
});
|
||||
});
|
||||
}).then(_.partial(resin.models.key.create, params.name)).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,23 +1,27 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var LOGS_HISTORY_COUNT, _, resin;
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
LOGS_HISTORY_COUNT = 200;
|
||||
|
||||
exports.logs = {
|
||||
module.exports = {
|
||||
signature: 'logs <uuid>',
|
||||
description: 'show device logs',
|
||||
help: 'Use this command to show logs for a specific device.\n\nBy default, the command prints all log messages and exit.\n\nTo limit the output to the n last lines, use the `--num` option along with a number.\nThis is similar to doing `resin logs <uuid> | tail -n X`.\n\nTo continuously stream output, and see new logs in real time, use the `--tail` option.\n\nNote that for now you need to provide the whole UUID for this command to work correctly,\nand the tool won\'t notice if you\'re using an invalid UUID.\n\nThis is due to some technical limitations that we plan to address soon.\n\nExamples:\n\n $ resin logs 23c73a12e3527df55c60b9ce647640c1b7da1b32d71e6a39849ac0f00db828\n $ resin logs 23c73a12e3527df55c60b9ce647640c1b7da1b32d71e6a39849ac0f00db828 --num 20\n $ resin logs 23c73a12e3527df55c60b9ce647640c1b7da1b32d71e6a39849ac0f00db828 --tail',
|
||||
help: 'Use this command to show logs for a specific device.\n\nBy default, the command prints all log messages and exit.\n\nTo continuously stream output, and see new logs in real time, use the `--tail` option.\n\nNote that for now you need to provide the whole UUID for this command to work correctly.\n\nThis is due to some technical limitations that we plan to address soon.\n\nExamples:\n\n $ resin logs 23c73a1\n $ resin logs 23c73a1',
|
||||
options: [
|
||||
{
|
||||
signature: 'num',
|
||||
parameter: 'num',
|
||||
description: 'number of lines to display',
|
||||
alias: 'n'
|
||||
}, {
|
||||
signature: 'tail',
|
||||
description: 'continuously stream output',
|
||||
boolean: true,
|
||||
@ -25,23 +29,29 @@
|
||||
}
|
||||
],
|
||||
permission: 'user',
|
||||
primary: true,
|
||||
action: function(params, options, done) {
|
||||
return resin.logs.subscribe(params.uuid, {
|
||||
history: options.num || LOGS_HISTORY_COUNT,
|
||||
tail: options.tail
|
||||
}, function(error, message) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
if (_.isArray(message)) {
|
||||
_.each(message, function(line) {
|
||||
return console.log(line);
|
||||
});
|
||||
} else {
|
||||
console.log(message);
|
||||
}
|
||||
return done();
|
||||
});
|
||||
var _, moment, printLine, promise, resin;
|
||||
_ = require('lodash');
|
||||
resin = require('resin-sdk');
|
||||
moment = require('moment');
|
||||
printLine = function(line) {
|
||||
var timestamp;
|
||||
timestamp = moment(line.timestamp).format('DD.MM.YY HH:mm:ss (ZZ)');
|
||||
return console.log(timestamp + " " + line.message);
|
||||
};
|
||||
promise = resin.logs.history(params.uuid).each(printLine);
|
||||
if (!options.tail) {
|
||||
return promise["catch"](done)["finally"](function() {
|
||||
return process.exit(0);
|
||||
});
|
||||
}
|
||||
return promise.then(function() {
|
||||
return resin.logs.subscribe(params.uuid).then(function(logs) {
|
||||
logs.on('line', printLine);
|
||||
return logs.on('error', done);
|
||||
});
|
||||
})["catch"](done);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,26 +1,46 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var async, resin;
|
||||
|
||||
async = require('async');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
exports.set = {
|
||||
signature: 'note <|note>',
|
||||
description: 'set a device note',
|
||||
help: 'Use this command to set or update a device note.\n\nIf note command isn\'t passed, the tool attempts to read from `stdin`.\n\nTo view the notes, use $ resin device <id>.\n\nExamples:\n\n $ resin note "My useful note" --device 317\n $ cat note.txt | resin note --device 317',
|
||||
help: 'Use this command to set or update a device note.\n\nIf note command isn\'t passed, the tool attempts to read from `stdin`.\n\nTo view the notes, use $ resin device <uuid>.\n\nExamples:\n\n $ resin note "My useful note" --device 7cf02a6\n $ cat note.txt | resin note --device 7cf02a6',
|
||||
options: [
|
||||
{
|
||||
signature: 'device',
|
||||
parameter: 'device',
|
||||
description: 'device id',
|
||||
description: 'device uuid',
|
||||
alias: ['d', 'dev'],
|
||||
required: 'You have to specify a device'
|
||||
}
|
||||
],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.models.device.note(options.device, params.note, done);
|
||||
var Promise, _, resin;
|
||||
Promise = require('bluebird');
|
||||
_ = require('lodash');
|
||||
resin = require('resin-sdk');
|
||||
return Promise["try"](function() {
|
||||
if (_.isEmpty(params.note)) {
|
||||
throw new Error('Missing note content');
|
||||
}
|
||||
return resin.models.device.note(options.device, params.note);
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,158 +1,190 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var _, async, commandOptions, diskio, fs, mkdirp, npm, os, packageJSON, path, progressStream, resin, updateActions, visuals;
|
||||
|
||||
_ = require('lodash-contrib');
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
os = require('os');
|
||||
|
||||
async = require('async');
|
||||
|
||||
path = require('path');
|
||||
|
||||
mkdirp = require('mkdirp');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
visuals = require('resin-cli-visuals');
|
||||
|
||||
progressStream = require('progress-stream');
|
||||
|
||||
diskio = require('diskio');
|
||||
var commandOptions, stepHandler;
|
||||
|
||||
commandOptions = require('./command-options');
|
||||
|
||||
npm = require('../npm');
|
||||
|
||||
packageJSON = require('../../package.json');
|
||||
|
||||
updateActions = require('./update');
|
||||
|
||||
exports.download = {
|
||||
signature: 'os download <id>',
|
||||
description: 'download device OS',
|
||||
help: 'Use this command to download the device OS configured to a specific network.\n\nEthernet:\n You can setup the device OS to use ethernet by setting the `--network` option to "ethernet".\n\nWifi:\n You can setup the device OS to use wifi by setting the `--network` option to "wifi".\n If you set "network" to "wifi", you will need to specify the `--ssid` and `--key` option as well.\n\nAlternatively, you can omit all kind of network configuration options to configure interactively.\n\nYou have to specify an output location with the `--output` option.\n\nExamples:\n\n $ resin os download 91 --output ~/MyResinOS.zip\n $ resin os download 91 --network ethernet --output ~/MyResinOS.zip\n $ resin os download 91 --network wifi --ssid MyNetwork --key secreykey123 --output ~/MyResinOS.zip\n $ resin os download 91 --network ethernet --output ~/MyResinOS.zip',
|
||||
signature: 'os download <type>',
|
||||
description: 'download an unconfigured os image',
|
||||
help: 'Use this command to download an unconfigured os image for a certain device type.\n\nExamples:\n\n $ resin os download parallella -o ../foo/bar/parallella.img',
|
||||
permission: 'user',
|
||||
options: [
|
||||
commandOptions.network, commandOptions.wifiSsid, commandOptions.wifiKey, {
|
||||
{
|
||||
signature: 'output',
|
||||
description: 'output path',
|
||||
parameter: 'output',
|
||||
description: 'output file',
|
||||
alias: 'o',
|
||||
required: 'You need to specify an output file'
|
||||
required: 'You have to specify an output location'
|
||||
}
|
||||
],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
var osParams;
|
||||
osParams = {
|
||||
network: options.network,
|
||||
wifiSsid: options.ssid,
|
||||
wifiKey: options.key,
|
||||
appId: params.id
|
||||
};
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
if (osParams.network != null) {
|
||||
return callback();
|
||||
}
|
||||
return visuals.patterns.selectNetworkParameters(function(error, parameters) {
|
||||
if (error != null) {
|
||||
return callback(error);
|
||||
}
|
||||
_.extend(osParams, parameters);
|
||||
return callback();
|
||||
});
|
||||
}, function(callback) {
|
||||
return mkdirp(path.dirname(options.output), _.unary(callback));
|
||||
}, function(callback) {
|
||||
var bar;
|
||||
console.info("Destination file: " + options.output + "\n");
|
||||
bar = new visuals.widgets.Progress('Downloading Device OS');
|
||||
return resin.models.os.download(osParams, options.output, callback, function(state) {
|
||||
var fs, manager, rindle, unzip, visuals;
|
||||
unzip = require('unzip2');
|
||||
fs = require('fs');
|
||||
rindle = require('rindle');
|
||||
manager = require('resin-image-manager');
|
||||
visuals = require('resin-cli-visuals');
|
||||
console.info("Getting device operating system for " + params.type);
|
||||
return manager.get(params.type).then(function(stream) {
|
||||
var bar, output, spinner;
|
||||
bar = new visuals.Progress('Downloading Device OS');
|
||||
spinner = new visuals.Spinner('Downloading Device OS (size unknown)');
|
||||
stream.on('progress', function(state) {
|
||||
if (state != null) {
|
||||
return bar.update(state);
|
||||
} else {
|
||||
return spinner.start();
|
||||
}
|
||||
});
|
||||
stream.on('end', function() {
|
||||
return spinner.stop();
|
||||
});
|
||||
if (stream.mime === 'application/zip') {
|
||||
output = unzip.Extract({
|
||||
path: options.output
|
||||
});
|
||||
} else {
|
||||
output = fs.createWriteStream(options.output);
|
||||
}
|
||||
], function(error) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
console.info("\nFinished downloading " + options.output);
|
||||
return done(null, options.output);
|
||||
});
|
||||
return rindle.wait(stream.pipe(output))["return"](options.output);
|
||||
}).tap(function(output) {
|
||||
return console.info('The image was downloaded successfully');
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.install = {
|
||||
signature: 'os install <image> [device]',
|
||||
description: 'write an operating system image to a device',
|
||||
help: 'Use this command to write an operating system image to a device.\n\nNote that this command requires admin privileges.\n\nIf `device` is omitted, you will be prompted to select a device interactively.\n\nNotice this command asks for confirmation interactively.\nYou can avoid this by passing the `--yes` boolean option.\n\nYou can quiet the progress bar by passing the `--quiet` boolean option.\n\nYou may have to unmount the device before attempting this operation.\n\nSee the `drives` command to get a list of all connected devices to your machine and their respective ids.\n\nIn Mac OS X:\n\n $ sudo diskutil unmountDisk /dev/xxx\n\nIn GNU/Linux:\n\n $ sudo umount /dev/xxx\n\nExamples:\n\n $ resin os install rpi.iso /dev/disk2',
|
||||
options: [commandOptions.yes],
|
||||
stepHandler = function(step) {
|
||||
var _, bar, helpers, rindle, visuals;
|
||||
_ = require('lodash');
|
||||
rindle = require('rindle');
|
||||
visuals = require('resin-cli-visuals');
|
||||
helpers = require('../utils/helpers');
|
||||
step.on('stdout', _.bind(process.stdout.write, process.stdout));
|
||||
step.on('stderr', _.bind(process.stderr.write, process.stderr));
|
||||
step.on('state', function(state) {
|
||||
if (state.operation.command === 'burn') {
|
||||
return;
|
||||
}
|
||||
return console.log(helpers.stateToString(state));
|
||||
});
|
||||
bar = new visuals.Progress('Writing Device OS');
|
||||
step.on('burn', _.bind(bar.update, bar));
|
||||
return rindle.wait(step);
|
||||
};
|
||||
|
||||
exports.configure = {
|
||||
signature: 'os configure <image> <uuid>',
|
||||
description: 'configure an os image',
|
||||
help: 'Use this command to configure a previously download operating system image with a device.\n\nExamples:\n\n $ resin os configure ../path/rpi.img 7cf02a6',
|
||||
permission: 'user',
|
||||
options: [
|
||||
{
|
||||
signature: 'advanced',
|
||||
description: 'show advanced commands',
|
||||
boolean: true,
|
||||
alias: 'v'
|
||||
}
|
||||
],
|
||||
action: function(params, options, done) {
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
return npm.isUpdated(packageJSON.name, packageJSON.version, callback);
|
||||
}, function(isUpdated, callback) {
|
||||
if (isUpdated) {
|
||||
return callback();
|
||||
}
|
||||
console.info('Resin CLI is outdated.\n\nIn order to avoid device compatibility issues, this command\nrequires that you have the Resin CLI updated.\n\nUpdating now...');
|
||||
return updateActions.update.action(params, options, _.unary(done));
|
||||
}, function(callback) {
|
||||
if (params.device != null) {
|
||||
return callback(null, params.device);
|
||||
}
|
||||
return visuals.patterns.selectDrive(function(error, device) {
|
||||
if (error != null) {
|
||||
return callback(error);
|
||||
}
|
||||
if (device == null) {
|
||||
return callback(new Error('No removable devices available'));
|
||||
}
|
||||
return callback(null, device);
|
||||
var _, form, helpers, init, resin;
|
||||
_ = require('lodash');
|
||||
resin = require('resin-sdk');
|
||||
form = require('resin-cli-form');
|
||||
init = require('resin-device-init');
|
||||
helpers = require('../utils/helpers');
|
||||
console.info('Configuring operating system image');
|
||||
return resin.models.device.get(params.uuid).get('device_type').then(resin.models.device.getManifestBySlug).get('options').then(function(questions) {
|
||||
var advancedGroup, override;
|
||||
if (!options.advanced) {
|
||||
advancedGroup = _.findWhere(questions, {
|
||||
name: 'advanced',
|
||||
isGroup: true
|
||||
});
|
||||
}, function(device, callback) {
|
||||
var message;
|
||||
params.device = device;
|
||||
message = "This will completely erase " + params.device + ". Are you sure you want to continue?";
|
||||
return visuals.patterns.confirm(options.yes, message, callback);
|
||||
}, function(confirmed, callback) {
|
||||
var bar, error, imageFileSize, imageFileStream, progress;
|
||||
if (!confirmed) {
|
||||
return done();
|
||||
if (advancedGroup != null) {
|
||||
override = helpers.getGroupDefaults(advancedGroup);
|
||||
}
|
||||
imageFileSize = fs.statSync(params.image).size;
|
||||
if (imageFileSize === 0) {
|
||||
error = new Error("Invalid OS image: " + params.image + ". The image is 0 bytes.");
|
||||
return callback(error);
|
||||
}
|
||||
return form.run(questions, {
|
||||
override: override
|
||||
});
|
||||
}).then(function(answers) {
|
||||
return init.configure(params.image, params.uuid, answers).then(stepHandler);
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.initialize = {
|
||||
signature: 'os initialize <image>',
|
||||
description: 'initialize an os image',
|
||||
help: 'Use this command to initialize a previously configured operating system image.\n\nExamples:\n\n $ resin os initialize ../path/rpi.img --type \'raspberry-pi\'',
|
||||
permission: 'user',
|
||||
options: [
|
||||
commandOptions.yes, {
|
||||
signature: 'type',
|
||||
description: 'device type',
|
||||
parameter: 'type',
|
||||
alias: 't',
|
||||
required: 'You have to specify a device type'
|
||||
}, {
|
||||
signature: 'drive',
|
||||
description: 'drive',
|
||||
parameter: 'drive',
|
||||
alias: 'd'
|
||||
}
|
||||
],
|
||||
root: true,
|
||||
action: function(params, options, done) {
|
||||
var Promise, form, init, patterns, resin, umount;
|
||||
Promise = require('bluebird');
|
||||
umount = Promise.promisifyAll(require('umount'));
|
||||
resin = require('resin-sdk');
|
||||
form = require('resin-cli-form');
|
||||
init = require('resin-device-init');
|
||||
patterns = require('../utils/patterns');
|
||||
console.info('Initializing device');
|
||||
return resin.models.device.getManifestBySlug(options.type).then(function(manifest) {
|
||||
var ref;
|
||||
return (ref = manifest.initialization) != null ? ref.options : void 0;
|
||||
}).then(function(questions) {
|
||||
return form.run(questions, {
|
||||
override: {
|
||||
drive: options.drive
|
||||
}
|
||||
progress = progressStream({
|
||||
length: imageFileSize,
|
||||
time: 500
|
||||
});
|
||||
if (!options.quiet) {
|
||||
bar = new visuals.widgets.Progress('Writing Device OS');
|
||||
progress.on('progress', function(status) {
|
||||
return bar.update(status);
|
||||
});
|
||||
}
|
||||
imageFileStream = fs.createReadStream(params.image).pipe(progress);
|
||||
return diskio.writeStream(params.device, imageFileStream, callback);
|
||||
});
|
||||
}).tap(function(answers) {
|
||||
var message;
|
||||
if (answers.drive == null) {
|
||||
return;
|
||||
}
|
||||
], function(error) {
|
||||
var resinWritePath, windosu;
|
||||
if (error == null) {
|
||||
return done();
|
||||
message = "This will erase " + answers.drive + ". Are you sure?";
|
||||
return patterns.confirm(options.yes, message)["return"](answers.drive).then(umount.umountAsync);
|
||||
}).tap(function(answers) {
|
||||
return init.initialize(params.image, options.type, answers).then(stepHandler);
|
||||
}).then(function(answers) {
|
||||
if (answers.drive == null) {
|
||||
return;
|
||||
}
|
||||
if (_.all([os.platform() === 'win32', error.code === 'EPERM' || error.code === 'EACCES', !options.fromScript])) {
|
||||
windosu = require('windosu');
|
||||
resinWritePath = "\"" + (path.join(__dirname, '..', '..', 'bin', 'resin-write')) + "\"";
|
||||
return windosu.exec("\"" + process.argv[0] + "\" " + resinWritePath + " \"" + params.image + "\" \"" + params.device + "\"");
|
||||
} else {
|
||||
return done(error);
|
||||
}
|
||||
});
|
||||
return umount.umountAsync(answers.drive).tap(function() {
|
||||
return console.info("You can safely remove " + answers.drive + " now");
|
||||
});
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,83 +0,0 @@
|
||||
(function() {
|
||||
var _, commandOptions, plugins, visuals;
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
visuals = require('resin-cli-visuals');
|
||||
|
||||
commandOptions = require('./command-options');
|
||||
|
||||
plugins = require('../plugins');
|
||||
|
||||
exports.list = {
|
||||
signature: 'plugins',
|
||||
description: 'list all plugins',
|
||||
help: 'Use this command to list all the installed resin plugins.\n\nExamples:\n\n $ resin plugins',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return plugins.list(function(error, resinPlugins) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
if (_.isEmpty(resinPlugins)) {
|
||||
console.log('You don\'t have any plugins yet');
|
||||
return done();
|
||||
}
|
||||
console.log(visuals.widgets.table.horizontal(resinPlugins, ['name', 'version', 'description', 'license']));
|
||||
return done();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.install = {
|
||||
signature: 'plugin install <name>',
|
||||
description: 'install a plugin',
|
||||
help: 'Use this command to install a resin plugin\n\nUse `--quiet` to prevent information logging.\n\nExamples:\n\n $ resin plugin install hello',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return plugins.install(params.name, function(error) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
console.info("Plugin installed: " + params.name);
|
||||
return done();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.update = {
|
||||
signature: 'plugin update <name>',
|
||||
description: 'update a plugin',
|
||||
help: 'Use this command to update a resin plugin\n\nUse `--quiet` to prevent information logging.\n\nExamples:\n\n $ resin plugin update hello',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return plugins.update(params.name, function(error, version) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
console.info("Plugin updated: " + params.name + "@" + version);
|
||||
return done();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.remove = {
|
||||
signature: 'plugin rm <name>',
|
||||
description: 'remove a plugin',
|
||||
help: 'Use this command to remove a resin.io plugin.\n\nNotice this command asks for confirmation interactively.\nYou can avoid this by passing the `--yes` boolean option.\n\nExamples:\n\n $ resin plugin rm hello\n $ resin plugin rm hello --yes',
|
||||
options: [commandOptions.yes],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return visuals.patterns.remove('plugin', options.yes, function(callback) {
|
||||
return plugins.remove(params.name, callback);
|
||||
}, function(error) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
console.info("Plugin removed: " + params.name);
|
||||
return done();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
@ -1,23 +0,0 @@
|
||||
(function() {
|
||||
var open, resin, url;
|
||||
|
||||
open = require('open');
|
||||
|
||||
url = require('url');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
exports.preferences = {
|
||||
signature: 'preferences',
|
||||
description: 'open preferences form',
|
||||
help: 'Use this command to open the preferences form.\n\nIn the future, we will allow changing all preferences directly from the terminal.\nFor now, we open your default web browser and point it to the web based preferences form.\n\nExamples:\n\n $ resin preferences',
|
||||
permission: 'user',
|
||||
action: function() {
|
||||
var absUrl, preferencesUrl;
|
||||
preferencesUrl = resin.settings.get('urls.preferences');
|
||||
absUrl = url.resolve(resin.settings.get('remoteUrl'), preferencesUrl);
|
||||
return open(absUrl);
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
31
build/actions/settings.js
Normal file
31
build/actions/settings.js
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
exports.list = {
|
||||
signature: 'settings',
|
||||
description: 'print current settings',
|
||||
help: 'Use this command to display detected settings\n\nExamples:\n\n $ resin settings',
|
||||
action: function(params, options, done) {
|
||||
var prettyjson, resin;
|
||||
resin = require('resin-sdk');
|
||||
prettyjson = require('prettyjson');
|
||||
return resin.settings.getAll().then(prettyjson.render).then(console.log).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
87
build/actions/ssh.js
Normal file
87
build/actions/ssh.js
Normal file
@ -0,0 +1,87 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var getSubShellCommand;
|
||||
|
||||
getSubShellCommand = function(command) {
|
||||
var os;
|
||||
os = require('os');
|
||||
if (os.platform() === 'win32') {
|
||||
return {
|
||||
program: 'sh',
|
||||
args: ['-c', command]
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
program: '/bin/sh',
|
||||
args: ['-c', command]
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
signature: 'ssh <uuid>',
|
||||
description: '(beta) get a shell into the running app container of a device',
|
||||
help: 'Use this command to get a shell into the running application container of\nyour device.\n\nExamples:\n\n $ resin ssh 7cf02a6\n $ resin ssh 7cf02a6 --port 8080',
|
||||
permission: 'user',
|
||||
primary: true,
|
||||
options: [
|
||||
{
|
||||
signature: 'port',
|
||||
parameter: 'port',
|
||||
description: 'ssh gateway port',
|
||||
alias: 't'
|
||||
}
|
||||
],
|
||||
action: function(params, options, done) {
|
||||
var Promise, child_process, resin, settings;
|
||||
child_process = require('child_process');
|
||||
Promise = require('bluebird');
|
||||
resin = require('resin-sdk');
|
||||
settings = require('resin-settings-client');
|
||||
if (options.port == null) {
|
||||
options.port = 22;
|
||||
}
|
||||
console.info("Connecting with: " + params.uuid);
|
||||
return Promise.props({
|
||||
isOnline: resin.models.device.isOnline(params.uuid),
|
||||
username: resin.auth.whoami(),
|
||||
uuid: resin.models.device.get(params.uuid).get('uuid'),
|
||||
containerId: resin.models.device.getApplicationInfo(params.uuid).get('containerId')
|
||||
}).then(function(arg) {
|
||||
var containerId, isOnline, username, uuid;
|
||||
isOnline = arg.isOnline, username = arg.username, uuid = arg.uuid, containerId = arg.containerId;
|
||||
if (!isOnline) {
|
||||
throw new Error('Device is not online');
|
||||
}
|
||||
if (containerId == null) {
|
||||
throw new Error('Did not find running application container');
|
||||
}
|
||||
return Promise["try"](function() {
|
||||
var command, spawn, subShellCommand;
|
||||
command = "ssh -t -o LogLevel=QUIET -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p " + options.port + " " + username + "@ssh." + (settings.get('proxyUrl')) + " enter " + uuid + " " + containerId;
|
||||
subShellCommand = getSubShellCommand(command);
|
||||
return spawn = child_process.spawn(subShellCommand.program, subShellCommand.args, {
|
||||
stdio: 'inherit'
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
72
build/actions/sync.js
Normal file
72
build/actions/sync.js
Normal file
@ -0,0 +1,72 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
module.exports = {
|
||||
signature: 'sync [source]',
|
||||
description: '(beta) sync your changes with a device',
|
||||
help: 'Use this command to sync your local changes to a certain device on the fly.\n\nThe `source` argument can be either a device uuid or an application name.\n\nYou can save all the options mentioned below in a `resin-sync.yml` file,\nby using the same option names as keys. For example:\n\n $ cat $PWD/resin-sync.yml\n source: src/\n before: \'echo Hello\'\n ignore:\n - .git\n - node_modules/\n progress: true\n\nNotice that explicitly passed command options override the ones set in the configuration file.\n\nExamples:\n\n $ resin sync MyApp\n $ resin sync 7cf02a6\n $ resin sync 7cf02a6 --port 8080\n $ resin sync 7cf02a6 --ignore foo,bar',
|
||||
permission: 'user',
|
||||
primary: true,
|
||||
options: [
|
||||
{
|
||||
signature: 'source',
|
||||
parameter: 'path',
|
||||
description: 'custom source path',
|
||||
alias: 's'
|
||||
}, {
|
||||
signature: 'ignore',
|
||||
parameter: 'paths',
|
||||
description: 'comma delimited paths to ignore when syncing',
|
||||
alias: 'i'
|
||||
}, {
|
||||
signature: 'before',
|
||||
parameter: 'command',
|
||||
description: 'execute a command before syncing',
|
||||
alias: 'b'
|
||||
}, {
|
||||
signature: 'progress',
|
||||
boolean: true,
|
||||
description: 'show progress',
|
||||
alias: 'p'
|
||||
}, {
|
||||
signature: 'port',
|
||||
parameter: 'port',
|
||||
description: 'ssh port',
|
||||
alias: 't'
|
||||
}
|
||||
],
|
||||
action: function(params, options, done) {
|
||||
var patterns, resin, resinSync;
|
||||
resin = require('resin-sdk');
|
||||
resinSync = require('resin-sync');
|
||||
patterns = require('../utils/patterns');
|
||||
if (options.ignore != null) {
|
||||
options.ignore = options.ignore.split(',');
|
||||
}
|
||||
return resin.models.device.has(params.source).then(function(isValidUUID) {
|
||||
if (isValidUUID) {
|
||||
return params.source;
|
||||
}
|
||||
return patterns.inferOrSelectDevice(params.source);
|
||||
}).then(function(uuid) {
|
||||
return resinSync.sync(uuid, options);
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
@ -1,23 +0,0 @@
|
||||
(function() {
|
||||
var npm, packageJSON;
|
||||
|
||||
npm = require('../npm');
|
||||
|
||||
packageJSON = require('../../package.json');
|
||||
|
||||
exports.update = {
|
||||
signature: 'update',
|
||||
description: 'update the resin cli',
|
||||
help: 'Use this command to update the Resin CLI\n\nThis command outputs information about the update process.\nUse `--quiet` to remove that output.\n\nThe Resin CLI checks for updates once per day.\n\nMajor updates require a manual update with this update command,\nwhile minor updates are applied automatically.\n\nExamples:\n\n $ resin update',
|
||||
action: function(params, options, done) {
|
||||
return npm.update(packageJSON.name, function(error, version) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
console.info("Upgraded " + packageJSON.name + " to v" + version + ".");
|
||||
return done(null, version);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
63
build/actions/wizard.js
Normal file
63
build/actions/wizard.js
Normal file
@ -0,0 +1,63 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
exports.wizard = {
|
||||
signature: 'quickstart [name]',
|
||||
description: 'getting started with resin.io',
|
||||
help: 'Use this command to run a friendly wizard to get started with resin.io.\n\nThe wizard will guide you through:\n\n - Create an application.\n - Initialise an SDCard with the resin.io operating system.\n - Associate an existing project directory with your resin.io application.\n - Push your project to your devices.\n\nExamples:\n\n $ resin quickstart\n $ resin quickstart MyApp',
|
||||
primary: true,
|
||||
action: function(params, options, done) {
|
||||
var Promise, capitano, patterns, resin;
|
||||
Promise = require('bluebird');
|
||||
capitano = Promise.promisifyAll(require('capitano'));
|
||||
resin = require('resin-sdk');
|
||||
patterns = require('../utils/patterns');
|
||||
return resin.auth.isLoggedIn().then(function(isLoggedIn) {
|
||||
if (isLoggedIn) {
|
||||
return;
|
||||
}
|
||||
console.info('Looks like you\'re not logged in yet!');
|
||||
console.info('Lets go through a quick wizard to get you started.\n');
|
||||
return capitano.runAsync('login');
|
||||
}).then(function() {
|
||||
if (params.name != null) {
|
||||
return;
|
||||
}
|
||||
return patterns.selectOrCreateApplication().tap(function(applicationName) {
|
||||
return resin.models.application.has(applicationName).then(function(hasApplication) {
|
||||
if (hasApplication) {
|
||||
return applicationName;
|
||||
}
|
||||
return capitano.runAsync("app create " + applicationName);
|
||||
});
|
||||
}).then(function(applicationName) {
|
||||
return params.name = applicationName;
|
||||
});
|
||||
}).then(function() {
|
||||
return capitano.runAsync("device init --application " + params.name);
|
||||
}).tap(patterns.awaitDevice).then(function(uuid) {
|
||||
return capitano.runAsync("device " + uuid);
|
||||
}).then(function() {
|
||||
return resin.models.application.get(params.name);
|
||||
}).then(function(application) {
|
||||
return console.log("Your device is ready to start pushing some code!\n\nCheck our official documentation for more information:\n\n http://docs.resin.io/#/pages/introduction/introduction.md\n\nClone an example or go to an existing application directory and run:\n\n $ git remote add resin " + application.git_repository + "\n $ git push resin master");
|
||||
}).nodeify(done);
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
138
build/app.js
138
build/app.js
@ -1,11 +1,28 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var _, actions, async, capitano, changeProjectDirectory, errors, plugins, resin, update;
|
||||
var Promise, _, actions, capitano, errors, events, plugins, resin, update;
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
async = require('async');
|
||||
Promise = require('bluebird');
|
||||
|
||||
capitano = require('capitano');
|
||||
capitano = Promise.promisifyAll(require('capitano'));
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
@ -13,17 +30,18 @@
|
||||
|
||||
errors = require('./errors');
|
||||
|
||||
plugins = require('./plugins');
|
||||
events = require('./events');
|
||||
|
||||
update = require('./update');
|
||||
plugins = require('./utils/plugins');
|
||||
|
||||
update = require('./utils/update');
|
||||
|
||||
capitano.permission('user', function(done) {
|
||||
return resin.auth.isLoggedIn(function(isLoggedIn) {
|
||||
return resin.auth.isLoggedIn().then(function(isLoggedIn) {
|
||||
if (!isLoggedIn) {
|
||||
return done(new Error('You have to log in'));
|
||||
throw new Error('You have to log in to continue\n\nRun the following command to go through the login wizard:\n\n $ resin login');
|
||||
}
|
||||
return done();
|
||||
});
|
||||
}).nodeify(done);
|
||||
});
|
||||
|
||||
capitano.command({
|
||||
@ -35,30 +53,12 @@
|
||||
}
|
||||
});
|
||||
|
||||
capitano.globalOption({
|
||||
signature: 'quiet',
|
||||
description: 'quiet (no output)',
|
||||
boolean: true,
|
||||
alias: 'q'
|
||||
});
|
||||
|
||||
capitano.globalOption({
|
||||
signature: 'project',
|
||||
parameter: 'path',
|
||||
description: 'project path',
|
||||
alias: 'j'
|
||||
});
|
||||
|
||||
capitano.globalOption({
|
||||
signature: 'no-color',
|
||||
description: 'disable colour highlighting',
|
||||
boolean: true
|
||||
});
|
||||
|
||||
capitano.command(actions.info.version);
|
||||
|
||||
capitano.command(actions.help.help);
|
||||
|
||||
capitano.command(actions.wizard.wizard);
|
||||
|
||||
capitano.command(actions.auth.login);
|
||||
|
||||
capitano.command(actions.auth.logout);
|
||||
@ -71,36 +71,32 @@
|
||||
|
||||
capitano.command(actions.app.list);
|
||||
|
||||
capitano.command(actions.app.info);
|
||||
|
||||
capitano.command(actions.app.remove);
|
||||
|
||||
capitano.command(actions.app.restart);
|
||||
|
||||
capitano.command(actions.app.associate);
|
||||
|
||||
capitano.command(actions.app.init);
|
||||
capitano.command(actions.app.info);
|
||||
|
||||
capitano.command(actions.device.list);
|
||||
|
||||
capitano.command(actions.device.supported);
|
||||
|
||||
capitano.command(actions.device.rename);
|
||||
|
||||
capitano.command(actions.device.init);
|
||||
|
||||
capitano.command(actions.device.info);
|
||||
|
||||
capitano.command(actions.device.remove);
|
||||
|
||||
capitano.command(actions.device.identify);
|
||||
|
||||
capitano.command(actions.drive.list);
|
||||
capitano.command(actions.device.reboot);
|
||||
|
||||
capitano.command(actions.device.register);
|
||||
|
||||
capitano.command(actions.device.move);
|
||||
|
||||
capitano.command(actions.device.info);
|
||||
|
||||
capitano.command(actions.notes.set);
|
||||
|
||||
capitano.command(actions.preferences.preferences);
|
||||
|
||||
capitano.command(actions.keys.list);
|
||||
|
||||
capitano.command(actions.keys.add);
|
||||
@ -117,56 +113,38 @@
|
||||
|
||||
capitano.command(actions.env.remove);
|
||||
|
||||
capitano.command(actions.logs.logs);
|
||||
|
||||
capitano.command(actions.os.download);
|
||||
|
||||
capitano.command(actions.os.install);
|
||||
capitano.command(actions.os.configure);
|
||||
|
||||
capitano.command(actions.examples.list);
|
||||
capitano.command(actions.os.initialize);
|
||||
|
||||
capitano.command(actions.examples.clone);
|
||||
capitano.command(actions.config.read);
|
||||
|
||||
capitano.command(actions.examples.info);
|
||||
capitano.command(actions.config.write);
|
||||
|
||||
capitano.command(actions.plugin.list);
|
||||
capitano.command(actions.config.inject);
|
||||
|
||||
capitano.command(actions.plugin.install);
|
||||
capitano.command(actions.config.reconfigure);
|
||||
|
||||
capitano.command(actions.plugin.update);
|
||||
capitano.command(actions.config.generate);
|
||||
|
||||
capitano.command(actions.plugin.remove);
|
||||
capitano.command(actions.settings.list);
|
||||
|
||||
capitano.command(actions.update.update);
|
||||
capitano.command(actions.logs);
|
||||
|
||||
changeProjectDirectory = function(directory) {
|
||||
try {
|
||||
return process.chdir(directory);
|
||||
} catch (_error) {
|
||||
return errors.handle(new Error("Invalid project: " + directory));
|
||||
}
|
||||
};
|
||||
capitano.command(actions.sync);
|
||||
|
||||
async.waterfall([
|
||||
function(callback) {
|
||||
return update.check(callback);
|
||||
}, function(callback) {
|
||||
return plugins.register('resin-plugin-', callback);
|
||||
}, function(callback) {
|
||||
var dataPrefix;
|
||||
dataPrefix = resin.settings.get('dataPrefix');
|
||||
return resin.data.prefix.set(dataPrefix, callback);
|
||||
}, function(callback) {
|
||||
var cli;
|
||||
cli = capitano.parse(process.argv);
|
||||
if (cli.global.quiet) {
|
||||
console.info = _.noop;
|
||||
}
|
||||
if (cli.global.project != null) {
|
||||
changeProjectDirectory(cli.global.project);
|
||||
}
|
||||
return capitano.execute(cli, callback);
|
||||
}
|
||||
], errors.handle);
|
||||
capitano.command(actions.ssh);
|
||||
|
||||
update.notify();
|
||||
|
||||
plugins.register(/^resin-plugin-(.+)$/).then(function() {
|
||||
var cli;
|
||||
cli = capitano.parse(process.argv);
|
||||
return events.trackCommand(cli).then(function() {
|
||||
return capitano.executeAsync(cli);
|
||||
});
|
||||
})["catch"](errors.handle);
|
||||
|
||||
}).call(this);
|
||||
|
@ -1,96 +0,0 @@
|
||||
[
|
||||
{
|
||||
"name": "basic-resin-node-project",
|
||||
"display_name": "Node.js Starter Project",
|
||||
"repository": "https://github.com/resin-io/basic-resin-node-project",
|
||||
"description": "This is a simple Hello, World project for node.js designed to act as a basis for future work. It demonstrates how to install native Linux packages and configure your application."
|
||||
},
|
||||
{
|
||||
"name": "cimon",
|
||||
"display_name": "Cimon",
|
||||
"repository": "https://bitbucket.org/efwe/cimon",
|
||||
"description": "A simple tool for reading temperatures from a USB-enabled thermometer. This project is used as the backend to efwe's awesome temperature visualisation at 123k.de.",
|
||||
"author": "efwe"
|
||||
},
|
||||
{
|
||||
"name": "firebaseDTL",
|
||||
"display_name": "Digital Temperature Logger",
|
||||
"repository": "https://github.com/shaunmulligan/firebaseDTL",
|
||||
"description": "A Firebase-backed Digital Temperature Logger allowing you to connect devices with multiple temperature sensors to a central cloud-based datastore.",
|
||||
"author": "Shaun Mulligan"
|
||||
},
|
||||
{
|
||||
"name": "digitiser",
|
||||
"display_name": "Digitiser",
|
||||
"repository": "https://github.com/shaunmulligan/digitiser",
|
||||
"description": "A tool for displaying integer values from a JSON endpoint on a MAX7219 7-segment display.",
|
||||
"author": "Shaun Mulligan"
|
||||
},
|
||||
{
|
||||
"name": "basic-gpio",
|
||||
"display_name": "Example Pi Pins Application",
|
||||
"repository": "https://github.com/shaunmulligan/basic-gpio",
|
||||
"description": "A simple application which demonstrates the use of the Pi Pins library to interface with GPIO.",
|
||||
"author": "Shaun Mulligan"
|
||||
},
|
||||
{
|
||||
"name": "coder",
|
||||
"display_name": "Google Coder",
|
||||
"repository": "https://github.com/resin-io/coder",
|
||||
"description": "Resin.io-enabled version of Google's excellent Coder project which makes it easy to develop web projects on your device."
|
||||
},
|
||||
{
|
||||
"name": "hoversnap",
|
||||
"display_name": "Hoversnap",
|
||||
"repository": "https://github.com/resin-io/hoversnap",
|
||||
"description": "A tool for controlling a camera using a foot switch in order to capture shots in which people appear to be flying."
|
||||
},
|
||||
{
|
||||
"name": "resin-piminer",
|
||||
"display_name": "Pi Miner",
|
||||
"repository": "https://github.com/csquared/resin-piminer",
|
||||
"description": "A bitcoin miner for the Raspberry Pi.",
|
||||
"author": "Chris Continanza"
|
||||
},
|
||||
{
|
||||
"name": "resin-cctv",
|
||||
"display_name": "Resin CCTV",
|
||||
"repository": "https://github.com/abresas/resin-cctv",
|
||||
"description": "A project which allows you to use your devices as a CCTV camera system which hooks into Dropbox.",
|
||||
"author": "Aleksis Brezas"
|
||||
},
|
||||
{
|
||||
"name": "resin_player",
|
||||
"display_name": "Resin Player",
|
||||
"repository": "https://bitbucket.org/lifeeth/resin_player/",
|
||||
"description": "A project which allows you to play squeezebox media through your devices.",
|
||||
"author": "Praneeth Bodduluri"
|
||||
},
|
||||
{
|
||||
"name": "salesforceTemp",
|
||||
"display_name": "Salesforce Temperature Probe",
|
||||
"repository": "https://github.com/shaunmulligan/salesforceTemp",
|
||||
"description": "Example application for interfacing with a temperature probe using Salesforce.com.",
|
||||
"author": "Shaun Mulligan"
|
||||
},
|
||||
{
|
||||
"name": "sms2speech",
|
||||
"display_name": "SMS to Speech",
|
||||
"repository": "https://github.com/alexandrosm/sms2speech",
|
||||
"description": "A simple tool which uses Twillio to read out incoming SMS messages.",
|
||||
"author": "Alexandros Marinos"
|
||||
},
|
||||
{
|
||||
"name": "resin-kiosk",
|
||||
"display_name": "Simple Digitiser Kiosk",
|
||||
"repository": "https://bitbucket.org/lifeeth/resin-kiosk",
|
||||
"description": "Displays values from a JSON endpoint on your browser in kiosk mode",
|
||||
"author": "Praneeth Bodduluri"
|
||||
},
|
||||
{
|
||||
"name": "text2speech",
|
||||
"display_name": "Text to Speech Converter",
|
||||
"repository": "https://github.com/resin-io/text2speech",
|
||||
"description": "A simple application that makes your device speak out loud."
|
||||
}
|
||||
]
|
@ -1,47 +1,40 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var _, os;
|
||||
var chalk, errors, patterns;
|
||||
|
||||
_ = require('lodash');
|
||||
chalk = require('chalk');
|
||||
|
||||
os = require('os');
|
||||
errors = require('resin-cli-errors');
|
||||
|
||||
exports.handle = function(error, exit) {
|
||||
var errorCode, message;
|
||||
if (exit == null) {
|
||||
exit = true;
|
||||
}
|
||||
if ((error == null) || !(error instanceof Error)) {
|
||||
patterns = require('./utils/patterns');
|
||||
|
||||
exports.handle = function(error) {
|
||||
var message;
|
||||
message = errors.interpret(error);
|
||||
if (message == null) {
|
||||
return;
|
||||
}
|
||||
if (process.env.DEBUG) {
|
||||
console.error(error.stack);
|
||||
} else {
|
||||
if (error.code === 'EISDIR') {
|
||||
console.error("File is a directory: " + error.path);
|
||||
} else if (error.code === 'ENOENT') {
|
||||
console.error("No such file or directory: " + error.path);
|
||||
} else if (error.code === 'EACCES' || error.code === 'EPERM') {
|
||||
message = 'You don\'t have enough privileges to run this operation.\n';
|
||||
if (os.platform() === 'win32') {
|
||||
message += 'Run a new Command Prompt as administrator and try running this command again.';
|
||||
} else {
|
||||
message += 'Try running this command again prefixing it with `sudo`.';
|
||||
}
|
||||
console.error(message);
|
||||
} else if (error.code === 'ENOGIT') {
|
||||
console.error('Git is not installed on this system.\nHead over to http://git-scm.com to install it and run this command again.');
|
||||
} else if (error.message != null) {
|
||||
console.error(error.message);
|
||||
}
|
||||
}
|
||||
if (_.isNumber(error.exitCode)) {
|
||||
errorCode = error.exitCode;
|
||||
} else {
|
||||
errorCode = 1;
|
||||
}
|
||||
if (exit) {
|
||||
return process.exit(errorCode);
|
||||
message = error.stack;
|
||||
}
|
||||
patterns.printErrorMessage(message);
|
||||
return process.exit(error.exitCode || 1);
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
41
build/events.js
Normal file
41
build/events.js
Normal file
@ -0,0 +1,41 @@
|
||||
(function() {
|
||||
var Mixpanel, Promise, _, capitanoState, packageJSON, resin;
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
Mixpanel = require('mixpanel');
|
||||
|
||||
Promise = require('bluebird');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
capitanoState = Promise.promisifyAll(require('capitano').state);
|
||||
|
||||
packageJSON = require('../package.json');
|
||||
|
||||
exports.getLoggerInstance = _.memoize(function() {
|
||||
return resin.models.config.getMixpanelToken().then(Mixpanel.init);
|
||||
});
|
||||
|
||||
exports.trackCommand = function(capitanoCommand) {
|
||||
return Promise.props({
|
||||
resinUrl: resin.settings.get('resinUrl'),
|
||||
username: resin.auth.whoami(),
|
||||
mixpanel: exports.getLoggerInstance()
|
||||
}).then(function(data) {
|
||||
return capitanoState.getMatchCommandAsync(capitanoCommand.command).then(function(command) {
|
||||
return data.mixpanel.track("[CLI] " + (command.signature.toString()), {
|
||||
distinct_id: data.username,
|
||||
argv: process.argv.join(' '),
|
||||
version: packageJSON.version,
|
||||
node: process.version,
|
||||
arch: process.arch,
|
||||
resinUrl: data.resinUrl,
|
||||
platform: process.platform,
|
||||
command: capitanoCommand
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
}).call(this);
|
63
build/npm.js
63
build/npm.js
@ -1,63 +0,0 @@
|
||||
(function() {
|
||||
var _, async, npm;
|
||||
|
||||
npm = require('npm');
|
||||
|
||||
async = require('async');
|
||||
|
||||
_ = require('lodash-contrib');
|
||||
|
||||
exports.update = function(name, callback) {
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
var options;
|
||||
options = {
|
||||
loglevel: 'silent',
|
||||
global: true
|
||||
};
|
||||
return npm.load(options, _.unary(callback));
|
||||
}, function(callback) {
|
||||
return npm.commands.update([name], function(error, data) {
|
||||
return callback(error, data);
|
||||
});
|
||||
}, function(data, callback) {
|
||||
var error, newVersion;
|
||||
if (_.isEmpty(data)) {
|
||||
error = new Error('You are already running the latest version');
|
||||
return callback(error);
|
||||
}
|
||||
newVersion = _.last(_.first(_.last(data)).split('@'));
|
||||
return callback(null, newVersion);
|
||||
}
|
||||
], callback);
|
||||
};
|
||||
|
||||
exports.getLatestVersion = function(name, callback) {
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
var options;
|
||||
options = {
|
||||
loglevel: 'silent',
|
||||
global: true
|
||||
};
|
||||
return npm.load(options, _.unary(callback));
|
||||
}, function(callback) {
|
||||
return npm.commands.view([name], true, function(error, data) {
|
||||
var versions;
|
||||
versions = _.keys(data);
|
||||
return callback(error, _.first(versions));
|
||||
});
|
||||
}
|
||||
], callback);
|
||||
};
|
||||
|
||||
exports.isUpdated = function(name, currentVersion, callback) {
|
||||
return exports.getLatestVersion(name, function(error, latestVersion) {
|
||||
if (error != null) {
|
||||
return callback(error);
|
||||
}
|
||||
return callback(null, currentVersion === latestVersion);
|
||||
});
|
||||
};
|
||||
|
||||
}).call(this);
|
@ -1,55 +0,0 @@
|
||||
(function() {
|
||||
var Nplugm, _, capitano, nplugm, registerPlugin;
|
||||
|
||||
Nplugm = require('nplugm');
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
capitano = require('capitano');
|
||||
|
||||
nplugm = null;
|
||||
|
||||
registerPlugin = function(plugin) {
|
||||
if (!_.isArray(plugin)) {
|
||||
return capitano.command(plugin);
|
||||
}
|
||||
return _.each(plugin, capitano.command);
|
||||
};
|
||||
|
||||
exports.register = function(prefix, callback) {
|
||||
nplugm = new Nplugm(prefix);
|
||||
return nplugm.list(function(error, plugins) {
|
||||
var i, len, plugin;
|
||||
if (error != null) {
|
||||
return callback(error);
|
||||
}
|
||||
for (i = 0, len = plugins.length; i < len; i++) {
|
||||
plugin = plugins[i];
|
||||
try {
|
||||
registerPlugin(nplugm.require(plugin));
|
||||
} catch (_error) {
|
||||
error = _error;
|
||||
console.error(error.message);
|
||||
}
|
||||
}
|
||||
return callback();
|
||||
});
|
||||
};
|
||||
|
||||
exports.list = function() {
|
||||
return nplugm.list.apply(nplugm, arguments);
|
||||
};
|
||||
|
||||
exports.install = function() {
|
||||
return nplugm.install.apply(nplugm, arguments);
|
||||
};
|
||||
|
||||
exports.update = function() {
|
||||
return nplugm.update.apply(nplugm, arguments);
|
||||
};
|
||||
|
||||
exports.remove = function() {
|
||||
return nplugm.remove.apply(nplugm, arguments);
|
||||
};
|
||||
|
||||
}).call(this);
|
@ -1,37 +0,0 @@
|
||||
(function() {
|
||||
var packageJSON, updateAction, updateNotifier;
|
||||
|
||||
updateNotifier = require('update-notifier');
|
||||
|
||||
packageJSON = require('../package.json');
|
||||
|
||||
updateAction = require('./actions/update');
|
||||
|
||||
exports.perform = function(callback) {
|
||||
return updateAction.update.action(null, null, callback);
|
||||
};
|
||||
|
||||
exports.notify = function(update) {
|
||||
if (!process.stdout.isTTY) {
|
||||
return;
|
||||
}
|
||||
return console.log("> Major update available: " + update.current + " -> " + update.latest + "\n> Run resin update to update.\n> Beware that a major release might introduce breaking changes.\n");
|
||||
};
|
||||
|
||||
exports.check = function(callback) {
|
||||
var notifier;
|
||||
notifier = updateNotifier({
|
||||
pkg: packageJSON
|
||||
});
|
||||
if (notifier.update == null) {
|
||||
return callback();
|
||||
}
|
||||
if (notifier.update.type === 'major') {
|
||||
exports.notify(notifier.update);
|
||||
return callback();
|
||||
}
|
||||
console.log("Performing " + notifier.update.type + " update, hold tight...");
|
||||
return exports.perform(callback);
|
||||
};
|
||||
|
||||
}).call(this);
|
66
build/utils/helpers.js
Normal file
66
build/utils/helpers.js
Normal file
@ -0,0 +1,66 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var Promise, _, capitano, chalk, os, president;
|
||||
|
||||
Promise = require('bluebird');
|
||||
|
||||
capitano = Promise.promisifyAll(require('capitano'));
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
_.str = require('underscore.string');
|
||||
|
||||
president = Promise.promisifyAll(require('president'));
|
||||
|
||||
os = require('os');
|
||||
|
||||
chalk = require('chalk');
|
||||
|
||||
exports.getGroupDefaults = function(group) {
|
||||
return _.chain(group).get('options').map(function(question) {
|
||||
return [question.name, question["default"]];
|
||||
}).object().value();
|
||||
};
|
||||
|
||||
exports.stateToString = function(state) {
|
||||
var percentage, result;
|
||||
percentage = _.str.lpad(state.percentage, 3, '0') + '%';
|
||||
result = (chalk.blue(percentage)) + " " + (chalk.cyan(state.operation.command));
|
||||
switch (state.operation.command) {
|
||||
case 'copy':
|
||||
return result + " " + state.operation.from.path + " -> " + state.operation.to.path;
|
||||
case 'replace':
|
||||
return result + " " + state.operation.file.path + ", " + state.operation.copy + " -> " + state.operation.replace;
|
||||
case 'run-script':
|
||||
return result + " " + state.operation.script;
|
||||
default:
|
||||
throw new Error("Unsupported operation: " + state.operation.type);
|
||||
}
|
||||
};
|
||||
|
||||
exports.sudo = function(command, message) {
|
||||
command = _.union(_.take(process.argv, 2), command);
|
||||
console.log(message);
|
||||
if (os.platform() !== 'win32') {
|
||||
console.log('Type your computer password to continue');
|
||||
}
|
||||
return president.executeAsync(command);
|
||||
};
|
||||
|
||||
}).call(this);
|
10
build/utils/messages.js
Normal file
10
build/utils/messages.js
Normal file
@ -0,0 +1,10 @@
|
||||
(function() {
|
||||
exports.gettingStarted = 'Run the following command to get a device started with Resin.io\n\n $ resin quickstart';
|
||||
|
||||
exports.reachingOut = 'If you need help, or just want to say hi, don\'t hesitate in reaching out at:\n\n GitHub: https://github.com/resin-io/resin-cli/issues/new\n Gitter: https://gitter.im/resin-io/chat';
|
||||
|
||||
exports.getHelp = 'If you need help, don\'t hesitate in contacting us at:\n\n GitHub: https://github.com/resin-io/resin-cli/issues/new\n Gitter: https://gitter.im/resin-io/chat';
|
||||
|
||||
exports.resinAsciiArt = '______ _ _\n| ___ \\ (_) (_)\n| |_/ /___ ___ _ _ __ _ ___\n| // _ \\/ __| | \'_ \\ | |/ _ \\\n| |\\ \\ __/\\__ \\ | | | |_| | (_) |\n\\_| \\_\\___||___/_|_| |_(_)_|\\___/';
|
||||
|
||||
}).call(this);
|
225
build/utils/patterns.js
Normal file
225
build/utils/patterns.js
Normal file
@ -0,0 +1,225 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var Promise, _, chalk, form, messages, resin, validation, visuals;
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
Promise = require('bluebird');
|
||||
|
||||
form = require('resin-cli-form');
|
||||
|
||||
visuals = require('resin-cli-visuals');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
chalk = require('chalk');
|
||||
|
||||
validation = require('./validation');
|
||||
|
||||
messages = require('./messages');
|
||||
|
||||
exports.authenticate = function(options) {
|
||||
return form.run([
|
||||
{
|
||||
message: 'Email:',
|
||||
name: 'email',
|
||||
type: 'input',
|
||||
validate: validation.validateEmail
|
||||
}, {
|
||||
message: 'Password:',
|
||||
name: 'password',
|
||||
type: 'password'
|
||||
}
|
||||
], {
|
||||
override: options
|
||||
}).then(resin.auth.login).then(resin.auth.twoFactor.isPassed).then(function(isTwoFactorAuthPassed) {
|
||||
if (isTwoFactorAuthPassed) {
|
||||
return;
|
||||
}
|
||||
return form.ask({
|
||||
message: 'Two factor auth challenge:',
|
||||
name: 'code',
|
||||
type: 'input'
|
||||
}).then(resin.auth.twoFactor.challenge)["catch"](function(error) {
|
||||
return resin.auth.logout().then(function() {
|
||||
if (error.name === 'ResinRequestError' && error.statusCode === 401) {
|
||||
throw new Error('Invalid two factor authentication code');
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
exports.askLoginType = function() {
|
||||
return form.ask({
|
||||
message: 'How would you like to login?',
|
||||
name: 'loginType',
|
||||
type: 'list',
|
||||
choices: [
|
||||
{
|
||||
name: 'Web authorization (recommended)',
|
||||
value: 'web'
|
||||
}, {
|
||||
name: 'Credentials',
|
||||
value: 'credentials'
|
||||
}, {
|
||||
name: 'Authentication token',
|
||||
value: 'token'
|
||||
}, {
|
||||
name: 'I don\'t have a Resin account!',
|
||||
value: 'register'
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
exports.selectDeviceType = function() {
|
||||
return resin.models.device.getSupportedDeviceTypes().then(function(deviceTypes) {
|
||||
return form.ask({
|
||||
message: 'Device Type',
|
||||
type: 'list',
|
||||
choices: deviceTypes
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
exports.confirm = function(yesOption, message) {
|
||||
return Promise["try"](function() {
|
||||
if (yesOption) {
|
||||
return true;
|
||||
}
|
||||
return form.ask({
|
||||
message: message,
|
||||
type: 'confirm',
|
||||
"default": false
|
||||
});
|
||||
}).then(function(confirmed) {
|
||||
if (!confirmed) {
|
||||
throw new Error('Aborted');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.selectApplication = function(filter) {
|
||||
return resin.models.application.hasAny().then(function(hasAnyApplications) {
|
||||
if (!hasAnyApplications) {
|
||||
throw new Error('You don\'t have any applications');
|
||||
}
|
||||
return resin.models.application.getAll();
|
||||
}).filter(filter || _.constant(true)).then(function(applications) {
|
||||
return form.ask({
|
||||
message: 'Select an application',
|
||||
type: 'list',
|
||||
choices: _.map(applications, function(application) {
|
||||
return {
|
||||
name: application.app_name + " (" + application.device_type + ")",
|
||||
value: application.app_name
|
||||
};
|
||||
})
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
exports.selectOrCreateApplication = function() {
|
||||
return resin.models.application.hasAny().then(function(hasAnyApplications) {
|
||||
if (!hasAnyApplications) {
|
||||
return;
|
||||
}
|
||||
return resin.models.application.getAll().then(function(applications) {
|
||||
applications = _.map(applications, function(application) {
|
||||
return {
|
||||
name: application.app_name + " (" + application.device_type + ")",
|
||||
value: application.app_name
|
||||
};
|
||||
});
|
||||
applications.unshift({
|
||||
name: 'Create a new application',
|
||||
value: null
|
||||
});
|
||||
return form.ask({
|
||||
message: 'Select an application',
|
||||
type: 'list',
|
||||
choices: applications
|
||||
});
|
||||
});
|
||||
}).then(function(application) {
|
||||
if (application != null) {
|
||||
return application;
|
||||
}
|
||||
return form.ask({
|
||||
message: 'Choose a Name for your new application',
|
||||
type: 'input',
|
||||
validate: validation.validateApplicationName
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
exports.awaitDevice = function(uuid) {
|
||||
return resin.models.device.getName(uuid).then(function(deviceName) {
|
||||
var poll, spinner;
|
||||
spinner = new visuals.Spinner("Waiting for " + deviceName + " to come online");
|
||||
poll = function() {
|
||||
return resin.models.device.isOnline(uuid).then(function(isOnline) {
|
||||
if (isOnline) {
|
||||
spinner.stop();
|
||||
console.info("The device **" + deviceName + "** is online!");
|
||||
} else {
|
||||
spinner.start();
|
||||
return Promise.delay(3000).then(poll);
|
||||
}
|
||||
});
|
||||
};
|
||||
console.info("Waiting for " + deviceName + " to connect to resin...");
|
||||
return poll()["return"](uuid);
|
||||
});
|
||||
};
|
||||
|
||||
exports.inferOrSelectDevice = function(applicationName) {
|
||||
return Promise["try"](function() {
|
||||
if (applicationName != null) {
|
||||
return resin.models.device.getAllByApplication(applicationName);
|
||||
}
|
||||
return resin.models.device.getAll();
|
||||
}).then(function(devices) {
|
||||
if (_.isEmpty(devices)) {
|
||||
throw new Error('You don\'t have any devices');
|
||||
}
|
||||
if (devices.length === 1) {
|
||||
return _.first(devices).uuid;
|
||||
}
|
||||
return form.ask({
|
||||
message: 'Select a device',
|
||||
type: 'list',
|
||||
choices: _.map(devices, function(device) {
|
||||
return {
|
||||
name: (device.name || 'Untitled') + " (" + (device.uuid.slice(0, 7)) + ")",
|
||||
value: device.uuid
|
||||
};
|
||||
})
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
exports.printErrorMessage = function(message) {
|
||||
console.error(chalk.red(message));
|
||||
return console.error(chalk.red("\n" + messages.getHelp + "\n"));
|
||||
};
|
||||
|
||||
}).call(this);
|
43
build/utils/plugins.js
Normal file
43
build/utils/plugins.js
Normal file
@ -0,0 +1,43 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var _, capitano, nplugm, patterns;
|
||||
|
||||
nplugm = require('nplugm');
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
capitano = require('capitano');
|
||||
|
||||
patterns = require('./patterns');
|
||||
|
||||
exports.register = function(regex) {
|
||||
return nplugm.list(regex).map(function(plugin) {
|
||||
var command;
|
||||
command = require(plugin);
|
||||
command.plugin = true;
|
||||
if (!_.isArray(command)) {
|
||||
return capitano.command(command);
|
||||
}
|
||||
return _.each(command, capitano.command);
|
||||
})["catch"](function(error) {
|
||||
return patterns.printErrorMessage(error.message);
|
||||
});
|
||||
};
|
||||
|
||||
}).call(this);
|
50
build/utils/update.js
Normal file
50
build/utils/update.js
Normal file
@ -0,0 +1,50 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var isRoot, notifier, packageJSON, updateNotifier;
|
||||
|
||||
updateNotifier = require('update-notifier');
|
||||
|
||||
isRoot = require('is-root');
|
||||
|
||||
packageJSON = require('../../package.json');
|
||||
|
||||
if (!isRoot()) {
|
||||
notifier = updateNotifier({
|
||||
pkg: packageJSON,
|
||||
updateCheckInterval: 0
|
||||
});
|
||||
}
|
||||
|
||||
exports.hasAvailableUpdate = function() {
|
||||
return notifier != null;
|
||||
};
|
||||
|
||||
exports.notify = function() {
|
||||
if (!exports.hasAvailableUpdate()) {
|
||||
return;
|
||||
}
|
||||
notifier.notify({
|
||||
defer: false
|
||||
});
|
||||
if (notifier.update != null) {
|
||||
return console.log('Notice that you might need administrator privileges depending on your setup\n');
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
44
build/utils/validation.js
Normal file
44
build/utils/validation.js
Normal file
@ -0,0 +1,44 @@
|
||||
|
||||
/*
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var validEmail;
|
||||
|
||||
validEmail = require('valid-email');
|
||||
|
||||
exports.validateEmail = function(input) {
|
||||
if (!validEmail(input)) {
|
||||
return 'Email is not valid';
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
exports.validatePassword = function(input) {
|
||||
if (input.length < 8) {
|
||||
return 'Password should be 8 characters long';
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
exports.validateApplicationName = function(input) {
|
||||
if (input.length < 4) {
|
||||
return 'The application name should be at least 4 characters';
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
}).call(this);
|
96
capitanodoc.json
Normal file
96
capitanodoc.json
Normal file
@ -0,0 +1,96 @@
|
||||
{
|
||||
"title": "Resin CLI Documentation",
|
||||
"introduction": "This tool allows you to interact with the resin.io api from the comfort of your command line.\n\nTo get started download the CLI from npm.\n\n\t$ npm install resin-cli -g\n\nThen authenticate yourself:\n\n\t$ resin login\n\nNow you have access to all the commands referenced below.",
|
||||
"categories": [
|
||||
{
|
||||
"title": "Application",
|
||||
"files": [
|
||||
"lib/actions/app.coffee"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Authentication",
|
||||
"files": [
|
||||
"lib/actions/auth.coffee"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Device",
|
||||
"files": [
|
||||
"lib/actions/device.coffee"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Environment Variables",
|
||||
"files": [
|
||||
"lib/actions/environment-variables.coffee"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Help",
|
||||
"files": [
|
||||
"lib/actions/help.coffee"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Information",
|
||||
"files": [
|
||||
"lib/actions/info.coffee"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Keys",
|
||||
"files": [
|
||||
"lib/actions/keys.coffee"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Logs",
|
||||
"files": [
|
||||
"lib/actions/logs.coffee"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Sync",
|
||||
"files": [
|
||||
"lib/actions/sync.coffee"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "SSH",
|
||||
"files": [
|
||||
"lib/actions/ssh.coffee"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Notes",
|
||||
"files": [
|
||||
"lib/actions/notes.coffee"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "OS",
|
||||
"files": [
|
||||
"lib/actions/os.coffee"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Config",
|
||||
"files": [
|
||||
"lib/actions/config.coffee"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Settings",
|
||||
"files": [
|
||||
"lib/actions/settings.coffee"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Wizard",
|
||||
"files": [
|
||||
"lib/actions/wizard.coffee"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
_resin() {
|
||||
COMPREPLY=()
|
||||
|
||||
local current="${COMP_WORDS[COMP_CWORD]}"
|
||||
local previous="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
local options="version help login logout signup drive whoami app apps init devices device note preferences keys key envs env logs os examples example"
|
||||
|
||||
case "${previous}" in
|
||||
app)
|
||||
local subcommands="create rm restart"
|
||||
COMPREPLY=( $(compgen -W "${subcommands}" -- ${current}) )
|
||||
return 0 ;;
|
||||
drive)
|
||||
local subcommands="list"
|
||||
COMPREPLY=( $(compgen -W "${subcommands}" -- ${current}) )
|
||||
return 0 ;;
|
||||
devices)
|
||||
local subcommands="supported"
|
||||
COMPREPLY=( $(compgen -W "${subcommands}" -- ${current}) )
|
||||
return 0 ;;
|
||||
device)
|
||||
local subcommands="rename rm identify init"
|
||||
COMPREPLY=( $(compgen -W "${subcommands}" -- ${current}) )
|
||||
return 0 ;;
|
||||
key)
|
||||
local subcommands="add rm"
|
||||
COMPREPLY=( $(compgen -W "${subcommands}" -- ${current}) )
|
||||
return 0 ;;
|
||||
env)
|
||||
local subcommands="add rename rm"
|
||||
COMPREPLY=( $(compgen -W "${subcommands}" -- ${current}) )
|
||||
return 0 ;;
|
||||
os)
|
||||
local subcommands="download install"
|
||||
COMPREPLY=( $(compgen -W "${subcommands}" -- ${current}) )
|
||||
return 0 ;;
|
||||
example)
|
||||
local subcommands="clone"
|
||||
COMPREPLY=( $(compgen -W "${subcommands}" -- ${current}) )
|
||||
return 0 ;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
|
||||
COMPREPLY=( $(compgen -W "${options}" -- ${current}) )
|
||||
return 0
|
||||
}
|
||||
|
||||
complete -F _resin resin
|
@ -1,10 +0,0 @@
|
||||
# app associate <id>
|
||||
|
||||
Use this command to associate a project directory with a resin application.
|
||||
|
||||
This command adds a 'resin' git remote to the directory and runs git init if necessary.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin app associate 91
|
||||
$ resin app associate 91 --project my/app/directory
|
@ -1,21 +0,0 @@
|
||||
# app create <name>
|
||||
|
||||
Use this command to create a new resin.io application.
|
||||
|
||||
You can specify the application type with the `--type` option.
|
||||
Otherwise, an interactive dropdown will be shown for you to select from.
|
||||
|
||||
You can see a list of supported device types with
|
||||
|
||||
$ resin devices supported
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin app create MyApp
|
||||
$ resin app create MyApp --type raspberry-pi
|
||||
|
||||
## Options
|
||||
|
||||
### --type, -t <type>
|
||||
|
||||
application type
|
@ -1,7 +0,0 @@
|
||||
# app <id>
|
||||
|
||||
Use this command to show detailed information for a single application.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin app 91
|
@ -1,13 +0,0 @@
|
||||
# init
|
||||
|
||||
Use this command to initialise a directory as a resin application.
|
||||
|
||||
This command performs the following steps:
|
||||
- Create a resin.io application.
|
||||
- Initialize the current directory as a git repository.
|
||||
- Add the corresponding git remote to the application.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin init
|
||||
$ resin init --project my/app/directory
|
@ -1,10 +0,0 @@
|
||||
# apps
|
||||
|
||||
Use this command to list all your applications.
|
||||
|
||||
Notice this command only shows the most important bits of information for each app.
|
||||
If you want detailed information, use resin app <id> instead.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin apps
|
@ -1,17 +0,0 @@
|
||||
# app rm <id>
|
||||
|
||||
Use this command to remove a resin.io application.
|
||||
|
||||
Notice this command asks for confirmation interactively.
|
||||
You can avoid this by passing the `--yes` boolean option.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin app rm 91
|
||||
$ resin app rm 91 --yes
|
||||
|
||||
## Options
|
||||
|
||||
### --yes, -y
|
||||
|
||||
confirm non interactively
|
@ -1,7 +0,0 @@
|
||||
# app restart <id>
|
||||
|
||||
Use this command to restart all devices that belongs to a certain application.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin app restart 91
|
@ -1,22 +0,0 @@
|
||||
# login
|
||||
|
||||
Use this command to login to your resin.io account.
|
||||
You need to login before you can use most of the commands this tool provides.
|
||||
|
||||
You can pass your credentials as `--username` and `--password` options, or you can omit the
|
||||
credentials, in which case the tool will present you with an interactive login form.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin login --username <username> --password <password>
|
||||
$ resin login
|
||||
|
||||
## Options
|
||||
|
||||
### --username, -u <username>
|
||||
|
||||
user name
|
||||
|
||||
### --password, -p <password>
|
||||
|
||||
user password
|
@ -1,7 +0,0 @@
|
||||
# logout
|
||||
|
||||
Use this command to logout from your resin.io account.o
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin logout
|
@ -1,31 +0,0 @@
|
||||
# signup
|
||||
|
||||
Use this command to signup for a resin.io account.
|
||||
|
||||
If signup is successful, you'll be logged in to your new user automatically.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin signup
|
||||
Email: me@mycompany.com
|
||||
Username: johndoe
|
||||
Password: ***********
|
||||
|
||||
$ resin signup --email me@mycompany.com --username johndoe --password ***********
|
||||
|
||||
$ resin whoami
|
||||
johndoe
|
||||
|
||||
## Options
|
||||
|
||||
### --email, -e <email>
|
||||
|
||||
user email
|
||||
|
||||
### --username, -u <username>
|
||||
|
||||
user name
|
||||
|
||||
### --password, -p <user password>
|
||||
|
||||
user password
|
@ -1,7 +0,0 @@
|
||||
# whoami
|
||||
|
||||
Use this command to find out the current logged in username.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin whoami
|
860
doc/cli.markdown
Normal file
860
doc/cli.markdown
Normal file
@ -0,0 +1,860 @@
|
||||
# Resin CLI Documentation
|
||||
|
||||
This tool allows you to interact with the resin.io api from the comfort of your command line.
|
||||
|
||||
To get started download the CLI from npm.
|
||||
|
||||
$ npm install resin-cli -g
|
||||
|
||||
Then authenticate yourself:
|
||||
|
||||
$ resin login
|
||||
|
||||
Now you have access to all the commands referenced below.
|
||||
|
||||
# Table of contents
|
||||
|
||||
- Application
|
||||
|
||||
- [app create <name>](#app-create-60-name-62-)
|
||||
- [apps](#apps)
|
||||
- [app <name>](#app-60-name-62-)
|
||||
- [app restart <name>](#app-restart-60-name-62-)
|
||||
- [app rm <name>](#app-rm-60-name-62-)
|
||||
|
||||
- Authentication
|
||||
|
||||
- [login](#login)
|
||||
- [logout](#logout)
|
||||
- [signup](#signup)
|
||||
- [whoami](#whoami)
|
||||
|
||||
- Device
|
||||
|
||||
- [devices](#devices)
|
||||
- [device <uuid>](#device-60-uuid-62-)
|
||||
- [device register <application>](#device-register-60-application-62-)
|
||||
- [device rm <uuid>](#device-rm-60-uuid-62-)
|
||||
- [device identify <uuid>](#device-identify-60-uuid-62-)
|
||||
- [device reboot <uuid>](#device-reboot-60-uuid-62-)
|
||||
- [device rename <uuid> [newName]](#device-rename-60-uuid-62-newname-)
|
||||
- [device move <uuid>](#device-move-60-uuid-62-)
|
||||
- [device init](#device-init)
|
||||
|
||||
- Environment Variables
|
||||
|
||||
- [envs](#envs)
|
||||
- [env rm <id>](#env-rm-60-id-62-)
|
||||
- [env add <key> [value]](#env-add-60-key-62-value-)
|
||||
- [env rename <id> <value>](#env-rename-60-id-62-60-value-62-)
|
||||
|
||||
- Help
|
||||
|
||||
- [help [command...]](#help-command-)
|
||||
|
||||
- Information
|
||||
|
||||
- [version](#version)
|
||||
|
||||
- Keys
|
||||
|
||||
- [keys](#keys)
|
||||
- [key <id>](#key-60-id-62-)
|
||||
- [key rm <id>](#key-rm-60-id-62-)
|
||||
- [key add <name> [path]](#key-add-60-name-62-path-)
|
||||
|
||||
- Logs
|
||||
|
||||
- [logs <uuid>](#logs-60-uuid-62-)
|
||||
|
||||
- Sync
|
||||
|
||||
- [sync [source]](#sync-source-)
|
||||
|
||||
- SSH
|
||||
|
||||
- [enter <uuid>](#enter-60-uuid-62-)
|
||||
|
||||
- Notes
|
||||
|
||||
- [note <|note>](#note-60-note-62-)
|
||||
|
||||
- OS
|
||||
|
||||
- [os download <type>](#os-download-60-type-62-)
|
||||
- [os configure <image> <uuid>](#os-configure-60-image-62-60-uuid-62-)
|
||||
- [os initialize <image>](#os-initialize-60-image-62-)
|
||||
|
||||
- Config
|
||||
|
||||
- [config read](#config-read)
|
||||
- [config write <key> <value>](#config-write-60-key-62-60-value-62-)
|
||||
- [config inject <file>](#config-inject-60-file-62-)
|
||||
- [config reconfigure](#config-reconfigure)
|
||||
- [config generate](#config-generate)
|
||||
|
||||
- Settings
|
||||
|
||||
- [settings](#settings)
|
||||
|
||||
- Wizard
|
||||
|
||||
- [quickstart [name]](#quickstart-name-)
|
||||
|
||||
# Application
|
||||
|
||||
## app create <name>
|
||||
|
||||
Use this command to create a new resin.io application.
|
||||
|
||||
You can specify the application type with the `--type` option.
|
||||
Otherwise, an interactive dropdown will be shown for you to select from.
|
||||
|
||||
You can see a list of supported device types with
|
||||
|
||||
$ resin devices supported
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin app create MyApp
|
||||
$ resin app create MyApp --type raspberry-pi
|
||||
|
||||
### Options
|
||||
|
||||
#### --type, -t <type>
|
||||
|
||||
application type
|
||||
|
||||
## apps
|
||||
|
||||
Use this command to list all your applications.
|
||||
|
||||
Notice this command only shows the most important bits of information for each app.
|
||||
If you want detailed information, use resin app <name> instead.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin apps
|
||||
|
||||
## app <name>
|
||||
|
||||
Use this command to show detailed information for a single application.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin app MyApp
|
||||
|
||||
## app restart <name>
|
||||
|
||||
Use this command to restart all devices that belongs to a certain application.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin app restart MyApp
|
||||
|
||||
## app rm <name>
|
||||
|
||||
Use this command to remove a resin.io application.
|
||||
|
||||
Notice this command asks for confirmation interactively.
|
||||
You can avoid this by passing the `--yes` boolean option.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin app rm MyApp
|
||||
$ resin app rm MyApp --yes
|
||||
|
||||
### Options
|
||||
|
||||
#### --yes, -y
|
||||
|
||||
confirm non interactively
|
||||
|
||||
# Authentication
|
||||
|
||||
## login
|
||||
|
||||
Use this command to login to your resin.io account.
|
||||
|
||||
This command will prompt you to login using the following login types:
|
||||
|
||||
- Web authorization: open your web browser and prompt you to authorize the CLI
|
||||
from the dashboard.
|
||||
|
||||
- Credentials: using email/password and 2FA.
|
||||
|
||||
- Token: using the authentication token from the preferences page.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin login
|
||||
$ resin login --web
|
||||
$ resin login --token "..."
|
||||
$ resin login --credentials
|
||||
$ resin login --credentials --email johndoe@gmail.com --password secret
|
||||
|
||||
### Options
|
||||
|
||||
#### --token, -t <token>
|
||||
|
||||
auth token
|
||||
|
||||
#### --web, -w
|
||||
|
||||
web-based login
|
||||
|
||||
#### --credentials, -c
|
||||
|
||||
credential-based login
|
||||
|
||||
#### --email, --e,u, --e,u <email>
|
||||
|
||||
email
|
||||
|
||||
#### --password, -p <password>
|
||||
|
||||
password
|
||||
|
||||
## logout
|
||||
|
||||
Use this command to logout from your resin.io account.o
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin logout
|
||||
|
||||
## signup
|
||||
|
||||
Use this command to signup for a resin.io account.
|
||||
|
||||
If signup is successful, you'll be logged in to your new user automatically.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin signup
|
||||
Email: me@mycompany.com
|
||||
Username: johndoe
|
||||
Password: ***********
|
||||
|
||||
$ resin whoami
|
||||
johndoe
|
||||
|
||||
## whoami
|
||||
|
||||
Use this command to find out the current logged in username and email address.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin whoami
|
||||
|
||||
# Device
|
||||
|
||||
## devices
|
||||
|
||||
Use this command to list all devices that belong to you.
|
||||
|
||||
You can filter the devices by application by using the `--application` option.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin devices
|
||||
$ resin devices --application MyApp
|
||||
$ resin devices --app MyApp
|
||||
$ resin devices -a MyApp
|
||||
|
||||
### Options
|
||||
|
||||
#### --application, --a,app, --a,app <application>
|
||||
|
||||
application name
|
||||
|
||||
## device <uuid>
|
||||
|
||||
Use this command to show information about a single device.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin device 7cf02a6
|
||||
|
||||
## device register <application>
|
||||
|
||||
Use this command to register a device to an application.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin device register MyApp
|
||||
|
||||
### Options
|
||||
|
||||
#### --uuid, -u <uuid>
|
||||
|
||||
custom uuid
|
||||
|
||||
## device rm <uuid>
|
||||
|
||||
Use this command to remove a device from resin.io.
|
||||
|
||||
Notice this command asks for confirmation interactively.
|
||||
You can avoid this by passing the `--yes` boolean option.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin device rm 7cf02a6
|
||||
$ resin device rm 7cf02a6 --yes
|
||||
|
||||
### Options
|
||||
|
||||
#### --yes, -y
|
||||
|
||||
confirm non interactively
|
||||
|
||||
## device identify <uuid>
|
||||
|
||||
Use this command to identify a device.
|
||||
|
||||
In the Raspberry Pi, the ACT led is blinked several times.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin device identify 23c73a1
|
||||
|
||||
## device reboot <uuid>
|
||||
|
||||
Use this command to remotely reboot a device
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin device reboot 23c73a1
|
||||
|
||||
## device rename <uuid> [newName]
|
||||
|
||||
Use this command to rename a device.
|
||||
|
||||
If you omit the name, you'll get asked for it interactively.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin device rename 7cf02a6
|
||||
$ resin device rename 7cf02a6 MyPi
|
||||
|
||||
## device move <uuid>
|
||||
|
||||
Use this command to move a device to another application you own.
|
||||
|
||||
If you omit the application, you'll get asked for it interactively.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin device move 7cf02a6
|
||||
$ resin device move 7cf02a6 --application MyNewApp
|
||||
|
||||
### Options
|
||||
|
||||
#### --application, --a,app, --a,app <application>
|
||||
|
||||
application name
|
||||
|
||||
## device init
|
||||
|
||||
Use this command to download the OS image of a certain application and write it to an SD Card.
|
||||
|
||||
Notice this command may ask for confirmation interactively.
|
||||
You can avoid this by passing the `--yes` boolean option.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin device init
|
||||
$ resin device init --application MyApp
|
||||
|
||||
### Options
|
||||
|
||||
#### --application, --a,app, --a,app <application>
|
||||
|
||||
application name
|
||||
|
||||
#### --yes, -y
|
||||
|
||||
confirm non interactively
|
||||
|
||||
#### --advanced, -v
|
||||
|
||||
enable advanced configuration
|
||||
|
||||
# Environment Variables
|
||||
|
||||
## envs
|
||||
|
||||
Use this command to list all environment variables for
|
||||
a particular application or device.
|
||||
|
||||
This command lists all custom environment variables.
|
||||
If you want to see all environment variables, including private
|
||||
ones used by resin, use the verbose option.
|
||||
|
||||
Example:
|
||||
|
||||
$ resin envs --application MyApp
|
||||
$ resin envs --application MyApp --verbose
|
||||
$ resin envs --device 7cf02a6
|
||||
|
||||
### Options
|
||||
|
||||
#### --application, --a,app, --a,app <application>
|
||||
|
||||
application name
|
||||
|
||||
#### --device, -d <device>
|
||||
|
||||
device uuid
|
||||
|
||||
#### --verbose, -v
|
||||
|
||||
show private environment variables
|
||||
|
||||
## env rm <id>
|
||||
|
||||
Use this command to remove an environment variable from an application.
|
||||
|
||||
Don't remove resin specific variables, as things might not work as expected.
|
||||
|
||||
Notice this command asks for confirmation interactively.
|
||||
You can avoid this by passing the `--yes` boolean option.
|
||||
|
||||
If you want to eliminate a device environment variable, pass the `--device` boolean option.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin env rm 215
|
||||
$ resin env rm 215 --yes
|
||||
$ resin env rm 215 --device
|
||||
|
||||
### Options
|
||||
|
||||
#### --yes, -y
|
||||
|
||||
confirm non interactively
|
||||
|
||||
#### --device, -d
|
||||
|
||||
device
|
||||
|
||||
## env add <key> [value]
|
||||
|
||||
Use this command to add an enviroment variable to an application.
|
||||
|
||||
If value is omitted, the tool will attempt to use the variable's value
|
||||
as defined in your host machine.
|
||||
|
||||
Use the `--device` option if you want to assign the environment variable
|
||||
to a specific device.
|
||||
|
||||
If the value is grabbed from the environment, a warning message will be printed.
|
||||
Use `--quiet` to remove it.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin env add EDITOR vim --application MyApp
|
||||
$ resin env add TERM --application MyApp
|
||||
$ resin env add EDITOR vim --device 7cf02a6
|
||||
|
||||
### Options
|
||||
|
||||
#### --application, --a,app, --a,app <application>
|
||||
|
||||
application name
|
||||
|
||||
#### --device, -d <device>
|
||||
|
||||
device uuid
|
||||
|
||||
## env rename <id> <value>
|
||||
|
||||
Use this command to rename an enviroment variable from an application.
|
||||
|
||||
Pass the `--device` boolean option if you want to rename a device environment variable.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin env rename 376 emacs
|
||||
$ resin env rename 376 emacs --device
|
||||
|
||||
### Options
|
||||
|
||||
#### --device, -d
|
||||
|
||||
device
|
||||
|
||||
# Help
|
||||
|
||||
## help [command...]
|
||||
|
||||
Get detailed help for an specific command.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin help apps
|
||||
$ resin help os download
|
||||
|
||||
### Options
|
||||
|
||||
#### --verbose, -v
|
||||
|
||||
show additional commands
|
||||
|
||||
# Information
|
||||
|
||||
## version
|
||||
|
||||
Display the Resin CLI version.
|
||||
|
||||
# Keys
|
||||
|
||||
## keys
|
||||
|
||||
Use this command to list all your SSH keys.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin keys
|
||||
|
||||
## key <id>
|
||||
|
||||
Use this command to show information about a single SSH key.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin key 17
|
||||
|
||||
## key rm <id>
|
||||
|
||||
Use this command to remove a SSH key from resin.io.
|
||||
|
||||
Notice this command asks for confirmation interactively.
|
||||
You can avoid this by passing the `--yes` boolean option.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin key rm 17
|
||||
$ resin key rm 17 --yes
|
||||
|
||||
### Options
|
||||
|
||||
#### --yes, -y
|
||||
|
||||
confirm non interactively
|
||||
|
||||
## key add <name> [path]
|
||||
|
||||
Use this command to associate a new SSH key with your account.
|
||||
|
||||
If `path` is omitted, the command will attempt
|
||||
to read the SSH key from stdin.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin key add Main ~/.ssh/id_rsa.pub
|
||||
$ cat ~/.ssh/id_rsa.pub | resin key add Main
|
||||
|
||||
# Logs
|
||||
|
||||
## logs <uuid>
|
||||
|
||||
Use this command to show logs for a specific device.
|
||||
|
||||
By default, the command prints all log messages and exit.
|
||||
|
||||
To continuously stream output, and see new logs in real time, use the `--tail` option.
|
||||
|
||||
Note that for now you need to provide the whole UUID for this command to work correctly.
|
||||
|
||||
This is due to some technical limitations that we plan to address soon.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin logs 23c73a1
|
||||
$ resin logs 23c73a1
|
||||
|
||||
### Options
|
||||
|
||||
#### --tail, -t
|
||||
|
||||
continuously stream output
|
||||
|
||||
# Sync
|
||||
|
||||
## sync [source]
|
||||
|
||||
Use this command to sync your local changes to a certain device on the fly.
|
||||
|
||||
The `source` argument can be either a device uuid or an application name.
|
||||
|
||||
You can save all the options mentioned below in a `resin-sync.yml` file,
|
||||
by using the same option names as keys. For example:
|
||||
|
||||
$ cat $PWD/resin-sync.yml
|
||||
source: src/
|
||||
before: 'echo Hello'
|
||||
ignore:
|
||||
- .git
|
||||
- node_modules/
|
||||
progress: true
|
||||
|
||||
Notice that explicitly passed command options override the ones set in the configuration file.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin sync MyApp
|
||||
$ resin sync 7cf02a6
|
||||
$ resin sync 7cf02a6 --port 8080
|
||||
$ resin sync 7cf02a6 --ignore foo,bar
|
||||
|
||||
### Options
|
||||
|
||||
#### --source, -s <path>
|
||||
|
||||
custom source path
|
||||
|
||||
#### --ignore, -i <paths>
|
||||
|
||||
comma delimited paths to ignore when syncing
|
||||
|
||||
#### --before, -b <command>
|
||||
|
||||
execute a command before syncing
|
||||
|
||||
#### --progress, -p
|
||||
|
||||
show progress
|
||||
|
||||
#### --port, -t <port>
|
||||
|
||||
ssh port
|
||||
|
||||
# SSH
|
||||
|
||||
## enter <uuid>
|
||||
|
||||
Use this command to get a shell into the running application container of
|
||||
your device.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin enter 7cf02a6
|
||||
$ resin enter 7cf02a6 --port 8080
|
||||
|
||||
### Options
|
||||
|
||||
#### --port, -t <port>
|
||||
|
||||
ssh port
|
||||
|
||||
# Notes
|
||||
|
||||
## note <|note>
|
||||
|
||||
Use this command to set or update a device note.
|
||||
|
||||
If note command isn't passed, the tool attempts to read from `stdin`.
|
||||
|
||||
To view the notes, use $ resin device <uuid>.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin note "My useful note" --device 7cf02a6
|
||||
$ cat note.txt | resin note --device 7cf02a6
|
||||
|
||||
### Options
|
||||
|
||||
#### --device, --d,dev, --d,dev <device>
|
||||
|
||||
device uuid
|
||||
|
||||
# OS
|
||||
|
||||
## os download <type>
|
||||
|
||||
Use this command to download an unconfigured os image for a certain device type.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin os download parallella -o ../foo/bar/parallella.img
|
||||
|
||||
### Options
|
||||
|
||||
#### --output, -o <output>
|
||||
|
||||
output path
|
||||
|
||||
## os configure <image> <uuid>
|
||||
|
||||
Use this command to configure a previously download operating system image with a device.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin os configure ../path/rpi.img 7cf02a6
|
||||
|
||||
### Options
|
||||
|
||||
#### --advanced, -v
|
||||
|
||||
show advanced commands
|
||||
|
||||
## os initialize <image>
|
||||
|
||||
Use this command to initialize a previously configured operating system image.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin os initialize ../path/rpi.img --type 'raspberry-pi'
|
||||
|
||||
### Options
|
||||
|
||||
#### --yes, -y
|
||||
|
||||
confirm non interactively
|
||||
|
||||
#### --type, -t <type>
|
||||
|
||||
device type
|
||||
|
||||
#### --drive, -d <drive>
|
||||
|
||||
drive
|
||||
|
||||
# Config
|
||||
|
||||
## config read
|
||||
|
||||
Use this command to read the config.json file from a provisioned device
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin config read --type raspberry-pi
|
||||
$ resin config read --type raspberry-pi --drive /dev/disk2
|
||||
|
||||
### Options
|
||||
|
||||
#### --type, -t <type>
|
||||
|
||||
device type
|
||||
|
||||
#### --drive, -d <drive>
|
||||
|
||||
drive
|
||||
|
||||
## config write <key> <value>
|
||||
|
||||
Use this command to write the config.json file of a provisioned device
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin config write --type raspberry-pi username johndoe
|
||||
$ resin config write --type raspberry-pi --drive /dev/disk2 username johndoe
|
||||
$ resin config write --type raspberry-pi files.network/settings "..."
|
||||
|
||||
### Options
|
||||
|
||||
#### --type, -t <type>
|
||||
|
||||
device type
|
||||
|
||||
#### --drive, -d <drive>
|
||||
|
||||
drive
|
||||
|
||||
## config inject <file>
|
||||
|
||||
Use this command to inject a config.json file to a provisioned device
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin config inject my/config.json --type raspberry-pi
|
||||
$ resin config inject my/config.json --type raspberry-pi --drive /dev/disk2
|
||||
|
||||
### Options
|
||||
|
||||
#### --type, -t <type>
|
||||
|
||||
device type
|
||||
|
||||
#### --drive, -d <drive>
|
||||
|
||||
drive
|
||||
|
||||
## config reconfigure
|
||||
|
||||
Use this command to reconfigure a provisioned device
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin config reconfigure --type raspberry-pi
|
||||
$ resin config reconfigure --type raspberry-pi --advanced
|
||||
$ resin config reconfigure --type raspberry-pi --drive /dev/disk2
|
||||
|
||||
### Options
|
||||
|
||||
#### --type, -t <type>
|
||||
|
||||
device type
|
||||
|
||||
#### --drive, -d <drive>
|
||||
|
||||
drive
|
||||
|
||||
#### --advanced, -v
|
||||
|
||||
show advanced commands
|
||||
|
||||
## config generate
|
||||
|
||||
Use this command to generate a config.json for a device or application
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin config generate --device 7cf02a6
|
||||
$ resin config generate --device 7cf02a6 --output config.json
|
||||
$ resin config generate --app MyApp
|
||||
$ resin config generate --app MyApp --output config.json
|
||||
|
||||
### Options
|
||||
|
||||
#### --application, --a,app, --a,app <application>
|
||||
|
||||
application name
|
||||
|
||||
#### --device, -d <device>
|
||||
|
||||
device uuid
|
||||
|
||||
#### --output, -o <output>
|
||||
|
||||
output
|
||||
|
||||
# Settings
|
||||
|
||||
## settings
|
||||
|
||||
Use this command to display detected settings
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin settings
|
||||
|
||||
# Wizard
|
||||
|
||||
## quickstart [name]
|
||||
|
||||
Use this command to run a friendly wizard to get started with resin.io.
|
||||
|
||||
The wizard will guide you through:
|
||||
|
||||
- Create an application.
|
||||
- Initialise an SDCard with the resin.io operating system.
|
||||
- Associate an existing project directory with your resin.io application.
|
||||
- Push your project to your devices.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin quickstart
|
||||
$ resin quickstart MyApp
|
||||
|
@ -1,9 +0,0 @@
|
||||
# device identify <uuid>
|
||||
|
||||
Use this command to identify a device.
|
||||
|
||||
In the Raspberry Pi, the ACT led is blinked several times.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin device identify 23c73a12e3527df55c60b9ce647640c1b7da1b32d71e6a39849ac0f00db828
|
@ -1,7 +0,0 @@
|
||||
# device <id>
|
||||
|
||||
Use this command to show information about a single device.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin device 317
|
@ -1,49 +0,0 @@
|
||||
# device init [device]
|
||||
|
||||
Use this command to download the OS image of a certain application and write it to an SD Card.
|
||||
|
||||
Note that this command requires admin privileges.
|
||||
|
||||
If `device` is omitted, you will be prompted to select a device interactively.
|
||||
|
||||
Notice this command asks for confirmation interactively.
|
||||
You can avoid this by passing the `--yes` boolean option.
|
||||
|
||||
You can quiet the progress bar by passing the `--quiet` boolean option.
|
||||
|
||||
You may have to unmount the device before attempting this operation.
|
||||
|
||||
You need to configure the network type and other settings:
|
||||
|
||||
Ethernet:
|
||||
You can setup the device OS to use ethernet by setting the `--network` option to "ethernet".
|
||||
|
||||
Wifi:
|
||||
You can setup the device OS to use wifi by setting the `--network` option to "wifi".
|
||||
If you set "network" to "wifi", you will need to specify the `--ssid` and `--key` option as well.
|
||||
|
||||
You can omit network related options to be asked about them interactively.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin device init --application 91
|
||||
$ resin device init --application 91 --network ethernet
|
||||
$ resin device init /dev/disk2 --application 91 --network wifi --ssid MyNetwork --key secret
|
||||
|
||||
## Options
|
||||
|
||||
### --application, --a,app, --a,app <application>
|
||||
|
||||
application id
|
||||
|
||||
### --network, -n <network>
|
||||
|
||||
network type
|
||||
|
||||
### --ssid, -s <ssid>
|
||||
|
||||
wifi ssid, if network is wifi
|
||||
|
||||
### --key, -k <key>
|
||||
|
||||
wifi key, if network is wifi
|
@ -1,13 +0,0 @@
|
||||
# devices
|
||||
|
||||
Use this command to list all devices that belong to a certain application.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin devices --application 91
|
||||
|
||||
## Options
|
||||
|
||||
### --application, --a,app, --a,app <application>
|
||||
|
||||
application id
|
@ -1,17 +0,0 @@
|
||||
# device rm <id>
|
||||
|
||||
Use this command to remove a device from resin.io.
|
||||
|
||||
Notice this command asks for confirmation interactively.
|
||||
You can avoid this by passing the `--yes` boolean option.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin device rm 317
|
||||
$ resin device rm 317 --yes
|
||||
|
||||
## Options
|
||||
|
||||
### --yes, -y
|
||||
|
||||
confirm non interactively
|
@ -1,10 +0,0 @@
|
||||
# device rename <id> [name]
|
||||
|
||||
Use this command to rename a device.
|
||||
|
||||
If you omit the name, you'll get asked for it interactively.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin device rename 317 MyPi
|
||||
$ resin device rename 317
|
@ -1,7 +0,0 @@
|
||||
# devices supported
|
||||
|
||||
Use this command to get the list of all supported devices
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin devices supported
|
@ -1,7 +0,0 @@
|
||||
# drives
|
||||
|
||||
Use this command to list all drives that are connected to your machine.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin drives
|
@ -1,22 +0,0 @@
|
||||
# env add <key> [value]
|
||||
|
||||
Use this command to add an enviroment variable to an application.
|
||||
|
||||
You need to pass the `--application` option.
|
||||
|
||||
If value is omitted, the tool will attempt to use the variable's value
|
||||
as defined in your host machine.
|
||||
|
||||
If the value is grabbed from the environment, a warning message will be printed.
|
||||
Use `--quiet` to remove it.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin env add EDITOR vim -a 91
|
||||
$ resin env add TERM -a 91
|
||||
|
||||
## Options
|
||||
|
||||
### --application, --a,app, --a,app <application>
|
||||
|
||||
application id
|
@ -1,23 +0,0 @@
|
||||
# envs
|
||||
|
||||
Use this command to list all environment variables for a particular application.
|
||||
Notice we will support per-device environment variables soon.
|
||||
|
||||
This command lists all custom environment variables set on the devices running
|
||||
the application. If you want to see all environment variables, including private
|
||||
ones used by resin, use the verbose option.
|
||||
|
||||
Example:
|
||||
|
||||
$ resin envs --application 91
|
||||
$ resin envs --application 91 --verbose
|
||||
|
||||
## Options
|
||||
|
||||
### --application, --a,app, --a,app <application>
|
||||
|
||||
application id
|
||||
|
||||
### --verbose, -v
|
||||
|
||||
show private environment variables
|
@ -1,19 +0,0 @@
|
||||
# env rm <id>
|
||||
|
||||
Use this command to remove an environment variable from an application.
|
||||
|
||||
Don't remove resin specific variables, as things might not work as expected.
|
||||
|
||||
Notice this command asks for confirmation interactively.
|
||||
You can avoid this by passing the `--yes` boolean option.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin env rm 215
|
||||
$ resin env rm 215 --yes
|
||||
|
||||
## Options
|
||||
|
||||
### --yes, -y
|
||||
|
||||
confirm non interactively
|
@ -1,7 +0,0 @@
|
||||
# env rename <id> <value>
|
||||
|
||||
Use this command to rename an enviroment variable from an application.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin env rename 376 emacs
|
@ -1,10 +0,0 @@
|
||||
# example clone <id>
|
||||
|
||||
Use this command to clone an example application to the current directory
|
||||
|
||||
This command outputs information about the cloning process.
|
||||
Use `--quiet` to remove that output.
|
||||
|
||||
Example:
|
||||
|
||||
$ resin example clone 3
|
@ -1,7 +0,0 @@
|
||||
# example <id>
|
||||
|
||||
Use this command to show information of a single example application
|
||||
|
||||
Example:
|
||||
|
||||
$ resin example 3
|
@ -1,7 +0,0 @@
|
||||
# examples
|
||||
|
||||
Use this command to list available example applications from resin.io
|
||||
|
||||
Example:
|
||||
|
||||
$ resin examples
|
@ -1,8 +0,0 @@
|
||||
# help [command...]
|
||||
|
||||
Get detailed help for an specific command.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin help apps
|
||||
$ resin help os download
|
@ -1,3 +0,0 @@
|
||||
# version
|
||||
|
||||
Display the Resin CLI, as well as the bundled NodeJS version.
|
@ -1,11 +0,0 @@
|
||||
# key add <name> [path]
|
||||
|
||||
Use this command to associate a new SSH key with your account.
|
||||
|
||||
If `path` is omitted, the command will attempt
|
||||
to read the SSH key from stdin.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin key add Main ~/.ssh/id_rsa.pub
|
||||
$ cat ~/.ssh/id_rsa.pub | resin key add Main
|
@ -1,7 +0,0 @@
|
||||
# key <id>
|
||||
|
||||
Use this command to show information about a single SSH key.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin key 17
|
@ -1,7 +0,0 @@
|
||||
# keys
|
||||
|
||||
Use this command to list all your SSH keys.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin keys
|
@ -1,17 +0,0 @@
|
||||
# key rm <id>
|
||||
|
||||
Use this command to remove a SSH key from resin.io.
|
||||
|
||||
Notice this command asks for confirmation interactively.
|
||||
You can avoid this by passing the `--yes` boolean option.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin key rm 17
|
||||
$ resin key rm 17 --yes
|
||||
|
||||
## Options
|
||||
|
||||
### --yes, -y
|
||||
|
||||
confirm non interactively
|
@ -1,18 +0,0 @@
|
||||
# note <|note>
|
||||
|
||||
Use this command to set or update a device note.
|
||||
|
||||
If note command isn't passed, the tool attempts to read from `stdin`.
|
||||
|
||||
To view the notes, use $ resin device <id>.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin note "My useful note" --device 317
|
||||
$ cat note.txt | resin note --device 317
|
||||
|
||||
## Options
|
||||
|
||||
### --device, --d,dev, --d,dev <device>
|
||||
|
||||
device id
|
@ -1,39 +0,0 @@
|
||||
# os download <id>
|
||||
|
||||
Use this command to download the device OS configured to a specific network.
|
||||
|
||||
Ethernet:
|
||||
You can setup the device OS to use ethernet by setting the `--network` option to "ethernet".
|
||||
|
||||
Wifi:
|
||||
You can setup the device OS to use wifi by setting the `--network` option to "wifi".
|
||||
If you set "network" to "wifi", you will need to specify the `--ssid` and `--key` option as well.
|
||||
|
||||
Alternatively, you can omit all kind of network configuration options to configure interactively.
|
||||
|
||||
You have to specify an output location with the `--output` option.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin os download 91 --output ~/MyResinOS.zip
|
||||
$ resin os download 91 --network ethernet --output ~/MyResinOS.zip
|
||||
$ resin os download 91 --network wifi --ssid MyNetwork --key secreykey123 --output ~/MyResinOS.zip
|
||||
$ resin os download 91 --network ethernet --output ~/MyResinOS.zip
|
||||
|
||||
## Options
|
||||
|
||||
### --network, -n <network>
|
||||
|
||||
network type
|
||||
|
||||
### --ssid, -s <ssid>
|
||||
|
||||
wifi ssid, if network is wifi
|
||||
|
||||
### --key, -k <key>
|
||||
|
||||
wifi key, if network is wifi
|
||||
|
||||
### --output, -o <output>
|
||||
|
||||
output file
|
@ -1,34 +0,0 @@
|
||||
# os install <image> [device]
|
||||
|
||||
Use this command to write an operating system image to a device.
|
||||
|
||||
Note that this command requires admin privileges.
|
||||
|
||||
If `device` is omitted, you will be prompted to select a device interactively.
|
||||
|
||||
Notice this command asks for confirmation interactively.
|
||||
You can avoid this by passing the `--yes` boolean option.
|
||||
|
||||
You can quiet the progress bar by passing the `--quiet` boolean option.
|
||||
|
||||
You may have to unmount the device before attempting this operation.
|
||||
|
||||
See the `drives` command to get a list of all connected devices to your machine and their respective ids.
|
||||
|
||||
In Mac OS X:
|
||||
|
||||
$ sudo diskutil unmountDisk /dev/xxx
|
||||
|
||||
In GNU/Linux:
|
||||
|
||||
$ sudo umount /dev/xxx
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin os install rpi.iso /dev/disk2
|
||||
|
||||
## Options
|
||||
|
||||
### --yes, -y
|
||||
|
||||
confirm non interactively
|
@ -1,9 +0,0 @@
|
||||
# plugin install <name>
|
||||
|
||||
Use this command to install a resin plugin
|
||||
|
||||
Use `--quiet` to prevent information logging.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin plugin install hello
|
@ -1,7 +0,0 @@
|
||||
# plugins
|
||||
|
||||
Use this command to list all the installed resin plugins.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin plugins
|
@ -1,17 +0,0 @@
|
||||
# plugin rm <name>
|
||||
|
||||
Use this command to remove a resin.io plugin.
|
||||
|
||||
Notice this command asks for confirmation interactively.
|
||||
You can avoid this by passing the `--yes` boolean option.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin plugin rm hello
|
||||
$ resin plugin rm hello --yes
|
||||
|
||||
## Options
|
||||
|
||||
### --yes, -y
|
||||
|
||||
confirm non interactively
|
@ -1,9 +0,0 @@
|
||||
# plugin update <name>
|
||||
|
||||
Use this command to update a resin plugin
|
||||
|
||||
Use `--quiet` to prevent information logging.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin plugin update hello
|
@ -1,10 +0,0 @@
|
||||
# preferences
|
||||
|
||||
Use this command to open the preferences form.
|
||||
|
||||
In the future, we will allow changing all preferences directly from the terminal.
|
||||
For now, we open your default web browser and point it to the web based preferences form.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin preferences
|
@ -1,15 +0,0 @@
|
||||
# update
|
||||
|
||||
Use this command to update the Resin CLI
|
||||
|
||||
This command outputs information about the update process.
|
||||
Use `--quiet` to remove that output.
|
||||
|
||||
The Resin CLI checks for updates once per day.
|
||||
|
||||
Major updates require a manual update with this update command,
|
||||
while minor updates are applied automatically.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin update
|
@ -1,20 +0,0 @@
|
||||
mkdirp = require('mkdirp')
|
||||
fs = require('fs')
|
||||
path = require('path')
|
||||
capitano = require('capitano')
|
||||
markdown = require('./markdown')
|
||||
|
||||
capitano.command
|
||||
signature: 'markdown <file> <output>'
|
||||
description: 'file to markdown'
|
||||
action: (params, options, done) ->
|
||||
mkdirp.sync(params.output)
|
||||
action = require(params.file)
|
||||
|
||||
for actionName, actionCommand of action
|
||||
output = path.join(params.output, "#{actionName}.md")
|
||||
fs.writeFileSync(output, markdown.command(actionCommand))
|
||||
|
||||
return done()
|
||||
|
||||
capitano.run(process.argv)
|
@ -1,23 +0,0 @@
|
||||
_ = require('lodash')
|
||||
utils = require('./utils')
|
||||
|
||||
exports.option = (option) ->
|
||||
result = utils.parseSignature(option)
|
||||
|
||||
exports.command = (command) ->
|
||||
result = """
|
||||
# #{command.signature}
|
||||
|
||||
#{command.help}\n
|
||||
"""
|
||||
|
||||
if not _.isEmpty(command.options)
|
||||
result += '\n## Options'
|
||||
|
||||
for option in command.options
|
||||
result += """
|
||||
\n\n### #{utils.parseSignature(option)}
|
||||
|
||||
#{option.description}
|
||||
"""
|
||||
return result
|
46
extras/capitanodoc/index.coffee
Normal file
46
extras/capitanodoc/index.coffee
Normal file
@ -0,0 +1,46 @@
|
||||
_ = require('lodash')
|
||||
path = require('path')
|
||||
capitanodoc = require('../../capitanodoc.json')
|
||||
markdown = require('./markdown')
|
||||
|
||||
result = {}
|
||||
result.title = capitanodoc.title
|
||||
result.introduction = capitanodoc.introduction
|
||||
result.categories = []
|
||||
|
||||
for commandCategory in capitanodoc.categories
|
||||
category = {}
|
||||
category.title = commandCategory.title
|
||||
category.commands = []
|
||||
|
||||
for file in commandCategory.files
|
||||
actions = require(path.join(process.cwd(), file))
|
||||
|
||||
if actions.signature?
|
||||
category.commands.push(_.omit(actions, 'action'))
|
||||
else
|
||||
for actionName, actionCommand of actions
|
||||
category.commands.push(_.omit(actionCommand, 'action'))
|
||||
|
||||
result.categories.push(category)
|
||||
|
||||
result.toc = _.cloneDeep(result.categories)
|
||||
result.toc = _.map result.toc, (category) ->
|
||||
category.commands = _.map category.commands, (command) ->
|
||||
return {
|
||||
signature: command.signature
|
||||
anchor: '#' + command.signature
|
||||
.replace(/\s/g,'-')
|
||||
.replace(/</g, '60-')
|
||||
.replace(/>/g, '-62-')
|
||||
.replace(/\[/g, '')
|
||||
.replace(/\]/g, '-')
|
||||
.replace(/--/g, '-')
|
||||
.replace(/\.\.\./g, '')
|
||||
.replace(/\|/g, '')
|
||||
.toLowerCase()
|
||||
}
|
||||
|
||||
return category
|
||||
|
||||
console.log(markdown.display(result))
|
66
extras/capitanodoc/markdown.coffee
Normal file
66
extras/capitanodoc/markdown.coffee
Normal file
@ -0,0 +1,66 @@
|
||||
_ = require('lodash')
|
||||
ent = require('ent')
|
||||
utils = require('./utils')
|
||||
|
||||
exports.command = (command) ->
|
||||
result = """
|
||||
## #{ent.encode(command.signature)}
|
||||
|
||||
#{command.help}\n
|
||||
"""
|
||||
|
||||
if not _.isEmpty(command.options)
|
||||
result += '\n### Options'
|
||||
|
||||
for option in command.options
|
||||
result += """
|
||||
\n\n#### #{utils.parseSignature(option)}
|
||||
|
||||
#{option.description}
|
||||
"""
|
||||
|
||||
result += '\n'
|
||||
|
||||
return result
|
||||
|
||||
exports.category = (category) ->
|
||||
result = """
|
||||
# #{category.title}\n
|
||||
"""
|
||||
|
||||
for command in category.commands
|
||||
result += '\n' + exports.command(command)
|
||||
|
||||
return result
|
||||
|
||||
exports.toc = (toc) ->
|
||||
result = '''
|
||||
# Table of contents\n
|
||||
'''
|
||||
|
||||
for category in toc
|
||||
|
||||
result += """
|
||||
\n- #{category.title}\n\n
|
||||
"""
|
||||
|
||||
for command in category.commands
|
||||
result += """
|
||||
\t- [#{ent.encode(command.signature)}](#{command.anchor})\n
|
||||
"""
|
||||
|
||||
return result
|
||||
|
||||
exports.display = (doc) ->
|
||||
result = """
|
||||
# #{doc.title}
|
||||
|
||||
#{doc.introduction}
|
||||
|
||||
#{exports.toc(doc.toc)}
|
||||
"""
|
||||
|
||||
for category in doc.categories
|
||||
result += '\n' + exports.category(category)
|
||||
|
||||
return result
|
@ -1,4 +1,5 @@
|
||||
_ = require('lodash')
|
||||
ent = require('ent')
|
||||
|
||||
exports.getOptionPrefix = (signature) ->
|
||||
if signature.length > 1
|
||||
@ -22,4 +23,4 @@ exports.parseSignature = (option) ->
|
||||
if option.parameter?
|
||||
result += " <#{option.parameter}>"
|
||||
|
||||
return result
|
||||
return ent.encode(result)
|
@ -1,12 +1,8 @@
|
||||
mkdirp = require('mkdirp')
|
||||
path = require('path')
|
||||
gulp = require('gulp')
|
||||
mocha = require('gulp-mocha')
|
||||
coffee = require('gulp-coffee')
|
||||
markedMan = require('gulp-marked-man')
|
||||
coffeelint = require('gulp-coffeelint')
|
||||
shell = require('gulp-shell')
|
||||
mochaNotifierReporter = require('mocha-notifier-reporter')
|
||||
packageJSON = require('./package.json')
|
||||
|
||||
OPTIONS =
|
||||
@ -15,33 +11,14 @@ OPTIONS =
|
||||
files:
|
||||
coffee: [ 'lib/**/*.coffee', 'gulpfile.coffee' ]
|
||||
app: [ 'lib/**/*.coffee', '!lib/**/*.spec.coffee' ]
|
||||
tests: 'tests/**/*.spec.coffee'
|
||||
json: [ 'lib/**/*.json' ]
|
||||
man: 'man/**/*.md'
|
||||
directories:
|
||||
man: 'man/'
|
||||
build: 'build/'
|
||||
|
||||
gulp.task 'man', ->
|
||||
gulp.src(OPTIONS.files.man)
|
||||
.pipe(markedMan())
|
||||
.pipe(gulp.dest(OPTIONS.directories.man))
|
||||
|
||||
gulp.task 'test', ->
|
||||
gulp.src(OPTIONS.files.tests, read: false)
|
||||
.pipe(mocha({
|
||||
reporter: mochaNotifierReporter.decorate('landing')
|
||||
}))
|
||||
|
||||
gulp.task 'coffee', [ 'test', 'lint', 'json' ], ->
|
||||
gulp.task 'coffee', [ 'lint' ], ->
|
||||
gulp.src(OPTIONS.files.app)
|
||||
.pipe(coffee())
|
||||
.pipe(gulp.dest(OPTIONS.directories.build))
|
||||
|
||||
gulp.task 'json', ->
|
||||
gulp.src(OPTIONS.files.json)
|
||||
.pipe(gulp.dest(OPTIONS.directories.build))
|
||||
|
||||
gulp.task 'lint', ->
|
||||
gulp.src(OPTIONS.files.coffee)
|
||||
.pipe(coffeelint({
|
||||
@ -51,9 +28,7 @@ gulp.task 'lint', ->
|
||||
|
||||
gulp.task 'build', [
|
||||
'coffee'
|
||||
'man'
|
||||
]
|
||||
|
||||
gulp.task 'watch', [ 'test', 'lint' ], ->
|
||||
gulp.watch([ OPTIONS.files.coffee, OPTIONS.files.json ], [ 'coffee' ])
|
||||
gulp.watch([ OPTIONS.files.man ], [ 'man' ])
|
||||
gulp.task 'watch', [ 'lint', 'coffee' ], ->
|
||||
gulp.watch([ OPTIONS.files.coffee ], [ 'coffee' ])
|
||||
|
@ -1,10 +1,20 @@
|
||||
path = require('path')
|
||||
_ = require('lodash-contrib')
|
||||
async = require('async')
|
||||
resin = require('resin-sdk')
|
||||
visuals = require('resin-cli-visuals')
|
||||
###
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
###
|
||||
|
||||
commandOptions = require('./command-options')
|
||||
vcs = require('resin-vcs')
|
||||
|
||||
exports.create =
|
||||
signature: 'app create <name>'
|
||||
@ -33,20 +43,25 @@ exports.create =
|
||||
}
|
||||
]
|
||||
permission: 'user'
|
||||
primary: true
|
||||
action: (params, options, done) ->
|
||||
async.waterfall([
|
||||
resin = require('resin-sdk')
|
||||
patterns = require('../utils/patterns')
|
||||
|
||||
(callback) ->
|
||||
return callback(null, options.type) if options.type?
|
||||
# Validate the the application name is available
|
||||
# before asking the device type.
|
||||
# https://github.com/resin-io/resin-cli/issues/30
|
||||
resin.models.application.has(params.name).then (hasApplication) ->
|
||||
if hasApplication
|
||||
throw new Error('You already have an application with that name!')
|
||||
|
||||
resin.models.device.getSupportedDeviceTypes (error, deviceTypes) ->
|
||||
return callback(error) if error?
|
||||
visuals.widgets.select('Select a type', deviceTypes, callback)
|
||||
|
||||
(type, callback) ->
|
||||
resin.models.application.create(params.name, type, callback)
|
||||
|
||||
], done)
|
||||
.then ->
|
||||
return options.type or patterns.selectDeviceType()
|
||||
.then (deviceType) ->
|
||||
return resin.models.application.create(params.name, deviceType)
|
||||
.then (application) ->
|
||||
console.info("Application created: #{application.app_name} (#{application.device_type}, id #{application.id})")
|
||||
.nodeify(done)
|
||||
|
||||
exports.list =
|
||||
signature: 'apps'
|
||||
@ -55,64 +70,71 @@ exports.list =
|
||||
Use this command to list all your applications.
|
||||
|
||||
Notice this command only shows the most important bits of information for each app.
|
||||
If you want detailed information, use resin app <id> instead.
|
||||
If you want detailed information, use resin app <name> instead.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin apps
|
||||
'''
|
||||
permission: 'user'
|
||||
primary: true
|
||||
action: (params, options, done) ->
|
||||
resin.models.application.getAll (error, applications) ->
|
||||
return done(error) if error?
|
||||
console.log visuals.widgets.table.horizontal applications, [
|
||||
resin = require('resin-sdk')
|
||||
visuals = require('resin-cli-visuals')
|
||||
|
||||
resin.models.application.getAll().then (applications) ->
|
||||
console.log visuals.table.horizontal applications, [
|
||||
'id'
|
||||
'app_name'
|
||||
'device_type'
|
||||
'online_devices'
|
||||
'devices_length'
|
||||
]
|
||||
return done()
|
||||
.nodeify(done)
|
||||
|
||||
exports.info =
|
||||
signature: 'app <id>'
|
||||
signature: 'app <name>'
|
||||
description: 'list a single application'
|
||||
help: '''
|
||||
Use this command to show detailed information for a single application.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin app 91
|
||||
$ resin app MyApp
|
||||
'''
|
||||
permission: 'user'
|
||||
primary: true
|
||||
action: (params, options, done) ->
|
||||
resin.models.application.get params.id, (error, application) ->
|
||||
return done(error) if error?
|
||||
console.log visuals.widgets.table.vertical application, [
|
||||
resin = require('resin-sdk')
|
||||
visuals = require('resin-cli-visuals')
|
||||
|
||||
resin.models.application.get(params.name).then (application) ->
|
||||
console.log visuals.table.vertical application, [
|
||||
"$#{application.app_name}$"
|
||||
'id'
|
||||
'app_name'
|
||||
'device_type'
|
||||
'git_repository'
|
||||
'commit'
|
||||
]
|
||||
return done()
|
||||
.nodeify(done)
|
||||
|
||||
exports.restart =
|
||||
signature: 'app restart <id>'
|
||||
signature: 'app restart <name>'
|
||||
description: 'restart an application'
|
||||
help: '''
|
||||
Use this command to restart all devices that belongs to a certain application.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin app restart 91
|
||||
$ resin app restart MyApp
|
||||
'''
|
||||
permission: 'user'
|
||||
action: (params, options, done) ->
|
||||
resin.models.application.restart(params.id, done)
|
||||
resin = require('resin-sdk')
|
||||
resin.models.application.restart(params.name).nodeify(done)
|
||||
|
||||
exports.remove =
|
||||
signature: 'app rm <id>'
|
||||
signature: 'app rm <name>'
|
||||
description: 'remove an application'
|
||||
help: '''
|
||||
Use this command to remove a resin.io application.
|
||||
@ -122,80 +144,15 @@ exports.remove =
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin app rm 91
|
||||
$ resin app rm 91 --yes
|
||||
$ resin app rm MyApp
|
||||
$ resin app rm MyApp --yes
|
||||
'''
|
||||
options: [ commandOptions.yes ]
|
||||
permission: 'user'
|
||||
action: (params, options, done) ->
|
||||
visuals.patterns.remove 'application', options.yes, (callback) ->
|
||||
resin.models.application.remove(params.id, callback)
|
||||
, done
|
||||
resin = require('resin-sdk')
|
||||
patterns = require('../utils/patterns')
|
||||
|
||||
exports.associate =
|
||||
signature: 'app associate <id>'
|
||||
description: 'associate a resin project'
|
||||
help: '''
|
||||
Use this command to associate a project directory with a resin application.
|
||||
|
||||
This command adds a 'resin' git remote to the directory and runs git init if necessary.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin app associate 91
|
||||
$ resin app associate 91 --project my/app/directory
|
||||
'''
|
||||
permission: 'user'
|
||||
action: (params, options, done) ->
|
||||
currentDirectory = process.cwd()
|
||||
|
||||
async.waterfall [
|
||||
|
||||
(callback) ->
|
||||
vcs.initialize(currentDirectory, callback)
|
||||
|
||||
(callback) ->
|
||||
resin.models.application.get(params.id, callback)
|
||||
|
||||
(application, callback) ->
|
||||
vcs.addRemote(currentDirectory, application.git_repository, callback)
|
||||
|
||||
], (error, remoteUrl) ->
|
||||
return done(error) if error?
|
||||
console.info("git repository added: #{remoteUrl}")
|
||||
return done(null, remoteUrl)
|
||||
|
||||
exports.init =
|
||||
signature: 'init'
|
||||
description: 'init an application'
|
||||
help: '''
|
||||
Use this command to initialise a directory as a resin application.
|
||||
|
||||
This command performs the following steps:
|
||||
- Create a resin.io application.
|
||||
- Initialize the current directory as a git repository.
|
||||
- Add the corresponding git remote to the application.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin init
|
||||
$ resin init --project my/app/directory
|
||||
'''
|
||||
permission: 'user'
|
||||
action: (params, options, done) ->
|
||||
|
||||
currentDirectory = process.cwd()
|
||||
|
||||
async.waterfall([
|
||||
|
||||
(callback) ->
|
||||
currentDirectoryBasename = path.basename(currentDirectory)
|
||||
visuals.widgets.ask('What is the name of your application?', currentDirectoryBasename, callback)
|
||||
|
||||
(applicationName, callback) ->
|
||||
exports.create.action(name: applicationName, options, callback)
|
||||
|
||||
(applicationId, callback) ->
|
||||
exports.associate.action(id: applicationId, options, callback)
|
||||
|
||||
], done)
|
||||
patterns.confirm(options.yes, 'Are you sure you want to delete the application?').then ->
|
||||
resin.models.application.remove(params.name)
|
||||
.nodeify(done)
|
||||
|
@ -1,62 +1,128 @@
|
||||
_ = require('lodash-contrib')
|
||||
url = require('url')
|
||||
async = require('async')
|
||||
resin = require('resin-sdk')
|
||||
visuals = require('resin-cli-visuals')
|
||||
###
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
###
|
||||
|
||||
exports.login =
|
||||
signature: 'login'
|
||||
description: 'login to resin.io'
|
||||
help: '''
|
||||
Use this command to login to your resin.io account.
|
||||
You need to login before you can use most of the commands this tool provides.
|
||||
|
||||
You can pass your credentials as `--username` and `--password` options, or you can omit the
|
||||
credentials, in which case the tool will present you with an interactive login form.
|
||||
This command will prompt you to login using the following login types:
|
||||
|
||||
- Web authorization: open your web browser and prompt you to authorize the CLI
|
||||
from the dashboard.
|
||||
|
||||
- Credentials: using email/password and 2FA.
|
||||
|
||||
- Token: using the authentication token from the preferences page.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin login --username <username> --password <password>
|
||||
$ resin login
|
||||
$ resin login --web
|
||||
$ resin login --token "..."
|
||||
$ resin login --credentials
|
||||
$ resin login --credentials --email johndoe@gmail.com --password secret
|
||||
'''
|
||||
options: [
|
||||
{
|
||||
signature: 'username'
|
||||
parameter: 'username'
|
||||
description: 'user name'
|
||||
alias: 'u'
|
||||
signature: 'token'
|
||||
description: 'auth token'
|
||||
parameter: 'token'
|
||||
alias: 't'
|
||||
}
|
||||
{
|
||||
signature: 'password'
|
||||
parameter: 'password'
|
||||
description: 'user password'
|
||||
alias: 'p'
|
||||
signature: 'web'
|
||||
description: 'web-based login'
|
||||
boolean: true
|
||||
alias: 'w'
|
||||
}
|
||||
{
|
||||
signature: 'credentials'
|
||||
description: 'credential-based login'
|
||||
boolean: true
|
||||
alias: 'c'
|
||||
}
|
||||
{
|
||||
signature: 'email'
|
||||
parameter: 'email'
|
||||
description: 'email'
|
||||
alias: [ 'e', 'u' ]
|
||||
}
|
||||
{
|
||||
signature: 'password'
|
||||
parameter: 'password'
|
||||
description: 'password'
|
||||
alias: 'p'
|
||||
}
|
||||
]
|
||||
primary: true
|
||||
action: (params, options, done) ->
|
||||
_ = require('lodash')
|
||||
Promise = require('bluebird')
|
||||
capitano = Promise.promisifyAll(require('capitano'))
|
||||
resin = require('resin-sdk')
|
||||
auth = require('resin-cli-auth')
|
||||
form = require('resin-cli-form')
|
||||
patterns = require('../utils/patterns')
|
||||
messages = require('../utils/messages')
|
||||
|
||||
hasOptionCredentials = not _.isEmpty(options)
|
||||
login = (options) ->
|
||||
if options.token?
|
||||
return Promise.try ->
|
||||
return options.token if _.isString(options.token)
|
||||
return form.ask
|
||||
message: 'Token (from the preferences page)'
|
||||
name: 'token'
|
||||
type: 'input'
|
||||
.then(resin.auth.loginWithToken)
|
||||
else if options.credentials
|
||||
return patterns.authenticate(options)
|
||||
else if options.web
|
||||
console.info('Connecting to the web dashboard')
|
||||
return auth.login()
|
||||
|
||||
if hasOptionCredentials
|
||||
return patterns.askLoginType().then (loginType) ->
|
||||
|
||||
if not options.username
|
||||
return done(new Error('Missing username'))
|
||||
if loginType is 'register'
|
||||
return capitano.runAsync('signup')
|
||||
|
||||
if not options.password
|
||||
return done(new Error('Missing password'))
|
||||
options[loginType] = true
|
||||
return login(options)
|
||||
|
||||
async.waterfall [
|
||||
resin.settings.get('resinUrl').then (resinUrl) ->
|
||||
console.log(messages.resinAsciiArt)
|
||||
console.log("\nLogging in to #{resinUrl}")
|
||||
return login(options)
|
||||
.then(resin.auth.whoami)
|
||||
.tap (username) ->
|
||||
console.info("Successfully logged in as: #{username}")
|
||||
console.info """
|
||||
|
||||
(callback) ->
|
||||
if hasOptionCredentials
|
||||
return callback(null, options)
|
||||
else
|
||||
return visuals.widgets.login(callback)
|
||||
Now what?
|
||||
|
||||
(credentials, callback) ->
|
||||
resin.auth.login(credentials, callback)
|
||||
#{messages.gettingStarted}
|
||||
|
||||
], done
|
||||
Find out about more super powers by running:
|
||||
|
||||
$ resin help
|
||||
|
||||
#{messages.reachingOut}
|
||||
"""
|
||||
.nodeify(done)
|
||||
|
||||
exports.logout =
|
||||
signature: 'logout'
|
||||
@ -70,7 +136,8 @@ exports.logout =
|
||||
'''
|
||||
permission: 'user'
|
||||
action: (params, options, done) ->
|
||||
resin.auth.logout(done)
|
||||
resin = require('resin-sdk')
|
||||
resin.auth.logout().nodeify(done)
|
||||
|
||||
exports.signup =
|
||||
signature: 'signup'
|
||||
@ -87,66 +154,42 @@ exports.signup =
|
||||
Username: johndoe
|
||||
Password: ***********
|
||||
|
||||
$ resin signup --email me@mycompany.com --username johndoe --password ***********
|
||||
|
||||
$ resin whoami
|
||||
johndoe
|
||||
'''
|
||||
options: [
|
||||
{
|
||||
signature: 'email'
|
||||
parameter: 'email'
|
||||
description: 'user email'
|
||||
alias: 'e'
|
||||
}
|
||||
{
|
||||
signature: 'username'
|
||||
parameter: 'username'
|
||||
description: 'user name'
|
||||
alias: 'u'
|
||||
}
|
||||
{
|
||||
signature: 'password'
|
||||
parameter: 'user password'
|
||||
description: 'user password'
|
||||
alias: 'p'
|
||||
}
|
||||
]
|
||||
action: (params, options, done) ->
|
||||
resin = require('resin-sdk')
|
||||
form = require('resin-cli-form')
|
||||
validation = require('../utils/validation')
|
||||
|
||||
hasOptionCredentials = not _.isEmpty(options)
|
||||
resin.settings.get('resinUrl').then (resinUrl) ->
|
||||
console.log("\nRegistering to #{resinUrl}")
|
||||
|
||||
if hasOptionCredentials
|
||||
form.run [
|
||||
message: 'Email:'
|
||||
name: 'email'
|
||||
type: 'input'
|
||||
validate: validation.validateEmail
|
||||
,
|
||||
message: 'Username:'
|
||||
name: 'username'
|
||||
type: 'input'
|
||||
,
|
||||
message: 'Password:'
|
||||
name: 'password'
|
||||
type: 'password',
|
||||
validate: validation.validatePassword
|
||||
]
|
||||
|
||||
if not options.email?
|
||||
return done(new Error('Missing email'))
|
||||
|
||||
if not options.username?
|
||||
return done(new Error('Missing username'))
|
||||
|
||||
if not options.password?
|
||||
return done(new Error('Missing password'))
|
||||
|
||||
async.waterfall([
|
||||
|
||||
(callback) ->
|
||||
return callback(null, options) if hasOptionCredentials
|
||||
visuals.widgets.register(callback)
|
||||
|
||||
(credentials, callback) ->
|
||||
resin.auth.register credentials, (error, token) ->
|
||||
return callback(error, credentials)
|
||||
|
||||
(credentials, callback) ->
|
||||
resin.auth.login(credentials, callback)
|
||||
|
||||
], done)
|
||||
.then(resin.auth.register)
|
||||
.then(resin.auth.loginWithToken)
|
||||
.nodeify(done)
|
||||
|
||||
exports.whoami =
|
||||
signature: 'whoami'
|
||||
description: 'get current username'
|
||||
description: 'get current username and email address'
|
||||
help: '''
|
||||
Use this command to find out the current logged in username.
|
||||
Use this command to find out the current logged in username and email address.
|
||||
|
||||
Examples:
|
||||
|
||||
@ -154,9 +197,19 @@ exports.whoami =
|
||||
'''
|
||||
permission: 'user'
|
||||
action: (params, options, done) ->
|
||||
resin.auth.whoami (error, username) ->
|
||||
Promise = require('bluebird')
|
||||
resin = require('resin-sdk')
|
||||
visuals = require('resin-cli-visuals')
|
||||
|
||||
if not username?
|
||||
return done(new Error('Username not found'))
|
||||
|
||||
console.log(username)
|
||||
Promise.props
|
||||
username: resin.auth.whoami()
|
||||
email: resin.auth.getEmail()
|
||||
url: resin.settings.get('resinUrl')
|
||||
.then (results) ->
|
||||
console.log visuals.table.vertical results, [
|
||||
'$account information$'
|
||||
'username'
|
||||
'email'
|
||||
'url'
|
||||
]
|
||||
.nodeify(done)
|
||||
|
@ -1,3 +1,19 @@
|
||||
###
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
###
|
||||
|
||||
_ = require('lodash')
|
||||
|
||||
exports.yes =
|
||||
@ -9,13 +25,25 @@ exports.yes =
|
||||
exports.optionalApplication =
|
||||
signature: 'application'
|
||||
parameter: 'application'
|
||||
description: 'application id'
|
||||
description: 'application name'
|
||||
alias: [ 'a', 'app' ]
|
||||
|
||||
exports.application = _.defaults
|
||||
required: 'You have to specify an application'
|
||||
, exports.optionalApplication
|
||||
|
||||
exports.optionalDevice =
|
||||
signature: 'device'
|
||||
parameter: 'device'
|
||||
description: 'device uuid'
|
||||
alias: 'd'
|
||||
|
||||
exports.booleanDevice =
|
||||
signature: 'device'
|
||||
description: 'device'
|
||||
boolean: true
|
||||
alias: 'd'
|
||||
|
||||
exports.network =
|
||||
signature: 'network'
|
||||
parameter: 'network'
|
||||
|
277
lib/actions/config.coffee
Normal file
277
lib/actions/config.coffee
Normal file
@ -0,0 +1,277 @@
|
||||
###
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
###
|
||||
|
||||
commandOptions = require('./command-options')
|
||||
|
||||
exports.read =
|
||||
signature: 'config read'
|
||||
description: 'read a device configuration'
|
||||
help: '''
|
||||
Use this command to read the config.json file from a provisioned device
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin config read --type raspberry-pi
|
||||
$ resin config read --type raspberry-pi --drive /dev/disk2
|
||||
'''
|
||||
options: [
|
||||
{
|
||||
signature: 'type'
|
||||
description: 'device type'
|
||||
parameter: 'type'
|
||||
alias: 't'
|
||||
required: 'You have to specify a device type'
|
||||
}
|
||||
{
|
||||
signature: 'drive'
|
||||
description: 'drive'
|
||||
parameter: 'drive'
|
||||
alias: 'd'
|
||||
}
|
||||
]
|
||||
permission: 'user'
|
||||
root: true
|
||||
action: (params, options, done) ->
|
||||
Promise = require('bluebird')
|
||||
config = require('resin-config-json')
|
||||
visuals = require('resin-cli-visuals')
|
||||
umount = Promise.promisifyAll(require('umount'))
|
||||
prettyjson = require('prettyjson')
|
||||
|
||||
Promise.try ->
|
||||
return options.drive or visuals.drive('Select the device drive')
|
||||
.tap(umount.umountAsync)
|
||||
.then (drive) ->
|
||||
return config.read(drive, options.type)
|
||||
.tap (configJSON) ->
|
||||
console.info(prettyjson.render(configJSON))
|
||||
.nodeify(done)
|
||||
|
||||
exports.write =
|
||||
signature: 'config write <key> <value>'
|
||||
description: 'write a device configuration'
|
||||
help: '''
|
||||
Use this command to write the config.json file of a provisioned device
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin config write --type raspberry-pi username johndoe
|
||||
$ resin config write --type raspberry-pi --drive /dev/disk2 username johndoe
|
||||
$ resin config write --type raspberry-pi files.network/settings "..."
|
||||
'''
|
||||
options: [
|
||||
{
|
||||
signature: 'type'
|
||||
description: 'device type'
|
||||
parameter: 'type'
|
||||
alias: 't'
|
||||
required: 'You have to specify a device type'
|
||||
}
|
||||
{
|
||||
signature: 'drive'
|
||||
description: 'drive'
|
||||
parameter: 'drive'
|
||||
alias: 'd'
|
||||
}
|
||||
]
|
||||
permission: 'user'
|
||||
root: true
|
||||
action: (params, options, done) ->
|
||||
Promise = require('bluebird')
|
||||
_ = require('lodash')
|
||||
config = require('resin-config-json')
|
||||
visuals = require('resin-cli-visuals')
|
||||
umount = Promise.promisifyAll(require('umount'))
|
||||
|
||||
Promise.try ->
|
||||
return options.drive or visuals.drive('Select the device drive')
|
||||
.tap(umount.umountAsync)
|
||||
.then (drive) ->
|
||||
config.read(drive, options.type).then (configJSON) ->
|
||||
console.info("Setting #{params.key} to #{params.value}")
|
||||
_.set(configJSON, params.key, params.value)
|
||||
return configJSON
|
||||
.tap ->
|
||||
return umount.umountAsync(drive)
|
||||
.then (configJSON) ->
|
||||
return config.write(drive, options.type, configJSON)
|
||||
.tap ->
|
||||
console.info('Done')
|
||||
.nodeify(done)
|
||||
|
||||
exports.inject =
|
||||
signature: 'config inject <file>'
|
||||
description: 'inject a device configuration file'
|
||||
help: '''
|
||||
Use this command to inject a config.json file to a provisioned device
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin config inject my/config.json --type raspberry-pi
|
||||
$ resin config inject my/config.json --type raspberry-pi --drive /dev/disk2
|
||||
'''
|
||||
options: [
|
||||
{
|
||||
signature: 'type'
|
||||
description: 'device type'
|
||||
parameter: 'type'
|
||||
alias: 't'
|
||||
required: 'You have to specify a device type'
|
||||
}
|
||||
{
|
||||
signature: 'drive'
|
||||
description: 'drive'
|
||||
parameter: 'drive'
|
||||
alias: 'd'
|
||||
}
|
||||
]
|
||||
permission: 'user'
|
||||
root: true
|
||||
action: (params, options, done) ->
|
||||
Promise = require('bluebird')
|
||||
config = require('resin-config-json')
|
||||
visuals = require('resin-cli-visuals')
|
||||
umount = Promise.promisifyAll(require('umount'))
|
||||
fs = Promise.promisifyAll(require('fs'))
|
||||
|
||||
Promise.try ->
|
||||
return options.drive or visuals.drive('Select the device drive')
|
||||
.tap(umount.umountAsync)
|
||||
.then (drive) ->
|
||||
fs.readFileAsync(params.file, 'utf8').then(JSON.parse).then (configJSON) ->
|
||||
return config.write(drive, options.type, configJSON)
|
||||
.tap ->
|
||||
console.info('Done')
|
||||
.nodeify(done)
|
||||
|
||||
exports.reconfigure =
|
||||
signature: 'config reconfigure'
|
||||
description: 'reconfigure a provisioned device'
|
||||
help: '''
|
||||
Use this command to reconfigure a provisioned device
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin config reconfigure --type raspberry-pi
|
||||
$ resin config reconfigure --type raspberry-pi --advanced
|
||||
$ resin config reconfigure --type raspberry-pi --drive /dev/disk2
|
||||
'''
|
||||
options: [
|
||||
{
|
||||
signature: 'type'
|
||||
description: 'device type'
|
||||
parameter: 'type'
|
||||
alias: 't'
|
||||
required: 'You have to specify a device type'
|
||||
}
|
||||
{
|
||||
signature: 'drive'
|
||||
description: 'drive'
|
||||
parameter: 'drive'
|
||||
alias: 'd'
|
||||
}
|
||||
{
|
||||
signature: 'advanced'
|
||||
description: 'show advanced commands'
|
||||
boolean: true
|
||||
alias: 'v'
|
||||
}
|
||||
]
|
||||
permission: 'user'
|
||||
root: true
|
||||
action: (params, options, done) ->
|
||||
Promise = require('bluebird')
|
||||
config = require('resin-config-json')
|
||||
visuals = require('resin-cli-visuals')
|
||||
capitano = Promise.promisifyAll(require('capitano'))
|
||||
umount = Promise.promisifyAll(require('umount'))
|
||||
|
||||
Promise.try ->
|
||||
return options.drive or visuals.drive('Select the device drive')
|
||||
.tap(umount.umountAsync)
|
||||
.then (drive) ->
|
||||
config.read(drive, options.type).get('uuid')
|
||||
.tap ->
|
||||
umount.umountAsync(drive)
|
||||
.then (uuid) ->
|
||||
configureCommand = "os configure #{drive} #{uuid}"
|
||||
if options.advanced
|
||||
configureCommand += ' --advanced'
|
||||
return capitano.runAsync(configureCommand)
|
||||
.then ->
|
||||
console.info('Done')
|
||||
.nodeify(done)
|
||||
|
||||
exports.generate =
|
||||
signature: 'config generate'
|
||||
description: 'generate a config.json file'
|
||||
help: '''
|
||||
Use this command to generate a config.json for a device or application
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin config generate --device 7cf02a6
|
||||
$ resin config generate --device 7cf02a6 --output config.json
|
||||
$ resin config generate --app MyApp
|
||||
$ resin config generate --app MyApp --output config.json
|
||||
'''
|
||||
options: [
|
||||
commandOptions.optionalApplication
|
||||
commandOptions.optionalDevice
|
||||
{
|
||||
signature: 'output'
|
||||
description: 'output'
|
||||
parameter: 'output'
|
||||
alias: 'o'
|
||||
}
|
||||
]
|
||||
permission: 'user'
|
||||
action: (params, options, done) ->
|
||||
Promise = require('bluebird')
|
||||
fs = Promise.promisifyAll(require('fs'))
|
||||
resin = require('resin-sdk')
|
||||
_ = require('lodash')
|
||||
form = require('resin-cli-form')
|
||||
deviceConfig = require('resin-device-config')
|
||||
prettyjson = require('prettyjson')
|
||||
|
||||
if not options.device? and not options.application?
|
||||
throw new Error '''
|
||||
You have to pass either a device or an application.
|
||||
|
||||
See the help page for examples:
|
||||
|
||||
$ resin help config generate
|
||||
'''
|
||||
|
||||
Promise.try ->
|
||||
if options.device?
|
||||
return resin.models.device.get(options.device)
|
||||
return resin.models.application.get(options.application)
|
||||
.then (resource) ->
|
||||
resin.models.device.getManifestBySlug(resource.device_type)
|
||||
.get('options')
|
||||
.then(form.run)
|
||||
.then (answers) ->
|
||||
if resource.uuid?
|
||||
return deviceConfig.getByDevice(resource.uuid, answers)
|
||||
return deviceConfig.getByApplication(resource.app_name, answers)
|
||||
.then (config) ->
|
||||
if options.output?
|
||||
return fs.writeFileAsync(options.output, JSON.stringify(config))
|
||||
|
||||
console.log(prettyjson.render(config))
|
||||
.nodeify(done)
|
@ -1,73 +1,137 @@
|
||||
_ = require('lodash-contrib')
|
||||
path = require('path')
|
||||
async = require('async')
|
||||
resin = require('resin-sdk')
|
||||
visuals = require('resin-cli-visuals')
|
||||
vcs = require('resin-vcs')
|
||||
###
|
||||
Copyright 2016 Resin.io
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
###
|
||||
|
||||
commandOptions = require('./command-options')
|
||||
osAction = require('./os')
|
||||
|
||||
exports.list =
|
||||
signature: 'devices'
|
||||
description: 'list all devices'
|
||||
help: '''
|
||||
Use this command to list all devices that belong to a certain application.
|
||||
Use this command to list all devices that belong to you.
|
||||
|
||||
You can filter the devices by application by using the `--application` option.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin devices --application 91
|
||||
$ resin devices
|
||||
$ resin devices --application MyApp
|
||||
$ resin devices --app MyApp
|
||||
$ resin devices -a MyApp
|
||||
'''
|
||||
options: [ commandOptions.application ]
|
||||
options: [ commandOptions.optionalApplication ]
|
||||
permission: 'user'
|
||||
primary: true
|
||||
action: (params, options, done) ->
|
||||
resin.models.device.getAllByApplication options.application, (error, devices) ->
|
||||
return done(error) if error?
|
||||
console.log visuals.widgets.table.horizontal devices, [
|
||||
Promise = require('bluebird')
|
||||
_ = require('lodash')
|
||||
resin = require('resin-sdk')
|
||||
visuals = require('resin-cli-visuals')
|
||||
|
||||
Promise.try ->
|
||||
if options.application?
|
||||
return resin.models.device.getAllByApplication(options.application)
|
||||
return resin.models.device.getAll()
|
||||
|
||||
.tap (devices) ->
|
||||
devices = _.map devices, (device) ->
|
||||
device.uuid = device.uuid.slice(0, 7)
|
||||
return device
|
||||
|
||||
console.log visuals.table.horizontal devices, [
|
||||
'id'
|
||||
'uuid'
|
||||
'name'
|
||||
'device_type'
|
||||
'is_online'
|
||||
'application_name'
|
||||
'status'
|
||||
'last_seen'
|
||||
'is_online'
|
||||
]
|
||||
|
||||
return done()
|
||||
.nodeify(done)
|
||||
|
||||
exports.info =
|
||||
signature: 'device <id>'
|
||||
signature: 'device <uuid>'
|
||||
description: 'list a single device'
|
||||
help: '''
|
||||
Use this command to show information about a single device.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin device 317
|
||||
$ resin device 7cf02a6
|
||||
'''
|
||||
permission: 'user'
|
||||
primary: true
|
||||
action: (params, options, done) ->
|
||||
resin.models.device.get params.id, (error, device) ->
|
||||
return done(error) if error?
|
||||
console.log visuals.widgets.table.vertical device, [
|
||||
'id'
|
||||
'name'
|
||||
'device_type'
|
||||
'is_online'
|
||||
'ip_address'
|
||||
'application_name'
|
||||
'status'
|
||||
'last_seen'
|
||||
'uuid'
|
||||
'commit'
|
||||
'supervisor_version'
|
||||
'is_web_accessible'
|
||||
'note'
|
||||
]
|
||||
resin = require('resin-sdk')
|
||||
visuals = require('resin-cli-visuals')
|
||||
|
||||
return done()
|
||||
resin.models.device.get(params.uuid).then (device) ->
|
||||
|
||||
resin.models.device.getStatus(device).then (status) ->
|
||||
device.status = status
|
||||
|
||||
console.log visuals.table.vertical device, [
|
||||
"$#{device.name}$"
|
||||
'id'
|
||||
'device_type'
|
||||
'status'
|
||||
'is_online'
|
||||
'ip_address'
|
||||
'application_name'
|
||||
'last_seen'
|
||||
'uuid'
|
||||
'commit'
|
||||
'supervisor_version'
|
||||
'is_web_accessible'
|
||||
'note'
|
||||
]
|
||||
.nodeify(done)
|
||||
|
||||
exports.register =
|
||||
signature: 'device register <application>'
|
||||
description: 'register a device'
|
||||
help: '''
|
||||
Use this command to register a device to an application.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin device register MyApp
|
||||
'''
|
||||
permission: 'user'
|
||||
options: [
|
||||
signature: 'uuid'
|
||||
description: 'custom uuid'
|
||||
parameter: 'uuid'
|
||||
alias: 'u'
|
||||
]
|
||||
action: (params, options, done) ->
|
||||
Promise = require('bluebird')
|
||||
resin = require('resin-sdk')
|
||||
|
||||
resin.models.application.get(params.application).then (application) ->
|
||||
|
||||
Promise.try ->
|
||||
return options.uuid or resin.models.device.generateUUID()
|
||||
.then (uuid) ->
|
||||
console.info("Registering to #{application.app_name}: #{uuid}")
|
||||
return resin.models.device.register(application.app_name, uuid)
|
||||
.get('uuid')
|
||||
.nodeify(done)
|
||||
|
||||
exports.remove =
|
||||
signature: 'device rm <id>'
|
||||
signature: 'device rm <uuid>'
|
||||
description: 'remove a device'
|
||||
help: '''
|
||||
Use this command to remove a device from resin.io.
|
||||
@ -77,15 +141,18 @@ exports.remove =
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin device rm 317
|
||||
$ resin device rm 317 --yes
|
||||
$ resin device rm 7cf02a6
|
||||
$ resin device rm 7cf02a6 --yes
|
||||
'''
|
||||
options: [ commandOptions.yes ]
|
||||
permission: 'user'
|
||||
action: (params, options, done) ->
|
||||
visuals.patterns.remove 'device', options.yes, (callback) ->
|
||||
resin.models.device.remove(params.id, callback)
|
||||
, done
|
||||
resin = require('resin-sdk')
|
||||
patterns = require('../utils/patterns')
|
||||
|
||||
patterns.confirm(options.yes, 'Are you sure you want to delete the device?').then ->
|
||||
resin.models.device.remove(params.uuid)
|
||||
.nodeify(done)
|
||||
|
||||
exports.identify =
|
||||
signature: 'device identify <uuid>'
|
||||
@ -97,14 +164,30 @@ exports.identify =
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin device identify 23c73a12e3527df55c60b9ce647640c1b7da1b32d71e6a39849ac0f00db828
|
||||
$ resin device identify 23c73a1
|
||||
'''
|
||||
permission: 'user'
|
||||
action: (params, options, done) ->
|
||||
resin.models.device.identify(params.uuid, done)
|
||||
resin = require('resin-sdk')
|
||||
resin.models.device.identify(params.uuid).nodeify(done)
|
||||
|
||||
exports.reboot =
|
||||
signature: 'device reboot <uuid>'
|
||||
description: 'restart a device'
|
||||
help: '''
|
||||
Use this command to remotely reboot a device
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin device reboot 23c73a1
|
||||
'''
|
||||
permission: 'user'
|
||||
action: (params, options, done) ->
|
||||
resin = require('resin-sdk')
|
||||
resin.models.device.reboot(params.uuid).nodeify(done)
|
||||
|
||||
exports.rename =
|
||||
signature: 'device rename <id> [name]'
|
||||
signature: 'device rename <uuid> [newName]'
|
||||
description: 'rename a resin device'
|
||||
help: '''
|
||||
Use this command to rename a device.
|
||||
@ -113,107 +196,128 @@ exports.rename =
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin device rename 317 MyPi
|
||||
$ resin device rename 317
|
||||
$ resin device rename 7cf02a6
|
||||
$ resin device rename 7cf02a6 MyPi
|
||||
'''
|
||||
permission: 'user'
|
||||
action: (params, options, done) ->
|
||||
async.waterfall [
|
||||
Promise = require('bluebird')
|
||||
_ = require('lodash')
|
||||
resin = require('resin-sdk')
|
||||
form = require('resin-cli-form')
|
||||
|
||||
(callback) ->
|
||||
if not _.isEmpty(params.name)
|
||||
return callback(null, params.name)
|
||||
visuals.widgets.ask('How do you want to name this device?', null, callback)
|
||||
Promise.try ->
|
||||
return params.newName if not _.isEmpty(params.newName)
|
||||
|
||||
(name, callback) ->
|
||||
resin.models.device.rename(params.id, name, callback)
|
||||
form.ask
|
||||
message: 'How do you want to name this device?'
|
||||
type: 'input'
|
||||
|
||||
], done
|
||||
.then(_.partial(resin.models.device.rename, params.uuid))
|
||||
.nodeify(done)
|
||||
|
||||
exports.supported =
|
||||
signature: 'devices supported'
|
||||
description: 'list all supported devices'
|
||||
exports.move =
|
||||
signature: 'device move <uuid>'
|
||||
description: 'move a device to another application'
|
||||
help: '''
|
||||
Use this command to get the list of all supported devices
|
||||
Use this command to move a device to another application you own.
|
||||
|
||||
If you omit the application, you'll get asked for it interactively.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin devices supported
|
||||
$ resin device move 7cf02a6
|
||||
$ resin device move 7cf02a6 --application MyNewApp
|
||||
'''
|
||||
permission: 'user'
|
||||
options: [ commandOptions.optionalApplication ]
|
||||
action: (params, options, done) ->
|
||||
resin.models.device.getSupportedDeviceTypes (error, devices) ->
|
||||
return done(error) if error?
|
||||
_.each(devices, _.unary(console.log))
|
||||
done()
|
||||
resin = require('resin-sdk')
|
||||
_ = require('lodash')
|
||||
patterns = require('../utils/patterns')
|
||||
|
||||
resin.models.device.get(params.uuid).then (device) ->
|
||||
return options.application or patterns.selectApplication (application) ->
|
||||
return _.all [
|
||||
application.device_type is device.device_type
|
||||
device.application_name isnt application.app_name
|
||||
]
|
||||
.tap (application) ->
|
||||
return resin.models.device.move(params.uuid, application)
|
||||
.then (application) ->
|
||||
console.info("#{params.uuid} was moved to #{application}")
|
||||
.nodeify(done)
|
||||
|
||||
exports.init =
|
||||
signature: 'device init [device]'
|
||||
signature: 'device init'
|
||||
description: 'initialise a device with resin os'
|
||||
help: '''
|
||||
Use this command to download the OS image of a certain application and write it to an SD Card.
|
||||
|
||||
Note that this command requires admin privileges.
|
||||
|
||||
If `device` is omitted, you will be prompted to select a device interactively.
|
||||
|
||||
Notice this command asks for confirmation interactively.
|
||||
Notice this command may ask for confirmation interactively.
|
||||
You can avoid this by passing the `--yes` boolean option.
|
||||
|
||||
You can quiet the progress bar by passing the `--quiet` boolean option.
|
||||
|
||||
You may have to unmount the device before attempting this operation.
|
||||
|
||||
You need to configure the network type and other settings:
|
||||
|
||||
Ethernet:
|
||||
You can setup the device OS to use ethernet by setting the `--network` option to "ethernet".
|
||||
|
||||
Wifi:
|
||||
You can setup the device OS to use wifi by setting the `--network` option to "wifi".
|
||||
If you set "network" to "wifi", you will need to specify the `--ssid` and `--key` option as well.
|
||||
|
||||
You can omit network related options to be asked about them interactively.
|
||||
|
||||
Examples:
|
||||
|
||||
$ resin device init --application 91
|
||||
$ resin device init --application 91 --network ethernet
|
||||
$ resin device init /dev/disk2 --application 91 --network wifi --ssid MyNetwork --key secret
|
||||
$ resin device init
|
||||
$ resin device init --application MyApp
|
||||
'''
|
||||
options: [
|
||||
commandOptions.optionalApplication
|
||||
commandOptions.network
|
||||
commandOptions.wifiSsid
|
||||
commandOptions.wifiKey
|
||||
commandOptions.yes
|
||||
{
|
||||
signature: 'advanced'
|
||||
description: 'enable advanced configuration'
|
||||
boolean: true
|
||||
alias: 'v'
|
||||
}
|
||||
]
|
||||
permission: 'user'
|
||||
action: (params, options, done) ->
|
||||
Promise = require('bluebird')
|
||||
capitano = Promise.promisifyAll(require('capitano'))
|
||||
rimraf = Promise.promisify(require('rimraf'))
|
||||
tmp = Promise.promisifyAll(require('tmp'))
|
||||
tmp.setGracefulCleanup()
|
||||
|
||||
params.id = options.application
|
||||
resin = require('resin-sdk')
|
||||
helpers = require('../utils/helpers')
|
||||
patterns = require('../utils/patterns')
|
||||
|
||||
async.waterfall([
|
||||
Promise.try ->
|
||||
return options.application if options.application?
|
||||
return patterns.selectApplication()
|
||||
.then(resin.models.application.get)
|
||||
.then (application) ->
|
||||
|
||||
(callback) ->
|
||||
return callback(null, options.application) if options.application?
|
||||
vcs.getApplicationId(process.cwd(), callback)
|
||||
download = ->
|
||||
tmp.tmpNameAsync().then (temporalPath) ->
|
||||
capitano.runAsync("os download #{application.device_type} --output #{temporalPath}")
|
||||
.disposer (temporalPath) ->
|
||||
return rimraf(temporalPath)
|
||||
|
||||
(applicationId, callback) ->
|
||||
params.id = applicationId
|
||||
return callback(null, params.device) if params.device?
|
||||
visuals.patterns.selectDrive(callback)
|
||||
Promise.using download(), (temporalPath) ->
|
||||
capitano.runAsync("device register #{application.app_name}")
|
||||
.then(resin.models.device.get)
|
||||
.tap (device) ->
|
||||
configure = "os configure #{temporalPath} #{device.uuid}"
|
||||
configure += ' --advanced' if options.advanced
|
||||
capitano.runAsync(configure).then ->
|
||||
message = '''
|
||||
Initializing a device requires administrative permissions
|
||||
given that we need to access raw devices directly.
|
||||
|
||||
(device, callback) ->
|
||||
params.device = device
|
||||
visuals.patterns.confirm(options.yes, "This will completely erase #{params.device}. Are you sure you want to continue?", callback)
|
||||
'''
|
||||
|
||||
(confirmed, callback) ->
|
||||
return done() if not confirmed
|
||||
options.yes = confirmed
|
||||
osAction.download.action(params, options, callback)
|
||||
helpers.sudo([ 'os', 'initialize', temporalPath, '--type', application.device_type ], message)
|
||||
|
||||
(outputFile, callback) ->
|
||||
params.image = outputFile
|
||||
osAction.install.action(params, options, callback)
|
||||
# Make sure the device resource is removed if there is an
|
||||
# error when configuring or initializing a device image
|
||||
.catch (error) ->
|
||||
resin.models.device.remove(device.uuid).finally ->
|
||||
throw error
|
||||
.then (device) ->
|
||||
console.log('Done')
|
||||
return device.uuid
|
||||
|
||||
], done)
|
||||
.nodeify(done)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user