squared 0.3.6 → 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 +46 -8
- 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 +431 -131
- data/lib/squared/workspace/project/docker.rb +572 -0
- data/lib/squared/workspace/project/git.rb +408 -169
- data/lib/squared/workspace/project/node.rb +50 -50
- data/lib/squared/workspace/project/python.rb +115 -24
- data/lib/squared/workspace/project/ruby.rb +35 -36
- 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))
|
@@ -254,14 +264,14 @@ module Squared
|
|
254
264
|
|
255
265
|
format_desc action, flag, '(-)project*'
|
256
266
|
task flag do |_, args|
|
257
|
-
args = args.to_a.reject { |val| name == val.to_s }
|
267
|
+
args = param_guard(action, flag, args: args.to_a.reject { |val| name == val.to_s })
|
258
268
|
if flag == :run
|
259
269
|
graph args
|
260
270
|
else
|
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
|
@@ -684,7 +871,7 @@ module Squared
|
|
684
871
|
log&.warn "ENV was discarded: #{var}" if var
|
685
872
|
task_invoke(cmd, exception: exception, warning: warning?)
|
686
873
|
else
|
687
|
-
print_item format_banner(cmd, banner: banner) if sync
|
874
|
+
print_item format_banner(cmd, banner: banner) if sync
|
688
875
|
args = var.is_a?(Hash) ? [var, cmd] : [cmd]
|
689
876
|
shell(*args, chdir: chdir, exception: exception)
|
690
877
|
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])
|
@@ -778,13 +970,7 @@ module Squared
|
|
778
970
|
next if pass.include?(meth)
|
779
971
|
|
780
972
|
if workspace.task_defined?(cmd = task_join(proj.name, meth))
|
781
|
-
if ENV.key?(key = "BANNER_#{proj.name.upcase}")
|
782
|
-
key = nil
|
783
|
-
else
|
784
|
-
ENV[key] = '0'
|
785
|
-
end
|
786
973
|
run(cmd, sync: false, banner: false)
|
787
|
-
ENV.delete(key) if key
|
788
974
|
elsif proj.has?(meth, tasks || group ? nil : workspace.baseref)
|
789
975
|
proj.__send__(meth.to_sym, sync: sync)
|
790
976
|
end
|
@@ -867,8 +1053,7 @@ module Squared
|
|
867
1053
|
def session_delete(*list, target: @session)
|
868
1054
|
ret = []
|
869
1055
|
list.each do |val|
|
870
|
-
|
871
|
-
if (key = target.find { |opt| opt =~ pat })
|
1056
|
+
if (key = target.find { |opt| opt.match?(/^#{Regexp.escape(shell_option(val))}(?: |=|$)/o) })
|
872
1057
|
target.delete(key)
|
873
1058
|
ret << key
|
874
1059
|
end
|
@@ -883,7 +1068,7 @@ module Squared
|
|
883
1068
|
def session_done(cmd)
|
884
1069
|
return cmd unless cmd.respond_to?(:done)
|
885
1070
|
|
886
|
-
raise_error('no args
|
1071
|
+
raise_error('no args added', hint: cmd.first || name) unless cmd.size > 1
|
887
1072
|
@session = nil if cmd == @session
|
888
1073
|
cmd.done
|
889
1074
|
end
|
@@ -904,9 +1089,12 @@ module Squared
|
|
904
1089
|
bare = []
|
905
1090
|
e = []
|
906
1091
|
b = []
|
1092
|
+
m = []
|
907
1093
|
p = []
|
908
1094
|
q = []
|
1095
|
+
qq = []
|
909
1096
|
i = []
|
1097
|
+
f = []
|
910
1098
|
list = list.map do |val|
|
911
1099
|
x, y = val.split('|')
|
912
1100
|
if y
|
@@ -926,12 +1114,17 @@ module Squared
|
|
926
1114
|
e << flag
|
927
1115
|
when 'b'
|
928
1116
|
b << flag
|
1117
|
+
when 'm'
|
1118
|
+
m << flag
|
929
1119
|
when 'q'
|
1120
|
+
qq << flag if val[n + 2] == 'q'
|
930
1121
|
q << flag
|
931
1122
|
when 'p'
|
932
1123
|
p << flag
|
933
1124
|
when 'i'
|
934
1125
|
i << flag
|
1126
|
+
when 'f'
|
1127
|
+
f << flag
|
935
1128
|
else
|
936
1129
|
reg << Regexp.escape(flag)
|
937
1130
|
end
|
@@ -952,23 +1145,27 @@ module Squared
|
|
952
1145
|
target << "--no-#{name}"
|
953
1146
|
else
|
954
1147
|
if opt =~ /^([^=]+)=(.+)$/
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
target <<
|
960
|
-
elsif
|
961
|
-
target << quote_option(
|
962
|
-
elsif
|
963
|
-
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)
|
964
1161
|
else
|
965
1162
|
ret << opt
|
966
1163
|
end
|
967
|
-
opt =
|
1164
|
+
opt = key
|
968
1165
|
else
|
969
1166
|
ret << opt
|
970
1167
|
end
|
971
|
-
found = true if first && pass.none? { |
|
1168
|
+
found = true if first && pass.none? { |s| opt.include?(s) }
|
972
1169
|
end
|
973
1170
|
end
|
974
1171
|
[ret, reg.empty? ? /\A\s+\z/ : /^(#{reg.join('|')})=(.+)$/]
|
@@ -977,7 +1174,7 @@ module Squared
|
|
977
1174
|
def option_clear(opts, target: @session, **kwargs)
|
978
1175
|
kwargs[:subject] ||= target&.first
|
979
1176
|
kwargs[:hint] ||= 'not used'
|
980
|
-
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?
|
981
1178
|
end
|
982
1179
|
|
983
1180
|
def print_item(*val)
|
@@ -1007,7 +1204,7 @@ module Squared
|
|
1007
1204
|
val
|
1008
1205
|
end
|
1009
1206
|
end
|
1010
|
-
out << sub_style(
|
1207
|
+
out << sub_style(ARG[:BORDER][1] * n, styles: border)
|
1011
1208
|
out.join("\n")
|
1012
1209
|
end
|
1013
1210
|
|
@@ -1019,7 +1216,7 @@ module Squared
|
|
1019
1216
|
sub.each { |h| s = sub_style(s, **h) }
|
1020
1217
|
s
|
1021
1218
|
end
|
1022
|
-
ret = [sub_style(
|
1219
|
+
ret = [sub_style(ARG[:BORDER][1] * n, styles: kwargs.key?(:border) ? kwargs[:border] : borderstyle), *lines]
|
1023
1220
|
ret.reverse! if reverse
|
1024
1221
|
ret.join("\n")
|
1025
1222
|
end
|
@@ -1045,7 +1242,7 @@ module Squared
|
|
1045
1242
|
if verbose
|
1046
1243
|
out = []
|
1047
1244
|
if data[:command]
|
1048
|
-
if /\A(?:"((?:[^"]|(?<=\\)")+)"|'((?:[^']|(?<=\\)')+)'|(\S+))
|
1245
|
+
if cmd =~ /\A(?:"((?:[^"]|(?<=\\)")+)"|'((?:[^']|(?<=\\)')+)'|(\S+)) /
|
1049
1246
|
path = $3 || $2 || $1
|
1050
1247
|
cmd = cmd.sub(path, File.basename(path).upcase)
|
1051
1248
|
end
|
@@ -1083,9 +1280,9 @@ module Squared
|
|
1083
1280
|
unless items.empty?
|
1084
1281
|
pad = items.size.to_s.size
|
1085
1282
|
items.each_with_index do |val, i|
|
1086
|
-
next unless reg.empty? || reg.any? { |pat| val[0]
|
1283
|
+
next unless reg.empty? || reg.any? { |pat| val[0].match?(pat) }
|
1087
1284
|
|
1088
|
-
out << "#{
|
1285
|
+
out << "#{i.succ.to_s.rjust(pad)}. #{each ? each.(val) : val[0]}"
|
1089
1286
|
end
|
1090
1287
|
end
|
1091
1288
|
sub = [headerstyle]
|
@@ -1119,9 +1316,9 @@ module Squared
|
|
1119
1316
|
opts.each { |val| target << shell_option(flag, val) }
|
1120
1317
|
end
|
1121
1318
|
|
1122
|
-
def append_hash(data, target: @session)
|
1319
|
+
def append_hash(data, target: @session, build: false)
|
1123
1320
|
target ||= []
|
1124
|
-
if (type = env('BUILD', suffix: 'TYPE') || ENV['BUILD_TYPE'])
|
1321
|
+
if build && (type = env('BUILD', suffix: 'TYPE') || ENV['BUILD_TYPE'])
|
1125
1322
|
type = "__#{type}__"
|
1126
1323
|
if (extra = data[type] || data[type.to_sym]).is_a?(Hash)
|
1127
1324
|
data = data.merge(extra)
|
@@ -1150,7 +1347,7 @@ module Squared
|
|
1150
1347
|
target
|
1151
1348
|
end
|
1152
1349
|
|
1153
|
-
def append_any(val, target: @session, delim: false)
|
1350
|
+
def append_any(val, target: @session, build: false, delim: false)
|
1154
1351
|
if delim && !target.include?('--')
|
1155
1352
|
target << '--'
|
1156
1353
|
else
|
@@ -1160,7 +1357,7 @@ module Squared
|
|
1160
1357
|
when String
|
1161
1358
|
target << val
|
1162
1359
|
when Hash
|
1163
|
-
append_hash(val, target: target)
|
1360
|
+
append_hash(val, target: target, build: build)
|
1164
1361
|
when Enumerable
|
1165
1362
|
if target.is_a?(Array)
|
1166
1363
|
target.concat(val.to_a)
|
@@ -1169,6 +1366,7 @@ module Squared
|
|
1169
1366
|
end
|
1170
1367
|
else
|
1171
1368
|
target.delete('--') if delim
|
1369
|
+
nil
|
1172
1370
|
end
|
1173
1371
|
end
|
1174
1372
|
|
@@ -1177,8 +1375,9 @@ module Squared
|
|
1177
1375
|
|
1178
1376
|
target << '--' if delim && !target.include?('--')
|
1179
1377
|
list.map do |val|
|
1180
|
-
|
1181
|
-
|
1378
|
+
item = escape ? shell_escape(val, quote: quote) : shell_quote(val)
|
1379
|
+
target << item
|
1380
|
+
item
|
1182
1381
|
end
|
1183
1382
|
end
|
1184
1383
|
|
@@ -1186,7 +1385,7 @@ module Squared
|
|
1186
1385
|
**kwargs)
|
1187
1386
|
return if (list = list.flatten).empty?
|
1188
1387
|
|
1189
|
-
list.
|
1388
|
+
list.each do |opt|
|
1190
1389
|
next unless (val = option(opt, **kwargs))
|
1191
1390
|
|
1192
1391
|
return target << (if flag
|
@@ -1203,7 +1402,7 @@ module Squared
|
|
1203
1402
|
return if (list = list.flatten).empty?
|
1204
1403
|
|
1205
1404
|
ret = []
|
1206
|
-
list.
|
1405
|
+
list.each do |flag|
|
1207
1406
|
next unless (val = option(flag, **kwargs))
|
1208
1407
|
|
1209
1408
|
if val == '0' && no
|
@@ -1219,16 +1418,63 @@ module Squared
|
|
1219
1418
|
target << '--no-color' if !ARG[:COLOR] || stdin? || option('no-color', ignore: false)
|
1220
1419
|
end
|
1221
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
|
+
|
1222
1459
|
def collect_hash(data, pass: [])
|
1223
1460
|
ret = []
|
1224
1461
|
data.each { |key, val| ret += val unless pass.include?(key) }
|
1225
1462
|
ret
|
1226
1463
|
end
|
1227
1464
|
|
1228
|
-
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)
|
1229
1475
|
if args && key
|
1230
1476
|
val = args[key]
|
1231
|
-
return val unless val.nil? || (pat && !val.match?(pat))
|
1477
|
+
return val unless val.nil? || (pat && !val.match?(pat)) || (values && !values.include?(val))
|
1232
1478
|
|
1233
1479
|
@session = nil
|
1234
1480
|
raise_error(action, "#{flag}[#{key}]", hint: val.nil? ? 'missing' : 'invalid')
|
@@ -1239,6 +1485,17 @@ module Squared
|
|
1239
1485
|
args
|
1240
1486
|
end
|
1241
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
|
+
|
1242
1499
|
def projectmap(files, parent: false)
|
1243
1500
|
files = files.select { |val| projectpath?(val) } unless parent
|
1244
1501
|
files.map { |val| val == '.' ? '.' : shell_quote(basepath(val.strip)) }
|
@@ -1280,22 +1537,28 @@ module Squared
|
|
1280
1537
|
val.compact.map { |s| color(s) }.flatten
|
1281
1538
|
end
|
1282
1539
|
|
1540
|
+
def epochtime
|
1541
|
+
DateTime.now.strftime('%Q').to_i
|
1542
|
+
end
|
1543
|
+
|
1283
1544
|
def on(event, from, *args, **kwargs)
|
1284
|
-
return unless from
|
1545
|
+
return unless from
|
1285
1546
|
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
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
|
1299
1562
|
end
|
1300
1563
|
end
|
1301
1564
|
end
|
@@ -1336,23 +1599,53 @@ module Squared
|
|
1336
1599
|
end
|
1337
1600
|
|
1338
1601
|
def run_set(cmd, val = nil, opts: nil, **)
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
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
|
1342
1636
|
if opts == false
|
1343
1637
|
@output[1] = false
|
1344
1638
|
elsif opts && opts != true
|
1345
1639
|
@output[1] = opts
|
1346
1640
|
end
|
1347
1641
|
end
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1642
|
+
return if dise
|
1643
|
+
|
1644
|
+
if val.is_a?(Hash)
|
1645
|
+
@output[2] = val
|
1646
|
+
elsif val == false
|
1647
|
+
@output[2] = false
|
1354
1648
|
end
|
1355
|
-
@output[0] = cmd
|
1356
1649
|
end
|
1357
1650
|
|
1358
1651
|
def script_set(cmd, prod: nil, args: nil, **)
|
@@ -1368,6 +1661,8 @@ module Squared
|
|
1368
1661
|
end
|
1369
1662
|
|
1370
1663
|
def as_get(val)
|
1664
|
+
return unless val
|
1665
|
+
|
1371
1666
|
@global && (ret = @as && @as[from] && @as[from][val]) ? ret : val
|
1372
1667
|
end
|
1373
1668
|
|
@@ -1402,19 +1697,20 @@ module Squared
|
|
1402
1697
|
|
1403
1698
|
def runnable?(val)
|
1404
1699
|
case val
|
1405
|
-
when String
|
1700
|
+
when String, Enumerable, Proc, Method
|
1406
1701
|
true
|
1407
|
-
when Enumerable
|
1408
|
-
!val.is_a?(Hash)
|
1409
1702
|
else
|
1410
1703
|
false
|
1411
1704
|
end
|
1412
1705
|
end
|
1413
1706
|
|
1707
|
+
def series?(val)
|
1708
|
+
val.is_a?(Array) && val.all? { |p| p.is_a?(Proc) || p.is_a?(Method) }
|
1709
|
+
end
|
1710
|
+
|
1414
1711
|
def session_arg?(*list, target: @session, value: false)
|
1415
1712
|
list.any? do |val|
|
1416
|
-
|
1417
|
-
target.any? { |opt| opt =~ pat }
|
1713
|
+
target.any? { |opt| opt.match?(/^#{Regexp.escape(shell_option(val))}#{value ? '[ =].' : '(?:[ =]|$)'}/o) }
|
1418
1714
|
end
|
1419
1715
|
end
|
1420
1716
|
|
@@ -1451,6 +1747,10 @@ module Squared
|
|
1451
1747
|
Base.tasks + VAR_SET
|
1452
1748
|
end
|
1453
1749
|
|
1750
|
+
def blocks
|
1751
|
+
BLK_SET
|
1752
|
+
end
|
1753
|
+
|
1454
1754
|
def borderstyle
|
1455
1755
|
((data = workspace.banner_get(*@ref, group: group)) && data[:border]) || theme[:border]
|
1456
1756
|
end
|