squared 0.2.2 → 0.3.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.
@@ -25,7 +25,7 @@ module Squared
25
25
  def bannerargs(*); end
26
26
 
27
27
  def tasks
28
- %i[build depend graph doc test copy clean].freeze
28
+ %i[build depend graph doc lint test copy clean].freeze
29
29
  end
30
30
 
31
31
  def as_path(val)
@@ -46,7 +46,7 @@ module Squared
46
46
  end
47
47
 
48
48
  def to_s
49
- super.match(/[^:]+\z/)[0]
49
+ super[/[^:]+\z/, 0]
50
50
  end
51
51
  end
52
52
 
@@ -68,12 +68,19 @@ module Squared
68
68
  @group = group&.to_s.freeze
69
69
  @depend = kwargs[:depend]
70
70
  @doc = kwargs[:doc]
71
+ @lint = kwargs[:lint]
71
72
  @test = kwargs[:test]
72
73
  @copy = kwargs[:copy]
73
74
  @clean = kwargs[:clean]
74
75
  @version = kwargs[:version]
75
- @exception = kwargs.key?(:exception) ? env_bool(kwargs[:exception]) : workspace.exception
76
- @pipe = kwargs.key?(:pipe) ? env_pipe(kwargs[:pipe]) : workspace.pipe
76
+ @envname = @name.gsub(/[^\w]+/, '_').upcase.freeze
77
+ kwargs[:exception] = 'PIPE_FAIL'
78
+ @exception = if kwargs.key?(:exception)
79
+ env_bool(kwargs[:exception], workspace.exception, strict: true)
80
+ else
81
+ workspace.exception
82
+ end
83
+ @pipe = kwargs.key?(:pipe) ? env_pipe(kwargs[:pipe], workspace.pipe, strict: true) : workspace.pipe
77
84
  @verbose = kwargs.key?(:verbose) ? kwargs[:verbose] : workspace.verbose
78
85
  @theme = if !@verbose
79
86
  {}
@@ -95,7 +102,6 @@ module Squared
95
102
  last: last,
96
103
  error: error
97
104
  }
98
- @envname = @name.gsub(/[^\w]+/, '_').upcase.freeze
99
105
  @desc = (@name.include?(':') ? @name.split(':').join(ARG[:SPACE]) : @name).freeze
100
106
  @parent = nil
101
107
  @global = false
@@ -116,6 +122,7 @@ module Squared
116
122
  end
117
123
  @depend = @script[:depend] if @depend.nil?
118
124
  @doc = @script[:doc] if @doc.nil?
125
+ @lint = @script[:lint] if @lint.nil?
119
126
  @test = @script[:test] if @test.nil?
120
127
  @clean = @script[:clean] if @clean.nil?
121
128
  @exclude = @script[:exclude] if @exclude.empty? && @script.key?(:exclude)
@@ -128,7 +135,7 @@ module Squared
128
135
  if @output[0].nil?
129
136
  if (scr = data[:script])
130
137
  @global = true
131
- script_set(scr, prod: kwargs[:prod])
138
+ script_set(scr, args: data.fetch(:args, kwargs[:args]), prod: kwargs[:prod])
132
139
  elsif (run = data[:run])
133
140
  @global = true
134
141
  run_set run
@@ -136,11 +143,11 @@ module Squared
136
143
  unless data[:env]
137
144
  if (scr = kwargs[:script])
138
145
  @global = false
139
- script_set scr
146
+ script_set(scr, args: kwargs[:args])
140
147
  elsif @script && !data[:global]
141
148
  if (scr = @script[:script])
142
149
  @global = false
143
- script_set scr
150
+ script_set(scr, args: @script.fetch(:args, kwargs[:args]))
144
151
  elsif (run = @script[:run])
145
152
  @global = false
146
153
  run_set run
@@ -151,6 +158,7 @@ module Squared
151
158
  @global = true
152
159
  run_set data[:run]
153
160
  end
161
+ @global = true
154
162
  end
155
163
 
156
164
  def initialize_events(ref, **)
@@ -194,14 +202,10 @@ module Squared
194
202
  end
195
203
 
196
204
  def initialize_env(dev: nil, prod: nil, **)
197
- pre = "BUILD_#{@envname}"
198
- @dev = env_match("#{pre}_DEV", dev)
199
- @prod = env_match("#{pre}_PROD", prod)
205
+ @dev = env_match('BUILD', dev, suffix: 'DEV', strict: true)
206
+ @prod = env_match('BUILD', prod, suffix: 'PROD', strict: true)
200
207
  cmd = @output[0]
201
- unless cmd == false || cmd.is_a?(Array) || (val = env('BUILD', suffix: 'OPTS')).nil?
202
- @output[cmd ? 1 : 3] = shell_split(val, join: true)
203
- end
204
- unless @output[2] == false || (val = env('BUILD', suffix: 'ENV')).nil?
208
+ if @output[2] != false && (val = env('BUILD', suffix: 'ENV'))
205
209
  begin
206
210
  data = JSON.parse(val)
207
211
  raise_error('invalid JSON object', val, hint: "#{prefix}_ENV") unless data.is_a?(Hash)
@@ -211,6 +215,10 @@ module Squared
211
215
  @output[2] = data
212
216
  end
213
217
  end
218
+ if cmd != false && !cmd.is_a?(Array)
219
+ @output[cmd ? 1 : 3] = shell_split(val, join: true) if (val = env('BUILD', suffix: 'OPTS'))
220
+ @output[4] = shell_split(val, join: true) if cmd.nil? && (val = env('SCRIPT', suffix: 'OPTS'))
221
+ end
214
222
  @version = val if (val = env('BUILD', suffix: 'VERSION'))
215
223
  return unless (val = env('BUILD', strict: true))
216
224
 
@@ -242,23 +250,16 @@ module Squared
242
250
  when 'graph'
243
251
  next unless graph?
244
252
 
245
- check = lambda do |args|
246
- next args if (args = args.to_a).empty?
247
-
248
- param_guard(action, flag, args: args.reject { |val| name == val.to_s })
249
- end
250
-
251
- format_desc action, flag, 'project*'
252
- if flag == :run
253
- task flag do |_, args|
254
- graph check.(args)
255
- end
256
- else
257
- task flag do |_, args|
258
- out, done = graph(check.(args), out: [])
253
+ format_desc action, flag, '(-)project*'
254
+ task flag do |_, args|
255
+ args = param_guard(action, flag, args: args.to_a.reject { |val| name == val.to_s })
256
+ if flag == :run
257
+ graph args
258
+ else
259
+ out, done = graph(args, out: [])
259
260
  out.map! do |val|
260
261
  done.each_with_index do |proj, i|
261
- next unless Regexp.new(" #{Regexp.escape(proj.name)}(?:@\\d|\\z)") =~ val
262
+ next unless val =~ / #{Regexp.escape(proj.name)}(?:@\d|\z)/
262
263
 
263
264
  val += " (#{i.succ})"
264
265
  break
@@ -301,8 +302,8 @@ module Squared
301
302
  false
302
303
  end
303
304
  end
304
- if path.is_a?(String) && (data = %r{^(.+)[\\/]\*+$}.match(path))
305
- return self unless checkdir.(path = basepath(data[1]))
305
+ if path.is_a?(String) && (seg = path[%r{^(.+)[\\/]\*+$}, 1])
306
+ return self unless checkdir.(path = basepath(seg))
306
307
 
307
308
  path = path.children.select { |val| checkdir.(val) }
308
309
  end
@@ -340,63 +341,87 @@ module Squared
340
341
 
341
342
  out = obj.link(self, *args, **kwargs, &blk) if obj.respond_to?(:link)
342
343
  if !out
343
- warn log_message(:warn, 'link not compatible', subject: obj.to_s, hint: name)
344
+ warn log_message(Logger::WARN, 'link not compatible', subject: obj.to_s, hint: name)
344
345
  elsif out.respond_to?(:build)
345
346
  out.build
346
347
  end
347
348
  self
348
349
  end
349
350
 
350
- def build(*args, from: :build, sync: invoked_sync?('build'), **)
351
+ def build(*args, sync: invoked_sync?('build'), from: :run, **)
351
352
  banner = verbose
352
353
  if args.empty?
353
- return unless from == :build
354
+ return unless from == :run
354
355
 
355
- cmd, opts, var, flags = @output
356
+ args = @output
356
357
  banner = verbose == 1 if task_invoked?('build', 'build:sync')
358
+ end
359
+ if args.all? { |val| val.is_a?(Array) }
360
+ cmd = []
361
+ var = {}
362
+ args.each do |val|
363
+ a, b, c, d, e = val
364
+ case b
365
+ when Hash
366
+ b = append_hash(b).join(' ')
367
+ when Enumerable
368
+ b = b.to_a.join(' ')
369
+ end
370
+ d = append_hash(d).join(' ') if d.is_a?(Hash)
371
+ if a
372
+ cmd << [a, d, b].compact.join(' ')
373
+ else
374
+ next unless respond_to?(:compose)
375
+
376
+ cmd << a if (a = compose(as_get(b), d, script: true, args: e, from: from))
377
+ end
378
+ var.merge!(c) if c.is_a?(Hash)
379
+ end
380
+ cmd = cmd.join(' && ')
357
381
  else
358
- cmd = args.shift
359
- opts = args.map { |val| shell_quote(val, force: false) }.join(' ')
382
+ cmd, opts, var, flags, scr = args
360
383
  end
361
384
  if cmd
385
+ cmd = as_get(cmd)
386
+ opts = compose(opts, script: false) if opts && respond_to?(:compose)
387
+ flags = append_hash(flags).join(' ') if flags.is_a?(Hash)
362
388
  case opts
363
- when String
364
- cmd = "#{cmd} #{opts}"
365
- when Array
366
- cmd = as_a(cmd).concat(opts).join(' && ')
389
+ when Hash
390
+ opts = append_hash(opts)
391
+ cmd = as_a(cmd).push(flags).concat(opts).compact.join(' ')
392
+ when Enumerable
393
+ cmd = as_a(cmd).concat(opts.to_a)
394
+ cmd.map! { |val| "#{val} #{flags}" } if flags
395
+ cmd = cmd.join(' && ')
367
396
  else
368
- cmd = [cmd, compose(opts, script: false)].compact.join(' ') unless opts == false || !respond_to?(:compose)
397
+ cmd = [cmd, flags, opts].compact.join(' ') if opts || flags
369
398
  end
370
399
  else
371
400
  return unless respond_to?(:compose)
372
401
 
373
- cmd = compose(opts, flags, from: from, script: true)
402
+ cmd = compose(as_get(opts), flags, script: true, args: scr, from: from)
374
403
  end
375
404
  run(cmd, var, from: from, banner: banner, sync: sync)
376
405
  end
377
406
 
378
407
  def depend(*, sync: invoked_sync?('depend'), **)
379
- return unless @depend
380
-
381
- run(@depend, from: :depend, sync: sync)
382
- end
383
-
384
- def copy(*, sync: invoked_sync?('copy'), **)
385
- return unless @copy
386
-
387
- run_s(@copy, from: :copy, sync: sync)
408
+ run_b(@depend, sync: sync, from: :depend)
388
409
  end
389
410
 
390
411
  def doc(*, sync: invoked_sync?('doc'), **)
391
- return unless @doc
412
+ run_b(@doc, sync: sync, from: :doc)
413
+ end
392
414
 
393
- build(*as_a(@doc), from: :doc, sync: sync)
415
+ def lint(*, sync: invoked_sync?('lint'), **)
416
+ run_b(@lint, sync: sync, from: :lint)
394
417
  end
395
418
 
396
419
  def test(*, sync: invoked_sync?('test'), **)
397
- return unless @test
420
+ run_b(@test, sync: sync, from: :test)
421
+ end
398
422
 
399
- build(*as_a(@test), from: :test, sync: sync)
423
+ def copy(*, sync: invoked_sync?('copy'), **)
424
+ run_b(@copy, sync: sync, from: :copy)
400
425
  end
401
426
 
402
427
  def clean(*, sync: invoked_sync?('clean'), **)
@@ -405,14 +430,22 @@ module Squared
405
430
  on :first, :clean
406
431
  case @clean
407
432
  when String
408
- run(@clean, from: :clean, sync: sync)
433
+ run_s(@clean, from: :clean, sync: sync)
434
+ when Hash
435
+ begin
436
+ @clean.each { |cmd, opts| build(cmd.to_s, opts, sync: sync) }
437
+ rescue StandardError => e
438
+ log.error e
439
+ ret = on(:error, from, e)
440
+ raise if @exception && ret != true
441
+ end
409
442
  when Enumerable
410
- (@clean.is_a?(Hash) ? @clean.values : as_a(@clean)).each do |val|
443
+ as_a(@clean).each do |val|
411
444
  val = val.to_s
412
445
  path = basepath(val)
413
446
  if path.directory? && val =~ %r{[\\/]\z}
414
447
  log.warn "rm -rf #{path}"
415
- path.rmtree(verbose: true)
448
+ path.rmtree(verbose: verbose)
416
449
  else
417
450
  log.warn "rm #{path}"
418
451
  (val.include?('*') ? Dir[path] : [path]).each do |file|
@@ -441,8 +474,9 @@ module Squared
441
474
  end
442
475
  end
443
476
  end
444
- pass.concat(split_escape(val)) if (val = env('GRAPH_PASS', strict: true))
445
- data = graph_collect(self, start)
477
+ pass += split_escape(val) if (val = env('GRAPH', suffix: 'PASS'))
478
+ start, neg = start.partition { |name| !name.start_with?('-') }
479
+ data = graph_collect(self, start, pass: neg.map { |name| name[1..-1] })
446
480
  unless out
447
481
  data[name] << self
448
482
  on :first, :graph
@@ -476,6 +510,12 @@ module Squared
476
510
  (@events[name.to_sym] ||= {})[key.to_sym] = [block_given? ? [blk] + args : args, kwargs]
477
511
  end
478
512
 
513
+ def as(cmd, script, to = nil)
514
+ script = { "#{script}": to } if to
515
+ data = (@as ||= {})[cmd.to_sym] ||= {}
516
+ script.each { |key, val| data[key.to_s] = val }
517
+ end
518
+
479
519
  def variable_set(key, *val, **kwargs)
480
520
  if variables.include?(key)
481
521
  case key
@@ -544,6 +584,10 @@ module Squared
544
584
  !!@doc
545
585
  end
546
586
 
587
+ def lint?
588
+ !!@lint
589
+ end
590
+
547
591
  def test?
548
592
  !!@test
549
593
  end
@@ -623,9 +667,16 @@ module Squared
623
667
  end
624
668
 
625
669
  def run(cmd = @session, var = nil, exception: @exception, sync: true, banner: true, chdir: path, from: nil, **)
670
+ unless cmd
671
+ if warning?
672
+ from &&= from.to_s
673
+ warn log_message(Logger::WARN, from || 'unknown', subject: project, hint: 'no command given')
674
+ end
675
+ return
676
+ end
626
677
  cmd = session_done(cmd)
627
678
  log.info cmd
628
- on :first, from if from
679
+ on :first, from
629
680
  begin
630
681
  if cmd.match?(/\A[^:]+:[^:]/) && workspace.task_defined?(cmd)
631
682
  log.warn "ENV was discarded: #{var}" if var
@@ -637,22 +688,32 @@ module Squared
637
688
  end
638
689
  rescue StandardError => e
639
690
  log.error e
640
- ret = on(:error, from, e) if from
691
+ ret = on(:error, from, e)
641
692
  raise unless ret == true
642
693
  else
643
- on :last, from if from
694
+ on :last, from
644
695
  end
645
696
  end
646
697
 
647
698
  def run_s(*cmd, env: nil, sync: true, banner: verbose != false, from: nil, **kwargs)
648
- on :first, from if from
699
+ on :first, from
649
700
  begin
650
701
  cmd.flatten.each { |val| run(val, env, sync: sync, banner: banner, **kwargs) }
651
702
  rescue StandardError => e
652
- ret = on(:error, from, e) if from
703
+ ret = on(:error, from, e)
653
704
  raise unless ret == true
654
705
  end
655
- on :last, from if from
706
+ on :last, from
707
+ end
708
+
709
+ def run_b(obj, from: nil, sync: true)
710
+ return unless obj
711
+
712
+ if obj.is_a?(Array) && obj.any? { |val| !val.is_a?(String) }
713
+ build(*obj, from: from, sync: sync)
714
+ else
715
+ run_s(obj.is_a?(Enumerable) ? obj.to_a : obj, from: from, sync: sync)
716
+ end
656
717
  end
657
718
 
658
719
  def graph_branch(target, data, tasks = nil, out = nil, sync: true, pass: [], done: [], depth: 0, last: false,
@@ -739,9 +800,11 @@ module Squared
739
800
  done
740
801
  end
741
802
 
742
- def graph_collect(target, start = [], data: {})
803
+ def graph_collect(target, start = [], data: {}, pass: [])
743
804
  deps = []
744
805
  (start.empty? ? target.instance_variable_get(:@graph) : start)&.each do |val|
806
+ next if pass.include?(val)
807
+
745
808
  if (obj = workspace.find(name: val))
746
809
  next unless obj.enabled?
747
810
 
@@ -749,8 +812,11 @@ module Squared
749
812
  else
750
813
  items = workspace.find(group: val, ref: val.to_sym)
751
814
  end
815
+
752
816
  items.each do |proj|
753
- graph_collect(proj, data: data) if proj.graph? && !data.key?(proj.name)
817
+ next if pass.include?(proj.name)
818
+
819
+ graph_collect(proj, data: data, pass: pass) if proj.graph? && !data.key?(proj.name)
754
820
  next if (objs = data.fetch(proj.name, [])).include?(target)
755
821
 
756
822
  deps << proj
@@ -781,11 +847,25 @@ module Squared
781
847
  if (val = PATH[prefix] || PATH[prefix.to_sym])
782
848
  cmd[0] = shell_quote(val, force: false)
783
849
  end
784
- split_escape(val).each { |opt| cmd << fill_option(opt) } if options && (val = env("#{prefix}_OPTIONS"))
785
850
  ret = JoinSet.new(cmd.flatten(1))
851
+ if options && (val = env("#{prefix}_OPTIONS"))
852
+ split_escape(val).each { |opt| ret.last(fill_option(opt), /^(--?[^ =]+)[ =].+$/) }
853
+ end
786
854
  main ? @session = ret : ret
787
855
  end
788
856
 
857
+ def session_delete(*list, target: @session)
858
+ ret = []
859
+ list.each do |val|
860
+ pat = /^#{Regexp.escape(shell_option(val))}(?: |=|$)/
861
+ if (key = target.find { |opt| opt =~ pat })
862
+ target.delete(key)
863
+ ret << key
864
+ end
865
+ end
866
+ ret
867
+ end
868
+
789
869
  def session_output(*cmd, **kwargs)
790
870
  session(*cmd, main: false, options: false, **kwargs)
791
871
  end
@@ -808,38 +888,86 @@ module Squared
808
888
  nil
809
889
  end
810
890
 
811
- def option_partition(opts, list, target: @session, no: [], first: false, pass: ['='])
812
- out = []
891
+ def option_sanitize(opts, list, target: @session, no: nil, first: false, pass: ['='])
892
+ ret = []
893
+ reg = []
813
894
  bare = []
814
- reg, list = list.partition do |val|
815
- next unless (n = val.index('='))
816
-
817
- bare << val[0..n - 1] if val.end_with?('?')
818
- true
895
+ e = []
896
+ b = []
897
+ p = []
898
+ q = []
899
+ i = []
900
+ list = list.map do |val|
901
+ x, y = val.split('|')
902
+ if y
903
+ if (n = val.index('='))
904
+ x += val[n..-1]
905
+ end
906
+ [x, y]
907
+ else
908
+ x
909
+ end
819
910
  end
820
- list += bare
821
- no = no.map { |val| (n = val.index('=')) ? val[0..n - 1] : val }
911
+ list.flatten.each do |val|
912
+ if (n = val.index('='))
913
+ flag = val[0, n]
914
+ case val[n + 1]
915
+ when 'e'
916
+ e << flag
917
+ when 'b'
918
+ b << flag
919
+ when 'q'
920
+ q << flag
921
+ when 'p'
922
+ p << flag
923
+ when 'i'
924
+ i << flag
925
+ else
926
+ reg << Regexp.escape(flag)
927
+ end
928
+ bare << flag if val.end_with?('?')
929
+ else
930
+ bare << val
931
+ end
932
+ end
933
+ no = (no || []).map { |val| (n = val.index('=')) ? val[0, n] : val }
934
+ bare += no
822
935
  found = false
823
936
  opts.each do |opt|
824
- next out << opt if found
937
+ next ret << opt if found
825
938
 
826
- if list.include?(opt)
939
+ if bare.include?(opt)
827
940
  target << (opt.size == 1 ? "-#{opt}" : "--#{opt}")
828
941
  elsif opt.start_with?('no-') && no.include?(name = opt[3..-1])
829
942
  target << "--no-#{name}"
830
943
  else
831
- out << opt
944
+ if opt =~ /^([^=]+)=(.+)$/
945
+ a = $1
946
+ if e.include?(a)
947
+ target << shell_option(a, $2)
948
+ elsif q.include?(a)
949
+ target << quote_option(a, $2)
950
+ elsif p.include?(a)
951
+ target << quote_option(a, basepath($2))
952
+ elsif b.include?(a) || (i.include?(a) && /^\d+$/.match?($2))
953
+ target << basic_option(a, $2)
954
+ else
955
+ ret << opt
956
+ end
957
+ opt = a
958
+ else
959
+ ret << opt
960
+ end
832
961
  found = true if first && pass.none? { |val| opt.include?(val) }
833
962
  end
834
963
  end
835
- pat = Regexp.new("^(#{reg.map { |val| val[0..val.index('=') - 1] }.join('|')})=(.+)$")
836
- [out, pat]
964
+ [ret, reg.empty? ? /\A\s+\z/ : /^(#{reg.join('|')})=(.+)$/]
837
965
  end
838
966
 
839
- def option_clear(params, target: @session, **kwargs)
967
+ def option_clear(opts, target: @session, **kwargs)
840
968
  kwargs[:subject] ||= target&.first
841
969
  kwargs[:hint] ||= 'not used'
842
- warn log_message(:warn, params.join(', '), **kwargs) unless params.empty?
970
+ warn log_message(Logger::WARN, opts.join(', '), **kwargs) unless opts.empty?
843
971
  end
844
972
 
845
973
  def print_item(*val)
@@ -982,41 +1110,78 @@ module Squared
982
1110
  opts.each { |val| target << shell_option(flag, val) }
983
1111
  end
984
1112
 
985
- def append_value(*opts, target: @session, delim: false, escape: true, quote: false)
986
- return if (opts = opts.flatten).empty?
987
-
988
- target << '--' if delim
989
- opts.each { |val| target << (escape ? shell_escape(val, quote: quote) : shell_quote(val)) }
990
- end
991
-
992
- def append_hash(opts, target: @session)
993
- out = target.to_s
994
- opts.each do |key, val|
995
- key = key.to_s
996
- key = shell_option(key) unless key[0] == '-'
997
- next if out =~ Regexp.new(" #{key}(?: |=|$)")
1113
+ def append_hash(data, target: @session)
1114
+ target ||= []
1115
+ if (type = env('BUILD', suffix: 'TYPE') || ENV['BUILD_TYPE'])
1116
+ type = "__#{type}__"
1117
+ if (extra = data[type] || data[type.to_sym]).is_a?(Hash)
1118
+ data = data.merge(extra)
1119
+ else
1120
+ extra = nil
1121
+ end
1122
+ end
1123
+ data.each do |key, val|
1124
+ next if (key = key.to_s).start_with?('__')
998
1125
 
1126
+ if val.nil? || extra || session_arg?(key, target: target)
1127
+ session_delete(key, target: target)
1128
+ next if val.nil?
1129
+ end
999
1130
  case val
1000
- when String
1001
- append_repeat(key, [val], target: target)
1002
1131
  when Array
1003
1132
  append_repeat(key, val, target: target)
1004
1133
  when Numeric
1005
- target << (key + (key.start_with?('--') ? '=' : '') + val.to_s)
1134
+ target << basic_option(key, val)
1006
1135
  when false
1007
- target << key.sub(/^--(?!no-)/, '--no-')
1136
+ target << shell_option(key).sub(/^--(?!no-)/, '--no-')
1008
1137
  else
1009
- target << key
1138
+ target << shell_option(key, val.is_a?(String) ? val : nil)
1010
1139
  end
1011
1140
  end
1141
+ target
1012
1142
  end
1013
1143
 
1014
- def append_first(list, target: @session, flag: true, equals: false, quote: false, escape: true, **kwargs)
1015
- list.each do |opt|
1144
+ def append_any(val, target: @session, delim: false)
1145
+ if delim && !target.include?('--')
1146
+ target << '--'
1147
+ else
1148
+ delim = false
1149
+ end
1150
+ case val
1151
+ when String
1152
+ target << val
1153
+ when Hash
1154
+ append_hash(val, target: target)
1155
+ when Enumerable
1156
+ if target.is_a?(Array)
1157
+ target.concat(val.to_a)
1158
+ else
1159
+ target.merge(val.to_a)
1160
+ end
1161
+ else
1162
+ target.delete('--') if delim
1163
+ end
1164
+ end
1165
+
1166
+ def append_value(*list, target: @session, delim: false, escape: false, quote: true)
1167
+ return if (list = list.flatten).empty?
1168
+
1169
+ target << '--' if delim && !target.include?('--')
1170
+ list.map do |val|
1171
+ target << (val = escape ? shell_escape(val, quote: quote) : shell_quote(val))
1172
+ val
1173
+ end
1174
+ end
1175
+
1176
+ def append_first(*list, target: @session, flag: true, equals: false, escape: true, quote: true, force: true,
1177
+ **kwargs)
1178
+ return if (list = list.flatten).empty?
1179
+
1180
+ list.flatten.each do |opt|
1016
1181
  next unless (val = option(opt, **kwargs))
1017
1182
 
1018
1183
  return target << (if flag
1019
- shell_option(opt, equals ? val : nil, quote: quote, escape: escape)
1184
+ shell_option(opt, equals ? val : nil, quote: quote, escape: escape, force: force)
1020
1185
  else
1021
1186
  shell_quote(val)
1022
1187
  end)
@@ -1024,18 +1189,33 @@ module Squared
1024
1189
  nil
1025
1190
  end
1026
1191
 
1027
- def append_option(list, target: @session, equals: false, quote: false, escape: true, **kwargs)
1028
- list.each do |flag|
1192
+ def append_option(*list, target: @session, no: false, equals: false, escape: true, quote: true, force: true,
1193
+ **kwargs)
1194
+ return if (list = list.flatten).empty?
1195
+
1196
+ ret = []
1197
+ list.flatten.each do |flag|
1029
1198
  next unless (val = option(flag, **kwargs))
1030
1199
 
1031
- target << shell_option(flag, equals ? val : nil, quote: quote, escape: escape)
1200
+ if val == '0' && no
1201
+ flag = "no-#{flag}"
1202
+ val = nil
1203
+ end
1204
+ ret << shell_option(flag, equals ? val : nil, escape: escape, quote: quote, force: force)
1032
1205
  end
1206
+ ret.each { |val| target << val } unless ret.empty?
1033
1207
  end
1034
1208
 
1035
1209
  def append_nocolor(target: @session)
1036
1210
  target << '--no-color' if !ARG[:COLOR] || stdin? || option('no-color', ignore: false)
1037
1211
  end
1038
1212
 
1213
+ def collect_hash(data, pass: [])
1214
+ ret = []
1215
+ data.each { |key, val| ret += val unless pass.include?(key) }
1216
+ ret
1217
+ end
1218
+
1039
1219
  def param_guard(action, flag, args: nil, key: nil, pat: nil)
1040
1220
  if args && key
1041
1221
  val = args[key]
@@ -1073,9 +1253,9 @@ module Squared
1073
1253
  end
1074
1254
 
1075
1255
  def indexitem(val)
1076
- return unless (data = /\A\^(\d+)(:.+)?\z/.match(val))
1256
+ return unless val =~ /\A\^(\d+)(:.+)?\z/
1077
1257
 
1078
- [data[1].to_i, data[2] ? data[2][1..-1] : nil]
1258
+ [$1.to_i, $2 && $2[1..-1]]
1079
1259
  end
1080
1260
 
1081
1261
  def indexerror(val, list = nil)
@@ -1091,8 +1271,8 @@ module Squared
1091
1271
  val.compact.map { |s| color(s) }.flatten
1092
1272
  end
1093
1273
 
1094
- def on(event, action, *args, **kwargs)
1095
- return unless (obj = @events[event][action])
1274
+ def on(event, from, *args, **kwargs)
1275
+ return unless from && (obj = @events[event][from])
1096
1276
 
1097
1277
  if obj.is_a?(Array) && obj[1].is_a?(Hash)
1098
1278
  opts = kwargs.empty? ? obj[1] : obj[1].merge(kwargs)
@@ -1111,7 +1291,7 @@ module Squared
1111
1291
  end
1112
1292
  end
1113
1293
 
1114
- def pwd_set(done = nil, pass: false, from: nil, &blk)
1294
+ def pwd_set(done = nil, pass: false, from: nil, dryrun: false, &blk)
1115
1295
  pwd = Pathname.pwd
1116
1296
  if block_given?
1117
1297
  begin
@@ -1124,8 +1304,10 @@ module Squared
1124
1304
  end
1125
1305
  rescue StandardError => e
1126
1306
  log.error e
1127
- ret = on(:error, from, e) if from
1128
- raise if exception && ret != true
1307
+ unless dryrun
1308
+ ret = on(:error, from, e)
1309
+ raise if exception && ret != true
1310
+ end
1129
1311
  else
1130
1312
  ret
1131
1313
  end
@@ -1145,6 +1327,8 @@ module Squared
1145
1327
  end
1146
1328
 
1147
1329
  def run_set(cmd, val = nil, opts: nil, **)
1330
+ return @output = cmd.dup if cmd.is_a?(Array)
1331
+
1148
1332
  unless @output[1] == false && !@output[0].nil?
1149
1333
  if opts == false
1150
1334
  @output[1] = false
@@ -1162,7 +1346,7 @@ module Squared
1162
1346
  @output[0] = cmd
1163
1347
  end
1164
1348
 
1165
- def script_set(cmd, prod: nil, **)
1349
+ def script_set(cmd, prod: nil, args: nil, **)
1166
1350
  return if @output[1] == false && @output[0].nil?
1167
1351
 
1168
1352
  @output[0] = nil
@@ -1171,23 +1355,29 @@ module Squared
1171
1355
  else
1172
1356
  cmd
1173
1357
  end
1358
+ @output[4] = args unless @output[4] == false || args.nil?
1359
+ end
1360
+
1361
+ def as_get(val)
1362
+ @global && (ret = @as && @as[from] && @as[from][val]) ? ret : val
1174
1363
  end
1175
1364
 
1176
1365
  def task_build(keys)
1177
1366
  namespace name do
1367
+ ws = workspace
1178
1368
  keys.each do |key|
1179
- next unless workspace.task_include?(self, key)
1369
+ next unless ws.task_include?(self, key)
1180
1370
 
1181
- action = workspace.series.name_get(key)
1182
- unless @pass.include?(key.to_s) || workspace.task_defined?(name, action)
1183
- workspace.task_desc(@desc, action)
1371
+ action = ws.series.name_get(key)
1372
+ unless @pass.include?(key.to_s) || ws.task_defined?(name, action) || ws.task_exclude?(action, self)
1373
+ ws.task_desc(@desc, action)
1184
1374
  task action do
1185
1375
  __send__(key)
1186
1376
  end
1187
1377
  end
1188
1378
  next if (items = @children.select { |item| item.task_include?(key) }).empty?
1189
1379
 
1190
- workspace.task_desc(@desc, action, 'workspace')
1380
+ ws.task_desc(@desc, action, 'workspace')
1191
1381
  task task_join(action, 'workspace') => items.map { |item| task_join(item.name, action) }
1192
1382
  end
1193
1383
  end
@@ -1212,6 +1402,13 @@ module Squared
1212
1402
  end
1213
1403
  end
1214
1404
 
1405
+ def session_arg?(*list, target: @session, value: false)
1406
+ list.any? do |val|
1407
+ pat = /^#{Regexp.escape(shell_option(val))}#{value ? '[ =].' : '(?:[ =]|$)'}/
1408
+ target.any? { |opt| opt =~ pat }
1409
+ end
1410
+ end
1411
+
1215
1412
  def from_sync?(*val)
1216
1413
  if task_invoked?(key = task_join(*val))
1217
1414
  !workspace.task_defined?(key, 'sync')