squared 0.9.0 → 0.9.2
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 +84 -1
- data/README.md +13 -6
- data/exe/sqd +264 -73
- data/lib/squared/common/base.rb +2 -0
- data/lib/squared/common/format.rb +1 -1
- data/lib/squared/common/prompt.rb +26 -8
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +5 -0
- data/lib/squared/workspace/project/base.rb +13 -11
- data/lib/squared/workspace/project/docker.rb +4 -4
- data/lib/squared/workspace/project/git.rb +4 -4
- data/lib/squared/workspace/project/node.rb +36 -23
- data/lib/squared/workspace/project/python.rb +123 -56
- data/lib/squared/workspace/project/ruby.rb +30 -20
- data/lib/squared/workspace/project/support/optionpartition.rb +20 -18
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7bc8d196a7c5068373757f7bbb9ba037cafd30500875d924628690f57451b927
|
|
4
|
+
data.tar.gz: '00078ddc57f3f357cc9833a679c42d636936d0db91e75a327a07ba19dedd0165'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c5b85d626962791e9da8355f82999b0ab8bcd1e63f88605c6a3dfecb8b5b515469373acb8f7d79eab4887b3b3f826e1d540133361b74e5c3e3160545215b3641
|
|
7
|
+
data.tar.gz: ee09108c1abea47c45ae2a931e01a9b1e42097dd597537796543321aaca03b9825d9942a26274c7fbca344f748b1d4b8765102dcd7b74f54489e7dc2115b5a97
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,81 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.9.2] - 2026-11-04
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- sqd: Option --no-gemfile for undoing bundle exec project wrapper.
|
|
8
|
+
- sqd: Option --commit for pushing files to remote branch.
|
|
9
|
+
- sqd: Option --mulitline for writing messages with newlines.
|
|
10
|
+
- sqd: Option --amend[-orig] for replacing current commit.
|
|
11
|
+
- sqd: Option --project can match common subtasks.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Logger warn statements from project misconfiguration were downgraded.
|
|
16
|
+
- sqd: Task creation from joins are validated before consuming arguments.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- sqd: Option --project did not support multiple patterns.
|
|
21
|
+
|
|
22
|
+
## [0.8.8]
|
|
23
|
+
|
|
24
|
+
- See `0.7.15`.
|
|
25
|
+
|
|
26
|
+
## [0.7.15]
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- Git command commit action pathspec was implemented.
|
|
31
|
+
- Common base argument TAB for column alignment was created.
|
|
32
|
+
- Node command package action deny can modify currently approved scripts.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- Node command package action [approve|deny] uses install-scripts ls.
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
|
|
40
|
+
- Bundle exec wrapper as a Hash did not support using alternate Gemfile.
|
|
41
|
+
- Common base ARG data objects were not frozen with __freeze__.
|
|
42
|
+
|
|
43
|
+
## [0.9.1] - 2026-10-22
|
|
44
|
+
|
|
45
|
+
### Added
|
|
46
|
+
|
|
47
|
+
- sqd: Option --gemfile for rerouting commands through bundle exec.
|
|
48
|
+
- Python install manager for Windows is supported.
|
|
49
|
+
- sqd: Option --sync for running threads in a series was implemented.
|
|
50
|
+
|
|
51
|
+
## [0.8.7]
|
|
52
|
+
|
|
53
|
+
### Added
|
|
54
|
+
|
|
55
|
+
- OptionPartition can be initialized with enum and pattern options.
|
|
56
|
+
|
|
57
|
+
### Fixed
|
|
58
|
+
|
|
59
|
+
- Python venv creation did not run post-install for package managers.
|
|
60
|
+
|
|
61
|
+
## [0.7.14]
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
|
|
65
|
+
- Python program meson prefix options use local path resolution.
|
|
66
|
+
- Bundle exec wrapper can be configured per application.
|
|
67
|
+
|
|
68
|
+
### Fixed
|
|
69
|
+
|
|
70
|
+
- Bundle exec wrapper did not accept boolean values.
|
|
71
|
+
|
|
72
|
+
## [0.6.21]
|
|
73
|
+
|
|
74
|
+
### Fixed
|
|
75
|
+
|
|
76
|
+
- RuboCop did not resolve config to project directory.
|
|
77
|
+
- Python program did not use correct separator for double dash options.
|
|
78
|
+
|
|
3
79
|
## [0.9.0] - 2026-10-12
|
|
4
80
|
|
|
5
81
|
### Added
|
|
@@ -63,7 +139,7 @@
|
|
|
63
139
|
|
|
64
140
|
- OptionPartition did not parse quoted option values.
|
|
65
141
|
|
|
66
|
-
## [0.6.20]
|
|
142
|
+
## [0.6.20]
|
|
67
143
|
|
|
68
144
|
### Added
|
|
69
145
|
|
|
@@ -2198,7 +2274,11 @@
|
|
|
2198
2274
|
|
|
2199
2275
|
- Changelog was created.
|
|
2200
2276
|
|
|
2277
|
+
[0.9.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.9.2
|
|
2278
|
+
[0.9.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.9.1
|
|
2201
2279
|
[0.9.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.9.0
|
|
2280
|
+
[0.8.8]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.8
|
|
2281
|
+
[0.8.7]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.7
|
|
2202
2282
|
[0.8.6]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.6
|
|
2203
2283
|
[0.8.5]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.5
|
|
2204
2284
|
[0.8.4]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.4
|
|
@@ -2206,6 +2286,8 @@
|
|
|
2206
2286
|
[0.8.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.2
|
|
2207
2287
|
[0.8.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.1
|
|
2208
2288
|
[0.8.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.0
|
|
2289
|
+
[0.7.15]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.15
|
|
2290
|
+
[0.7.14]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.14
|
|
2209
2291
|
[0.7.13]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.13
|
|
2210
2292
|
[0.7.12]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.12
|
|
2211
2293
|
[0.7.11]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.11
|
|
@@ -2220,6 +2302,7 @@
|
|
|
2220
2302
|
[0.7.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.2
|
|
2221
2303
|
[0.7.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.1
|
|
2222
2304
|
[0.7.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.0
|
|
2305
|
+
[0.6.21]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.21
|
|
2223
2306
|
[0.6.20]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.20
|
|
2224
2307
|
[0.6.19]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.19
|
|
2225
2308
|
[0.6.18]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.18
|
data/README.md
CHANGED
|
@@ -32,7 +32,7 @@ gem install squared
|
|
|
32
32
|
There is an additional program wrapper for ``rake`` to be used when running batch commands and to enable global settings more easily.
|
|
33
33
|
|
|
34
34
|
```xml
|
|
35
|
-
Usage: sqd [options] [rake options] [global...] [:targets...] -- [rake targets...]
|
|
35
|
+
Usage: sqd [options] [rake options] [pathspec...] -- [global...] [:targets...] -- [rake targets...]
|
|
36
36
|
|
|
37
37
|
-R, --ref STR,STR Run global commands by class reference
|
|
38
38
|
-G, --group STR,STR Run global commands by project group
|
|
@@ -43,18 +43,25 @@ Usage: sqd [options] [rake options] [global...] [:targets...] -- [rake targets..
|
|
|
43
43
|
|
|
44
44
|
-s, --[no-]strict Do not run commands with invalid arguments
|
|
45
45
|
--update Use update strategy for applicable commands
|
|
46
|
-
|
|
46
|
+
-u, --parallel STR,PAT Run standard tasks with multi-task threads
|
|
47
|
+
-U, --sync STR,PAT Run parallel tasks in a series sequentially
|
|
47
48
|
-F, --force [STR,STR] Enable force through ENV by application
|
|
48
49
|
-y, --yes [STR,STR] Enable auto-approve through ENV by application
|
|
49
50
|
-d, --dry-run Run commands without any modifying actions
|
|
50
51
|
|
|
51
|
-
-S, --select PAGE[:CHOICE] Prompt menu selection pagination display (e.g.
|
|
52
|
+
-S, --select PAGE[:CHOICE] Prompt menu selection pagination display (e.g. 20:60)
|
|
53
|
+
-M, --multiline STR Use advanced editor with custom message terminator (e.g. EOF)
|
|
52
54
|
|
|
55
|
+
-g, --[no-]gemfile Execute commands using bundle exec and nearest Gemfile
|
|
53
56
|
-p, --pipe 0|1|2 Set file descriptor for communication
|
|
54
57
|
-o, --pipe-out FILE Write command data stream to a file
|
|
55
58
|
--fail 0..4 Set application exception level
|
|
56
59
|
--log-level SEVERITY Set logger and exception state (debug, info, warn, error, fatal)
|
|
57
60
|
|
|
61
|
+
-c, --commit Push files remotely on active branch from current directory
|
|
62
|
+
--amend Replace the tip of the active branch remotely with a force push
|
|
63
|
+
--amend-orig Perform an amend commit without changing the message
|
|
64
|
+
|
|
58
65
|
--[no-]banner Display executing command attributes
|
|
59
66
|
-x, --[no-]color Use enhanced styling for terminal output
|
|
60
67
|
-X, --plain Disable banner and styling for all commands
|
|
@@ -102,11 +109,11 @@ Workspace::Application
|
|
|
102
109
|
.clean("rake clean", group: "default")
|
|
103
110
|
.clean(["build/"], group: "app")
|
|
104
111
|
.log({ file: "tmp/%Y-%m-%d.log", level: "debug" }, group: "app")
|
|
105
|
-
.add("pathname", run: "rake compile", copy: "rake install", test: "rake test", group: "default", env: { # Ruby (with C extensions)
|
|
112
|
+
.add("pathname", run: "rake compile", copy: "rake install", test: "rake test", exec: true, group: "default", env: { # Ruby (with C extensions)
|
|
106
113
|
"CFLAGS" => "-fPIC -O1"
|
|
107
114
|
})
|
|
108
|
-
.add("optparse", doc: "rake rdoc", gemspec: "optparse.gemspec", group: "default") # Uses bundler/gem_tasks (without C extensions)
|
|
109
|
-
.add("logger", copy: { from: "lib", glob: "**/*.rb", into: "/home/user/.local/gem/ruby/4.0.0/gems/logger-1.7.0" }, clean: ["tmp/"]) do
|
|
115
|
+
.add("optparse", doc: "rake rdoc", gemspec: "optparse.gemspec", exec: { rake: true, ruby: '../Gemfile', rbs: false }, group: "default") # Uses bundler/gem_tasks (without C extensions)
|
|
116
|
+
.add("logger", copy: { from: "lib", glob: "**/*.rb", into: "/home/user/.local/gem/ruby/4.0.0/gems/logger-1.7.0" }, clean: ["tmp/"]) do # autodetect: true | "rvm" | "rbenv" | "asdf" | "mise" | bundler"
|
|
110
117
|
self.gemdir = "/home/user/.local/gem/ruby/4.0.0/gems/logger-1.7.0" # Default for "into"
|
|
111
118
|
end
|
|
112
119
|
.add("e-mc", "emc", copy: { from: "publish", scope: "@e-mc", also: [:pir, "squared-express/"] }, ref: :node)
|
data/exe/sqd
CHANGED
|
@@ -6,36 +6,41 @@ require 'rake'
|
|
|
6
6
|
require 'optparse'
|
|
7
7
|
|
|
8
8
|
class SqdParser < OptionParser
|
|
9
|
-
include Squared
|
|
9
|
+
include Squared
|
|
10
|
+
include Common::Format
|
|
10
11
|
include Utils
|
|
11
12
|
|
|
13
|
+
OPT_DASH = /^--?[^-]/.freeze
|
|
14
|
+
|
|
12
15
|
attr_reader :options, :global
|
|
16
|
+
attr_accessor :argv
|
|
13
17
|
|
|
14
18
|
def initialize(*)
|
|
15
|
-
super
|
|
16
19
|
@options = { 'project-args': [], 'project-env': [] }
|
|
17
20
|
@global = []
|
|
21
|
+
@argv = ARGV.dup
|
|
22
|
+
super
|
|
18
23
|
@program_name = 'squared'
|
|
19
24
|
@raise_unknown = false
|
|
20
25
|
@require_exact = true
|
|
21
26
|
end
|
|
22
27
|
|
|
23
28
|
def parse_global(list, assert:)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
ARGV.each_with_index do |val, index|
|
|
29
|
+
error_exit "cannot be used with --#{assert}" if options.key?(assert)
|
|
30
|
+
each_with_index do |val, index|
|
|
27
31
|
if val == '--'
|
|
28
32
|
separator!(index: index)
|
|
29
33
|
break
|
|
30
34
|
end
|
|
31
|
-
|
|
35
|
+
found = list.map { |name| "#{val}:#{name}" }.select { |name| tasks.include?(name) }
|
|
36
|
+
next if found.empty?
|
|
32
37
|
|
|
33
|
-
global.concat(
|
|
38
|
+
global.concat(found)
|
|
34
39
|
ARGV[index] = ''
|
|
35
40
|
end
|
|
36
41
|
end
|
|
37
42
|
|
|
38
|
-
def parse_common(list,
|
|
43
|
+
def parse_common(list, arg:)
|
|
39
44
|
if list && !list.include?('*')
|
|
40
45
|
session[arg].merge!(list.to_h { |key| [key, 'true'] })
|
|
41
46
|
else
|
|
@@ -43,18 +48,159 @@ class SqdParser < OptionParser
|
|
|
43
48
|
end
|
|
44
49
|
end
|
|
45
50
|
|
|
46
|
-
def
|
|
51
|
+
def parse_series(list, flag:)
|
|
52
|
+
pattern, parallel = list.partition do |val|
|
|
53
|
+
next false if val.match?(%r{^[\w~`!@#%&\-=:;"'<>/]+$})
|
|
54
|
+
|
|
55
|
+
Regexp.new(val)
|
|
56
|
+
rescue RegexpError
|
|
57
|
+
false
|
|
58
|
+
end
|
|
59
|
+
s = flag == :sync ? '!' : ''
|
|
60
|
+
(session[:APP][:"build_pattern#{s}"] ||= []).concat(pattern.map { |pat| Regexp.new(pat) }) unless pattern.empty?
|
|
61
|
+
(session[:APP][:"build_parallel#{s}"] ||= []).concat(parallel) unless parallel.empty?
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def parse_range(val, max:, arg:, min: 0)
|
|
65
|
+
error_exit('out of range', hint: val) unless val.between?(min, max)
|
|
66
|
+
session[arg] = val
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def parse_rakefile
|
|
70
|
+
OptionParser.new do |opts|
|
|
71
|
+
opts.raise_unknown = false
|
|
72
|
+
opts.on('--rakefile', '-f [FILENAME]', '') do |val|
|
|
73
|
+
return val || ''
|
|
74
|
+
end
|
|
75
|
+
end.parse(ARGV.dup)
|
|
76
|
+
nil
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def option_select(val)
|
|
80
|
+
page, choice = val.split(/\D/, 2).map(&:to_i)
|
|
81
|
+
error_exit('not an integer', hint: val) if choice.nil? ? page == 0 : choice == 0
|
|
82
|
+
session[:PAGE] = page if page > 0
|
|
83
|
+
session[:CHOICE] = choice if choice.to_i > 0
|
|
84
|
+
ENV['SELECT'] = "#{page}:#{choice}"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def option_multiline(val)
|
|
88
|
+
Common::Prompt.multiline = val
|
|
89
|
+
rescue NotImplementedError => e
|
|
90
|
+
warn log_warn(e, hint: argv.find { |val| multilineopts.include?(val) })
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def option_gemfile(val)
|
|
94
|
+
require 'pathname'
|
|
95
|
+
session[:APP][:ruby_gemfile] = val
|
|
96
|
+
return unless val
|
|
97
|
+
return if ENV['RUBYOPT']&.match?(/(^|\b)-r.+#{File::SEPARATOR}bundler#{File::SEPARATOR}setup\b/)
|
|
98
|
+
|
|
99
|
+
gemfile = Pathname.pwd.ascend { |path| break path if path.join('Gemfile').file? } || ENV['BUNDLE_GEMFILE']
|
|
100
|
+
return unless gemfile && (argv.delete('--gemfile') || argv.delete('-g'))
|
|
101
|
+
|
|
102
|
+
argv.unshift('sqd')
|
|
103
|
+
if gemfile.is_a?(String)
|
|
104
|
+
gemfile = Common::Shell.shell_escape(Pathname.new(gemfile).relative_path_from(Dir.pwd), quote: true)
|
|
105
|
+
argv.unshift("--gemfile=#{gemfile}")
|
|
106
|
+
gemfile = Dir.pwd
|
|
107
|
+
end
|
|
108
|
+
ENV['BUNDLE_GEMFILE'] = nil
|
|
109
|
+
exec(Common::Shell.shell_bin('bundle'), 'exec', *argv, chdir: gemfile)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def option_loglevel(val)
|
|
113
|
+
require 'logger'
|
|
114
|
+
severity = case val
|
|
115
|
+
when :debug then Logger::DEBUG
|
|
116
|
+
when :info then Logger::INFO
|
|
117
|
+
when :warn then Logger::WARN
|
|
118
|
+
when :error then Logger::ERROR
|
|
119
|
+
when :fatal then Logger::FATAL
|
|
120
|
+
else
|
|
121
|
+
val.to_i
|
|
122
|
+
end
|
|
123
|
+
session[:LEVEL] = severity
|
|
124
|
+
ENV['LOG_LEVEL'] = severity.to_s
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def option_commit(*opts, flag:)
|
|
128
|
+
require 'squared/workspace'
|
|
129
|
+
c = argv.index { |val| opts.include?(val) } || error_exit('option was not found', hint: opts.last)
|
|
130
|
+
check_exclusive('-c', '--commit', '--amend', '--amend-orig', flag: argv[c])
|
|
131
|
+
first = lambda do
|
|
132
|
+
if ARGV.empty?
|
|
133
|
+
m = argv.index { |val| multilineopts.include?(val) }
|
|
134
|
+
t = argv.index { |val| !val.match?(OPT_DASH) } || -1
|
|
135
|
+
return true if c == 0 || (m == 0 && c == 2) || t > c
|
|
136
|
+
end
|
|
137
|
+
!rakefile?
|
|
138
|
+
end
|
|
139
|
+
refs = []
|
|
140
|
+
found = argv[c.succ]
|
|
141
|
+
j = -1
|
|
142
|
+
each_with_index do |pat, i|
|
|
143
|
+
found = nil if pat == found
|
|
144
|
+
if i == j
|
|
145
|
+
ARGV[i.pred] = ''
|
|
146
|
+
ARGV[i] = ''
|
|
147
|
+
option_multiline pat
|
|
148
|
+
next
|
|
149
|
+
end
|
|
150
|
+
next if found
|
|
151
|
+
|
|
152
|
+
case pat
|
|
153
|
+
when '--'
|
|
154
|
+
ARGV[i] = ''
|
|
155
|
+
break
|
|
156
|
+
when *multilineopts
|
|
157
|
+
j = i.succ
|
|
158
|
+
next
|
|
159
|
+
when OPT_DASH
|
|
160
|
+
next if refs.empty? || Dir[pat].empty?
|
|
161
|
+
else
|
|
162
|
+
next if refs.empty? && Dir[pat].empty?
|
|
163
|
+
end
|
|
164
|
+
refs << pat
|
|
165
|
+
ARGV[i] = ''
|
|
166
|
+
end
|
|
167
|
+
if refs.empty?
|
|
168
|
+
if !`git status -s --ignore-submodules=all --ignored=no`.empty?
|
|
169
|
+
refs << '*'
|
|
170
|
+
elsif first.call
|
|
171
|
+
warn 'No files to commit.'
|
|
172
|
+
exit 1
|
|
173
|
+
else
|
|
174
|
+
return
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
Workspace::Application
|
|
178
|
+
.new
|
|
179
|
+
.add(File.basename(Dir.pwd), ref: :git) { commit(flag, refs: refs.uniq, pass: nil) }
|
|
180
|
+
exit if first.call
|
|
181
|
+
self.argv = ARGV.dup
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def option_verbose
|
|
185
|
+
unless session[:VERBOSE]
|
|
186
|
+
session[:VERBOSE] = $VERBOSE ? 1 : 0
|
|
187
|
+
global.unshift('--verbose')
|
|
188
|
+
end
|
|
189
|
+
ENV['VERBOSE'] = (session[:VERBOSE] += 1).to_s
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def banner_set(val)
|
|
47
193
|
session[:BANNER] = val
|
|
48
194
|
ENV['BANNER'] = val ? 'true' : 'false'
|
|
49
195
|
end
|
|
50
196
|
|
|
51
|
-
def color_set(val
|
|
197
|
+
def color_set(val)
|
|
52
198
|
if (session[:COLOR] = val)
|
|
53
199
|
enable_aixterm
|
|
54
200
|
enable_drawing
|
|
55
201
|
else
|
|
56
202
|
enable_drawing false
|
|
57
|
-
|
|
203
|
+
Common.const_get(:VAR)[:colors].freeze
|
|
58
204
|
end
|
|
59
205
|
ENV['NO_COLOR'] = val ? nil : '1'
|
|
60
206
|
ENV['FORCE_COLOR'] = val ? '2' : '0'
|
|
@@ -71,68 +217,111 @@ class SqdParser < OptionParser
|
|
|
71
217
|
rescue RegexpError
|
|
72
218
|
false
|
|
73
219
|
end
|
|
220
|
+
subtasks = []
|
|
74
221
|
pattern.each do |val|
|
|
75
222
|
val = if val == '*'
|
|
76
223
|
'[^:]+'
|
|
77
224
|
else
|
|
78
225
|
val.sub(/^\*/, '.*')
|
|
79
226
|
.sub(/(?<!\.)\*$/, '.*')
|
|
80
|
-
.gsub(
|
|
227
|
+
.gsub(/(?<!\\)\.([*+])(?!\?)/, '[^:]\1?')
|
|
81
228
|
end
|
|
82
|
-
|
|
229
|
+
pat = /^(#{val.chomp(':')}):/
|
|
230
|
+
tasks.each do |task|
|
|
231
|
+
next unless task =~ pat
|
|
232
|
+
|
|
233
|
+
subtasks << $1
|
|
234
|
+
name = task.split(':', 2).first
|
|
235
|
+
project << name unless project.include?(name)
|
|
236
|
+
end
|
|
83
237
|
end
|
|
84
238
|
exit 1 if project.empty? && !pattern.empty?
|
|
85
|
-
|
|
239
|
+
subtasks.uniq!
|
|
86
240
|
options[:'project-env'].each do |val|
|
|
87
241
|
n = val.index('=')
|
|
88
|
-
key = val[...n]
|
|
89
|
-
val = val[n.succ
|
|
242
|
+
key = val[0...n]
|
|
243
|
+
val = val[n.succ..-1].stripquote
|
|
90
244
|
project.each { |name| ENV["#{key}_#{env_key(name.split(':').first)}"] = val }
|
|
91
245
|
end
|
|
92
|
-
|
|
246
|
+
each_with_index do |val, index|
|
|
93
247
|
if val == '--'
|
|
94
248
|
separator!(index: index)
|
|
95
249
|
break
|
|
96
250
|
end
|
|
97
251
|
next unless val.start_with?(':')
|
|
98
252
|
|
|
99
|
-
|
|
100
|
-
|
|
253
|
+
found = subtasks.map { |name| "#{name}#{val}" }.select { |name| tasks.include?(name) }
|
|
254
|
+
if (args = options[:'project-args'].shift)
|
|
255
|
+
found.map! { |name| "#{name}[#{args}]" }
|
|
256
|
+
end
|
|
257
|
+
global.concat(found)
|
|
101
258
|
ARGV[index] = ''
|
|
102
259
|
end
|
|
103
260
|
end
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
next false if val.match?(%r{^[\w~`!@#%&\-=:;"'<>/]+$})
|
|
261
|
+
Rake.application.run(global.concat(ARGV))
|
|
262
|
+
end
|
|
107
263
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
264
|
+
def tasks
|
|
265
|
+
@tasks ||= Rake.with_application do |rake|
|
|
266
|
+
if (rakefile = parse_rakefile)
|
|
267
|
+
rakefiles = rake.instance_variable_get(:@rakefiles)
|
|
268
|
+
rakefiles.clear
|
|
269
|
+
rakefiles << rakefile
|
|
111
270
|
end
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
session[:APP][:build_parallel] = parallel unless parallel.empty?
|
|
115
|
-
end
|
|
116
|
-
ARGV.reject!(&:empty?)
|
|
117
|
-
Rake.application.run(global.concat(ARGV))
|
|
271
|
+
rake.raw_load_rakefile
|
|
272
|
+
end.tasks.map(&:name)
|
|
118
273
|
end
|
|
119
274
|
|
|
120
275
|
def separator!(index:)
|
|
121
276
|
ARGV[index] = '' if ARGV.grep('--').size > 1
|
|
122
277
|
end
|
|
123
278
|
|
|
124
|
-
def
|
|
279
|
+
def check_exclusive(*args, flag:)
|
|
280
|
+
args.delete(flag)
|
|
281
|
+
return unless (n = index(*args))
|
|
282
|
+
|
|
283
|
+
error_exit "cannot be used with #{argv[n]}"
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
def error_exit(*val, hint: nil)
|
|
125
287
|
raise OptionParser::InvalidArgument, message(*val, hint: hint), caller(1)
|
|
126
288
|
end
|
|
289
|
+
|
|
290
|
+
def session
|
|
291
|
+
Common::ARG
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
def multilineopts
|
|
295
|
+
%w[-M --multiline]
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def each_with_index(&blk)
|
|
299
|
+
ARGV.each_with_index(&blk)
|
|
300
|
+
ARGV.reject!(&:empty?)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def index(*args)
|
|
304
|
+
argv.each_with_index do |val, i|
|
|
305
|
+
return i if args.any? { |s| val == s || (s.start_with?('--') && val.start_with?("#{s}=")) }
|
|
306
|
+
end
|
|
307
|
+
nil
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def warn(*args)
|
|
311
|
+
$stderr.puts(*args)
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def rakefile?
|
|
315
|
+
Rake.application.find_rakefile_location || parse_rakefile ? true : false
|
|
316
|
+
end
|
|
127
317
|
end
|
|
128
318
|
|
|
129
319
|
SqdParser.new do |sqd|
|
|
130
|
-
|
|
131
|
-
sqd.banner = 'Usage: sqd [options] [rake options] [global...] [:targets...] -- [rake targets...]'
|
|
320
|
+
sqd.banner = 'Usage: sqd [options] [rake options] [pathspec...] -- [global...] [:targets...] -- [rake targets...]'
|
|
132
321
|
sqd.separator ''
|
|
133
322
|
sqd.on('-R', '--ref STR,STR', Array, 'Run global commands by class reference') do |val|
|
|
134
323
|
sqd.parse_global(val, assert: :group)
|
|
135
|
-
session[:APP][:series_ref_min] = 1
|
|
324
|
+
sqd.session[:APP][:series_ref_min] = 1
|
|
136
325
|
end
|
|
137
326
|
sqd.on('-G', '--group STR,STR', Array, 'Run global commands by project group') do |val|
|
|
138
327
|
sqd.parse_global(val, assert: :ref)
|
|
@@ -143,82 +332,84 @@ SqdParser.new do |sqd|
|
|
|
143
332
|
sqd.options[:'project-args'] << val
|
|
144
333
|
end
|
|
145
334
|
sqd.on('-e', '--project-env KEY=STR', 'Provide command ENV variables for :targets (multiple)') do |val|
|
|
146
|
-
sqd.error_exit('missing value', "#{val}=") unless val.include?('=')
|
|
335
|
+
sqd.error_exit('missing value', hint: "#{val}=") unless val.include?('=')
|
|
147
336
|
sqd.options[:'project-env'] << val
|
|
148
337
|
end
|
|
149
338
|
sqd.separator ''
|
|
150
339
|
sqd.on('-s', '--[no-]strict', 'Do not run commands with invalid arguments') do |val|
|
|
151
|
-
session[:STRICT] = val
|
|
340
|
+
sqd.session[:STRICT] = val
|
|
152
341
|
ENV['STRICT'] = val ? 'true' : 'false'
|
|
153
342
|
end
|
|
154
343
|
sqd.on('--update', 'Use update strategy for applicable commands') do
|
|
155
344
|
ENV['UPDATE'] = 'true'
|
|
156
345
|
end
|
|
157
|
-
sqd.on('--parallel STR,PAT', Array, 'Run standard tasks with multi-task threads')
|
|
346
|
+
sqd.on('-u', '--parallel STR,PAT', Array, 'Run standard tasks with multi-task threads') do |val|
|
|
347
|
+
sqd.parse_series(val, flag: :parallel)
|
|
348
|
+
end
|
|
349
|
+
sqd.on('-U', '--sync STR,PAT', Array, 'Run parallel tasks in a series sequentially') do |val|
|
|
350
|
+
sqd.parse_series(val, flag: :sync)
|
|
351
|
+
end
|
|
158
352
|
sqd.on('-F', '--force [STR,STR]', Array, 'Enable force through ENV by application') do |val|
|
|
159
|
-
sqd.parse_common(val,
|
|
353
|
+
sqd.parse_common(val, arg: :FORCE)
|
|
160
354
|
end
|
|
161
355
|
sqd.on('-y', '--yes [STR,STR]', Array, 'Enable auto-approve through ENV by application') do |val|
|
|
162
|
-
sqd.parse_common(val,
|
|
356
|
+
sqd.parse_common(val, arg: :YES)
|
|
163
357
|
end
|
|
164
358
|
sqd.on('-d', '--dry-run', 'Run commands without any modifying actions') do
|
|
165
359
|
ENV['DRY_RUN'] = 'true'
|
|
166
360
|
end
|
|
167
361
|
sqd.separator ''
|
|
168
|
-
sqd.on('-S', '--select PAGE[:CHOICE]', 'Prompt menu selection pagination display (e.g.
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
ENV['SELECT'] = "#{page}:#{choice}"
|
|
362
|
+
sqd.on('-S', '--select PAGE[:CHOICE]', 'Prompt menu selection pagination display (e.g. 20:60)') do |val|
|
|
363
|
+
sqd.option_select(val)
|
|
364
|
+
end
|
|
365
|
+
sqd.on('-M', '--multiline STR', 'Use advanced editor with custom message terminator (e.g. EOF)') do |val|
|
|
366
|
+
sqd.option_multiline(val)
|
|
174
367
|
end
|
|
175
368
|
sqd.separator ''
|
|
369
|
+
sqd.on('-g', '--[no-]gemfile', 'Execute commands using bundle exec and nearest Gemfile') do |val|
|
|
370
|
+
sqd.option_gemfile(val)
|
|
371
|
+
end
|
|
176
372
|
sqd.on('-p', '--pipe 0|1|2', Integer, 'Set file descriptor for communication') do |val|
|
|
177
|
-
sqd.
|
|
178
|
-
session[:PIPE] = val
|
|
373
|
+
sqd.parse_range(val, max: 2, arg: :PIPE)
|
|
179
374
|
end
|
|
180
375
|
sqd.on('-o', '--pipe-out FILE', 'Write command data stream to a file') do |val|
|
|
181
|
-
sqd.error_exit("missing an explicit \".#{File::SEPARATOR}\"", val) unless val.include?(File::SEPARATOR)
|
|
182
|
-
session[:OUT] = val
|
|
376
|
+
sqd.error_exit("missing an explicit \".#{File::SEPARATOR}\"", hint: val) unless val.include?(File::SEPARATOR)
|
|
377
|
+
sqd.session[:OUT] = val
|
|
183
378
|
end
|
|
184
379
|
sqd.on('--fail 0..4', Integer, 'Set application exception level') do |val|
|
|
185
|
-
sqd.
|
|
186
|
-
session[:FAIL] = val
|
|
380
|
+
sqd.parse_range(val, max: 4, arg: :FAIL)
|
|
187
381
|
end
|
|
188
382
|
%i[debug info warn error fatal].then do |state|
|
|
189
383
|
values = state + (0..4).map(&:to_s)
|
|
190
384
|
sqd.on('--log-level SEVERITY', values, "Set logger and exception state (#{state.join(', ')})") do |val|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
385
|
+
sqd.option_loglevel(val)
|
|
386
|
+
end
|
|
387
|
+
end
|
|
388
|
+
if Pathname.pwd.join('.git').directory?
|
|
389
|
+
sqd.separator ''
|
|
390
|
+
sqd.on('-c', '--commit', 'Push files remotely on active branch from current directory') do
|
|
391
|
+
sqd.option_commit('-c', '--commit', flag: :pathspec)
|
|
392
|
+
end
|
|
393
|
+
sqd.on('--amend', 'Replace the tip of the active branch remotely with a force push') do
|
|
394
|
+
sqd.option_commit('--amend', flag: :amend)
|
|
395
|
+
end
|
|
396
|
+
sqd.on('--amend-orig', 'Perform an amend commit without changing the message') do
|
|
397
|
+
sqd.option_commit('--amend-orig', flag: :'amend-orig')
|
|
203
398
|
end
|
|
204
399
|
end
|
|
205
400
|
sqd.separator ''
|
|
206
401
|
sqd.on('--[no-]banner', 'Display executing command attributes') do |val|
|
|
207
|
-
sqd.banner_set(val
|
|
402
|
+
sqd.banner_set(val)
|
|
208
403
|
end
|
|
209
404
|
sqd.on('-x', '--[no-]color', 'Use enhanced styling for terminal output') do |val|
|
|
210
|
-
sqd.color_set(val
|
|
405
|
+
sqd.color_set(val)
|
|
211
406
|
end
|
|
212
407
|
sqd.on('-X', '--plain', 'Disable banner and styling for all commands') do
|
|
213
|
-
sqd.banner_set(false
|
|
214
|
-
sqd.color_set(false
|
|
408
|
+
sqd.banner_set(false)
|
|
409
|
+
sqd.color_set(false)
|
|
215
410
|
end
|
|
216
411
|
sqd.on('-v', '--verbose', 'Increase output verbosity (multiple)') do
|
|
217
|
-
|
|
218
|
-
session[:VERBOSE] = $VERBOSE ? 1 : 0
|
|
219
|
-
sqd.global.unshift('--verbose')
|
|
220
|
-
end
|
|
221
|
-
ENV['VERBOSE'] = (session[:VERBOSE] += 1).to_s
|
|
412
|
+
sqd.option_verbose
|
|
222
413
|
end
|
|
223
414
|
sqd.on('--version', 'Print the current version') do
|
|
224
415
|
puts Squared::VERSION
|
data/lib/squared/common/base.rb
CHANGED
|
@@ -17,6 +17,7 @@ module Squared
|
|
|
17
17
|
BANNER: true,
|
|
18
18
|
PAGE: 20,
|
|
19
19
|
CHOICE: 100,
|
|
20
|
+
TAB: 4,
|
|
20
21
|
QUOTE: "'",
|
|
21
22
|
SPACE: ' => ',
|
|
22
23
|
SUCCESS: 'Success',
|
|
@@ -105,6 +106,7 @@ module Squared
|
|
|
105
106
|
|
|
106
107
|
def __freeze__
|
|
107
108
|
PATH.freeze
|
|
109
|
+
ARG.each_value { |val| val.freeze if val.is_a?(::Hash) || val.is_a?(::Array) }
|
|
108
110
|
ARG.freeze
|
|
109
111
|
VAR.each_value(&:freeze)
|
|
110
112
|
VAR[:theme].each_value { |val| val.freeze.each_value(&:freeze) }
|