squared 0.5.12 → 0.6.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 +94 -0
- data/README.md +75 -34
- data/lib/squared/common/base.rb +1 -22
- data/lib/squared/common/format.rb +32 -24
- data/lib/squared/common/prompt.rb +55 -32
- data/lib/squared/common/shell.rb +43 -10
- data/lib/squared/common/system.rb +69 -36
- data/lib/squared/common/utils.rb +29 -6
- data/lib/squared/config.rb +17 -21
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +80 -81
- data/lib/squared/workspace/project/base.rb +493 -329
- data/lib/squared/workspace/project/docker.rb +375 -273
- data/lib/squared/workspace/project/git.rb +326 -310
- data/lib/squared/workspace/project/node.rb +485 -254
- data/lib/squared/workspace/project/python.rb +328 -199
- data/lib/squared/workspace/project/ruby.rb +643 -342
- data/lib/squared/workspace/project/support/class.rb +166 -68
- data/lib/squared/workspace/repo.rb +38 -34
- data/lib/squared/workspace/series.rb +6 -6
- data/lib/squared/workspace/support/base.rb +3 -24
- data/lib/squared/workspace/support/variables.rb +48 -0
- data/lib/squared/workspace/support.rb +1 -1
- data/lib/squared/workspace.rb +1 -1
- metadata +2 -2
- data/lib/squared/workspace/support/data.rb +0 -11
data/lib/squared/common/shell.rb
CHANGED
|
@@ -49,19 +49,17 @@ module Squared
|
|
|
49
49
|
val = val.to_s
|
|
50
50
|
return val if (!force && !val.include?(' ')) || val.empty?
|
|
51
51
|
|
|
52
|
-
if option && val.match?(/(?:\A|\A[^=\s]+(?:=|\s+)|#{Rake::Win32.windows? ? '[\\\/]' : '\/'})(["']).+\1\z/
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if double || Rake::Win32.windows? || (ARG[:QUOTE] == '"' && !override)
|
|
52
|
+
if option && val.match?(/(?:\A|\A[^=\s]+(?:=|\s+)|#{Rake::Win32.windows? ? '[\\\/]' : '\/'})(["']).+\1\z/mo)
|
|
53
|
+
val
|
|
54
|
+
elsif double || Rake::Win32.windows? || (ARG[:QUOTE] == '"' && !override)
|
|
57
55
|
"\"#{val.gsub(/(?<!\\)"/, '\\"')}\""
|
|
58
56
|
else
|
|
59
57
|
"'#{val.gsub("'", "'\\\\''")}'"
|
|
60
58
|
end
|
|
61
59
|
end
|
|
62
60
|
|
|
63
|
-
def shell_option(flag, val = nil,
|
|
64
|
-
|
|
61
|
+
def shell_option(flag, val = nil, sep: '=', escape: true, quote: true, force: true, double: false, merge: false,
|
|
62
|
+
override: false)
|
|
65
63
|
flag = flag.to_s
|
|
66
64
|
if flag =~ /\A(["'])(.+)\1\z/
|
|
67
65
|
double = $1 == '"'
|
|
@@ -70,19 +68,19 @@ module Squared
|
|
|
70
68
|
override = true
|
|
71
69
|
end
|
|
72
70
|
b = if flag[0] == '-'
|
|
73
|
-
flag[1] == '-' ?
|
|
71
|
+
flag[1] == '-' ? sep : ' '
|
|
74
72
|
elsif flag.size == 1
|
|
75
73
|
a = '-'
|
|
76
74
|
merge ? '' : ' '
|
|
77
75
|
else
|
|
78
76
|
a = '--'
|
|
79
|
-
|
|
77
|
+
sep
|
|
80
78
|
end
|
|
81
79
|
"#{a}#{flag}#{unless val.nil?
|
|
82
80
|
"#{b}#{if escape
|
|
83
81
|
shell_escape(val, quote: quote, double: double, override: override)
|
|
84
82
|
elsif quote
|
|
85
|
-
shell_quote(val, option:
|
|
83
|
+
shell_quote(val, option: false, force: force, double: double, override: override)
|
|
86
84
|
else
|
|
87
85
|
val
|
|
88
86
|
end}"
|
|
@@ -96,6 +94,41 @@ module Squared
|
|
|
96
94
|
ret.join(join.is_a?(::String) ? join : ' ')
|
|
97
95
|
end
|
|
98
96
|
|
|
97
|
+
def shell_parse(val, escape: false, force: true, **kwargs)
|
|
98
|
+
a = []
|
|
99
|
+
b = []
|
|
100
|
+
c = []
|
|
101
|
+
d = []
|
|
102
|
+
e = [a, b]
|
|
103
|
+
j = -1
|
|
104
|
+
val.shellsplit.each_with_index do |opt, i|
|
|
105
|
+
if opt == '--'
|
|
106
|
+
e = [c, d]
|
|
107
|
+
elsif opt =~ /\A--?[^=]+(=|\z)/
|
|
108
|
+
j = $1 == '=' ? -1 : i
|
|
109
|
+
e[0] << [opt]
|
|
110
|
+
elsif j >= 0
|
|
111
|
+
e[0][j] << opt
|
|
112
|
+
else
|
|
113
|
+
e[1] << shell_quote(opt, option: false, force: force)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
ret = [[a, b], [], [c, d]].flat_map do |e, f|
|
|
117
|
+
next '--' unless e
|
|
118
|
+
|
|
119
|
+
e.flat_map do |item|
|
|
120
|
+
if item.size == 1
|
|
121
|
+
fill_option(item.first)
|
|
122
|
+
else
|
|
123
|
+
flag = item.shift
|
|
124
|
+
item.map! { |s| shell_option(flag, s, escape: escape, force: force, **kwargs) }
|
|
125
|
+
end
|
|
126
|
+
end.concat(f)
|
|
127
|
+
end
|
|
128
|
+
ret.pop if ret.last == '--'
|
|
129
|
+
ret
|
|
130
|
+
end
|
|
131
|
+
|
|
99
132
|
def shell_bin(name, env: true)
|
|
100
133
|
key = name.upcase
|
|
101
134
|
shell_quote((env && ENV["PATH_#{key}"]) || PATH[key] || PATH[key.to_sym] || name, option: false, force: false,
|
|
@@ -6,6 +6,25 @@ require 'rake'
|
|
|
6
6
|
module Squared
|
|
7
7
|
module Common
|
|
8
8
|
module System
|
|
9
|
+
class << self
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def parse_link(val)
|
|
13
|
+
case val
|
|
14
|
+
when ::TrueClass, 's'
|
|
15
|
+
1
|
|
16
|
+
when 'r'
|
|
17
|
+
2
|
|
18
|
+
when 'h'
|
|
19
|
+
3
|
|
20
|
+
else
|
|
21
|
+
raise ArgumentError, "unrecognized 'link' flag: #{val}" if val
|
|
22
|
+
|
|
23
|
+
0
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
9
28
|
module_function
|
|
10
29
|
|
|
11
30
|
def shell(*args, name: :system, **kwargs)
|
|
@@ -29,11 +48,11 @@ module Squared
|
|
|
29
48
|
raise $?.to_s
|
|
30
49
|
end
|
|
31
50
|
|
|
32
|
-
def copy_dir(src, dest, glob = ['**/*'], create: false, link: nil,
|
|
33
|
-
|
|
51
|
+
def copy_dir(src, dest, glob = ['**/*'], create: false, link: nil, preserve: nil, force: false, verbose: true,
|
|
52
|
+
pass: nil, hidden: false)
|
|
34
53
|
base = Pathname.new(src)
|
|
35
54
|
target = Pathname.new(dest)
|
|
36
|
-
raise
|
|
55
|
+
raise Errno::ENOENT, dest.cleanpath.to_s unless create || target.parent.exist?
|
|
37
56
|
|
|
38
57
|
subdir = {}
|
|
39
58
|
target.mkpath if create
|
|
@@ -57,53 +76,67 @@ module Squared
|
|
|
57
76
|
end
|
|
58
77
|
count = 0
|
|
59
78
|
soft = 0
|
|
79
|
+
type = System.send :parse_link, link
|
|
60
80
|
subdir.each do |dir, files|
|
|
61
|
-
|
|
62
|
-
files.dup
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
if link == 'hard'
|
|
73
|
-
FileUtils.ln(file, dir, force: force, verbose: false)
|
|
74
|
-
else
|
|
75
|
-
FileUtils.ln_s(file, dir, force: force, verbose: false)
|
|
81
|
+
unless type == 0
|
|
82
|
+
items = files.dup
|
|
83
|
+
files.clear
|
|
84
|
+
items.each do |file|
|
|
85
|
+
if file.exist?
|
|
86
|
+
if !file.symlink?
|
|
87
|
+
files << file
|
|
88
|
+
elsif !force
|
|
89
|
+
next
|
|
76
90
|
end
|
|
77
|
-
soft += 1
|
|
78
91
|
end
|
|
92
|
+
case type
|
|
93
|
+
when 1
|
|
94
|
+
FileUtils.ln_s(file, dir, force: force, verbose: false)
|
|
95
|
+
when 2
|
|
96
|
+
FileUtils.ln_s(file.relative_path_from(dir), dir, force: force, verbose: false)
|
|
97
|
+
else
|
|
98
|
+
FileUtils.ln(file, dir, force: force, verbose: false)
|
|
99
|
+
end
|
|
100
|
+
soft += 1
|
|
79
101
|
end
|
|
80
102
|
end
|
|
81
103
|
next if files.empty?
|
|
82
104
|
|
|
83
|
-
out = FileUtils.cp(files, dir, verbose: false)
|
|
105
|
+
out = FileUtils.cp(files, dir, preserve: preserve, verbose: false)
|
|
84
106
|
count += out.size
|
|
85
107
|
end
|
|
86
108
|
puts [target.realpath, subdir.size, soft > 0 ? "#{count}+#{soft}" : count].join(' => ') if verbose
|
|
87
109
|
end
|
|
88
110
|
|
|
89
|
-
def copy_guard(src, dest, link: nil, force: false, verbose: true)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
111
|
+
def copy_guard(*src, dest, base: '.', create: false, link: nil, preserve: nil, force: false, verbose: true)
|
|
112
|
+
src = src.compact.flatten
|
|
113
|
+
dest = Pathname.new(dest).realdirpath
|
|
114
|
+
base = Pathname.new(base).realpath
|
|
115
|
+
dir = if dest.directory?
|
|
116
|
+
true
|
|
117
|
+
elsif src.size > 1
|
|
118
|
+
raise Errno::ENOENT, dest.cleanpath.to_s unless create && !dest.exist?
|
|
119
|
+
|
|
120
|
+
dest.mkpath
|
|
121
|
+
true
|
|
122
|
+
end
|
|
123
|
+
targets = src.map! { |file| [base + file, dir ? dest + File.basename(file) : dest] }
|
|
124
|
+
return if !force && (targets = targets.reject { |to| to[1].exist? }).empty?
|
|
125
|
+
|
|
126
|
+
type = System.send :parse_link, link
|
|
127
|
+
targets.each do |file, to|
|
|
128
|
+
case type
|
|
129
|
+
when 0
|
|
130
|
+
FileUtils.cp(file, to, preserve: preserve, verbose: verbose)
|
|
131
|
+
when 1
|
|
132
|
+
FileUtils.ln_s(file, to, force: force, verbose: verbose)
|
|
133
|
+
when 2
|
|
134
|
+
FileUtils.ln_s(file.relative_path_from(dir ? to.dirname : to), to, force: force, verbose: verbose)
|
|
135
|
+
else
|
|
136
|
+
FileUtils.ln(file, to, force: force, verbose: verbose)
|
|
97
137
|
end
|
|
98
138
|
end
|
|
99
|
-
|
|
100
|
-
when 'hard', 1
|
|
101
|
-
FileUtils.ln(src, dest, force: force, verbose: verbose)
|
|
102
|
-
when ::TrueClass, 'soft', 0
|
|
103
|
-
FileUtils.ln_s(src, dest, force: force, verbose: verbose)
|
|
104
|
-
else
|
|
105
|
-
FileUtils.cp(src, dest, verbose: verbose)
|
|
106
|
-
end
|
|
139
|
+
nil
|
|
107
140
|
end
|
|
108
141
|
end
|
|
109
142
|
end
|
data/lib/squared/common/utils.rb
CHANGED
|
@@ -9,21 +9,44 @@ module Squared
|
|
|
9
9
|
module Utils
|
|
10
10
|
module_function
|
|
11
11
|
|
|
12
|
-
def
|
|
13
|
-
|
|
12
|
+
def as_a(obj, *meth, flat: nil, compact: false, &blk)
|
|
13
|
+
return [] if obj.nil?
|
|
14
|
+
|
|
15
|
+
unless obj.is_a?(::Array)
|
|
16
|
+
obj = if obj.respond_to?(:to_ary)
|
|
17
|
+
obj.to_ary
|
|
18
|
+
elsif obj.respond_to?(:to_a) && !obj.is_a?(::Hash) && (val = obj.to_a).is_a?(::Array)
|
|
19
|
+
val
|
|
20
|
+
else
|
|
21
|
+
[obj]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
obj = flat.is_a?(::Numeric) ? obj.flatten(flat) : obj.flatten if flat
|
|
25
|
+
obj = obj.compact if compact
|
|
26
|
+
obj = obj.map(&meth.shift) until meth.empty?
|
|
27
|
+
return obj unless block_given?
|
|
28
|
+
|
|
29
|
+
obj.select(&blk)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def split_escape(val, char: ',', &blk)
|
|
33
|
+
ret = val.split(/\s*(?<!\\)#{char}\s*/)
|
|
34
|
+
return ret unless block_given?
|
|
35
|
+
|
|
36
|
+
ret.each(&blk)
|
|
14
37
|
end
|
|
15
38
|
|
|
16
39
|
def split_option(val)
|
|
17
40
|
val = val.strip
|
|
18
41
|
return [val, '', ''] unless (i = val.index('='))
|
|
19
42
|
|
|
20
|
-
last = val[
|
|
43
|
+
last = val[i.succ..-1].strip
|
|
21
44
|
quote = ''
|
|
22
45
|
if last =~ /\A(["'])(.+)\1\z/
|
|
23
46
|
last = $2
|
|
24
47
|
quote = $1
|
|
25
48
|
end
|
|
26
|
-
[val[0..
|
|
49
|
+
[val[0..i.pred], last, quote]
|
|
27
50
|
end
|
|
28
51
|
|
|
29
52
|
def task_invoke(*cmd, args: [], exception: true, warning: true)
|
|
@@ -105,9 +128,9 @@ module Squared
|
|
|
105
128
|
end
|
|
106
129
|
end
|
|
107
130
|
|
|
108
|
-
def env(key, default = nil, suffix: nil, strict: false, equals: nil, ignore: nil)
|
|
131
|
+
def env(key, default = nil, suffix: nil, strict: false, equals: nil, ignore: nil, **)
|
|
109
132
|
ret = env_value(key, suffix: suffix, strict: strict)
|
|
110
|
-
return
|
|
133
|
+
return Array(equals).any? { |val| val.to_s == ret } unless equals.nil?
|
|
111
134
|
|
|
112
135
|
ret.empty? || (ignore && Array(ignore).any? { |val| val.to_s == ret }) ? default : ret
|
|
113
136
|
end
|
data/lib/squared/config.rb
CHANGED
|
@@ -86,7 +86,7 @@ module Squared
|
|
|
86
86
|
['path not found', realpath]
|
|
87
87
|
else
|
|
88
88
|
@required = true
|
|
89
|
-
project ? [project, '
|
|
89
|
+
project ? [project, 'missing'] : %w[name missing]
|
|
90
90
|
end
|
|
91
91
|
warn log_message(Logger::WARN, msg, subject: self.class, hint: hint)
|
|
92
92
|
end
|
|
@@ -106,7 +106,7 @@ module Squared
|
|
|
106
106
|
next unless (data = Viewer.parse(type, type.upcase, ext))
|
|
107
107
|
end
|
|
108
108
|
obj, ext = data
|
|
109
|
-
target = file ||
|
|
109
|
+
target = file || (realpath if target?)
|
|
110
110
|
|
|
111
111
|
task_desc(command, *ext, target: target)
|
|
112
112
|
task type, [:keys] do |_, args|
|
|
@@ -205,14 +205,14 @@ module Squared
|
|
|
205
205
|
|
|
206
206
|
def read_keys(reader, type, file, keys, ext: [type], opts: {})
|
|
207
207
|
if file && (mime = mimetype(file)) && basepath(file).exist?
|
|
208
|
-
raise_error
|
|
208
|
+
raise_error file, mime, hint: 'invalid' unless ext.include?(mime)
|
|
209
209
|
else
|
|
210
210
|
if ext.include?(mime)
|
|
211
211
|
alt = file
|
|
212
212
|
file = nil
|
|
213
213
|
ext[0] = mime
|
|
214
214
|
elsif file
|
|
215
|
-
keys.
|
|
215
|
+
keys.unshift(file)
|
|
216
216
|
alt = basepath "#{main}.{#{ext.join(',')}}"
|
|
217
217
|
file = Dir[alt].first
|
|
218
218
|
else
|
|
@@ -220,7 +220,7 @@ module Squared
|
|
|
220
220
|
args = { hint: 'no keys' }
|
|
221
221
|
end
|
|
222
222
|
unless file
|
|
223
|
-
args ||= {
|
|
223
|
+
args ||= { kind: Errno::ENOENT }
|
|
224
224
|
raise_error(reader.name, "#{File.basename(alt, '.*')}.#{ext.first}", **args)
|
|
225
225
|
end
|
|
226
226
|
end
|
|
@@ -237,22 +237,18 @@ module Squared
|
|
|
237
237
|
title = Pathname.new(file)
|
|
238
238
|
.realpath
|
|
239
239
|
.to_s
|
|
240
|
-
.sub(
|
|
240
|
+
.sub(/^#{Regexp.escape(File.join(Dir.pwd, ''))}/, '')
|
|
241
241
|
emphasize(lines, title: title, sub: unless stdin?
|
|
242
242
|
[
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
{ pat: /\A((?~: ): )(true|false)(\s*)\z/m, styles: theme[:boolean],
|
|
253
|
-
index: 2 },
|
|
254
|
-
{ pat: /\A((?~: ): (?!undefined))([^"\[{].*)\z/m, styles: theme[:value],
|
|
255
|
-
index: 2 }
|
|
243
|
+
opt_style(theme[:banner], /\A((?:[^:]|(?<! ):(?! ))+)\z/),
|
|
244
|
+
opt_style(theme[:undefined], /\A(.*?)(<[^>]+>)(.+)\z/m, 2),
|
|
245
|
+
opt_style(theme[:key], /\A((?~ : ))( : (?!undefined).+)\z/m),
|
|
246
|
+
opt_style(theme[:number], /\A((?~: ): )(-?[\d.]+)(\s*)\z/m, 2),
|
|
247
|
+
opt_style(theme[:string], /\A((?~: ): ")(.+)("\s*)\z/m, 2),
|
|
248
|
+
opt_style(theme[:hash], /\A((?~: ): \{)(.+)(\}\s*)\z/m, 2),
|
|
249
|
+
opt_style(theme[:array], /\A((?~: ): \[)(.+)(\]\s*)\z/m, 2),
|
|
250
|
+
opt_style(theme[:boolean], /\A((?~: ): )(true|false)(\s*)\z/m, 2),
|
|
251
|
+
opt_style(theme[:value], /\A((?~: ): (?!undefined))([^"\[{].*)\z/m, 2)
|
|
256
252
|
]
|
|
257
253
|
end, border: theme[:border])
|
|
258
254
|
end
|
|
@@ -309,8 +305,8 @@ module Squared
|
|
|
309
305
|
def task_desc(command, *ext, target: nil)
|
|
310
306
|
return unless Rake::TaskManager.record_task_metadata
|
|
311
307
|
|
|
312
|
-
val = "#{ext.first}[#{
|
|
313
|
-
args = *name.split(':').
|
|
308
|
+
val = "#{ext.first}[#{"file?=#{File.basename(main)}.#{ext.last}," if target}keys+]"
|
|
309
|
+
args = *name.split(':').push(command, val)
|
|
314
310
|
if project
|
|
315
311
|
project.workspace.task_desc(*args)
|
|
316
312
|
else
|
data/lib/squared/version.rb
CHANGED