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
@@ -0,0 +1,57 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ require 'nrser/refinements/types'
5
+ using NRSER::Types
6
+
7
+
8
+ # Namespace
9
+ # =======================================================================
10
+
11
+ module Locd
12
+ module CLI
13
+ module Command
14
+
15
+
16
+ # Definitions
17
+ # =======================================================================
18
+
19
+ class Job < Agent
20
+
21
+ desc "add [OPTIONS] -- CMD_TEMPLATE...",
22
+ "Add job that runs in the current directory"
23
+
24
+ include_shared t[ groups:
25
+ t.has_any( :write,
26
+ :add,
27
+ :respond_with_agents ) ]
28
+
29
+ option :every,
30
+ desc: "How often to start the job",
31
+ type: :string
32
+
33
+ option :at,
34
+ desc: "Day/time to start the job",
35
+ type: :hash
36
+
37
+ def add *cmd_template, **kwds
38
+ logger.trace "#{ self.class.name }##{ __method__ }",
39
+ options: options,
40
+ cmd_template: cmd_template,
41
+ kwds: kwds,
42
+ shared: self.class.shared_method_options
43
+
44
+ kwds[:start_interval] ||= get_start_interval
45
+
46
+ super *cmd_template, **kwds
47
+ end
48
+
49
+ end # class Job
50
+
51
+
52
+ # /Namespace
53
+ # =======================================================================
54
+
55
+ end # module Command
56
+ end # module CLI
57
+ end # module Locd
@@ -59,6 +59,7 @@ class Main < Base
59
59
  #
60
60
 
61
61
  common_class_options :backtrace
62
+ common_class_options :color
62
63
 
63
64
  class_option :log_level,
64
65
  desc: "Set log level",
@@ -220,9 +221,8 @@ class Main < Base
220
221
  Locd::CLI::Command::Proxy,
221
222
  desc: 'Deal with the HTTP proxy that routes requests to servers'
222
223
 
223
-
224
- # subcommand 'rotate-logs',
225
- subcommand 'rotate_logs',
224
+
225
+ subcommand 'rotate-logs',
226
226
  Locd::CLI::Command::RotateLogs,
227
227
  desc: 'Deal with the log rotation job'
228
228
 
@@ -1,18 +1,21 @@
1
+ # encoding: UTF-8
1
2
  # frozen_string_literal: true
2
3
 
4
+
3
5
  # Requirements
4
6
  # =======================================================================
5
7
 
6
- # Stdlib
7
- # -----------------------------------------------------------------------
8
+ ### Stdlib ###
9
+
8
10
  require 'shellwords'
9
11
 
10
- # Deps
11
- # -----------------------------------------------------------------------
12
+ ### Deps ###
13
+
12
14
  require 'thor'
13
15
 
14
- # Project / Package
15
- # -----------------------------------------------------------------------
16
+ ### Project / Package ###
17
+
18
+ require_relative './agent'
16
19
 
17
20
 
18
21
  # Refinements
@@ -22,6 +25,14 @@ require 'nrser/refinements/types'
22
25
  using NRSER::Types
23
26
 
24
27
 
28
+ # Namespace
29
+ # =======================================================================
30
+
31
+ module Locd
32
+ module CLI
33
+ module Command
34
+
35
+
25
36
  # Definitions
26
37
  # =======================================================================
27
38
 
@@ -29,7 +40,7 @@ using NRSER::Types
29
40
  #
30
41
  # @see http://whatisthor.com/
31
42
  #
32
- class Locd::CLI::Command::Proxy < Locd::CLI::Command::Agent
43
+ class Proxy < Agent
33
44
 
34
45
 
35
46
  # Helpers
@@ -52,7 +63,7 @@ class Locd::CLI::Command::Proxy < Locd::CLI::Command::Agent
52
63
  logger.error "Proxy agent plist not found",
53
64
  expected_path: Locd::Agent::Proxy.plist_abs_path.to_s
54
65
 
55
- logger.info "Run `locd setup` to create it."
66
+ logger.info "Run `locd proxy add` to create it."
56
67
 
57
68
  exit 1
58
69
  end
@@ -65,19 +76,23 @@ class Locd::CLI::Command::Proxy < Locd::CLI::Command::Agent
65
76
  public
66
77
 
67
78
 
68
-
69
79
  # Commands
70
80
  # ============================================================================
71
81
 
72
82
  desc "add",
73
83
  "Add agents that runs a command in the current directory"
74
- include_options groups: [:write, :add, :respond_with_agents]
84
+
85
+ include_shared t[ groups: t.HasAny( :add,
86
+ :respond_with_agents ) ]
87
+
88
+ include_shared t[ groups: :write, name: t.Not( :label ) ]
89
+
75
90
  def add
76
91
  agent = agent_class.add **option_kwds( groups: :write )
77
92
 
78
93
  logger.info "`#{ agent.label }` agent created."
79
94
 
80
- agent.load if options[:load]
95
+ agent.reload if options[:load]
81
96
 
82
97
  respond agent
83
98
  end
@@ -85,11 +100,13 @@ class Locd::CLI::Command::Proxy < Locd::CLI::Command::Agent
85
100
 
86
101
  desc "run",
87
102
  "Run the proxy server (in the foreground)"
103
+
88
104
  method_option :bind,
89
105
  desc: "Address to bind the proxy server to",
90
106
  aliases: ['-b', '--host', '-h'],
91
107
  type: :string,
92
108
  default: Locd.config[:proxy, :bind]
109
+
93
110
  method_option :port,
94
111
  desc: "Port to run the proxy on",
95
112
  aliases: '-p',
@@ -104,6 +121,7 @@ class Locd::CLI::Command::Proxy < Locd::CLI::Command::Agent
104
121
 
105
122
  desc "port",
106
123
  "Get port Loc'd proxy is running on or configured for"
124
+
107
125
  def port
108
126
  respond Locd::Proxy.port
109
127
  end
@@ -145,33 +163,39 @@ class Locd::CLI::Command::Proxy < Locd::CLI::Command::Agent
145
163
 
146
164
  desc "start",
147
165
  "Start the proxy"
148
- option :write,
149
- desc: "Set `launchd` *Disabled* key to `false`",
150
- type: :boolean
166
+ include_shared t[ groups: :start ]
151
167
  def start
152
- proxy.start **option_kwds( :write )
168
+ proxy.start **option_kwds( groups: :start )
153
169
  end
154
170
 
155
171
 
156
172
  desc "stop",
157
173
  "Stop the proxy"
158
- include_options groups: [:stop]
174
+ include_shared t[ groups: :stop ]
159
175
  option :write,
160
176
  desc: "Set `launchd` *Disabled* key to `true`",
161
177
  type: :boolean
162
178
  def stop
163
- proxy.stop **option_kwds( :unload, groups: :stop )
179
+ proxy.stop **option_kwds( groups: :stop )
164
180
  end
165
181
 
166
182
 
167
183
  desc "restart",
168
184
  "Restart the proxy"
169
- include_options groups: [:stop]
185
+ include_shared t[ groups: t.HasAny( :start, :stop ) ]
170
186
  option :write,
171
187
  desc: "Set `launchd` *Disabled* key to `false`",
172
188
  type: :boolean
173
189
  def restart
174
- proxy.restart **option_kwds( :write, groups: :stop )
190
+ proxy.restart **option_kwds( groups: [ :start, :stop ] )
175
191
  end
176
192
 
177
- end # module Locd::CLI::Proxy
193
+ end # class Proxy
194
+
195
+
196
+ # /Namespace
197
+ # ============================================================================
198
+
199
+ end # module Command
200
+ end # module CLI
201
+ end # module Locd
@@ -22,12 +22,20 @@ require 'nrser/refinements/types'
22
22
  using NRSER::Types
23
23
 
24
24
 
25
+ # Namespace
26
+ # =======================================================================
27
+
28
+ module Locd
29
+ module CLI
30
+ module Command
31
+
32
+
25
33
  # Definitions
26
34
  # =======================================================================
27
35
 
28
36
  # Manage log rotation.
29
37
  #
30
- class Locd::CLI::Command::RotateLogs < Locd::CLI::Command::Job
38
+ class RotateLogs < Job
31
39
 
32
40
 
33
41
  # Helpers
@@ -58,7 +66,13 @@ class Locd::CLI::Command::RotateLogs < Locd::CLI::Command::Job
58
66
  agent
59
67
  end
60
68
  end
61
-
69
+
70
+
71
+ def find_only! pattern; agent; end
72
+
73
+ def find_multi! pattern; [ agent ]; end
74
+
75
+
62
76
  # end protected
63
77
  public
64
78
 
@@ -66,35 +80,7 @@ class Locd::CLI::Command::RotateLogs < Locd::CLI::Command::Job
66
80
  # Commands
67
81
  # ============================================================================
68
82
 
69
- desc "add [OPTIONS] [-- CMD_TEMPLATE...]",
70
- "Add agents that runs a command in the current directory"
71
- include_options groups: [:write, :add, :respond_with_agents]
72
- def add *cmd_template, **kwds
73
- if cmd_template.empty? || cmd_template.all?( &:empty? )
74
- cmd_template = agent_class.default_cmd_template
75
- end
76
-
77
- if options.key? :label
78
- raise Thor::ProhibitedArgumentError,
79
- "Label can not be customized on system agents"
80
- end
81
-
82
- kwds[:start_interval] ||= if options[:every] || options[:at]
83
- get_start_interval
84
- else
85
- agent_class.default_start_interval
86
- end
87
-
88
- super *cmd_template, **kwds
89
-
90
- # agent = agent_class.add **add_kwds
91
- #
92
- # logger.info "`#{ agent.label }` agent created."
93
- #
94
- # agent.reload if options[:load]
95
- #
96
- # respond agent
97
- end
83
+ require_relative './rotate_logs/add'
98
84
 
99
85
 
100
86
  desc "run",
@@ -107,22 +93,6 @@ class Locd::CLI::Command::RotateLogs < Locd::CLI::Command::Job
107
93
  # Agent Interface
108
94
  # ----------------------------------------------------------------------------
109
95
 
110
- desc 'status',
111
- 'Print agent status'
112
- def status
113
- respond \
114
- label: agent.label,
115
- status: agent.status
116
- end
117
-
118
-
119
- desc "rm",
120
- "Remove (uninstall, delete) the agent"
121
- map remove: :rm
122
- def rm
123
- agent.remove
124
- end
125
-
126
96
 
127
97
  desc "plist",
128
98
  "Show the agent's launchd property list"
@@ -147,7 +117,7 @@ class Locd::CLI::Command::RotateLogs < Locd::CLI::Command::Job
147
117
 
148
118
  desc "stop",
149
119
  "Stop the agent"
150
- include_options groups: [:stop]
120
+ include_shared t[ groups: :stop ]
151
121
  option :write,
152
122
  desc: "Set `launchd` *Disabled* key to `true`",
153
123
  type: :boolean
@@ -158,12 +128,21 @@ class Locd::CLI::Command::RotateLogs < Locd::CLI::Command::Job
158
128
 
159
129
  desc "restart",
160
130
  "Restart the agent"
161
- include_options groups: [:stop]
131
+ include_shared t[ groups: :stop ]
162
132
  option :write,
163
133
  desc: "Set `launchd` *Disabled* key to `false`",
164
134
  type: :boolean
165
135
  def restart
166
136
  agent.restart **option_kwds( :write, groups: :stop )
167
137
  end
138
+
168
139
 
169
140
  end # module Locd::CLI::RotateLogs
141
+
142
+
143
+ # /Namespace
144
+ # ========================================================================
145
+
146
+ end # module Command
147
+ end # module CLI
148
+ end # module Locd
@@ -0,0 +1,44 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ require 'nrser/refinements/types'
5
+ using NRSER::Types
6
+
7
+
8
+ # Namespace
9
+ # =======================================================================
10
+
11
+ module Locd
12
+ module CLI
13
+ module Command
14
+
15
+
16
+ # Definitions
17
+ # =======================================================================
18
+
19
+ class RotateLogs < Job
20
+
21
+ desc "add [OPTIONS] [-- CMD_TEMPLATE...]",
22
+ "Add the rotate-logs agent"
23
+
24
+ include_shared t[ groups: t.has_any( :add, :respond_with_agents ) ]
25
+
26
+ def add
27
+ agent = agent_class.add **option_kwds( groups: [ :write, :add ] )
28
+
29
+ logger.info "#{ agent_class.name } `#{ agent.label }` created."
30
+
31
+ agent.reload if options[:load]
32
+
33
+ respond agent
34
+ end
35
+
36
+ end # class RotateLogs
37
+
38
+
39
+ # /Namespace
40
+ # =======================================================================
41
+
42
+ end # module Command
43
+ end # module CLI
44
+ end # module Locd
@@ -12,6 +12,8 @@ require 'pathname'
12
12
  # -----------------------------------------------------------------------
13
13
  require 'nrser'
14
14
  require 'nrser/core_ext/object'
15
+ require 'nrser/labs/i8'
16
+ require 'nrser/labs/i8/struct'
15
17
 
16
18
 
17
19
  # Project / Package
@@ -64,7 +66,21 @@ class Locd::Config
64
66
  # @return [String]
65
67
  #
66
68
  KEY_SEPARATOR = '.'
69
+
67
70
 
71
+ # Classes
72
+ # ============================================================================
73
+
74
+ class FileLoad < I8::Struct.new(
75
+ name: t.label?,
76
+ path: t.Path,
77
+ prev: t.Hash,
78
+ parse: t.Hash,
79
+ post: t.Hash,
80
+ )
81
+
82
+ end # class FileLoad
83
+
68
84
 
69
85
  # Attributes
70
86
  # ============================================================================
@@ -74,6 +90,13 @@ class Locd::Config
74
90
  # @return [Pathname]
75
91
  #
76
92
  attr_reader :default_config_path
93
+
94
+
95
+ # TODO document `file_loads` attribute.
96
+ #
97
+ # @return [Array<FileLoad>]
98
+ #
99
+ attr_reader :file_loads
77
100
 
78
101
 
79
102
  # Constructor
@@ -85,16 +108,29 @@ class Locd::Config
85
108
  @default_config_path = default_config_path.to_pn
86
109
  @dev_config_path = dev_config_path.to_pn
87
110
 
111
+ @file_loads = []
88
112
  @from_files = {}
89
113
 
90
- load_file! default_config_path
114
+ begin
115
+ load_file! default_config_path, name: :default
116
+ rescue StandardError => error
117
+ logger.error "Failed to load default config!", error
118
+ end
91
119
 
92
- if user_config_path.exist?
93
- load_file! user_config_path
120
+ begin
121
+ if user_config_path.exist?
122
+ load_file! user_config_path, name: :user
123
+ end
124
+ rescue Exception => error
125
+ logger.error "Failed to load user config!", error
94
126
  end
95
127
 
96
- if dev_config_path && dev_config_path.exist?
97
- load_file! dev_config_path
128
+ begin
129
+ if dev_config_path && dev_config_path.exist?
130
+ load_file! dev_config_path, name: :dev
131
+ end
132
+ rescue Exception => error
133
+ logger.error "Failed to load dev config!", error
98
134
  end
99
135
  end # #initialize
100
136
 
@@ -113,11 +149,19 @@ class Locd::Config
113
149
  #
114
150
  # @return [nil]
115
151
  #
116
- def load_file! path
117
- path.
118
- to_pn.
119
- read.
120
- thru { |contents| @from_files.deep_merge! YAML.load( contents ) }
152
+ def load_file! path, name: nil
153
+ parse = path.to_pn.read.thru { |str| YAML.safe_load str }
154
+ post = @from_files.deep_merge parse
155
+
156
+ @file_loads << FileLoad.new(
157
+ name: name,
158
+ path: path,
159
+ prev: @from_files,
160
+ parse: parse,
161
+ post: post,
162
+ )
163
+
164
+ @from_files = post
121
165
 
122
166
  nil
123
167
  end # #load_file!
@@ -164,10 +208,20 @@ class Locd::Config
164
208
 
165
209
  return value if type.nil?
166
210
 
167
- if value.is_a?( String ) && type.has_from_s?
168
- type.from_s value
169
- else
170
- type.check! value
211
+ begin
212
+ if value.is_a?( String ) && type.has_from_s?
213
+ type.from_s value
214
+ else
215
+ type.check! value
216
+ end
217
+ rescue NRSER::TypeError => error
218
+ error.context.merge! \
219
+ key: key,
220
+ value: value,
221
+ type: type,
222
+ current_config_from_files: @from_files
223
+
224
+ raise error
171
225
  end
172
226
  end
173
227
 
@@ -247,22 +301,36 @@ class Locd::Config
247
301
  end
248
302
 
249
303
 
304
+ # Absolute path to Loc'd home directory (it's workspace). Doesn't check that
305
+ # the directory exists or anything.
306
+ #
250
307
  # @return [Pathname]
251
- # Absolute path to Loc'd home directory (it's workspace).
252
- # Directory may not exist, or may be something else like a file.
253
308
  #
254
309
  def home_dir
255
- self[:home, type: t.abs_path].to_pn
310
+ self[:home].to_pn
256
311
  end
257
312
 
258
-
313
+
314
+ # Directory to save system logs in (proxy, newsyslog, etc...)
315
+ #
316
+ # @return [Pathname]
317
+ #
259
318
  def log_dir
260
319
  self[
261
- :log_dir,
262
- type: t.abs_path,
320
+ :log,
321
+ :dir,
263
322
  default: (home_dir / 'log')
264
323
  ]
265
324
  end
325
+
326
+
327
+ def tmp_dir
328
+ self[
329
+ :tmp,
330
+ :dir,
331
+ default: ( home_dir / 'tmp' )
332
+ ]
333
+ end
266
334
 
267
335
 
268
336
  # @return [Pathname]