confctl 1.0.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 (130) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +11 -0
  3. data/.gitignore +8 -0
  4. data/.overcommit.yml +6 -0
  5. data/.rubocop.yml +67 -0
  6. data/.rubocop_todo.yml +5 -0
  7. data/.ruby-version +1 -0
  8. data/CHANGELOG.md +2 -0
  9. data/Gemfile +2 -0
  10. data/LICENSE.txt +674 -0
  11. data/README.md +522 -0
  12. data/Rakefile +40 -0
  13. data/bin/confctl +4 -0
  14. data/confctl.gemspec +33 -0
  15. data/example/.gitignore +2 -0
  16. data/example/README.md +38 -0
  17. data/example/cluster/cluster.nix +7 -0
  18. data/example/cluster/module-list.nix +3 -0
  19. data/example/cluster/nixos-machine/config.nix +15 -0
  20. data/example/cluster/nixos-machine/hardware.nix +4 -0
  21. data/example/cluster/nixos-machine/module.nix +8 -0
  22. data/example/cluster/vpsadminos-container/config.nix +22 -0
  23. data/example/cluster/vpsadminos-container/module.nix +8 -0
  24. data/example/cluster/vpsadminos-machine/config.nix +22 -0
  25. data/example/cluster/vpsadminos-machine/hardware.nix +4 -0
  26. data/example/cluster/vpsadminos-machine/module.nix +8 -0
  27. data/example/cluster/vpsfreecz-vps/config.nix +25 -0
  28. data/example/cluster/vpsfreecz-vps/module.nix +8 -0
  29. data/example/configs/confctl.nix +10 -0
  30. data/example/configs/swpins.nix +28 -0
  31. data/example/data/default.nix +5 -0
  32. data/example/data/ssh-keys.nix +7 -0
  33. data/example/environments/base.nix +13 -0
  34. data/example/modules/module-list.nix +13 -0
  35. data/example/shell.nix +11 -0
  36. data/example/swpins/channels/nixos-unstable.json +35 -0
  37. data/example/swpins/channels/vpsadminos-staging.json +35 -0
  38. data/lib/confctl/cli/app.rb +551 -0
  39. data/lib/confctl/cli/attr_filters.rb +51 -0
  40. data/lib/confctl/cli/cluster.rb +1248 -0
  41. data/lib/confctl/cli/command.rb +206 -0
  42. data/lib/confctl/cli/configuration.rb +296 -0
  43. data/lib/confctl/cli/gen_data.rb +97 -0
  44. data/lib/confctl/cli/generation.rb +335 -0
  45. data/lib/confctl/cli/log_view.rb +267 -0
  46. data/lib/confctl/cli/output_formatter.rb +288 -0
  47. data/lib/confctl/cli/swpins/base.rb +40 -0
  48. data/lib/confctl/cli/swpins/channel.rb +73 -0
  49. data/lib/confctl/cli/swpins/cluster.rb +80 -0
  50. data/lib/confctl/cli/swpins/core.rb +86 -0
  51. data/lib/confctl/cli/swpins/utils.rb +55 -0
  52. data/lib/confctl/cli/swpins.rb +5 -0
  53. data/lib/confctl/cli/tag_filters.rb +30 -0
  54. data/lib/confctl/cli.rb +5 -0
  55. data/lib/confctl/conf_cache.rb +105 -0
  56. data/lib/confctl/conf_dir.rb +88 -0
  57. data/lib/confctl/erb_template.rb +37 -0
  58. data/lib/confctl/exceptions.rb +3 -0
  59. data/lib/confctl/gcroot.rb +30 -0
  60. data/lib/confctl/generation/build.rb +145 -0
  61. data/lib/confctl/generation/build_list.rb +106 -0
  62. data/lib/confctl/generation/host.rb +35 -0
  63. data/lib/confctl/generation/host_list.rb +81 -0
  64. data/lib/confctl/generation/unified.rb +117 -0
  65. data/lib/confctl/generation/unified_list.rb +63 -0
  66. data/lib/confctl/git_repo_mirror.rb +79 -0
  67. data/lib/confctl/health_checks/base.rb +66 -0
  68. data/lib/confctl/health_checks/run_command.rb +179 -0
  69. data/lib/confctl/health_checks/systemd/properties.rb +84 -0
  70. data/lib/confctl/health_checks/systemd/property_check.rb +31 -0
  71. data/lib/confctl/health_checks/systemd/property_list.rb +20 -0
  72. data/lib/confctl/health_checks.rb +5 -0
  73. data/lib/confctl/hook.rb +35 -0
  74. data/lib/confctl/line_buffer.rb +53 -0
  75. data/lib/confctl/logger.rb +151 -0
  76. data/lib/confctl/machine.rb +107 -0
  77. data/lib/confctl/machine_control.rb +172 -0
  78. data/lib/confctl/machine_list.rb +108 -0
  79. data/lib/confctl/machine_status.rb +135 -0
  80. data/lib/confctl/module_options.rb +95 -0
  81. data/lib/confctl/nix.rb +382 -0
  82. data/lib/confctl/nix_build.rb +108 -0
  83. data/lib/confctl/nix_collect_garbage.rb +64 -0
  84. data/lib/confctl/nix_copy.rb +49 -0
  85. data/lib/confctl/nix_format.rb +124 -0
  86. data/lib/confctl/nix_literal_expression.rb +15 -0
  87. data/lib/confctl/parallel_executor.rb +43 -0
  88. data/lib/confctl/pattern.rb +9 -0
  89. data/lib/confctl/settings.rb +50 -0
  90. data/lib/confctl/std_line_buffer.rb +40 -0
  91. data/lib/confctl/swpins/change_set.rb +151 -0
  92. data/lib/confctl/swpins/channel.rb +62 -0
  93. data/lib/confctl/swpins/channel_list.rb +47 -0
  94. data/lib/confctl/swpins/cluster_name.rb +94 -0
  95. data/lib/confctl/swpins/cluster_name_list.rb +15 -0
  96. data/lib/confctl/swpins/core.rb +137 -0
  97. data/lib/confctl/swpins/deployed_info.rb +23 -0
  98. data/lib/confctl/swpins/spec.rb +20 -0
  99. data/lib/confctl/swpins/specs/base.rb +184 -0
  100. data/lib/confctl/swpins/specs/directory.rb +51 -0
  101. data/lib/confctl/swpins/specs/git.rb +135 -0
  102. data/lib/confctl/swpins/specs/git_rev.rb +24 -0
  103. data/lib/confctl/swpins.rb +17 -0
  104. data/lib/confctl/system_command.rb +10 -0
  105. data/lib/confctl/user_script.rb +13 -0
  106. data/lib/confctl/user_scripts.rb +41 -0
  107. data/lib/confctl/utils/file.rb +21 -0
  108. data/lib/confctl/version.rb +3 -0
  109. data/lib/confctl.rb +43 -0
  110. data/man/man8/confctl-options.nix.8 +1334 -0
  111. data/man/man8/confctl-options.nix.8.md +1340 -0
  112. data/man/man8/confctl.8 +660 -0
  113. data/man/man8/confctl.8.md +654 -0
  114. data/nix/evaluator.nix +160 -0
  115. data/nix/lib/default.nix +83 -0
  116. data/nix/lib/machine/default.nix +74 -0
  117. data/nix/lib/machine/info.nix +5 -0
  118. data/nix/lib/swpins/eval.nix +71 -0
  119. data/nix/lib/swpins/options.nix +94 -0
  120. data/nix/machines.nix +31 -0
  121. data/nix/modules/cluster/default.nix +459 -0
  122. data/nix/modules/confctl/cli.nix +21 -0
  123. data/nix/modules/confctl/generations.nix +84 -0
  124. data/nix/modules/confctl/nix.nix +28 -0
  125. data/nix/modules/confctl/swpins.nix +55 -0
  126. data/nix/modules/module-list.nix +19 -0
  127. data/shell.nix +42 -0
  128. data/template/confctl-options.nix/main.erb +45 -0
  129. data/template/confctl-options.nix/options.erb +15 -0
  130. metadata +353 -0
@@ -0,0 +1,288 @@
1
+ require 'rainbow'
2
+
3
+ module ConfCtl::Cli
4
+ class OutputFormatter
5
+ def self.to_s(*args)
6
+ f = new(*args)
7
+ f.to_s
8
+ end
9
+
10
+ def self.print(*args, **kwargs)
11
+ f = new(*args, **kwargs)
12
+ f.print
13
+ end
14
+
15
+ def initialize(objects, cols = nil, header: true, sort: nil, layout: nil, empty: '-', color: false)
16
+ @objects = objects
17
+ @header = header
18
+ @sort = sort
19
+ @layout = layout
20
+ @empty = empty
21
+ @color = color
22
+
23
+ if @layout.nil?
24
+ @layout = if many?
25
+ :columns
26
+
27
+ else
28
+ :rows
29
+ end
30
+ end
31
+
32
+ if cols
33
+ @cols = parse_cols(cols)
34
+
35
+ elsif @objects.is_a?(::Array)
36
+ if @objects.count == 0
37
+ @cols = []
38
+ else
39
+ @cols ||= parse_cols(@objects.first.keys)
40
+ end
41
+
42
+ elsif @objects.is_a?(::Hash) # Single item
43
+ @cols ||= parse_cols(@objects.keys)
44
+
45
+ else
46
+ raise "unsupported type #{@objects.class}"
47
+ end
48
+ end
49
+
50
+ def to_s
51
+ @out = ''
52
+ generate
53
+ @out
54
+ end
55
+
56
+ def print
57
+ @out = nil
58
+ generate
59
+ end
60
+
61
+ protected
62
+
63
+ def parse_cols(cols)
64
+ ret = []
65
+
66
+ cols.each do |c|
67
+ base = {
68
+ align: 'left'
69
+ }
70
+
71
+ if c.is_a?(::String) || c.is_a?(::Symbol)
72
+ base.update({
73
+ name: c,
74
+ label: c.to_s.upcase
75
+ })
76
+ ret << base
77
+
78
+ elsif c.is_a?(::Hash)
79
+ base.update(c)
80
+ ret << base
81
+
82
+ else
83
+ raise "unsupported column type #{c.class}"
84
+ end
85
+ end
86
+
87
+ ret
88
+ end
89
+
90
+ def generate
91
+ return if @cols.empty?
92
+
93
+ prepare
94
+
95
+ case @layout
96
+ when :columns
97
+ columns
98
+
99
+ when :rows
100
+ rows
101
+
102
+ else
103
+ raise "unsupported layout '#{@layout}'"
104
+ end
105
+ end
106
+
107
+ # Each object is printed on one line, it's parameters aligned into columns.
108
+ def columns
109
+ # Calculate column widths
110
+ @cols.each_with_index do |c, i|
111
+ c[:width] = col_width(i, c)
112
+ end
113
+
114
+ # Print header
115
+ if @header
116
+ line(@cols.map.with_index do |c, i|
117
+ fmt =
118
+ if i == (@cols.count - 1)
119
+ '%s'
120
+ elsif c[:align].to_sym == :right
121
+ "%#{c[:width]}s"
122
+ else
123
+ "%-#{c[:width]}s"
124
+ end
125
+
126
+ format(fmt, c[:label])
127
+ end.join(' '))
128
+ end
129
+
130
+ # Print data
131
+ @str_objects.each do |o|
132
+ line(@cols.map.with_index do |c, i|
133
+ s = o[i].to_s
134
+
135
+ if @color
136
+ # If there are colors in the string, they affect the string size
137
+ # and thus sprintf formatting. sprintf is working with characters
138
+ # that the terminal will consume and not display (escape sequences).
139
+ # The format string needs to be changed to accomodate for those
140
+ # unprintable characters.
141
+ s_nocolor = Rainbow::StringUtils.uncolor(s)
142
+
143
+ w = if s_nocolor.length == s.length
144
+ c[:width]
145
+
146
+ else
147
+ c[:width] + (s.length - s_nocolor.length)
148
+ end
149
+ else
150
+ w = c[:width]
151
+ end
152
+
153
+ fmt =
154
+ if i == (@cols.count - 1)
155
+ '%s'
156
+ elsif c[:align].to_sym == :right
157
+ "%#{w}s"
158
+ else
159
+ "%-#{w}s"
160
+ end
161
+
162
+ format(fmt, s)
163
+ end.join(' '))
164
+ end
165
+ end
166
+
167
+ # Each object is printed on multiple lines, one parameter per line.
168
+ def rows
169
+ w = heading_width if @header
170
+
171
+ @str_objects.each do |o|
172
+ @cols.each_index do |i|
173
+ c = @cols[i]
174
+
175
+ unless @header
176
+ line o[i]
177
+ next
178
+ end
179
+
180
+ if o[i].is_a?(::String) && o[i].index("\n")
181
+ lines = o[i].split("\n")
182
+ v = ([lines.first] + lines[1..].map { |l| (' ' * (w + 3)) + l }).join("\n")
183
+
184
+ else
185
+ v = o[i]
186
+ end
187
+
188
+ # rubocop:disable Lint/FormatParameterMismatch
189
+ line format("%#{w}s: %s", c[:label], v)
190
+ # rubocop:enable Lint/FormatParameterMismatch
191
+ end
192
+
193
+ line
194
+ end
195
+ end
196
+
197
+ def line(str = '')
198
+ if @out
199
+ @out += "#{str}\n"
200
+
201
+ else
202
+ puts str
203
+ end
204
+ end
205
+
206
+ def prepare
207
+ @str_objects = []
208
+
209
+ each_object do |o|
210
+ arr = []
211
+
212
+ @cols.each do |c|
213
+ v = o[c[:name]]
214
+ str = (c[:display] ? c[:display].call(v, o) : v)
215
+ str = @empty if !str || (str.is_a?(::String) && str.empty?)
216
+
217
+ arr << str
218
+ end
219
+
220
+ @str_objects << arr
221
+ end
222
+
223
+ if @sort
224
+ col_indexes = @sort.map do |s|
225
+ i = @cols.index { |c| c[:name] == s }
226
+ raise "unknown sort column '#{s}'" unless i
227
+
228
+ i
229
+ end
230
+
231
+ @str_objects.sort! do |a, b|
232
+ a_vals = col_indexes.map { |i| a[i] }
233
+ b_vals = col_indexes.map { |i| b[i] }
234
+ cmp = a_vals <=> b_vals
235
+ next(cmp) if cmp
236
+
237
+ next(-1) if [nil, @empty].detect { |v| a_vals.include?(v) }
238
+ next(1) if [nil, @empty].detect { |v| b_vals.include?(v) }
239
+
240
+ 0
241
+ end
242
+ end
243
+
244
+ @str_objects
245
+ end
246
+
247
+ def col_width(i, c)
248
+ w = c[:label].to_s.length
249
+
250
+ @str_objects.each do |o|
251
+ len = if @color
252
+ Rainbow::StringUtils.uncolor(o[i].to_s).length
253
+ else
254
+ o[i].to_s.length
255
+ end
256
+
257
+ w = len if len > w
258
+ end
259
+
260
+ w + 1
261
+ end
262
+
263
+ def heading_width
264
+ w = @cols.first[:label].to_s.length
265
+
266
+ @cols.each do |c|
267
+ len = c[:label].to_s.length
268
+
269
+ w = len if len > w
270
+ end
271
+
272
+ w + 1
273
+ end
274
+
275
+ def each_object(&)
276
+ if @objects.is_a?(::Array)
277
+ @objects.each(&)
278
+
279
+ else
280
+ yield(@objects)
281
+ end
282
+ end
283
+
284
+ def many?
285
+ @objects.is_a?(::Array) && @objects.size > 1
286
+ end
287
+ end
288
+ end
@@ -0,0 +1,40 @@
1
+ require 'confctl/cli/command'
2
+ require 'confctl/cli/swpins/utils'
3
+
4
+ module ConfCtl::Cli
5
+ class Swpins::Base < Command
6
+ include Swpins::Utils
7
+
8
+ def update
9
+ run_command(Swpins::Core, :update)
10
+ run_command(Swpins::Channel, :update)
11
+ run_command(Swpins::Cluster, :update)
12
+ end
13
+
14
+ def reconfigure
15
+ each_channel('*') do |chan|
16
+ if chan.valid?
17
+ puts "Reconfiguring channel #{chan.name}"
18
+ chan.save
19
+ else
20
+ puts "Channel #{chan.name} needs update"
21
+ chan.specs.each do |name, s|
22
+ puts " update #{name}" unless s.valid?
23
+ end
24
+ end
25
+ end
26
+
27
+ each_cluster_name('*') do |cn|
28
+ if cn.valid?
29
+ puts "Reconfiguring machine #{cn.name}"
30
+ cn.save
31
+ else
32
+ puts "Machine #{cn.name} needs update"
33
+ cn.specs.each do |name, s|
34
+ puts " update #{name}" unless s.valid?
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,73 @@
1
+ require 'confctl/cli/command'
2
+ require 'confctl/cli/swpins/utils'
3
+
4
+ module ConfCtl::Cli
5
+ class Swpins::Channel < Command
6
+ include Swpins::Utils
7
+
8
+ def list
9
+ rows = []
10
+
11
+ each_channel_spec(args[0] || '*', args[1] || '*') do |chan, spec|
12
+ rows << {
13
+ channel: chan.name,
14
+ sw: spec.name,
15
+ type: spec.type,
16
+ pin: spec.status
17
+ }
18
+ end
19
+
20
+ OutputFormatter.print(
21
+ rows,
22
+ %i[channel sw type pin],
23
+ layout: :columns
24
+ )
25
+ end
26
+
27
+ def set
28
+ require_args!('channel-pattern', 'sw-pattern', 'version...', strict: false)
29
+ channels = []
30
+ change_set = ConfCtl::Swpins::ChangeSet.new
31
+
32
+ each_channel_spec(args[0], args[1]) do |chan, spec|
33
+ change_set.add(chan, spec)
34
+ spec_set_msg(chan, spec) { spec.prefetch_set(args[2..]) }
35
+ channels << chan unless channels.include?(chan)
36
+ end
37
+
38
+ channels.each(&:save)
39
+
40
+ return unless opts[:commit]
41
+
42
+ change_set.commit(
43
+ type: opts[:downgrade] ? :downgrade : :upgrade,
44
+ changelog: opts[:changelog]
45
+ )
46
+ end
47
+
48
+ def update
49
+ require_args!(optional: %w[channel-pattern sw-pattern])
50
+ channels = []
51
+ change_set = ConfCtl::Swpins::ChangeSet.new
52
+
53
+ each_channel_spec(args[0] || '*', args[1] || '*') do |chan, spec|
54
+ if spec.can_update?
55
+ change_set.add(chan, spec)
56
+ spec_update_msg(chan, spec) { spec.prefetch_update }
57
+ channels << chan unless channels.include?(chan)
58
+ else
59
+ puts "#{spec.name} not configured for update"
60
+ end
61
+ end
62
+
63
+ channels.each(&:save)
64
+
65
+ return unless opts[:commit]
66
+
67
+ change_set.commit(
68
+ type: opts[:downgrade] ? :downgrade : :upgrade,
69
+ changelog: opts[:changelog]
70
+ )
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,80 @@
1
+ require 'confctl/cli/command'
2
+ require 'confctl/cli/swpins/utils'
3
+
4
+ module ConfCtl::Cli
5
+ class Swpins::Cluster < Command
6
+ include Swpins::Utils
7
+
8
+ def list
9
+ rows = []
10
+
11
+ each_cluster_name_spec(args[0] || '*', args[1] || '*') do |cn, spec|
12
+ rows << {
13
+ cluster_name: cn.name,
14
+ sw: spec.name,
15
+ channel: spec.channel,
16
+ type: spec.type,
17
+ pin: spec.status
18
+ }
19
+ end
20
+
21
+ OutputFormatter.print(
22
+ rows,
23
+ %i[cluster_name sw channel type pin],
24
+ layout: :columns
25
+ )
26
+ end
27
+
28
+ def set
29
+ require_args!('cluster-name', 'sw', 'version...', strict: false)
30
+ cluster_names = []
31
+ change_set = ConfCtl::Swpins::ChangeSet.new
32
+
33
+ each_cluster_name_spec(args[0], args[1]) do |cluster_name, spec|
34
+ if spec.from_channel?
35
+ puts "Skipping #{spec.name} as it comes from channel #{spec.channel}"
36
+ else
37
+ change_set.add(cluster_name, spec)
38
+ spec_set_msg(cluster_name, spec) { spec.prefetch_set(args[2..]) }
39
+ cluster_names << cluster_name unless cluster_names.include?(cluster_name)
40
+ end
41
+ end
42
+
43
+ cluster_names.each(&:save)
44
+
45
+ return unless opts[:commit]
46
+
47
+ change_set.commit(
48
+ type: opts[:downgrade] ? :downgrade : :upgrade,
49
+ changelog: opts[:changelog]
50
+ )
51
+ end
52
+
53
+ def update
54
+ require_args!(optional: %w[cluster-name sw])
55
+ cluster_names = []
56
+ change_set = ConfCtl::Swpins::ChangeSet.new
57
+
58
+ each_cluster_name_spec(args[0] || '*', args[1] || '*') do |cluster_name, spec|
59
+ if spec.from_channel?
60
+ puts "Skipping #{spec.name} as it comes from channel #{spec.channel}"
61
+ elsif spec.can_update?
62
+ change_set.add(cluster_name, spec)
63
+ spec_update_msg(cluster_name, spec) { spec.prefetch_update }
64
+ cluster_names << cluster_name unless cluster_names.include?(cluster_name)
65
+ else
66
+ puts "#{spec.name} not configured for update"
67
+ end
68
+ end
69
+
70
+ cluster_names.each(&:save)
71
+
72
+ return unless opts[:commit]
73
+
74
+ change_set.commit(
75
+ type: opts[:downgrade] ? :downgrade : :upgrade,
76
+ changelog: opts[:changelog]
77
+ )
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,86 @@
1
+ require 'confctl/cli/command'
2
+ require 'confctl/cli/swpins/utils'
3
+
4
+ module ConfCtl::Cli
5
+ class Swpins::Core < Command
6
+ include Swpins::Utils
7
+
8
+ def list
9
+ core = ConfCtl::Swpins::Core.get
10
+
11
+ rows = []
12
+
13
+ core.specs.each do |name, spec|
14
+ next if args[0] && !ConfCtl::Pattern.match(args[0], name)
15
+
16
+ rows << {
17
+ sw: spec.name,
18
+ channel: spec.channel,
19
+ type: spec.type,
20
+ pin: spec.status
21
+ }
22
+ end
23
+
24
+ OutputFormatter.print(
25
+ rows,
26
+ %i[sw channel type pin],
27
+ layout: :columns
28
+ )
29
+ end
30
+
31
+ def set
32
+ require_args!('sw', 'version...', strict: false)
33
+
34
+ core = ConfCtl::Swpins::Core.get
35
+ change_set = ConfCtl::Swpins::ChangeSet.new
36
+
37
+ core.specs.each_value do |spec|
38
+ if spec.from_channel?
39
+ puts "Skipping #{spec.name} as it comes from channel #{spec.channel}"
40
+ else
41
+ change_set.add(core, spec)
42
+ spec_set_msg(core, spec) { spec.prefetch_set(args[1..]) }
43
+ end
44
+ end
45
+
46
+ core.save
47
+ core.pre_evaluate
48
+
49
+ return unless opts[:commit]
50
+
51
+ change_set.commit(
52
+ type: opts[:downgrade] ? :downgrade : :upgrade,
53
+ changelog: opts[:changelog]
54
+ )
55
+ end
56
+
57
+ def update
58
+ require_args!(optional: %w[sw])
59
+ core = ConfCtl::Swpins::Core.get
60
+ change_set = ConfCtl::Swpins::ChangeSet.new
61
+
62
+ core.specs.each do |name, spec|
63
+ next if args[0] && !ConfCtl::Pattern.match(args[0], name)
64
+
65
+ if spec.from_channel?
66
+ puts "Skipping #{spec.name} as it comes from channel #{spec.channel}"
67
+ elsif spec.can_update?
68
+ change_set.add(core, spec)
69
+ spec_update_msg(core, spec) { spec.prefetch_update }
70
+ else
71
+ puts "#{spec.name} not configured for update"
72
+ end
73
+ end
74
+
75
+ core.save
76
+ core.pre_evaluate
77
+
78
+ return unless opts[:commit]
79
+
80
+ change_set.commit(
81
+ type: opts[:downgrade] ? :downgrade : :upgrade,
82
+ changelog: opts[:changelog]
83
+ )
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,55 @@
1
+ module ConfCtl::Cli
2
+ module Swpins::Utils
3
+ def cluster_name_list(pattern)
4
+ ConfCtl::Swpins::ClusterNameList.new(pattern:)
5
+ end
6
+
7
+ def each_cluster_name(cn_pattern)
8
+ cluster_name_list(cn_pattern).each do |cn|
9
+ cn.parse
10
+ yield(cn)
11
+ end
12
+ end
13
+
14
+ def each_cluster_name_spec(cn_pattern, sw_pattern)
15
+ each_cluster_name(cn_pattern) do |cn|
16
+ cn.specs.each do |name, spec|
17
+ yield(cn, spec) if ConfCtl::Pattern.match?(sw_pattern, name)
18
+ end
19
+ end
20
+ end
21
+
22
+ def channel_list(pattern)
23
+ ConfCtl::Swpins::ChannelList.pattern(pattern)
24
+ end
25
+
26
+ def each_channel(chan_pattern)
27
+ channel_list(chan_pattern).each do |chan|
28
+ chan.parse
29
+ yield(chan)
30
+ end
31
+ end
32
+
33
+ def each_channel_spec(chan_pattern, sw_pattern)
34
+ each_channel(chan_pattern) do |chan|
35
+ chan.specs.each do |name, spec|
36
+ yield(chan, spec) if ConfCtl::Pattern.match?(sw_pattern, name)
37
+ end
38
+ end
39
+ end
40
+
41
+ def spec_set_msg(parent, spec)
42
+ $stdout.write("Configuring #{spec.name} in #{parent.name}")
43
+ $stdout.flush
44
+ yield
45
+ puts " -> #{spec.version}"
46
+ end
47
+
48
+ def spec_update_msg(parent, spec)
49
+ $stdout.write("Updating #{spec.name} in #{parent.name}")
50
+ $stdout.flush
51
+ yield
52
+ puts " -> #{spec.version}"
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,5 @@
1
+ module ConfCtl::Cli
2
+ module Swpins; end
3
+ end
4
+
5
+ require_rel 'swpins'
@@ -0,0 +1,30 @@
1
+ module ConfCtl::Cli
2
+ class TagFilters
3
+ # @param str_tags [Array<String>]
4
+ def initialize(str_tags)
5
+ @must = []
6
+ @cant = []
7
+ parse_all(str_tags)
8
+ end
9
+
10
+ # @param machine [ConfCtl::Machine]
11
+ def pass?(machine)
12
+ must.all? { |t| machine['tags'].include?(t) } \
13
+ && cant.all? { |t| !machine['tags'].include?(t) }
14
+ end
15
+
16
+ protected
17
+
18
+ attr_reader :must, :cant
19
+
20
+ def parse_all(str_tags)
21
+ str_tags.each do |t|
22
+ if t.start_with?('^')
23
+ cant << t[1..]
24
+ else
25
+ must << t
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,5 @@
1
+ module ConfCtl
2
+ module Cli; end
3
+ end
4
+
5
+ require_rel 'cli'