squared 0.4.8 → 0.4.9
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 +76 -1
- data/README.ruby.md +44 -31
- data/lib/squared/common/format.rb +10 -17
- data/lib/squared/common/prompt.rb +38 -13
- data/lib/squared/common/shell.rb +21 -14
- data/lib/squared/common/system.rb +2 -2
- data/lib/squared/common/utils.rb +1 -1
- data/lib/squared/config.rb +3 -3
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +11 -15
- data/lib/squared/workspace/project/base.rb +79 -35
- data/lib/squared/workspace/project/docker.rb +22 -24
- data/lib/squared/workspace/project/git.rb +666 -362
- data/lib/squared/workspace/project/node.rb +14 -15
- data/lib/squared/workspace/project/python.rb +35 -41
- data/lib/squared/workspace/project/ruby.rb +133 -105
- data/lib/squared/workspace/project/support/class.rb +29 -13
- data/lib/squared/workspace/repo.rb +4 -4
- data/lib/squared/workspace/series.rb +9 -6
- data/lib/squared/workspace.rb +1 -1
- metadata +3 -3
@@ -213,7 +213,7 @@ module Squared
|
|
213
213
|
file = val.is_a?(String) ? Time.now.strftime(val) : "#{@name}-#{Date.today}.log"
|
214
214
|
end
|
215
215
|
if file
|
216
|
-
file = (val = env('LOG_DIR')) ? @workspace.home.join(val, file) : @workspace.home
|
216
|
+
file = (val = env('LOG_DIR')) ? @workspace.home.join(val, file) : @workspace.home + file
|
217
217
|
begin
|
218
218
|
file = file.realdirpath
|
219
219
|
rescue StandardError => e
|
@@ -225,7 +225,7 @@ module Squared
|
|
225
225
|
end
|
226
226
|
log[:progname] ||= @name
|
227
227
|
if (val = env('LOG_LEVEL', ignore: false))
|
228
|
-
log[:level] = val.match?(
|
228
|
+
log[:level] = val.match?(/\d/) ? log_sym(val.to_i) : val
|
229
229
|
end
|
230
230
|
log.delete(:file)
|
231
231
|
@log = [file, log]
|
@@ -240,10 +240,10 @@ module Squared
|
|
240
240
|
unless @output[0] == false || @output[0].is_a?(Array)
|
241
241
|
if (val = env('BUILD', suffix: 'OPTS'))
|
242
242
|
n = @output[0] ? 1 : 3
|
243
|
-
@output[n] = merge_opts(@output[n], shell_split(val
|
243
|
+
@output[n] = merge_opts(@output[n], shell_split(val))
|
244
244
|
end
|
245
245
|
if (val = env(ref.to_s.upcase, suffix: 'OPTS'))
|
246
|
-
@output[4] = merge_opts(@output[4], shell_split(val
|
246
|
+
@output[4] = merge_opts(@output[4], shell_split(val))
|
247
247
|
end
|
248
248
|
end
|
249
249
|
@version = val if (val = env('BUILD', suffix: 'VERSION'))
|
@@ -324,7 +324,7 @@ module Squared
|
|
324
324
|
else
|
325
325
|
force = args.fetch(:force, false)
|
326
326
|
end
|
327
|
-
unpack(
|
327
|
+
unpack(path + dir, uri: tag, digest: digest, ext: ext, force: force)
|
328
328
|
end
|
329
329
|
end
|
330
330
|
end
|
@@ -401,10 +401,10 @@ module Squared
|
|
401
401
|
self
|
402
402
|
end
|
403
403
|
|
404
|
-
def build(*args, sync: invoked_sync?('build'), from:
|
404
|
+
def build(*args, sync: invoked_sync?('build'), from: :run, **)
|
405
405
|
banner = verbose
|
406
406
|
if args.empty?
|
407
|
-
return unless from ==
|
407
|
+
return unless from == :run
|
408
408
|
|
409
409
|
run_b(@run, sync: sync, from: from) if series?(@run)
|
410
410
|
args = @output
|
@@ -443,7 +443,7 @@ module Squared
|
|
443
443
|
cmd, opts, var, flags, extra = args
|
444
444
|
end
|
445
445
|
if cmd
|
446
|
-
cmd = as_get
|
446
|
+
cmd = as_get cmd
|
447
447
|
opts = compose(opts, script: false) if opts && respond_to?(:compose)
|
448
448
|
flags = append_hash(flags).join(' ') if flags.is_a?(Hash)
|
449
449
|
case opts
|
@@ -461,6 +461,7 @@ module Squared
|
|
461
461
|
return unless (opts || extra) && respond_to?(:compose)
|
462
462
|
|
463
463
|
cmd = compose(as_get(opts), flags, script: true, args: extra, from: from)
|
464
|
+
from = :script if from == :run && script?
|
464
465
|
end
|
465
466
|
run(cmd, var, from: from, banner: banner, sync: sync)
|
466
467
|
end
|
@@ -516,13 +517,13 @@ module Squared
|
|
516
517
|
else
|
517
518
|
if @clean.is_a?(Enumerable) && !series?(@clean)
|
518
519
|
@clean.each do |val|
|
519
|
-
|
520
|
-
if
|
521
|
-
log&.warn "rm -rf #{
|
522
|
-
rm_rf(
|
520
|
+
entry = path + (val = val.to_s)
|
521
|
+
if entry.directory? && val.match?(%r{[\\/]$})
|
522
|
+
log&.warn "rm -rf #{entry}"
|
523
|
+
rm_rf(entry, verbose: verbose)
|
523
524
|
else
|
524
|
-
log&.warn "rm #{
|
525
|
-
(val.include?('*') ? Dir[
|
525
|
+
log&.warn "rm #{entry}"
|
526
|
+
(val.include?('*') ? Dir[entry] : [entry]).each do |file|
|
526
527
|
next unless File.file?(file)
|
527
528
|
|
528
529
|
begin
|
@@ -571,7 +572,7 @@ module Squared
|
|
571
572
|
end
|
572
573
|
end
|
573
574
|
|
574
|
-
def unpack(target, sync: true,
|
575
|
+
def unpack(target, uri:, sync: true, digest: nil, ext: nil, force: false, depth: 1, headers: {},
|
575
576
|
from: :unpack)
|
576
577
|
if !target.exist?
|
577
578
|
target.mkpath
|
@@ -685,7 +686,7 @@ module Squared
|
|
685
686
|
break unless entry.directory?
|
686
687
|
|
687
688
|
i = 0
|
688
|
-
while (dest = target
|
689
|
+
while (dest = target + "#{File.basename(file.path)}-#{i}").exist?
|
689
690
|
i += 1
|
690
691
|
end
|
691
692
|
FileUtils.mv(entry, dest)
|
@@ -915,7 +916,7 @@ module Squared
|
|
915
916
|
end
|
916
917
|
return
|
917
918
|
end
|
918
|
-
cmd = session_done
|
919
|
+
cmd = session_done cmd
|
919
920
|
log&.info cmd
|
920
921
|
on :first, from
|
921
922
|
begin
|
@@ -1122,7 +1123,7 @@ module Squared
|
|
1122
1123
|
end
|
1123
1124
|
ret = JoinSet.new(cmd.flatten(1))
|
1124
1125
|
if options && (val = env("#{prefix}_OPTIONS"))
|
1125
|
-
split_escape(val).each { |opt| ret.last(fill_option(opt),
|
1126
|
+
split_escape(val).each { |opt| ret.last(fill_option(opt), /\A(--?[^ =]+)[ =].+\z/m) }
|
1126
1127
|
end
|
1127
1128
|
main ? @session = ret : ret
|
1128
1129
|
end
|
@@ -1130,7 +1131,7 @@ module Squared
|
|
1130
1131
|
def session_delete(*args, target: @session)
|
1131
1132
|
ret = []
|
1132
1133
|
args.each do |val|
|
1133
|
-
pat =
|
1134
|
+
pat = /\A#{Regexp.escape(shell_option(val))}(?: |=|\z)/
|
1134
1135
|
if (key = target.find { |opt| opt.match?(pat) })
|
1135
1136
|
target.delete(key)
|
1136
1137
|
ret << key
|
@@ -1172,6 +1173,10 @@ module Squared
|
|
1172
1173
|
OptionPartition.clear(target, opts, styles: theme[:inline], **kwargs)
|
1173
1174
|
end
|
1174
1175
|
|
1176
|
+
def print_success(*)
|
1177
|
+
puts 'Success'
|
1178
|
+
end
|
1179
|
+
|
1175
1180
|
def print_item(*val)
|
1176
1181
|
puts if @@print_order > 0 && stdout?
|
1177
1182
|
@@print_order += 1
|
@@ -1204,7 +1209,7 @@ module Squared
|
|
1204
1209
|
|
1205
1210
|
def print_footer(*lines, sub: nil, reverse: false, right: false, **kwargs)
|
1206
1211
|
n = Project.max_width(lines)
|
1207
|
-
sub = as_a
|
1212
|
+
sub = as_a sub
|
1208
1213
|
lines.map! do |val|
|
1209
1214
|
s = right ? val.rjust(n) : val.ljust(n)
|
1210
1215
|
sub.each { |h| s = sub_style(s, **h) }
|
@@ -1471,7 +1476,7 @@ module Squared
|
|
1471
1476
|
end
|
1472
1477
|
end
|
1473
1478
|
|
1474
|
-
def param_guard(action, flag, args
|
1479
|
+
def param_guard(action, flag, args:, key: nil, pat: nil, values: nil)
|
1475
1480
|
if args && key
|
1476
1481
|
val = args.fetch(key, nil)
|
1477
1482
|
return val unless val.nil? || (pat && !val.match?(pat)) || (values && !values.include?(val))
|
@@ -1497,24 +1502,59 @@ module Squared
|
|
1497
1502
|
b = sub_style("#{pkg} #{ver}", styles: theme[:inline])
|
1498
1503
|
c, d = rev == 1 || lock ? ['y/N', 'N'] : ['Y/n', 'Y']
|
1499
1504
|
e = lock ? " #{sub_style('(locked)', styles: color(:red))}" : ''
|
1500
|
-
confirm("Upgrade to #{a}? #{b + e} [#{c}] ", d
|
1505
|
+
confirm("Upgrade to #{a}? #{b + e} [#{c}] ", d)
|
1501
1506
|
end
|
1502
1507
|
|
1503
|
-
def choice_index(msg, list, values: nil, multiple: false, accept: nil, trim: nil
|
1504
|
-
|
1505
|
-
|
1508
|
+
def choice_index(msg, list, values: nil, multiple: false, accept: nil, series: false, trim: nil, column: nil,
|
1509
|
+
attempts: 5, force: true)
|
1510
|
+
puts if !series && @@print_order > 0
|
1511
|
+
msg = "#{msg} (optional)" unless force
|
1512
|
+
unless (ret = choice(msg, list, multiple: multiple, force: force, attempts: attempts)) || !force
|
1513
|
+
raise_error 'user cancelled'
|
1514
|
+
end
|
1515
|
+
if ret.nil? || ret.empty?
|
1516
|
+
return unless force
|
1517
|
+
|
1518
|
+
exit 1
|
1519
|
+
end
|
1506
1520
|
ret = multiple ? ret.map! { |val| val.sub(trim, '') } : ret.sub(trim, '') if trim
|
1507
|
-
|
1521
|
+
if column
|
1522
|
+
a, b = as_a(column)
|
1523
|
+
ret = as_a(ret).map! { |val| val[a, b || 1] }
|
1524
|
+
ret = ret.first unless multiple
|
1525
|
+
end
|
1526
|
+
if accept
|
1527
|
+
a = as_a(ret).map { |val| sub_style(val, styles: theme[:inline]) }.join(', ')
|
1528
|
+
accept = as_a(accept).map { |val| as_a(val) }
|
1529
|
+
if accept.any? { |val| val[1] == true }
|
1530
|
+
ret = [ret]
|
1531
|
+
multiple = -1
|
1532
|
+
end
|
1533
|
+
loop do
|
1534
|
+
c = confirm("#{accept.first[0]}#{a ? " [#{a}]" : ''} [y/N] ", 'N', timeout: 60)
|
1535
|
+
if accept.shift[1] == true
|
1536
|
+
ret << c
|
1537
|
+
elsif !c
|
1538
|
+
break
|
1539
|
+
end
|
1540
|
+
a = nil
|
1541
|
+
break if accept.empty?
|
1542
|
+
end
|
1543
|
+
exit 1 unless accept.empty?
|
1544
|
+
end
|
1508
1545
|
if values
|
1509
|
-
ret = [ret]
|
1546
|
+
ret = [ret] unless accept && multiple == -1
|
1510
1547
|
values.each do |val|
|
1511
|
-
|
1512
|
-
|
1513
|
-
|
1548
|
+
if val.is_a?(Array)
|
1549
|
+
val, force = val
|
1550
|
+
else
|
1551
|
+
force = false
|
1552
|
+
end
|
1553
|
+
val = readline(val, force: force)
|
1514
1554
|
ret << (val.empty? ? nil : val)
|
1515
1555
|
end
|
1516
1556
|
end
|
1517
|
-
@@print_order += 1
|
1557
|
+
@@print_order += 1 unless series
|
1518
1558
|
ret
|
1519
1559
|
end
|
1520
1560
|
|
@@ -1547,7 +1587,7 @@ module Squared
|
|
1547
1587
|
raise_error 'pathspec not within worktree' unless pass || files.size == proj.size
|
1548
1588
|
files = proj
|
1549
1589
|
end
|
1550
|
-
files.map { |val| val == '.' ? '.' : shell_quote(
|
1590
|
+
files.map { |val| val == '.' ? '.' : shell_quote(path + val) }
|
1551
1591
|
end
|
1552
1592
|
|
1553
1593
|
def semver(val)
|
@@ -1583,7 +1623,7 @@ module Squared
|
|
1583
1623
|
end
|
1584
1624
|
|
1585
1625
|
def colormap(val)
|
1586
|
-
val.compact.
|
1626
|
+
val.compact.flat_map { |s| color(s) }
|
1587
1627
|
end
|
1588
1628
|
|
1589
1629
|
def epochtime
|
@@ -1592,7 +1632,7 @@ module Squared
|
|
1592
1632
|
|
1593
1633
|
def verbosetype
|
1594
1634
|
case verbose
|
1595
|
-
when
|
1635
|
+
when TrueClass
|
1596
1636
|
1
|
1597
1637
|
when Numeric
|
1598
1638
|
verbose.succ
|
@@ -1627,7 +1667,7 @@ module Squared
|
|
1627
1667
|
pwd = Pathname.pwd
|
1628
1668
|
if block_given?
|
1629
1669
|
begin
|
1630
|
-
if path == pwd || pass == true || (pass.is_a?(String) && semscan(pass).join
|
1670
|
+
if path == pwd || pass == true || (pass.is_a?(String) && semscan(pass).join <= RUBY_VERSION)
|
1631
1671
|
ret = yield
|
1632
1672
|
else
|
1633
1673
|
Dir.chdir(path)
|
@@ -1794,6 +1834,10 @@ module Squared
|
|
1794
1834
|
end
|
1795
1835
|
end
|
1796
1836
|
|
1837
|
+
def success?(ret)
|
1838
|
+
ret == true && stdout? && banner?
|
1839
|
+
end
|
1840
|
+
|
1797
1841
|
def banner?
|
1798
1842
|
ARG[:BANNER] && !env('BANNER', equals: '0')
|
1799
1843
|
end
|
@@ -4,8 +4,6 @@ module Squared
|
|
4
4
|
module Workspace
|
5
5
|
module Project
|
6
6
|
class Docker < Base
|
7
|
-
include Prompt
|
8
|
-
|
9
7
|
COMPOSEFILE = %w[compose.yaml compose.yml docker-compose.yaml compose.yml docker-compose.yml].freeze
|
10
8
|
BAKEFILE = %w[docker-bake.json docker-bake.hcl docker-bake.override.json docker-bake.override.hcl].freeze
|
11
9
|
DIR_DOCKER = (COMPOSEFILE + BAKEFILE).freeze
|
@@ -37,15 +35,15 @@ module Squared
|
|
37
35
|
run: %w[d|detach init i|interactive no-healthcheck oom-kill-disable privileged P|publish-all q|quiet
|
38
36
|
read-only rm runtime t|tty add-host=q annotation=q a|attach=b blkio-weight-device=i cap-add=b
|
39
37
|
cap-drop=b cgroup-parent=b cgroupns=b cidfile=p detach-keys=q device=q device-cgroup-rule=q
|
40
|
-
device-read-bps=q device-read-iops=q device-write-bps=q device-write-iops=q
|
41
|
-
|
42
|
-
|
43
|
-
health-start-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
38
|
+
device-read-bps=q device-read-iops=q device-write-bps=q device-write-iops=q disable-content-trust=b?
|
39
|
+
dns=e dns-option=e dns-search=e domainname=b entrypoint=q e|env=qq env-file=p expose=e gpus=q
|
40
|
+
group-add=b health-cmd=q health-interval=b health-retries=i health-start-interval=b
|
41
|
+
health-start-period=b health-timeout=b h|hostname=e io-maxbandwidth=b io-maxiops=b ip=b ip6=e ipc=b
|
42
|
+
isolation=b kernel-memory=b l|label=q label-file=p link=b link-local-ip=b log-driver=b log-opt=q
|
43
|
+
mac-address=e memory-swappiness=b mount=qq name=b network=b network-alias=b oom-score-adj=b pid=b
|
44
|
+
platform=b p|publish=e pull=b restart=b runtime=b security-opt=q shm-size=b sig-proxy=b?
|
45
|
+
stop-signal=b stop-timeout=i storage-opt=q sysctl=q tmpfs=q ulimit=q user=e userns=b uts=b
|
46
|
+
v|volume=q volume-driver=b volumes-from=b w|workdir=q].freeze,
|
49
47
|
exec: %w[d|detach i|interactive privileged t|tty detach-keys=q e|env=qq env-file=p user=e
|
50
48
|
w|workdir=q].freeze,
|
51
49
|
update: %w[blkio-weight=i cpu-period=i cpu-quota=i cpu-rt-period=i cpu-rt-runtime=i c|cpu-shares=i cpus=f
|
@@ -163,7 +161,7 @@ module Squared
|
|
163
161
|
when 'container'
|
164
162
|
case flag
|
165
163
|
when :exec, :commit
|
166
|
-
format_desc(action, flag, flag == :exec ? 'id/name
|
164
|
+
format_desc(action, flag, flag == :exec ? 'id/name,opts*,args+' : 'id/name,tag?,opts*')
|
167
165
|
task flag, [:id] do |_, args|
|
168
166
|
if flag == :exec && !args.id
|
169
167
|
choice_command flag
|
@@ -173,7 +171,7 @@ module Squared
|
|
173
171
|
end
|
174
172
|
end
|
175
173
|
when :run
|
176
|
-
format_desc action, flag, 'image
|
174
|
+
format_desc action, flag, 'image,opts*,args*'
|
177
175
|
task flag, [:image] do |_, args|
|
178
176
|
if args.image
|
179
177
|
container(flag, args.extras, id: args.image)
|
@@ -204,8 +202,8 @@ module Squared
|
|
204
202
|
when 'network'
|
205
203
|
format_desc action, flag, 'target,opts*'
|
206
204
|
task flag, [:target] do |_, args|
|
207
|
-
if
|
208
|
-
network(flag, args.extras, target: target)
|
205
|
+
if args.target
|
206
|
+
network(flag, args.extras, target: args.target)
|
209
207
|
else
|
210
208
|
choice_command flag
|
211
209
|
end
|
@@ -307,7 +305,7 @@ module Squared
|
|
307
305
|
end
|
308
306
|
end
|
309
307
|
op.append(args, escape: true)
|
310
|
-
contextdir
|
308
|
+
contextdir context if context
|
311
309
|
end
|
312
310
|
end
|
313
311
|
op.clear(pass: false)
|
@@ -361,7 +359,7 @@ module Squared
|
|
361
359
|
args << k
|
362
360
|
next
|
363
361
|
when 'source', 'src', 'destination', 'dst', 'target'
|
364
|
-
v =
|
362
|
+
v = path + v
|
365
363
|
v = shell_quote(v, option: false, force: false) if q == ''
|
366
364
|
tmpfs = false if k[0] == 's'
|
367
365
|
end
|
@@ -420,7 +418,7 @@ module Squared
|
|
420
418
|
when :rm
|
421
419
|
status = %w[created exited dead]
|
422
420
|
end
|
423
|
-
ps = docker_output('ps -a', *status.map { |s| "--filter
|
421
|
+
ps = docker_output('ps -a', *status.map { |s| "--filter=\"status=#{s}\"" })
|
424
422
|
list_image(flag, ps, no: no, hint: "status: #{status.join(', ')}", from: from) do |img|
|
425
423
|
run(cmd.temp(img), from: from)
|
426
424
|
end
|
@@ -489,7 +487,7 @@ module Squared
|
|
489
487
|
op.clear
|
490
488
|
from = :"network:#{flag}"
|
491
489
|
list_image(flag, docker_output('ps -a'), from: from) do |img|
|
492
|
-
|
490
|
+
print_success if success?(run(cmd.temp(target, img), from: from))
|
493
491
|
end
|
494
492
|
end
|
495
493
|
|
@@ -550,7 +548,7 @@ module Squared
|
|
550
548
|
def append_file(type, target: @session)
|
551
549
|
return unless type == 2 || type == 4 || @file.is_a?(Array)
|
552
550
|
|
553
|
-
files = as_a(@file).map { |val| quote_option('file',
|
551
|
+
files = as_a(@file).map { |val| quote_option('file', path + val) }
|
554
552
|
if target.is_a?(Set)
|
555
553
|
target.merge(files)
|
556
554
|
else
|
@@ -585,7 +583,7 @@ module Squared
|
|
585
583
|
pwd_set do
|
586
584
|
found = false
|
587
585
|
index = 0
|
588
|
-
pat = /^(?:#{dnsname(name)}|#{tagname(project)}|#{tagmain.split(':').first})(?:[_.,:-]|$)/
|
586
|
+
pat = /^(?:#{dnsname(name)}|#{tagname(project)}|#{tagmain.split(':', 2).first})(?:[_.,:-]|$)/
|
589
587
|
IO.popen(session_done(cmd << '--format=json')).each do |line|
|
590
588
|
data = JSON.parse(line)
|
591
589
|
id = data['ID']
|
@@ -675,7 +673,7 @@ module Squared
|
|
675
673
|
puts " # #{header}"
|
676
674
|
case flag
|
677
675
|
when :run, :exec
|
678
|
-
values = [['Options', flag == :run], ['
|
676
|
+
values = [['Options', flag == :run], ['Arguments', flag == :exec]]
|
679
677
|
cmd = flag.to_s
|
680
678
|
else
|
681
679
|
values = [['Options', false], ['Container', true]]
|
@@ -683,7 +681,7 @@ module Squared
|
|
683
681
|
end
|
684
682
|
out, opts, args = choice_index(msg, lines, values: values)
|
685
683
|
ret = run docker_output(cmd, opts, '--', out.split(/\s+/)[index], args)
|
686
|
-
|
684
|
+
print_success if success?(ret && cmd.start_with?('network'))
|
687
685
|
end
|
688
686
|
end
|
689
687
|
|
@@ -703,7 +701,7 @@ module Squared
|
|
703
701
|
end
|
704
702
|
|
705
703
|
def contextdir(val = nil)
|
706
|
-
val && projectpath?(val) ? shell_quote(
|
704
|
+
val && projectpath?(val) ? shell_quote(path + val) : '.'
|
707
705
|
end
|
708
706
|
|
709
707
|
def tagname(val)
|