squared 0.4.5 → 0.4.7

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.
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'date'
4
- require 'time'
5
- require 'digest'
6
-
7
3
  module Squared
8
4
  module Workspace
9
5
  module Git
@@ -116,6 +112,9 @@ module Squared
116
112
  end
117
113
 
118
114
  def rev_clear(name)
115
+ if Dir.exist?(name) && (proj = find(name))
116
+ name = proj.name
117
+ end
119
118
  rev_write if rev_entry(name, 'revision', val: '', create: false)
120
119
  end
121
120
 
@@ -138,7 +137,7 @@ module Squared
138
137
  private
139
138
 
140
139
  def rev_timenow
141
- DateTime.now.strftime('%Q').to_i + time_offset
140
+ Time.now.utc.strftime('%s%L').to_i
142
141
  end
143
142
  end
144
143
  Application.include Git
@@ -160,11 +159,12 @@ module Squared
160
159
  show: %w[s exit-code histogram].freeze
161
160
  }.freeze,
162
161
  fetch: {
163
- base: %w[multiple progress P|prune-tags refetch stdin u|update-head-ok recurse-submodules=b
162
+ base: %w[multiple progress P|prune-tags refetch stdin u|update-head-ok
164
163
  recurse-submodules-default=b].freeze,
165
164
  pull: %w[4 6 n t a|append atomic dry-run f|force k|keep n|negotiate-only prefetch p|prune q|quiet
166
165
  set-upstream unshallow update-shallow v|verbose deepen=i depth=i j|jobs=i negotiation-tip=q
167
- refmap=q o|server-option=q shallow-exclude=e shallow-since=b upload-pack=q].freeze
166
+ recurse-submodules=v refmap=q o|server-option=q shallow-exclude=e shallow-since=v
167
+ upload-pack=q].freeze
168
168
  }.freeze,
169
169
  log: {
170
170
  base: %w[all all-match alternate-refs author-date-order basic-regexp bisect boundary cherry cherry-mark
@@ -196,7 +196,7 @@ module Squared
196
196
  X|exclude-from=p exclude-per-directory=p format=q with-tree=q].freeze,
197
197
  ls_remote: %w[exit-code get-url q|quiet o|server-option=q symref sort=q upload-pack=q].freeze,
198
198
  mv: %w[k f|force n|dry-run v|verbose].freeze,
199
- pull: %w[e n allow-unrelated-histories ff-only S|gpg-sign=qq log=i r|rebase=b? s|strategy=b
199
+ pull: %w[e n allow-unrelated-histories ff-only S|gpg-sign=qq log=i r|rebase=v? s|strategy=b
200
200
  X|strategy-option=b].freeze,
201
201
  merge: %w[e n allow-unrelated-histories ff-only m=q q|quiet v|verbose cleanup=b F|file=p S|gpg-sign=qq
202
202
  into-name=e log=i s|strategy=b X|strategy-option=b].freeze,
@@ -325,7 +325,7 @@ module Squared
325
325
  'rev' => %i[commit branch output parseopt build].freeze,
326
326
  'show' => %i[format oneline textconv].freeze,
327
327
  'stash' => %i[push pop apply drop clear list].freeze,
328
- 'tag' => %i[add delete list].freeze
328
+ 'tag' => %i[add sign delete list].freeze
329
329
  })
330
330
 
331
331
  def initialize(*, **)
@@ -388,7 +388,7 @@ module Squared
388
388
  refs = param_guard(action, flag, args: args.to_a)
389
389
  tag(flag, refs: refs)
390
390
  end
391
- when :add
391
+ when :add, :sign
392
392
  format_desc action, flag, 'name,message?,commit?'
393
393
  task flag, [:name, :message, :commit] do |_, args|
394
394
  name = param_guard(action, flag, args: args, key: :name)
@@ -519,7 +519,7 @@ module Squared
519
519
  end
520
520
  when :delete
521
521
  format_desc action, flag, '(^~)name+'
522
- task flag, [:name] do |_, args|
522
+ task flag do |_, args|
523
523
  refs = param_guard(action, flag, args: args.to_a)
524
524
  branch(flag, refs: refs)
525
525
  end
@@ -686,27 +686,28 @@ module Squared
686
686
  end
687
687
 
688
688
  def depend(*, **)
689
- workspace.rev_clear name
689
+ workspace.rev_clear(name)
690
690
  super
691
691
  end
692
692
 
693
693
  def clean(*, **)
694
- workspace.rev_clear name
694
+ workspace.rev_clear(name)
695
695
  super
696
696
  end
697
697
 
698
698
  def pull(flag = nil, opts = [], sync: invoked_sync?('pull', flag), remote: nil)
699
- cmd, opts = git_session('pull', flag && "--#{flag}", opts: opts)
699
+ cmd, opts = git_session('pull', opts: opts)
700
700
  if flag == :rebase
701
- cmd << '--autostash' if option('autostash')
701
+ cmd << '--rebase'
702
702
  elsif (val = option('rebase', ignore: false))
703
703
  cmd << case val
704
- when '0'
704
+ when '0', 'false'
705
705
  '--no-rebase'
706
706
  else
707
707
  VAL_GIT[:rebase][:value].include?(val) ? basic_option('rebase', val) : '--rebase'
708
708
  end
709
709
  end
710
+ cmd << '--autostash' if option('autostash')
710
711
  append_pull(opts, OPT_GIT[:pull] + OPT_GIT[:fetch][:pull],
711
712
  no: OPT_GIT[:no][:pull] + OPT_GIT[:no][:fetch][:pull], remote: remote, flag: flag)
712
713
  source(sync: sync, sub: if verbose
@@ -724,15 +725,15 @@ module Squared
724
725
  cmd, opts = git_session('rebase', opts: opts)
725
726
  case flag
726
727
  when :branch
727
- branch = option_sanitize(opts, OPT_GIT[:rebase], no: OPT_GIT[:no][:rebase]).first
728
- case branch.size
728
+ op = OptionPartition.new(opts, OPT_GIT[:rebase], cmd, project: self, no: OPT_GIT[:no][:rebase])
729
+ case op.size
729
730
  when 0
730
731
  append_head
731
732
  when 1, 2
732
- append_value(branch, delim: true)
733
+ op.append(delim: true)
733
734
  else
734
- append_value([branch.pop, branch.pop].reverse, delim: true)
735
- option_clear(branch, pass: false)
735
+ op.append(op.pop(2), delim: true)
736
+ .clear(pass: false)
736
737
  end
737
738
  when :onto
738
739
  return unless upstream
@@ -751,10 +752,10 @@ module Squared
751
752
 
752
753
  def fetch(flag = nil, opts = [], sync: invoked_sync?('fetch', flag), remote: nil)
753
754
  cmd, opts = git_session('fetch', opts: opts)
754
- cmd << '--all' if !remote && !opts.include?('multiple') && option('all')
755
- cmd << '--verbose' if verbose && !opts.include?('quiet')
756
- append_pull(opts, collect_hash(OPT_GIT[:fetch]), no: collect_hash(OPT_GIT[:no][:fetch]),
757
- remote: remote, flag: flag)
755
+ append_pull(opts, collect_hash(OPT_GIT[:fetch]), no: collect_hash(OPT_GIT[:no][:fetch]), remote: remote,
756
+ flag: flag)
757
+ cmd << '--all' if !remote && !session_arg?('multiple') && option('all')
758
+ cmd << '--verbose' if verbose && !session_arg?('quiet')
758
759
  source(sync: sync, **threadargs)
759
760
  end
760
761
 
@@ -783,25 +784,25 @@ module Squared
783
784
  def stash(flag = nil, opts = [], sync: invoked_sync?('stash', flag))
784
785
  if flag
785
786
  cmd, opts = git_session('stash', flag, opts: opts)
786
- refs = option_sanitize(opts, OPT_GIT[:stash][:common] + OPT_GIT[:stash].fetch(flag, [])).first
787
+ op = OptionPartition.new(opts, OPT_GIT[:stash][:common] + OPT_GIT[:stash].fetch(flag, []), cmd,
788
+ project: self)
787
789
  case flag
788
790
  when :push
789
- append_pathspec refs
791
+ append_pathspec op.extras
790
792
  when :pop, :apply, :drop
791
- unless refs.empty?
792
- cmd << shell_escape(refs.pop)
793
- option_clear refs
793
+ unless op.empty?
794
+ op << shell_escape(op.pop)
795
+ op.clear
794
796
  end
795
797
  when :clear
796
- if confirm("Remove #{sub_style('all', styles: theme[:active])} the stash entries? [y/N] ", 'N')
798
+ if confirm("Remove #{sub_style('all', styles: theme[:active])} stash entries? [y/N] ", 'N')
797
799
  source(stdout: true)
798
800
  end
799
801
  return
800
802
  when :list
801
803
  out, banner, from = source(io: true)
802
804
  print_item banner
803
- ret = write_lines(out)
804
- list_result(ret, 'objects', from: from)
805
+ list_result(write_lines(out), 'objects', from: from)
805
806
  return
806
807
  end
807
808
  else
@@ -861,18 +862,19 @@ module Squared
861
862
  sha = git_spawn('rev-parse --verify HEAD').first.to_s.chomp
862
863
  return if sha.empty?
863
864
 
864
- args = []
865
865
  kwargs = kwargs.key?(:include) || kwargs.key?(:exclude) ? statusargs.() : @revbuild || {}
866
866
  case flag
867
867
  when :build
868
- opts = option_sanitize(opts, OPT_GIT[:status], target: args).first
869
- option_clear(opts, append: true)
868
+ op = OptionPartition.new(opts, OPT_GIT[:status], project: self)
869
+ op.clear(append: true)
870
+ args = op.to_a
870
871
  else
872
+ args = []
871
873
  args << basic_option('untracked-files', flag) if (flag = option('untracked-files', prefix: 'git'))
872
874
  args << basic_option('ignore-submodules', flag) if (flag = option('ignore-submodules', prefix: 'git'))
873
875
  args << basic_option('ignored', flag) if (flag = option('ignored', prefix: 'git'))
874
876
  end
875
- if (cur = workspace.rev_entry(name)) && cur['revision'] == sha
877
+ if (cur = workspace.rev_entry(name)) && cur['revision'] == sha && !env('REVBUILD_FORCE')
876
878
  files = status_digest(*args, **kwargs)
877
879
  if cur['files'].size == files.size && cur['files'].find { |key, val| files[key] != val }.nil?
878
880
  if verbose
@@ -901,13 +903,14 @@ module Squared
901
903
  cmd, opts = git_session('reset', opts: opts)
902
904
  case flag
903
905
  when :commit, :index
904
- files = option_sanitize(opts, OPT_GIT[:reset] + VAL_GIT[:reset], no: OPT_GIT[:no][:reset]).first
906
+ op = OptionPartition.new(opts, OPT_GIT[:reset] + VAL_GIT[:reset], cmd,
907
+ project: self, no: OPT_GIT[:no][:reset])
905
908
  if flag == :commit
906
- append_value(commit, delim: true)
907
- option_clear(files, pass: false)
909
+ op.append(commit, delim: true)
910
+ .clear(pass: false)
908
911
  ref = false
909
912
  else
910
- (refs ||= []).concat(files)
913
+ (refs ||= []).concat(op.extras)
911
914
  end
912
915
  when :mode
913
916
  return unless VAL_GIT[:reset].include?(mode)
@@ -919,8 +922,6 @@ module Squared
919
922
  end
920
923
  when :patch
921
924
  cmd << '--patch'
922
- else
923
- return
924
925
  end
925
926
  unless ref == false
926
927
  append_commit(ref, head: true)
@@ -949,13 +950,13 @@ module Squared
949
950
  when :detach
950
951
  cmd << '--detach' << commit
951
952
  else
952
- refs = option_sanitize(opts, OPT_GIT[:checkout], no: OPT_GIT[:no][:checkout]).first
953
+ op = OptionPartition.new(opts, OPT_GIT[:checkout], cmd, project: self, no: OPT_GIT[:no][:checkout])
953
954
  if flag == :commit
954
- append_value(commit, delim: true)
955
- option_clear(refs, pass: false)
955
+ op.append(commit, delim: true)
956
+ .clear(pass: false)
956
957
  else
957
958
  append_head
958
- append_pathspec refs
959
+ append_pathspec op.extras
959
960
  end
960
961
  end
961
962
  source
@@ -964,12 +965,13 @@ module Squared
964
965
  def tag(flag, opts = [], refs: [], message: nil, commit: nil)
965
966
  cmd, opts = git_session('tag', opts: opts)
966
967
  case flag
967
- when :add
968
- if option('sign')
968
+ when :add, :sign
969
+ if flag == :sign || option('sign')
969
970
  cmd << '--sign'
970
971
  elsif !session_arg?('s', 'sign', 'u', 'local-user')
971
972
  cmd << '--annotate'
972
973
  end
974
+ cmd << '--force' if option('force')
973
975
  if !commit && message && (sha = commithash(message))
974
976
  commit = sha
975
977
  else
@@ -978,12 +980,11 @@ module Squared
978
980
  append_value refs
979
981
  append_head commit
980
982
  when :list
981
- cmd << '--list'
982
- grep = option_sanitize(opts, OPT_GIT[:tag], no: OPT_GIT[:no][:tag]).first
983
+ op = OptionPartition.new(opts, OPT_GIT[:tag], cmd << '--list', project: self, no: OPT_GIT[:no][:tag])
983
984
  out, banner, from = source(io: true)
984
985
  print_item banner
985
- ret = write_lines(out, grep: grep)
986
- list_result(ret, 'tags', from: from, grep: grep)
986
+ ret = write_lines(out, grep: op.extras)
987
+ list_result(ret, 'tags', from: from, grep: op.extras)
987
988
  return
988
989
  when :delete
989
990
  cmd << '--delete'
@@ -996,55 +997,56 @@ module Squared
996
997
 
997
998
  def logx(flag, opts = [], range: [], index: [])
998
999
  cmd, opts = git_session('log', opts: opts)
999
- refs = option_sanitize(opts, collect_hash(OPT_GIT[:log]), no: collect_hash(OPT_GIT[:no][:log])).first
1000
+ op = OptionPartition.new(opts, collect_hash(OPT_GIT[:log]), cmd,
1001
+ project: self, no: collect_hash(OPT_GIT[:no][:log]))
1000
1002
  case flag
1001
1003
  when :between, :contain
1002
- cmd << shell_quote(range.join(flag == :between ? '..' : '...'))
1004
+ op << shell_quote(range.join(flag == :between ? '..' : '...'))
1003
1005
  else
1004
- cmd.merge(index)
1006
+ op.merge(index)
1005
1007
  end
1006
1008
  append_nocolor
1007
- append_pathspec refs
1009
+ append_pathspec op.extras
1008
1010
  source(exception: false)
1009
1011
  end
1010
1012
 
1011
1013
  def diff(flag, opts = [], refs: [], branch: nil, range: [], index: [])
1012
1014
  cmd, opts = git_session('diff', opts: opts)
1013
- files = option_sanitize(opts, collect_hash(OPT_GIT[:diff]) + OPT_GIT[:log][:diff],
1014
- no: OPT_GIT[:no][:log][:diff]).first
1015
+ op = OptionPartition.new(opts, collect_hash(OPT_GIT[:diff]) + OPT_GIT[:log][:diff], cmd,
1016
+ project: self, no: OPT_GIT[:no][:log][:diff])
1015
1017
  case flag
1016
1018
  when :files, :view, :between, :contain
1017
- cmd.delete('--cached')
1019
+ op.delete('--cached')
1018
1020
  end
1019
1021
  append_nocolor
1020
1022
  if flag == :files
1021
- cmd << '--no-index'
1023
+ op << '--no-index'
1022
1024
  append_pathspec(refs, parent: true)
1023
1025
  else
1024
1026
  case flag
1025
1027
  when :view
1026
- cmd << '--merge-base' if option('merge-base')
1027
- cmd << shell_quote(range.first, quote: true) << shell_quote(range.last, quote: true)
1028
+ op << '--merge-base' if option('merge-base')
1029
+ op << shell_quote(range.first, quote: true) << shell_quote(range.last, quote: true)
1028
1030
  when :between, :contain
1029
- cmd.delete('--merge-base')
1030
- cmd << shell_quote(range.join(flag == :between ? '..' : '...'))
1031
+ op.delete('--merge-base')
1032
+ op << shell_quote(range.join(flag == :between ? '..' : '...'))
1031
1033
  else
1032
- cmd << '--merge-base' if option('merge-base')
1033
- cmd << shell_quote(branch) if branch
1034
+ op << '--merge-base' if option('merge-base')
1035
+ op << shell_quote(branch) if branch
1034
1036
  if !index.empty?
1035
- if session_arg?('cached')
1037
+ if op.arg?('cached')
1036
1038
  raise_error("one commit only: #{index.join(', ')}", hint: '--cached') if index.size > 1
1037
- cmd << index.first
1039
+ op << index.first
1038
1040
  else
1039
- cmd.merge(index)
1041
+ op.merge(index)
1040
1042
  end
1041
1043
  elsif (n = option('index', ignore: false))
1042
- cmd << "HEAD~#{n}"
1044
+ op << "HEAD~#{n}"
1043
1045
  end
1044
1046
  end
1045
- append_pathspec files
1047
+ append_pathspec op.extras
1046
1048
  end
1047
- source(exception: session_arg?('exit-code'))
1049
+ source(exception: op.arg?('exit-code'))
1048
1050
  end
1049
1051
 
1050
1052
  def commit(flag, *, refs: [], message: nil, pass: false)
@@ -1119,10 +1121,10 @@ module Squared
1119
1121
  cmd, opts = git_session('merge', opts: opts)
1120
1122
  case flag
1121
1123
  when :commit, :'no-commit'
1122
- refs = option_sanitize(opts, OPT_GIT[:merge], no: OPT_GIT[:no][:merge]).first
1123
- raise_error 'no branch/commit' if refs.empty?
1124
- cmd << "--#{flag}" << '--'
1125
- append_commit(*refs)
1124
+ op = OptionPartition.new(opts, OPT_GIT[:merge], cmd, project: self, no: OPT_GIT[:no][:merge])
1125
+ raise_error 'no branch/commit' if op.empty?
1126
+ op << "--#{flag}" << '--'
1127
+ append_commit(*op.extras)
1126
1128
  else
1127
1129
  return unless VAL_GIT[:merge][:send].include?(command)
1128
1130
 
@@ -1138,7 +1140,7 @@ module Squared
1138
1140
  when :create
1139
1141
  if (arg = option('track', ignore: false))
1140
1142
  cmd << case arg
1141
- when '0'
1143
+ when '0', 'false'
1142
1144
  '--no-track'
1143
1145
  when 'direct', 'inherit'
1144
1146
  basic_option('track', arg)
@@ -1151,7 +1153,7 @@ module Squared
1151
1153
  return unless ref
1152
1154
 
1153
1155
  if ref.start_with?('^')
1154
- cmd << '--unset-upstream' << shell_escape(arg[1..-1])
1156
+ cmd << '--unset-upstream' << shell_escape(ref[1..-1])
1155
1157
  target = nil
1156
1158
  stdout = true
1157
1159
  else
@@ -1179,14 +1181,16 @@ module Squared
1179
1181
  cmd << '--edit-description'
1180
1182
  when :current
1181
1183
  cmd << '--show-current'
1184
+ source(banner: verbosetype > 1, stdout: true)
1185
+ return
1182
1186
  when :list
1183
- opts = option_sanitize(opts, OPT_GIT[:branch], no: OPT_GIT[:no][:branch], single: /^v+$/).first
1184
- cmd << '--list'
1185
- opts.each { |val| cmd << shell_quote(val) }
1187
+ op = OptionPartition.new(opts, OPT_GIT[:branch], cmd << '--list',
1188
+ project: self, no: OPT_GIT[:no][:branch], single: /^v+$/)
1189
+ op.each { |val| op << shell_quote(val) }
1186
1190
  out, banner, from = source(io: true)
1187
1191
  print_item banner
1188
1192
  ret = write_lines(out, sub: [
1189
- { pat: /^(\*\s+)(\S+)(\s*)$/, styles: color(:green), index: 2 },
1193
+ { pat: /^(\*\s+)(\S+)(.*)$/, styles: color(:green), index: 2 },
1190
1194
  { pat: %r{^(\s*)(remotes/\S+)(.*)$}, styles: color(:red), index: 2 }
1191
1195
  ])
1192
1196
  list_result(ret, 'branches', from: from)
@@ -1229,9 +1233,9 @@ module Squared
1229
1233
  end
1230
1234
 
1231
1235
  def restore(flag, opts = [])
1232
- opts = git_session('restore', "--#{flag}", opts: opts).last
1233
- refs = option_sanitize(opts, OPT_GIT[:restore], no: OPT_GIT[:no][:restore]).first
1234
- append_pathspec(refs, pass: false)
1236
+ cmd, opts = git_session('restore', "--#{flag}", opts: opts)
1237
+ op = OptionPartition.new(opts, OPT_GIT[:restore], cmd, project: self, no: OPT_GIT[:no][:restore])
1238
+ append_pathspec(op.extras, pass: false)
1235
1239
  source(sync: false, stderr: true)
1236
1240
  end
1237
1241
 
@@ -1240,11 +1244,10 @@ module Squared
1240
1244
  case flag
1241
1245
  when :textconv
1242
1246
  cmd << '--textconv'
1243
- files = files.map { |val| Dir[val] }
1244
- .flatten
1245
- .select { |val| projectpath?(val) }
1246
- .map { |val| shell_quote("HEAD:#{val}") }
1247
- append_value files
1247
+ append_value(files.map { |val| Dir[val] }
1248
+ .flatten
1249
+ .select { |val| projectpath?(val) }
1250
+ .map! { |val| shell_quote("HEAD:#{val}") })
1248
1251
  source(banner: false)
1249
1252
  return
1250
1253
  when :oneline
@@ -1262,13 +1265,14 @@ module Squared
1262
1265
  end
1263
1266
  end
1264
1267
  end
1265
- refs = option_sanitize(opts, OPT_GIT[:show] + OPT_GIT[:diff][:show] + OPT_GIT[:log][:diff],
1266
- no: OPT_GIT[:no][:show] + collect_hash(OPT_GIT[:no][:log], pass: [:base])).first
1267
- unless val == 'oneline' && session_arg?('abbrev-commit')
1268
- cmd << basic_option('abbrev', val) if (val = option('abbrev')) && val.to_i > 0
1268
+ op = OptionPartition.new(opts, OPT_GIT[:show] + OPT_GIT[:diff][:show] + OPT_GIT[:log][:diff], cmd,
1269
+ project: self,
1270
+ no: OPT_GIT[:no][:show] + collect_hash(OPT_GIT[:no][:log], pass: [:base]))
1271
+ unless val == 'oneline' && op.arg?('abbrev-commit')
1272
+ op << basic_option('abbrev', val) if (val = option('abbrev')) && val.to_i > 0
1269
1273
  banner = true
1270
1274
  end
1271
- append_value(refs, delim: true)
1275
+ op.append(delim: true)
1272
1276
  source(exception: false, banner: banner)
1273
1277
  end
1274
1278
 
@@ -1287,60 +1291,60 @@ module Squared
1287
1291
  cmd << '--abbrev-ref'
1288
1292
  append_commit(ref, head: true)
1289
1293
  else
1290
- args = option_sanitize(opts, OPT_GIT[:rev_parse][flag]).first
1291
- append_value(args, escape: session_arg?('sq-quote'))
1294
+ op = OptionPartition.new(opts, OPT_GIT[:rev_parse][flag], cmd, project: self)
1295
+ op.append(escape: op.arg?('sq-quote'))
1292
1296
  end
1293
- source(banner: verbose == 1)
1297
+ source(banner: verbosetype > 1)
1294
1298
  end
1295
1299
 
1296
1300
  def ls_remote(flag, opts = [], remote: nil)
1297
1301
  cmd, opts = git_session('ls-remote', '--refs', opts: opts)
1298
1302
  cmd << "--#{flag}" unless flag == :remote
1299
- grep = option_sanitize(opts, OPT_GIT[:ls_remote]).first
1300
- cmd << shell_quote(remote) if remote
1303
+ op = OptionPartition.new(opts, OPT_GIT[:ls_remote], cmd, project: self)
1304
+ op << shell_quote(remote) if remote
1301
1305
  out, banner, from = source(io: true)
1302
1306
  print_item banner
1303
- ret = write_lines(out, grep: grep)
1304
- list_result(ret, flag.to_s, from: from, grep: grep)
1307
+ ret = write_lines(out, grep: op.extras)
1308
+ list_result(ret, flag.to_s, from: from, grep: op.extras)
1305
1309
  end
1306
1310
 
1307
1311
  def ls_files(flag, opts = [])
1308
- opts = git_session('ls-files', "--#{flag}", opts: opts).last
1309
- grep = option_sanitize(opts, OPT_GIT[:ls_files]).first
1312
+ cmd, opts = git_session('ls-files', "--#{flag}", opts: opts)
1313
+ op = OptionPartition.new(opts, OPT_GIT[:ls_files], cmd, project: self)
1310
1314
  out, banner, from = source(io: true)
1311
1315
  print_item banner
1312
- ret = write_lines(out, grep: grep)
1313
- list_result(ret, 'files', from: from, grep: grep)
1316
+ ret = write_lines(out, grep: op.extras)
1317
+ list_result(ret, 'files', from: from, grep: op.extras)
1314
1318
  end
1315
1319
 
1316
1320
  def git(flag, opts = [])
1317
1321
  cmd, opts = git_session(flag, opts: opts)
1318
- refs = option_sanitize(opts, OPT_GIT[flag], no: OPT_GIT[:no][flag]).first
1322
+ op = OptionPartition.new(opts, OPT_GIT[flag], cmd, project: self, no: OPT_GIT[:no][flag])
1319
1323
  sync = false
1320
1324
  stderr = true
1321
1325
  case flag
1322
1326
  when :clean
1323
- refs = projectmap(refs)
1327
+ refs = projectmap(op.extras)
1324
1328
  unless refs.empty?
1325
- cmd << '--'
1326
- cmd.merge(refs)
1329
+ op << '--'
1330
+ op.merge(refs)
1327
1331
  end
1328
1332
  sync = true
1329
1333
  stderr = false
1330
1334
  when :revert
1331
- if VAL_GIT[:rebase][:send].any? { |val| session_arg?(val) }
1332
- option_clear refs
1333
- elsif refs.empty?
1335
+ if VAL_GIT[:rebase][:send].any? { |val| op.arg?(val) }
1336
+ op.clear
1337
+ elsif op.empty?
1334
1338
  raise_error 'no commit given'
1335
1339
  else
1336
- append_commit(*refs)
1340
+ append_commit(*op.extras)
1337
1341
  end
1338
1342
  when :mv
1339
- refs = projectmap(refs)
1343
+ refs = projectmap(op.extras)
1340
1344
  raise_error 'no source/destination' unless refs.size > 1
1341
- cmd.merge(refs)
1345
+ op.merge(refs)
1342
1346
  when :rm
1343
- append_pathspec(refs, expect: true)
1347
+ append_pathspec(op.extras, expect: true)
1344
1348
  end
1345
1349
  source(sync: sync, stderr: stderr)
1346
1350
  end
@@ -1471,15 +1475,13 @@ module Squared
1471
1475
  glob = kwargs.fetch(:include, [])
1472
1476
  pass = kwargs.fetch(:exclude, [])
1473
1477
  ret = {}
1474
- git_spawn('status -s --porcelain', *args, stdout: false)
1475
- .first
1476
- .each do |line|
1477
- next unless (file = line[/^[A-Z ?!]{3}"?(.+?)"?$/, 1])
1478
- next if !glob.empty? && glob.none? { |val| File.fnmatch?(val, file, File::FNM_DOTMATCH) }
1479
- next if !pass.empty? && pass.any? { |val| File.fnmatch?(val, file, File::FNM_DOTMATCH) }
1480
-
1481
- ret[file] = algorithm.hexdigest(File.read(basepath(file)))
1482
- end
1478
+ git_spawn('status -s --porcelain', *args, stdout: false).first.each do |line|
1479
+ next unless (file = line[/^[A-Z ?!]{3}"?(.+?)"?$/, 1])
1480
+ next if !glob.empty? && glob.none? { |val| File.fnmatch?(val, file, File::FNM_DOTMATCH) }
1481
+ next if !pass.empty? && pass.any? { |val| File.fnmatch?(val, file, File::FNM_DOTMATCH) }
1482
+
1483
+ ret[file] = algorithm.hexdigest(File.read(basepath(file)))
1484
+ end
1483
1485
  ret
1484
1486
  end
1485
1487
 
@@ -1487,43 +1489,44 @@ module Squared
1487
1489
  source(git_output(*cmd), io: true, banner: false, stdout: stdout)
1488
1490
  end
1489
1491
 
1490
- def append_pull(opts, list, target: @session, no: nil, flag: nil, remote: nil)
1491
- cmd << '--force' if option('force')
1492
- rsm = append_submodules(target: target)
1493
- out = []
1492
+ def append_pull(opts, list, target: @session, flag: nil, no: nil, remote: nil)
1493
+ target << '--force' if option('force', target: target)
1494
+ append_submodules(target: target)
1494
1495
  refspec = []
1495
- opts, pat = option_sanitize(opts, remote ? list + ['refspec=b'] : list, target: target, no: no)
1496
- opts.each do |opt|
1497
- if opt =~ pat
1496
+ op = OptionPartition.new(opts, remote ? list + ['refspec=v'] : list, target, project: self, no: no)
1497
+ op.each do |opt|
1498
+ if opt =~ op.values
1498
1499
  case $1
1499
1500
  when 'rebase'
1500
- target << basic_option($1, $2) if VAL_GIT[:rebase][:value].include?($2)
1501
+ op << basic_option($1, $2) if VAL_GIT[:rebase][:value].include?($2)
1501
1502
  when 'shallow-since'
1502
1503
  next unless (val = Date.parse($2))
1503
1504
 
1504
- target << quote_option($1, val.strftime('%F %T'))
1505
+ op << quote_option($1, val.strftime('%F %T'))
1505
1506
  when 'recurse-submodules'
1506
- target << basic_option($1, $2) unless rsm
1507
+ op << basic_option($1, $2) unless op.arg?('recurse-submodules')
1507
1508
  when 'refspec'
1508
1509
  refspec << shell_escape($2, quote: true)
1509
1510
  end
1511
+ elsif op.arg?('--multiple')
1512
+ op.found << opt
1510
1513
  else
1511
- out << opt
1514
+ op.errors << opt
1512
1515
  end
1513
1516
  end
1514
1517
  if remote
1515
- append_value(remote, target: target, delim: true)
1516
- if (val = option('refspec', strict: true))
1517
- append_value(split_escape(val), target: target)
1518
+ op.append(remote, delim: true)
1519
+ if (val = option('refspec', target: target, strict: true))
1520
+ op.append(*split_escape(val))
1518
1521
  else
1519
- target.merge(refspec)
1522
+ op.merge(refspec)
1520
1523
  end
1521
- target.delete('--all')
1522
- elsif target.include?('--multiple')
1523
- target.merge(out.map { |opt| shell_escape(opt, quote: true) })
1524
- out.clear
1524
+ op.delete('--all')
1525
+ elsif op.arg?('--multiple')
1526
+ op.swap.merge(op.map! { |opt| shell_escape(opt, quote: true) })
1527
+ return
1525
1528
  end
1526
- option_clear(out, target: target, subject: flag.to_s) if flag
1529
+ op.clear(errors: true, subject: flag.to_s) if flag
1527
1530
  end
1528
1531
 
1529
1532
  def append_commit(*val, target: @session, head: false)
@@ -1536,10 +1539,10 @@ module Squared
1536
1539
  end
1537
1540
 
1538
1541
  def append_pathspec(files = [], target: @session, expect: false, parent: false, pass: true)
1539
- if session_arg?('pathspec-from-file')
1542
+ if session_arg?('pathspec-from-file', target: target)
1540
1543
  option_clear files
1541
1544
  else
1542
- if files.empty? && (val = option('pathspec'))
1545
+ if files.empty? && (val = option('pathspec', target: target))
1543
1546
  files = split_escape(val)
1544
1547
  end
1545
1548
  files = projectmap(files, parent: parent, pass: pass)
@@ -1562,7 +1565,7 @@ module Squared
1562
1565
  end
1563
1566
 
1564
1567
  def append_submodules(from = nil, target: @session)
1565
- return unless (val = option('recurse-submodules', ignore: false))
1568
+ return unless (val = option('recurse-submodules', target: target, ignore: false))
1566
1569
 
1567
1570
  if from == :clone
1568
1571
  projectmap(split_escape(val)).each do |path|
@@ -1571,7 +1574,7 @@ module Squared
1571
1574
  target
1572
1575
  else
1573
1576
  target << case val
1574
- when 'no', '0'
1577
+ when 'no', '0', 'false'
1575
1578
  '--no-recurse-submodules'
1576
1579
  when 'yes', 'on-demand'
1577
1580
  "--recurse-submodules#{from == :reset ? '' : "=#{val}"}"
@@ -1585,9 +1588,9 @@ module Squared
1585
1588
  dir = worktree ? ["--work-tree=#{shell_quote(path)}", "--git-dir=#{shell_quote(gitpath)}"] : []
1586
1589
  return session('git', *dir, *cmd, **kwargs) unless opts
1587
1590
 
1588
- opts = option_sanitize(opts, OPT_GIT[:common], target: dir).first
1589
- ret = session('git', *dir, *cmd, **kwargs)
1590
- [ret, opts]
1591
+ op = OptionPartition.new(opts, OPT_GIT[:common], dir, project: self)
1592
+ ret = session('git', *op.to_a, *cmd, **kwargs)
1593
+ [ret, op.extras]
1591
1594
  end
1592
1595
 
1593
1596
  def git_output(*cmd, **kwargs)
@@ -1595,13 +1598,15 @@ module Squared
1595
1598
  end
1596
1599
 
1597
1600
  def dryrun?(*, target: @session, **)
1598
- !!target&.include?('--dry-run')
1601
+ return false unless target
1602
+
1603
+ target.include?('--dry-run')
1599
1604
  end
1600
1605
 
1601
1606
  def quiet?(target: @session)
1602
1607
  return false unless target
1603
1608
 
1604
- target.include?('--quiet') || (target.include?('-q') && target.first == 'git')
1609
+ target.include?('--quiet') || (target.include?('-q') && stripext(target.first) == 'git')
1605
1610
  end
1606
1611
 
1607
1612
  def gitpath