squared 0.1.7 → 0.2.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.
@@ -4,44 +4,61 @@ module Squared
4
4
  module Workspace
5
5
  module Project
6
6
  class Ruby < Git
7
- VAR_SET = %i[version autodetect].freeze
8
7
  GEMFILE = %w[Gemfile Gemfile.lock gem.deps.rb Isolate].freeze
9
- RUBY_DIR = (GEMFILE + Rake::Application::DEFAULT_RAKEFILES + ['README.rdoc']).freeze
10
- OPT_INSTALL = %w[system frozen no-cache no-prune].freeze
11
- OPT_UPDATE = %w[all redownload conservative local strict group=s].freeze
12
- OPT_OUTDATED = %w[pre only-explicit local strict group=s].freeze
13
- private_constant :VAR_SET, :GEMFILE, :RUBY_DIR, :OPT_INSTALL, :OPT_UPDATE, :OPT_OUTDATED
8
+ DIR_RUBY = (GEMFILE + Rake::Application::DEFAULT_RAKEFILES + ['README.rdoc']).freeze
9
+ FOR_INSTALL = %w[full-index quiet retry gemfile=s j=i jobs=i retry=i].freeze
10
+ OPT_INSTALL = %w[binstubs frozen system no-cache no-prune path=s binstubs=? standalone=? target-rbconfig=s
11
+ trust-policy=s with=s without=s].freeze
12
+ OPT_UPDATE = %w[conservative local pre redownload ruby strict bundler=? g=s group=s source=s].freeze
13
+ OPT_OUTDATED = %w[filter-major filter-minor filter-patch groups local parseable pre only-explicit strict
14
+ update-strict g=s group=s source=s].freeze
15
+ OPT_GEM = {
16
+ COMMON: %w[V backtrace debug q quiet norc silent verbose no-verbose config-file=s].freeze,
17
+ INSTALL: ['version=s'].freeze,
18
+ UPDATE: ['system=?'].freeze,
19
+ OUTDATED: %w[b both clear-sources l local no-http-proxy r remote B bulk-threshold=i p=s http-proxy=?
20
+ platform=s source=s].freeze,
21
+ PRISTINE: %w[all env-shebang no-env-shebang extensions no-extensions only-missing-extensions only-executables
22
+ only-plugins n=s bindir=s i=s install-dir=s skip=s v=s version=s].freeze,
23
+ NO_GENERAL: %w[env-shebang force format-executable http-proxy lock minimal-deps post-install-message
24
+ prerelease suggestions user-install wrappers].freeze,
25
+ GENERAL: %w[f g w b both clear-sources conservative document=? default development development-all E explain
26
+ ignore-dependencies l local N no-document r remote vendor n=s bindir=s build-root=s
27
+ bulk-threshold=i document=s g=s file=? p=s http-proxy=s i=s install-dir=s platform=s s=s source=s
28
+ target-rbconfig=? P=s trust-policy=s without=s].freeze
29
+ }.freeze
30
+ private_constant :GEMFILE, :DIR_RUBY, :FOR_INSTALL, :OPT_INSTALL, :OPT_UPDATE, :OPT_OUTDATED, :OPT_GEM
14
31
 
15
32
  class << self
16
33
  def populate(*); end
17
34
  def batchargs(*); end
18
35
 
19
36
  def tasks
20
- %i[outdated].freeze
37
+ [:outdated].freeze
21
38
  end
22
39
 
23
40
  def bannerargs
24
- %i[dependfile].freeze
41
+ [:dependfile].freeze
25
42
  end
26
43
 
27
44
  def config?(val)
28
45
  return false unless (val = as_path(val))
29
46
 
30
- RUBY_DIR.any? { |file| val.join(file).exist? }
47
+ DIR_RUBY.any? { |file| val.join(file).exist? }
31
48
  end
32
49
  end
33
50
 
34
51
  @@tasks[ref] = {
35
- install: %i[redownload local prefer-local gem with without].freeze,
36
- update: %i[all patch minor major].freeze,
37
- outdated: %i[patch minor major].freeze,
38
- pristine: %i[gem all version].freeze,
39
- exec: nil,
40
- config: nil,
41
- rake: nil
52
+ 'install' => %i[redownload local prefer-local].freeze,
53
+ 'update' => %i[patch minor major all].freeze,
54
+ 'outdated' => %i[patch minor major].freeze,
55
+ 'gem' => %i[install user-install update outdated pristine].freeze,
56
+ 'exec' => nil,
57
+ 'config' => nil,
58
+ 'rake' => nil
42
59
  }.freeze
43
60
 
44
- def initialize(*, version: nil, autodetect: false, **kwargs)
61
+ def initialize(*, autodetect: false, **kwargs)
45
62
  super
46
63
  if @pass.include?(Ruby.ref)
47
64
  initialize_ref(Ruby.ref)
@@ -50,7 +67,6 @@ module Squared
50
67
  initialize_build(Ruby.ref, **kwargs)
51
68
  initialize_env(**kwargs)
52
69
  end
53
- @version = env('BUILD', version, suffix: 'VERSION')
54
70
  @autodetect = autodetect
55
71
  @dependindex = GEMFILE.index { |file| basepath(file).exist? }
56
72
  @dependfile = basepath(GEMFILE[@dependindex || 0])
@@ -60,9 +76,10 @@ module Squared
60
76
  File.foreach(file) do |line|
61
77
  next unless line =~ %r{\brequire\s+(["'])bundler/gem_tasks\1}
62
78
 
63
- @output[0] = 'bundle exec rake build'
64
- @copy = 'bundle exec rake install'
65
- @clean = 'bundle exec rake clean' if @clean.nil?
79
+ cmd = bundle_output('exec', 'rake').to_s
80
+ @output[0] = "#{cmd} build"
81
+ @copy = "#{cmd} install"
82
+ @clean = "#{cmd} clean" if @clean.nil?
66
83
  break
67
84
  end
68
85
  rescue StandardError => e
@@ -74,23 +91,26 @@ module Squared
74
91
  Ruby.ref
75
92
  end
76
93
 
77
- def populate(*)
94
+ def populate(*, **)
78
95
  super
79
96
  return unless outdated? && ref?(Ruby.ref)
80
97
 
81
98
  namespace name do
82
99
  @@tasks[Ruby.ref].each do |action, flags|
100
+ next if @pass.include?(action)
101
+
83
102
  if flags.nil?
84
103
  case action
85
- when :exec, :config
86
- desc format_desc(action, nil, 'command+')
87
- task action, [:command] do |_, args|
88
- bundle(action, args.to_a)
104
+ when 'exec', 'config'
105
+ format_desc action, nil, 'command+'
106
+ task action do |_, args|
107
+ args = param_guard('bundle', action, args: args.to_a)
108
+ bundle(action, *args)
89
109
  end
90
- when :rake
110
+ when 'rake'
91
111
  next unless rakefile
92
112
 
93
- desc format_desc(action, nil, 'command*|^index,args*|#,pattern*')
113
+ format_desc action, nil, 'command*|^index,args*|#,pattern*'
94
114
  task action, [:command] do |_, args|
95
115
  if args.command == '#'
96
116
  format_list(read_rakefile, 'rake[^N]', 'tasks', grep: args.extras, from: rakefile.to_s,
@@ -116,49 +136,33 @@ module Squared
116
136
  namespace action do
117
137
  flags.each do |flag|
118
138
  case action
119
- when :install
120
- case flag
121
- when :gem
122
- desc format_desc(action, flag, 'name+')
123
- task flag, [:name] do |_, args|
124
- opts = guard_params(action, flag, args: args.to_a)
125
- depend(flag, opts: opts)
126
- end
127
- when :with, :without
128
- desc format_desc(action, flag, 'group+')
129
- task flag, [:group] do |_, args|
130
- opts = guard_params(action, flag, args: args.to_a)
131
- depend(flag, opts: opts)
132
- end
133
- else
134
- desc format_desc(action, flag, OPT_INSTALL)
135
- task flag, [:opts] do |_, args|
136
- depend(flag, opts: args.to_a)
137
- end
139
+ when 'install'
140
+ format_desc(action, flag, FOR_INSTALL + OPT_INSTALL) if @@task_desc
141
+ task flag do |_, args|
142
+ depend(flag, opts: args.to_a)
143
+ end
144
+ when 'update', 'outdated'
145
+ if @@task_desc
146
+ format_desc(action, flag, action == 'update' ? FOR_INSTALL + OPT_UPDATE : OPT_OUTDATED)
138
147
  end
139
- when :update, :outdated
140
- desc format_desc(action, flag, action == :update ? OPT_UPDATE : OPT_OUTDATED)
141
- task flag, [:opts] do |_, args|
148
+ task flag do |_, args|
142
149
  __send__(action, flag, opts: args.to_a)
143
150
  end
144
- when :pristine
151
+ when 'gem'
145
152
  case flag
146
- when :gem
147
- desc format_desc(action, flag, 'name+')
148
- task flag, [:name] do |_, args|
149
- opts = guard_params(action, flag, args: args.to_a)
150
- pristine(flag, opts: opts)
153
+ when :outdated
154
+ format_desc action, flag, gemoption(flag) if @@task_desc
155
+ task flag do |_, args|
156
+ gemx(flag, opts: args.to_a)
151
157
  end
152
- when :all
153
- desc format_desc(action, flag, 'skip*')
154
- task flag, [:skip] do |_, args|
155
- pristine(flag, opts: args.to_a)
158
+ else
159
+ if @@task_desc
160
+ format_desc(action, flag, gemoption(flag),
161
+ after: "name+#{flag == :pristine ? '|name?@version' : ''}")
156
162
  end
157
- when :version
158
- desc format_desc(action, flag, 'version?')
159
- task flag, [:version] do |_, args|
160
- version = guard_params(action, flag, args: args, key: :version)
161
- pristine(flag, version: version)
163
+ task flag, [:name] do |_, args|
164
+ opts = param_guard(action, flag, args: args.to_a)
165
+ gemx(flag, opts: opts)
162
166
  end
163
167
  end
164
168
  end
@@ -173,79 +177,69 @@ module Squared
173
177
  if @depend && !flag
174
178
  super
175
179
  elsif outdated?
176
- case flag
177
- when :gem
178
- gem_session 'install'
179
- append_value opts
180
- when :with, :without
181
- bundle_session 'install'
182
- append_repeat flag, opts
183
- when :redownload, :local, :'prefer-local'
184
- cmd = bundle_session 'install', "--#{flag}"
185
- if (val = option('trust-policy', ignore: false))
186
- cmd << shell_option('trust-policy', case val
187
- when '0'
188
- 'NoSecurity'
189
- when '1'
190
- 'AlmostNoSecurity'
191
- when '2'
192
- 'LowSecurity'
193
- when '3'
194
- 'MediumSecurity'
195
- when '4'
196
- 'HighSecurity'
197
- else
198
- val
199
- end, escape: false)
200
- end
201
- append_bundle opts, OPT_INSTALL
180
+ cmd = bundle_session 'install'
181
+ if flag
182
+ cmd << "--#{flag}"
183
+ append_bundle opts, FOR_INSTALL + OPT_INSTALL
184
+ from = :install
202
185
  else
203
- bundle_session 'install'
204
- append_bundle
186
+ if (n = option('jobs')).to_i > 0
187
+ cmd << "-j#{n}"
188
+ end
189
+ from = :depend
205
190
  end
206
- run_rb(sync: sync)
191
+ run_rb(from: from, sync: sync)
207
192
  end
208
193
  end
209
194
 
210
- def copy(from: 'lib', into: @gemdir, override: false, **kwargs)
211
- glob = kwargs[:include]
212
- pass = kwargs[:exclude]
195
+ def copy(from: 'lib', include: nil, exclude: nil, into: @gemdir, override: false)
213
196
  if @copy && !override
214
197
  return super if runnable?(@copy)
215
198
 
216
199
  from = @copy[:from] if @copy.key?(:from)
217
200
  glob = @copy[:include] if @copy.key?(:include)
218
- pass = @copy[:exclude] if @copy.key?(:exclude)
201
+ exclude = @copy[:exclude] if @copy.key?(:exclude)
219
202
  into = @copy[:into] if @copy.key?(:into)
220
203
  end
221
204
  return unless into
222
205
 
206
+ on :first, :copy
223
207
  dest = Pathname.new(into).realpath
224
- print_item unless @output[0] || task_invoked?(/\Acopy(?::#{Ruby.ref}|\z)/)
208
+ print_item unless @output[0] || task_invoked?(/^copy(?::#{Ruby.ref}|$)/)
225
209
  glob = as_a(glob || '**/*')
226
210
  as_a(from).each_with_index do |val, i|
227
211
  a = basepath(val)
228
212
  b = dest.join(val)
229
- c = glob[i] || glob.first
213
+ c = glob[i] || glob[0]
230
214
  log.info "cp #{a.join(c)} #{b}"
231
- copy_d(a, b, glob: c, pass: pass, verbose: verbose)
215
+ begin
216
+ copy_dir(a, b, c, pass: exclude, verbose: verbose)
217
+ rescue StandardError => e
218
+ log.error e
219
+ ret = on(:error, :copy, e)
220
+ raise if exception && ret != true
221
+ end
232
222
  end
223
+ on :last, :copy
233
224
  end
234
225
 
235
- def outdated(rev = nil, opts: [], sync: invoked_sync?('outdated', rev))
236
- cmd = bundle_session 'outdated', rev && "--#{rev}"
237
- append_bundle opts, OPT_OUTDATED
238
- cmd = session_done(cmd)
239
- log.info cmd
240
- banner = format_banner(cmd)
226
+ def outdated(flag = nil, opts: [], sync: invoked_sync?('outdated', flag))
227
+ cmd = bundle_output 'outdated'
228
+ if flag
229
+ cmd << "--#{flag}"
230
+ append_bundle(opts, OPT_OUTDATED, target: cmd)
231
+ end
232
+ log.info cmd.to_s
233
+ on :first, :outdated
234
+ banner = format_banner(cmd.to_s)
241
235
  print_item banner if sync
242
- start = 0
243
- found = 0
244
- major = 0
245
- pwd_set do
236
+ pwd_set(from: :outdated) do
237
+ start = 0
238
+ found = 0
239
+ major = 0
246
240
  buffer = []
247
241
  out = ->(val) { sync ? puts(val) : buffer << val }
248
- IO.popen("#{cmd} --no-color").each do |line|
242
+ IO.popen(cmd.temp('--no-color')).each do |line|
249
243
  if start > 0
250
244
  unless stdin?
251
245
  data = line.scan(SEM_VER)
@@ -297,26 +291,31 @@ module Squared
297
291
  end
298
292
  end
299
293
  unless styles.empty?
300
- case styles[0]
294
+ case styles.first
301
295
  when :green
302
- line = sub_style(line, pat: /^(\S+)(.+)$/, styles: theme[styles[1] == :bold ? :major : :active])
296
+ line = sub_style(line, pat: /^(\S+)(.+)$/, styles: theme[styles.last == :bold ? :major : :active])
303
297
  found += 1
304
298
  when :yellow
305
299
  found += 1
306
300
  end
307
- styles = styles.compact.map { |s| color(s) }.flatten
308
- line = sub_style(line, pat: /^((?:\S+\s+){2})(#{Regexp.escape(l)})(.*)$/, index: 2, styles: styles)
301
+ if theme[:current]
302
+ line = sub_style(line, styles: theme[:current], pat: /^(.+)(#{Regexp.escape(c)})(.+)$/,
303
+ index: 2)
304
+ end
305
+ line = sub_style(line, *colormap(styles), pat: /^((?:\S+\s+){2})(#{Regexp.escape(l)})(.*)$/,
306
+ index: 2)
309
307
  end
310
308
  end
311
309
  out.("#{start.to_s.rjust(2)}. #{line}")
312
- start += 1
313
310
  elsif line =~ /^Gem /
314
311
  unless stdin?
315
312
  sub = { pat: /^(.+)(?<!\dm)(Gem|Latest)(.+)$/, styles: theme[:header], index: 2 }
316
313
  out.(print_footer(" # #{line.chomp}", reverse: true, sub: [sub, sub]))
317
314
  end
318
- start += 1
315
+ else
316
+ next
319
317
  end
318
+ start += 1
320
319
  end
321
320
  unless sync
322
321
  print_item banner
@@ -338,39 +337,159 @@ module Squared
338
337
  puts 'No updates were found'
339
338
  end
340
339
  end
340
+ on :last, :outdated
341
341
  end
342
342
 
343
343
  def update(flag, opts: [])
344
344
  bundle_session 'update', "--#{flag}"
345
- append_bundle opts, OPT_UPDATE
346
- run_rb
345
+ append_bundle opts, FOR_INSTALL + OPT_UPDATE
346
+ run_rb(from: :update)
347
347
  end
348
348
 
349
- def pristine(flag, version: nil, opts: [])
350
- cmd = gem_session 'pristine'
349
+ def gemx(flag, opts: [])
350
+ cmd = gem_session
351
351
  case flag
352
- when :gem
353
- append_value opts
354
- when :all
355
- cmd << '--all'
356
- append_repeat 'skip', opts
357
- when :version
358
- cmd << project << shell_option('version', version)
352
+ when :outdated
353
+ cmd << "-C #{shell_quote(path)}" if (pass = Gem::VERSION >= '3.4.2')
354
+ cmd << flag
355
+ when :'user-install'
356
+ cmd << 'install' << "--#{flag}"
357
+ else
358
+ cmd << flag
359
+ end
360
+ no = flag == :pristine || flag == :outdated ? [] : OPT_GEM[:NO_GENERAL]
361
+ opts, pat = option_partition(opts, gemoption(flag), no: no, first: true)
362
+ out = []
363
+ opts.each do |opt|
364
+ if opt =~ pat
365
+ case $1
366
+ when 'build-root', 'config-file', 'target-rbconfig',
367
+ 'n', 'bindir', 'g', 'file', 'i', 'install-dir'
368
+ cmd << quote_option($1, basepath($2))
369
+ when 'p', 'http-proxy', 's', 'source'
370
+ cmd << shell_quote($1, $2)
371
+ when 'bulk-threshold'
372
+ cmd << basic_option($1, $2) if $2.to_i > 0
373
+ else
374
+ cmd << shell_option($1, $2)
375
+ end
376
+ else
377
+ out << opt
378
+ end
379
+ end
380
+ from = :"gem:#{flag == :'user-install' ? 'install' : flag}"
381
+ if flag == :outdated
382
+ log.info cmd.to_s
383
+ on :first, from
384
+ print_item format_banner(cmd.to_s)
385
+ pwd_set(pass: pass, from: from) do
386
+ items = [[%w[Gem Current Latest], nil]]
387
+ IO.popen(cmd.done).each do |line|
388
+ if (data = line.match(/^(\S+) \((\S+) < ([^)]+)\)$/))
389
+ cur = semscan(data[2])
390
+ lat = semscan(data[3])
391
+ items << [data.to_a.drop(1), if semmajor?(cur, lat)
392
+ %i[green bold]
393
+ else
394
+ cur[2] == lat[2] ? [:yellow] : [:green]
395
+ end]
396
+ else
397
+ puts line
398
+ end
399
+ end
400
+ if items.size == 1
401
+ puts 'No updates were found'
402
+ else
403
+ pad = [items.size.to_s.size + 1, 3].max
404
+ d = 0
405
+ e = 0
406
+ f = 0
407
+ items.each do |item|
408
+ a, b, c = item.first
409
+ d = a.size if a.size > d
410
+ e = b.size if b.size > e
411
+ f = c.size if c.size > f
412
+ end
413
+ major = 0
414
+ minor = 0
415
+ patch = 0
416
+ items.each_with_index do |item, i|
417
+ next if i == 0 && stdin?
418
+
419
+ a, b, c = item.first
420
+ if i == 0
421
+ line = "#{' #'.ljust(pad)} #{a.ljust(d)} #{b.rjust(e)} #{c.rjust(f)}"
422
+ n = line.size
423
+ 2.times do
424
+ line = sub_style(line, pat: /^(.+)(?<!\dm)(#{a}|#{c})(.*)$/, styles: theme[:header], index: 2)
425
+ end
426
+ puts line
427
+ puts '-' * n
428
+ else
429
+ styles = item.last
430
+ a = a.ljust(d)
431
+ if styles.first == :green
432
+ a = sub_style(a, styles: if styles.size == 2
433
+ major += 1
434
+ theme[:major]
435
+ else
436
+ minor += 1
437
+ theme[:active]
438
+ end)
439
+ else
440
+ patch += 1
441
+ end
442
+ b = b.rjust(e)
443
+ b = sub_style(b, styles: theme[:current]) if theme[:current]
444
+ c = sub_style(c.rjust(f), *colormap(styles))
445
+ puts "#{"#{i}.".rjust(pad)} #{a} #{b} #{c}"
446
+ end
447
+ end
448
+ unless stdin?
449
+ status = print_footer("major #{major} / minor #{minor} / patch #{patch}", right: true).split("\n")
450
+ status[1] = sub_style(status[1], pat: /^( +major )(\d+)(.+)$/, styles: theme[:major], index: 2)
451
+ status[1] = sub_style(status[1], pat: /^(.+)(minor )(\d+)(.+)$/, styles: theme[:active], index: 3)
452
+ puts status
453
+ end
454
+ end
455
+ end
456
+ on :last, from
457
+ else
458
+ if out.empty? && !cmd.find { |val| val =~ /^--system(?:=|$)/ }
459
+ raise_error('gem', flag, hint: 'no gemname given')
460
+ else
461
+ if flag == :pristine
462
+ if cmd.include?('--all')
463
+ append_repeat 'skip', out
464
+ out.clear
465
+ elsif (n = out.first =~ /@/)
466
+ name = out.first
467
+ if n == 0
468
+ cmd << shell_escape(project)
469
+ version = name[1..-1]
470
+ else
471
+ cmd << shell_escape(name[0..n - 1])
472
+ version = name[n + 1..-1]
473
+ end
474
+ cmd << shell_option('version', version)
475
+ out.clear
476
+ end
477
+ end
478
+ append_value out
479
+ end
480
+ run_rb(from: from)
359
481
  end
360
- run_rb
361
482
  end
362
483
 
363
- def bundle(flag, cmd)
364
- guard_params('bundle', flag, args: cmd)
365
- run_s "bundle #{flag} #{cmd.join(' ')}"
484
+ def bundle(cmd, *args)
485
+ run_s(bundle_session(cmd, *args), from: :bundle)
366
486
  end
367
487
 
368
488
  def rake(*cmd)
369
- file = shell_option('rakefile', rakefile, quote: true, escape: false)
370
489
  if cmd.empty?
371
- run_s("rake #{file}", chdir: workspace.pwd)
490
+ run_s(rake_output(rakeapp), from: :rake, chdir: workspace.pwd)
372
491
  else
373
- run_s(*cmd.map { |val| "rake #{file} #{val}" }, chdir: workspace.pwd, banner: false)
492
+ run_s(*cmd.map { |val| rake_output(rakeapp, val) }, from: :rake, chdir: workspace.pwd, banner: false)
374
493
  end
375
494
  end
376
495
 
@@ -382,25 +501,37 @@ module Squared
382
501
  return true if super || (@copy.is_a?(Hash) && copy.fetch(:into, nil))
383
502
  return gemdir? if @gemdir
384
503
 
385
- if @version && (val = ENV['GEM_HOME'])
386
- @gemdir = Pathname.new(val).join(gempath)
504
+ if @version && (home = ENV['GEM_HOME'])
505
+ @gemdir = Pathname.new(home).join(gempath)
387
506
  return true if gemdir?
388
507
  end
389
508
  return false unless @autodetect
390
509
 
391
- unsafe = ->(hint) { raise_error('failed to parse', hint: hint) }
392
- out = pwd_set { `gem list --local -d #{project}` }
393
- unsafe.('version') unless (data = /#{Regexp.escape(project)} \(([^)]+)\)/.match(out))
394
- ver = data[1].split(/\s*,\s*/)
395
- ver.unshift(@version).uniq! if @version
396
- ver.each do |v|
397
- next unless (data = /\(#{Regexp.escape(v)}(?:,[^)]+|\b)\):([^\n]+)/.match(out))
398
-
399
- log.warn "using version #{v} (given #{@version})" if @version && @version != v
400
- @version = v
401
- break
510
+ set = lambda do |val|
511
+ log.warn "using version #{val} (given #{@version})" if @version && @version != val
512
+ @version = val
513
+ end
514
+ out = pwd_set { `#{gem_output('list', '--local', '-d', shell_escape(project, quote: true))}` }
515
+ if (data = /#{Regexp.escape(project)} \(([^)]+)\)/.match(out))
516
+ ver = data[1].split(/\s*,\s*/)
517
+ ver.unshift(@version).uniq! if @version
518
+ ver.each do |val|
519
+ next unless (data = /\(#{Regexp.escape(val)}(?:,[^)]+|\b)\):([^\n]+)/.match(out))
520
+
521
+ set.(val)
522
+ break
523
+ end
402
524
  end
403
- unsafe.('path') unless data
525
+ unless data || RUBY_VERSION < '2.6'
526
+ target = RUBY_VERSION.start_with?('2.6') ? RubyVM : $LOAD_PATH
527
+ if (path = target.resolve_feature_path(project)&.last)
528
+ gems = ['', 'gems', "#{project}-([^#{File::SEPARATOR}]+)", ''].join(File::SEPARATOR)
529
+ if (ver = Regexp.new(gems).match(path)) && (data = /\A(.+)#{gempath}/.match(path))
530
+ set.(ver[1])
531
+ end
532
+ end
533
+ end
534
+ raise_error('failed to parse', hint: @version || 'path') unless data
404
535
  @gemdir = Pathname.new(data[1].strip).join(gempath)
405
536
  rescue StandardError => e
406
537
  log.error e
@@ -417,38 +548,58 @@ module Squared
417
548
 
418
549
  private
419
550
 
420
- def run_rb(sync: true)
421
- run(sync: sync, banner: !@session.include?('--quiet'))
551
+ def run_rb(**kwargs)
552
+ run(banner: !@session.include?('--quiet'), **kwargs)
422
553
  end
423
554
 
424
- def append_bundle(opts = nil, list = nil)
425
- if (val = option('jobs')).to_i > 0
426
- @session << "-j#{val}"
427
- end
428
- return unless opts && list
429
-
555
+ def append_bundle(opts, list, target: @session)
556
+ opts, pat = option_partition(opts, list, target: target)
557
+ out = []
430
558
  opts.each do |opt|
431
- if list.include?(opt)
432
- @session << "--#{opt}"
433
- elsif opt.match(/^g(?:roup)?=(.+)$/)
434
- @session << shell_option('group', $1)
559
+ if opt =~ pat
560
+ case $1
561
+ when 'path', 'gemfile', 'binstubs', 'target-rbconfig'
562
+ target << quote_option($1, basepath($2))
563
+ when 'standalone', 'with', 'without', 'g', 'group'
564
+ target << shell_quote($1, $2)
565
+ when 'retry', 'j', 'jobs'
566
+ target << basic_option($1, $2) if $2.to_i > 0
567
+ else
568
+ target << shell_option($1, $2)
569
+ end
570
+ else
571
+ out << opt
435
572
  end
436
573
  end
574
+ option_clear(out, target: target)
437
575
  end
438
576
 
439
- def gem_session(*cmd)
440
- ret = session('gem', *cmd)
441
- if (val = option('config-file', ignore: false))
442
- ret << shell_option('config-file', basepath(val), quote: true)
443
- end
444
- ret << '--norc' if option('norc')
577
+ def gem_session(*cmd, **kwargs)
578
+ ret = session('gem', *cmd, **kwargs)
579
+ ret << '--no-verbose' unless verbose
445
580
  ret
446
581
  end
447
582
 
448
- def bundle_session(*cmd)
449
- session('bundle', *cmd)
450
- append_nocolor option('no-color')
451
- @session
583
+ def bundle_session(*cmd, **kwargs)
584
+ ret = session('bundle', *cmd, **kwargs)
585
+ append_nocolor(target: ret)
586
+ ret
587
+ end
588
+
589
+ def rake_session(*cmd, **kwargs)
590
+ session('rake', *cmd, **kwargs)
591
+ end
592
+
593
+ def gem_output(*cmd, **kwargs)
594
+ session_output('gem', *cmd, **kwargs)
595
+ end
596
+
597
+ def bundle_output(*cmd, **kwargs)
598
+ session_output('bundle', *cmd, **kwargs)
599
+ end
600
+
601
+ def rake_output(*cmd, **kwargs)
602
+ session_output('rake', *cmd, **kwargs)
452
603
  end
453
604
 
454
605
  def read_rakefile
@@ -457,8 +608,8 @@ module Squared
457
608
  ret = []
458
609
  pass = Rake::VERSION >= '13.0.4'
459
610
  pwd_set(pass: pass) do
460
- IO.popen("rake#{pass ? " -C #{shell_quote(path)}" : ''} -AT").each do |line|
461
- next unless (data = /\Arake ((?:[^\[: ]+:?)+)(\[[^\]]+\])?/.match(line))
611
+ IO.popen(rake_output(pass ? "-C #{shell_quote(path)}" : nil, '-AT').to_s).each do |line|
612
+ next unless (data = /^rake ((?:[^\[: ]+:?)+)(\[[^\]]+\])?/.match(line))
462
613
 
463
614
  ret << [data[1], data[2]]
464
615
  end
@@ -471,8 +622,7 @@ module Squared
471
622
  end
472
623
 
473
624
  def variables
474
- ret = super + VAR_SET
475
- ret.freeze
625
+ (super + %i[version autodetect]).freeze
476
626
  end
477
627
 
478
628
  def rakefile
@@ -480,9 +630,23 @@ module Squared
480
630
  basepath(file) if file
481
631
  end
482
632
 
633
+ def rakeapp
634
+ quote_option 'rakefile', Rake.application.rakefile
635
+ end
636
+
483
637
  def gempath
484
638
  File.join('gems', "#{project}-#{@version}")
485
639
  end
640
+
641
+ def gemoption(flag)
642
+ target = flag == :'user-install' ? :INSTALL : flag.upcase
643
+ OPT_GEM[:COMMON] + OPT_GEM[target] + case flag
644
+ when :pristine, :outdated
645
+ []
646
+ else
647
+ OPT_GEM[:GENERAL] + OPT_GEM[:NO_GENERAL]
648
+ end
649
+ end
486
650
  end
487
651
 
488
652
  Application.implement Ruby