squared 0.4.6 → 0.4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +77 -0
- data/README.ruby.md +52 -32
- data/lib/squared/common/base.rb +1 -0
- data/lib/squared/common/class.rb +20 -5
- data/lib/squared/common/format.rb +30 -22
- data/lib/squared/common/prompt.rb +39 -1
- data/lib/squared/common/shell.rb +14 -10
- data/lib/squared/common/system.rb +3 -3
- data/lib/squared/common/utils.rb +17 -10
- data/lib/squared/config.rb +1 -2
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +39 -23
- data/lib/squared/workspace/project/base.rb +242 -243
- data/lib/squared/workspace/project/docker.rb +119 -72
- data/lib/squared/workspace/project/git.rb +252 -214
- data/lib/squared/workspace/project/node.rb +65 -67
- data/lib/squared/workspace/project/python.rb +69 -57
- data/lib/squared/workspace/project/ruby.rb +297 -98
- data/lib/squared/workspace/project/support/class.rb +199 -0
- data/lib/squared/workspace/project/support.rb +3 -0
- data/lib/squared/workspace/project.rb +1 -0
- data/lib/squared/workspace/repo.rb +6 -8
- data/lib/squared/workspace/series.rb +7 -6
- data/lib/squared/workspace.rb +1 -8
- metadata +3 -1
@@ -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
|
@@ -13,13 +14,15 @@ module Squared
|
|
13
14
|
include Shell
|
14
15
|
include Prompt
|
15
16
|
include Utils
|
17
|
+
include Support
|
16
18
|
include Rake::DSL
|
17
19
|
|
18
20
|
VAR_SET = %i[parent global envname dependfile dependindex theme run script env pass].freeze
|
19
21
|
BLK_SET = %i[run depend doc lint test copy clean].freeze
|
20
22
|
SEM_VER = /\b(\d+)(?:(\.)(\d+))?(?:(\.)(\d+)(\S+)?)?\b/.freeze
|
21
23
|
URI_SCHEME = %r{^([a-z][a-z\d+-.]*)://[^@:\[\]\\^<>|\s]}i.freeze
|
22
|
-
|
24
|
+
TASK_METADATA = Rake::TaskManager.record_task_metadata
|
25
|
+
private_constant :VAR_SET, :BLK_SET, :SEM_VER, :URI_SCHEME, :TASK_METADATA
|
23
26
|
|
24
27
|
class << self
|
25
28
|
def populate(*); end
|
@@ -44,7 +47,9 @@ module Squared
|
|
44
47
|
@ref ||= to_s.downcase.to_sym
|
45
48
|
end
|
46
49
|
|
47
|
-
def subtasks(val)
|
50
|
+
def subtasks(val = nil, &blk)
|
51
|
+
return @@tasks[val || ref].each(&blk) if block_given?
|
52
|
+
|
48
53
|
@@tasks[ref] = val.freeze
|
49
54
|
end
|
50
55
|
|
@@ -58,12 +63,11 @@ module Squared
|
|
58
63
|
end
|
59
64
|
|
60
65
|
@@tasks = {}
|
61
|
-
@@task_desc = Rake::TaskManager.record_task_metadata
|
62
66
|
@@print_order = 0
|
63
67
|
|
64
68
|
subtasks({
|
65
69
|
'graph' => %i[run print].freeze,
|
66
|
-
'unpack' => %i[zip tar ext].freeze
|
70
|
+
'unpack' => %i[zip tar gem ext].freeze
|
67
71
|
})
|
68
72
|
|
69
73
|
attr_reader :name, :project, :workspace, :path, :theme, :exception, :pipe, :verbose,
|
@@ -94,7 +98,7 @@ module Squared
|
|
94
98
|
@exception = env_bool(kwargs[:exception], workspace.exception, strict: true)
|
95
99
|
@pipe = env_pipe(kwargs[:pipe], workspace.pipe, strict: true)
|
96
100
|
@verbose = case verbose
|
97
|
-
when
|
101
|
+
when NilClass
|
98
102
|
workspace.verbose
|
99
103
|
when String
|
100
104
|
env_bool(verbose, workspace.verbose, strict: true, index: true)
|
@@ -192,19 +196,24 @@ module Squared
|
|
192
196
|
return if @log
|
193
197
|
|
194
198
|
log = log.is_a?(Hash) ? log.dup : { file: log }
|
195
|
-
|
196
|
-
file =
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
199
|
+
if (file = env('LOG_FILE'))
|
200
|
+
file = Time.now.strftime(file)
|
201
|
+
elsif (val = env('LOG_AUTO'))
|
202
|
+
file = "#{@name}-%s.log" % [case val
|
203
|
+
when 'y', 'year'
|
204
|
+
Date.today.year
|
205
|
+
when 'm', 'month'
|
206
|
+
Date.today.strftime('%Y-%m')
|
207
|
+
when 'd', 'day', '1'
|
208
|
+
Date.today
|
209
|
+
else
|
210
|
+
val.include?('%') ? Time.now.strftime(val) : Time.now.strftime('%FT%T%:z')
|
211
|
+
end]
|
212
|
+
elsif (val = log[:file])
|
213
|
+
file = val.is_a?(String) ? Time.now.strftime(val) : "#{@name}-#{Date.today}.log"
|
214
|
+
end
|
215
|
+
if file
|
216
|
+
file = (val = env('LOG_DIR')) ? @workspace.home.join(val, file) : @workspace.home.join(file)
|
208
217
|
begin
|
209
218
|
file = file.realdirpath
|
210
219
|
rescue StandardError => e
|
@@ -259,7 +268,7 @@ module Squared
|
|
259
268
|
return unless ref?(Base.ref)
|
260
269
|
|
261
270
|
namespace name do
|
262
|
-
|
271
|
+
Base.subtasks do |action, flags|
|
263
272
|
next if @pass.include?(action)
|
264
273
|
|
265
274
|
namespace action do
|
@@ -292,17 +301,21 @@ module Squared
|
|
292
301
|
end
|
293
302
|
end
|
294
303
|
when 'unpack'
|
295
|
-
format_desc(action, flag, 'tag/url,dir,digest?,f
|
304
|
+
format_desc(action, flag, 'tag/url,dir,digest?,f|force?', before: flag == :ext ? 'ext' : nil)
|
296
305
|
params = %i[tag dir digest force]
|
297
306
|
params.unshift(:ext) if flag == :ext
|
298
307
|
task flag, params do |_, args|
|
299
|
-
ext = param_guard(action, flag, args: args, key: :ext)
|
308
|
+
ext = flag == :ext ? param_guard(action, flag, args: args, key: :ext) : flag.to_s
|
300
309
|
tag = param_guard(action, flag, args: args, key: :tag)
|
301
310
|
dir = param_guard(action, flag, args: args, key: :dir)
|
302
311
|
unless tag.match?(URI_SCHEME)
|
303
|
-
|
304
|
-
|
305
|
-
|
312
|
+
if flag == :gem
|
313
|
+
tag = "https://rubygems.org/downloads/#{File.basename(tag, '.gem')}.gem"
|
314
|
+
elsif @release
|
315
|
+
tag = "%s.#{ext}" % [@release.include?('??') ? @release.sub('??', tag) : @release + tag]
|
316
|
+
else
|
317
|
+
raise_error("no base uri: #{tag}", hint: ext)
|
318
|
+
end
|
306
319
|
end
|
307
320
|
case (digest = args.digest)
|
308
321
|
when 'f', 'force'
|
@@ -311,7 +324,7 @@ module Squared
|
|
311
324
|
else
|
312
325
|
force = args.fetch(:force, false)
|
313
326
|
end
|
314
|
-
unpack(basepath(dir), uri: tag, digest: digest, ext: ext
|
327
|
+
unpack(basepath(dir), uri: tag, digest: digest, ext: ext, force: force)
|
315
328
|
end
|
316
329
|
end
|
317
330
|
end
|
@@ -343,15 +356,15 @@ module Squared
|
|
343
356
|
end
|
344
357
|
end
|
345
358
|
if path.is_a?(String) && (seg = path[%r{^(.+)[\\/]\*+$}, 1])
|
346
|
-
return self unless checkdir.(path = basepath(seg))
|
359
|
+
return self unless checkdir.call(path = basepath(seg))
|
347
360
|
|
348
|
-
path = path.children.select { |val| checkdir.(val) }
|
361
|
+
path = path.children.select { |val| checkdir.call(val) }
|
349
362
|
end
|
350
363
|
if path.is_a?(Array)
|
351
364
|
name = @name if name == true
|
352
365
|
path.each { |val| add(val, name && task_join(name, File.basename(val)), **kwargs, &blk) }
|
353
366
|
return self
|
354
|
-
elsif !projectpath?(path = basepath(path)) || !checkdir.(path)
|
367
|
+
elsif !projectpath?(path = basepath(path)) || !checkdir.call(path)
|
355
368
|
return self
|
356
369
|
elsif name.is_a?(Symbol)
|
357
370
|
name = name.to_s
|
@@ -395,12 +408,19 @@ module Squared
|
|
395
408
|
|
396
409
|
run_b(@run, sync: sync, from: from) if series?(@run)
|
397
410
|
args = @output
|
398
|
-
banner =
|
411
|
+
banner = verbosetype > 1 if task_invoked?('build', 'build:sync', 'default')
|
412
|
+
end
|
413
|
+
if args.first.is_a?(Struct)
|
414
|
+
f, blk = args.first.to_a
|
415
|
+
args[0] = instance_eval(&blk) || f
|
416
|
+
return unless args[0]
|
399
417
|
end
|
400
418
|
if args.all? { |val| val.is_a?(Array) }
|
401
419
|
cmd = []
|
402
420
|
var = {}
|
403
421
|
args.each do |val|
|
422
|
+
next instance_exec(*val[1..-1], &val[0]) if val.first.is_a?(Proc)
|
423
|
+
|
404
424
|
a, b, c, d, e = val
|
405
425
|
case b
|
406
426
|
when Hash
|
@@ -450,7 +470,7 @@ module Squared
|
|
450
470
|
end
|
451
471
|
|
452
472
|
def archive(*, sync: invoked_sync?('archive'), **)
|
453
|
-
return unless @archive.is_a?(
|
473
|
+
return unless @archive.is_a?(Hash)
|
454
474
|
|
455
475
|
unpack(path, **@archive, sync: sync, from: :archive)
|
456
476
|
end
|
@@ -471,11 +491,18 @@ module Squared
|
|
471
491
|
run_b(@copy, sync: sync, from: :copy)
|
472
492
|
end
|
473
493
|
|
474
|
-
def clean(
|
494
|
+
def clean(*args, sync: invoked_sync?('clean'), pass: false, **kwargs)
|
475
495
|
return unless @clean
|
476
496
|
|
477
|
-
on :first, :clean
|
497
|
+
on :first, :clean unless pass
|
478
498
|
case @clean
|
499
|
+
when Struct
|
500
|
+
if (any = instance_eval(&@clean.block) || @clean.run)
|
501
|
+
temp = @clean
|
502
|
+
@clean = any
|
503
|
+
clean(*args, sync: sync, pass: true, **kwargs)
|
504
|
+
@clean = temp
|
505
|
+
end
|
479
506
|
when String
|
480
507
|
run_s(@clean, sync: sync)
|
481
508
|
when Hash
|
@@ -488,12 +515,11 @@ module Squared
|
|
488
515
|
end
|
489
516
|
else
|
490
517
|
if @clean.is_a?(Enumerable) && !series?(@clean)
|
491
|
-
|
492
|
-
val = val.to_s
|
493
|
-
path = basepath(val)
|
518
|
+
@clean.each do |val|
|
519
|
+
path = basepath(val = val.to_s)
|
494
520
|
if path.directory? && val.match?(%r{[\\/]$})
|
495
521
|
log&.warn "rm -rf #{path}"
|
496
|
-
|
522
|
+
rm_rf(path, verbose: verbose)
|
497
523
|
else
|
498
524
|
log&.warn "rm #{path}"
|
499
525
|
(val.include?('*') ? Dir[path] : [path]).each do |file|
|
@@ -511,7 +537,7 @@ module Squared
|
|
511
537
|
run_b(@clean, sync: sync)
|
512
538
|
end
|
513
539
|
end
|
514
|
-
on :last, :clean
|
540
|
+
on :last, :clean unless pass
|
515
541
|
end
|
516
542
|
|
517
543
|
def graph(start = [], tasks = nil, sync: invoked_sync?('graph'), pass: [], out: nil)
|
@@ -519,13 +545,13 @@ module Squared
|
|
519
545
|
tasks ||= []
|
520
546
|
split_escape(val).each do |task|
|
521
547
|
if ref?(task.to_sym) && (script = workspace.script_get(:graph, ref: task.to_sym))
|
522
|
-
tasks
|
548
|
+
tasks.concat(script[:graph])
|
523
549
|
else
|
524
550
|
tasks << task
|
525
551
|
end
|
526
552
|
end
|
527
553
|
end
|
528
|
-
pass
|
554
|
+
pass.concat(split_escape(val)) if (val = env('GRAPH', suffix: 'PASS'))
|
529
555
|
start, neg = start.partition { |name| !name.start_with?('-') }
|
530
556
|
data = graph_collect(self, start, pass: neg.map! { |name| name[1..-1] })
|
531
557
|
unless out
|
@@ -554,8 +580,11 @@ module Squared
|
|
554
580
|
elsif !target.empty?
|
555
581
|
raise_error('directory not empty', hint: target) unless force || env('UNPACK_FORCE')
|
556
582
|
create = true
|
583
|
+
elsif !uri
|
584
|
+
raise_error('no download uri', hint: target)
|
557
585
|
end
|
558
586
|
if digest
|
587
|
+
require 'digest'
|
559
588
|
if (n = digest.index(':').to_i) > 0
|
560
589
|
size = digest[0, n].downcase
|
561
590
|
digest = digest[n + 1..-1]
|
@@ -582,11 +611,10 @@ module Squared
|
|
582
611
|
if (val = env('HEADERS')) && (val = parse_json(val, hint: "HEADERS_#{@envname}"))
|
583
612
|
headers = val
|
584
613
|
end
|
585
|
-
require 'open-uri'
|
586
614
|
data = nil
|
587
615
|
(uri = as_a(uri)).each_with_index do |url, index|
|
588
616
|
last = index == uri.size - 1
|
589
|
-
|
617
|
+
fetch_uri(url, headers) do |f|
|
590
618
|
data = f.read
|
591
619
|
if algo && algo.hexdigest(data) != digest
|
592
620
|
data = nil
|
@@ -610,13 +638,19 @@ module Squared
|
|
610
638
|
raise_error('no content', hint: url)
|
611
639
|
end
|
612
640
|
end
|
613
|
-
ext ||= URI.parse(uri).path[
|
614
|
-
|
615
|
-
|
641
|
+
raise_error('no content type', hint: uri) unless ext ||= URI.parse(uri).path[/\.(\w+)(\?|$)/i, 1]
|
642
|
+
ext = ext.downcase
|
643
|
+
if (val = env("#{%w[zip 7z gem].include?(ext) ? ext.upcase : 'TAR'}_DEPTH", ignore: false))
|
644
|
+
depth = val.to_i
|
616
645
|
end
|
617
646
|
begin
|
618
|
-
|
619
|
-
|
647
|
+
if ext == 'gem'
|
648
|
+
dir = Dir.mktmpdir
|
649
|
+
file = File.new(File.join(dir, File.basename(uri)), 'w')
|
650
|
+
else
|
651
|
+
require 'tempfile'
|
652
|
+
file = Tempfile.new("#{name}-")
|
653
|
+
end
|
620
654
|
file.write(data)
|
621
655
|
file.close
|
622
656
|
if create
|
@@ -639,6 +673,9 @@ module Squared
|
|
639
673
|
depth = 0
|
640
674
|
when '7z'
|
641
675
|
session '7z', 'x', shell_quote(file.path), "-o#{shell_quote(target)}"
|
676
|
+
when 'gem'
|
677
|
+
session 'gem', 'unpack', shell_quote(file.path), quote_option('target', target)
|
678
|
+
depth = 0 unless val
|
642
679
|
else
|
643
680
|
raise_error("unsupported format: #{ext}", hint: uri)
|
644
681
|
end
|
@@ -647,7 +684,10 @@ module Squared
|
|
647
684
|
entry = target.children.first
|
648
685
|
break unless entry.directory?
|
649
686
|
|
650
|
-
|
687
|
+
i = 0
|
688
|
+
while (dest = target.join("#{File.basename(file.path)}-#{i}")).exist?
|
689
|
+
i += 1
|
690
|
+
end
|
651
691
|
FileUtils.mv(entry, dest)
|
652
692
|
dest.children.each { |child| FileUtils.mv(child, target) }
|
653
693
|
dest.rmdir
|
@@ -655,7 +695,11 @@ module Squared
|
|
655
695
|
depth -= 1
|
656
696
|
end
|
657
697
|
ensure
|
658
|
-
|
698
|
+
if dir
|
699
|
+
remove_entry dir
|
700
|
+
elsif file
|
701
|
+
file.unlink
|
702
|
+
end
|
659
703
|
end
|
660
704
|
end
|
661
705
|
|
@@ -715,7 +759,7 @@ module Squared
|
|
715
759
|
@parent = val if (val = val.first).is_a?(Project::Base)
|
716
760
|
when :graph
|
717
761
|
@graph = case val.first
|
718
|
-
when
|
762
|
+
when NilClass, FalseClass
|
719
763
|
nil
|
720
764
|
else
|
721
765
|
val.flatten.map!(&:to_s).freeze
|
@@ -918,7 +962,13 @@ module Squared
|
|
918
962
|
|
919
963
|
def run_b(obj, from: nil, sync: true)
|
920
964
|
case obj
|
921
|
-
when
|
965
|
+
when Struct
|
966
|
+
if (any = instance_eval(&obj.block) || obj.run)
|
967
|
+
run_b(any, from: from, sync: sync)
|
968
|
+
end
|
969
|
+
when Proc
|
970
|
+
instance_eval(&obj)
|
971
|
+
when Method
|
922
972
|
obj.call
|
923
973
|
else
|
924
974
|
if series?(obj)
|
@@ -947,14 +997,14 @@ module Squared
|
|
947
997
|
end
|
948
998
|
start = target.name
|
949
999
|
if depth == 0
|
950
|
-
items = check.(dedupe.(start))
|
1000
|
+
items = check.call(dedupe.call(start))
|
951
1001
|
single = items.size == 1
|
952
1002
|
else
|
953
|
-
items = check.(data[start])
|
1003
|
+
items = check.call(data[start])
|
954
1004
|
end
|
955
1005
|
if out
|
956
1006
|
a, b, c, d, e = ARG[:GRAPH]
|
957
|
-
f = tag.(target)
|
1007
|
+
f = tag.call(target)
|
958
1008
|
out << case depth
|
959
1009
|
when 0
|
960
1010
|
f
|
@@ -971,15 +1021,15 @@ module Squared
|
|
971
1021
|
items.each_with_index do |proj, i|
|
972
1022
|
next if done.include?(proj)
|
973
1023
|
|
974
|
-
t = dedupe.(proj.name)
|
1024
|
+
t = dedupe.call(proj.name)
|
975
1025
|
j = if out
|
976
|
-
if i == items.size - 1 || check.(post = items[i + 1..-1]).empty?
|
1026
|
+
if i == items.size - 1 || check.call(post = items[i + 1..-1]).empty?
|
977
1027
|
true
|
978
1028
|
elsif !t.empty? && depth > 0
|
979
1029
|
post.reject { |pr| t.include?(pr) }.empty?
|
980
1030
|
end
|
981
1031
|
end
|
982
|
-
unless start == proj.name || (none = check.(t).empty?)
|
1032
|
+
unless start == proj.name || (none = check.call(t).empty?)
|
983
1033
|
graph_branch(proj, data, tasks, out, sync: sync, pass: pass, done: done, depth: depth.succ,
|
984
1034
|
single: single, last: j == true, context: target)
|
985
1035
|
end
|
@@ -1005,7 +1055,7 @@ module Squared
|
|
1005
1055
|
elsif none
|
1006
1056
|
a, b, c, d = ARG[:GRAPH]
|
1007
1057
|
out << if depth == 0
|
1008
|
-
"#{i == items.size - 1 ? d : c}#{b * 4} #{tag.(proj)}"
|
1058
|
+
"#{i == items.size - 1 ? d : c}#{b * 4} #{tag.call(proj)}"
|
1009
1059
|
else
|
1010
1060
|
s = ''.dup
|
1011
1061
|
k = 0
|
@@ -1015,7 +1065,7 @@ module Squared
|
|
1015
1065
|
s += "#{indent || (last && data[final].last == context) ? ' ' : a} "
|
1016
1066
|
k += 1
|
1017
1067
|
end
|
1018
|
-
s + "#{j ? d : c}#{b * 3} #{tag.(proj)}"
|
1068
|
+
s + "#{j ? d : c}#{b * 3} #{tag.call(proj)}"
|
1019
1069
|
end
|
1020
1070
|
end
|
1021
1071
|
done << proj
|
@@ -1043,7 +1093,7 @@ module Squared
|
|
1043
1093
|
next if (objs = data.fetch(proj.name, [])).include?(target)
|
1044
1094
|
|
1045
1095
|
deps << proj
|
1046
|
-
deps
|
1096
|
+
deps.concat(objs)
|
1047
1097
|
end
|
1048
1098
|
end
|
1049
1099
|
data[target.name] = deps.uniq.reject { |proj| proj == target }
|
@@ -1066,7 +1116,7 @@ module Squared
|
|
1066
1116
|
end
|
1067
1117
|
|
1068
1118
|
def session(*cmd, prefix: cmd.first, main: true, path: true, options: true)
|
1069
|
-
prefix = prefix.to_s.upcase
|
1119
|
+
prefix = stripext(prefix.to_s).upcase
|
1070
1120
|
if path && (val = ENV["PATH_#{prefix}"] || PATH[prefix] || PATH[prefix.to_sym])
|
1071
1121
|
cmd[0] = shell_quote(val, force: false)
|
1072
1122
|
end
|
@@ -1077,9 +1127,9 @@ module Squared
|
|
1077
1127
|
main ? @session = ret : ret
|
1078
1128
|
end
|
1079
1129
|
|
1080
|
-
def session_delete(*
|
1130
|
+
def session_delete(*args, target: @session)
|
1081
1131
|
ret = []
|
1082
|
-
|
1132
|
+
args.each do |val|
|
1083
1133
|
pat = /^#{Regexp.escape(shell_option(val))}(?: |=|$)/
|
1084
1134
|
if (key = target.find { |opt| opt.match?(pat) })
|
1085
1135
|
target.delete(key)
|
@@ -1101,122 +1151,25 @@ module Squared
|
|
1101
1151
|
cmd.done
|
1102
1152
|
end
|
1103
1153
|
|
1104
|
-
def option(*args,
|
1154
|
+
def option(*args, target: @session, prefix: target&.first, **kwargs)
|
1105
1155
|
if prefix
|
1106
|
-
prefix = File.basename(prefix, File.extname(prefix))
|
1107
1156
|
args.each do |val|
|
1108
|
-
ret = env("#{prefix}_#{val.gsub(/\W/, '_')}".upcase, **kwargs)
|
1157
|
+
ret = env("#{stripext(prefix)}_#{val.gsub(/\W/, '_')}".upcase, **kwargs)
|
1109
1158
|
return ret if ret
|
1110
1159
|
end
|
1111
1160
|
end
|
1112
1161
|
nil
|
1113
1162
|
end
|
1114
1163
|
|
1115
|
-
def option_sanitize(opts, list, target: @session,
|
1116
|
-
|
1117
|
-
|
1118
|
-
bare = []
|
1119
|
-
e = []
|
1120
|
-
b = []
|
1121
|
-
m = []
|
1122
|
-
p = []
|
1123
|
-
q = []
|
1124
|
-
qq = []
|
1125
|
-
i = []
|
1126
|
-
f = []
|
1127
|
-
si = []
|
1128
|
-
list.map do |val|
|
1129
|
-
x, y = val.split('|')
|
1130
|
-
if y
|
1131
|
-
if (n = val.index('='))
|
1132
|
-
x += val[n..-1]
|
1133
|
-
end
|
1134
|
-
[x, y]
|
1135
|
-
else
|
1136
|
-
x
|
1137
|
-
end
|
1138
|
-
end
|
1139
|
-
.flatten
|
1140
|
-
.each do |val|
|
1141
|
-
if (n = val.index('='))
|
1142
|
-
flag = val[0, n]
|
1143
|
-
case val[n + 1]
|
1144
|
-
when 'e'
|
1145
|
-
e << flag
|
1146
|
-
when 'b'
|
1147
|
-
b << flag
|
1148
|
-
when 'm'
|
1149
|
-
m << flag
|
1150
|
-
when 'q'
|
1151
|
-
qq << flag if val[n + 2] == 'q'
|
1152
|
-
q << flag
|
1153
|
-
when 'p'
|
1154
|
-
p << flag
|
1155
|
-
when 'i'
|
1156
|
-
i << flag
|
1157
|
-
when 'f'
|
1158
|
-
f << flag
|
1159
|
-
when 'n'
|
1160
|
-
si << flag
|
1161
|
-
else
|
1162
|
-
reg << Regexp.escape(flag)
|
1163
|
-
end
|
1164
|
-
bare << flag if val.end_with?('?')
|
1165
|
-
else
|
1166
|
-
bare << val
|
1167
|
-
end
|
1168
|
-
end
|
1169
|
-
no = (no || []).map { |val| (n = val.index('=')) ? val[0, n] : val }
|
1170
|
-
bare += no
|
1171
|
-
found = false
|
1172
|
-
opts.each do |opt|
|
1173
|
-
next ret << opt if found
|
1174
|
-
|
1175
|
-
if single&.match?(opt)
|
1176
|
-
target << "-#{opt}"
|
1177
|
-
elsif bare.include?(opt)
|
1178
|
-
target << (opt.size == 1 ? "-#{opt}" : "--#{opt}")
|
1179
|
-
elsif opt.start_with?('no-') && no.include?(name = opt[3..-1])
|
1180
|
-
target << "--no-#{name}"
|
1181
|
-
else
|
1182
|
-
if opt =~ /\A([^=]+)=(.+)\z/
|
1183
|
-
key = $1
|
1184
|
-
val = $2
|
1185
|
-
match = ->(flag, pat) { flag.include?(key) && pat.match?(val) }
|
1186
|
-
if e.include?(key)
|
1187
|
-
target << shell_option(key, val)
|
1188
|
-
elsif q.include?(key)
|
1189
|
-
target << quote_option(key, val, double: qq.include?(key))
|
1190
|
-
elsif p.include?(key)
|
1191
|
-
target << quote_option(key, basepath(val))
|
1192
|
-
elsif m.include?(key)
|
1193
|
-
target << basic_option(key, val, merge: true)
|
1194
|
-
elsif b.include?(key) || match.(i, /^\d+$/) || match.(f, /^\d*(?:\.\d+)?$/) || match.(si, /^-?\d+$/)
|
1195
|
-
target << basic_option(key, val)
|
1196
|
-
else
|
1197
|
-
ret << opt
|
1198
|
-
end
|
1199
|
-
opt = key
|
1200
|
-
else
|
1201
|
-
ret << opt
|
1202
|
-
found = true if args
|
1203
|
-
end
|
1204
|
-
found = true if first && pass.none? { |s| opt.include?(s) }
|
1205
|
-
end
|
1206
|
-
end
|
1207
|
-
[ret, reg.empty? ? /\A\s+\z/ : /^(#{reg.join('|')})=(.+)$/]
|
1164
|
+
def option_sanitize(opts, list, target: @session, **kwargs)
|
1165
|
+
op = OptionPartition.new(opts, list, target, project: self, **kwargs)
|
1166
|
+
[op.extras, op.values]
|
1208
1167
|
end
|
1209
1168
|
|
1210
|
-
def option_clear(opts, target: @session,
|
1211
|
-
return
|
1212
|
-
|
1213
|
-
kwargs[:subject] ||= target&.first
|
1214
|
-
kwargs[:hint] ||= 'unrecognized'
|
1215
|
-
warn log_message(Logger::WARN, opts.join(', '), pass: true, **kwargs)
|
1216
|
-
append_value(opts, delim: true) if append
|
1217
|
-
return if pass || confirm("Run? [#{sub_style(target, styles: theme[:inline])}] [y/N] ", 'N', timeout: 30)
|
1169
|
+
def option_clear(opts, target: @session, **kwargs)
|
1170
|
+
return unless target
|
1218
1171
|
|
1219
|
-
|
1172
|
+
OptionPartition.clear(target, opts, styles: theme[:inline], **kwargs)
|
1220
1173
|
end
|
1221
1174
|
|
1222
1175
|
def print_item(*val)
|
@@ -1263,7 +1216,7 @@ module Squared
|
|
1263
1216
|
end
|
1264
1217
|
|
1265
1218
|
def format_desc(action, flag, opts = nil, **kwargs)
|
1266
|
-
return unless
|
1219
|
+
return unless TASK_METADATA
|
1267
1220
|
|
1268
1221
|
ret = [@desc, action]
|
1269
1222
|
ret << flag if flag
|
@@ -1323,7 +1276,7 @@ module Squared
|
|
1323
1276
|
items.each_with_index do |val, i|
|
1324
1277
|
next unless reg.empty? || reg.any? { |pat| val[0].match?(pat) }
|
1325
1278
|
|
1326
|
-
out << "#{i.succ.to_s.rjust(pad)}. #{each ? each.(val) : val[0]}"
|
1279
|
+
out << "#{i.succ.to_s.rjust(pad)}. #{each ? each.call(val) : val[0]}"
|
1327
1280
|
end
|
1328
1281
|
end
|
1329
1282
|
sub = [headerstyle]
|
@@ -1331,7 +1284,7 @@ module Squared
|
|
1331
1284
|
out = ["No #{type} were found:", '']
|
1332
1285
|
unless grep.empty?
|
1333
1286
|
i = 0
|
1334
|
-
out
|
1287
|
+
out.concat(grep.map { |s| "#{i += 1}. #{s}" })
|
1335
1288
|
out << ''
|
1336
1289
|
end
|
1337
1290
|
if from
|
@@ -1358,7 +1311,6 @@ module Squared
|
|
1358
1311
|
end
|
1359
1312
|
|
1360
1313
|
def append_hash(data, target: @session, build: false)
|
1361
|
-
target ||= []
|
1362
1314
|
if build && (type = env('BUILD', suffix: 'TYPE') || ENV['BUILD_TYPE'])
|
1363
1315
|
type = "__#{type}__"
|
1364
1316
|
if (extra = data[type] || data[type.to_sym]).is_a?(Hash)
|
@@ -1379,7 +1331,7 @@ module Squared
|
|
1379
1331
|
append_repeat(key, val, target: target)
|
1380
1332
|
when Numeric
|
1381
1333
|
target << basic_option(key, val)
|
1382
|
-
when
|
1334
|
+
when FalseClass
|
1383
1335
|
target << shell_option(key).sub(/^--(?!no-)/, '--no-')
|
1384
1336
|
else
|
1385
1337
|
target << shell_option(key, val.is_a?(String) ? val : nil)
|
@@ -1411,22 +1363,17 @@ module Squared
|
|
1411
1363
|
end
|
1412
1364
|
end
|
1413
1365
|
|
1414
|
-
def append_value(*list, target: @session,
|
1415
|
-
return
|
1366
|
+
def append_value(*list, target: @session, **kwargs)
|
1367
|
+
return unless target
|
1416
1368
|
|
1417
|
-
target
|
1418
|
-
list.map! do |val|
|
1419
|
-
ret = escape ? shell_escape(val, quote: quote) : shell_quote(val)
|
1420
|
-
target << ret
|
1421
|
-
ret
|
1422
|
-
end
|
1369
|
+
OptionPartition.append(target, *list, **kwargs)
|
1423
1370
|
end
|
1424
1371
|
|
1425
1372
|
def append_first(*list, target: @session, flag: true, equals: false, escape: true, quote: true, force: true,
|
1426
1373
|
**kwargs)
|
1427
|
-
return if
|
1374
|
+
return if list.empty?
|
1428
1375
|
|
1429
|
-
list.each do |opt|
|
1376
|
+
list.flatten.each do |opt|
|
1430
1377
|
next unless (val = option(opt, **kwargs))
|
1431
1378
|
|
1432
1379
|
return target << (if flag
|
@@ -1440,11 +1387,11 @@ module Squared
|
|
1440
1387
|
|
1441
1388
|
def append_option(*list, target: @session, no: false, equals: false, escape: true, quote: true, force: true,
|
1442
1389
|
**kwargs)
|
1443
|
-
return if
|
1390
|
+
return if list.empty?
|
1444
1391
|
|
1445
1392
|
ret = []
|
1446
|
-
list.each do |flag|
|
1447
|
-
next unless (val = option(flag, **kwargs))
|
1393
|
+
list.flatten.each do |flag|
|
1394
|
+
next unless (val = option(flag, target: target, **kwargs))
|
1448
1395
|
|
1449
1396
|
if val == '0' && no
|
1450
1397
|
flag = "no-#{flag}"
|
@@ -1456,50 +1403,52 @@ module Squared
|
|
1456
1403
|
end
|
1457
1404
|
|
1458
1405
|
def append_nocolor(target: @session)
|
1459
|
-
target << '--no-color' if !ARG[:COLOR] || stdin? || option('
|
1406
|
+
target << '--no-color' if !ARG[:COLOR] || stdin? || option('color', target: target, equals: '0')
|
1460
1407
|
end
|
1461
1408
|
|
1462
1409
|
def merge_opts(base, data)
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1466
|
-
|
1467
|
-
|
1468
|
-
|
1469
|
-
|
1470
|
-
|
1471
|
-
|
1472
|
-
|
1473
|
-
|
1474
|
-
|
1475
|
-
|
1476
|
-
|
1477
|
-
|
1478
|
-
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1483
|
-
|
1484
|
-
|
1485
|
-
|
1486
|
-
|
1487
|
-
|
1488
|
-
|
1489
|
-
|
1490
|
-
|
1491
|
-
|
1492
|
-
|
1493
|
-
|
1494
|
-
|
1495
|
-
|
1496
|
-
|
1497
|
-
|
1410
|
+
case data
|
1411
|
+
when String
|
1412
|
+
case base
|
1413
|
+
when String
|
1414
|
+
"#{base} #{data}"
|
1415
|
+
when Hash
|
1416
|
+
"#{append_hash(base).join(' ')} #{data}"
|
1417
|
+
when Enumerable
|
1418
|
+
"#{base.to_a.join(' ')} #{data}"
|
1419
|
+
else
|
1420
|
+
data
|
1421
|
+
end
|
1422
|
+
when Hash
|
1423
|
+
case base
|
1424
|
+
when String
|
1425
|
+
"#{base} #{append_hash(data).join(' ')}"
|
1426
|
+
when Hash
|
1427
|
+
base.merge(data)
|
1428
|
+
when Enumerable
|
1429
|
+
Set.new(base.to_a + append_hash(data)).to_a
|
1430
|
+
else
|
1431
|
+
data
|
1432
|
+
end
|
1433
|
+
when Enumerable
|
1434
|
+
case base
|
1435
|
+
when String
|
1436
|
+
"#{base} #{data.to_a.join(' ')}"
|
1437
|
+
when Hash
|
1438
|
+
"#{append_hash(base).join(' ')} #{data.to_a.join(' ')}"
|
1439
|
+
when Enumerable
|
1440
|
+
Set.new(base.to_a + data.to_a).to_a
|
1441
|
+
else
|
1442
|
+
data
|
1443
|
+
end
|
1444
|
+
else
|
1445
|
+
base
|
1446
|
+
end
|
1498
1447
|
end
|
1499
1448
|
|
1500
1449
|
def collect_hash(data, pass: [])
|
1501
1450
|
ret = []
|
1502
|
-
data.each { |key, val| ret
|
1451
|
+
data.each { |key, val| ret.concat(val) unless pass.include?(key) }
|
1503
1452
|
ret
|
1504
1453
|
end
|
1505
1454
|
|
@@ -1513,6 +1462,15 @@ module Squared
|
|
1513
1462
|
ret
|
1514
1463
|
end
|
1515
1464
|
|
1465
|
+
def fetch_uri(*args, **kwargs, &blk)
|
1466
|
+
require 'open-uri'
|
1467
|
+
if RUBY_VERSION < '2.5'
|
1468
|
+
open(*args, **kwargs, &blk)
|
1469
|
+
else
|
1470
|
+
URI.open(*args, **kwargs, &blk)
|
1471
|
+
end
|
1472
|
+
end
|
1473
|
+
|
1516
1474
|
def param_guard(action, flag, args: nil, key: nil, pat: nil, values: nil)
|
1517
1475
|
if args && key
|
1518
1476
|
val = args.fetch(key, nil)
|
@@ -1527,6 +1485,39 @@ module Squared
|
|
1527
1485
|
args
|
1528
1486
|
end
|
1529
1487
|
|
1488
|
+
def confirm_outdated(pkg, ver, rev, lock: false)
|
1489
|
+
a = sub_style(case rev
|
1490
|
+
when 1
|
1491
|
+
'MAJOR'
|
1492
|
+
when 2
|
1493
|
+
'MINOR'
|
1494
|
+
else
|
1495
|
+
'PATCH'
|
1496
|
+
end, styles: theme[:header])
|
1497
|
+
b = sub_style("#{pkg} #{ver}", styles: theme[:inline])
|
1498
|
+
c, d = rev == 1 || lock ? ['y/N', 'N'] : ['Y/n', 'Y']
|
1499
|
+
e = lock ? " #{sub_style('(locked)', styles: color(:red))}" : ''
|
1500
|
+
confirm("Upgrade to #{a}? #{b + e} [#{c}] ", d, timeout: 60)
|
1501
|
+
end
|
1502
|
+
|
1503
|
+
def choice_index(msg, list, values: nil, multiple: false, accept: nil, trim: nil)
|
1504
|
+
puts if @@print_order > 0
|
1505
|
+
raise_error 'user cancelled' unless (ret = choice(msg, list, multiple: multiple))
|
1506
|
+
ret = multiple ? ret.map! { |val| val.sub(trim, '') } : ret.sub(trim, '') if trim
|
1507
|
+
exit 1 if accept && !confirm("#{accept} [#{ret.join(', ')}] [y/N] ", 'N', timeout: 60)
|
1508
|
+
if values
|
1509
|
+
ret = [ret]
|
1510
|
+
values.each do |val|
|
1511
|
+
val, req = val if val.is_a?(Array)
|
1512
|
+
val = Readline.readline("#{val} (#{req ? 'required' : 'optional'}): ", true).strip
|
1513
|
+
raise_error 'user cancelled' if req && val.empty?
|
1514
|
+
ret << (val.empty? ? nil : val)
|
1515
|
+
end
|
1516
|
+
end
|
1517
|
+
@@print_order += 1
|
1518
|
+
ret
|
1519
|
+
end
|
1520
|
+
|
1530
1521
|
def runenv
|
1531
1522
|
nil
|
1532
1523
|
end
|
@@ -1539,12 +1530,11 @@ module Squared
|
|
1539
1530
|
end
|
1540
1531
|
end
|
1541
1532
|
|
1542
|
-
def relativepath(*
|
1543
|
-
return [] if
|
1533
|
+
def relativepath(*list, all: false)
|
1534
|
+
return [] if list.empty?
|
1544
1535
|
|
1545
|
-
|
1546
|
-
|
1547
|
-
val = val.absolute? ? val.to_s.sub(pat, '') : val.to_s
|
1536
|
+
list.flatten.map! { |val| Pathname.new(val) }.select { |val| projectpath?(val) }.map! do |val|
|
1537
|
+
val = val.absolute? ? val.relative_path_from(path).to_s : val.to_s
|
1548
1538
|
val = val[2..-1] if val.start_with?('./')
|
1549
1539
|
val = "#{val}*" if all && val.end_with?('/')
|
1550
1540
|
val
|
@@ -1553,11 +1543,11 @@ module Squared
|
|
1553
1543
|
|
1554
1544
|
def projectmap(files, parent: false, pass: true)
|
1555
1545
|
unless parent
|
1556
|
-
|
1557
|
-
raise_error 'pathspec not within worktree' unless pass || files.size ==
|
1558
|
-
files =
|
1546
|
+
proj = files.select { |val| projectpath?(val) }
|
1547
|
+
raise_error 'pathspec not within worktree' unless pass || files.size == proj.size
|
1548
|
+
files = proj
|
1559
1549
|
end
|
1560
|
-
files.map { |val| val == '.' ? '.' : shell_quote(basepath(val
|
1550
|
+
files.map { |val| val == '.' ? '.' : shell_quote(basepath(val)) }
|
1561
1551
|
end
|
1562
1552
|
|
1563
1553
|
def semver(val)
|
@@ -1597,7 +1587,18 @@ module Squared
|
|
1597
1587
|
end
|
1598
1588
|
|
1599
1589
|
def epochtime
|
1600
|
-
|
1590
|
+
Time.now.strftime('%s%L').to_i
|
1591
|
+
end
|
1592
|
+
|
1593
|
+
def verbosetype
|
1594
|
+
case verbose
|
1595
|
+
when TrueClasss
|
1596
|
+
1
|
1597
|
+
when Numeric
|
1598
|
+
verbose.succ
|
1599
|
+
else
|
1600
|
+
0
|
1601
|
+
end
|
1601
1602
|
end
|
1602
1603
|
|
1603
1604
|
def on(event, from, *args, **kwargs)
|
@@ -1622,15 +1623,15 @@ module Squared
|
|
1622
1623
|
end
|
1623
1624
|
end
|
1624
1625
|
|
1625
|
-
def pwd_set(done = nil, pass: false, from: nil, dryrun: false
|
1626
|
+
def pwd_set(done = nil, pass: false, from: nil, dryrun: false)
|
1626
1627
|
pwd = Pathname.pwd
|
1627
1628
|
if block_given?
|
1628
1629
|
begin
|
1629
1630
|
if path == pwd || pass == true || (pass.is_a?(String) && semscan(pass).join >= RUBY_VERSION)
|
1630
|
-
ret =
|
1631
|
+
ret = yield
|
1631
1632
|
else
|
1632
1633
|
Dir.chdir(path)
|
1633
|
-
ret =
|
1634
|
+
ret = yield
|
1634
1635
|
Dir.chdir(pwd)
|
1635
1636
|
end
|
1636
1637
|
rescue StandardError => e
|
@@ -1681,13 +1682,13 @@ module Squared
|
|
1681
1682
|
@output = if cmd.all? { |data| data.is_a?(Hash) }
|
1682
1683
|
diso = false
|
1683
1684
|
dise = false
|
1684
|
-
cmd.map { |data| parse.(data) }
|
1685
|
+
cmd.map { |data| parse.call(data) }
|
1685
1686
|
else
|
1686
1687
|
cmd.dup
|
1687
1688
|
end
|
1688
1689
|
return
|
1689
1690
|
when Hash
|
1690
|
-
@output = parse.(data)
|
1691
|
+
@output = parse.call(data)
|
1691
1692
|
else
|
1692
1693
|
@output[0] = cmd
|
1693
1694
|
end
|
@@ -1747,7 +1748,8 @@ module Squared
|
|
1747
1748
|
end
|
1748
1749
|
|
1749
1750
|
def projectpath?(val)
|
1750
|
-
Pathname.new(val).
|
1751
|
+
val = Pathname.new(val).cleanpath
|
1752
|
+
val.absolute? ? val.to_s.start_with?(File.join(path, '')) : !val.to_s.start_with?(File.join('..', ''))
|
1751
1753
|
end
|
1752
1754
|
|
1753
1755
|
def semmajor?(cur, want)
|
@@ -1767,11 +1769,8 @@ module Squared
|
|
1767
1769
|
val.is_a?(Array) && val.all? { |p| p.is_a?(Proc) || p.is_a?(Method) }
|
1768
1770
|
end
|
1769
1771
|
|
1770
|
-
def session_arg?(*
|
1771
|
-
|
1772
|
-
pat = /^#{Regexp.escape(shell_option(val))}#{value ? '[ =].' : '(?:[ =]|$)'}/
|
1773
|
-
target.any? { |opt| opt.match?(pat) }
|
1774
|
-
end
|
1772
|
+
def session_arg?(*args, target: @session, **kwargs)
|
1773
|
+
!!target && OptionPartition.arg?(target, *args, **kwargs)
|
1775
1774
|
end
|
1776
1775
|
|
1777
1776
|
def from_sync?(*val)
|