textus 0.8.1 → 0.10.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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +329 -0
  3. data/README.md +50 -22
  4. data/SPEC.md +194 -63
  5. data/docs/architecture.md +22 -4
  6. data/docs/conventions.md +24 -17
  7. data/lib/textus/application/context.rb +44 -0
  8. data/lib/textus/application/reads/audit.rb +69 -0
  9. data/lib/textus/application/reads/blame.rb +79 -0
  10. data/lib/textus/application/reads/freshness.rb +77 -0
  11. data/lib/textus/application/reads/get.rb +62 -0
  12. data/lib/textus/application/reads/policy_explain.rb +39 -0
  13. data/lib/textus/application/refresh/all.rb +41 -0
  14. data/lib/textus/application/refresh/orchestrator.rb +69 -0
  15. data/lib/textus/application/refresh/worker.rb +79 -0
  16. data/lib/textus/application/writes/accept.rb +44 -0
  17. data/lib/textus/application/writes/build.rb +116 -0
  18. data/lib/textus/application/writes/delete.rb +36 -0
  19. data/lib/textus/application/writes/publish.rb +25 -0
  20. data/lib/textus/application/writes/put.rb +43 -0
  21. data/lib/textus/builder/pipeline.rb +1 -1
  22. data/lib/textus/builder/renderer/json.rb +1 -1
  23. data/lib/textus/builder/renderer/markdown.rb +1 -1
  24. data/lib/textus/builder/renderer/text.rb +1 -1
  25. data/lib/textus/builder/renderer/yaml.rb +1 -1
  26. data/lib/textus/builder/renderer.rb +1 -1
  27. data/lib/textus/cli/group/policy.rb +11 -0
  28. data/lib/textus/cli/verb/accept.rb +2 -2
  29. data/lib/textus/cli/verb/audit.rb +30 -0
  30. data/lib/textus/cli/verb/blame.rb +16 -0
  31. data/lib/textus/cli/verb/build.rb +2 -1
  32. data/lib/textus/cli/verb/delete.rb +2 -2
  33. data/lib/textus/cli/verb/freshness.rb +16 -0
  34. data/lib/textus/cli/verb/get.rb +7 -1
  35. data/lib/textus/cli/verb/hook_run.rb +4 -4
  36. data/lib/textus/cli/verb/mv.rb +1 -2
  37. data/lib/textus/cli/verb/policy_explain.rb +14 -0
  38. data/lib/textus/cli/verb/policy_list.rb +25 -0
  39. data/lib/textus/cli/verb/put.rb +10 -8
  40. data/lib/textus/cli/verb/refresh.rb +2 -2
  41. data/lib/textus/cli/verb/refresh_stale.rb +18 -0
  42. data/lib/textus/cli/verb/reject.rb +14 -0
  43. data/lib/textus/cli/verb.rb +14 -0
  44. data/lib/textus/cli.rb +16 -2
  45. data/lib/textus/composition.rb +72 -0
  46. data/lib/textus/doctor/check/handler_allowlist.rb +33 -0
  47. data/lib/textus/doctor/check/intake_registration.rb +46 -0
  48. data/lib/textus/doctor/check/legacy_intake_fields.rb +57 -0
  49. data/lib/textus/doctor/check/policy_ambiguity.rb +49 -0
  50. data/lib/textus/doctor.rb +7 -1
  51. data/lib/textus/domain/action.rb +9 -0
  52. data/lib/textus/domain/freshness/evaluator.rb +30 -0
  53. data/lib/textus/domain/freshness/policy.rb +18 -0
  54. data/lib/textus/domain/freshness/verdict.rb +12 -0
  55. data/lib/textus/domain/outcome.rb +10 -0
  56. data/lib/textus/domain/permission.rb +15 -0
  57. data/lib/textus/domain/policy/handler_allowlist.rb +17 -0
  58. data/lib/textus/domain/policy/matcher.rb +51 -0
  59. data/lib/textus/domain/policy/promote.rb +24 -0
  60. data/lib/textus/domain/policy/refresh.rb +48 -0
  61. data/lib/textus/domain/policy.rb +7 -0
  62. data/lib/textus/hooks/builtin.rb +5 -5
  63. data/lib/textus/hooks/dispatcher.rb +15 -1
  64. data/lib/textus/hooks/dsl.rb +18 -0
  65. data/lib/textus/hooks/registry.rb +12 -5
  66. data/lib/textus/infra/clock.rb +9 -0
  67. data/lib/textus/infra/event_bus.rb +27 -0
  68. data/lib/textus/infra/publisher.rb +73 -0
  69. data/lib/textus/infra/refresh/detached.rb +38 -0
  70. data/lib/textus/infra/refresh/lock.rb +44 -0
  71. data/lib/textus/init.rb +71 -28
  72. data/lib/textus/intro.rb +17 -14
  73. data/lib/textus/manifest/entry.rb +39 -13
  74. data/lib/textus/manifest/policies.rb +83 -0
  75. data/lib/textus/manifest.rb +30 -11
  76. data/lib/textus/projection.rb +1 -1
  77. data/lib/textus/proposal.rb +4 -21
  78. data/lib/textus/refresh.rb +9 -45
  79. data/lib/textus/store/mover.rb +14 -9
  80. data/lib/textus/store/reader.rb +10 -8
  81. data/lib/textus/store/staleness.rb +5 -17
  82. data/lib/textus/store/validator.rb +46 -20
  83. data/lib/textus/store/writer.rb +51 -14
  84. data/lib/textus/store.rb +30 -10
  85. data/lib/textus/version.rb +1 -1
  86. data/lib/textus.rb +1 -0
  87. metadata +46 -5
  88. data/lib/textus/builder.rb +0 -86
  89. data/lib/textus/cli/verb/stale.rb +0 -14
  90. data/lib/textus/publisher.rb +0 -71
  91. data/lib/textus/store/view.rb +0 -29
@@ -1,71 +0,0 @@
1
- require "json"
2
- require "digest"
3
- require "fileutils"
4
-
5
- module Textus
6
- # Publishes built artifacts from the store to repo-relative consumer paths.
7
- # Publish = copy + sentinel. The in-store file is already the consumer-shaped
8
- # artifact; no parsing or stripping. Sentinels live under
9
- # `<store_root>/sentinels/` and mirror the target's repo-relative layout so
10
- # consumer directories aren't polluted with `.textus-managed.json` siblings.
11
- module Publisher
12
- SENTINEL_SUFFIX = ".textus-managed.json".freeze
13
- SENTINEL_DIR = "sentinels".freeze
14
-
15
- def self.publish(source:, target:, store_root:)
16
- FileUtils.mkdir_p(File.dirname(target))
17
- refuse_if_unmanaged(target, store_root)
18
- File.delete(target) if File.symlink?(target)
19
- FileUtils.cp(source, target)
20
- write_sentinel(target, store_root: store_root, source: source)
21
- cleanup_legacy_sentinel(target)
22
- end
23
-
24
- def self.refuse_if_unmanaged(target, store_root)
25
- return unless File.exist?(target) || File.symlink?(target)
26
- return if managed?(target, store_root)
27
-
28
- raise PublishError.new("refusing to clobber unmanaged file at #{target}", target: target)
29
- end
30
-
31
- def self.managed?(target, store_root)
32
- File.exist?(sentinel_path(target, store_root)) || File.exist?(legacy_sentinel_path(target))
33
- end
34
-
35
- def self.write_sentinel(target, store_root:, source:)
36
- path = sentinel_path(target, store_root)
37
- FileUtils.mkdir_p(File.dirname(path))
38
- File.write(path, JSON.generate(
39
- "source" => source,
40
- "target" => target,
41
- "sha256" => Digest::SHA256.hexdigest(File.binread(target)),
42
- "mode" => "copy",
43
- ))
44
- end
45
-
46
- # Sentinel layout: <store_root>/sentinels/<target_rel_to_repo>.textus-managed.json
47
- # The full target extension is preserved so a marketplace.json and
48
- # marketplace.yaml don't collide.
49
- def self.sentinel_path(target, store_root)
50
- repo_root = File.dirname(store_root)
51
- rel = relative_to(target, repo_root) || File.basename(target)
52
- File.join(store_root, SENTINEL_DIR, rel + SENTINEL_SUFFIX)
53
- end
54
-
55
- def self.legacy_sentinel_path(target)
56
- target + SENTINEL_SUFFIX
57
- end
58
-
59
- def self.cleanup_legacy_sentinel(target)
60
- FileUtils.rm_f(legacy_sentinel_path(target))
61
- end
62
-
63
- def self.relative_to(path, base)
64
- path = File.expand_path(path)
65
- base = File.expand_path(base)
66
- return nil unless path.start_with?(base + File::SEPARATOR)
67
-
68
- path[(base.length + 1)..]
69
- end
70
- end
71
- end
@@ -1,29 +0,0 @@
1
- module Textus
2
- class Store
3
- class View
4
- READ_METHODS = %i[get list where schema_envelope deps rdeps published stale validate_all].freeze
5
- WRITE_METHODS = %i[put delete accept].freeze
6
-
7
- def initialize(store, writable: false, as: nil)
8
- raise UsageError.new("writable Store::View requires an as: role") if writable && (as.nil? || as.to_s.empty?)
9
-
10
- @store = store
11
- @writable = writable
12
- @as = as
13
- end
14
-
15
- READ_METHODS.each do |m|
16
- define_method(m) { |*args, **kw| @store.reader.public_send(m, *args, **kw) }
17
- end
18
-
19
- WRITE_METHODS.each do |m|
20
- define_method(m) do |*args, **kw|
21
- raise UsageError.new("Store::View is read-only") unless @writable
22
-
23
- kw[:as] = @as unless kw.key?(:as)
24
- @store.public_send(m, *args, **kw)
25
- end
26
- end
27
- end
28
- end
29
- end