prick 0.31.0 → 0.32.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/exe/prick +10 -3
- data/lib/prick/builder/parser.rb +4 -3
- data/lib/prick/environment.rb +317 -101
- data/lib/prick/local/command.rb +0 -4
- data/lib/prick/local/fmt.rb +74 -31
- data/lib/prick/state.rb +26 -14
- data/lib/prick/subcommand/prick-bash.rb +53 -0
- data/lib/prick/subcommand/prick-list.rb +15 -2
- data/lib/prick/subcommand/prick-release.rb +1 -1
- data/lib/prick/version.rb +1 -1
- data/lib/prick.rb +10 -3
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fed99dbfdf6e89642b4e8fdddf976efa58b1c8b75d9169fa460bd8190805cc63
|
4
|
+
data.tar.gz: 97fec32bbd130043b2c782f133ab5af30e9bcc5c42d4c83a26311f486786d671
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35859b1f387d1bf8ccb04a37a853d509e8038102f9521a7b4b35884db5d2682e5a06bd3dda9f4aff704a105603d9df17a43d2d1bbfa66f39ba751584b73b7cb9
|
7
|
+
data.tar.gz: cc7dfb26f5c10b1489d82f5be5c824e7d7d118de29d9ceae6b424e26506701650da57ed800107ce8ad10ea0bda3e1d29934000170702b285ae3d7a3a8123426f
|
data/exe/prick
CHANGED
@@ -121,10 +121,10 @@ SPEC = %(
|
|
121
121
|
|
122
122
|
build! -f,force -t,time --dump=KIND? -- [SCHEMA]
|
123
123
|
Build the project. If SCHEMA is defined, later schemas are excluded.
|
124
|
-
KIND can be 'nodes', 'allnodes' or 'batches' (the default)
|
124
|
+
KIND can be 'nodes', 'allnodes' or 'batches' (the default).
|
125
125
|
|
126
|
-
|
127
|
-
|
126
|
+
Schemas marked with 'no refresh' is not built unless the --force is
|
127
|
+
present
|
128
128
|
|
129
129
|
make! -t,time --dump=KIND? -- [SCHEMA]
|
130
130
|
@ Only rebuild changed files
|
@@ -133,6 +133,10 @@ SPEC = %(
|
|
133
133
|
rebuild affected parts of the project. KIND can be 'nodes', 'allnodes' or
|
134
134
|
'batches' (the default)
|
135
135
|
|
136
|
+
bash! --main
|
137
|
+
Emit a bash script to build the database. The script is constructed from
|
138
|
+
the build attributes in the environment file
|
139
|
+
|
136
140
|
fox! -- FILE...
|
137
141
|
Load fox file data. Data are reset to their initial state after build
|
138
142
|
before the fox data are loaded. This makes it possible to experiment with
|
@@ -357,6 +361,9 @@ begin
|
|
357
361
|
dump = cmd.dump? ? cmd.dump("batches")&.to_sym || :batches : nil
|
358
362
|
Prick::SubCommand.make(database, username, args.expect(0..1), timer: cmd.time?, dump: dump)
|
359
363
|
|
364
|
+
when :bash!
|
365
|
+
Prick::SubCommand.bash(main: cmd.main?)
|
366
|
+
|
360
367
|
when :fox!
|
361
368
|
require_db
|
362
369
|
Prick::SubCommand.fox(database, username, args)
|
data/lib/prick/builder/parser.rb
CHANGED
@@ -50,12 +50,13 @@ module Prick
|
|
50
50
|
# The hierarchy of environments is defined in the PRICK_ENVIRONMENT_FILE
|
51
51
|
#
|
52
52
|
def expand_filename(dir, filename)
|
53
|
-
|
53
|
+
envs = Prick.state.environments
|
54
|
+
env = envs[Prick.state.environment]
|
54
55
|
bash_vars = Prick.state.bash_environment
|
55
56
|
|
56
57
|
last = nil
|
57
|
-
for env in [
|
58
|
-
bash_vars["ENVIRONMENT"] = env
|
58
|
+
for env in [env] + env.ancestors.reverse
|
59
|
+
bash_vars["ENVIRONMENT"] = env.name
|
59
60
|
file = expand_variables(filename, bash_vars)
|
60
61
|
last ||= (file != last and file) or return nil # return if no ENVIRONMENT substitution
|
61
62
|
path = (file.start_with?("/") ? file : File.join(dir, file))
|
data/lib/prick/environment.rb
CHANGED
@@ -1,150 +1,366 @@
|
|
1
|
+
require 'set'
|
1
2
|
require 'yaml'
|
2
3
|
require 'dsort'
|
3
4
|
|
4
|
-
# TODO
|
5
|
-
# o
|
6
|
-
#
|
7
|
-
|
5
|
+
# TODO
|
6
|
+
# o Add a CODE type
|
7
|
+
# o super
|
8
8
|
module Prick
|
9
|
-
# An environment as defined in the prick.environment file. The environment is
|
10
|
-
# constant across all instances of State so we ensure that it is loaded only
|
11
|
-
# once
|
12
9
|
class Environment
|
13
|
-
# Environments
|
10
|
+
# The enclosing Environments object. Used in #types
|
11
|
+
attr_reader :environments
|
12
|
+
|
13
|
+
# Environment name (String)
|
14
14
|
attr_reader :name
|
15
15
|
|
16
|
-
#
|
17
|
-
|
16
|
+
# List of names of inherited environments
|
17
|
+
def inherit = assignments[:inherit]
|
18
|
+
|
19
|
+
# List of directly inherited environment objects. Assigned by the
|
20
|
+
# analyzer
|
21
|
+
attr_accessor :parents
|
22
|
+
|
23
|
+
# Ancestors (array of Environment objects) sorted in dependency order
|
24
|
+
attr_accessor :ancestors
|
25
|
+
|
26
|
+
# The ancestor that defines the build attribute or nil if ambigous.
|
27
|
+
# Assigned by the analyzer
|
28
|
+
attr_accessor :super_environment
|
18
29
|
|
19
|
-
|
20
|
-
def parents = @values[:parents]
|
30
|
+
def has_super?() = !super_environment.nil?
|
21
31
|
|
22
|
-
#
|
23
|
-
|
24
|
-
|
32
|
+
# Map from variable identifier to the environment that defines the value.
|
33
|
+
# This assumes there are no ambigous assignments
|
34
|
+
def assigners
|
35
|
+
@assigners ||= begin
|
36
|
+
effective_variables.keys.map { |ident|
|
37
|
+
if assignments.key?(ident)
|
38
|
+
[ident, self]
|
39
|
+
else
|
40
|
+
[ident, ancestors.reverse.find { |env| env.assignments.key?(ident) }]
|
41
|
+
end
|
42
|
+
}.to_h
|
43
|
+
end
|
25
44
|
end
|
26
45
|
|
27
|
-
#
|
28
|
-
def
|
46
|
+
# Environment comment
|
47
|
+
def comment = assignments[:comment]
|
29
48
|
|
30
|
-
#
|
31
|
-
|
49
|
+
# Map from variable identifier (Symbol) to type. Type is one of the strings
|
50
|
+
# listed in Environments::TYPES
|
51
|
+
def types() = @environments.types
|
32
52
|
|
33
|
-
#
|
34
|
-
|
53
|
+
# Map from variable identifier (Symbol) to value. Inherited variables are not
|
54
|
+
# included in #assignments
|
55
|
+
attr_reader :assignments
|
35
56
|
|
36
|
-
#
|
37
|
-
|
38
|
-
attr_accessor :effective_values
|
57
|
+
# Return true if the environment assigns an attribute
|
58
|
+
def assign?(ident) = @assignments.key?(ident)
|
39
59
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
60
|
+
# Map from variable identifier (Symbol) to effective value. Initially equal
|
61
|
+
# to #assignments but are later augmented or merged with the corresponding
|
62
|
+
# assignments from inherited environments
|
63
|
+
attr_accessor :effective_variables
|
44
64
|
|
45
|
-
def initialize(name)
|
65
|
+
def initialize(environments, name, assignments)
|
66
|
+
constrain environments, Environments
|
67
|
+
constrain name, String
|
68
|
+
constrain assignments, { Symbol => Object }
|
69
|
+
@environments = environments
|
46
70
|
@name = name
|
47
|
-
@
|
48
|
-
@
|
49
|
-
@
|
50
|
-
@@ENVIRONMENTS[name] = self
|
71
|
+
@assignments = assignments
|
72
|
+
@assignments[:inherit] ||= []
|
73
|
+
@effective_variables = assignments.transform_values { |v| v.dup } # Deep-dup
|
51
74
|
end
|
52
75
|
|
53
|
-
|
54
|
-
if hash
|
55
|
-
parse(yaml)
|
56
|
-
analyze
|
57
|
-
end
|
58
|
-
end
|
76
|
+
forward_to :effective_variables, :key?, :[], :[]=, :to_h, :empty?, :size, :each, :map
|
59
77
|
|
60
|
-
|
61
|
-
def
|
62
|
-
|
63
|
-
|
78
|
+
def bash() = "build_#{name}"
|
79
|
+
def super_bash() = (has_super? ? "build_#{name}_super" : nil)
|
80
|
+
def bash_environment
|
81
|
+
effective_variables.map { |ident, value|
|
82
|
+
["PRICK_ENVIRONMENT_#{ident.upcase}", value]
|
64
83
|
}.to_h
|
65
84
|
end
|
66
85
|
|
86
|
+
def inspect = "#<#{self.class} @name=#{@name}>"
|
87
|
+
|
67
88
|
def dump
|
68
|
-
puts name
|
89
|
+
puts "#{name}:"
|
69
90
|
indent {
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
91
|
+
self.each { |ident,val|
|
92
|
+
if ident == :build
|
93
|
+
puts "super: #{super_environment&.name || 'false'}"
|
94
|
+
end
|
95
|
+
assigner = assigners[ident]&.name || name
|
96
|
+
assigner_str = (assigner != name ? " (#{assigner})" : "")
|
97
|
+
if types[ident] == "TEXT"
|
98
|
+
puts "#{ident}#{assigner_str}:"
|
99
|
+
indent { puts val }
|
100
|
+
else
|
101
|
+
puts "#{ident}#{assigner_str}: #{val.inspect}"
|
102
|
+
end
|
103
|
+
if ident == :inherit
|
104
|
+
puts "ancestors: #{ancestors.map(&:name).inspect}"
|
105
|
+
end
|
79
106
|
}
|
80
107
|
}
|
81
108
|
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class Environments
|
112
|
+
# Map from environment name to Environment object
|
113
|
+
attr_reader :environments
|
114
|
+
|
115
|
+
# Environments acts like a hash from name to Environment object
|
116
|
+
forward_to :@environments, :[], :[]=, :key?, :keys, :values, :each, :map
|
117
|
+
|
118
|
+
# Maps from variable name (Symbol) to type (String)
|
119
|
+
attr_reader :types
|
82
120
|
|
83
|
-
|
84
|
-
|
121
|
+
# List of all variables (Symbol). Same as 'types.keys'
|
122
|
+
def variables = types.keys
|
123
|
+
|
124
|
+
# List of variable identifiers defined by prick
|
125
|
+
def prick_variables = @@PRICK_VARIABLES
|
126
|
+
|
127
|
+
# List of user defined variables
|
128
|
+
def user_variables = variables - prick_variables
|
129
|
+
|
130
|
+
def initialize(hash)
|
131
|
+
@types = @@TYPES.dup
|
132
|
+
@environments = {}
|
133
|
+
parse_variables(hash)
|
134
|
+
parse_environments(hash)
|
135
|
+
analyze
|
85
136
|
end
|
86
137
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
def self.yaml_to_array(value)
|
93
|
-
case value
|
94
|
-
when /\n/; [value.split("\n")]
|
95
|
-
when nil ; []
|
96
|
-
when String; value.split
|
97
|
-
else [value.to_s]
|
98
|
-
end
|
99
|
-
# !value.nil? && Array(value).flatten.compact.map(&:to_s).map(&:split).flatten
|
138
|
+
def undent(s)
|
139
|
+
s = s[1..] if s[0] == "\n"
|
140
|
+
s =~ /^(\s*)\S$/m
|
141
|
+
indent = $1
|
142
|
+
s.gsub(/^#{indent}/m, "")
|
100
143
|
end
|
101
144
|
|
102
|
-
def
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
145
|
+
def bash_environment
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
def bash_command(environment = nil)
|
150
|
+
constrain environment, String, nil
|
151
|
+
if environment
|
152
|
+
env = self[environment] or raise "Unknown environment: '#{environment}'"
|
153
|
+
envs = [env]
|
154
|
+
else
|
155
|
+
envs = environments
|
156
|
+
end
|
157
|
+
|
158
|
+
puts "### SCRIPT by #{File.basename(__FILE__)}"
|
159
|
+
|
160
|
+
puts undent %(
|
161
|
+
|
162
|
+
## STACK METHODS - ChatGPT
|
163
|
+
|
164
|
+
# global variable
|
165
|
+
super_stack=()
|
166
|
+
|
167
|
+
function push_super_stack() {
|
168
|
+
local method=$1
|
169
|
+
super_stack+=($method)
|
170
|
+
}
|
171
|
+
|
172
|
+
function pop_super_stack() {
|
173
|
+
super_stack=("${super_stack[@]::${#super_stack[@]}-1}")
|
174
|
+
}
|
175
|
+
|
176
|
+
function super() {
|
177
|
+
eval ${super_stack[-1]}
|
178
|
+
}
|
179
|
+
)
|
180
|
+
|
181
|
+
puts "## ENVIRONMENT METHODS"
|
182
|
+
puts
|
183
|
+
for name, env in environments
|
184
|
+
puts "function build_#{name}() {"
|
185
|
+
assigner = env.assigners[:build]
|
186
|
+
indent {
|
187
|
+
if assigner == env
|
188
|
+
if env.has_super?
|
189
|
+
puts "push_super_stack #{env.super_bash}"
|
190
|
+
end
|
191
|
+
puts env[:build]
|
192
|
+
if env.has_super?
|
193
|
+
puts "pop_super_stack"
|
117
194
|
end
|
195
|
+
else
|
196
|
+
puts "build_#{assigner.name} # default super"
|
118
197
|
end
|
119
|
-
|
120
|
-
|
198
|
+
}
|
199
|
+
puts "}"
|
200
|
+
puts
|
201
|
+
if env.has_super? && assigner == env
|
202
|
+
puts "build_#{name}_super() { build_#{env.super_environment.name}; }"
|
203
|
+
puts
|
121
204
|
end
|
122
205
|
end
|
206
|
+
|
207
|
+
if environment
|
208
|
+
puts "## DEFAULT BUILD METHOD"
|
209
|
+
puts
|
210
|
+
puts "function build() { build_#{environment}; }"
|
211
|
+
puts
|
212
|
+
end
|
123
213
|
end
|
124
214
|
|
125
|
-
def
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
215
|
+
def dump
|
216
|
+
puts "Types"
|
217
|
+
indent { types.each { |k,v| puts "#{k}: #{v}" } }
|
218
|
+
puts
|
219
|
+
puts "Environments"
|
220
|
+
indent { environments.values.each { |env| env.dump } }
|
221
|
+
end
|
222
|
+
|
223
|
+
private
|
224
|
+
TYPES = %w(BOOLEAN STRING LIST TEXT)
|
225
|
+
@@TYPES = { comment: "STRING", inherit: "LIST", build: "TEXT" }
|
226
|
+
@@PRICK_VARIABLES = @@TYPES.keys
|
130
227
|
|
131
|
-
|
132
|
-
|
133
|
-
|
228
|
+
def parse_variables(yaml)
|
229
|
+
decls = yaml.delete("variables") || ""
|
230
|
+
decls.split.each { |decl|
|
231
|
+
decl =~ /^(.*):(.*)$/ or ShellOpts.error "Illegal declaration of '#{decl}' in variable list"
|
232
|
+
name, type = $1.to_sym, $2
|
233
|
+
type = type.upcase
|
234
|
+
TYPES.include?(type) or ShellOpts.error "Illegal type '#{type}'"
|
235
|
+
@types[name] = type
|
134
236
|
}
|
237
|
+
end
|
238
|
+
|
239
|
+
def parse_environments(yaml)
|
240
|
+
yaml.each { |environment, variables|
|
241
|
+
assignments = variables.map { |ident, value|
|
242
|
+
ident = ident.to_sym
|
243
|
+
case types[ident]
|
244
|
+
when "BOOLEAN"
|
245
|
+
[TrueClass, FalseClass].include?(value.class) or raise "Illegal value for #{ident}: #{value}"
|
246
|
+
;
|
247
|
+
when "STRING"
|
248
|
+
; # nop
|
249
|
+
when "LIST"
|
250
|
+
value = value.split
|
251
|
+
when "TEXT"
|
252
|
+
value = value.chomp
|
253
|
+
when nil
|
254
|
+
ShellOpts.error "Unknown variable '#{ident}'"
|
255
|
+
else
|
256
|
+
raise ArgumentError
|
257
|
+
end
|
258
|
+
[ident, value]
|
259
|
+
}.to_h
|
260
|
+
@environments[environment] = Environment.new(self, environment, assignments)
|
261
|
+
}
|
262
|
+
end
|
263
|
+
|
264
|
+
def analyze
|
265
|
+
# Assign Environment#parent
|
266
|
+
values.each { |env|
|
267
|
+
env.parents = env.inherit.map { |name|
|
268
|
+
self[name] or raise ArgumentError, "Can't find '#{name}' environment referred from '#{name}'"
|
269
|
+
}
|
270
|
+
}
|
271
|
+
|
272
|
+
# Sort environment names in dependency order
|
273
|
+
deps = self.map { |name, env| [name, env.inherit] }
|
274
|
+
sorted_environments = DSort.dsort(deps).map { |name| self[name] }
|
135
275
|
|
136
276
|
# Compute effective attribute values by processing environments in
|
137
|
-
# dependency order so that all
|
277
|
+
# dependency order so that all inherited environments are computed before
|
138
278
|
# the current environment
|
139
|
-
for
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
279
|
+
for env in sorted_environments
|
280
|
+
for inherited in env.parents
|
281
|
+
for ident, type in types
|
282
|
+
next if ident == :comment # Comments are not inherited
|
283
|
+
next if !inherited.key?(ident)
|
284
|
+
value = inherited[ident]
|
285
|
+
case type
|
286
|
+
when "BOOLEAN"; env[ident] = value if !env.key?(ident)
|
287
|
+
when "STRING"; env[ident] ||= value
|
288
|
+
when "LIST";
|
289
|
+
next if ident == :inherit # Does not accumulate
|
290
|
+
# FIXME !inherited.key? should prevent env[ident].nil?
|
291
|
+
env[ident] = (value + (env[ident] || [])).uniq
|
292
|
+
when "TEXT"; env[ident] = env[ident] || value
|
293
|
+
else
|
294
|
+
raise ArgumentError
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
# Assign #ancestors
|
301
|
+
sorted_indexes = sorted_environments.map.with_index { |env, idx| [env.name, idx] }.to_h
|
302
|
+
for env in sorted_environments
|
303
|
+
env.ancestors =
|
304
|
+
(env.parents + env.parents.map(&:ancestors))
|
305
|
+
.flatten
|
306
|
+
.uniq
|
307
|
+
.sort_by { |env| sorted_indexes[env.name] }
|
308
|
+
end
|
309
|
+
|
310
|
+
# Check ambigous string, text, and boolean definitions (:initial is never
|
311
|
+
# ambigous and :comment is special). TODO: Find a faster algorithm
|
312
|
+
for env in sorted_environments
|
313
|
+
for ident, value in env.effective_variables
|
314
|
+
type = types[ident]
|
315
|
+
|
316
|
+
# Ignore mergeable types (LIST)
|
317
|
+
next if !%w(STRING TEXT BOOLEAN).include?(type)
|
318
|
+
|
319
|
+
# Ignore :initial and :comment
|
320
|
+
next if [:initial, :comment].include?(ident)
|
321
|
+
|
322
|
+
# Ignore if variable is assigned in the current environment and not the
|
323
|
+
# special :build attribute
|
324
|
+
next if env.assignments.key?(ident) && ident != :build
|
325
|
+
|
326
|
+
# Pool of ancestors. When an environment assigns a value, all ancestors
|
327
|
+
# of the environment are removed from the pool. If any remaining environment
|
328
|
+
# also assigns the variable, the definition is ambigous. 'pool' and
|
329
|
+
# 'queue' works together to provide a set of environments with
|
330
|
+
# queue-like properties
|
331
|
+
pool = Set.new(env.ancestors)
|
332
|
+
|
333
|
+
# Queue of ancestors. It is used to iterate the pool environments in
|
334
|
+
# reversed dependency order
|
335
|
+
queue = env.ancestors.reverse
|
336
|
+
|
337
|
+
# Look for the first environment that assigns the variable
|
338
|
+
while ancestor = queue.shift
|
339
|
+
next if !pool.include?(ancestor)
|
340
|
+
if ancestor.assignments.key?(ident)
|
341
|
+
# Remove all ancestors that are inherited by the assigning environment
|
342
|
+
pool -= ancestor.ancestors
|
343
|
+
if ident == :build
|
344
|
+
env.super_environment = ancestor #if ident == :build
|
345
|
+
end
|
346
|
+
break
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
# Check that remaining environments do not also assign the variable.
|
351
|
+
# The :block attribute is checked even if defined in the current
|
352
|
+
# environment to be able to tell if 'super' is ambigous
|
353
|
+
while ancestor = queue.shift
|
354
|
+
next if !pool.include?(ancestor)
|
355
|
+
if ancestor.assign?(ident)
|
356
|
+
if ident == :build && env.assign?(:build)
|
357
|
+
env.super_environment = nil
|
358
|
+
else
|
359
|
+
raise ArgumentError, "Ambigious definition of '#{ident}' in #{ancestor.name} environment"
|
360
|
+
end
|
361
|
+
end
|
145
362
|
end
|
146
363
|
end
|
147
|
-
env.effective_values.transform_values! { |v| v.uniq }
|
148
364
|
end
|
149
365
|
end
|
150
366
|
end
|
data/lib/prick/local/command.rb
CHANGED
data/lib/prick/local/fmt.rb
CHANGED
@@ -5,52 +5,95 @@ module Fmt
|
|
5
5
|
widths = headers.map(&:size)
|
6
6
|
signs = []
|
7
7
|
types = []
|
8
|
+
indexes = [] # absolute position of column. Zero based
|
8
9
|
for i in (0...headers.size)
|
9
|
-
|
10
|
-
|
11
|
-
[
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
10
|
+
value_width =
|
11
|
+
table.map { |row|
|
12
|
+
case value = row[i]
|
13
|
+
when TrueClass, FalseClass
|
14
|
+
types[i] = 's'
|
15
|
+
signs[i] = '-'
|
16
|
+
5
|
17
|
+
when NilClass
|
18
|
+
types[i] = 's'
|
19
|
+
signs[i] = '-'
|
20
|
+
4
|
21
|
+
when String
|
22
|
+
types[i] = 's'
|
23
|
+
signs[i] = '-'
|
24
|
+
value.split("\n").map(&:size).max || 0
|
25
|
+
when Integer
|
26
|
+
types[i] = 'i'
|
27
|
+
signs[i] = ''
|
28
|
+
Math.log10(value) + 1
|
29
|
+
when Array
|
30
|
+
types[i] = 's'
|
31
|
+
signs[i] = '-'
|
32
|
+
all_size = value.join(' ').size
|
33
|
+
if all_size < 60
|
34
|
+
all_size
|
35
|
+
else
|
36
|
+
value.map(&:size).max
|
37
|
+
end
|
38
|
+
when PrickVersion
|
39
|
+
types[i] = 's'
|
40
|
+
signs[i] = '-'
|
41
|
+
value.to_s.size
|
42
|
+
else
|
43
|
+
raise ArgumentError, "Illegal value: '#{value}' (#{value.class})"
|
44
|
+
end
|
45
|
+
}.max || 0
|
46
|
+
widths[i] = [widths[i], value_width].max
|
47
|
+
indexes[i] = (i == 0 ? 0 : indexes[i-1] + widths[i-1] + 1)
|
35
48
|
end
|
36
49
|
|
37
|
-
widths = widths.map { _1 }
|
38
|
-
|
39
50
|
for width, value in widths.zip(headers)
|
40
51
|
printf "%-#{width}s ", value
|
41
52
|
end
|
42
53
|
puts
|
54
|
+
|
43
55
|
widths.each.with_index { |width, index|
|
44
56
|
char = (headers[index] =~ /^\s*$/ ? " " : "-")
|
45
57
|
printf "%#{width}s ", char * width
|
46
58
|
}
|
47
59
|
puts
|
60
|
+
|
48
61
|
for row in table
|
49
|
-
|
50
|
-
|
51
|
-
|
62
|
+
# for index, sign, width, type, value in signs.zip(indexes, signs, widths, types, row) # FIXME doesn't work?
|
63
|
+
for i in (0...headers.size)
|
64
|
+
index, sign, width, type, value = indexes[i], signs[i], widths[i], types[i], row[i]
|
65
|
+
|
66
|
+
if value && value =~ /\n/m
|
67
|
+
value = value.split("\n")
|
68
|
+
print value.first
|
69
|
+
for line in value[1..]
|
70
|
+
puts
|
71
|
+
print "#{' ' * index}#{line}"
|
72
|
+
end
|
73
|
+
elsif value.is_a?(Array)
|
74
|
+
values = value.dup
|
75
|
+
lines = []
|
76
|
+
while !values.empty?
|
77
|
+
rest = width
|
78
|
+
line = []
|
79
|
+
while !values.empty? && values.first.size <= rest
|
80
|
+
rest -= values.first.size
|
81
|
+
line << values.shift
|
82
|
+
end
|
83
|
+
lines << line.join(" ")
|
84
|
+
end
|
85
|
+
print lines.first
|
86
|
+
for line in lines[1..]
|
87
|
+
puts
|
88
|
+
print "#{' ' * index}#{line}"
|
89
|
+
end
|
90
|
+
else
|
91
|
+
value = (value.nil? ? "-" : value)
|
92
|
+
printf "%#{sign}#{width}#{type} ", "#{value}"
|
93
|
+
end
|
52
94
|
end
|
53
95
|
puts
|
54
96
|
end
|
55
97
|
end
|
56
98
|
end
|
99
|
+
|
data/lib/prick/state.rb
CHANGED
@@ -52,14 +52,17 @@ module Prick
|
|
52
52
|
# database is absent
|
53
53
|
attr_accessor :username
|
54
54
|
|
55
|
-
#
|
56
|
-
|
57
|
-
|
55
|
+
# Map from environment name to environment object
|
56
|
+
attr_reader :environments
|
57
|
+
|
58
|
+
# Name of current environment. If not set in the state file, the enviroment
|
59
|
+
# is read from the database when the first connection is established by the
|
60
|
+
# #connection method. Use '#environments[environment]' to get the
|
58
61
|
# corresponding Environment object
|
59
62
|
def environment() @environment end
|
60
63
|
def environment=(env)
|
61
64
|
constrain env, String, nil
|
62
|
-
env.nil? ||
|
65
|
+
env.nil? || environments.key?(env) or raise "Illegal environment: '#{env}'"
|
63
66
|
@environment = env
|
64
67
|
end
|
65
68
|
|
@@ -122,7 +125,7 @@ module Prick
|
|
122
125
|
self.environment =
|
123
126
|
environment ||
|
124
127
|
Prick.state.environment ||
|
125
|
-
|
128
|
+
environments.key?(database_environment) && database_environment ||
|
126
129
|
DEFAULT_ENVIRONMENT
|
127
130
|
end
|
128
131
|
if block_given?
|
@@ -193,13 +196,18 @@ module Prick
|
|
193
196
|
})
|
194
197
|
|
195
198
|
# PRICK_ENVIRONMENT_* variables
|
196
|
-
|
199
|
+
if !Prick.state.environment.nil?
|
200
|
+
hash.merge! environments[environment].bash_environment
|
201
|
+
end
|
197
202
|
end
|
198
203
|
end
|
199
204
|
|
200
205
|
# @scope can be :global (variables are exported), :local (variables are
|
201
206
|
# declared local), or nil (variables are global but not exported)
|
207
|
+
#
|
208
|
+
# Only non-text variables are emitted
|
202
209
|
def bash_source(vars = nil, scope: nil)
|
210
|
+
exclude = Array(exclude || []).flatten.map { _1.to_s }
|
203
211
|
case scope
|
204
212
|
when :global; prefix="export "
|
205
213
|
when :local; prefix="local "
|
@@ -208,8 +216,11 @@ module Prick
|
|
208
216
|
raise ArgumentError, "Illegal value for scope: #{scope.inspect}"
|
209
217
|
end
|
210
218
|
|
211
|
-
|
219
|
+
vars ||= bash_environment&.keys || []
|
220
|
+
assignments = []
|
221
|
+
vars.each { |var|
|
212
222
|
val = bash_environment[var]
|
223
|
+
# next if val =~ /['"\n]/m # We don't quote
|
213
224
|
if val.is_a?(Array)
|
214
225
|
if val.first.is_a?(Array)
|
215
226
|
val = val.map { |v| v.join("\n") }.join("\n")
|
@@ -217,13 +228,14 @@ module Prick
|
|
217
228
|
val = val.join(" ")
|
218
229
|
end
|
219
230
|
end
|
220
|
-
"#{prefix}#{var}
|
221
|
-
}
|
231
|
+
assignments << "#{prefix}#{var}='#{val}'\n"
|
232
|
+
}
|
233
|
+
assignments.join
|
222
234
|
end
|
223
235
|
|
224
236
|
# It is an error if the project file exists.
|
225
|
-
def save_project
|
226
|
-
!File.exists?(project_file) or Prick.error "Won't overwrite '#{project_file}'"
|
237
|
+
def save_project(overwrite: false)
|
238
|
+
overwrite || !File.exists?(project_file) or Prick.error "Won't overwrite '#{project_file}'"
|
227
239
|
hash = { name: name, title: title, version: version.to_s, prick: prick_version.to_s }
|
228
240
|
save_yaml(project_file, hash)
|
229
241
|
end
|
@@ -279,7 +291,7 @@ module Prick
|
|
279
291
|
puts "#{method}: #{self.send method}"
|
280
292
|
end
|
281
293
|
puts "environments:"
|
282
|
-
indent {
|
294
|
+
indent { environments.dump }
|
283
295
|
}
|
284
296
|
end
|
285
297
|
|
@@ -288,7 +300,7 @@ module Prick
|
|
288
300
|
|
289
301
|
def read_yaml(file)
|
290
302
|
begin
|
291
|
-
YAML.load
|
303
|
+
YAML.load File.read(file).sub(/^__END__\n.*/m, "")
|
292
304
|
rescue Errno::ENOENT
|
293
305
|
Prick.error "Can't read #{file}"
|
294
306
|
end
|
@@ -354,7 +366,7 @@ module Prick
|
|
354
366
|
|
355
367
|
def load_environment_file
|
356
368
|
hash = environment_file ? read_yaml(environment_file) : {}
|
357
|
-
|
369
|
+
@environments = Environments.new(hash)
|
358
370
|
@environment_loaded = true
|
359
371
|
end
|
360
372
|
|
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
class IO
|
4
|
+
def self.capture(&block) # ChatGPT
|
5
|
+
block_given? or raise ArgumentError
|
6
|
+
stdout = $stdout
|
7
|
+
begin
|
8
|
+
$stdout = StringIO.new
|
9
|
+
yield
|
10
|
+
$stdout.string
|
11
|
+
ensure
|
12
|
+
$stdout = stdout
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module Prick::SubCommand
|
18
|
+
def self.bash(main: false)
|
19
|
+
# IO.capture {
|
20
|
+
env = Prick.state.environment # Shorthands
|
21
|
+
envs = Prick.state.environments
|
22
|
+
|
23
|
+
puts "#!/usr/bin/bash"
|
24
|
+
puts
|
25
|
+
puts "# This file is auto-generated by prick. Please don't touch"
|
26
|
+
puts
|
27
|
+
puts ". bash.include"
|
28
|
+
puts
|
29
|
+
|
30
|
+
# Emit environment. PRICK_ENVIRONMENT_BUILD is excluded because its value
|
31
|
+
# is bash source that is hard to escape and there is no use for this
|
32
|
+
# variable anyway
|
33
|
+
puts "### ENVIRONMENT by state.rb"
|
34
|
+
puts
|
35
|
+
puts Prick.state.bash_source(scope: :global)
|
36
|
+
puts
|
37
|
+
|
38
|
+
# Emit script
|
39
|
+
if env
|
40
|
+
envs.bash_command env
|
41
|
+
else
|
42
|
+
envs.bash_command
|
43
|
+
end
|
44
|
+
|
45
|
+
if main
|
46
|
+
puts "### MAIN by prick-load.rb"
|
47
|
+
puts
|
48
|
+
puts "build"
|
49
|
+
end
|
50
|
+
# }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Prick::SubCommand
|
2
2
|
def self.list_environments(format: :long)
|
3
|
-
environments =
|
3
|
+
environments = Prick.state.environments.values.select { |env| env.comment }
|
4
4
|
if format == :short
|
5
5
|
puts environments.map(&:name)
|
6
6
|
else
|
@@ -16,7 +16,20 @@ module Prick::SubCommand
|
|
16
16
|
else
|
17
17
|
headers = %w(variable value)
|
18
18
|
vars = Prick.state.bash_environment(all: all).reject { |k,v| k == "PATH" }
|
19
|
-
rows = vars.map
|
19
|
+
rows = vars.map
|
20
|
+
# rows = vars.map { |k,v|
|
21
|
+
# if v.is_a?(Array)
|
22
|
+
# if v.first&.is_a?(Array)
|
23
|
+
# v = v.first
|
24
|
+
# else
|
25
|
+
# v = v.join(" ")
|
26
|
+
# end
|
27
|
+
# else
|
28
|
+
# v = v.to_s
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# [k, v]
|
32
|
+
# }
|
20
33
|
Fmt.puts_table(headers, rows)
|
21
34
|
end
|
22
35
|
end
|
@@ -8,7 +8,7 @@ module Prick
|
|
8
8
|
Git.synchronized? or raise "Won't release: Repository is not synchronized with origin"
|
9
9
|
|
10
10
|
version = Prick.state.version.increment!(kind).to_s
|
11
|
-
Prick.state.save_project
|
11
|
+
Prick.state.save_project(overwrite: true)
|
12
12
|
|
13
13
|
Git.add(Prick.state.project_file)
|
14
14
|
Git.add(Prick.state.schema_file)
|
data/lib/prick/version.rb
CHANGED
data/lib/prick.rb
CHANGED
@@ -2,9 +2,15 @@ require 'prick/version.rb'
|
|
2
2
|
|
3
3
|
require 'pg_conn'
|
4
4
|
|
5
|
-
require 'fixture_fox'
|
6
5
|
require 'indented_io'
|
6
|
+
|
7
7
|
require 'constrain'
|
8
|
+
include Constrain
|
9
|
+
|
10
|
+
require 'forward_to'
|
11
|
+
include ForwardTo
|
12
|
+
|
13
|
+
require 'fixture_fox'
|
8
14
|
|
9
15
|
module Prick
|
10
16
|
class Error < RuntimeError; end
|
@@ -33,17 +39,18 @@ module Prick
|
|
33
39
|
end
|
34
40
|
|
35
41
|
require_relative 'prick/subcommand/subcommand.rb'
|
42
|
+
require_relative 'prick/subcommand/prick-bash.rb'
|
36
43
|
require_relative 'prick/subcommand/prick-build.rb'
|
37
44
|
require_relative 'prick/subcommand/prick-clean.rb'
|
38
45
|
require_relative 'prick/subcommand/prick-create.rb'
|
39
46
|
require_relative 'prick/subcommand/prick-drop.rb'
|
40
|
-
require_relative 'prick/subcommand/prick-set.rb'
|
41
|
-
require_relative 'prick/subcommand/prick-list.rb'
|
42
47
|
require_relative 'prick/subcommand/prick-fox.rb'
|
43
48
|
require_relative 'prick/subcommand/prick-init.rb'
|
49
|
+
require_relative 'prick/subcommand/prick-list.rb'
|
44
50
|
require_relative 'prick/subcommand/prick-make.rb'
|
45
51
|
require_relative 'prick/subcommand/prick-migrate.rb'
|
46
52
|
require_relative 'prick/subcommand/prick-release.rb'
|
53
|
+
require_relative 'prick/subcommand/prick-set.rb'
|
47
54
|
require_relative 'prick/subcommand/prick-setup.rb'
|
48
55
|
require_relative 'prick/subcommand/prick-teardown.rb'
|
49
56
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prick
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.32.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Claus Rasmussen
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-04-
|
11
|
+
date: 2024-04-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: semantic
|
@@ -219,6 +219,7 @@ files:
|
|
219
219
|
- lib/prick/share/migrate/migration/diff.before-tables.sql
|
220
220
|
- lib/prick/share/migrate/migration/diff.tables.sql
|
221
221
|
- lib/prick/state.rb
|
222
|
+
- lib/prick/subcommand/prick-bash.rb
|
222
223
|
- lib/prick/subcommand/prick-build.rb
|
223
224
|
- lib/prick/subcommand/prick-clean.rb
|
224
225
|
- lib/prick/subcommand/prick-create.rb
|
@@ -238,7 +239,7 @@ files:
|
|
238
239
|
homepage: http://www.nowhere.com/
|
239
240
|
licenses: []
|
240
241
|
metadata: {}
|
241
|
-
post_install_message:
|
242
|
+
post_install_message:
|
242
243
|
rdoc_options: []
|
243
244
|
require_paths:
|
244
245
|
- lib
|
@@ -254,7 +255,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
254
255
|
version: '0'
|
255
256
|
requirements: []
|
256
257
|
rubygems_version: 3.3.7
|
257
|
-
signing_key:
|
258
|
+
signing_key:
|
258
259
|
specification_version: 4
|
259
260
|
summary: A release control and management system for postgresql
|
260
261
|
test_files: []
|