lux-hammer 0.3.15 → 0.3.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a61994d8f82b575a019cfb1171935b334b840cdb5561fcc56e9ba2c141a314d2
4
- data.tar.gz: a4d4d730c830b4d30de13dc9e0c27e9cc2fa3902c9297154d4fe81ba5365fe94
3
+ metadata.gz: 1e64c1f3c63eddb83350353d2a5f5977e5afe544a68d9ed43eea129debc017e7
4
+ data.tar.gz: 8e5cfe7fa2ff99d970f172b77e5d23fb7ea27722f5103cfd2edf2c4aba4d5579
5
5
  SHA512:
6
- metadata.gz: 0e4c0a5f1fbf47550df2929670e647cf7e1e390e7b3aab0b71932dc5f9557295953c39cdf9fafc6ac719d53b94ed14058bd1a2bb32bcaf9bb79ff3b2198fee16
7
- data.tar.gz: b0012fd33259c5ea63af2d3ea0040c4a618292042f842dbda523f462d90fbc9138c04217c3c86a7d52fd56a6b650249ab2dd9bb6f070e1f1a24497ab68e6dbe2
6
+ metadata.gz: 452eee357de3639419009dae5b0160ab337e0dbea42aee6c44e084284e5e5557d2c2df8c803ed2bd8564e4808f49e1422c1bb9d5ea9a6bbbab57f1f217f2084a
7
+ data.tar.gz: 6572ee28bdb6e8f26328a315d29bdde5bb0a63190b13fa7255008b3d44db23c3337616fb485b78e3eeab73822d30e1c1263457ee473c00a94dae073e65ded3c6
data/.version CHANGED
@@ -1 +1 @@
1
- 0.3.15
1
+ 0.3.16
data/AGENTS.md CHANGED
@@ -313,7 +313,7 @@ Task contracts:
313
313
  `hammer/cron_web.rb` - no webrick, keep it dependency-free): jobs
314
314
  table, per-job log tail, POST run-now, `/json` status. Flags:
315
315
  `--port`, `--pass` (HTTP basic auth on every route, any username,
316
- constant-time compare; falls back to `HAMMER_CRON_PASS` env),
316
+ constant-time compare; falls back to `CRON_HTTP_PASS` env),
317
317
  `--list` (print jobs + next runs, exit), `--service` (print launchd
318
318
  plist / systemd unit, carries `--pass` when set, install hints on
319
319
  stderr).
data/README.md CHANGED
@@ -683,11 +683,11 @@ On a shared machine, protect the UI with HTTP basic auth - useful since
683
683
  "run now" executes tasks:
684
684
 
685
685
  ```sh
686
- hammer h:cron --pass=secret # or: HAMMER_CRON_PASS=secret hammer h:cron
686
+ hammer h:cron --pass=secret # or: CRON_HTTP_PASS=secret hammer h:cron
687
687
  curl -u :secret http://127.0.0.1:4267/json # any username, password checked
688
688
  ```
689
689
 
690
- Prefer the `HAMMER_CRON_PASS` env var when other users can read your
690
+ Prefer the `CRON_HTTP_PASS` env var when other users can read your
691
691
  process list (`ps` shows flag values). A `--service` unit generated
692
692
  while `--pass` is set carries the flag along, so keep that file private.
693
693
  Note this is plain HTTP - credentials are encoded, not encrypted; for
@@ -135,7 +135,7 @@ class Hammer
135
135
  example 'h:cron --list'
136
136
  example 'h:cron --service > ~/.config/systemd/user/hammer-cron.service'
137
137
  opt :port, type: :integer, default: 4267, desc: 'web UI port (binds 127.0.0.1 only)'
138
- opt :pass, type: :string, desc: 'HTTP basic-auth password for the web UI (or HAMMER_CRON_PASS env)'
138
+ opt :pass, type: :string, desc: 'HTTP basic-auth password for the web UI (or CRON_HTTP_PASS env)'
139
139
  opt :list, type: :boolean, desc: 'print scheduled jobs + next runs, then exit'
140
140
  opt :service, type: :boolean, desc: 'print a launchd plist (macOS) / systemd unit (linux)'
141
141
  proc do |opts|
@@ -144,7 +144,7 @@ class Hammer
144
144
  end
145
145
  require_relative 'cron_server'
146
146
  server = Hammer::CronServer.new(self.class.root, port: opts[:port],
147
- pass: opts[:pass] || ENV['HAMMER_CRON_PASS'])
147
+ pass: opts[:pass] || ENV['CRON_HTTP_PASS'])
148
148
  if opts[:service]
149
149
  server.print_service_unit
150
150
  elsif opts[:list]
@@ -265,41 +265,11 @@ class Hammer
265
265
  def print_service_unit
266
266
  if RUBY_PLATFORM.include?('darwin')
267
267
  label = "com.lux-hammer.cron.#{File.basename(@root_dir)}"
268
- puts <<~XML
269
- <?xml version="1.0" encoding="UTF-8"?>
270
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
271
- <plist version="1.0">
272
- <dict>
273
- <key>Label</key><string>#{label}</string>
274
- <key>ProgramArguments</key>
275
- <array>
276
- <string>#{@hammer_bin}</string>
277
- <string>h:cron</string>
278
- <string>--port=#{@port}</string>#{@pass ? "\n <string>--pass=#{@pass}</string>" : ''}
279
- </array>
280
- <key>WorkingDirectory</key><string>#{@root_dir}</string>
281
- <key>RunAtLoad</key><true/>
282
- <key>KeepAlive</key><true/>
283
- <key>StandardOutPath</key><string>#{@root_dir}/log/hammer/cron-server.log</string>
284
- <key>StandardErrorPath</key><string>#{@root_dir}/log/hammer/cron-server.log</string>
285
- </dict>
286
- </plist>
287
- XML
268
+ puts launchd_service_unit(label)
288
269
  warn Shell.paint("# save to ~/Library/LaunchAgents/#{label}.plist, then:", :gray)
289
270
  warn Shell.paint("# launchctl load ~/Library/LaunchAgents/#{label}.plist", :gray)
290
271
  else
291
- puts <<~UNIT
292
- [Unit]
293
- Description=hammer h:cron job server (#{File.basename(@root_dir)})
294
-
295
- [Service]
296
- ExecStart=#{@hammer_bin} h:cron --port=#{@port}#{" --pass=#{@pass}" if @pass}
297
- WorkingDirectory=#{@root_dir}
298
- Restart=on-failure
299
-
300
- [Install]
301
- WantedBy=default.target
302
- UNIT
272
+ puts systemd_service_unit
303
273
  warn Shell.paint('# save to ~/.config/systemd/user/hammer-cron.service, then:', :gray)
304
274
  warn Shell.paint('# systemctl --user enable --now hammer-cron', :gray)
305
275
  end
@@ -326,6 +296,71 @@ class Hammer
326
296
 
327
297
  private
328
298
 
299
+ def launchd_service_unit(label = "com.lux-hammer.cron.#{File.basename(@root_dir)}")
300
+ args = [@hammer_bin, 'h:cron', "--port=#{@port}"]
301
+ args << "--pass=#{@pass}" if @pass
302
+ arguments = args.map { |arg| " <string>#{xml_escape(arg)}</string>" }.join("\n")
303
+ log_path = File.join(@root_dir, 'log/hammer/cron-server.log')
304
+
305
+ <<~XML
306
+ <?xml version="1.0" encoding="UTF-8"?>
307
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
308
+ <plist version="1.0">
309
+ <dict>
310
+ <key>Label</key><string>#{xml_escape(label)}</string>
311
+ <key>ProgramArguments</key>
312
+ <array>
313
+ #{arguments}
314
+ </array>
315
+ <key>WorkingDirectory</key><string>#{xml_escape(@root_dir)}</string>
316
+ <key>RunAtLoad</key><true/>
317
+ <key>KeepAlive</key><true/>
318
+ <key>StandardOutPath</key><string>#{xml_escape(log_path)}</string>
319
+ <key>StandardErrorPath</key><string>#{xml_escape(log_path)}</string>
320
+ </dict>
321
+ </plist>
322
+ XML
323
+ end
324
+
325
+ def systemd_service_unit
326
+ args = [@hammer_bin, 'h:cron', "--port=#{@port}"]
327
+ args << "--pass=#{@pass}" if @pass
328
+
329
+ <<~UNIT
330
+ [Unit]
331
+ Description=#{systemd_quote("hammer h:cron job server (#{File.basename(@root_dir)})")}
332
+
333
+ [Service]
334
+ ExecStart=#{args.map { |arg| systemd_quote(arg) }.join(' ')}
335
+ WorkingDirectory=#{systemd_quote(@root_dir)}
336
+ Restart=on-failure
337
+
338
+ [Install]
339
+ WantedBy=default.target
340
+ UNIT
341
+ end
342
+
343
+ def xml_escape(value)
344
+ value.to_s.gsub('&', '&amp;').gsub('<', '&lt;').gsub('>', '&gt;')
345
+ .gsub('"', '&quot;').gsub("'", '&apos;')
346
+ end
347
+
348
+ def systemd_quote(value)
349
+ escaped = value.to_s.gsub(/[\x00-\x1f\x7f%$\\"]/) do |char|
350
+ case char
351
+ when '%' then '%%'
352
+ when '$' then '$$'
353
+ when '\\' then '\\\\'
354
+ when '"' then '\\"'
355
+ when "\n" then '\\n'
356
+ when "\r" then '\\r'
357
+ when "\t" then '\\t'
358
+ else format('\\x%02x', char.ord)
359
+ end
360
+ end
361
+ %Q{"#{escaped}"}
362
+ end
363
+
329
364
  # Refuse to start when the state file points at another live h:cron -
330
365
  # two schedulers would double-fire every job. Best-effort (no lock
331
366
  # file): kill(0) tells us whether that pid is still alive.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lux-hammer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.15
4
+ version: 0.3.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dino Reic