squared 0.5.6 → 0.5.8

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.
@@ -9,6 +9,7 @@ module Squared
9
9
  module Workspace
10
10
  module Project
11
11
  class Base
12
+ include Comparable
12
13
  include Common::Format
13
14
  include System
14
15
  include Shell
@@ -16,7 +17,6 @@ module Squared
16
17
  include Utils
17
18
  include Support
18
19
  include Rake::DSL
19
- include ::Comparable
20
20
 
21
21
  VAR_SET = %i[parent global script index envname desc dependfile dependindex theme archive env dev prod graph
22
22
  pass only exclude asdf].freeze
@@ -89,6 +89,7 @@ module Squared
89
89
  @name = name.to_s.freeze
90
90
  @project = @path.basename.to_s.freeze
91
91
  @group = group&.to_s.freeze
92
+ @envname = env_key(@name).freeze
92
93
  @depend = kwargs[:depend]
93
94
  @doc = kwargs[:doc]
94
95
  @lint = kwargs[:lint]
@@ -104,7 +105,7 @@ module Squared
104
105
  @ref = []
105
106
  @children = []
106
107
  @events = hashobj.update({ first: first, last: last, error: error })
107
- @envname = env_key(@name).freeze
108
+ @as = hashobj
108
109
  @desc = (@name.include?(':') ? @name.split(':').join(ARG[:SPACE]) : @name).freeze
109
110
  @parent = nil
110
111
  @global = false
@@ -207,7 +208,7 @@ module Squared
207
208
  file &&= @workspace.home.join(env('LOG_DIR', ''), file).realdirpath
208
209
  rescue StandardError => e
209
210
  file = nil
210
- warn log_message(Logger::WARN, e) if warning?
211
+ print_error e
211
212
  end
212
213
  log[:progname] ||= @name
213
214
  if (val = env('LOG_LEVEL', ignore: false))
@@ -299,7 +300,7 @@ module Squared
299
300
  end
300
301
 
301
302
  def verbose=(val)
302
- @verbose = case val
303
+ @verbose = case (val = env('VERBOSE', val))
303
304
  when NilClass
304
305
  workspace.verbose
305
306
  when String
@@ -374,7 +375,7 @@ module Squared
374
375
  else
375
376
  force = args.fetch(:force, false)
376
377
  end
377
- unpack(path + dir, uri: tag, digest: digest, ext: ext, force: force)
378
+ unpack(basepath(dir), uri: tag, digest: digest, ext: ext, force: force)
378
379
  end
379
380
  when 'asdf'
380
381
  break unless @asdf
@@ -434,14 +435,13 @@ module Squared
434
435
  name = @name if name == true
435
436
  path.each { |val| add(val, name && task_join(name, File.basename(val)), **kwargs, &blk) }
436
437
  return self
437
- elsif !projectpath?(path = basepath(path)) || !checkdir?(path)
438
- return self
439
438
  end
439
+ return self unless projectpath?(path = basepath(path)) && checkdir?(path)
440
+
440
441
  kwargs = @withargs.yield_self { |data| data.dup.update(kwargs) } if @withargs
441
442
  kwargs[:group] = group unless kwargs.key?(:group)
442
443
  kwargs[:ref] = ref unless kwargs.key?(:ref)
443
444
  parent = self
444
- proj = nil
445
445
  name = case name
446
446
  when String, Symbol
447
447
  name.to_s
@@ -450,10 +450,9 @@ module Squared
450
450
  end
451
451
  workspace.add(path, name, **kwargs) do
452
452
  __send__ :parent_set, parent
453
- proj = self
453
+ @children << self
454
+ instance_eval(&blk) if block_given?
454
455
  end
455
- @children << proj
456
- proj.instance_eval(&blk) if block_given?
457
456
  self
458
457
  end
459
458
 
@@ -467,7 +466,7 @@ module Squared
467
466
 
468
467
  out = obj.link(self, *args, **kwargs, &blk) if obj.respond_to?(:link)
469
468
  if !out
470
- warn log_message(Logger::WARN, 'link not compatible', subject: obj.to_s, hint: name)
469
+ print_error('link not compatible', subject: obj, hint: name)
471
470
  elsif out.respond_to?(:build)
472
471
  out.build
473
472
  end
@@ -507,7 +506,7 @@ module Squared
507
506
  else
508
507
  next unless respond_to?(:compose)
509
508
 
510
- cmd << a if (a = compose(as_get(b), d, script: true, args: e, from: from))
509
+ cmd << a if (a = compose(as_get(b, from), d, script: true, args: e, from: from))
511
510
  end
512
511
  var.update(c) if c.is_a?(Hash)
513
512
  end
@@ -515,8 +514,12 @@ module Squared
515
514
  else
516
515
  cmd, opts, var, flags, extra = args
517
516
  end
517
+ if cmd.is_a?(Proc) || cmd.is_a?(Method)
518
+ run_b(cmd, sync: sync, from: from)
519
+ return
520
+ end
518
521
  if cmd
519
- cmd = as_get cmd
522
+ cmd = as_get(cmd, from)
520
523
  opts = compose(opts, script: false) if opts && respond_to?(:compose)
521
524
  flags = append_hash(flags).join(' ') if flags.is_a?(Hash)
522
525
  case opts
@@ -533,7 +536,7 @@ module Squared
533
536
  else
534
537
  return unless (opts || extra) && respond_to?(:compose)
535
538
 
536
- cmd = compose(as_get(opts), flags, script: true, args: extra, from: from)
539
+ cmd = compose(as_get(opts, from), flags, script: true, args: extra, from: from)
537
540
  from = :script if from == :run && script?
538
541
  end
539
542
  run(cmd, var, sync: sync, from: from, banner: banner)
@@ -558,7 +561,7 @@ module Squared
558
561
  on_error(:prereqs, e, exception: true)
559
562
  end
560
563
  end
561
- warn log_message(Logger::WARN, name, 'method not found', subject: 'prereqs', hint: meth)
564
+ print_error(name, 'method not found', subject: 'prereqs', hint: meth)
562
565
  end
563
566
  elsif proj.build?
564
567
  proj.build(sync: sync)
@@ -613,7 +616,7 @@ module Squared
613
616
  else
614
617
  if @clean.is_a?(Enumerable) && !series?(@clean)
615
618
  @clean.each do |val|
616
- entry = path + (val = val.to_s)
619
+ entry = basepath(val = val.to_s)
617
620
  if entry.directory? && val.match?(%r{[\\/]\z})
618
621
  log&.warn "rm -rf #{entry}"
619
622
  rm_rf(entry, verbose: verbose)
@@ -622,11 +625,9 @@ module Squared
622
625
  (val.include?('*') ? Dir[entry] : [entry]).each do |file|
623
626
  next unless File.file?(file)
624
627
 
625
- begin
626
- File.delete(file)
627
- rescue StandardError => e
628
- log&.error e
629
- end
628
+ File.delete(file)
629
+ rescue StandardError => e
630
+ log&.error e
630
631
  end
631
632
  end
632
633
  end
@@ -747,7 +748,7 @@ module Squared
747
748
  delete = true
748
749
  end
749
750
  if create
750
- warn log_message(Logger::WARN, 'force remove', subject: name, hint: target)
751
+ print_error('force remove', subject: name, hint: target)
751
752
  target.rmtree
752
753
  target.mkpath
753
754
  end
@@ -847,9 +848,8 @@ module Squared
847
848
  end
848
849
 
849
850
  def as(cmd, script, to = nil)
850
- script = { "#{script}": to } if to
851
- data = (@as ||= {})[cmd.to_sym] ||= {}
852
- script.each { |key, val| data[key.to_s] = val }
851
+ data = @as[cmd.to_sym]
852
+ (to ? [[script, to]] : script).each { |key, val| data[key.to_s] = val }
853
853
  self
854
854
  end
855
855
 
@@ -866,6 +866,55 @@ module Squared
866
866
  self
867
867
  end
868
868
 
869
+ def run(cmd = @session, var = nil, exception: self.exception, sync: true, from: nil, banner: true, chdir: path,
870
+ interactive: nil, hint: nil, **)
871
+ unless cmd
872
+ print_error('no command given', subject: project, hint: from || 'unknown', pass: true)
873
+ return
874
+ end
875
+ cmd = cmd.target if cmd.is_a?(OptionPartition)
876
+ if interactive && (!@session || !option('y'))
877
+ title, y = case interactive
878
+ when Array
879
+ interactive
880
+ when String
881
+ [interactive, 'N']
882
+ else
883
+ ['Run', 'Y']
884
+ end
885
+ exit 1 unless confirm("#{title}? [#{sub_style(cmd.to_s, styles: theme[:inline])}]", y)
886
+ end
887
+ cmd = session_done cmd
888
+ log&.info cmd
889
+ on :first, from
890
+ begin
891
+ if cmd.start_with?(/[^:]+:[^:]/) && workspace.task_defined?(cmd)
892
+ log&.warn "ENV discarded: #{var}" if var
893
+ task_invoke(cmd, exception: exception, warning: warning?)
894
+ else
895
+ print_item format_banner(hint ? "#{cmd} (#{hint})" : cmd, banner: banner) if sync
896
+ if var != false && (pre = runenv)
897
+ case pre
898
+ when Hash
899
+ var = var.is_a?(Hash) ? pre.merge(var) : pre
900
+ when Enumerable
901
+ cmd = command(*pre.to_a, cmd)
902
+ else
903
+ cmd = command pre, cmd
904
+ end
905
+ end
906
+ args = var.is_a?(Hash) ? [var, cmd] : [cmd]
907
+ ret = shell(*args, chdir: chdir, exception: exception)
908
+ end
909
+ rescue StandardError => e
910
+ on_error(from, e, exception: true)
911
+ false
912
+ else
913
+ on :last, from
914
+ ret
915
+ end
916
+ end
917
+
869
918
  def variable_set(key, *args, **kwargs, &blk)
870
919
  if block_given?
871
920
  if blocks.include?(key)
@@ -917,6 +966,8 @@ module Squared
917
966
  self
918
967
  end
919
968
 
969
+ alias apply variable_set
970
+
920
971
  def enabled?(ref = nil, **)
921
972
  return false if ref && !ref?(ref)
922
973
 
@@ -1027,7 +1078,7 @@ module Squared
1027
1078
  path.parent.ascend.each do |dir|
1028
1079
  target = dir.join(*args)
1029
1080
  return target if target.exist?
1030
- break if (ascend.is_a?(String) && dir.join(ascend).exist?) || workspace.root == dir || parent&.path == dir
1081
+ break if (ascend && dir.join(ascend).exist?) || workspace.root == dir || parent&.path == dir
1031
1082
  end
1032
1083
  ret
1033
1084
  end
@@ -1054,55 +1105,6 @@ module Squared
1054
1105
  log_console(*args, pipe: kwargs[:pipe] || pipe)
1055
1106
  end
1056
1107
 
1057
- def run(cmd = @session, var = nil, exception: self.exception, sync: true, from: nil, banner: true, chdir: path,
1058
- interactive: nil, hint: nil, **)
1059
- unless cmd
1060
- warn log_message(Logger::WARN, 'no command given', subject: project, hint: from || 'unknown', pass: true)
1061
- return
1062
- end
1063
- cmd = cmd.target if cmd.is_a?(OptionPartition)
1064
- if interactive && (!@session || !option('y'))
1065
- title, y = case interactive
1066
- when Array
1067
- interactive
1068
- when String
1069
- [interactive, 'N']
1070
- else
1071
- ['Run', 'Y']
1072
- end
1073
- exit 1 unless confirm("#{title}? [#{sub_style(cmd.to_s, styles: theme[:inline])}]", y)
1074
- end
1075
- cmd = session_done cmd
1076
- log&.info cmd
1077
- on :first, from
1078
- begin
1079
- if cmd.start_with?(/[^:]+:[^:]/) && workspace.task_defined?(cmd)
1080
- log&.warn "ENV discarded: #{var}" if var
1081
- task_invoke(cmd, exception: exception, warning: warning?)
1082
- else
1083
- print_item format_banner(hint ? "#{cmd} (#{hint})" : cmd, banner: banner) if sync
1084
- if var != false && (pre = runenv)
1085
- case pre
1086
- when Hash
1087
- var = var.is_a?(Hash) ? pre.merge(var) : pre
1088
- when Enumerable
1089
- cmd = command(*pre.to_a, cmd)
1090
- else
1091
- cmd = command pre, cmd
1092
- end
1093
- end
1094
- args = var.is_a?(Hash) ? [var, cmd] : [cmd]
1095
- ret = shell(*args, chdir: chdir, exception: exception)
1096
- end
1097
- rescue StandardError => e
1098
- on_error(from, e, exception: true)
1099
- false
1100
- else
1101
- on :last, from
1102
- ret
1103
- end
1104
- end
1105
-
1106
1108
  def run_s(*cmd, env: nil, sync: true, from: nil, banner: verbose != false, **kwargs)
1107
1109
  on :first, from
1108
1110
  begin
@@ -1301,15 +1303,7 @@ module Squared
1301
1303
  end
1302
1304
 
1303
1305
  def session_delete(*args, target: @session)
1304
- ret = []
1305
- args.each do |val|
1306
- pat = /\A#{Regexp.escape(shell_option(val))}(?: |=|\z)/
1307
- if (key = target.find { |opt| opt.match?(pat) })
1308
- target.delete(key)
1309
- ret << key
1310
- end
1311
- end
1312
- ret
1306
+ OptionPartition.delete(target, *args)
1313
1307
  end
1314
1308
 
1315
1309
  def session_output(*cmd, **kwargs)
@@ -1351,8 +1345,8 @@ module Squared
1351
1345
  puts 'Success'
1352
1346
  end
1353
1347
 
1354
- def print_error(err, loglevel: Logger::WARN, pass: false)
1355
- warn log_message(loglevel, err, pass: pass) if warning?
1348
+ def print_error(*args, loglevel: Logger::WARN, **kwargs)
1349
+ warn log_message(loglevel, *args, **kwargs) if warning?
1356
1350
  end
1357
1351
 
1358
1352
  def print_item(*val)
@@ -1410,7 +1404,7 @@ module Squared
1410
1404
  if verbose && kwargs[:start]
1411
1405
  msg = sub_style('completed', styles: theme[:active])
1412
1406
  puts log_message(Logger::INFO, *args, msg, subject: kwargs[:subject],
1413
- hint: time_format(epochtime - kwargs[:start]))
1407
+ hint: time_format(time_epoch - kwargs[:start]))
1414
1408
  end
1415
1409
  end
1416
1410
  end
@@ -1522,7 +1516,7 @@ module Squared
1522
1516
  next if (key = key.to_s).start_with?('__')
1523
1517
 
1524
1518
  if val.nil? || extra || session_arg?(key, target: target)
1525
- session_delete(key, target: target)
1519
+ OptionPartition.delete_key(target, key)
1526
1520
  next if val.nil?
1527
1521
  end
1528
1522
  case val
@@ -1658,7 +1652,7 @@ module Squared
1658
1652
  raise_error("invalid JSON #{kind.name}", val, hint: hint) if kind && !ret.is_a?(kind)
1659
1653
  rescue StandardError => e
1660
1654
  log&.warn e
1661
- warn log_message(Logger::WARN, e, subject: name) if warning?
1655
+ print_error(e, subject: name)
1662
1656
  else
1663
1657
  ret
1664
1658
  end
@@ -1786,7 +1780,7 @@ module Squared
1786
1780
  raise_error 'pathspec not within worktree' unless pass || files.size == proj.size
1787
1781
  files = proj
1788
1782
  end
1789
- files.map { |val| val == '.' ? '.' : shell_quote(path + val) }
1783
+ files.map { |val| val == '.' ? '.' : shell_quote(basepath(val)) }
1790
1784
  end
1791
1785
 
1792
1786
  def matchmap(list, prefix = nil)
@@ -2041,14 +2035,12 @@ module Squared
2041
2035
 
2042
2036
  def dependfile_set(list)
2043
2037
  @dependindex = list.index { |file| basepath(file).exist? }.tap do |index|
2044
- @dependfile = @path + list[index || 0]
2038
+ @dependfile = basepath(list[index || 0])
2045
2039
  end
2046
2040
  end
2047
2041
 
2048
- def as_get(val)
2049
- return unless val
2050
-
2051
- @global && (ret = @as && @as[from] && @as[from][val]) ? ret : val
2042
+ def as_get(val, from)
2043
+ (@global && @as[from][val]) || val
2052
2044
  end
2053
2045
 
2054
2046
  def task_build(keys)
@@ -6,7 +6,7 @@ module Squared
6
6
  class Docker < Base
7
7
  COMPOSEFILE = %w[compose.yaml compose.yml docker-compose.yaml docker-compose.yml].freeze
8
8
  BAKEFILE = %w[docker-bake.json docker-bake.hcl docker-bake.override.json docker-bake.override.hcl].freeze
9
- DIR_DOCKER = (COMPOSEFILE + BAKEFILE).freeze
9
+ DIR_DOCKER = (COMPOSEFILE + BAKEFILE + ['Dockerfile']).freeze
10
10
  OPT_DOCKER = {
11
11
  common: %w[tls tlsverify config=p c|context=b D|debug H|host=q l|log-level=b tlscacert=p tlscert=p
12
12
  tlskey=p].freeze,
@@ -91,7 +91,7 @@ module Squared
91
91
  def config?(val)
92
92
  return false unless (val = as_path(val))
93
93
 
94
- val.join('Dockerfile').exist? || DIR_DOCKER.any? { |file| val.join(file).exist? }
94
+ DIR_DOCKER.any? { |file| val.join(file).exist? }
95
95
  end
96
96
  end
97
97
 
@@ -310,7 +310,7 @@ module Squared
310
310
  append_context
311
311
  when :bake, :compose
312
312
  option(from == :bake ? 'target' : 'service', ignore: false) do |a|
313
- ret.merge(split_escape(a).map! { |b| shell_escape(b) })
313
+ ret.merge(split_escape(a).map! { |b| shell_quote(b) })
314
314
  end
315
315
  end
316
316
  ret
@@ -412,7 +412,7 @@ module Squared
412
412
  args << k
413
413
  next
414
414
  when 'source', 'src', 'destination', 'dst', 'target', 'volume-subpath', 'image-path'
415
- v = path + v
415
+ v = basepath v
416
416
  v = shell_quote(v, option: false, force: false) if q == ''
417
417
  end
418
418
  args << "#{k}=#{q + v + q}"
@@ -531,7 +531,7 @@ module Squared
531
531
  list_image(flag, docker_output('image ls -a'), from: from) do |val|
532
532
  op << val
533
533
  if flag == :tag
534
- op << tagname("#{@project}:#{op.extras.first}")
534
+ op << tagname("#{@project}:#{op.first}")
535
535
  break
536
536
  end
537
537
  end
@@ -586,16 +586,15 @@ module Squared
586
586
  end
587
587
 
588
588
  def dockerfile(val = nil)
589
- if val == 'Dockerfile'
590
- @file = false
591
- elsif val
589
+ if val
592
590
  @file = if val.is_a?(Array)
593
591
  val = val.select { |file| basepath(file).exist? }
594
592
  val.size > 1 ? val : val.first
595
- else
596
- val || DIR_DOCKER.find { |file| basepath(file).exist? }
593
+ elsif val == true
594
+ DIR_DOCKER.find { |file| basepath(file).exist? }
595
+ elsif val != 'Dockerfile'
596
+ val
597
597
  end
598
- @file ||= false
599
598
  end
600
599
  basepath((@file.is_a?(Array) ? @file.first : @file) || 'Dockerfile')
601
600
  end
@@ -604,9 +603,9 @@ module Squared
604
603
 
605
604
  def read_composefile(*keys, target: nil)
606
605
  require 'yaml'
607
- target = ENV['COMPOSE_FILE']&.split(workspace.windows? ? ';' : ':') if !target || target.empty?
606
+ target = ENV['COMPOSE_FILE']&.split(workspace.windows? ? ';' : ':') unless target && !target.empty?
608
607
  Array(target || dockerfile).each do |val|
609
- doc = YAML.load_file(path + val)
608
+ doc = YAML.load_file(basepath(val))
610
609
  if keys.empty?
611
610
  yield doc
612
611
  elsif (data = doc.dig(*keys))
@@ -648,17 +647,17 @@ module Squared
648
647
  end
649
648
 
650
649
  def append_file(type, target: @session)
651
- return if ENV['COMPOSE_FILE'] && compose?(type)
650
+ return if !@file || (ENV['COMPOSE_FILE'] && compose?(type))
652
651
 
653
652
  unless @file.is_a?(Array)
654
653
  case type
655
654
  when 2, 4
656
655
  return
657
656
  when 3
658
- return unless COMPOSEFILE.map { |val| path + val }.select(&:exist?).size > 1
657
+ return unless COMPOSEFILE.map { |val| basepath(val) }.select(&:exist?).size > 1
659
658
  end
660
659
  end
661
- files = Array(@file).map { |val| quote_option('file', path + val) }
660
+ files = Array(@file).map { |val| quote_option('file', basepath(val)) }
662
661
  if target.is_a?(Set)
663
662
  opts = target.to_a.insert(2, *files)
664
663
  target.clear.merge(opts)
@@ -839,7 +838,7 @@ module Squared
839
838
  end
840
839
 
841
840
  def contextdir(val = nil)
842
- val && projectpath?(val) ? shell_quote(path + val) : '.'
841
+ val && projectpath?(val) ? shell_quote(basepath(val)) : '.'
843
842
  end
844
843
 
845
844
  def tagjoin(*args, char: '/')
@@ -104,11 +104,11 @@ module Squared
104
104
  end
105
105
 
106
106
  def rev_timeutc(*keys)
107
- rev_entry(*keys, val: rev_timenow)
107
+ rev_entry(*keys, val: time_epoch)
108
108
  end
109
109
 
110
110
  def rev_timesince(*keys, clock: false)
111
- epoch = rev_timenow - rev_entry(*keys).to_i
111
+ epoch = time_epoch - rev_entry(*keys).to_i
112
112
  rescue StandardError
113
113
  nil
114
114
  else
@@ -545,7 +545,7 @@ module Squared
545
545
  commit1 = commithead args.commit1
546
546
  if commit1
547
547
  commit2 = commithead param_guard(action, flag, args: args, key: :commit2)
548
- args = args.extras.to_a
548
+ args = args.extras
549
549
  range = [commit1, commit2]
550
550
  else
551
551
  range, opts, refs = choice_commit(multiple: view ? true : 2, values: %w[Options Pathspec])
@@ -752,12 +752,12 @@ module Squared
752
752
  args = args.extras
753
753
  else
754
754
  commit, mode = choice_commit(values: ['Mode [mixed|soft|hard|N]'])
755
- args = args.extras.to_a.concat(case mode&.downcase
756
- when 'h', 'hard' then ['hard']
757
- when 's', 'soft' then ['soft']
758
- when 'n', 'N' then ['mixed', 'N']
759
- else ['mixed']
760
- end)
755
+ args = args.extras.concat(case mode&.downcase
756
+ when 'h', 'hard' then ['hard']
757
+ when 's', 'soft' then ['soft']
758
+ when 'n', 'N' then ['mixed', 'N']
759
+ else ['mixed']
760
+ end)
761
761
  end
762
762
  print_success if success?(reset(flag, args, commit: commit))
763
763
  end
@@ -1028,7 +1028,7 @@ module Squared
1028
1028
  return unless upstream
1029
1029
 
1030
1030
  op = OptionPartition.new(opts, OPT_GIT[:rebase], cmd, project: self, no: OPT_GIT[:no][:rebase])
1031
- cmd << upstream
1031
+ op << upstream
1032
1032
  append_head op.shift
1033
1033
  op.clear(pass: false)
1034
1034
  when :onto
@@ -1117,7 +1117,7 @@ module Squared
1117
1117
  if op.empty?
1118
1118
  values = [['Branch name', true]]
1119
1119
  else
1120
- op << op.pop
1120
+ op << op.shift
1121
1121
  end
1122
1122
  end
1123
1123
  out = choice_index('Choose a stash', git_spawn('stash list', stdout: false),
@@ -1128,7 +1128,7 @@ module Squared
1128
1128
  op << out
1129
1129
  end
1130
1130
  elsif !op.empty?
1131
- op << op.pop
1131
+ op << op.shift
1132
1132
  elsif flag == :branch
1133
1133
  raise_error 'no branch name'
1134
1134
  end
@@ -1236,10 +1236,10 @@ module Squared
1236
1236
  return
1237
1237
  end
1238
1238
  end
1239
- start = epochtime
1239
+ start = time_epoch
1240
1240
  build(@output, sync: sync, from: :'git:revbuild')
1241
1241
  rescue StandardError => e
1242
- warn log_message(Logger::WARN, e, pass: true) if warning?
1242
+ print_error(e, pass: true)
1243
1243
  else
1244
1244
  print_status(name, subject: 'revbuild', start: start, from: :completed)
1245
1245
  workspace.rev_write(name, { 'revision' => sha, 'files' => status_digest(*args, **kwargs) },
@@ -1270,7 +1270,6 @@ module Squared
1270
1270
  end
1271
1271
  when :patch
1272
1272
  cmd << '--patch'
1273
- append_pathspec(refs, pass: false)
1274
1273
  when :undo
1275
1274
  cmd << '--hard HEAD@{1}'
1276
1275
  ref = false
@@ -1490,12 +1489,12 @@ module Squared
1490
1489
  case flag
1491
1490
  when :commit, :'no-commit'
1492
1491
  op = OptionPartition.new(opts, OPT_GIT[:merge], cmd, project: self, no: OPT_GIT[:no][:merge])
1493
- raise_error 'no branch/commit' if op.empty?
1494
1492
  op << "--#{flag}" << '--'
1495
1493
  if branch
1496
1494
  op << branch
1497
1495
  op.clear(pass: false)
1498
1496
  else
1497
+ raise_error 'no branch/commit' if op.empty?
1499
1498
  append_commit(*op.extras)
1500
1499
  end
1501
1500
  else
@@ -1602,9 +1601,7 @@ module Squared
1602
1601
  end
1603
1602
  on :last, from
1604
1603
  end
1605
- if ret == 0
1606
- warn log_message(Logger::WARN, name, 'no ref found', subject: 'branch', hint: 'head', pass: true)
1607
- end
1604
+ print_error(name, 'no ref found', subject: 'branch', hint: 'head', pass: true) if ret == 0
1608
1605
  return
1609
1606
  end
1610
1607
  return unless success?(source(stdout: stdout))
@@ -1747,8 +1744,8 @@ module Squared
1747
1744
  end)
1748
1745
  case flag
1749
1746
  when :blame
1750
- raise_error 'no file found' unless (n = op.index { |s| (path + s).file? })
1751
- op << '--' << shell_quote(path + op.delete_at(n))
1747
+ raise_error 'no file found' unless (n = op.index { |s| basepath(s).file? })
1748
+ op << '--' << shell_quote(basepath(op.delete_at(n)))
1752
1749
  op.clear
1753
1750
  when :revert
1754
1751
  if VAL_GIT[:rebase][:send].any? { |val| op.arg?(val) }
@@ -1812,7 +1809,10 @@ module Squared
1812
1809
  from = nil
1813
1810
  banner = nil
1814
1811
  else
1815
- banner = nil if banner && (multiple || !banner?)
1812
+ if banner
1813
+ banner = nil unless banner? && !multiple
1814
+ args = true
1815
+ end
1816
1816
  if cmd.respond_to?(:done)
1817
1817
  if from.nil? && (from = cmd.drop(1).find { |val| val.match?(/\A[a-z]{1,2}[a-z-]*\z/) })
1818
1818
  from = :"git:#{from}"
@@ -1825,17 +1825,14 @@ module Squared
1825
1825
  log&.info cmd
1826
1826
  banner = if banner
1827
1827
  banner = (banner.is_a?(String) ? banner : cmd).gsub(File.join(path, ''), '')
1828
- format_banner(hint ? "#{banner} (#{hint})" : banner, banner: true)
1828
+ format_banner(hint ? "#{banner} (#{hint})" : banner)
1829
1829
  end
1830
1830
  on :first, from
1831
1831
  begin
1832
1832
  if io
1833
- ret = if stdout
1834
- `#{cmd}`
1835
- else
1836
- banner ? [IO.popen(cmd), banner, from] : IO.popen(cmd)
1837
- end
1838
- return ret
1833
+ return `#{cmd}` if stdout
1834
+
1835
+ return args ? [IO.popen(cmd), banner || '', from] : IO.popen(cmd)
1839
1836
  elsif stdin? ? sync : stdout
1840
1837
  print_item banner unless multiple
1841
1838
  ret = `#{cmd}`
@@ -1951,7 +1948,7 @@ module Squared
1951
1948
  next if !glob.empty? && glob.none? { |val| File.fnmatch?(val, file, File::FNM_DOTMATCH) }
1952
1949
  next if !pass.empty? && pass.any? { |val| File.fnmatch?(val, file, File::FNM_DOTMATCH) }
1953
1950
 
1954
- ret[file] = algorithm.hexdigest(File.read(path + file))
1951
+ ret[file] = algorithm.hexdigest(File.read(basepath(file)))
1955
1952
  end
1956
1953
  ret
1957
1954
  end
@@ -1983,7 +1980,7 @@ module Squared
1983
1980
  when 'recurse-submodules'
1984
1981
  op.append?($1, $2, type: :basic)
1985
1982
  when 'refspec'
1986
- refspec << shell_escape($2, quote: true)
1983
+ refspec << shell_quote($2)
1987
1984
  end
1988
1985
  elsif op.arg?('multiple')
1989
1986
  op.found << opt
@@ -2001,12 +1998,12 @@ module Squared
2001
1998
  end
2002
1999
  op.delete('--all')
2003
2000
  elsif op.arg?('multiple')
2004
- op.swap.merge(op.map! { |opt| shell_escape(opt, quote: true) })
2001
+ op.add_quote(*op.found)
2005
2002
  return
2006
2003
  elsif option('all')
2007
2004
  op << '--all'
2008
2005
  end
2009
- op.clear(errors: true, subject: flag.to_s) if flag
2006
+ op.clear(errors: true, subject: flag) if flag
2010
2007
  end
2011
2008
 
2012
2009
  def append_commit(*val, target: @session, head: false)