locd 0.1.12 → 0.1.13

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.
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