w-stdlib 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +10 -0
- data/lib/aws.rb +84 -0
- data/lib/case_insensitive_hash.rb +24 -0
- data/lib/core_ext/array.rb +57 -0
- data/lib/core_ext/aws.rb +38 -0
- data/lib/core_ext/file.rb +19 -0
- data/lib/core_ext/hash.rb +27 -0
- data/lib/core_ext/io.rb +20 -0
- data/lib/core_ext/ipv4net.rb +9 -0
- data/lib/core_ext/object.rb +16 -0
- data/lib/core_ext/openssl.rb +38 -0
- data/lib/core_ext/string.rb +110 -0
- data/lib/core_ext/uri.rb +21 -0
- data/lib/github_client.rb +59 -0
- data/lib/glob.rb +13 -0
- data/lib/prelude.rb +25 -0
- data/lib/processes.rb +74 -0
- data/lib/uri.rb +16 -0
- data/lib/w-stdlib.rb +1 -0
- data/w-stdlib.gemspec +9 -0
- metadata +65 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f7cb8e2bf20665a3a90bfa7cdfbf7db465f5867bce893d78783b3ccfa38d245a
|
4
|
+
data.tar.gz: 3ce32ae202b1a5f77fa3cf90e97295d775a4c2fa6487daa92fbb8a4f6c6830fa
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 43bae6362746dd9b6bbddf3fa1fc74a8272be4db2e15df2fb65daaa9905a7938b2a8f5faf45228e29348678bd2d390a3258eedae83218ff37ee68e1c5a4ed4b5
|
7
|
+
data.tar.gz: 7e8447678675d9df0e2c8fea625833c893a471403df9713aac377b06a86afbfbe34d2697e86b237e860708b2bd96073528fe427d8ff31b1311a42bf1c323873f
|
data/Gemfile
ADDED
data/lib/aws.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require_relative '../lib/glob'
|
2
|
+
require_relative '../lib/core_ext/string'
|
3
|
+
require_relative '../lib/core_ext/object'
|
4
|
+
require_relative '../lib/core_ext/hash'
|
5
|
+
|
6
|
+
using StringExt
|
7
|
+
using ObjectExt
|
8
|
+
using HashExt
|
9
|
+
|
10
|
+
|
11
|
+
module IAM
|
12
|
+
class AssumeRoleStatement
|
13
|
+
def initialize(s)
|
14
|
+
@effect = s['Effect']
|
15
|
+
@action = s['Action']
|
16
|
+
@principal = s['Principal'].map_vals(&:lift_array) # principals can be string or string[]
|
17
|
+
end
|
18
|
+
|
19
|
+
def allow?
|
20
|
+
@effect.downcase == 'allow'
|
21
|
+
end
|
22
|
+
|
23
|
+
def deny?
|
24
|
+
@effect.downcase == 'deny'
|
25
|
+
end
|
26
|
+
|
27
|
+
def assume_role?
|
28
|
+
@action.include? 'sts:AssumeRole'
|
29
|
+
end
|
30
|
+
|
31
|
+
def applies_to_principal?(arn)
|
32
|
+
@principal.fetch('AWS', []).any? { Glob.new(_1).match? arn }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class AssumeRolePolicyDocument
|
37
|
+
def initialize(doc)
|
38
|
+
@doc = doc
|
39
|
+
@statements = doc['Statement'].map { AssumeRoleStatement.new _1 }
|
40
|
+
end
|
41
|
+
|
42
|
+
# initializes from a hash of params. it supports docs as
|
43
|
+
# url encoded json strings, like the aws api returns or
|
44
|
+
# docs that are nested hashes and arrays
|
45
|
+
def self.from_role(role)
|
46
|
+
doc = role[:assume_role_policy_document]
|
47
|
+
doc = role["AssumeRolePolicyDocument"] unless doc
|
48
|
+
raise 'invalid role' unless doc
|
49
|
+
|
50
|
+
doc = doc.url_decode.from_json if doc.is_a? String
|
51
|
+
|
52
|
+
self.new doc
|
53
|
+
end
|
54
|
+
|
55
|
+
def can_assume?(arn)
|
56
|
+
return false if explicitly_denied? arn
|
57
|
+
return true if explicitly_allowed? arn
|
58
|
+
false
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
def explicitly_denied?(arn)
|
63
|
+
@statements.any? { _1.deny? && _1.assume_role? && _1.applies_to_principal?(arn) }
|
64
|
+
end
|
65
|
+
|
66
|
+
def explicitly_allowed?(arn)
|
67
|
+
@statements.any? { _1.allow? && _1.assume_role? && _1.applies_to_principal?(arn) }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class Role
|
72
|
+
attr_reader :doc, :arn
|
73
|
+
def initialize(params)
|
74
|
+
@params = params
|
75
|
+
@arn = params[:arn]
|
76
|
+
@arn = params['Arn'] unless @arn
|
77
|
+
@doc = AssumeRolePolicyDocument.from_role params
|
78
|
+
end
|
79
|
+
|
80
|
+
def can_assume?(arn)
|
81
|
+
@doc.can_assume?(arn)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class CaseInsensitiveHash < Hash
|
2
|
+
def [](key)
|
3
|
+
super _insensitive(key)
|
4
|
+
end
|
5
|
+
|
6
|
+
def []=(key, value)
|
7
|
+
super _insensitive(key), value
|
8
|
+
end
|
9
|
+
|
10
|
+
# Keeping it DRY.
|
11
|
+
protected
|
12
|
+
|
13
|
+
def _insensitive(key)
|
14
|
+
key.respond_to?(:upcase) ? key.upcase : key
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.from_pairs(pairs)
|
18
|
+
h = CaseInsensitiveHash.new
|
19
|
+
pairs.each do |k, v|
|
20
|
+
h[k] = v
|
21
|
+
end
|
22
|
+
h
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'parallel'
|
2
|
+
require 'etc'
|
3
|
+
require_relative '../../lib/core_ext/string'
|
4
|
+
|
5
|
+
using StringExt
|
6
|
+
|
7
|
+
module ArrayExt
|
8
|
+
refine Array do
|
9
|
+
def tail
|
10
|
+
self[1..self.length]
|
11
|
+
end
|
12
|
+
|
13
|
+
def but_last
|
14
|
+
self.tap(&:pop)
|
15
|
+
end
|
16
|
+
|
17
|
+
def choose
|
18
|
+
return first if length < 2
|
19
|
+
loop do
|
20
|
+
each_with_index { puts "#{_2 + 1}: #{block_given? ? yield(_1) : _1 }" }
|
21
|
+
print "> "
|
22
|
+
input = STDIN.gets.strip
|
23
|
+
break if input.downcase == 'q'
|
24
|
+
|
25
|
+
i = input.to_i
|
26
|
+
next if i <= 0 || i > length
|
27
|
+
|
28
|
+
return self[i - 1]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def p_each(opts=nil, &blk)
|
33
|
+
opts = {in_threads: Etc.nprocessors} if opts.nil?
|
34
|
+
Parallel.each(self, opts, &blk)
|
35
|
+
end
|
36
|
+
|
37
|
+
def p_map(opts=nil, &blk)
|
38
|
+
opts = {in_threads: Etc.nprocessors} if opts.nil?
|
39
|
+
Parallel.map(self, opts, &blk)
|
40
|
+
end
|
41
|
+
|
42
|
+
def puts_all
|
43
|
+
each { puts _1.to_s }
|
44
|
+
end
|
45
|
+
|
46
|
+
def search(str)
|
47
|
+
select do
|
48
|
+
s = block_given? ? yield(_1) : _1.to_s
|
49
|
+
s.matches_pat? str
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_h_by
|
54
|
+
map { [yield(_1), _1] }.to_h
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/core_ext/aws.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative './string'
|
2
|
+
require 'aws-sdk-iam'
|
3
|
+
require 'aws-sdk-core/arn_parser'
|
4
|
+
|
5
|
+
using StringExt
|
6
|
+
|
7
|
+
module IamExt
|
8
|
+
refine Aws::IAM::Client do
|
9
|
+
def arn_to_policies(arn)
|
10
|
+
arn = arn.strip
|
11
|
+
type, name = Aws::ARNParser.parse(arn).resource.split('/', 2) rescue return []
|
12
|
+
return [] unless name && type
|
13
|
+
|
14
|
+
policies = []
|
15
|
+
|
16
|
+
attached_policies = send(:"list_attached_#{type}_policies", {:"#{type}_name" => name}).attached_policies
|
17
|
+
attached_policies.each do |p|
|
18
|
+
error "fetching #{p.policy_arn}"
|
19
|
+
version_id = list_policy_versions(policy_arn: p.policy_arn).versions.find { _1.is_default_version }.version_id
|
20
|
+
policy = get_policy_version(policy_arn: p.policy_arn, version_id: version_id).policy_version
|
21
|
+
policies << policy.document.url_decode.from_json
|
22
|
+
rescue Aws::IAM::Errors::NoSuchEntity
|
23
|
+
error "#{a} #{p.policy_name} not found"
|
24
|
+
end
|
25
|
+
|
26
|
+
inline_policies = send(:"list_#{type}_policies", {:"#{type}_name" => name}).policy_names
|
27
|
+
inline_policies.each do |policy_name|
|
28
|
+
error "fetching #{policy_name}"
|
29
|
+
policy = send(:"get_#{type}_policy", {:"#{type}_name" => name, :policy_name => policy_name})
|
30
|
+
policies << policy.policy_document.url_decode.from_json
|
31
|
+
rescue Aws::IAM::Errors::NoSuchEntity
|
32
|
+
error "#{a} #{p.policy_arn} not found"
|
33
|
+
end
|
34
|
+
|
35
|
+
policies
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative '../../lib/core_ext/string'
|
2
|
+
|
3
|
+
using StringExt
|
4
|
+
|
5
|
+
module HashExt
|
6
|
+
refine Hash do
|
7
|
+
def map_vals
|
8
|
+
map { [_1, yield(_2)] }.to_h
|
9
|
+
end
|
10
|
+
|
11
|
+
def map_keys
|
12
|
+
map { [yield(_1), _2] }.to_h
|
13
|
+
end
|
14
|
+
|
15
|
+
def search(pat)
|
16
|
+
select { _1.to_s.matches_pat?(pat) || _2.to_s.matches_pat?(pat) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def search_keys(pat)
|
20
|
+
select { _1.to_s.matches_pat?(pat) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def puts_all
|
24
|
+
each { puts "#{_1}: #{_2}"}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/core_ext/io.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative './string'
|
2
|
+
|
3
|
+
using StringExt
|
4
|
+
|
5
|
+
module IOExt
|
6
|
+
refine IO do
|
7
|
+
def lines
|
8
|
+
read.lines.map(&:strip)
|
9
|
+
end
|
10
|
+
|
11
|
+
def json_props_or_lines(*path)
|
12
|
+
s = read
|
13
|
+
begin
|
14
|
+
s.from_json.lift_array.map { _1.dig(*path) }
|
15
|
+
rescue JSON::ParserError
|
16
|
+
s.lines
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require_relative '../case_insensitive_hash'
|
3
|
+
|
4
|
+
module OpenSSLExt
|
5
|
+
refine OpenSSL::X509::Certificate do
|
6
|
+
def cn
|
7
|
+
subject['CN']
|
8
|
+
end
|
9
|
+
|
10
|
+
def sans
|
11
|
+
extensions
|
12
|
+
.find { _1.oid == 'subjectAltName' }
|
13
|
+
.value
|
14
|
+
.split(/,\s+/)
|
15
|
+
.map { _1.gsub(/^DNS:/,'') }
|
16
|
+
end
|
17
|
+
|
18
|
+
def dns_names
|
19
|
+
[cn] + sans
|
20
|
+
end
|
21
|
+
end
|
22
|
+
refine OpenSSL::X509::Name do
|
23
|
+
def to_h
|
24
|
+
str = to_s
|
25
|
+
if str.start_with?("/")
|
26
|
+
# /A=B/C=D format
|
27
|
+
CaseInsensitiveHash.from_pairs str[1..-1].split("/").map { _1.split('=', 2) }
|
28
|
+
else
|
29
|
+
# Comma-separated
|
30
|
+
CaseInsensitiveHash.from_pairs str.split(",").map { _1.split('=', 2) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def [](key)
|
35
|
+
to_h[key]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'json'
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
module StringExt
|
6
|
+
refine String do
|
7
|
+
def from_json
|
8
|
+
JSON.parse self
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_b64
|
12
|
+
Base64.encode64 self
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_bool
|
16
|
+
self.downcase == 'true'
|
17
|
+
end
|
18
|
+
|
19
|
+
def from_b64
|
20
|
+
Base64.decode64 self
|
21
|
+
end
|
22
|
+
|
23
|
+
def url_encode
|
24
|
+
CGI.escape self
|
25
|
+
end
|
26
|
+
|
27
|
+
def url_decode
|
28
|
+
CGI.unescape self
|
29
|
+
end
|
30
|
+
|
31
|
+
def words
|
32
|
+
self.split(/\s+/)
|
33
|
+
end
|
34
|
+
|
35
|
+
def chars
|
36
|
+
self.split('')
|
37
|
+
end
|
38
|
+
|
39
|
+
def map(&blk)
|
40
|
+
self.chars.map(&blk).join('')
|
41
|
+
end
|
42
|
+
|
43
|
+
def select(&blk)
|
44
|
+
self.chars.select(&blk).join('')
|
45
|
+
end
|
46
|
+
|
47
|
+
def reject(&blk)
|
48
|
+
self.chars.reject(&blk).join('')
|
49
|
+
end
|
50
|
+
|
51
|
+
def any?(&blk)
|
52
|
+
self.chars.any?(&blk)
|
53
|
+
end
|
54
|
+
|
55
|
+
def all?(&blk)
|
56
|
+
self.chars.all?(&blk)
|
57
|
+
end
|
58
|
+
|
59
|
+
def grep(pat)
|
60
|
+
self.lines.select { _1.matches_pat? pat }
|
61
|
+
end
|
62
|
+
|
63
|
+
def matches_pat?(pat)
|
64
|
+
case pat
|
65
|
+
when String
|
66
|
+
self.include_ignore_case? pat
|
67
|
+
when Regexp
|
68
|
+
self =~ pat
|
69
|
+
else
|
70
|
+
raise "matches_pat? only works on String and Regexp. You passed: #{pat.class}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def prefix(p)
|
75
|
+
p + self
|
76
|
+
end
|
77
|
+
|
78
|
+
def to_bs
|
79
|
+
n, units = self.scan(/([0-9.]+)(B|KB|MB|GB)/).first
|
80
|
+
raise "Invalid size: #{self}" unless n && units
|
81
|
+
sizes = {
|
82
|
+
'B' => 1,
|
83
|
+
'KB' => 1024,
|
84
|
+
'MB' => 1024 ** 2,
|
85
|
+
'GB' => 1024 ** 3,
|
86
|
+
}
|
87
|
+
scale = sizes.fetch(units, 1)
|
88
|
+
n.to_f*scale
|
89
|
+
end
|
90
|
+
|
91
|
+
def to_regexp
|
92
|
+
Regexp.new self
|
93
|
+
end
|
94
|
+
|
95
|
+
def regexp_encode
|
96
|
+
Regexp.quote self
|
97
|
+
end
|
98
|
+
|
99
|
+
def include_ignore_case?(s)
|
100
|
+
downcase.include? s.downcase
|
101
|
+
end
|
102
|
+
|
103
|
+
def is_numeric?
|
104
|
+
Float(self)
|
105
|
+
true
|
106
|
+
rescue
|
107
|
+
false
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/lib/core_ext/uri.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module QueryParamsMixin
|
4
|
+
def query_params
|
5
|
+
query.nil? ? {} : URI.decode_www_form(query).to_h
|
6
|
+
end
|
7
|
+
|
8
|
+
def with_query_params
|
9
|
+
params = query_params
|
10
|
+
yield params
|
11
|
+
self.query = URI.encode_www_form(params)
|
12
|
+
self
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module URI
|
17
|
+
class Generic
|
18
|
+
include QueryParamsMixin
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'http'
|
2
|
+
require 'json'
|
3
|
+
require 'uri'
|
4
|
+
require_relative '../lib/core_ext/uri'
|
5
|
+
require_relative '../lib/uri'
|
6
|
+
require_relative '../lib/core_ext/string'
|
7
|
+
|
8
|
+
using StringExt
|
9
|
+
|
10
|
+
class GithubClient
|
11
|
+
def initialize(username='', base_url='https://api.github.com')
|
12
|
+
@url = URI.parse base_url
|
13
|
+
@username = username
|
14
|
+
end
|
15
|
+
|
16
|
+
def repos
|
17
|
+
paginate('/repositories')
|
18
|
+
end
|
19
|
+
|
20
|
+
def repos_for_org(org)
|
21
|
+
paginate("/orgs/#{org}/repos")
|
22
|
+
end
|
23
|
+
|
24
|
+
def users
|
25
|
+
paginate('/users')
|
26
|
+
end
|
27
|
+
|
28
|
+
def user_perms(owner, repo, username)
|
29
|
+
url = @url.clone
|
30
|
+
url.path = "/repos/#{owner}/#{repo}/collaborators/#{username}/permission"
|
31
|
+
auth = {user: @username, pass: token}
|
32
|
+
puts url.to_s
|
33
|
+
HTTP.basic_auth(auth)
|
34
|
+
.headers({"Accept" => "application/vnd.github.v3+json"})
|
35
|
+
.get(url.to_s)
|
36
|
+
.to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def token
|
41
|
+
File.read(File.join(ENV['HOME'], '.keys', 'github')).strip
|
42
|
+
end
|
43
|
+
def paginate(path)
|
44
|
+
url = @url.clone
|
45
|
+
url.path = path
|
46
|
+
Enumerator.new do |e|
|
47
|
+
paged_uri = URI::Paged.new(url)
|
48
|
+
loop do
|
49
|
+
repos = HTTP.get(paged_uri.get).to_s.from_json
|
50
|
+
break if repos.empty?
|
51
|
+
|
52
|
+
repos.each { e.yield _1 }
|
53
|
+
rescue JSON::ParserError
|
54
|
+
break
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
data/lib/glob.rb
ADDED
data/lib/prelude.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
def fatal(msg, code=1, pref='[!] ')
|
2
|
+
STDERR.puts pref + msg
|
3
|
+
exit code
|
4
|
+
end
|
5
|
+
|
6
|
+
def info(msg, pref='[+] ')
|
7
|
+
STDERR.puts pref + msg
|
8
|
+
end
|
9
|
+
|
10
|
+
def error(msg, pref='[!] ')
|
11
|
+
STDERR.puts pref + msg
|
12
|
+
end
|
13
|
+
|
14
|
+
def json_file(name)
|
15
|
+
JSON.parse File.read(name)
|
16
|
+
end
|
17
|
+
|
18
|
+
def home_join(*paths)
|
19
|
+
home = ENV['HOME']
|
20
|
+
if paths.empty?
|
21
|
+
home
|
22
|
+
else
|
23
|
+
File.join home, *paths
|
24
|
+
end
|
25
|
+
end
|
data/lib/processes.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'sys/proctable'
|
2
|
+
require_relative '../lib/core_ext/file'
|
3
|
+
require_relative '../lib/core_ext/string'
|
4
|
+
using FileExt
|
5
|
+
using StringExt
|
6
|
+
|
7
|
+
module Processes
|
8
|
+
def self.snapshot
|
9
|
+
Snapshot.new Sys::ProcTable.ps
|
10
|
+
end
|
11
|
+
|
12
|
+
class Snapshot
|
13
|
+
def initialize(procs)
|
14
|
+
@procs = procs
|
15
|
+
@pid_to_proc = @procs.map { [_1.pid, _1] }.to_h
|
16
|
+
end
|
17
|
+
|
18
|
+
def all
|
19
|
+
@procs.map { Processes::Process.new self, _1 }
|
20
|
+
end
|
21
|
+
|
22
|
+
def for_pid(pid)
|
23
|
+
proc = @pid_to_proc[pid]
|
24
|
+
return nil unless proc
|
25
|
+
Processes::Process.new self, proc
|
26
|
+
end
|
27
|
+
|
28
|
+
def search_cmdline(name)
|
29
|
+
@procs
|
30
|
+
.select { _1.cmdline.downcase.include? name.downcase }
|
31
|
+
.reject { _1.pid == ::Process.pid }
|
32
|
+
.map { Processes::Process.new self, _1 }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Process
|
37
|
+
def initialize(snapshot, proc)
|
38
|
+
raise 'proc cant be nil' unless proc
|
39
|
+
@snapshot = snapshot
|
40
|
+
@proc = proc
|
41
|
+
end
|
42
|
+
|
43
|
+
def parent
|
44
|
+
proc = @snapshot.for_pid(self.ppid)
|
45
|
+
return nil unless proc
|
46
|
+
Processes::Process.new @snapshot, proc
|
47
|
+
end
|
48
|
+
|
49
|
+
def open_files
|
50
|
+
raise unless pid.is_numeric?
|
51
|
+
`lsof -p #{pid}`
|
52
|
+
.lines
|
53
|
+
.drop(1)
|
54
|
+
.map { _1.strip.scan(/(\/.*$)/).first&.first }
|
55
|
+
.reject(&:nil?)
|
56
|
+
.uniq
|
57
|
+
.select { File.file? _1 }
|
58
|
+
.map { File.new _1 }
|
59
|
+
end
|
60
|
+
|
61
|
+
def sig_kill
|
62
|
+
raise unless pid.is_numeric?
|
63
|
+
`kill -9 #{pid}`
|
64
|
+
end
|
65
|
+
|
66
|
+
def children
|
67
|
+
@snapshot.all.select { _1.ppid == pid }.map { Process.new @snapshot, _1 }
|
68
|
+
end
|
69
|
+
|
70
|
+
private def method_missing(symbol, *args)
|
71
|
+
@proc.send symbol, *args
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/uri.rb
ADDED
data/lib/w-stdlib.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require ''
|
data/w-stdlib.gemspec
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
Gem::Specification.new do |g|
|
2
|
+
g.name = 'w-stdlib'
|
3
|
+
g.version = '0.0.1'
|
4
|
+
g.summary = 'Pre-alpha package that contains abstractions that I find useful when scripting. Not suitable for production use. Breaking changes highly likely even with minor version bumps. Use at your own risk'
|
5
|
+
g.description = g.summary
|
6
|
+
g.authors = ['will@btlr.dev']
|
7
|
+
g.email = 'will@btlr.dev'
|
8
|
+
g.files = Dir['lib/**/*'] + %w(Gemfile w-stdlib.gemspec)
|
9
|
+
end
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: w-stdlib
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- will@btlr.dev
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-10-27 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Pre-alpha package that contains abstractions that I find useful when
|
14
|
+
scripting. Not suitable for production use. Breaking changes highly likely even
|
15
|
+
with minor version bumps. Use at your own risk
|
16
|
+
email: will@btlr.dev
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- Gemfile
|
22
|
+
- lib/aws.rb
|
23
|
+
- lib/case_insensitive_hash.rb
|
24
|
+
- lib/core_ext/array.rb
|
25
|
+
- lib/core_ext/aws.rb
|
26
|
+
- lib/core_ext/file.rb
|
27
|
+
- lib/core_ext/hash.rb
|
28
|
+
- lib/core_ext/io.rb
|
29
|
+
- lib/core_ext/ipv4net.rb
|
30
|
+
- lib/core_ext/object.rb
|
31
|
+
- lib/core_ext/openssl.rb
|
32
|
+
- lib/core_ext/string.rb
|
33
|
+
- lib/core_ext/uri.rb
|
34
|
+
- lib/github_client.rb
|
35
|
+
- lib/glob.rb
|
36
|
+
- lib/prelude.rb
|
37
|
+
- lib/processes.rb
|
38
|
+
- lib/uri.rb
|
39
|
+
- lib/w-stdlib.rb
|
40
|
+
- w-stdlib.gemspec
|
41
|
+
homepage:
|
42
|
+
licenses: []
|
43
|
+
metadata: {}
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options: []
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
requirements: []
|
59
|
+
rubygems_version: 3.0.3
|
60
|
+
signing_key:
|
61
|
+
specification_version: 4
|
62
|
+
summary: Pre-alpha package that contains abstractions that I find useful when scripting.
|
63
|
+
Not suitable for production use. Breaking changes highly likely even with minor
|
64
|
+
version bumps. Use at your own risk
|
65
|
+
test_files: []
|