squared 0.8.1 → 0.8.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 258af4963cc0c6951fd5f14a96218cbb9cd3016714ba8b03d1fc016a7fb6d894
4
- data.tar.gz: 58211867320953b6bd4c7fae463195e65590754369bd3cbb8896fd46e41f18d4
3
+ metadata.gz: 53991d0e40acab903d9e2715fcc37a2f69853bcbc25ba610c04c1a7331ac865c
4
+ data.tar.gz: fa4913add4c429e7bbceda66f75721af58620b54549591a911bb7b4b4081e913
5
5
  SHA512:
6
- metadata.gz: 5f0026e471c3dcfd8f75eae152732a9ce7b12347f1e5a86464434adc1fbc4ea87e3fb627c456db49145ec534255155c1e3600c623159d4420e5ab0c5c33233d0
7
- data.tar.gz: f692395f2fdc71738669010a392cbf5fe4793edc71b920dd7873748a97bc0e5bef8cc6e17d2af93ec16d92480b86b554204fd5f4a2ce04e52d2704988cb2b3a6
6
+ metadata.gz: 5a81aadedff0d5e4288879f31f80aa0cc3c1d2997958278e0724067da6faa0452223660829870349334d35f37d6936b6ea83313c76981f67b5d095a3f8f85202
7
+ data.tar.gz: 84a885286b2abad87cd7b381e1fb2b71c0f7619b0486b6647b5b766eccae2fc8bb9ae845853f42115ff019e10b9d15e225b4f19d480288b9b9d194a4730b2fd3
data/CHANGELOG.md CHANGED
@@ -1,5 +1,52 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.8.2] - 2026-07-05
4
+
5
+ ### Added
6
+
7
+ - Docker client global options can be preconfigured for every session.
8
+ - Docker command image action history was implemented.
9
+ - NPM command install can bypass engines with ENV and engine-strict=false.
10
+
11
+ ### Changed
12
+
13
+ - OptionPartition method uniq! parameter pass was converted into keyword.
14
+ - Project global ENV for BANNER and STRICT can accept boolean values.
15
+ - Series method exclude? parameter empty was converted into keyword.
16
+
17
+ ## [0.7.9] - 2026-07-04
18
+
19
+ ### Added
20
+
21
+ - Docker command image action inspect was implemented.
22
+
23
+ ### Changed
24
+
25
+ - Project global ENV for BANNER and STRICT can accept boolean values.
26
+
27
+ ## [0.6.16]
28
+
29
+ ### Added
30
+
31
+ - Git command pull action all supports filter pattern negation.
32
+
33
+ ## [0.5.25]
34
+
35
+ ### Fixed
36
+
37
+ - See `0.4.39`.
38
+
39
+ ## [0.4.39]
40
+
41
+ ### Changed
42
+
43
+ - Common global argument OUT with a file separator overrides PIPE.
44
+
45
+ ### Fixed
46
+
47
+ - Git output list results did not hide footer when banner was disabled.
48
+ - Project banners which were empty were being printed.
49
+
3
50
  ## [0.8.1] - 2026-06-17
4
51
 
5
52
  ### Fixed
@@ -1938,8 +1985,10 @@
1938
1985
 
1939
1986
  - Changelog was created.
1940
1987
 
1988
+ [0.8.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.2
1941
1989
  [0.8.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.1
1942
1990
  [0.8.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.0
1991
+ [0.7.9]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.9
1943
1992
  [0.7.8]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.8
1944
1993
  [0.7.7]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.7
1945
1994
  [0.7.6]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.6
@@ -1949,6 +1998,7 @@
1949
1998
  [0.7.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.2
1950
1999
  [0.7.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.1
1951
2000
  [0.7.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.0
2001
+ [0.6.16]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.16
1952
2002
  [0.6.15]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.15
1953
2003
  [0.6.14]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.14
1954
2004
  [0.6.13]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.13
@@ -1965,6 +2015,7 @@
1965
2015
  [0.6.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.2
1966
2016
  [0.6.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.1
1967
2017
  [0.6.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.0
2018
+ [0.5.25]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.25
1968
2019
  [0.5.24]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.24
1969
2020
  [0.5.23]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.23
1970
2021
  [0.5.22]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.22
@@ -1990,6 +2041,7 @@
1990
2041
  [0.5.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.2-ruby
1991
2042
  [0.5.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.1-ruby
1992
2043
  [0.5.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.0-ruby
2044
+ [0.4.39]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.39
1993
2045
  [0.4.38]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.38
1994
2046
  [0.4.37]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.37
1995
2047
  [0.4.36]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.36
data/README.md CHANGED
@@ -98,6 +98,7 @@ Workspace::Application
98
98
  .with(:docker, only: ["build", "compose"], hide: [:windows?]) do # When true hide entire group (formerly pass 0.6.0)
99
99
  .add("squared", "docker", file: "Dockerfile", context: ".", tag: "latest", registry: "localhost:5000", username: "squared", # compose publish => { oci: "oci://docker.io" }
100
100
  args: "--ssh=default",
101
+ client: { config: '/home/user/.docker', tls: true }, # global options
101
102
  secrets: ["id=github,env=GITHUB_TOKEN"],
102
103
  mounts: ["src=.,dst=/project,ro,bind-propagation=rshared"]) do # Docker
103
104
  series(:clean) do # run | depend | doc | lint | test | copy | clean
@@ -871,44 +872,44 @@ Features can be enabled through ENV when calling global tasks such as through *C
871
872
 
872
873
  * Prefix: BUNDLE/GEM/RBS
873
874
 
874
- | Command | Flag | ENV |
875
- | :--------- | :-------- | :---------------------------------------------------------- |
876
- | depend | - | BINSTUBS=s JOBS=n |
877
- | depend | update | VERSION=major|minor|patch STRICT CONSERVATIVE |
878
- | outdated | - | U|UPDATE=major|minor|patch ONLY_EXPLICIT DRY_RUN |
879
- | gem | outdated | DOCUMENT=0,1 USER_INSTALL=0,1 |
880
- | rbs | prototype | Y=0,1 |
875
+ | Command | Flag | ENV |
876
+ | :--------- | :-------- | :------------------------------------------------------------------- |
877
+ | depend | - | BINSTUBS=s JOBS=n |
878
+ | depend | update | VERSION=major|minor|patch STRICT CONSERVATIVE |
879
+ | outdated | - | U|UPDATE=major|minor|patch ONLY_EXPLICIT DRY_RUN |
880
+ | gem | outdated | DOCUMENT=0,1 USER_INSTALL=0,1 |
881
+ | rbs | prototype | Y=0,1 |
881
882
 
882
883
  #### Node
883
884
 
884
885
  * Prefix: NPM/PNPM/YARN
885
886
 
886
- | Command | Flag | ENV |
887
- | :------------- | :------------- | :------------------------------------------------- |
888
- | depend | - | FORCE CI IGNORE_SCRIPTS |
889
- | outdated | - | U|UPDATE=major|minor|patch SAVE_EXACT DIFF DRY_RUN |
890
- | publish | - | OTP=s TAG=s ACCESS=0,1,s DRY_RUN Y |
891
- | depend package | * | PACAKGE_LOCK|LOCKFILE=0 NO_LOCKFILE=1 Y |
892
- | npm | depend | APPROVE_SCRIPTS=s |
893
- | npm | package | SAVE IGNORE_SCRIPTS STRICT_PEER_DEPS |
894
- | pnpm | depend | PUBLIC_HOIST_PATTERN=s APPROVE_BUILDS |
895
- | pnpm | depend:add | ALLOW_BUILD=s |
896
- | yarn | depend package | IGNORE_ENGINES |
897
- | yarn | depend:add | W|IGNORE_WORKSPACE_ROOT_CHECK=0 |
898
- | npm pnpm | depend package | CPU=s OS=s LIBC=s |
887
+ | Command | Flag | ENV |
888
+ | :------------- | :------------- | :---------------------------------------------------------- |
889
+ | depend | - | FORCE CI IGNORE_SCRIPTS |
890
+ | outdated | - | U|UPDATE=major|minor|patch SAVE_EXACT DIFF DRY_RUN |
891
+ | publish | - | OTP=s TAG=s ACCESS=0,1,s DRY_RUN Y |
892
+ | depend package | * | PACAKGE_LOCK|LOCKFILE=0 NO_LOCKFILE=1 Y |
893
+ | npm | depend | APPROVE_SCRIPTS=0,1,s ALLOW_SCRIPTS=0,1,s ENGINE_STRICT=0,1 |
894
+ | npm | package | SAVE IGNORE_SCRIPTS STRICT_PEER_DEPS |
895
+ | pnpm | depend | PUBLIC_HOIST_PATTERN=s APPROVE_BUILDS |
896
+ | pnpm | depend:add | ALLOW_BUILD=s |
897
+ | yarn | depend package | IGNORE_ENGINES |
898
+ | yarn | depend:add | W|IGNORE_WORKSPACE_ROOT_CHECK=0 |
899
+ | npm pnpm | depend package | CPU=s OS=s LIBC=s |
899
900
 
900
901
  #### Python
901
902
 
902
903
  * Prefix: PIP/POETRY
903
904
 
904
- | Command | Flag | ENV |
905
- | :--------- | :-------- | :---------------------------------------------------------- |
906
- | global | * | CACHE_DIR=0,s PROXY=s PYTHON=s COLOR=0 |
907
- | depend | - | E|EDITABLE=0,s BUILD_ISOLATION=0 |
908
- | outdated | - | U|UPDATE=major|minor|patch NOT_REQUIRED=0 L|LOCAL DRY_RUN |
909
- | venv | exec | INTERACTIVE=0 |
910
- | poetry | * | PROJECT=s |
911
- | poetry | depend | NO_ROOT |
905
+ | Command | Flag | ENV |
906
+ | :--------- | :-------- | :------------------------------------------------------------------- |
907
+ | global | * | CACHE_DIR=0,s PROXY=s PYTHON=s COLOR=0 |
908
+ | depend | - | E|EDITABLE=0,s BUILD_ISOLATION=0 |
909
+ | outdated | - | U|UPDATE=major|minor|patch NOT_REQUIRED=0 L|LOCAL DRY_RUN |
910
+ | venv | exec | INTERACTIVE=0 |
911
+ | poetry | * | PROJECT=s |
912
+ | poetry | depend | NO_ROOT |
912
913
 
913
914
  ## LICENSE
914
915
 
@@ -166,11 +166,19 @@ module Squared
166
166
  end
167
167
 
168
168
  def env_pipe(key, default = 1, root: nil, **kwargs)
169
+ out = 1
169
170
  case key
170
171
  when ::String
171
172
  case (ret = env_value(key, **kwargs))
172
173
  when '0', '1', '2'
173
174
  return ret.to_i
175
+ else
176
+ out = default if default.is_a?(::Numeric)
177
+ if ret.include?(File::SEPARATOR)
178
+ default = ret
179
+ elsif key.include?(File::SEPARATOR)
180
+ default = key
181
+ end
174
182
  end
175
183
  when ::Numeric
176
184
  return key if key.between?(0, 2)
@@ -181,7 +189,7 @@ module Squared
181
189
  (root ? Pathname.new(root) + default : Pathname.new(default)).realdirpath
182
190
  rescue => e
183
191
  warn e
184
- 1
192
+ out
185
193
  end
186
194
  end
187
195
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- VERSION = '0.8.1'
4
+ VERSION = '0.8.2'
5
5
  end
@@ -115,7 +115,13 @@ module Squared
115
115
  @stage = Support.hashlist
116
116
  self.home = home
117
117
  self.exception = env_bool exception
118
- self.pipe = $DEBUG ? 2 : env_pipe(pipe, (ARG[:OUT] && env(ARG[:OUT])) || 1, root: home)
118
+ self.pipe = if $DEBUG
119
+ 2
120
+ elsif (out = ARG[:OUT]) && out.include?(File::SEPARATOR)
121
+ env_pipe(out, pipe, root: home)
122
+ else
123
+ env_pipe(pipe, (out && env(out)) || 1, root: home)
124
+ end
119
125
  self.verbose = if $VERBOSE.nil?
120
126
  false
121
127
  elsif verbose.nil?
@@ -1612,7 +1612,7 @@ module Squared
1612
1612
  append_keys(kwargs, b, :opts)
1613
1613
  with.concat(c)
1614
1614
  end
1615
- OptionPartition.uniq!(args, pass) if pass
1615
+ OptionPartition.uniq!(args, pass: pass) if pass
1616
1616
  [args, kwargs, with]
1617
1617
  end
1618
1618
 
@@ -1633,7 +1633,7 @@ module Squared
1633
1633
  end
1634
1634
  if args
1635
1635
  args.unshift(*a)
1636
- OptionPartition.uniq!(args, pass) if pass
1636
+ OptionPartition.uniq!(args, pass: pass) if pass
1637
1637
  end
1638
1638
  kwargs&.update(b) { |_, obj| obj }
1639
1639
  nil
@@ -1703,7 +1703,13 @@ module Squared
1703
1703
  ret += 1
1704
1704
  break out if first
1705
1705
  end
1706
- print_item banner, lines if banner && (ret > 0 || (!pass && !first))
1706
+ if banner && (ret > 0 || (!pass && !first))
1707
+ if banner.empty?
1708
+ print_item(*lines)
1709
+ else
1710
+ print_item(banner, *lines)
1711
+ end
1712
+ end
1707
1713
  ret
1708
1714
  end
1709
1715
 
@@ -1729,7 +1735,7 @@ module Squared
1729
1735
  end
1730
1736
 
1731
1737
  def print_run(cmd, banner = true, verbose: nil, **)
1732
- return if banner || !stdout? || verbose == false || env('BANNER', equals: '0')
1738
+ return if banner || !stdout? || verbose == false || env('BANNER', equals: %w[0 false])
1733
1739
 
1734
1740
  puts "\n> #{cmd}"
1735
1741
  printsucc
@@ -1738,7 +1744,7 @@ module Squared
1738
1744
  def print_item(*val, series: false)
1739
1745
  puts unless printfirst?
1740
1746
  printsucc unless series
1741
- puts val unless val.empty? || (val.size == 1 && !val.first)
1747
+ puts val unless val.empty? || (val.size == 1 && (!val.first || val.first.empty?))
1742
1748
  end
1743
1749
 
1744
1750
  def print_banner(*lines, client: false, styles: theme[:banner], border: borderstyle)
@@ -2701,7 +2707,12 @@ module Squared
2701
2707
  end
2702
2708
 
2703
2709
  def banner?
2704
- ARG[:BANNER] && env('BANNER', notequals: '0')
2710
+ case (val = env('BANNER', ignore: false))
2711
+ when '0', 'false'
2712
+ false
2713
+ else
2714
+ !val.nil? || ARG[:BANNER]
2715
+ end
2705
2716
  end
2706
2717
 
2707
2718
  def pwd?
@@ -2736,7 +2747,12 @@ module Squared
2736
2747
  end
2737
2748
 
2738
2749
  def strict?
2739
- (ARG[:STRICT] || exception?(Logger::FATAL)) && env('STRICT', notequals: '0')
2750
+ case (val = env('STRICT', ignore: false))
2751
+ when '0', 'false'
2752
+ false
2753
+ else
2754
+ !val.nil? || ARG[:STRICT] || exception?(Logger::FATAL)
2755
+ end
2740
2756
  end
2741
2757
 
2742
2758
  def serve?
@@ -56,7 +56,7 @@ module Squared
56
56
  exec: %w[d|detach i|interactive privileged t|tty detach-keys=q e|env=qq env-file=p u|user=e
57
57
  w|workdir=q].freeze,
58
58
  commit: %w[no-pause a|author=q c|change=q m|message=q pause=b?].freeze,
59
- inspect: %w[s|size f|format=q type=b].freeze,
59
+ inspect: %w[s|size f|format=q].freeze,
60
60
  start: %w[a|attach i|interactive detach-keys=q].freeze,
61
61
  stop: %w[s|signal=b t|timeout=i].freeze,
62
62
  restart: %w[s|signal=b t|timeout=i].freeze,
@@ -65,11 +65,14 @@ module Squared
65
65
  attach: %w[no-stdin detach-keys=q sig-proxy=!?].freeze
66
66
  }.freeze,
67
67
  image: {
68
+ common: %w[platform=q].freeze,
69
+ inspect: %w[f|format].freeze,
70
+ history: %w[f|format no-trunc q|quiet H|human=!?].freeze,
68
71
  ls: %w[a|all digests no-trunc q|quiet tree f|filter=q format=q].freeze,
69
- pull: %w[a|all-tags platform=q q|quiet].freeze,
70
- push: %w[a|all-tags platform=q q|quiet].freeze,
71
- rm: %w[f|force no-prune platform=q].freeze,
72
- save: %w[o|output=p platform=q].freeze
72
+ pull: %w[a|all-tags q|quiet].freeze,
73
+ push: %w[a|all-tags q|quiet].freeze,
74
+ rm: %w[f|force no-prune].freeze,
75
+ save: %w[o|output=p].freeze
73
76
  }.freeze,
74
77
  network: {
75
78
  connect: %w[alias=b driver-opt=q gw-priority=n ip=b ip6=q link=b link-local-ip=q].freeze,
@@ -114,7 +117,7 @@ module Squared
114
117
  'build' => %i[tag context].freeze,
115
118
  'compose' => %i[build create publish run exec up down service].freeze,
116
119
  'bake' => %i[build compose check].freeze,
117
- 'image' => %i[ls rm pull push tag save].freeze,
120
+ 'image' => %i[ls rm pull push tag save inspect history].freeze,
118
121
  'container' => %i[attach commit create diff exec inspect kill pause restart rm run start stats stop top
119
122
  unpause update].freeze,
120
123
  'network' => %i[connect disconnect create].freeze,
@@ -124,13 +127,31 @@ module Squared
124
127
  attr_reader :context
125
128
  attr_accessor :tag
126
129
 
127
- def initialize(*, mounts: [], **kwargs)
130
+ def initialize(*, client: nil, mounts: [], **kwargs)
128
131
  super
129
132
  self.global = nil
130
133
  return unless dockerfile(kwargs[:file]).exist?
131
134
 
132
135
  @tag = kwargs[:tag] || tagname("#{@project}:#{@version || 'latest'}")
133
136
  @context = kwargs[:context]
137
+ @client = if client
138
+ opts = []
139
+ client.each do |key, val|
140
+ val = case (key = key.to_s)
141
+ when 'config'
142
+ basepath!(val, type: 'd')
143
+ when 'tlscacert', 'tlscert', 'tlskey'
144
+ basepath!(val, type: 'f')
145
+ when 'context', 'host', 'log-level'
146
+ quote_option(key, val)
147
+ when 'debug', 'tls', 'tlsverify'
148
+ opts << key
149
+ next
150
+ end
151
+ opts << quote_option(key, val) if val
152
+ end
153
+ opts unless opts.empty?
154
+ end
134
155
  @mounts = mounts
135
156
  @secrets = kwargs[:secrets]
136
157
  @registry = tagjoin kwargs[:registry], kwargs[:username]
@@ -278,7 +299,7 @@ module Squared
278
299
  end
279
300
  end
280
301
  else
281
- format_desc action, flag, "opts*,id/name#{flag == :update ? '+' : '*'}"
302
+ format_desc action, flag, "opts*,id/name#{flag == :update || flag == :inspect ? '+' : '*'}"
282
303
  task flag do |_, args|
283
304
  container flag, args.to_a
284
305
  end
@@ -289,7 +310,7 @@ module Squared
289
310
  next unless @registry
290
311
 
291
312
  format_desc action, flag, 'tag?,registry/username?,opts*'
292
- task flag, [:tag] do |_, args|
313
+ task flag do |_, args|
293
314
  image flag, args.to_a
294
315
  end
295
316
  when :pull
@@ -298,6 +319,16 @@ module Squared
298
319
  id = param_guard(action, flag, args: args, key: :tag)
299
320
  image(flag, args.extras, id: id)
300
321
  end
322
+ when :inspect, :history
323
+ format_desc action, flag, "opts*,id#{'+' if flag == :inspect}"
324
+ task flag do |_, args|
325
+ args = args.to_a
326
+ if args.empty?
327
+ choice_command :image, flag
328
+ else
329
+ image flag, args.to_a
330
+ end
331
+ end
301
332
  else
302
333
  format_desc(action, flag, case flag
303
334
  when :rm, :save then 'id,opts*'
@@ -536,7 +567,7 @@ module Squared
536
567
  end
537
568
  end
538
569
  append_command(flag, id || tagmain, op.extras)
539
- when :update
570
+ when :update, :inspect
540
571
  raise ArgumentError, message('missing container', hint: flag) if op.empty?
541
572
 
542
573
  op.append(escape: true, strip: /^:/)
@@ -576,7 +607,9 @@ module Squared
576
607
 
577
608
  def image(flag, opts = [], sync: true, id: nil, registry: nil, filter: nil)
578
609
  cmd, opts = docker_session('image', flag, opts: opts)
579
- op = OptionPartition.new(opts, OPT_DOCKER[:image].fetch(flag, []), cmd, project: self, strict: strict?)
610
+ list = OPT_DOCKER[:image].fetch(flag, [])
611
+ list += OPT_DOCKER[:image][:common] unless flag == :ls || flag == :tag
612
+ op = OptionPartition.new(opts, list, cmd, project: self, strict: strict?)
580
613
  exception = exception?
581
614
  banner = true
582
615
  from = symjoin 'image', flag
@@ -654,6 +687,15 @@ module Squared
654
687
  sync = false
655
688
  exception ||= true
656
689
  banner = false
690
+ when :inspect, :history
691
+ raise ArgumentError, message('missing image', hint: flag) if op.empty?
692
+
693
+ if flag == :history
694
+ op.add_first(escape: true, strip: /^:/)
695
+ .clear
696
+ else
697
+ op.append(escape: true, strip: /^:/)
698
+ end
657
699
  end
658
700
  success?(run(sync: sync, exception: exception, banner: banner, from: from), flag == :tag || flag == :save)
659
701
  end
@@ -725,6 +767,7 @@ module Squared
725
767
  end
726
768
 
727
769
  def docker_session(*cmd, opts: nil)
770
+ opts = OptionPartition.union(Array(opts), @client) if @client
728
771
  return session('docker', *cmd) unless opts
729
772
 
730
773
  op = OptionPartition.new(opts, OPT_DOCKER[:common], project: self, strict: strict?)
@@ -1118,13 +1118,13 @@ module Squared
1118
1118
  op = OptionPartition.new(opts, OPT_GIT[:pull], cmd, project: self, strict: strict?,
1119
1119
  no: OPT_GIT[:no][:pull])
1120
1120
  opts -= op.extras
1121
- reg = matchmap op
1121
+ reg, neg = matchmap(op, negate: true)
1122
1122
  session_done op.target
1123
1123
  heads = []
1124
1124
  cur = nil
1125
1125
  foreachref('heads', format: '%(if)%(HEAD)%(then)* %(end)%(refname:short)').each do |line|
1126
1126
  cur ||= line.delete_prefix!('* ')
1127
- heads << line if matchany?(reg, line)
1127
+ heads << line if matchany?(reg, line) && !matchany?(neg, line, empty: false)
1128
1128
  end
1129
1129
  raise message('head not found', hint: 'for-each-ref') unless cur
1130
1130
 
@@ -1304,7 +1304,7 @@ module Squared
1304
1304
  op.clear
1305
1305
  out, banner, from = source(io: true)
1306
1306
  print_item banner
1307
- list_result(write_lines(out), 'objects', from: from)
1307
+ list_result(write_lines(out), 'objects', banner: banner, from: from)
1308
1308
  return
1309
1309
  end
1310
1310
  else
@@ -1356,7 +1356,7 @@ module Squared
1356
1356
  end
1357
1357
  out, banner, from = source(io: true)
1358
1358
  ret = write_lines(out, banner: banner, sub: sub)
1359
- list_result(ret, 'files', action: 'modified', from: from)
1359
+ list_result(ret, 'files', action: 'modified', banner: banner, from: from)
1360
1360
  end
1361
1361
 
1362
1362
  def revbuild(flag = nil, opts = [], **kwargs)
@@ -1525,7 +1525,7 @@ module Squared
1525
1525
  out, banner, from = source(io: true)
1526
1526
  print_item banner
1527
1527
  ret = write_lines(out, grep: op.extras)
1528
- list_result(ret, 'tags', grep: op.extras, from: from)
1528
+ list_result(ret, 'tags', grep: op.extras, banner: banner, from: from)
1529
1529
  return
1530
1530
  end
1531
1531
  if (ret = source) && (remote ||= option('remote'))
@@ -1536,9 +1536,9 @@ module Squared
1536
1536
 
1537
1537
  def log_(flag, opts = [], range: [], index: [], grep: [])
1538
1538
  cmd, opts = git_session('log', opts: opts)
1539
- op = OptionPartition.new(opts, collect_hash(OPT_GIT[:log]), cmd, project: self, strict: strict?,
1540
- no: collect_hash(OPT_GIT[:no][:log]),
1541
- first: matchpathspec)
1539
+ op = OptionPartition.new(opts, collect_hash(OPT_GIT[:log]), cmd,
1540
+ project: self, strict: strict?, no: collect_hash(OPT_GIT[:no][:log]),
1541
+ first: matchpathspec)
1542
1542
  case flag
1543
1543
  when :between, :contain
1544
1544
  op.add_quote(range.join(flag == :between ? '..' : '...'))
@@ -1794,7 +1794,7 @@ module Squared
1794
1794
  opt_style(color(:green), /^(\*\s+)(\S+)(.*)$/, 2),
1795
1795
  opt_style(color(:red), %r{^(\s*)(remotes/\S+)(.*)$}, 2)
1796
1796
  ])
1797
- list_result(ret, 'branches', from: from)
1797
+ list_result(ret, 'branches', banner: banner, from: from)
1798
1798
  return
1799
1799
  else
1800
1800
  if (head = git_spawn('rev-parse --abbrev-ref HEAD').chomp).empty?
@@ -1803,7 +1803,7 @@ module Squared
1803
1803
  git_spawn 'fetch --all --prune --quiet' if option('sync')
1804
1804
  cmd << '-vv --no-abbrev --list'
1805
1805
  out, banner, from = source(io: true)
1806
- first = workspace.size > 1
1806
+ first = from_base?('branch')
1807
1807
  grep = first ? [/^\*\s+#{Regexp.escape(head)}\s/] : []
1808
1808
  ret = write_lines(out, grep: grep, banner: banner, first: first) do |line, index|
1809
1809
  next line if stdin?
@@ -1876,9 +1876,7 @@ module Squared
1876
1876
 
1877
1877
  def restore(flag, opts = [], commit: nil, files: nil)
1878
1878
  cmd, opts = git_session('restore', shell_option(flag, commit, escape: false, force: false), opts: opts)
1879
- op = OptionPartition.new(opts,
1880
- OPT_GIT[:restore] + OPT_GIT[:log][:diff_context],
1881
- cmd,
1879
+ op = OptionPartition.new(opts, OPT_GIT[:restore] + OPT_GIT[:log][:diff_context], cmd,
1882
1880
  project: self, strict: strict?, no: OPT_GIT[:no][:restore], first: matchpathspec)
1883
1881
  append_pathspec(op.extras + (files || []), pass: false)
1884
1882
  source(sync: false, stderr: true)
@@ -1907,8 +1905,7 @@ module Squared
1907
1905
  end
1908
1906
  list = OPT_GIT[:show] + OPT_GIT[:diff][:show] + OPT_GIT[:log][:diff] + OPT_GIT[:log][:diff_context]
1909
1907
  op = OptionPartition.new(opts, list, cmd,
1910
- project: self,
1911
- strict: strict?,
1908
+ project: self, strict: strict?,
1912
1909
  no: OPT_GIT[:no][:show] + collect_hash(OPT_GIT[:no][:log], pass: [:base]))
1913
1910
  op.append(delim: true)
1914
1911
  source(exception: false, banner: flag != :oneline)
@@ -1933,8 +1930,8 @@ module Squared
1933
1930
  cmd << '--sq-quote'
1934
1931
  args = true
1935
1932
  end
1936
- OptionPartition.new(opts, OPT_GIT[:rev_parse], cmd,
1937
- project: self, strict: strict?, no: OPT_GIT[:no][:rev_parse], args: args)
1933
+ OptionPartition.new(opts, OPT_GIT[:rev_parse], cmd, project: self, strict: strict?, args: args,
1934
+ no: OPT_GIT[:no][:rev_parse])
1938
1935
  .append(escape: args)
1939
1936
  end
1940
1937
  source(banner: verbose?)
@@ -1962,7 +1959,7 @@ module Squared
1962
1959
  out, banner, from = source(io: true)
1963
1960
  print_item banner
1964
1961
  ret = write_lines(out, grep: op.extras, prefix: "refs/#{flag}/")
1965
- list_result(ret, flag.to_s, grep: op.extras, from: from)
1962
+ list_result(ret, flag.to_s, grep: op.extras, banner: banner, from: from)
1966
1963
  end
1967
1964
 
1968
1965
  def ls_files(flag, opts = [])
@@ -1972,7 +1969,7 @@ module Squared
1972
1969
  out, banner, from = source(io: true)
1973
1970
  print_item banner
1974
1971
  ret = write_lines(out, grep: op.extras)
1975
- list_result(ret, 'files', grep: op.extras, from: from)
1972
+ list_result(ret, 'files', grep: op.extras, banner: banner, from: from)
1976
1973
  end
1977
1974
 
1978
1975
  def git(flag, opts = [], extras: [])
@@ -2147,10 +2144,10 @@ module Squared
2147
2144
  end
2148
2145
  end
2149
2146
 
2150
- def list_result(size, type, action: 'found', grep: [], from: nil)
2147
+ def list_result(size, type, action: 'found', grep: [], banner: nil, from: nil)
2151
2148
  if size == 0
2152
2149
  puts empty_status("No #{type} were #{action}", 'grep', grep.join(', '))
2153
- elsif stdout?
2150
+ elsif stdout? && (banner.nil? || (banner.is_a?(String) && !banner.empty?))
2154
2151
  styles = theme.fetch(:banner, []).reject { |val| val.to_s.end_with?('!') }
2155
2152
  styles << :bold if styles.size <= 1
2156
2153
  puts print_footer("#{size} #{size == 1 ? type.sub(/((?<!l)e)?s\z/, '') : type}",
@@ -2219,8 +2216,8 @@ module Squared
2219
2216
  append_submodules(target: target, from: from)
2220
2217
  return if !remote && opts.empty?
2221
2218
 
2222
- op = OptionPartition.new(opts, remote ? list + ['refspec=v'] : list, target, project: self, strict: strict?,
2223
- no: no)
2219
+ op = OptionPartition.new(opts, remote ? list + ['refspec=v'] : list, target,
2220
+ project: self, strict: strict?, no: no)
2224
2221
  refspec = op.each_with_object([]) do |opt, out|
2225
2222
  if opt =~ op.values
2226
2223
  case $1
@@ -8,8 +8,8 @@ module Squared
8
8
  common: %w[dry-run=!? force=!? loglevel=b include-workspace-root=!? workspaces=!? w|workspace=v].freeze,
9
9
  common_scripts: %w[dangerously-allow-all-scripts=!? strict-allow-scripts=!? allow-scripts=q].freeze,
10
10
  install: %w[package-lock-only=!? prefer-dedupe=!? E|save-exact=!? before=q cpu=b libc=b os=b].freeze,
11
- install_a: %w[audit=! bin-links=! foreground-scripts=!? fund=! ignore-scripts=!? install-links=!?
12
- package-lock=! strict-peer-deps=!? include=b install-strategy=b omit=b].freeze,
11
+ install_a: %w[audit=! bin-links=! engine-strict=!? foreground-scripts=!? fund=! ignore-scripts=!?
12
+ install-links=!? package-lock=! strict-peer-deps=!? include=b install-strategy=b omit=b].freeze,
13
13
  install_b: %w[no-save B|save-bundle D|save-dev O|save-optional save-peer P|save-prod g|global=!?
14
14
  S|save=!?].freeze,
15
15
  install_c: %w[allow-directory=b? allow-file=b? allow-git=b? allow-remote=b?].freeze,
@@ -327,7 +327,7 @@ module Squared
327
327
  when 'package'
328
328
  format_desc(action, flag, 'opts*', before: case flag
329
329
  when :dedupe, :rebuild then nil
330
- when :reinstall then 'force?'
330
+ when :reinstall then 'f/orce?'
331
331
  else 'name*'
332
332
  end)
333
333
  task flag do |_, args|
@@ -672,8 +672,7 @@ module Squared
672
672
  cmd << '--ignore-scripts' if option('ignore-scripts')
673
673
  cmd << '--dangerously-allow-all-builds' if option('approve-builds')
674
674
  else
675
- cmd = session 'npm'
676
- cmd << (ci = option('ci') ? 'ci' : 'install')
675
+ cmd = session('npm', (ci = option('ci', prefix: 'npm')) ? 'ci' : 'install')
677
676
  option('approve-scripts') do |val|
678
677
  cmd = npm_output 'approve-scripts'
679
678
  cmd << case val
@@ -687,6 +686,26 @@ module Squared
687
686
  print_run cmd, silent?
688
687
  run(cmd, banner: false)
689
688
  end
689
+ option('allow-scripts', ignore: false) do |val|
690
+ cmd << case val
691
+ when '0'
692
+ '--ignore-scripts'
693
+ when 'false'
694
+ '--strict-allow-scripts'
695
+ when '1', 'true'
696
+ '--dangerously-allow-all-scripts'
697
+ else
698
+ quote_option 'allow-scripts', val
699
+ end
700
+ end
701
+ option('engine-strict', ignore: false) do |val|
702
+ cmd << case val
703
+ when '0', 'false'
704
+ '--engine-strict=false'
705
+ else
706
+ '--engine-strict'
707
+ end
708
+ end
690
709
  cmd << '--workspaces=false' if ws
691
710
  cmd << '--force' if option('force')
692
711
  append_nocolor
@@ -1088,6 +1107,7 @@ module Squared
1088
1107
 
1089
1108
  def package(flag, opts = [], packages: [], from: nil)
1090
1109
  workspace.rev_clear(name)
1110
+ force = true if flag == :reinstall && has_value!(opts, 'f')
1091
1111
  yarn = dependtype(:yarn)
1092
1112
  if yarn > 0 && !(yarn == 1 && ((flag == :update && !packages.empty?) || %i[approve deny
1093
1113
  rebuild].include?(flag)))
@@ -1101,8 +1121,8 @@ module Squared
1101
1121
  end
1102
1122
  when :reinstall
1103
1123
  if yarn == 1
1104
- remove_modules(prefix: 'yarn') if opts.include?('force')
1105
- elsif opts.delete('force')
1124
+ remove_modules(prefix: 'yarn') if opts.include?('force') || force
1125
+ elsif opts.delete('force') || force
1106
1126
  opts << 'check-cache'
1107
1127
  end
1108
1128
  opts << 'no-lockfile' if lockfile(true)
@@ -1171,7 +1191,7 @@ module Squared
1171
1191
  spec = 1
1172
1192
  flag = :install
1173
1193
  when :reinstall
1174
- remove_modules(prefix: 'npm') if opts.delete('force')
1194
+ remove_modules(prefix: 'npm') if opts.delete('force') || force
1175
1195
  opts.unshift('package-lock=false') if lockfile(true)
1176
1196
  flag = :install
1177
1197
  end
@@ -507,16 +507,23 @@ module Squared
507
507
  format_desc action, flag, 'f/orce?,l/ocal?,opts*'
508
508
  task flag do |_, args|
509
509
  opts = args.to_a
510
- opts << 'local' if has_value!(opts, 'l')
510
+ opts << 'local' if has_value!(opts, 'l', 'local')
511
511
  opts << 'redownload' if has_value!(opts, 'f', 'force')
512
512
  if (lock = basepath!('Gemfile.lock'))
513
- config = basepath '.bundle', 'config'
514
- if config.exist? && config.read.match?(/\bBUNDLE_FROZEN:\s+"true"/)
515
- if opts.include?('redownload')
516
- run(bundle_output('config unset frozen'), banner: false)
517
- else
518
- print_error('Gemfile.lock is frozen', subject: name, hint: flag)
513
+ case (val = ENV['BUNDLE_FROZEN'])
514
+ when '0', 'false'
515
+ nil
516
+ else
517
+ if val
518
+ print_error("BUNDLE_FROZEN: #{val}", loglevel: Logger::INFO, subject: name, hint: flag)
519
519
  lock = nil
520
+ elsif basepath!('.bundle', 'config')&.read&.match?(/\bBUNDLE_FROZEN:\s+"true"/)
521
+ if opts.include?('redownload')
522
+ run(bundle_output('config unset frozen'), banner: false)
523
+ else
524
+ print_error('Gemfile.lock is frozen', subject: name, hint: flag)
525
+ lock = nil
526
+ end
520
527
  end
521
528
  end
522
529
  lock&.delete
@@ -1843,8 +1850,8 @@ module Squared
1843
1850
  private
1844
1851
 
1845
1852
  def run_repl(*args, opts:, banner:, from:, delim: true, **kwargs)
1846
- op = OptionPartition.new(opts, OPT_RUBY[from], session(*bundle_args(from)), project: self, strict: strict?,
1847
- first: [/\.rb$/])
1853
+ op = OptionPartition.new(opts, OPT_RUBY[from], session(*bundle_args(from)),
1854
+ project: self, strict: strict?, first: [/\.rb$/])
1848
1855
  r = []
1849
1856
  r << 'bundler/setup' if !op.arg?('r') && bundle_load
1850
1857
  r.concat(Array(kwargs[:name])) if kwargs[:name]
@@ -100,7 +100,17 @@ module Squared
100
100
  ret.select { |val| single ? val.size == 1 : val.size > 1 }
101
101
  end
102
102
 
103
- def uniq!(list, pass = [])
103
+ def union(list, other)
104
+ base = list.map { |val| parse_option(val).first }
105
+ other.each do |val|
106
+ next if base.include?(parse_option(val).first)
107
+
108
+ list << val
109
+ end
110
+ list
111
+ end
112
+
113
+ def uniq!(list, pass: [])
104
114
  keys = {}
105
115
  list.each_with_index do |val, i|
106
116
  j = val =~ OPT_VALUE ? $1 : val
@@ -564,11 +574,17 @@ module Squared
564
574
  end
565
575
 
566
576
  def add_first(fallback = nil, prefix: nil, path: false, escape: false, reverse: false, expect: false,
567
- **kwargs)
577
+ strip: nil, **kwargs)
568
578
  val = (reverse ? pop : shift) || fallback
569
579
  if val
570
580
  temp = val
571
- val = val.delete_prefix(prefix) if prefix && val.is_a?(String)
581
+ if val.is_a?(String)
582
+ val = val.delete_prefix(prefix) if prefix
583
+ if strip
584
+ pat, s = Array(strip)
585
+ val = val.gsub(pat, s || '')
586
+ end
587
+ end
572
588
  unless block_given? && !(val = yield val).is_a?(String)
573
589
  if path
574
590
  add_path(val, **kwargs)
@@ -35,13 +35,29 @@ module Squared
35
35
  end
36
36
  end
37
37
 
38
- def matchmap(list, prefix: nil)
39
- list.map do |val|
40
- next val if val.is_a?(Regexp)
41
-
42
- val = ".*#{val}" if prefix && !val.sub!(/\A(\^|\\A)/, '')
43
- Regexp.new("#{prefix}#{val == '*' ? '.+' : val}")
38
+ def matchmap(list, prefix: nil, negate: false)
39
+ ret = negate ? [[], []] : []
40
+ list.each do |val|
41
+ unless val.is_a?(Regexp)
42
+ val = val.dup
43
+ n = 1 if negate && val.delete_prefix!('!')
44
+ if prefix
45
+ a = nil
46
+ val.sub!(/\A(\^|\\A)/) do |s|
47
+ a = s
48
+ nil
49
+ end
50
+ val = ".*#{val}" unless a
51
+ end
52
+ end
53
+ pat = Regexp.new("#{a}#{prefix}#{val == '*' ? '.+' : val}")
54
+ if negate
55
+ ret[n || 0] << pat
56
+ else
57
+ ret << pat
58
+ end
44
59
  end
60
+ ret
45
61
  end
46
62
 
47
63
  def matchany?(list, *args, empty: true)
@@ -157,8 +157,6 @@ module Squared
157
157
  [proj, proj.build? && (script || run), doc && proj.doc?, lint && proj.lint?, test && proj.test?]
158
158
  end
159
159
  .select do |proj, run, doc, lint, test|
160
- next unless proj
161
-
162
160
  proj.doc(sync: true) if doc
163
161
  proj.build(sync: true) if run
164
162
  next if n.anybits?(4)
@@ -88,7 +88,7 @@ module Squared
88
88
  update @session[:parent] if @session[:id].uniq.size > 1
89
89
  update @session[:group]
90
90
  each do |key, items|
91
- next if exclude?(key, true) || @workspace.task_exclude?(t = name_get(key))
91
+ next if exclude?(key, empty: true) || @workspace.task_exclude?(t = name_get(key))
92
92
 
93
93
  key = task_name t
94
94
  title = format_desc(key, out: true)
@@ -217,7 +217,7 @@ module Squared
217
217
  already_invoked? parallel, val
218
218
  end
219
219
 
220
- def exclude?(key, empty = false)
220
+ def exclude?(key, empty: false)
221
221
  @exclude.include?(key) || (empty && (!key?(key) || self[key].empty?))
222
222
  end
223
223
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: squared
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - An Pham
@@ -125,7 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
125
125
  - !ruby/object:Gem::Version
126
126
  version: '0'
127
127
  requirements: []
128
- rubygems_version: 4.0.12
128
+ rubygems_version: 4.0.15
129
129
  specification_version: 4
130
130
  summary: Rake task generator for managing multi-language workspaces.
131
131
  test_files: []