nub 0.0.21
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/nub.rb +33 -0
- data/lib/nub/cmds.rb +153 -0
- data/lib/nub/config.rb +83 -0
- data/lib/nub/log.rb +254 -0
- data/lib/nub/net.rb +76 -0
- data/lib/nub/string.rb +35 -0
- data/lib/nub/thread_comm.rb +65 -0
- data/lib/nub/user.rb +36 -0
- metadata +51 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 102f1cf06e8b45889dd60b7372e5111f492a97fdf8ed8caafd30b3dac5690dd3
|
4
|
+
data.tar.gz: e921565b8a4ab7ef8644a1e0993d7187105840f38d73d21c6145cb420d7d8952
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 27f89bc3db8382e91415a3009d2cc76136734cf4f25685a5f40797b0cfdebabfc3fd5ff808eb4f84366c949bea3a5eebf38e8d333fcda2d58242f6716eb868f2
|
7
|
+
data.tar.gz: 5110db336085570bb0ec25497f4f61edc0f5d063de501e6edbbd01401846eb9c52a667d14b124f8363a7f853d94e0f8f71843b7be4e8653e832f5520ac127357
|
data/lib/nub.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#MIT License
|
3
|
+
#Copyright (c) 2018 phR0ze
|
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 all
|
13
|
+
#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 THE
|
21
|
+
#SOFTWARE.
|
22
|
+
|
23
|
+
module Nub
|
24
|
+
require 'nub/cmds'
|
25
|
+
require 'nub/config'
|
26
|
+
require 'nub/log'
|
27
|
+
require 'nub/net'
|
28
|
+
require 'nub/string'
|
29
|
+
require 'nub/thread_comm'
|
30
|
+
require 'nub/user'
|
31
|
+
end
|
32
|
+
|
33
|
+
# vim: ft=ruby:ts=2:sw=2:sts=2
|
data/lib/nub/cmds.rb
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
#MIT License
|
2
|
+
#Copyright (c) 2018 phR0ze
|
3
|
+
#
|
4
|
+
#Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
#of this software and associated documentation files (the "Software"), to deal
|
6
|
+
#in the Software without restriction, including without limitation the rights
|
7
|
+
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
#copies of the Software, and to permit persons to whom the Software is
|
9
|
+
#furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
#The above copyright notice and this permission notice shall be included in all
|
12
|
+
#copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
20
|
+
#SOFTWARE.
|
21
|
+
|
22
|
+
require 'optparse' # cmd line options: OptionParser
|
23
|
+
|
24
|
+
begin
|
25
|
+
require 'colorize'
|
26
|
+
rescue Exception => e
|
27
|
+
mod = e.message.split(' ').last.sub('/', '-')
|
28
|
+
mod = e.message[/.*Could not find '(.*?)'.*/, 1] if e.message.include?("Could not find")
|
29
|
+
!puts("Error: install missing package with 'sudo pacman -S ruby-#{mod}'") and exit
|
30
|
+
end
|
31
|
+
|
32
|
+
# Command option class provides a way to encapsulate a command with
|
33
|
+
# any additional properties.
|
34
|
+
class CmdOpt
|
35
|
+
attr_reader(:key)
|
36
|
+
attr_reader(:conf)
|
37
|
+
attr_reader(:type)
|
38
|
+
attr_reader(:desc)
|
39
|
+
attr_reader(:required)
|
40
|
+
def initialize(conf, desc, type:nil, required:false)
|
41
|
+
@conf = conf.gsub(' ', '=')
|
42
|
+
@key = conf.gsub('-', '').split('=').first.to_sym
|
43
|
+
@type = type
|
44
|
+
@desc = desc
|
45
|
+
@required = required
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Simple command wrapper around options parsing
|
50
|
+
# When multiple commands are given they share the options passed along with them
|
51
|
+
class Cmds
|
52
|
+
|
53
|
+
# Option and command names have all hyphens removed
|
54
|
+
attr_accessor(:cmds)
|
55
|
+
attr_accessor(:opts)
|
56
|
+
|
57
|
+
# Initialize the commands for your application
|
58
|
+
# Params:
|
59
|
+
# +app+:: application name e.g. reduce
|
60
|
+
# +version+:: version of the application e.g. 1.0.0
|
61
|
+
# +examples+:: optional examples to list after the title before usage
|
62
|
+
def initialize(app, version, examples)
|
63
|
+
@opts = {}
|
64
|
+
@cmds = {}
|
65
|
+
@cmds_config = {}
|
66
|
+
|
67
|
+
@app = app
|
68
|
+
@version = version
|
69
|
+
@examples = examples || ''
|
70
|
+
end
|
71
|
+
|
72
|
+
# Hash like accessor for checking if a command is set
|
73
|
+
def [](key)
|
74
|
+
return @cmds[key] if @cmds[key]
|
75
|
+
return @opts[key] if @opts[key]
|
76
|
+
end
|
77
|
+
|
78
|
+
# Hash like accessor for editing options
|
79
|
+
def []=(key, value)
|
80
|
+
@opts[key] = value
|
81
|
+
end
|
82
|
+
|
83
|
+
# Add a command to the command list
|
84
|
+
# Params:
|
85
|
+
# +cmd+:: name of the command
|
86
|
+
# +desc+:: description of the command
|
87
|
+
# +opts+:: list of command options
|
88
|
+
def add(cmd, desc, opts)
|
89
|
+
@cmds_config[cmd] = {desc: desc, inopts: opts, outopts: OptionParser.new{|parser|
|
90
|
+
required = opts.map{|x| x.conf if x.required}.compact * ' '
|
91
|
+
required += ' ' if not required.empty?
|
92
|
+
parser.banner = "#{banner}\nUsage: ./#{@app} #{cmd} #{required}[options]"
|
93
|
+
opts.each{|opt| parser.on(opt.conf, opt.type, opt.desc){|x| @opts[opt.key] = x }}
|
94
|
+
}}
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns banner string
|
98
|
+
def banner
|
99
|
+
banner = "#{@app}_v#{@version}\n#{'-' * 80}".colorize(:light_yellow)
|
100
|
+
return banner
|
101
|
+
end
|
102
|
+
|
103
|
+
# Construct the command line parser and parse
|
104
|
+
def parse!
|
105
|
+
|
106
|
+
# Construct help for the application
|
107
|
+
help = "COMMANDS:\n"
|
108
|
+
@cmds_config.each{|k,v| help += " #{k.ljust(33, ' ')}#{v[:desc]}\n" }
|
109
|
+
help += "\nsee './#{@app} COMMAND --help' for specific command info"
|
110
|
+
|
111
|
+
# Construct top level option parser
|
112
|
+
@optparser = OptionParser.new do |parser|
|
113
|
+
parser.banner = "#{banner}\n#{@examples}Usage: ./#{@app} commands [options]"
|
114
|
+
parser.on('-h', '--help', 'Print command/options help') {|x| !puts(parser) and exit }
|
115
|
+
parser.separator(help)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Invoke the option parser with help if any un-recognized commands are given
|
119
|
+
cmds = ARGV.select{|x| not x.start_with?('-')}
|
120
|
+
ARGV.clear and ARGV << '-h' if ARGV.empty? or cmds.any?{|x| not @cmds_config[x]}
|
121
|
+
cmds.each{|x| puts("Error: Invalid command '#{x}'".colorize(:red)) if not @cmds_config[x]}
|
122
|
+
@optparser.order!
|
123
|
+
|
124
|
+
# Now remove them from ARGV leaving only options
|
125
|
+
ARGV.reject!{|x| not x.start_with?('-')}
|
126
|
+
|
127
|
+
# Parse each command which will consume options from ARGV
|
128
|
+
cmds.each do |cmd|
|
129
|
+
begin
|
130
|
+
@cmds[cmd.gsub('-', '_').to_sym] = true
|
131
|
+
@cmds_config[cmd][:outopts].order!
|
132
|
+
|
133
|
+
# Ensure that all required options were given
|
134
|
+
@cmds_config[cmd][:inopts].each{|x|
|
135
|
+
if x.required and not @opts[x.key]
|
136
|
+
puts("Error: Missing required option '#{x.key}'".colorize(:red))
|
137
|
+
ARGV.clear and ARGV << "-h"
|
138
|
+
@cmds_config[cmd][:outopts].order!
|
139
|
+
end
|
140
|
+
}
|
141
|
+
rescue OptionParser::InvalidOption => e
|
142
|
+
# Options parser will raise an invalid exception if it doesn't recognize something
|
143
|
+
# However we want to ignore that as it may be another command's option
|
144
|
+
ARGV << e.to_s[/(-.*)/, 1]
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Ensure all options were consumed
|
149
|
+
!puts("Error: invalid options #{ARGV}".colorize(:red)) and exit if ARGV.any?
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# vim: ft=ruby:ts=2:sw=2:sts=2
|
data/lib/nub/config.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
#MIT License
|
2
|
+
#Copyright (c) 2018 phR0ze
|
3
|
+
#
|
4
|
+
#Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
#of this software and associated documentation files (the "Software"), to deal
|
6
|
+
#in the Software without restriction, including without limitation the rights
|
7
|
+
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
#copies of the Software, and to permit persons to whom the Software is
|
9
|
+
#furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
#The above copyright notice and this permission notice shall be included in all
|
12
|
+
#copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
20
|
+
#SOFTWARE.
|
21
|
+
|
22
|
+
require 'yaml'
|
23
|
+
|
24
|
+
begin
|
25
|
+
require 'colorize'
|
26
|
+
rescue Exception => e
|
27
|
+
mod = e.message.split(' ').last.sub('/', '-')
|
28
|
+
mod = e.message[/.*Could not find '(.*?)'.*/, 1] if e.message.include?("Could not find")
|
29
|
+
!puts("Error: install missing package with 'sudo pacman -S ruby-#{mod}'") and exit
|
30
|
+
end
|
31
|
+
|
32
|
+
require_relative 'user'
|
33
|
+
require_relative 'log'
|
34
|
+
|
35
|
+
# Simple YAML configuration for an application
|
36
|
+
# uses singleton pattern for single source of truth
|
37
|
+
module Config
|
38
|
+
|
39
|
+
# Private properties
|
40
|
+
@@_yml = nil
|
41
|
+
|
42
|
+
# Public properties
|
43
|
+
class << self
|
44
|
+
attr_accessor :path
|
45
|
+
end
|
46
|
+
|
47
|
+
# Singleton new alternate
|
48
|
+
# @param config_name [String] name of the config file
|
49
|
+
def self.init(config_name)
|
50
|
+
@path = "/home/#{User.name}/.config/#{config_name}"
|
51
|
+
|
52
|
+
# Open the config file or create in memory yml
|
53
|
+
begin
|
54
|
+
@@_yml = File.exists?(@path) ? YAML.load_file(@path) : {}
|
55
|
+
rescue Exception => e
|
56
|
+
Log.puts("Error: #{e}".colorize(:red)) and exit
|
57
|
+
end
|
58
|
+
|
59
|
+
return nil
|
60
|
+
end
|
61
|
+
|
62
|
+
# Simple bool whether the config exists or not on disk
|
63
|
+
def exists?
|
64
|
+
return File.exists?(@path)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Hash like getter
|
68
|
+
def self.[](key)
|
69
|
+
return @@_yml[key]
|
70
|
+
end
|
71
|
+
|
72
|
+
# Hash like setter
|
73
|
+
def self.[]=(key, val)
|
74
|
+
return @@_yml[key] = val
|
75
|
+
end
|
76
|
+
|
77
|
+
# Save the config file
|
78
|
+
def self.save
|
79
|
+
File.open(@path, 'w'){|f| f << @@_yml.to_yaml } if @@_yml
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# vim: ft=ruby:ts=2:sw=2:sts=2
|
data/lib/nub/log.rb
ADDED
@@ -0,0 +1,254 @@
|
|
1
|
+
#MIT License
|
2
|
+
#Copyright (c) 2018 phR0ze
|
3
|
+
#
|
4
|
+
#Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
#of this software and associated documentation files (the "Software"), to deal
|
6
|
+
#in the Software without restriction, including without limitation the rights
|
7
|
+
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
#copies of the Software, and to permit persons to whom the Software is
|
9
|
+
#furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
#The above copyright notice and this permission notice shall be included in all
|
12
|
+
#copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
20
|
+
#SOFTWARE.
|
21
|
+
|
22
|
+
require 'time'
|
23
|
+
require 'monitor'
|
24
|
+
require 'ostruct'
|
25
|
+
|
26
|
+
begin
|
27
|
+
require 'colorize'
|
28
|
+
rescue Exception => e
|
29
|
+
mod = e.message.split(' ').last.sub('/', '-')
|
30
|
+
mod = e.message[/.*Could not find '(.*?)'.*/, 1] if e.message.include?("Could not find")
|
31
|
+
!puts("Error: install missing package with 'sudo pacman -S ruby-#{mod}'") and exit
|
32
|
+
end
|
33
|
+
|
34
|
+
ColorPair = Struct.new(:str, :color)
|
35
|
+
ColorMap = {
|
36
|
+
"30" => "black",
|
37
|
+
"31" => "red",
|
38
|
+
"32" => "green",
|
39
|
+
"33" => "yellow",
|
40
|
+
"34" => "blue",
|
41
|
+
"35" => "magenta",
|
42
|
+
"36" => "cyan",
|
43
|
+
"37" => "white",
|
44
|
+
"39" => "gray88" # default
|
45
|
+
}
|
46
|
+
|
47
|
+
LogLevel = OpenStruct.new({
|
48
|
+
error: 0,
|
49
|
+
warn: 1,
|
50
|
+
info: 2,
|
51
|
+
debug: 3
|
52
|
+
})
|
53
|
+
|
54
|
+
# Singleton logger for use with both console and gtk+ apps
|
55
|
+
# logs to both a file and the console/queue for shell/UI apps
|
56
|
+
# uses Mutex.synchronize where required to provide thread safty
|
57
|
+
module Log
|
58
|
+
extend self
|
59
|
+
|
60
|
+
# Private properties
|
61
|
+
@@_level = 3
|
62
|
+
@@_queue = nil
|
63
|
+
@@_stdout = true
|
64
|
+
@@_monitor = Monitor.new
|
65
|
+
|
66
|
+
# Public properties
|
67
|
+
class << self
|
68
|
+
attr_reader(:id, :path)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Singleton new alternate initialize
|
72
|
+
# Can be called multiple times to reset
|
73
|
+
# @param path [String] path to log file
|
74
|
+
# @param queue [Bool] use a queue as well
|
75
|
+
# @param stdout [Bool] turn on or off stdout
|
76
|
+
# @param level [LogLevel] level at which to log
|
77
|
+
def init(path:nil, level:LogLevel.debug, queue:false, stdout:true)
|
78
|
+
@id ||= 'singleton'.object_id
|
79
|
+
|
80
|
+
@path = path ? File.expand_path(path) : nil
|
81
|
+
@@_level = level
|
82
|
+
@@_queue = queue ? Queue.new : nil
|
83
|
+
@@_stdout = stdout
|
84
|
+
|
85
|
+
# Open log file creating as needed
|
86
|
+
if @path
|
87
|
+
FileUtils.mkdir_p(File.dirname(@path)) if !File.exist?(File.dirname(@path))
|
88
|
+
@file = File.open(@path, 'a')
|
89
|
+
@file.sync = true
|
90
|
+
end
|
91
|
+
|
92
|
+
return nil
|
93
|
+
end
|
94
|
+
|
95
|
+
# Format the given string for use in log
|
96
|
+
def format(str)
|
97
|
+
@@_monitor.synchronize{
|
98
|
+
|
99
|
+
# Locate caller
|
100
|
+
stack = caller_locations(3,10)
|
101
|
+
i = -1
|
102
|
+
while i += 1 do
|
103
|
+
mod = File.basename(stack[i].path, '.rb')
|
104
|
+
break if !['log', 'monitor'].include?(mod)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Save lineno from non log call but use method name rather than rescue or block
|
108
|
+
lineno = stack[i].lineno
|
109
|
+
nested = ['rescue in', 'block in', 'each']
|
110
|
+
while nested.any?{|x| stack[i].label.include?(x)} do
|
111
|
+
i += 1
|
112
|
+
end
|
113
|
+
loc = ":#{File.basename(stack[i].path, '.rb')}:#{stack[i].label}:#{lineno}"
|
114
|
+
|
115
|
+
return "#{Time.now.utc.iso8601(3)}#{loc}:: #{str}"
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
def print(*args)
|
120
|
+
@@_monitor.synchronize{
|
121
|
+
str = !args.first.is_a?(Hash) ? args.first.to_s : ''
|
122
|
+
|
123
|
+
# Determine if stamp should be used
|
124
|
+
stamp = true
|
125
|
+
opts = args.find{|x| x.is_a?(Hash)}
|
126
|
+
if opts and opts.key?(:stamp)
|
127
|
+
stamp = opts[:stamp]
|
128
|
+
end
|
129
|
+
|
130
|
+
# Format message
|
131
|
+
str = format(str) if stamp
|
132
|
+
|
133
|
+
if !str.empty?
|
134
|
+
@file << strip_colorize(str) if @path
|
135
|
+
@@_queue << str if @@_queue
|
136
|
+
$stdout.print(str) if @@_stdout
|
137
|
+
end
|
138
|
+
|
139
|
+
return true
|
140
|
+
}
|
141
|
+
end
|
142
|
+
|
143
|
+
def puts(*args)
|
144
|
+
@@_monitor.synchronize{
|
145
|
+
str = !args.first.is_a?(Hash) ? args.first.to_s : ''
|
146
|
+
|
147
|
+
# Determine if stamp should be used
|
148
|
+
stamp = true
|
149
|
+
opts = args.find{|x| x.is_a?(Hash)}
|
150
|
+
if opts and opts.key?(:stamp)
|
151
|
+
stamp = opts[:stamp]
|
152
|
+
end
|
153
|
+
|
154
|
+
# Format message
|
155
|
+
str = format(str) if stamp
|
156
|
+
|
157
|
+
# Handle output
|
158
|
+
@file.puts(strip_colorize(str)) if @path
|
159
|
+
@@_queue << "#{str}\n" if @@_queue
|
160
|
+
$stdout.puts(str) if @@_stdout
|
161
|
+
|
162
|
+
return true
|
163
|
+
}
|
164
|
+
end
|
165
|
+
|
166
|
+
def error(*args)
|
167
|
+
return puts(*args) if LogLevel.error <= @@_level
|
168
|
+
return true
|
169
|
+
end
|
170
|
+
|
171
|
+
def warn(*args)
|
172
|
+
return puts(*args) if LogLevel.warn <= @@_level
|
173
|
+
return true
|
174
|
+
end
|
175
|
+
|
176
|
+
def info(*args)
|
177
|
+
return puts(*args) if LogLevel.info <= @@_level
|
178
|
+
return true
|
179
|
+
end
|
180
|
+
|
181
|
+
def debug(*args)
|
182
|
+
return puts(*args) if LogLevel.debug <= @@_level
|
183
|
+
return true
|
184
|
+
end
|
185
|
+
|
186
|
+
# Log the given message in red and exit
|
187
|
+
# @param msg [String] message to log
|
188
|
+
def die(msg)
|
189
|
+
puts(msg.colorize(:red)) and exit
|
190
|
+
end
|
191
|
+
|
192
|
+
# Remove an item from the queue, block until one exists
|
193
|
+
def pop()
|
194
|
+
return @@_queue ? @@_queue.pop : nil
|
195
|
+
end
|
196
|
+
|
197
|
+
# Check if the log queue is empty
|
198
|
+
def empty?
|
199
|
+
return @@_queue ? @@_queue.empty? : true
|
200
|
+
end
|
201
|
+
|
202
|
+
# Strip the ansi color codes from the given string
|
203
|
+
# @param str [String] string with ansi color codes
|
204
|
+
# @returns [String] string without any ansi codes
|
205
|
+
def strip_colorize(str)
|
206
|
+
@@_monitor.synchronize{
|
207
|
+
return str.gsub(/\e\[0;[39]\d;49m/, '').gsub(/\e\[0m/, '')
|
208
|
+
}
|
209
|
+
end
|
210
|
+
|
211
|
+
# Tokenize the given colorized string
|
212
|
+
# @param str [String] string with ansi color codes
|
213
|
+
# @returns [Array] array of Token
|
214
|
+
def tokenize_colorize(str)
|
215
|
+
@@_monitor.synchronize{
|
216
|
+
tokens = []
|
217
|
+
matches = str.to_enum(:scan, /\e\[0;[39]\d;49m(.*?[\s]*)\e\[0m/).map{Regexp.last_match}
|
218
|
+
|
219
|
+
i, istart, iend = 0, 0, 0
|
220
|
+
match = matches[i]
|
221
|
+
while istart < str.size
|
222
|
+
color = "39"
|
223
|
+
iend = str.size
|
224
|
+
token = str[istart..iend]
|
225
|
+
|
226
|
+
# Current token is not a match
|
227
|
+
if match && match.begin(0) != istart
|
228
|
+
iend = match.begin(0)-1
|
229
|
+
token = str[istart..iend]
|
230
|
+
istart = iend + 1
|
231
|
+
|
232
|
+
# Current token is a match
|
233
|
+
elsif match && match.begin(0) == istart
|
234
|
+
iend = match.end(0)
|
235
|
+
token = match.captures.first
|
236
|
+
color = match.to_s[/\e\[0;(\d+);49m.*/, 1]
|
237
|
+
i += 1; match = matches[i]
|
238
|
+
istart = iend
|
239
|
+
|
240
|
+
# Ending
|
241
|
+
else
|
242
|
+
istart = iend
|
243
|
+
end
|
244
|
+
|
245
|
+
# Create token and advance
|
246
|
+
tokens << ColorPair.new(token, color)
|
247
|
+
end
|
248
|
+
|
249
|
+
return tokens
|
250
|
+
}
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
# vim: ft=ruby:ts=2:sw=2:sts=2
|
data/lib/nub/net.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#MIT License
|
3
|
+
#Copyright (c) 2018 phR0ze
|
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 all
|
13
|
+
#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 THE
|
21
|
+
#SOFTWARE.
|
22
|
+
require 'ostruct'
|
23
|
+
|
24
|
+
module Net
|
25
|
+
@@_proxy = nil
|
26
|
+
@@_agents = OpenStruct.new({
|
27
|
+
windows_ie_6: 'Windows IE 6',
|
28
|
+
windows_ie_7: 'Windows IE 7',
|
29
|
+
windows_mozilla: 'Windows Mozilla',
|
30
|
+
mac_safari: 'Mac Safari',
|
31
|
+
mac_firefox: 'Mac FireFox',
|
32
|
+
mac_mozilla: 'Mac Mozilla',
|
33
|
+
linux_mozilla: 'Linux Mozilla',
|
34
|
+
linux_firefox: 'Linux Firefox',
|
35
|
+
linux_konqueror: 'Linux Konqueror',
|
36
|
+
iphone: 'iPhone'
|
37
|
+
})
|
38
|
+
|
39
|
+
# Accessors
|
40
|
+
def self.agents; @@_agents; end
|
41
|
+
def self.proxy_uri; http_proxy ? http_proxy.split(':')[1][2..-1] : nil; end
|
42
|
+
def self.proxy_port; http_proxy ? http_proxy.split(':').last : nil; end
|
43
|
+
def self.ftp_proxy; get_proxy if @@_proxy.nil?; @@_proxy['ftp_proxy']; end
|
44
|
+
def self.http_proxy; get_proxy if @@_proxy.nil?; @@_proxy['http_proxy']; end
|
45
|
+
def self.https_proxy; get_proxy if @@_proxy.nil?; @@_proxy['https_proxy']; end
|
46
|
+
def self.no_proxy; get_proxy if @@_proxy.nil?; @@_proxy['no_proxy']; end
|
47
|
+
|
48
|
+
# Get the system proxy variables
|
49
|
+
def self.get_proxy
|
50
|
+
@@_proxy = {
|
51
|
+
'ftp_proxy' => ENV['ftp_proxy'],
|
52
|
+
'http_proxy' => ENV['http_proxy'],
|
53
|
+
'https_proxy' => ENV['https_proxy'],
|
54
|
+
'no_proxy' => ENV['no_proxy']
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
# Get a shell export string for proxies
|
59
|
+
def self.proxy_export
|
60
|
+
get_proxy if @@_proxy.nil?
|
61
|
+
return proxy_exist? ? (@@_proxy.map{|k,v| "export #{k}=#{v}"} * ';') + ";" : nil
|
62
|
+
end
|
63
|
+
|
64
|
+
# Check if a proxy is set
|
65
|
+
def self.proxy_exist?
|
66
|
+
get_proxy if @@_proxy.nil?
|
67
|
+
return !@@_proxy['http_proxy'].nil?
|
68
|
+
end
|
69
|
+
|
70
|
+
# Check if the system is configured for the kernel to forward ip traffic
|
71
|
+
def self.ip_forward?
|
72
|
+
return `cat /proc/sys/net/ipv4/ip_forward`.include?('1')
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# vim: ft=ruby:ts=2:sw=2:sts=2
|
data/lib/nub/string.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#MIT License
|
2
|
+
#Copyright (c) 2018 phR0ze
|
3
|
+
#
|
4
|
+
#Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
#of this software and associated documentation files (the "Software"), to deal
|
6
|
+
#in the Software without restriction, including without limitation the rights
|
7
|
+
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
#copies of the Software, and to permit persons to whom the Software is
|
9
|
+
#furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
#The above copyright notice and this permission notice shall be included in all
|
12
|
+
#copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
20
|
+
#SOFTWARE.
|
21
|
+
|
22
|
+
# Monkey patch string with some useful methods
|
23
|
+
class String
|
24
|
+
def to_ascii
|
25
|
+
options = {
|
26
|
+
:invalid => :replace,
|
27
|
+
:undef => :replace,
|
28
|
+
:replace => '',
|
29
|
+
:universal_newline => true
|
30
|
+
}
|
31
|
+
return self.encode(Encoding.find('ASCII'), options)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# vim: ft=ruby:ts=2:sw=2:sts=2
|
@@ -0,0 +1,65 @@
|
|
1
|
+
#MIT License
|
2
|
+
#Copyright (c) 2018 phR0ze
|
3
|
+
#
|
4
|
+
#Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
#of this software and associated documentation files (the "Software"), to deal
|
6
|
+
#in the Software without restriction, including without limitation the rights
|
7
|
+
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
#copies of the Software, and to permit persons to whom the Software is
|
9
|
+
#furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
#The above copyright notice and this permission notice shall be included in all
|
12
|
+
#copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
20
|
+
#SOFTWARE.
|
21
|
+
|
22
|
+
require 'ostruct'
|
23
|
+
|
24
|
+
# Provides a simple messaging mechanism between threads
|
25
|
+
ThreadMsg = Struct.new(:cmd, :value)
|
26
|
+
|
27
|
+
# Thread with communication queues for simple messaging
|
28
|
+
class ThreadComm < Thread
|
29
|
+
def initialize
|
30
|
+
@comm_in = Queue.new
|
31
|
+
@comm_out = Queue.new
|
32
|
+
|
33
|
+
# Proc.new will return the block given to this method
|
34
|
+
# pass it along to thread .new with arguments
|
35
|
+
super(@comm_in, @comm_out, &Proc.new)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Check if the message queue is empty
|
39
|
+
def empty?
|
40
|
+
return @comm_out.empty?
|
41
|
+
end
|
42
|
+
|
43
|
+
# Pop a message off the thread's outbound queue or block
|
44
|
+
def pop
|
45
|
+
msg = @comm_out.pop
|
46
|
+
return msg if msg.is_a?(ThreadMsg)
|
47
|
+
return ThreadMsg.new(msg)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Push the given message onto the threads inbound queue
|
51
|
+
# @param msg [ThreadMsg] message to the thread
|
52
|
+
# @param cmd [String] message command to the thread
|
53
|
+
# @param value [String] message value to the thread
|
54
|
+
def push(*args)
|
55
|
+
if args.first.is_a?(ThreadMsg)
|
56
|
+
@comm_in << args.first
|
57
|
+
elsif args.size == 1
|
58
|
+
@comm_in << ThreadMsg.new(args.first)
|
59
|
+
else
|
60
|
+
@comm_in << ThreadMsg.new(args.first, args.last)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# vim: ft=ruby:ts=2:sw=2:sts=2
|
data/lib/nub/user.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#MIT License
|
3
|
+
#Copyright (c) 2018 phR0ze
|
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 all
|
13
|
+
#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 THE
|
21
|
+
#SOFTWARE.
|
22
|
+
|
23
|
+
module User
|
24
|
+
|
25
|
+
# Check if the current user has root privileges
|
26
|
+
def self.root?
|
27
|
+
return Process.uid.zero?
|
28
|
+
end
|
29
|
+
|
30
|
+
# Get the current user taking into account sudo priviledges
|
31
|
+
def self.name
|
32
|
+
return Process.uid.zero? ? Etc.getpwuid(ENV['SUDO_UID'].to_i).name : ENV['USER']
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# vim: ft=ruby:ts=2:sw=2:sts=2
|
metadata
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nub
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.21
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Patrick Crummett
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-03-22 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Collection of useful utilities
|
14
|
+
email:
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/nub.rb
|
20
|
+
- lib/nub/cmds.rb
|
21
|
+
- lib/nub/config.rb
|
22
|
+
- lib/nub/log.rb
|
23
|
+
- lib/nub/net.rb
|
24
|
+
- lib/nub/string.rb
|
25
|
+
- lib/nub/thread_comm.rb
|
26
|
+
- lib/nub/user.rb
|
27
|
+
homepage: https://github.com/phR0ze/ruby-nub
|
28
|
+
licenses:
|
29
|
+
- MIT
|
30
|
+
metadata: {}
|
31
|
+
post_install_message:
|
32
|
+
rdoc_options: []
|
33
|
+
require_paths:
|
34
|
+
- lib
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
requirements: []
|
46
|
+
rubyforge_project:
|
47
|
+
rubygems_version: 2.7.3
|
48
|
+
signing_key:
|
49
|
+
specification_version: 4
|
50
|
+
summary: Collection of useful utilities
|
51
|
+
test_files: []
|