Compare commits

...

583 Commits

Author SHA1 Message Date
6beb6ff44e 4.0.0 2016-04-26 16:17:01 +03:00
c2cd10f6a7 Update changelog 2016-04-26 16:16:02 +03:00
4d3769def8 Merge pull request #337 from resin-io/enter-container-command
Implement resin enter <uuid> command
2016-04-26 16:13:00 +03:00
42bfb3b0cc Implement resin ssh <uuid> command 2016-04-26 16:00:54 +03:00
d9c2717fe4 Merge pull request #340 from resin-io/upgrade-sync-packages
Use resin-sync v2.0.1 and resin-sdk v5.3.0
2016-04-26 15:57:23 +03:00
8e93577f90 Use resin-sync v2.0.1 and resin-sdk v5.3.0 2016-04-26 15:55:21 +03:00
5b7e1b656e Merge pull request #339 from resin-io/feat/infer-or-select-device
Implement a function to attempt to infer a device selection
2016-04-25 14:30:36 -04:00
4a05ce3f53 Attempt to infer the device uuid in resin sync
This PR adds functionality to `resin sync` to try to infer what the
device uuid is as follows:

- If the argument to `resin sync` is an app, get all the devices from
that application. If there is only one, auto-select it, otherwise show
an interactive drive selection widget.

- If the argument to `resin sync` is a uuid, use it directly, without
trying to infer anything.

- If no argument is passed to `resin sync`, display an interactive
selection widget showing all your devices from all your applications.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-04-25 08:57:19 -04:00
61574a8522 Merge pull request #338 from resin-io/change-sync-description
Change sync description
2016-04-25 08:37:33 -04:00
9400d4027a Update resin-settings-client version 2016-04-25 14:47:15 +03:00
b5ec49dda1 Remove resin sync 'exec after rsync' feature as it's not supported by
ssh gateway
2016-04-25 14:47:05 +03:00
1c66efb4fa v3.0.2 2016-04-08 13:30:40 -04:00
68fca3d030 Merge pull request #336 from resin-io/fix/os-configure-shorter-uuids
Fix shorter uuids not working with the `os configure` command
2016-04-08 13:29:35 -04:00
325304aebe Fix shorter uuids not working with the os configure command
`resin-device-init`, which is used by the `os configure` command was
still running an older SDK version, that didn't support shorter uuids.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
2016-04-08 13:28:21 -04:00
a50cf5b198 Merge pull request #335 from resin-io/doc/plugin-development
Link to resin-plugin-hello from README
2016-03-31 10:19:48 -04:00
1b7aeeafc1 Link to resin-plugin-hello from README 2016-03-31 10:11:05 -04:00
6e3c2ef168 v3.0.1 2016-03-29 11:30:11 -04:00
d9b4753690 Merge pull request #334 from resin-io/fix/event-explosion
Log CLI events based on original command signature
2016-03-29 11:29:17 -04:00
ca40d7ca65 Log CLI events based on original command signature
Currently we log a CLI event with the passed command, however this might
include usr params, like a uuid, and therefore cause thousands of
different event names in Mixpanel.
2016-03-29 11:27:53 -04:00
4aa8362be9 v3.0.0 2016-03-28 09:29:31 -04:00
d68b61a913 Merge pull request #333 from resin-io/misc/regenerate-docs
Regenerate docs and include sync
2016-03-28 09:26:08 -04:00
20969ef249 Regenerate docs and include sync 2016-03-28 09:25:40 -04:00
469d35fcc1 Merge pull request #332 from resin-io/feat/sync
Integrate sync plugin in the Resin CLI
2016-03-28 09:22:36 -04:00
e9b8c38eeb Integrate sync plugin in the Resin CLI 2016-03-28 09:21:25 -04:00
d4c44bf350 Merge pull request #331 from resin-io/feat/config-generate-application
Allow generating a config.json from an application with config generate
2016-03-21 15:46:52 -04:00
2d8cf7c479 Allow generating a config.json from an application with config generate
Currently, `config generate` requires a device uuid. The command now
accepts either a uuid or an application name, and generates a
config.json accordingly.
2016-03-21 15:42:54 -04:00
ca6e715bfa Merge pull request #330 from resin-io/upgrade/device-config
Upgrade resin-device-config to v3.0.0
2016-03-21 15:05:28 -04:00
3a839c947e Upgrade resin-device-config to v3.0.0 2016-03-21 15:01:59 -04:00
9896de3c34 Merge pull request #329 from resin-io/feat/config-inject
Implement config inject command
2016-03-18 09:13:19 -04:00
03d7520de2 Implement config inject command
This command allows to user to inject a whole `config.json` file to a
provisioned device.
2016-03-17 16:07:19 -04:00
4fc8b130f8 Merge pull request #328 from resin-io/fix/innacurate-invalid-2fa-code
Only throw "Invalid 2FA code" if we're sure that's the cause
2016-03-17 15:38:15 -04:00
c5692f8b13 Only throw "Invalid 2FA code" if we're sure that's the cause
Currently, such error will be thrown when
`resin.auth.twoFactor.challenge()` rejects, but an invalid code is not
the only thing this function can reject for.
2016-03-17 15:37:02 -04:00
85561b5d50 Merge pull request #326 from resin-io/doc/eaccess-login
Document the case where EACCES is thrown during login
2016-03-09 11:04:17 -04:00
88c0833ae2 Document the case where EACCES is thrown during login 2016-03-09 11:03:45 -04:00
7df78a0c9e Merge pull request #325 from resin-io/misc/update
Force update alert to be always shown
2016-03-08 09:26:22 -04:00
30663b0301 Force update alert to be always shown
If `updateCheckInterval` has any meanginful value, the alert will be
shown one out of ten times, or something like that, making the user
likely to miss updates.

The underlying issue is that `update-notifier`, if it detects a cached
update notification, it deletes it, and only attempts to show it back if
`updateCheckInterval` is greater than `Date.now() - lastUpdateCheck`.
2016-03-08 09:23:03 -04:00
4ffba0ed56 Merge pull request #324 from resin-io/upgrade/dependencies
Upgrade most outdated dependencies
2016-03-07 11:42:10 -04:00
a522c70f92 Upgrade most outdated dependencies 2016-03-07 08:44:10 -04:00
f295837840 v2.7.0 2016-03-07 08:34:32 -04:00
091ae8eb03 Merge pull request #322 from resin-io/feat/device-reboot
Implement device reboot command
2016-03-07 08:33:14 -04:00
6405c6bb6f Implement device reboot command
Fixes: https://github.com/resin-io/resin-cli/issues/319
2016-03-04 09:38:11 -04:00
797122ce37 Merge pull request #320 from resin-io/feat/config-generate
Implement config generate command
2016-02-29 08:40:15 -04:00
f81db5a775 Merge pull request #321 from resin-io/misc/regenerate-docs
Regenerate docs
2016-02-26 22:40:53 -04:00
0f84aea47d Regenerate docs 2016-02-26 22:38:16 -04:00
84ed20d3ec Implement config generate command
This command allows the user to generate a config.json file and either
print it to stdout or save it to a file.
2016-02-26 22:37:15 -04:00
9870727e36 v2.6.2 2016-02-19 08:36:25 -04:00
db3de2137b Remove hardcoded readdir path
This was probably used for debugging at some point and got commited
accidentally.
2016-02-19 08:35:10 -04:00
92c6af91ca Merge pull request #317 from imrehg/badge
badge fixes
2016-02-13 22:18:18 -04:00
d578f62dca escape gitter image link
This is to fix bage link on npmjs.org, hopefully, as currently
it seems it cannot handle real spaces in image URLs.
2016-02-13 09:27:42 +08:00
d4527220c3 fix dependencies badge link 2016-02-13 09:21:08 +08:00
d5797124f5 Merge pull request #316 from resin-io/misc/mbr-error-troubleshotting
Move Invalid MBR error explanation to TROUBLESHOOTING
2016-02-12 19:26:14 -04:00
654c3c627d Move Invalid MBR error explanation to TROUBLESHOOTING 2016-02-12 14:45:00 -04:00
3953b00e77 v2.6.1 2016-02-12 14:41:37 -04:00
13f33da280 Merge pull request #315 from resin-io/feat/capitano-analytics
Inject analytics in Capitano
2016-02-12 14:38:31 -04:00
356d2ef6b2 Inject analytics in Capitano 2016-02-12 14:34:16 -04:00
36a8179e0c Merge pull request #314 from resin-io/upgrade/form
Upgrade resin-cli-form to v1.4.0
2016-02-11 12:54:33 -04:00
aedb9c732f Upgrade resin-cli-form to v1.4.0 2016-02-11 12:49:56 -04:00
c3bd433532 Merge pull request #313 from resin-io/feat/devices-is-online
Show if a device is online in devices command
2016-02-11 09:50:43 -04:00
d72750de65 Show if a device is online in devices command
Fixes: https://github.com/resin-io/resin-cli/issues/312
2016-02-10 08:51:00 -04:00
ccd8e73c4e Merge pull request #310 from resin-io/fix/309/device-name-help
Refer to device uuids in command help
2016-01-28 09:11:25 -04:00
6c677fe8cd Refer to device uuids in command help
Currently the CLI asks for a device "name" on device options while it
actually needs a "uuid".

Fixes: https://github.com/resin-io/resin-cli/issues/309
2016-01-28 09:10:11 -04:00
eaa1a798c5 Merge pull request #308 from resin-io/upgrade/image-manager
Upgrade Resin Image Manager to v4.0.0
2016-01-26 16:07:30 -04:00
da1b446b3b Upgrade Resin Image Manager to v4.0.0 2016-01-26 15:38:58 -04:00
18b4509fef Merge pull request #307 from resin-io/feature/device-status
Show parsed device status in device command
2016-01-26 15:09:03 -04:00
35bba04b16 Show parsed device status in device command 2016-01-26 12:16:55 -04:00
dd382158dd Merge pull request #306 from resin-io/misc/messages
Improve messages
2016-01-25 09:50:56 -04:00
40f015de93 Fix grammar issue: Administration -> Administrative 2016-01-25 09:00:04 -04:00
bee523828a Improve awaitDevice success message 2016-01-25 08:59:09 -04:00
474635401a Merge pull request #305 from resin-io/doc/mbr-error
Document corruped image MBR error
2016-01-24 18:16:35 -04:00
a8c30bb395 Document corruped image MBR error 2016-01-22 10:14:55 -04:00
9e00fdaf31 Merge pull request #304 from resin-io/doc/readme-header
Improve README header style
2016-01-21 23:18:36 -04:00
5f83c870ed Improve README header style
- Use SVG badges.
- Set description as a blockquote before the title.
2016-01-21 23:17:02 -04:00
5d89533afc Merge pull request #303 from resin-io/doc/login-error
Add information on how to login on user permission error
2016-01-21 23:12:20 -04:00
a346c3f043 Add information on how to login on user permission error 2016-01-21 23:07:08 -04:00
de0649c980 v2.6.0 2016-01-21 15:59:52 -04:00
b7300deab7 Merge pull request #302 from resin-io/upgrade/manager
Upgrade Resin Image Manager to v3.2.6
2016-01-21 15:50:45 -04:00
70b2ba3ab9 Upgrade Resin Image Manager to v3.2.6 2016-01-21 15:49:44 -04:00
8cbf792786 Merge pull request #301 from resin-io/doc/remove-ci-badges
Remove build status CI badges from README
2016-01-21 10:43:46 -04:00
bca9a7f51f Remove build status CI badges from README
CI integration was removed in
96f0b5fbd6,
but it looks like we forgot to remove the badges.
2016-01-21 10:42:45 -04:00
4bf079377b Merge pull request #300 from resin-io/feat/shorter-uuids
Support shorter uuids
2016-01-21 10:41:55 -04:00
ebefd816b6 Show shorter uuids when listing devices 2016-01-21 10:26:13 -04:00
fb1ef0df63 Promote shorter uuids in all examples 2016-01-21 10:23:40 -04:00
4489b1daa0 Merge pull request #299 from resin-io/misc/remove-tests
Remove tests tasks and CI configuration
2016-01-21 10:18:53 -04:00
96f0b5fbd6 Remove tests tasks and CI configuration
We don't have any tests in this repository
2016-01-21 10:16:54 -04:00
f6897ad41f Merge pull request #298 from resin-io/upgrade/sdk
Upgrade Resin SDK to v5.0.1
2016-01-21 10:14:56 -04:00
69e031da28 Upgrade Resin SDK to v5.0.1
This breaking change doesn't affect the CLI in any way, so we can
upgrade directly.
2016-01-21 10:13:15 -04:00
c61a7ef94a Merge pull request #296 from resin-io/ci/notifications
Improve Travis and Appveyor notifications
2016-01-18 11:32:48 -04:00
65bc22c02c Merge pull request #295 from resin-io/fix/delete-device-resource-on-errors
Remove registered device resource in case of errors in quickstart
2016-01-14 10:58:18 -04:00
1d55ea4dcf Improve Travis and Appveyor notifications 2016-01-14 10:49:11 -04:00
add30b33a1 Remove registered device resource in case of errors in quickstart
A device resource needs to be registered with the API before being able
to create the `config.json` file that goes in a device.

This means thats the device image is configured and written to an
external drive (e.g: SDCard) *after* the device resource registered.

If any of the above operations fail, there will be an unitialized orphan
device living in the selected application that the user will have to
remove himself.
2016-01-14 09:14:45 -04:00
999120e711 Merge pull request #293 from resin-io/doc/faq
Improve FAQ
2016-01-13 09:34:22 -04:00
67ce0f7f2d Merge pull request #294 from resin-io/feat/login-register
Redirect users to signup from login if they don't have an account
2016-01-13 09:34:16 -04:00
4645ad06bc Redirect users to signup from login if they don't have an account 2016-01-13 00:25:31 -04:00
612437ae58 Improvee FAQ with more frequent questions 2016-01-13 00:20:18 -04:00
35a821b904 Improve FAQ staging resin url title 2016-01-13 00:13:07 -04:00
e4359834d6 Rename README documentation section to FAQ 2016-01-13 00:12:04 -04:00
ef7e39450c Merge pull request #292 from resin-io/feat/ux-improvements
UX CLI improvements
2016-01-12 14:28:47 -04:00
c3a5998d5c Reuse messages 2016-01-12 10:45:32 -04:00
78ab2af8ba Print verbose help in resin help command 2016-01-12 10:39:29 -04:00
11354de596 Print an informative message after successful login 2016-01-12 10:30:56 -04:00
86cac606e4 Add Resin.io ASCII art in login 2016-01-12 10:23:46 -04:00
9b052c9aa5 Handle authentication in quickstart
If the user is not logged in, make quickstart prompt for authentication
automatically.
2016-01-12 10:12:44 -04:00
8d709aea7d Implement purely interactive login command
The new login command interactively asks the user if he wants to login
using web/credentials/token.
2016-01-12 09:08:03 -04:00
70ea8dd1a3 Redirect users to GitHub and Gitter in case of errors
Users will ge a better experience by knowing exactly where to go for
help if things go wrong.
2016-01-12 08:31:40 -04:00
11c0d2a847 Merge pull request #289 from resin-io/help/device-init-primary
Don't make `device init` a primary command
2016-01-12 08:08:38 -04:00
301b8a6ba3 Merge pull request #290 from resin-io/doc/quickstart-sudo
Stop instructing users to run quickstart as root
2016-01-12 08:08:34 -04:00
acb0aa445c Merge pull request #291 from resin-io/doc/support-gitter
Point users to Gitter in Support README section
2016-01-12 08:08:29 -04:00
a90d578c85 Point users to Gitter in Support README section 2016-01-11 16:04:22 -04:00
d859228aa9 Stop instructing users to run quickstart as root
Elevation is asked in specific steps automatically.
2016-01-11 16:01:40 -04:00
2be105d329 Don't make device init a primary command
Unlikely that a user will run this directly having the more high level
`quickstart`.
2016-01-11 16:00:07 -04:00
6d48fcfd6f Merge pull request #288 from resin-io/misc/build
Build CoffeeScript files with LICENSE additions
2016-01-11 15:59:06 -04:00
551a315432 Build CoffeeScript files with LICENSE additions 2016-01-11 15:58:35 -04:00
351dfdb892 Merge pull request #287 from resin-io/feat/gitter-badge
Add Gitter badge
2016-01-11 12:19:06 -04:00
dc6727fbf1 Add Gitter badge 2016-01-11 11:28:33 -04:00
af88e48c39 Merge pull request #285 from resin-io/doc/license
Change license to Apache 2.0
2016-01-04 10:25:33 -04:00
9cfce68489 Change license to Apache 2.0 2016-01-03 23:58:51 -04:00
8393ff647c Merge pull request #283 from resin-io/doc/cli-staging
Document how to point the CLI to staging
2016-01-01 02:19:43 -04:00
63122a5f51 Merge pull request #282 from resin-io/feat/credential-auth
Add optional credential-based authentication
2015-12-31 22:02:31 -04:00
0ad4598575 Document how to point the CLI to staging 2015-12-31 22:00:39 -04:00
b71c28cec0 Add optional credential-based authentication 2015-12-12 00:11:04 -04:00
b0ab23dad4 v2.5.0 2015-12-11 21:30:02 -04:00
de9297c351 Merge pull request #281 from resin-io/feat/logs-timestamp
Add timestamp to logs lines
2015-12-11 21:26:21 -04:00
26e3cb7957 Add timestamp to logs lines 2015-12-11 20:28:29 -04:00
bb78a3ca09 Merge pull request #280 from resin-io/feat/lazy-loading
Lazy load command actions dependencies
2015-12-07 16:21:32 -03:00
210680c9c9 Lazy load command actions dependencies
In my system (MBPr 13), printing the current version takes over 2
seconds:

```sh
$ time ./bin/resin version
2.4.0
./bin/resin version  1.37s user 0.19s system 73% cpu 2.130 total
```

The CLI takes almost all of these time to parse the dependency tree
before returning control over the actually called command.

To mitigate this problem, we only require the NPM dependencies a command
requires when executing such command, and thus prevent dependencies from
being required and parsed unnecessary.

After this improvement, printing the original example (`resin version`)
returns in less than a second (2x improvement):

```sh
$ time ./bin/resin version
2.4.0
./bin/resin version  0.88s user 0.09s system 102% cpu 0.938 total
```
2015-12-07 11:48:54 -03:00
6810eb31fd Merge pull request #279 from resin-io/jviotti/feat/npmignore
Add npmignore
2015-12-04 11:02:01 -04:00
f5b6df483d Merge pull request #278 from resin-io/jviotti/doc/readme-inst
Add --production to installation instructions
2015-12-04 10:55:56 -04:00
7d0da7adc0 Merge pull request #277 from resin-io/jviotti/feat/token-login
Support for login in with token
2015-12-04 10:55:39 -04:00
785f2b4ef5 Add npmignore 2015-12-04 08:51:28 -04:00
b668a8c7d0 Add --production to installation instructions 2015-12-04 08:31:39 -04:00
2e247faae4 Merge pull request #276 from resin-io/jviotti/feat/quickstart-after-instructions
Add helpful instructions after quickstart
2015-12-03 10:24:13 -04:00
3997a61b78 Support for login in with token
This is useful in the scenario when the user is using the CLI in an
environment in which he/she doesn't have access to a web browser, like a
headless server or a Vagrant development environment.
2015-12-03 10:22:22 -04:00
8ef27f0525 Add helpful instructions after quickstart 2015-12-02 16:28:32 -04:00
20855be968 Merge pull request #275 from resin-io/jviotti/feat/sudo-explain
Explain why we need the computer password on device init
2015-12-02 15:59:27 -04:00
800d13e3cd Merge pull request #274 from resin-io/jviotti/feat/id-devices
Show id in devices command
2015-12-02 15:59:21 -04:00
abc8399260 Explain why we need the computer password on device init 2015-12-02 11:15:20 -04:00
9ad2ba1131 Show id in devices command 2015-12-02 09:06:41 -04:00
0f8d6a98e3 v2.4.0 2015-12-01 14:43:53 -04:00
81af8c74b4 Merge pull request #273 from resin-io/jviotti/update/doc
Update generated documentation
2015-12-01 14:41:29 -04:00
16ab74294f Update generated documentation 2015-12-01 12:56:53 -04:00
f8bcc9d1ea Merge pull request #272 from resin-io/jviotti/feature/automatic-login-exchange
Perform automatic token exchange with the dashboard
2015-12-01 12:56:07 -04:00
9a89e3c3ca Perform automatic token exchange with the dashboard 2015-11-25 09:25:08 -04:00
359c37f259 Merge pull request #270 from resin-io/jviotti/fix/remove-debug-download-msg
Simplify download output message
2015-11-24 11:07:40 -04:00
1ba5697986 Merge pull request #271 from resin-io/jviotti/dependencies/remove-unused
Remove unused dependencies
2015-11-24 11:07:21 -04:00
647ed1e7aa Remove unused dependencies 2015-11-24 00:06:44 -04:00
b881e23c1c Merge pull request #269 from resin-io/jviotti/feature/device-type-in-app-list
Show device types when selecting applications
2015-11-23 23:39:34 -04:00
ae8621dc81 Simplify download output message
The message displayed the output of the download, which was mainly used
for debugging purposes when developing `device init` and `quickstart`.
2015-11-23 23:38:28 -04:00
e08c3752f9 Show device types when selecting applications
Some CLI commans prompt to select an existing application, presending a
dropdown with all the application names, however it's hard to remember
which application belon to which device type, which makes it easier to
select the wrong application.
2015-11-23 09:23:08 -04:00
65646d1206 v2.3.0 2015-11-20 13:01:58 -04:00
e42d3e8c4c Merge pull request #266 from resin-io/jviotti/feature/resin-url-info
Clarify resin url on auth and whoami
2015-11-18 16:15:46 -04:00
a4642f6184 Clarify resin url on auth and whoami
When you change the `resinUrl` config from time to time it can be
confusing to remember where you're logging in, or in which host you're
in.

Currently I have to check the configuration files/environment variables
manually or run `resin settings`.

This PR prints the detected resin url on `resin login` and `resin
whoami` so it's always clear where you are.
2015-11-16 10:11:08 -04:00
038c871911 Merge pull request #265 from resin-io/jviotti/feature/settings
Implement settings command
2015-11-16 09:03:20 -04:00
f52dd2976f Implement settings command
This command allows the user to list all detected settings.
2015-11-15 22:08:02 -04:00
d079a57da4 Merge pull request #264 from resin-io/jviotti/fix/devices-uuid
Show uuid in devices command
2015-11-13 15:33:17 -04:00
43697a3476 Show uuid in devices command
The command to get information about a device, `resin device` requires a
`uuid` as a parameter. Given that we don't show uuids in `resin
devices`, the user has no way to know what uuid to pass to get extra
information.

We also remove some non very used information columns from `resin
devices` to make space for the uuid.
2015-11-13 14:06:55 -04:00
b893bd1e39 Merge pull request #262 from resin-io/jviotti/feature/windows-elevation
Handle Windows permissions elevation automatically
2015-11-12 14:05:44 -04:00
c3b5a768e1 Handle Windows permissions elevation automatically 2015-11-12 13:30:48 -04:00
111ea44b40 Resin CLI v2.2.0 2015-11-12 08:33:51 -04:00
d1b25c17b6 Merge pull request #261 from resin-io/jviotti/feature/move-device
Implement device move command
2015-11-12 08:32:55 -04:00
ba318f2939 Implement device move command
This command allows to user to move a device to another application he
owns.
2015-11-12 07:47:16 -04:00
7ac0291c53 Merge pull request #260 from resin-io/jviotti/102/feature/device-reconfigure
Implement config reconfigure command
2015-11-11 10:59:31 -04:00
f64676ab98 Implement config reconfigure command
This command allows the user to reconfigure an already provisioned
device.

Fixes: https://github.com/resin-io/resin-cli/issues/102
2015-11-11 10:38:45 -04:00
d522cbe1ca Merge pull request #259 from resin-io/jviotti/refactor/resin-config-json
Make use of resin-config-json for config commands
2015-11-11 10:27:24 -04:00
4fc7a4e436 Make use of resin-config-json for config commands
This module encapsulates the low level details of `config.json` I/O and
tests them extensively.

See: https://github.com/resin-io/resin-config-json
2015-11-11 10:04:46 -04:00
79f2b4f0d5 Merge pull request #258 from resin-io/jviotti/doc/regenerate
Regenerate documentation
2015-11-11 09:17:52 -04:00
880a7b1e25 Regenerate documentation 2015-11-11 08:45:38 -04:00
89c5bb3080 Resin CLI v2.1.0 2015-11-11 08:31:32 -04:00
a71fb8ca4d Merge pull request #257 from resin-io/jviotti/feature/config-json-write
Implement config write command
2015-11-11 08:29:10 -04:00
3b35aed3bf Implement config write command
This command allows the user to overwrite properties of the config.json
file.
2015-11-10 14:28:18 -04:00
0bc3b9460f Merge pull request #256 from resin-io/jviotti/feature/read-config
Implement config read command
2015-11-10 13:08:54 -04:00
5509a3e9fd Implement config read command
This command is used to read a config.json from a provisioned device
2015-11-10 12:53:34 -04:00
f84d0d0980 Merge pull request #253 from resin-io/jviotti/refactor/sudo-president
Use president to provide sudo functionality
2015-10-27 07:58:17 -04:00
c866f6e46c Use president to provide sudo functionality 2015-10-26 09:47:49 -04:00
3192f9d2ef Merge pull request #252 from resin-io/jviotti/fix/239/sudo-explain
Clarify the need of computer password during sudo
2015-10-26 09:42:26 -04:00
de83a06db8 Clarify the need of computer password during sudo
Since we only prompt "Password:", it might be confusing for some users
that think they have to enter their Resin.io password instead.

Fixes: https://github.com/resin-io/resin-cli/issues/239
2015-10-26 08:49:41 -04:00
9260c8dce2 Resin CLI v2.0.1 2015-10-26 08:46:16 -04:00
bea5f22732 Merge pull request #251 from resin-io/jviotti/fix/stream-wait-sudo
Refer to the correct waiting stream function
2015-10-26 08:45:14 -04:00
363f12f81b Refer to the correct waiting stream function
We recently changed to using `rindle`, however looks like we forgot
to replace this particular instance.
2015-10-26 08:34:07 -04:00
1cbd33679f Resin CLI v2.0.0 2015-10-26 08:08:20 -04:00
e962371b59 Merge pull request #248 from resin-io/jviotti/remove/associate
Remove app associate command
2015-10-21 14:13:28 -04:00
77a3d4d6f6 Merge pull request #249 from resin-io/jviotti/fix/validation-module
Fix validation module require typo
2015-10-21 14:13:21 -04:00
fc5fe6cf68 Fix validation module require typo 2015-10-21 13:28:51 -04:00
f921488e8c Remove app associate command 2015-10-21 13:25:22 -04:00
8fe08642f5 Merge pull request #245 from resin-io/jviotti/feature/simplify-quickstart
Remove project directory creation in quickstart
2015-10-21 13:20:35 -04:00
822632718f Merge pull request #247 from resin-io/jvioti/refactor/os
Remove unused getOperatingSystem function
2015-10-21 11:43:19 -04:00
f66cd00646 Remove project directory creation in quickstart
The last part of `quickstart` feels weird. By consensus, we remove the
part that attempts to create a project directory and leave that step to
the user.
2015-10-21 11:18:29 -04:00
5498e45a35 Merge pull request #246 from resin-io/jviotti/refactor/rindle
Use rindle instead of custom waitStream
2015-10-21 11:15:12 -04:00
38479b3191 Merge pull request #244 from resin-io/jviotti/refactor/unused-npm
Remove unused npm dependency
2015-10-21 10:22:09 -04:00
965fd8fc19 Remove unused getOperatingSystem function 2015-10-21 10:20:38 -04:00
7a4f551a47 Use rindle instead of custom waitStream 2015-10-21 10:17:10 -04:00
303fd74012 Merge pull request #243 from resin-io/jviotti/feature/validation
Refactor validation to a single place
2015-10-21 10:11:46 -04:00
6a7d1b0c70 Remove unused npm dependency 2015-10-21 10:02:08 -04:00
c1e6a28640 Refactor validation to a single place 2015-10-21 09:37:25 -04:00
ec72f93480 Merge pull request #242 from resin-io/jviotti/feature/us-pw-login
Implement user/password login with 2FA support
2015-10-21 09:32:17 -04:00
8913fb515b Implement user/password login with 2FA support 2015-10-21 08:28:20 -04:00
6f91ff898f Merge pull request #241 from resin-io/jviotti/doc/drive
Regenerate os initialize documentation
2015-10-20 10:22:40 -04:00
aa949103f6 Merge pull request #240 from resin-io/jviotti/feature/device-init-advanced
Allow advanced option in device init
2015-10-20 09:47:04 -04:00
14bd4ad74e Regenerate os initialize documentation 2015-10-20 09:17:48 -04:00
f2507daa09 Allow advanced option in device init
This option is inherited to `os configure`.
2015-10-20 09:16:56 -04:00
ff81c1e514 Merge pull request #234 from resin-io/jviotti/feature/advanced-options
Ignore advanced configuration questions by default
2015-10-20 09:12:38 -04:00
7ce92b47a0 Merge pull request #238 from resin-io/jviotti/cleanup/dependencies
Remove unused resin-device-config
2015-10-19 16:04:50 -04:00
bde5cc65da Merge pull request #235 from resin-io/jviotti/fix/device-register-help
Load device info after all other device commands
2015-10-19 15:51:15 -04:00
ec9347c3a4 Merge pull request #237 from resin-io/jviotti/fix/hound
Change java_script to javascript in hound config
2015-10-19 15:51:07 -04:00
ceb8dada1d Remove unused resin-device-config 2015-10-19 15:26:09 -04:00
f4186acf80 Merge pull request #236 from resin-io/jviotti/feature/device-register-uuid
Allow passing a custom uuid to device register
2015-10-19 15:17:25 -04:00
05ce54eac1 Change java_script to javascript in hound config
They seemed to change this recently.
2015-10-19 14:21:10 -04:00
d28ecf3230 Allow passing a custom uuid to device register 2015-10-19 14:16:47 -04:00
8562f723c5 Load device info after all other device commands
This command obscures help pages for all device commands registered
afterwards since it's a common prefix for all of them.
2015-10-19 14:14:04 -04:00
f6d2043747 Merge pull request #232 from resin-io/jviotti/fix/app-create-validation
Require application name to have at least 4 characters
2015-10-19 14:06:43 -04:00
485818f3b5 Merge pull request #233 from resin-io/jviotti/fix/app-create-type
Fix --type option taking no effect in app create
2015-10-19 14:03:59 -04:00
ec28bd9c9e Ignore advanced configuration questions by default
The advanced questions can be enabled by passing `--advanced` in `os
configure`.
2015-10-19 14:02:57 -04:00
ad68dcf692 Fix --type option taking no effect in app create 2015-10-19 13:07:23 -04:00
0b7e2a2c8c Require application name to have at least 4 characters
We get a weird error message from pine otherwise:

	ResinRequestError: Request error: It is necessary that each app name
	that is of a user (Auth), has a Length (Type) that is greater than or
	equal to 4.
2015-10-19 10:56:02 -04:00
b6ebd0631a Merge pull request #229 from resin-io/jviotti/feature/os-initialize-type-option
Take device type as an option in os initialize
2015-10-15 09:59:44 -04:00
7ace4bdfa6 Merge pull request #230 from resin-io/jviotti/fix/update
Improve the way the update notifier is shown
2015-10-15 09:43:20 -04:00
1cfbd4197d Improve the way the update notifier is shown
Current has the following problems:

- Our custom message gets printed even if the notifier doesn't contain
an update.

- The notifier box is deferred, therefore it's printed at the end of the
command. Since our custom message is printed at the beginning, it makes
no sense at all.
2015-10-15 09:18:45 -04:00
b2425d2c0e Take device type as an option in os initialize 2015-10-15 09:11:38 -04:00
0ba914236a Merge pull request #228 from resin-io/jviotti/feature/os-initialize-drive
Support drive option in os initialize
2015-10-15 08:49:26 -04:00
71ee0a6cf7 Support drive option in os initialize
This allows the user to bypass the drive selection dialog.

This option can be used along with `--yes` to make the command
completely non-interactive. For example:

	$ resin os initialize rpi.img 'raspberry-pi' --drive /dev/disk2 --yes
2015-10-15 08:14:35 -04:00
4326ad4d9c Merge pull request #227 from resin-io/jviotti/fix/os-initialise-yes
Add missing `yes` option to `os initialize`
2015-10-15 07:44:33 -04:00
055bac6ff4 Merge pull request #226 from resin-io/jviotti/feature/223/update-sudo
Clarify the need for admin privileges on update
2015-10-15 07:40:15 -04:00
58713dc291 Add missing yes option to os initialize
This option is tried to be used within the command, but is not defined
as a formal Capitano option.
2015-10-14 17:49:27 -04:00
adf4aef517 Clarify the need for admin privileges on update
Fixes: https://github.com/resin-io/resin-cli/issues/223
2015-10-14 13:45:08 -04:00
a17bb2cc09 Merge pull request #220 from resin-io/jviotti/changelog/spacing
Remove spaces between lists in CHANGELOG
2015-10-13 13:04:08 -04:00
48d620f7cd Remove spaces between lists in CHANGELOG
GitHub displays the lists in a weird way otherwise.
2015-10-13 12:39:43 -04:00
fa7b104762 Resin CLI v1.1.0 2015-10-13 12:37:50 -04:00
faf2fa167f Merge pull request #219 from resin-io/jviotti/doc/troubleshoot
Remove outdated troubleshooting information
2015-10-13 12:17:46 -04:00
ad1e68427c Remove outdated troubleshooting information 2015-10-13 11:46:21 -04:00
e9147f0f6f Merge pull request #218 from resin-io/jviotti/fix/windows-edison
Avoid _.ary in temporal path disposer
2015-10-12 18:28:30 -04:00
cddf630907 Avoid _.ary in temporal path disposer
For some reason fails with a weird Bluebird error on Windows
2015-10-12 18:12:58 -04:00
494a286cae Merge pull request #217 from resin-io/jviotti/upgrade/sdk
Upgrade SDK to v3.0.0
2015-10-12 09:03:59 -04:00
e5e871ddcd Upgrade SDK to v3.0.0
Breaking changes in this version:

- `resin.models.device.generateUUID()` is now async.
2015-10-12 08:34:22 -04:00
5a3166e3de Merge pull request #215 from resin-io/jviotti/fix/await-wrap
Shorten the length of await device message
2015-10-07 12:41:57 -04:00
3149464c7a Shorten the length of await device message
If the spinner message doesn't fit in your terminal, each spinner
position will be printed in different lines.

We mitigate this by dramatically shortenning the message.
2015-10-07 11:38:59 -04:00
97d9b7816f Merge pull request #214 from resin-io/jviotti/feature/plugin-warn-red
Print plugin warnings in red as other errors
2015-10-06 19:18:33 -04:00
ec77437080 Print plugin warnings in red as other errors
For the sake of consistency.
2015-10-06 18:51:17 -04:00
d65882639a Merge pull request #211 from resin-io/jviotti/feature/101/help-topics
Separate general help per topic relevance
2015-10-02 09:12:58 -04:00
f8470287c1 Separate general help per topic relevance
Only list primary commands by default, unless a `--verbose` option is
passed to list the additional ones.

Fixes: https://github.com/resin-io/resin-cli/issues/101
2015-10-02 08:50:32 -04:00
3cc41ed62a Merge pull request #212 from resin-io/jviotti/fix/109/root-owner
Call os initialize as an elevated process
2015-10-01 14:08:19 -04:00
445e37ccaf Call os initialize as an elevated process
Currently, the fact that `os initialize` requires elevated permissions
forced us to require calling commands that reuse it, such as `device
init` and `quickstart` with administrator permissions as well.

This ended up causing issues like saving images in the cache that belong
to root, or initializing git repositories that requires `sudo` to
commit.

The solution is to call `os initialize` as a child process preppending
`sudo` within `device init`.

Fixes: https://github.com/resin-io/resin-cli/issues/109
2015-10-01 13:07:53 -04:00
ed6427c541 Merge pull request #210 from resin-io/jviotti/feature/os-init-type
Make os initialize take a device type instead of a uuid
2015-09-30 15:59:58 -04:00
90be01b05d Make os initialize take a device type instead of a uuid 2015-09-30 14:31:23 -04:00
1124293b9a Merge pull request #209 from resin-io/jviotti/doc/update
Regenerate documentation
2015-09-30 14:30:43 -04:00
0e804fdfd8 Regenerate documentation 2015-09-30 12:07:44 -04:00
0443a35f2b Merge pull request #207 from resin-io/jviotti/fix/promise-using
Fix incorrect Promise.using syntax
2015-09-30 12:06:51 -04:00
3a148217e0 Merge pull request #208 from resin-io/jviotti/fix/manifest-device-type
Send device type correctly to getManifestBySlug
2015-09-30 12:06:45 -04:00
79d1892b66 Send device type correctly to getManifestBySlug
Currently, we we're sending the wholea device object to
`getManifestBySlug`, which ended up in an unsupported device error.
2015-09-30 11:38:34 -04:00
0e06ac464f Fix incorrect Promise.using syntax
`Promise.using` takes the function that acts on the resource as the
second argument, instead of as `.then()`.
2015-09-30 11:37:27 -04:00
5ae83d8337 Merge pull request #206 from resin-io/jviotti/fix/uncompress-os-download
Uncompress zip packages in os download
2015-09-30 10:48:36 -04:00
8694ee2c59 Merge pull request #205 from resin-io/jviotti/feature/rimraf-file-disposer
Use rimraf for deleting os temporary files
2015-09-30 10:31:46 -04:00
8234f7675a Uncompress zip packages in os download
When downloading an operating system image, if the image is a zip
package, uncompress it automatically.
2015-09-30 10:16:24 -04:00
15cb0c4889 Use rimraf for deleting os temporary files
We already use `rimraf` for deleting os temporary directories, however
there are a few benefits of using it for files as well:

- Simplicity. We avoid having to check if a path is a file or directory.
- `rimraf` attempts to workaround the known Windows issues of anti
viruses not closing files. Described in more detail here: https://github.com/resin-io/resin-cli/blob/master/TROUBLESHOOTING.md#i-get-ebusy-errors-after-initializing-a-device-even-as-administrator-on-windows
2015-09-30 10:06:08 -04:00
a3ebd9827f Merge pull request #204 from resin-io/jviotti/fix/console.info
Use console.info in os download
2015-09-30 10:05:19 -04:00
30d84f015a Merge pull request #199 from resin-io/jviotti/feature/197/device-init-apps
Prompt for select application if running device init with no arguments
2015-09-29 15:31:59 -04:00
686414b03d Merge pull request #198 from resin-io/jviotti/feature/temp-disposer
Use Promise.disposer() to make sure temp files are deleted
2015-09-29 15:25:09 -04:00
6377618c12 Use console.info in os download
`console.info` calls can be quieted by the `--quiet` option.
2015-09-29 15:15:39 -04:00
f17e9c97b8 Prompt for select application if running device init with no arguments
Currently, if `device init` was ran without an application argument, we
attempted to get the application name from the current directory, given
it was a git repository.

This approach led to confusions from time to time, so now we prompt the
user to select one of it's own applications from a dropdown instead of
checking the current directory in this edge case.

Fixes: https://github.com/resin-io/resin-cli/issues/197
2015-09-29 15:10:59 -04:00
21fcdfaff6 Use Promise.disposer() to make sure temp files are deleted 2015-09-29 15:08:24 -04:00
4072edcced Merge pull request #203 from resin-io/jviotti/feature/os-initialize
Implement os initialize command
2015-09-29 14:59:59 -04:00
d704c10197 Implement os initialize command
This command initialized an operating system image with a disk device.
2015-09-29 14:52:34 -04:00
dea2a7f055 Merge pull request #202 from resin-io/jviotti/feature/device-register
Implement device register command
2015-09-29 14:41:03 -04:00
7e6eb4b9e4 Implement device register command
This command registers a new device with the passed application,
returning the new device uuid.
2015-09-29 14:33:31 -04:00
61474fba5c Merge pull request #201 from resin-io/jviotti/feature/os-configure
Implement os configure
2015-09-29 14:26:03 -04:00
42256384be Implement os configure
This command, given a path to an image and a device uuid, perform
configuration based on the resin-device-type manifests.
2015-09-29 13:47:10 -04:00
e25f232fe5 Merge pull request #200 from resin-io/jviotti/feature/os-download
Implement os download command
2015-09-29 13:11:24 -04:00
f6d8f12ba2 Implement os download command
This command download an unconfigured image to both the cache and to the
specified location by the `--output` option.
2015-09-29 13:03:14 -04:00
d2b9e6fd8c Merge branch 'jviotti/doc/anti-virus-ebusy' 2015-09-21 09:28:13 -04:00
cf7effacc0 Document anti virus and EBUSY errors on Windows 2015-09-21 09:27:18 -04:00
1eb7aba293 Merge branch 'master' of https://github.com/resin-io/resin-cli 2015-09-21 09:25:57 -04:00
21e916679c Update author email to @resin.io 2015-09-21 09:15:27 -04:00
d574743c21 Merge pull request #195 from resin-io/jviotti/docs/cygwin-to-troubleshooting
Move Cygwin caveat from README to TROUBLESHOOTING
2015-09-21 08:57:39 -04:00
d8a2b82662 Move Cygwin caveat from README to TROUBLESHOOTING 2015-09-21 08:51:54 -04:00
f4ebd890df Merge pull request #194 from resin-io/jviotti/doc/troubleshooting
Add Troubleshooting guide
2015-09-21 08:47:14 -04:00
b0be5de83a Add Troubleshooting guide
This guide described common Resin CLI issues and how to fix them.
2015-09-21 08:32:11 -04:00
ba21ddd010 Merge pull request #192 from resin-io/jviotti/doc/readme
Improve README.md
2015-09-21 08:01:44 -04:00
eecd7a0fd8 Improve README.md
- Make user oriented instead of developer oriented.
- Remove deprecated information.
- Add Requisites section.
- Add Getting Started section.
- Add Support section.
- Add License section.
2015-09-21 07:56:24 -04:00
eb4c2f62a7 Resin CLI v1.0.0 2015-09-11 21:21:44 +03:00
dc1e5e6512 Merge pull request #190 from resin-io/jviotti/message/await
Improve device awaiting message
2015-09-11 19:19:14 +03:00
adc0b183cd Improve device awaiting message
Current message sounds too robotic.
2015-09-11 19:13:30 +03:00
828b4f73d1 Fix selecting existing application in quickstart 2015-09-11 18:30:30 +03:00
82a0761f49 Merge pull request #189 from resin-io/jviotti/feature/error-highlight
Highlight errors in red
2015-09-11 14:59:14 +03:00
904b9f07fb Highlight errors in red
- Move error translation logic to resin-io/resin-cli-errors.
- Force `process.exit()`.
2015-09-11 14:47:38 +03:00
3c0acaa7da Merge pull request #188 from resin-io/jviotti/feature/device-specs
Implement device specs. Fix #99
2015-09-11 13:10:44 +03:00
64c8420c9d Implement device specs. Fix #99
Support for all devices. Tested in the following ones:

- Intel Edison.
- Raspberry Pi 2.
- Parallella.
2015-09-11 13:02:59 +03:00
26e3dc1aa7 Merge pull request #187 from resin-io/jviotti/feature/ignore-resinrc
Add resinrc.yml to gitignore
2015-09-08 09:31:40 +03:00
3bc22a7b7c Merge pull request #186 from resin-io/jviotti/refactor/settings
Use settings from the SDK during login
2015-09-08 09:16:05 +03:00
7e5b2695fe Add resinrc.yml to gitignore
Some modules have an use case for shipping the configuration file with
the project, however this is not the case for the CLI.
2015-09-08 09:07:48 +03:00
79afa79fd9 Use settings from the SDK during login
This enforces all clients to use the Resin Settings Client version that
the SDK provides, reducing incompatibilities caused by different modules
requiring different Resin Settings Client versions.
2015-09-08 09:06:03 +03:00
cdaaddb826 Merge pull request #185 from resin-io/jviotti/upgrade/sdk
Upgrade Resin SDK to v2.7.2
2015-09-07 11:45:25 +03:00
ec5f6a7cd8 Upgrade Resin SDK to v2.7.2 2015-09-07 11:25:01 +03:00
72f34031a9 Merge pull request #184 from resin-io/jviotti/fix/token-auth
Check token validity against the API when login
2015-09-05 20:48:22 +03:00
dc257b5cab Check token validity against the API when login
Consider the following case:

The SDK is configured to point to staging, but the user passes a token
from production, or viceversa. Since the token is valid in a sense that
is valid JWT and contains real data, the CLI will report as a success.

The user will then get Unauthorized errors when using the API.
2015-09-05 20:17:34 +03:00
4bdcd3d2ee Merge pull request #180 from resin-io/issue_#103
Resin CLI Events integration. Fix #103
2015-09-05 20:11:52 +03:00
b0650530cc Resin CLI Events integration. Fix #103 2015-09-05 19:15:31 +03:00
454669ada2 Merge pull request #183 from resin-io/jviotti/182/docs/update
Update documentation
2015-09-01 13:09:42 -04:00
a65975596e Merge pull request #181 from resin-io/reword-example
Replace device name with uuid in env-variables command example
2015-09-01 13:03:27 -04:00
91f878cfc0 Update documentation
- There were changes to commands.
- Regenerates `login` documentation with production url.

Fixes: https://github.com/resin-io/resin-cli/issues/182
2015-09-01 13:01:47 -04:00
8c3e832cdc Replace device name with uuid in env-variables command example 2015-09-01 00:56:01 +03:00
a5c670902d Merge pull request #179 from resin-io/jviotti/appveyor/cache
Add Appveyor cache support
2015-08-28 08:42:57 -04:00
14be1d5f9f Add Appveyor cache support 2015-08-28 08:22:26 -04:00
41d6d5c670 Merge pull request #178 from resin-io/jviotti/refactor/quickstart
Refactor quickstart
2015-08-27 10:13:56 -04:00
a090e6c21d Refactor quickstart
- Use promises.
- Move some logic to `helpers`.
- Inline `device await` command.
2015-08-27 10:01:33 -04:00
d78c1ffa47 Merge pull request #176 from resin-io/jviotti/cleanup/compiled-files
Remove orphaned files from build/
2015-08-27 09:03:38 -04:00
5808d20d88 Merge pull request #177 from resin-io/modify-capitanodoc
Update capitanodoc.json
2015-08-27 15:45:05 +03:00
7f4065e3da Update capitanodoc.json 2015-08-27 15:30:38 +03:00
07daa51051 Remove orphaned files from build/
Some files were deleted from `lib/` but still live in `build/`. More
specifically:

- `build/actions/update.js`.
- `build/data/`.
2015-08-27 08:29:22 -04:00
d10d4ce185 Merge pull request #174 from resin-io/jviotti/feature/confirm-abortion
Add `Aborted` error message when not accepting a confirmation
2015-08-24 08:47:29 -04:00
7f763e7881 Merge pull request #175 from resin-io/jviotti/fix/update-root
Don't check for available updates when running as root
2015-08-24 07:41:56 -04:00
5de0f66d7a Don't check for available updates when running as root
`update-notifier` persist its update check results in a file, which is
then read when running again the application.

If this file gets written when the application is being run as root, we
get ugly EPERM issues.
2015-08-20 16:54:22 -04:00
354921ca92 Add Aborted error message when not accepting a confirmation
This prevents a lot of duplicate code to check for confirmation status
and exit from the current action.
2015-08-20 16:16:20 -04:00
fb28cc7d2f Merge pull request #173 from resin-io/jviotti/upgrade/form
Upgrade Resin CLI Form to v1.2.1
2015-08-20 16:11:17 -04:00
7cf89a9bf6 Merge pull request #172 from resin-io/jviotti/cleanup/readme
Remove Man pages section from README.md
2015-08-20 16:11:09 -04:00
a3cbc549d8 Upgrade Resin CLI Form to v1.2.1
This version contains a fix for a bug that prevented `when` properties
from working as expected.
2015-08-20 15:55:57 -04:00
1c48328347 Remove Man pages section from README.md
Man pages are not longer being produced.
2015-08-20 12:04:11 -04:00
9b69fe3c3c Merge pull request #171 from resin-io/jviotti/upgrade/cli-form
Update Resin CLI Form to v1.2.0
2015-08-20 12:02:26 -04:00
dc513a08f6 Update Resin CLI Form to v1.2.0
This version includes support for the `drive` input type.
2015-08-20 11:55:53 -04:00
fcc44949a7 Merge pull request #169 from resin-io/jviotti/refactor/plugins
Upgrade Nplugm to v3.0.0
2015-08-19 12:49:32 -04:00
006764af66 Merge pull request #170 from resin-io/jviotti/cleanup-resin-write
Remove unused resin-write bin script
2015-08-19 12:49:25 -04:00
b879d3f9ea Remove unused resin-write bin script
This script was used along with windosu as a workaround to call `device
init` with elevated permissions.

Since Windows elevation is not used anymore for now, this script can be
removed.
2015-08-19 11:30:48 -04:00
7f4863da86 Upgrade Nplugm to v3.0.0
This new version supports promises and contains speed improvements.
2015-08-19 11:27:28 -04:00
ba6f50d171 Merge pull request #168 from resin-io/jviotti/cleanup/plugins
Remove plugins manipulation commands
2015-08-19 11:14:35 -04:00
a803d4f646 Remove plugins manipulation commands
Since we're now forcing users to rely on `npm` directly for updates, we
can also get rid of plugin commands that attempt to
install/update/remove using npm programatically and require users to use
`npm` directly as well.

This commit removes the following commands:

- `plugins`
- `plugin install`
- `plugin update`
- `plugin remove`

Despite plugin related commands being removed, *the functionality that
scans for plugins and registers them remains intact*.
2015-08-19 10:57:42 -04:00
85d940df66 Merge pull request #165 from resin-io/jviotti/feature/update-notifier
Notify the user if there is an available update
2015-08-19 07:56:40 -04:00
6f9535ca34 Merge pull request #167 from resin-io/issue-166
Display msg when app/device does not have env variables. Fix #166.
2015-08-18 18:17:21 +03:00
019e2ac357 Display msg when app/device does not have env variables. Fix #166 2015-08-18 18:12:08 +03:00
433916e18a Merge pull request #164 from resin-io/issue-90
Add message informing the user about potential delay in system img initialization. Fix #90.
2015-08-18 16:04:44 +03:00
f19588032f Notify the user if there is an available update
For this we use the `update-notifier` module with its default settings.

This module will print a nice banner prompting the user to run the
corresponding npm command to update.
2015-08-18 08:53:06 -04:00
0595452c3d Add message informing the user about potential delay in system img initialization. Fix #90. 2015-08-18 15:43:52 +03:00
d6305df48e Merge pull request #163 from resin-io/issue-108
Reword ending message in quickstart. Fix #108
2015-08-18 15:00:38 +03:00
f7084580b2 Merge pull request #162 from resin-io/issue-106
Reword output during download in device init. Fix #106.
2015-08-18 14:59:08 +03:00
3dd5f5858a Reword ending message in quickstart. Fix #108 2015-08-18 14:34:15 +03:00
02a06e1e7c Reword output during download in device init. Fix #106. 2015-08-18 13:55:04 +03:00
50daf8ef73 Merge pull request #161 from resin-io/jviotti/refactor/env
Refactor env action module to use promises
2015-08-17 10:42:40 -04:00
fd5a34a1c4 Refactor env action module to use promises 2015-08-17 10:32:22 -04:00
51fda13684 Merge pull request #160 from resin-io/jviotti/remove/devices-supported
Remove `devices supported` command
2015-08-17 10:22:10 -04:00
a698b25fda Remove devices supported command
The command is not necessary and unused.
2015-08-17 10:05:36 -04:00
89bd861d8e Merge pull request #159 from resin-io/jviotti/refactor/device
Refactor device actions to use promises
2015-08-17 10:03:57 -04:00
e5b7aae4ae Refactor device actions to use promises 2015-08-17 09:49:59 -04:00
031168ceed Merge pull request #158 from resin-io/jviotti/refactor/keys
Refactor keys action to use promises
2015-08-17 09:46:53 -04:00
09a5788902 Refactor keys action to use promises 2015-08-17 09:32:05 -04:00
713664d103 Merge pull request #157 from resin-io/jviotti/feature/settings-projects-dir
Make use of `projectsDirectory` SDK setting in Quickstart
2015-08-17 09:20:30 -04:00
f63391acf9 Make use of projectsDirectory SDK setting in Quickstart
We were currently building this path ourselves, hardcoding the place of
the resin local per user directory instead of relying on the foundations
that `resin-settings-client` give us.
2015-08-17 09:06:27 -04:00
79ee4302ec Merge pull request #156 from resin-io/jviotti/upgrade/sdk
Upgrade Resin SDK to v2.4.1
2015-08-17 08:59:17 -04:00
9adda22921 Upgrade Resin SDK to v2.4.1
This new version contains fixes for the following issues:

- https://github.com/resin-io/resin-cli/issues/87
- https://github.com/resin-io/resin-cli/issues/120
2015-08-17 08:42:17 -04:00
25311f2a18 Merge pull request #146 from resin-io/jviotti/refactor/auth
Refactor auth actions to use promises
2015-08-17 08:41:19 -04:00
70c060b124 Refactor auth actions to use promises 2015-08-17 08:22:48 -04:00
7a8a3c851b Merge pull request #138 from resin-io/refactor/help
Refactor help module
2015-08-17 08:02:15 -04:00
1096b2d212 Merge pull request #143 from resin-io/jviotti/refactor/app
Refactor app actions to use promises
2015-08-17 08:02:04 -04:00
ee286c5690 Merge pull request #144 from resin-io/jviotti/refactor/note
Refactor note set command to use promises
2015-08-17 08:01:47 -04:00
1da1d2e6fc Merge pull request #152 from resin-io/jviotti/fix/151/ssh-key-list
Print ssh key separately from the information table
2015-08-17 08:01:32 -04:00
64be9f936d Merge pull request #155 from resin-io/jviotti/feature/107/await-spinner
Implement a spinner when awaiting for a device. Fix #107
2015-08-17 08:01:22 -04:00
30f24333c0 Implement a spinner when awaiting for a device. Fix #107
Fixes:

- https://github.com/resin-io/resin-cli/issues/107
2015-08-14 14:35:38 -04:00
30f6a78282 Merge pull request #154 from resin-io/jviotti/fix/device-await
Fix broken device await command
2015-08-14 14:31:00 -04:00
8c9a0e0ff1 Fix broken device await command
There were two issues that prevented this command from working
correctly:

1- `Promise.delay()` is used, but `Promise` was not imported.
2- The following line had incorrect indentation (spaces instead of
		tabs):

		poll().nodeify(done)

Therefore CoffeeScript interpreted that the line had to be executed at
the end of the `poll()` function, causing `poll()` to never be called.
2015-08-14 14:11:49 -04:00
8268bbf700 Merge pull request #150 from resin-io/jviotti/upgrade/sdk
Upgrade Resin SDK to v2.4.0
2015-08-14 12:42:31 -04:00
e712e2f266 Print ssh key separately from the information table
Since the public key string is long, it might wrap to lines below,
causing the table layout to break.

A quick solutio is to print the ssh key after the table.

Fixes:

- https://github.com/resin-io/resin-cli/issues/151
2015-08-14 12:25:55 -04:00
0807b6a2d9 Upgrade Resin SDK to v2.4.0
This release fixes:

- Check if device exists before removing it "resin device rm <uuid>"
	- https://github.com/resin-io/resin-cli/issues/123

- Check if app exists before removing it "resin app rm <appName>"
	- https://github.com/resin-io/resin-cli/issues/114

- Command does not display correct output "resin key <id>"
	- https://github.com/resin-io/resin-cli/issues/112

Since it includes the following PRs:

- https://github.com/resin-io/resin-sdk/pull/103
- https://github.com/resin-io/resin-sdk/pull/107
2015-08-14 12:17:59 -04:00
83382cc8f7 Merge pull request #145 from resin-io/jviotti/fix/logs-help-indentation
Fix logs command help string indentation
2015-08-14 08:27:38 -04:00
8401aaeae2 Merge pull request #149 from resin-io/jviotti/fix/111/email-validation
Validate that email address is valid during signup. Fix #111
2015-08-14 07:58:40 -04:00
abf5740950 Merge pull request #148 from resin-io/jviotti/fix/14/logs-history
Force logs command to exit when not in --tail mode. Fix #14.
2015-08-14 07:58:05 -04:00
606777508d Merge pull request #147 from resin-io/jviotti/cleanup/preferences
Remove preferences command
2015-08-14 07:57:14 -04:00
e9ec6c67b2 Validate that email address is valid during signup. Fix #111
For this we use a third party dependency from npm called `valid-email`
to avoid hardcoding and having to mantain a regular expression.
2015-08-13 15:22:22 -04:00
69566f7fc3 Force logs command to exit when not in --tail mode. Fix #14.
PubNub keeps the process alive after a history query for some reason, so
trying to print the logs history like:

	$ resin logs <uuid>

Will result in the logs being printed correctly, but the process waiting
infinitely without ending.

The workaround consists in forcing `process.exit` to exit the process
with an error code zero.

Caveats:

- This workaround prevents this command to be used programatically.

Issue: https://github.com/resin-io/resin-cli/issues/14
2015-08-13 15:08:16 -04:00
6e4b299c7d Remove preferences command 2015-08-13 15:00:51 -04:00
ef35ebf79d Fix logs command help string indentation
For some reason it was indented a few times unnecesarily.
2015-08-13 14:33:19 -04:00
1bc78edf71 Refactor help module
Main changes:

- Use the `columnify` module to display the commands instead of using
manual parsing.

- Extract logic to create a string representation from an option
signature to Capitano, and reuse here.

See https://github.com/resin-io/capitano/pull/28

Some bugs were caught and fixes during the refactoring:

- In command help, if the command didn't exist, we reused default
Capitanos command not found function which uses `process.exit(1)`. This
was changed to pass a custom error to `done()`, so the command fails
correctly when using programatically.

- General help didn't call `done()` at all, thus causing problems if
using the command programatically someday.
2015-08-13 14:19:07 -04:00
d5204a09f7 Refactor note set command to use promises 2015-08-13 14:17:02 -04:00
4647aa70c0 Implement utils/helpers to abstract common app patterns
- Add helpers.confirm() to abstract the process of asking for
confirmation.
- Add helpers.selectDeviceType() to abstract the form needed to ask for
device types.

The functions on this module are reused by app actions.
2015-08-13 14:04:47 -04:00
2e8ec3ac64 Merge pull request #142 from resin-io/jviotti/cleanup/dependencies
Remove unused dependencies imports from various files
2015-08-13 13:51:22 -04:00
25c6246e9f Refactor app actions to use promises
Use promises instead of `async` internally inside the following
commands:

- app create.
- app remove.
- app associate.
2015-08-13 13:42:49 -04:00
5408938007 Merge pull request #141 from resin-io/jviotti/cleanup/shell-completion
Remove command shell completion script
2015-08-13 13:08:08 -04:00
50cb04b6f7 Remove unused dependencies imports from various files 2015-08-13 13:04:22 -04:00
09fe4b11ad Merge pull request #139 from resin-io/jviotti/feature/drive-widget
Use Visuals drive widget in device init
2015-08-13 12:35:41 -04:00
4157f21e06 Merge pull request #140 from resin-io/jviotti/cleanup/elevate
Remove outdated Windows elevation mechanism
2015-08-13 12:23:26 -04:00
4900230881 Remove command shell completion script
This feature is unused and doesn't provide much value.

In the future, we may include autocompletion support built in the CLI.
2015-08-13 12:21:55 -04:00
e60c0605e5 Use Visuals drive widget in device init
- Replace custom `drivelist` logic in "device init" with the new `drive`
widget.
2015-08-13 11:56:16 -04:00
085781fa18 Upgrade Resin CLI Visuals to v1.1.0
This version contains the `drive` widget.
2015-08-13 11:55:31 -04:00
08ad8bd5d7 Merge pull request #137 from resin-io/cleanup/slim
Slim down unused functionality
2015-08-13 11:52:57 -04:00
3d36e5f5d3 Remove outdated Windows elevation mechanism
This functionality is outdated and not using anymore due to limitations
in the way it was addressed.

The module and dependencies are removed for now, and will be added back
in the future, once a better approach is planned.
2015-08-13 11:45:50 -04:00
57319f26a6 Slim down unused functionality 2015-08-12 08:17:46 -04:00
11033683fd Stop supporting iojs 2015-08-06 12:12:44 -04:00
e5166c6c8e Use Install-Product instead of Update-NodeJsInstallation 2015-08-06 11:46:57 -04:00
5c96663d1e Merge pull request #134 from resin-io/remove/drive-command
Remove drive command
2015-08-05 12:24:25 -04:00
ffb48c8669 Merge pull request #135 from resin-io/remove/examples-commands
Remove examples commands
2015-08-05 07:04:03 -04:00
12145a2393 Merge pull request #132 from resin-io/upgrade_travis
Test node v0.12 and io.js
2015-08-05 07:03:51 -04:00
f379866c1c Merge pull request #67 from resin-io/feature/wizard
Implement Quickstart command
2015-08-04 13:19:37 -04:00
dc030f4cd1 Implement Quickstart command 2015-08-04 20:16:55 +03:00
b726a2d778 Remove examples commands 2015-08-04 10:00:09 -04:00
a715ec9dc1 Remove drive command 2015-08-04 09:57:59 -04:00
d24b871964 Merge pull request #131 from resin-io/remove/selfupdate
Remove selfupdate functionality
2015-08-04 09:53:48 -04:00
bd0c4e6034 Merge pull request #133 from resin-io/upgrade_appveyor
Add io.js testing in Appveyor
2015-08-04 09:27:36 -04:00
95637e5608 Test node v0.12 and io.js 2015-08-04 14:15:30 +03:00
93b394ed76 Add io.js testing in Appveyor 2015-08-04 13:26:13 +03:00
b515e427ff Merge pull request #129 from resin-io/issue_#73
Add email address to the returned information, when using whoami(). Fix #73.
2015-08-03 16:14:47 -04:00
26b1acf5ef Merge pull request #130 from resin-io/remove/man
Remove man pages
2015-08-03 16:14:23 -04:00
f31eb7c2b5 Add email address to the returned information, when using whoami(). Fix #73. 2015-08-03 21:24:22 +03:00
d423a6ea24 Remove selfupdate functionality
We added this because we thought that knowledge of the supported device types, along with the configuration procedures was going to be encoded in the CLI.

With device specs, this is not longer the case.
2015-08-03 12:20:42 -04:00
4211333e4e Remove man pages 2015-08-03 12:08:49 -04:00
f220e380a7 Merge pull request #125 from resin-io/issue_#117
Display correctly the newly-created application id. Fix #117
2015-07-29 21:43:31 +03:00
9564b4e478 Display correctly the newly-created application id. Fix #117 2015-07-29 21:17:21 +03:00
e2125b8ce9 Fix #73 2015-07-29 21:15:29 +03:00
0bb0e6ea4b Merge pull request #124 from resin-io/integrate-new-resin-visuals-functionality
Integrate new resin-cli-visuals functionality
2015-07-29 09:43:24 -04:00
cf512cc01b Integrate new resin-cli-visuals functionality 2015-07-29 16:34:31 +03:00
fe3e68c3af Merge pull request #121 from resin-io/modify-function-description
Replace device name with uuid, found in resin envs examples in enviroment-variables
2015-07-28 08:49:19 -04:00
0bbfbe36c7 Replace device name with uuid, found in resin envs examples in enviroment-variables 2015-07-27 22:49:11 +03:00
d6ae689593 Merge pull request #118 from resin-io/resin-cli-form
Integrate resin-cli-form
2015-07-27 13:30:48 -04:00
5b5d1be52f Integrate resin-cli-form 2015-07-27 19:50:47 +03:00
cb808869dd Merge pull request #110 from resin-io/support_promises
Add promise support for Resin-SDK dependency
2015-07-24 08:02:40 -04:00
64d83dccfb Add promise support for Resin-SDK dependency 2015-07-24 00:24:17 +03:00
122253bb25 Merge pull request #95 from resin-io/fix/device-registered-at
Add registered_at UNIX epoch
2015-07-23 13:00:29 -04:00
1d53db2854 Add registered_at UNIX epoch 2015-07-23 12:47:49 -04:00
30dc5ea1ea Merge pull request #97 from resin-io/upgrade/dependencies
Upgrade dependencies
2015-07-15 09:08:35 -04:00
58c7ff1f1b Upgrade dependencies 2015-07-15 09:01:50 -04:00
57b9d634be Merge pull request #96 from resin-io/upgrade-visuals
Upgrade resin-cli-visuals dependency
2015-07-14 15:12:54 -04:00
6fb25dea88 Upgrade resin-cli-visuals dependencies 2015-07-14 18:18:19 +03:00
10478e389a Merge pull request #94 from resin-io/upgrade_vcs_dependencies
Upgrade Resin VCS dependencies
2015-07-13 07:37:02 -04:00
46fa4ee2a2 Upgrade Resin VCS dependencies 2015-07-11 00:03:20 +03:00
a7cefe44bf Merge pull request #86 from resin-io/feature/remove-selfupdate
Remove selfupdate functionality. Notify in all cases.
2015-07-09 13:45:09 -04:00
3d03585318 Merge pull request #93 from resin-io/feature/last_seen-undefined
Default device.last_seen to 'Not seen'. Closes #84.
2015-07-09 13:44:59 -04:00
076c3428ee Upgrade Resin CLI Visuals to v0.3.2 2015-07-09 13:43:20 -04:00
9d4ac46985 Default device.last_seen to 'Not seen'. Closes #84. 2015-07-09 09:56:39 -04:00
24edb867fa Upgrade Resin CLI Visuals to v0.3.1 2015-07-09 09:46:08 -04:00
e926ac46c9 Remove selfupdate functionality. Notify in all cases. 2015-07-09 08:18:06 -04:00
9ffd657dbb Merge pull request #85 from resin-io/feature/regenerate-docs
Regenerate docs
2015-07-07 18:40:40 -04:00
aa3cb39551 Regenerate docs 2015-07-07 18:01:25 -04:00
0acbdac66f Use NPM 2.12.1 in Appveyor due to a bug in 2.12.0 2015-07-02 14:28:19 -04:00
5619bdbb67 Resin CLI v0.11.1 2015-06-15 10:09:10 -04:00
381e63bfc9 Merge pull request #70 from resin-io/refactor/new-visuals
Upgrade Resin CLI Visuals and use it's new capabilities
2015-06-12 09:47:30 -04:00
e779347ff2 Merge pull request #69 from resin-io/feature/no-chop-key
Don't chop SSH key
2015-06-11 12:48:16 -04:00
8fa906dd48 Upgrade Resin CLI Visuals and use it's new capabilities 2015-06-11 12:46:56 -04:00
7e5ecd634d HOTFIX: isLoggedIn now returns a possible error 2015-06-11 12:40:49 -04:00
29cf4c1e89 Don't chop SSH key 2015-06-11 08:08:45 -04:00
73736abdea Merge pull request #68 from resin-io/feature/config
Implement config command
2015-06-11 07:57:31 -04:00
9ab411bade Resin CLI v0.11.0 2015-06-10 12:52:28 -04:00
ef33156de7 Implement config command 2015-06-10 12:34:42 -04:00
6d8fd6e547 Merge pull request #66 from resin-io/feature/device-init-has-app
Check that the passed application exists before asking to choose device
2015-06-09 08:28:10 -04:00
bab90a8bf2 Merge pull request #65 from resin-io/fix/app-rm-help
Fix app commands order of definition. Closes #62.
2015-06-08 12:44:57 -04:00
43f0288c6c Check that the passed application exists before asking to choose device 2015-06-08 12:31:17 -04:00
47e6371e2e Merge pull request #64 from resin-io/feature/config-inject
Implement config injection
2015-06-05 12:06:54 -04:00
5e400ed335 Fix app commands order of definition. Closes #62.
This caused `resin help app rm` erroneusly show the help page for `resin app`.
2015-06-04 11:54:15 -04:00
56a78b57af Merge branch 'master' of https://github.com/resin-io/resin-cli 2015-06-04 10:38:53 -04:00
2bfeb7f42c Associate a device before first boot 2015-06-04 10:10:15 -04:00
37e0f12f89 Merge pull request #57 from resin-io/feature/associate-confirmation
Ask for confirmation on app associate command
2015-06-04 08:22:01 -04:00
fdd0e4a966 Implement config injection 2015-06-04 08:06:37 -04:00
38df7e0038 Use min mocha reporter 2015-06-04 08:06:08 -04:00
e9efb78280 Merge pull request #56 from resin-io/feature/login-feedback
Display feedback message after login
2015-06-03 08:46:18 -04:00
0424d7b640 Merge pull request #60 from resin-io/fix/login-browser-session
Open dashboardUrl instead of remoteUrl in auth login
2015-06-03 08:45:00 -04:00
2b80c7c91f Merge pull request #59 from resin-io/feature/app-create-feedback
Print feedback message after app create
2015-06-02 17:08:44 -04:00
142e2c0a65 Merge pull request #58 from resin-io/feature/tty-feedback
Quiet console.info if stdout is being redirected
2015-06-02 17:08:31 -04:00
1ed9ae7d60 Open dashboardUrl instead of remoteUrl in auth login 2015-06-02 13:21:59 -04:00
329bf25dbd Print feedback message after app create 2015-06-02 13:04:08 -04:00
e18ffba183 Quiet console.info if stdout is being redirected
We use `console.info()` for feedback messages.
2015-06-02 12:36:17 -04:00
ae3f0b429d Ask for confirmacion on app associate command 2015-06-02 12:32:35 -04:00
34736c4e9b Display feedback message after login 2015-06-02 11:57:52 -04:00
806678ee5f Merge pull request #55 from resin-io/feature/device-env-vars
Add per device environment variable support
2015-06-02 08:13:10 -04:00
1e70401bdd Make use of NPM@2 in Appveyor to prevent lock permission issues 2015-06-01 08:46:19 -04:00
3c7615f20d Upgrade drivelist to v1.2.2
Contains isSystem() fix for Linux
2015-06-01 08:35:48 -04:00
054d5e4879 Add per device environment variable support 2015-05-28 12:32:08 -04:00
b04ed43bed Merge pull request #54 from resin-io/fix/device-await-help
Fix device await help not showing up
2015-05-28 08:46:42 -04:00
c2bbb952c5 Fix device await help not showing up 2015-05-27 15:14:36 -04:00
63a9e1859b Merge pull request #53 from resin-io/feature/example-name
Accept names instead of ids in example commands
2015-05-25 08:53:06 -04:00
68ef069e6a Accept names instead of ids in example commands 2015-05-21 11:58:15 -04:00
72d4b21cb4 Configure appveyor CI 2015-05-21 10:52:37 -04:00
e8b931680d Merge pull request #52 from resin-io/fix/remove-test-notifier
Remove Mocha notification integration
2015-05-20 13:50:47 -04:00
218b407f30 Remove Mocha notification integration
It doesn't work in tmux and causes the process to hang.
2015-05-20 13:15:39 -04:00
773cc27145 Resin CLI v0.10.8 2015-05-19 15:04:52 -04:00
1c76e2e15b Upgrade Resin Image to v1.1.3 2015-05-19 15:02:12 -04:00
e466cfd6ff Resin CLI v0.10.7 2015-05-18 10:39:07 -04:00
992b04d521 Merge pull request #51 from resin-io/feature/nicer-logs
Expose logs as cli.actions.logs instead of cli.actions.logs.logs
2015-05-18 10:38:41 -04:00
5c16c86871 Merge pull request #50 from resin-io/fix/js-main
Point to a JavaScript file in package.json main property
2015-05-18 10:38:28 -04:00
78af9bbb10 Expose logs as cli.actions.logs instead of cli.actions.logs.logs 2015-05-18 09:37:27 -04:00
b78c48d89f Point to a JavaScript file in package.json main property 2015-05-18 09:35:10 -04:00
1f8c610bb0 Resin CLI v0.10.6 2015-05-14 11:50:43 -03:00
d220728380 Merge pull request #49 from resin-io/feature/device-list-devices
Return devices array to the done callback in device list command
2015-05-14 11:47:25 -03:00
db58e9986c Return devices array to the done callback in device list command
Useful when using the CLI programatically.
2015-05-14 11:43:41 -03:00
2a5e66eca6 Merge pull request #48 from resin-io/feature/use-selfupdate
Make use of selfupdate
2015-05-14 11:40:23 -03:00
e7e8ec296c Make use of selfupdate 2015-05-14 11:32:18 -03:00
80e69c56d0 Resin CLI v0.10.5 2015-05-11 14:42:00 -03:00
ce3c6aecff Upgrade Resin SDK to v1.4.3 2015-05-11 14:39:55 -03:00
300f76ba83 Upgrade Resin SDK to v1.4.2 2015-05-11 14:27:09 -03:00
a4e8a38bf4 Merge pull request #44 from resin-io/fix/download-exit
Fix callback not being called on success in os download command
2015-05-11 14:26:07 -03:00
9bb04f43a8 Fix callback not being called on success in os download command 2015-05-11 14:23:34 -03:00
9b0c08bd46 Don't umount in os install as it's already handled in Resin Image 2015-05-11 13:10:06 -03:00
679d48e86e Merge branch 'master' of github.com:resin-io/resin-cli 2015-05-11 13:08:44 -03:00
4b6bf60531 Upgrade Resin Image to v1.1.2 2015-05-11 12:38:19 -03:00
d8ce6648e2 Handle device unmounting in os install command 2015-05-11 10:04:05 -03:00
402bc2d3a8 Merge pull request #43 from resin-io/fix/non-interactive-login
Make login command behave non interactively if a token is passed as an argument
2015-05-11 09:46:07 -03:00
f3e193be0f Make login command behave non interactively if a token is passed as an argument 2015-05-11 09:42:25 -03:00
f5b461612b Upgrade Capitano to v1.6.0 2015-05-11 09:30:07 -03:00
d2514a3fc3 Resin CLI v0.10.4 2015-05-08 14:29:02 -03:00
2019f9fdeb Merge pull request #42 from resin-io/feature/use-resin-image
Make use of resin-image to remove image writing logic from the CLI
2015-05-08 14:28:33 -03:00
656f3e5cd9 Make use of resin-image to remove image writing logic from the CLI 2015-05-08 14:26:04 -03:00
741acfbba3 Merge pull request #41 from resin-io/feature/command-run
Make use of capitano.run() to run subcommands
2015-05-08 14:23:37 -03:00
4b7eca02a0 Resin CLI v0.10.3 2015-05-07 12:03:40 -03:00
c7788a80e1 Upgrade Resin SDK to v1.4.1
That version includes the os download piping issue fix
2015-05-07 12:03:12 -03:00
08648894e3 Merge pull request #40 from resin-io/feature/device-await
Implement device await command
2015-05-06 11:18:42 -03:00
4c5d5697bc Implement device await command 2015-05-06 11:14:08 -03:00
c758a5b9ea Make use of capitano.run() to run subcommands 2015-05-05 17:34:24 -03:00
2af54e2e28 Merge pull request #39 from resin-io/feature/coffee-compile
Compile CoffeeScript by default when initializing watch task
2015-05-05 06:49:45 -03:00
cf9b23b987 Compile CoffeeScript by default when initializing watch task 2015-05-05 00:21:30 -04:00
f8380ec8e6 Merge pull request #38 from resin-io/feature/os-install-umount
Handle device unmounting in os install command
2015-05-05 00:06:25 -04:00
cd3245a631 Handle device unmounting in os install command 2015-05-02 10:34:11 -04:00
144a155208 Merge pull request #36 from resin-io/feature/standard-version
Implement --version/-v global options. Closes #35
2015-04-30 13:12:51 -04:00
7f7ca13001 Implement --version/-v global options. Closes #35 2015-04-30 11:56:15 -04:00
361e149063 Merge pull request #34 from resin-io/fix/note-validation
Fix note command validation issues
2015-04-29 14:43:47 -04:00
fab85b381a Throw a nice error if note contents are missing 2015-04-29 14:39:46 -04:00
faecf103bf Upgrade Resin SDK to v1.3.4
This version addresses the device validation issue
2015-04-29 14:39:28 -04:00
a0f8c1aa8c Merge pull request #33 from resin-io/fix/devices-app-name
Fix devices command not showing application names. Closes #32
2015-04-29 14:13:09 -04:00
24726b575d Fix devices command not showing application names. Closes #32 2015-04-29 14:07:59 -04:00
688b89a099 Resin CLI v0.10.2 2015-04-28 09:34:41 -04:00
2e39110cc0 Merge pull request #31 from resin-io/feature/app-uniqueness
Check that an application exists before asking it's type. Closes #30
2015-04-28 09:33:59 -04:00
193cedae26 Check that an application exists before asking it's type. Closes #30 2015-04-28 09:18:21 -04:00
3d1f023ef5 Merge pull request #29 from resin-io/feature/list-all-devices
Make devices command list all devices if no application option
2015-04-27 11:26:00 -04:00
9bb51d7146 Make devices command list all devices if no application option. Closes #17 2015-04-27 11:21:30 -04:00
84900aa588 Remove outdated uuid checking help message 2015-04-27 10:51:26 -04:00
b2bce3c4ac Upgrade Resin SDK 2015-04-27 10:49:28 -04:00
8c11620a42 Upgrade Resin SDK 2015-04-27 10:33:34 -04:00
7c1e0ac2e9 Merge pull request #28 from resin-io/fix/logs-messages
Fix logs printing, as messages got added a message property
2015-04-27 10:05:16 -04:00
9a3c844336 Print logs correctly, as they recently got a message field added 2015-04-27 09:30:57 -04:00
69039d21c2 Resin CLI v0.10.1 2015-04-21 11:28:24 -04:00
34c9cdd8bb Upgrade Resin SDK to v1.2.1 2015-04-21 11:26:40 -04:00
0a8b30e824 Resin CLI v0.10.0 2015-04-21 09:06:45 -04:00
ea5b521262 Merge pull request #26 from resin-io/fix/device-init-temp-output
Fix temporary os download output option in device init
2015-04-21 09:06:11 -04:00
3bc71577b5 Fix temporary os download output option in device init 2015-04-21 08:37:40 -04:00
0fb24162fc Merge pull request #24 from resin-io/fix/update
Fix logical issue in update command
2015-04-20 14:14:33 -04:00
d0d63f5bbb Merge pull request #25 from resin-io/deduplicate/whoami
Remove duplicated whoami command
2015-04-20 14:14:25 -04:00
8041905144 Remove duplicated whoami command 2015-04-20 12:46:43 -04:00
37d96e238d Fix logical issue in update command 2015-04-20 12:42:31 -04:00
ae8c941bfe Resin CLI v0.9.0 2015-04-20 12:15:57 -04:00
4c16835ca4 Merge pull request #23 from resin-io/feature/device-init-app-name
Make device init and os download take app names instead of ids
2015-04-20 12:14:53 -04:00
7bd8922a4e Upgrade Resin VCS to v1.2.0 and make use of vcs.getApplicationName() 2015-04-20 11:41:26 -04:00
42b2e2fcf0 Regenerate documentation 2015-04-20 09:14:47 -04:00
f7256e9927 Make device init command take an application name instead of id 2015-04-20 09:13:15 -04:00
85444a5a6a Make os download command accept an application name instead of id 2015-04-20 09:06:40 -04:00
ac115c7ea3 Merge pull request #22 from resin-io/feature/clone-dir
Make "example clone" clone to a new directory
2015-04-20 08:59:28 -04:00
3c2a440553 Make "example clone" clone to a new directory 2015-04-20 08:56:10 -04:00
b29ce3ee04 Resin CLI v0.8.1 2015-04-17 15:09:40 -04:00
2b4394f3ce Merge pull request #21 from resin-io/fix/progress-context
Bind progress update function to avoid context issues
2015-04-17 14:45:17 -04:00
60f704eaa9 Merge pull request #20 from resin-io/fix/elevate-lodash
Add lodash dependency to lib/elevate.coffee
2015-04-17 14:44:50 -04:00
caa4fcf754 Bind progress update function to avoid context issues 2015-04-17 10:11:02 -04:00
c4d1e4244e Upgrade Nplugm to v2.2.0 2015-04-17 10:10:35 -04:00
a6dc155028 Add lodash dependency to lib/elevate.coffee
Depedency was missing and thus elevating functions threw errors.
2015-04-17 09:22:21 -04:00
9c65d11e66 Add documentation anchor support 2015-04-16 11:11:51 -04:00
26f50e7a74 Merge pull request #16 from resin-io/documentation/single-page
Implement Single Page documentation
2015-04-16 09:51:00 -04:00
e4773da1d7 Implement Single Page documentation 2015-04-16 09:49:54 -04:00
dfd8086f63 Resin CLI v0.8.0 2015-04-08 08:37:07 -04:00
ec513c61ad Merge pull request #10 from resin-io/fix/login
Fix bug with login with token
2015-04-08 08:35:57 -04:00
a96ab487ba Fix bug with login with token
The commit was merged from an older branch, in which settings was
still part of the SDK.
2015-04-08 08:25:27 -04:00
cd28c985ce Merge pull request #9 from resin-io/feature/version
Remove bundled node version from version command
2015-04-07 10:56:18 -04:00
727af42ad4 Merge pull request #8 from resin-io/feature/login-with-token
Login with token
2015-04-07 08:12:12 -04:00
e96d411f3e Merge pull request #7 from resin-io/feature/rpi-bundle
Mock local Raspberry Pi bundle
2015-04-07 08:11:43 -04:00
4a7d3d5945 Mock local Raspberry Pi bundle 2015-04-07 08:10:26 -04:00
03f05305cf Fix tiny text issue 2015-04-07 08:07:06 -04:00
af6e9ef85d Merge pull request #6 from resin-io/feature/elevate
Move windosu elevate logic to another module
2015-04-07 08:05:23 -04:00
8533a4a303 Remove bundled node version from version command 2015-04-06 17:18:00 -04:00
85f9234c74 Add .resinconf to gitignore 2015-04-06 17:05:13 -04:00
064afd6705 Fetch TOKEN_URL from the resin sdk 2015-04-06 17:05:13 -04:00
978ff91f87 Remove tab query from preferences token url constant
Tab queries were removed from the web frontend.
2015-04-06 17:04:43 -04:00
5cebbce7bb Update login command documentation 2015-04-06 17:04:03 -04:00
1cd0f02db5 Attempt to open a browser to the token location automatically 2015-04-06 17:04:03 -04:00
77695bb505 Allow login with token 2015-04-06 17:02:53 -04:00
4e4428fdbb Move windosu elevate logic to another module 2015-04-06 16:49:53 -04:00
6e978d74dd Merge pull request #5 from resin-io/feature/hound-config
Add .hound.yml
2015-04-06 10:19:13 -04:00
58974af77b Add .hound.yml 2015-04-06 10:08:49 -04:00
11a0eae7a0 Merge pull request #4 from resin-io/feature/sudo-update
Elevate update command permissions if necessary
2015-04-02 12:53:45 -04:00
2a4ba895e5 Elevate privileges of update command if necessary 2015-04-01 12:51:04 -04:00
19c019076e "resin-cli" "0.7.0" 2015-03-31 13:17:32 -04:00
dfa18d3cb3 Merge pull request #3 from resin-io/fix/selfupdate
Use child_process to trigger self update
2015-03-31 13:15:58 -04:00
782c92885d Use child_process to trigger self update
Using the NPM API led to weird issues.

See https://github.com/npm/npm/issues/7723.
2015-03-24 08:44:02 -04:00
a14dfa6cf1 Fix long line lint warning 2015-03-23 18:32:28 -04:00
f3b6f9d117 Add missing example to device init 2015-03-23 08:25:45 -04:00
63b2b3feb6 Upgrade resin-vcs to 1.1.0 2015-03-23 08:24:29 -04:00
9237dd25ac "resin-cli" "0.6.0" 2015-03-23 08:18:13 -04:00
df9c4ce2fd Reference applications and devices by name 2015-03-23 08:17:55 -04:00
fa5a7abbbf Merge pull request #2 from resin-io/feature/whoami
Reimplement whoami command
2015-03-20 08:55:26 -04:00
cd8bb7882e Reimplement whoami command 2015-03-19 15:57:43 -04:00
3c0378142a Resin CLI v0.5.0 2015-03-19 11:45:38 -04:00
a524bffaa2 Integrate with SDK v1.0.0 2015-03-19 11:45:07 -04:00
4b3decbe03 Resin CLI v0.4.1 2015-03-17 08:54:27 -04:00
fa258a84cc Show a spinner if no progress state in os download command 2015-03-16 11:45:17 -04:00
5efa7309be Fix bug in device init 2015-03-16 11:06:44 -04:00
6e6a01c33c HTML Encode documentation require parameters 2015-03-16 08:51:26 -04:00
94ce15bc2c Make CapitanoDoc output *.markdown files 2015-03-16 08:45:44 -04:00
139 changed files with 5669 additions and 3916 deletions

2
.gitignore vendored
View File

@ -32,3 +32,5 @@ bin/node
release/build
npm-shrinkwrap.json
.resinconf
resinrc.yml

5
.hound.yml Normal file
View File

@ -0,0 +1,5 @@
coffee_script:
config_file: coffeelint.json
javascript:
enabled: false

4
.npmignore Normal file
View File

@ -0,0 +1,4 @@
tests
doc
lib
extras

View File

@ -1,4 +0,0 @@
language: node_js
node_js:
- "0.11"
- "0.10"

227
CHANGELOG.md Normal file
View 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
View File

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

View File

@ -1,65 +1,77 @@
# Resin CLI
Resin CLI
=========
> The official Resin CLI tool.
[![npm version](https://badge.fury.io/js/resin-cli.svg)](http://badge.fury.io/js/resin-cli)
[![dependencies](https://david-dm.org/resin-io/resin-cli.png)](https://david-dm.org/resin-io/resin-cli.png)
[![Build Status](https://travis-ci.org/resin-io/resin-cli.svg?branch=master)](https://travis-ci.org/resin-io/resin-cli)
[![dependencies](https://david-dm.org/resin-io/resin-cli.svg)](https://david-dm.org/resin-io/resin-cli)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](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
View 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
```

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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();
}
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +0,0 @@
# app <id>
Use this command to show detailed information for a single application.
Examples:
$ resin app 91

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +0,0 @@
# logout
Use this command to logout from your resin.io account.o
Examples:
$ resin logout

View File

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

View File

@ -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
View 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 &#60;name&#62;](#app-create-60-name-62-)
- [apps](#apps)
- [app &#60;name&#62;](#app-60-name-62-)
- [app restart &#60;name&#62;](#app-restart-60-name-62-)
- [app rm &#60;name&#62;](#app-rm-60-name-62-)
- Authentication
- [login](#login)
- [logout](#logout)
- [signup](#signup)
- [whoami](#whoami)
- Device
- [devices](#devices)
- [device &#60;uuid&#62;](#device-60-uuid-62-)
- [device register &#60;application&#62;](#device-register-60-application-62-)
- [device rm &#60;uuid&#62;](#device-rm-60-uuid-62-)
- [device identify &#60;uuid&#62;](#device-identify-60-uuid-62-)
- [device reboot &#60;uuid&#62;](#device-reboot-60-uuid-62-)
- [device rename &#60;uuid&#62; [newName]](#device-rename-60-uuid-62-newname-)
- [device move &#60;uuid&#62;](#device-move-60-uuid-62-)
- [device init](#device-init)
- Environment Variables
- [envs](#envs)
- [env rm &#60;id&#62;](#env-rm-60-id-62-)
- [env add &#60;key&#62; [value]](#env-add-60-key-62-value-)
- [env rename &#60;id&#62; &#60;value&#62;](#env-rename-60-id-62-60-value-62-)
- Help
- [help [command...]](#help-command-)
- Information
- [version](#version)
- Keys
- [keys](#keys)
- [key &#60;id&#62;](#key-60-id-62-)
- [key rm &#60;id&#62;](#key-rm-60-id-62-)
- [key add &#60;name&#62; [path]](#key-add-60-name-62-path-)
- Logs
- [logs &#60;uuid&#62;](#logs-60-uuid-62-)
- Sync
- [sync [source]](#sync-source-)
- SSH
- [enter &#60;uuid&#62;](#enter-60-uuid-62-)
- Notes
- [note &#60;|note&#62;](#note-60-note-62-)
- OS
- [os download &#60;type&#62;](#os-download-60-type-62-)
- [os configure &#60;image&#62; &#60;uuid&#62;](#os-configure-60-image-62-60-uuid-62-)
- [os initialize &#60;image&#62;](#os-initialize-60-image-62-)
- Config
- [config read](#config-read)
- [config write &#60;key&#62; &#60;value&#62;](#config-write-60-key-62-60-value-62-)
- [config inject &#60;file&#62;](#config-inject-60-file-62-)
- [config reconfigure](#config-reconfigure)
- [config generate](#config-generate)
- Settings
- [settings](#settings)
- Wizard
- [quickstart [name]](#quickstart-name-)
# Application
## app create &#60;name&#62;
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 &#60;type&#62;
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 &#60;name&#62;
Use this command to show detailed information for a single application.
Examples:
$ resin app MyApp
## app restart &#60;name&#62;
Use this command to restart all devices that belongs to a certain application.
Examples:
$ resin app restart MyApp
## app rm &#60;name&#62;
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 &#60;token&#62;
auth token
#### --web, -w
web-based login
#### --credentials, -c
credential-based login
#### --email, --e,u, --e,u &#60;email&#62;
email
#### --password, -p &#60;password&#62;
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 &#60;application&#62;
application name
## device &#60;uuid&#62;
Use this command to show information about a single device.
Examples:
$ resin device 7cf02a6
## device register &#60;application&#62;
Use this command to register a device to an application.
Examples:
$ resin device register MyApp
### Options
#### --uuid, -u &#60;uuid&#62;
custom uuid
## device rm &#60;uuid&#62;
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 &#60;uuid&#62;
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 &#60;uuid&#62;
Use this command to remotely reboot a device
Examples:
$ resin device reboot 23c73a1
## device rename &#60;uuid&#62; [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 &#60;uuid&#62;
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 &#60;application&#62;
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 &#60;application&#62;
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 &#60;application&#62;
application name
#### --device, -d &#60;device&#62;
device uuid
#### --verbose, -v
show private environment variables
## env rm &#60;id&#62;
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 &#60;key&#62; [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 &#60;application&#62;
application name
#### --device, -d &#60;device&#62;
device uuid
## env rename &#60;id&#62; &#60;value&#62;
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 &#60;id&#62;
Use this command to show information about a single SSH key.
Examples:
$ resin key 17
## key rm &#60;id&#62;
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 &#60;name&#62; [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 &#60;uuid&#62;
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 &#60;path&#62;
custom source path
#### --ignore, -i &#60;paths&#62;
comma delimited paths to ignore when syncing
#### --before, -b &#60;command&#62;
execute a command before syncing
#### --progress, -p
show progress
#### --port, -t &#60;port&#62;
ssh port
# SSH
## enter &#60;uuid&#62;
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 &#60;port&#62;
ssh port
# Notes
## note &#60;|note&#62;
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 &#60;device&#62;
device uuid
# OS
## os download &#60;type&#62;
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 &#60;output&#62;
output path
## os configure &#60;image&#62; &#60;uuid&#62;
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 &#60;image&#62;
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 &#60;type&#62;
device type
#### --drive, -d &#60;drive&#62;
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 &#60;type&#62;
device type
#### --drive, -d &#60;drive&#62;
drive
## config write &#60;key&#62; &#60;value&#62;
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 &#60;type&#62;
device type
#### --drive, -d &#60;drive&#62;
drive
## config inject &#60;file&#62;
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 &#60;type&#62;
device type
#### --drive, -d &#60;drive&#62;
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 &#60;type&#62;
device type
#### --drive, -d &#60;drive&#62;
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 &#60;application&#62;
application name
#### --device, -d &#60;device&#62;
device uuid
#### --output, -o &#60;output&#62;
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

View File

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

View File

@ -1,7 +0,0 @@
# device <id>
Use this command to show information about a single device.
Examples:
$ resin device 317

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +0,0 @@
# devices supported
Use this command to get the list of all supported devices
Examples:
$ resin devices supported

View File

@ -1,7 +0,0 @@
# drives
Use this command to list all drives that are connected to your machine.
Examples:
$ resin drives

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +0,0 @@
# example <id>
Use this command to show information of a single example application
Example:
$ resin example 3

View File

@ -1,7 +0,0 @@
# examples
Use this command to list available example applications from resin.io
Example:
$ resin examples

View File

@ -1,8 +0,0 @@
# help [command...]
Get detailed help for an specific command.
Examples:
$ resin help apps
$ resin help os download

View File

@ -1,3 +0,0 @@
# version
Display the Resin CLI, as well as the bundled NodeJS version.

View File

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

View File

@ -1,7 +0,0 @@
# key <id>
Use this command to show information about a single SSH key.
Examples:
$ resin key 17

View File

@ -1,7 +0,0 @@
# keys
Use this command to list all your SSH keys.
Examples:
$ resin keys

View File

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

View File

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

View File

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

View 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

View File

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

View File

@ -1,7 +0,0 @@
# plugins
Use this command to list all the installed resin plugins.
Examples:
$ resin plugins

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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))

View 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

View File

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

View File

@ -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' ])

View File

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

View File

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

View File

@ -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
View 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)

View File

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