squared 0.2.10 → 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, **)
@@ -163,24 +171,19 @@ module Squared
163
171
  return if @log
164
172
 
165
173
  log = log.is_a?(Hash) ? log.dup : { file: log }
166
- if (file = env('LOG_FILE'))
167
- file = DateTime.now.strftime(file)
168
- elsif (val = env('LOG_AUTO'))
169
- file = "#{@name}-%s.log" % [case val
170
- when 'y', 'year'
171
- Date.today.year
172
- when 'm', 'month'
173
- Date.today.strftime('%Y-%m')
174
- when 'd', 'day', '1'
175
- Date.today
176
- else
177
- val.include?('%') ? DateTime.now.strftime(val) : DateTime.now.strftime
178
- end]
179
- elsif (val = log[:file])
180
- file = val.is_a?(String) ? DateTime.now.strftime(val) : "#{@name}-#{Date.today}.log"
181
- end
182
- if file
183
- file = (val = env('LOG_DIR')) ? @workspace.home.join(val, file) : @workspace.home.join(file)
174
+ unless (file = env('LOG_FILE'))
175
+ file = case env('LOG_AUTO')
176
+ when 'y', 'year'
177
+ "#{@name}-#{Date.today.year}.log"
178
+ when 'm', 'month'
179
+ "#{@name}-#{Date.today.strftime('%Y-%m')}.log"
180
+ when 'd', 'day', '1'
181
+ "#{@name}-#{Date.today}.log"
182
+ end
183
+ end
184
+ if file ||= log[:file]
185
+ file = Date.today.strftime(file)
186
+ file = (dir = env('LOG_DIR')) ? @workspace.home.join(dir, file) : @workspace.home.join(file)
184
187
  begin
185
188
  file = file.realdirpath
186
189
  rescue StandardError => e
@@ -199,23 +202,23 @@ module Squared
199
202
  end
200
203
 
201
204
  def initialize_env(dev: nil, prod: nil, **)
202
- pre = "BUILD_#{@envname}"
203
- @dev = env_match("#{pre}_DEV", dev)
204
- @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)
205
207
  cmd = @output[0]
206
- unless cmd == false || cmd.is_a?(Array) || (val = env('BUILD', suffix: 'OPTS')).nil?
207
- @output[cmd ? 1 : 3] = shell_split(val, escape: false, join: true)
208
- end
209
- unless @output[2] == false || (val = env('BUILD', suffix: 'ENV')).nil?
208
+ if @output[2] != false && (val = env('BUILD', suffix: 'ENV'))
210
209
  begin
211
210
  data = JSON.parse(val)
212
211
  raise_error('invalid JSON object', val, hint: "#{prefix}_ENV") unless data.is_a?(Hash)
213
212
  rescue StandardError => e
214
- log&.warn e
213
+ log.warn e
215
214
  else
216
215
  @output[2] = data
217
216
  end
218
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
219
222
  @version = val if (val = env('BUILD', suffix: 'VERSION'))
220
223
  return unless (val = env('BUILD', strict: true))
221
224
 
@@ -247,23 +250,16 @@ module Squared
247
250
  when 'graph'
248
251
  next unless graph?
249
252
 
250
- check = lambda do |args|
251
- next args if (args = args.to_a).empty?
252
-
253
- param_guard(action, flag, args: args.reject { |val| name == val.to_s })
254
- end
255
-
256
- format_desc action, flag, 'project*'
257
- if flag == :run
258
- task flag do |_, args|
259
- graph check.(args)
260
- end
261
- else
262
- task flag do |_, args|
263
- 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: [])
264
260
  out.map! do |val|
265
261
  done.each_with_index do |proj, i|
266
- next unless Regexp.new(" #{Regexp.escape(proj.name)}(?:@\\d|\\z)") =~ val
262
+ next unless val =~ / #{Regexp.escape(proj.name)}(?:@\d|\z)/
267
263
 
268
264
  val += " (#{i.succ})"
269
265
  break
@@ -302,12 +298,12 @@ module Squared
302
298
  if val.directory? && !val.empty?
303
299
  true
304
300
  else
305
- log&.warn "workspace \"#{val}\" (#{val.empty? ? 'empty' : 'not found'})"
301
+ log.warn "workspace \"#{val}\" (#{val.empty? ? 'empty' : 'not found'})"
306
302
  false
307
303
  end
308
304
  end
309
- if path.is_a?(String) && (data = %r{^(.+)[\\/]\*+$}.match(path))
310
- 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))
311
307
 
312
308
  path = path.children.select { |val| checkdir.(val) }
313
309
  end
@@ -345,64 +341,87 @@ module Squared
345
341
 
346
342
  out = obj.link(self, *args, **kwargs, &blk) if obj.respond_to?(:link)
347
343
  if !out
348
- 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)
349
345
  elsif out.respond_to?(:build)
350
346
  out.build
351
347
  end
352
348
  self
353
349
  end
354
350
 
355
- def build(*args, from: :run, sync: invoked_sync?('build'), **)
351
+ def build(*args, sync: invoked_sync?('build'), from: :run, **)
356
352
  banner = verbose
357
353
  if args.empty?
358
354
  return unless from == :run
359
355
 
360
- cmd, opts, var, flags = @output
356
+ args = @output
361
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(' && ')
362
381
  else
363
- cmd = args.shift
364
- opts = args.map { |val| shell_quote(val, force: false) }.join(' ')
382
+ cmd, opts, var, flags, scr = args
365
383
  end
366
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)
367
388
  case opts
368
- when String
369
- cmd = "#{cmd} #{opts}"
370
- when Array
371
- 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(' && ')
372
396
  else
373
- cmd = [cmd, compose(opts, script: false)].compact.join(' ') unless opts == false || !respond_to?(:compose)
397
+ cmd = [cmd, flags, opts].compact.join(' ') if opts || flags
374
398
  end
375
399
  else
376
400
  return unless respond_to?(:compose)
377
401
 
378
- cmd = compose(opts, flags, from: from, script: true)
379
- from = :script if from == :run && script?
402
+ cmd = compose(as_get(opts), flags, script: true, args: scr, from: from)
380
403
  end
381
404
  run(cmd, var, from: from, banner: banner, sync: sync)
382
405
  end
383
406
 
384
407
  def depend(*, sync: invoked_sync?('depend'), **)
385
- return unless @depend
386
-
387
- run(@depend, from: :depend, sync: sync)
388
- end
389
-
390
- def copy(*, sync: invoked_sync?('copy'), **)
391
- return unless @copy
392
-
393
- run_s(@copy, from: :copy, sync: sync)
408
+ run_b(@depend, sync: sync, from: :depend)
394
409
  end
395
410
 
396
411
  def doc(*, sync: invoked_sync?('doc'), **)
397
- return unless @doc
412
+ run_b(@doc, sync: sync, from: :doc)
413
+ end
398
414
 
399
- build(*as_a(@doc), from: :doc, sync: sync)
415
+ def lint(*, sync: invoked_sync?('lint'), **)
416
+ run_b(@lint, sync: sync, from: :lint)
400
417
  end
401
418
 
402
419
  def test(*, sync: invoked_sync?('test'), **)
403
- return unless @test
420
+ run_b(@test, sync: sync, from: :test)
421
+ end
404
422
 
405
- build(*as_a(@test), from: :test, sync: sync)
423
+ def copy(*, sync: invoked_sync?('copy'), **)
424
+ run_b(@copy, sync: sync, from: :copy)
406
425
  end
407
426
 
408
427
  def clean(*, sync: invoked_sync?('clean'), **)
@@ -411,23 +430,31 @@ module Squared
411
430
  on :first, :clean
412
431
  case @clean
413
432
  when String
414
- 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
415
442
  when Enumerable
416
- (@clean.is_a?(Hash) ? @clean.values : as_a(@clean)).each do |val|
443
+ as_a(@clean).each do |val|
417
444
  val = val.to_s
418
445
  path = basepath(val)
419
446
  if path.directory? && val =~ %r{[\\/]\z}
420
- log&.warn "rm -rf #{path}"
421
- FileUtils.rm_rf(path, verbose: verbose)
447
+ log.warn "rm -rf #{path}"
448
+ path.rmtree(verbose: verbose)
422
449
  else
423
- log&.warn "rm #{path}"
450
+ log.warn "rm #{path}"
424
451
  (val.include?('*') ? Dir[path] : [path]).each do |file|
425
452
  next unless File.file?(file)
426
453
 
427
454
  begin
428
455
  File.delete(file)
429
456
  rescue StandardError => e
430
- log&.error e
457
+ log.error e
431
458
  end
432
459
  end
433
460
  end
@@ -447,8 +474,9 @@ module Squared
447
474
  end
448
475
  end
449
476
  end
450
- pass.concat(split_escape(val)) if (val = env('GRAPH_PASS', strict: true))
451
- 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] })
452
480
  unless out
453
481
  data[name] << self
454
482
  on :first, :graph
@@ -482,6 +510,12 @@ module Squared
482
510
  (@events[name.to_sym] ||= {})[key.to_sym] = [block_given? ? [blk] + args : args, kwargs]
483
511
  end
484
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
+
485
519
  def variable_set(key, *val, **kwargs)
486
520
  if variables.include?(key)
487
521
  case key
@@ -506,7 +540,7 @@ module Squared
506
540
  instance_variable_set :"@#{key}", val.first
507
541
  end
508
542
  else
509
- log&.warn "variable_set: @#{key} (private)"
543
+ log.warn "variable_set: @#{key} (private)"
510
544
  end
511
545
  end
512
546
 
@@ -550,6 +584,10 @@ module Squared
550
584
  !!@doc
551
585
  end
552
586
 
587
+ def lint?
588
+ !!@lint
589
+ end
590
+
553
591
  def test?
554
592
  !!@test
555
593
  end
@@ -629,12 +667,19 @@ module Squared
629
667
  end
630
668
 
631
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
632
677
  cmd = session_done(cmd)
633
- log&.info cmd
634
- on :first, from if from
678
+ log.info cmd
679
+ on :first, from
635
680
  begin
636
681
  if cmd.match?(/\A[^:]+:[^:]/) && workspace.task_defined?(cmd)
637
- log&.warn "ENV was discarded: #{var}" if var
682
+ log.warn "ENV was discarded: #{var}" if var
638
683
  task_invoke(cmd, exception: exception, warning: warning?)
639
684
  else
640
685
  print_item format_banner(cmd, banner: banner) if sync
@@ -642,23 +687,33 @@ module Squared
642
687
  shell(*args, chdir: chdir, exception: exception)
643
688
  end
644
689
  rescue StandardError => e
645
- log&.error e
646
- ret = on(:error, from, e) if from
690
+ log.error e
691
+ ret = on(:error, from, e)
647
692
  raise unless ret == true
648
693
  else
649
- on :last, from if from
694
+ on :last, from
650
695
  end
651
696
  end
652
697
 
653
698
  def run_s(*cmd, env: nil, sync: true, banner: verbose != false, from: nil, **kwargs)
654
- on :first, from if from
699
+ on :first, from
655
700
  begin
656
701
  cmd.flatten.each { |val| run(val, env, sync: sync, banner: banner, **kwargs) }
657
702
  rescue StandardError => e
658
- ret = on(:error, from, e) if from
703
+ ret = on(:error, from, e)
659
704
  raise unless ret == true
660
705
  end
661
- 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
662
717
  end
663
718
 
664
719
  def graph_branch(target, data, tasks = nil, out = nil, sync: true, pass: [], done: [], depth: 0, last: false,
@@ -745,9 +800,11 @@ module Squared
745
800
  done
746
801
  end
747
802
 
748
- def graph_collect(target, start = [], data: {})
803
+ def graph_collect(target, start = [], data: {}, pass: [])
749
804
  deps = []
750
805
  (start.empty? ? target.instance_variable_get(:@graph) : start)&.each do |val|
806
+ next if pass.include?(val)
807
+
751
808
  if (obj = workspace.find(name: val))
752
809
  next unless obj.enabled?
753
810
 
@@ -755,8 +812,11 @@ module Squared
755
812
  else
756
813
  items = workspace.find(group: val, ref: val.to_sym)
757
814
  end
815
+
758
816
  items.each do |proj|
759
- 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)
760
820
  next if (objs = data.fetch(proj.name, [])).include?(target)
761
821
 
762
822
  deps << proj
@@ -783,15 +843,29 @@ module Squared
783
843
  end
784
844
 
785
845
  def session(*cmd, prefix: cmd.first, main: true, options: true)
786
- prefix = stripext(prefix.to_s).upcase
846
+ prefix = prefix.to_s.upcase
787
847
  if (val = PATH[prefix] || PATH[prefix.to_sym])
788
848
  cmd[0] = shell_quote(val, force: false)
789
849
  end
790
- split_escape(val).each { |opt| cmd << fill_option(opt) } if options && (val = env("#{prefix}_OPTIONS"))
791
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
792
854
  main ? @session = ret : ret
793
855
  end
794
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
+
795
869
  def session_output(*cmd, **kwargs)
796
870
  session(*cmd, main: false, options: false, **kwargs)
797
871
  end
@@ -804,50 +878,96 @@ module Squared
804
878
  cmd.done
805
879
  end
806
880
 
807
- def option(*args, target: @session, prefix: target&.first, **kwargs)
881
+ def option(*args, prefix: @session&.first, **kwargs)
808
882
  if prefix
809
883
  args.each do |val|
810
- ret = env("#{stripext(prefix)}_#{val.gsub(/\W/, '_')}".upcase, **kwargs)
884
+ ret = env("#{prefix}_#{val.gsub(/\W/, '_')}".upcase, **kwargs)
811
885
  return ret if ret
812
886
  end
813
887
  end
814
888
  nil
815
889
  end
816
890
 
817
- def option_partition(opts, list, target: @session, no: [], first: false, pass: ['='])
818
- out = []
891
+ def option_sanitize(opts, list, target: @session, no: nil, first: false, pass: ['='])
892
+ ret = []
893
+ reg = []
819
894
  bare = []
820
- reg, list = list.partition do |val|
821
- next unless (n = val.index('='))
822
-
823
- bare << val[0..n - 1] if val.end_with?('?')
824
- 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
825
910
  end
826
- list += bare
827
- 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
828
935
  found = false
829
936
  opts.each do |opt|
830
- next out << opt if found
937
+ next ret << opt if found
831
938
 
832
- if list.include?(opt)
939
+ if bare.include?(opt)
833
940
  target << (opt.size == 1 ? "-#{opt}" : "--#{opt}")
834
941
  elsif opt.start_with?('no-') && no.include?(name = opt[3..-1])
835
942
  target << "--no-#{name}"
836
943
  else
837
- 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
838
961
  found = true if first && pass.none? { |val| opt.include?(val) }
839
962
  end
840
963
  end
841
- pat = Regexp.new("^(#{reg.map { |val| val[0..val.index('=') - 1] }.join('|')})=(.+)$")
842
- [out, pat]
964
+ [ret, reg.empty? ? /\A\s+\z/ : /^(#{reg.join('|')})=(.+)$/]
843
965
  end
844
966
 
845
- def option_clear(params, target: @session, **kwargs)
846
- return if params.empty?
847
-
967
+ def option_clear(opts, target: @session, **kwargs)
848
968
  kwargs[:subject] ||= target&.first
849
- kwargs[:hint] ||= 'unrecognized'
850
- warn log_message(:warn, params.join(', '), **kwargs)
969
+ kwargs[:hint] ||= 'not used'
970
+ warn log_message(Logger::WARN, opts.join(', '), **kwargs) unless opts.empty?
851
971
  end
852
972
 
853
973
  def print_item(*val)
@@ -990,18 +1110,23 @@ module Squared
990
1110
  opts.each { |val| target << shell_option(flag, val) }
991
1111
  end
992
1112
 
993
- def append_value(*opts, target: @session, delim: false, escape: true, quote: false)
994
- return if (opts = opts.flatten).empty?
995
-
996
- target << '--' if delim
997
- opts.each { |val| target << (escape ? shell_escape(val, quote: quote) : shell_quote(val)) }
998
- end
999
-
1000
- def append_hash(opts, target: @session)
1001
- out = target.to_s
1002
- opts.each do |key, val|
1003
- 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?('__')
1004
1125
 
1126
+ if val.nil? || extra || session_arg?(key, target: target)
1127
+ session_delete(key, target: target)
1128
+ next if val.nil?
1129
+ end
1005
1130
  case val
1006
1131
  when Array
1007
1132
  append_repeat(key, val, target: target)
@@ -1013,14 +1138,50 @@ module Squared
1013
1138
  target << shell_option(key, val.is_a?(String) ? val : nil)
1014
1139
  end
1015
1140
  end
1141
+ target
1016
1142
  end
1017
1143
 
1018
- def append_first(list, target: @session, flag: true, equals: false, quote: false, escape: true, **kwargs)
1019
- list.each do |opt|
1020
- next unless (val = option(opt, target: target, **kwargs))
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|
1181
+ next unless (val = option(opt, **kwargs))
1021
1182
 
1022
1183
  return target << (if flag
1023
- shell_option(opt, equals ? val : nil, quote: quote, escape: escape)
1184
+ shell_option(opt, equals ? val : nil, quote: quote, escape: escape, force: force)
1024
1185
  else
1025
1186
  shell_quote(val)
1026
1187
  end)
@@ -1028,21 +1189,36 @@ module Squared
1028
1189
  nil
1029
1190
  end
1030
1191
 
1031
- def append_option(list, target: @session, equals: false, quote: false, escape: true, **kwargs)
1032
- list.each do |flag|
1033
- next unless (val = option(flag, target: target, **kwargs))
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?
1034
1195
 
1035
- target << shell_option(flag, equals ? val : nil, quote: quote, escape: escape)
1196
+ ret = []
1197
+ list.flatten.each do |flag|
1198
+ next unless (val = option(flag, **kwargs))
1199
+
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)
1036
1205
  end
1206
+ ret.each { |val| target << val } unless ret.empty?
1037
1207
  end
1038
1208
 
1039
1209
  def append_nocolor(target: @session)
1040
- target << '--no-color' if !ARG[:COLOR] || stdin? || option('no-color', target: target, ignore: false)
1210
+ target << '--no-color' if !ARG[:COLOR] || stdin? || option('no-color', ignore: false)
1211
+ end
1212
+
1213
+ def collect_hash(data, pass: [])
1214
+ ret = []
1215
+ data.each { |key, val| ret += val unless pass.include?(key) }
1216
+ ret
1041
1217
  end
1042
1218
 
1043
1219
  def param_guard(action, flag, args: nil, key: nil, pat: nil)
1044
1220
  if args && key
1045
- val = args.fetch(key, nil)
1221
+ val = args[key]
1046
1222
  return val unless val.nil? || (pat && !val.match?(pat))
1047
1223
 
1048
1224
  @session = nil
@@ -1077,9 +1253,9 @@ module Squared
1077
1253
  end
1078
1254
 
1079
1255
  def indexitem(val)
1080
- return unless (data = /\A\^(\d+)(:.+)?\z/.match(val))
1256
+ return unless val =~ /\A\^(\d+)(:.+)?\z/
1081
1257
 
1082
- [data[1].to_i, data[2] ? data[2][1..-1] : nil]
1258
+ [$1.to_i, $2 && $2[1..-1]]
1083
1259
  end
1084
1260
 
1085
1261
  def indexerror(val, list = nil)
@@ -1095,8 +1271,8 @@ module Squared
1095
1271
  val.compact.map { |s| color(s) }.flatten
1096
1272
  end
1097
1273
 
1098
- def on(event, action, *args, **kwargs)
1099
- return unless (obj = @events[event][action])
1274
+ def on(event, from, *args, **kwargs)
1275
+ return unless from && (obj = @events[event][from])
1100
1276
 
1101
1277
  if obj.is_a?(Array) && obj[1].is_a?(Hash)
1102
1278
  opts = kwargs.empty? ? obj[1] : obj[1].merge(kwargs)
@@ -1115,11 +1291,11 @@ module Squared
1115
1291
  end
1116
1292
  end
1117
1293
 
1118
- def pwd_set(done = nil, pass: false, from: nil, &blk)
1294
+ def pwd_set(done = nil, pass: false, from: nil, dryrun: false, &blk)
1119
1295
  pwd = Pathname.pwd
1120
1296
  if block_given?
1121
1297
  begin
1122
- if path == pwd || pass == true || (pass.is_a?(String) && semscan(pass).join <= RUBY_VERSION)
1298
+ if path == pwd || pass == true || (pass.is_a?(String) && semscan(pass).join >= RUBY_VERSION)
1123
1299
  ret = instance_eval(&blk)
1124
1300
  else
1125
1301
  Dir.chdir(path)
@@ -1127,9 +1303,11 @@ module Squared
1127
1303
  Dir.chdir(pwd)
1128
1304
  end
1129
1305
  rescue StandardError => e
1130
- log&.error e
1131
- ret = on(:error, from, e) if from
1132
- raise if exception && ret != true
1306
+ log.error e
1307
+ unless dryrun
1308
+ ret = on(:error, from, e)
1309
+ raise if exception && ret != true
1310
+ end
1133
1311
  else
1134
1312
  ret
1135
1313
  end
@@ -1149,6 +1327,8 @@ module Squared
1149
1327
  end
1150
1328
 
1151
1329
  def run_set(cmd, val = nil, opts: nil, **)
1330
+ return @output = cmd.dup if cmd.is_a?(Array)
1331
+
1152
1332
  unless @output[1] == false && !@output[0].nil?
1153
1333
  if opts == false
1154
1334
  @output[1] = false
@@ -1166,7 +1346,7 @@ module Squared
1166
1346
  @output[0] = cmd
1167
1347
  end
1168
1348
 
1169
- def script_set(cmd, prod: nil, **)
1349
+ def script_set(cmd, prod: nil, args: nil, **)
1170
1350
  return if @output[1] == false && @output[0].nil?
1171
1351
 
1172
1352
  @output[0] = nil
@@ -1175,31 +1355,36 @@ module Squared
1175
1355
  else
1176
1356
  cmd
1177
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
1178
1363
  end
1179
1364
 
1180
1365
  def task_build(keys)
1181
1366
  namespace name do
1367
+ ws = workspace
1182
1368
  keys.each do |key|
1183
- next unless workspace.task_include?(self, key)
1369
+ next unless ws.task_include?(self, key)
1184
1370
 
1185
- action = workspace.series.name_get(key)
1186
- unless @pass.include?(key.to_s) || workspace.task_defined?(name, action)
1187
- 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)
1188
1374
  task action do
1189
1375
  __send__(key)
1190
1376
  end
1191
1377
  end
1192
1378
  next if (items = @children.select { |item| item.task_include?(key) }).empty?
1193
1379
 
1194
- workspace.task_desc(@desc, action, 'workspace')
1380
+ ws.task_desc(@desc, action, 'workspace')
1195
1381
  task task_join(action, 'workspace') => items.map { |item| task_join(item.name, action) }
1196
1382
  end
1197
1383
  end
1198
1384
  end
1199
1385
 
1200
1386
  def projectpath?(val)
1201
- val = Pathname.new(val).cleanpath
1202
- val.absolute? ? val.to_s.start_with?(File.join(path, '')) : !val.to_s.start_with?(File.join('..', ''))
1387
+ Pathname.new(val).absolute? ? val.to_s.start_with?(File.join(path, '')) : !val.to_s.start_with?('..')
1203
1388
  end
1204
1389
 
1205
1390
  def semmajor?(cur, want)
@@ -1217,6 +1402,13 @@ module Squared
1217
1402
  end
1218
1403
  end
1219
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
+
1220
1412
  def from_sync?(*val)
1221
1413
  if task_invoked?(key = task_join(*val))
1222
1414
  !workspace.task_defined?(key, 'sync')