squared 0.0.4 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
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