potluck 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 50b13dbd4649490c2673d9dde14aef89251279b2ea39c6cb816d110320078efa
4
+ data.tar.gz: f380c5e9c07a27b55bfa20a5a4deddbb3e1978ecb9d63db8acc5888e9457f533
5
+ SHA512:
6
+ metadata.gz: 878a3446024f4ef4ac5464acb7866ed5517d27dd4a113ed2e2f24c119d9a0416bc82eb5cf00462a0dd4e3a602a566bf15a9f1b900c8e28fba5734399ed5a3d48
7
+ data.tar.gz: 0fe2162e70524a4bd85eba990d32b5d5397c4366bb8532d3f8a11a06824e7bce169f03b4dbe27e04600f0763a62a6f4a596a597f24ce4197a1bdb07e8ee8de07
data/LICENSE ADDED
@@ -0,0 +1,16 @@
1
+ Copyright 2021 Nate Pickens
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
4
+ documentation files (the "Software"), to deal in the Software without restriction, including without
5
+ limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
6
+ the Software, and to permit persons to whom the Software is furnished to do so, subject to the following
7
+ conditions:
8
+
9
+ The above copyright notice and this permission notice shall be included in all copies or substantial
10
+ portions of the Software.
11
+
12
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
13
+ LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
14
+ EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
15
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
16
+ OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,30 @@
1
+ # Potluck
2
+
3
+ Potluck is an extensible Ruby framework for managing external processes.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your Gemfile:
8
+
9
+ ```ruby
10
+ gem('potluck')
11
+ ```
12
+
13
+ Or install manually on the command line:
14
+
15
+ ```bash
16
+ gem install potluck
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ [Coming soon.]
22
+
23
+ ## Contributing
24
+
25
+ Bug reports and pull requests are welcome on GitHub at https://github.com/npickens/potluck.
26
+
27
+ ## License
28
+
29
+ The gem is available as open source under the terms of the
30
+ [MIT License](https://opensource.org/licenses/MIT).
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/lib/potluck.rb ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative('potluck/dish')
4
+
5
+ module Potluck
6
+ DIR = File.expand_path(File.join(ENV['HOME'], '.potluck')).freeze
7
+ IS_MACOS = !!RUBY_PLATFORM[/darwin/]
8
+ end
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Potluck
4
+ class Dish
5
+ SERVICE_PREFIX = 'potluck.npickens.'
6
+
7
+ PLIST_XML = '<?xml version="1.0" encoding="UTF-8"?>'
8
+ PLIST_DOCTYPE = '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/Prope'\
9
+ 'rtyList-1.0.dtd">'
10
+
11
+ LAUNCHCTL_ERROR_REGEX = /^-|\t[^0]\t/.freeze
12
+
13
+ def initialize(logger: nil, is_local: nil)
14
+ @logger = logger
15
+ @is_local = is_local.nil? ? (IS_MACOS && ensure_launchctl! rescue false) : is_local
16
+ end
17
+
18
+ def ensure_launchctl!
19
+ @@launchctl = `which launchctl` && $? == 0 unless defined?(@@launchctl)
20
+ @@launchctl || raise("Cannot manage #{self.class.to_s.split('::').last}: launchctl not found")
21
+ end
22
+
23
+ def ensure_plist
24
+ File.write(self.class.plist_path, self.class.plist)
25
+ end
26
+
27
+ def status
28
+ return :inactive unless @is_local && ensure_launchctl!
29
+
30
+ output = `launchctl list 2>&1 | grep #{SERVICE_PREFIX}#{self.class.service_name}`
31
+
32
+ if $? != 0
33
+ :inactive
34
+ elsif output[LAUNCHCTL_ERROR_REGEX]
35
+ :error
36
+ else
37
+ :active
38
+ end
39
+ end
40
+
41
+ def start
42
+ return unless @is_local && ensure_launchctl!
43
+
44
+ ensure_plist
45
+
46
+ case status
47
+ when :error then stop
48
+ when :active then return
49
+ end
50
+
51
+ run("launchctl bootstrap gui/#{Process.uid} #{self.class.plist_path}")
52
+ wait { status == :inactive }
53
+
54
+ raise("Could not start #{self.class.pretty_name}") if status != :active
55
+
56
+ log("#{self.class.pretty_name} started")
57
+ end
58
+
59
+ def stop
60
+ return unless @is_local && ensure_launchctl! && status != :inactive
61
+
62
+ run("launchctl bootout gui/#{Process.uid}/#{self.class.launchctl_name}")
63
+ wait { status != :inactive }
64
+
65
+ raise("Could not stop #{self.class.pretty_name}") if status != :inactive
66
+
67
+ log("#{self.class.pretty_name} stopped")
68
+ end
69
+
70
+ def restart
71
+ return unless @is_local && ensure_launchctl!
72
+
73
+ stop
74
+ start
75
+ end
76
+
77
+ def run(command, redirect_stderr: true)
78
+ output = `#{command}#{' 2>&1' if redirect_stderr}`
79
+ status = $?
80
+
81
+ if status != 0
82
+ output.split("\n").each { |line| log(line, :error) }
83
+ raise("Command exited with status #{status.to_i}: #{command}")
84
+ else
85
+ output
86
+ end
87
+ end
88
+
89
+ def log(message, error = false)
90
+ if @logger
91
+ error ? @logger.error(message) : @logger.info(message)
92
+ else
93
+ error ? $stderr.puts(message) : $stdout.puts(message)
94
+ end
95
+ end
96
+
97
+ private
98
+
99
+ def wait(timeout = 30, &block)
100
+ while block.call && timeout > 0
101
+ reduce = [[(30 - timeout.to_i) / 5.0, 0.1].max, 1].min
102
+ timeout -= reduce
103
+
104
+ sleep(reduce)
105
+ end
106
+ end
107
+
108
+ def self.pretty_name
109
+ @pretty_name ||= self.to_s.split('::').last
110
+ end
111
+
112
+ def self.service_name
113
+ @service_name ||= pretty_name.downcase
114
+ end
115
+
116
+ def self.launchctl_name
117
+ "#{SERVICE_PREFIX}#{service_name}"
118
+ end
119
+
120
+ def self.plist_path
121
+ File.join(DIR, "#{launchctl_name}.plist")
122
+ end
123
+
124
+ def self.plist(content)
125
+ <<~EOS
126
+ #{PLIST_XML}
127
+ #{PLIST_DOCTYPE}
128
+ <plist version="1.0">
129
+ <dict>
130
+ <key>Label</key>
131
+ <string>#{launchctl_name}</string>
132
+ <key>RunAtLoad</key>
133
+ <true/>
134
+ <key>KeepAlive</key>
135
+ <false/>
136
+ #{content.gsub(/^/, ' ').strip}
137
+ </dict>
138
+ </plist>
139
+ EOS
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Potluck
4
+ VERSION = '0.0.1'
5
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: potluck
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Nate Pickens
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-03-27 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: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 5.11.2
34
+ - - "<"
35
+ - !ruby/object:Gem::Version
36
+ version: 6.0.0
37
+ type: :development
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 5.11.2
44
+ - - "<"
45
+ - !ruby/object:Gem::Version
46
+ version: 6.0.0
47
+ description: An extensible Ruby framework for managing external processes.
48
+ email:
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - LICENSE
54
+ - README.md
55
+ - VERSION
56
+ - lib/potluck.rb
57
+ - lib/potluck/dish.rb
58
+ - lib/potluck/version.rb
59
+ homepage: https://github.com/npickens/potluck
60
+ licenses:
61
+ - MIT
62
+ metadata:
63
+ allowed_push_host: https://rubygems.org
64
+ homepage_uri: https://github.com/npickens/potluck
65
+ source_code_uri: https://github.com/npickens/potluck
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 2.5.8
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubygems_version: 3.2.3
82
+ signing_key:
83
+ specification_version: 4
84
+ summary: An extensible Ruby framework for managing external processes.
85
+ test_files: []