squared 0.2.4 → 0.3.1

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,23 +202,23 @@ 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
- raise_error('invalid JSON object', val, hint: "#{prefix}_ENV") unless data.is_a?(Hash)
211
+ raise_error('invalid JSON object', val, hint: "BUILD_#{@envname}_ENV") unless data.is_a?(Hash)
208
212
  rescue StandardError => e
209
213
  log.warn e
210
214
  else
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,18 +1110,23 @@ 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
- next if out =~ / #{Regexp.escape(shell_option(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?('__')
996
1125
 
1126
+ if val.nil? || extra || session_arg?(key, target: target)
1127
+ session_delete(key, target: target)
1128
+ next if val.nil?
1129
+ end
997
1130
  case val
998
1131
  when Array
999
1132
  append_repeat(key, val, target: target)
@@ -1005,14 +1138,50 @@ module Squared
1005
1138
  target << shell_option(key, val.is_a?(String) ? val : nil)
1006
1139
  end
1007
1140
  end
1141
+ target
1142
+ end
1143
+
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
1008
1174
  end
1009
1175
 
1010
- def append_first(list, target: @session, flag: true, equals: false, quote: false, escape: true, **kwargs)
1011
- list.each do |opt|
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|
1012
1181
  next unless (val = option(opt, **kwargs))
1013
1182
 
1014
1183
  return target << (if flag
1015
- shell_option(opt, equals ? val : nil, quote: quote, escape: escape)
1184
+ shell_option(opt, equals ? val : nil, quote: quote, escape: escape, force: force)
1016
1185
  else
1017
1186
  shell_quote(val)
1018
1187
  end)
@@ -1020,18 +1189,33 @@ module Squared
1020
1189
  nil
1021
1190
  end
1022
1191
 
1023
- def append_option(list, target: @session, equals: false, quote: false, escape: true, **kwargs)
1024
- 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|
1025
1198
  next unless (val = option(flag, **kwargs))
1026
1199
 
1027
- 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)
1028
1205
  end
1206
+ ret.each { |val| target << val } unless ret.empty?
1029
1207
  end
1030
1208
 
1031
1209
  def append_nocolor(target: @session)
1032
1210
  target << '--no-color' if !ARG[:COLOR] || stdin? || option('no-color', ignore: false)
1033
1211
  end
1034
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
+
1035
1219
  def param_guard(action, flag, args: nil, key: nil, pat: nil)
1036
1220
  if args && key
1037
1221
  val = args[key]
@@ -1069,9 +1253,9 @@ module Squared
1069
1253
  end
1070
1254
 
1071
1255
  def indexitem(val)
1072
- return unless (data = /\A\^(\d+)(:.+)?\z/.match(val))
1256
+ return unless val =~ /\A\^(\d+)(:.+)?\z/
1073
1257
 
1074
- [data[1].to_i, data[2] ? data[2][1..-1] : nil]
1258
+ [$1.to_i, $2 && $2[1..-1]]
1075
1259
  end
1076
1260
 
1077
1261
  def indexerror(val, list = nil)
@@ -1087,8 +1271,8 @@ module Squared
1087
1271
  val.compact.map { |s| color(s) }.flatten
1088
1272
  end
1089
1273
 
1090
- def on(event, action, *args, **kwargs)
1091
- return unless (obj = @events[event][action])
1274
+ def on(event, from, *args, **kwargs)
1275
+ return unless from && (obj = @events[event][from])
1092
1276
 
1093
1277
  if obj.is_a?(Array) && obj[1].is_a?(Hash)
1094
1278
  opts = kwargs.empty? ? obj[1] : obj[1].merge(kwargs)
@@ -1107,7 +1291,7 @@ module Squared
1107
1291
  end
1108
1292
  end
1109
1293
 
1110
- def pwd_set(done = nil, pass: false, from: nil, &blk)
1294
+ def pwd_set(done = nil, pass: false, from: nil, dryrun: false, &blk)
1111
1295
  pwd = Pathname.pwd
1112
1296
  if block_given?
1113
1297
  begin
@@ -1120,8 +1304,10 @@ module Squared
1120
1304
  end
1121
1305
  rescue StandardError => e
1122
1306
  log.error e
1123
- ret = on(:error, from, e) if from
1124
- raise if exception && ret != true
1307
+ unless dryrun
1308
+ ret = on(:error, from, e)
1309
+ raise if exception && ret != true
1310
+ end
1125
1311
  else
1126
1312
  ret
1127
1313
  end
@@ -1141,6 +1327,8 @@ module Squared
1141
1327
  end
1142
1328
 
1143
1329
  def run_set(cmd, val = nil, opts: nil, **)
1330
+ return @output = cmd.dup if cmd.is_a?(Array)
1331
+
1144
1332
  unless @output[1] == false && !@output[0].nil?
1145
1333
  if opts == false
1146
1334
  @output[1] = false
@@ -1158,7 +1346,7 @@ module Squared
1158
1346
  @output[0] = cmd
1159
1347
  end
1160
1348
 
1161
- def script_set(cmd, prod: nil, **)
1349
+ def script_set(cmd, prod: nil, args: nil, **)
1162
1350
  return if @output[1] == false && @output[0].nil?
1163
1351
 
1164
1352
  @output[0] = nil
@@ -1167,23 +1355,29 @@ module Squared
1167
1355
  else
1168
1356
  cmd
1169
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
1170
1363
  end
1171
1364
 
1172
1365
  def task_build(keys)
1173
1366
  namespace name do
1367
+ ws = workspace
1174
1368
  keys.each do |key|
1175
- next unless workspace.task_include?(self, key)
1369
+ next unless ws.task_include?(self, key)
1176
1370
 
1177
- action = workspace.series.name_get(key)
1178
- unless @pass.include?(key.to_s) || workspace.task_defined?(name, action)
1179
- 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)
1180
1374
  task action do
1181
1375
  __send__(key)
1182
1376
  end
1183
1377
  end
1184
1378
  next if (items = @children.select { |item| item.task_include?(key) }).empty?
1185
1379
 
1186
- workspace.task_desc(@desc, action, 'workspace')
1380
+ ws.task_desc(@desc, action, 'workspace')
1187
1381
  task task_join(action, 'workspace') => items.map { |item| task_join(item.name, action) }
1188
1382
  end
1189
1383
  end
@@ -1208,6 +1402,13 @@ module Squared
1208
1402
  end
1209
1403
  end
1210
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
+
1211
1412
  def from_sync?(*val)
1212
1413
  if task_invoked?(key = task_join(*val))
1213
1414
  !workspace.task_defined?(key, 'sync')