tty-exit 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +297 -0
- data/lib/tty-exit.rb +1 -0
- data/lib/tty/exit.rb +225 -0
- data/lib/tty/exit/code.rb +143 -0
- data/lib/tty/exit/registry.rb +26 -0
- data/lib/tty/exit/version.rb +7 -0
- metadata +59 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 90291ac39f6262d62023d9466a8f79edca9b001072c68cb60799ea45d462bf02
|
4
|
+
data.tar.gz: f9c7422bedb2eef073fe21636842a8e60914497fb2800ad1d14819a8da29b600
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bbfc7bd556613417a2ee20411033040ad438cfde2bec149435d46e7541b81aa9e5ee31d4dc3045b5410c4e5fb86db0baa1cd359de933e95a1c97631a8550c64f
|
7
|
+
data.tar.gz: 11a3cc9803ca5b1ac3eac8f2eaf5e3e4648e87c20eaac5854855e0e4fb0dd7961cccda02bfcb3ef49ec96d96b97ad7777a64ef1055948afa344bcd78ed7d755a
|
data/CHANGELOG.md
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2020 Piotr Murach
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,297 @@
|
|
1
|
+
<div align="center">
|
2
|
+
<a href="https://piotrmurach.github.io/tty" target="_blank"><img width="130" src="https://cdn.rawgit.com/piotrmurach/tty/master/images/tty.png" alt="tty logo" /></a>
|
3
|
+
</div>
|
4
|
+
|
5
|
+
# TTY::Exit [![Gitter](https://badges.gitter.im/Join%20Chat.svg)][gitter]
|
6
|
+
|
7
|
+
[![Gem Version](https://badge.fury.io/rb/tty-exit.svg)][gem]
|
8
|
+
[![Build Status](https://secure.travis-ci.org/piotrmurach/tty-exit.svg?branch=master)][travis]
|
9
|
+
[![Build status](https://ci.appveyor.com/api/projects/status/rtm3po27ouarfrhf?svg=true)][appveyor]
|
10
|
+
[![Code Climate](https://codeclimate.com/github/piotrmurach/tty-exit/badges/gpa.svg)][codeclimate]
|
11
|
+
[![Coverage Status](https://coveralls.io/repos/github/piotrmurach/tty-exit/badge.svg)][coverage]
|
12
|
+
[![Inline docs](http://inch-ci.org/github/piotrmurach/tty-exit.svg?branch=master)][inchpages]
|
13
|
+
|
14
|
+
[gitter]: https://gitter.im/piotrmurach/tty
|
15
|
+
[gem]: http://badge.fury.io/rb/tty-exit
|
16
|
+
[travis]: http://travis-ci.org/piotrmurach/tty-exit
|
17
|
+
[appveyor]: https://ci.appveyor.com/project/piotrmurach/tty-exit
|
18
|
+
[codeclimate]: https://codeclimate.com/github/piotrmurach/tty-exit
|
19
|
+
[coverage]: https://coveralls.io/github/piotrmurach/tty-exit
|
20
|
+
[inchpages]: http://inch-ci.org/github/piotrmurach/tty-exit
|
21
|
+
|
22
|
+
> Terminal exit codes for humans and machines.
|
23
|
+
|
24
|
+
The goal of this library is to provide human friendly and standard way to use exit status codes in command line applications. Instead of saying `exit(64)`, you can say `exit_with(:usage_error)`. Both indicate a failure to the parent process but the `:usage_error` is so much nicer! Wouldn't you agree? That's why `tty-exit` gathers a list of all the most common exit codes as used by POSIX-compliant tools on different Unix systems for you to use.
|
25
|
+
|
26
|
+
The exit statuses range from 0 to 255 (inclusive). Any other exit status than 0 indicates a failure of some kind. The exit codes in the range 64-78 are adapted from the OpenBSD [sysexits.h](https://man.openbsd.org/sysexits.3). The codes between 125 and 128 are reserved for shell statuses as defined in [Advanced Bash Scripting Guide, Appendix E](http://tldp.org/LDP/abs/html/exitcodes.html). The codes in the 129-154 range correspond with the fatal signals as defined in [signal](https://man.openbsd.org/signal.3).
|
27
|
+
|
28
|
+
**TTY::Exit** provides independent terminal exit codes component for [TTY](https://github.com/piotrmurach/tty) toolkit.
|
29
|
+
|
30
|
+
## Installation
|
31
|
+
|
32
|
+
Add this line to your application's Gemfile:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
gem 'tty-exit'
|
36
|
+
```
|
37
|
+
|
38
|
+
And then execute:
|
39
|
+
|
40
|
+
$ bundle install
|
41
|
+
|
42
|
+
Or install it yourself as:
|
43
|
+
|
44
|
+
$ gem install tty-exit
|
45
|
+
|
46
|
+
## Contents
|
47
|
+
|
48
|
+
* [1. Usage](#1-usage)
|
49
|
+
* [2. API](#2-api)
|
50
|
+
* [2.1 exit_code](#21-exit_code)
|
51
|
+
* [2.2 exit_message](#22-exit_message)
|
52
|
+
* [2.3 exit_with](#23-exit_with)
|
53
|
+
* [2.4 register_exit](#24-register_exit)
|
54
|
+
* [2.5 exit_reserved?](#25-exit_reserved)
|
55
|
+
* [2.6 exit_valid?](#26-exit_valid)
|
56
|
+
* [2.7 exit_success?](#27-exit_success)
|
57
|
+
* [2.8 exit_codes](#28-exit_codes)
|
58
|
+
* [2.9 exit_messages](#29-exit_messages)
|
59
|
+
|
60
|
+
## 1. Usage
|
61
|
+
|
62
|
+
To exit from any program use `exit_with` method. Instead of a number, you can use a readable name for the exit status:
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
TTY::Exit.exit_with(:usage_error)
|
66
|
+
```
|
67
|
+
|
68
|
+
The above will exit program immediately with an exit code indicating a failure:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
puts $?.exitstatus
|
72
|
+
# => 64
|
73
|
+
```
|
74
|
+
|
75
|
+
All the reserved exit statuses have a matching exit message. To display a default message, as a second argument to `exit_with` you can pass `:default` value:
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
TTY::Exit.exit_with(:usage_error, :default)
|
79
|
+
```
|
80
|
+
|
81
|
+
That will produce the following user friendly message:
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
# => "ERROR(64): Command line usage error"
|
85
|
+
```
|
86
|
+
|
87
|
+
The preferred way is to include **TTY::Exit** module in your code:
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
class Command
|
91
|
+
include TTY::Exit
|
92
|
+
|
93
|
+
def execute
|
94
|
+
exit_with(:config_error, :default)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
This will print an error message and return appropriate exit status:
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
cmd = Command.new
|
103
|
+
cmd.execute
|
104
|
+
# => "ERROR(78): Configuration Error"
|
105
|
+
puts $?.exitstatus
|
106
|
+
# => 78
|
107
|
+
```
|
108
|
+
|
109
|
+
To see the full list of reserved exit codes go to [2.8 exit_codes](#28-exit-codes) section.
|
110
|
+
|
111
|
+
## 2. API
|
112
|
+
|
113
|
+
### 2.1 exit_code
|
114
|
+
|
115
|
+
There are many built-in exit codes that can be referenced using a name.
|
116
|
+
|
117
|
+
For example to return an exit code denoting success, you can use `:ok` or `:success`:
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
TTY::Exit.exit_code(:ok) # => 0
|
121
|
+
TTY::Exit.exit_code(:success) # => 0
|
122
|
+
```
|
123
|
+
|
124
|
+
Any other exit status than 0 indicates a failure of some kind. For example, when a command cannot be found use `:not_found`:
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
TTY::Exit.exit_code(:not_found)
|
128
|
+
# => 127
|
129
|
+
```
|
130
|
+
|
131
|
+
You can also use an exit code directly:
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
TTY::Exit.exit_code(127)
|
135
|
+
# => 127
|
136
|
+
```
|
137
|
+
|
138
|
+
### 2.2 exit_message
|
139
|
+
|
140
|
+
One of the downsides of exit codes is that they are not very communicative to the user. Why not have both? An exit code and a user friendly message. That's what `exit_message` is for. All the reserved exit codes have corresponding user friendly messages.
|
141
|
+
|
142
|
+
For example, when returning exit code `64` for usage error:
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
TTY::Exit.exit_message(:usage_error)
|
146
|
+
TTY::Exit.exit_message(64)
|
147
|
+
```
|
148
|
+
|
149
|
+
Will return:
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
# => "ERROR(64): Command line usage error"
|
153
|
+
```
|
154
|
+
|
155
|
+
The default messages are used by the `exit_with` method and can be overwritten by a custom one.
|
156
|
+
|
157
|
+
### 2.3 exit_with
|
158
|
+
|
159
|
+
To exit program with an exit code use `exit_with`. This method accepts a name or a code for the exit status.
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
TTY::Exit.exit_with(:usage_error)
|
163
|
+
TTY::Exit.exit_with(64)
|
164
|
+
```
|
165
|
+
|
166
|
+
Both will produce the same outcome.
|
167
|
+
|
168
|
+
As a second argument you can specify a user friendly message to be printed to `stderr` before exit. To use predefined messages use `:default` as a value:
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
TTY::Exit.exit_with(:usage_error, :default)
|
172
|
+
# => "ERROR(64): Command line usage error"
|
173
|
+
```
|
174
|
+
|
175
|
+
Optionally, you can provide a custom message to display to the user.
|
176
|
+
|
177
|
+
```ruby
|
178
|
+
TTY::Exit.exit_with(:usge_error, "Wrong arguments")
|
179
|
+
# => "Wrong arguments"
|
180
|
+
```
|
181
|
+
|
182
|
+
Finally, you can redirect output to a different stream using `:io` option. By default, message is printed to `stderr`:
|
183
|
+
|
184
|
+
```ruby
|
185
|
+
TTY::Exit.exit_with(:usage_error, io: $stdout)
|
186
|
+
```
|
187
|
+
|
188
|
+
Since `TTY::Exit` is a module, you can include it in your code to get access to all the methods:
|
189
|
+
|
190
|
+
```ruby
|
191
|
+
class Command
|
192
|
+
include TTY::Exit
|
193
|
+
|
194
|
+
def execute
|
195
|
+
exit_with(:usage_error, :default)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
```
|
199
|
+
|
200
|
+
### 2.4 register_exit
|
201
|
+
|
202
|
+
If the provided exit codes don't match your needs, you can add your own using the `register_exit` method.
|
203
|
+
|
204
|
+
For example, to register a custom exit with `:too_long` name and the status `7` that will notify user and programs about too many arguments do:
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
class Command
|
208
|
+
include TTY::Exit
|
209
|
+
|
210
|
+
register_exit(:too_long, 7, "Argument list too long")
|
211
|
+
|
212
|
+
def execute
|
213
|
+
exit_with(:too_long, :default)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
```
|
217
|
+
|
218
|
+
Then when the command gets run:
|
219
|
+
|
220
|
+
```ruby
|
221
|
+
cmd = Command.new
|
222
|
+
cmd.execute
|
223
|
+
# =>
|
224
|
+
# ERROR(7): Argument list too long
|
225
|
+
```
|
226
|
+
|
227
|
+
### 2.5 exit_reserved?
|
228
|
+
|
229
|
+
To check if an exit code is already reserved by Unix system use `exit_reserved?`. This is useful in situations where you want to add it your command line application custom exit codes. The check accepts only integer numbers in range 0 to 255 inclusive:
|
230
|
+
|
231
|
+
```ruby
|
232
|
+
TTY::Exit.exit_reserved?(126) # => true
|
233
|
+
TTY::Exit.exit_reserved?(100) # => false
|
234
|
+
```
|
235
|
+
|
236
|
+
### 2.6 exit_valid?
|
237
|
+
|
238
|
+
The exit statuses range from 0 to 255 (inclusive). The `exit_valid?` method helps you check if an exit status is within the range or not.
|
239
|
+
|
240
|
+
```ruby
|
241
|
+
TTY::Exit.exit_valid?(11) # => true
|
242
|
+
TTY::Exit.exit_valid?(522) # => false
|
243
|
+
```
|
244
|
+
|
245
|
+
### 2.7 exit_success?
|
246
|
+
|
247
|
+
Any other exit status than 0 indicates a failure of some kind. The `exit_success?` is a more descriptive way to determine if a program succeeded or not.
|
248
|
+
|
249
|
+
```ruby
|
250
|
+
TTY::Exit.exit_success?(0) # => true
|
251
|
+
TTY::Exit.exit_success?(7) # => false
|
252
|
+
```
|
253
|
+
|
254
|
+
### 2.8 exit_codes
|
255
|
+
|
256
|
+
You can access all the predefined exit codes and their names with `exit_codes` method:
|
257
|
+
|
258
|
+
```ruby
|
259
|
+
TTY::Exit.exit_codes
|
260
|
+
# =>
|
261
|
+
# "{:ok=>0, :success=>0, :error=>1, :shell_misuse=>2, :usage_error=>64, :data_error=>65, ... }"
|
262
|
+
```
|
263
|
+
|
264
|
+
### 2.9 exit_messages
|
265
|
+
|
266
|
+
To see what default messages are for the predefined exit codes use `exit_messages`:
|
267
|
+
|
268
|
+
```ruby
|
269
|
+
TTY::Exit.exit_messages
|
270
|
+
# =>
|
271
|
+
# "{0=>"Successful termination", 1=>"An error occurred", 2=>"Misuse of shell builtins", 64=>"Command line usage error", ... }"
|
272
|
+
```
|
273
|
+
|
274
|
+
The exit statuses range from 0 to 255 (inclusive). Any other exit status than 0 indicates a failure of some kind. The exit codes in the range 64-78 are adapted from the OpenBSD [sysexits.h](https://man.openbsd.org/sysexits.3). The codes between 125 and 128 are reserved for shell statuses as defined in [Advanced Bash Scripting Guide, Appendix E](http://tldp.org/LDP/abs/html/exitcodes.html). The codes in the 129-154 range correspond with the fatal signals as defined in [signal](https://man.openbsd.org/signal.3).
|
275
|
+
|
276
|
+
|
277
|
+
## Development
|
278
|
+
|
279
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
280
|
+
|
281
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
282
|
+
|
283
|
+
## Contributing
|
284
|
+
|
285
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/piotrmurach/tty-exit. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/piotrmurach/tty-exit/blob/master/CODE_OF_CONDUCT.md).
|
286
|
+
|
287
|
+
## License
|
288
|
+
|
289
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
290
|
+
|
291
|
+
## Code of Conduct
|
292
|
+
|
293
|
+
Everyone interacting in the TTY::Exit project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/piotrmurach/tty-exit/blob/master/CODE_OF_CONDUCT.md).
|
294
|
+
|
295
|
+
## Copyright
|
296
|
+
|
297
|
+
Copyright (c) 2020 Piotr Murach. See LICENSE for further details.
|
data/lib/tty-exit.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_relative "tty/exit"
|
data/lib/tty/exit.rb
ADDED
@@ -0,0 +1,225 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "exit/code"
|
4
|
+
require_relative "exit/registry"
|
5
|
+
require_relative "exit/version"
|
6
|
+
|
7
|
+
module TTY
|
8
|
+
# Terminal exit codes for humans and machines
|
9
|
+
module Exit
|
10
|
+
extend self
|
11
|
+
|
12
|
+
Error = Class.new(StandardError)
|
13
|
+
|
14
|
+
# @api private
|
15
|
+
def self.included(base)
|
16
|
+
base.instance_eval do
|
17
|
+
def register_exit(*args)
|
18
|
+
Registry.register_exit(*args)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
NAME_TO_EXIT_CODE = {
|
24
|
+
ok: Code::SUCCESS,
|
25
|
+
success: Code::SUCCESS,
|
26
|
+
error: Code::ERROR,
|
27
|
+
shell_misuse: Code::SHELL_MISUSE,
|
28
|
+
|
29
|
+
usage_error: Code::USAGE_ERROR,
|
30
|
+
data_err: Code::DATA_ERROR,
|
31
|
+
data_error: Code::DATA_ERROR,
|
32
|
+
no_input: Code::NO_INPUT,
|
33
|
+
no_user: Code::NO_USER,
|
34
|
+
no_host: Code::NO_HOST,
|
35
|
+
service_unavailable: Code::SERVICE_UNAVAILABLE,
|
36
|
+
software_error: Code::SOFTWARE_ERROR,
|
37
|
+
system_error: Code::SYSTEM_ERROR,
|
38
|
+
system_file_missing: Code::SYSTEM_FILE_MISSING,
|
39
|
+
cant_create: Code::CANT_CREATE,
|
40
|
+
io_error: Code::IO_ERROR,
|
41
|
+
io_err: Code::IO_ERROR,
|
42
|
+
temp_fail: Code::TEMP_FAIL,
|
43
|
+
protocol: Code::PROTOCOL,
|
44
|
+
no_perm: Code::NO_PERM,
|
45
|
+
no_permission: Code::NO_PERM,
|
46
|
+
config_error: Code::CONFIG_ERROR,
|
47
|
+
configuration_error: Code::CONFIG_ERROR,
|
48
|
+
|
49
|
+
cannot_execute: Code::CANNOT_EXECUTE,
|
50
|
+
not_found: Code::COMMAND_NOT_FOUND,
|
51
|
+
command_not_found: Code::COMMAND_NOT_FOUND,
|
52
|
+
invalid_argument: Code::INVALID_ARGUMENT,
|
53
|
+
|
54
|
+
hangup: Code::HANGUP,
|
55
|
+
interrupt: Code::INTERRUPT,
|
56
|
+
quit: Code::QUIT,
|
57
|
+
illegal_instruction: Code::ILLEGAL_INSTRUCTION,
|
58
|
+
trace_trap: Code::TRACE_TRAP,
|
59
|
+
abort: Code::ABORT,
|
60
|
+
kill: Code::KILL,
|
61
|
+
bus_error: Code::BUS_ERROR,
|
62
|
+
memory_error: Code::MEMORY_ERROR,
|
63
|
+
segmentation_fault: Code::MEMORY_ERROR,
|
64
|
+
pipe: Code::PIPE,
|
65
|
+
alarm: Code::ALARM,
|
66
|
+
user1: Code::USER1,
|
67
|
+
user2: Code::USER2
|
68
|
+
}.freeze
|
69
|
+
private_constant :NAME_TO_EXIT_CODE
|
70
|
+
|
71
|
+
CODE_TO_EXIT_MESSAGE = {
|
72
|
+
Code::SUCCESS => "Successful termination",
|
73
|
+
Code::ERROR => "An error occurred",
|
74
|
+
Code::SHELL_MISUSE => "Misuse of shell builtins",
|
75
|
+
|
76
|
+
Code::USAGE_ERROR => "Command line usage error",
|
77
|
+
Code::DATA_ERROR => "Data format error",
|
78
|
+
Code::NO_INPUT => "Cannot open input",
|
79
|
+
Code::NO_USER => "User name unknown",
|
80
|
+
Code::NO_HOST => "Host name unknown",
|
81
|
+
Code::SERVICE_UNAVAILABLE => "Service unavailable",
|
82
|
+
Code::SOFTWARE_ERROR => "Internal software error",
|
83
|
+
Code::SYSTEM_ERROR => "System error (e.g. can't fork)",
|
84
|
+
Code::SYSTEM_FILE_MISSING => "Critical OS file missing",
|
85
|
+
Code::CANT_CREATE => "Can't create user output file",
|
86
|
+
Code::IO_ERROR => "Input/output error",
|
87
|
+
Code::TEMP_FAIL => "Temp failure, user is invited to retry",
|
88
|
+
Code::PROTOCOL => "Remote error in protocol",
|
89
|
+
Code::NO_PERM => "Permission denied",
|
90
|
+
Code::CONFIG_ERROR => "Configuration error",
|
91
|
+
|
92
|
+
Code::CANNOT_EXECUTE => "Command invoked cannot execute",
|
93
|
+
Code::COMMAND_NOT_FOUND => "Command not found",
|
94
|
+
Code::INVALID_ARGUMENT => "Invalid argument",
|
95
|
+
|
96
|
+
Code::HANGUP => "Hangup detected on controlling terminal or death of controlling process.",
|
97
|
+
Code::INTERRUPT => "Interrupted by Control-C",
|
98
|
+
Code::QUIT => "Quit program",
|
99
|
+
Code::ILLEGAL_INSTRUCTION => "Illegal instruction",
|
100
|
+
Code::TRACE_TRAP => "Trace/breakpoint trap",
|
101
|
+
Code::ABORT => "Abort program",
|
102
|
+
Code::KILL => "Kill program",
|
103
|
+
Code::BUS_ERROR => "Access to an undefined portion of a memory object",
|
104
|
+
Code::MEMORY_ERROR => "An invalid virtual memory reference or segmentation fault",
|
105
|
+
Code::PIPE => "Write on a pipe with no one to read it",
|
106
|
+
Code::ALARM => "Alarm clock",
|
107
|
+
Code::USER1 => "User-defined signal 1",
|
108
|
+
Code::USER2 => "User-defined signal 2"
|
109
|
+
}.freeze
|
110
|
+
private_constant :CODE_TO_EXIT_MESSAGE
|
111
|
+
|
112
|
+
# Check if an exit code is valid, that it's within the 0-255 (inclusive)
|
113
|
+
#
|
114
|
+
# @param [Integer] code
|
115
|
+
# the code to check
|
116
|
+
#
|
117
|
+
# @return [Boolean]
|
118
|
+
#
|
119
|
+
# @api public
|
120
|
+
def exit_valid?(code)
|
121
|
+
code >= 0 && code <= 255
|
122
|
+
end
|
123
|
+
|
124
|
+
# Check if an exit code is already defined by Unix system
|
125
|
+
#
|
126
|
+
# @param [Integer] code
|
127
|
+
# the code to check
|
128
|
+
#
|
129
|
+
# @return [Boolean]
|
130
|
+
#
|
131
|
+
# @api public
|
132
|
+
def exit_reserved?(code)
|
133
|
+
(code >= Code::SUCCESS && code <= Code::SHELL_MISUSE) ||
|
134
|
+
(code >= Code::USAGE_ERROR && code <= Code::CONFIG_ERROR) ||
|
135
|
+
(code >= Code::CANNOT_EXECUTE && code <= Code::USER2)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Check if the exit status was successful.
|
139
|
+
#
|
140
|
+
# @param [Integer] code
|
141
|
+
#
|
142
|
+
# @api public
|
143
|
+
def exit_success?(code)
|
144
|
+
code == Code::SUCCESS
|
145
|
+
end
|
146
|
+
|
147
|
+
# A user friendly explanation of the exit code
|
148
|
+
#
|
149
|
+
# @example
|
150
|
+
# TTY::Exit.exit_message(:usage_error)
|
151
|
+
# # => "Command line usage error"
|
152
|
+
#
|
153
|
+
# @param [String,Integer] name_or_code
|
154
|
+
#
|
155
|
+
# @api public
|
156
|
+
def exit_message(name_or_code = :ok)
|
157
|
+
(Registry.exits[name_or_code] || {})[:message] ||
|
158
|
+
CODE_TO_EXIT_MESSAGE[exit_code(name_or_code)] || ""
|
159
|
+
end
|
160
|
+
|
161
|
+
# Provide a list of reserved status messages
|
162
|
+
#
|
163
|
+
# @api public
|
164
|
+
def exit_messages
|
165
|
+
CODE_TO_EXIT_MESSAGE
|
166
|
+
end
|
167
|
+
|
168
|
+
# Provide exit code for a name or status
|
169
|
+
#
|
170
|
+
# @example
|
171
|
+
# TTY::Exit.exit_code(:usage_error)
|
172
|
+
# # => 64
|
173
|
+
#
|
174
|
+
# @param [String,Integer] name_or_code
|
175
|
+
#
|
176
|
+
# @return [Integer]
|
177
|
+
# the exit code
|
178
|
+
#
|
179
|
+
# @api public
|
180
|
+
def exit_code(name_or_code = :ok)
|
181
|
+
case name_or_code
|
182
|
+
when String, Symbol
|
183
|
+
(Registry.exits[name_or_code.to_sym] || {})[:code] ||
|
184
|
+
NAME_TO_EXIT_CODE.fetch(name_or_code.to_sym) do
|
185
|
+
raise Error, "Name '#{name_or_code}' isn't recognized."
|
186
|
+
end
|
187
|
+
when Numeric
|
188
|
+
if exit_valid?(name_or_code.to_i)
|
189
|
+
name_or_code.to_i
|
190
|
+
else
|
191
|
+
raise Error, "Provided code outside of the range (0 - 255)"
|
192
|
+
end
|
193
|
+
else
|
194
|
+
raise Error, "Provide a name or a number as an exit code"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# Provide a list of reserved codes
|
199
|
+
#
|
200
|
+
# @api public
|
201
|
+
def exit_codes
|
202
|
+
NAME_TO_EXIT_CODE
|
203
|
+
end
|
204
|
+
|
205
|
+
# Exit this process with a given status code
|
206
|
+
#
|
207
|
+
# @param [String,Integer] name_or_code
|
208
|
+
# The name for an exit code or code itself
|
209
|
+
# @param [String] message
|
210
|
+
# The message to print to io stream
|
211
|
+
# @param [IO] io
|
212
|
+
# The io to print message to
|
213
|
+
#
|
214
|
+
# @return [nil]
|
215
|
+
#
|
216
|
+
# @api public
|
217
|
+
def exit_with(name_or_code = :ok, message = nil, io: $stderr)
|
218
|
+
if message == :default
|
219
|
+
message = "ERROR(#{exit_code(name_or_code)}): #{exit_message(name_or_code)}"
|
220
|
+
end
|
221
|
+
io.print(message) if message
|
222
|
+
::Kernel.exit(exit_code(name_or_code))
|
223
|
+
end
|
224
|
+
end # Exit
|
225
|
+
end # TTY
|
@@ -0,0 +1,143 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
module Exit
|
5
|
+
# All reserved exit codes as constants
|
6
|
+
module Code
|
7
|
+
# No errors
|
8
|
+
SUCCESS = 0
|
9
|
+
|
10
|
+
# Catchall for general errors
|
11
|
+
ERROR = 1
|
12
|
+
|
13
|
+
# Missing keyword or command, or permission problem
|
14
|
+
# (and diff return code on a failed binary file comparison).
|
15
|
+
SHELL_MISUSE = 2
|
16
|
+
|
17
|
+
# The start base code to reduce possibility of clashing with other
|
18
|
+
# exit statuses that programs may already run.
|
19
|
+
BASE = 64
|
20
|
+
|
21
|
+
# The command was used incorrectly, e.g., with the wrong number
|
22
|
+
# of arguments, a bad flag, a bad syntax in a parameter, or whatever.
|
23
|
+
USAGE_ERROR = BASE # 64
|
24
|
+
|
25
|
+
# The input data was incorrect in some way.
|
26
|
+
# This should only be used for user's data & not system files.
|
27
|
+
DATA_ERROR = BASE + 1 # 65
|
28
|
+
|
29
|
+
# An input file (not a system file) did not exist or was not readable.
|
30
|
+
NO_INPUT = BASE + 2 # 66
|
31
|
+
|
32
|
+
# The user specified did not exist. This might be used for mail
|
33
|
+
# addresses or remote logins.
|
34
|
+
NO_USER = BASE + 3 # 67
|
35
|
+
|
36
|
+
# The host specified did not exist. This is used in mail addresses
|
37
|
+
# or network requests.
|
38
|
+
NO_HOST = BASE + 4 # 68
|
39
|
+
|
40
|
+
# A service is unavailable. This can occur if a support program
|
41
|
+
# or file does not exist. This can also be used as a catchall
|
42
|
+
# message when something you wanted to do doesn't work,
|
43
|
+
# but you don't know why.
|
44
|
+
SERVICE_UNAVAILABLE = BASE + 5 # 69
|
45
|
+
|
46
|
+
# An internal software error has been detected. This should be
|
47
|
+
# limited to non-operating system related errors as possible.
|
48
|
+
SOFTWARE_ERROR = BASE + 6 # 70
|
49
|
+
|
50
|
+
# An operating system error has been detected. This is intended
|
51
|
+
# to be used for such things as "cannot fork", "cannot create pipe",
|
52
|
+
# or the like. It includes things like getuid returning a user that
|
53
|
+
# does not exist in the passwd file.
|
54
|
+
SYSTEM_ERROR = BASE + 7 # 71
|
55
|
+
|
56
|
+
# Some system file (e.g., /etc/passwd, /etc/utmp, etc.) does not exist,
|
57
|
+
# cannot be opened, or has some sort of error (e.g., syntax error).
|
58
|
+
SYSTEM_FILE_MISSING = BASE + 8 #72
|
59
|
+
|
60
|
+
# A (user specified) output file cannot be created.
|
61
|
+
CANT_CREATE = BASE + 9 # 73
|
62
|
+
|
63
|
+
# An error occurred while doing I/O on some file.
|
64
|
+
IO_ERROR = BASE + 10 # 74
|
65
|
+
|
66
|
+
# Temporary failure, indicating something that is not really an error.
|
67
|
+
# For example that a mailer could not create a connection, and the
|
68
|
+
# request should be reattempted later.
|
69
|
+
TEMP_FAIL = BASE + 11 # 75
|
70
|
+
|
71
|
+
# The remote system returned something that was 'not possible' during
|
72
|
+
# a protocol exchange.
|
73
|
+
PROTOCOL = BASE + 12 # 76
|
74
|
+
|
75
|
+
# You did not have sufficient permission to perform the operation.
|
76
|
+
# This is not intended for file system problems, which should use
|
77
|
+
# NO_INPUT or CANT_CREATE, but rather for higher level permissions.
|
78
|
+
NO_PERM = BASE + 13 # 77
|
79
|
+
|
80
|
+
# Something was found in an unconfigured or misconfigured state.
|
81
|
+
CONFIG_ERROR = BASE + 14 # 78
|
82
|
+
|
83
|
+
# Command invoked cannot execute. This may be due to permission
|
84
|
+
# issues.
|
85
|
+
CANNOT_EXECUTE = 126
|
86
|
+
|
87
|
+
# "command not found", possible typos in shell command or
|
88
|
+
# unrecognized characters
|
89
|
+
COMMAND_NOT_FOUND = 127
|
90
|
+
|
91
|
+
# The start base code for the system interrupt signals.
|
92
|
+
SIGNAL_BASE = 128
|
93
|
+
|
94
|
+
# Exit takes only integer args in the range 0 - 255,
|
95
|
+
# e.g. exit 3.14159 is invalid.
|
96
|
+
INVALID_ARGUMENT = SIGNAL_BASE
|
97
|
+
|
98
|
+
# This indicates that program received SIGHUP signal.
|
99
|
+
# It means that the controlling pseudo or virtual terminal
|
100
|
+
# has been closed.
|
101
|
+
HANGUP = SIGNAL_BASE + 1 # 129
|
102
|
+
|
103
|
+
# This indicates that program received SIGINT signal.
|
104
|
+
# An interrupt signal that by default this causes the
|
105
|
+
# process to terminate.
|
106
|
+
INTERRUPT = SIGNAL_BASE + 2 # 130
|
107
|
+
|
108
|
+
# This indicates that program received SIGQUIT signal.
|
109
|
+
QUIT = SIGNAL_BASE + 3 # 131
|
110
|
+
|
111
|
+
# This indicates that program received SIGQUIT signal.
|
112
|
+
ILLEGAL_INSTRUCTION = SIGNAL_BASE + 4 # 132
|
113
|
+
|
114
|
+
# This indicates that program received SIGTRAP signal.
|
115
|
+
TRACE_TRAP = SIGNAL_BASE + 5 # 133
|
116
|
+
|
117
|
+
# This indicates that program received SIGABRT signal.
|
118
|
+
ABORT = SIGNAL_BASE + 6 # 134
|
119
|
+
|
120
|
+
# This indicates that program received SIGKILL signal.
|
121
|
+
KILL = SIGNAL_BASE + 9 # 137
|
122
|
+
|
123
|
+
# This indicates that program received SIGBUS signal.
|
124
|
+
# Access to an undefined portion of a memory object
|
125
|
+
BUS_ERROR = SIGNAL_BASE + 10 # 138
|
126
|
+
|
127
|
+
# This indicates that program received SIGSEGV signal.
|
128
|
+
MEMORY_ERROR = SIGNAL_BASE + 11 # 139
|
129
|
+
|
130
|
+
# This indicates that program received SIGPIPE signal.
|
131
|
+
PIPE = SIGNAL_BASE + 13 # 141
|
132
|
+
|
133
|
+
# This indicates that program received SIGALARM signal.
|
134
|
+
ALARM = SIGNAL_BASE + 14 # 142
|
135
|
+
|
136
|
+
# This indicates that program received SIGUSR1 signal.
|
137
|
+
USER1 = SIGNAL_BASE + 30 # 158
|
138
|
+
|
139
|
+
# This indicates that program received SIGUSR2 signal.
|
140
|
+
USER2 = SIGNAL_BASE + 31 # 159
|
141
|
+
end # Code
|
142
|
+
end # Exit
|
143
|
+
end # TTY
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
module Exit
|
5
|
+
module Registry
|
6
|
+
# A storage for custom exit codes
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
def self.exits
|
10
|
+
@exits ||= {}
|
11
|
+
end
|
12
|
+
|
13
|
+
# Register a custom exit code
|
14
|
+
#
|
15
|
+
# @param [String] name
|
16
|
+
# @param [Integer] code
|
17
|
+
# @param [String] message
|
18
|
+
#
|
19
|
+
# @api public
|
20
|
+
def self.register_exit(name, code, message)
|
21
|
+
exits[name] = {code: code, message: message}
|
22
|
+
exits[code] = {code: code, message: message}
|
23
|
+
end
|
24
|
+
end # Registry
|
25
|
+
end # Exit
|
26
|
+
end # TTY
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tty-exit
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Piotr Murach
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-02-01 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Terminal exit codes for humans and machines
|
14
|
+
email:
|
15
|
+
- piotr@piotrmurach.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files:
|
19
|
+
- README.md
|
20
|
+
- CHANGELOG.md
|
21
|
+
files:
|
22
|
+
- CHANGELOG.md
|
23
|
+
- LICENSE.txt
|
24
|
+
- README.md
|
25
|
+
- lib/tty-exit.rb
|
26
|
+
- lib/tty/exit.rb
|
27
|
+
- lib/tty/exit/code.rb
|
28
|
+
- lib/tty/exit/registry.rb
|
29
|
+
- lib/tty/exit/version.rb
|
30
|
+
homepage: https://ttytoolkit.org
|
31
|
+
licenses:
|
32
|
+
- MIT
|
33
|
+
metadata:
|
34
|
+
allowed_push_host: https://rubygems.org
|
35
|
+
bug_tracker_uri: https://github.com/piotrmurach/tty-exit/issues
|
36
|
+
changelog_uri: https://github.com/piotrmurach/tty-exit/blob/master/CHANGELOG.md
|
37
|
+
documentation_uri: https://www.rubydoc.info/gems/tty-exit
|
38
|
+
homepage_uri: https://ttytoolkit.org
|
39
|
+
source_code_uri: https://github.com/piotrmurach/tty-exit
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: 2.0.0
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
requirements: []
|
55
|
+
rubygems_version: 3.1.2
|
56
|
+
signing_key:
|
57
|
+
specification_version: 4
|
58
|
+
summary: Terminal exit codes for humans and machines
|
59
|
+
test_files: []
|