squared 0.8.6 → 0.9.0.pre1
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 +35 -25
- data/README.md +158 -126
- data/exe/sqd +224 -0
- data/lib/squared/common/base.rb +7 -3
- data/lib/squared/common/format.rb +8 -3
- data/lib/squared/common/prompt.rb +65 -33
- data/lib/squared/common/shell.rb +3 -1
- data/lib/squared/common/system.rb +2 -9
- data/lib/squared/config.rb +3 -3
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +26 -29
- data/lib/squared/workspace/project/base.rb +104 -61
- data/lib/squared/workspace/project/docker.rb +93 -44
- data/lib/squared/workspace/project/git.rb +65 -96
- data/lib/squared/workspace/project/node.rb +14 -12
- data/lib/squared/workspace/project/python.rb +75 -35
- data/lib/squared/workspace/project/ruby.rb +61 -52
- data/lib/squared/workspace/project/support/class.rb +1 -1
- data/lib/squared/workspace/project/support/optionpartition.rb +16 -28
- data/lib/squared/workspace/repo.rb +5 -5
- data/lib/squared/workspace/series.rb +4 -2
- data/squared.gemspec +7 -5
- metadata +21 -5
|
@@ -102,7 +102,7 @@ module Squared
|
|
|
102
102
|
|
|
103
103
|
@@tasks = {}
|
|
104
104
|
@@graph = { _: [] }
|
|
105
|
-
@@asdf = Pathname.new(ENV['ASDF_DIR'] || "#{Dir.home}/.asdf").
|
|
105
|
+
@@asdf = Pathname.new(ENV['ASDF_DIR'] || "#{Dir.home}/.asdf").then do |path|
|
|
106
106
|
version = if path.join('asdf.sh').exist?
|
|
107
107
|
15
|
|
108
108
|
elsif ENV['ASDF_DATA_DIR'] && (path = Pathname.new(ENV['ASDF_DATA_DIR'])).exist?
|
|
@@ -640,7 +640,7 @@ module Squared
|
|
|
640
640
|
end
|
|
641
641
|
env('GRAPH', suffix: 'PASS') { |val| pass.concat(split_escape(val)) }
|
|
642
642
|
start, neg = start.partition { |name| !name.start_with?('-') }
|
|
643
|
-
data = graph_collect(self, start, pass: neg.map { |name| name[1
|
|
643
|
+
data = graph_collect(self, start, pass: neg.map { |name| name[1..] })
|
|
644
644
|
unless out
|
|
645
645
|
data[name] << self
|
|
646
646
|
on :first, :graph
|
|
@@ -700,7 +700,7 @@ module Squared
|
|
|
700
700
|
headers = headers.is_a?(Hash) ? headers.merge(data) : data
|
|
701
701
|
end
|
|
702
702
|
if file
|
|
703
|
-
ext ||= File.extname(file)[1
|
|
703
|
+
ext ||= File.extname(file)[1..]
|
|
704
704
|
else
|
|
705
705
|
require 'open-uri'
|
|
706
706
|
data = nil
|
|
@@ -876,7 +876,7 @@ module Squared
|
|
|
876
876
|
return
|
|
877
877
|
end
|
|
878
878
|
cmd = cmd.target if cmd.is_a?(OptionPartition)
|
|
879
|
-
if interactive && sync && (
|
|
879
|
+
if interactive && sync && !(@session && option('y'))
|
|
880
880
|
print_item(series: true)
|
|
881
881
|
msg, y, h = case interactive
|
|
882
882
|
when Array
|
|
@@ -924,9 +924,9 @@ module Squared
|
|
|
924
924
|
end
|
|
925
925
|
end
|
|
926
926
|
|
|
927
|
-
def scope(
|
|
927
|
+
def scope(...)
|
|
928
928
|
namespace name do
|
|
929
|
-
task(
|
|
929
|
+
task(...)
|
|
930
930
|
end
|
|
931
931
|
end
|
|
932
932
|
|
|
@@ -1174,20 +1174,10 @@ module Squared
|
|
|
1174
1174
|
ret = basepath(*args)
|
|
1175
1175
|
return ret unless ascend && !ret.exist?
|
|
1176
1176
|
|
|
1177
|
-
case ascend
|
|
1178
|
-
when String, Pathname
|
|
1179
|
-
root = Pathname.new(ascend).cleanpath
|
|
1180
|
-
root = nil unless root.absolute? && root.directory?
|
|
1181
|
-
end
|
|
1182
1177
|
path.parent.ascend.each do |dir|
|
|
1183
1178
|
target = dir.join(*args)
|
|
1184
1179
|
return target if target.exist?
|
|
1185
|
-
|
|
1186
|
-
if root
|
|
1187
|
-
break if dir == root
|
|
1188
|
-
elsif workspace.root == dir || parent&.path == dir || (ascend.is_a?(String) && dir.join(ascend).exist?)
|
|
1189
|
-
break
|
|
1190
|
-
end
|
|
1180
|
+
break if (ascend.is_a?(String) && dir.join(ascend).exist?) || workspace.root == dir || parent&.path == dir
|
|
1191
1181
|
end
|
|
1192
1182
|
ret
|
|
1193
1183
|
end
|
|
@@ -1298,26 +1288,25 @@ module Squared
|
|
|
1298
1288
|
file = if (val = env('LOG_FILE'))
|
|
1299
1289
|
Time.now.strftime(val)
|
|
1300
1290
|
elsif (val = env('LOG_AUTO'))
|
|
1301
|
-
|
|
1291
|
+
d = Time.now
|
|
1302
1292
|
"#{@name}-%s.log" % [case val
|
|
1303
1293
|
when 'y', 'year'
|
|
1304
|
-
|
|
1294
|
+
d.year
|
|
1305
1295
|
when 'm', 'month'
|
|
1306
|
-
|
|
1296
|
+
d.strftime('%Y-%m')
|
|
1307
1297
|
when 'd', 'day', '1'
|
|
1308
|
-
|
|
1298
|
+
d.strftime('%Y-%m-%d')
|
|
1309
1299
|
else
|
|
1310
|
-
val.include?('%') ?
|
|
1300
|
+
val.include?('%') ? d.strftime(val) : d.strftime('%FT%T%:z')
|
|
1311
1301
|
end]
|
|
1312
1302
|
elsif (val = log[:file])
|
|
1313
1303
|
if val.is_a?(String)
|
|
1314
1304
|
Time.now.strftime(val)
|
|
1315
1305
|
else
|
|
1316
|
-
|
|
1317
|
-
"#{@name}-#{Date.today}.log"
|
|
1306
|
+
"#{@name}-#{Time.now.strftime('%Y-%m-%d')}.log"
|
|
1318
1307
|
end
|
|
1319
1308
|
end
|
|
1320
|
-
.
|
|
1309
|
+
.then do |path|
|
|
1321
1310
|
next unless path
|
|
1322
1311
|
|
|
1323
1312
|
@workspace.home.join(env('LOG_DIR', ''), path).realdirpath
|
|
@@ -1375,7 +1364,7 @@ module Squared
|
|
|
1375
1364
|
run(val, var, sync: sync, banner: banner, **kwargs)
|
|
1376
1365
|
end
|
|
1377
1366
|
rescue => e
|
|
1378
|
-
on_error(e, exception: exception?
|
|
1367
|
+
on_error(e, exception: kwargs.fetch(:exception, exception?))
|
|
1379
1368
|
end
|
|
1380
1369
|
on :last, from
|
|
1381
1370
|
end
|
|
@@ -1476,7 +1465,7 @@ module Squared
|
|
|
1476
1465
|
|
|
1477
1466
|
t = uniq.call(name = proj.name)
|
|
1478
1467
|
j = if out
|
|
1479
|
-
if i == items.size.pred || (post = items[i.succ
|
|
1468
|
+
if i == items.size.pred || (post = items[i.succ..] - done).empty?
|
|
1480
1469
|
true
|
|
1481
1470
|
elsif !t.empty? && depth > 0
|
|
1482
1471
|
(post - t).empty?
|
|
@@ -1582,14 +1571,18 @@ module Squared
|
|
|
1582
1571
|
end
|
|
1583
1572
|
|
|
1584
1573
|
def env(key, default = nil, suffix: nil, strict: false, ignore: nil, **kwargs, &blk)
|
|
1585
|
-
name = "#{key}_#{envname_get}"
|
|
1574
|
+
name = suffix == false ? key : "#{key}_#{envname_get}"
|
|
1586
1575
|
ret = if suffix
|
|
1587
1576
|
ENV["#{name}_#{suffix}"] || (ignore == false && ENV["#{key}_#{suffix}"]) || ''
|
|
1588
1577
|
elsif strict
|
|
1589
1578
|
ENV[name].to_s
|
|
1590
1579
|
else
|
|
1591
1580
|
ignore = ['0'].freeze if ignore.nil?
|
|
1592
|
-
|
|
1581
|
+
if key =~ /^(.+)_(FORCE|YES|Y)$/ && !(ret = __arg__($2 == 'Y' ? 'YES' : $2, $1)).nil?
|
|
1582
|
+
ret
|
|
1583
|
+
else
|
|
1584
|
+
ENV[name] || ENV.fetch(key, '')
|
|
1585
|
+
end
|
|
1593
1586
|
end
|
|
1594
1587
|
env_yield(ret, default, ignore: ignore, **kwargs, &blk)
|
|
1595
1588
|
end
|
|
@@ -1693,19 +1686,38 @@ module Squared
|
|
|
1693
1686
|
**kwargs)
|
|
1694
1687
|
return unless prefix
|
|
1695
1688
|
|
|
1689
|
+
getarg = ->(key) { ARG[key][s = prefix.downcase] || ARG[key][s.to_sym] }
|
|
1696
1690
|
args.each do |key|
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1691
|
+
ret = case key.downcase
|
|
1692
|
+
when 'force'
|
|
1693
|
+
getarg.call(:FORCE)
|
|
1694
|
+
when 'y'
|
|
1695
|
+
getarg.call(:YES)
|
|
1696
|
+
end
|
|
1697
|
+
return yield(ret) if !ret.nil? && block_given?
|
|
1698
|
+
|
|
1699
|
+
case ret.to_s
|
|
1700
|
+
when '0'
|
|
1701
|
+
next
|
|
1702
|
+
when 'true'
|
|
1703
|
+
return true
|
|
1704
|
+
when 'false'
|
|
1705
|
+
return false
|
|
1706
|
+
else
|
|
1707
|
+
ret ||= env(env_key(prefix.to_s.stripext, key), **kwargs)
|
|
1708
|
+
next unless ret && (!pat || ret.match?(pat))
|
|
1709
|
+
|
|
1710
|
+
if target
|
|
1711
|
+
if path
|
|
1712
|
+
target << quote_option(key, basepath(ret))
|
|
1713
|
+
elsif quote
|
|
1714
|
+
target << quote_option(key, ret)
|
|
1715
|
+
elsif escape
|
|
1716
|
+
target << shell_option(key, ret)
|
|
1717
|
+
end
|
|
1706
1718
|
end
|
|
1719
|
+
return block_given? ? yield(ret) : ret
|
|
1707
1720
|
end
|
|
1708
|
-
return block_given? ? yield(ret) : ret
|
|
1709
1721
|
end
|
|
1710
1722
|
nil
|
|
1711
1723
|
end
|
|
@@ -1818,6 +1830,8 @@ module Squared
|
|
|
1818
1830
|
|
|
1819
1831
|
case from
|
|
1820
1832
|
when :outdated
|
|
1833
|
+
return if ENV['BANNER'] == 'false'
|
|
1834
|
+
|
|
1821
1835
|
out = print_footer("major #{args[0]} / minor #{args[1]} / patch #{args[2]}", right: true).split("\n")
|
|
1822
1836
|
sub_style!(out[1], **opt_style(theme[:major], /^( +major )(\d+)(.+)$/, 2))
|
|
1823
1837
|
sub_style!(out[1], **opt_style(theme[:active], /^(.+)(minor )(\d+)(.+)$/, 3))
|
|
@@ -2040,27 +2054,27 @@ module Squared
|
|
|
2040
2054
|
val
|
|
2041
2055
|
end
|
|
2042
2056
|
end
|
|
2043
|
-
base.update(data)
|
|
2044
|
-
.update(ret)
|
|
2057
|
+
base.update(data, ret)
|
|
2045
2058
|
end
|
|
2046
2059
|
|
|
2047
2060
|
def merge_opts(base, data)
|
|
2061
|
+
s = '%s %s'
|
|
2048
2062
|
case data
|
|
2049
2063
|
when String
|
|
2050
2064
|
case base
|
|
2051
2065
|
when String
|
|
2052
|
-
|
|
2066
|
+
s % [base, data]
|
|
2053
2067
|
when Hash
|
|
2054
|
-
|
|
2068
|
+
s % [append_hash(base, target: []).join(' '), data]
|
|
2055
2069
|
when Enumerable
|
|
2056
|
-
|
|
2070
|
+
s % [base.to_a.join(' '), data]
|
|
2057
2071
|
else
|
|
2058
2072
|
data
|
|
2059
2073
|
end
|
|
2060
2074
|
when Hash
|
|
2061
2075
|
case base
|
|
2062
2076
|
when String
|
|
2063
|
-
|
|
2077
|
+
s % [base, append_hash(data, target: []).join(' ')]
|
|
2064
2078
|
when Hash
|
|
2065
2079
|
base.merge(data)
|
|
2066
2080
|
when Enumerable
|
|
@@ -2071,9 +2085,9 @@ module Squared
|
|
|
2071
2085
|
when Enumerable
|
|
2072
2086
|
case base
|
|
2073
2087
|
when String
|
|
2074
|
-
|
|
2088
|
+
s % [base, data.to_a.join(' ')]
|
|
2075
2089
|
when Hash
|
|
2076
|
-
|
|
2090
|
+
s % [append_hash(base, target: []).join(' '), data.to_a.join(' ')]
|
|
2077
2091
|
when Enumerable
|
|
2078
2092
|
Set.new(base.to_a + data.to_a).to_a
|
|
2079
2093
|
else
|
|
@@ -2107,6 +2121,17 @@ module Squared
|
|
|
2107
2121
|
end || []
|
|
2108
2122
|
end
|
|
2109
2123
|
|
|
2124
|
+
def parse_select(kwargs = {})
|
|
2125
|
+
pa, ch = ENV.fetch('SELECT', '0:0').split(':').map(&:to_i)
|
|
2126
|
+
if pa > 0
|
|
2127
|
+
kwargs[:page] = pa
|
|
2128
|
+
elsif !kwargs.key?(:page)
|
|
2129
|
+
kwargs[:page] = ARG[:PAGE]
|
|
2130
|
+
end
|
|
2131
|
+
kwargs[:max] = ch if ch > 0
|
|
2132
|
+
kwargs
|
|
2133
|
+
end
|
|
2134
|
+
|
|
2110
2135
|
def param_guard(action, flag, args:, key: nil, pat: nil, values: nil)
|
|
2111
2136
|
if args && key
|
|
2112
2137
|
val = args.fetch(key, nil)
|
|
@@ -2140,9 +2165,9 @@ module Squared
|
|
|
2140
2165
|
end
|
|
2141
2166
|
|
|
2142
2167
|
def choice_index(msg, list, values: nil, accept: nil, series: false, trim: nil, column: nil, multiple: false,
|
|
2143
|
-
force: true, **kwargs)
|
|
2168
|
+
force: true, pipe: self.pipe, **kwargs)
|
|
2144
2169
|
puts unless series || printfirst?
|
|
2145
|
-
ret = choice(msg, list, multiple: multiple, force: force, **kwargs)
|
|
2170
|
+
ret = choice(msg, list, multiple: multiple, force: force, pipe: pipe, **parse_select(kwargs))
|
|
2146
2171
|
unless ret && !ret.empty?
|
|
2147
2172
|
exit 1 if force
|
|
2148
2173
|
return
|
|
@@ -2226,12 +2251,12 @@ module Squared
|
|
|
2226
2251
|
end
|
|
2227
2252
|
|
|
2228
2253
|
def relativepath(*list, all: false)
|
|
2229
|
-
list.
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2254
|
+
list.filter_map do |val|
|
|
2255
|
+
next unless projectpath?(file = Pathname.new(val))
|
|
2256
|
+
|
|
2257
|
+
out = (file.absolute? ? file.relative_path_from(path) : file.cleanpath).to_s
|
|
2258
|
+
all && file.to_s.end_with?('/') ? "#{out}/*" : out
|
|
2259
|
+
end
|
|
2235
2260
|
end
|
|
2236
2261
|
|
|
2237
2262
|
def projectmap(files, resolve: true, parent: false, pass: true)
|
|
@@ -2334,6 +2359,19 @@ module Squared
|
|
|
2334
2359
|
cur[2] == lat[2] ? 3 : 2
|
|
2335
2360
|
end
|
|
2336
2361
|
|
|
2362
|
+
def semapp(name, *args, minor: true, patch: true, pre: false, env: false)
|
|
2363
|
+
if args.empty?
|
|
2364
|
+
args << '--version'
|
|
2365
|
+
else
|
|
2366
|
+
args.map! { |s| shell_quote(s, force: false) }
|
|
2367
|
+
end
|
|
2368
|
+
n = minor ? patch ? pre ? -1 : 4 : 2 : 0
|
|
2369
|
+
IO.popen([shell_bin(name, env: env), *args], chdir: path, &:read).scan(SEM_VER).first
|
|
2370
|
+
&.slice(0..n)&.join or raise
|
|
2371
|
+
rescue
|
|
2372
|
+
'0.0.0'
|
|
2373
|
+
end
|
|
2374
|
+
|
|
2337
2375
|
def semmajor?(cur, want)
|
|
2338
2376
|
(cur[0] == '0' && want[0] == '0' ? cur[2] != want[2] : cur[0] != want[0]) && !want[6]
|
|
2339
2377
|
end
|
|
@@ -2347,7 +2385,7 @@ module Squared
|
|
|
2347
2385
|
end
|
|
2348
2386
|
|
|
2349
2387
|
def indexitem(val)
|
|
2350
|
-
[$1.to_i, $2 && $2[1
|
|
2388
|
+
[$1.to_i, $2 && $2[1..]] if val =~ /\A[=^#{indexchar}](\d+)(:.+)?\z/
|
|
2351
2389
|
end
|
|
2352
2390
|
|
|
2353
2391
|
def indexerror(val, list = nil)
|
|
@@ -2451,7 +2489,6 @@ module Squared
|
|
|
2451
2489
|
def pwd_set(cmd = nil, pass: false, timeout: nil, from: @on[:from].last, **kwargs, &blk)
|
|
2452
2490
|
return if from == false
|
|
2453
2491
|
|
|
2454
|
-
require 'timeout'
|
|
2455
2492
|
unless (path.to_s == Dir.pwd || pass) && (mri? || !windows?)
|
|
2456
2493
|
pwd = Dir.pwd
|
|
2457
2494
|
Dir.chdir(path)
|
|
@@ -2748,7 +2785,15 @@ module Squared
|
|
|
2748
2785
|
end
|
|
2749
2786
|
|
|
2750
2787
|
def dryrun?(target: @session, prefix: target&.first, **)
|
|
2751
|
-
|
|
2788
|
+
val = ENV['DRY_RUN'] if (val = option('dry-run', target: target, prefix: prefix)).nil?
|
|
2789
|
+
case val.to_s
|
|
2790
|
+
when '0' then nil
|
|
2791
|
+
when 'false'
|
|
2792
|
+
return false
|
|
2793
|
+
else
|
|
2794
|
+
return true if val
|
|
2795
|
+
end
|
|
2796
|
+
Array(target).include?('--dry-run')
|
|
2752
2797
|
end
|
|
2753
2798
|
|
|
2754
2799
|
def pwd?
|
|
@@ -2775,9 +2820,7 @@ module Squared
|
|
|
2775
2820
|
workspace.warning
|
|
2776
2821
|
end
|
|
2777
2822
|
|
|
2778
|
-
def exception?(*level
|
|
2779
|
-
return kwargs[:exception] if kwargs.key?(:exception)
|
|
2780
|
-
|
|
2823
|
+
def exception?(*level)
|
|
2781
2824
|
ret = exception
|
|
2782
2825
|
return ret unless ret.is_a?(Numeric)
|
|
2783
2826
|
|
|
@@ -128,6 +128,7 @@ module Squared
|
|
|
128
128
|
'image' => %i[ls rm pull push tag save inspect history].freeze,
|
|
129
129
|
'container' => %i[attach commit create diff exec inspect kill logs pause restart rm run start stats stop top
|
|
130
130
|
unpause update].freeze,
|
|
131
|
+
'run' => %i[rmi rmd mount volume entrypoint].freeze,
|
|
131
132
|
'network' => %i[connect disconnect create rm].freeze,
|
|
132
133
|
'ls' => nil
|
|
133
134
|
})
|
|
@@ -303,13 +304,22 @@ module Squared
|
|
|
303
304
|
end
|
|
304
305
|
end
|
|
305
306
|
else
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
307
|
+
single = %i[logs diff attach top].freeze
|
|
308
|
+
format_desc action, flag, "opts*,id/name#{if flag == :stats
|
|
309
|
+
'*'
|
|
310
|
+
elsif !single.include?(flag)
|
|
311
|
+
'+'
|
|
312
|
+
end}|:"
|
|
311
313
|
task flag do |_, args|
|
|
312
|
-
|
|
314
|
+
args = args.to_a
|
|
315
|
+
if choice!(args, first: false)
|
|
316
|
+
args.concat(Array(choice_command(:container, multiple: !single.include?(flag))))
|
|
317
|
+
if flag == :rm
|
|
318
|
+
stop = filter_ps(:stop, column: 'ID').select { |id| args.include?(id) }
|
|
319
|
+
container :stop, stop if !stop.empty? && confirm_basic('Stop?', stop.join(', '))
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
container flag, args
|
|
313
323
|
end
|
|
314
324
|
end
|
|
315
325
|
when 'image'
|
|
@@ -358,18 +368,47 @@ module Squared
|
|
|
358
368
|
end
|
|
359
369
|
end
|
|
360
370
|
end
|
|
371
|
+
when 'run'
|
|
372
|
+
format_desc action, flag, 'id|:,opts*'
|
|
373
|
+
task flag, [:id] do |_, args|
|
|
374
|
+
id = if args.id == ':'
|
|
375
|
+
choice_command(:image, multiple: false)
|
|
376
|
+
else
|
|
377
|
+
param_guard(action, flag, args: args, key: :id)
|
|
378
|
+
end
|
|
379
|
+
args = case flag
|
|
380
|
+
when :mount
|
|
381
|
+
mount = []
|
|
382
|
+
loop do
|
|
383
|
+
s = readline("Enter mount ##{mount.size.succ}", force: false)
|
|
384
|
+
break if s.empty?
|
|
385
|
+
|
|
386
|
+
mount << (s.include?('type=') ? s : "type=bind,#{s}")
|
|
387
|
+
end
|
|
388
|
+
mount.map { |val| quote_option('mount', val, double: true) }
|
|
389
|
+
when :volume
|
|
390
|
+
choice_command(:volume, multiple: true, series: true).map do |val|
|
|
391
|
+
basic_option 'volume', val
|
|
392
|
+
end
|
|
393
|
+
when :entrypoint
|
|
394
|
+
["entrypoint=#{shell_quote(readline('Entrypoint', force: true), double: true)}"]
|
|
395
|
+
when :rmi
|
|
396
|
+
%w[rm i t]
|
|
397
|
+
when :rmd
|
|
398
|
+
%w[rm d]
|
|
399
|
+
end + args.extras
|
|
400
|
+
container(:run, args.uniq, id: id)
|
|
401
|
+
end
|
|
361
402
|
when 'network'
|
|
362
403
|
format_desc action, flag, 'name,opts*'
|
|
363
404
|
task flag, [:name] do |_, args|
|
|
364
|
-
name =
|
|
365
|
-
param_guard(action, flag, args: args, key: :name)
|
|
366
|
-
else
|
|
367
|
-
args.name
|
|
368
|
-
end
|
|
405
|
+
name = flag == :create ? param_guard(action, flag, args: args, key: :name) : args.name
|
|
369
406
|
if name
|
|
370
407
|
network(flag, args.extras, name: name)
|
|
408
|
+
elsif flag == :rm
|
|
409
|
+
choice_command :'network:rm'
|
|
371
410
|
else
|
|
372
|
-
choice_command
|
|
411
|
+
choice_command(flag, id: choice_command(:container, force: false), series: true)
|
|
373
412
|
end
|
|
374
413
|
end
|
|
375
414
|
end
|
|
@@ -501,7 +540,7 @@ module Squared
|
|
|
501
540
|
if flag == :publish
|
|
502
541
|
id ||= option('tag', ignore: false) || op.shift || tagmain
|
|
503
542
|
registry ||= option('registry') || op.shift || @oci
|
|
504
|
-
|
|
543
|
+
op.clear(strict: true)
|
|
505
544
|
op << shell_quote(tagjoin(registry, id))
|
|
506
545
|
return unless confirm_command(op.to_s, title: from, target: id)
|
|
507
546
|
else
|
|
@@ -516,10 +555,10 @@ module Squared
|
|
|
516
555
|
if multiple
|
|
517
556
|
op.concat(service) if service
|
|
518
557
|
op.append(delim: true, escape: true, strip: ':')
|
|
519
|
-
|
|
520
|
-
raise ArgumentError, message('no service was selected', hint: flag) unless service
|
|
521
|
-
|
|
558
|
+
elsif service
|
|
522
559
|
append_command(flag, service, op.extras, prompt: '::')
|
|
560
|
+
else
|
|
561
|
+
raise ArgumentError, message('no service was selected', hint: flag)
|
|
523
562
|
end
|
|
524
563
|
end
|
|
525
564
|
end
|
|
@@ -668,7 +707,7 @@ module Squared
|
|
|
668
707
|
args = if name
|
|
669
708
|
index += 1
|
|
670
709
|
opts.dup << "name=#{index == 0 ? name : "#{name}-#{index}"}"
|
|
671
|
-
elsif choice!(opts, only: true)
|
|
710
|
+
elsif choice!(opts, empty: true, only: true)
|
|
672
711
|
OptionPartition.strip(readline('Enter arguments', force: false))
|
|
673
712
|
else
|
|
674
713
|
opts
|
|
@@ -720,9 +759,9 @@ module Squared
|
|
|
720
759
|
when :push
|
|
721
760
|
id ||= option('tag', ignore: false) || op.shift || tagmain
|
|
722
761
|
registry ||= option('registry') || op.shift || self.registry
|
|
723
|
-
emptyargs op, flag
|
|
724
762
|
raise ArgumentError, message('username/registry not specified', hint: flag) unless registry
|
|
725
763
|
|
|
764
|
+
op.clear(strict: true)
|
|
726
765
|
uri = shell_quote tagjoin(registry, id)
|
|
727
766
|
op << uri
|
|
728
767
|
img = docker_output 'image tag', id, uri
|
|
@@ -745,7 +784,7 @@ module Squared
|
|
|
745
784
|
success?(run(sync: sync, exception: exception, banner: banner, from: from), status)
|
|
746
785
|
end
|
|
747
786
|
|
|
748
|
-
def network(flag, opts = [],
|
|
787
|
+
def network(flag, opts = [], name: nil)
|
|
749
788
|
cmd, opts = docker_session('network', flag, opts: opts)
|
|
750
789
|
op = OptionPartition.new(opts, OPT_DOCKER[:network].fetch(flag, []), cmd, **dockerinit)
|
|
751
790
|
.clear
|
|
@@ -891,7 +930,7 @@ module Squared
|
|
|
891
930
|
target
|
|
892
931
|
end
|
|
893
932
|
|
|
894
|
-
def filter_ps(flag,
|
|
933
|
+
def filter_ps(flag, column: nil, from: :'container:ps')
|
|
895
934
|
no = false
|
|
896
935
|
status = case flag.to_sym
|
|
897
936
|
when :start
|
|
@@ -927,7 +966,7 @@ module Squared
|
|
|
927
966
|
pwd_set(from: from) do
|
|
928
967
|
index = 1
|
|
929
968
|
all = option('all', prefix: 'docker')
|
|
930
|
-
y = from
|
|
969
|
+
y = from == :'image:rm' && option('y', prefix: 'docker')
|
|
931
970
|
filter = env('DOCKER_FILTER', filter).to_s
|
|
932
971
|
pat = if OptionPartition.pattern?(filter)
|
|
933
972
|
Regexp.new(filter)
|
|
@@ -1009,18 +1048,22 @@ module Squared
|
|
|
1009
1048
|
confirm "#{s} #{sub_style(target, theme[:subject])}#{" as #{sub_style(as, theme[:inline])}" if as}?", 'N'
|
|
1010
1049
|
end
|
|
1011
1050
|
|
|
1012
|
-
def choice_command(flag, *action)
|
|
1051
|
+
def choice_command(flag, *action, id: nil, multiple: nil, series: false, force: true)
|
|
1013
1052
|
msg, cmd = case flag
|
|
1014
|
-
when :exec
|
|
1053
|
+
when :exec, :container
|
|
1015
1054
|
['Choose a container', 'ps -a']
|
|
1016
1055
|
when :bake
|
|
1017
1056
|
['Choose a target', 'buildx bake --list=type=targets']
|
|
1018
|
-
when :connect, :disconnect
|
|
1057
|
+
when :connect, :disconnect, :'network:rm'
|
|
1019
1058
|
['Choose a network', 'network ls']
|
|
1020
1059
|
when :service
|
|
1021
1060
|
['Choose a service',
|
|
1022
1061
|
'compose ps -a ' \
|
|
1023
1062
|
'--format="table {{.Service}}\t{{.Name}}\t{{.Image}}\t{{.Command}}\t{{.Status}}\t{{.Ports}}"']
|
|
1063
|
+
when :volume
|
|
1064
|
+
['Choose a volume',
|
|
1065
|
+
'volume ls ' \
|
|
1066
|
+
'--format="table {{.Name}}\t{{.Driver}}\t{{.Mountpoint}}"']
|
|
1024
1067
|
else
|
|
1025
1068
|
['Choose an image',
|
|
1026
1069
|
'images -a ' \
|
|
@@ -1031,28 +1074,40 @@ module Squared
|
|
|
1031
1074
|
puts log_message('none found', subject: name, hint: "docker #{cmd.split(' ', 3)[0, 2].join(' ')}")
|
|
1032
1075
|
return
|
|
1033
1076
|
end
|
|
1034
|
-
|
|
1035
|
-
|
|
1077
|
+
parse = lambda do |list|
|
|
1078
|
+
ret = Array(list).map { |val| val.split(/\s+/, 2).first }.reject(&:empty?)
|
|
1079
|
+
return ret.first if multiple == false
|
|
1080
|
+
|
|
1081
|
+
ret unless ret.empty?
|
|
1082
|
+
end
|
|
1083
|
+
puts "#{"\n" if id && !printfirst?} # #{lines.shift}"
|
|
1036
1084
|
ctx = flag.to_s
|
|
1037
1085
|
case flag
|
|
1038
1086
|
when :run, :exec
|
|
1039
1087
|
values = [['Options', flag == :run], ['Arguments', flag == :exec]]
|
|
1040
1088
|
when :rm, :bake
|
|
1041
1089
|
values = ['Options']
|
|
1042
|
-
multiple = true
|
|
1090
|
+
multiple = true if multiple.nil?
|
|
1043
1091
|
ctx = flag == :rm ? 'image rm' : "buildx bake -f #{shell_quote(dockerfile)}"
|
|
1044
1092
|
when :save
|
|
1045
1093
|
values = [['Output', true], 'Platform']
|
|
1046
|
-
multiple = true
|
|
1094
|
+
multiple = true if multiple.nil?
|
|
1047
1095
|
when :service
|
|
1048
|
-
values = []
|
|
1049
|
-
multiple = true
|
|
1096
|
+
values = ['Options']
|
|
1097
|
+
multiple = true if multiple.nil?
|
|
1050
1098
|
ctx = 'compose'
|
|
1051
1099
|
when :connect, :disconnect
|
|
1052
|
-
values = ['Options', ['Container', true]]
|
|
1100
|
+
values = id ? ['Options'] : ['Options', ['Container', true]]
|
|
1053
1101
|
ctx = "network #{flag}"
|
|
1102
|
+
when :'network:rm'
|
|
1103
|
+
values = ['Options']
|
|
1104
|
+
multiple = true if multiple.nil?
|
|
1105
|
+
ctx = 'network rm'
|
|
1106
|
+
when :container, :image, :volume
|
|
1107
|
+
return parse.call(choice_index(msg, lines, multiple: multiple, series: series, force: force,
|
|
1108
|
+
attempts: force ? 3 : 1))
|
|
1054
1109
|
end
|
|
1055
|
-
out, opts, args = choice_index(msg, lines, multiple: multiple,
|
|
1110
|
+
out, opts, args = choice_index(msg, lines, values: values, multiple: multiple, series: series)
|
|
1056
1111
|
cmd = docker_output(ctx, *action)
|
|
1057
1112
|
case flag
|
|
1058
1113
|
when :tag
|
|
@@ -1067,8 +1122,10 @@ module Squared
|
|
|
1067
1122
|
else
|
|
1068
1123
|
cmd << opts << '--'
|
|
1069
1124
|
end
|
|
1070
|
-
cmd.merge(
|
|
1071
|
-
|
|
1125
|
+
cmd.merge(parse.call(out))
|
|
1126
|
+
cmd << args
|
|
1127
|
+
cmd.merge(Array(id)) if id
|
|
1128
|
+
success?(run(cmd, { 'NO_COLOR' => 'true' }), ctx.start_with?('network', 'tag', 'save'))
|
|
1072
1129
|
end
|
|
1073
1130
|
|
|
1074
1131
|
def filetype(val = dockerfile)
|
|
@@ -1108,14 +1165,14 @@ module Squared
|
|
|
1108
1165
|
s = val.join(':')
|
|
1109
1166
|
return s unless s.size > max
|
|
1110
1167
|
end
|
|
1111
|
-
ret[
|
|
1168
|
+
ret[...max]
|
|
1112
1169
|
end
|
|
1113
1170
|
|
|
1114
1171
|
def dnsname(val, max: 63, char: nil)
|
|
1115
1172
|
ret = val.sub(/^[^a-z]+/i, '')
|
|
1116
1173
|
.sub(/[^a-z\d]+$/i, '')
|
|
1117
1174
|
.gsub(/[^a-z\d#{char}]+/i, '-')
|
|
1118
|
-
.gsub(/-{2,}/, '-')[
|
|
1175
|
+
.gsub(/-{2,}/, '-')[...max]
|
|
1119
1176
|
char ? ret : ret.downcase
|
|
1120
1177
|
end
|
|
1121
1178
|
|
|
@@ -1123,10 +1180,6 @@ module Squared
|
|
|
1123
1180
|
dnsname(val, max: 128, char: '.').gsub(/\.{2,}/, '.')
|
|
1124
1181
|
end
|
|
1125
1182
|
|
|
1126
|
-
def charname(val)
|
|
1127
|
-
val.gsub(/[^\w.-]+/, '_')
|
|
1128
|
-
end
|
|
1129
|
-
|
|
1130
1183
|
def tagmain
|
|
1131
1184
|
tag.is_a?(Array) ? tag.first : tag
|
|
1132
1185
|
end
|
|
@@ -1135,10 +1188,6 @@ module Squared
|
|
|
1135
1188
|
{ project: self, strict: strict?, explicit: '=', bool: %w[1 0 true false] }
|
|
1136
1189
|
end
|
|
1137
1190
|
|
|
1138
|
-
def emptyargs(list, hint = nil)
|
|
1139
|
-
raise ArgumentError, message('unrecognized args', list.join(', '), hint: hint) unless list.empty?
|
|
1140
|
-
end
|
|
1141
|
-
|
|
1142
1191
|
def anypath?(*args)
|
|
1143
1192
|
args.any? { |val| basepath!(val) }
|
|
1144
1193
|
end
|