squared 0.3.6 → 0.4.1
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 +70 -2
- data/README.md +13 -2
- data/README.ruby.md +171 -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 +32 -15
- data/lib/squared/common/prompt.rb +2 -2
- data/lib/squared/common/shell.rb +52 -39
- data/lib/squared/common/utils.rb +68 -2
- 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 +622 -0
- data/lib/squared/workspace/project/git.rb +427 -164
- data/lib/squared/workspace/project/node.rb +48 -50
- data/lib/squared/workspace/project/python.rb +115 -25
- data/lib/squared/workspace/project/ruby.rb +33 -35
- 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 +3 -2
@@ -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])
|
@@ -867,8 +1059,7 @@ module Squared
|
|
867
1059
|
def session_delete(*list, target: @session)
|
868
1060
|
ret = []
|
869
1061
|
list.each do |val|
|
870
|
-
|
871
|
-
if (key = target.find { |opt| opt =~ pat })
|
1062
|
+
if (key = target.find { |opt| opt.match?(/^#{Regexp.escape(shell_option(val))}(?: |=|$)/o) })
|
872
1063
|
target.delete(key)
|
873
1064
|
ret << key
|
874
1065
|
end
|
@@ -883,7 +1074,7 @@ module Squared
|
|
883
1074
|
def session_done(cmd)
|
884
1075
|
return cmd unless cmd.respond_to?(:done)
|
885
1076
|
|
886
|
-
raise_error('no args
|
1077
|
+
raise_error('no args added', hint: cmd.first || name) unless cmd.size > 1
|
887
1078
|
@session = nil if cmd == @session
|
888
1079
|
cmd.done
|
889
1080
|
end
|
@@ -904,9 +1095,12 @@ module Squared
|
|
904
1095
|
bare = []
|
905
1096
|
e = []
|
906
1097
|
b = []
|
1098
|
+
m = []
|
907
1099
|
p = []
|
908
1100
|
q = []
|
1101
|
+
qq = []
|
909
1102
|
i = []
|
1103
|
+
f = []
|
910
1104
|
list = list.map do |val|
|
911
1105
|
x, y = val.split('|')
|
912
1106
|
if y
|
@@ -926,12 +1120,17 @@ module Squared
|
|
926
1120
|
e << flag
|
927
1121
|
when 'b'
|
928
1122
|
b << flag
|
1123
|
+
when 'm'
|
1124
|
+
m << flag
|
929
1125
|
when 'q'
|
1126
|
+
qq << flag if val[n + 2] == 'q'
|
930
1127
|
q << flag
|
931
1128
|
when 'p'
|
932
1129
|
p << flag
|
933
1130
|
when 'i'
|
934
1131
|
i << flag
|
1132
|
+
when 'f'
|
1133
|
+
f << flag
|
935
1134
|
else
|
936
1135
|
reg << Regexp.escape(flag)
|
937
1136
|
end
|
@@ -952,23 +1151,27 @@ module Squared
|
|
952
1151
|
target << "--no-#{name}"
|
953
1152
|
else
|
954
1153
|
if opt =~ /^([^=]+)=(.+)$/
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
target <<
|
960
|
-
elsif
|
961
|
-
target << quote_option(
|
962
|
-
elsif
|
963
|
-
target <<
|
1154
|
+
key = $1
|
1155
|
+
val = $2
|
1156
|
+
match = ->(flag, pat) { flag.include?(key) && pat.match?(val) }
|
1157
|
+
if e.include?(key)
|
1158
|
+
target << shell_option(key, val)
|
1159
|
+
elsif q.include?(key)
|
1160
|
+
target << quote_option(key, val, double: qq.include?(key))
|
1161
|
+
elsif p.include?(key)
|
1162
|
+
target << quote_option(key, basepath(val))
|
1163
|
+
elsif m.include?(key)
|
1164
|
+
target << basic_option(key, val, merge: true)
|
1165
|
+
elsif b.include?(key) || match.(i, /^\d+$/) || match.(f, /^\d*(?:\.\d+)?$/)
|
1166
|
+
target << basic_option(key, val)
|
964
1167
|
else
|
965
1168
|
ret << opt
|
966
1169
|
end
|
967
|
-
opt =
|
1170
|
+
opt = key
|
968
1171
|
else
|
969
1172
|
ret << opt
|
970
1173
|
end
|
971
|
-
found = true if first && pass.none? { |
|
1174
|
+
found = true if first && pass.none? { |s| opt.include?(s) }
|
972
1175
|
end
|
973
1176
|
end
|
974
1177
|
[ret, reg.empty? ? /\A\s+\z/ : /^(#{reg.join('|')})=(.+)$/]
|
@@ -977,7 +1180,7 @@ module Squared
|
|
977
1180
|
def option_clear(opts, target: @session, **kwargs)
|
978
1181
|
kwargs[:subject] ||= target&.first
|
979
1182
|
kwargs[:hint] ||= 'not used'
|
980
|
-
warn log_message(Logger::WARN, opts.join(', '), **kwargs) unless opts.empty?
|
1183
|
+
warn log_message(Logger::WARN, opts.join(', '), pass: true, **kwargs) unless opts.empty?
|
981
1184
|
end
|
982
1185
|
|
983
1186
|
def print_item(*val)
|
@@ -1007,7 +1210,7 @@ module Squared
|
|
1007
1210
|
val
|
1008
1211
|
end
|
1009
1212
|
end
|
1010
|
-
out << sub_style(
|
1213
|
+
out << sub_style(ARG[:BORDER][1] * n, styles: border)
|
1011
1214
|
out.join("\n")
|
1012
1215
|
end
|
1013
1216
|
|
@@ -1019,7 +1222,7 @@ module Squared
|
|
1019
1222
|
sub.each { |h| s = sub_style(s, **h) }
|
1020
1223
|
s
|
1021
1224
|
end
|
1022
|
-
ret = [sub_style(
|
1225
|
+
ret = [sub_style(ARG[:BORDER][1] * n, styles: kwargs.key?(:border) ? kwargs[:border] : borderstyle), *lines]
|
1023
1226
|
ret.reverse! if reverse
|
1024
1227
|
ret.join("\n")
|
1025
1228
|
end
|
@@ -1045,7 +1248,7 @@ module Squared
|
|
1045
1248
|
if verbose
|
1046
1249
|
out = []
|
1047
1250
|
if data[:command]
|
1048
|
-
if /\A(?:"((?:[^"]|(?<=\\)")+)"|'((?:[^']|(?<=\\)')+)'|(\S+))
|
1251
|
+
if cmd =~ /\A(?:"((?:[^"]|(?<=\\)")+)"|'((?:[^']|(?<=\\)')+)'|(\S+)) /
|
1049
1252
|
path = $3 || $2 || $1
|
1050
1253
|
cmd = cmd.sub(path, File.basename(path).upcase)
|
1051
1254
|
end
|
@@ -1083,9 +1286,9 @@ module Squared
|
|
1083
1286
|
unless items.empty?
|
1084
1287
|
pad = items.size.to_s.size
|
1085
1288
|
items.each_with_index do |val, i|
|
1086
|
-
next unless reg.empty? || reg.any? { |pat| val[0]
|
1289
|
+
next unless reg.empty? || reg.any? { |pat| val[0].match?(pat) }
|
1087
1290
|
|
1088
|
-
out << "#{
|
1291
|
+
out << "#{i.succ.to_s.rjust(pad)}. #{each ? each.(val) : val[0]}"
|
1089
1292
|
end
|
1090
1293
|
end
|
1091
1294
|
sub = [headerstyle]
|
@@ -1119,9 +1322,9 @@ module Squared
|
|
1119
1322
|
opts.each { |val| target << shell_option(flag, val) }
|
1120
1323
|
end
|
1121
1324
|
|
1122
|
-
def append_hash(data, target: @session)
|
1325
|
+
def append_hash(data, target: @session, build: false)
|
1123
1326
|
target ||= []
|
1124
|
-
if (type = env('BUILD', suffix: 'TYPE') || ENV['BUILD_TYPE'])
|
1327
|
+
if build && (type = env('BUILD', suffix: 'TYPE') || ENV['BUILD_TYPE'])
|
1125
1328
|
type = "__#{type}__"
|
1126
1329
|
if (extra = data[type] || data[type.to_sym]).is_a?(Hash)
|
1127
1330
|
data = data.merge(extra)
|
@@ -1150,7 +1353,7 @@ module Squared
|
|
1150
1353
|
target
|
1151
1354
|
end
|
1152
1355
|
|
1153
|
-
def append_any(val, target: @session, delim: false)
|
1356
|
+
def append_any(val, target: @session, build: false, delim: false)
|
1154
1357
|
if delim && !target.include?('--')
|
1155
1358
|
target << '--'
|
1156
1359
|
else
|
@@ -1160,7 +1363,7 @@ module Squared
|
|
1160
1363
|
when String
|
1161
1364
|
target << val
|
1162
1365
|
when Hash
|
1163
|
-
append_hash(val, target: target)
|
1366
|
+
append_hash(val, target: target, build: build)
|
1164
1367
|
when Enumerable
|
1165
1368
|
if target.is_a?(Array)
|
1166
1369
|
target.concat(val.to_a)
|
@@ -1169,6 +1372,7 @@ module Squared
|
|
1169
1372
|
end
|
1170
1373
|
else
|
1171
1374
|
target.delete('--') if delim
|
1375
|
+
nil
|
1172
1376
|
end
|
1173
1377
|
end
|
1174
1378
|
|
@@ -1177,8 +1381,9 @@ module Squared
|
|
1177
1381
|
|
1178
1382
|
target << '--' if delim && !target.include?('--')
|
1179
1383
|
list.map do |val|
|
1180
|
-
|
1181
|
-
|
1384
|
+
item = escape ? shell_escape(val, quote: quote) : shell_quote(val)
|
1385
|
+
target << item
|
1386
|
+
item
|
1182
1387
|
end
|
1183
1388
|
end
|
1184
1389
|
|
@@ -1186,7 +1391,7 @@ module Squared
|
|
1186
1391
|
**kwargs)
|
1187
1392
|
return if (list = list.flatten).empty?
|
1188
1393
|
|
1189
|
-
list.
|
1394
|
+
list.each do |opt|
|
1190
1395
|
next unless (val = option(opt, **kwargs))
|
1191
1396
|
|
1192
1397
|
return target << (if flag
|
@@ -1203,7 +1408,7 @@ module Squared
|
|
1203
1408
|
return if (list = list.flatten).empty?
|
1204
1409
|
|
1205
1410
|
ret = []
|
1206
|
-
list.
|
1411
|
+
list.each do |flag|
|
1207
1412
|
next unless (val = option(flag, **kwargs))
|
1208
1413
|
|
1209
1414
|
if val == '0' && no
|
@@ -1219,16 +1424,63 @@ module Squared
|
|
1219
1424
|
target << '--no-color' if !ARG[:COLOR] || stdin? || option('no-color', ignore: false)
|
1220
1425
|
end
|
1221
1426
|
|
1427
|
+
def merge_opts(base, data)
|
1428
|
+
return data unless base
|
1429
|
+
return base unless data
|
1430
|
+
|
1431
|
+
ret = case data
|
1432
|
+
when String
|
1433
|
+
case base
|
1434
|
+
when String
|
1435
|
+
"#{base} #{data}"
|
1436
|
+
when Hash
|
1437
|
+
"#{append_hash(base).join(' ')} #{data}"
|
1438
|
+
when Enumerable
|
1439
|
+
"#{base.to_a.join(' ')} #{data}"
|
1440
|
+
end
|
1441
|
+
when Hash
|
1442
|
+
case base
|
1443
|
+
when String
|
1444
|
+
"#{base} #{append_hash(data).join(' ')}"
|
1445
|
+
when Hash
|
1446
|
+
base.merge(data)
|
1447
|
+
when Enumerable
|
1448
|
+
base.to_a + append_hash(data)
|
1449
|
+
end
|
1450
|
+
when Enumerable
|
1451
|
+
case base
|
1452
|
+
when String
|
1453
|
+
"#{base} #{data.to_a.join(' ')}"
|
1454
|
+
when Hash
|
1455
|
+
"#{append_hash(base).join(' ')} #{data.to_a.join(' ')}"
|
1456
|
+
when Enumerable
|
1457
|
+
base.to_a + data.to_a
|
1458
|
+
end
|
1459
|
+
else
|
1460
|
+
base
|
1461
|
+
end
|
1462
|
+
ret || data
|
1463
|
+
end
|
1464
|
+
|
1222
1465
|
def collect_hash(data, pass: [])
|
1223
1466
|
ret = []
|
1224
1467
|
data.each { |key, val| ret += val unless pass.include?(key) }
|
1225
1468
|
ret
|
1226
1469
|
end
|
1227
1470
|
|
1228
|
-
def
|
1471
|
+
def parse_json(val, hint: nil)
|
1472
|
+
ret = JSON.parse(val)
|
1473
|
+
raise_error('invalid JSON object', val, hint: hint) unless ret.is_a?(Hash)
|
1474
|
+
rescue StandardError => e
|
1475
|
+
log&.warn e
|
1476
|
+
else
|
1477
|
+
ret
|
1478
|
+
end
|
1479
|
+
|
1480
|
+
def param_guard(action, flag, args: nil, key: nil, pat: nil, values: nil)
|
1229
1481
|
if args && key
|
1230
1482
|
val = args[key]
|
1231
|
-
return val unless val.nil? || (pat && !val.match?(pat))
|
1483
|
+
return val unless val.nil? || (pat && !val.match?(pat)) || (values && !values.include?(val))
|
1232
1484
|
|
1233
1485
|
@session = nil
|
1234
1486
|
raise_error(action, "#{flag}[#{key}]", hint: val.nil? ? 'missing' : 'invalid')
|
@@ -1239,6 +1491,17 @@ module Squared
|
|
1239
1491
|
args
|
1240
1492
|
end
|
1241
1493
|
|
1494
|
+
def relativepath(*files, all: false)
|
1495
|
+
return [] if files.empty?
|
1496
|
+
|
1497
|
+
files.flatten.map { |val| Pathname.new(val) }.select { |val| projectpath?(val) }.map do |val|
|
1498
|
+
val = val.absolute? ? val.to_s.sub(/^#{Regexp.escape(File.join(path, ''))}/o, '') : val.to_s
|
1499
|
+
val = val[2..-1] if val.start_with?('./')
|
1500
|
+
val = "#{val}*" if all && val.end_with?('/')
|
1501
|
+
val
|
1502
|
+
end
|
1503
|
+
end
|
1504
|
+
|
1242
1505
|
def projectmap(files, parent: false)
|
1243
1506
|
files = files.select { |val| projectpath?(val) } unless parent
|
1244
1507
|
files.map { |val| val == '.' ? '.' : shell_quote(basepath(val.strip)) }
|
@@ -1280,22 +1543,28 @@ module Squared
|
|
1280
1543
|
val.compact.map { |s| color(s) }.flatten
|
1281
1544
|
end
|
1282
1545
|
|
1546
|
+
def epochtime
|
1547
|
+
DateTime.now.strftime('%Q').to_i
|
1548
|
+
end
|
1549
|
+
|
1283
1550
|
def on(event, from, *args, **kwargs)
|
1284
|
-
return unless from
|
1551
|
+
return unless from
|
1285
1552
|
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1553
|
+
@events[event][from]&.each do |obj|
|
1554
|
+
if obj.is_a?(Array) && obj[1].is_a?(Hash)
|
1555
|
+
opts = kwargs.empty? ? obj[1] : obj[1].merge(kwargs)
|
1556
|
+
target = obj[0]
|
1557
|
+
else
|
1558
|
+
opts = kwargs
|
1559
|
+
target = obj
|
1560
|
+
end
|
1561
|
+
as_a(target, flat: true).each do |cmd|
|
1562
|
+
case cmd
|
1563
|
+
when Proc, Method
|
1564
|
+
cmd.call(*args, **opts)
|
1565
|
+
when String
|
1566
|
+
run(cmd, **opts)
|
1567
|
+
end
|
1299
1568
|
end
|
1300
1569
|
end
|
1301
1570
|
end
|
@@ -1336,23 +1605,53 @@ module Squared
|
|
1336
1605
|
end
|
1337
1606
|
|
1338
1607
|
def run_set(cmd, val = nil, opts: nil, **)
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1608
|
+
diso = @output[1] == false && !@output[0].nil?
|
1609
|
+
dise = @output[2] == false
|
1610
|
+
parse = lambda do |data|
|
1611
|
+
ret = []
|
1612
|
+
if data[:command]
|
1613
|
+
ret[0] = data[:command]
|
1614
|
+
ret[1] = data[:opts] unless diso
|
1615
|
+
ret[3] = data[:args]
|
1616
|
+
elsif data[:script]
|
1617
|
+
ret[1] = data[:script]
|
1618
|
+
ret[3] = data[:opts]
|
1619
|
+
ret[4] = data[:args]
|
1620
|
+
else
|
1621
|
+
ret[0] = false
|
1622
|
+
end
|
1623
|
+
ret[2] = data[:env] unless dise
|
1624
|
+
ret
|
1625
|
+
end
|
1626
|
+
case cmd
|
1627
|
+
when Array
|
1628
|
+
@output = if cmd.all? { |data| data.is_a?(Hash) }
|
1629
|
+
diso = false
|
1630
|
+
dise = false
|
1631
|
+
cmd.map { |data| parse.(data) }
|
1632
|
+
else
|
1633
|
+
cmd.dup
|
1634
|
+
end
|
1635
|
+
return
|
1636
|
+
when Hash
|
1637
|
+
@output = parse.(data)
|
1638
|
+
else
|
1639
|
+
@output[0] = cmd
|
1640
|
+
end
|
1641
|
+
unless diso
|
1342
1642
|
if opts == false
|
1343
1643
|
@output[1] = false
|
1344
1644
|
elsif opts && opts != true
|
1345
1645
|
@output[1] = opts
|
1346
1646
|
end
|
1347
1647
|
end
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1648
|
+
return if dise
|
1649
|
+
|
1650
|
+
if val.is_a?(Hash)
|
1651
|
+
@output[2] = val
|
1652
|
+
elsif val == false
|
1653
|
+
@output[2] = false
|
1354
1654
|
end
|
1355
|
-
@output[0] = cmd
|
1356
1655
|
end
|
1357
1656
|
|
1358
1657
|
def script_set(cmd, prod: nil, args: nil, **)
|
@@ -1368,6 +1667,8 @@ module Squared
|
|
1368
1667
|
end
|
1369
1668
|
|
1370
1669
|
def as_get(val)
|
1670
|
+
return unless val
|
1671
|
+
|
1371
1672
|
@global && (ret = @as && @as[from] && @as[from][val]) ? ret : val
|
1372
1673
|
end
|
1373
1674
|
|
@@ -1402,19 +1703,20 @@ module Squared
|
|
1402
1703
|
|
1403
1704
|
def runnable?(val)
|
1404
1705
|
case val
|
1405
|
-
when String
|
1706
|
+
when String, Enumerable, Proc, Method
|
1406
1707
|
true
|
1407
|
-
when Enumerable
|
1408
|
-
!val.is_a?(Hash)
|
1409
1708
|
else
|
1410
1709
|
false
|
1411
1710
|
end
|
1412
1711
|
end
|
1413
1712
|
|
1713
|
+
def series?(val)
|
1714
|
+
val.is_a?(Array) && val.all? { |p| p.is_a?(Proc) || p.is_a?(Method) }
|
1715
|
+
end
|
1716
|
+
|
1414
1717
|
def session_arg?(*list, target: @session, value: false)
|
1415
1718
|
list.any? do |val|
|
1416
|
-
|
1417
|
-
target.any? { |opt| opt =~ pat }
|
1719
|
+
target.any? { |opt| opt.match?(/^#{Regexp.escape(shell_option(val))}#{value ? '[ =].' : '(?:[ =]|$)'}/o) }
|
1418
1720
|
end
|
1419
1721
|
end
|
1420
1722
|
|
@@ -1451,6 +1753,10 @@ module Squared
|
|
1451
1753
|
Base.tasks + VAR_SET
|
1452
1754
|
end
|
1453
1755
|
|
1756
|
+
def blocks
|
1757
|
+
BLK_SET
|
1758
|
+
end
|
1759
|
+
|
1454
1760
|
def borderstyle
|
1455
1761
|
((data = workspace.banner_get(*@ref, group: group)) && data[:border]) || theme[:border]
|
1456
1762
|
end
|