squared 0.0.1 → 0.0.2

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.
@@ -4,60 +4,80 @@ module Squared
4
4
  module Repo
5
5
  module Project
6
6
  class Node < Git
7
+ REF = :node
8
+ private_constant :REF
9
+
7
10
  class << self
11
+ def populate(*); end
12
+
8
13
  def tasks
9
14
  nil
10
15
  end
11
16
 
12
- def to_sym
13
- :node
14
- end
15
-
16
17
  def prod?
17
18
  ENV['NODE_ENV'] == 'production'
18
19
  end
19
20
 
20
- def is_a?(path)
21
- if path.is_a?(::String) || path.is_a?(::Pathname)
22
- Pathname.new(path).join('package.json').exist?
21
+ def is_a?(val)
22
+ if val.is_a?(::Pathname) || (val.is_a?(::String) && (val = Pathname.new(val)))
23
+ val.join('package.json').exist?
23
24
  else
24
25
  super
25
26
  end
26
27
  end
27
28
  end
28
29
 
29
- @@tasks[:node] = {
30
- install: %i[force dedupe],
31
- outdated: %i[major minor patch]
30
+ @@tasks[REF] = {
31
+ install: %i[force dedupe frozen],
32
+ outdated: %i[major minor patch],
33
+ run: nil
32
34
  }.freeze
33
35
 
34
36
  def initialize(name, project, workspace, **kwargs)
35
37
  super
36
- @clean ||= ['build/']
38
+ initialize_script(REF)
39
+ if (opts = env('BUILD', strict: true))
40
+ raise ArgumentError, message("BUILD_#{@name.upcase}", opts) if @output[0].is_a?(::Array)
41
+
42
+ @output[1] = opts
43
+ else
44
+ @output[1] = (@script && @script[:run]) || workspace.script
45
+ end
37
46
  @dev = workspace.bool_match(env('BUILD', suffix: 'DEV'), kwargs.delete(:dev))
38
47
  @prod = workspace.bool_match(env('BUILD', suffix: 'PROD'), kwargs.delete(:prod))
39
- @package = {}
48
+ @pm = {}
40
49
  end
41
50
 
42
51
  def populate(*)
43
52
  super
44
53
  return unless outdated?
45
54
 
46
- namespace @name do
47
- @@tasks[:node].each do |action, flags|
48
- namespace action do
49
- flags.each do |flag|
50
- case action
51
- when :install
52
- desc format_desc(action, flag)
53
- task flag do
54
- install flag
55
- end
56
- when :outdated
57
- desc format_desc(action, flag, %w[prune dry-run], req: 'opts?')
58
- task flag, [:opts] do |_, args|
59
- opts = collect_args(args, :opts)
60
- outdated(flag, opts: opts)
55
+ namespace name do
56
+ @@tasks[REF].each do |action, flags|
57
+ if flags.nil?
58
+ case action
59
+ when :run
60
+ desc format_desc(action, nil, 'command+')
61
+ task action, [:command] do |_, args|
62
+ command = collect_args(args, :command)
63
+ guard_params(action, 'command', args: command)
64
+ run_script command
65
+ end
66
+ end
67
+ else
68
+ namespace action do
69
+ flags.each do |flag|
70
+ case action
71
+ when :install
72
+ desc format_desc(action, flag)
73
+ task flag do
74
+ install flag
75
+ end
76
+ when :outdated
77
+ desc format_desc(action, flag, %w[prune dry-run], req: 'opts?')
78
+ task flag, [:opts] do |_, args|
79
+ outdated(flag, opts: collect_args(args, :opts))
80
+ end
61
81
  end
62
82
  end
63
83
  end
@@ -66,26 +86,24 @@ module Squared
66
86
  end
67
87
  end
68
88
 
69
- def copy(from: 'build', glob: '**/*', basedir: 'node_modules', into: nil, also: [], override: false)
89
+ def copy(from: 'build', glob: '**/*', subdir: 'node_modules', into: nil, also: [], override: false)
70
90
  if @copy && !override
71
91
  return super if @copy.is_a?(::String)
72
92
 
73
93
  from = @copy[:from] if @copy.key?(:from)
74
94
  glob = @copy[:glob] if @copy.key?(:glob)
75
- basedir = @copy[:basedir] if @copy.key?(:basedir)
95
+ subdir = @copy[:subdir] if @copy.key?(:subdir)
76
96
  into = @copy[:into] if @copy.key?(:into)
77
97
  also = @copy[:also] if @copy.key?(:also)
78
98
  end
79
- return unless basedir
80
-
81
- items = [@project == @workspace.main ? nil : @workspace.home].concat(as_a(also))
99
+ items = [project == workspace.main ? nil : workspace.home].concat(as_a(also))
82
100
  items.each_with_index do |dir, i|
83
101
  if i == 0
84
102
  next unless dev? & !doc?
85
103
 
86
104
  dest = dir
87
105
  elsif dir.is_a?(::String)
88
- dest = @workspace.root_path(dir)
106
+ dest = workspace.root_path(dir)
89
107
  elsif dir.is_a?(::Symbol)
90
108
  dest = Repo.resolve(dir)&.path
91
109
  elsif dir.is_a?(Project)
@@ -99,8 +117,8 @@ module Squared
99
117
  from = val
100
118
  when :glob
101
119
  glob = val
102
- when :basedir
103
- basedir = val
120
+ when :subdir
121
+ subdir = val
104
122
  when :into
105
123
  into = val
106
124
  end
@@ -110,7 +128,7 @@ module Squared
110
128
  next unless dest&.directory?
111
129
 
112
130
  from = base_path(from)
113
- dest = dest.join(basedir, into || @project)
131
+ dest = dest.join(subdir, into || project)
114
132
  warn "cp #{from.join(glob)} #{dest}"
115
133
  copy_d(from, dest, glob: glob, verbose: verbose?)
116
134
  end
@@ -120,15 +138,30 @@ module Squared
120
138
  if @depend
121
139
  super
122
140
  else
141
+ frozen = flag == :frozen
123
142
  force = flag == :force
124
143
  dedupe = flag == :dedupe
125
144
  if (yarn = install_type(:yarn)) > 0
126
- cmd = session 'yarn', 'install'
145
+ cmd = session 'yarn'
127
146
  if yarn > 1
128
- cmd << '--check-cache' if force
147
+ if dedupe
148
+ cmd << 'dedupe'
149
+ else
150
+ cmd << 'install'
151
+ if force
152
+ cmd << '--check-cache'
153
+ elsif frozen
154
+ cmd << '--immutable'
155
+ end
156
+ end
129
157
  else
158
+ cmd << 'install'
159
+ if force
160
+ cmd << '--force'
161
+ elsif frozen
162
+ cmd << '--frozen-lockfile'
163
+ end
130
164
  cmd << '--production' if prod?
131
- cmd << '--force' if force
132
165
  cmd << '--ignore-engines' unless env('YARN_IGNORE_ENGINES', equals: '0')
133
166
  end
134
167
  elsif pnpm?
@@ -137,19 +170,29 @@ module Squared
137
170
  cmd << 'dedupe'
138
171
  else
139
172
  cmd << 'install'
140
- cmd << '--force' if force
173
+ if force
174
+ cmd << '--force'
175
+ elsif frozen
176
+ cmd << '--frozen-lockfile'
177
+ end
141
178
  end
142
179
  cmd << '--prod' if prod?
180
+ cmd << '--ignore-workspace' if env('NODE_WORKSPACES', equals: '0')
143
181
  append_nocolor
144
182
  else
145
- cmd = session 'npm'
146
- cmd << (dedupe ? 'dedupe' : 'install')
183
+ cmd = session 'npm', dedupe ? 'dedupe' : 'install'
184
+ if force
185
+ cmd << '--force'
186
+ elsif frozen
187
+ cmd << '--package-lock-only'
188
+ end
147
189
  cmd << '--omit=dev' if prod?
148
- cmd << '--force' if force
190
+ cmd << '--workspaces=false' if env('NODE_WORKSPACES', equals: '0')
191
+ cmd << '--package-lock=false' if env('NPM_PACKAGE_LOCK', equals: '0')
149
192
  append_nocolor
150
193
  end
151
194
  append_loglevel
152
- run(exception: @workspace.exception)
195
+ run(exception: workspace.exception)
153
196
  end
154
197
  end
155
198
 
@@ -159,23 +202,25 @@ module Squared
159
202
  cmd = pnpm? ? 'pnpm outdated' : 'npm outdated'
160
203
  print_item format_banner(message("#{cmd}#{opts.include?('dry-run') ? ' --dry-run' : ''}"), multitask: true)
161
204
  pwd = Dir.pwd
162
- Dir.chdir(@path)
205
+ Dir.chdir(path)
163
206
  info cmd
164
207
  data = `#{cmd} --json --loglevel=error`
165
208
  Dir.chdir(pwd)
166
- target = base_path('package.json')
167
- doc = File.read(target)
209
+ doc = File.read(package)
168
210
  json = JSON.parse(doc)
211
+ pat = /^(\d+)(\.)(\d+)(\.)(\d+)$/
169
212
  dep1 = json['dependencies'] || {}
170
213
  dep2 = json['devDependencies'] || {}
171
214
  found = []
172
215
  avail = []
173
216
  if !data.empty?
174
- validate = ->(ver) { /^\d+\.\d+\.\d+$/.match?(ver) }
217
+ validate = ->(ver) { ver.match?(pat) }
175
218
  JSON.parse(data).each_pair do |key, val|
176
- file = dep1[key] || dep2[key]
219
+ val = val.find { |item| item['dependent'] == json['name'] } if val.is_a?(Array)
220
+ next unless val && (file = dep1[key] || dep2[key])
221
+
177
222
  ch = file[0]
178
- if !/[~^]/.match?(ch)
223
+ unless ch.match?(/[~^]/)
179
224
  avail << [key, file, val['latest'], true]
180
225
  next
181
226
  end
@@ -202,7 +247,14 @@ module Squared
202
247
  if upgrade
203
248
  next if file == want
204
249
 
205
- found << [key, file, want]
250
+ index = if a != c
251
+ 1
252
+ elsif b != d
253
+ 3
254
+ else
255
+ 5
256
+ end
257
+ found << [key, file, want, index]
206
258
  else
207
259
  avail << [key, file, val['latest'], false]
208
260
  end
@@ -223,13 +275,13 @@ module Squared
223
275
  else
224
276
  ['No packages were updated', 'possible']
225
277
  end
226
- puts Project.footer(empty_status(msg, hint, pending + val))
278
+ puts print_footer(empty_status(msg, hint, pending + val))
227
279
  end
228
280
  if !found.empty?
229
- col1 = size_col.(found, 0)
230
- col2 = size_col.(found, 1)
281
+ col1 = size_col.(found, 0) + 4
282
+ col2 = size_col.(found, 1) + 4
231
283
  found.each_with_index do |item, i|
232
- a, b, c = item
284
+ a, b, c, d = item
233
285
  cur = modified
234
286
  doc.sub!(/("#{Regexp.escape(a)}"\s*:\s*)"([~^])#{Regexp.escape(b)}"/) do |capture|
235
287
  if $2 == '~' && rev != :patch
@@ -241,29 +293,37 @@ module Squared
241
293
  "#{$1}\"#{$2 || ''}#{c}\""
242
294
  end
243
295
  end
244
- hint = if cur == -1
245
- 'SKIP'
246
- else
247
- modified > cur ? c : 'FAIL'
248
- end
249
- puts "#{pad_ord.(i, found)}. #{a.ljust(col1)}\t#{b.ljust(col2)}\t#{hint}"
296
+ a = a.ljust(col1)
297
+ c = if cur == -1
298
+ 'SKIP'
299
+ elsif modified == cur
300
+ 'FAIL'
301
+ elsif d == 1
302
+ a = sub_style(a, :bold)
303
+ sub_style(c, :green, :bold)
304
+ else
305
+ sub_style(c, :green, :bold, pat: pat, index: d)
306
+ end
307
+ puts "#{pad_ord.(i, found)}. #{a}#{b.ljust(col2)}#{c}"
250
308
  end
251
309
  pending = avail.reduce(pending) { |a, b| a + (b[3] ? 0 : 1) }
252
310
  if opts.include?('dry-run') || (modified == 0 && pending > 0)
253
311
  footer.(modified)
254
312
  elsif modified > 0
255
- File.write(target, doc)
313
+ File.write(package, doc)
256
314
  modified = -1
257
315
  footer.()
258
316
  commit(:add, 'package.json', pass: true)
259
317
  install if opts.include?('prune')
260
318
  end
261
319
  elsif !avail.empty?
262
- col1 = size_col.(avail, 0)
263
- col2 = size_col.(avail, 2)
320
+ col1 = size_col.(avail, 0) + 4
321
+ col2 = size_col.(avail, 1)
322
+ col3 = size_col.(avail, 2) + 4
264
323
  avail.each_with_index do |item, i|
265
324
  a, b, c, d = item
266
- puts "#{pad_ord.(i, avail)}. #{a.ljust(col1)}\t#{c.ljust(col2)}\t#{d ? 'locked at' : 'from'} #{b}"
325
+ e = sub_style(b.ljust(col2), d ? :red : :yellow)
326
+ puts "#{pad_ord.(i, avail)}. #{a.ljust(col1)}#{c.ljust(col3)}#{e} (#{d ? 'locked' : 'latest'})"
267
327
  pending += 1 unless d
268
328
  end
269
329
  footer.()
@@ -272,7 +332,12 @@ module Squared
272
332
  end
273
333
  end
274
334
 
275
- def compose(opts)
335
+ def run_script(cmd)
336
+ cmd.each { |val| run_s compose(val) }
337
+ end
338
+
339
+ def compose(args)
340
+ args ||= @output[1]
276
341
  cmd = [if yarn?
277
342
  'yarn'
278
343
  else
@@ -280,86 +345,93 @@ module Squared
280
345
  end]
281
346
  cmd << 'run'
282
347
  append_loglevel cmd
283
- if opts.is_a?(::Array)
284
- cmd += opts
348
+ if args.is_a?(::Array)
349
+ cmd += args
350
+ elsif args.is_a?(::String)
351
+ cmd << args
285
352
  else
286
- cmd << (opts || @workspace.script)
353
+ raise ArgumentError, message("#{cmd.first} script name", hint: args.nil? ? 'missing' : 'invalid')
287
354
  end
288
355
  cmd.join(' ')
289
356
  end
290
357
 
291
- def install_type(prog)
358
+ def install_type(prog = nil)
359
+ prog ||= yarn? ? :yarn : :pnpm
292
360
  key = :"#{prog}?"
293
- send(key) if respond_to?(key)
294
- @package[prog.to_sym] || 0
361
+ __send__(key) if respond_to?(key)
362
+ @pm[prog] || 0
363
+ end
364
+
365
+ def build?
366
+ @output[0] != false && (!@output[0].nil? || !@output[1].nil?)
295
367
  end
296
368
 
297
369
  def depend?
298
- !@depend.nil? || outdated?
370
+ !!@depend || outdated?
299
371
  end
300
372
 
301
373
  def copy?
302
- !@copy.nil?
374
+ !!@copy
303
375
  end
304
376
 
305
377
  def outdated?
306
- base_path('package.json').exist?
378
+ package.exist?
307
379
  end
308
380
 
309
381
  def yarn?
310
- (@package[:yarn] ||= if File.exist?(base_path('yarn.lock'))
311
- if File.exist?(rc = base_path('.yarnrc.yml'))
312
- begin
313
- require 'yaml'
314
- doc = YAML.load_file(rc)
315
- doc.nodeLinker == 'node-modules' ? 2 : 3
316
- rescue StandardError
317
- 3
318
- end
319
- else
320
- 1
321
- end
322
- else
323
- ver = env('NODE_INSTALL')
324
- if ver&.start_with?('yarn')
325
- ver.include?('@1') ? 1 : 3
326
- else
327
- 0
328
- end
329
- end) > 0
382
+ (@pm[:yarn] ||= if File.exist?(base_path('yarn.lock'))
383
+ if File.exist?(rc = base_path('.yarnrc.yml'))
384
+ begin
385
+ require 'yaml'
386
+ doc = YAML.load_file(rc)
387
+ doc.nodeLinker == 'node-modules' ? 2 : 3
388
+ rescue StandardError
389
+ 3
390
+ end
391
+ else
392
+ 1
393
+ end
394
+ else
395
+ ver = env('NODE_INSTALL')
396
+ if ver&.start_with?('yarn')
397
+ ver.include?('@1') ? 1 : 3
398
+ else
399
+ 0
400
+ end
401
+ end) > 0
330
402
  end
331
403
 
332
404
  def pnpm?
333
- (@package[:pnpm] ||= if File.exist?(base_path('pnpm-lock.yaml'))
334
- begin
335
- require 'yaml'
336
- doc = YAML.load_file(base_path('node_modules/.modules.yaml'))
337
- case doc['nodeLinker']
338
- when 'hoisted'
339
- 1
340
- when 'pnp'
341
- 3
342
- else
343
- 4
344
- end
345
- rescue StandardError
346
- 4
347
- end
348
- else
349
- env('NODE_INSTALL')&.start_with?('pnpm') ? 4 : 0
350
- end) > 0
405
+ (@pm[:pnpm] ||= if File.exist?(base_path('pnpm-lock.yaml'))
406
+ begin
407
+ require 'yaml'
408
+ doc = YAML.load_file(base_path('node_modules/.modules.yaml'))
409
+ case doc['nodeLinker']
410
+ when 'hoisted'
411
+ 1
412
+ when 'pnp'
413
+ 3
414
+ else
415
+ 4
416
+ end
417
+ rescue StandardError
418
+ 4
419
+ end
420
+ else
421
+ env('NODE_INSTALL')&.start_with?('pnpm') ? 4 : 0
422
+ end) > 0
351
423
  end
352
424
 
353
425
  def dev?
354
426
  return false if Node.prod?
355
427
 
356
- @workspace.dev?(@dev, script: @output.last)
428
+ workspace.dev?(script: @output[1], pat: @dev, global: !@script || @script[:run].nil?)
357
429
  end
358
430
 
359
431
  def prod?
360
432
  return true if Node.prod?
361
433
 
362
- @workspace.prod?(@prod, script: @output.last)
434
+ workspace.prod?(script: @output[1], pat: @prod, global: !@script || @script[:run].nil?)
363
435
  end
364
436
 
365
437
  protected
@@ -367,27 +439,39 @@ module Squared
367
439
  def append_loglevel(cmd = @session)
368
440
  return unless (level = env('NODE_LOGLEVEL'))
369
441
 
442
+ silent = !workspace.verbose || level == 'silent'
370
443
  if yarn?
371
444
  if install_type(:yarn) == 1
372
- case level
373
- when 'silent', 'verbose'
374
- cmd << "--#{level}"
445
+ if silent
446
+ cmd << '--silent'
447
+ elsif level == 'verbose'
448
+ cmd << '--verbose'
375
449
  end
376
450
  end
377
451
  elsif pnpm?
378
- case level
379
- when 'debug', 'info', 'warn', 'error'
380
- cmd << "--loglevel=#{level}"
381
- when 'silent'
452
+ if silent
382
453
  cmd << '--reporter=silent'
454
+ else
455
+ case level
456
+ when 'debug', 'info', 'warn', 'error'
457
+ cmd << "--loglevel=#{level}"
458
+ end
383
459
  end
460
+ elsif silent
461
+ cmd << '--loglevel=silent'
384
462
  else
385
463
  case level
386
- when 'silent', 'error', 'warn', 'notice', 'http', 'info', 'verbose', 'silly'
464
+ when 'error', 'warn', 'notice', 'http', 'info', 'verbose', 'silly'
387
465
  cmd << "--loglevel=#{level}"
388
466
  end
389
467
  end
390
468
  end
469
+
470
+ private
471
+
472
+ def package
473
+ @package ||= base_path('package.json')
474
+ end
391
475
  end
392
476
  end
393
477
  end
@@ -4,31 +4,37 @@ module Squared
4
4
  module Repo
5
5
  module Project
6
6
  class Python < Git
7
+ REF = :python
8
+ REQUIREMENTS = %w[requirements.txt pyproject.toml setup.py].freeze
9
+ private_constant :REF, :REQUIREMENTS
10
+
7
11
  class << self
12
+ def populate(*); end
13
+
8
14
  def tasks
9
15
  nil
10
16
  end
11
17
 
12
- def to_sym
13
- :python
14
- end
15
-
16
18
  def venv?
17
- path = ENV['VIRTUAL_ENV']
18
- !path.nil? && Dir.exist?(path)
19
+ val = ENV['VIRTUAL_ENV']
20
+ !val.nil? && Dir.exist?(val)
19
21
  end
20
22
 
21
- def is_a?(path)
22
- if path.is_a?(::String) || path.is_a?(::Pathname)
23
- base = Pathname.new(path)
24
- ['setup.py', 'requirements.txt'].any? { |file| base.join(file).exist? }
23
+ def is_a?(val)
24
+ if val.is_a?(::Pathname) || (val.is_a?(::String) && (val = Pathname.new(val)))
25
+ REQUIREMENTS.any? { |file| val.join(file).exist? }
25
26
  else
26
27
  super
27
28
  end
28
29
  end
29
30
  end
30
31
 
31
- @@tasks[:python] = {
32
+ def initialize(name, project, workspace, **kwargs)
33
+ super
34
+ initialize_build(REF, **kwargs)
35
+ end
36
+
37
+ @@tasks[REF] = {
32
38
  install: %i[upgrade force]
33
39
  }.freeze
34
40
 
@@ -36,8 +42,8 @@ module Squared
36
42
  super
37
43
  return unless outdated?
38
44
 
39
- namespace @name do
40
- @@tasks[:python].each do |action, flags|
45
+ namespace name do
46
+ @@tasks[REF].each do |action, flags|
41
47
  namespace action do
42
48
  flags.each do |flag|
43
49
  case action
@@ -65,32 +71,45 @@ module Squared
65
71
  def depend(flag = nil, opts: [])
66
72
  if @depend
67
73
  super
68
- else
69
- cmd = pip_session 'install -r requirements.txt'
70
- case flag
71
- when :upgrade
72
- cmd << '--upgrade'
73
- cmd << '--upgrade-strategy=eager' if opts.include?('eager')
74
- when :force
75
- cmd << '--force-reinstall'
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"
76
94
  end
77
- cmd << '--pre' if opts.include?('pre')
78
- cmd << '--require-virtualenv' if opts.include?('venv')
79
- cmd << '--no-cache-dir' if opts.include?('no-cache')
80
- cmd << '--dry-run' if opts.include?('dry-run')
81
- append_nocolor
82
- run(exception: @workspace.exception)
83
95
  end
84
96
  end
85
97
 
86
98
  def outdated(*); end
87
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
+
88
107
  def depend?
89
- !@depend.nil? || outdated?
108
+ !!@depend || outdated?
90
109
  end
91
110
 
92
111
  def outdated?
93
- base_path('requirements.txt').exist?
112
+ install_type > 0
94
113
  end
95
114
 
96
115
  private