squared 0.4.29 → 0.5.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.
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'json'
4
4
  require 'date'
5
+ require 'time'
5
6
  require 'logger'
6
7
 
7
8
  module Squared
@@ -18,10 +19,10 @@ module Squared
18
19
  include Rake::DSL
19
20
 
20
21
  VAR_SET = %i[parent global script index envname desc dependfile dependindex theme archive env dev prod graph
21
- pass only exclude].freeze
22
+ pass exclude].freeze
22
23
  BLK_SET = %i[run depend doc lint test copy clean].freeze
23
- SEM_VER = /\b(\d+)(?:(\.)(\d+))?(?:(\.)(\d+))?[-.]?(\S+)?\b/.freeze
24
- URI_SCHEME = %r{\A([a-z][a-z\d+-.]*)://[^@:\[\]\\^<>|\s]}i.freeze
24
+ SEM_VER = /\b(\d+)(?:(\.)(\d+))?(?:(\.)(\d+)(\S+)?)?\b/.freeze
25
+ URI_SCHEME = %r{^([a-z][a-z\d+-.]*)://[^@:\[\]\\^<>|\s]}i.freeze
25
26
  TASK_METADATA = Rake::TaskManager.record_task_metadata
26
27
  private_constant :VAR_SET, :BLK_SET, :SEM_VER, :URI_SCHEME, :TASK_METADATA
27
28
 
@@ -72,9 +73,8 @@ module Squared
72
73
  'unpack' => %i[zip tar gem ext].freeze
73
74
  })
74
75
 
75
- attr_reader :name, :project, :workspace, :path, :theme, :group, :parent, :dependfile,
76
- :exception, :pipe, :verbose
77
- attr_accessor :global
76
+ attr_reader :name, :project, :workspace, :path, :theme, :exception, :pipe, :verbose,
77
+ :group, :parent, :dependfile
78
78
 
79
79
  def initialize(workspace, path, name, *, group: nil, first: {}, last: {}, error: {}, common: ARG[:COMMON],
80
80
  **kwargs)
@@ -83,36 +83,38 @@ module Squared
83
83
  @name = name.to_s.freeze
84
84
  @project = @path.basename.to_s.freeze
85
85
  @group = group&.to_s.freeze
86
- @envname = env_key(@name).freeze
87
86
  @depend = kwargs[:depend]
88
87
  @doc = kwargs[:doc]
89
88
  @lint = kwargs[:lint]
90
89
  @test = kwargs[:test]
91
90
  @copy = kwargs[:copy]
92
91
  @clean = kwargs[:clean]
92
+ @version = kwargs[:version]
93
93
  @release = kwargs[:release]
94
- self.version = kwargs[:version]
95
- self.exception = env_bool(kwargs[:exception], workspace.exception, strict: true)
96
- self.pipe = env_pipe(kwargs[:pipe], workspace.pipe, strict: true)
97
- self.verbose = case (val = env('VERBOSE', kwargs[:verbose]))
98
- when String
99
- env_bool(val, workspace.verbose, strict: true, index: true)
100
- else
101
- val.nil? ? workspace.verbose : val
102
- end
103
94
  @output = []
104
95
  @ref = []
105
96
  @children = []
106
- @events = hashobj.update({ first: first, last: last, error: error })
107
- @as = hashobj
97
+ @events = {
98
+ first: first,
99
+ last: last,
100
+ error: error
101
+ }
102
+ @envname = @name.gsub(/[^\w]+/, '_').upcase.freeze
108
103
  @desc = (@name.include?(':') ? @name.split(':').join(ARG[:SPACE]) : @name).freeze
109
104
  @parent = nil
110
105
  @global = false
106
+ @log = nil
107
+ @dev = nil
108
+ @prod = nil
109
+ @withargs = nil
110
+ @session = nil
111
111
  @index = -1
112
112
  run_set(kwargs[:run], kwargs[:env], opts: kwargs.fetch(:opts, true))
113
+ exception_set kwargs[:exception]
114
+ pipe_set kwargs[:pipe]
115
+ verbose_set kwargs[:verbose]
113
116
  graph_set kwargs[:graph]
114
117
  pass_set kwargs[:pass]
115
- only_set kwargs[:only]
116
118
  exclude_set kwargs[:exclude]
117
119
  archive_set kwargs[:archive]
118
120
  theme_set common
@@ -144,10 +146,8 @@ module Squared
144
146
  data = @workspace.script_find(*@ref, @group)
145
147
  if @output[0].nil?
146
148
  if (scr = data[:script])
147
- unless kwargs[:script] == false
148
- @global = true
149
- script_set(scr, args: data.fetch(:args, kwargs[:args]), prod: kwargs[:prod])
150
- end
149
+ @global = true
150
+ script_set(scr, args: data.fetch(:args, kwargs[:args]), prod: kwargs[:prod])
151
151
  elsif (run = data[:run])
152
152
  @global = true
153
153
  run_set run
@@ -170,12 +170,15 @@ module Squared
170
170
  @global = true
171
171
  run_set data[:run]
172
172
  end
173
+ @global = true
173
174
  end
174
175
 
175
176
  def initialize_events(ref, **)
176
177
  return unless (events = @workspace.events_get(group: @group, ref: ref))
177
178
 
178
- events.each { |task, data| data.each { |ev, blk| @events[ev][task] ||= [blk] } }
179
+ events.each do |task, data|
180
+ data.each { |ev, blk| (@events[ev] ||= {})[task] ||= [blk] }
181
+ end
179
182
  end
180
183
 
181
184
  def initialize_logger(log: nil, **)
@@ -202,7 +205,7 @@ module Squared
202
205
  file &&= @workspace.home.join(env('LOG_DIR', ''), file).realdirpath
203
206
  rescue StandardError => e
204
207
  file = nil
205
- print_error e
208
+ warn log_message(Logger::WARN, e, pass: true) if warning?
206
209
  end
207
210
  log[:progname] ||= @name
208
211
  if (val = env('LOG_LEVEL', ignore: false))
@@ -215,7 +218,7 @@ module Squared
215
218
  def initialize_env(dev: nil, prod: nil, **)
216
219
  @dev = env_match('BUILD', dev, suffix: 'DEV', strict: true)
217
220
  @prod = env_match('BUILD', prod, suffix: 'PROD', strict: true)
218
- if (val = env('BUILD', suffix: 'ENV')) && @output[2] != false
221
+ if @output[2] != false && (val = env('BUILD', suffix: 'ENV'))
219
222
  @output[2] = parse_json(val, hint: "BUILD_#{@envname}_ENV") || @output[2]
220
223
  end
221
224
  unless @output[0] == false || @output[0].is_a?(Array)
@@ -240,26 +243,21 @@ module Squared
240
243
  end
241
244
  end
242
245
 
243
- def ==(other)
244
- equal?(other)
245
- end
246
-
247
246
  def <=>(other)
248
- return unless workspace == other.workspace
249
- return 0 if equal?(other)
247
+ return 0 unless workspace == other.workspace
250
248
 
251
249
  a, b = graph_deps
252
250
  return 1 if a.include?(other)
253
251
 
254
252
  c, d = graph_deps other
255
- e = b - d
256
- f = d - b
253
+ e = b.reject { |val| d.include?(val) }
254
+ f = d.reject { |val| b.include?(val) }
257
255
  if parent == other.parent
258
256
  g = []
259
257
  h = []
260
258
  else
261
- g = a - c
262
- h = c - a
259
+ g = a.reject { |val| c.include?(val) }
260
+ h = c.reject { |val| a.include?(val) }
263
261
  end
264
262
  g << self
265
263
  h << other
@@ -269,47 +267,18 @@ module Squared
269
267
  -1
270
268
  elsif h.any? { |val| e.include?(val) }
271
269
  1
272
- elsif e.any? { |val| f.include?(val) } # rubocop:disable Lint/DuplicateBranch
270
+ elsif e.any? { |val| f.include?(val) }
273
271
  -1
274
- elsif f.any? { |val| e.include?(val) } # rubocop:disable Lint/DuplicateBranch
272
+ elsif f.any? { |val| e.include?(val) }
275
273
  1
276
274
  elsif @index >= 0 && (i = other.instance_variable_get(:@index)) >= 0
277
- @index <=> i
275
+ @index <= i ? -1 : 1
276
+ else
277
+ 0
278
278
  end
279
279
  rescue StandardError => e
280
280
  log&.debug e
281
- nil
282
- end
283
-
284
- def version=(val)
285
- @version = val&.to_s
286
- end
287
-
288
- def exception=(val)
289
- @exception = case val
290
- when Numeric, TrueClass, FalseClass
291
- val
292
- else
293
- workspace.exception
294
- end
295
- end
296
-
297
- def pipe=(val)
298
- @pipe = case val
299
- when Numeric, Pathname
300
- val
301
- else
302
- workspace.pipe
303
- end
304
- end
305
-
306
- def verbose=(val)
307
- @verbose = case val
308
- when Numeric, TrueClass, FalseClass
309
- val
310
- else
311
- workspace.verbose
312
- end
281
+ 0
313
282
  end
314
283
 
315
284
  def ref
@@ -322,36 +291,41 @@ module Squared
322
291
 
323
292
  namespace name do
324
293
  Base.subtasks do |action, flags|
325
- next if task_pass?(action)
294
+ next if @pass.include?(action)
326
295
 
327
296
  namespace action do
328
297
  flags.each do |flag|
329
298
  case action
330
299
  when 'graph'
331
- break unless graph?
300
+ next unless graph?
332
301
 
333
302
  format_desc action, flag, '(-)project*'
334
303
  task flag do |_, args|
335
- args = args.to_a.reject { |val| name == val.to_s }
304
+ args = args.to_a.reject { |val| name == val }
336
305
  if flag == :run
337
306
  graph args
338
307
  else
339
308
  out, done = graph(args, out: [])
340
309
  out.map! do |val|
341
- n = done.index { |proj| val.match?(/ #{Regexp.escape(proj.name)}(?:@\d|\z)/) }
342
- n ? "#{val} (#{n.succ})" : val
310
+ done.each_with_index do |proj, i|
311
+ if val.match?(/ #{Regexp.escape(proj.name)}(?:@\d|\z)/)
312
+ val += " (#{i.succ})"
313
+ break
314
+ end
315
+ end
316
+ val
343
317
  end
344
318
  emphasize(out, title: path, right: true, border: borderstyle, sub: [
345
319
  { pat: /\A(#{Regexp.escape(path.to_s)})(.*)\z/, styles: theme[:header] },
346
320
  { pat: /\A(#{Regexp.escape(name)})(.*)\z/, styles: theme[:active] },
347
- { pat: /\A(.+ )(\()(\d+)(\))(.*)\z/, styles: theme[:inline], index: 3 }
321
+ { pat: /\A((?~ \() \()(\d+)(\).*)\z/, styles: theme[:inline], index: 2 }
348
322
  ])
349
323
  end
350
324
  end
351
325
  when 'unpack'
352
326
  format_desc(action, flag, 'tag/url,dir,digest?,f|force?', before: flag == :ext ? 'ext' : nil)
353
327
  params = %i[tag dir digest force]
354
- params.unshift(:ext) if flag == :ext
328
+ params.prepend(:ext) if flag == :ext
355
329
  task flag, params do |_, args|
356
330
  ext = flag == :ext ? param_guard(action, flag, args: args, key: :ext) : flag.to_s
357
331
  tag = param_guard(action, flag, args: args, key: :tag)
@@ -372,7 +346,7 @@ module Squared
372
346
  else
373
347
  force = args.fetch(:force, false)
374
348
  end
375
- unpack(basepath(dir), uri: tag, digest: digest, ext: ext, force: force)
349
+ unpack(path + dir, uri: tag, digest: digest, ext: ext, force: force)
376
350
  end
377
351
  end
378
352
  end
@@ -395,33 +369,35 @@ module Squared
395
369
  end
396
370
 
397
371
  def add(path, name = nil, **kwargs, &blk)
398
- if path.is_a?(String) && path =~ %r{\A(.+)[\\/]\*+\z}
399
- return self unless checkdir?(path = basepath($1))
372
+ if path.is_a?(String) && (seg = path[%r{\A(.+)[\\/]\*+\z}, 1])
373
+ return self unless checkdir?(path = basepath(seg))
400
374
 
401
375
  path = path.children.select { |val| checkdir?(val) }
402
376
  end
403
377
  if path.is_a?(Array)
404
- name = self.name if name == true
378
+ name = @name if name == true
405
379
  path.each { |val| add(val, name && task_join(name, File.basename(val)), **kwargs, &blk) }
406
- elsif projectpath?(path = basepath(path)) && checkdir?(path)
407
- kwargs = hashdup(@withargs).update(kwargs) if @withargs
408
- kwargs[:group] = group if group && !kwargs.key?(:group)
409
- kwargs[:ref] = ref unless kwargs.key?(:ref)
410
- parent = self
411
- proj = nil
412
- name = case name
413
- when String, Symbol
414
- name.to_s
415
- else
416
- path.basename
417
- end
418
- workspace.add(path, name, **kwargs) do
419
- __send__ :parent_set, parent
420
- proj = self
421
- instance_eval(&blk) if block_given?
422
- end
423
- @children << proj
424
- end
380
+ return self
381
+ elsif !projectpath?(path = basepath(path)) || !checkdir?(path)
382
+ return self
383
+ end
384
+ kwargs = @withargs.yield_self { |data| data.dup.update(kwargs) } if @withargs
385
+ kwargs[:group] = group unless kwargs.key?(:group)
386
+ kwargs[:ref] = ref unless kwargs.key?(:ref)
387
+ parent = self
388
+ proj = nil
389
+ name = case name
390
+ when String, Symbol
391
+ name.to_s
392
+ else
393
+ path.basename
394
+ end
395
+ workspace.add(path, name, **kwargs) do
396
+ __send__ :parent_set, parent
397
+ proj = self
398
+ end
399
+ @children << proj
400
+ proj.instance_eval(&blk) if block_given?
425
401
  self
426
402
  end
427
403
 
@@ -431,13 +407,13 @@ module Squared
431
407
  end
432
408
 
433
409
  def inject(obj, *args, **kwargs, &blk)
434
- if enabled?
435
- out = obj.link(self, *args, **kwargs, &blk) if obj.respond_to?(:link)
436
- if !out
437
- print_error('link not compatible', subject: obj, hint: name)
438
- elsif out.respond_to?(:build)
439
- out.build
440
- end
410
+ return self unless enabled?
411
+
412
+ out = obj.link(self, *args, **kwargs, &blk) if obj.respond_to?(:link)
413
+ if !out
414
+ warn log_message(Logger::WARN, 'link not compatible', subject: obj.to_s, hint: name, pass: true)
415
+ elsif out.respond_to?(:build)
416
+ out.build
441
417
  end
442
418
  self
443
419
  end
@@ -454,59 +430,55 @@ module Squared
454
430
  if args.first.is_a?(Struct)
455
431
  f, blk = args.first.to_a
456
432
  args[0] = instance_eval(&blk) || f
457
- return unless args.first
433
+ return unless args[0]
458
434
  end
459
435
  if args.all? { |val| val.is_a?(Array) }
460
436
  cmd = []
461
437
  var = {}
462
438
  args.each do |val|
463
- next instance_exec(*val[1..-1], &val.first) if val.first.is_a?(Proc)
439
+ next instance_exec(*val[1..-1], &val[0]) if val.first.is_a?(Proc)
464
440
 
465
441
  a, b, c, d, e = val
466
442
  case b
467
443
  when Hash
468
- b = append_hash(b, target: [], build: true).join(' ')
444
+ b = append_hash(b, build: true).join(' ')
469
445
  when Enumerable
470
446
  b = b.to_a.join(' ')
471
447
  end
472
- d = append_hash(d, target: []).join(' ') if d.is_a?(Hash)
448
+ d = append_hash(d).join(' ') if d.is_a?(Hash)
473
449
  if a
474
450
  cmd << [a, d, b].compact.join(' ')
475
451
  else
476
452
  next unless respond_to?(:compose)
477
453
 
478
- cmd << a if (a = compose(as_get(b, from), d, script: true, args: e, from: from))
454
+ cmd << a if (a = compose(as_get(b), d, script: true, args: e, from: from))
479
455
  end
480
- var.merge!(c) if c.is_a?(Hash)
456
+ var.update(c) if c.is_a?(Hash)
481
457
  end
482
458
  cmd = cmd.join(' && ')
483
459
  else
484
460
  cmd, opts, var, flags, extra = args
485
- if cmd
486
- return run_b(cmd, sync: sync, from: from) if cmd.is_a?(Proc) || cmd.is_a?(Method)
487
-
488
- cmd = as_get(cmd, from)
489
- opts = compose(opts, script: false) if opts && respond_to?(:compose)
490
- flags = append_hash(flags, target: []).join(' ') if flags.is_a?(Hash)
491
- case opts
492
- when Hash
493
- cmd = Array(cmd).push(flags)
494
- .concat(append_hash(opts, target: [], build: true))
495
- .compact
496
- .join(' ')
497
- when Enumerable
498
- cmd = Array(cmd).concat(opts.to_a)
499
- cmd.map! { |val| "#{val} #{flags}" } if flags
500
- cmd = cmd.join(' && ')
501
- else
502
- cmd = [cmd, flags, opts].compact.join(' ') if opts || flags
503
- end
461
+ end
462
+ if cmd
463
+ cmd = as_get cmd
464
+ opts = compose(opts, script: false) if opts && respond_to?(:compose)
465
+ flags = append_hash(flags).join(' ') if flags.is_a?(Hash)
466
+ case opts
467
+ when Hash
468
+ opts = append_hash(opts, build: true)
469
+ cmd = as_a(cmd).append(flags).concat(opts).compact.join(' ')
470
+ when Enumerable
471
+ cmd = as_a(cmd).concat(opts.to_a)
472
+ cmd.map! { |val| "#{val} #{flags}" } if flags
473
+ cmd = cmd.join(' && ')
504
474
  else
505
- return unless (opts || extra) && respond_to?(:compose)
506
-
507
- cmd = compose(as_get(opts, from), flags, script: true, args: extra, from: from)
508
- from = :script if from == :run && script?
475
+ cmd = [cmd, flags, opts].compact.join(' ') if opts || flags
509
476
  end
477
+ else
478
+ return unless (opts || extra) && respond_to?(:compose)
479
+
480
+ cmd = compose(as_get(opts), flags, script: true, args: extra, from: from)
481
+ from = :script if from == :run && script?
510
482
  end
511
483
  run(cmd, var, sync: sync, from: from, banner: banner)
512
484
  end
@@ -521,15 +493,19 @@ module Squared
521
493
  next if @@graph[:_].include?(proj)
522
494
 
523
495
  if (val = ENV["PREREQS_#{proj.instance_variable_get(:@envname)}"] || ENV["PREREQS_#{proj.ref.upcase}"])
524
- split_escape(val).each do |meth|
496
+ val.split(/\s*,\s*/).each do |meth|
525
497
  if proj.respond_to?(meth.to_sym)
526
498
  begin
527
499
  proj.__send__(meth, sync: sync)
528
500
  rescue StandardError => e
529
- on_error(e, :prereqs, exception: true)
501
+ ret = on(:error, :prereqs, e)
502
+ raise unless ret == true
503
+ else
504
+ next
530
505
  end
531
- else
532
- print_error(name, "method: #{meth}", subject: 'prereqs', hint: 'undefined')
506
+ end
507
+ if warning?
508
+ warn log_message(Logger::WARN, name, 'method not found', subject: 'prereqs', hint: meth, pass: true)
533
509
  end
534
510
  end
535
511
  elsif proj.build?
@@ -547,7 +523,7 @@ module Squared
547
523
  end
548
524
 
549
525
  def doc(*, sync: invoked_sync?('doc'), **)
550
- run_b(@doc, sync: sync, banner: verbosetype > (from_base?('doc') ? 1 : 0), from: :doc)
526
+ run_b(@doc, sync: sync, from: :doc, banner: from_base?('doc') ? verbosetype > 1 : verbose)
551
527
  end
552
528
 
553
529
  def lint(*, sync: invoked_sync?('lint'), **)
@@ -568,9 +544,9 @@ module Squared
568
544
  on :first, :clean unless pass
569
545
  case @clean
570
546
  when Struct
571
- if (val = instance_eval(&@clean.block) || @clean.run)
547
+ if (any = instance_eval(&@clean.block) || @clean.run)
572
548
  temp = @clean
573
- @clean = val
549
+ @clean = any
574
550
  clean(*args, sync: sync, pass: true, **kwargs)
575
551
  @clean = temp
576
552
  end
@@ -580,15 +556,17 @@ module Squared
580
556
  begin
581
557
  @clean.each { |cmd, opts| build(cmd.to_s, opts, sync: sync) }
582
558
  rescue StandardError => e
583
- on_error e, :clean
559
+ log&.error e
560
+ ret = on(:error, from, e)
561
+ raise if exception && ret != true
584
562
  end
585
563
  else
586
564
  if @clean.is_a?(Enumerable) && !series?(@clean)
587
565
  @clean.each do |val|
588
- entry = basepath(val = val.to_s)
566
+ entry = path + (val = val.to_s)
589
567
  if entry.directory? && val.match?(%r{[\\/]\z})
590
568
  log&.warn "rm -rf #{entry}"
591
- rm_rf(entry, verbose: verbosetype > 0)
569
+ rm_rf(entry, verbose: verbose)
592
570
  else
593
571
  log&.warn "rm #{entry}"
594
572
  (val.include?('*') ? Dir[entry] : [entry]).each do |file|
@@ -629,7 +607,8 @@ module Squared
629
607
  end
630
608
  ret = graph_branch(self, data, tasks, out, sync: sync, pass: pass)
631
609
  rescue StandardError => e
632
- on_error(e, :graph, exception: true)
610
+ ret = on(:error, :graph, e)
611
+ raise unless ret == true
633
612
  else
634
613
  if out
635
614
  [out, ret]
@@ -638,13 +617,13 @@ module Squared
638
617
  end
639
618
  end
640
619
 
641
- def unpack(target, file = nil, uri: nil, sync: true, digest: nil, ext: nil, force: false, depth: 1, headers: {},
642
- verbose: self.verbose, from: :unpack)
620
+ def unpack(target, uri:, sync: true, digest: nil, ext: nil, force: false, depth: 1, headers: {}, from: :unpack)
621
+ require 'open-uri'
643
622
  if !target.exist?
644
623
  target.mkpath
645
624
  elsif !target.directory?
646
625
  raise_error('invalid location', hint: target)
647
- elsif !file && !target.empty?
626
+ elsif !target.empty?
648
627
  raise_error('directory not empty', hint: target) unless force || env('UNPACK_FORCE')
649
628
  create = true
650
629
  end
@@ -665,95 +644,87 @@ module Squared
665
644
  when 128, 'sha512'
666
645
  Digest::SHA512
667
646
  else
668
- raise_error "invalid checksum: #{digest}"
647
+ raise_error("invalid checksum: #{digest}", hint: name)
669
648
  end
670
649
  end
671
650
  if (val = env('HEADERS')) && (val = parse_json(val, hint: "HEADERS_#{@envname}"))
672
651
  headers = headers.is_a?(Hash) ? headers.merge(val) : val
673
652
  end
674
- if file
675
- ext ||= File.extname(file)[1..-1]
676
- else
677
- data = nil
678
- (uri = Array(uri)).each_with_index do |url, index|
679
- fetch_uri(url, headers) do |f|
680
- data = f.read
681
- if algo && algo.hexdigest(data) != digest
682
- data = nil
683
- raise_error("checksum failed: #{digest}", hint: url) if index == uri.size - 1
684
- end
685
- next if ext && index == 0
686
-
687
- case f.content_type
688
- when 'application/zip'
689
- ext = 'zip'
690
- when %r{application/(?:x-)?gzip}
691
- ext = 'tgz'
692
- when 'application/x-xz'
693
- ext = 'txz'
694
- when 'application/x-7z-compressed'
695
- ext = '7z'
696
- end
653
+ data = nil
654
+ (uri = as_a(uri)).each_with_index do |url, index|
655
+ URI.open(url, headers) do |f|
656
+ data = f.read
657
+ if algo && algo.hexdigest(data) != digest
658
+ data = nil
659
+ raise_error("checksum failed: #{digest}", hint: url) if index == uri.size - 1
660
+ end
661
+ next if ext && index == 0
662
+
663
+ case f.content_type
664
+ when 'application/zip'
665
+ ext = 'zip'
666
+ when 'application/x-gzip'
667
+ ext = 'tgz'
668
+ when 'application/x-xz'
669
+ ext = 'txz'
697
670
  end
698
- break uri = url if data
699
- end
700
- unless data && (ext ||= URI.decode_www_form_component(URI.parse(uri).path[/\.([\w%]+)(?:\?|\z)/, 1]))
701
- raise_error("no content#{data ? ' type' : ''}", hint: uri)
702
671
  end
672
+ break uri = url if data
673
+ end
674
+ unless data && (ext ||= URI.parse(uri).path[/\.(\w+)(?:\?|\z)/, 1])
675
+ raise_error("no content#{data ? ' type' : ''}", hint: uri)
703
676
  end
704
677
  ext = ext.downcase
705
678
  if (val = env("#{%w[zip 7z gem].include?(ext) ? ext.upcase : 'TAR'}_DEPTH", ignore: false))
706
679
  depth = val.to_i
707
680
  end
708
681
  begin
709
- unless file
710
- if ext == 'gem'
711
- dir = Dir.mktmpdir
712
- file = File.new(File.join(dir, File.basename(uri)), 'w')
713
- else
714
- require 'tempfile'
715
- file = Tempfile.new("#{name}-")
716
- end
717
- file.write(data)
718
- file.close
719
- file = Pathname.new(file)
720
- delete = true
682
+ if ext == 'gem'
683
+ dir = Dir.mktmpdir
684
+ file = File.new(File.join(dir, File.basename(uri)), 'w')
685
+ else
686
+ require 'tempfile'
687
+ file = Tempfile.new("#{name}-")
721
688
  end
689
+ file.write(data)
690
+ file.close
722
691
  if create
723
- print_error('force remove', subject: name, hint: target)
692
+ warn log_message(Logger::WARN, 'force remove', subject: name, hint: target, pass: true)
724
693
  target.rmtree
725
694
  target.mkpath
726
695
  end
727
696
  case ext
728
697
  when 'zip', 'aar'
729
- session 'unzip', shell_quote(file), quote_option('d', target)
730
- when 'tar', 'tgz', 'txz', 'tar.gz', 'tar.xz', 'gz', 'xz'
698
+ session 'unzip', shell_quote(file.path), quote_option('d', target)
699
+ when 'tar', 'tgz', 'tar.gz', 'tar.xz', 'gz', 'xz'
731
700
  flags = +(verbose ? 'v' : '')
732
701
  if ext.end_with?('gz')
733
702
  flags += 'z'
734
703
  elsif ext.end_with?('xz')
735
704
  flags += 'J'
736
705
  end
737
- session 'tar', "-x#{flags}", basic_option('strip-components', depth), quote_option('f', file),
706
+ session 'tar', "-x#{flags}", basic_option('strip-components', depth), quote_option('f', file.path),
738
707
  quote_option('C', target)
739
708
  depth = 0
740
709
  when '7z'
741
- session '7z', 'x', shell_quote(file), "-o#{shell_quote(target)}"
710
+ session '7z', 'x', shell_quote(file.path), "-o#{shell_quote(target)}"
742
711
  when 'gem'
743
- session 'gem', 'unpack', shell_quote(file), quote_option('target', target)
712
+ session 'gem', 'unpack', shell_quote(file.path), quote_option('target', target)
744
713
  depth = 0 unless val
745
714
  else
746
- raise_error("unsupported format: #{ext}", hint: uri || file)
715
+ raise_error("unsupported format: #{ext}", hint: uri)
747
716
  end
748
- run(sync: sync, banner: verbose, from: from)
717
+ run(sync: sync, from: from)
749
718
  while depth > 0 && target.children.size == 1
750
719
  entry = target.children.first
751
720
  break unless entry.directory?
752
721
 
753
722
  i = 0
754
- i += 1 while (dest = target + "#{File.basename(file)}-#{i}").exist?
723
+ while (dest = target + "#{File.basename(file.path)}-#{i}").exist?
724
+ i += 1
725
+ end
755
726
  FileUtils.mv(entry, dest)
756
- dest.children.each { |child| FileUtils.mv(child, target) }
727
+ dest.each_child { |child| FileUtils.mv(child, target) }
757
728
  dest.rmdir
758
729
  target = entry
759
730
  depth -= 1
@@ -761,8 +732,8 @@ module Squared
761
732
  ensure
762
733
  if dir
763
734
  remove_entry dir
764
- elsif delete && file&.exist?
765
- file.unlink
735
+ else
736
+ file&.unlink
766
737
  end
767
738
  end
768
739
  end
@@ -780,7 +751,7 @@ module Squared
780
751
  end
781
752
 
782
753
  def event(name, key, *args, override: false, **kwargs, &blk)
783
- data = @events[name.to_sym]
754
+ data = @events[name.to_sym] ||= {}
784
755
  items = if override
785
756
  data[key.to_sym] = []
786
757
  else
@@ -791,8 +762,9 @@ module Squared
791
762
  end
792
763
 
793
764
  def as(cmd, script, to = nil)
794
- data = @as[cmd.to_sym]
795
- (to ? [[script, to]] : script).each { |key, val| data[key.to_s] = val }
765
+ script = { "#{script}": to } if to
766
+ data = (@as ||= {})[cmd.to_sym] ||= {}
767
+ script.each { |key, val| data[key.to_s] = val }
796
768
  self
797
769
  end
798
770
 
@@ -809,57 +781,14 @@ module Squared
809
781
  self
810
782
  end
811
783
 
812
- def run(cmd = @session, var = nil, exception: self.exception, sync: true, from: nil, banner: true, chdir: path,
813
- interactive: nil, hint: nil, **)
814
- unless cmd
815
- print_error('no command given', subject: project, hint: from || 'unknown', pass: true)
816
- return
817
- end
818
- cmd = cmd.target if cmd.is_a?(OptionPartition)
819
- if interactive && (!@session || !option('y'))
820
- title, y = case interactive
821
- when Array
822
- interactive
823
- when String
824
- [interactive, 'N']
825
- else
826
- ['Run', 'Y']
827
- end
828
- yn = y == 'Y' ? 'Y/n' : 'y/N'
829
- exit 1 unless confirm("#{title}? [#{sub_style(cmd.to_s, styles: theme[:inline])}] [#{yn}] ", y)
830
- end
831
- cmd = session_done cmd
832
- log&.info cmd
833
- on :first, from
834
- begin
835
- if cmd.match?(/\A[^:]+:[^:]/) && workspace.task_defined?(cmd)
836
- log&.warn "ENV discarded: #{var}" if var
837
- task_invoke(cmd, exception: exception, warning: warning?)
838
- else
839
- print_item format_banner(hint ? "#{cmd} (#{hint})" : cmd, banner: banner) if sync
840
- if var != false && (pre = runenv)
841
- case pre
842
- when Hash
843
- var = var.is_a?(Hash) ? pre.merge(var) : pre
844
- when Enumerable
845
- cmd = command(*pre.to_a, cmd)
846
- else
847
- cmd = command(pre, cmd)
848
- end
849
- end
850
- args = var.is_a?(Hash) ? [var, cmd] : [cmd]
851
- ret = shell(*args, chdir: chdir, exception: exception)
784
+ def variable_set(key, *args, **kwargs, &blk)
785
+ if block_given?
786
+ if blocks.include?(key)
787
+ series key, &blk
788
+ return self
852
789
  end
853
- rescue StandardError => e
854
- on_error(e, from, exception: true)
855
- false
856
- else
857
- on :last, from
858
- ret
790
+ args = block_args args, &blk
859
791
  end
860
- end
861
-
862
- def variable_set(key, *args, **kwargs, &blk)
863
792
  if variables.include?(key) || blocks.include?(key)
864
793
  val = case args.size
865
794
  when 0
@@ -876,14 +805,10 @@ module Squared
876
805
  graph_set val
877
806
  when :pass
878
807
  pass_set val
879
- when :only
880
- only_set val
881
808
  when :exclude
882
809
  exclude_set val
883
810
  when :parent
884
811
  parent_set val
885
- when :archive
886
- archive_set val
887
812
  when :run
888
813
  run_set(*args, **kwargs)
889
814
  when :script
@@ -893,14 +818,7 @@ module Squared
893
818
  when :dependfile
894
819
  @dependfile = basepath(*args)
895
820
  else
896
- if block_given?
897
- if blocks.include?(key)
898
- series key, &blk
899
- return self
900
- end
901
- val = block_args val, &blk
902
- end
903
- instance_variable_set(:"@#{key}", val.first)
821
+ instance_variable_set(:"@#{key}", val)
904
822
  end
905
823
  else
906
824
  log&.warn "variable_set: @#{key} (private)"
@@ -908,8 +826,6 @@ module Squared
908
826
  self
909
827
  end
910
828
 
911
- alias apply variable_set
912
-
913
829
  def enabled?(ref = nil, **)
914
830
  return false if ref && !ref?(ref)
915
831
 
@@ -1002,7 +918,7 @@ module Squared
1002
918
  def log
1003
919
  return @log unless @log.is_a?(Array)
1004
920
 
1005
- @log = Logger.new(enabled? ? @log.first : nil, **@log.last)
921
+ @log = Logger.new(enabled? ? @log[0] : nil, **@log[1])
1006
922
  end
1007
923
 
1008
924
  def allref
@@ -1020,7 +936,7 @@ module Squared
1020
936
  path.parent.ascend.each do |dir|
1021
937
  target = dir.join(*args)
1022
938
  return target if target.exist?
1023
- break if (ascend && dir.join(ascend).exist?) || workspace.root == dir || parent&.path == dir
939
+ break if (ascend.is_a?(String) && dir.join(ascend).exist?) || workspace.root == dir || parent&.path == dir
1024
940
  end
1025
941
  ret
1026
942
  end
@@ -1043,8 +959,51 @@ module Squared
1043
959
 
1044
960
  private
1045
961
 
1046
- def puts(*args, **kwargs)
1047
- log_console(*args, pipe: kwargs[:pipe] || pipe)
962
+ def puts(*args)
963
+ puts_oe(*args, pipe: pipe)
964
+ end
965
+
966
+ def run(cmd = @session, var = nil, exception: @exception, sync: true, from: nil, banner: true, chdir: path, **)
967
+ unless cmd
968
+ if warning?
969
+ from &&= from.to_s
970
+ warn log_message(Logger::WARN, from || 'unknown', subject: project, hint: 'no command given', pass: true)
971
+ end
972
+ return
973
+ end
974
+ cmd = cmd.target if cmd.is_a?(OptionPartition)
975
+ cmd = session_done cmd
976
+ log&.info cmd
977
+ on :first, from
978
+ begin
979
+ if cmd.start_with?(/[^:]+:[^:]/) && workspace.task_defined?(cmd)
980
+ log&.warn "ENV discarded: #{var}" if var
981
+ task_invoke(cmd, exception: exception, warning: warning?)
982
+ else
983
+ print_item format_banner(cmd, banner: banner) if sync
984
+ if var != false && (pre = runenv)
985
+ case pre
986
+ when Hash
987
+ var = var.is_a?(Hash) ? pre.merge(var) : pre
988
+ when Enumerable
989
+ cmd = command(*pre.to_a, cmd)
990
+ else
991
+ cmd = command pre, cmd
992
+ end
993
+ end
994
+ args = var.is_a?(Hash) ? [var, cmd] : [cmd]
995
+ ret = shell(*args, chdir: chdir, exception: exception)
996
+ end
997
+ rescue StandardError => e
998
+ log&.error e
999
+ ret = on(:error, from, e)
1000
+ raise unless ret == true
1001
+
1002
+ false
1003
+ else
1004
+ on :last, from
1005
+ ret
1006
+ end
1048
1007
  end
1049
1008
 
1050
1009
  def run_s(*cmd, env: nil, sync: true, from: nil, banner: verbose != false, **kwargs)
@@ -1052,7 +1011,7 @@ module Squared
1052
1011
  begin
1053
1012
  cmd.flatten.each { |val| run(val, env, sync: sync, banner: banner, **kwargs) }
1054
1013
  rescue StandardError => e
1055
- ret = on :error, from, e
1014
+ ret = on(:error, from, e)
1056
1015
  raise unless ret == true
1057
1016
  end
1058
1017
  on :last, from
@@ -1074,7 +1033,7 @@ module Squared
1074
1033
  elsif obj.is_a?(Array) && obj.any? { |val| !val.is_a?(String) }
1075
1034
  build(*obj, **kwargs)
1076
1035
  elsif obj
1077
- run_s(*Array(obj), **kwargs)
1036
+ run_s(obj.is_a?(Enumerable) ? obj.to_a : obj, **kwargs)
1078
1037
  end
1079
1038
  end
1080
1039
  end
@@ -1082,7 +1041,6 @@ module Squared
1082
1041
  def graph_branch(target, data, tasks = nil, out = nil, sync: true, pass: [], done: [], depth: 0,
1083
1042
  single: false, last: false, context: nil)
1084
1043
  tag = ->(proj) { "#{proj.name}#{SEM_VER.match?(proj.version) ? "@#{proj.version}" : ''}" }
1085
- script = ->(proj) { workspace.script_get(:graph, group: proj.group, ref: proj.allref)&.fetch(:graph, nil) }
1086
1044
  check = ->(deps) { deps.reject { |val| done.include?(val) } }
1087
1045
  dedupe = lambda do |name|
1088
1046
  next [] unless (ret = data[name])
@@ -1122,7 +1080,7 @@ module Squared
1122
1080
 
1123
1081
  t = dedupe.call(proj.name)
1124
1082
  j = if out
1125
- if i == items.size - 1 || check.call(post = items[(i + 1)..-1]).empty?
1083
+ if i == items.size - 1 || check.call(post = items[i + 1..-1]).empty?
1126
1084
  true
1127
1085
  elsif !t.empty? && depth > 0
1128
1086
  post.reject { |pr| t.include?(pr) }.empty?
@@ -1133,7 +1091,10 @@ module Squared
1133
1091
  single: single, last: j == true, context: target)
1134
1092
  end
1135
1093
  if !out
1136
- (tasks || (subtasks = script.call(proj)) || (dev? ? %w[build copy] : %w[depend build])).each do |meth|
1094
+ if !tasks && (script = workspace.script_get(:graph, group: proj.group, ref: proj.allref))
1095
+ group = script[:graph]
1096
+ end
1097
+ (tasks || group || (dev? ? ['build', 'copy'] : ['depend', 'build'])).each do |meth|
1137
1098
  next if pass.include?(meth)
1138
1099
 
1139
1100
  if workspace.task_defined?(cmd = task_join(proj.name, meth))
@@ -1144,7 +1105,7 @@ module Squared
1144
1105
  end
1145
1106
  run(cmd, sync: false, banner: false)
1146
1107
  ENV.delete(key) if key
1147
- elsif proj.has?(meth, tasks || subtasks ? nil : workspace.baseref)
1108
+ elsif proj.has?(meth, tasks || group ? nil : workspace.baseref)
1148
1109
  proj.__send__(meth.to_sym, sync: sync)
1149
1110
  end
1150
1111
  end
@@ -1169,7 +1130,7 @@ module Squared
1169
1130
  done
1170
1131
  end
1171
1132
 
1172
- def graph_collect(target, start = [], data: {}, pass: [], root: [])
1133
+ def graph_collect(target, start = [], data: {}, pass: [])
1173
1134
  deps = []
1174
1135
  (start.empty? ? target.instance_variable_get(:@graph) : start)&.each do |val|
1175
1136
  next if pass.include?(val)
@@ -1181,13 +1142,12 @@ module Squared
1181
1142
  else
1182
1143
  items = workspace.find(group: val, ref: val.to_sym)
1183
1144
  end
1145
+
1184
1146
  items.each do |proj|
1185
- next if pass.include?(name = proj.name)
1147
+ next if pass.include?(proj.name)
1186
1148
 
1187
- if proj.graph? && !data.key?(name) && !root.include?(name)
1188
- graph_collect(proj, data: data, pass: pass, root: root + [name, target.name])
1189
- end
1190
- next if (objs = data.fetch(name, [])).include?(target)
1149
+ graph_collect(proj, data: data, pass: pass) if proj.graph? && !data.key?(proj.name)
1150
+ next if (objs = data.fetch(proj.name, [])).include?(target)
1191
1151
 
1192
1152
  deps << proj
1193
1153
  deps.concat(objs)
@@ -1227,23 +1187,31 @@ module Squared
1227
1187
  end
1228
1188
  return ret == equals.to_s unless equals.nil?
1229
1189
 
1230
- ret.empty? || (ignore && Array(ignore).any? { |val| ret == val.to_s }) ? default : ret
1190
+ ret.empty? || (ignore && as_a(ignore).any? { |val| ret == val.to_s }) ? default : ret
1231
1191
  end
1232
1192
 
1233
1193
  def session(*cmd, prefix: cmd.first, main: true, path: true, options: true)
1234
- prefix = stripext prefix.to_s
1235
- if path && (val = shell_bin(prefix))
1194
+ prefix = stripext(prefix.to_s).upcase
1195
+ if path && (val = ENV["PATH_#{prefix}"] || PATH[prefix] || PATH[prefix.to_sym])
1236
1196
  cmd[0] = shell_quote(val, force: false)
1237
1197
  end
1238
1198
  ret = JoinSet.new(cmd.flatten(1))
1239
- if options && (val = env("#{prefix.upcase}_OPTIONS"))
1240
- split_escape(val).each { |opt| ret.last(fill_option(opt), /\A(--?[^\[\]=\s-][^\[\]=\s]*)[=\s].+\z/m) }
1199
+ if options && (val = env("#{prefix}_OPTIONS"))
1200
+ split_escape(val).each { |opt| ret.last(fill_option(opt), /\A(--?[^ =]+)[ =].+\z/m) }
1241
1201
  end
1242
1202
  main ? @session = ret : ret
1243
1203
  end
1244
1204
 
1245
1205
  def session_delete(*args, target: @session)
1246
- OptionPartition.delete(target, *args)
1206
+ ret = []
1207
+ args.each do |val|
1208
+ pat = /\A#{Regexp.escape(shell_option(val))}(?: |=|\z)/
1209
+ if (key = target.find { |opt| opt.match?(pat) })
1210
+ target.delete(key)
1211
+ ret << key
1212
+ end
1213
+ end
1214
+ ret
1247
1215
  end
1248
1216
 
1249
1217
  def session_output(*cmd, **kwargs)
@@ -1253,7 +1221,7 @@ module Squared
1253
1221
  def session_done(cmd)
1254
1222
  return cmd unless cmd.respond_to?(:done)
1255
1223
 
1256
- raise_error('no args added', hint: cmd.first) unless cmd.size > 1
1224
+ raise_error('no args added', hint: cmd.first || name) unless cmd.size > 1
1257
1225
  @session = nil if cmd == @session
1258
1226
  cmd.done
1259
1227
  end
@@ -1265,20 +1233,17 @@ module Squared
1265
1233
  end
1266
1234
 
1267
1235
  def option(*args, target: @session, prefix: target&.first, **kwargs)
1268
- return unless prefix
1236
+ if prefix
1237
+ args.each do |val|
1238
+ next unless (ret = env("#{stripext(prefix)}_#{val.gsub(/\W/, '_')}".upcase, **kwargs))
1239
+ return ret unless block_given?
1269
1240
 
1270
- args.each do |val|
1271
- ret = env(env_key(stripext(prefix), val), **kwargs)
1272
- return ret if ret
1241
+ return yield ret
1242
+ end
1273
1243
  end
1274
1244
  nil
1275
1245
  end
1276
1246
 
1277
- def option_sanitize(opts, list, target: @session, **kwargs)
1278
- op = OptionPartition.new(opts, list, target, project: self, **kwargs)
1279
- [op.extras, op.values]
1280
- end
1281
-
1282
1247
  def option_clear(opts, target: @session, **kwargs)
1283
1248
  return unless target
1284
1249
 
@@ -1289,17 +1254,13 @@ module Squared
1289
1254
  puts 'Success'
1290
1255
  end
1291
1256
 
1292
- def print_error(*args, loglevel: Logger::WARN, **kwargs)
1293
- warn log_message(loglevel, *args, **kwargs) if warning?
1294
- end
1295
-
1296
1257
  def print_item(*val)
1297
1258
  puts unless printfirst?
1298
1259
  printsucc
1299
1260
  puts val unless val.empty? || (val.size == 1 && val.first.nil?)
1300
1261
  end
1301
1262
 
1302
- def print_banner(*lines, client: false, styles: theme[:banner], border: borderstyle, **)
1263
+ def print_banner(*lines, styles: theme[:banner], border: borderstyle, client: false)
1303
1264
  pad = 0
1304
1265
  if styles
1305
1266
  if styles.any? { |s| s.to_s.end_with?('!') }
@@ -1308,7 +1269,7 @@ module Squared
1308
1269
  styles = [:bold] + styles
1309
1270
  end
1310
1271
  end
1311
- n = Project.max_width(lines)
1272
+ n = line_width lines
1312
1273
  ch = ' ' * pad
1313
1274
  index = -1
1314
1275
  lines.map! do |val|
@@ -1323,64 +1284,45 @@ module Squared
1323
1284
  (lines << sub_style(ARG[:BORDER][1] * n, styles: border)).join("\n")
1324
1285
  end
1325
1286
 
1326
- def print_footer(*lines, sub: nil, reverse: false, right: false, border: borderstyle, **)
1327
- n = Project.max_width(lines)
1287
+ def print_footer(*lines, sub: nil, reverse: false, right: false, **kwargs)
1288
+ n = line_width lines
1328
1289
  lines.map! do |val|
1329
1290
  s = right ? val.rjust(n) : val.ljust(n)
1330
1291
  sub&.each { |h| s = sub_style(s, **h) }
1331
1292
  s
1332
1293
  end
1333
- ret = [sub_style(ARG[:BORDER][1] * n, styles: border)].concat(lines)
1294
+ ret = [sub_style(ARG[:BORDER][1] * n, styles: kwargs.key?(:border) ? kwargs[:border] : borderstyle), *lines]
1334
1295
  ret.reverse! if reverse
1335
1296
  ret.join("\n")
1336
1297
  end
1337
1298
 
1338
- def print_status(*args, from: nil, **kwargs)
1339
- return if stdin?
1340
-
1341
- case from
1342
- when :outdated
1343
- out = print_footer("major #{args[0]} / minor #{args[1]} / patch #{args[2]}", right: true).split("\n")
1344
- out[1] = sub_style(out[1], pat: /^( +major )(\d+)(.+)$/, styles: theme[:major], index: 2)
1345
- out[1] = sub_style(out[1], pat: /^(.+)(minor )(\d+)(.+)$/, styles: theme[:active], index: 3)
1346
- puts out
1347
- when :completed
1348
- if verbose && kwargs[:start]
1349
- msg = sub_style('completed', styles: theme[:active])
1350
- puts log_message(Logger::INFO, *args, msg, subject: kwargs[:subject],
1351
- hint: time_format(epochtime - kwargs[:start]))
1352
- end
1353
- end
1354
- end
1355
-
1356
1299
  def format_desc(action, flag, opts = nil, **kwargs)
1357
1300
  return unless TASK_METADATA
1358
1301
 
1359
- ret = [@desc, action]
1360
- ret << flag if flag
1361
- workspace.format_desc(ret, opts, **kwargs)
1302
+ workspace.format_desc([@desc, action, flag].compact, opts, **kwargs)
1362
1303
  end
1363
1304
 
1364
1305
  def format_banner(cmd, banner: true)
1365
1306
  return unless banner && banner?
1366
1307
 
1367
1308
  if (data = workspace.banner_get(*@ref, group: group))
1368
- return if data.empty?
1309
+ return if !data.command && data.order.empty?
1369
1310
 
1370
1311
  client = true
1371
1312
  else
1372
- data = { command: true, order: [:path], styles: theme[:banner], border: theme[:border] }
1313
+ data = Workspace::Support::BannerData.new(true, [:path], theme[:banner], theme[:border])
1373
1314
  end
1374
1315
  if verbose
1375
1316
  out = []
1376
- if data[:command]
1317
+ if data.command
1377
1318
  if cmd =~ /\A(?:"((?:[^"]|(?<=\\)")+)"|'((?:[^']|(?<=\\)')+)'|(\S+))( |\z)/
1378
1319
  path = $3 || $2 || $1
1379
- cmd = cmd.sub(path, stripext(path).upcase)
1320
+ name = stripext path
1321
+ cmd = cmd.sub(path, data.command == 0 ? name : name.upcase)
1380
1322
  end
1381
1323
  out << cmd
1382
1324
  end
1383
- data[:order].each do |val|
1325
+ data.order.each do |val|
1384
1326
  if val.is_a?(Array)
1385
1327
  s = ' '
1386
1328
  found = false
@@ -1390,7 +1332,7 @@ module Squared
1390
1332
  meth
1391
1333
  elsif respond_to?(meth)
1392
1334
  found = true
1393
- __send__(meth)
1335
+ __send__ meth
1394
1336
  end
1395
1337
  end
1396
1338
  val = val.compact.join(s)
@@ -1400,9 +1342,9 @@ module Squared
1400
1342
  end
1401
1343
  out << val.to_s
1402
1344
  end
1403
- print_banner(*out, styles: data[:styles], border: data[:border], client: client)
1345
+ print_banner(*out, styles: data.styles, border: data.border, client: client)
1404
1346
  elsif workspace.series.multiple?
1405
- "## #{__send__(data[:order].first || :path)} ##"
1347
+ "## #{__send__(data.order.first || :path)} ##"
1406
1348
  end
1407
1349
  end
1408
1350
 
@@ -1412,9 +1354,9 @@ module Squared
1412
1354
  unless items.empty?
1413
1355
  pad = items.size.to_s.size
1414
1356
  items.each_with_index do |val, i|
1415
- next unless matchany?(val.first, reg)
1357
+ next unless reg.empty? || reg.any? { |pat| val[0].match?(pat) }
1416
1358
 
1417
- out << "#{i.succ.to_s.rjust(pad)}. #{each ? each.call(val) : val.first}"
1359
+ out << "#{i.succ.to_s.rjust(pad)}. #{each ? each.call(val) : val[0]}"
1418
1360
  end
1419
1361
  end
1420
1362
  sub = [headerstyle]
@@ -1426,13 +1368,13 @@ module Squared
1426
1368
  out << ''
1427
1369
  end
1428
1370
  if from
1429
- out << (from = from.to_s)
1371
+ out << from
1430
1372
  pat = /\A(#{Regexp.escape(from)})(.*)\z/
1431
1373
  end
1432
1374
  else
1433
1375
  pat = /\A(\s*\d+\.)(.+)\z/
1434
1376
  unless grep.empty?
1435
- footer = "#{out.size} found "
1377
+ footer = "#{out.size} found"
1436
1378
  sub << { pat: /\A(\d+)( .+)\z/, styles: theme[:inline] }
1437
1379
  end
1438
1380
  end
@@ -1448,7 +1390,7 @@ module Squared
1448
1390
  opts.each { |val| target << shell_option(flag, val) }
1449
1391
  end
1450
1392
 
1451
- def append_hash(data, target: @session || [], build: false)
1393
+ def append_hash(data, target: @session, build: false)
1452
1394
  if build && (type = env('BUILD', suffix: 'TYPE') || ENV['BUILD_TYPE'])
1453
1395
  type = "__#{type}__"
1454
1396
  if (extra = data[type] || data[type.to_sym]).is_a?(Hash)
@@ -1461,7 +1403,7 @@ module Squared
1461
1403
  next if (key = key.to_s).start_with?('__')
1462
1404
 
1463
1405
  if val.nil? || extra || session_arg?(key, target: target)
1464
- OptionPartition.delete_key(target, key)
1406
+ session_delete(key, target: target)
1465
1407
  next if val.nil?
1466
1408
  end
1467
1409
  case val
@@ -1479,14 +1421,15 @@ module Squared
1479
1421
  end
1480
1422
 
1481
1423
  def append_any(val, target: @session, build: false, delim: false)
1424
+ return unless val
1425
+
1482
1426
  if delim && !target.include?('--')
1483
1427
  target << '--'
1484
1428
  else
1485
1429
  delim = false
1486
1430
  end
1431
+ val = shell_split(val) if val.is_a?(String)
1487
1432
  case val
1488
- when String
1489
- target << val
1490
1433
  when Hash
1491
1434
  append_hash(val, target: target, build: build)
1492
1435
  when Enumerable
@@ -1517,7 +1460,7 @@ module Squared
1517
1460
  return target << (if flag
1518
1461
  shell_option(opt, equals ? val : nil, quote: quote, escape: escape, force: force)
1519
1462
  else
1520
- shell_quote(val)
1463
+ shell_quote val
1521
1464
  end)
1522
1465
  end
1523
1466
  nil
@@ -1527,18 +1470,18 @@ module Squared
1527
1470
  **kwargs)
1528
1471
  return if list.empty?
1529
1472
 
1530
- kwargs[:ignore] = false if no && !kwargs.key?(:ignore)
1531
- ret = []
1532
- list.flatten.each do |flag|
1533
- next unless (val = option(flag, target: target, **kwargs))
1473
+ [].tap do |ret|
1474
+ list.flatten.each do |flag|
1475
+ next unless (val = option(flag, target: target, **kwargs))
1534
1476
 
1535
- if no && val == '0'
1536
- flag = "no-#{flag}"
1537
- val = nil
1477
+ if val == '0' && no
1478
+ flag = "no-#{flag}"
1479
+ val = nil
1480
+ end
1481
+ ret << shell_option(flag, equals ? val : nil, escape: escape, quote: quote, force: force)
1538
1482
  end
1539
- ret << shell_option(flag, equals ? val : nil, escape: escape, quote: quote, force: force)
1483
+ ret.each { |val| target << val } unless ret.empty?
1540
1484
  end
1541
- ret.each { |val| target << val } unless ret.empty?
1542
1485
  end
1543
1486
 
1544
1487
  def append_nocolor(target: @session)
@@ -1552,7 +1495,7 @@ module Squared
1552
1495
  when String
1553
1496
  "#{base} #{data}"
1554
1497
  when Hash
1555
- "#{append_hash(base, target: []).join(' ')} #{data}"
1498
+ "#{append_hash(base).join(' ')} #{data}"
1556
1499
  when Enumerable
1557
1500
  "#{base.to_a.join(' ')} #{data}"
1558
1501
  else
@@ -1561,11 +1504,11 @@ module Squared
1561
1504
  when Hash
1562
1505
  case base
1563
1506
  when String
1564
- "#{base} #{append_hash(data, target: []).join(' ')}"
1507
+ "#{base} #{append_hash(data).join(' ')}"
1565
1508
  when Hash
1566
1509
  base.merge(data)
1567
1510
  when Enumerable
1568
- Set.new(base.to_a + append_hash(data, target: [])).to_a
1511
+ Set.new(base.to_a + append_hash(data)).to_a
1569
1512
  else
1570
1513
  data
1571
1514
  end
@@ -1574,7 +1517,7 @@ module Squared
1574
1517
  when String
1575
1518
  "#{base} #{data.to_a.join(' ')}"
1576
1519
  when Hash
1577
- "#{append_hash(base, target: []).join(' ')} #{data.to_a.join(' ')}"
1520
+ "#{append_hash(base).join(' ')} #{data.to_a.join(' ')}"
1578
1521
  when Enumerable
1579
1522
  Set.new(base.to_a + data.to_a).to_a
1580
1523
  else
@@ -1586,9 +1529,9 @@ module Squared
1586
1529
  end
1587
1530
 
1588
1531
  def collect_hash(data, pass: [])
1589
- ret = []
1590
- data.each { |key, val| ret.concat(val) unless pass.include?(key) }
1591
- ret
1532
+ [].tap do |ret|
1533
+ data.each { |key, val| ret.concat(val) unless pass.include?(key) }
1534
+ end
1592
1535
  end
1593
1536
 
1594
1537
  def parse_json(val, kind: Hash, hint: nil)
@@ -1596,20 +1539,11 @@ module Squared
1596
1539
  raise_error("invalid JSON #{kind.name}", val, hint: hint) if kind && !ret.is_a?(kind)
1597
1540
  rescue StandardError => e
1598
1541
  log&.warn e
1599
- print_error(e, subject: name)
1542
+ warn log_message(Logger::WARN, e, subject: name, pass: true) if warning?
1600
1543
  else
1601
1544
  ret
1602
1545
  end
1603
1546
 
1604
- def fetch_uri(*args, **kwargs, &blk)
1605
- require 'open-uri'
1606
- if RUBY_VERSION < '2.5'
1607
- open(*args, **kwargs, &blk)
1608
- else
1609
- URI.open(*args, **kwargs, &blk)
1610
- end
1611
- end
1612
-
1613
1547
  def param_guard(action, flag, args:, key: nil, pat: nil, values: nil)
1614
1548
  if args && key
1615
1549
  val = args.fetch(key, nil)
@@ -1624,7 +1558,7 @@ module Squared
1624
1558
  args
1625
1559
  end
1626
1560
 
1627
- def confirm_outdated(pkg, ver, rev, lock: false)
1561
+ def confirm_outdated(pkg, ver, rev, cur = nil, lock: false, col1: 0)
1628
1562
  a = sub_style(case rev
1629
1563
  when 1
1630
1564
  'MAJOR'
@@ -1632,48 +1566,52 @@ module Squared
1632
1566
  'MINOR'
1633
1567
  else
1634
1568
  'PATCH'
1635
- end, styles: theme[:header])
1636
- b = sub_style("#{pkg} #{ver}", styles: theme[:inline])
1569
+ end, styles: (rev == 1 && theme[:major]) || theme[:header])
1570
+ b = sub_style(pkg.ljust(col1), styles: theme[:inline])
1637
1571
  c, d = rev == 1 || lock ? ['y/N', 'N'] : ['Y/n', 'Y']
1638
- e = lock ? " #{sub_style('(locked)', styles: color(:red))}" : ''
1639
- confirm "Upgrade to #{a}? #{b + e} [#{c}] ", d
1572
+ e = lock ? sub_style((cur || 'locked').rjust(7), styles: color(:red)) : cur&.rjust(7)
1573
+ confirm "#{a}: #{b}#{e} #{sub_style(ver.rjust(col1 > 0 ? 10 : 0), styles: theme[:inline])} [#{c}] ", d
1640
1574
  end
1641
1575
 
1642
- def choice_index(msg, list, values: nil, accept: nil, series: false, trim: nil, column: nil, multiple: false,
1643
- force: true, **kwargs)
1576
+ def choice_index(msg, list, values: nil, accept: nil, series: false, trim: nil, column: nil,
1577
+ multiple: false, force: true, **kwargs)
1644
1578
  puts if !series && !printfirst?
1645
1579
  msg = "#{msg} (optional)" unless force
1646
- unless (ret = choice(msg, list, multiple: multiple, force: force, **kwargs)) && !ret.empty?
1647
- exit 1 if force
1648
- return
1580
+ unless (ret = choice(msg, list, multiple: multiple, force: force, **kwargs)) || !force
1581
+ raise_error 'user cancelled'
1582
+ end
1583
+ if ret.nil? || ret.empty?
1584
+ return unless force
1585
+
1586
+ exit 1
1649
1587
  end
1650
1588
  ret = multiple ? ret.map! { |val| val.sub(trim, '') } : ret.sub(trim, '') if trim
1651
1589
  if column
1652
- a, b = Array(column)
1653
- ret = Array(ret).map! { |val| val[a, b || 1] }
1590
+ a, b = as_a column
1591
+ ret = as_a(ret).map! { |val| val[a, b || 1] }
1654
1592
  ret = ret.first unless multiple
1655
1593
  end
1656
1594
  if accept
1657
- hint = Array(ret).map { |val| sub_style(val, styles: theme[:inline]) }.join(', ')
1658
- accept = Array(accept).map { |val| Array(val) }
1659
- ret = Array(ret) if accept.any? { |val| val[1] == true }
1595
+ a = as_a(ret).map { |val| sub_style(val, styles: theme[:inline]) }.join(', ')
1596
+ accept = as_a(accept).map { |val| as_a(val) }
1597
+ if accept.any? { |val| val[1] == true }
1598
+ ret = [ret]
1599
+ multiple = -1
1600
+ end
1660
1601
  loop do
1661
- item = accept.first
1662
- d, e = item[2] ? ['Y', '[Y/n]'] : ['N', '[y/N]']
1663
- c = confirm("#{item[0]}#{hint ? " [#{hint}]" : ''} #{e} ", d, timeout: 60)
1664
- if item[1] == true
1602
+ c = confirm("#{accept.first[0]}#{a ? " [#{a}]" : ''} [y/N] ", 'N', timeout: 60)
1603
+ if accept.shift[1] == true
1665
1604
  ret << c
1666
1605
  elsif !c
1667
1606
  break
1668
1607
  end
1669
- hint = nil
1670
- accept.shift
1608
+ a = nil
1671
1609
  break if accept.empty?
1672
1610
  end
1673
1611
  exit 1 unless accept.empty?
1674
1612
  end
1675
1613
  if values
1676
- ret = Array(ret)
1614
+ ret = [ret] unless accept && multiple == -1
1677
1615
  values.each do |val|
1678
1616
  if val.is_a?(Array)
1679
1617
  val, force = val
@@ -1688,8 +1626,8 @@ module Squared
1688
1626
  ret
1689
1627
  end
1690
1628
 
1691
- def command_args(args, min: 0, force: false, **kwargs)
1692
- return if args.size > min || option('i', 'interactive', **kwargs, equals: '0')
1629
+ def command_args(args, force: false, **kwargs)
1630
+ return unless args.size == 1 && !option('i', 'interactive', **kwargs, equals: '0')
1693
1631
 
1694
1632
  readline('Enter arguments', force: force)
1695
1633
  end
@@ -1698,7 +1636,7 @@ module Squared
1698
1636
  if (ret = instance_eval(&blk)).nil?
1699
1637
  val
1700
1638
  else
1701
- Array(ret)
1639
+ ret.is_a?(Array) ? ret : [ret]
1702
1640
  end
1703
1641
  end
1704
1642
 
@@ -1707,17 +1645,21 @@ module Squared
1707
1645
  end
1708
1646
 
1709
1647
  def command(*args)
1710
- return args.join(' && ') unless workspace.powershell?
1711
-
1712
- "powershell.exe -Command #{shell_quote("& {#{args.join(' ; ')}}", option: false, double: true)}"
1648
+ if workspace.powershell?
1649
+ "powershell.exe -Command \"& {#{args.join(' ; ')}}\""
1650
+ else
1651
+ args.join(' && ')
1652
+ end
1713
1653
  end
1714
1654
 
1715
1655
  def relativepath(*list, all: false)
1716
1656
  return [] if list.empty?
1717
1657
 
1718
1658
  list.flatten.map! { |val| Pathname.new(val) }.select { |val| projectpath?(val) }.map! do |val|
1719
- ret = (val.absolute? ? val.relative_path_from(path) : val.cleanpath).to_s
1720
- all && val.to_s.end_with?('/') ? "#{ret}/*" : ret
1659
+ val = val.absolute? ? val.relative_path_from(path).to_s : val.to_s
1660
+ val = val[2..-1] if val.start_with?('./')
1661
+ val = "#{val}*" if all && val.end_with?('/')
1662
+ val
1721
1663
  end
1722
1664
  end
1723
1665
 
@@ -1727,18 +1669,7 @@ module Squared
1727
1669
  raise_error 'pathspec not within worktree' unless pass || files.size == proj.size
1728
1670
  files = proj
1729
1671
  end
1730
- files.map { |val| val == '.' ? '.' : shell_quote(basepath(val)) }
1731
- end
1732
-
1733
- def matchmap(list, prefix = nil)
1734
- list.map do |val|
1735
- if val.is_a?(Regexp)
1736
- val
1737
- else
1738
- val = ".*#{val}" if prefix && !val.sub!(/\A(\^|\\A)/, '')
1739
- Regexp.new("#{prefix}#{val == '*' ? '.+' : val}")
1740
- end
1741
- end
1672
+ files.map { |val| val == '.' ? '.' : shell_quote(path + val) }
1742
1673
  end
1743
1674
 
1744
1675
  def semver(val)
@@ -1754,53 +1685,23 @@ module Squared
1754
1685
  end
1755
1686
 
1756
1687
  def semscan(val, fill: true)
1757
- ret = val.scan(SEM_VER).first
1758
- fill ? semver(ret) : ret
1759
- end
1760
-
1761
- def semcmp(val, other)
1762
- return 0 if val == other
1763
- return -1 if (b = other.scan(SEM_VER)).empty?
1764
- return 1 if (a = val.scan(SEM_VER)).empty?
1765
-
1766
- a, b = [a.first, b.first].map! do |c|
1767
- begin
1768
- d = Integer(c[5]).to_s
1769
- rescue StandardError
1770
- d = c[5] ? '-1' : '0'
1771
- end
1772
- [c[0], c[2], c[4] || '0', d]
1773
- end
1774
- a.each_with_index do |c, index|
1775
- next if c == (d = b[index])
1776
-
1777
- return c.to_i < d.to_i ? 1 : -1
1778
- end
1779
- 0
1780
- end
1781
-
1782
- def semgte?(val, other)
1783
- semcmp(val, other) != 1
1688
+ val.scan(SEM_VER).first.yield_self { |data| fill ? semver(data) : data }
1784
1689
  end
1785
1690
 
1786
1691
  def indexitem(val)
1787
- [$1.to_i, $2 && $2[1..-1]] if val =~ /\A[=^#{indexchar}](\d+)(:.+)?\z/
1692
+ [$1.to_i, $2 && $2[1..-1]] if val =~ /\A\^(\d+)(:.+)?\z/
1788
1693
  end
1789
1694
 
1790
1695
  def indexerror(val, list = nil)
1791
1696
  raise_error("requested index #{val}", hint: list && "of #{list.size}")
1792
1697
  end
1793
1698
 
1794
- def indexchar
1795
- workspace.windows? ? '=' : '^'
1796
- end
1797
-
1798
1699
  def printsucc
1799
1700
  @@print_order += 1
1800
1701
  end
1801
1702
 
1802
1703
  def color(val)
1803
- (ret = theme[val]) && !ret.empty? ? ret : [val]
1704
+ theme[val].yield_self { |styles| styles && !styles.empty? ? styles : [val] }
1804
1705
  end
1805
1706
 
1806
1707
  def colormap(val)
@@ -1823,9 +1724,9 @@ module Squared
1823
1724
  end
1824
1725
 
1825
1726
  def on(event, from, *args, **kwargs)
1826
- return unless from && @events.key?(event)
1727
+ return unless from && (data = @events[event])
1827
1728
 
1828
- Array(@events[event][from]).each do |obj|
1729
+ data[from]&.each do |obj|
1829
1730
  target, opts = if obj.is_a?(Array) && obj[1].is_a?(Hash)
1830
1731
  [obj[0], kwargs.empty? ? obj[1] : obj[1].merge(kwargs)]
1831
1732
  else
@@ -1842,49 +1743,27 @@ module Squared
1842
1743
  end
1843
1744
  end
1844
1745
 
1845
- def on_error(err, from, exception: self.exception, pass: false, dryrun: false)
1846
- log&.error err
1847
- unless dryrun
1848
- ret = on :error, from, err
1849
- raise err if exception && ret != true
1850
- end
1851
- print_error(err, pass: pass) unless ret
1852
- end
1853
-
1854
- def pwd_set(done = nil, pass: false, from: nil, dryrun: false)
1855
- pwd = Pathname.pwd
1856
- if block_given?
1857
- begin
1858
- if (path == pwd || pass == true) && (workspace.mri? || !workspace.windows?)
1859
- ret = yield
1860
- else
1861
- Dir.chdir path
1862
- ret = yield
1863
- Dir.chdir pwd
1864
- end
1865
- rescue StandardError => e
1866
- on_error(e, from, dryrun: dryrun)
1867
- else
1868
- ret
1869
- end
1870
- elsif @pwd == pwd
1871
- @pwd = nil
1872
- pwd unless done
1873
- elsif @pwd
1874
- return unless path == pwd
1875
-
1876
- Dir.chdir(@pwd)
1877
- @pwd = nil
1878
- elsif !done && path != pwd
1879
- @pwd = pwd
1746
+ def pwd_set(pass: false, from: nil)
1747
+ pwd = Dir.pwd
1748
+ if path.to_s == pwd || pass == true || (pass.is_a?(String) && semscan(pass).join <= RUBY_VERSION)
1749
+ ret = yield
1750
+ else
1880
1751
  Dir.chdir(path)
1881
- @pwd
1752
+ ret = yield
1753
+ Dir.chdir(pwd)
1882
1754
  end
1755
+ rescue StandardError => e
1756
+ puts e
1757
+ log&.error e
1758
+ ret = on(:error, from, e)
1759
+ raise if exception && ret != true
1760
+ else
1761
+ ret
1883
1762
  end
1884
1763
 
1885
1764
  def run_set(cmd, val = nil, opts: nil, **)
1886
- noopt = @output[1] == false && !@output[0].nil?
1887
- noenv = @output[2] == false
1765
+ diso = @output[1] == false && !@output[0].nil?
1766
+ dise = @output[2] == false
1888
1767
  parse = lambda do |data|
1889
1768
  ret = []
1890
1769
  if data[:command]
@@ -1904,8 +1783,8 @@ module Squared
1904
1783
  case cmd
1905
1784
  when Array
1906
1785
  @output = if cmd.all? { |data| data.is_a?(Hash) }
1907
- noopt = false
1908
- noenv = false
1786
+ diso = false
1787
+ dise = false
1909
1788
  cmd.map { |data| parse.call(data) }
1910
1789
  else
1911
1790
  cmd.dup
@@ -1916,14 +1795,14 @@ module Squared
1916
1795
  else
1917
1796
  @output[0] = cmd
1918
1797
  end
1919
- unless noopt
1798
+ unless diso
1920
1799
  if opts == false
1921
1800
  @output[1] = false
1922
1801
  elsif opts && opts != true
1923
1802
  @output[1] = opts
1924
1803
  end
1925
1804
  end
1926
- return if noenv
1805
+ return if dise
1927
1806
 
1928
1807
  if val.is_a?(Hash)
1929
1808
  @output[2] = val
@@ -1952,18 +1831,33 @@ module Squared
1952
1831
  @parent = val if val.is_a?(Project::Base)
1953
1832
  end
1954
1833
 
1834
+ def exception_set(val)
1835
+ @exception = env_bool(val, workspace.exception, strict: true)
1836
+ end
1837
+
1838
+ def pipe_set(val)
1839
+ @pipe = env_pipe(val, workspace.pipe, strict: true)
1840
+ end
1841
+
1842
+ def verbose_set(val)
1843
+ @verbose = case val
1844
+ when NilClass
1845
+ workspace.verbose
1846
+ when String
1847
+ env_bool(val, workspace.verbose, strict: true, index: true)
1848
+ else
1849
+ val
1850
+ end
1851
+ end
1852
+
1955
1853
  def graph_set(val)
1956
1854
  @graph = if val
1957
- Array(val).map { |s| workspace.prefix ? workspace.task_name(s).to_sym : s.to_sym }.freeze
1855
+ as_a(val).map { |s| workspace.prefix ? workspace.task_name(s).to_sym : s.to_sym }.freeze
1958
1856
  end
1959
1857
  end
1960
1858
 
1961
1859
  def pass_set(val)
1962
- @pass = Array(val).freeze
1963
- end
1964
-
1965
- def only_set(val)
1966
- @only = val && as_a(val, :to_s).freeze
1860
+ @pass = (val ? as_a(val, :to_s) : []).freeze
1967
1861
  end
1968
1862
 
1969
1863
  def exclude_set(val)
@@ -1991,12 +1885,14 @@ module Squared
1991
1885
 
1992
1886
  def dependfile_set(list)
1993
1887
  @dependindex = list.index { |file| basepath(file).exist? }.tap do |index|
1994
- @dependfile = basepath(list[index || 0])
1888
+ @dependfile = @path + list[index || 0]
1995
1889
  end
1996
1890
  end
1997
1891
 
1998
- def as_get(val, from)
1999
- (@global && @as[from][val]) || val
1892
+ def as_get(val)
1893
+ return unless val
1894
+
1895
+ @global && (ret = @as && @as[from] && @as[from][val]) ? ret : val
2000
1896
  end
2001
1897
 
2002
1898
  def task_build(keys)
@@ -2009,7 +1905,7 @@ module Squared
2009
1905
  unless @pass.include?(key.to_s) || ws.task_defined?(name, action) || ws.task_exclude?(action, self)
2010
1906
  ws.task_desc(@desc, action)
2011
1907
  task action do
2012
- __send__(key)
1908
+ __send__ key
2013
1909
  end
2014
1910
  end
2015
1911
  next if (items = @children.select { |item| item.task_include?(key) }).empty?
@@ -2020,24 +1916,17 @@ module Squared
2020
1916
  end
2021
1917
  end
2022
1918
 
2023
- def task_pass?(key)
2024
- @only ? !@only.include?(key) : @pass.include?(key)
2025
- end
2026
-
2027
- def matchany?(val, list, empty: true)
2028
- list.empty? ? empty : list.any? { |pat| val.match?(pat) }
2029
- end
2030
-
2031
1919
  def projectpath?(val)
2032
- ret = Pathname.new(val).cleanpath
2033
- ret.absolute? ? ret.to_s.start_with?(File.join(path, '')) : !ret.to_s.start_with?(File.join('..', ''))
1920
+ Pathname.new(val).cleanpath.yield_self do |file|
1921
+ file.absolute? ? file.to_s.start_with?(File.join(path, '')) : !file.to_s.start_with?(File.join('..', ''))
1922
+ end
2034
1923
  end
2035
1924
 
2036
1925
  def checkdir?(val)
2037
1926
  if val.directory? && !val.empty?
2038
1927
  true
2039
1928
  else
2040
- log&.warn "directory \"#{val}\" (#{val.directory? ? 'empty' : 'not found'})"
1929
+ log&.warn "directory \"#{val}\" (#{val.empty? ? 'empty' : 'not found'})"
2041
1930
  false
2042
1931
  end
2043
1932
  end
@@ -2082,22 +1971,17 @@ module Squared
2082
1971
  return false if workspace.series.chain?(val = task_join(name, action))
2083
1972
  return true if task_invoked?(val) && (!task_invoked?(ac) || !workspace.task_defined?(ac, 'sync'))
2084
1973
 
2085
- val = workspace.series.name_get(action)
2086
- val != action && invoked_sync?(val)
1974
+ workspace.series.name_get(action).yield_self { |name| name != action && invoked_sync?(name) }
2087
1975
  end
2088
1976
 
2089
- def success?(ret, display = true)
2090
- ret == true && display && stdout? && banner?
1977
+ def success?(ret)
1978
+ ret == true && stdout? && banner?
2091
1979
  end
2092
1980
 
2093
1981
  def banner?
2094
1982
  ARG[:BANNER] && !env('BANNER', equals: '0')
2095
1983
  end
2096
1984
 
2097
- def pwd?
2098
- path == Pathname.pwd
2099
- end
2100
-
2101
1985
  def stdin?
2102
1986
  pipe == 0
2103
1987
  end
@@ -2129,20 +2013,8 @@ module Squared
2129
2013
  BLK_SET
2130
2014
  end
2131
2015
 
2132
- def hashobj
2133
- Workspace::Support.hashobj
2134
- end
2135
-
2136
- def hashlist
2137
- Workspace::Support.hashlist
2138
- end
2139
-
2140
- def hashdup
2141
- Workspace::Support.hashdup
2142
- end
2143
-
2144
2016
  def borderstyle
2145
- ((data = workspace.banner_get(*@ref, group: group)) && data[:border]) || theme[:border]
2017
+ workspace.banner_get(*@ref, group: group)&.border || theme[:border]
2146
2018
  end
2147
2019
 
2148
2020
  def headerstyle
@@ -2155,7 +2027,7 @@ module Squared
2155
2027
  end
2156
2028
 
2157
2029
  Application.implement(Base, base: true)
2158
- Application.attr_banner = Common::SymSet.new(%i[name project path ref group parent])
2030
+ Application.attr_banner = Set.new(%i[name project path ref group parent])
2159
2031
  end
2160
2032
  end
2161
2033
  end