locd 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|