squared 0.8.6 → 0.9.0.pre2
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 +45 -1
- data/README.md +155 -114
- data/exe/sqd +219 -0
- data/lib/squared/common/base.rb +7 -3
- data/lib/squared/common/format.rb +8 -3
- data/lib/squared/common/prompt.rb +66 -32
- 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 +24 -13
- data/lib/squared/workspace/project/base.rb +105 -46
- data/lib/squared/workspace/project/docker.rb +93 -44
- data/lib/squared/workspace/project/git.rb +60 -86
- data/lib/squared/workspace/project/node.rb +86 -66
- data/lib/squared/workspace/project/python.rb +62 -23
- data/lib/squared/workspace/project/ruby.rb +52 -37
- data/lib/squared/workspace/project/support/class.rb +1 -1
- data/lib/squared/workspace/project/support/optionpartition.rb +15 -14
- data/lib/squared/workspace/repo.rb +5 -5
- data/lib/squared/workspace/series.rb +4 -2
- data/squared.gemspec +7 -5
- metadata +20 -4
data/exe/sqd
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
$:.unshift(File.expand_path('../lib', __dir__)) if File.exist?(File.expand_path('../squared.gemspec', __dir__))
|
|
5
|
+
|
|
6
|
+
require 'squared'
|
|
7
|
+
require 'rake'
|
|
8
|
+
require 'optparse'
|
|
9
|
+
|
|
10
|
+
class SqdParser < OptionParser
|
|
11
|
+
include Squared::Common::Format
|
|
12
|
+
include Utils
|
|
13
|
+
|
|
14
|
+
attr_reader :options, :global
|
|
15
|
+
|
|
16
|
+
def initialize(*)
|
|
17
|
+
super
|
|
18
|
+
@options = { 'project-args': [], 'project-env': [] }
|
|
19
|
+
@global = []
|
|
20
|
+
@program_name = 'squared'
|
|
21
|
+
@raise_unknown = false
|
|
22
|
+
@require_exact = true
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def parse_global(list, assert:)
|
|
26
|
+
raise ArgumentError, "cannot be used with --#{assert}" if options.key?(assert)
|
|
27
|
+
|
|
28
|
+
ARGV.each_with_index do |val, index|
|
|
29
|
+
if val == '--'
|
|
30
|
+
separator!(index: index)
|
|
31
|
+
break
|
|
32
|
+
end
|
|
33
|
+
next if val.start_with?('-') || val.include?(':') || val.empty?
|
|
34
|
+
|
|
35
|
+
global.concat(list.map { |name| "#{val}:#{name}" })
|
|
36
|
+
ARGV[index] = ''
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def parse_common(list, session:, arg:)
|
|
41
|
+
if list && !list.include?('*')
|
|
42
|
+
session[arg].merge!(list.to_h { |key| [key, 'true'] })
|
|
43
|
+
else
|
|
44
|
+
session[arg] = Hash.new('true')
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def banner_set(val, session:)
|
|
49
|
+
session[:BANNER] = val
|
|
50
|
+
ENV['BANNER'] = val ? 'true' : 'false'
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def color_set(val, session:)
|
|
54
|
+
if (session[:COLOR] = val)
|
|
55
|
+
enable_aixterm
|
|
56
|
+
enable_drawing
|
|
57
|
+
else
|
|
58
|
+
enable_drawing false
|
|
59
|
+
Squared::Common.const_get(:VAR)[:colors].freeze
|
|
60
|
+
end
|
|
61
|
+
ENV['NO_COLOR'] = val ? nil : '1'
|
|
62
|
+
ENV['FORCE_COLOR'] = val ? '2' : '0'
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def run
|
|
66
|
+
parse!(into: options)
|
|
67
|
+
if (project = options[:project])
|
|
68
|
+
pattern, project = project.partition do |val|
|
|
69
|
+
next true if val == '*'
|
|
70
|
+
|
|
71
|
+
val = ".#{val}" if val.start_with?('*')
|
|
72
|
+
val.match?(/[*+\[(]|(?<!\\)\.\.|\{\d+\}/) && Regexp.new(val)
|
|
73
|
+
rescue RegexpError
|
|
74
|
+
false
|
|
75
|
+
end
|
|
76
|
+
pattern.each do |val|
|
|
77
|
+
val = if val == '*'
|
|
78
|
+
'[^:]+'
|
|
79
|
+
else
|
|
80
|
+
val.sub(/^\*/, '.*')
|
|
81
|
+
.sub(/(?<!\.)\*$/, '.*')
|
|
82
|
+
.gsub(/\.([*+])/, '[^:]\1?')
|
|
83
|
+
end
|
|
84
|
+
IO.popen("rake -T \"^#{val}:\"").each { |line| project << $1 if line =~ /\Arake (#{val}):/o }
|
|
85
|
+
end
|
|
86
|
+
exit 1 if project.empty? && !pattern.empty?
|
|
87
|
+
project.uniq!
|
|
88
|
+
options[:'project-env'].each do |val|
|
|
89
|
+
n = val.index('=')
|
|
90
|
+
key = val[...n]
|
|
91
|
+
val = val[n.succ..].stripquote
|
|
92
|
+
project.each { |name| ENV["#{key}_#{env_key(name.split(':').first)}"] = val }
|
|
93
|
+
end
|
|
94
|
+
ARGV.each_with_index do |val, index|
|
|
95
|
+
if val == '--'
|
|
96
|
+
separator!(index: index)
|
|
97
|
+
break
|
|
98
|
+
end
|
|
99
|
+
next unless val.start_with?(':')
|
|
100
|
+
|
|
101
|
+
args = options[:'project-args'].shift
|
|
102
|
+
global.concat(project.map { |name| "#{name}#{val}#{"[#{args}]" if args}" })
|
|
103
|
+
ARGV[index] = ''
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
ARGV.reject!(&:empty?)
|
|
107
|
+
Rake.application.run(global.concat(ARGV))
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def separator!(index:)
|
|
111
|
+
ARGV[index] = '' if ARGV.grep('--').size > 1
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def error_exit(*val, hint)
|
|
115
|
+
raise OptionParser::InvalidArgument, message(*val, hint: hint), caller(1)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
SqdParser.new do |sqd|
|
|
120
|
+
session = Squared::Common::ARG
|
|
121
|
+
sqd.banner = 'Usage: sqd [options] [rake options] [global...] [:targets...] -- [rake targets...]'
|
|
122
|
+
sqd.separator ''
|
|
123
|
+
sqd.on('-R', '--ref STR,STR', Array, 'Run global commands by class reference') do |val|
|
|
124
|
+
sqd.parse_global(val, assert: :group)
|
|
125
|
+
session[:APP][:series_ref_min] = 1
|
|
126
|
+
end
|
|
127
|
+
sqd.on('-G', '--group STR,STR', Array, 'Run global commands by project group') do |val|
|
|
128
|
+
sqd.parse_global(val, assert: :ref)
|
|
129
|
+
end
|
|
130
|
+
sqd.separator ''
|
|
131
|
+
sqd.on('-P', '--project STR,PAT', Array, 'Run project commands with common arguments')
|
|
132
|
+
sqd.on('-a', '--project-args STR,STR', 'Provide command arguments for :targets (multiple)') do |val|
|
|
133
|
+
sqd.options[:'project-args'] << val
|
|
134
|
+
end
|
|
135
|
+
sqd.on('-e', '--project-env KEY=STR', 'Provide command ENV variables for :targets (multiple)') do |val|
|
|
136
|
+
sqd.error_exit('missing value', "#{val}=") unless val.include?('=')
|
|
137
|
+
sqd.options[:'project-env'] << val
|
|
138
|
+
end
|
|
139
|
+
sqd.separator ''
|
|
140
|
+
sqd.on('-s', '--[no-]strict', 'Do not run commands with invalid arguments') do |val|
|
|
141
|
+
session[:STRICT] = val
|
|
142
|
+
ENV['STRICT'] = val ? 'true' : 'false'
|
|
143
|
+
end
|
|
144
|
+
sqd.on('--update', 'Use update strategy for applicable commands') do
|
|
145
|
+
ENV['UPDATE'] = 'true'
|
|
146
|
+
end
|
|
147
|
+
sqd.on('-F', '--force [STR,STR]', Array, 'Enable force through ENV by application') do |val|
|
|
148
|
+
sqd.parse_common(val, session: session, arg: :FORCE)
|
|
149
|
+
end
|
|
150
|
+
sqd.on('-y', '--yes [STR,STR]', Array, 'Enable auto-approve through ENV by application') do |val|
|
|
151
|
+
sqd.parse_common(val, session: session, arg: :YES)
|
|
152
|
+
end
|
|
153
|
+
sqd.on('-d', '--dry-run', 'Run commands without any modifying actions') do
|
|
154
|
+
ENV['DRY_RUN'] = 'true'
|
|
155
|
+
end
|
|
156
|
+
sqd.separator ''
|
|
157
|
+
sqd.on('-S', '--select PAGE[:CHOICE]', 'Prompt menu selection pagination display (e.g. 15:75)') do |val|
|
|
158
|
+
page, choice = val.split(/\D/, 2).map(&:to_i)
|
|
159
|
+
sqd.error_exit('not an integer', val) if choice.nil? ? page == 0 : choice == 0
|
|
160
|
+
session[:PAGE] = page if page > 0
|
|
161
|
+
session[:CHOICE] = choice if choice.to_i > 0
|
|
162
|
+
ENV['SELECT'] = "#{page}:#{choice}"
|
|
163
|
+
end
|
|
164
|
+
sqd.separator ''
|
|
165
|
+
sqd.on('-p', '--pipe 0|1|2', Integer, 'Set file descriptor for communication') do |val|
|
|
166
|
+
sqd.error_exit('out of range', val) unless val.between?(0, 2)
|
|
167
|
+
session[:PIPE] = val
|
|
168
|
+
end
|
|
169
|
+
sqd.on('-o', '--pipe-out FILE', 'Write command data stream to a file') do |val|
|
|
170
|
+
sqd.error_exit("missing an explicit \".#{File::SEPARATOR}\"", val) unless val.include?(File::SEPARATOR)
|
|
171
|
+
session[:OUT] = val
|
|
172
|
+
end
|
|
173
|
+
sqd.on('--fail 0..4', Integer, 'Set application exception level') do |val|
|
|
174
|
+
sqd.error_exit('out of range', val) unless val.between?(0, 4)
|
|
175
|
+
session[:FAIL] = val
|
|
176
|
+
end
|
|
177
|
+
%i[debug info warn error fatal].then do |state|
|
|
178
|
+
values = state + (0..4).map(&:to_s)
|
|
179
|
+
sqd.on('--log-level SEVERITY', values, "Set logger and exception state (#{state.join(', ')})") do |val|
|
|
180
|
+
require 'logger'
|
|
181
|
+
severity = case val
|
|
182
|
+
when :debug then Logger::DEBUG
|
|
183
|
+
when :info then Logger::INFO
|
|
184
|
+
when :warn then Logger::WARN
|
|
185
|
+
when :error then Logger::ERROR
|
|
186
|
+
when :fatal then Logger::FATAL
|
|
187
|
+
else
|
|
188
|
+
val.to_i
|
|
189
|
+
end
|
|
190
|
+
session[:LEVEL] = severity
|
|
191
|
+
ENV['LOG_LEVEL'] = severity.to_s
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
sqd.separator ''
|
|
195
|
+
sqd.on('--[no-]banner', 'Display executing command attributes') do |val|
|
|
196
|
+
sqd.banner_set(val, session: session)
|
|
197
|
+
end
|
|
198
|
+
sqd.on('-x', '--[no-]color', 'Use enhanced styling for terminal output') do |val|
|
|
199
|
+
sqd.color_set(val, session: session)
|
|
200
|
+
end
|
|
201
|
+
sqd.on('-X', '--plain', 'Disable banner and styling for all commands') do
|
|
202
|
+
sqd.banner_set(false, session: session)
|
|
203
|
+
sqd.color_set(false, session: session)
|
|
204
|
+
end
|
|
205
|
+
sqd.on('-v', '--verbose', 'Increase output verbosity (multiple)') do
|
|
206
|
+
unless session[:VERBOSE]
|
|
207
|
+
session[:VERBOSE] = $VERBOSE ? 1 : 0
|
|
208
|
+
sqd.global.unshift('--verbose')
|
|
209
|
+
end
|
|
210
|
+
ENV['VERBOSE'] = (session[:VERBOSE] += 1).to_s
|
|
211
|
+
end
|
|
212
|
+
sqd.on('--version', 'Print the current version') do
|
|
213
|
+
puts Squared::VERSION
|
|
214
|
+
exit 0
|
|
215
|
+
end
|
|
216
|
+
sqd.on('-h', '--help', 'Print the command line options') do
|
|
217
|
+
sqd.help_exit
|
|
218
|
+
end
|
|
219
|
+
end.run
|
data/lib/squared/common/base.rb
CHANGED
|
@@ -11,13 +11,17 @@ module Squared
|
|
|
11
11
|
COMMON: true,
|
|
12
12
|
VERBOSE: nil,
|
|
13
13
|
STRICT: false,
|
|
14
|
+
FORCE: {},
|
|
15
|
+
YES: {},
|
|
16
|
+
APP: {},
|
|
14
17
|
BANNER: true,
|
|
15
|
-
|
|
18
|
+
PAGE: 20,
|
|
19
|
+
CHOICE: 100,
|
|
16
20
|
QUOTE: "'",
|
|
17
21
|
SPACE: ' => ',
|
|
18
22
|
SUCCESS: 'Success',
|
|
19
|
-
GRAPH: %w[| - | \\ -]
|
|
20
|
-
BORDER: %w[| - - - - - | | - -]
|
|
23
|
+
GRAPH: %w[| - | \\ -],
|
|
24
|
+
BORDER: %w[| - - - - - | | - -],
|
|
21
25
|
VIEW: 'view',
|
|
22
26
|
LEVEL: ENV.fetch('LOG_LEVEL', 0).to_i,
|
|
23
27
|
COLOR: ENV.fetch('NO_COLOR', '').empty?
|
|
@@ -50,9 +50,14 @@ module Squared
|
|
|
50
50
|
self
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
-
def enable_drawing
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
def enable_drawing(state = true)
|
|
54
|
+
if state
|
|
55
|
+
ARG[:GRAPH] = BOX_GRAPH unless ARG[:GRAPH].frozen?
|
|
56
|
+
ARG[:BORDER] = BOX_BORDER unless ARG[:BORDER].frozen?
|
|
57
|
+
else
|
|
58
|
+
ARG[:GRAPH].freeze
|
|
59
|
+
ARG[:BORDER].freeze
|
|
60
|
+
end
|
|
56
61
|
self
|
|
57
62
|
end
|
|
58
63
|
|
|
@@ -1,27 +1,21 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'timeout'
|
|
4
|
+
|
|
3
5
|
module Squared
|
|
4
6
|
module Common
|
|
5
7
|
module Prompt
|
|
6
8
|
def self.reline
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
require 'reline'
|
|
13
|
-
Reline
|
|
14
|
-
rescue LoadError
|
|
15
|
-
require 'readline'
|
|
16
|
-
Readline
|
|
17
|
-
end
|
|
18
|
-
end
|
|
9
|
+
require 'reline'
|
|
10
|
+
Reline
|
|
11
|
+
rescue LoadError
|
|
12
|
+
require 'readline'
|
|
13
|
+
Readline
|
|
19
14
|
end
|
|
20
15
|
|
|
21
16
|
module_function
|
|
22
17
|
|
|
23
18
|
def confirm(msg, accept = nil, agree: 'Y', cancel: 'N', force: false, attempts: 3, timeout: 60)
|
|
24
|
-
require 'timeout'
|
|
25
19
|
if agree == 'Y' && cancel == 'N' && !msg.match?(%r{\[(Yn|nY|Y/n|y/N)\]})
|
|
26
20
|
case accept
|
|
27
21
|
when 'Y'
|
|
@@ -34,7 +28,7 @@ module Squared
|
|
|
34
28
|
cancel = /^#{Regexp.escape(cancel)}$/i if cancel.is_a?(::String)
|
|
35
29
|
Timeout.timeout(timeout) do
|
|
36
30
|
while (ch = Prompt.reline.readline(msg))
|
|
37
|
-
ch
|
|
31
|
+
ch.chomp!
|
|
38
32
|
case (ch.empty? ? accept : ch)
|
|
39
33
|
when agree
|
|
40
34
|
return true
|
|
@@ -48,15 +42,15 @@ module Squared
|
|
|
48
42
|
end
|
|
49
43
|
rescue Interrupt
|
|
50
44
|
puts
|
|
51
|
-
exit
|
|
45
|
+
exit
|
|
52
46
|
else
|
|
53
47
|
exit 1 if force
|
|
54
48
|
false
|
|
55
49
|
end
|
|
56
50
|
|
|
57
|
-
def choice(msg, list = nil, min: 1, max:
|
|
58
|
-
|
|
59
|
-
|
|
51
|
+
def choice(msg, list = nil, min: 1, max: nil, multiple: false, index: false, grep: nil, border: nil, force: true,
|
|
52
|
+
attempts: 3, timeout: 0, pipe: 1, scroll: true, empty: nil, page: 25)
|
|
53
|
+
std = pipe == 2 ? $stderr : $stdout
|
|
60
54
|
multiple = Array(multiple) if multiple.is_a?(::Numeric)
|
|
61
55
|
if list
|
|
62
56
|
grep &&= Array(grep).map { |val| Regexp.new(val) }
|
|
@@ -64,33 +58,70 @@ module Squared
|
|
|
64
58
|
next if grep&.none? { |pat| pat.match?(val) }
|
|
65
59
|
|
|
66
60
|
out << val.to_s.chomp
|
|
67
|
-
puts '%2d. %s' % [out.size, val]
|
|
68
61
|
end
|
|
69
|
-
max = items.size
|
|
62
|
+
max = max ? [max, items.size].min : items.size
|
|
70
63
|
if max == 0
|
|
71
64
|
raise ArgumentError, 'empty selection list' unless empty
|
|
72
65
|
|
|
73
66
|
puts empty
|
|
74
67
|
exit 1
|
|
75
68
|
end
|
|
69
|
+
tmpl = "%#{[items.size.to_s.size, 2].max}d. %s"
|
|
70
|
+
items = items.map.with_index { |item, i| [item, tmpl % [i.succ, item]] }
|
|
76
71
|
min = grep ? 1 : [min, max].min
|
|
77
|
-
|
|
78
|
-
|
|
72
|
+
require 'io/console'
|
|
73
|
+
if min > 1 || max < items.size
|
|
74
|
+
items = items[min.pred...max]
|
|
75
|
+
min = 1
|
|
76
|
+
end
|
|
77
|
+
page = page ? [page, max].min : max
|
|
78
|
+
cur = 0
|
|
79
|
+
line = 0
|
|
80
|
+
last = (max / page.to_f).ceil
|
|
81
|
+
pre = msg
|
|
82
|
+
scroll = true if border
|
|
83
|
+
clear = -> { std.print "\r\e[K" }
|
|
84
|
+
write = lambda do |s, buf = true|
|
|
85
|
+
line += [s.lines.size, 1].max if buf
|
|
86
|
+
clear.call unless scroll && !border
|
|
87
|
+
std.puts s
|
|
88
|
+
end
|
|
89
|
+
render = lambda do |index, init = false|
|
|
90
|
+
fr = index * page
|
|
91
|
+
to = [fr + page, max].min
|
|
92
|
+
unless init
|
|
93
|
+
std.cursor_up((scroll ? 0 : page) + line.succ)
|
|
94
|
+
clear.call
|
|
95
|
+
end
|
|
96
|
+
line = 0
|
|
97
|
+
items[fr...to].each { |item| write.call(item.last, false) }
|
|
79
98
|
if border == true
|
|
80
|
-
|
|
99
|
+
write.call(print_footer)
|
|
81
100
|
elsif border
|
|
82
|
-
|
|
101
|
+
write.call(print_footer(border: border))
|
|
102
|
+
end
|
|
103
|
+
fr = scroll ? 1 : fr.succ
|
|
104
|
+
suf = "|,#{multiple.is_a?(::Array) ? "{#{multiple.join(',')}}" : '*'}" if multiple
|
|
105
|
+
msg = "#{pre + (force ? ':' : '?')} [#{fr}-#{to}#{"/#{max}" if scroll && to < max}#{suf}] "
|
|
106
|
+
if cur == last.pred
|
|
107
|
+
cur = -1
|
|
108
|
+
last = 0 if scroll || (attempts -= 1) == 0
|
|
109
|
+
end
|
|
110
|
+
if init && last > 1 && !scroll
|
|
111
|
+
write.call('', false)
|
|
112
|
+
std.cursor_up(1)
|
|
83
113
|
end
|
|
84
|
-
msg = "#{msg + (force ? ':' : '?')} [#{min}-#{max}#{if (n = multiple)
|
|
85
|
-
"|,#{n.is_a?(::Array) ? "{#{n.join(',')}}" : '*'}"
|
|
86
|
-
end}] "
|
|
87
114
|
end
|
|
115
|
+
render.call(0, true)
|
|
116
|
+
else
|
|
117
|
+
max ||= 1
|
|
118
|
+
last = 0
|
|
88
119
|
end
|
|
89
120
|
between = ->(s) { s.match?(/^\d+$/) && s.to_i.between?(min, max <= min ? Float::INFINITY : max) }
|
|
90
121
|
Timeout.timeout(timeout) do
|
|
91
122
|
while (ch = Prompt.reline.readline(msg))
|
|
92
123
|
ch.strip!
|
|
93
|
-
|
|
124
|
+
if !ch.empty?
|
|
94
125
|
if ch == '-' && !force
|
|
95
126
|
break
|
|
96
127
|
elsif multiple
|
|
@@ -114,12 +145,15 @@ module Squared
|
|
|
114
145
|
k.uniq!
|
|
115
146
|
k.sort!
|
|
116
147
|
unless multiple.is_a?(::Array) && !multiple.include?(k.size)
|
|
117
|
-
return index || !items ? k : k.map { |i| items[i.pred] }
|
|
148
|
+
return index || !items ? k : k.map { |i| items[i.pred].first }
|
|
118
149
|
end
|
|
119
150
|
end
|
|
120
151
|
elsif between.call(ch)
|
|
121
|
-
return index || !items ? ch.to_i : items[ch.to_i.pred]
|
|
152
|
+
return index || !items ? ch.to_i : items[ch.to_i.pred].first
|
|
122
153
|
end
|
|
154
|
+
elsif last > 0
|
|
155
|
+
render.call(cur += 1)
|
|
156
|
+
next
|
|
123
157
|
end
|
|
124
158
|
attempts -= 1
|
|
125
159
|
next if attempts > 0
|
|
@@ -128,8 +162,8 @@ module Squared
|
|
|
128
162
|
break
|
|
129
163
|
end
|
|
130
164
|
rescue Interrupt
|
|
131
|
-
puts
|
|
132
|
-
exit
|
|
165
|
+
std.puts
|
|
166
|
+
exit
|
|
133
167
|
else
|
|
134
168
|
[] if multiple
|
|
135
169
|
end
|
data/lib/squared/common/shell.rb
CHANGED
|
@@ -167,7 +167,9 @@ module Squared
|
|
|
167
167
|
end
|
|
168
168
|
|
|
169
169
|
def line_width(lines)
|
|
170
|
-
|
|
170
|
+
require 'io/console/size'
|
|
171
|
+
cols = IO.default_console_size.last
|
|
172
|
+
[lines.empty? ? cols : [lines.max_by(&:size).size, cols].max, Rake.application.terminal_width].min
|
|
171
173
|
end
|
|
172
174
|
|
|
173
175
|
def fill_option(val, **kwargs)
|
|
@@ -28,15 +28,8 @@ module Squared
|
|
|
28
28
|
module_function
|
|
29
29
|
|
|
30
30
|
def shell(*args, name: :system, **kwargs)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
elsif RUBY_VERSION < '2.6'
|
|
34
|
-
ex = kwargs.delete(:exception)
|
|
35
|
-
end
|
|
36
|
-
ret = Kernel.send(name, *args, **kwargs)
|
|
37
|
-
raise $?.to_s if ex && !ret
|
|
38
|
-
|
|
39
|
-
ret
|
|
31
|
+
kwargs.delete(:exception) unless name == :system
|
|
32
|
+
Kernel.send(name, *args, **kwargs)
|
|
40
33
|
end
|
|
41
34
|
|
|
42
35
|
def shell_t(*args, timeout: 0, **kwargs)
|
data/lib/squared/config.rb
CHANGED
|
@@ -65,7 +65,7 @@ module Squared
|
|
|
65
65
|
command = File.basename(@main)
|
|
66
66
|
command = ARG[:VIEW] if command == @name
|
|
67
67
|
end
|
|
68
|
-
ext = @ext[1
|
|
68
|
+
ext = @ext[1..].downcase
|
|
69
69
|
if (data = @@mime_obj[ext])
|
|
70
70
|
add(data[1].first, command: command, opts: opts, ext: data[1])
|
|
71
71
|
else
|
|
@@ -98,7 +98,7 @@ module Squared
|
|
|
98
98
|
namespace task_name(name) do |ns|
|
|
99
99
|
@mime.each do |type, items|
|
|
100
100
|
items.each do |command, file, opts|
|
|
101
|
-
next if Rake::Task.task_defined?(
|
|
101
|
+
next if Rake::Task.task_defined?(task_join(ns.scope.path, command, type))
|
|
102
102
|
|
|
103
103
|
namespace command do
|
|
104
104
|
unless (data = @@mime_obj[type])
|
|
@@ -288,7 +288,7 @@ module Squared
|
|
|
288
288
|
if project
|
|
289
289
|
project.workspace.task_name(val)
|
|
290
290
|
else
|
|
291
|
-
@prefix ?
|
|
291
|
+
@prefix ? task_join(@prefix, val) : val.to_s
|
|
292
292
|
end
|
|
293
293
|
end
|
|
294
294
|
|
data/lib/squared/version.rb
CHANGED
|
@@ -163,6 +163,9 @@ module Squared
|
|
|
163
163
|
end
|
|
164
164
|
@pass.items.concat(kwargs[:pass].map { |val| val.is_a?(Regexp) ? val : val.to_s }) if kwargs[:pass]
|
|
165
165
|
@series = Application.register(self, @base.to_a, exclude: kwargs.fetch(:exclude, []))
|
|
166
|
+
if (n = ARG[:APP][:series_ref_min])
|
|
167
|
+
@series.ref_min = n
|
|
168
|
+
end
|
|
166
169
|
self.closed = 'begin'
|
|
167
170
|
pb = @stage.key?('project:begin')
|
|
168
171
|
pe = @stage.key?('project:end')
|
|
@@ -341,7 +344,7 @@ module Squared
|
|
|
341
344
|
case val
|
|
342
345
|
when Symbol
|
|
343
346
|
found = true
|
|
344
|
-
banner_include?(val)
|
|
347
|
+
banner_include?(val, ref: ref)
|
|
345
348
|
when String
|
|
346
349
|
true
|
|
347
350
|
else
|
|
@@ -353,7 +356,7 @@ module Squared
|
|
|
353
356
|
elsif meth.size == 1
|
|
354
357
|
meth = meth.first
|
|
355
358
|
end
|
|
356
|
-
elsif !banner_include?(meth = meth.to_sym)
|
|
359
|
+
elsif !banner_include?(meth = meth.to_sym, ref: ref)
|
|
357
360
|
next
|
|
358
361
|
end
|
|
359
362
|
data.order << meth
|
|
@@ -409,7 +412,11 @@ module Squared
|
|
|
409
412
|
end || @kind[name]&.last
|
|
410
413
|
if proj
|
|
411
414
|
@base << proj
|
|
412
|
-
|
|
415
|
+
args = Array(proj.bannerargs)
|
|
416
|
+
unless args.empty?
|
|
417
|
+
@banner.store[proj.ref] = args
|
|
418
|
+
@banner.items.concat(args)
|
|
419
|
+
end
|
|
413
420
|
else
|
|
414
421
|
proj = Application.impl_project
|
|
415
422
|
end
|
|
@@ -590,7 +597,7 @@ module Squared
|
|
|
590
597
|
def task_namespace(val, first: false)
|
|
591
598
|
return unless (ret = val.to_s.split(':')).size > 1
|
|
592
599
|
|
|
593
|
-
first ? ret.first : task_join(*ret[
|
|
600
|
+
first ? ret.first : task_join(*ret[..-2])
|
|
594
601
|
end
|
|
595
602
|
|
|
596
603
|
def task_resolve(obj, key)
|
|
@@ -960,7 +967,7 @@ module Squared
|
|
|
960
967
|
key = task_name(task_join(name, target))
|
|
961
968
|
sync = true
|
|
962
969
|
exception = exception?
|
|
963
|
-
if store && (kwargs = store[
|
|
970
|
+
if store && (kwargs = store[task_join(target, name)])
|
|
964
971
|
sync = kwargs[:sync] if kwargs.key?(:sync)
|
|
965
972
|
exception = kwargs[:exception] if kwargs.key?(:exception)
|
|
966
973
|
end
|
|
@@ -981,9 +988,11 @@ module Squared
|
|
|
981
988
|
end
|
|
982
989
|
end
|
|
983
990
|
when Array
|
|
984
|
-
cmd =
|
|
985
|
-
|
|
986
|
-
|
|
991
|
+
cmd = items.filter_map do |proj|
|
|
992
|
+
next unless task_defined?(out = task_join(proj.name, args.first))
|
|
993
|
+
|
|
994
|
+
out
|
|
995
|
+
end
|
|
987
996
|
next if cmd.empty?
|
|
988
997
|
|
|
989
998
|
args = args.drop(1)
|
|
@@ -1024,7 +1033,7 @@ module Squared
|
|
|
1024
1033
|
@events[label][name][task] = on
|
|
1025
1034
|
end
|
|
1026
1035
|
data[label][name][task] = val
|
|
1027
|
-
(data.store[label] ||= {})[
|
|
1036
|
+
(data.store[label] ||= {})[task_join(name, task)] = store if store
|
|
1028
1037
|
end
|
|
1029
1038
|
self
|
|
1030
1039
|
end
|
|
@@ -1038,7 +1047,7 @@ module Squared
|
|
|
1038
1047
|
Array(group).each do |val|
|
|
1039
1048
|
val = val.to_s
|
|
1040
1049
|
if val.start_with?('-')
|
|
1041
|
-
target[:exclude] << val[1
|
|
1050
|
+
target[:exclude] << val[1..]
|
|
1042
1051
|
else
|
|
1043
1052
|
target[:group][val] = data
|
|
1044
1053
|
end
|
|
@@ -1047,7 +1056,7 @@ module Squared
|
|
|
1047
1056
|
Array(ref).each do |val|
|
|
1048
1057
|
val = val.to_s
|
|
1049
1058
|
if val.start_with?('-')
|
|
1050
|
-
target[:exclude] << val[1
|
|
1059
|
+
target[:exclude] << val[1..].to_sym
|
|
1051
1060
|
else
|
|
1052
1061
|
target[:ref][val.to_sym] = data
|
|
1053
1062
|
end
|
|
@@ -1125,8 +1134,10 @@ module Squared
|
|
|
1125
1134
|
exception != false && exception != Logger::INFO
|
|
1126
1135
|
end
|
|
1127
1136
|
|
|
1128
|
-
def banner_include?(val)
|
|
1129
|
-
Application.attr_banner.include?(val)
|
|
1137
|
+
def banner_include?(val, ref: nil)
|
|
1138
|
+
return true if Application.attr_banner.include?(val)
|
|
1139
|
+
|
|
1140
|
+
ref ? Array(ref).any? { |proj| @banner.store[proj]&.include?(val) } : @banner.items.include?(val)
|
|
1130
1141
|
end
|
|
1131
1142
|
|
|
1132
1143
|
def scriptobj
|