locd 0.1.3
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 +108 -0
- data/.gitmodules +9 -0
- data/.qb-options.yml +4 -0
- data/.rspec +3 -0
- data/.travis.yml +5 -0
- data/.yardopts +7 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +72 -0
- data/Rakefile +6 -0
- data/VERSION +1 -0
- data/config/default.yml +24 -0
- data/doc/files/design/domains_and_labels.md +117 -0
- data/doc/files/topics/agents.md +16 -0
- data/doc/files/topics/launchd.md +15 -0
- data/doc/files/topics/plists.md +39 -0
- data/doc/include/plist.md +3 -0
- data/exe/locd +24 -0
- data/lib/locd.rb +75 -0
- data/lib/locd/agent.rb +1186 -0
- data/lib/locd/agent/job.rb +142 -0
- data/lib/locd/agent/proxy.rb +111 -0
- data/lib/locd/agent/rotate_logs.rb +82 -0
- data/lib/locd/agent/site.rb +174 -0
- data/lib/locd/agent/system.rb +270 -0
- data/lib/locd/cli.rb +4 -0
- data/lib/locd/cli/command.rb +9 -0
- data/lib/locd/cli/command/agent.rb +310 -0
- data/lib/locd/cli/command/base.rb +243 -0
- data/lib/locd/cli/command/job.rb +110 -0
- data/lib/locd/cli/command/main.rb +201 -0
- data/lib/locd/cli/command/proxy.rb +177 -0
- data/lib/locd/cli/command/rotate_logs.rb +152 -0
- data/lib/locd/cli/command/site.rb +47 -0
- data/lib/locd/cli/table.rb +157 -0
- data/lib/locd/config.rb +237 -0
- data/lib/locd/config/base.rb +93 -0
- data/lib/locd/errors.rb +65 -0
- data/lib/locd/label.rb +61 -0
- data/lib/locd/launchctl.rb +209 -0
- data/lib/locd/logging.rb +360 -0
- data/lib/locd/newsyslog.rb +402 -0
- data/lib/locd/pattern.rb +193 -0
- data/lib/locd/proxy.rb +272 -0
- data/lib/locd/proxymachine.rb +34 -0
- data/lib/locd/util.rb +49 -0
- data/lib/locd/version.rb +26 -0
- data/locd.gemspec +66 -0
- metadata +262 -0
@@ -0,0 +1,270 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Refinements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
using NRSER
|
8
|
+
using NRSER::Types
|
9
|
+
|
10
|
+
|
11
|
+
# Definitions
|
12
|
+
# =======================================================================
|
13
|
+
|
14
|
+
# Mixin for common stuff that system agents do different.
|
15
|
+
#
|
16
|
+
# System agents are specific types of {Locd::Agent} built in to Loc'd to
|
17
|
+
# handle things like proxying HTTP request site ({Locd::Agent::Proxy}),
|
18
|
+
# rotating logs so they don't get unwieldily ({Locd::Agent::RotaeLogs}),
|
19
|
+
# and probably more in the future, like serving a site index, API, etc.
|
20
|
+
#
|
21
|
+
# System agents are singular - there's only one of each for a Loc'd
|
22
|
+
# label namespace, which is set via the configuration, and Loc'd uses
|
23
|
+
# that label namespace, together with the each system agent's `.label_name`,
|
24
|
+
# to form the agent's unique label, which is how it finds the system agents.
|
25
|
+
#
|
26
|
+
# This was really just to make it simpler by side-stepping how to handle
|
27
|
+
# many proxies and log rotators and such because besides the dev/release
|
28
|
+
# situation described above I can't really think of any reason you would want
|
29
|
+
# to create and manage multiple of each system agent.
|
30
|
+
#
|
31
|
+
# As a consequence, {Locd::Agent} subclasses that mix {Locd::Agent::System}
|
32
|
+
# in must define a `.label_name` class method.
|
33
|
+
#
|
34
|
+
module Locd::Agent::System
|
35
|
+
|
36
|
+
@@classes = Hamster::Set.new
|
37
|
+
|
38
|
+
def self.classes
|
39
|
+
@@classes
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def self.label? label
|
44
|
+
label.is_a?( String ) \
|
45
|
+
&& label.start_with?( Locd.config[:namespace, :label] )
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
# Is a plist for one of this config's system agents?
|
50
|
+
#
|
51
|
+
# @param plist (see Locd::Agent.plist?)
|
52
|
+
#
|
53
|
+
# @return [Boolean]
|
54
|
+
# `true` if the plist is for a system agent for this Loc'd config.
|
55
|
+
#
|
56
|
+
def self.plist? plist
|
57
|
+
!!(
|
58
|
+
plist.dig( Locd::Agent::CONFIG_KEY, 'is_system' ) \
|
59
|
+
&& label?( plist['Label'] )
|
60
|
+
)
|
61
|
+
end # .plist?
|
62
|
+
|
63
|
+
|
64
|
+
# Find the concrete {Locd::Agent} subclass (that has mixed in
|
65
|
+
# {Locd::Agent::System}) for a property list.
|
66
|
+
#
|
67
|
+
# @param plist (see Locd::Agent.plist?)
|
68
|
+
#
|
69
|
+
# @return [Class<Locd::Agent>]
|
70
|
+
# If the plist is for one of {.classes}, returns that class.
|
71
|
+
#
|
72
|
+
# @return [nil]
|
73
|
+
# If the plist is:
|
74
|
+
#
|
75
|
+
# 1. Not a system plist (see {.plist?})
|
76
|
+
#
|
77
|
+
# 2. If none of {.classes} claim it (via their `.plist?` method).
|
78
|
+
#
|
79
|
+
# Though, really, this one shouldn't happen except in weird version
|
80
|
+
# switching situations maybe or something.
|
81
|
+
#
|
82
|
+
def self.class_for plist
|
83
|
+
return nil unless plist?( plist )
|
84
|
+
|
85
|
+
classes.to_a.find_bounded( max: 1 ) { |cls| cls.plist? plist }.first
|
86
|
+
end # .class_for
|
87
|
+
|
88
|
+
|
89
|
+
def self.included base
|
90
|
+
base.extend ClassMethods
|
91
|
+
@@classes = @@classes.add base
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
# Mixed in to classes themselves that include {Locd::Agent::System}.
|
96
|
+
#
|
97
|
+
module ClassMethods
|
98
|
+
|
99
|
+
def label
|
100
|
+
"#{ Locd.config[:namespace, :label] }.#{ label_name }"
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
# The property lists for system agents are identified by their unique
|
105
|
+
# label (unique to the label namespace).
|
106
|
+
#
|
107
|
+
# @param (see Locd::Agent.plist?)
|
108
|
+
# @return (see Locd::Agent.plist?)
|
109
|
+
#
|
110
|
+
def plist? plist
|
111
|
+
plist['Label'] == self.label
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
# Overridden as convenience, defaults the label to `.label`.
|
116
|
+
#
|
117
|
+
# @param (see Locd::Agent.plist_abs_path)
|
118
|
+
# @return (see Locd::Agent.plist_abs_path)
|
119
|
+
#
|
120
|
+
def plist_abs_path label = self.label
|
121
|
+
super label
|
122
|
+
end # .plist_abs_path
|
123
|
+
|
124
|
+
|
125
|
+
# By default system agent logs are placed in the Loc'd log directory,
|
126
|
+
# which is `<locd_home>/log` and named `<label>.log`.
|
127
|
+
#
|
128
|
+
# It does not depend on the `workdir` parameter at all - `workdir` is
|
129
|
+
# only included to conform to the {Locd::Agent.default_log_path} signature.
|
130
|
+
#
|
131
|
+
# @example
|
132
|
+
# # Considering
|
133
|
+
# Locd.config.log_dir
|
134
|
+
# # => #<Pathname:/Users/nrser/.locd/log>
|
135
|
+
#
|
136
|
+
# # then
|
137
|
+
# default_log_path _, 'com.nrser.locd.proxy'
|
138
|
+
# # => #<Pathname:/Users/nrser/.locd/log/com.nrser.locd.proxy.log>
|
139
|
+
#
|
140
|
+
# @see Locd::Config#log_dir
|
141
|
+
# @see Locd.config
|
142
|
+
# @see Locd::Agent.default_log_path
|
143
|
+
#
|
144
|
+
# @param [Pathname] workdir
|
145
|
+
# Not used.
|
146
|
+
#
|
147
|
+
# @param [String] label
|
148
|
+
# The agent's label.
|
149
|
+
#
|
150
|
+
# @return [Pathname]
|
151
|
+
# Absolute path to the log file.
|
152
|
+
#
|
153
|
+
def default_log_path workdir, label
|
154
|
+
Locd.config.log_dir / "#{ label }.log"
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
# @!group Querying
|
159
|
+
# --------------------------------------------------------------------------
|
160
|
+
|
161
|
+
# Get the agent.
|
162
|
+
#
|
163
|
+
# @return [Locd::Agent]
|
164
|
+
# If the agent exists.
|
165
|
+
#
|
166
|
+
# @return [nil]
|
167
|
+
# If the agent does not exist.
|
168
|
+
#
|
169
|
+
def get
|
170
|
+
super label
|
171
|
+
end
|
172
|
+
|
173
|
+
# @!endgroup
|
174
|
+
|
175
|
+
|
176
|
+
# @!group Creating the Agent
|
177
|
+
# --------------------------------------------------------------------------
|
178
|
+
|
179
|
+
# Wrapper that keyword arguments to `.add` and `.create_plist_data` are
|
180
|
+
# passed through before forwarding up to the super method.
|
181
|
+
#
|
182
|
+
# Provides default values and checks that necessary values like `label`
|
183
|
+
# and `is_system` are either not provided in the call or match the
|
184
|
+
# expected values.
|
185
|
+
#
|
186
|
+
# @param [String] bin:
|
187
|
+
# The executable that will be used by system agents to call Loc'd.
|
188
|
+
#
|
189
|
+
# @param workdir: (see Locd::Agent.add)
|
190
|
+
#
|
191
|
+
# @param **kwds
|
192
|
+
# Merged into the returned {Hash}.
|
193
|
+
#
|
194
|
+
# @raise [ArgumentError]
|
195
|
+
# If `kwds` contains bad values.
|
196
|
+
#
|
197
|
+
def default_write_kwds bin: Locd.config[:bin],
|
198
|
+
workdir: Locd.config.home_dir,
|
199
|
+
**kwds
|
200
|
+
|
201
|
+
if kwds.key?( :is_system ) && kwds[:is_system] != true
|
202
|
+
raise ArgumentError.new binding.erb <<~END
|
203
|
+
The `:is_system` keyword **must** be `true` for system agents.
|
204
|
+
|
205
|
+
It's how we recognize them!
|
206
|
+
|
207
|
+
Found
|
208
|
+
|
209
|
+
<%= kwds[:is_system] %>
|
210
|
+
|
211
|
+
END
|
212
|
+
end
|
213
|
+
|
214
|
+
if kwds.key?( :label ) && kwds[:label] != self.label
|
215
|
+
raise ArgumentError.new binding.erb <<~END
|
216
|
+
Can not customize system agent labels!
|
217
|
+
|
218
|
+
It **must** be `<%= self.label %>`, because that's how Loc'd finds it.
|
219
|
+
|
220
|
+
You can change the part before the `.proxy` via the
|
221
|
+
|
222
|
+
locd.namespace.label
|
223
|
+
|
224
|
+
configuration value. Create or edit the file at
|
225
|
+
|
226
|
+
<%= Locd.config.user_config_path %>
|
227
|
+
|
228
|
+
to define overrides (nested YAML hashes, deep merged).
|
229
|
+
|
230
|
+
END
|
231
|
+
end
|
232
|
+
|
233
|
+
{
|
234
|
+
bin: bin,
|
235
|
+
workdir: workdir,
|
236
|
+
**kwds,
|
237
|
+
is_system: true,
|
238
|
+
label: self.label,
|
239
|
+
}
|
240
|
+
end
|
241
|
+
|
242
|
+
|
243
|
+
# Wrapper that passes keywords though {#default_write_kwds} before
|
244
|
+
# calling the super method.
|
245
|
+
#
|
246
|
+
# @param (see Locd::Agent.create_plist_data)
|
247
|
+
# @return (see Locd::Agent.create_plist_data)
|
248
|
+
# @raise (see Locd::Agent.create_plist_data)
|
249
|
+
#
|
250
|
+
def create_plist_data **kwds
|
251
|
+
super **default_write_kwds( **kwds )
|
252
|
+
end
|
253
|
+
|
254
|
+
|
255
|
+
# Wrapper that passes keywords though {#default_write_kwds} before
|
256
|
+
# calling the super method.
|
257
|
+
#
|
258
|
+
# @param (see Locd::Agent.add)
|
259
|
+
# @return (see Locd::Agent.add)
|
260
|
+
# @raise (see Locd::Agent.add)
|
261
|
+
#
|
262
|
+
def add **kwds
|
263
|
+
super **default_write_kwds( **kwds )
|
264
|
+
end # .add
|
265
|
+
|
266
|
+
# @!endgroup Creating the Agent
|
267
|
+
|
268
|
+
end # module ClassMethods
|
269
|
+
|
270
|
+
end # module Locd::Agent::System
|
data/lib/locd/cli.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
module Locd::CLI::Command; end
|
2
|
+
|
3
|
+
require_relative './command/base'
|
4
|
+
require_relative './command/agent'
|
5
|
+
require_relative './command/site'
|
6
|
+
require_relative './command/job'
|
7
|
+
require_relative './command/proxy'
|
8
|
+
require_relative './command/rotate_logs'
|
9
|
+
require_relative './command/main'
|
@@ -0,0 +1,310 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Requirements
|
4
|
+
# =======================================================================
|
5
|
+
|
6
|
+
# Stdlib
|
7
|
+
# -----------------------------------------------------------------------
|
8
|
+
|
9
|
+
# Deps
|
10
|
+
# -----------------------------------------------------------------------
|
11
|
+
|
12
|
+
# Project / Package
|
13
|
+
# -----------------------------------------------------------------------
|
14
|
+
|
15
|
+
|
16
|
+
# Refinements
|
17
|
+
# =======================================================================
|
18
|
+
|
19
|
+
using NRSER
|
20
|
+
using NRSER::Types
|
21
|
+
|
22
|
+
|
23
|
+
# Definitions
|
24
|
+
# =======================================================================
|
25
|
+
|
26
|
+
# CLI interface using the `thor` gem.
|
27
|
+
#
|
28
|
+
# @see http://whatisthor.com/
|
29
|
+
#
|
30
|
+
class Locd::CLI::Command::Agent < Locd::CLI::Command::Base
|
31
|
+
|
32
|
+
# Helpers
|
33
|
+
# ==========================================================================
|
34
|
+
#
|
35
|
+
|
36
|
+
def self.agent_class
|
37
|
+
Locd::Agent
|
38
|
+
end # .agent_class
|
39
|
+
|
40
|
+
def self.agent_type
|
41
|
+
agent_class.name.split( '::' ).last.downcase
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
protected
|
46
|
+
# ==========================================================================
|
47
|
+
|
48
|
+
def agent_class
|
49
|
+
self.class.agent_class
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def agent_type
|
54
|
+
self.class.agent_type
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
def agent_table agents
|
59
|
+
Locd::CLI::Table.build do |t|
|
60
|
+
t.col "PID", &:pid
|
61
|
+
t.col "LEC", desc: "Last Exit Code", &:last_exit_code
|
62
|
+
t.col "Label", &:label
|
63
|
+
t.col "File" do |agent| agent_file agent end
|
64
|
+
|
65
|
+
t.rows agents
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
# Find exactly one {Locd::Agent} for a `pattern`, using the any `:pattern`
|
71
|
+
# shared options provided, and raising if there are no matches or more
|
72
|
+
# than one.
|
73
|
+
#
|
74
|
+
# @param pattern (see Locd::Agent.find_only!)
|
75
|
+
#
|
76
|
+
# @return [Locd::Agent]
|
77
|
+
# Matched agent.
|
78
|
+
#
|
79
|
+
# @raise If more or less than one agent is matched.
|
80
|
+
#
|
81
|
+
def find_only! pattern
|
82
|
+
agent_class.find_only! pattern, **option_kwds( groups: :pattern )
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
def find_multi! pattern
|
87
|
+
# Behavior depend on the `:all` option...
|
88
|
+
if options[:all]
|
89
|
+
# `:all` is set, so we find all the agents for the pattern, raising
|
90
|
+
# if we don't find any
|
91
|
+
agent_class.find_all!(
|
92
|
+
pattern,
|
93
|
+
**option_kwds( groups: :pattern )
|
94
|
+
).values
|
95
|
+
else
|
96
|
+
# `:all` is not set, so we need to find exactly one or error
|
97
|
+
[find_only!( pattern )]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# end protected
|
102
|
+
public
|
103
|
+
|
104
|
+
|
105
|
+
# Shared Options
|
106
|
+
# ============================================================================
|
107
|
+
|
108
|
+
shared_option :long,
|
109
|
+
groups: :respond_with_agents,
|
110
|
+
desc: "Display agent details",
|
111
|
+
aliases: '-l',
|
112
|
+
type: :boolean
|
113
|
+
|
114
|
+
# `:pattern` Group
|
115
|
+
# ----------------------------------------------------------------------------
|
116
|
+
#
|
117
|
+
# Options when provided a `PATTERN` argument used to find agents by label.
|
118
|
+
#
|
119
|
+
|
120
|
+
shared_option :exact,
|
121
|
+
groups: :pattern,
|
122
|
+
desc: "Force PATTERN to match entire label string",
|
123
|
+
aliases: '-x',
|
124
|
+
type: :boolean
|
125
|
+
|
126
|
+
shared_option :recursive,
|
127
|
+
groups: :pattern,
|
128
|
+
desc: "Workdir patterns match all subdirs too",
|
129
|
+
aliases: '-r',
|
130
|
+
type: :boolean
|
131
|
+
|
132
|
+
shared_option :all,
|
133
|
+
groups: :multi,
|
134
|
+
desc: "Apply to ALL agents that PATTERN matches",
|
135
|
+
aliases: '-a',
|
136
|
+
type: :boolean
|
137
|
+
|
138
|
+
|
139
|
+
# `:write` Group
|
140
|
+
# ----------------------------------------------------------------------------
|
141
|
+
#
|
142
|
+
# Options when writing an agent `.plist` (`create`, `update`).
|
143
|
+
#
|
144
|
+
|
145
|
+
shared_option :label,
|
146
|
+
groups: :write,
|
147
|
+
desc: "Agent label, which is also the domain the proxy will serve it at",
|
148
|
+
aliases: ['--name', '-n'],
|
149
|
+
type: :string #,
|
150
|
+
# required: true
|
151
|
+
|
152
|
+
shared_option :workdir,
|
153
|
+
groups: :write,
|
154
|
+
desc: "Working directory for the agent's command",
|
155
|
+
aliases: ['--dir'],
|
156
|
+
type: :string
|
157
|
+
|
158
|
+
shared_option :log_path,
|
159
|
+
groups: :write,
|
160
|
+
desc: "Path to log agent's STDOUT and STDERR (combined)",
|
161
|
+
aliases: ['--log'],
|
162
|
+
type: :string
|
163
|
+
|
164
|
+
|
165
|
+
shared_option :force,
|
166
|
+
groups: :add,
|
167
|
+
desc: "Overwrite any existing agent",
|
168
|
+
aliases: '-f',
|
169
|
+
type: :boolean,
|
170
|
+
default: false
|
171
|
+
|
172
|
+
|
173
|
+
shared_option :load,
|
174
|
+
groups: :add,
|
175
|
+
desc: "Load the agent into `launchd`",
|
176
|
+
type: :boolean,
|
177
|
+
default: true
|
178
|
+
|
179
|
+
|
180
|
+
shared_option :unload,
|
181
|
+
groups: :start,
|
182
|
+
desc: "Unload the agent from `launchd` after stopping",
|
183
|
+
type: :boolean,
|
184
|
+
default: true
|
185
|
+
|
186
|
+
# Commands
|
187
|
+
# ============================================================================
|
188
|
+
|
189
|
+
# Querying
|
190
|
+
# ----------------------------------------------------------------------------
|
191
|
+
|
192
|
+
desc "ls [PATTERN]",
|
193
|
+
"List agents"
|
194
|
+
map list: :ls
|
195
|
+
include_options :long,
|
196
|
+
groups: :pattern
|
197
|
+
def ls pattern = nil
|
198
|
+
results = if pattern.nil?
|
199
|
+
agent_class.all
|
200
|
+
else
|
201
|
+
agent_class.list pattern, **option_kwds( groups: :pattern )
|
202
|
+
end
|
203
|
+
|
204
|
+
respond results.values.sort
|
205
|
+
end
|
206
|
+
|
207
|
+
|
208
|
+
# Write Commands
|
209
|
+
# ----------------------------------------------------------------------------
|
210
|
+
|
211
|
+
desc "add CMD_TEMPLATE...",
|
212
|
+
"Add agents that runs a command in the current directory"
|
213
|
+
include_options groups: [:write, :add, :respond_with_agents]
|
214
|
+
def add *cmd_template
|
215
|
+
agent = agent_class.add \
|
216
|
+
cmd_template: cmd_template,
|
217
|
+
**option_kwds( groups: :write )
|
218
|
+
|
219
|
+
logger.info "`#{ agent.label }` agent created."
|
220
|
+
|
221
|
+
agent.load if options[:load]
|
222
|
+
|
223
|
+
respond agent
|
224
|
+
end
|
225
|
+
|
226
|
+
|
227
|
+
desc "update PATTERN [OPTIONS] [-- CMD_TEMPLATE...]",
|
228
|
+
"Update an existing agent"
|
229
|
+
include_options groups: [:pattern, :write, :respond_with_agents]
|
230
|
+
def update pattern, *cmd_template
|
231
|
+
agent = find_only! pattern
|
232
|
+
|
233
|
+
new_agent = agent.update \
|
234
|
+
cmd_template: cmd_template,
|
235
|
+
**option_kwds( groups: :write )
|
236
|
+
|
237
|
+
logger.info "Agent `#{ agent.label }` updated"
|
238
|
+
|
239
|
+
respond agent
|
240
|
+
end
|
241
|
+
|
242
|
+
|
243
|
+
desc "open PATTERN",
|
244
|
+
"Open an agent's URL in the browser"
|
245
|
+
include_options groups: [:pattern, :multi]
|
246
|
+
def open pattern
|
247
|
+
find_multi!( pattern ).each do |agent|
|
248
|
+
Cmds! "open %s", agent.url
|
249
|
+
logger.info "Opened agent `#{ agent.label }` at #{ agent.url }"
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
|
254
|
+
desc "rm PATTERN",
|
255
|
+
"Remove (uninstall, delete) a agent"
|
256
|
+
map remove: :rm
|
257
|
+
include_options groups: [:pattern, :multi]
|
258
|
+
def rm pattern
|
259
|
+
agent_class.remove pattern, **option_kwds( :exact )
|
260
|
+
end
|
261
|
+
|
262
|
+
|
263
|
+
desc "plist PATTERN",
|
264
|
+
"Show an agent's launchd property list"
|
265
|
+
include_options groups: :pattern
|
266
|
+
def plist pattern
|
267
|
+
# TODO Why doesn't this use {#find_only!}?
|
268
|
+
agent = agent_class.find_only! pattern, **option_kwds( :exact )
|
269
|
+
|
270
|
+
if options[:json] || options[:yaml]
|
271
|
+
respond agent.plist
|
272
|
+
else
|
273
|
+
respond agent.path.read
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
|
278
|
+
desc "start PATTERN",
|
279
|
+
"Start an agent"
|
280
|
+
include_options groups: :pattern
|
281
|
+
option :write,
|
282
|
+
desc: "Set `launchd` *Disabled* key to `false`",
|
283
|
+
type: :boolean
|
284
|
+
def start pattern
|
285
|
+
find_only!( pattern ).start
|
286
|
+
end
|
287
|
+
|
288
|
+
|
289
|
+
desc "stop PATTERN",
|
290
|
+
"Stop an agent"
|
291
|
+
include_options groups: [:pattern, :stop]
|
292
|
+
option :write,
|
293
|
+
desc: "Set `launchd` *Disabled* key to `true`",
|
294
|
+
type: :boolean
|
295
|
+
def stop pattern
|
296
|
+
find_only!( pattern ).stop **option_kwds( :unload )
|
297
|
+
end
|
298
|
+
|
299
|
+
|
300
|
+
desc "restart PATTERN",
|
301
|
+
"Restart an agent"
|
302
|
+
include_options groups: [:pattern, :stop]
|
303
|
+
option :write,
|
304
|
+
desc: "Set `launchd` *Disabled* key to `false`",
|
305
|
+
type: :boolean
|
306
|
+
def restart pattern
|
307
|
+
find_only!( pattern ).restart
|
308
|
+
end
|
309
|
+
|
310
|
+
end # class Locd::CLI::Command::Agent
|