squared 0.0.1

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.
@@ -0,0 +1,357 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module Squared
6
+ module Repo
7
+ module Project
8
+ class Base
9
+ include Common
10
+ include Shell
11
+ include System
12
+ include Task
13
+ include ::Rake::DSL
14
+ extend Forwardable
15
+
16
+ class << self
17
+ def tasks
18
+ [].freeze
19
+ end
20
+
21
+ def to_s
22
+ to_sym.to_s.capitalize
23
+ end
24
+
25
+ def to_sym
26
+ :base
27
+ end
28
+ end
29
+
30
+ @@print_order = 0
31
+ @@tasks = {}
32
+
33
+ attr_reader :name, :project, :workspace, :group, :path, :logger
34
+
35
+ protected :logger
36
+
37
+ def_delegators :logger, :log, :level=, :<<, :debug, :info, :warn, :error, :fatal, :unknown
38
+
39
+ def initialize(name, project, workspace, **kwargs)
40
+ @name = name.to_s
41
+ @path = workspace.root_path(project.to_s)
42
+ @project = @path.basename.to_s
43
+ @workspace = workspace
44
+ @depend = kwargs[:depend]
45
+ @doc = kwargs[:doc]
46
+ @group = kwargs[:group]&.to_s
47
+ run = kwargs[:run]
48
+ opts = env('BUILD', strict: true)
49
+ raise ArgumentError, message("BUILD_#{name.to_s.upcase}", opts) if opts && run.is_a?(::Array)
50
+
51
+ @output = [run, opts]
52
+ @copy = kwargs[:copy]
53
+ @clean = kwargs[:clean]
54
+ log = kwargs[:log]
55
+ log = { file: log } unless log.is_a?(::Hash)
56
+ if (logfile = env('LOG_FILE')).nil? && (auto = env('LOG_AUTO'))
57
+ require 'date'
58
+ logfile = case auto
59
+ when 'y', 'year'
60
+ "#{name}-#{Date.today.year}.log"
61
+ when 'm', 'month'
62
+ "#{name}-#{Date.today.strftime('%Y-%m')}.log"
63
+ when 'd', 'day', '1'
64
+ "#{name}-#{Date.today}.log"
65
+ else
66
+ log[:file]
67
+ end
68
+ else
69
+ logfile = log[:file]
70
+ end
71
+ if (dir = env('LOG_DIR'))
72
+ logfile &&= Pathname.new(dir).join(logfile)
73
+ end
74
+ @logger = Logger.new(logfile, level: env('LOG_LEVEL') || log[:level] || Logger::INFO)
75
+ @logger.progname = name
76
+ @session = nil
77
+ end
78
+
79
+ def populate(*)
80
+ namespace @name do
81
+ @workspace.series.each_key do |key|
82
+ case key
83
+ when :build, :refresh, :depend, :outdated, :doc, :copy, :clean
84
+ next unless has?(key)
85
+ else
86
+ next unless @workspace.task_defined?(self, key)
87
+ end
88
+ desc message(@name, key)
89
+ task key do
90
+ send(key)
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ def build(*args)
97
+ if args.empty?
98
+ cmd, opts = @output
99
+ opts &&= shell_escape(opts)
100
+ else
101
+ cmd = args.shift
102
+ opts = sanitize_args(*args)
103
+ end
104
+ if cmd
105
+ if opts
106
+ cmd = "#{cmd} #{opts}"
107
+ elsif cmd.is_a?(::Array)
108
+ cmd = cmd.join(' && ')
109
+ end
110
+ banner = verbose?
111
+ else
112
+ return unless respond_to?(:compose)
113
+
114
+ cmd = compose(opts)
115
+ banner = env('REPO_BUILD') == 'verbose'
116
+ end
117
+ run(cmd, exception: @workspace.exception, banner: banner)
118
+ end
119
+
120
+ def refresh(*)
121
+ build
122
+ key = "#{@name}:copy"
123
+ if ::Rake::Task.task_defined?(key)
124
+ invoke key
125
+ else
126
+ copy
127
+ end
128
+ end
129
+
130
+ def depend(*)
131
+ run(@depend, exception: @workspace.exception) if @depend
132
+ end
133
+
134
+ def doc
135
+ build @doc if @doc
136
+ end
137
+
138
+ def copy(*)
139
+ run_s @copy
140
+ end
141
+
142
+ def clean
143
+ return run_s @clean if @clean.is_a?(::String)
144
+
145
+ @clean&.each do |path|
146
+ path = path.to_s
147
+ if %r{[\\/]$}.match?(path)
148
+ dir = Pathname.new(path)
149
+ dir = base_path(dir) unless dir.absolute?
150
+ next unless dir.directory?
151
+
152
+ warn "rm -rf #{dir}"
153
+ dir.rmtree(verbose: true)
154
+ else
155
+ files = path.include?('*') ? Dir[base_path(path)] : [base_path(path)]
156
+ files.each do |val|
157
+ begin
158
+ File.delete(val) if File.file?(val)
159
+ rescue StandardError => e
160
+ warn e
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
166
+
167
+ def styles
168
+ @workspace.styles
169
+ end
170
+
171
+ def base_path(*args)
172
+ @path.join(*args)
173
+ end
174
+
175
+ def to_s
176
+ @path.to_s
177
+ end
178
+
179
+ def to_sym
180
+ @name.to_sym
181
+ end
182
+
183
+ def enabled?
184
+ @path.directory? && !@path.empty?
185
+ end
186
+
187
+ def has?(method)
188
+ respond_to?(m = :"#{method}?") && send(m)
189
+ end
190
+
191
+ def build?
192
+ return false if @output[0] == false
193
+
194
+ !doc? || !@output[0].nil?
195
+ end
196
+
197
+ def refresh?
198
+ build?
199
+ end
200
+
201
+ def depend?
202
+ !@depend.nil?
203
+ end
204
+
205
+ def doc?
206
+ !@doc.nil?
207
+ end
208
+
209
+ def copy?
210
+ @copy.is_a?(::String)
211
+ end
212
+
213
+ def clean?
214
+ !@clean.nil?
215
+ end
216
+
217
+ def verbose?
218
+ @workspace.verbose && !pipe?
219
+ end
220
+
221
+ protected
222
+
223
+ def run(cmd = @session, exception: false, banner: true, req: nil)
224
+ return if req && !base_path(req).exist?
225
+
226
+ cmd = close_session(cmd)
227
+ info cmd
228
+ print_item format_banner(cmd, banner: banner)
229
+ begin
230
+ shell(cmd, chdir: @path, exception: exception)
231
+ rescue StandardError => e
232
+ error e
233
+ raise
234
+ end
235
+ end
236
+
237
+ def run_s(cmd)
238
+ run(cmd, exception: @workspace.exception, banner: verbose?) if cmd.is_a?(::String)
239
+ end
240
+
241
+ def env(key, suffix: nil, equals: nil, strict: false)
242
+ val = "#{key}_#{@name.upcase}"
243
+ ret = if suffix
244
+ ENV.fetch(([val] + as_a(suffix)).join('_'), '')
245
+ else
246
+ ENV.fetch(val, strict ? '' : ENV[key]).to_s
247
+ end
248
+ return ret == equals.to_s unless equals.nil?
249
+
250
+ ret unless ret.empty? || ret == '0'
251
+ end
252
+
253
+ def session(*cmd, options: nil)
254
+ if (val = ENV["#{(options || cmd.first).upcase}_OPTIONS"])
255
+ split_escape(val).each do |opt|
256
+ cmd << (if opt.start_with?('-')
257
+ shell_escape(opt).sub('\\=', '=')
258
+ else
259
+ opt.size == 1 || /^[a-z]\d+$/i.match?(opt) ? "-#{opt}" : "--#{opt}"
260
+ end)
261
+ end
262
+ end
263
+ @session = JoinSet.new(cmd)
264
+ end
265
+
266
+ def close_session(cmd)
267
+ return cmd unless cmd.respond_to?(:done)
268
+ raise ArgumentError, message('none were provided', hint: @name) if cmd.empty?
269
+
270
+ @session = nil if cmd == @session
271
+ cmd.done
272
+ end
273
+
274
+ def print_item(*val)
275
+ puts unless @@print_order == 0 || pipe?
276
+ @@print_order += 1
277
+ puts val unless val.empty? || (val.size == 1 && val.first.nil?)
278
+ end
279
+
280
+ def format_desc(action, flag, opts = nil, req: 'opts*')
281
+ opts = "#{req}=#{opts.join(',')}" if opts.is_a?(::Array)
282
+ message(@name, action, opts ? "#{flag}[#{opts}]" : flag)
283
+ end
284
+
285
+ def format_banner(cmd, banner: true, multitask: false)
286
+ return unless banner
287
+
288
+ if verbose?
289
+ pad = 0
290
+ if (args = styles[:banner])
291
+ if args.any? { |s| s.to_s.end_with?('!') }
292
+ pad = 1
293
+ elsif args.size <= 1
294
+ args = [:bold] + args
295
+ end
296
+ end
297
+ Project.banner(cmd.sub(/^\S+/, &:upcase), @path.to_s, styles: args, pad: pad, first: pad == 0)
298
+ elsif multitask && @workspace.multitask?
299
+ "## #{@path} ##"
300
+ end
301
+ end
302
+
303
+ def empty_status(msg, title, obj)
304
+ "#{msg}#{!obj || obj == 0 || obj.to_s.empty? ? '' : message(hint: message(title, obj.to_s))}"
305
+ end
306
+
307
+ def append_nocolor
308
+ @session << (!ENV.fetch('NO_COLOR', '').empty? || pipe? ? '--no-color' : '')
309
+ end
310
+
311
+ def guard_params(action, flag, args: nil, key: nil, pat: nil)
312
+ if args && key
313
+ return unless (val = args[key]).nil? || (pat && !pat.match?(val))
314
+
315
+ @session = nil
316
+ raise ArgumentError, message(action, "#{flag}[#{key}]", hint: val.nil? ? 'missing' : 'invalid')
317
+ elsif args.is_a?(::Array)
318
+ return unless args.empty?
319
+
320
+ @session = nil
321
+ raise ArgumentError, message(action, "#{flag}[]", hint: 'empty')
322
+ end
323
+ return unless action.to_s.empty?
324
+
325
+ @session = nil
326
+ raise ArgumentError, message('parameter', flag, hint: 'missing')
327
+ end
328
+
329
+ def pipe?
330
+ @workspace.pipe?
331
+ end
332
+
333
+ def invoked_sync?(action)
334
+ return true if invoked?(group = "#{action}:sync")
335
+
336
+ missing = ->(val) { ::Rake::Task.tasks.none? { |item| item.name == val } }
337
+ check = lambda do |val|
338
+ if invoked?(val)
339
+ missing.("#{val}:sync")
340
+ elsif invoked?("#{val}:sync")
341
+ true
342
+ end
343
+ end
344
+ if @group
345
+ ret = check.("#{action}:#{@group}")
346
+ return ret unless ret.nil?
347
+ end
348
+ if (base = @workspace.find_base(self))
349
+ ret = check.("#{action}:#{base.to_sym}")
350
+ return ret unless ret.nil?
351
+ end
352
+ invoked?("#{@name}:#{action}") && (!invoked?(action) || missing.(group))
353
+ end
354
+ end
355
+ end
356
+ end
357
+ end