textus 0.20.2 → 0.22.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +92 -0
- data/README.md +7 -4
- data/SPEC.md +42 -3
- data/lib/textus/application/reads/audit.rb +40 -15
- data/lib/textus/application/reads/pulse.rb +63 -0
- data/lib/textus/application/writes/materializer.rb +1 -1
- data/lib/textus/application/writes/publish.rb +25 -106
- data/lib/textus/{intro.rb → boot.rb} +27 -5
- data/lib/textus/builder/pipeline.rb +2 -2
- data/lib/textus/cli/verb/audit.rb +2 -0
- data/lib/textus/cli/verb/{intro.rb → boot.rb} +3 -3
- data/lib/textus/cli/verb/pulse.rb +17 -0
- data/lib/textus/cli.rb +1 -1
- data/lib/textus/errors.rb +16 -0
- data/lib/textus/infra/audit_log.rb +126 -16
- data/lib/textus/manifest/entry/base.rb +41 -4
- data/lib/textus/manifest/entry/derived.rb +40 -4
- data/lib/textus/manifest/entry/intake.rb +15 -3
- data/lib/textus/manifest/entry/leaf.rb +6 -5
- data/lib/textus/manifest/entry/nested.rb +42 -3
- data/lib/textus/manifest/entry/parser.rb +8 -44
- data/lib/textus/manifest/entry/validators/events.rb +1 -1
- data/lib/textus/manifest/entry/validators/format_matrix.rb +5 -4
- data/lib/textus/manifest/entry/validators/index_filename.rb +2 -1
- data/lib/textus/manifest/entry/validators/inject_boot.rb +19 -0
- data/lib/textus/manifest/entry/validators/publish_each.rb +4 -3
- data/lib/textus/manifest/entry/validators.rb +1 -1
- data/lib/textus/manifest/entry.rb +3 -0
- data/lib/textus/manifest/resolver.rb +4 -4
- data/lib/textus/manifest/schema.rb +20 -6
- data/lib/textus/manifest.rb +10 -0
- data/lib/textus/operations.rb +8 -1
- data/lib/textus/store.rb +5 -1
- data/lib/textus/version.rb +1 -1
- metadata +6 -4
- data/lib/textus/manifest/entry/validators/inject_intro.rb +0 -21
|
@@ -5,6 +5,9 @@ module Textus
|
|
|
5
5
|
# constants on Entry. Canonical source is the PublishEach validator.
|
|
6
6
|
PUBLISH_EACH_VARS = Validators::PublishEach::KNOWN_VARS
|
|
7
7
|
PUBLISH_EACH_VAR_RE = Validators::PublishEach::VAR_RE
|
|
8
|
+
|
|
9
|
+
# Populated by each Entry::* subclass at load time.
|
|
10
|
+
REGISTRY = {}
|
|
8
11
|
end
|
|
9
12
|
end
|
|
10
13
|
end
|
|
@@ -42,7 +42,7 @@ module Textus
|
|
|
42
42
|
# entry with nested: true in the raw YAML — e.g. Intake entries covering
|
|
43
43
|
# a directory of leaf files).
|
|
44
44
|
def nested_entry?(entry)
|
|
45
|
-
entry.
|
|
45
|
+
entry.nested?
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
def build_resolution(entry, remaining, key)
|
|
@@ -51,7 +51,7 @@ module Textus
|
|
|
51
51
|
else
|
|
52
52
|
raise UnknownKey.new(key, suggestions: suggestions_for(key)) unless nested_entry?(entry)
|
|
53
53
|
|
|
54
|
-
index_fn = entry.
|
|
54
|
+
index_fn = entry.index_filename
|
|
55
55
|
path = if index_fn
|
|
56
56
|
File.join(@manifest.root, "zones", entry.path, *remaining, index_fn)
|
|
57
57
|
else
|
|
@@ -71,14 +71,14 @@ module Textus
|
|
|
71
71
|
base = File.join(@manifest.root, "zones", entry.path)
|
|
72
72
|
return [] unless File.directory?(base)
|
|
73
73
|
|
|
74
|
-
entry_index_filename = entry.
|
|
74
|
+
entry_index_filename = entry.index_filename
|
|
75
75
|
glob_pattern = entry_index_filename ? "**/#{entry_index_filename}" : nested_glob(entry.format)
|
|
76
76
|
Dir.glob(File.join(base, glob_pattern)).filter_map { |path| nested_row_for(entry, base, path) }
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
def nested_row_for(entry, base, path)
|
|
80
80
|
rel = path.sub(%r{\A#{Regexp.escape(base)}/?}, "")
|
|
81
|
-
entry_if = entry.
|
|
81
|
+
entry_if = entry.index_filename
|
|
82
82
|
stripped = entry_if ? File.dirname(rel) : rel.sub(/#{Regexp.escape(File.extname(rel))}\z/, "")
|
|
83
83
|
segs = stripped.split("/").reject { |s| s.empty? || s == "." }
|
|
84
84
|
return nil if segs.empty?
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
module Textus
|
|
2
2
|
class Manifest
|
|
3
3
|
module Schema
|
|
4
|
-
ROOT_KEYS = %w[version roles zones entries rules].freeze
|
|
4
|
+
ROOT_KEYS = %w[version roles zones entries rules audit].freeze
|
|
5
5
|
ROLE_KEYS = %w[name kind].freeze
|
|
6
6
|
ROLE_KINDS = %w[accept_authority generator proposer runner].freeze
|
|
7
7
|
ZONE_KEYS = %w[name write_policy read_policy].freeze
|
|
8
8
|
ENTRY_KEYS = %w[
|
|
9
9
|
key path zone kind schema owner nested format
|
|
10
10
|
compute template publish_to publish_each
|
|
11
|
-
intake events
|
|
11
|
+
intake events inject_boot index_filename
|
|
12
12
|
].freeze
|
|
13
13
|
COMPUTE_KEYS = %w[kind select pluck sort_by limit transform command sources].freeze
|
|
14
14
|
INTAKE_KEYS = %w[handler config].freeze
|
|
@@ -16,22 +16,37 @@ module Textus
|
|
|
16
16
|
REFRESH_KEYS = %w[ttl on_stale sync_budget_ms fetch_timeout_seconds].freeze
|
|
17
17
|
FETCH_TIMEOUT_SECONDS_CEILING = 3600
|
|
18
18
|
PROMOTION_KEYS = %w[requires].freeze
|
|
19
|
+
AUDIT_KEYS = %w[max_size keep].freeze
|
|
19
20
|
|
|
20
21
|
def self.validate!(raw)
|
|
21
22
|
raise BadManifest.new("manifest must be a hash") unless raw.is_a?(Hash)
|
|
22
23
|
|
|
23
24
|
walk(raw, ROOT_KEYS, "$")
|
|
24
25
|
validate_roles!(raw["roles"])
|
|
25
|
-
|
|
26
|
+
validate_zones!(raw["zones"])
|
|
27
|
+
validate_entries!(raw["entries"])
|
|
28
|
+
validate_rules!(raw["rules"])
|
|
29
|
+
walk(raw["audit"], AUDIT_KEYS, "$.audit") if raw["audit"].is_a?(Hash)
|
|
30
|
+
validate_zone_writers_declared!(raw)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.validate_zones!(zones)
|
|
34
|
+
Array(zones).each_with_index do |z, i|
|
|
26
35
|
walk(z, ZONE_KEYS, "$.zones[#{i}]")
|
|
27
36
|
end
|
|
28
|
-
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.validate_entries!(entries)
|
|
40
|
+
Array(entries).each_with_index do |e, i|
|
|
29
41
|
path = "$.entries[#{i}]"
|
|
30
42
|
walk(e, ENTRY_KEYS, path)
|
|
31
43
|
walk(e["compute"], COMPUTE_KEYS, "#{path}.compute") if e["compute"].is_a?(Hash)
|
|
32
44
|
walk(e["intake"], INTAKE_KEYS, "#{path}.intake") if e["intake"].is_a?(Hash)
|
|
33
45
|
end
|
|
34
|
-
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.validate_rules!(rules)
|
|
49
|
+
Array(rules).each_with_index do |r, i|
|
|
35
50
|
path = "$.rules[#{i}]"
|
|
36
51
|
walk(r, RULE_KEYS, path)
|
|
37
52
|
if r["refresh"].is_a?(Hash)
|
|
@@ -40,7 +55,6 @@ module Textus
|
|
|
40
55
|
end
|
|
41
56
|
walk(r["promotion"], PROMOTION_KEYS, "#{path}.promotion") if r["promotion"].is_a?(Hash)
|
|
42
57
|
end
|
|
43
|
-
validate_zone_writers_declared!(raw)
|
|
44
58
|
end
|
|
45
59
|
|
|
46
60
|
def self.validate_zone_writers_declared!(raw)
|
data/lib/textus/manifest.rb
CHANGED
|
@@ -30,6 +30,16 @@ module Textus
|
|
|
30
30
|
)
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
+
AUDIT_DEFAULTS = { max_size: 10_485_760, keep: 5 }.freeze
|
|
34
|
+
|
|
35
|
+
def audit_config
|
|
36
|
+
raw = @raw["audit"] || {}
|
|
37
|
+
{
|
|
38
|
+
max_size: raw["max_size"] || AUDIT_DEFAULTS[:max_size],
|
|
39
|
+
keep: raw["keep"] || AUDIT_DEFAULTS[:keep],
|
|
40
|
+
}
|
|
41
|
+
end
|
|
42
|
+
|
|
33
43
|
def role_mapping
|
|
34
44
|
@role_mapping ||= RoleKinds.resolve(@raw["roles"])
|
|
35
45
|
end
|
data/lib/textus/operations.rb
CHANGED
|
@@ -115,11 +115,18 @@ module Textus
|
|
|
115
115
|
def rdeps(...) = Application::Reads::Rdeps.new(manifest: @manifest).call(...)
|
|
116
116
|
def published(...) = Application::Reads::Published.new(manifest: @manifest).call(...)
|
|
117
117
|
def stale(...) = Application::Reads::Stale.new(manifest: @manifest).call(...)
|
|
118
|
-
def audit(...) = Application::Reads::Audit.new(manifest: @manifest, root: @root).call(...)
|
|
118
|
+
def audit(...) = Application::Reads::Audit.new(manifest: @manifest, root: @root, audit_log: @audit_log).call(...)
|
|
119
119
|
def blame(...) = Application::Reads::Blame.new(manifest: @manifest, root: @root).call(...)
|
|
120
120
|
def policy_explain(...) = Application::Reads::PolicyExplain.new(manifest: @manifest).call(...)
|
|
121
121
|
def freshness(...) = Application::Reads::Freshness.new(ctx: @ctx, manifest: @manifest, file_store: @file_store).call(...)
|
|
122
122
|
|
|
123
|
+
def pulse(...)
|
|
124
|
+
Application::Reads::Pulse.new(
|
|
125
|
+
ctx: @ctx, manifest: @manifest, file_store: @file_store,
|
|
126
|
+
audit_log: @audit_log, root: @root, store: @store
|
|
127
|
+
).call(...)
|
|
128
|
+
end
|
|
129
|
+
|
|
123
130
|
def validate_all(...)
|
|
124
131
|
Application::Reads::ValidateAll.new(
|
|
125
132
|
ctx: @ctx, manifest: @manifest, file_store: @file_store, schemas: @schemas, audit_log: @audit_log,
|
data/lib/textus/store.rb
CHANGED
|
@@ -33,7 +33,11 @@ module Textus
|
|
|
33
33
|
@manifest = Manifest.load(@root)
|
|
34
34
|
@schemas = Schemas.new(File.join(@root, "schemas"))
|
|
35
35
|
@file_store = Infra::Storage::FileStore.new
|
|
36
|
-
@audit_log = Infra::AuditLog.new(
|
|
36
|
+
@audit_log = Infra::AuditLog.new(
|
|
37
|
+
@root,
|
|
38
|
+
max_size: @manifest.audit_config[:max_size],
|
|
39
|
+
keep: @manifest.audit_config[:keep],
|
|
40
|
+
)
|
|
37
41
|
@bus = Hooks::Bus.new
|
|
38
42
|
Infra::AuditSubscriber.new(@audit_log).attach(@bus)
|
|
39
43
|
Hooks::Builtin.register_all(@bus)
|
data/lib/textus/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: textus
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.22.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Patrick
|
|
@@ -123,6 +123,7 @@ files:
|
|
|
123
123
|
- lib/textus/application/reads/list.rb
|
|
124
124
|
- lib/textus/application/reads/policy_explain.rb
|
|
125
125
|
- lib/textus/application/reads/published.rb
|
|
126
|
+
- lib/textus/application/reads/pulse.rb
|
|
126
127
|
- lib/textus/application/reads/rdeps.rb
|
|
127
128
|
- lib/textus/application/reads/schema_envelope.rb
|
|
128
129
|
- lib/textus/application/reads/stale.rb
|
|
@@ -142,6 +143,7 @@ files:
|
|
|
142
143
|
- lib/textus/application/writes/publish.rb
|
|
143
144
|
- lib/textus/application/writes/put.rb
|
|
144
145
|
- lib/textus/application/writes/reject.rb
|
|
146
|
+
- lib/textus/boot.rb
|
|
145
147
|
- lib/textus/builder/pipeline.rb
|
|
146
148
|
- lib/textus/builder/renderer.rb
|
|
147
149
|
- lib/textus/builder/renderer/json.rb
|
|
@@ -159,6 +161,7 @@ files:
|
|
|
159
161
|
- lib/textus/cli/verb/accept.rb
|
|
160
162
|
- lib/textus/cli/verb/audit.rb
|
|
161
163
|
- lib/textus/cli/verb/blame.rb
|
|
164
|
+
- lib/textus/cli/verb/boot.rb
|
|
162
165
|
- lib/textus/cli/verb/build.rb
|
|
163
166
|
- lib/textus/cli/verb/delete.rb
|
|
164
167
|
- lib/textus/cli/verb/deps.rb
|
|
@@ -168,10 +171,10 @@ files:
|
|
|
168
171
|
- lib/textus/cli/verb/hook_run.rb
|
|
169
172
|
- lib/textus/cli/verb/hooks.rb
|
|
170
173
|
- lib/textus/cli/verb/init.rb
|
|
171
|
-
- lib/textus/cli/verb/intro.rb
|
|
172
174
|
- lib/textus/cli/verb/list.rb
|
|
173
175
|
- lib/textus/cli/verb/mv.rb
|
|
174
176
|
- lib/textus/cli/verb/published.rb
|
|
177
|
+
- lib/textus/cli/verb/pulse.rb
|
|
175
178
|
- lib/textus/cli/verb/put.rb
|
|
176
179
|
- lib/textus/cli/verb/rdeps.rb
|
|
177
180
|
- lib/textus/cli/verb/refresh.rb
|
|
@@ -242,7 +245,6 @@ files:
|
|
|
242
245
|
- lib/textus/infra/refresh/lock.rb
|
|
243
246
|
- lib/textus/infra/storage/file_store.rb
|
|
244
247
|
- lib/textus/init.rb
|
|
245
|
-
- lib/textus/intro.rb
|
|
246
248
|
- lib/textus/key/distance.rb
|
|
247
249
|
- lib/textus/key/grammar.rb
|
|
248
250
|
- lib/textus/key/path.rb
|
|
@@ -258,7 +260,7 @@ files:
|
|
|
258
260
|
- lib/textus/manifest/entry/validators/events.rb
|
|
259
261
|
- lib/textus/manifest/entry/validators/format_matrix.rb
|
|
260
262
|
- lib/textus/manifest/entry/validators/index_filename.rb
|
|
261
|
-
- lib/textus/manifest/entry/validators/
|
|
263
|
+
- lib/textus/manifest/entry/validators/inject_boot.rb
|
|
262
264
|
- lib/textus/manifest/entry/validators/publish_each.rb
|
|
263
265
|
- lib/textus/manifest/resolver.rb
|
|
264
266
|
- lib/textus/manifest/role_kinds.rb
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
module Textus
|
|
2
|
-
class Manifest
|
|
3
|
-
class Entry
|
|
4
|
-
module Validators
|
|
5
|
-
module InjectIntro
|
|
6
|
-
def self.call(entry)
|
|
7
|
-
inject_intro = entry.respond_to?(:inject_intro) ? entry.inject_intro : false
|
|
8
|
-
return unless inject_intro
|
|
9
|
-
|
|
10
|
-
raise UsageError.new("entry '#{entry.key}': inject_intro: is only valid on derived entries") unless entry.in_generator_zone?
|
|
11
|
-
|
|
12
|
-
has_template = entry.respond_to?(:template) && !entry.template.nil?
|
|
13
|
-
return if has_template
|
|
14
|
-
|
|
15
|
-
raise UsageError.new("entry '#{entry.key}': inject_intro: requires a template:")
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|