squared 0.0.4 → 0.0.6

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.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: squared
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - An Pham
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-02 00:00:00.000000000 Z
11
+ date: 2024-11-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -50,21 +50,24 @@ files:
50
50
  - README.ruby.md
51
51
  - lib/squared.rb
52
52
  - lib/squared/common.rb
53
+ - lib/squared/common/base.rb
53
54
  - lib/squared/common/class.rb
54
55
  - lib/squared/common/format.rb
55
56
  - lib/squared/common/shell.rb
56
57
  - lib/squared/common/system.rb
57
58
  - lib/squared/common/task.rb
58
59
  - lib/squared/config.rb
59
- - lib/squared/repo.rb
60
- - lib/squared/repo/project.rb
61
- - lib/squared/repo/project/base.rb
62
- - lib/squared/repo/project/git.rb
63
- - lib/squared/repo/project/node.rb
64
- - lib/squared/repo/project/python.rb
65
- - lib/squared/repo/project/ruby.rb
66
- - lib/squared/repo/workspace.rb
67
60
  - lib/squared/version.rb
61
+ - lib/squared/workspace.rb
62
+ - lib/squared/workspace/application.rb
63
+ - lib/squared/workspace/project.rb
64
+ - lib/squared/workspace/project/base.rb
65
+ - lib/squared/workspace/project/git.rb
66
+ - lib/squared/workspace/project/node.rb
67
+ - lib/squared/workspace/project/python.rb
68
+ - lib/squared/workspace/project/ruby.rb
69
+ - lib/squared/workspace/repo.rb
70
+ - lib/squared/workspace/series.rb
68
71
  - squared.gemspec
69
72
  homepage: https://github.com/anpham6/squared
70
73
  licenses:
@@ -1,123 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Squared
4
- module Repo
5
- module Project
6
- class Python < Git
7
- REF = :python
8
- REQUIREMENTS = %w[requirements.txt pyproject.toml setup.py].freeze
9
- private_constant :REF, :REQUIREMENTS
10
-
11
- class << self
12
- def populate(*); end
13
-
14
- def tasks
15
- nil
16
- end
17
-
18
- def venv?
19
- val = ENV['VIRTUAL_ENV']
20
- !val.nil? && Dir.exist?(val)
21
- end
22
-
23
- def is_a?(val)
24
- if (val = as_path(val))
25
- REQUIREMENTS.any? { |file| val.join(file).exist? }
26
- else
27
- super
28
- end
29
- end
30
- end
31
-
32
- def initialize(name, path, workspace, *, **kwargs)
33
- super
34
- initialize_build(REF, **kwargs)
35
- end
36
-
37
- @@tasks[REF] = {
38
- install: %i[upgrade force]
39
- }.freeze
40
-
41
- def populate(*)
42
- super
43
- return unless outdated?
44
-
45
- namespace name do
46
- @@tasks[REF].each do |action, flags|
47
- namespace action do
48
- flags.each do |flag|
49
- case action
50
- when :install
51
- options = lambda do |*opts|
52
- opts += %w[pre venv no-cache dry-run]
53
- format_desc(action, flag, opts)
54
- end
55
- case flag
56
- when :upgrade
57
- desc options.('eager')
58
- when :force
59
- desc options.()
60
- end
61
- task flag do |_, args|
62
- depend(flag, opts: collect_args(args, :opts), override: true)
63
- end
64
- end
65
- end
66
- end
67
- end
68
- end
69
- end
70
-
71
- def depend(flag = nil, opts: [], override: false)
72
- if @depend && !override
73
- super
74
- elsif outdated?
75
- case install_type
76
- when 1, 2
77
- cmd = pip_session 'install'
78
- case flag
79
- when :upgrade
80
- cmd << '--upgrade'
81
- cmd << '--upgrade-strategy=eager' if opts.include?('eager')
82
- when :force
83
- cmd << '--force-reinstall'
84
- end
85
- cmd << '--pre' if opts.include?('pre')
86
- cmd << '--require-virtualenv' if opts.include?('venv')
87
- cmd << '--no-cache-dir' if opts.include?('no-cache')
88
- cmd << '--dry-run' if opts.include?('dry-run')
89
- append_nocolor
90
- cmd << (install_type == 1 ? '-r requirements.txt' : '.')
91
- run(exception: workspace.exception)
92
- when 3
93
- run_s "#{@bin} setup.py install"
94
- end
95
- end
96
- end
97
-
98
- def outdated(*); end
99
-
100
- def install_type(*)
101
- return @requirements if @requirements
102
-
103
- ret = REQUIREMENTS.index { |file| base_path(file).exist? }
104
- @requirements = ret ? ret + 1 : 0
105
- end
106
-
107
- def depend?
108
- !!@depend || outdated?
109
- end
110
-
111
- def outdated?
112
- install_type > 0
113
- end
114
-
115
- private
116
-
117
- def pip_session(*cmd)
118
- session('pip', *cmd)
119
- end
120
- end
121
- end
122
- end
123
- end
@@ -1,501 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Squared
4
- module Repo
5
- class Workspace
6
- include Common
7
- include Format
8
- include System
9
- include Task
10
- include ::Rake::DSL
11
-
12
- TASK_NAME = {
13
- build: [],
14
- copy: [],
15
- depend: [],
16
- outdated: [],
17
- refresh: [],
18
- doc: [],
19
- test: [],
20
- clean: []
21
- }
22
- TASK_BASE = {}
23
- private_constant :TASK_NAME, :TASK_BASE
24
-
25
- class << self
26
- def implement(*objs)
27
- objs.each do |obj|
28
- next unless obj < Project::Base
29
-
30
- project_kind.unshift(obj)
31
- obj.tasks&.each do |val|
32
- TASK_NAME[val] = []
33
- TASK_BASE[val] = obj
34
- end
35
- end
36
- end
37
-
38
- def find(path: nil, ref: nil)
39
- if ref.is_a?(::Symbol) || ref.is_a?(::String)
40
- ret = project_kind.find { |proj| proj.to_sym == ref.to_sym }
41
- return ret if ret
42
- end
43
- project_kind.find { |proj| proj.is_a?(path) } if path
44
- end
45
-
46
- def to_s
47
- /[^:]+$/.match(super.to_s)[0]
48
- end
49
-
50
- attr_reader :project_kind
51
- end
52
-
53
- @project_kind = []
54
-
55
- attr_reader :main, :root, :home, :series, :theme
56
- attr_accessor :manifest, :manifest_url, :exception, :pipe, :verbose, :warning
57
-
58
- def initialize(main, *, common: true, **)
59
- @main = main.to_s
60
- @home = if (val = env('REPO_HOME'))
61
- home = Pathname.new(val)
62
- if @main == home.basename.to_s
63
- @root = home.parent
64
- if home.exist?
65
- @root = nil unless home.directory?
66
- elsif !@root.exist?
67
- @root.mkpath
68
- elsif !empty?(@root)
69
- if repo_prompt(@root)
70
- @override = true
71
- else
72
- @root = nil
73
- end
74
- end
75
- end
76
- raise ArgumentError, message('REPO_HOME', val, hint: 'invalid') unless @root
77
-
78
- home.realdirpath
79
- elsif (val = env('REPO_ROOT'))
80
- @root = Pathname.new(val).realdirpath
81
- if !@root.exist?
82
- @root.mkpath
83
- elsif !empty?(@root)
84
- raise ArgumentError, message('REPO_ROOT', val, hint: 'exist') unless repo_prompt(@root)
85
-
86
- @override = true
87
- end
88
- @root.join(@main).realdirpath
89
- else
90
- empty?(pwd = Pathname.pwd) ? pwd.join(@main) : pwd
91
- end
92
- @root ||= @home.parent
93
- @series = TASK_NAME.dup
94
- @theme = common ? __get__(:theme)[:workspace] : {}
95
- @project = {}
96
- @script = {
97
- group: {},
98
- ref: {},
99
- build: nil,
100
- dev: nil,
101
- prod: nil
102
- }
103
- @exception = !env('PIPE_FAIL', ignore: '0').nil?
104
- @pipe = !env('PIPE_OUT', ignore: '0').nil?
105
- @verbose = !@pipe
106
- @warning = !empty?(@root, init: false)
107
- end
108
-
109
- def build(**kwargs)
110
- return unless enabled?
111
-
112
- default = kwargs[:default]
113
- parallel = env('REPO_SYNC', ignore: '0') ? [] : (kwargs[:parallel] || []).map!(&:to_sym)
114
-
115
- group = {}
116
- parent = {}
117
- incl = []
118
- @project.each do |name, proj|
119
- next unless proj.enabled?
120
-
121
- series.each do |key, items|
122
- target = "#{name}:#{key}"
123
- case key
124
- when :build, :refresh, :depend, :copy, :outdated, :doc, :test, :clean
125
- valid = proj.has?(key) || ::Rake::Task.task_defined?(target)
126
- next unless valid || (key == :refresh && series[:build].include?(target = "#{name}:build"))
127
- else
128
- next unless task_defined?(proj, key)
129
- end
130
- if proj.group
131
- incl << proj.group
132
- (group[:"#{key}:#{proj.group}"] ||= []).push(target)
133
- else
134
- items << target
135
- end
136
- next unless (base = find_base(proj))
137
-
138
- unless (id = base.to_sym.to_s) == proj.group
139
- incl << id
140
- (parent[:"#{key}:#{id}"] ||= []).push(target)
141
- end
142
- end
143
- proj.populate(**kwargs)
144
- end
145
- series.merge!(parent) if incl.uniq.size > 1
146
- series.merge!(group)
147
- series[:refresh].clear if series[:refresh].all? { |target| target.end_with?(':build') }
148
-
149
- if repo?
150
- branch = env('REPO_MANIFEST') || read_manifest
151
- target = branch || manifest
152
- stage = nil
153
- failfast = true
154
- cmd = []
155
- newline = ARGV.index { |val| val.start_with?('repo:') }.to_i > 0
156
- parse_opts = lambda do |args|
157
- collect_args(args, :opts).each do |val|
158
- case val
159
- when 'no-fail'
160
- failfast = false
161
- when 'force'
162
- cmd << '--force-checkout'
163
- when 'rebase'
164
- cmd << '--rebase'
165
- when 'detach'
166
- cmd << '--detach'
167
- when 'gc'
168
- cmd << '--auto-gc'
169
- when 'no-update'
170
- cmd << '--no-manifest-update'
171
- end
172
- end
173
- end
174
- status = lambda do |val, alt = nil|
175
- ver = branch || alt
176
- ver ? message('repo', val.sub('{0}', 'opts*=force,rebase,detach,gc,no-update,no-fail'), ver) : 'inactive'
177
- end
178
-
179
- namespace :repo do |repo|
180
- desc status.('all[{0}]')
181
- task :all, [:opts] do |_, args|
182
- parse_opts.(args)
183
- stage ||= :all
184
- repo[:sync].invoke
185
- # rubocop:disable Style/CombinableLoops
186
- @project.each_value { |proj| proj.depend if proj.enabled? }
187
- @project.each_value do |proj|
188
- next unless proj.enabled? && proj.build?
189
-
190
- proj.has?(:dev) ? proj.refresh : proj.build
191
- end
192
- # rubocop:enable Style/CombinableLoops
193
- end
194
-
195
- desc status.("init[manifest?=#{target},{0}]", target)
196
- task :init, [:manifest, :opts] do |_, args|
197
- parse_opts.(args)
198
- stage = :init
199
- puts if newline
200
- system("repo init -u #{manifest_url} -m #{args.manifest || target}.xml", chdir: root)
201
- repo[:all].invoke
202
- end
203
-
204
- desc status.('sync[{0}]')
205
- task :sync, [:opts] do |_, args|
206
- raise LoadError, message('repo is not initialized', 'rake repo:init') unless branch || stage == :init
207
-
208
- parse_opts.(args)
209
- cmd << "-j#{ENV.fetch('REPO_JOBS', ::Rake::CpuCounter.count)}"
210
- cmd << '--fail-fast' if failfast
211
- puts if newline && stage != :init
212
- begin
213
- shell("repo sync #{cmd.join(' ')}", chdir: root, exception: failfast)
214
- rescue StandardError => e
215
- emphasize(e, title: "rake stash repo:#{stage || 'sync'}")
216
- raise
217
- end
218
- end
219
- end
220
- end
221
-
222
- Workspace.project_kind.each { |obj| obj.populate(self, **kwargs) }
223
-
224
- if !series[:build].empty?
225
- init = [:depend, dev? && !series[:refresh].empty? ? :refresh : :build]
226
-
227
- task default: default || init[1]
228
-
229
- desc 'init'
230
- task init: init
231
- elsif default && !series[default].empty?
232
- task default: default
233
- end
234
-
235
- series.each do |key, items|
236
- next if items.empty?
237
-
238
- unless (valid = parallel.include?(key))
239
- group = key.to_s
240
- valid = parallel.include?(group.split(':').first.to_sym) if group.include?(':')
241
- end
242
- if valid && items.size > 1
243
- desc "#{key} (thread)"
244
- multitask key => items
245
-
246
- desc "#{key} (sync)"
247
- task "#{key}:sync": items
248
- else
249
- desc key.to_s
250
- task key => items
251
- end
252
- end
253
-
254
- yield self if block_given?
255
- end
256
-
257
- def repo(url, manifest = 'latest', run: nil, dev: nil, prod: nil)
258
- @manifest_url = url
259
- @manifest = manifest
260
- script = case (val = env('REPO_BUILD'))
261
- when 'verbose'
262
- run ? "#{run}:verbose" : nil
263
- when 'silent'
264
- @verbose = false
265
- @warning = false
266
- run
267
- else
268
- val || run
269
- end
270
- case env('REPO_WARN')
271
- when '0'
272
- @warning = false
273
- when '1'
274
- @warning = true
275
- end
276
- script ? run(script, dev: bool_match(env('REPO_DEV'), dev), prod: bool_match(env('REPO_DEV'), prod)) : self
277
- end
278
-
279
- def run(script, group: nil, ref: nil, **kwargs)
280
- if group || ref
281
- script_command :run, script, group, ref
282
- else
283
- @script[:build] = script
284
- @script[:dev] = kwargs[:dev]
285
- @script[:prod] = kwargs[:prod]
286
- self
287
- end
288
- end
289
-
290
- def depend(script, group: nil, ref: nil)
291
- script_command :depend, script, group, ref
292
- end
293
-
294
- def clean(script, group: nil, ref: nil)
295
- script_command :clean, script, group, ref
296
- end
297
-
298
- def doc(script, group: nil, ref: nil)
299
- script_command :doc, script, group, ref
300
- end
301
-
302
- def test(script, group: nil, ref: nil)
303
- script_command :test, script, group, ref
304
- end
305
-
306
- def add(name, path = nil, **kwargs)
307
- path = root_path((path || name).to_s)
308
- ref = kwargs[:ref]
309
- project = if !ref.is_a?(::Class)
310
- Workspace.find(path: path, ref: ref)
311
- elsif ref < Project::Base
312
- ref
313
- end
314
- instance = (project || Project::Base).new(name, path, self, **kwargs)
315
- @project[n = name.to_sym] = instance
316
- __get__(:project)[n] = instance unless kwargs[:private]
317
- self
318
- end
319
-
320
- def compose(name, &blk)
321
- namespace(name, &blk)
322
- self
323
- end
324
-
325
- def apply(&blk)
326
- instance_eval(&blk)
327
- self
328
- end
329
-
330
- def style(name, *args, target: nil, empty: false)
331
- data = nil
332
- if target
333
- as_a(target).each_with_index do |val, i|
334
- if i == 0
335
- break unless (data = __get__(:theme)[val.to_sym])
336
- else
337
- data = data[val.to_sym] ||= {}
338
- end
339
- end
340
- return unless data
341
- end
342
- apply_style(data || theme, name, *args, empty: empty)
343
- self
344
- end
345
-
346
- def script(group: nil, ref: nil)
347
- if group || ref
348
- (group && @script[:group][group.to_sym]) || (ref && @script[:ref][ref.to_sym])
349
- else
350
- @script[:build]
351
- end
352
- end
353
-
354
- def env(key, equals: nil, ignore: nil)
355
- ret = ENV.fetch("#{key}_#{main.gsub(/[^\w]/, '_').upcase}", ENV[key]).to_s
356
- return ret == equals.to_s if equals
357
-
358
- ret.empty? || as_a(ignore).any? { |val| ret == val.to_s } ? nil : ret
359
- end
360
-
361
- def read_manifest(*)
362
- require 'rexml/document'
363
- file = root_path('.repo/manifest.xml')
364
- return unless file.exist?
365
-
366
- doc = REXML::Document.new(file.read)
367
- doc.elements['manifest/include'].attributes['name']&.sub('.xml', '')
368
- end
369
-
370
- def root_path(*args)
371
- root.join(*args)
372
- end
373
-
374
- def home_path(*args)
375
- home.join(*args)
376
- end
377
-
378
- def find_base(obj)
379
- Workspace.project_kind.find { |proj| obj.instance_of?(proj) }
380
- end
381
-
382
- def bool_match(val, pat)
383
- case val
384
- when nil, ''
385
- pat.is_a?(::Regexp) ? pat : nil
386
- when '0'
387
- false
388
- when '1'
389
- true
390
- else
391
- Regexp.new(val)
392
- end
393
- end
394
-
395
- def to_s
396
- root.to_s
397
- end
398
-
399
- def inspect
400
- "#<#{self.class}: #{main} => #{self}>"
401
- end
402
-
403
- def enabled?
404
- repo? || @project.any? { |_, proj| proj.enabled? }
405
- end
406
-
407
- def repo?
408
- !manifest_url.nil? && (empty?(root) || @override)
409
- end
410
-
411
- def multitask?
412
- ::Rake::Task.tasks.any? do |item|
413
- next unless item.already_invoked
414
-
415
- item.name.end_with?(':sync') || (!item.name.include?(':') && !item.name.start_with?('all', 'init'))
416
- end
417
- end
418
-
419
- def empty?(dir, init: true)
420
- return true if dir.empty? || (init && dir.join('.repo').directory?)
421
- return true if dir.children.size == 1 && dir.join(dir.children.first).to_s == __FILE__
422
-
423
- dir == root && !env('REPO_ROOT').nil? && root.children.none? do |path|
424
- path.directory? && !path.basename.to_s.start_with?('.') && path.to_s != home.to_s
425
- end
426
- end
427
-
428
- def task_defined?(obj, key)
429
- obj.is_a?(TASK_BASE[key])
430
- end
431
-
432
- def dev?(script: nil, pat: nil, global: nil)
433
- with?(:dev, script: script, pat: pat, global: (pat.nil? && global.nil?) || global)
434
- end
435
-
436
- def prod?(script: nil, pat: nil, global: false)
437
- return false if global && (@script[:dev] == true || !@script[:prod])
438
-
439
- with?(:prod, script: script, pat: pat, global: global)
440
- end
441
-
442
- protected
443
-
444
- def confirm(msg, agree: 'Y', cancel: 'N', attempts: 5, timeout: 15)
445
- require 'readline'
446
- require 'timeout'
447
- Timeout.timeout(ENV.fetch('REPO_TIMEOUT', timeout).to_i) do
448
- ret = false
449
- begin
450
- while (ch = Readline.readline(msg, true))
451
- case ch.chomp.upcase
452
- when agree
453
- ret = true
454
- break
455
- when cancel
456
- break
457
- end
458
- attempts -= 1
459
- exit 1 unless attempts >= 0
460
- end
461
- rescue Interrupt
462
- puts
463
- exit 0
464
- else
465
- ret
466
- end
467
- end
468
- end
469
-
470
- private
471
-
472
- def script_command(task, val, group, ref)
473
- if group
474
- label = :group
475
- items = as_a(group)
476
- else
477
- label = :ref
478
- items = as_a(ref)
479
- end
480
- items.each { |name| (@script[label][name.to_sym] ||= {})[task] = val }
481
- self
482
- end
483
-
484
- def repo_prompt(path)
485
- return false unless path.directory?
486
-
487
- confirm "#{log_title(:warn)} \"#{sub_style(path, :bold)}\" is not empty. Continue with installation? [y/N] "
488
- end
489
-
490
- def with?(state, script: nil, pat: nil, global: false)
491
- pat = @script[state] if pat.nil? && global
492
- return pat == true unless pat.is_a?(::Regexp)
493
- return false if !script && !global
494
-
495
- pat.match?(script || @script[:build])
496
- end
497
- end
498
- end
499
- end
500
-
501
- Repo = Squared::Repo