tty-exit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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]
|
6
|
+
|
7
|
+
[][gem]
|
8
|
+
[][travis]
|
9
|
+
[][appveyor]
|
10
|
+
[][codeclimate]
|
11
|
+
[][coverage]
|
12
|
+
[][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: []
|