squared 0.0.9 → 0.0.11

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.
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'json'
3
4
  require 'date'
4
5
  require 'logger'
5
6
 
@@ -12,12 +13,18 @@ module Squared
12
13
  include System
13
14
  include Shell
14
15
  include Task
16
+ include Utils
15
17
  include ::Rake::DSL
16
18
 
17
- SEM_VER = /(\d+)(?:(\.)(\d+))?(?:(\.)(\d+))?/.freeze
19
+ SEM_VER = /(\d+)(?:(\.)(\d+))?(?:(\.)(\d+)(\S+)?)?/.freeze
20
+
21
+ VAR_SET = %i[parent global envname theme run script env depend doc test copy clean].freeze
22
+ private_constant :VAR_SET
18
23
 
19
24
  class << self
20
25
  def populate(*); end
26
+ def batchargs(*); end
27
+ def aliasargs(*); end
21
28
 
22
29
  def tasks
23
30
  [].freeze
@@ -39,42 +46,106 @@ module Squared
39
46
  def to_s
40
47
  super.to_s.match(/[^:]+$/)[0]
41
48
  end
49
+
50
+ def config?(*)
51
+ false
52
+ end
42
53
  end
43
54
 
44
55
  @@print_order = 0
45
56
  @@tasks = {}
46
57
 
47
- attr_reader :name, :project, :workspace, :group, :path, :theme
58
+ attr_reader :name, :project, :workspace, :path, :exception, :pipe, :verbose, :theme, :group, :parent
48
59
 
49
- def initialize(name, path, workspace, *, group: nil, **kwargs)
50
- @name = name.to_s
60
+ def initialize(workspace, path, name, *, group: nil, pass: nil, exclude: nil, common: ARG[:COMMON], **kwargs)
51
61
  @path = path
52
- @project = @path.basename.to_s
53
62
  @workspace = workspace
54
- @group = group&.to_s
63
+ @name = name.to_s.freeze
64
+ @project = @path.basename.to_s.freeze
65
+ @group = group&.to_s.freeze
55
66
  @depend = kwargs[:depend]
56
67
  @doc = kwargs[:doc]
57
68
  @test = kwargs[:test]
58
- @output = [kwargs[:run], nil]
59
69
  @copy = kwargs[:copy]
60
70
  @clean = kwargs[:clean]
61
- @theme = if !workspace.verbose
71
+ @exception = kwargs.key?(:exception) ? env_bool(kwargs[:exception]) : workspace.exception
72
+ @pipe = kwargs.key?(:pipe) ? env_pipe(kwargs[:pipe]) : workspace.pipe
73
+ @verbose = kwargs.key?(:verbose) ? kwargs[:verbose] : workspace.verbose
74
+ @theme = if !@verbose
62
75
  {}
63
- elsif kwargs.fetch(:common, true)
76
+ elsif common
64
77
  workspace.theme
65
78
  else
66
79
  __get__(:theme)[:project][to_sym] ||= {}
67
80
  end
81
+ @output = []
68
82
  @ref = []
69
- @exclude = as_a(kwargs[:exclude], :to_sym).freeze
83
+ @children = []
84
+ @pass = (pass ? as_a(pass, :to_sym) : []).freeze
85
+ @exclude = (exclude ? as_a(exclude, :to_sym) : []).freeze
86
+ @envname = @name.gsub(/[^\w]+/, '_').upcase.freeze
87
+ @desc = (@name.include?(':') ? @name.split(':').join(ARG[:SPACE]) : @name).freeze
88
+ @parent = nil
89
+ @global = false
90
+ run_set(kwargs[:run], kwargs[:env], opts: kwargs.fetch(:opts, true))
70
91
  initialize_ref(Base.ref)
92
+ end
93
+
94
+ def initialize_ref(ref)
95
+ @ref << ref unless @exclude.include?(ref)
96
+ end
97
+
98
+ def initialize_build(ref, **kwargs)
99
+ initialize_ref(ref)
100
+ if (@script = @workspace.script_get(group: @group, ref: ref))
101
+ if @script[:log] && !kwargs.key?(:log)
102
+ kwargs[:log] = @script[:log]
103
+ @log = nil
104
+ end
105
+ @depend = @script[:depend] if @depend.nil?
106
+ @doc = @script[:doc] if @doc.nil?
107
+ @test = @script[:test] if @test.nil?
108
+ @clean = @script[:clean] if @clean.nil?
109
+ @exclude = @script[:exclude] if @exclude.empty? && @script.key?(:exclude)
110
+ end
71
111
  initialize_logger(**kwargs)
112
+ return if @output[0] == false
113
+
114
+ data = @workspace.script_find(*@ref, @group)
115
+ if @output[0].nil?
116
+ if (scr = data[:script])
117
+ @global = true
118
+ script_set(scr, prod: kwargs[:prod])
119
+ elsif (run = data[:run])
120
+ @global = true
121
+ run_set run
122
+ end
123
+ unless data[:env]
124
+ if (scr = kwargs[:script])
125
+ @global = false
126
+ script_set scr
127
+ elsif @script && !data[:global]
128
+ if (scr = @script[:script])
129
+ @global = false
130
+ script_set scr
131
+ elsif (run = @script[:run])
132
+ @global = false
133
+ run_set run
134
+ end
135
+ end
136
+ end
137
+ elsif data[:env] && data[:run]
138
+ @global = true
139
+ run_set data[:run]
140
+ end
72
141
  end
73
142
 
74
143
  def initialize_logger(log: nil, **)
144
+ return if @log
145
+
75
146
  log = log.is_a?(::Hash) ? log.dup : { file: log }
76
- if (file = env('LOG_FILE')).nil? && (auto = env('LOG_AUTO'))
77
- file = case auto
147
+ unless (file = env('LOG_FILE'))
148
+ file = case env('LOG_AUTO')
78
149
  when 'y', 'year'
79
150
  "#{@name}-#{Date.today.year}.log"
80
151
  when 'm', 'month'
@@ -85,53 +156,51 @@ module Squared
85
156
  end
86
157
  if file ||= log[:file]
87
158
  file = Date.today.strftime(file)
88
- file = (dir = env('LOG_DIR')) ? Pathname.new(dir).join(file) : Pathname.new(file)
159
+ file = (dir = env('LOG_DIR')) ? @workspace.home.join(dir, file) : @workspace.home.join(file)
89
160
  begin
90
161
  file = file.realdirpath
91
162
  rescue StandardError => e
92
- raise if @workspace.exception
163
+ raise if @exception
93
164
 
94
165
  file = nil
95
- warn e if @workspace.warning
166
+ warn log_message(::Logger::WARN, e) if warning?
96
167
  end
97
168
  end
98
- log[:progname] = @name
99
- log[:level] = env('LOG_LEVEL', log[:level] || Logger::INFO, ignore: nil)
169
+ log[:progname] ||= @name
170
+ if (val = env('LOG_LEVEL', ignore: false))
171
+ log[:level] = val
172
+ end
100
173
  log.delete(:file)
101
174
  @log = [file, log]
102
175
  end
103
176
 
104
- def initialize_build(ref, **kwargs)
105
- initialize_script(ref, **kwargs)
106
- if (val = env('BUILD', strict: true))
107
- @output[0] = val
108
- elsif @script && @output[0] != false
109
- @output[0] ||= @script[:run]
177
+ def initialize_env(dev: nil, prod: nil, **)
178
+ pre = "BUILD_#{@envname}"
179
+ @dev = env_match("#{pre}_DEV", dev)
180
+ @prod = env_match("#{pre}_PROD", prod)
181
+ cmd = @output[0]
182
+ unless cmd == false || cmd.is_a?(::Array) || (val = env('BUILD', suffix: 'OPTS')).nil?
183
+ @output[cmd ? 1 : 3] = shell_split(val, join: true)
110
184
  end
111
- @dev = kwargs.delete(:dev)
112
- if env('BUILD', suffix: 'DEV', equals: '0')
113
- @dev = false
114
- elsif env('BUILD', suffix: 'DEV')
115
- @dev = true
116
- elsif @dev.nil?
117
- @dev = !group.nil? && workspace.dev?(group: group, global: true)
185
+ unless @output[2] == false || (val = env('BUILD', suffix: 'ENV')).nil?
186
+ begin
187
+ data = JSON.parse(val)
188
+ raise_error('invalid JSON object', val, hint: "#{prefix}_ENV") unless data.is_a?(::Hash)
189
+ @output[2] = data
190
+ rescue StandardError => e
191
+ log.warn e
192
+ end
118
193
  end
119
- end
120
-
121
- def initialize_script(ref, **)
122
- initialize_ref(ref)
123
- return unless (script = workspace.script(group: group, ref: ref))
124
-
125
- @depend = script[:depend] if @depend.nil?
126
- @doc = script[:doc] if @doc.nil?
127
- @test = script[:test] if @test.nil?
128
- @clean = script[:clean] if @clean.nil?
129
- @exclude = script[:exclude] if @exclude.empty? && script.key?(:exclude)
130
- @script = script
131
- end
194
+ return unless (val = env('BUILD', strict: true))
132
195
 
133
- def initialize_ref(ref)
134
- @ref << ref unless @exclude.include?(ref)
196
+ @global = false
197
+ if val == '0'
198
+ @output = [false]
199
+ elsif script?
200
+ script_set val
201
+ else
202
+ run_set val
203
+ end
135
204
  end
136
205
 
137
206
  def ref
@@ -139,80 +208,114 @@ module Squared
139
208
  end
140
209
 
141
210
  def populate(*)
142
- valid = ref?(Base.ref)
143
- series = workspace.series
144
-
145
211
  namespace name do
146
- series.each_key do |key|
147
- next unless series.include?(key) ? has?(key) && valid : workspace.task_extend?(self, key)
148
-
149
- desc message(*name.split(':'), key)
150
- task key do
151
- __send__(key)
212
+ workspace.series.each_key do |key|
213
+ next unless workspace.task_include?(self, key)
214
+
215
+ alt = workspace.series.name_get(key)
216
+ unless workspace.task_defined?(name, alt)
217
+ desc message(@desc, alt)
218
+ task alt do
219
+ __send__(key)
220
+ end
152
221
  end
222
+ next if (items = @children.select { |item| workspace.task_include?(item, key) }).empty?
223
+
224
+ desc message(@desc, alt, 'workspace')
225
+ task task_join(alt, 'workspace') => items.map { |item| task_join(item.name, alt) }
153
226
  end
154
227
  end
155
228
  end
156
229
 
157
- def build(*args, sync: true)
230
+ def with(**kwargs, &blk)
231
+ @withargs = kwargs.empty? ? nil : kwargs
232
+ if block_given?
233
+ instance_eval(&blk)
234
+ @withargs = nil
235
+ end
236
+ self
237
+ end
238
+
239
+ def add(path, name = nil, **kwargs, &blk)
240
+ if path.is_a?(::String) && (data = %r{^(.+)[\\/]\*+$}.match(path))
241
+ path = base_path(data[1]).children.select(&:directory?)
242
+ end
243
+ if path.is_a?(::Array)
244
+ name = @name if name == true
245
+ path.each { |val| add(val, name && task_join(name, File.basename(val)), **kwargs, &blk) }
246
+ return self
247
+ elsif !source_path?(path = base_path(path))
248
+ return self
249
+ elsif !name.is_a?(::String) && !name.is_a?(::Symbol)
250
+ name = nil
251
+ end
252
+ if @withargs
253
+ data = @withargs.dup
254
+ data.merge!(kwargs)
255
+ kwargs = data
256
+ end
257
+ kwargs[:group] = group unless kwargs.key?(:group)
258
+ kwargs[:ref] = ref unless kwargs.key?(:ref)
259
+ parent = self
260
+ proj = nil
261
+ workspace.add(path, name || path.basename, **kwargs) do
262
+ variable_set :parent, parent
263
+ proj = self
264
+ end
265
+ @children << proj
266
+ proj.instance_eval(&blk) if block_given?
267
+ self
268
+ end
269
+
270
+ def build(*args, sync: invoked_sync?('build'), **)
158
271
  if args.empty?
159
- cmd, opts = @output
160
- opts &&= shell_escape(opts)
272
+ cmd, opts, var, flags = @output
273
+ banner = verbose == 1
161
274
  else
162
275
  cmd = args.shift
163
- opts = sanitize_args(*args)
276
+ opts = args.map { |val| shell_quote(val, force: false) }.join(' ')
277
+ banner = verbose
164
278
  end
165
279
  if cmd
166
- if opts
280
+ case opts
281
+ when ::String
167
282
  cmd = "#{cmd} #{opts}"
168
- elsif cmd.is_a?(::Array)
283
+ when ::Array
169
284
  cmd = cmd.join(' && ')
285
+ else
286
+ cmd = [cmd, compose(opts, script: false)].compact.join(' ') unless opts == false || !respond_to?(:compose)
170
287
  end
171
- banner = verbose?
172
288
  else
173
289
  return unless respond_to?(:compose)
174
290
 
175
- cmd = compose(opts)
176
- banner = env('REPO_BUILD') == 'verbose'
177
- end
178
- run(cmd, banner: banner, sync: sync)
179
- end
180
-
181
- def refresh(*)
182
- build(sync: invoked_sync?('depend'))
183
- key = "#{name}:copy"
184
- if workspace.task_defined?(key)
185
- invoke(key, exception: workspace.exception, warning: workspace.warning)
186
- else
187
- copy
291
+ cmd = compose(opts, flags, script: true)
188
292
  end
293
+ run(cmd, var, banner: banner, sync: sync)
189
294
  end
190
295
 
191
- def depend(*)
192
- run(@depend, sync: invoked_sync?('depend')) if @depend
296
+ def depend(*, sync: invoked_sync?('depend'), **)
297
+ run(@depend, sync: sync) if @depend
193
298
  end
194
299
 
195
- def copy(*)
196
- run_s(@copy, sync: invoked_sync?('copy')) if @copy
300
+ def copy(*, sync: invoked_sync?('copy'), **)
301
+ run_s(@copy, sync: sync) if @copy
197
302
  end
198
303
 
199
- def doc
200
- build(@doc, sync: invoked_sync?('doc')) if @doc
304
+ def doc(*, sync: invoked_sync?('doc'), **)
305
+ build(@doc, sync: sync) if @doc
201
306
  end
202
307
 
203
- def test
204
- build(@test, sync: invoked_sync?('test')) if @test
308
+ def test(*, sync: invoked_sync?('test'), **)
309
+ build(@test, sync: sync) if @test
205
310
  end
206
311
 
207
- def clean
208
- return unless @clean
209
-
210
- if @clean.is_a?(::String)
312
+ def clean(*)
313
+ case @clean
314
+ when ::String
211
315
  run_s(@clean, sync: invoked_sync?('clean'))
212
- else
213
- @clean.each do |val|
214
- val = val.to_s
215
- if val =~ %r{[\\/]$}
316
+ when ::Enumerable
317
+ as_a(@clean).each do |val|
318
+ if (val = val.to_s) =~ %r{[\\/]$}
216
319
  dir = Pathname.new(val)
217
320
  dir = base_path(dir) unless dir.absolute?
218
321
  next unless dir.directory?
@@ -239,10 +342,52 @@ module Squared
239
342
  @log = Logger.new(enabled? ? @log[0] : nil, **@log[1])
240
343
  end
241
344
 
242
- def base_path(*args)
243
- path.join(*args)
345
+ def base_path(*args, ascend: nil)
346
+ ret = path.join(*args)
347
+ return ret unless ascend && !ret.exist?
348
+
349
+ path.parent.ascend.each do |dir|
350
+ target = dir.join(*args)
351
+ return target if target.exist?
352
+ break if (ascend.is_a?(String) && dir.join(ascend).exist?) || workspace.root == dir || parent&.path == dir
353
+ end
354
+ ret
244
355
  end
245
356
 
357
+ def color(val)
358
+ ret = theme[val]
359
+ ret && !ret.empty? ? ret : [val]
360
+ end
361
+
362
+ def variable_set(key, *val, **kwargs)
363
+ if variables.include?(key)
364
+ case key
365
+ when :run
366
+ run_set(*val, **kwargs)
367
+ when :script
368
+ script_set(*val, **kwargs)
369
+ when :env
370
+ run_set(output[0], *val, **kwargs)
371
+ when :parent
372
+ @parent = val if (val = val.first).is_a?(Project::Base)
373
+ else
374
+ instance_variable_set :"@#{key}", val.first
375
+ end
376
+ else
377
+ log.warn "variable_set: @#{key} (private)"
378
+ end
379
+ end
380
+
381
+ def variables
382
+ VAR_SET
383
+ end
384
+
385
+ def allref
386
+ @ref.reverse_each
387
+ end
388
+
389
+ def version(*); end
390
+
246
391
  def inspect
247
392
  "#<#{self.class}: #{name} => #{self}>"
248
393
  end
@@ -255,12 +400,16 @@ module Squared
255
400
  name.to_sym
256
401
  end
257
402
 
258
- def enabled?
403
+ def enabled?(ref = nil)
404
+ return false if ref && !ref?(ref)
405
+
259
406
  path.directory? && !path.empty?
260
407
  end
261
408
 
262
- def has?(method)
263
- respond_to?(m = :"#{method}?") && __send__(m)
409
+ def has?(meth, ref = nil)
410
+ return false if ref && !ref?(ref)
411
+
412
+ respond_to?(meth = :"#{meth}?") && __send__(meth)
264
413
  end
265
414
 
266
415
  def ref?(val)
@@ -268,15 +417,19 @@ module Squared
268
417
  end
269
418
 
270
419
  def build?
271
- !!@output[0]
420
+ !!@output[0] || script?
272
421
  end
273
422
 
274
- def refresh?
275
- build? && (copy? || workspace.task_defined?("#{name}:copy"))
423
+ def script?
424
+ @output[0].nil? && !!@output[1] && respond_to?(:compose)
276
425
  end
277
426
 
278
427
  def depend?
279
- @depend != false && (!@depend.nil? || has?('outdated'))
428
+ !!@depend
429
+ end
430
+
431
+ def copy?
432
+ runnable?(@copy) || workspace.task_defined?(name, 'copy')
280
433
  end
281
434
 
282
435
  def doc?
@@ -287,34 +440,40 @@ module Squared
287
440
  !!@test
288
441
  end
289
442
 
290
- def copy?
291
- @copy.is_a?(::String)
292
- end
293
-
294
443
  def clean?
295
- !!@clean
444
+ runnable?(@clean) || workspace.task_defined?(name, 'clean')
296
445
  end
297
446
 
298
447
  def dev?
299
- !!@dev
448
+ @dev != false && workspace.dev?(pat: @dev, **scriptargs)
449
+ end
450
+
451
+ def prod?
452
+ @prod != false && workspace.prod?(pat: @prod, **scriptargs)
300
453
  end
301
454
 
302
455
  private
303
456
 
304
- def run(cmd = @session, exception: workspace.exception, banner: true, sync: true, req: nil, **)
457
+ def puts(*args)
458
+ puts_oe(*args, pipe: pipe)
459
+ end
460
+
461
+ def run(cmd = @session, var = nil, exception: @exception, sync: true, req: nil, banner: ARG[:BANNER], **)
305
462
  if req && !base_path(req).exist?
306
463
  log.warn "#{req} (not found)"
307
464
  return
308
465
  end
309
- cmd = close_session(cmd)
466
+ cmd = session_done(cmd)
310
467
  log.info cmd
311
468
  begin
312
469
  if cmd =~ /^\S+:(\S+:?)+$/ && workspace.task_defined?(cmd)
313
470
  print_item if sync
314
- invoke(cmd, exception: exception, warning: workspace.warning)
471
+ log.warn "ENV was discarded: #{var}" if var
472
+ invoke(cmd, exception: exception, warning: warning?)
315
473
  else
316
474
  print_item format_banner(cmd, banner: banner) if sync
317
- shell(cmd, chdir: path, exception: exception)
475
+ args = var.is_a?(::Hash) ? [var, cmd] : [cmd]
476
+ shell(*args, chdir: path, exception: exception)
318
477
  end
319
478
  rescue StandardError => e
320
479
  log.error e
@@ -322,42 +481,57 @@ module Squared
322
481
  end
323
482
  end
324
483
 
325
- def run_s(cmd, **kwargs)
326
- run(cmd, banner: verbose?, **kwargs) if cmd.is_a?(::String)
484
+ def run_s(*cmd, env: nil, **kwargs)
485
+ cmd.each { |val| run(val, env, banner: !!verbose, **kwargs) }
327
486
  end
328
487
 
329
- def env(key, default = nil, equals: nil, ignore: ['0'].freeze, suffix: nil, strict: false)
330
- @env ||= name.gsub(/[^\w]+/, '_').upcase
331
- a = "#{key}_#{@env}"
332
- b = ''
333
- if suffix
334
- a = [a, suffix].flatten.join('_')
335
- elsif !strict
336
- b = ENV.fetch(key, '')
337
- end
338
- ret = ENV.fetch(a, b)
488
+ def run_task(key)
489
+ return false unless workspace.task_defined?(key)
490
+
491
+ invoke(key, **workspace.invokeargs)
492
+ true
493
+ end
494
+
495
+ def env(key, default = nil, suffix: nil, equals: nil, ignore: nil, strict: false)
496
+ a = "#{key}_#{@envname}"
497
+ ret = if suffix
498
+ ENV.fetch("#{a}_#{suffix}", '')
499
+ else
500
+ ignore = ['0'].freeze if ignore.nil? && !strict
501
+ ENV[a] || (strict ? '' : ENV.fetch(key, ''))
502
+ end
339
503
  return ret == equals.to_s unless equals.nil?
340
504
 
341
- ret.empty? || as_a(ignore).any? { |val| ret == val.to_s } ? default : ret
505
+ ret.empty? || (ignore && as_a(ignore).any? { |val| ret == val.to_s }) ? default : ret
342
506
  end
343
507
 
344
- def session(*cmd, options: nil)
345
- if (val = ENV["#{(options || cmd.first).upcase}_OPTIONS"])
508
+ def session(*cmd, prefix: cmd.first)
509
+ if (val = env("#{prefix.upcase}_OPTIONS"))
346
510
  split_escape(val).each { |opt| cmd << fill_option(opt) }
347
511
  end
348
512
  @session = JoinSet.new(cmd)
349
513
  end
350
514
 
351
- def close_session(cmd)
352
- return cmd unless cmd.respond_to?(:done)
515
+ def session_done(cmd)
516
+ return cmd.to_s unless cmd.respond_to?(:done)
353
517
 
354
- raise_error('none were provided', hint: name) if cmd.empty?
518
+ raise_error('no args were added', hint: cmd.first || name) unless cmd.size > 1
355
519
  @session = nil if cmd == @session
356
520
  cmd.done
357
521
  end
358
522
 
523
+ def option(*args, prefix: @session&.first, **kwargs)
524
+ if prefix
525
+ args.each do |val|
526
+ ret = env("#{prefix}_#{val.gsub(/\W/, '_')}".upcase, **kwargs)
527
+ return ret if ret
528
+ end
529
+ end
530
+ nil
531
+ end
532
+
359
533
  def print_item(*val)
360
- puts unless @@print_order == 0 || pipe?
534
+ puts unless @@print_order == 0 || stdin?
361
535
  @@print_order += 1
362
536
  puts val unless val.empty? || (val.size == 1 && val.first.nil?)
363
537
  end
@@ -387,41 +561,64 @@ module Squared
387
561
  out.join("\n")
388
562
  end
389
563
 
390
- def print_footer(*lines, sub: nil, border: theme[:border], reverse: false)
564
+ def print_footer(*lines, sub: nil, reverse: false, right: false, **kwargs)
565
+ border = kwargs.key?(:border) ? kwargs[:border] : borderstyle
391
566
  n = Project.max_width(lines)
392
567
  sub = as_a(sub)
393
568
  lines.map! do |val|
394
- s = val.ljust(n)
569
+ s = right ? val.rjust(n) : val.ljust(n)
395
570
  sub.each { |h| s = sub_style(s, **h) }
396
571
  s
397
572
  end
398
- ret = [sub_style('-' * n, styles: border), *lines]
573
+ ret = [sub_style('-' * n, styles: border || theme[:border]), *lines]
399
574
  ret.reverse! if reverse
400
575
  ret.join("\n")
401
576
  end
402
577
 
403
- def format_desc(action, flag, opts = nil, req: '', arg: 'opts*')
578
+ def format_desc(action, flag, opts = nil, req: nil, arg: 'opts*')
404
579
  opts = "#{arg}=#{opts.join(',')}" if opts.is_a?(::Array)
405
- unless flag
580
+ val = [@desc]
581
+ if flag
582
+ val << action
583
+ else
406
584
  flag = action
407
- action = ''
408
585
  end
409
- req = opts ? "#{req}," : "[#{req}]" unless req.to_s.empty?
410
- message(*name.split(':'), action, opts ? "#{flag}[#{req}#{opts}]" : flag.to_s + req)
586
+ req = opts ? "#{req}," : "[#{req}]" if req
587
+ val << (opts ? "#{flag}[#{req}#{opts}]" : "#{flag}#{req}")
588
+ message(*val)
411
589
  end
412
590
 
413
- def format_banner(cmd, banner: true, multiple: false)
591
+ def format_banner(cmd, banner: ARG[:BANNER], multiple: false)
414
592
  return unless banner
415
593
 
416
- if (data = workspace.banner(group: group, ref: ref))
594
+ if (data = workspace.banner_get(*@ref, group: group))
417
595
  client = true
418
596
  else
419
597
  data = { command: true, order: %i[path], styles: theme[:banner], border: theme[:border] }
420
598
  end
421
- if verbose?
599
+ if verbose
422
600
  out = []
423
601
  out << cmd.sub(/^\S+/, &:upcase) if data[:command]
424
- data[:order].each { |val| out << val.to_s if (val = __send__(val)) }
602
+ data[:order].each do |val|
603
+ if val.is_a?(::Array)
604
+ s = ' '
605
+ found = false
606
+ val = val.map do |meth|
607
+ if meth.is_a?(::String)
608
+ s = ''
609
+ meth
610
+ elsif respond_to?(meth)
611
+ found = true
612
+ __send__(meth)
613
+ end
614
+ end
615
+ val = val.compact.join(s)
616
+ next unless found && !val.empty?
617
+ elsif (val = __send__(val)).nil?
618
+ next
619
+ end
620
+ out << val.to_s
621
+ end
425
622
  print_banner(*out, styles: data[:styles], border: data[:border], client: client)
426
623
  elsif multiple && workspace.series.multiple?
427
624
  "## #{__send__(data[:order].first || :path)} ##"
@@ -432,8 +629,20 @@ module Squared
432
629
  "#{msg}#{!always && (!obj || obj == 0 || obj.to_s.empty?) ? '' : message(hint: message(title, obj.to_s))}"
433
630
  end
434
631
 
435
- def append_nocolor
436
- @session << (!ENV.fetch('NO_COLOR', '').empty? || pipe? ? '--no-color' : '')
632
+ def append_repeat(flag, opts)
633
+ opts.each { |val| @session << "--#{flag}=#{shell_escape(val, quote: true)}" }
634
+ end
635
+
636
+ def append_value(opts)
637
+ opts.each { |val| @session << val }
638
+ end
639
+
640
+ def append_nocolor(flag = nil)
641
+ @session << '--no-color' if flag || !ARG[:COLOR] || stdin?
642
+ end
643
+
644
+ def task_join(*val)
645
+ val.join(':')
437
646
  end
438
647
 
439
648
  def guard_params(action, flag, args: nil, key: nil, pat: nil)
@@ -450,22 +659,11 @@ module Squared
450
659
  end
451
660
  end
452
661
 
453
- def store_pwd(done = nil)
454
- if @pwd
455
- Dir.chdir(@pwd)
456
- @pwd = nil
457
- elsif !done && Dir.pwd != path.to_s
458
- @pwd = Dir.pwd
459
- Dir.chdir(path)
460
- @pwd
461
- end
462
- end
463
-
464
662
  def semver(val)
465
- unless val[3]
466
- val[3] = '.'
467
- val[4] = '0'
468
- end
663
+ return val if val[3]
664
+
665
+ val[3] = '.'
666
+ val[4] = '0'
469
667
  unless val[1]
470
668
  val[1] = '.'
471
669
  val[2] = '0'
@@ -474,39 +672,122 @@ module Squared
474
672
  end
475
673
 
476
674
  def semmajor(cur, want)
477
- cur[0] == '0' && want[0] == '0' ? cur[2] != want[2] : cur[0] != want[0]
675
+ (cur[0] == '0' && want[0] == '0' ? cur[2] != want[2] : cur[0] != want[0]) && !want[5]
478
676
  end
479
677
 
480
- def verbose?
481
- workspace.verbose
678
+ def semscan(val)
679
+ val.scan(SEM_VER).first
482
680
  end
483
681
 
484
- def pipe?
485
- workspace.pipe
486
- end
682
+ def pwd_set(done = nil, &blk)
683
+ pwd = Pathname.pwd
684
+ if block_given?
685
+ if path == pwd
686
+ instance_eval(&blk)
687
+ else
688
+ Dir.chdir(path)
689
+ instance_eval(&blk)
690
+ Dir.chdir(pwd)
691
+ end
692
+ elsif @pwd == pwd
693
+ @pwd = nil
694
+ pwd unless done
695
+ elsif @pwd
696
+ return unless path == pwd
487
697
 
488
- def invoked_sync?(action, flag = nil)
489
- action = workspace.task_name(action)
490
- return true if !flag.nil? || workspace.series.sync?("#{action}:sync")
698
+ Dir.chdir(@pwd)
699
+ @pwd = nil
700
+ elsif !done && path != pwd
701
+ @pwd = pwd
702
+ Dir.chdir(path)
703
+ @pwd
704
+ end
705
+ end
491
706
 
492
- check = lambda do |val|
493
- if invoked?(val)
494
- !workspace.task_defined?("#{val}:sync")
495
- elsif workspace.series.sync?("#{val}:sync")
496
- true
707
+ def run_set(cmd, val = nil, opts: nil, **)
708
+ unless @output[1] == false && !@output[0].nil?
709
+ if opts == false
710
+ @output[1] = false
711
+ elsif opts && opts != true
712
+ @output[1] = opts
497
713
  end
498
714
  end
499
- if group
500
- ret = check.("#{action}:#{group}")
501
- return ret unless ret.nil?
715
+ unless @output[2] == false
716
+ if val.is_a?(::Hash)
717
+ @output[2] = val
718
+ elsif val == false
719
+ @output[2] = false
720
+ end
721
+ end
722
+ @output[0] = cmd
723
+ end
724
+
725
+ def script_set(cmd, prod: nil, **)
726
+ return if @output[1] == false && @output[0].nil?
727
+
728
+ @output[0] = nil
729
+ @output[1] = if @global && cmd.is_a?(::Array)
730
+ cmd[prod == true ? 1 : 0]
731
+ else
732
+ cmd
733
+ end
734
+ end
735
+
736
+ def source_path?(val)
737
+ Pathname.new(val).absolute? ? val.to_s.start_with?(File.join(path, '')) : !val.to_s.match?(%r{^\.\.[/\\]})
738
+ end
739
+
740
+ def runnable?(val)
741
+ case val
742
+ when ::String
743
+ true
744
+ when ::Enumerable
745
+ !val.is_a?(::Hash)
746
+ else
747
+ false
748
+ end
749
+ end
750
+
751
+ def from_sync?(*val)
752
+ if invoked?(key = task_join(*val))
753
+ !workspace.task_defined?(key, 'sync')
754
+ elsif workspace.series.sync?(task_join(key, 'sync'))
755
+ true
502
756
  end
503
- if (base = workspace.find_base(self))
504
- ret = check.("#{action}:#{base.ref}")
505
- return ret unless ret.nil?
757
+ end
758
+
759
+ def invoked_sync?(action, val = nil)
760
+ return true if !val.nil? || from_sync?(ac = workspace.task_name(action))
761
+
762
+ return val if group && !(val = from_sync?(ac, group)).nil?
763
+ return val if (base = workspace.find_base(self)) && !(val = from_sync?(ac, base.ref)).nil?
764
+
765
+ return true if invoked?(name, ac) && (!invoked?(ac) || !workspace.task_defined?(ac, 'sync'))
766
+
767
+ val = workspace.series.name_get(action)
768
+ val == action ? false : invoked_sync?(val)
769
+ end
770
+
771
+ def stdin?
772
+ pipe == 0
773
+ end
774
+
775
+ def warning?
776
+ workspace.warning
777
+ end
778
+
779
+ def borderstyle
780
+ if (data = workspace.banner_get(*@ref, group: group))
781
+ data[:border]
506
782
  end
507
- invoked?("#{name}:#{action}") && (!invoked?(action) || !workspace.task_defined?("#{action}:sync"))
783
+ end
784
+
785
+ def scriptargs
786
+ { target: script? ? @output[1] : @output[0], ref: ref, group: group, global: @global }
508
787
  end
509
788
  end
789
+
790
+ Application.base_project = Base
510
791
  end
511
792
  end
512
793
  end