textus 0.15.0 → 0.18.0

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 (120) hide show
  1. checksums.yaml +4 -4
  2. data/ARCHITECTURE.md +14 -14
  3. data/CHANGELOG.md +313 -0
  4. data/README.md +13 -9
  5. data/SPEC.md +13 -10
  6. data/docs/conventions.md +2 -2
  7. data/lib/textus/application/context.rb +24 -0
  8. data/lib/textus/application/reads/audit.rb +1 -1
  9. data/lib/textus/application/reads/blame.rb +3 -1
  10. data/lib/textus/application/reads/deps.rb +1 -1
  11. data/lib/textus/application/reads/freshness.rb +12 -3
  12. data/lib/textus/application/reads/get.rb +32 -8
  13. data/lib/textus/application/reads/get_or_refresh.rb +5 -5
  14. data/lib/textus/application/reads/list.rb +3 -1
  15. data/lib/textus/application/reads/published.rb +1 -1
  16. data/lib/textus/application/reads/rdeps.rb +1 -1
  17. data/lib/textus/application/reads/schema_envelope.rb +3 -1
  18. data/lib/textus/application/reads/stale.rb +1 -1
  19. data/lib/textus/application/reads/uid.rb +1 -1
  20. data/lib/textus/application/reads/validate_all.rb +6 -1
  21. data/lib/textus/application/reads/validator.rb +84 -0
  22. data/lib/textus/application/reads/where.rb +4 -1
  23. data/lib/textus/application/refresh/all.rb +8 -1
  24. data/lib/textus/application/refresh/orchestrator.rb +2 -3
  25. data/lib/textus/application/refresh/worker.rb +18 -15
  26. data/lib/textus/application/writes/accept.rb +12 -12
  27. data/lib/textus/application/writes/build.rb +3 -4
  28. data/lib/textus/application/writes/delete.rb +10 -15
  29. data/lib/textus/application/writes/envelope_io.rb +106 -0
  30. data/lib/textus/application/writes/mv.rb +25 -27
  31. data/lib/textus/application/writes/publish.rb +8 -9
  32. data/lib/textus/application/writes/put.rb +12 -16
  33. data/lib/textus/application/writes/reject.rb +10 -10
  34. data/lib/textus/builder/pipeline.rb +2 -2
  35. data/lib/textus/cli/group/hook.rb +1 -3
  36. data/lib/textus/cli/group/key.rb +1 -4
  37. data/lib/textus/cli/group/refresh.rb +1 -2
  38. data/lib/textus/cli/group/rule.rb +1 -3
  39. data/lib/textus/cli/group/schema.rb +1 -5
  40. data/lib/textus/cli/group.rb +12 -16
  41. data/lib/textus/cli/verb/accept.rb +3 -1
  42. data/lib/textus/cli/verb/audit.rb +3 -1
  43. data/lib/textus/cli/verb/blame.rb +3 -1
  44. data/lib/textus/cli/verb/build.rb +4 -2
  45. data/lib/textus/cli/verb/delete.rb +3 -1
  46. data/lib/textus/cli/verb/deps.rb +3 -1
  47. data/lib/textus/cli/verb/doctor.rb +2 -0
  48. data/lib/textus/cli/verb/freshness.rb +3 -1
  49. data/lib/textus/cli/verb/get.rb +3 -1
  50. data/lib/textus/cli/verb/hook_run.rb +3 -0
  51. data/lib/textus/cli/verb/hooks.rb +3 -0
  52. data/lib/textus/cli/verb/init.rb +2 -0
  53. data/lib/textus/cli/verb/intro.rb +2 -0
  54. data/lib/textus/cli/verb/key_normalize.rb +3 -0
  55. data/lib/textus/cli/verb/list.rb +3 -1
  56. data/lib/textus/cli/verb/mv.rb +4 -1
  57. data/lib/textus/cli/verb/published.rb +3 -1
  58. data/lib/textus/cli/verb/put.rb +3 -1
  59. data/lib/textus/cli/verb/rdeps.rb +3 -1
  60. data/lib/textus/cli/verb/refresh.rb +1 -1
  61. data/lib/textus/cli/verb/refresh_stale.rb +3 -0
  62. data/lib/textus/cli/verb/reject.rb +3 -1
  63. data/lib/textus/cli/verb/rule_explain.rb +4 -1
  64. data/lib/textus/cli/verb/rule_list.rb +3 -0
  65. data/lib/textus/cli/verb/schema.rb +4 -1
  66. data/lib/textus/cli/verb/schema_diff.rb +3 -0
  67. data/lib/textus/cli/verb/schema_init.rb +3 -0
  68. data/lib/textus/cli/verb/schema_migrate.rb +3 -0
  69. data/lib/textus/cli/verb/uid.rb +4 -1
  70. data/lib/textus/cli/verb/where.rb +3 -1
  71. data/lib/textus/cli/verb.rb +30 -0
  72. data/lib/textus/cli.rb +18 -27
  73. data/lib/textus/doctor/check/audit_log.rb +1 -1
  74. data/lib/textus/doctor/check/hooks.rb +3 -1
  75. data/lib/textus/doctor/check/intake_registration.rb +3 -3
  76. data/lib/textus/doctor/check/schema_violations.rb +1 -1
  77. data/lib/textus/doctor/check/sentinels.rb +2 -2
  78. data/lib/textus/domain/freshness/evaluator.rb +1 -1
  79. data/lib/textus/domain/freshness/policy.rb +1 -1
  80. data/lib/textus/domain/freshness/verdict.rb +1 -1
  81. data/lib/textus/domain/freshness.rb +40 -0
  82. data/lib/textus/domain/policy/predicates/schema_valid.rb +2 -2
  83. data/lib/textus/{store → domain}/sentinel.rb +1 -1
  84. data/lib/textus/{store → domain}/staleness/generator_check.rb +1 -1
  85. data/lib/textus/{store → domain}/staleness/intake_check.rb +1 -1
  86. data/lib/textus/{store → domain}/staleness.rb +1 -1
  87. data/lib/textus/entry/json.rb +1 -1
  88. data/lib/textus/entry/markdown.rb +1 -1
  89. data/lib/textus/entry/yaml.rb +1 -1
  90. data/lib/textus/envelope.rb +7 -3
  91. data/lib/textus/errors.rb +19 -0
  92. data/lib/textus/hooks/builtin.rb +6 -6
  93. data/lib/textus/hooks/dispatcher.rb +17 -9
  94. data/lib/textus/hooks/loader.rb +20 -17
  95. data/lib/textus/hooks/registry.rb +4 -0
  96. data/lib/textus/{store → infra}/audit_log.rb +1 -1
  97. data/lib/textus/infra/audit_subscriber.rb +43 -0
  98. data/lib/textus/infra/publisher.rb +3 -3
  99. data/lib/textus/infra/storage/file_store.rb +26 -0
  100. data/lib/textus/init.rb +11 -9
  101. data/lib/textus/manifest/resolution.rb +5 -0
  102. data/lib/textus/manifest.rb +4 -3
  103. data/lib/textus/migrate_keys.rb +1 -1
  104. data/lib/textus/operations.rb +83 -16
  105. data/lib/textus/projection.rb +2 -2
  106. data/lib/textus/refresh.rb +1 -1
  107. data/lib/textus/schema/tools.rb +5 -5
  108. data/lib/textus/schemas.rb +46 -0
  109. data/lib/textus/store.rb +12 -49
  110. data/lib/textus/uid.rb +18 -0
  111. data/lib/textus/version.rb +1 -1
  112. data/lib/textus.rb +17 -1
  113. metadata +14 -13
  114. data/lib/textus/hooks/dsl.rb +0 -11
  115. data/lib/textus/operations/reads.rb +0 -56
  116. data/lib/textus/operations/refresh.rb +0 -27
  117. data/lib/textus/operations/writes.rb +0 -21
  118. data/lib/textus/store/reader.rb +0 -69
  119. data/lib/textus/store/validator.rb +0 -82
  120. data/lib/textus/store/writer.rb +0 -102
@@ -9,9 +9,9 @@ module Textus
9
9
  :new_mentry, :uid, :etag_before
10
10
  )
11
11
 
12
- def initialize(ctx:, bus:)
12
+ def initialize(ctx:, envelope_io:)
13
13
  @ctx = ctx
14
- @bus = bus
14
+ @envelope_io = envelope_io
15
15
  end
16
16
 
17
17
  def call(old_key, new_key, dry_run: false)
@@ -26,23 +26,28 @@ module Textus
26
26
 
27
27
  private
28
28
 
29
- def manifest = @ctx.store.manifest
30
- def reader = @ctx.store.reader
29
+ def manifest = @ctx.manifest
30
+ def reader_get(key) = (@reader_get ||= Textus::Application::Reads::Get.new(ctx: @ctx)).call(key)
31
31
 
32
32
  def prepare_plan(old_key, new_key)
33
33
  manifest.validate_key!(old_key)
34
34
  manifest.validate_key!(new_key)
35
35
  raise UsageError.new("mv: old and new keys are identical") if old_key == new_key
36
36
 
37
- old_mentry, old_path, = manifest.resolve(old_key)
38
- raise UnknownKey.new(old_key) unless File.exist?(old_path)
37
+ old_res = manifest.resolve(old_key)
38
+ old_mentry = old_res.entry
39
+ old_path = old_res.path
40
+ raise UnknownKey.new(old_key) unless @ctx.file_store.exists?(old_path)
39
41
 
40
- new_mentry, new_path, = manifest.resolve(new_key)
42
+ new_res = manifest.resolve(new_key)
43
+ new_mentry = new_res.entry
44
+ new_path = new_res.path
41
45
  validate_zone_and_format!(old_mentry, new_mentry)
42
- validate_writer!(old_mentry, old_key)
43
- raise UsageError.new("mv: target '#{new_key}' already exists at #{new_path}") if File.exist?(new_path)
46
+ @ctx.authorize_write!(old_mentry)
47
+ @ctx.authorize_write!(new_mentry)
48
+ raise UsageError.new("mv: target '#{new_key}' already exists at #{new_path}") if @ctx.file_store.exists?(new_path)
44
49
 
45
- pre_env = reader.get(old_key)
50
+ pre_env = reader_get(old_key)
46
51
  plan = MovePlan.new(
47
52
  old_key: old_key, new_key: new_key,
48
53
  old_path: old_path, new_path: new_path,
@@ -64,17 +69,10 @@ module Textus
64
69
  raise UsageError.new("mv: format mismatch (#{old_mentry.format} → #{new_mentry.format}); refusing.")
65
70
  end
66
71
 
67
- def validate_writer!(mentry, key)
68
- writers = manifest.zone_writers(mentry.zone)
69
- return if writers.include?(@ctx.role)
70
-
71
- raise WriteForbidden.new(key, mentry.zone, writers: writers)
72
- end
73
-
74
72
  def ensure_uid!(plan, pre_env:)
75
73
  return plan if plan.uid
76
74
 
77
- env = Textus::Application::Writes::Put.new(ctx: @ctx, bus: @bus).call(
75
+ env = Textus::Application::Writes::Put.new(ctx: @ctx, envelope_io: @envelope_io).call(
78
76
  plan.old_key,
79
77
  meta: pre_env.meta,
80
78
  body: pre_env.body,
@@ -99,19 +97,19 @@ module Textus
99
97
  }
100
98
  extras["correlation_id"] = @ctx.correlation_id if @ctx.correlation_id
101
99
 
102
- @ctx.store.audit_log.append(
100
+ @ctx.audit_log.append(
103
101
  role: @ctx.role, verb: "mv", key: plan.new_key,
104
102
  etag_before: plan.etag_before, etag_after: etag_after,
105
103
  extras: extras
106
104
  )
107
- new_envelope = reader.get(plan.new_key)
108
- @bus.publish(:entry_renamed,
109
- store: @ctx.with_role(@ctx.role),
110
- key: plan.new_key,
111
- from_key: plan.old_key,
112
- to_key: plan.new_key,
113
- envelope: new_envelope,
114
- correlation_id: @ctx.correlation_id)
105
+ new_envelope = reader_get(plan.new_key)
106
+ @ctx.bus.publish(:entry_renamed,
107
+ store: @ctx.with_role(@ctx.role),
108
+ key: plan.new_key,
109
+ from_key: plan.old_key,
110
+ to_key: plan.new_key,
111
+ envelope: new_envelope,
112
+ correlation_id: @ctx.correlation_id)
115
113
  new_envelope
116
114
  end
117
115
 
@@ -5,9 +5,8 @@ module Textus
5
5
  # `:file_published` for each copy. Mirror of `Build` for the publish
6
6
  # half — split out from the old Build per ADR 0007.
7
7
  class Publish
8
- def initialize(ctx:, bus:)
8
+ def initialize(ctx:)
9
9
  @ctx = ctx
10
- @bus = bus
11
10
  end
12
11
 
13
12
  def call(prefix: nil)
@@ -42,13 +41,13 @@ module Textus
42
41
  end
43
42
 
44
43
  Textus::Infra::Publisher.publish(source: row[:path], target: target_abs, store_root: store.root)
45
- @bus.publish(:file_published,
46
- store: @ctx.with_role(@ctx.role),
47
- key: row[:key],
48
- envelope: store.reader.get(row[:key]),
49
- source: row[:path],
50
- target: target_abs,
51
- correlation_id: @ctx.correlation_id)
44
+ @ctx.bus.publish(:file_published,
45
+ store: @ctx.with_role(@ctx.role),
46
+ key: row[:key],
47
+ envelope: Textus::Application::Reads::Get.new(ctx: @ctx).call(row[:key]),
48
+ source: row[:path],
49
+ target: target_abs,
50
+ correlation_id: @ctx.correlation_id)
52
51
  { "key" => row[:key], "source" => row[:path], "target" => target_abs }
53
52
  end
54
53
  end
@@ -2,34 +2,30 @@ module Textus
2
2
  module Application
3
3
  module Writes
4
4
  class Put
5
- def initialize(ctx:, bus:)
5
+ def initialize(ctx:, envelope_io:)
6
6
  @ctx = ctx
7
- @bus = bus
7
+ @envelope_io = envelope_io
8
8
  end
9
9
 
10
10
  def call(key, meta: nil, body: nil, content: nil, if_etag: nil, suppress_events: false)
11
- @ctx.store.manifest.validate_key!(key)
12
- mentry, = @ctx.store.manifest.resolve(key)
11
+ @ctx.manifest.validate_key!(key)
12
+ mentry = @ctx.manifest.resolve(key).entry
13
13
 
14
- unless @ctx.can_write?(mentry.zone)
15
- raise WriteForbidden.new(key, mentry.zone,
16
- writers: @ctx.store.manifest.zone_writers(mentry.zone))
17
- end
14
+ @ctx.authorize_write!(mentry)
18
15
 
19
- envelope = @ctx.store.writer.write_envelope_to_disk(
16
+ envelope = @envelope_io.write(
20
17
  key,
21
18
  mentry: mentry,
22
- payload: Textus::Store::Writer::Payload.new(meta: meta, body: body, content: content),
23
- ctx: @ctx,
19
+ payload: Textus::Application::Writes::EnvelopeIO::Payload.new(meta: meta, body: body, content: content),
24
20
  if_etag: if_etag,
25
21
  )
26
22
 
27
23
  unless suppress_events
28
- @bus.publish(:entry_put,
29
- store: @ctx.with_role(@ctx.role),
30
- key: key,
31
- envelope: envelope,
32
- correlation_id: @ctx.correlation_id)
24
+ @ctx.bus.publish(:entry_put,
25
+ store: @ctx.with_role(@ctx.role),
26
+ key: key,
27
+ envelope: envelope,
28
+ correlation_id: @ctx.correlation_id)
33
29
  end
34
30
 
35
31
  envelope
@@ -2,32 +2,32 @@ module Textus
2
2
  module Application
3
3
  module Writes
4
4
  class Reject
5
- def initialize(ctx:, bus:)
5
+ def initialize(ctx:, envelope_io:)
6
6
  @ctx = ctx
7
- @bus = bus
7
+ @envelope_io = envelope_io
8
8
  end
9
9
 
10
10
  def call(pending_key)
11
11
  raise ProposalError.new("only human role can reject proposals; got '#{@ctx.role}'") unless @ctx.role == "human"
12
12
 
13
- mentry, = @ctx.store.manifest.resolve(pending_key)
13
+ mentry = @ctx.manifest.resolve(pending_key).entry
14
14
  unless mentry.in_proposal_zone?
15
15
  raise ProposalError.new("reject: '#{pending_key}' is not in a proposal zone (zone=#{mentry.zone})")
16
16
  end
17
17
 
18
- env = @ctx.store.reader.get(pending_key)
18
+ env = Textus::Application::Reads::Get.new(ctx: @ctx).call(pending_key)
19
19
  proposal = env.meta&.dig("proposal") or
20
20
  raise ProposalError.new("entry has no proposal block: #{pending_key}")
21
21
  target_key = proposal["target_key"] or
22
22
  raise ProposalError.new("proposal missing target_key")
23
23
 
24
- Textus::Application::Writes::Delete.new(ctx: @ctx, bus: @bus).call(pending_key, suppress_events: true)
24
+ Textus::Application::Writes::Delete.new(ctx: @ctx, envelope_io: @envelope_io).call(pending_key, suppress_events: true)
25
25
 
26
- @bus.publish(:proposal_rejected,
27
- store: @ctx.with_role(@ctx.role),
28
- key: pending_key,
29
- target_key: target_key,
30
- correlation_id: @ctx.correlation_id)
26
+ @ctx.bus.publish(:proposal_rejected,
27
+ store: @ctx.with_role(@ctx.role),
28
+ key: pending_key,
29
+ target_key: target_key,
30
+ correlation_id: @ctx.correlation_id)
31
31
 
32
32
  { "protocol" => PROTOCOL, "rejected" => pending_key, "target_key" => target_key }
33
33
  end
@@ -64,9 +64,9 @@ module Textus
64
64
  if mentry.projection
65
65
  ops = Operations.for(store)
66
66
  Projection.new(
67
- reader: ops.reads.get.method(:call),
67
+ reader: ops.method(:get),
68
68
  spec: mentry.projection,
69
- lister: ops.reads.list.method(:call),
69
+ lister: ops.method(:list),
70
70
  transform_resolver: ->(name) { store.registry.rpc_callable(:transform_rows, name) },
71
71
  transform_context: Application::Context.system(store),
72
72
  ).run
@@ -2,9 +2,7 @@ module Textus
2
2
  class CLI
3
3
  class Group
4
4
  class Hook < Group
5
- self.cli_name = "hook"
6
- subcommands["list"] = Verb::Hooks
7
- subcommands["run"] = Verb::HookRun
5
+ command_name "hook"
8
6
  end
9
7
  end
10
8
  end
@@ -2,10 +2,7 @@ module Textus
2
2
  class CLI
3
3
  class Group
4
4
  class Key < Group
5
- self.cli_name = "key"
6
- subcommands["mv"] = Verb::Mv
7
- subcommands["uid"] = Verb::Uid
8
- subcommands["normalize"] = Verb::KeyNormalize
5
+ command_name "key"
9
6
  end
10
7
  end
11
8
  end
@@ -2,8 +2,7 @@ module Textus
2
2
  class CLI
3
3
  class Group
4
4
  class Refresh < Group
5
- self.cli_name = "refresh"
6
- subcommands["stale"] = Verb::RefreshStale
5
+ command_name "refresh"
7
6
 
8
7
  def parse(argv)
9
8
  if argv.first == "stale"
@@ -2,9 +2,7 @@ module Textus
2
2
  class CLI
3
3
  class Group
4
4
  class Rule < Group
5
- self.cli_name = "rule"
6
- subcommands["list"] = Verb::RuleList
7
- subcommands["explain"] = Verb::RuleExplain
5
+ command_name "rule"
8
6
  end
9
7
  end
10
8
  end
@@ -2,11 +2,7 @@ module Textus
2
2
  class CLI
3
3
  class Group
4
4
  class Schema < Group
5
- self.cli_name = "schema"
6
- subcommands["show"] = Verb::Schema
7
- subcommands["init"] = Verb::SchemaInit
8
- subcommands["diff"] = Verb::SchemaDiff
9
- subcommands["migrate"] = Verb::SchemaMigrate
5
+ command_name "schema"
10
6
  end
11
7
  end
12
8
  end
@@ -2,19 +2,14 @@ module Textus
2
2
  class CLI
3
3
  class Group < Verb
4
4
  class << self
5
+ # Subcommands are auto-derived: any Verb descendant whose
6
+ # `parent_group` is this group counts as a subcommand. Sorted
7
+ # alphabetically by command_name for stable help output.
5
8
  def subcommands
6
- @subcommands ||= {}
7
- end
8
-
9
- def cli_name
10
- @cli_name || raise("subclass must define cli_name")
11
- end
12
-
13
- attr_writer :cli_name
14
-
15
- def inherited(subclass)
16
- super
17
- subclass.instance_variable_set(:@subcommands, {})
9
+ Verb.descendants
10
+ .select { |k| k.parent_group == self && k.command_name }
11
+ .sort_by(&:command_name)
12
+ .to_h { |k| [k.command_name, k] }
18
13
  end
19
14
 
20
15
  def needs_store?
@@ -24,18 +19,19 @@ module Textus
24
19
  end
25
20
 
26
21
  def parse(argv)
22
+ subs = self.class.subcommands
27
23
  subname = argv.shift
28
24
  if subname.nil?
29
25
  raise UsageError.new(
30
- "#{self.class.cli_name} requires a subcommand: #{self.class.subcommands.keys.join(", ")}",
26
+ "#{self.class.command_name} requires a subcommand: #{subs.keys.join(", ")}",
31
27
  )
32
28
  end
33
29
 
34
- @sub_klass = self.class.subcommands[subname]
30
+ @sub_klass = subs[subname]
35
31
  unless @sub_klass
36
32
  raise UsageError.new(
37
- "unknown #{self.class.cli_name} subcommand '#{subname}'. " \
38
- "Valid: #{self.class.subcommands.keys.join(", ")}",
33
+ "unknown #{self.class.command_name} subcommand '#{subname}'. " \
34
+ "Valid: #{subs.keys.join(", ")}",
39
35
  )
40
36
  end
41
37
 
@@ -2,11 +2,13 @@ module Textus
2
2
  class CLI
3
3
  class Verb
4
4
  class Accept < Verb
5
+ command_name "accept"
6
+
5
7
  option :as_flag, "--as=ROLE"
6
8
 
7
9
  def call(store)
8
10
  key = positional.shift or raise UsageError.new("accept requires a key")
9
- emit(operations_for(store).writes.accept.call(key))
11
+ emit(operations_for(store).accept(key))
10
12
  end
11
13
  end
12
14
  end
@@ -2,6 +2,8 @@ module Textus
2
2
  class CLI
3
3
  class Verb
4
4
  class Audit < Verb
5
+ command_name "audit"
6
+
5
7
  option :key_filter, "--key=KEY"
6
8
  option :zone, "--zone=Z"
7
9
  option :role_filter, "--role=ROLE"
@@ -13,7 +15,7 @@ module Textus
13
15
  def call(store)
14
16
  ops = operations_for(store)
15
17
  since_time = since && Textus::Application::Reads::Audit.parse_since(since, now: ops.ctx.now)
16
- rows = ops.reads.audit.call(
18
+ rows = ops.audit(
17
19
  key: key_filter,
18
20
  zone: zone,
19
21
  role: role_filter,
@@ -2,11 +2,13 @@ module Textus
2
2
  class CLI
3
3
  class Verb
4
4
  class Blame < Verb
5
+ command_name "blame"
6
+
5
7
  option :limit, "--limit=N"
6
8
 
7
9
  def call(store)
8
10
  key = positional.shift or raise UsageError.new("blame requires a key")
9
- rows = operations_for(store).reads.blame.call(key: key, limit: limit&.to_i)
11
+ rows = operations_for(store).blame(key: key, limit: limit&.to_i)
10
12
  emit({ "verb" => "blame", "key" => key, "rows" => rows })
11
13
  end
12
14
  end
@@ -2,13 +2,15 @@ module Textus
2
2
  class CLI
3
3
  class Verb
4
4
  class Build < Verb
5
+ command_name "build"
6
+
5
7
  option :prefix, "--prefix=K"
6
8
 
7
9
  def call(store)
8
10
  Textus::Infra::BuildLock.with(root: store.root) do
9
11
  ops = Textus::Operations.for(store, role: "builder")
10
- build_res = ops.writes.build.call(prefix: prefix)
11
- publish_res = ops.writes.publish.call(prefix: prefix)
12
+ build_res = ops.build(prefix: prefix)
13
+ publish_res = ops.publish(prefix: prefix)
12
14
  emit({ "protocol" => Textus::PROTOCOL,
13
15
  "built" => build_res["built"],
14
16
  "published_leaves" => publish_res["published_leaves"] })
@@ -2,12 +2,14 @@ module Textus
2
2
  class CLI
3
3
  class Verb
4
4
  class Delete < Verb
5
+ command_name "delete"
6
+
5
7
  option :as_flag, "--as=ROLE"
6
8
  option :if_etag, "--if-etag=E"
7
9
 
8
10
  def call(store)
9
11
  key = positional.shift or raise UsageError.new("delete requires a key")
10
- emit(operations_for(store).writes.delete.call(key, if_etag: if_etag))
12
+ emit(operations_for(store).delete(key, if_etag: if_etag))
11
13
  end
12
14
  end
13
15
  end
@@ -2,9 +2,11 @@ module Textus
2
2
  class CLI
3
3
  class Verb
4
4
  class Deps < Verb
5
+ command_name "deps"
6
+
5
7
  def call(store)
6
8
  key = positional.shift or raise UsageError.new("deps requires a key")
7
- emit({ "key" => key, "deps" => operations_for(store).reads.deps.call(key) })
9
+ emit({ "key" => key, "deps" => operations_for(store).deps(key) })
8
10
  end
9
11
  end
10
12
  end
@@ -2,6 +2,8 @@ module Textus
2
2
  class CLI
3
3
  class Verb
4
4
  class Doctor < Verb
5
+ command_name "doctor"
6
+
5
7
  option :checks, "--check=NAME"
6
8
 
7
9
  def call(store)
@@ -2,11 +2,13 @@ module Textus
2
2
  class CLI
3
3
  class Verb
4
4
  class Freshness < Verb
5
+ command_name "freshness"
6
+
5
7
  option :prefix, "--prefix=KEY"
6
8
  option :zone, "--zone=Z"
7
9
 
8
10
  def call(store)
9
- rows = operations_for(store).reads.freshness.call(prefix: prefix, zone: zone)
11
+ rows = operations_for(store).freshness(prefix: prefix, zone: zone)
10
12
  emit({ "verb" => "freshness", "rows" => rows })
11
13
  end
12
14
  end
@@ -2,11 +2,13 @@ module Textus
2
2
  class CLI
3
3
  class Verb
4
4
  class Get < Verb
5
+ command_name "get"
6
+
5
7
  option :as_flag, "--as=ROLE"
6
8
 
7
9
  def call(store)
8
10
  key = positional.shift or raise UsageError.new("get requires a key")
9
- result = operations_for(store).reads.get_or_refresh.call(key)
11
+ result = operations_for(store).get_or_refresh(key)
10
12
  raise Textus::UnknownKey.new(key, suggestions: store.manifest.suggestions_for(key)) if result.nil?
11
13
 
12
14
  emit(result.to_h_for_wire)
@@ -2,6 +2,9 @@ module Textus
2
2
  class CLI
3
3
  class Verb
4
4
  class HookRun < Verb
5
+ command_name "run"
6
+ parent_group Group::Hook
7
+
5
8
  def parse(argv)
6
9
  @raw_argv = argv
7
10
  end
@@ -2,6 +2,9 @@ module Textus
2
2
  class CLI
3
3
  class Verb
4
4
  class Hooks < Verb
5
+ command_name "list"
6
+ parent_group Group::Hook
7
+
5
8
  option :event_filter, "--event=E"
6
9
 
7
10
  def call(store) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
@@ -2,6 +2,8 @@ module Textus
2
2
  class CLI
3
3
  class Verb
4
4
  class Init < Verb
5
+ command_name "init"
6
+
5
7
  def self.needs_store? = false
6
8
 
7
9
  def call(_store)
@@ -2,6 +2,8 @@ module Textus
2
2
  class CLI
3
3
  class Verb
4
4
  class Intro < Verb
5
+ command_name "intro"
6
+
5
7
  def call(store)
6
8
  emit(Textus::Intro.run(store))
7
9
  end
@@ -2,6 +2,9 @@ module Textus
2
2
  class CLI
3
3
  class Verb
4
4
  class KeyNormalize < Verb
5
+ command_name "normalize"
6
+ parent_group Group::Key
7
+
5
8
  option :write, "--write"
6
9
  option :dry_run, "--dry-run"
7
10
 
@@ -2,11 +2,13 @@ module Textus
2
2
  class CLI
3
3
  class Verb
4
4
  class List < Verb
5
+ command_name "list"
6
+
5
7
  option :prefix, "--prefix=KEY"
6
8
  option :zone, "--zone=Z"
7
9
 
8
10
  def call(store)
9
- emit({ "entries" => operations_for(store).reads.list.call(prefix: prefix, zone: zone) })
11
+ emit({ "entries" => operations_for(store).list(prefix: prefix, zone: zone) })
10
12
  end
11
13
  end
12
14
  end
@@ -2,13 +2,16 @@ module Textus
2
2
  class CLI
3
3
  class Verb
4
4
  class Mv < Verb
5
+ command_name "mv"
6
+ parent_group Group::Key
7
+
5
8
  option :as_flag, "--as=ROLE"
6
9
  option :dry_run, "--dry-run"
7
10
 
8
11
  def call(store)
9
12
  old_key = positional.shift or raise UsageError.new("mv requires <old-key> <new-key>")
10
13
  new_key = positional.shift or raise UsageError.new("mv requires <old-key> <new-key>")
11
- emit(operations_for(store).writes.mv.call(old_key, new_key, dry_run: dry_run || false))
14
+ emit(operations_for(store).mv(old_key, new_key, dry_run: dry_run || false))
12
15
  end
13
16
  end
14
17
  end
@@ -2,8 +2,10 @@ module Textus
2
2
  class CLI
3
3
  class Verb
4
4
  class Published < Verb
5
+ command_name "published"
6
+
5
7
  def call(store)
6
- emit({ "published" => operations_for(store).reads.published.call })
8
+ emit({ "published" => operations_for(store).published })
7
9
  end
8
10
  end
9
11
  end
@@ -2,6 +2,8 @@ module Textus
2
2
  class CLI
3
3
  class Verb
4
4
  class Put < Verb
5
+ command_name "put"
6
+
5
7
  option :as_flag, "--as=ROLE"
6
8
  option :use_stdin, "--stdin"
7
9
  option :fetch_name, "--fetch=NAME"
@@ -43,7 +45,7 @@ module Textus
43
45
  meta = payload["_meta"] || {}
44
46
  body = payload["body"] || ""
45
47
  if_etag = payload["if_etag"]
46
- result = Textus::Operations.for(store, role: role).writes.put.call(key, meta: meta, body: body, if_etag: if_etag)
48
+ result = Textus::Operations.for(store, role: role).put(key, meta: meta, body: body, if_etag: if_etag)
47
49
  emit(result.to_h_for_wire)
48
50
  end
49
51
  end
@@ -2,9 +2,11 @@ module Textus
2
2
  class CLI
3
3
  class Verb
4
4
  class Rdeps < Verb
5
+ command_name "rdeps"
6
+
5
7
  def call(store)
6
8
  key = positional.shift or raise UsageError.new("rdeps requires a key")
7
- emit({ "key" => key, "rdeps" => operations_for(store).reads.rdeps.call(key) })
9
+ emit({ "key" => key, "rdeps" => operations_for(store).rdeps(key) })
8
10
  end
9
11
  end
10
12
  end
@@ -6,7 +6,7 @@ module Textus
6
6
 
7
7
  def call(store)
8
8
  key = positional.shift or raise UsageError.new("refresh requires a key")
9
- emit(operations_for(store).refresh.worker.run(key).to_h_for_wire)
9
+ emit(operations_for(store).refresh(key).to_h_for_wire)
10
10
  end
11
11
  end
12
12
  end
@@ -2,6 +2,9 @@ module Textus
2
2
  class CLI
3
3
  class Verb
4
4
  class RefreshStale < Verb
5
+ command_name "stale"
6
+ parent_group Group::Refresh
7
+
5
8
  option :prefix, "--prefix=KEY"
6
9
  option :zone, "--zone=Z"
7
10
  option :as_flag, "--as=ROLE"