squared 0.3.5 → 0.4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +53 -2
- data/README.md +13 -2
- data/README.ruby.md +168 -88
- data/lib/squared/app.rb +1 -0
- data/lib/squared/common/base.rb +6 -1
- data/lib/squared/common/class.rb +1 -1
- data/lib/squared/common/format.rb +24 -12
- data/lib/squared/common/prompt.rb +2 -2
- data/lib/squared/common/shell.rb +52 -39
- data/lib/squared/common/utils.rb +54 -1
- data/lib/squared/config.rb +1 -1
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +16 -13
- data/lib/squared/workspace/project/base.rb +429 -123
- data/lib/squared/workspace/project/docker.rb +572 -0
- data/lib/squared/workspace/project/git.rb +405 -157
- data/lib/squared/workspace/project/node.rb +51 -51
- data/lib/squared/workspace/project/python.rb +115 -24
- data/lib/squared/workspace/project/ruby.rb +33 -34
- data/lib/squared/workspace/project.rb +7 -1
- data/lib/squared/workspace/repo.rb +9 -4
- data/lib/squared/workspace/series.rb +1 -1
- metadata +2 -1
@@ -15,8 +15,10 @@ module Squared
|
|
15
15
|
include Rake::DSL
|
16
16
|
|
17
17
|
VAR_SET = %i[parent global envname dependfile theme run script env pass].freeze
|
18
|
+
BLK_SET = %i[run depend doc lint test copy clean].freeze
|
18
19
|
SEM_VER = /\b(\d+)(?:(\.)(\d+))?(?:(\.)(\d+)(\S+)?)?\b/.freeze
|
19
|
-
|
20
|
+
URI_SCHEME = %r{^([a-z][a-z\d+-.]*)://[^@:\[\]\\^<>|\s]}i.freeze
|
21
|
+
private_constant :VAR_SET, :BLK_SET, :SEM_VER, :URI_SCHEME
|
20
22
|
|
21
23
|
class << self
|
22
24
|
def populate(*); end
|
@@ -25,7 +27,7 @@ module Squared
|
|
25
27
|
def bannerargs(*); end
|
26
28
|
|
27
29
|
def tasks
|
28
|
-
%i[build
|
30
|
+
(%i[build archive graph] + BLK_SET).freeze
|
29
31
|
end
|
30
32
|
|
31
33
|
def as_path(val)
|
@@ -51,7 +53,8 @@ module Squared
|
|
51
53
|
end
|
52
54
|
|
53
55
|
(@@tasks = {})[ref] = {
|
54
|
-
'graph' => %i[run print].freeze
|
56
|
+
'graph' => %i[run print].freeze,
|
57
|
+
'unpack' => %i[zip tar tgz tar.gz txz tar.xz].freeze
|
55
58
|
}.freeze
|
56
59
|
@@task_desc = Rake::TaskManager.record_task_metadata
|
57
60
|
@@print_order = 0
|
@@ -59,8 +62,8 @@ module Squared
|
|
59
62
|
attr_reader :name, :project, :workspace, :path, :theme, :exception, :pipe, :verbose,
|
60
63
|
:group, :parent, :dependfile
|
61
64
|
|
62
|
-
def initialize(workspace, path, name, *, group: nil, graph: nil, pass: nil, exclude: nil,
|
63
|
-
first: {}, last: {}, error: {}, common: ARG[:COMMON], **kwargs)
|
65
|
+
def initialize(workspace, path, name, *, group: nil, graph: nil, pass: nil, exclude: nil, release: nil,
|
66
|
+
archive: nil, first: {}, last: {}, error: {}, common: ARG[:COMMON], **kwargs)
|
64
67
|
@path = path
|
65
68
|
@workspace = workspace
|
66
69
|
@name = name.to_s.freeze
|
@@ -73,6 +76,13 @@ module Squared
|
|
73
76
|
@copy = kwargs[:copy]
|
74
77
|
@clean = kwargs[:clean]
|
75
78
|
@version = kwargs[:version]
|
79
|
+
@archive = case archive
|
80
|
+
when String, Array
|
81
|
+
{ uri: archive }
|
82
|
+
when Hash
|
83
|
+
archive
|
84
|
+
end
|
85
|
+
@release = release
|
76
86
|
@envname = @name.gsub(/[^\w]+/, '_').upcase.freeze
|
77
87
|
@exception = env_bool(kwargs[:exception], workspace.exception, strict: true)
|
78
88
|
@pipe = env_pipe(kwargs[:pipe], workspace.pipe, strict: true)
|
@@ -108,7 +118,7 @@ module Squared
|
|
108
118
|
@parent = nil
|
109
119
|
@global = false
|
110
120
|
run_set(kwargs[:run], kwargs[:env], opts: kwargs.fetch(:opts, true))
|
111
|
-
initialize_ref
|
121
|
+
initialize_ref Base.ref
|
112
122
|
end
|
113
123
|
|
114
124
|
def initialize_ref(ref)
|
@@ -116,7 +126,7 @@ module Squared
|
|
116
126
|
end
|
117
127
|
|
118
128
|
def initialize_build(ref, **kwargs)
|
119
|
-
initialize_ref
|
129
|
+
initialize_ref ref
|
120
130
|
if (@script = @workspace.script_get(group: @group, ref: ref))
|
121
131
|
if @script[:log] && !kwargs.key?(:log)
|
122
132
|
kwargs[:log] = @script[:log]
|
@@ -166,7 +176,9 @@ module Squared
|
|
166
176
|
def initialize_events(ref, **)
|
167
177
|
return unless (events = @workspace.events_get(group: @group, ref: ref))
|
168
178
|
|
169
|
-
events.each
|
179
|
+
events.each do |task, data|
|
180
|
+
data.each { |ev, blk| (@events[ev] ||= {})[task] ||= [blk] }
|
181
|
+
end
|
170
182
|
end
|
171
183
|
|
172
184
|
def initialize_logger(log: nil, **)
|
@@ -192,12 +204,12 @@ module Squared
|
|
192
204
|
raise if @exception
|
193
205
|
|
194
206
|
file = nil
|
195
|
-
warn log_message(Logger::WARN, e) if warning?
|
207
|
+
warn log_message(Logger::WARN, e, pass: true) if warning?
|
196
208
|
end
|
197
209
|
end
|
198
210
|
log[:progname] ||= @name
|
199
211
|
if (val = env('LOG_LEVEL', ignore: false))
|
200
|
-
log[:level] = val
|
212
|
+
log[:level] = val.match?(/^\d$/) ? log_sym(val.to_i) : val
|
201
213
|
end
|
202
214
|
log.delete(:file)
|
203
215
|
@log = [file, log]
|
@@ -206,20 +218,18 @@ module Squared
|
|
206
218
|
def initialize_env(dev: nil, prod: nil, **)
|
207
219
|
@dev = env_match('BUILD', dev, suffix: 'DEV', strict: true)
|
208
220
|
@prod = env_match('BUILD', prod, suffix: 'PROD', strict: true)
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
221
|
+
unless @output[2] == false || !(val = env('BUILD', suffix: 'ENV'))
|
222
|
+
data = parse_json(val, hint: "BUILD_#{@envname}_ENV")
|
223
|
+
@output[2] = data if data
|
224
|
+
end
|
225
|
+
unless @output[0] == false || @output[0].is_a?(Array)
|
226
|
+
if (val = env('BUILD', suffix: 'OPTS'))
|
227
|
+
n = @output[0] ? 1 : 3
|
228
|
+
@output[n] = merge_opts(@output[n], shell_split(val, escape: false))
|
229
|
+
end
|
230
|
+
if (val = env(ref.to_s.upcase, suffix: 'OPTS'))
|
231
|
+
@output[4] = merge_opts(@output[4], shell_split(val, escape: false))
|
218
232
|
end
|
219
|
-
end
|
220
|
-
if cmd != false && !cmd.is_a?(Array)
|
221
|
-
@output[cmd ? 1 : 3] = shell_split(val, escape: false, join: true) if (val = env('BUILD', suffix: 'OPTS'))
|
222
|
-
@output[4] = shell_split(val, escape: false, join: true) if !cmd && (val = env('SCRIPT', suffix: 'OPTS'))
|
223
233
|
end
|
224
234
|
@version = val if (val = env('BUILD', suffix: 'VERSION'))
|
225
235
|
return unless (val = env('BUILD', strict: true))
|
@@ -261,7 +271,7 @@ module Squared
|
|
261
271
|
out, done = graph(args, out: [])
|
262
272
|
out.map! do |val|
|
263
273
|
done.each_with_index do |proj, i|
|
264
|
-
next unless val
|
274
|
+
next unless val.match?(/ #{Regexp.escape(proj.name)}(?:@\d|\z)/)
|
265
275
|
|
266
276
|
val += " (#{i.succ})"
|
267
277
|
break
|
@@ -275,6 +285,25 @@ module Squared
|
|
275
285
|
])
|
276
286
|
end
|
277
287
|
end
|
288
|
+
when 'unpack'
|
289
|
+
format_desc action, flag, 'tag/url,dir,digest?,f/force?'
|
290
|
+
task flag, [:tag, :dir, :digest, :force] do |_, args|
|
291
|
+
tag = param_guard(action, flag, args: args, key: :tag)
|
292
|
+
dir = param_guard(action, flag, args: args, key: :dir)
|
293
|
+
unless tag.match?(URI_SCHEME)
|
294
|
+
raise_error 'no base uri' unless @release
|
295
|
+
|
296
|
+
tag = "#{@release.include?('??') ? @release.sub('??', tag) : @release + tag}.#{flag}"
|
297
|
+
end
|
298
|
+
case (digest = args.digest)
|
299
|
+
when 'f', 'force'
|
300
|
+
digest = nil
|
301
|
+
force = true
|
302
|
+
else
|
303
|
+
force = args.fetch(:force, false)
|
304
|
+
end
|
305
|
+
unpack(basepath(dir), uri: tag, digest: digest, ext: flag.to_s, force: force)
|
306
|
+
end
|
278
307
|
end
|
279
308
|
end
|
280
309
|
end
|
@@ -343,18 +372,19 @@ module Squared
|
|
343
372
|
|
344
373
|
out = obj.link(self, *args, **kwargs, &blk) if obj.respond_to?(:link)
|
345
374
|
if !out
|
346
|
-
warn log_message(Logger::WARN, 'link not compatible', subject: obj.to_s, hint: name)
|
375
|
+
warn log_message(Logger::WARN, 'link not compatible', subject: obj.to_s, hint: name, pass: true)
|
347
376
|
elsif out.respond_to?(:build)
|
348
377
|
out.build
|
349
378
|
end
|
350
379
|
self
|
351
380
|
end
|
352
381
|
|
353
|
-
def build(*args, sync: invoked_sync?('build'), from: :
|
382
|
+
def build(*args, sync: invoked_sync?('build'), from: @buildtype || :build, **)
|
354
383
|
banner = verbose
|
355
384
|
if args.empty?
|
356
|
-
return unless from == :
|
385
|
+
return unless from == (@buildtype || :build)
|
357
386
|
|
387
|
+
run_b(@run, sync: sync, from: from) if series?(@run)
|
358
388
|
args = @output
|
359
389
|
banner = verbose == 1 if task_invoked?('build', 'build:sync')
|
360
390
|
end
|
@@ -365,7 +395,7 @@ module Squared
|
|
365
395
|
a, b, c, d, e = val
|
366
396
|
case b
|
367
397
|
when Hash
|
368
|
-
b = append_hash(b).join(' ')
|
398
|
+
b = append_hash(b, build: true).join(' ')
|
369
399
|
when Enumerable
|
370
400
|
b = b.to_a.join(' ')
|
371
401
|
end
|
@@ -381,7 +411,7 @@ module Squared
|
|
381
411
|
end
|
382
412
|
cmd = cmd.join(' && ')
|
383
413
|
else
|
384
|
-
cmd, opts, var, flags,
|
414
|
+
cmd, opts, var, flags, extra = args
|
385
415
|
end
|
386
416
|
if cmd
|
387
417
|
cmd = as_get(cmd)
|
@@ -389,7 +419,7 @@ module Squared
|
|
389
419
|
flags = append_hash(flags).join(' ') if flags.is_a?(Hash)
|
390
420
|
case opts
|
391
421
|
when Hash
|
392
|
-
opts = append_hash(opts)
|
422
|
+
opts = append_hash(opts, build: true)
|
393
423
|
cmd = as_a(cmd).push(flags).concat(opts).compact.join(' ')
|
394
424
|
when Enumerable
|
395
425
|
cmd = as_a(cmd).concat(opts.to_a)
|
@@ -399,9 +429,9 @@ module Squared
|
|
399
429
|
cmd = [cmd, flags, opts].compact.join(' ') if opts || flags
|
400
430
|
end
|
401
431
|
else
|
402
|
-
return unless respond_to?(:compose)
|
432
|
+
return unless (opts || extra) && respond_to?(:compose)
|
403
433
|
|
404
|
-
cmd = compose(as_get(opts), flags, script: true, args:
|
434
|
+
cmd = compose(as_get(opts), flags, script: true, args: extra, from: from)
|
405
435
|
end
|
406
436
|
run(cmd, var, from: from, banner: banner, sync: sync)
|
407
437
|
end
|
@@ -410,6 +440,12 @@ module Squared
|
|
410
440
|
run_b(@depend, sync: sync, from: :depend)
|
411
441
|
end
|
412
442
|
|
443
|
+
def archive(*, sync: invoked_sync?('archive'), **)
|
444
|
+
return unless @archive.is_a?(Array)
|
445
|
+
|
446
|
+
unpack(path, **@archive, sync: sync, from: :archive)
|
447
|
+
end
|
448
|
+
|
413
449
|
def doc(*, sync: invoked_sync?('doc'), **)
|
414
450
|
run_b(@doc, sync: sync, from: :doc)
|
415
451
|
end
|
@@ -439,27 +475,31 @@ module Squared
|
|
439
475
|
rescue StandardError => e
|
440
476
|
log&.error e
|
441
477
|
ret = on(:error, from, e)
|
442
|
-
raise if
|
478
|
+
raise if exception && ret != true
|
443
479
|
end
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
480
|
+
else
|
481
|
+
if @clean.is_a?(Enumerable) && !series?(@clean)
|
482
|
+
as_a(@clean).each do |val|
|
483
|
+
val = val.to_s
|
484
|
+
path = basepath(val)
|
485
|
+
if path.directory? && val.match?(%r{[\\/]$})
|
486
|
+
log&.warn "rm -rf #{path}"
|
487
|
+
path.rmtree(verbose: verbose)
|
488
|
+
else
|
489
|
+
log&.warn "rm #{path}"
|
490
|
+
(val.include?('*') ? Dir[path] : [path]).each do |file|
|
491
|
+
next unless File.file?(file)
|
492
|
+
|
493
|
+
begin
|
494
|
+
File.delete(file)
|
495
|
+
rescue StandardError => e
|
496
|
+
log&.error e
|
497
|
+
end
|
460
498
|
end
|
461
499
|
end
|
462
500
|
end
|
501
|
+
else
|
502
|
+
run_b(@clean, sync: sync)
|
463
503
|
end
|
464
504
|
end
|
465
505
|
on :last, :clean
|
@@ -496,6 +536,119 @@ module Squared
|
|
496
536
|
end
|
497
537
|
end
|
498
538
|
|
539
|
+
def unpack(target, sync: true, uri: nil, digest: nil, ext: nil, force: false, depth: 1, headers: {},
|
540
|
+
from: :unpack)
|
541
|
+
if !target.exist?
|
542
|
+
target.mkpath
|
543
|
+
elsif !target.directory?
|
544
|
+
raise_error('invalid location', hint: target)
|
545
|
+
elsif !target.empty?
|
546
|
+
raise_error('directory not empty', hint: target) unless force || env('UNPACK_FORCE')
|
547
|
+
create = true
|
548
|
+
end
|
549
|
+
if digest
|
550
|
+
if (n = digest.index(':').to_i) > 0
|
551
|
+
size = digest[0, n].downcase
|
552
|
+
digest = digest[n + 1..-1]
|
553
|
+
else
|
554
|
+
size = digest.size
|
555
|
+
end
|
556
|
+
algo = case size
|
557
|
+
when 32, 'md5'
|
558
|
+
Digest::MD5
|
559
|
+
when 'rmd160'
|
560
|
+
Digest::RMD160
|
561
|
+
when 40, 'sha1'
|
562
|
+
Digest::SHA1
|
563
|
+
when 64, 'sha256'
|
564
|
+
Digest::SHA256
|
565
|
+
when 96, 'sha384'
|
566
|
+
Digest::SHA384
|
567
|
+
when 128, 'sha512'
|
568
|
+
Digest::SHA512
|
569
|
+
else
|
570
|
+
raise_error("invalid checksum: #{digest}", hint: name)
|
571
|
+
end
|
572
|
+
end
|
573
|
+
if (val = env('HEADERS')) && (out = parse_json(val, hint: "HEADERS_#{@envname}"))
|
574
|
+
headers = out
|
575
|
+
end
|
576
|
+
require 'open-uri'
|
577
|
+
data = nil
|
578
|
+
(uri = as_a(uri)).each_with_index do |url, index|
|
579
|
+
last = index == uri.size - 1
|
580
|
+
URI.open(url, headers) do |f|
|
581
|
+
data = f.read
|
582
|
+
if algo && algo.hexdigest(data) != digest
|
583
|
+
data = nil
|
584
|
+
raise_error("checksum failed: #{digest}", hint: url) if last
|
585
|
+
end
|
586
|
+
next if ext && index == 0
|
587
|
+
|
588
|
+
case f.content_type
|
589
|
+
when 'application/zip'
|
590
|
+
ext = 'zip'
|
591
|
+
when 'application/x-gzip'
|
592
|
+
ext = 'tgz'
|
593
|
+
when 'application/x-xz'
|
594
|
+
ext = 'txz'
|
595
|
+
end
|
596
|
+
end
|
597
|
+
if data
|
598
|
+
uri = url
|
599
|
+
break
|
600
|
+
elsif last
|
601
|
+
raise_error('no content', hint: url)
|
602
|
+
end
|
603
|
+
end
|
604
|
+
ext ||= URI.parse(uri).path[/^.+?\.((?:tar\.)?\w+)$/i, 1]
|
605
|
+
if (n = env("#{ext == 'zip' ? 'ZIP' : 'TAR'}_DEPTH", ignore: false))
|
606
|
+
depth = n.to_i
|
607
|
+
end
|
608
|
+
begin
|
609
|
+
require 'tempfile'
|
610
|
+
file = Tempfile.new("#{name}-")
|
611
|
+
file.write(data)
|
612
|
+
file.close
|
613
|
+
if create
|
614
|
+
warn log_message(Logger::WARN, name, 'force remove', hint: target, pass: true)
|
615
|
+
target.rmtree(verbose: true)
|
616
|
+
target.mkpath
|
617
|
+
end
|
618
|
+
case ext
|
619
|
+
when 'zip', 'aar'
|
620
|
+
session 'unzip', shell_quote(file.path), quote_option('d', target)
|
621
|
+
when 'tar', 'tgz', 'tar.gz', 'tar.xz'
|
622
|
+
flags = +(verbose ? 'v' : '')
|
623
|
+
case ext
|
624
|
+
when 'tgz', 'tar.gz'
|
625
|
+
flags += 'z'
|
626
|
+
when 'txz', 'tar.xz'
|
627
|
+
flags += 'J'
|
628
|
+
end
|
629
|
+
session 'tar', "-x#{flags}", basic_option('strip-components', depth), quote_option('f', file.path),
|
630
|
+
quote_option('C', target)
|
631
|
+
depth = 0
|
632
|
+
else
|
633
|
+
raise_error("unsupported format: #{ext}", hint: uri)
|
634
|
+
end
|
635
|
+
run(sync: sync, from: from)
|
636
|
+
while depth > 0 && target.children.size == 1
|
637
|
+
entry = target.children.first
|
638
|
+
break unless entry.directory?
|
639
|
+
|
640
|
+
dest = target.join(File.basename(file.path))
|
641
|
+
FileUtils.mv(entry, dest)
|
642
|
+
dest.children.each { |file| FileUtils.mv(file, target) }
|
643
|
+
dest.rmdir
|
644
|
+
target = entry
|
645
|
+
depth -= 1
|
646
|
+
end
|
647
|
+
ensure
|
648
|
+
file&.unlink
|
649
|
+
end
|
650
|
+
end
|
651
|
+
|
499
652
|
def first(key, *args, **kwargs, &blk)
|
500
653
|
event(:first, key, *args, **kwargs, &blk)
|
501
654
|
end
|
@@ -508,17 +661,38 @@ module Squared
|
|
508
661
|
event(:error, key, *args, **kwargs, &blk)
|
509
662
|
end
|
510
663
|
|
511
|
-
def event(name, key, *args, **kwargs, &blk)
|
512
|
-
|
664
|
+
def event(name, key, *args, override: false, **kwargs, &blk)
|
665
|
+
data = @events[name.to_sym] ||= {}
|
666
|
+
items = if override
|
667
|
+
data[key.to_sym] = []
|
668
|
+
else
|
669
|
+
data[key.to_sym] ||= []
|
670
|
+
end
|
671
|
+
items << [block_given? ? [blk] + args : args, kwargs]
|
672
|
+
self
|
513
673
|
end
|
514
674
|
|
515
675
|
def as(cmd, script, to = nil)
|
516
676
|
script = { "#{script}": to } if to
|
517
677
|
data = (@as ||= {})[cmd.to_sym] ||= {}
|
518
678
|
script.each { |key, val| data[key.to_s] = val }
|
679
|
+
self
|
519
680
|
end
|
520
681
|
|
521
|
-
def
|
682
|
+
def series(key, override: false, &blk)
|
683
|
+
if blocks.include?(key.to_sym) && block_given?
|
684
|
+
if !override && series?(target = instance_variable_get(:"@#{key}"))
|
685
|
+
target << blk
|
686
|
+
else
|
687
|
+
instance_variable_set :"@#{key}", [blk]
|
688
|
+
end
|
689
|
+
else
|
690
|
+
log&.warn "series: @#{key} (invalid)"
|
691
|
+
end
|
692
|
+
self
|
693
|
+
end
|
694
|
+
|
695
|
+
def variable_set(key, *val, **kwargs, &blk)
|
522
696
|
if variables.include?(key)
|
523
697
|
case key
|
524
698
|
when :build, :run
|
@@ -539,17 +713,22 @@ module Squared
|
|
539
713
|
when :dependfile
|
540
714
|
@dependfile = basepath(*val)
|
541
715
|
else
|
542
|
-
|
716
|
+
if blocks.include?(key) && block_given?
|
717
|
+
series key, &blk
|
718
|
+
else
|
719
|
+
instance_variable_set(:"@#{key}", block_given? && val.empty? ? blk : val.first)
|
720
|
+
end
|
543
721
|
end
|
544
722
|
else
|
545
723
|
log&.warn "variable_set: @#{key} (private)"
|
546
724
|
end
|
725
|
+
self
|
547
726
|
end
|
548
727
|
|
549
728
|
def enabled?(ref = nil, **)
|
550
729
|
return false if ref && !ref?(ref)
|
551
730
|
|
552
|
-
path.directory? && !path.empty?
|
731
|
+
(path.directory? && !path.empty?) || archive?
|
553
732
|
end
|
554
733
|
|
555
734
|
def has?(meth, ref = nil)
|
@@ -563,7 +742,7 @@ module Squared
|
|
563
742
|
end
|
564
743
|
|
565
744
|
def build?
|
566
|
-
!!@output[0] || script?
|
745
|
+
!!@output[0] || script? || series?(@run)
|
567
746
|
end
|
568
747
|
|
569
748
|
def script?
|
@@ -574,6 +753,10 @@ module Squared
|
|
574
753
|
!!@depend
|
575
754
|
end
|
576
755
|
|
756
|
+
def archive?
|
757
|
+
@archive.is_a?(Hash) && (!path.exist? || path.empty?)
|
758
|
+
end
|
759
|
+
|
577
760
|
def graph?
|
578
761
|
@graph.is_a?(Array) && !@graph.empty?
|
579
762
|
end
|
@@ -634,8 +817,12 @@ module Squared
|
|
634
817
|
@ref.reverse_each
|
635
818
|
end
|
636
819
|
|
637
|
-
def basepath(*args
|
638
|
-
|
820
|
+
def basepath(*args)
|
821
|
+
path.join(*args)
|
822
|
+
end
|
823
|
+
|
824
|
+
def rootpath(*args, ascend: nil)
|
825
|
+
ret = basepath(*args)
|
639
826
|
return ret unless ascend && !ret.exist?
|
640
827
|
|
641
828
|
path.parent.ascend.each do |dir|
|
@@ -672,7 +859,7 @@ module Squared
|
|
672
859
|
unless cmd
|
673
860
|
if warning?
|
674
861
|
from &&= from.to_s
|
675
|
-
warn log_message(Logger::WARN, from || 'unknown', subject: project, hint: 'no command given')
|
862
|
+
warn log_message(Logger::WARN, from || 'unknown', subject: project, hint: 'no command given', pass: true)
|
676
863
|
end
|
677
864
|
return
|
678
865
|
end
|
@@ -709,18 +896,23 @@ module Squared
|
|
709
896
|
end
|
710
897
|
|
711
898
|
def run_b(obj, from: nil, sync: true)
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
build(*obj, from: from, sync: sync)
|
899
|
+
case obj
|
900
|
+
when Proc, Method
|
901
|
+
obj.call
|
716
902
|
else
|
717
|
-
|
903
|
+
if series?(obj)
|
904
|
+
obj.each(&:call)
|
905
|
+
elsif obj.is_a?(Array) && obj.any? { |val| !val.is_a?(String) }
|
906
|
+
build(*obj, from: from, sync: sync)
|
907
|
+
elsif obj
|
908
|
+
run_s(obj.is_a?(Enumerable) ? obj.to_a : obj, from: from, sync: sync)
|
909
|
+
end
|
718
910
|
end
|
719
911
|
end
|
720
912
|
|
721
913
|
def graph_branch(target, data, tasks = nil, out = nil, sync: true, pass: [], done: [], depth: 0,
|
722
914
|
single: false, last: false, context: nil)
|
723
|
-
tag = ->(proj) { "#{proj.name}#{SEM_VER
|
915
|
+
tag = ->(proj) { "#{proj.name}#{SEM_VER.match?(proj.version) ? "@#{proj.version}" : ''}" }
|
724
916
|
check = ->(deps) { deps.reject { |val| done.include?(val) } }
|
725
917
|
dedupe = lambda do |name|
|
726
918
|
next [] unless (ret = data[name])
|
@@ -861,8 +1053,7 @@ module Squared
|
|
861
1053
|
def session_delete(*list, target: @session)
|
862
1054
|
ret = []
|
863
1055
|
list.each do |val|
|
864
|
-
|
865
|
-
if (key = target.find { |opt| opt =~ pat })
|
1056
|
+
if (key = target.find { |opt| opt.match?(/^#{Regexp.escape(shell_option(val))}(?: |=|$)/o) })
|
866
1057
|
target.delete(key)
|
867
1058
|
ret << key
|
868
1059
|
end
|
@@ -877,7 +1068,7 @@ module Squared
|
|
877
1068
|
def session_done(cmd)
|
878
1069
|
return cmd unless cmd.respond_to?(:done)
|
879
1070
|
|
880
|
-
raise_error('no args
|
1071
|
+
raise_error('no args added', hint: cmd.first || name) unless cmd.size > 1
|
881
1072
|
@session = nil if cmd == @session
|
882
1073
|
cmd.done
|
883
1074
|
end
|
@@ -898,9 +1089,12 @@ module Squared
|
|
898
1089
|
bare = []
|
899
1090
|
e = []
|
900
1091
|
b = []
|
1092
|
+
m = []
|
901
1093
|
p = []
|
902
1094
|
q = []
|
1095
|
+
qq = []
|
903
1096
|
i = []
|
1097
|
+
f = []
|
904
1098
|
list = list.map do |val|
|
905
1099
|
x, y = val.split('|')
|
906
1100
|
if y
|
@@ -920,12 +1114,17 @@ module Squared
|
|
920
1114
|
e << flag
|
921
1115
|
when 'b'
|
922
1116
|
b << flag
|
1117
|
+
when 'm'
|
1118
|
+
m << flag
|
923
1119
|
when 'q'
|
1120
|
+
qq << flag if val[n + 2] == 'q'
|
924
1121
|
q << flag
|
925
1122
|
when 'p'
|
926
1123
|
p << flag
|
927
1124
|
when 'i'
|
928
1125
|
i << flag
|
1126
|
+
when 'f'
|
1127
|
+
f << flag
|
929
1128
|
else
|
930
1129
|
reg << Regexp.escape(flag)
|
931
1130
|
end
|
@@ -946,23 +1145,27 @@ module Squared
|
|
946
1145
|
target << "--no-#{name}"
|
947
1146
|
else
|
948
1147
|
if opt =~ /^([^=]+)=(.+)$/
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
target <<
|
954
|
-
elsif
|
955
|
-
target << quote_option(
|
956
|
-
elsif
|
957
|
-
target <<
|
1148
|
+
key = $1
|
1149
|
+
val = $2
|
1150
|
+
match = ->(flag, pat) { flag.include?(key) && pat.match?(val) }
|
1151
|
+
if e.include?(key)
|
1152
|
+
target << shell_option(key, val)
|
1153
|
+
elsif q.include?(key)
|
1154
|
+
target << quote_option(key, val, double: qq.include?(key))
|
1155
|
+
elsif p.include?(key)
|
1156
|
+
target << quote_option(key, basepath(val))
|
1157
|
+
elsif m.include?(key)
|
1158
|
+
target << basic_option(key, val, merge: true)
|
1159
|
+
elsif b.include?(key) || match.(i, /^\d+$/) || match.(f, /^\d*(?:\.\d+)?$/)
|
1160
|
+
target << basic_option(key, val)
|
958
1161
|
else
|
959
1162
|
ret << opt
|
960
1163
|
end
|
961
|
-
opt =
|
1164
|
+
opt = key
|
962
1165
|
else
|
963
1166
|
ret << opt
|
964
1167
|
end
|
965
|
-
found = true if first && pass.none? { |
|
1168
|
+
found = true if first && pass.none? { |s| opt.include?(s) }
|
966
1169
|
end
|
967
1170
|
end
|
968
1171
|
[ret, reg.empty? ? /\A\s+\z/ : /^(#{reg.join('|')})=(.+)$/]
|
@@ -971,7 +1174,7 @@ module Squared
|
|
971
1174
|
def option_clear(opts, target: @session, **kwargs)
|
972
1175
|
kwargs[:subject] ||= target&.first
|
973
1176
|
kwargs[:hint] ||= 'not used'
|
974
|
-
warn log_message(Logger::WARN, opts.join(', '), **kwargs) unless opts.empty?
|
1177
|
+
warn log_message(Logger::WARN, opts.join(', '), pass: true, **kwargs) unless opts.empty?
|
975
1178
|
end
|
976
1179
|
|
977
1180
|
def print_item(*val)
|
@@ -1001,7 +1204,7 @@ module Squared
|
|
1001
1204
|
val
|
1002
1205
|
end
|
1003
1206
|
end
|
1004
|
-
out << sub_style(
|
1207
|
+
out << sub_style(ARG[:BORDER][1] * n, styles: border)
|
1005
1208
|
out.join("\n")
|
1006
1209
|
end
|
1007
1210
|
|
@@ -1013,7 +1216,7 @@ module Squared
|
|
1013
1216
|
sub.each { |h| s = sub_style(s, **h) }
|
1014
1217
|
s
|
1015
1218
|
end
|
1016
|
-
ret = [sub_style(
|
1219
|
+
ret = [sub_style(ARG[:BORDER][1] * n, styles: kwargs.key?(:border) ? kwargs[:border] : borderstyle), *lines]
|
1017
1220
|
ret.reverse! if reverse
|
1018
1221
|
ret.join("\n")
|
1019
1222
|
end
|
@@ -1039,7 +1242,7 @@ module Squared
|
|
1039
1242
|
if verbose
|
1040
1243
|
out = []
|
1041
1244
|
if data[:command]
|
1042
|
-
if /\A(?:"((?:[^"]|(?<=\\)")+)"|'((?:[^']|(?<=\\)')+)'|(\S+))
|
1245
|
+
if cmd =~ /\A(?:"((?:[^"]|(?<=\\)")+)"|'((?:[^']|(?<=\\)')+)'|(\S+)) /
|
1043
1246
|
path = $3 || $2 || $1
|
1044
1247
|
cmd = cmd.sub(path, File.basename(path).upcase)
|
1045
1248
|
end
|
@@ -1077,9 +1280,9 @@ module Squared
|
|
1077
1280
|
unless items.empty?
|
1078
1281
|
pad = items.size.to_s.size
|
1079
1282
|
items.each_with_index do |val, i|
|
1080
|
-
next unless reg.empty? || reg.any? { |pat| val[0]
|
1283
|
+
next unless reg.empty? || reg.any? { |pat| val[0].match?(pat) }
|
1081
1284
|
|
1082
|
-
out << "#{
|
1285
|
+
out << "#{i.succ.to_s.rjust(pad)}. #{each ? each.(val) : val[0]}"
|
1083
1286
|
end
|
1084
1287
|
end
|
1085
1288
|
sub = [headerstyle]
|
@@ -1113,9 +1316,9 @@ module Squared
|
|
1113
1316
|
opts.each { |val| target << shell_option(flag, val) }
|
1114
1317
|
end
|
1115
1318
|
|
1116
|
-
def append_hash(data, target: @session)
|
1319
|
+
def append_hash(data, target: @session, build: false)
|
1117
1320
|
target ||= []
|
1118
|
-
if (type = env('BUILD', suffix: 'TYPE') || ENV['BUILD_TYPE'])
|
1321
|
+
if build && (type = env('BUILD', suffix: 'TYPE') || ENV['BUILD_TYPE'])
|
1119
1322
|
type = "__#{type}__"
|
1120
1323
|
if (extra = data[type] || data[type.to_sym]).is_a?(Hash)
|
1121
1324
|
data = data.merge(extra)
|
@@ -1144,7 +1347,7 @@ module Squared
|
|
1144
1347
|
target
|
1145
1348
|
end
|
1146
1349
|
|
1147
|
-
def append_any(val, target: @session, delim: false)
|
1350
|
+
def append_any(val, target: @session, build: false, delim: false)
|
1148
1351
|
if delim && !target.include?('--')
|
1149
1352
|
target << '--'
|
1150
1353
|
else
|
@@ -1154,7 +1357,7 @@ module Squared
|
|
1154
1357
|
when String
|
1155
1358
|
target << val
|
1156
1359
|
when Hash
|
1157
|
-
append_hash(val, target: target)
|
1360
|
+
append_hash(val, target: target, build: build)
|
1158
1361
|
when Enumerable
|
1159
1362
|
if target.is_a?(Array)
|
1160
1363
|
target.concat(val.to_a)
|
@@ -1163,6 +1366,7 @@ module Squared
|
|
1163
1366
|
end
|
1164
1367
|
else
|
1165
1368
|
target.delete('--') if delim
|
1369
|
+
nil
|
1166
1370
|
end
|
1167
1371
|
end
|
1168
1372
|
|
@@ -1171,8 +1375,9 @@ module Squared
|
|
1171
1375
|
|
1172
1376
|
target << '--' if delim && !target.include?('--')
|
1173
1377
|
list.map do |val|
|
1174
|
-
|
1175
|
-
|
1378
|
+
item = escape ? shell_escape(val, quote: quote) : shell_quote(val)
|
1379
|
+
target << item
|
1380
|
+
item
|
1176
1381
|
end
|
1177
1382
|
end
|
1178
1383
|
|
@@ -1180,7 +1385,7 @@ module Squared
|
|
1180
1385
|
**kwargs)
|
1181
1386
|
return if (list = list.flatten).empty?
|
1182
1387
|
|
1183
|
-
list.
|
1388
|
+
list.each do |opt|
|
1184
1389
|
next unless (val = option(opt, **kwargs))
|
1185
1390
|
|
1186
1391
|
return target << (if flag
|
@@ -1197,7 +1402,7 @@ module Squared
|
|
1197
1402
|
return if (list = list.flatten).empty?
|
1198
1403
|
|
1199
1404
|
ret = []
|
1200
|
-
list.
|
1405
|
+
list.each do |flag|
|
1201
1406
|
next unless (val = option(flag, **kwargs))
|
1202
1407
|
|
1203
1408
|
if val == '0' && no
|
@@ -1213,16 +1418,63 @@ module Squared
|
|
1213
1418
|
target << '--no-color' if !ARG[:COLOR] || stdin? || option('no-color', ignore: false)
|
1214
1419
|
end
|
1215
1420
|
|
1421
|
+
def merge_opts(base, data)
|
1422
|
+
return data unless base
|
1423
|
+
return base unless data
|
1424
|
+
|
1425
|
+
ret = case data
|
1426
|
+
when String
|
1427
|
+
case base
|
1428
|
+
when String
|
1429
|
+
"#{base} #{data}"
|
1430
|
+
when Hash
|
1431
|
+
"#{append_hash(base).join(' ')} #{data}"
|
1432
|
+
when Enumerable
|
1433
|
+
"#{base.to_a.join(' ')} #{data}"
|
1434
|
+
end
|
1435
|
+
when Hash
|
1436
|
+
case base
|
1437
|
+
when String
|
1438
|
+
"#{base} #{append_hash(data).join(' ')}"
|
1439
|
+
when Hash
|
1440
|
+
base.merge(data)
|
1441
|
+
when Enumerable
|
1442
|
+
base.to_a + append_hash(data)
|
1443
|
+
end
|
1444
|
+
when Enumerable
|
1445
|
+
case base
|
1446
|
+
when String
|
1447
|
+
"#{base} #{data.to_a.join(' ')}"
|
1448
|
+
when Hash
|
1449
|
+
"#{append_hash(base).join(' ')} #{data.to_a.join(' ')}"
|
1450
|
+
when Enumerable
|
1451
|
+
base.to_a + data.to_a
|
1452
|
+
end
|
1453
|
+
else
|
1454
|
+
base
|
1455
|
+
end
|
1456
|
+
ret || data
|
1457
|
+
end
|
1458
|
+
|
1216
1459
|
def collect_hash(data, pass: [])
|
1217
1460
|
ret = []
|
1218
1461
|
data.each { |key, val| ret += val unless pass.include?(key) }
|
1219
1462
|
ret
|
1220
1463
|
end
|
1221
1464
|
|
1222
|
-
def
|
1465
|
+
def parse_json(val, hint: nil)
|
1466
|
+
ret = JSON.parse(val)
|
1467
|
+
raise_error('invalid JSON object', val, hint: hint) unless ret.is_a?(Hash)
|
1468
|
+
rescue StandardError => e
|
1469
|
+
log&.warn e
|
1470
|
+
else
|
1471
|
+
ret
|
1472
|
+
end
|
1473
|
+
|
1474
|
+
def param_guard(action, flag, args: nil, key: nil, pat: nil, values: nil)
|
1223
1475
|
if args && key
|
1224
1476
|
val = args[key]
|
1225
|
-
return val unless val.nil? || (pat && !val.match?(pat))
|
1477
|
+
return val unless val.nil? || (pat && !val.match?(pat)) || (values && !values.include?(val))
|
1226
1478
|
|
1227
1479
|
@session = nil
|
1228
1480
|
raise_error(action, "#{flag}[#{key}]", hint: val.nil? ? 'missing' : 'invalid')
|
@@ -1233,6 +1485,17 @@ module Squared
|
|
1233
1485
|
args
|
1234
1486
|
end
|
1235
1487
|
|
1488
|
+
def relativepath(*files, all: false)
|
1489
|
+
return [] if files.empty?
|
1490
|
+
|
1491
|
+
files.flatten.map { |val| Pathname.new(val) }.select { |val| projectpath?(val) }.map do |val|
|
1492
|
+
val = val.absolute? ? val.to_s.sub(/^#{Regexp.escape(File.join(path, ''))}/o, '') : val.to_s
|
1493
|
+
val = val[2..-1] if val.start_with?('./')
|
1494
|
+
val = "#{val}*" if all && val.end_with?('/')
|
1495
|
+
val
|
1496
|
+
end
|
1497
|
+
end
|
1498
|
+
|
1236
1499
|
def projectmap(files, parent: false)
|
1237
1500
|
files = files.select { |val| projectpath?(val) } unless parent
|
1238
1501
|
files.map { |val| val == '.' ? '.' : shell_quote(basepath(val.strip)) }
|
@@ -1274,22 +1537,28 @@ module Squared
|
|
1274
1537
|
val.compact.map { |s| color(s) }.flatten
|
1275
1538
|
end
|
1276
1539
|
|
1540
|
+
def epochtime
|
1541
|
+
DateTime.now.strftime('%Q').to_i
|
1542
|
+
end
|
1543
|
+
|
1277
1544
|
def on(event, from, *args, **kwargs)
|
1278
|
-
return unless from
|
1545
|
+
return unless from
|
1279
1546
|
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1547
|
+
@events[event][from]&.each do |obj|
|
1548
|
+
if obj.is_a?(Array) && obj[1].is_a?(Hash)
|
1549
|
+
opts = kwargs.empty? ? obj[1] : obj[1].merge(kwargs)
|
1550
|
+
target = obj[0]
|
1551
|
+
else
|
1552
|
+
opts = kwargs
|
1553
|
+
target = obj
|
1554
|
+
end
|
1555
|
+
as_a(target, flat: true).each do |cmd|
|
1556
|
+
case cmd
|
1557
|
+
when Proc, Method
|
1558
|
+
cmd.call(*args, **opts)
|
1559
|
+
when String
|
1560
|
+
run(cmd, **opts)
|
1561
|
+
end
|
1293
1562
|
end
|
1294
1563
|
end
|
1295
1564
|
end
|
@@ -1330,23 +1599,53 @@ module Squared
|
|
1330
1599
|
end
|
1331
1600
|
|
1332
1601
|
def run_set(cmd, val = nil, opts: nil, **)
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1602
|
+
diso = @output[1] == false && !@output[0].nil?
|
1603
|
+
dise = @output[2] == false
|
1604
|
+
parse = lambda do |data|
|
1605
|
+
ret = []
|
1606
|
+
if data[:command]
|
1607
|
+
ret[0] = data[:command]
|
1608
|
+
ret[1] = data[:opts] unless diso
|
1609
|
+
ret[3] = data[:args]
|
1610
|
+
elsif data[:script]
|
1611
|
+
ret[1] = data[:script]
|
1612
|
+
ret[3] = data[:opts]
|
1613
|
+
ret[4] = data[:args]
|
1614
|
+
else
|
1615
|
+
ret[0] = false
|
1616
|
+
end
|
1617
|
+
ret[2] = data[:env] unless dise
|
1618
|
+
ret
|
1619
|
+
end
|
1620
|
+
case cmd
|
1621
|
+
when Array
|
1622
|
+
@output = if cmd.all? { |data| data.is_a?(Hash) }
|
1623
|
+
diso = false
|
1624
|
+
dise = false
|
1625
|
+
cmd.map { |data| parse.(data) }
|
1626
|
+
else
|
1627
|
+
cmd.dup
|
1628
|
+
end
|
1629
|
+
return
|
1630
|
+
when Hash
|
1631
|
+
@output = parse.(data)
|
1632
|
+
else
|
1633
|
+
@output[0] = cmd
|
1634
|
+
end
|
1635
|
+
unless diso
|
1336
1636
|
if opts == false
|
1337
1637
|
@output[1] = false
|
1338
1638
|
elsif opts && opts != true
|
1339
1639
|
@output[1] = opts
|
1340
1640
|
end
|
1341
1641
|
end
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1347
|
-
|
1642
|
+
return if dise
|
1643
|
+
|
1644
|
+
if val.is_a?(Hash)
|
1645
|
+
@output[2] = val
|
1646
|
+
elsif val == false
|
1647
|
+
@output[2] = false
|
1348
1648
|
end
|
1349
|
-
@output[0] = cmd
|
1350
1649
|
end
|
1351
1650
|
|
1352
1651
|
def script_set(cmd, prod: nil, args: nil, **)
|
@@ -1362,6 +1661,8 @@ module Squared
|
|
1362
1661
|
end
|
1363
1662
|
|
1364
1663
|
def as_get(val)
|
1664
|
+
return unless val
|
1665
|
+
|
1365
1666
|
@global && (ret = @as && @as[from] && @as[from][val]) ? ret : val
|
1366
1667
|
end
|
1367
1668
|
|
@@ -1396,19 +1697,20 @@ module Squared
|
|
1396
1697
|
|
1397
1698
|
def runnable?(val)
|
1398
1699
|
case val
|
1399
|
-
when String
|
1700
|
+
when String, Enumerable, Proc, Method
|
1400
1701
|
true
|
1401
|
-
when Enumerable
|
1402
|
-
!val.is_a?(Hash)
|
1403
1702
|
else
|
1404
1703
|
false
|
1405
1704
|
end
|
1406
1705
|
end
|
1407
1706
|
|
1707
|
+
def series?(val)
|
1708
|
+
val.is_a?(Array) && val.all? { |p| p.is_a?(Proc) || p.is_a?(Method) }
|
1709
|
+
end
|
1710
|
+
|
1408
1711
|
def session_arg?(*list, target: @session, value: false)
|
1409
1712
|
list.any? do |val|
|
1410
|
-
|
1411
|
-
target.any? { |opt| opt =~ pat }
|
1713
|
+
target.any? { |opt| opt.match?(/^#{Regexp.escape(shell_option(val))}#{value ? '[ =].' : '(?:[ =]|$)'}/o) }
|
1412
1714
|
end
|
1413
1715
|
end
|
1414
1716
|
|
@@ -1445,6 +1747,10 @@ module Squared
|
|
1445
1747
|
Base.tasks + VAR_SET
|
1446
1748
|
end
|
1447
1749
|
|
1750
|
+
def blocks
|
1751
|
+
BLK_SET
|
1752
|
+
end
|
1753
|
+
|
1448
1754
|
def borderstyle
|
1449
1755
|
((data = workspace.banner_get(*@ref, group: group)) && data[:border]) || theme[:border]
|
1450
1756
|
end
|