squared 0.4.3 → 0.4.5
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 +56 -0
- data/README.ruby.md +131 -61
- data/lib/squared/common/format.rb +2 -6
- data/lib/squared/common/shell.rb +2 -1
- data/lib/squared/common/utils.rb +8 -5
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +12 -1
- data/lib/squared/workspace/project/base.rb +121 -46
- data/lib/squared/workspace/project/docker.rb +125 -58
- data/lib/squared/workspace/project/git.rb +59 -66
- data/lib/squared/workspace/project/node.rb +25 -27
- data/lib/squared/workspace/project/python.rb +214 -79
- data/lib/squared/workspace/project/ruby.rb +96 -40
- data/lib/squared/workspace/repo.rb +1 -1
- metadata +3 -3
@@ -4,13 +4,15 @@ module Squared
|
|
4
4
|
module Workspace
|
5
5
|
module Project
|
6
6
|
class Python < Git
|
7
|
-
REQUIREMENTS = %w[requirements.txt pyproject.toml setup.cfg
|
7
|
+
REQUIREMENTS = %w[requirements.txt poetry.lock pyproject.toml setup.cfg].freeze
|
8
8
|
SETUPTOOLS = %w[setup.py pyproject.toml].freeze
|
9
9
|
DIR_PYTHON = (REQUIREMENTS + SETUPTOOLS).freeze
|
10
10
|
OPT_PYTHON = {
|
11
11
|
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,
|
12
12
|
build: %w[n|no-isolation s|sdist v|verbose w|wheel x|skip-dependency-check C|config-setting=q installer=b
|
13
|
-
o|outdir=p].freeze
|
13
|
+
o|outdir=p].freeze,
|
14
|
+
venv: %w[clear copies symlinks system-site-packages upgrade upgrade-deps without-scm-ignore-files
|
15
|
+
without-pip prompt=q].freeze
|
14
16
|
}.freeze
|
15
17
|
OPT_PIP = {
|
16
18
|
common: %w[debug disable-pip-version-check isolated no-cache-dir no-color no-input no-python-version-warning
|
@@ -22,7 +24,9 @@ module Squared
|
|
22
24
|
config-settings=q c|constraint=p e|editable=b? extra-index-url=q f|find-links=q global-option=q
|
23
25
|
implementation=b i|index-url=q no-binary=q only-binary=q platform=q prefix=p progress-bar=b
|
24
26
|
python-version=q report=p r|requirement=p root=p root-user-action=b src=p t|target=p
|
25
|
-
upgrade-strategy=b].freeze
|
27
|
+
upgrade-strategy=b].freeze,
|
28
|
+
uninstall: %w[break-system-packages y|yes r|requirement=p root-user-action=b].freeze,
|
29
|
+
freeze: %w[all exclude-editable l|local user exclude=b path=p r|requirement=p].freeze
|
26
30
|
}.freeze
|
27
31
|
OPT_POETRY = {
|
28
32
|
common: %w[ansi no-ansi no-cache n|no-interaction no-plugins P|project=p q|quiet v|verbose].freeze,
|
@@ -67,7 +71,9 @@ module Squared
|
|
67
71
|
end
|
68
72
|
end
|
69
73
|
|
70
|
-
|
74
|
+
attr_reader :venv
|
75
|
+
|
76
|
+
def initialize(*, venv: nil, **kwargs)
|
71
77
|
super
|
72
78
|
if @pass.include?(Python.ref)
|
73
79
|
initialize_ref Python.ref
|
@@ -78,13 +84,16 @@ module Squared
|
|
78
84
|
end
|
79
85
|
@dependindex = REQUIREMENTS.index { |file| basepath(file).exist? }
|
80
86
|
@dependfile = basepath(REQUIREMENTS[@dependindex || 0])
|
87
|
+
venv_set venv if venv
|
81
88
|
end
|
82
89
|
|
83
|
-
|
90
|
+
subtasks({
|
91
|
+
'venv' => %i[create remove show].freeze,
|
92
|
+
'pip' => %i[uninstall freeze].freeze,
|
84
93
|
'install' => %i[user force upgrade target editable].freeze,
|
85
94
|
'build' => %i[python poetry hatch].freeze,
|
86
95
|
'publish' => %i[poetry twine hatch].freeze
|
87
|
-
}
|
96
|
+
})
|
88
97
|
|
89
98
|
def ref
|
90
99
|
Python.ref
|
@@ -101,6 +110,51 @@ module Squared
|
|
101
110
|
namespace action do
|
102
111
|
flags.each do |flag|
|
103
112
|
case action
|
113
|
+
when 'venv'
|
114
|
+
if flag == :create
|
115
|
+
format_desc action, flag, 'dir,opts*'
|
116
|
+
task flag, [:dir] do |_, args|
|
117
|
+
dir = param_guard(action, flag, args: args, key: :dir)
|
118
|
+
opts = python_session('-m venv', opts: args.extras).last
|
119
|
+
opts = option_sanitize(opts, OPT_PYTHON[:venv]).first
|
120
|
+
append_value(dir = basepath(dir), delim: true)
|
121
|
+
option_clear(opts, pass: false)
|
122
|
+
run(exception: true)
|
123
|
+
puts(dir.directory? ? "Success: #{dir}" : 'Failed')
|
124
|
+
end
|
125
|
+
elsif venv
|
126
|
+
case flag
|
127
|
+
when :remove
|
128
|
+
next unless projectpath?(venv)
|
129
|
+
|
130
|
+
format_desc action, flag, 'c|reate?,d|epend?'
|
131
|
+
task flag do |_, args|
|
132
|
+
venv.rmtree(verbose: true)
|
133
|
+
venv_init if has_value?(%w[c create], args.to_a)
|
134
|
+
depend if has_value?(%w[d depend], args.to_a)
|
135
|
+
end
|
136
|
+
when :show
|
137
|
+
format_desc action, flag
|
138
|
+
task flag do
|
139
|
+
puts venv
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
when 'pip'
|
144
|
+
case flag
|
145
|
+
when :freeze
|
146
|
+
format_desc action, flag, 'file?=requirements.txt,opts*'
|
147
|
+
task flag do |_, args|
|
148
|
+
if (file = pip(flag, args.to_a)) && verbose
|
149
|
+
puts File.read(file)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
when :uninstall
|
153
|
+
format_desc action, flag, 'package+,opts*'
|
154
|
+
task flag do |_, args|
|
155
|
+
pip flag, args.to_a
|
156
|
+
end
|
157
|
+
end
|
104
158
|
when 'install'
|
105
159
|
format_desc(action, flag, 'opts*', before: case flag
|
106
160
|
when :target
|
@@ -167,23 +221,30 @@ module Squared
|
|
167
221
|
if @depend && !flag
|
168
222
|
super
|
169
223
|
elsif outdated?
|
224
|
+
venv_init
|
170
225
|
workspace.rev_clear name
|
171
|
-
if !flag && dependtype ==
|
172
|
-
cmd = session 'poetry', 'install'
|
226
|
+
if !flag && dependtype == 2
|
227
|
+
cmd = session 'poetry', 'install', '-n'
|
228
|
+
cmd << '--no-ansi' unless verbose
|
173
229
|
cmd << '--no-root' if option('no-root')
|
174
230
|
else
|
175
231
|
cmd = pip_session 'install'
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
232
|
+
if flag
|
233
|
+
case flag
|
234
|
+
when :user
|
235
|
+
cmd << '--user'
|
236
|
+
when :target
|
237
|
+
cmd << quote_option('target', basepath(target))
|
238
|
+
when :force
|
239
|
+
cmd << '--force-reinstall'
|
240
|
+
end
|
241
|
+
append_pip(flag, opts, from: :install)
|
183
242
|
else
|
243
|
+
if (val = option('editable', 'e'))
|
244
|
+
cmd << quote_option('e', editable(val))
|
245
|
+
end
|
184
246
|
append_global
|
185
247
|
end
|
186
|
-
append_pip(flag, opts, from: :install) if flag
|
187
248
|
if dependtype == 1 && !session_arg?('e', 'editable')
|
188
249
|
cmd << '-r requirements.txt' unless session_arg?('r', 'requirement')
|
189
250
|
elsif !session_arg?('e', 'editable', value: true)
|
@@ -208,7 +269,7 @@ module Squared
|
|
208
269
|
pwd_set(from: :outdated) do
|
209
270
|
buffer = []
|
210
271
|
out = ->(val) { sync ? puts(val) : buffer << val }
|
211
|
-
IO.popen(cmd).each do |line|
|
272
|
+
IO.popen(runenv || {}, cmd).each do |line|
|
212
273
|
next if line.match?(/^[\s-]+$/)
|
213
274
|
|
214
275
|
if start > 0
|
@@ -272,7 +333,7 @@ module Squared
|
|
272
333
|
out = append_pip(flag, opts, from: :install)
|
273
334
|
case flag
|
274
335
|
when :editable
|
275
|
-
cmd << '
|
336
|
+
cmd << quote_option('e', out.shift || '.')
|
276
337
|
option_clear out
|
277
338
|
when :upgrade
|
278
339
|
cmd << '--upgrade'
|
@@ -283,24 +344,21 @@ module Squared
|
|
283
344
|
end
|
284
345
|
|
285
346
|
def buildx(flag, opts = [])
|
286
|
-
cmd = session flag
|
287
347
|
out = []
|
288
348
|
srcdir = nil
|
289
349
|
case flag
|
290
350
|
when :python
|
291
|
-
cmd
|
292
|
-
list = OPT_PYTHON[:build]
|
351
|
+
cmd, opts = python_session('-m build', opts: opts)
|
352
|
+
list = OPT_PYTHON[:build]
|
293
353
|
when :poetry
|
294
|
-
cmd
|
354
|
+
cmd = session 'poetry', 'build'
|
295
355
|
list = OPT_POETRY[:build] + OPT_POETRY[:common]
|
296
356
|
when :hatch
|
297
|
-
cmd
|
298
|
-
list = OPT_HATCH[:build]
|
357
|
+
cmd, opts = hatch_session('build', opts: opts)
|
358
|
+
list = OPT_HATCH[:build]
|
299
359
|
end
|
300
|
-
option_sanitize(opts, list).first.each do |opt|
|
301
|
-
if
|
302
|
-
cmd << "-#{$1}"
|
303
|
-
elsif !srcdir && basepath(opt).exist? && projectpath?(opt)
|
360
|
+
option_sanitize(opts, list, single: flag == :python ? /^(?:v+|q+|b+)$/ : /^(?:v+|q+)$/).first.each do |opt|
|
361
|
+
if !srcdir && basepath(opt).exist? && projectpath?(opt)
|
304
362
|
srcdir = opt
|
305
363
|
else
|
306
364
|
out << opt
|
@@ -331,7 +389,6 @@ module Squared
|
|
331
389
|
|
332
390
|
def publish(flag, opts = [])
|
333
391
|
cmd = session flag
|
334
|
-
out = []
|
335
392
|
case flag
|
336
393
|
when :poetry
|
337
394
|
cmd << 'publish'
|
@@ -340,16 +397,10 @@ module Squared
|
|
340
397
|
cmd << 'upload'
|
341
398
|
list = OPT_TWINE[:publish]
|
342
399
|
when :hatch
|
343
|
-
|
344
|
-
list = OPT_HATCH[:publish]
|
345
|
-
end
|
346
|
-
option_sanitize(opts, list).first.each do |opt|
|
347
|
-
if flag != :twine && opt =~ /^(v+|q+)$/
|
348
|
-
cmd << "-#{$1}"
|
349
|
-
else
|
350
|
-
out << opt
|
351
|
-
end
|
400
|
+
opts = hatch_session('publish', opts: opts).last
|
401
|
+
list = OPT_HATCH[:publish]
|
352
402
|
end
|
403
|
+
out = option_sanitize(opts, list, single: flag == :twine ? nil : /^(?:v+|q+)$/).first
|
353
404
|
if out.empty?
|
354
405
|
dist = basepath.join('dist')
|
355
406
|
raise_error('no source files given', hint: dist) unless dist.directory? && !dist.empty?
|
@@ -359,6 +410,23 @@ module Squared
|
|
359
410
|
run(from: :"#{flag}:publish")
|
360
411
|
end
|
361
412
|
|
413
|
+
def pip(flag, opts = [])
|
414
|
+
cmd = pip_session flag
|
415
|
+
out = append_pip(nil, opts, from: flag)
|
416
|
+
case flag
|
417
|
+
when :uninstall
|
418
|
+
raise_error('no packages given', subject: name, hint: 'uninstall') if out.empty?
|
419
|
+
cmd.merge(out)
|
420
|
+
when :freeze
|
421
|
+
venv_init
|
422
|
+
ret = basepath(out.shift || 'requirements.txt')
|
423
|
+
cmd << '>' << shell_quote(ret)
|
424
|
+
option_clear out
|
425
|
+
end
|
426
|
+
run(from: :"pip:#{flag}")
|
427
|
+
ret
|
428
|
+
end
|
429
|
+
|
362
430
|
def variable_set(key, *val, **)
|
363
431
|
case key
|
364
432
|
when :dependfile
|
@@ -369,6 +437,8 @@ module Squared
|
|
369
437
|
else
|
370
438
|
log.warn "variable_set: @#{key}=#{req} (not supported)"
|
371
439
|
end
|
440
|
+
when :venv
|
441
|
+
@venv = val.empty? ? nil : basepath(*val)
|
372
442
|
else
|
373
443
|
super
|
374
444
|
end
|
@@ -385,63 +455,128 @@ module Squared
|
|
385
455
|
private
|
386
456
|
|
387
457
|
def pip_session(*cmd)
|
388
|
-
session('pip', *cmd)
|
458
|
+
session('pip', *cmd, path: venv.nil?)
|
389
459
|
end
|
390
460
|
|
391
|
-
def python_session(*cmd)
|
392
|
-
session('python', *cmd)
|
461
|
+
def python_session(*cmd, opts: nil)
|
462
|
+
return session('python', *cmd, path: venv.nil?) unless opts
|
463
|
+
|
464
|
+
out = []
|
465
|
+
opts = option_sanitize(opts, OPT_PYTHON[:common], target: out, single: /^v+$/).first
|
466
|
+
ret = session('python', *out, *cmd, path: venv.nil?)
|
467
|
+
[ret, opts]
|
393
468
|
end
|
394
469
|
|
395
|
-
def
|
396
|
-
|
397
|
-
return [] unless from && !opts.empty?
|
470
|
+
def hatch_session(*cmd, opts: nil)
|
471
|
+
return session('hatch', *cmd, path: venv.nil?) unless opts
|
398
472
|
|
399
|
-
opts, pat = option_sanitize(opts, OPT_PIP[from] + OPT_PIP[:common], target: target)
|
400
473
|
out = []
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
474
|
+
opts = option_sanitize(opts, OPT_HATCH[:common], target: out, single: /^(?:v+|q+)$/).first
|
475
|
+
ret = session('hatch', *out, *cmd, path: venv.nil?)
|
476
|
+
[ret, opts]
|
477
|
+
end
|
478
|
+
|
479
|
+
def append_pip(flag, opts, from: nil)
|
480
|
+
if !from || opts.empty?
|
481
|
+
append_global
|
482
|
+
return []
|
483
|
+
end
|
484
|
+
opts, pat = option_sanitize(opts, OPT_PIP[from] + OPT_PIP[:common], single: /^(?:v+|q+)$/)
|
485
|
+
append_global
|
486
|
+
if from == :install
|
487
|
+
out = []
|
488
|
+
edit = nil
|
489
|
+
opts.each do |opt|
|
490
|
+
if opt =~ pat
|
491
|
+
case $1
|
492
|
+
when 'e', 'editable'
|
493
|
+
edit = $2
|
494
|
+
end
|
495
|
+
elsif flag == :editable && !edit
|
496
|
+
edit = opt
|
497
|
+
else
|
498
|
+
out << opt
|
409
499
|
end
|
410
|
-
elsif flag == :editable && !edit
|
411
|
-
edit = opt
|
412
|
-
else
|
413
|
-
out << opt
|
414
500
|
end
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
501
|
+
if edit
|
502
|
+
edit = editable(edit)
|
503
|
+
if flag == :editable
|
504
|
+
out << edit
|
505
|
+
else
|
506
|
+
target << quote_option('e', edit)
|
507
|
+
end
|
508
|
+
end
|
509
|
+
case flag
|
510
|
+
when :editable, :upgrade
|
511
|
+
out
|
420
512
|
else
|
421
|
-
|
513
|
+
option_clear out
|
514
|
+
[]
|
422
515
|
end
|
423
|
-
end
|
424
|
-
case flag
|
425
|
-
when :editable, :upgrade
|
426
|
-
out
|
427
516
|
else
|
428
|
-
|
429
|
-
[]
|
517
|
+
opts
|
430
518
|
end
|
431
519
|
end
|
432
520
|
|
433
|
-
def append_global
|
521
|
+
def append_global(target: @session)
|
434
522
|
if (val = option('cache-dir'))
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
523
|
+
target << case val
|
524
|
+
when '0', 'false'
|
525
|
+
'--no-cache-dir'
|
526
|
+
else
|
527
|
+
quote_option('cache-dir', basepath(val))
|
528
|
+
end
|
529
|
+
end
|
530
|
+
target << shell_option('proxy', val) if (val = option('proxy'))
|
531
|
+
target << quote_option('python', basepath(val)) if (val = option('python'))
|
532
|
+
append_nocolor(target: target)
|
533
|
+
end
|
534
|
+
|
535
|
+
def editable(val)
|
536
|
+
%r{^[a-z]+(?:\+[a-z]+)?://}i.match?(val) ? val : basepath(val)
|
537
|
+
end
|
538
|
+
|
539
|
+
def variables
|
540
|
+
(super + %i[venv]).freeze
|
541
|
+
end
|
542
|
+
|
543
|
+
def runenv
|
544
|
+
return unless venv
|
545
|
+
|
546
|
+
if workspace.windows?
|
547
|
+
shell_quote(venvbin.join(workspace.powershell? ? 'Activate.ps1' : 'activate.bat'), option: false)
|
548
|
+
else
|
549
|
+
{ 'VIRTUAL_ENV' => venv.to_s, 'PATH' => "#{venvbin}:#{ENV['PATH']}" }
|
441
550
|
end
|
442
|
-
|
443
|
-
|
444
|
-
|
551
|
+
end
|
552
|
+
|
553
|
+
def venvbin
|
554
|
+
@venv.join(workspace.windows? ? 'Scripts' : 'bin')
|
555
|
+
end
|
556
|
+
|
557
|
+
def venv_set(val)
|
558
|
+
@venv = Pathname.new(val)
|
559
|
+
@venv = basepath(@venv) unless @venv.absolute?
|
560
|
+
if projectpath?(@venv)
|
561
|
+
if @venv.exist?
|
562
|
+
log.debug "venv found: #{@venv}"
|
563
|
+
elsif @path.directory? && !@path.empty?
|
564
|
+
@venv.mkpath
|
565
|
+
log.info "venv mkdir: #{@venv}"
|
566
|
+
end
|
567
|
+
elsif !@venv.directory?
|
568
|
+
log.warn "venv invalid: #{@venv}"
|
569
|
+
@venv = nil
|
570
|
+
end
|
571
|
+
end
|
572
|
+
|
573
|
+
def venv_init
|
574
|
+
return if !venv || (venvbin.directory? && !venvbin.empty?)
|
575
|
+
|
576
|
+
puts log_message(Logger::INFO, venv, subject: 'venv', hint: 'init')
|
577
|
+
cmd = python_session '-m venv', shell_option('prompt', name), '--upgrade-deps', shell_quote(venv)
|
578
|
+
run(cmd, false, exception: true, banner: false)
|
579
|
+
puts log_message(Logger::INFO, venv, subject: 'venv', hint: 'created')
|
445
580
|
end
|
446
581
|
end
|
447
582
|
|