squared 0.0.1

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.
@@ -0,0 +1,394 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Squared
4
+ module Repo
5
+ module Project
6
+ class Node < Git
7
+ class << self
8
+ def tasks
9
+ nil
10
+ end
11
+
12
+ def to_sym
13
+ :node
14
+ end
15
+
16
+ def prod?
17
+ ENV['NODE_ENV'] == 'production'
18
+ end
19
+
20
+ def is_a?(path)
21
+ if path.is_a?(::String) || path.is_a?(::Pathname)
22
+ Pathname.new(path).join('package.json').exist?
23
+ else
24
+ super
25
+ end
26
+ end
27
+ end
28
+
29
+ @@tasks[:node] = {
30
+ install: %i[force dedupe],
31
+ outdated: %i[major minor patch]
32
+ }.freeze
33
+
34
+ def initialize(name, project, workspace, **kwargs)
35
+ super
36
+ @clean ||= ['build/']
37
+ @dev = workspace.bool_match(env('BUILD', suffix: 'DEV'), kwargs.delete(:dev))
38
+ @prod = workspace.bool_match(env('BUILD', suffix: 'PROD'), kwargs.delete(:prod))
39
+ @package = {}
40
+ end
41
+
42
+ def populate(*)
43
+ super
44
+ return unless outdated?
45
+
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)
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ def copy(from: 'build', glob: '**/*', basedir: 'node_modules', into: nil, also: [], override: false)
70
+ if @copy && !override
71
+ return super if @copy.is_a?(::String)
72
+
73
+ from = @copy[:from] if @copy.key?(:from)
74
+ glob = @copy[:glob] if @copy.key?(:glob)
75
+ basedir = @copy[:basedir] if @copy.key?(:basedir)
76
+ into = @copy[:into] if @copy.key?(:into)
77
+ also = @copy[:also] if @copy.key?(:also)
78
+ end
79
+ return unless basedir
80
+
81
+ items = [@project == @workspace.main ? nil : @workspace.home].concat(as_a(also))
82
+ items.each_with_index do |dir, i|
83
+ if i == 0
84
+ next unless dev? & !doc?
85
+
86
+ dest = dir
87
+ elsif dir.is_a?(::String)
88
+ dest = @workspace.root_path(dir)
89
+ elsif dir.is_a?(::Symbol)
90
+ dest = Repo.resolve(dir)&.path
91
+ elsif dir.is_a?(Project)
92
+ dest = dir.path
93
+ elsif dir.is_a?(::Hash)
94
+ into = nil
95
+ glob = nil
96
+ dir.each do |key, val|
97
+ case key.to_sym
98
+ when :from
99
+ from = val
100
+ when :glob
101
+ glob = val
102
+ when :basedir
103
+ basedir = val
104
+ when :into
105
+ into = val
106
+ end
107
+ end
108
+ next unless into
109
+ end
110
+ next unless dest&.directory?
111
+
112
+ from = base_path(from)
113
+ dest = dest.join(basedir, into || @project)
114
+ warn "cp #{from.join(glob)} #{dest}"
115
+ copy_d(from, dest, glob: glob, verbose: verbose?)
116
+ end
117
+ end
118
+
119
+ def depend(flag = nil)
120
+ if @depend
121
+ super
122
+ else
123
+ force = flag == :force
124
+ dedupe = flag == :dedupe
125
+ if (yarn = install_type(:yarn)) > 0
126
+ cmd = session 'yarn', 'install'
127
+ if yarn > 1
128
+ cmd << '--check-cache' if force
129
+ else
130
+ cmd << '--production' if prod?
131
+ cmd << '--force' if force
132
+ cmd << '--ignore-engines' unless env('YARN_IGNORE_ENGINES', equals: '0')
133
+ end
134
+ elsif pnpm?
135
+ cmd = session 'pnpm'
136
+ if dedupe
137
+ cmd << 'dedupe'
138
+ else
139
+ cmd << 'install'
140
+ cmd << '--force' if force
141
+ end
142
+ cmd << '--prod' if prod?
143
+ append_nocolor
144
+ else
145
+ cmd = session 'npm'
146
+ cmd << (dedupe ? 'dedupe' : 'install')
147
+ cmd << '--omit=dev' if prod?
148
+ cmd << '--force' if force
149
+ append_nocolor
150
+ end
151
+ append_loglevel
152
+ run(exception: @workspace.exception)
153
+ end
154
+ end
155
+
156
+ def outdated(rev = nil, opts: [])
157
+ require 'json'
158
+ rev ||= prod? ? :patch : :minor
159
+ cmd = pnpm? ? 'pnpm outdated' : 'npm outdated'
160
+ print_item format_banner(message("#{cmd}#{opts.include?('dry-run') ? ' --dry-run' : ''}"), multitask: true)
161
+ pwd = Dir.pwd
162
+ Dir.chdir(@path)
163
+ info cmd
164
+ data = `#{cmd} --json --loglevel=error`
165
+ Dir.chdir(pwd)
166
+ target = base_path('package.json')
167
+ doc = File.read(target)
168
+ json = JSON.parse(doc)
169
+ dep1 = json['dependencies'] || {}
170
+ dep2 = json['devDependencies'] || {}
171
+ found = []
172
+ avail = []
173
+ if !data.empty?
174
+ validate = ->(ver) { /^\d+\.\d+\.\d+$/.match?(ver) }
175
+ JSON.parse(data).each_pair do |key, val|
176
+ file = dep1[key] || dep2[key]
177
+ ch = file[0]
178
+ if !/[~^]/.match?(ch)
179
+ avail << [key, file, val['latest'], true]
180
+ next
181
+ end
182
+ file = file[1..-1]
183
+ cur = val['current']
184
+ want = if rev == :major && validate.(val['latest'])
185
+ [val['latest'], val['wanted']].max { |a, b| a <=> b }
186
+ else
187
+ val['wanted']
188
+ end
189
+ next unless (cur != want || file != want) && (validate.(want) || !validate.(file))
190
+
191
+ a, b = file.split('.')
192
+ c, d = want.split('.')
193
+ upgrade = false
194
+ case rev
195
+ when :major
196
+ upgrade = a == '0' ? c == '0' : true
197
+ when :minor
198
+ upgrade = ch == '^' && (a == '0' ? c == '0' && b == d : a == c)
199
+ when :patch
200
+ upgrade = a == c && b == d
201
+ end
202
+ if upgrade
203
+ next if file == want
204
+
205
+ found << [key, file, want]
206
+ else
207
+ avail << [key, file, val['latest'], false]
208
+ end
209
+ end
210
+ end
211
+ pending = 0
212
+ modified = 0
213
+ size_col = ->(items, i) { items.map { |a| a[i] }.max_by(&:size).size }
214
+ pad_ord = lambda do |val, ord|
215
+ ret = val.succ.to_s
216
+ ord.size > 9 ? ret.rjust(ord.size.to_s.size) : ret
217
+ end
218
+ footer = lambda do |val = 0|
219
+ next unless verbose?
220
+
221
+ msg, hint = if modified == -1
222
+ ['Packages were updated', 'more possible']
223
+ else
224
+ ['No packages were updated', 'possible']
225
+ end
226
+ puts Project.footer(empty_status(msg, hint, pending + val))
227
+ end
228
+ if !found.empty?
229
+ col1 = size_col.(found, 0)
230
+ col2 = size_col.(found, 1)
231
+ found.each_with_index do |item, i|
232
+ a, b, c = item
233
+ cur = modified
234
+ doc.sub!(/("#{Regexp.escape(a)}"\s*:\s*)"([~^])#{Regexp.escape(b)}"/) do |capture|
235
+ if $2 == '~' && rev != :patch
236
+ cur = -1
237
+ pending += 1
238
+ capture
239
+ else
240
+ modified += 1
241
+ "#{$1}\"#{$2 || ''}#{c}\""
242
+ end
243
+ 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}"
250
+ end
251
+ pending = avail.reduce(pending) { |a, b| a + (b[3] ? 0 : 1) }
252
+ if opts.include?('dry-run') || (modified == 0 && pending > 0)
253
+ footer.(modified)
254
+ elsif modified > 0
255
+ File.write(target, doc)
256
+ modified = -1
257
+ footer.()
258
+ commit(:add, 'package.json', pass: true)
259
+ install if opts.include?('prune')
260
+ end
261
+ elsif !avail.empty?
262
+ col1 = size_col.(avail, 0)
263
+ col2 = size_col.(avail, 2)
264
+ avail.each_with_index do |item, i|
265
+ a, b, c, d = item
266
+ puts "#{pad_ord.(i, avail)}. #{a.ljust(col1)}\t#{c.ljust(col2)}\t#{d ? 'locked at' : 'from'} #{b}"
267
+ pending += 1 unless d
268
+ end
269
+ footer.()
270
+ else
271
+ puts 'No updates were found'
272
+ end
273
+ end
274
+
275
+ def compose(opts)
276
+ cmd = [if yarn?
277
+ 'yarn'
278
+ else
279
+ pnpm? ? 'pnpm' : 'npm'
280
+ end]
281
+ cmd << 'run'
282
+ append_loglevel cmd
283
+ if opts.is_a?(::Array)
284
+ cmd += opts
285
+ else
286
+ cmd << (opts || @workspace.script)
287
+ end
288
+ cmd.join(' ')
289
+ end
290
+
291
+ def install_type(prog)
292
+ key = :"#{prog}?"
293
+ send(key) if respond_to?(key)
294
+ @package[prog.to_sym] || 0
295
+ end
296
+
297
+ def depend?
298
+ !@depend.nil? || outdated?
299
+ end
300
+
301
+ def copy?
302
+ !@copy.nil?
303
+ end
304
+
305
+ def outdated?
306
+ base_path('package.json').exist?
307
+ end
308
+
309
+ 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
330
+ end
331
+
332
+ 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
351
+ end
352
+
353
+ def dev?
354
+ return false if Node.prod?
355
+
356
+ @workspace.dev?(@dev, script: @output.last)
357
+ end
358
+
359
+ def prod?
360
+ return true if Node.prod?
361
+
362
+ @workspace.prod?(@prod, script: @output.last)
363
+ end
364
+
365
+ protected
366
+
367
+ def append_loglevel(cmd = @session)
368
+ return unless (level = env('NODE_LOGLEVEL'))
369
+
370
+ if yarn?
371
+ if install_type(:yarn) == 1
372
+ case level
373
+ when 'silent', 'verbose'
374
+ cmd << "--#{level}"
375
+ end
376
+ end
377
+ elsif pnpm?
378
+ case level
379
+ when 'debug', 'info', 'warn', 'error'
380
+ cmd << "--loglevel=#{level}"
381
+ when 'silent'
382
+ cmd << '--reporter=silent'
383
+ end
384
+ else
385
+ case level
386
+ when 'silent', 'error', 'warn', 'notice', 'http', 'info', 'verbose', 'silly'
387
+ cmd << "--loglevel=#{level}"
388
+ end
389
+ end
390
+ end
391
+ end
392
+ end
393
+ end
394
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Squared
4
+ module Repo
5
+ module Project
6
+ class Python < Git
7
+ class << self
8
+ def tasks
9
+ nil
10
+ end
11
+
12
+ def to_sym
13
+ :python
14
+ end
15
+
16
+ def venv?
17
+ path = ENV['VIRTUAL_ENV']
18
+ !path.nil? && Dir.exist?(path)
19
+ end
20
+
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? }
25
+ else
26
+ super
27
+ end
28
+ end
29
+ end
30
+
31
+ @@tasks[:python] = {
32
+ install: %i[upgrade force]
33
+ }.freeze
34
+
35
+ def populate(*)
36
+ super
37
+ return unless outdated?
38
+
39
+ namespace @name do
40
+ @@tasks[:python].each do |action, flags|
41
+ namespace action do
42
+ flags.each do |flag|
43
+ case action
44
+ when :install
45
+ options = lambda do |*opts|
46
+ opts += %w[pre venv no-cache dry-run]
47
+ format_desc(action, flag, opts)
48
+ end
49
+ case flag
50
+ when :upgrade
51
+ desc options.('eager')
52
+ when :force
53
+ desc options.()
54
+ end
55
+ task flag do |_, args|
56
+ install(flag, opts: collect_args(args, :opts))
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ def depend(flag = nil, opts: [])
66
+ if @depend
67
+ 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'
76
+ 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
+ end
84
+ end
85
+
86
+ def outdated(*); end
87
+
88
+ def depend?
89
+ !@depend.nil? || outdated?
90
+ end
91
+
92
+ def outdated?
93
+ base_path('requirements.txt').exist?
94
+ end
95
+
96
+ private
97
+
98
+ def pip_session(*cmd)
99
+ session('pip', *cmd)
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end