cli_tools 0.0.1
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/.gitignore +17 -0
- data/.rspec +2 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +42 -0
- data/Rakefile +4 -0
- data/cli_tools.gemspec +23 -0
- data/lib/cli_tools/console.rb +106 -0
- data/lib/cli_tools/include.rb +7 -0
- data/lib/cli_tools/system.rb +165 -0
- data/lib/cli_tools/version.rb +3 -0
- data/lib/cli_tools.rb +11 -0
- data/spec/cli_tools_included_spec.rb +7 -0
- data/spec/cli_tools_spec.rb +13 -0
- data/spec/spec_helper.rb +5 -0
- metadata +90 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 97ca4006c9d4aad3f468fee6c21a6e7f7ed92939
|
4
|
+
data.tar.gz: bd7c470b4d297335eb7bc463dd87448f4f2ac34e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ed93a838a7f58d8313baa67d84bb430c0202f23b353b2fbce7238e5475cdd0bb326b1fcffe069a38dd57a6c33794dc4059564ea88d3da15a0c523e30566a2a43
|
7
|
+
data.tar.gz: 058bc0e697e24561a7d9228021e4dd564e0768d88f628ce2a7777e9d371a6d07e7c8d8b0c7ed4b592713c8431b92b398461859a7a7674cf5883259f53af9775e
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Alex Kukushkin
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# Tools for CLI application
|
2
|
+
|
3
|
+
A collection of helper methods for ruby CLI application.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'cli_tools'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install cli_tools
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
require 'cli_tools'
|
23
|
+
include CliTools
|
24
|
+
|
25
|
+
puts esc_green("Hello")+' world!' # outputs 'Hello world!' where 'Hello' is painted green
|
26
|
+
```
|
27
|
+
|
28
|
+
OR: all the methods automatically included into Kernel:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
require 'cli_tools/include'
|
32
|
+
|
33
|
+
puts esc_green("Hello")+' world!'
|
34
|
+
```
|
35
|
+
|
36
|
+
## Contributing
|
37
|
+
|
38
|
+
1. Fork it
|
39
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
40
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
41
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
42
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/cli_tools.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cli_tools/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "cli_tools"
|
8
|
+
spec.version = CliTools::VERSION
|
9
|
+
spec.authors = ["Alex Kukushkin"]
|
10
|
+
spec.email = ["alex@kukushk.in"]
|
11
|
+
spec.description = %q{A collection of helper methods for ruby CLI applications}
|
12
|
+
spec.summary = %q{CLI application helper methods}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module CliTools
|
2
|
+
|
3
|
+
# Replaces current line in the output with a new one.
|
4
|
+
#
|
5
|
+
def putr( str = '' )
|
6
|
+
# move cursor to beginning of line
|
7
|
+
cr = "\r"
|
8
|
+
|
9
|
+
# ANSI escape code to clear line from cursor to end of line
|
10
|
+
# cf. http://en.wikipedia.org/wiki/ANSI_escape_code
|
11
|
+
clear = "\e[0K"
|
12
|
+
|
13
|
+
# reset lines
|
14
|
+
reset = cr + clear
|
15
|
+
|
16
|
+
print "#{reset}#{str}"
|
17
|
+
$stdout.flush
|
18
|
+
end
|
19
|
+
|
20
|
+
# Puts a 'beep' ANSI code.
|
21
|
+
#
|
22
|
+
def put_beep
|
23
|
+
print "\a"
|
24
|
+
$stdout.flush
|
25
|
+
end
|
26
|
+
|
27
|
+
# Clears console screen and puts cursor in 0,0.
|
28
|
+
#
|
29
|
+
def put_cls
|
30
|
+
cls = `clear`
|
31
|
+
putr cls
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns ANSI escaped string.
|
35
|
+
#
|
36
|
+
def esc_string( esc, text )
|
37
|
+
esc+text.to_s+"\e[0m"
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns ANSI escaped string for the red colored text.
|
41
|
+
#
|
42
|
+
def esc_red( text )
|
43
|
+
esc_string "\e[31m", text
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns ANSI escaped string for the green colored text.
|
47
|
+
#
|
48
|
+
def esc_green( text )
|
49
|
+
esc_string "\e[32m", text
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns ANSI escaped string for the yellow colored text.
|
53
|
+
#
|
54
|
+
def esc_yellow( text )
|
55
|
+
esc_string "\e[33m", text
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns ANSI escaped string for the blue colored text.
|
59
|
+
#
|
60
|
+
def esc_blue( text )
|
61
|
+
esc_string "\e[34m", text
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns ANSI escaped string for the bold text.
|
65
|
+
#
|
66
|
+
def esc_bold( text )
|
67
|
+
esc_string "\e[01;37m", text
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
# Returns pressed key or +nil+ if there is no keyboard input.
|
72
|
+
#
|
73
|
+
def kb_getkey
|
74
|
+
kb_raw_no_echo_mode
|
75
|
+
|
76
|
+
begin
|
77
|
+
return $stdin.read_nonblock(1)
|
78
|
+
rescue
|
79
|
+
return nil
|
80
|
+
ensure
|
81
|
+
kb_restore_mode
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Switches the input mode to raw and disables echo.
|
86
|
+
#
|
87
|
+
# *WARNING*: This method requires the external "stty" program!
|
88
|
+
#
|
89
|
+
# Pasted from +HighLine+ gem.
|
90
|
+
#
|
91
|
+
def kb_raw_no_echo_mode
|
92
|
+
@tty_state = `stty -g`
|
93
|
+
system "stty raw -echo cbreak isig"
|
94
|
+
end
|
95
|
+
|
96
|
+
# Restores a previously saved input mode.
|
97
|
+
#
|
98
|
+
# *WARNING*: This method requires the external "stty" program!
|
99
|
+
#
|
100
|
+
# Pasted from +HighLine+ gem.
|
101
|
+
#
|
102
|
+
def kb_restore_mode
|
103
|
+
system "stty #{@tty_state}"
|
104
|
+
end
|
105
|
+
|
106
|
+
end # module CliTools
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module CliTools
|
4
|
+
|
5
|
+
# Execs cmd in a shell and returns true if command executed successfully,
|
6
|
+
# or throws an exception if command failed.
|
7
|
+
#
|
8
|
+
SH_STORED_OUTPUT_LIMIT = 2048
|
9
|
+
SH_STORED_OUTPUT_LINES = 8
|
10
|
+
def sh( cmd, echo = true, capture_output = nil, &block )
|
11
|
+
if _sh_captured_output.size == 0 && capture_output.nil? && block.nil?
|
12
|
+
# simple form
|
13
|
+
puts cmd if echo
|
14
|
+
system cmd or raise ShellExecutionError.new("Failed to execute: '#{cmd}' (#{$?})", $?, '')
|
15
|
+
return true
|
16
|
+
end
|
17
|
+
|
18
|
+
# ok, it's a bit more complex
|
19
|
+
exit_status = nil
|
20
|
+
current_output = ''
|
21
|
+
if echo
|
22
|
+
_sh_captured_output.each do |output_channel|
|
23
|
+
_sh_capture_concat output_channel, cmd+"\n"
|
24
|
+
end
|
25
|
+
if capture_output
|
26
|
+
_sh_capture_concat capture_output, cmd+"\n"
|
27
|
+
else
|
28
|
+
puts cmd
|
29
|
+
end
|
30
|
+
end
|
31
|
+
i = STDIN
|
32
|
+
Open3.popen2e( cmd ) do |i, oe, t|
|
33
|
+
i = STDIN
|
34
|
+
oe.sync = true
|
35
|
+
while oe_char = oe.getc do
|
36
|
+
# puts "sh: block tick"
|
37
|
+
_sh_captured_output.each do |output_channel|
|
38
|
+
_sh_capture_concat output_channel, oe_char
|
39
|
+
end
|
40
|
+
if capture_output
|
41
|
+
_sh_capture_concat capture_output, oe_char
|
42
|
+
else
|
43
|
+
putc oe_char
|
44
|
+
end
|
45
|
+
current_output += oe_char
|
46
|
+
if current_output.size > SH_STORED_OUTPUT_LIMIT
|
47
|
+
# squeeze cached output
|
48
|
+
current_output = current_output.split("\n").last(SH_STORED_OUTPUT_LINES).join("\n")
|
49
|
+
end
|
50
|
+
yield(oe_char) if block
|
51
|
+
end
|
52
|
+
exit_status = t.value
|
53
|
+
end
|
54
|
+
if exit_status != 0
|
55
|
+
raise ShellExecutionError.new("Failed to execute: '#{cmd}' (#{exit_status})", exit_status, current_output)
|
56
|
+
end
|
57
|
+
true
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
# Captures all outputs of all the #sh executed inside the block into +output+.
|
62
|
+
#
|
63
|
+
def sh_capture_output( output, &block )
|
64
|
+
_sh_captured_output << output
|
65
|
+
yield
|
66
|
+
ensure
|
67
|
+
_sh_captured_output.delete output
|
68
|
+
end
|
69
|
+
|
70
|
+
# Prints message and captures it if capture output is enabled.
|
71
|
+
#
|
72
|
+
def sh_capture_echo( message )
|
73
|
+
_sh_captured_output.each do |output_channel|
|
74
|
+
_sh_capture_concat output_channel, message+"\n"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Concatenates output buffer and text.
|
79
|
+
# If output buffer object is a String, the content is #replace-d,
|
80
|
+
# otherwise object must provide #text property-accessor.
|
81
|
+
#
|
82
|
+
def _sh_capture_concat( output_buffer, text )
|
83
|
+
if output_buffer.is_a? String
|
84
|
+
output_buffer.replace( output_buffer + text )
|
85
|
+
else
|
86
|
+
output_buffer.text += text
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns list of capture channels.
|
91
|
+
# This list is local to the current thread.
|
92
|
+
#
|
93
|
+
def _sh_captured_output
|
94
|
+
Thread.current[:sh_captured_output] ||= []
|
95
|
+
Thread.current[:sh_captured_output]
|
96
|
+
end
|
97
|
+
|
98
|
+
# Exception class which holds command execution status and current output
|
99
|
+
# for exceptions raised from '#sh' method call.
|
100
|
+
#
|
101
|
+
class ShellExecutionError < StandardError
|
102
|
+
attr_reader :status, :output
|
103
|
+
def initialize( msg = "Failed to execute 'sh'", status, output )
|
104
|
+
super msg
|
105
|
+
@status = status
|
106
|
+
@output = output
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Copy file if newer.
|
111
|
+
#
|
112
|
+
def copy_if_newer( from, to, echo = true )
|
113
|
+
# if Mac OS X:
|
114
|
+
os = os_name()
|
115
|
+
if os == 'macosx'
|
116
|
+
sh "cp -nf #{from} #{to}", echo
|
117
|
+
else
|
118
|
+
# update, force, preserve attrs
|
119
|
+
sh "cp -ufp #{from} #{to}", echo
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Returns the amount in bytes of free disk space in the specified folder.
|
124
|
+
#
|
125
|
+
def fs_disk_free( path )
|
126
|
+
result = `df -P -k #{path}`.split("\n")[1]
|
127
|
+
device, d_size, d_usage, d_free = result.split(" ")[0..3]
|
128
|
+
|
129
|
+
d_free.to_i*1024 # in bytes
|
130
|
+
end
|
131
|
+
|
132
|
+
# Returns the amount in bytes of used disk space in the specified folder.
|
133
|
+
#
|
134
|
+
def fs_disk_used( path )
|
135
|
+
# First, dereference path
|
136
|
+
if File.symlink? path
|
137
|
+
p = File.readlink( path )
|
138
|
+
else
|
139
|
+
p = path
|
140
|
+
end
|
141
|
+
result = `du -ks #{p} 2>/dev/null`
|
142
|
+
size = 0
|
143
|
+
result.split("\n").each do |line|
|
144
|
+
if m = /(\d+)\s+.*/.match(line)
|
145
|
+
size += m[1].to_i*1024
|
146
|
+
end
|
147
|
+
end
|
148
|
+
size
|
149
|
+
end
|
150
|
+
|
151
|
+
# Returns a host OS name in lowercase.
|
152
|
+
#
|
153
|
+
def os_name
|
154
|
+
name = `uname` rescue '' # Windows?
|
155
|
+
name.chomp!
|
156
|
+
|
157
|
+
case name
|
158
|
+
when 'Darwin' then 'macosx'
|
159
|
+
when 'Linux' then 'linux'
|
160
|
+
else
|
161
|
+
"unknown(#{name})"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
end # module CliTools
|
data/lib/cli_tools.rb
ADDED
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cli_tools
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alex Kukushkin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-12-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: A collection of helper methods for ruby CLI applications
|
42
|
+
email:
|
43
|
+
- alex@kukushk.in
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- .gitignore
|
49
|
+
- .rspec
|
50
|
+
- Gemfile
|
51
|
+
- LICENSE.txt
|
52
|
+
- README.md
|
53
|
+
- Rakefile
|
54
|
+
- cli_tools.gemspec
|
55
|
+
- lib/cli_tools.rb
|
56
|
+
- lib/cli_tools/console.rb
|
57
|
+
- lib/cli_tools/include.rb
|
58
|
+
- lib/cli_tools/system.rb
|
59
|
+
- lib/cli_tools/version.rb
|
60
|
+
- spec/cli_tools_included_spec.rb
|
61
|
+
- spec/cli_tools_spec.rb
|
62
|
+
- spec/spec_helper.rb
|
63
|
+
homepage: ''
|
64
|
+
licenses:
|
65
|
+
- MIT
|
66
|
+
metadata: {}
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options: []
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
requirements: []
|
82
|
+
rubyforge_project:
|
83
|
+
rubygems_version: 2.0.6
|
84
|
+
signing_key:
|
85
|
+
specification_version: 4
|
86
|
+
summary: CLI application helper methods
|
87
|
+
test_files:
|
88
|
+
- spec/cli_tools_included_spec.rb
|
89
|
+
- spec/cli_tools_spec.rb
|
90
|
+
- spec/spec_helper.rb
|