squared 0.8.6 → 0.9.0.pre1

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.
data/exe/sqd ADDED
@@ -0,0 +1,224 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $:.unshift(File.expand_path('../lib', __dir__)) if File.exist?(File.expand_path('../squared.gemspec', __dir__))
5
+
6
+ require 'squared'
7
+ require 'rake'
8
+ require 'optparse'
9
+
10
+ class SqdParser < OptionParser
11
+ include Squared::Common::Format
12
+ include Utils
13
+
14
+ attr_reader :options, :global
15
+
16
+ def initialize(*)
17
+ super
18
+ @options = { 'project-args': [], 'project-env': [] }
19
+ @global = []
20
+ @program_name = 'squared'
21
+ @raise_unknown = false
22
+ @require_exact = true
23
+ end
24
+
25
+ def parse_global(list, assert:)
26
+ raise ArgumentError, "cannot be used with --#{assert}" if options.key?(assert)
27
+
28
+ ARGV.each_with_index do |val, index|
29
+ if val == '--'
30
+ separator!(index: index)
31
+ break
32
+ end
33
+ next if val.start_with?('-') || val.include?(':') || val.empty?
34
+
35
+ global.concat(list.map { |name| "#{val}:#{name}" })
36
+ ARGV[index] = ''
37
+ end
38
+ end
39
+
40
+ def parse_common(list, session:, arg:)
41
+ if list && !list.include?('*')
42
+ session[arg].merge!(list.to_h { |key| [key, 'true'] })
43
+ else
44
+ session[arg] = Hash.new('true')
45
+ end
46
+ end
47
+
48
+ def banner_set(val, session:)
49
+ session[:BANNER] = val
50
+ ENV['BANNER'] = val ? 'true' : 'false'
51
+ end
52
+
53
+ def color_set(val, session:)
54
+ if (session[:COLOR] = val)
55
+ enable_aixterm
56
+ enable_drawing
57
+ else
58
+ enable_drawing false
59
+ Squared::Common.const_get(:VAR)[:colors].freeze
60
+ end
61
+ ENV['NO_COLOR'] = val ? nil : '1'
62
+ ENV['FORCE_COLOR'] = val ? '2' : '0'
63
+ end
64
+
65
+ def run
66
+ parse!(into: options)
67
+ if (project = options[:project])
68
+ pattern, project = project.partition do |val|
69
+ next true if val == '*'
70
+
71
+ val = ".#{val}" if val.start_with?('*')
72
+ val.match?(/[*+\[(]|(?<!\\)\.\.|\{\d+\}/) && Regexp.new(val)
73
+ rescue RegexpError
74
+ false
75
+ end
76
+ pattern.each do |val|
77
+ val = if val == '*'
78
+ '[^:]+'
79
+ else
80
+ val.sub(/^\*/, '.*')
81
+ .sub(/(?<!\.)\*$/, '.*')
82
+ .gsub(/\.([*+])/, '[^:]\1?')
83
+ end
84
+ IO.popen("rake -T \"^#{val}:\"").each { |line| project << $1 if line =~ /\Arake (#{val}):/o }
85
+ end
86
+ exit 1 if project.empty? && !pattern.empty?
87
+ project.uniq!
88
+ options[:'project-env'].each do |val|
89
+ n = val.index('=')
90
+ key = val[...n]
91
+ val = val[n.succ..].stripquote
92
+ project.each { |name| ENV["#{key}_#{env_key(name.split(':').first)}"] = val }
93
+ end
94
+ ARGV.each_with_index do |val, index|
95
+ if val == '--'
96
+ separator!(index: index)
97
+ break
98
+ end
99
+ next unless val.start_with?(':')
100
+
101
+ args = options[:'project-args'].shift
102
+ global.concat(project.map { |name| "#{name}#{val}#{"[#{args}]" if args}" })
103
+ ARGV[index] = ''
104
+ end
105
+ end
106
+ ARGV.reject!(&:empty?)
107
+ Rake.application.run(global.concat(ARGV))
108
+ end
109
+
110
+ def separator!(index:)
111
+ ARGV[index] = '' if ARGV.grep('--').size > 1
112
+ end
113
+
114
+ def error_exit(*val, hint)
115
+ raise OptionParser::InvalidArgument, message(*val, hint: hint)
116
+ end
117
+ end
118
+
119
+ SqdParser.new do |sqd|
120
+ session = Squared::Common::ARG
121
+ sqd.banner = 'Usage: sqd [options] [rake options] [global...] [:targets...] -- [rake targets...]'
122
+ sqd.separator ''
123
+ sqd.on('-R', '--ref STR,STR', Array, 'Run global commands by class reference') do |val|
124
+ sqd.parse_global(val, assert: :group)
125
+ session[:APP][:series_ref_min] = 1
126
+ end
127
+ sqd.on('-G', '--group STR,STR', Array, 'Run global commands by project group') do |val|
128
+ sqd.parse_global(val, assert: :ref)
129
+ end
130
+ sqd.separator ''
131
+ sqd.on('-P', '--project STR,PAT', Array, 'Run project commands with common arguments')
132
+ sqd.on('-a', '--project-args STR,STR', 'Provide command arguments for :targets (multiple)') do |val|
133
+ sqd.options[:'project-args'] << val
134
+ end
135
+ sqd.on('-e', '--project-env KEY=STR', 'Provide command ENV variables for :targets (multiple)') do |val|
136
+ sqd.error_exit('missing value', "#{val}=") unless val.include?('=')
137
+
138
+ sqd.options[:'project-env'] << val
139
+ end
140
+ sqd.separator ''
141
+ sqd.on('-s', '--[no-]strict', 'Do not run commands with invalid arguments') do |val|
142
+ session[:STRICT] = val
143
+ ENV['STRICT'] = val ? 'true' : 'false'
144
+ end
145
+ sqd.on('--update', 'Use update strategy for applicable commands') do
146
+ ENV['UPDATE'] = 'true'
147
+ end
148
+ sqd.on('-F', '--force [STR,STR]', Array, 'Enable force through ENV by application') do |val|
149
+ sqd.parse_common(val, session: session, arg: :FORCE)
150
+ end
151
+ sqd.on('-y', '--yes [STR,STR]', Array, 'Enable auto-approve through ENV by application') do |val|
152
+ sqd.parse_common(val, session: session, arg: :YES)
153
+ end
154
+ sqd.on('-d', '--dry-run', 'Run commands without any modifying actions') do
155
+ ENV['DRY_RUN'] = 'true'
156
+ end
157
+ sqd.separator ''
158
+ sqd.on('-S', '--select PAGE:CHOICE', 'Prompt menu selection pagination limits') do |val|
159
+ page, choice = val.split(/\D/, 2).map(&:to_i)
160
+ sqd.error_exit('not an integer', val) if choice.nil? ? page == 0 : choice == 0
161
+
162
+ session[:PAGE] = page if page > 0
163
+ session[:CHOICE] = choice if choice.to_i > 0
164
+ ENV['SELECT'] = "#{page}:#{choice}"
165
+ end
166
+ sqd.separator ''
167
+ sqd.on('-p', '--pipe 0|1|2', Integer, 'Set file descriptor for communication') do |val|
168
+ sqd.error_exit('out of range', val) unless val.between?(0, 2)
169
+
170
+ session[:PIPE] = val
171
+ end
172
+ sqd.on('-o', '--pipe-out FILE', 'Write command data stream to a file') do |val|
173
+ sqd.error_exit("missing an explicit \".#{File::SEPARATOR}\"", val) unless val.include?(File::SEPARATOR)
174
+
175
+ session[:OUT] = val
176
+ end
177
+ sqd.on('--fail 0..4', Integer, 'Set application exception level') do |val|
178
+ sqd.error_exit('out of range', val) unless val.between?(0, 4)
179
+
180
+ session[:FAIL] = val
181
+ end
182
+ %i[debug info warn error fatal].then do |state|
183
+ values = state + (0..4).map(&:to_s)
184
+ sqd.on('--log-level SEVERITY', values, "Set logger and exception state (#{state.join(', ')})") do |val|
185
+ require 'logger'
186
+ severity = case val
187
+ when :debug then Logger::DEBUG
188
+ when :info then Logger::INFO
189
+ when :warn then Logger::WARN
190
+ when :error then Logger::ERROR
191
+ when :fatal then Logger::FATAL
192
+ else
193
+ val.to_i
194
+ end
195
+ session[:LEVEL] = severity
196
+ ENV['LOG_LEVEL'] = severity.to_s
197
+ end
198
+ end
199
+ sqd.separator ''
200
+ sqd.on('--[no-]banner', 'Display executing command attributes') do |val|
201
+ sqd.banner_set(val, session: session)
202
+ end
203
+ sqd.on('-x', '--[no-]color', 'Use enhanced styling for terminal output') do |val|
204
+ sqd.color_set(val, session: session)
205
+ end
206
+ sqd.on('-X', '--plain', 'Disable banner and styling for all commands') do
207
+ sqd.banner_set(false, session: session)
208
+ sqd.color_set(false, session: session)
209
+ end
210
+ sqd.on('-v', '--verbose', 'Increase output verbosity (multiple)') do
211
+ unless session[:VERBOSE]
212
+ session[:VERBOSE] = $VERBOSE ? 1 : 0
213
+ sqd.global.unshift('--verbose')
214
+ end
215
+ ENV['VERBOSE'] = (session[:VERBOSE] += 1).to_s
216
+ end
217
+ sqd.on('--version', 'Print the current version') do
218
+ puts Squared::VERSION
219
+ exit 0
220
+ end
221
+ sqd.on('-h', '--help', 'Print the command line options') do
222
+ sqd.help_exit
223
+ end
224
+ end.run
@@ -11,13 +11,17 @@ module Squared
11
11
  COMMON: true,
12
12
  VERBOSE: nil,
13
13
  STRICT: false,
14
+ FORCE: {},
15
+ YES: {},
16
+ APP: {},
14
17
  BANNER: true,
15
- CHOICE: 25,
18
+ PAGE: 20,
19
+ CHOICE: 100,
16
20
  QUOTE: "'",
17
21
  SPACE: ' => ',
18
22
  SUCCESS: 'Success',
19
- GRAPH: %w[| - | \\ -].freeze,
20
- BORDER: %w[| - - - - - | | - -].freeze,
23
+ GRAPH: %w[| - | \\ -],
24
+ BORDER: %w[| - - - - - | | - -],
21
25
  VIEW: 'view',
22
26
  LEVEL: ENV.fetch('LOG_LEVEL', 0).to_i,
23
27
  COLOR: ENV.fetch('NO_COLOR', '').empty?
@@ -50,9 +50,14 @@ module Squared
50
50
  self
51
51
  end
52
52
 
53
- def enable_drawing
54
- ARG[:GRAPH] = BOX_GRAPH
55
- ARG[:BORDER] = BOX_BORDER
53
+ def enable_drawing(state = true)
54
+ if state
55
+ ARG[:GRAPH] = BOX_GRAPH unless ARG[:GRAPH].frozen?
56
+ ARG[:BORDER] = BOX_BORDER unless ARG[:BORDER].frozen?
57
+ else
58
+ ARG[:GRAPH].freeze
59
+ ARG[:BORDER].freeze
60
+ end
56
61
  self
57
62
  end
58
63
 
@@ -1,27 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'timeout'
4
+
3
5
  module Squared
4
6
  module Common
5
7
  module Prompt
6
8
  def self.reline
7
- if RUBY_ENGINE == 'ruby' && RUBY_VERSION < '2.7'
8
- require 'readline'
9
- Readline
10
- else
11
- begin
12
- require 'reline'
13
- Reline
14
- rescue LoadError
15
- require 'readline'
16
- Readline
17
- end
18
- end
9
+ require 'reline'
10
+ Reline
11
+ rescue LoadError
12
+ require 'readline'
13
+ Readline
19
14
  end
20
15
 
21
16
  module_function
22
17
 
23
18
  def confirm(msg, accept = nil, agree: 'Y', cancel: 'N', force: false, attempts: 3, timeout: 60)
24
- require 'timeout'
25
19
  if agree == 'Y' && cancel == 'N' && !msg.match?(%r{\[(Yn|nY|Y/n|y/N)\]})
26
20
  case accept
27
21
  when 'Y'
@@ -34,7 +28,7 @@ module Squared
34
28
  cancel = /^#{Regexp.escape(cancel)}$/i if cancel.is_a?(::String)
35
29
  Timeout.timeout(timeout) do
36
30
  while (ch = Prompt.reline.readline(msg))
37
- ch = ch.chomp
31
+ ch.chomp!
38
32
  case (ch.empty? ? accept : ch)
39
33
  when agree
40
34
  return true
@@ -54,9 +48,9 @@ module Squared
54
48
  false
55
49
  end
56
50
 
57
- def choice(msg, list = nil, min: 1, max: 1, multiple: false, index: false, grep: nil, border: nil, auto: true,
58
- force: true, attempts: 3, timeout: 0, empty: nil)
59
- require 'timeout'
51
+ def choice(msg, list = nil, min: 1, max: nil, multiple: false, index: false, grep: nil, border: nil, force: true,
52
+ attempts: 3, timeout: 0, pipe: 1, scroll: true, empty: nil, page: 25)
53
+ std = pipe == 2 ? $stderr : $stdout
60
54
  multiple = Array(multiple) if multiple.is_a?(::Numeric)
61
55
  if list
62
56
  grep &&= Array(grep).map { |val| Regexp.new(val) }
@@ -64,36 +58,71 @@ module Squared
64
58
  next if grep&.none? { |pat| pat.match?(val) }
65
59
 
66
60
  out << val.to_s.chomp
67
- puts '%2d. %s' % [out.size, val]
68
61
  end
69
- max = items.size
62
+ max = max ? [max, items.size].min : items.size
70
63
  if max == 0
71
64
  raise ArgumentError, 'empty selection list' unless empty
72
65
 
73
66
  puts empty
74
67
  exit 1
75
68
  end
69
+ tmpl = "%#{[items.size.to_s.size, 2].max}d. %s"
70
+ items = items.map.with_index { |item, i| [item, tmpl % [i.succ, item]] }
76
71
  min = grep ? 1 : [min, max].min
77
- if auto
78
- auto.times { puts } if auto.is_a?(::Numeric)
72
+ require 'io/console'
73
+ if min > 1 || max < items.size
74
+ items = items[min.pred...max]
75
+ min = 1
76
+ end
77
+ page = page ? [page, max].min : max
78
+ cur = 0
79
+ line = 0
80
+ last = (max / page.to_f).ceil
81
+ pre = msg
82
+ scroll = true if border
83
+ clear = -> { std.print "\r\e[K" }
84
+ write = lambda do |s, buf = true|
85
+ line += [s.lines.size, 1].max if buf
86
+ clear.call unless scroll && !border
87
+ std.puts s
88
+ end
89
+ render = lambda do |index, init = false|
90
+ fr = index * page
91
+ to = [fr + page, max].min
92
+ unless init
93
+ std.cursor_up((scroll ? 0 : page) + line.succ)
94
+ clear.call
95
+ end
96
+ line = 0
97
+ items[fr...to].each { |item| write.call(item.last, false) }
79
98
  if border == true
80
- puts print_footer
99
+ write.call(print_footer)
81
100
  elsif border
82
- puts print_footer(border: border)
101
+ write.call(print_footer(border: border))
102
+ end
103
+ fr = scroll ? 1 : fr.succ
104
+ suf = "|,#{multiple.is_a?(::Array) ? "{#{multiple.join(',')}}" : '*'}" if multiple
105
+ msg = "#{pre + (force ? ':' : '?')} [#{fr}-#{to}#{"/#{max}" if scroll && to < max}#{suf}] "
106
+ if cur == last.pred
107
+ cur = -1
108
+ last = 0 if scroll || (attempts -= 1) == 0
109
+ end
110
+ if init && last > 1 && !scroll
111
+ write.call('', false)
112
+ std.cursor_up(1)
83
113
  end
84
- msg = "#{msg + (force ? ':' : '?')} [#{min}-#{max}#{if (n = multiple)
85
- "|,#{n.is_a?(::Array) ? "{#{n.join(',')}}" : '*'}"
86
- end}] "
87
114
  end
115
+ render.call(0, true)
116
+ else
117
+ max ||= 1
118
+ last = 0
88
119
  end
89
120
  between = ->(s) { s.match?(/^\d+$/) && s.to_i.between?(min, max <= min ? Float::INFINITY : max) }
90
121
  Timeout.timeout(timeout) do
91
122
  while (ch = Prompt.reline.readline(msg))
92
123
  ch.strip!
93
- unless ch.empty?
94
- if ch == '-' && !force
95
- break
96
- elsif multiple
124
+ if !ch.empty?
125
+ if multiple
97
126
  k = if ch == '*'
98
127
  (min..max).to_a
99
128
  else
@@ -114,12 +143,15 @@ module Squared
114
143
  k.uniq!
115
144
  k.sort!
116
145
  unless multiple.is_a?(::Array) && !multiple.include?(k.size)
117
- return index || !items ? k : k.map { |i| items[i.pred] }
146
+ return index || !items ? k : k.map { |i| items[i.pred].first }
118
147
  end
119
148
  end
120
149
  elsif between.call(ch)
121
- return index || !items ? ch.to_i : items[ch.to_i.pred]
150
+ return index || !items ? ch.to_i : items[ch.to_i.pred].first
122
151
  end
152
+ elsif last > 0
153
+ render.call(cur += 1)
154
+ next
123
155
  end
124
156
  attempts -= 1
125
157
  next if attempts > 0
@@ -128,7 +160,7 @@ module Squared
128
160
  break
129
161
  end
130
162
  rescue Interrupt
131
- puts
163
+ std.puts
132
164
  exit 0
133
165
  else
134
166
  [] if multiple
@@ -167,7 +167,9 @@ module Squared
167
167
  end
168
168
 
169
169
  def line_width(lines)
170
- [lines.empty? ? 80 : [lines.max_by(&:size).size, 80].max, Rake.application.terminal_width].min
170
+ require 'io/console/size'
171
+ cols = IO.default_console_size.last
172
+ [lines.empty? ? cols : [lines.max_by(&:size).size, cols].max, Rake.application.terminal_width].min
171
173
  end
172
174
 
173
175
  def fill_option(val, **kwargs)
@@ -28,15 +28,8 @@ module Squared
28
28
  module_function
29
29
 
30
30
  def shell(*args, name: :system, **kwargs)
31
- if name != :system
32
- kwargs.delete(:exception)
33
- elsif RUBY_VERSION < '2.6'
34
- ex = kwargs.delete(:exception)
35
- end
36
- ret = Kernel.send(name, *args, **kwargs)
37
- raise $?.to_s if ex && !ret
38
-
39
- ret
31
+ kwargs.delete(:exception) unless name == :system
32
+ Kernel.send(name, *args, **kwargs)
40
33
  end
41
34
 
42
35
  def shell_t(*args, timeout: 0, **kwargs)
@@ -65,7 +65,7 @@ module Squared
65
65
  command = File.basename(@main)
66
66
  command = ARG[:VIEW] if command == @name
67
67
  end
68
- ext = @ext[1..-1].downcase
68
+ ext = @ext[1..].downcase
69
69
  if (data = @@mime_obj[ext])
70
70
  add(data[1].first, command: command, opts: opts, ext: data[1])
71
71
  else
@@ -98,7 +98,7 @@ module Squared
98
98
  namespace task_name(name) do |ns|
99
99
  @mime.each do |type, items|
100
100
  items.each do |command, file, opts|
101
- next if Rake::Task.task_defined?("#{ns.scope.path}:#{command}:#{type}")
101
+ next if Rake::Task.task_defined?(task_join(ns.scope.path, command, type))
102
102
 
103
103
  namespace command do
104
104
  unless (data = @@mime_obj[type])
@@ -288,7 +288,7 @@ module Squared
288
288
  if project
289
289
  project.workspace.task_name(val)
290
290
  else
291
- @prefix ? "#{@prefix}:#{val}" : val.to_s
291
+ @prefix ? task_join(@prefix, val) : val.to_s
292
292
  end
293
293
  end
294
294
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- VERSION = '0.8.6'
4
+ VERSION = '0.9.0.pre1'
5
5
  end
@@ -163,6 +163,9 @@ module Squared
163
163
  end
164
164
  @pass.items.concat(kwargs[:pass].map { |val| val.is_a?(Regexp) ? val : val.to_s }) if kwargs[:pass]
165
165
  @series = Application.register(self, @base.to_a, exclude: kwargs.fetch(:exclude, []))
166
+ if (n = ARG[:APP][:series_ref_min])
167
+ @series.ref_min = n
168
+ end
166
169
  self.closed = 'begin'
167
170
  pb = @stage.key?('project:begin')
168
171
  pe = @stage.key?('project:end')
@@ -341,7 +344,7 @@ module Squared
341
344
  case val
342
345
  when Symbol
343
346
  found = true
344
- banner_include?(val)
347
+ banner_include?(val, ref: ref)
345
348
  when String
346
349
  true
347
350
  else
@@ -353,7 +356,7 @@ module Squared
353
356
  elsif meth.size == 1
354
357
  meth = meth.first
355
358
  end
356
- elsif !banner_include?(meth = meth.to_sym)
359
+ elsif !banner_include?(meth = meth.to_sym, ref: ref)
357
360
  next
358
361
  end
359
362
  data.order << meth
@@ -403,13 +406,17 @@ module Squared
403
406
  end
404
407
  unless ref.is_a?(Symbol) && (proj = @base.find { |item| item.ref == ref })
405
408
  proj = if !ref.is_a?(Class)
406
- find_project(ref: ref, path: path)
409
+ require_project(ref) || Application.find(ref: ref, path: path)
407
410
  elsif Application.extends(ref)
408
411
  ref
409
412
  end || @kind[name]&.last
410
413
  if proj
411
414
  @base << proj
412
- @banner.items.concat(Array(proj.bannerargs))
415
+ args = Array(proj.bannerargs)
416
+ unless args.empty?
417
+ @banner.store[proj.ref] = args
418
+ @banner.items.concat(args)
419
+ end
413
420
  else
414
421
  proj = Application.impl_project
415
422
  end
@@ -447,16 +454,6 @@ module Squared
447
454
  self
448
455
  end
449
456
 
450
- def assign(ref = @ref, &blk)
451
- proj = ref && find_project(ref: ref)
452
- if proj
453
- proj.class_eval(&blk)
454
- else
455
- warn log_message(Logger::ERROR, 'class not found', subject: main, hint: ref)
456
- end
457
- self
458
- end
459
-
460
457
  def stage(val, first: false, &blk)
461
458
  data = @stage[val]
462
459
  if first == true
@@ -484,7 +481,7 @@ module Squared
484
481
  obj = begin
485
482
  JSON.parse(homepath(obj).read, { symbolize_names: true })
486
483
  rescue => e
487
- warn log_message(Logger::ERROR, e, subject: main)
484
+ warn log_message(Logger::ERROR, e)
488
485
  end
489
486
  end
490
487
  apply_style(data || theme, obj, args, empty: empty) if obj && (!target || data)
@@ -590,7 +587,7 @@ module Squared
590
587
  def task_namespace(val, first: false)
591
588
  return unless (ret = val.to_s.split(':')).size > 1
592
589
 
593
- first ? ret.first : task_join(*ret[0..-2])
590
+ first ? ret.first : task_join(*ret[..-2])
594
591
  end
595
592
 
596
593
  def task_resolve(obj, key)
@@ -960,7 +957,7 @@ module Squared
960
957
  key = task_name(task_join(name, target))
961
958
  sync = true
962
959
  exception = exception?
963
- if store && (kwargs = store["#{target}:#{name}"])
960
+ if store && (kwargs = store[task_join(target, name)])
964
961
  sync = kwargs[:sync] if kwargs.key?(:sync)
965
962
  exception = kwargs[:exception] if kwargs.key?(:exception)
966
963
  end
@@ -981,9 +978,11 @@ module Squared
981
978
  end
982
979
  end
983
980
  when Array
984
- cmd = args.first
985
- cmd = items.map { |proj| "#{proj.name}:#{cmd}" }
986
- .select { |val| task_defined?(val) }
981
+ cmd = items.filter_map do |proj|
982
+ next unless task_defined?(out = task_join(proj.name, args.first))
983
+
984
+ out
985
+ end
987
986
  next if cmd.empty?
988
987
 
989
988
  args = args.drop(1)
@@ -1024,7 +1023,7 @@ module Squared
1024
1023
  @events[label][name][task] = on
1025
1024
  end
1026
1025
  data[label][name][task] = val
1027
- (data.store[label] ||= {})["#{name}:#{task}"] = store if store
1026
+ (data.store[label] ||= {})[task_join(name, task)] = store if store
1028
1027
  end
1029
1028
  self
1030
1029
  end
@@ -1038,7 +1037,7 @@ module Squared
1038
1037
  Array(group).each do |val|
1039
1038
  val = val.to_s
1040
1039
  if val.start_with?('-')
1041
- target[:exclude] << val[1..-1]
1040
+ target[:exclude] << val[1..]
1042
1041
  else
1043
1042
  target[:group][val] = data
1044
1043
  end
@@ -1047,7 +1046,7 @@ module Squared
1047
1046
  Array(ref).each do |val|
1048
1047
  val = val.to_s
1049
1048
  if val.start_with?('-')
1050
- target[:exclude] << val[1..-1].to_sym
1049
+ target[:exclude] << val[1..].to_sym
1051
1050
  else
1052
1051
  target[:ref][val.to_sym] = data
1053
1052
  end
@@ -1092,10 +1091,6 @@ module Squared
1092
1091
  nil
1093
1092
  end
1094
1093
 
1095
- def find_project(ref:, path: nil)
1096
- require_project(ref) || Application.find(ref: ref, path: path)
1097
- end
1098
-
1099
1094
  def root?(path, pass: [])
1100
1095
  return false unless path.directory?
1101
1096
 
@@ -1125,8 +1120,10 @@ module Squared
1125
1120
  exception != false && exception != Logger::INFO
1126
1121
  end
1127
1122
 
1128
- def banner_include?(val)
1129
- Application.attr_banner.include?(val) || @banner.items.include?(val)
1123
+ def banner_include?(val, ref: nil)
1124
+ return true if Application.attr_banner.include?(val)
1125
+
1126
+ ref ? Array(ref).any? { |proj| @banner.store[proj]&.include?(val) } : @banner.items.include?(val)
1130
1127
  end
1131
1128
 
1132
1129
  def scriptobj