locd 0.1.12 → 0.1.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/NAME +1 -0
  4. data/VERSION +1 -1
  5. data/config/default.lit.yaml +43 -0
  6. data/lib/locd.rb +0 -3
  7. data/lib/locd/agent.rb +50 -13
  8. data/lib/locd/agent/proxy.rb +27 -12
  9. data/lib/locd/agent/rotate_logs.rb +2 -2
  10. data/lib/locd/agent/site.rb +4 -1
  11. data/lib/locd/agent/system.rb +47 -12
  12. data/lib/locd/cli/command/agent.rb +48 -404
  13. data/lib/locd/cli/command/agent/add.rb +12 -4
  14. data/lib/locd/cli/command/agent/ls.rb +56 -0
  15. data/lib/locd/cli/command/agent/open.rb +53 -0
  16. data/lib/locd/cli/command/agent/plist.rb +43 -0
  17. data/lib/locd/cli/command/agent/restart.rb +43 -0
  18. data/lib/locd/cli/command/agent/rm.rb +46 -0
  19. data/lib/locd/cli/command/agent/shared.rb +253 -0
  20. data/lib/locd/cli/command/agent/start.rb +38 -0
  21. data/lib/locd/cli/command/agent/status.rb +41 -0
  22. data/lib/locd/cli/command/agent/stop.rb +39 -0
  23. data/lib/locd/cli/command/agent/tail.rb +82 -0
  24. data/lib/locd/cli/command/agent/truncate_logs.rb +65 -0
  25. data/lib/locd/cli/command/agent/update.rb +48 -0
  26. data/lib/locd/cli/command/base.rb +35 -3
  27. data/lib/locd/cli/command/job.rb +29 -36
  28. data/lib/locd/cli/command/job/add.rb +57 -0
  29. data/lib/locd/cli/command/main.rb +3 -3
  30. data/lib/locd/cli/command/proxy.rb +44 -20
  31. data/lib/locd/cli/command/rotate_logs.rb +28 -49
  32. data/lib/locd/cli/command/rotate_logs/add.rb +44 -0
  33. data/lib/locd/config.rb +88 -20
  34. data/lib/locd/config/types.rb +56 -27
  35. data/lib/locd/newsyslog.rb +23 -24
  36. data/lib/locd/proxy.rb +21 -9
  37. data/lib/locd/version.rb +94 -5
  38. data/locd.gemspec +10 -4
  39. metadata +67 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 912bd2acbe925cbd22b04ea99e395de57152da05
4
- data.tar.gz: d40f1a8e8d2569400868cf2d6486e63dec5829e0
3
+ metadata.gz: 4f94096db9ae78d4d6a256a23d22b40b0d345c0e
4
+ data.tar.gz: e09575a1e5757b99012e7d14a68a97d0aa0a1ef0
5
5
  SHA512:
6
- metadata.gz: 412920e9c3501cba333a675f8e9ca4b71ce88048ffbe214e33496c952f65642e0ee5b1d26c8a65a6e848cc8dd15276c35f012014b93fcc162410f65f0aee204e
7
- data.tar.gz: b4fddfc9a03b4c874cb62256e53a8029d433416e795de3d9929af1a6a1696f62af4e16aee61fabe77bc5c67fddaa246e1ee7ae286aa11f8a962da5b13b2e8a19
6
+ metadata.gz: cd4def91dc1851b6290cf9cac485ba6b1dbd290a1a860de95c2e50a05191cac35aa4740c73686eedb3827e96a8116711f5f4c3f33c3c7913288f290e62922f86
7
+ data.tar.gz: 655fd3801f4b54eaa0083255dcb2aab2d2be3a1245b9dee3e9c13d980f135e015e71476e3e255d0660903ff1b38b98c4624065459c33a771a6085ca31d8ce811
data/Gemfile CHANGED
@@ -2,9 +2,9 @@ source "https://rubygems.org"
2
2
 
3
3
  git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
- # gem 'nrser', path: './dev/packages/gems/nrser'
5
+ gem 'nrser', path: './dev/packages/gems/nrser'
6
6
  # gem 'cmds', path: './dev/packages/gems/cmds'
7
- # gem 'atli', path: './dev/packages/gems/atli'
7
+ gem 'atli', path: './dev/packages/gems/atli'
8
8
 
9
9
  # Specify your gem's dependencies in locd.gemspec
10
10
  gemspec
data/NAME ADDED
@@ -0,0 +1 @@
1
+ locd
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.12
1
+ 0.1.13
@@ -0,0 +1,43 @@
1
+ locd:
2
+ home: ~/.locd
3
+ tmp:
4
+ $format: ${#locd/home}/tmp
5
+ bin: locd
6
+
7
+ cli:
8
+ log:
9
+ level: info
10
+ application: Locd
11
+ dest: $stderr
12
+
13
+ bash_comp:
14
+ log:
15
+ level: warn
16
+ dest:
17
+ $format: ${#locd/tmp}/bash_comp.log
18
+ # /CLI
19
+
20
+ namespace:
21
+ label: com.nrser.locd
22
+ env: LOCD
23
+
24
+ proxy:
25
+ port: 8888
26
+ bind: 127.0.0.1
27
+
28
+ rotate_logs:
29
+ newsyslog:
30
+ tmp_conf_dir:
31
+ $format: ${#locd/tmp}/newsyslog
32
+ start_interval:
33
+ minute: 0
34
+
35
+ agent:
36
+ config_key: locd_config
37
+
38
+ site:
39
+ bind: 127.0.0.1
40
+ ports:
41
+ start: 55000
42
+ end: 56000
43
+
@@ -44,9 +44,6 @@ module Locd
44
44
  HOST_RE = /^Host\:\ /i
45
45
 
46
46
 
47
- ROTATE_LOGS_LABEL = 'com.nrser.locd.rotate-logs'
48
-
49
-
50
47
  # Mixins
51
48
  # ============================================================================
52
49
 
@@ -1,21 +1,19 @@
1
+ # encoding: UTF-8
1
2
  # frozen_string_literal: true
2
3
 
3
4
  # Requirements
4
5
  # =======================================================================
5
6
 
6
- # Stdlib
7
- # -----------------------------------------------------------------------
7
+ ### Stdlib ###
8
8
 
9
- # Deps
10
- # -----------------------------------------------------------------------
11
- require 'plist'
12
9
  require 'fileutils'
10
+
11
+ ### Deps ###
12
+
13
+ require 'plist'
13
14
  require 'nrser'
14
15
  require 'nrser/props/immutable/hash'
15
16
 
16
- # Project / Package
17
- # -----------------------------------------------------------------------
18
-
19
17
 
20
18
  # Refinements
21
19
  # =======================================================================
@@ -24,10 +22,15 @@ require 'nrser/refinements/types'
24
22
  using NRSER::Types
25
23
 
26
24
 
25
+ # Namespace
26
+ # ============================================================================
27
+
28
+ module Locd
29
+
30
+
27
31
  # Definitions
28
32
  # =======================================================================
29
33
 
30
-
31
34
  # Represents a backend agent that the proxy can route to.
32
35
  #
33
36
  # Agents are managed by `launchd`, macOS's system service manager, and
@@ -37,7 +40,7 @@ using NRSER::Types
37
40
  # From there they can be managed directly with macOS's `launchctl` utility,
38
41
  # with the `lunchy` gem, etc.
39
42
  #
40
- class Locd::Agent
43
+ class Agent
41
44
 
42
45
  # Constants
43
46
  # ==========================================================================
@@ -373,7 +376,7 @@ class Locd::Agent
373
376
  # @param [String] label
374
377
  # The agent's label.
375
378
  #
376
- # @return [Locd::Agent]
379
+ # @return [Agent]
377
380
  # If a Loc'd agent with `label` is installed.
378
381
  #
379
382
  # @return [nil]
@@ -388,6 +391,29 @@ class Locd::Agent
388
391
  end
389
392
 
390
393
 
394
+ # Like {.get} but raises if the agent is not found.
395
+ #
396
+ # @param [String] label
397
+ # The agent's label.
398
+ #
399
+ # @return [Agent]
400
+ # The agent.
401
+ #
402
+ # @raise [NotFoundError]
403
+ # If the agent isn't there.
404
+ #
405
+ def self.get! label
406
+ get( label ).tap do |agent|
407
+ if agent.nil?
408
+ raise NotFoundError, [
409
+ self, "with label", label,
410
+ "not found. Expected the property list at", plist_abs_path( label )
411
+ ].map( &:to_s ).join( ' ' )
412
+ end
413
+ end
414
+ end
415
+
416
+
391
417
  # Find a single {Locd::Agent} matching `pattern` or raise.
392
418
  #
393
419
  # Parameters are passed to {Locd::Label.regexp_for_glob} and the resulting
@@ -441,7 +467,7 @@ class Locd::Agent
441
467
  if agents.empty?
442
468
  raise NRSER::CountError.new(
443
469
  "No agents found for pattern from #{ pattern.source.inspect }",
444
- subject: agents,
470
+ value: agents,
445
471
  expected: '#count > 0',
446
472
  )
447
473
  end
@@ -1011,6 +1037,11 @@ class Locd::Agent
1011
1037
  end
1012
1038
 
1013
1039
 
1040
+ def ensure_running **start_kwds
1041
+ start( **start_kwds ) unless running?
1042
+ end
1043
+
1044
+
1014
1045
  # Stop the agent.
1015
1046
  #
1016
1047
  # @param [Boolean] unload:
@@ -1269,7 +1300,13 @@ class Locd::Agent
1269
1300
 
1270
1301
  # end protected
1271
1302
 
1272
- end # class Locd::Launchd
1303
+ end # class Agent
1304
+
1305
+
1306
+ # /Namespace
1307
+ # ============================================================================
1308
+
1309
+ end # module Locd
1273
1310
 
1274
1311
 
1275
1312
  # Post-Processing
@@ -1,18 +1,20 @@
1
+ # encoding: UTF-8
1
2
  # frozen_string_literal: true
2
3
 
3
4
  # Requirements
4
5
  # =======================================================================
5
6
 
6
- # Stdlib
7
- # -----------------------------------------------------------------------
7
+ ### Stdlib ###
8
8
 
9
- # Deps
10
- # -----------------------------------------------------------------------
11
- require 'plist'
12
9
  require 'fileutils'
13
10
 
14
- # Project / Package
15
- # -----------------------------------------------------------------------
11
+ ### Deps ###
12
+
13
+ require 'plist'
14
+
15
+ ### Project / Package ###
16
+
17
+ require_relative './system'
16
18
 
17
19
 
18
20
  # Refinements
@@ -22,19 +24,25 @@ require 'nrser/refinements/types'
22
24
  using NRSER::Types
23
25
 
24
26
 
27
+ # Namespace
28
+ # ============================================================================
29
+
30
+ module Locd
31
+ class Agent
32
+
33
+
25
34
  # Definitions
26
35
  # =======================================================================
27
36
 
28
-
29
37
  # An server {Locd::Agent} (HTTP only at the moment) that the proxy can
30
38
  # route requests to.
31
39
  #
32
- class Locd::Agent::Proxy < Locd::Agent
40
+ class Proxy < Agent
33
41
 
34
42
  # Mixins
35
43
  # ============================================================================
36
44
 
37
- include Locd::Agent::System
45
+ include System
38
46
 
39
47
 
40
48
  # Constants
@@ -44,7 +52,7 @@ class Locd::Agent::Proxy < Locd::Agent
44
52
  #
45
53
  # @return [Hamster::SortedSet<Symbol>]
46
54
  #
47
- TO_H_NAMES = Locd::Agent::TO_H_NAMES.union [:port, :url]
55
+ TO_H_NAMES = Agent::TO_H_NAMES.union [:port, :url]
48
56
 
49
57
 
50
58
  # Class Methods
@@ -108,4 +116,11 @@ class Locd::Agent::Proxy < Locd::Agent
108
116
 
109
117
  # @!endgroup Instance Methods: Attribute Readers
110
118
 
111
- end # class Locd::Agent::Proxy
119
+ end # class Proxy
120
+
121
+
122
+ # /Namespace
123
+ # ============================================================================
124
+
125
+ end # class Agent
126
+ end # module Locd
@@ -53,12 +53,12 @@ class Locd::Agent::RotateLogs < Locd::Agent::Job
53
53
  # @return [String]
54
54
  #
55
55
  def self.default_cmd_template
56
- "{bin} rotate-logs run"
56
+ "{bin} rotate-logs run --backtrace"
57
57
  end # .cmd_template
58
58
 
59
59
 
60
60
  def self.default_start_interval
61
- NRSER.deep_symbolize_keys Locd.config[:rotate_logs, :start_interval]
61
+ Locd.config[:rotate_logs, :start_interval].deep_symbolize_keys
62
62
  end
63
63
 
64
64
 
@@ -92,7 +92,10 @@ class Locd::Agent::Site < Locd::Agent
92
92
  # `true` if we think this `plist` belongs to a site.
93
93
  #
94
94
  def self.plist? plist
95
- !! plist.dig( Locd.config[:agent, :config_key], 'port' )
95
+ !!(
96
+ plist.dig( Locd.config[:agent, :config_key], 'port' ) &&
97
+ plist.dig( Locd.config[:agent, :config_key], 'is_system' ) != true
98
+ )
96
99
  end # .plist?
97
100
 
98
101
 
@@ -40,27 +40,52 @@ module Locd::Agent::System
40
40
  end
41
41
 
42
42
 
43
- def self.label? label
44
- label.is_a?( String ) \
45
- && label.start_with?( Locd.config[:namespace, :label] )
43
+ # Is an agent label for a system agent of *this* Loc'd instance?
44
+ #
45
+ # @note
46
+ # We can't tell if a label is a system agent label for *any* Loc'd instance
47
+ # since the prefix can be configured to anything (via the
48
+ # `locd:namespace:label` key).
49
+ #
50
+ # @return [Boolean]
51
+ #
52
+ def self.instance_label? label
53
+ label.is_a?( String ) &&
54
+ label.start_with?( "#{ Locd.config[:namespace, :label] }." )
46
55
  end
47
56
 
48
57
 
49
- # Is a plist for one of this config's system agents?
58
+ # Is the plist for a system agent of *any* Loc'd instance?
59
+ #
60
+ # In case it's not obvious, this tests true given plists of system agents
61
+ # of *other* Loc'd instance configurations besides just this one, which can
62
+ # be useful to weed things out. Maybe.
50
63
  #
51
64
  # @param plist (see Locd::Agent.plist?)
52
65
  #
53
66
  # @return [Boolean]
54
- # `true` if the plist is for a system agent for this Loc'd config.
67
+ # `true` if the plist is for a system agent.
55
68
  #
56
69
  def self.plist? plist
57
- !!(
58
- plist.dig( Locd.config[:agent, :config_key], 'is_system' ) \
59
- && label?( plist['Label'] )
60
- )
70
+ plist.dig( Locd.config[:agent, :config_key], 'is_system' ) == true
61
71
  end # .plist?
62
72
 
63
73
 
74
+ # Is a plist for a system agent of *this* Loc'd instance?
75
+ #
76
+ # @see plist?
77
+ # @see instance_label?
78
+ #
79
+ # @param plist (see Locd::Agent.plist?)
80
+ #
81
+ # @return [Boolean]
82
+ # `true` if the plist is for a system agent for this Loc'd instance config.
83
+ #
84
+ def self.instance_plist? plist
85
+ plist?( plist ) && instance_label?( plist[ 'Label' ] )
86
+ end
87
+
88
+
64
89
  # Find the concrete {Locd::Agent} subclass (that has mixed in
65
90
  # {Locd::Agent::System}) for a property list.
66
91
  #
@@ -166,8 +191,18 @@ module Locd::Agent::System
166
191
  # @return [nil]
167
192
  # If the agent does not exist.
168
193
  #
169
- def get
170
- super label
194
+ def get label = self.label
195
+ unless label == self.label
196
+ raise NRSER::AttributeError.new \
197
+ "System agents have a fixed label, must be", self.label
198
+ end
199
+
200
+ super( label )
201
+ end
202
+
203
+
204
+ def get! label = self.label
205
+ super( label )
171
206
  end
172
207
 
173
208
  # @!endgroup
@@ -231,7 +266,7 @@ module Locd::Agent::System
231
266
  end
232
267
 
233
268
  {
234
- bin: bin,
269
+ bin: bin.to_s,
235
270
  workdir: workdir,
236
271
  **kwds,
237
272
  is_system: true,
@@ -3,15 +3,11 @@
3
3
  # Requirements
4
4
  # =======================================================================
5
5
 
6
- # Stdlib
7
- # -----------------------------------------------------------------------
8
-
9
- # Deps
10
- # -----------------------------------------------------------------------
11
-
12
6
  # Project / Package
13
7
  # -----------------------------------------------------------------------
14
8
 
9
+ require_relative './base'
10
+
15
11
 
16
12
  # Refinements
17
13
  # =======================================================================
@@ -20,6 +16,14 @@ require 'nrser/refinements/types'
20
16
  using NRSER::Types
21
17
 
22
18
 
19
+ # Namespace
20
+ # =======================================================================
21
+
22
+ module Locd
23
+ module CLI
24
+ module Command
25
+
26
+
23
27
  # Definitions
24
28
  # =======================================================================
25
29
 
@@ -27,7 +31,7 @@ using NRSER::Types
27
31
  #
28
32
  # @see http://whatisthor.com/
29
33
  #
30
- class Locd::CLI::Command::Agent < Locd::CLI::Command::Base
34
+ class Agent < Base
31
35
 
32
36
  # Helpers
33
37
  # ==========================================================================
@@ -66,6 +70,21 @@ class Locd::CLI::Command::Agent < Locd::CLI::Command::Base
66
70
  end
67
71
  end
68
72
 
73
+
74
+ # The {#pattern} argument is not required because system agent subclasses
75
+ # don't need or want one.
76
+ #
77
+ # My current solution is to check {#pattern} before using it in
78
+ # {#find_only!} and {#find_multi!} and override those in system agent
79
+ # commands.
80
+ #
81
+ def check_pattern! pattern
82
+ if pattern.nil?
83
+ raise Thor::RequiredArgumentMissingError,
84
+ "No value provided for required arguments 'pattern'"
85
+ end
86
+ end
87
+
69
88
 
70
89
  # Find exactly one {Locd::Agent} for a `pattern`, using the any `:pattern`
71
90
  # shared options provided, and raising if there are no matches or more
@@ -79,11 +98,13 @@ class Locd::CLI::Command::Agent < Locd::CLI::Command::Base
79
98
  # @raise If more or less than one agent is matched.
80
99
  #
81
100
  def find_only! pattern
101
+ check_pattern! pattern
82
102
  agent_class.find_only! pattern, **option_kwds( groups: :pattern )
83
103
  end
84
104
 
85
105
 
86
106
  def find_multi! pattern
107
+ check_pattern! pattern
87
108
  # Behavior depend on the `:all` option...
88
109
  if options[:all]
89
110
  # `:all` is set, so we find all the agents for the pattern, raising
@@ -101,147 +122,11 @@ class Locd::CLI::Command::Agent < Locd::CLI::Command::Base
101
122
  # end protected
102
123
  public
103
124
 
104
- def_shared :argument,
105
- name: :pattern,
106
- groups: :pattern,
107
- desc: "Label or workdir pattern to find agent(s)",
108
- type: :string,
109
- required: true,
110
- complete: ->( klass:, **etc ) { klass.agent_class.labels.to_a }
111
-
112
125
 
113
126
  # Shared Options
114
127
  # ============================================================================
115
128
 
116
- shared_option :long,
117
- groups: :respond_with_agents,
118
- group: "Display",
119
- desc: "Display agent details table",
120
- aliases: '-l',
121
- type: :boolean
122
-
123
- # `:pattern` Group
124
- # ----------------------------------------------------------------------------
125
- #
126
- # Options when provided a `PATTERN` argument used to find agents by label.
127
- #
128
-
129
- shared_option :full,
130
- groups: :pattern,
131
- desc: "Require label PATTERN to match entire string",
132
- aliases: '-u',
133
- type: :boolean
134
-
135
- shared_option :ignore_case,
136
- groups: :pattern,
137
- desc: "Make label PATTERN case-insensitive",
138
- aliases: '-i',
139
- type: :boolean
140
-
141
- shared_option :recursive,
142
- groups: :pattern,
143
- desc: "Make workdir PATTERN match all subdirs too",
144
- aliases: '-r',
145
- type: :boolean
146
-
147
- # NOTE We don't expose the workdir pattern's `:cwd` option...
148
- # If you want to match a directory from the CLI, just provide that
149
- # directory... no reason to specify the `:cwd` in an option then
150
- # provide a relative PATTERN
151
- #
152
-
153
- # `:multi` Group
154
- # ----------------------------------------------------------------------------
155
- #
156
- # For commands that can match multiple agents.
157
- #
158
-
159
- shared_option :all,
160
- groups: :multi,
161
- group: "Pattern",
162
- desc: "Apply to ALL agents that PATTERN matches",
163
- aliases: '-a',
164
- type: :boolean
165
-
166
-
167
- # `:write` Group
168
- # ----------------------------------------------------------------------------
169
- #
170
- # Options when writing an agent `.plist` (`create`, `update`).
171
- #
172
-
173
- shared_option :label,
174
- groups: :write,
175
- desc: "Agent label, which is also the domain the proxy will serve it at",
176
- aliases: ['--name', '-n'],
177
- type: :string #,
178
- # required: true
179
-
180
- shared_option :workdir,
181
- groups: :write,
182
- desc: "Working directory for the agent's command",
183
- aliases: ['--dir'],
184
- type: :string
185
-
186
- shared_option :log_path,
187
- groups: :write,
188
- desc: "Path to log agent's STDOUT and STDERR (combined)",
189
- aliases: ['--log'],
190
- type: :string
191
-
192
- shared_option :keep_alive,
193
- groups: :write,
194
- desc: "Try to keep the agent running",
195
- type: :boolean,
196
- default: false
197
-
198
- shared_option :run_at_load,
199
- groups: :write,
200
- desc: "Start the agent when loading it",
201
- type: :boolean,
202
- default: false
203
-
204
-
205
- # `:add` Group
206
- # ----------------------------------------------------------------------------
207
-
208
- shared_option :force,
209
- groups: :add,
210
- desc: "Overwrite any existing agent",
211
- type: :boolean,
212
- default: false
213
-
214
-
215
- shared_option :load,
216
- groups: :add,
217
- desc: "Load the agent into `launchd`",
218
- type: :boolean,
219
- default: true
220
-
221
-
222
- # `:start` Group
223
- # --------------------------------------------------------------------------
224
- #
225
- # Relevant options when starting agents.
226
- #
227
-
228
- shared_option :load,
229
- groups: :start,
230
- desc: "Load the agent before starting",
231
- type: :boolean,
232
- default: true
233
-
234
- shared_option :force,
235
- groups: :start,
236
- desc: "Force loading of agent even if it's disabled",
237
- type: :boolean,
238
- default: false
239
-
240
- shared_option :enable,
241
- groups: :start,
242
- desc: "Set `launchd` *Disabled* key to `false`",
243
- type: :boolean,
244
- default: false
129
+ require_relative './agent/shared'
245
130
 
246
131
 
247
132
  # Commands
@@ -250,281 +135,40 @@ class Locd::CLI::Command::Agent < Locd::CLI::Command::Base
250
135
  # Querying
251
136
  # ----------------------------------------------------------------------------
252
137
 
253
- desc "ls",
254
- "List agents"
255
-
256
- map list: :ls
257
-
258
- include_shared groups: :pattern
259
-
260
- include_options :long,
261
- groups: :pattern
262
-
263
- def ls # pattern = nil
264
- results = if pattern.nil?
265
- agent_class.all
266
- else
267
- agent_class.list pattern, **option_kwds( groups: :pattern )
268
- end
269
-
270
- respond results.values.sort
271
- end
272
-
273
-
274
- desc "plist PATTERN [OPTIONS]",
275
- "Print an agent's launchd property list"
276
-
277
- include_options groups: :pattern
278
-
279
- def plist pattern
280
- agent = find_only! pattern
281
-
282
- if options[:json] || options[:yaml]
283
- respond agent.plist
284
- else
285
- respond agent.path.read
286
- end
287
- end
288
-
289
-
290
- desc 'status PATTERN',
291
- "Print agent status"
292
-
293
- include_options groups: :pattern
294
-
295
- def status pattern
296
- agent = find_only! pattern
297
- respond \
298
- label: agent.label,
299
- status: agent.status.to_h( compact: false )
300
- end
138
+ require_relative './agent/ls'
139
+ require_relative './agent/plist'
140
+ require_relative './agent/status'
301
141
 
302
142
 
303
143
  # Commands for Manipulating Agent Definitions
304
144
  # ----------------------------------------------------------------------------
305
145
 
306
146
  require_relative './agent/add'
307
-
308
-
309
- desc "update PATTERN [OPTIONS] [-- CMD_TEMPLATE...]",
310
- "Update an existing agent"
311
-
312
- include_options groups: [:pattern, :write, :respond_with_agents]
313
-
314
- def update pattern, *cmd_template
315
- agent = find_only! pattern
316
-
317
- new_agent = agent.update \
318
- cmd_template: cmd_template,
319
- **option_kwds( groups: :write )
320
-
321
- logger.info "Agent `#{ agent.label }` updated"
322
-
323
- respond agent
324
- end
325
-
326
-
327
- desc "rm PATTERN [OPTIONS]",
328
- "Remove (uninstall, delete) a agent"
329
-
330
- map remove: :rm
331
-
332
- include_options groups: [:pattern, :multi]
333
-
334
- option :logs,
335
- desc: "Remove logs too",
336
- type: :boolean,
337
- default: false
338
-
339
- def rm pattern
340
- kwds = option_kwds :logs
341
- find_multi!( pattern ).each { |agent| agent.remove **kwds }
342
- end
343
-
147
+ require_relative './agent/update'
148
+ require_relative './agent/rm'
149
+
344
150
 
345
151
  # Commands for Manipulating Agent State
346
152
  # --------------------------------------------------------------------------
347
153
 
348
- desc "start PATTERN [OPTIONS]",
349
- "Start an agent"
350
-
351
- include_options groups: [ :pattern, :multi, :start ]
352
-
353
- def start pattern
354
- kwds = option_kwds :load, :force, :enable
355
- find_multi!( pattern ).each { |agent| agent.start **kwds }
356
- end
357
-
358
-
359
- desc "stop PATTERN [OPTIONS]",
360
- "Stop an agent"
361
-
362
- include_options groups: [:pattern, :multi, :stop]
363
-
364
- option :unload,
365
- desc: "Unload the agent from `launchd` after stopping",
366
- type: :boolean,
367
- default: true
368
-
369
- option :disable,
370
- desc: "Set `launchd` *Disabled* key to `true`",
371
- type: :boolean,
372
- default: false
373
-
374
- def stop pattern
375
- kwds = option_kwds :unload, :disable
376
- find_multi!( pattern ).each { |agent| agent.stop **kwds }
377
- end
378
-
379
-
380
- desc "restart PATTERN [OPTIONS]",
381
- "Restart an agent"
382
-
383
- include_options groups: [:pattern, :multi, :stop]
384
-
385
- option :reload,
386
- desc: "Unload and reload the agent in `launchd`",
387
- type: :boolean,
388
- default: true
389
-
390
- option :force,
391
- desc: "Force loading of agent even if it's disabled",
392
- type: :boolean,
393
- default: false
394
-
395
- option :enable,
396
- desc: "Set `launchd` *Disabled* key to `false`",
397
- type: :boolean,
398
- default: false
399
-
400
- def restart pattern
401
- kwds = option_kwds :reload, :force, :enable
402
- find_multi!( pattern ).each { |agent| agent.restart **kwds }
403
- end
154
+ require_relative './agent/start'
155
+ require_relative './agent/stop'
156
+ require_relative './agent/restart'
404
157
 
405
158
 
406
159
  # Assorted Other Commands
407
160
  # ----------------------------------------------------------------------------
408
161
 
409
- desc "open [OPTIONS]",
410
- "Open an agent's URL in the browser"
162
+ require_relative './agent/open'
163
+ require_relative './agent/truncate_logs'
164
+ require_relative './agent/tail'
411
165
 
412
- include_options groups: [ :pattern, :multi, :start ]
166
+ end # class Agent
413
167
 
414
- # include_shared groups: [ :pattern, :multi, :start ]
415
-
416
- arg :pattern,
417
- desc: "Label or workdir pattern to find agent(s)",
418
- type: :string,
419
- required: true,
420
- complete: ->( klass:, **etc ) { klass.agent_class.labels.to_a }
421
168
 
422
- option :start,
423
- desc: %{ Start any stopped agents before opening },
424
- type: :boolean,
425
- default: true
426
-
427
- def open # pattern
428
- find_multi!( pattern ).each do |agent|
429
- if options[:start] && agent.stopped?
430
- agent.start **option_kwds( groups: :start )
431
- end
432
-
433
- Cmds! "open %s", agent.url
434
-
435
- logger.info "Opened agent `#{ agent.label }` at #{ agent.url }"
436
- end
437
- end
438
-
439
-
440
- desc 'truncate_logs PATTERN',
441
- "Truncate agent log file(s)."
442
-
443
- include_options groups: [:pattern, :multi]
444
-
445
- option :restart,
446
- desc: "Restart the agent after truncation",
447
- type: :boolean,
448
- default: true
449
-
450
- def truncate_logs pattern
451
- find_multi!( pattern ).each do |agent|
452
- log_paths = [agent.out_path, agent.err_path].compact.uniq
453
-
454
- unless log_paths.empty?
455
- restart = options[:restart] && agent.running?
456
-
457
- agent.stop if restart
458
-
459
- log_paths.each do |log_path|
460
- begin
461
- log_path.open( 'w' ) { |f| f.truncate 0 }
462
- rescue Exception => error
463
- logger.error "Failed to truncate #{ log_path }", error
464
- else
465
- logger.info "Truncated",
466
- 'file' => log_path.to_s,
467
- 'agent.label' => agent.label
468
- end
469
- end # each log_path
470
-
471
- agent.start if restart
472
- end # unless log_paths.empty?
473
- end # each agent
474
- end # #truncate_logs
475
-
476
-
477
- desc 'tail [OPTIONS] PATTERN [-- TAIL_OPTIONS]',
478
- "Tail agent logs"
479
-
480
- include_options groups: :pattern
481
-
482
- option :stream,
483
- desc: "Stream to tail. May omit if uses single log file.",
484
- aliases: ['-s'],
485
- type: :string,
486
- enum: ['out', 'err']
487
-
488
- option :follow,
489
- desc: "Run with `tail -F`",
490
- aliases: [ '-f' ],
491
- type: :boolean
492
-
493
- def tail pattern, *tail_options
494
- agent = find_only! pattern
495
-
496
- path = case options[:stream]
497
- when nil
498
- paths = agent.log_paths
499
-
500
- unless paths.length == 1
501
- raise Thor::RequiredArgumentMissingError.new binding.erb <<~END
502
- Agent `<%= agent.label %>` has multiple log files.
503
-
504
- out: <%= agent.out_path.to_s %>
505
- err: <%= agent.err_path.to_s %>
506
-
507
- Must specify one via the `--stream` option.
508
-
509
- END
510
- end
511
-
512
- paths[0]
513
-
514
- when 'out'
515
- agent.out_path
516
-
517
- when 'err'
518
- agent.err_path
519
-
520
- else
521
- raise "WTF"
522
- end
523
-
524
- cmd = ['tail']
525
- cmd += ['-F'] if options[:follow]
526
-
527
- exec *cmd, *tail_options, path.to_s
528
- end # #tail
529
-
530
- end # class Locd::CLI::Command::Agent
169
+ # /Namespace
170
+ # =======================================================================
171
+
172
+ end # module Command
173
+ end # module CLI
174
+ end # module Locd