Module: Mailmate::CLI::Verify Private
Overview
This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.
‘mm-verify` — batch-confirm `mm-modify –emit-check` tickets against the `#flags` index in ONE index-flush wait.
MailMate flushes ‘#flags` to disk a few seconds after an AppleScript action, and it’s a single global file. So a batch of N modifies can be confirmed by waiting once for that flush and reading the index once —not by polling per message (which would pay the latency N times). Feed this the tickets ‘mm-modify –emit-check` printed (a JSON array, or newline-delimited JSON objects); it polls the index until every ticket’s expectations hold or –check-timeout elapses, then prints a JSON summary.
Exit: 0 all confirmed, 3 one or more failed, 2 bad input.
Instance Method Summary collapse
- #build_parser(opts) ⇒ Object private
-
#check_all(tickets) ⇒ Object
private
One pass: read #flags fresh, then evaluate every ticket against it.
-
#fresh_flags_reader ⇒ Object
private
Force a fresh read of #flags (bypass the staleness throttle so each poll sees the latest on-disk state).
-
#parse_tickets(raw) ⇒ Object
private
Accepts a JSON array of ticket objects, or newline-delimited JSON objects (what ‘mm-modify –emit-check` prints, one per line).
- #read_input(opts, argv) ⇒ Object private
- #run(argv) ⇒ Object private
- #usage_error(parser, msg) ⇒ Object private
-
#verify(tickets, timeout:, poll:) ⇒ Object
private
Poll the #flags index until every ticket’s expectations hold or the timeout elapses; one index read per poll iteration covers the whole batch.
Instance Method Details
#build_parser(opts) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/mailmate/cli/verify.rb', line 118 def build_parser(opts) OptionParser.new do |o| o. = <<~BANNER Usage: mm-verify [tickets.json] [options] mm-modify <id> <action> --emit-check | ... | mm-verify Confirm a batch of `mm-modify --emit-check` tickets against the #flags index, paying the index-flush wait ONCE for the whole batch. Input is a JSON array of tickets, or newline-delimited JSON objects, read from a file (positional or --file), a JSON argument, or stdin. Output: a JSON summary {checked, passed, failed, waited_seconds, results}. Exit 0 if all confirmed, 3 if any failed, 2 on bad input. BANNER o.on("--file PATH", "Read tickets from PATH instead of stdin") { |p| opts[:file] = p } o.on("--check-timeout SECONDS", Float, "Max seconds to wait for #flags to reflect the batch (default 8.0)") { |s| opts[:check_timeout] = s } o.on("--poll SECONDS", Float, "Index re-read interval while waiting (default 0.25)") { |s| opts[:poll] = s } o.on("--compact", "Compact JSON output (default pretty)") { opts[:pretty] = false } end end |
#check_all(tickets) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
One pass: read #flags fresh, then evaluate every ticket against it.
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/mailmate/cli/verify.rb', line 71 def check_all(tickets) reader = fresh_flags_reader tickets.map do |t| eml_id = t["eml_id"].to_i exps = Array(t["expectations"]) flags = reader ? reader.flags_for(eml_id) : [] unmet = exps.reject { |kind, arg| Mailmate::FlagCheck.met?(flags, kind, arg) } { "eml_id" => eml_id, "message_id" => t["message_id"], "ok" => unmet.empty?, "flags" => flags, "unmet" => unmet.map { |kind, arg| Mailmate::FlagCheck.label(kind, arg) }, } end end |
#fresh_flags_reader ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Force a fresh read of #flags (bypass the staleness throttle so each poll sees the latest on-disk state). nil if the index is absent.
90 91 92 93 94 95 |
# File 'lib/mailmate/cli/verify.rb', line 90 def fresh_flags_reader Mailmate::IndexReader.reset!("#flags") Mailmate::IndexReader.for("#flags") rescue ArgumentError nil end |
#parse_tickets(raw) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Accepts a JSON array of ticket objects, or newline-delimited JSON objects (what ‘mm-modify –emit-check` prints, one per line). A bare single object is wrapped.
100 101 102 103 104 105 106 107 108 109 |
# File 'lib/mailmate/cli/verify.rb', line 100 def parse_tickets(raw) s = raw.strip if s.start_with?("[") Array(JSON.parse(s)) elsif s.start_with?("{") && !s.include?("\n") [JSON.parse(s)] else s.each_line.map(&:strip).reject(&:empty?).map { |line| JSON.parse(line) } end end |
#read_input(opts, argv) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
111 112 113 114 115 116 |
# File 'lib/mailmate/cli/verify.rb', line 111 def read_input(opts, argv) return File.read(opts[:file]) if opts[:file] return argv.join("\n") unless argv.empty? return nil if $stdin.tty? $stdin.read end |
#run(argv) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/mailmate/cli/verify.rb', line 25 def run(argv) opts = { check_timeout: 8.0, poll: 0.25, pretty: true, file: nil } parser = build_parser(opts) parser.parse!(argv) raw = read_input(opts, argv) return usage_error(parser, "no ticket input (pass a file, JSON arg, or pipe on stdin)") if raw.nil? || raw.strip.empty? tickets = begin parse_tickets(raw) rescue JSON::ParserError => e warn "mm-verify: could not parse tickets as JSON array or NDJSON: #{e.}" return 2 end return usage_error(parser, "no tickets found in input") if tickets.empty? summary = verify(tickets, timeout: opts[:check_timeout], poll: opts[:poll]) $stdout.puts(opts[:pretty] ? JSON.pretty_generate(summary) : JSON.generate(summary)) summary["failed"].zero? ? 0 : 3 end |
#usage_error(parser, msg) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
139 140 141 142 143 |
# File 'lib/mailmate/cli/verify.rb', line 139 def usage_error(parser, msg) warn "mm-verify: #{msg}" warn parser.help 2 end |
#verify(tickets, timeout:, poll:) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Poll the #flags index until every ticket’s expectations hold or the timeout elapses; one index read per poll iteration covers the whole batch. Returns the summary Hash.
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/mailmate/cli/verify.rb', line 50 def verify(tickets, timeout:, poll:) deadline = Time.now + timeout started = Time.now results = nil loop do results = check_all(tickets) break if results.all? { |r| r["ok"] } break if Time.now >= deadline sleep(poll) end passed = results.count { |r| r["ok"] } { "checked" => results.size, "passed" => passed, "failed" => results.size - passed, "waited_seconds" => (Time.now - started).round(2), "results" => results, } end |