squared 0.0.10 → 0.0.12
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/README.ruby.md +98 -26
- data/lib/squared/app.rb +10 -0
- data/lib/squared/common/base.rb +12 -16
- data/lib/squared/common/class.rb +26 -1
- data/lib/squared/common/format.rb +79 -24
- data/lib/squared/common/prompt.rb +36 -0
- data/lib/squared/common/shell.rb +4 -3
- data/lib/squared/common/system.rb +15 -47
- data/lib/squared/common/utils.rb +51 -16
- data/lib/squared/common.rb +1 -4
- data/lib/squared/config.rb +48 -43
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +245 -125
- data/lib/squared/workspace/project/base.rb +448 -188
- data/lib/squared/workspace/project/git.rb +97 -113
- data/lib/squared/workspace/project/node.rb +217 -109
- data/lib/squared/workspace/project/python.rb +37 -34
- data/lib/squared/workspace/project/ruby.rb +137 -100
- data/lib/squared/workspace/project.rb +0 -3
- data/lib/squared/workspace/repo.rb +32 -18
- data/lib/squared/workspace/series.rb +82 -53
- data/lib/squared/workspace.rb +6 -5
- data/lib/squared.rb +1 -11
- metadata +4 -3
- data/lib/squared/common/task.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2d9e8c772c9f4d0ce5c54dbeb1b9583d2e477f155036faf34cfc547659c34ec4
|
4
|
+
data.tar.gz: 87de412a78c0071eabd4b26713cbf84978a92fca6ea1a6dfe18653ddf22c90ee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '08475f426b15c41dab20fbead5d7c1ead70f5d80384e0a0772cbe7b101512a4402a1bb1231b2550f7da16aac2796f8411f6a6e3e570ae728d59b03f88fea5960'
|
7
|
+
data.tar.gz: 5c0334640b20dda82641925cd94b41d76be4cd4e603355fef593a5cd69731ac926febab67f3ffa494267291ec9d89efba2f8a9ac4dde978ab2814a0f8a481a67
|
data/README.ruby.md
CHANGED
@@ -34,7 +34,14 @@ Projects from any accessible folder can be added either relative to `REPO_ROOT`
|
|
34
34
|
|
35
35
|
```ruby
|
36
36
|
require "squared"
|
37
|
-
|
37
|
+
|
38
|
+
require "squared/workspace"
|
39
|
+
require "squared/workspace/repo" # Optional
|
40
|
+
require "squared/workspace/project/node" #
|
41
|
+
require "squared/workspace/project/python" #
|
42
|
+
require "squared/workspace/project/ruby" #
|
43
|
+
# OR
|
44
|
+
require "squared/app" # All workspace related modules
|
38
45
|
|
39
46
|
# NODE_ENV = production
|
40
47
|
# REPO_ROOT = /workspaces
|
@@ -52,7 +59,7 @@ require "squared/workspace/repo" # Repo (optional)
|
|
52
59
|
|
53
60
|
Workspace::Application
|
54
61
|
.new(Dir.pwd, main: "squared") # Dir.pwd? (main? is implicitly basename)
|
55
|
-
.banner("group", "project", styles:
|
62
|
+
.banner("group", "project", styles: ["yellow", "black"], border: "bold") # name | project | path | ref | group? | parent? | version?
|
56
63
|
.repo("https://github.com/anpham6/squared-repo", "nightly", script: ["build:dev", "build:prod"], ref: :node) # Repo (optional)
|
57
64
|
.run("rake install", ref: :ruby)
|
58
65
|
.depend(false, group: "default")
|
@@ -63,13 +70,17 @@ Workspace::Application
|
|
63
70
|
"CFLAGS" => "-fPIC -O1"
|
64
71
|
})
|
65
72
|
.add("optparse", doc: "rake rdoc", group: "default") # Uses bundler/gem_tasks (without C extensions)
|
66
|
-
.add("logger", copy: { from: "lib", glob: "**/*.rb",
|
67
|
-
.add("e-mc", "emc", copy: { from: "publish",
|
68
|
-
.add("pi-r", "pir", copy: { from: "publish",
|
73
|
+
.add("logger", copy: { from: "lib", glob: "**/*.rb", into: "~/.rvm/gems/ruby-3.3.5/gems/logger-1.6.1" }, clean: ["tmp/"]) # autodetect: true
|
74
|
+
.add("e-mc", "emc", copy: { from: "publish", scope: "@e-mc", also: [:pir, "squared-express/"] }, ref: :node) # Node
|
75
|
+
.add("pi-r", "pir", copy: { from: "publish", scope: "@pi-r" }, clean: ["publish/**/*.js", "tmp/"]) # Trailing slash required for directories
|
69
76
|
.add("squared", script: ["build:stage1", "build:stage2"], group: "app") do # Copy target (main)
|
70
|
-
add("publish/sqd-cli", "cli", exclude: [:git])
|
71
|
-
add("publish/sqd-serve")
|
77
|
+
add("publish/sqd-cli", "cli", exclude: [:git]) # rake cli:build
|
78
|
+
add("publish/sqd-serve") # rake sqd-serve:build
|
72
79
|
add("publish/sqd-admin", group: "sqd", exclude: [:base])
|
80
|
+
# OR
|
81
|
+
with(exclude: [:base]) { add("publish/*", "packages") } # rake packages:sqd-serve:build
|
82
|
+
# OR
|
83
|
+
add(["publish/sqd-cli", "publish/sqd-serve", "publish/sqd-admin"], true, exclude: [:base]) # rake squared:sqd-serve:build
|
73
84
|
end
|
74
85
|
.add("squared/sqd", exclude: [:git]) do
|
75
86
|
variable_set :script, "build:sqd" # Override detection
|
@@ -77,7 +88,7 @@ Workspace::Application
|
|
77
88
|
variable_set :clean, ["build/sqd/"]
|
78
89
|
end
|
79
90
|
.style("banner", 255.255) # 256 colors (fg | fg.bg | -0.bg)
|
80
|
-
.build(default: "status", parallel: ["pull", "fetch", "rebase", "copy", "clean"]) do |workspace|
|
91
|
+
.build(default: "status", parallel: ["pull", "fetch", "rebase", "copy", "clean", "outdated:ruby"]) do |workspace|
|
81
92
|
workspace
|
82
93
|
.enable_aixterm
|
83
94
|
.style({
|
@@ -97,28 +108,80 @@ Workspace::Application
|
|
97
108
|
.new(ENV["SQUARED_HOME"], prefix: "rb", common: false) # Local styles
|
98
109
|
.group("ruby", "default", run: "rake build", copy: "rake install", clean: "rake clean", ref: :ruby, override: {
|
99
110
|
pathname: {
|
100
|
-
run: "rake compile"
|
111
|
+
run: "rake compile" # rake rb:pathname:build
|
101
112
|
}
|
102
113
|
})
|
103
|
-
.with(:python) do
|
104
|
-
banner(
|
105
|
-
doc("make html")
|
106
|
-
run(false)
|
107
|
-
exclude(%i[base git])
|
108
|
-
add("android-docs", "android")
|
109
|
-
add("chrome-docs", "chrome")
|
110
|
-
end
|
114
|
+
.with(:python) do # ref=Symbol | group=String
|
115
|
+
banner([:name, ": ", :version], "path") # chrome-docs: 0.1.0 | /workspaces/chrome-docs
|
116
|
+
doc("make html") # rake rb:doc:python
|
117
|
+
run(false) # rake rb:build:python (disabled)
|
118
|
+
exclude(%i[base git]) # Project::Git.ref (superclass)
|
119
|
+
add("android-docs", "android") # rake rb:android:doc
|
120
|
+
add("chrome-docs", "chrome") # rake rb:chrome:doc
|
121
|
+
end #
|
111
122
|
.style("inline", "bold")
|
112
123
|
.build
|
113
124
|
```
|
114
125
|
|
115
|
-
**NOTE**: The use of "**ref**" (class name) is only necessary when
|
126
|
+
**NOTE**: The use of "**ref**" (class name) is only necessary when initializing an empty directory (e.g. *rake repo:init*).
|
127
|
+
|
128
|
+
### Graph
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
Workspace::Application
|
132
|
+
.new(main: "squared")
|
133
|
+
.with(:python) do
|
134
|
+
add("android-docs", "android")
|
135
|
+
add("chrome-docs", "chrome", graph: "android")
|
136
|
+
end
|
137
|
+
.with(:node) do
|
138
|
+
graph(["build", "copy"]) # Optional
|
139
|
+
add("e-mc", "emc")
|
140
|
+
add("pi-r", "pir", graph: "emc")
|
141
|
+
add("squared-express", "express", graph: "pir")
|
142
|
+
add("squared", graph: ["chrome", "express"])
|
143
|
+
end
|
144
|
+
.with(:ruby) do
|
145
|
+
add("pathname")
|
146
|
+
add("fileutils", graph: "pathname")
|
147
|
+
add("optparse")
|
148
|
+
add("rake", graph: ["fileutils", "optparse"])
|
149
|
+
end
|
150
|
+
.build
|
151
|
+
```
|
152
|
+
|
153
|
+
```sh
|
154
|
+
rake pir:graph # emc + pir
|
155
|
+
rake express:graph # emc + pir + express
|
156
|
+
rake chrome:graph # android + chrome
|
157
|
+
rake graph:python # same
|
158
|
+
rake squared:graph # android + chrome + emc + pir + express + squared
|
159
|
+
rake graph:node # same
|
160
|
+
rake rake:graph # pathname + fileutils + optparse + rake
|
161
|
+
rake graph:ruby # same
|
162
|
+
rake graph # graph:node + graph:ruby
|
163
|
+
```
|
164
|
+
|
165
|
+
### Batch
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
Workspace::Series.batch(:ruby, :node, {
|
169
|
+
stage: %i[graph test],
|
170
|
+
reset: %i[stash pull]
|
171
|
+
})
|
172
|
+
```
|
173
|
+
|
174
|
+
### Rename
|
175
|
+
|
176
|
+
```ruby
|
177
|
+
Workspace::Series.rename("depend", "install")
|
178
|
+
```
|
116
179
|
|
117
180
|
## Usage
|
118
181
|
|
119
182
|
```sh
|
120
|
-
rake -T
|
121
|
-
rake
|
183
|
+
rake -T # List tasks
|
184
|
+
rake # rake status (usually "build")
|
122
185
|
|
123
186
|
# GIT_OPTIONS=rebase
|
124
187
|
rake pull # All except "default" + "app"
|
@@ -145,6 +208,7 @@ rake build:app # squared + cli + sqd-serve
|
|
145
208
|
rake squared:build:workspace # cli + sqd-serve
|
146
209
|
rake pull:sqd # sqd-admin
|
147
210
|
rake squared:pull:workspace # sqd-serve + sqd-admin
|
211
|
+
rake squared:outdated:workspace # cli + sqd-serve + sqd-admin
|
148
212
|
```
|
149
213
|
|
150
214
|
## Methods
|
@@ -153,6 +217,7 @@ Task:
|
|
153
217
|
|
154
218
|
* run
|
155
219
|
* depend
|
220
|
+
* graph
|
156
221
|
* test
|
157
222
|
* doc
|
158
223
|
* clean
|
@@ -179,14 +244,21 @@ Non-task:
|
|
179
244
|
### Build
|
180
245
|
|
181
246
|
```ruby
|
247
|
+
# :env :run :opts
|
182
248
|
# LD_LIBRARY_PATH="path/to/lib" CFLAGS="-Wall" gcc a.c -o a.o -c
|
183
249
|
BUILD_${NAME} # gcc a.c -o a.o
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
#
|
188
|
-
|
189
|
-
BUILD_${NAME}
|
250
|
+
BUILD_OPTS_${NAME} # -c
|
251
|
+
BUILD_ENV_${NAME} # {"LD_LIBRARY_PATH":"path/to/lib","CFLAGS":"-Wall"} (hash/json)
|
252
|
+
|
253
|
+
# :env :opts :script
|
254
|
+
# NODE_ENV="production" NO_COLOR="1" npm run --loglevel=error --workspaces=false build:dev
|
255
|
+
BUILD_${NAME} # build:dev
|
256
|
+
BUILD_OPTS_${NAME} # --loglevel=error --workspaces=false
|
257
|
+
BUILD_ENV_${NAME} # {"NODE_ENV":"production","NO_COLOR":"1"} (hash/json)
|
258
|
+
BUILD_DEV_${NAME} # pattern,0,1 (:dev)
|
259
|
+
BUILD_PROD_${NAME} # pattern,0,1 (:prod)
|
260
|
+
|
261
|
+
BUILD_${NAME}=0 # skip project
|
190
262
|
```
|
191
263
|
|
192
264
|
These options also support the project specific suffix `${NAME}`. (e.g. LOG_FILE_SQUARED)
|
data/lib/squared/app.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'workspace'
|
4
|
+
require_relative 'workspace/repo'
|
5
|
+
require_relative 'workspace/project/node'
|
6
|
+
require_relative 'workspace/project/python'
|
7
|
+
require_relative 'workspace/project/ruby'
|
8
|
+
require_relative 'config'
|
9
|
+
|
10
|
+
Common = Squared::Common
|
data/lib/squared/common/base.rb
CHANGED
@@ -2,10 +2,16 @@
|
|
2
2
|
|
3
3
|
module Squared
|
4
4
|
module Common
|
5
|
-
|
5
|
+
ARG = {
|
6
6
|
PIPE: 1,
|
7
|
+
OUT: nil,
|
8
|
+
VERBOSE: nil,
|
7
9
|
FAIL: false,
|
8
|
-
COMMON: true
|
10
|
+
COMMON: true,
|
11
|
+
BANNER: true,
|
12
|
+
SPACE: ' => ',
|
13
|
+
GRAPH: ['│', '─', '├', '└', '┬'],
|
14
|
+
COLOR: ENV.fetch('NO_COLOR', '').empty?
|
9
15
|
}
|
10
16
|
VAR = {
|
11
17
|
project: {},
|
@@ -70,6 +76,7 @@ module Squared
|
|
70
76
|
end
|
71
77
|
|
72
78
|
def __freeze__
|
79
|
+
ARG.freeze
|
73
80
|
VAR.each_value(&:freeze)
|
74
81
|
VAR[:theme].each_value(&:freeze)
|
75
82
|
VAR.freeze
|
@@ -77,30 +84,19 @@ module Squared
|
|
77
84
|
|
78
85
|
module_function
|
79
86
|
|
80
|
-
def env(key, default = nil, equals: nil, ignore: nil, **)
|
81
|
-
ret = ENV.fetch(key, '')
|
82
|
-
return ret == equals.to_s unless equals.nil?
|
83
|
-
|
84
|
-
ret.empty? || (ignore && as_a(ignore).any? { |val| ret == val.to_s }) ? default : ret
|
85
|
-
end
|
86
|
-
|
87
|
-
def message(*args, hint: nil)
|
88
|
-
args.reject(&:empty?).join(' => ') + (hint ? " (#{hint})" : '')
|
89
|
-
end
|
90
|
-
|
91
87
|
def as_a(obj, meth = nil, flat: nil, compact: false)
|
92
88
|
return [] if obj.nil?
|
93
89
|
|
94
90
|
unless obj.is_a?(::Array)
|
95
|
-
obj = if
|
91
|
+
obj = if obj.respond_to?(:to_a) && !obj.is_a?(::Hash) && (val = obj.to_a).is_a?(::Array)
|
96
92
|
val
|
97
93
|
else
|
98
94
|
[obj]
|
99
95
|
end
|
100
96
|
end
|
101
97
|
obj = obj.flatten(flat.is_a?(::Numeric) ? flat : nil) if flat
|
102
|
-
obj = obj.
|
103
|
-
|
98
|
+
obj = obj.compact if compact
|
99
|
+
meth ? obj.map(&meth) : obj
|
104
100
|
end
|
105
101
|
end
|
106
102
|
end
|
data/lib/squared/common/class.rb
CHANGED
@@ -1,12 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'set'
|
4
|
+
require 'forwardable'
|
4
5
|
|
5
6
|
module Squared
|
6
7
|
module Common
|
8
|
+
class SymSet
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
def self.to_s
|
12
|
+
super.match(/[^:]+$/)[0]
|
13
|
+
end
|
14
|
+
|
15
|
+
def_delegators :@data, :+, :each, :each_with_index, :entries, :to_a, :include?
|
16
|
+
|
17
|
+
def initialize(data = [])
|
18
|
+
@data = ::Set.new(data)
|
19
|
+
end
|
20
|
+
|
21
|
+
def add(val)
|
22
|
+
@data.add(val.to_sym)
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
@data.to_s.sub('Set', SymSet.to_s)
|
27
|
+
end
|
28
|
+
|
29
|
+
alias inspect to_s
|
30
|
+
end
|
31
|
+
|
7
32
|
class JoinSet < ::Set
|
8
33
|
def self.to_s
|
9
|
-
super.
|
34
|
+
super.match(/[^:]+$/)[0]
|
10
35
|
end
|
11
36
|
|
12
37
|
def initialize(data = [], delim: ' ')
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'pathname'
|
3
4
|
require 'logger'
|
4
5
|
|
5
6
|
require_relative 'base'
|
@@ -40,7 +41,7 @@ module Squared
|
|
40
41
|
private
|
41
42
|
|
42
43
|
def sub_style(val, *args, styles: nil, pat: nil, index: 1)
|
43
|
-
return val unless
|
44
|
+
return val unless ARG[:COLOR]
|
44
45
|
|
45
46
|
if pat && index != 0
|
46
47
|
return val unless (data = pat.match(val))
|
@@ -106,7 +107,7 @@ module Squared
|
|
106
107
|
out
|
107
108
|
end
|
108
109
|
|
109
|
-
def check_style(
|
110
|
+
def check_style(args, empty: true)
|
110
111
|
ret = []
|
111
112
|
colors = __get__(:colors)
|
112
113
|
as_a(args, flat: true, compact: true).each do |val|
|
@@ -123,7 +124,7 @@ module Squared
|
|
123
124
|
ret if empty || !ret.empty?
|
124
125
|
end
|
125
126
|
|
126
|
-
def apply_style(data, key,
|
127
|
+
def apply_style(data, key, args, empty: true)
|
127
128
|
return if data.is_a?(::Symbol) && (data = __get__(:theme)[data]).nil?
|
128
129
|
|
129
130
|
set = ->(k, v) { data[k] = check_style(v, empty: empty) }
|
@@ -137,15 +138,15 @@ module Squared
|
|
137
138
|
def log_sym(level)
|
138
139
|
if level.is_a?(::Numeric)
|
139
140
|
case level
|
140
|
-
when Logger::DEBUG
|
141
|
+
when ::Logger::DEBUG
|
141
142
|
:debug
|
142
|
-
when Logger::INFO
|
143
|
+
when ::Logger::INFO
|
143
144
|
:info
|
144
|
-
when Logger::WARN
|
145
|
+
when ::Logger::WARN
|
145
146
|
:warn
|
146
|
-
when Logger::ERROR
|
147
|
+
when ::Logger::ERROR
|
147
148
|
:error
|
148
|
-
when Logger::FATAL
|
149
|
+
when ::Logger::FATAL
|
149
150
|
:fatal
|
150
151
|
else
|
151
152
|
:unknown
|
@@ -155,7 +156,7 @@ module Squared
|
|
155
156
|
end
|
156
157
|
end
|
157
158
|
|
158
|
-
def log_title(level, color:
|
159
|
+
def log_title(level, color: ARG[:COLOR])
|
159
160
|
theme = __get__(:theme)[:logger]
|
160
161
|
styles = theme[level = log_sym(level)] || theme[level = :unknown]
|
161
162
|
case (ret = +level.to_s.upcase)
|
@@ -165,7 +166,7 @@ module Squared
|
|
165
166
|
color ? sub_style(ret, *styles) : ret
|
166
167
|
end
|
167
168
|
|
168
|
-
def log_message(level, *args, subject: nil, hint: nil, color:
|
169
|
+
def log_message(level, *args, subject: nil, hint: nil, color: ARG[:COLOR])
|
169
170
|
args = args.map(&:to_s)
|
170
171
|
if args.size > 1
|
171
172
|
title = log_title(level, color: false)
|
@@ -183,49 +184,103 @@ module Squared
|
|
183
184
|
end
|
184
185
|
end
|
185
186
|
|
186
|
-
def
|
187
|
-
|
187
|
+
def puts_oe(*args, pipe: 1)
|
188
|
+
if pipe.is_a?(::Pathname)
|
189
|
+
begin
|
190
|
+
::File.open(pipe, 'a') do |f|
|
191
|
+
br = ::File::SEPARATOR == '\\' ? "\r\n" : "\n"
|
192
|
+
args.flatten.each { |val| f.write("#{strip_style(val.chomp)}#{br}") }
|
193
|
+
end
|
194
|
+
return
|
195
|
+
rescue StandardError
|
196
|
+
pipe = 2
|
197
|
+
end
|
198
|
+
end
|
199
|
+
(pipe == 2 ? $stderr : $stdout).puts(*args)
|
188
200
|
end
|
189
201
|
|
190
202
|
module_function
|
191
203
|
|
192
|
-
def
|
204
|
+
def message(*args, hint: nil, empty: false)
|
205
|
+
(empty ? args.reject { |val| val.nil? || val.empty? } : args).join(ARG[:SPACE]) + (hint ? " (#{hint})" : '')
|
206
|
+
end
|
207
|
+
|
208
|
+
def emphasize(val, title: nil, footer: nil, right: false, cols: nil, sub: nil, border: nil, pipe: nil)
|
193
209
|
n = 0
|
194
|
-
|
195
|
-
|
196
|
-
|
210
|
+
max = ->(v) { n = [n, v.max_by(&:size).size].max }
|
211
|
+
set = lambda do |v|
|
212
|
+
ret = as_a(v, :to_s)
|
213
|
+
max.(ret)
|
214
|
+
ret
|
197
215
|
end
|
216
|
+
title &&= set.(title)
|
217
|
+
footer &&= set.(footer)
|
198
218
|
if val.is_a?(::Array)
|
199
|
-
lines = val
|
219
|
+
lines = val.map(&:to_s)
|
200
220
|
else
|
201
221
|
lines = val.to_s.lines.map(&:chomp)
|
202
|
-
lines[0] = "#{val.class}: #{lines.first}" if (err = val.is_a?(
|
222
|
+
lines[0] = "#{val.class}: #{lines.first}" if (err = val.is_a?(StandardError))
|
203
223
|
end
|
204
|
-
n = cols ||
|
224
|
+
n = cols || max.(lines)
|
205
225
|
if $stdout.tty?
|
206
226
|
require 'io/console'
|
207
227
|
(n = [n, $stdout.winsize[1] - 4].min) rescue nil
|
208
228
|
end
|
209
229
|
out = []
|
210
230
|
bord = '-' * (n + 4)
|
211
|
-
|
231
|
+
bord = sub_style(bord, styles: border) if border
|
232
|
+
sub = as_a(sub)
|
212
233
|
pr = lambda do |line|
|
213
234
|
s = line.ljust(n)
|
214
|
-
sub
|
215
|
-
"| #{s} |"
|
235
|
+
sub.each { |h| s = sub_style(s, **h) }
|
236
|
+
s = "| #{s} |"
|
237
|
+
if border
|
238
|
+
s = sub_style(s, pat: /^(\|)(.+)$/m, styles: border)
|
239
|
+
s = sub_style(s, pat: /^(.+)(\|)$/m, styles: border, index: 2)
|
240
|
+
end
|
241
|
+
s
|
216
242
|
end
|
217
243
|
out << bord
|
218
|
-
|
244
|
+
if title
|
245
|
+
out += title.map { |t| pr.(t) }
|
246
|
+
out << bord
|
247
|
+
end
|
219
248
|
lines.each { |line| out << pr.(line) }
|
220
249
|
out << bord
|
250
|
+
if footer
|
251
|
+
unless sub.empty? && !right
|
252
|
+
footer.map! do |s|
|
253
|
+
s = s.rjust(n + 4) if right
|
254
|
+
sub.each { |h| s = sub_style(s, **h) }
|
255
|
+
s
|
256
|
+
end
|
257
|
+
end
|
258
|
+
out += footer
|
259
|
+
end
|
221
260
|
if block_given?
|
222
261
|
yield out
|
223
|
-
elsif pipe
|
262
|
+
elsif pipe
|
263
|
+
case pipe
|
264
|
+
when 0
|
265
|
+
pipe = $stdin
|
266
|
+
when 2
|
267
|
+
pipe = $stderr
|
268
|
+
else
|
269
|
+
pipe = $stdout unless pipe.respond_to?(:puts)
|
270
|
+
end
|
224
271
|
pipe.puts out
|
225
272
|
else
|
226
273
|
err ? warn(out) : puts(out)
|
227
274
|
end
|
228
275
|
end
|
276
|
+
|
277
|
+
def strip_style(val)
|
278
|
+
val.gsub(/\x1B\[(\d+;?)+m/, '')
|
279
|
+
end
|
280
|
+
|
281
|
+
def raise_error(*args, hint: nil, kind: ArgumentError)
|
282
|
+
raise kind, message(*args, hint: hint, empty: true)
|
283
|
+
end
|
229
284
|
end
|
230
285
|
end
|
231
286
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Squared
|
4
|
+
module Common
|
5
|
+
module Prompt
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def confirm(msg, default = nil, agree: 'Y', cancel: 'N', attempts: 5, timeout: 15)
|
9
|
+
require 'readline'
|
10
|
+
require 'timeout'
|
11
|
+
agree = /^#{agree}$/i if agree.is_a?(::String)
|
12
|
+
cancel = /^#{cancel}$/i if cancel.is_a?(::String)
|
13
|
+
Timeout.timeout(timeout) do
|
14
|
+
begin
|
15
|
+
while (ch = Readline.readline(msg, true))
|
16
|
+
ch = ch.chomp
|
17
|
+
case (ch.empty? ? default : ch)
|
18
|
+
when agree
|
19
|
+
return true
|
20
|
+
when cancel
|
21
|
+
return false
|
22
|
+
end
|
23
|
+
attempts -= 1
|
24
|
+
exit 1 unless attempts >= 0
|
25
|
+
end
|
26
|
+
rescue Interrupt
|
27
|
+
puts
|
28
|
+
exit 0
|
29
|
+
else
|
30
|
+
false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/squared/common/shell.rb
CHANGED
@@ -9,9 +9,10 @@ module Squared
|
|
9
9
|
module_function
|
10
10
|
|
11
11
|
def shell_escape(val, quote: false)
|
12
|
-
|
12
|
+
val = val.to_s
|
13
|
+
return ::Shellwords.escape(val) unless ::Rake::Win32.windows?
|
13
14
|
|
14
|
-
quote ? shell_quote(
|
15
|
+
quote ? shell_quote(val, force: false) : val
|
15
16
|
end
|
16
17
|
|
17
18
|
def shell_quote(val, force: true)
|
@@ -22,7 +23,7 @@ module Squared
|
|
22
23
|
end
|
23
24
|
|
24
25
|
def shell_split(val, quote: false, join: false)
|
25
|
-
ret = Shellwords.split(val).map do |opt|
|
26
|
+
ret = ::Shellwords.split(val).map do |opt|
|
26
27
|
if (data = /^(--?[^= ]+)(=|\s+)?(["'])?(.+?)\3?$/m.match(opt))
|
27
28
|
next opt unless data[2] && !data[3]
|
28
29
|
|
@@ -8,67 +8,37 @@ module Squared
|
|
8
8
|
module System
|
9
9
|
module_function
|
10
10
|
|
11
|
-
def shell(*
|
11
|
+
def shell(*args, **kwargs)
|
12
12
|
if RUBY_VERSION =~ /^2\.[0-5]\./
|
13
13
|
exception = kwargs.delete(:exception)
|
14
|
-
ret = system(*
|
15
|
-
|
14
|
+
ret = system(*args, **kwargs)
|
15
|
+
return ret if ret || !exception
|
16
16
|
|
17
|
-
|
17
|
+
raise $?.to_s
|
18
18
|
else
|
19
|
-
system(*
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def confirm(msg, default = nil, agree: 'Y', cancel: 'N', attempts: 5, timeout: 15)
|
24
|
-
require 'readline'
|
25
|
-
require 'timeout'
|
26
|
-
agree = /^#{agree}$/i if agree.is_a?(::String)
|
27
|
-
cancel = /^#{cancel}$/i if cancel.is_a?(::String)
|
28
|
-
Timeout.timeout(timeout) do
|
29
|
-
begin
|
30
|
-
while (ch = Readline.readline(msg, true))
|
31
|
-
ch = ch.chomp
|
32
|
-
ch = default if ch.empty?
|
33
|
-
case ch
|
34
|
-
when agree
|
35
|
-
return true
|
36
|
-
when cancel
|
37
|
-
return false
|
38
|
-
end
|
39
|
-
attempts -= 1
|
40
|
-
exit 1 unless attempts >= 0
|
41
|
-
end
|
42
|
-
rescue Interrupt
|
43
|
-
puts
|
44
|
-
exit 0
|
45
|
-
else
|
46
|
-
false
|
47
|
-
end
|
19
|
+
system(*args, **kwargs)
|
48
20
|
end
|
49
21
|
end
|
50
22
|
|
51
23
|
def copy_d(src, dest, glob: ['**/*'], create: false, verbose: true)
|
52
|
-
src = Pathname.new(src)
|
53
|
-
dest = Pathname.new(dest)
|
24
|
+
src = ::Pathname.new(src)
|
25
|
+
dest = ::Pathname.new(dest)
|
54
26
|
raise "#{dest} (not found)" if !create && !dest.exist?
|
55
27
|
|
56
28
|
subdir = []
|
57
29
|
files = 0
|
58
30
|
dest.mkpath if create
|
59
|
-
glob
|
60
|
-
|
61
|
-
|
62
|
-
ent = Pathname.new(path)
|
63
|
-
next if ent.directory?
|
31
|
+
(glob.is_a?(::Array) ? glob : [glob]).each do |val|
|
32
|
+
::Dir.glob(src.join(val)) do |path|
|
33
|
+
next if (path = ::Pathname.new(path)).directory?
|
64
34
|
|
65
|
-
target = dest.join(
|
35
|
+
target = dest.join(path.relative_path_from(src))
|
66
36
|
dir = target.dirname
|
67
37
|
unless subdir.include?(dir.to_s)
|
68
38
|
dir.mkpath
|
69
39
|
subdir << dir.to_s
|
70
40
|
end
|
71
|
-
copy_f
|
41
|
+
copy_f path, target
|
72
42
|
files += 1
|
73
43
|
end
|
74
44
|
end
|
@@ -77,15 +47,13 @@ module Squared
|
|
77
47
|
|
78
48
|
def copy_f(src, dest, overwrite: true, verbose: false)
|
79
49
|
unless overwrite
|
80
|
-
path = Pathname.new(dest)
|
81
|
-
|
82
|
-
src = [src] unless src.is_a?(::Array)
|
83
|
-
src = src.reject { |val| path.join(File.basename(val)).exist? }
|
50
|
+
if (path = ::Pathname.new(dest)).directory?
|
51
|
+
src = (src.is_a?(::Array) ? src : [src]).reject { |val| path.join(::File.basename(val)).exist? }
|
84
52
|
elsif path.exist?
|
85
53
|
return
|
86
54
|
end
|
87
55
|
end
|
88
|
-
FileUtils.cp(src, dest, verbose: verbose)
|
56
|
+
::FileUtils.cp(src, dest, verbose: verbose)
|
89
57
|
end
|
90
58
|
end
|
91
59
|
end
|