squared 0.0.4 → 0.0.6

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.
@@ -1,20 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- module Repo
4
+ module Workspace
5
5
  module Project
6
6
  class Git < Base
7
7
  include Format
8
8
 
9
9
  REF = :git
10
- private_constant :REF
10
+ OPT_PULL = %w[all tags prune ff-only autostash dry-run].freeze
11
+ OPT_FETCH = %w[tags prune prune-tags depth=n dry-run].freeze
12
+ private_constant :REF, :OPT_PULL, :OPT_FETCH
11
13
 
12
14
  class << self
13
15
  def populate(workspace, parallel: [], **)
14
- return if workspace.series[:pull].empty?
16
+ return if workspace.series.pull.empty?
15
17
 
16
18
  desc 'all[git?=rebase|stash]'
17
- task :all, [:git] do |_, args|
19
+ task 'all', [:git] do |_, args|
18
20
  sync = ->(key) { parallel.include?(key) ? :"#{key}:sync" : key }
19
21
  pull = case args.git
20
22
  when 'rebase'
@@ -46,10 +48,10 @@ module Squared
46
48
  @@tasks[REF] = {
47
49
  checkout: %i[branch detach force merge],
48
50
  commit: %i[add amend amend-orig all no-all],
49
- diff: %i[head cached branch],
51
+ diff: %i[head cached branch files],
50
52
  fetch: %i[all submodules unshallow],
51
53
  files: %i[cached modified deleted others],
52
- pull: %i[rebase no-rebase commit no-commit submodules],
54
+ pull: %i[head rebase no-rebase commit no-commit submodules],
53
55
  stash: %i[push pop apply list clear],
54
56
  refs: %i[heads tags],
55
57
  reset: %i[head soft mixed hard merge keep submodules],
@@ -67,13 +69,13 @@ module Squared
67
69
  flags.each do |flag|
68
70
  case action
69
71
  when :pull
70
- desc format_desc(action, flag, %w[all tags prune ff-only autostash dry-run])
72
+ desc format_desc(action, flag, OPT_PULL)
71
73
  task flag, [:opts] do |_, args|
72
74
  opts = collect_args(args, :opts)
73
75
  pull(flag, opts: opts)
74
76
  end
75
77
  when :fetch
76
- desc format_desc(action, flag, %w[tags prune prune-tags depth=n dry-run])
78
+ desc format_desc(action, flag, OPT_FETCH)
77
79
  task flag, [:opts] do |_, args|
78
80
  opts = collect_args(args, :opts)
79
81
  fetch(flag, opts: opts)
@@ -82,7 +84,7 @@ module Squared
82
84
  if flag == :all
83
85
  desc format_desc(action, flag, 'message?')
84
86
  task flag, [:message] do |_, args|
85
- commit(:all, message: args.fetch(:message, nil))
87
+ commit(flag, message: args.fetch(:message, nil))
86
88
  end
87
89
  else
88
90
  desc format_desc(action, flag, 'pathspec+')
@@ -94,8 +96,8 @@ module Squared
94
96
  when :stash
95
97
  if flag == :push
96
98
  desc format_desc(action, flag, 'pathspec*')
97
- task :push, [:pathspec] do |_, args|
98
- stash(:push, collect_args(args, :pathspec))
99
+ task flag, [:pathspec] do |_, args|
100
+ stash(flag, collect_args(args, :pathspec))
99
101
  end
100
102
  else
101
103
  desc format_desc(action, flag, 'commit?')
@@ -120,18 +122,25 @@ module Squared
120
122
  task flag, [:pathspec] do |_, args|
121
123
  files = collect_args(args, :pathspec)
122
124
  index = /^\d+$/.match?(files.first) && !option('index') ? files.shift.to_i : 0
123
- diff(:head, files, index: index)
125
+ diff(flag, files, index: index)
124
126
  end
125
127
  when :cached
126
128
  desc format_desc(action, flag, 'pathspec*')
127
129
  task flag, [:pathspec] do |_, args|
128
- diff(:cached, collect_args(args, :pathspec))
130
+ diff(flag, collect_args(args, :pathspec))
129
131
  end
130
132
  when :branch
131
133
  desc format_desc(action, flag, 'name,pathspec*')
132
134
  task flag, [:name, :pathspec] do |_, args|
133
135
  guard_params(action, flag, args: args, key: :name)
134
- diff(:branch, collect_args(args, :pathspec), branch: args.name)
136
+ diff(flag, collect_args(args, :pathspec), branch: args.name)
137
+ end
138
+ when :files
139
+ desc format_desc(action, flag, 'path1,path2')
140
+ task flag, [:path1, :path2] do |_, args|
141
+ guard_params(action, flag, args: args, key: :path1)
142
+ guard_params(action, flag, args: args, key: :path2)
143
+ diff(flag, [args.path1, args.path2])
135
144
  end
136
145
  end
137
146
  when :checkout
@@ -157,12 +166,12 @@ module Squared
157
166
  commit = args.commit
158
167
  end
159
168
  guard_params('checkout', :branch, args: args, key: :create, pat: /^[Bb]$/) if create
160
- checkout(:branch, branch: args.name, create: create, commit: commit, detach: detach)
169
+ checkout(flag, branch: args.name, create: create, commit: commit, detach: detach)
161
170
  end
162
171
  when :detach
163
172
  desc format_desc(action, flag, 'branch/commit?')
164
173
  task flag, [:commit] do |_, args|
165
- checkout(:detach, commit: args.commit)
174
+ checkout(flag, commit: args.commit)
166
175
  end
167
176
  else
168
177
  desc format_desc(action, flag, 'pathspec*')
@@ -175,7 +184,7 @@ module Squared
175
184
  desc format_desc(action, flag, 'ref?=HEAD,pathspec+')
176
185
  task flag, [:ref, :pathspec] do |_, args|
177
186
  guard_params(action, flag, args: args, key: :pathspec)
178
- reset(:head, collect_args(args, :pathspec), ref: args.ref)
187
+ reset(flag, collect_args(args, :pathspec), ref: args.ref)
179
188
  end
180
189
  else
181
190
  desc format_desc(action, flag, 'ref?=HEAD')
@@ -202,14 +211,8 @@ module Squared
202
211
  elsif flag == :commit || option('commit')
203
212
  cmd << '--commit'
204
213
  end
205
- append_submodules flag
206
- opts.each do |val|
207
- case val
208
- when 'all', 'tags', 'prune', 'ff-only', 'autostash', 'dry-run'
209
- cmd << "--#{val}"
210
- end
211
- end
212
- source(sync: sync, stderr: true, exception: !workspace.multitask?)
214
+ append_pull opts, OPT_PULL, flag
215
+ source(sync: sync, stderr: true, exception: !workspace.series.multiple?)
213
216
  end
214
217
 
215
218
  def rebase
@@ -219,16 +222,8 @@ module Squared
219
222
  def fetch(flag = nil, opts: [])
220
223
  cmd = git_session 'fetch'
221
224
  cmd << '--all' if flag == :all || option('all')
222
- append_submodules flag
223
- opts.each do |val|
224
- case val
225
- when 'tags', 'prune', 'prune-tags', 'dry-run'
226
- cmd << "--#{val}"
227
- else
228
- cmd << "--depth=#{$1}" if /^depth=(\d+)$/.match(val)
229
- end
230
- end
231
- source(sync: invoked_sync?('fetch', flag), stderr: true, exception: !workspace.multitask?)
225
+ append_pull opts, OPT_FETCH, flag
226
+ source(sync: invoked_sync?('fetch', flag), stderr: true, exception: !workspace.series.multiple?)
232
227
  end
233
228
 
234
229
  def stash(flag = :push, files = [], commit: nil)
@@ -236,10 +231,10 @@ module Squared
236
231
  case flag
237
232
  when :apply, :pop
238
233
  cmd << '--index' if option('index')
239
- cmd << commit if commit
234
+ cmd << commit
240
235
  else
241
- %w[all staged include-untracked].each { |val| cmd << "--#{val}" if option(val) }
242
- append_message option('message')
236
+ append_option %w[all staged include-untracked]
237
+ append_message option('message', 'm', zero: false)
243
238
  append_pathspec files
244
239
  end
245
240
  source(sync: invoked_sync?('stash', flag), exception: workspace.exception)
@@ -259,9 +254,7 @@ module Squared
259
254
  'all'
260
255
  end}"
261
256
  end
262
- if (val = option('pathspec'))
263
- append_pathspec split_escape(val)
264
- end
257
+ append_pathspec
265
258
  out, banner = source(io: true)
266
259
  if banner && invoked_sync?('status')
267
260
  print_item banner
@@ -302,17 +295,16 @@ module Squared
302
295
  when :branch
303
296
  cmd << '--detach' if detach == 'd' || option('detach')
304
297
  if create
305
- cmd << "-#{create} #{branch}"
298
+ cmd << "-#{create}" << branch
306
299
  if (val = option('start-point'))
307
300
  cmd << val
308
301
  end
309
302
  else
310
303
  cmd << branch
311
304
  end
312
- cmd << commit if commit
305
+ cmd << commit
313
306
  when :detach
314
- cmd << "--#{flag}"
315
- cmd << commit if commit
307
+ cmd << "--#{flag}" << commit
316
308
  else
317
309
  cmd << "--#{flag}"
318
310
  append_ours
@@ -351,10 +343,13 @@ module Squared
351
343
 
352
344
  def diff(flag, files = [], branch: nil, index: 0)
353
345
  cmd = git_session 'diff'
354
- if /^#[0-9a-f]{5,40}\#$/.match?(sha = files.first)
355
- files.shift
356
- else
357
- sha = nil
346
+ unless flag == :files
347
+ if /^#[0-9a-f]{5,40}\#$/.match?(sha = files.first)
348
+ sha = sha[1..-2]
349
+ files.shift
350
+ else
351
+ sha = nil
352
+ end
358
353
  end
359
354
  if (val = option('unified')).to_i > 0
360
355
  cmd << "--unified=#{val}"
@@ -366,6 +361,8 @@ module Squared
366
361
  cmd << '--merge-base' if option('merge-base')
367
362
  when :branch
368
363
  cmd << branch
364
+ when :files
365
+ cmd << '--no-index'
369
366
  else
370
367
  if (val = option('index')) || index > 0
371
368
  cmd << "HEAD~#{val || index}"
@@ -373,25 +370,24 @@ module Squared
373
370
  cmd << '--merge-base'
374
371
  end
375
372
  end
376
- cmd << sha if sha
377
- append_pathspec files
378
- source
373
+ cmd << sha
374
+ append_pathspec(files, pass: flag == :files)
375
+ source(exception: cmd.include?('--exit-code'))
379
376
  end
380
377
 
381
378
  def commit(flag, files = [], message: nil, pass: false)
382
- message = option('message') if message.nil?
379
+ message ||= option('message', 'm', zero: false)
383
380
  amend = flag.to_s.start_with?('amend')
384
381
  if !message && !amend
385
382
  return if pass
386
383
 
387
- raise ArgumentError, message('commit', 'GIT_MESSAGE="description"', hint: 'missing')
384
+ raise_error('commit', 'GIT_MESSAGE="description"', hint: 'missing')
388
385
  end
389
386
  pathspec = if flag == :all || (amend && files.size == 1 && files.first == '*')
390
387
  '--all'
391
388
  else
392
389
  files = source_path(as_a(files))
393
- raise ArgumentError, message('commit', 'pathspec', hint: 'missing') if files.empty?
394
-
390
+ raise_error('commit', 'pathspec', hint: 'missing') if files.empty?
395
391
  "-- #{files.join(' ')}"
396
392
  end
397
393
  if !push?
@@ -404,7 +400,7 @@ module Squared
404
400
  break
405
401
  end
406
402
  end
407
- raise ArgumentError, message('commit', 'work tree is not usable') unless push?
403
+ raise_error('commit', 'work tree is not usable') unless push?
408
404
 
409
405
  cmd = git_session 'commit'
410
406
  cmd << '--dry-run' if option('dry-run')
@@ -448,9 +444,9 @@ module Squared
448
444
 
449
445
  def source(cmd = @session, exception: true, banner: true, io: false, sync: true, stdout: false, stderr: false)
450
446
  cmd = close_session(cmd)
451
- info cmd
447
+ log.info cmd
452
448
  begin
453
- banner = format_banner(cmd.gsub(trailing_slash(path), ''), banner: banner, multitask: true)
449
+ banner = format_banner(cmd.gsub(File.join(path, ''), ''), banner: banner, multiple: true)
454
450
  cmd = cmd.sub(/^git\b/, "git --work-tree #{shell_quote(path)} --git-dir #{shell_quote(gitdir)}")
455
451
  if io
456
452
  [IO.popen(cmd), banner]
@@ -481,10 +477,10 @@ module Squared
481
477
  end
482
478
  end
483
479
  rescue StandardError => e
484
- error e
480
+ log.error e
485
481
  raise if exception
486
482
 
487
- emphasize e, message('git', cmd)
483
+ warn e
488
484
  end
489
485
  end
490
486
 
@@ -497,7 +493,7 @@ module Squared
497
493
  next if grep && !line.match?(grep)
498
494
 
499
495
  if loglevel
500
- log loglevel, line
496
+ log.add loglevel, line
501
497
  else
502
498
  sub&.each { |h| line = sub_style(line, **h) }
503
499
  if banner
@@ -516,37 +512,53 @@ module Squared
516
512
  return unless verbose?
517
513
 
518
514
  if size > 0
519
- args = theme[:banner]&.reject { |s| s.to_s.end_with?('!') } || []
520
- args << :bold if args.size <= 1
521
- puts print_footer "#{sub_style(size, *args)} #{size == 1 ? type.sub(/s$/, '') : type}"
515
+ styles = theme.fetch(:banner, []).reject { |s| s.to_s.end_with?('!') }
516
+ styles << :bold if styles.size <= 1
517
+ puts print_footer("#{size} #{size == 1 ? type.sub(/s$/, '') : type}",
518
+ sub: { styles: styles, pat: /^(\d+)(.+)$/ })
522
519
  else
523
520
  puts empty_status("No #{type} were #{action}", 'grep', grep)
524
521
  end
525
522
  end
526
523
 
527
- def source_path(files)
528
- files.select { |val| source_path?(val) }.map { |val| val == '.' ? '.' : shell_quote(base_path(val.strip)) }
524
+ def source_path(files, pass: false)
525
+ files = files.select { |val| source_path?(val) } unless pass
526
+ files.map { |val| val == '.' ? '.' : shell_quote(base_path(val.strip)) }
529
527
  end
530
528
 
531
529
  def source_path?(val)
532
- return val.to_s.start_with?("#{path}#{::File::SEPARATOR}") if Pathname.new(val).absolute?
530
+ return val.to_s.start_with?(File.join(path, '').to_s) if Pathname.new(val).absolute?
533
531
 
534
532
  !val.match?(%r{^\.\.[/\\]})
535
533
  end
536
534
 
537
535
  private
538
536
 
537
+ def append_pull(opts, list, flag = nil)
538
+ append_submodules flag
539
+ opts.each do |opt|
540
+ if list.include?(opt)
541
+ @session << "--#{opt}"
542
+ elsif opt.match(/^depth=(\d+)$/)
543
+ @session << "--depth=#{$1}"
544
+ end
545
+ end
546
+ end
547
+
539
548
  def append_commit(val)
540
549
  val = val.to_s.strip
541
550
  val.empty? ? 'HEAD' : val
542
551
  end
543
552
 
544
- def append_pathspec(files, expect: false)
545
- files = source_path(files)
546
- if files.empty?
547
- raise ArgumentError, message('pathspec not within worktree', hint: 'invalid') if expect
548
- else
553
+ def append_pathspec(files = [], expect: false, pass: false)
554
+ if files.empty? && (val = option('pathspec'))
555
+ files = split_escape(val)
556
+ end
557
+ files = source_path(files, pass: pass)
558
+ if !files.empty?
549
559
  @session << "-- #{files.join(' ')}"
560
+ elsif expect
561
+ raise_error(pass ? 'pathspec not present' : 'pathspec not within worktree', hint: 'invalid')
550
562
  end
551
563
  end
552
564
 
@@ -555,9 +567,7 @@ module Squared
555
567
  end
556
568
 
557
569
  def append_head
558
- return unless (val = option('head')) || (val = option('tree-ish'))
559
-
560
- @session << val
570
+ @session << (option('head') || option('tree-ish'))
561
571
  end
562
572
 
563
573
  def append_ours
@@ -576,11 +586,19 @@ module Squared
576
586
  end
577
587
  end
578
588
 
579
- def option(val, equals: nil)
580
- ret = ENV.fetch("GIT_#{val.gsub(/\W/, '_').upcase}", '')
581
- return ret == equals.to_s unless equals.nil?
589
+ def append_option(list)
590
+ list.each { |val| @session << "--#{val}" if option(val) }
591
+ end
582
592
 
583
- ret unless ret.empty? || ret == '0'
593
+ def option(*args, equals: nil, zero: true)
594
+ for val in args
595
+ break if (ret = ENV["GIT_#{val.gsub(/\W/, '_').upcase}"])
596
+ end
597
+ if !equals.nil?
598
+ ret == equals.to_s
599
+ elsif !ret.nil? && !ret.empty? && !(ret == '0' && zero)
600
+ ret
601
+ end
584
602
  end
585
603
 
586
604
  def git_session(*cmd)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- module Repo
4
+ module Workspace
5
5
  module Project
6
6
  class Node < Git
7
7
  REF = :node
@@ -33,19 +33,21 @@ module Squared
33
33
  run: nil
34
34
  }.freeze
35
35
 
36
- def initialize(name, path, workspace, *, **kwargs)
36
+ attr_reader :package
37
+
38
+ def initialize(name, path, workspace, *, dev: nil, prod: nil, **kwargs)
37
39
  super
38
40
  initialize_script(REF)
39
41
  if (opts = env('BUILD', strict: true))
40
- raise ArgumentError, message("BUILD_#{@name.upcase}", opts) if @output[0].is_a?(::Array)
41
-
42
+ raise_error("BUILD_#{@name.upcase}", opts) if @output[0].is_a?(::Array)
42
43
  @output[1] = opts
43
44
  else
44
45
  @output[1] = (@script && @script[:run]) || workspace.script
45
46
  end
46
- @dev = workspace.bool_match(env('BUILD', suffix: 'DEV'), kwargs.delete(:dev))
47
- @prod = workspace.bool_match(env('BUILD', suffix: 'PROD'), kwargs.delete(:prod))
47
+ @dev = dev
48
+ @prod = prod
48
49
  @pm = {}
50
+ @package = base_path('package.json')
49
51
  end
50
52
 
51
53
  def populate(*)
@@ -105,7 +107,7 @@ module Squared
105
107
  elsif dir.is_a?(::String)
106
108
  dest = workspace.root_path(dir)
107
109
  elsif dir.is_a?(::Symbol)
108
- dest = Repo.resolve(dir)&.path
110
+ dest = Workspace.resolve(dir)&.path
109
111
  elsif dir.is_a?(Project)
110
112
  dest = dir.path
111
113
  elsif dir.is_a?(::Hash)
@@ -129,7 +131,7 @@ module Squared
129
131
 
130
132
  from = base_path(from)
131
133
  dest = dest.join(subdir, into || project)
132
- warn "cp #{from.join(glob)} #{dest}"
134
+ log.warn "cp #{from.join(glob)} #{dest}"
133
135
  copy_d(from, dest, glob: glob, verbose: verbose?)
134
136
  end
135
137
  end
@@ -192,7 +194,7 @@ module Squared
192
194
  append_nocolor
193
195
  end
194
196
  append_loglevel
195
- run(exception: workspace.exception)
197
+ run(exception: workspace.exception, sync: invoked_sync?('depend'))
196
198
  end
197
199
  end
198
200
 
@@ -200,37 +202,37 @@ module Squared
200
202
  require 'json'
201
203
  rev ||= prod? ? :patch : :minor
202
204
  cmd = pnpm? ? 'pnpm outdated' : 'npm outdated'
203
- print_item format_banner(message("#{cmd}#{opts.include?('dry-run') ? ' --dry-run' : ''}"), multitask: true)
205
+ if invoked_sync?('outdated')
206
+ print_item format_banner(message("#{cmd}#{opts.include?('dry-run') ? ' --dry-run' : ''}"), multiple: true)
207
+ end
204
208
  pwd = Dir.pwd
205
209
  Dir.chdir(path)
206
- info cmd
210
+ log.info cmd
207
211
  data = `#{cmd} --json --loglevel=error`
208
212
  Dir.chdir(pwd)
209
213
  json = JSON.parse(doc = package.read)
210
- pat = /^(\d+)(\.)(\d+)(\.)(\d+)$/
211
214
  dep1 = json['dependencies'] || {}
212
215
  dep2 = json['devDependencies'] || {}
213
216
  found = []
214
217
  avail = []
215
218
  if !data.empty?
216
- validate = ->(ver) { ver.match?(pat) }
217
219
  JSON.parse(data).each_pair do |key, val|
218
220
  val = val.find { |item| item['dependent'] == json['name'] } if val.is_a?(Array)
219
221
  next unless val && (file = dep1[key] || dep2[key])
220
222
 
221
223
  ch = file[0]
222
- unless ch.match?(/[~^]/)
224
+ unless ch =~ /[~^]/
223
225
  avail << [key, file, val['latest'], true]
224
226
  next
225
227
  end
226
228
  file = file[1..-1]
227
229
  cur = val['current']
228
- want = if rev == :major && validate.(val['latest'])
230
+ want = if rev == :major && val['latest'] =~ SEM_VER
229
231
  [val['latest'], val['wanted']].max { |a, b| a <=> b }
230
232
  else
231
233
  val['wanted']
232
234
  end
233
- next unless (cur != want || file != want) && (validate.(want) || !validate.(file))
235
+ next unless (cur != want || file != want) && (want.match?(SEM_VER) || !file.match?(SEM_VER))
234
236
 
235
237
  a, b = file.split('.')
236
238
  c, d = want.split('.')
@@ -241,7 +243,7 @@ module Squared
241
243
  when :minor
242
244
  upgrade = ch == '^' && (a == '0' ? c == '0' && b == d : a == c)
243
245
  when :patch
244
- upgrade = a == c && b == d
246
+ upgrade = a == c && b == d && Regexp.last_match(5)
245
247
  end
246
248
  if upgrade
247
249
  next if file == want
@@ -301,7 +303,7 @@ module Squared
301
303
  a = sub_style(a, :bold)
302
304
  sub_style(c, :green, :bold)
303
305
  else
304
- sub_style(c, :green, :bold, pat: pat, index: d)
306
+ sub_style(c, :green, :bold, pat: SEM_VER, index: d)
305
307
  end
306
308
  puts "#{pad_ord.(i, found)}. #{a}#{b.ljust(col2)}#{c}"
307
309
  end
@@ -349,7 +351,7 @@ module Squared
349
351
  elsif args.is_a?(::String)
350
352
  cmd << args
351
353
  else
352
- raise ArgumentError, message("#{cmd.first} script name", hint: args.nil? ? 'missing' : 'invalid')
354
+ raise_error("#{cmd.first} script name", hint: args.nil? ? 'missing' : 'invalid')
353
355
  end
354
356
  cmd.join(' ')
355
357
  end
@@ -366,7 +368,7 @@ module Squared
366
368
  end
367
369
 
368
370
  def depend?
369
- !!@depend || outdated?
371
+ outdated? || !!@depend
370
372
  end
371
373
 
372
374
  def copy?
@@ -465,12 +467,6 @@ module Squared
465
467
  end
466
468
  end
467
469
  end
468
-
469
- private
470
-
471
- def package
472
- @package ||= base_path('package.json')
473
- end
474
470
  end
475
471
  end
476
472
  end