squared 0.4.13 → 0.4.15
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/CHANGELOG.md +105 -0
- data/README.ruby.md +1 -1
- data/lib/squared/common/base.rb +5 -2
- data/lib/squared/common/format.rb +8 -2
- data/lib/squared/common/prompt.rb +1 -1
- data/lib/squared/common/system.rb +21 -14
- data/lib/squared/common/utils.rb +7 -3
- data/lib/squared/config.rb +6 -5
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +39 -29
- data/lib/squared/workspace/project/base.rb +115 -71
- data/lib/squared/workspace/project/docker.rb +12 -10
- data/lib/squared/workspace/project/git.rb +88 -57
- data/lib/squared/workspace/project/node.rb +37 -41
- data/lib/squared/workspace/project/python.rb +248 -47
- data/lib/squared/workspace/project/ruby.rb +135 -105
- data/lib/squared/workspace/project/support/class.rb +37 -1
- data/lib/squared/workspace/repo.rb +2 -1
- data/lib/squared/workspace/series.rb +8 -8
- data/lib/squared/workspace/support/data.rb +2 -2
- data/lib/squared/workspace.rb +8 -0
- metadata +1 -1
@@ -8,7 +8,7 @@ module Squared
|
|
8
8
|
DIR_PYTHON = (DEP_PYTHON + %w[README.rst]).freeze
|
9
9
|
OPT_PYTHON = {
|
10
10
|
common: %w[b B d E h i I O OO P q s S u v x c=q m=b W=b X=q check-hash-based-pycs=b].freeze,
|
11
|
-
build: %w[n|no-isolation s|sdist v|verbose w|wheel
|
11
|
+
build: %w[n|no-isolation s|sdist x|skip-dependency-check v|verbose w|wheel C|config-setting=q installer=b
|
12
12
|
o|outdir=p].freeze,
|
13
13
|
venv: %w[clear copies symlinks system-site-packages upgrade upgrade-deps without-scm-ignore-files without-pip
|
14
14
|
prompt=q].freeze
|
@@ -28,11 +28,18 @@ module Squared
|
|
28
28
|
freeze: %w[all exclude-editable l|local user exclude=b path=p r|requirement=p].freeze
|
29
29
|
}.freeze
|
30
30
|
OPT_POETRY = {
|
31
|
-
common: %w[ansi no-ansi no-cache n|no-interaction no-plugins
|
31
|
+
common: %w[ansi no-ansi no-cache n|no-interaction no-plugins q|quiet v|verbose P|project=p].freeze,
|
32
32
|
build: %w[clean config-settings=qq f|format=b o|output=p].freeze,
|
33
|
-
publish: %w[build dry-run
|
33
|
+
publish: %w[build dry-run skip-existing cert=p client-cert=p dist-dir=p p|password=b r|repository=b
|
34
34
|
u|username=b].freeze
|
35
35
|
}.freeze
|
36
|
+
OPT_PDM = {
|
37
|
+
common: %w[I|ignore-python no-cache n|non-interactive].freeze,
|
38
|
+
build: %w[C=bm no-clean no-isolation no-sdist no-wheel quiet verbose config-setting=q d|dest=p p|project=p
|
39
|
+
k|skip=b].freeze,
|
40
|
+
publish: %w[no-build no-very-ssl quiet S|sign skip-existing verbose ca-certs=p c|comment=q d|dest=p identity=b
|
41
|
+
p|password=q p|project=p r|repository=q k|skip=b u|username=b].freeze
|
42
|
+
}.freeze
|
36
43
|
OPT_HATCH = {
|
37
44
|
common: %w[color interactive no-color no-interactive cache-dir=p config=p data-dir=p e|env=b p|project=b
|
38
45
|
q|quiet v|verbose].freeze,
|
@@ -41,11 +48,11 @@ module Squared
|
|
41
48
|
p|publisher=b r|repo=b u|user=q].freeze
|
42
49
|
}.freeze
|
43
50
|
OPT_TWINE = {
|
44
|
-
publish: %w[attestations disable-progress-bar non-interactive skip-existing verbose
|
45
|
-
|
51
|
+
publish: %w[attestations disable-progress-bar non-interactive s|sign skip-existing verbose cert=p
|
52
|
+
client-cert=p c|comment=q config-file=p i|identity=b p|password=q r|repository=b repository-url=q
|
46
53
|
sign-with=b u|username=q].freeze
|
47
54
|
}.freeze
|
48
|
-
private_constant :DEP_PYTHON, :DIR_PYTHON, :OPT_PYTHON, :OPT_PIP, :OPT_POETRY, :OPT_HATCH, :OPT_TWINE
|
55
|
+
private_constant :DEP_PYTHON, :DIR_PYTHON, :OPT_PYTHON, :OPT_PIP, :OPT_POETRY, :OPT_PDM, :OPT_HATCH, :OPT_TWINE
|
49
56
|
|
50
57
|
class << self
|
51
58
|
def populate(*); end
|
@@ -71,7 +78,7 @@ module Squared
|
|
71
78
|
|
72
79
|
attr_reader :venv, :editable
|
73
80
|
|
74
|
-
def initialize(*,
|
81
|
+
def initialize(*, editable: '.', verbose: nil, **kwargs)
|
75
82
|
super
|
76
83
|
if @pass.include?(Python.ref)
|
77
84
|
initialize_ref Python.ref
|
@@ -80,18 +87,20 @@ module Squared
|
|
80
87
|
initialize_build(Python.ref, **kwargs)
|
81
88
|
initialize_env(**kwargs)
|
82
89
|
end
|
83
|
-
dependfile_set DEP_PYTHON
|
84
90
|
@verbose = verbose.size if verbose.is_a?(String) && verbose.match?(/\Av+\z/)
|
91
|
+
dependfile_set DEP_PYTHON
|
85
92
|
editable_set editable
|
86
|
-
venv_set venv
|
93
|
+
venv_set kwargs[:venv]
|
87
94
|
end
|
88
95
|
|
89
96
|
subtasks({
|
90
97
|
'venv' => %i[exec create remove show].freeze,
|
91
98
|
'pip' => %i[uninstall freeze].freeze,
|
92
99
|
'install' => %i[user force upgrade target editable].freeze,
|
93
|
-
'
|
94
|
-
'
|
100
|
+
'outdated' => %i[major minor patch].freeze,
|
101
|
+
'build' => %i[python poetry pdm hatch].freeze,
|
102
|
+
'publish' => %i[poetry pdm hatch twine].freeze,
|
103
|
+
'run' => nil,
|
95
104
|
'exec' => nil
|
96
105
|
})
|
97
106
|
|
@@ -109,6 +118,62 @@ module Squared
|
|
109
118
|
|
110
119
|
if flags.nil?
|
111
120
|
case action
|
121
|
+
when 'run'
|
122
|
+
next unless pyprojectfile
|
123
|
+
|
124
|
+
format_desc action, nil, "script+|#{indexchar}index+|#,pattern*"
|
125
|
+
task action, [:command] do |_, args|
|
126
|
+
found = 0
|
127
|
+
['tool.poetry.scripts', 'tool.pdm.scripts', 'project.scripts'].each_with_index do |table, index|
|
128
|
+
next if (list = read_pyproject(table)).empty?
|
129
|
+
|
130
|
+
if args.command == '#'
|
131
|
+
format_list(list, "run[#{indexchar}N]", 'scripts', grep: args.extras, from: pyprojectfile)
|
132
|
+
found |= 1
|
133
|
+
else
|
134
|
+
args.to_a.each do |val|
|
135
|
+
if (n, = indexitem(val))
|
136
|
+
if (script, = list[n - 1])
|
137
|
+
case index
|
138
|
+
when 0
|
139
|
+
script = session_output 'poetry', 'run', script
|
140
|
+
when 1
|
141
|
+
script = pdm_session 'run', script
|
142
|
+
else
|
143
|
+
venv_init
|
144
|
+
end
|
145
|
+
found |= 1
|
146
|
+
run(script, from: :run)
|
147
|
+
elsif exception
|
148
|
+
indexerror n, list
|
149
|
+
else
|
150
|
+
found |= 2
|
151
|
+
log.warn "run script #{n} of #{list.size} (out of range)"
|
152
|
+
end
|
153
|
+
else
|
154
|
+
case index
|
155
|
+
when 0
|
156
|
+
found |= 1
|
157
|
+
run(session_output('poetry', 'run', val), from: :run)
|
158
|
+
when 1
|
159
|
+
found |= 1
|
160
|
+
run(pdm_session('run', val), from: :run)
|
161
|
+
else
|
162
|
+
raise_error("script: #{val}", hint: 'unknown') if exception
|
163
|
+
found |= 2
|
164
|
+
log.warn "run script \"#{val}\" (not indexed)"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
break
|
170
|
+
end
|
171
|
+
unless found.anybits?(1)
|
172
|
+
puts log_message(found == 0 ? Logger::INFO : Logger.WARN,
|
173
|
+
"no scripts #{found == 0 ? 'found' : 'executed'}",
|
174
|
+
subject: name, hint: pyprojectfile)
|
175
|
+
end
|
176
|
+
end
|
112
177
|
when 'exec'
|
113
178
|
format_desc action, nil, 'command|:,args*'
|
114
179
|
task action do |_, args|
|
@@ -123,7 +188,7 @@ module Squared
|
|
123
188
|
end
|
124
189
|
args.join(' ')
|
125
190
|
end
|
126
|
-
|
191
|
+
shell(cmd, name: :exec, chdir: path)
|
127
192
|
end
|
128
193
|
end
|
129
194
|
else
|
@@ -214,14 +279,30 @@ module Squared
|
|
214
279
|
depend flag, args.to_a
|
215
280
|
end
|
216
281
|
end
|
282
|
+
when 'outdated'
|
283
|
+
format_desc action, flag, 'eager?,user?'
|
284
|
+
task flag do |_, args|
|
285
|
+
outdated flag, args.to_a
|
286
|
+
end
|
217
287
|
when 'build'
|
288
|
+
case flag
|
289
|
+
when :poetry
|
290
|
+
next unless build_backend == 'poetry.core.masonry.api'
|
291
|
+
when :pdm
|
292
|
+
next unless build_backend == 'pdm.backend'
|
293
|
+
when :hatch
|
294
|
+
next unless build_backend == 'hatchling.build'
|
295
|
+
end
|
218
296
|
format_desc(action, flag, 'opts*', after: case flag
|
219
297
|
when :python then 'srcdir?'
|
298
|
+
when :poetry then 'output?'
|
299
|
+
when :pdm then 'dest?'
|
220
300
|
when :hatch then 'location?'
|
221
301
|
end)
|
222
302
|
task flag do |_, args|
|
223
303
|
build! flag, args.to_a
|
224
304
|
end
|
305
|
+
break unless flag == :python
|
225
306
|
when 'publish'
|
226
307
|
format_desc(action, flag, 'opts*', after: case flag
|
227
308
|
when :hatch then 'artifacts?'
|
@@ -269,7 +350,7 @@ module Squared
|
|
269
350
|
end
|
270
351
|
end
|
271
352
|
|
272
|
-
def outdated(
|
353
|
+
def outdated(flag = nil, opts = [], sync: invoked_sync?('outdated'))
|
273
354
|
cmd = pip_session 'list', '--outdated'
|
274
355
|
append_global
|
275
356
|
cmd = session_done cmd
|
@@ -279,28 +360,35 @@ module Squared
|
|
279
360
|
print_item banner if sync
|
280
361
|
start = 0
|
281
362
|
found = 0
|
282
|
-
major =
|
363
|
+
major = []
|
364
|
+
minor = []
|
365
|
+
patch = []
|
283
366
|
pwd_set(from: :outdated) do
|
284
367
|
buffer = []
|
285
368
|
out = ->(val) { sync ? puts(val) : buffer << val }
|
286
369
|
IO.popen(runenv || {}, cmd).each do |line|
|
287
|
-
next if line.match?(/^[
|
370
|
+
next if line.match?(/^[ -]+$/)
|
288
371
|
|
289
372
|
if start > 0
|
290
373
|
unless stdin?
|
291
|
-
|
292
|
-
next unless
|
374
|
+
cur, lat = line.scan(SEM_VER)
|
375
|
+
next unless cur && lat
|
293
376
|
|
294
377
|
latest = lat.join
|
295
378
|
current = cur.join
|
296
379
|
semver cur
|
297
380
|
semver lat
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
381
|
+
name = line.split(' ', 2).first
|
382
|
+
type = if semmajor?(cur, lat)
|
383
|
+
major << name
|
384
|
+
2
|
385
|
+
elsif cur[2] == lat[2]
|
386
|
+
patch << name
|
387
|
+
0
|
388
|
+
else
|
389
|
+
minor << name
|
390
|
+
1
|
391
|
+
end
|
304
392
|
if type == 0
|
305
393
|
styles = color(:yellow)
|
306
394
|
else
|
@@ -334,7 +422,18 @@ module Squared
|
|
334
422
|
puts buffer
|
335
423
|
end
|
336
424
|
if found > 0
|
337
|
-
|
425
|
+
print_status(major.size, minor.size, patch.size, from: :outdated)
|
426
|
+
pkg = case flag
|
427
|
+
when :major
|
428
|
+
major + minor + patch
|
429
|
+
when :minor
|
430
|
+
minor + patch
|
431
|
+
when :patch
|
432
|
+
patch
|
433
|
+
end
|
434
|
+
unless !pkg || pkg.empty?
|
435
|
+
install(:upgrade, pkg, strategy: opts.include?('eager') ? 'eager' : nil, user: opts.include?('user'))
|
436
|
+
end
|
338
437
|
elsif start == 0
|
339
438
|
puts 'No updates were found'
|
340
439
|
end
|
@@ -342,7 +441,7 @@ module Squared
|
|
342
441
|
on :last, :outdated
|
343
442
|
end
|
344
443
|
|
345
|
-
def install(flag, opts = [], strategy: nil)
|
444
|
+
def install(flag, opts = [], strategy: nil, user: nil)
|
346
445
|
cmd = pip_session 'install'
|
347
446
|
out = append_pip(flag, opts, from: :install)
|
348
447
|
case flag
|
@@ -352,6 +451,7 @@ module Squared
|
|
352
451
|
when :upgrade
|
353
452
|
raise_error('no packages listed', hint: flag) if out.empty?
|
354
453
|
cmd << '--upgrade'
|
454
|
+
cmd << '--user' if user
|
355
455
|
cmd << basic_option('upgrade-strategy', strategy) if strategy
|
356
456
|
append_value out
|
357
457
|
end
|
@@ -366,6 +466,9 @@ module Squared
|
|
366
466
|
when :poetry
|
367
467
|
cmd = poetry_session 'build'
|
368
468
|
list = OPT_POETRY[:build] + OPT_POETRY[:common]
|
469
|
+
when :pdm
|
470
|
+
cmd, opts = pdm_session('build', opts: opts)
|
471
|
+
list = OPT_PDM[:build]
|
369
472
|
when :hatch
|
370
473
|
cmd, opts = hatch_session('build', opts: opts)
|
371
474
|
list = OPT_HATCH[:build]
|
@@ -373,7 +476,7 @@ module Squared
|
|
373
476
|
srcdir = nil
|
374
477
|
op = OptionPartition.new(opts, list, cmd, project: self, single: singleopt(flag))
|
375
478
|
op.each do |opt|
|
376
|
-
if !srcdir && basepath(opt).exist? && projectpath?(opt)
|
479
|
+
if !srcdir && basepath(opt.chomp('*')).exist? && projectpath?(opt.chomp('*'))
|
377
480
|
srcdir = opt
|
378
481
|
else
|
379
482
|
op.found << opt
|
@@ -381,12 +484,13 @@ module Squared
|
|
381
484
|
end
|
382
485
|
op.swap
|
383
486
|
case flag
|
384
|
-
when :poetry
|
487
|
+
when :poetry, :pdm
|
385
488
|
if srcdir
|
386
|
-
|
489
|
+
args = flag == :pdm ? ['d', 'dest'] : ['o', 'output']
|
490
|
+
if op.arg?(*args)
|
387
491
|
op.extras << srcdir
|
388
492
|
else
|
389
|
-
op << quote_option(
|
493
|
+
op << quote_option(args.last, path + srcdir)
|
390
494
|
end
|
391
495
|
srcdir = nil
|
392
496
|
end
|
@@ -408,21 +512,35 @@ module Squared
|
|
408
512
|
when :poetry
|
409
513
|
poetry_session 'publish'
|
410
514
|
list = OPT_POETRY[:publish] + OPT_POETRY[:common]
|
411
|
-
when :
|
412
|
-
|
413
|
-
list =
|
515
|
+
when :pdm
|
516
|
+
opts = pdm_session('publish', opts: opts).last
|
517
|
+
list = OPT_PDM[:publish]
|
414
518
|
when :hatch
|
415
519
|
opts = hatch_session('publish', opts: opts).last
|
416
520
|
list = OPT_HATCH[:publish]
|
521
|
+
when :twine
|
522
|
+
session 'twine', 'upload'
|
523
|
+
list = OPT_TWINE[:publish]
|
417
524
|
end
|
418
525
|
op = OptionPartition.new(opts, list, @session, project: self, single: singleopt(flag))
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
526
|
+
dist = lambda do
|
527
|
+
(path + 'dist').tap do |dir|
|
528
|
+
raise_error('no source files found', hint: dir) unless dir.directory? && !dir.empty?
|
529
|
+
end
|
423
530
|
end
|
424
|
-
|
425
|
-
|
531
|
+
case flag
|
532
|
+
when :hatch, :twine
|
533
|
+
if op.empty?
|
534
|
+
op.extras << "#{dist.call}/*"
|
535
|
+
else
|
536
|
+
op.map! { |val| path + val }
|
537
|
+
end
|
538
|
+
op.append
|
539
|
+
else
|
540
|
+
dist.call unless op.arg?(*(flag == :poetry ? ['dist-dir'] : ['d', 'dest']))
|
541
|
+
op.clear(pass: false)
|
542
|
+
end
|
543
|
+
run(from: :"#{flag}:publish", interactive: "Publish #{sub_style(project, styles: theme[:active])}")
|
426
544
|
end
|
427
545
|
|
428
546
|
def pip(flag, opts = [])
|
@@ -491,11 +609,19 @@ module Squared
|
|
491
609
|
ret
|
492
610
|
end
|
493
611
|
|
612
|
+
def pdm_session(*cmd, opts: nil)
|
613
|
+
create_session(*cmd, name: 'pdm', common: OPT_PDM[:common], opts: opts)
|
614
|
+
end
|
615
|
+
|
494
616
|
def hatch_session(*cmd, opts: nil)
|
495
|
-
|
617
|
+
create_session(*cmd, name: 'hatch', common: OPT_HATCH[:common], opts: opts)
|
618
|
+
end
|
619
|
+
|
620
|
+
def create_session(*cmd, name:, common:, opts: nil)
|
621
|
+
return session(name, *preopts, *cmd, path: venv.nil?) unless opts
|
496
622
|
|
497
|
-
op = OptionPartition.new(opts,
|
498
|
-
ret = session(
|
623
|
+
op = OptionPartition.new(opts, common, project: self, single: singleopt)
|
624
|
+
ret = session(name, *op.to_a, *cmd, path: venv.nil?)
|
499
625
|
[ret, op.extras]
|
500
626
|
end
|
501
627
|
|
@@ -573,13 +699,77 @@ module Squared
|
|
573
699
|
append_nocolor(target: target)
|
574
700
|
end
|
575
701
|
|
576
|
-
def
|
577
|
-
@
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
702
|
+
def build_backend
|
703
|
+
@build_backend ||= read_pyproject('build-system', 'build-backend') || ''
|
704
|
+
end
|
705
|
+
|
706
|
+
def read_pyproject(table, key = nil)
|
707
|
+
return [] unless (file = pyprojectfile)
|
708
|
+
|
709
|
+
unless (ret = (@pyproject ||= {})[table])
|
710
|
+
ret = []
|
711
|
+
start = /^\s*\[#{Regexp.escape(table)}\]\s*$/
|
712
|
+
ch = nil
|
713
|
+
found = false
|
714
|
+
File.foreach(file) do |line|
|
715
|
+
if found
|
716
|
+
break if line.match?(/^\s*\[[\w.-]+\]\s*$/)
|
717
|
+
|
718
|
+
if ch
|
719
|
+
val = line.rstrip
|
720
|
+
case ch
|
721
|
+
when '}', ']'
|
722
|
+
ch = nil if val.end_with?(ch)
|
723
|
+
val = "\n#{val}"
|
724
|
+
else
|
725
|
+
if val.chomp!(ch)
|
726
|
+
ch = nil
|
727
|
+
else
|
728
|
+
val = line
|
729
|
+
end
|
730
|
+
end
|
731
|
+
ret.last[1] += val
|
732
|
+
elsif (data = line.match(/^\s*(\S+)\s*=\s*([+-]?[\d.]+|true|false|("""|'''|["'\[{])(.*?))\s*$/))
|
733
|
+
if (val = data[4])
|
734
|
+
case (ch = data[3])
|
735
|
+
when '{', '['
|
736
|
+
val = "#{ch}#{val}"
|
737
|
+
ch = ch == '{' ? '}' : ']'
|
738
|
+
ch = nil if val.end_with?(ch)
|
739
|
+
else
|
740
|
+
if val.chomp!(ch)
|
741
|
+
ch = nil
|
742
|
+
elsif ch.size == 1
|
743
|
+
next
|
582
744
|
end
|
745
|
+
end
|
746
|
+
else
|
747
|
+
val = case (val = data[2])
|
748
|
+
when 'true'
|
749
|
+
true
|
750
|
+
when 'false'
|
751
|
+
false
|
752
|
+
else
|
753
|
+
val.include?('.') ? val.to_f : val.to_i
|
754
|
+
end
|
755
|
+
end
|
756
|
+
ret << [data[1], val]
|
757
|
+
end
|
758
|
+
else
|
759
|
+
found = line.match?(start)
|
760
|
+
end
|
761
|
+
end
|
762
|
+
@pyproject[table] = ret
|
763
|
+
end
|
764
|
+
return ret.find { |val| val[0] == key }&.last if key
|
765
|
+
|
766
|
+
ret
|
767
|
+
end
|
768
|
+
|
769
|
+
def pyprojectfile
|
770
|
+
return unless (ret = basepath(DEP_PYTHON[2])).exist?
|
771
|
+
|
772
|
+
ret
|
583
773
|
end
|
584
774
|
|
585
775
|
def singleopt(flag = nil)
|
@@ -622,7 +812,18 @@ module Squared
|
|
622
812
|
@venv&.join(workspace.windows? ? 'Scripts' : 'bin')
|
623
813
|
end
|
624
814
|
|
815
|
+
def editable_set(val)
|
816
|
+
@editable = case val
|
817
|
+
when '.', Pathname
|
818
|
+
val
|
819
|
+
when String
|
820
|
+
Pathname.new(editable)
|
821
|
+
end
|
822
|
+
end
|
823
|
+
|
625
824
|
def venv_set(val)
|
825
|
+
return unless val
|
826
|
+
|
626
827
|
if val.is_a?(Array)
|
627
828
|
val, *opts = val
|
628
829
|
@venvopts = opts
|