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
data/exe/sqd
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
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)
|
|
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
|
+
|
|
138
|
+
sqd.options[:'project-env'] << val
|
|
139
|
+
end
|
|
140
|
+
sqd.separator ''
|
|
141
|
+
sqd.on('-s', '--[no-]strict', 'Do not run commands with invalid arguments') do |val|
|
|
142
|
+
session[:STRICT] = val
|
|
143
|
+
ENV['STRICT'] = val ? 'true' : 'false'
|
|
144
|
+
end
|
|
145
|
+
sqd.on('--update', 'Use update strategy for applicable commands') do
|
|
146
|
+
ENV['UPDATE'] = 'true'
|
|
147
|
+
end
|
|
148
|
+
sqd.on('-F', '--force [STR,STR]', Array, 'Enable force through ENV by application') do |val|
|
|
149
|
+
sqd.parse_common(val, session: session, arg: :FORCE)
|
|
150
|
+
end
|
|
151
|
+
sqd.on('-y', '--yes [STR,STR]', Array, 'Enable auto-approve through ENV by application') do |val|
|
|
152
|
+
sqd.parse_common(val, session: session, arg: :YES)
|
|
153
|
+
end
|
|
154
|
+
sqd.on('-d', '--dry-run', 'Run commands without any modifying actions') do
|
|
155
|
+
ENV['DRY_RUN'] = 'true'
|
|
156
|
+
end
|
|
157
|
+
sqd.separator ''
|
|
158
|
+
sqd.on('-S', '--select PAGE:CHOICE', 'Prompt menu selection pagination limits') do |val|
|
|
159
|
+
page, choice = val.split(/\D/, 2).map(&:to_i)
|
|
160
|
+
sqd.error_exit('not an integer', val) if choice.nil? ? page == 0 : choice == 0
|
|
161
|
+
|
|
162
|
+
session[:PAGE] = page if page > 0
|
|
163
|
+
session[:CHOICE] = choice if choice.to_i > 0
|
|
164
|
+
ENV['SELECT'] = "#{page}:#{choice}"
|
|
165
|
+
end
|
|
166
|
+
sqd.separator ''
|
|
167
|
+
sqd.on('-p', '--pipe 0|1|2', Integer, 'Set file descriptor for communication') do |val|
|
|
168
|
+
sqd.error_exit('out of range', val) unless val.between?(0, 2)
|
|
169
|
+
|
|
170
|
+
session[:PIPE] = val
|
|
171
|
+
end
|
|
172
|
+
sqd.on('-o', '--pipe-out FILE', 'Write command data stream to a file') do |val|
|
|
173
|
+
sqd.error_exit("missing an explicit \".#{File::SEPARATOR}\"", val) unless val.include?(File::SEPARATOR)
|
|
174
|
+
|
|
175
|
+
session[:OUT] = val
|
|
176
|
+
end
|
|
177
|
+
sqd.on('--fail 0..4', Integer, 'Set application exception level') do |val|
|
|
178
|
+
sqd.error_exit('out of range', val) unless val.between?(0, 4)
|
|
179
|
+
|
|
180
|
+
session[:FAIL] = val
|
|
181
|
+
end
|
|
182
|
+
%i[debug info warn error fatal].then do |state|
|
|
183
|
+
values = state + (0..4).map(&:to_s)
|
|
184
|
+
sqd.on('--log-level SEVERITY', values, "Set logger and exception state (#{state.join(', ')})") do |val|
|
|
185
|
+
require 'logger'
|
|
186
|
+
severity = case val
|
|
187
|
+
when :debug then Logger::DEBUG
|
|
188
|
+
when :info then Logger::INFO
|
|
189
|
+
when :warn then Logger::WARN
|
|
190
|
+
when :error then Logger::ERROR
|
|
191
|
+
when :fatal then Logger::FATAL
|
|
192
|
+
else
|
|
193
|
+
val.to_i
|
|
194
|
+
end
|
|
195
|
+
session[:LEVEL] = severity
|
|
196
|
+
ENV['LOG_LEVEL'] = severity.to_s
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
sqd.separator ''
|
|
200
|
+
sqd.on('--[no-]banner', 'Display executing command attributes') do |val|
|
|
201
|
+
sqd.banner_set(val, session: session)
|
|
202
|
+
end
|
|
203
|
+
sqd.on('-x', '--[no-]color', 'Use enhanced styling for terminal output') do |val|
|
|
204
|
+
sqd.color_set(val, session: session)
|
|
205
|
+
end
|
|
206
|
+
sqd.on('-X', '--plain', 'Disable banner and styling for all commands') do
|
|
207
|
+
sqd.banner_set(false, session: session)
|
|
208
|
+
sqd.color_set(false, session: session)
|
|
209
|
+
end
|
|
210
|
+
sqd.on('-v', '--verbose', 'Increase output verbosity (multiple)') do
|
|
211
|
+
unless session[:VERBOSE]
|
|
212
|
+
session[:VERBOSE] = $VERBOSE ? 1 : 0
|
|
213
|
+
sqd.global.unshift('--verbose')
|
|
214
|
+
end
|
|
215
|
+
ENV['VERBOSE'] = (session[:VERBOSE] += 1).to_s
|
|
216
|
+
end
|
|
217
|
+
sqd.on('--version', 'Print the current version') do
|
|
218
|
+
puts Squared::VERSION
|
|
219
|
+
exit 0
|
|
220
|
+
end
|
|
221
|
+
sqd.on('-h', '--help', 'Print the command line options') do
|
|
222
|
+
sqd.help_exit
|
|
223
|
+
end
|
|
224
|
+
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
|
|
@@ -54,9 +48,9 @@ module Squared
|
|
|
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,36 +58,71 @@ 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
|
-
|
|
94
|
-
if
|
|
95
|
-
break
|
|
96
|
-
elsif multiple
|
|
124
|
+
if !ch.empty?
|
|
125
|
+
if multiple
|
|
97
126
|
k = if ch == '*'
|
|
98
127
|
(min..max).to_a
|
|
99
128
|
else
|
|
@@ -114,12 +143,15 @@ module Squared
|
|
|
114
143
|
k.uniq!
|
|
115
144
|
k.sort!
|
|
116
145
|
unless multiple.is_a?(::Array) && !multiple.include?(k.size)
|
|
117
|
-
return index || !items ? k : k.map { |i| items[i.pred] }
|
|
146
|
+
return index || !items ? k : k.map { |i| items[i.pred].first }
|
|
118
147
|
end
|
|
119
148
|
end
|
|
120
149
|
elsif between.call(ch)
|
|
121
|
-
return index || !items ? ch.to_i : items[ch.to_i.pred]
|
|
150
|
+
return index || !items ? ch.to_i : items[ch.to_i.pred].first
|
|
122
151
|
end
|
|
152
|
+
elsif last > 0
|
|
153
|
+
render.call(cur += 1)
|
|
154
|
+
next
|
|
123
155
|
end
|
|
124
156
|
attempts -= 1
|
|
125
157
|
next if attempts > 0
|
|
@@ -128,7 +160,7 @@ module Squared
|
|
|
128
160
|
break
|
|
129
161
|
end
|
|
130
162
|
rescue Interrupt
|
|
131
|
-
puts
|
|
163
|
+
std.puts
|
|
132
164
|
exit 0
|
|
133
165
|
else
|
|
134
166
|
[] if multiple
|
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
|
|
@@ -403,13 +406,17 @@ module Squared
|
|
|
403
406
|
end
|
|
404
407
|
unless ref.is_a?(Symbol) && (proj = @base.find { |item| item.ref == ref })
|
|
405
408
|
proj = if !ref.is_a?(Class)
|
|
406
|
-
|
|
409
|
+
require_project(ref) || Application.find(ref: ref, path: path)
|
|
407
410
|
elsif Application.extends(ref)
|
|
408
411
|
ref
|
|
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
|
|
@@ -447,16 +454,6 @@ module Squared
|
|
|
447
454
|
self
|
|
448
455
|
end
|
|
449
456
|
|
|
450
|
-
def assign(ref = @ref, &blk)
|
|
451
|
-
proj = ref && find_project(ref: ref)
|
|
452
|
-
if proj
|
|
453
|
-
proj.class_eval(&blk)
|
|
454
|
-
else
|
|
455
|
-
warn log_message(Logger::ERROR, 'class not found', subject: main, hint: ref)
|
|
456
|
-
end
|
|
457
|
-
self
|
|
458
|
-
end
|
|
459
|
-
|
|
460
457
|
def stage(val, first: false, &blk)
|
|
461
458
|
data = @stage[val]
|
|
462
459
|
if first == true
|
|
@@ -484,7 +481,7 @@ module Squared
|
|
|
484
481
|
obj = begin
|
|
485
482
|
JSON.parse(homepath(obj).read, { symbolize_names: true })
|
|
486
483
|
rescue => e
|
|
487
|
-
warn log_message(Logger::ERROR, e
|
|
484
|
+
warn log_message(Logger::ERROR, e)
|
|
488
485
|
end
|
|
489
486
|
end
|
|
490
487
|
apply_style(data || theme, obj, args, empty: empty) if obj && (!target || data)
|
|
@@ -590,7 +587,7 @@ module Squared
|
|
|
590
587
|
def task_namespace(val, first: false)
|
|
591
588
|
return unless (ret = val.to_s.split(':')).size > 1
|
|
592
589
|
|
|
593
|
-
first ? ret.first : task_join(*ret[
|
|
590
|
+
first ? ret.first : task_join(*ret[..-2])
|
|
594
591
|
end
|
|
595
592
|
|
|
596
593
|
def task_resolve(obj, key)
|
|
@@ -960,7 +957,7 @@ module Squared
|
|
|
960
957
|
key = task_name(task_join(name, target))
|
|
961
958
|
sync = true
|
|
962
959
|
exception = exception?
|
|
963
|
-
if store && (kwargs = store[
|
|
960
|
+
if store && (kwargs = store[task_join(target, name)])
|
|
964
961
|
sync = kwargs[:sync] if kwargs.key?(:sync)
|
|
965
962
|
exception = kwargs[:exception] if kwargs.key?(:exception)
|
|
966
963
|
end
|
|
@@ -981,9 +978,11 @@ module Squared
|
|
|
981
978
|
end
|
|
982
979
|
end
|
|
983
980
|
when Array
|
|
984
|
-
cmd =
|
|
985
|
-
|
|
986
|
-
|
|
981
|
+
cmd = items.filter_map do |proj|
|
|
982
|
+
next unless task_defined?(out = task_join(proj.name, args.first))
|
|
983
|
+
|
|
984
|
+
out
|
|
985
|
+
end
|
|
987
986
|
next if cmd.empty?
|
|
988
987
|
|
|
989
988
|
args = args.drop(1)
|
|
@@ -1024,7 +1023,7 @@ module Squared
|
|
|
1024
1023
|
@events[label][name][task] = on
|
|
1025
1024
|
end
|
|
1026
1025
|
data[label][name][task] = val
|
|
1027
|
-
(data.store[label] ||= {})[
|
|
1026
|
+
(data.store[label] ||= {})[task_join(name, task)] = store if store
|
|
1028
1027
|
end
|
|
1029
1028
|
self
|
|
1030
1029
|
end
|
|
@@ -1038,7 +1037,7 @@ module Squared
|
|
|
1038
1037
|
Array(group).each do |val|
|
|
1039
1038
|
val = val.to_s
|
|
1040
1039
|
if val.start_with?('-')
|
|
1041
|
-
target[:exclude] << val[1
|
|
1040
|
+
target[:exclude] << val[1..]
|
|
1042
1041
|
else
|
|
1043
1042
|
target[:group][val] = data
|
|
1044
1043
|
end
|
|
@@ -1047,7 +1046,7 @@ module Squared
|
|
|
1047
1046
|
Array(ref).each do |val|
|
|
1048
1047
|
val = val.to_s
|
|
1049
1048
|
if val.start_with?('-')
|
|
1050
|
-
target[:exclude] << val[1
|
|
1049
|
+
target[:exclude] << val[1..].to_sym
|
|
1051
1050
|
else
|
|
1052
1051
|
target[:ref][val.to_sym] = data
|
|
1053
1052
|
end
|
|
@@ -1092,10 +1091,6 @@ module Squared
|
|
|
1092
1091
|
nil
|
|
1093
1092
|
end
|
|
1094
1093
|
|
|
1095
|
-
def find_project(ref:, path: nil)
|
|
1096
|
-
require_project(ref) || Application.find(ref: ref, path: path)
|
|
1097
|
-
end
|
|
1098
|
-
|
|
1099
1094
|
def root?(path, pass: [])
|
|
1100
1095
|
return false unless path.directory?
|
|
1101
1096
|
|
|
@@ -1125,8 +1120,10 @@ module Squared
|
|
|
1125
1120
|
exception != false && exception != Logger::INFO
|
|
1126
1121
|
end
|
|
1127
1122
|
|
|
1128
|
-
def banner_include?(val)
|
|
1129
|
-
Application.attr_banner.include?(val)
|
|
1123
|
+
def banner_include?(val, ref: nil)
|
|
1124
|
+
return true if Application.attr_banner.include?(val)
|
|
1125
|
+
|
|
1126
|
+
ref ? Array(ref).any? { |proj| @banner.store[proj]&.include?(val) } : @banner.items.include?(val)
|
|
1130
1127
|
end
|
|
1131
1128
|
|
|
1132
1129
|
def scriptobj
|