squared 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 = as_path(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
- def initialize(name, project, workspace, **kwargs)
36
+ def initialize(name, path, 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,24 @@ 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)
168
- json = JSON.parse(doc)
209
+ json = JSON.parse(doc = package.read)
210
+ pat = /^(\d+)(\.)(\d+)(\.)(\d+)$/
169
211
  dep1 = json['dependencies'] || {}
170
212
  dep2 = json['devDependencies'] || {}
171
213
  found = []
172
214
  avail = []
173
215
  if !data.empty?
174
- validate = ->(ver) { /^\d+\.\d+\.\d+$/.match?(ver) }
216
+ validate = ->(ver) { ver.match?(pat) }
175
217
  JSON.parse(data).each_pair do |key, val|
176
- file = dep1[key] || dep2[key]
218
+ val = val.find { |item| item['dependent'] == json['name'] } if val.is_a?(Array)
219
+ next unless val && (file = dep1[key] || dep2[key])
220
+
177
221
  ch = file[0]
178
- if !/[~^]/.match?(ch)
222
+ unless ch.match?(/[~^]/)
179
223
  avail << [key, file, val['latest'], true]
180
224
  next
181
225
  end
@@ -202,7 +246,14 @@ module Squared
202
246
  if upgrade
203
247
  next if file == want
204
248
 
205
- found << [key, file, want]
249
+ index = if a != c
250
+ 1
251
+ elsif b != d
252
+ 3
253
+ else
254
+ 5
255
+ end
256
+ found << [key, file, want, index]
206
257
  else
207
258
  avail << [key, file, val['latest'], false]
208
259
  end
@@ -223,13 +274,13 @@ module Squared
223
274
  else
224
275
  ['No packages were updated', 'possible']
225
276
  end
226
- puts Project.footer(empty_status(msg, hint, pending + val))
277
+ puts print_footer(empty_status(msg, hint, pending + val))
227
278
  end
228
279
  if !found.empty?
229
- col1 = size_col.(found, 0)
230
- col2 = size_col.(found, 1)
280
+ col1 = size_col.(found, 0) + 4
281
+ col2 = size_col.(found, 1) + 4
231
282
  found.each_with_index do |item, i|
232
- a, b, c = item
283
+ a, b, c, d = item
233
284
  cur = modified
234
285
  doc.sub!(/("#{Regexp.escape(a)}"\s*:\s*)"([~^])#{Regexp.escape(b)}"/) do |capture|
235
286
  if $2 == '~' && rev != :patch
@@ -241,29 +292,37 @@ module Squared
241
292
  "#{$1}\"#{$2 || ''}#{c}\""
242
293
  end
243
294
  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}"
295
+ a = a.ljust(col1)
296
+ c = if cur == -1
297
+ 'SKIP'
298
+ elsif modified == cur
299
+ 'FAIL'
300
+ elsif d == 1
301
+ a = sub_style(a, :bold)
302
+ sub_style(c, :green, :bold)
303
+ else
304
+ sub_style(c, :green, :bold, pat: pat, index: d)
305
+ end
306
+ puts "#{pad_ord.(i, found)}. #{a}#{b.ljust(col2)}#{c}"
250
307
  end
251
308
  pending = avail.reduce(pending) { |a, b| a + (b[3] ? 0 : 1) }
252
309
  if opts.include?('dry-run') || (modified == 0 && pending > 0)
253
310
  footer.(modified)
254
311
  elsif modified > 0
255
- File.write(target, doc)
312
+ File.write(package, doc)
256
313
  modified = -1
257
314
  footer.()
258
315
  commit(:add, 'package.json', pass: true)
259
316
  install if opts.include?('prune')
260
317
  end
261
318
  elsif !avail.empty?
262
- col1 = size_col.(avail, 0)
263
- col2 = size_col.(avail, 2)
319
+ col1 = size_col.(avail, 0) + 4
320
+ col2 = size_col.(avail, 1)
321
+ col3 = size_col.(avail, 2) + 4
264
322
  avail.each_with_index do |item, i|
265
323
  a, b, c, d = item
266
- puts "#{pad_ord.(i, avail)}. #{a.ljust(col1)}\t#{c.ljust(col2)}\t#{d ? 'locked at' : 'from'} #{b}"
324
+ e = sub_style(b.ljust(col2), d ? :red : :yellow)
325
+ puts "#{pad_ord.(i, avail)}. #{a.ljust(col1)}#{c.ljust(col3)}#{e} (#{d ? 'locked' : 'latest'})"
267
326
  pending += 1 unless d
268
327
  end
269
328
  footer.()
@@ -272,7 +331,12 @@ module Squared
272
331
  end
273
332
  end
274
333
 
275
- def compose(opts)
334
+ def run_script(cmd)
335
+ cmd.each { |val| run_s compose(val) }
336
+ end
337
+
338
+ def compose(args)
339
+ args ||= @output[1]
276
340
  cmd = [if yarn?
277
341
  'yarn'
278
342
  else
@@ -280,86 +344,93 @@ module Squared
280
344
  end]
281
345
  cmd << 'run'
282
346
  append_loglevel cmd
283
- if opts.is_a?(::Array)
284
- cmd += opts
347
+ if args.is_a?(::Array)
348
+ cmd += args
349
+ elsif args.is_a?(::String)
350
+ cmd << args
285
351
  else
286
- cmd << (opts || @workspace.script)
352
+ raise ArgumentError, message("#{cmd.first} script name", hint: args.nil? ? 'missing' : 'invalid')
287
353
  end
288
354
  cmd.join(' ')
289
355
  end
290
356
 
291
- def install_type(prog)
357
+ def install_type(prog = nil)
358
+ prog ||= yarn? ? :yarn : :pnpm
292
359
  key = :"#{prog}?"
293
- send(key) if respond_to?(key)
294
- @package[prog.to_sym] || 0
360
+ __send__(key) if respond_to?(key)
361
+ @pm[prog] || 0
362
+ end
363
+
364
+ def build?
365
+ @output[0] != false && (!@output[0].nil? || !@output[1].nil?)
295
366
  end
296
367
 
297
368
  def depend?
298
- !@depend.nil? || outdated?
369
+ !!@depend || outdated?
299
370
  end
300
371
 
301
372
  def copy?
302
- !@copy.nil?
373
+ !!@copy
303
374
  end
304
375
 
305
376
  def outdated?
306
- base_path('package.json').exist?
377
+ package.exist?
307
378
  end
308
379
 
309
380
  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
381
+ (@pm[:yarn] ||= if File.exist?(base_path('yarn.lock'))
382
+ if File.exist?(rc = base_path('.yarnrc.yml'))
383
+ begin
384
+ require 'yaml'
385
+ doc = YAML.load_file(rc)
386
+ doc.nodeLinker == 'node-modules' ? 2 : 3
387
+ rescue StandardError
388
+ 3
389
+ end
390
+ else
391
+ 1
392
+ end
393
+ else
394
+ ver = env('NODE_INSTALL')
395
+ if ver&.start_with?('yarn')
396
+ ver.include?('@1') ? 1 : 3
397
+ else
398
+ 0
399
+ end
400
+ end) > 0
330
401
  end
331
402
 
332
403
  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
404
+ (@pm[:pnpm] ||= if File.exist?(base_path('pnpm-lock.yaml'))
405
+ begin
406
+ require 'yaml'
407
+ doc = YAML.load_file(base_path('node_modules/.modules.yaml'))
408
+ case doc['nodeLinker']
409
+ when 'hoisted'
410
+ 1
411
+ when 'pnp'
412
+ 3
413
+ else
414
+ 4
415
+ end
416
+ rescue StandardError
417
+ 4
418
+ end
419
+ else
420
+ env('NODE_INSTALL')&.start_with?('pnpm') ? 4 : 0
421
+ end) > 0
351
422
  end
352
423
 
353
424
  def dev?
354
425
  return false if Node.prod?
355
426
 
356
- @workspace.dev?(@dev, script: @output.last)
427
+ workspace.dev?(script: @output[1], pat: @dev, global: !@script || @script[:run].nil?)
357
428
  end
358
429
 
359
430
  def prod?
360
431
  return true if Node.prod?
361
432
 
362
- @workspace.prod?(@prod, script: @output.last)
433
+ workspace.prod?(script: @output[1], pat: @prod, global: !@script || @script[:run].nil?)
363
434
  end
364
435
 
365
436
  protected
@@ -367,27 +438,39 @@ module Squared
367
438
  def append_loglevel(cmd = @session)
368
439
  return unless (level = env('NODE_LOGLEVEL'))
369
440
 
441
+ silent = !workspace.verbose || level == 'silent'
370
442
  if yarn?
371
443
  if install_type(:yarn) == 1
372
- case level
373
- when 'silent', 'verbose'
374
- cmd << "--#{level}"
444
+ if silent
445
+ cmd << '--silent'
446
+ elsif level == 'verbose'
447
+ cmd << '--verbose'
375
448
  end
376
449
  end
377
450
  elsif pnpm?
451
+ if silent
452
+ cmd << '--reporter=silent'
453
+ level ||= 'error'
454
+ end
378
455
  case level
379
456
  when 'debug', 'info', 'warn', 'error'
380
457
  cmd << "--loglevel=#{level}"
381
- when 'silent'
382
- cmd << '--reporter=silent'
383
458
  end
459
+ elsif silent
460
+ cmd << '--loglevel=silent'
384
461
  else
385
462
  case level
386
- when 'silent', 'error', 'warn', 'notice', 'http', 'info', 'verbose', 'silly'
463
+ when 'error', 'warn', 'notice', 'http', 'info', 'verbose', 'silly'
387
464
  cmd << "--loglevel=#{level}"
388
465
  end
389
466
  end
390
467
  end
468
+
469
+ private
470
+
471
+ def package
472
+ @package ||= base_path('package.json')
473
+ end
391
474
  end
392
475
  end
393
476
  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 = as_path(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, path, 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