squared 0.7.1 → 0.7.3

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.
@@ -72,6 +72,8 @@ module Squared
72
72
  }.freeze,
73
73
  network: {
74
74
  connect: %w[alias=b driver-opt=q gw-priority=n ip=b ip6=q link=b link-local-ip=q].freeze,
75
+ create: %w[attachable config-only gateway=q ingress internal ipv4 ipv6 aux-address=q config-from=b
76
+ d|driver=b ip-range=q ipam-driver=b ipam-opt=q label=q o|opt=q scope=b subnet=q].freeze,
75
77
  disconnect: %w[f|force].freeze
76
78
  }.freeze
77
79
  }.freeze
@@ -114,7 +116,7 @@ module Squared
114
116
  'image' => %i[ls rm pull push tag save].freeze,
115
117
  'container' => %i[run create exec update commit inspect diff start stop restart pause unpause top stats kill
116
118
  rm].freeze,
117
- 'network' => %i[connect disconnect].freeze,
119
+ 'network' => %i[connect disconnect create].freeze,
118
120
  'ls' => nil
119
121
  })
120
122
 
@@ -126,7 +128,7 @@ module Squared
126
128
  self.global = nil
127
129
  return unless dockerfile(kwargs[:file]).exist?
128
130
 
129
- self.tag = kwargs[:tag] || tagname("#{@project}:#{@version || 'latest'}")
131
+ @tag = kwargs[:tag] || tagname("#{@project}:#{@version || 'latest'}")
130
132
  @context = kwargs[:context]
131
133
  @mounts = mounts
132
134
  @secrets = kwargs[:secrets]
@@ -296,14 +298,18 @@ module Squared
296
298
  end
297
299
  else
298
300
  format_desc(action, flag, case flag
299
- when :rm, :save then 'id*,opts*'
300
- when :tag then 'version?'
301
+ when :rm, :save then 'id,opts*'
302
+ when :tag then 'version'
301
303
  else 'opts*,args*'
302
- end)
304
+ end, before: 'pattern?')
303
305
  task flag do |_, args|
304
306
  args = args.to_a
307
+ n = args.size
308
+ if (n > 1 || (flag == :ls && n > 0)) && OptionPartition.pattern?(args.first)
309
+ filter = args.shift
310
+ end
305
311
  if !args.empty? || flag == :ls
306
- image flag, args
312
+ image(flag, args, filter: filter)
307
313
  else
308
314
  choice_command flag
309
315
  end
@@ -312,8 +318,9 @@ module Squared
312
318
  when 'network'
313
319
  format_desc action, flag, 'target,opts*'
314
320
  task flag, [:target] do |_, args|
315
- if args.target
316
- network(flag, args.extras, target: args.target)
321
+ target = flag == :create ? param_guard(action, flag, args: args, key: :target) : args.target
322
+ if target
323
+ network(flag, args.extras, target: target)
317
324
  else
318
325
  choice_command flag
319
326
  end
@@ -329,8 +336,8 @@ module Squared
329
336
  def clean(*, sync: invoked_sync?('clean'), **)
330
337
  if runnable?(@clean)
331
338
  super
332
- else
333
- image(:rm, sync: sync)
339
+ elsif sync || option('y', prefix: 'docker')
340
+ image :rm
334
341
  end
335
342
  end
336
343
 
@@ -528,7 +535,7 @@ module Squared
528
535
  return unless confirm_command(cmd.to_s, title: from, target: id, as: latest)
529
536
 
530
537
  registry = option('registry') || @registry
531
- run(from: from, exception: registry.nil? ? exception : true)
538
+ run(from: from, exception: registry.nil? ? exception? : true)
532
539
  return unless registry
533
540
 
534
541
  opts = []
@@ -553,7 +560,7 @@ module Squared
553
560
  run(from: from)
554
561
  end
555
562
 
556
- def image(flag, opts = [], sync: true, id: nil, registry: nil)
563
+ def image(flag, opts = [], sync: true, id: nil, registry: nil, filter: nil)
557
564
  cmd, opts = docker_session('image', flag, opts: opts)
558
565
  op = OptionPartition.new(opts, OPT_DOCKER[:image].fetch(flag, []), cmd, project: self)
559
566
  exception = exception?
@@ -571,7 +578,7 @@ module Squared
571
578
  opts.delete(val)
572
579
  break
573
580
  end
574
- list_image(:run, from: from) do |val|
581
+ list_image(:run, filter: filter, from: from) do |val|
575
582
  container(:run, if name
576
583
  opts.dup << "name=#{index == 0 ? name : "#{name}-#{index}"}"
577
584
  else
@@ -585,7 +592,7 @@ module Squared
585
592
  when :rm
586
593
  unless id
587
594
  if op.empty?
588
- list_image(:rm, from: from) { |val| image(:rm, opts, sync: sync, id: val) }
595
+ list_image(:rm, filter: filter, from: from) { |val| image(:rm, opts, sync: sync, id: val) }
589
596
  else
590
597
  op.each { |val| run(cmd.temp(val), sync: sync, from: from) }
591
598
  end
@@ -597,13 +604,16 @@ module Squared
597
604
  banner = false
598
605
  end
599
606
  when :tag, :save
600
- list_image(flag, from: from) do |val|
607
+ found = false
608
+ list_image(flag, filter: filter, from: from) do |val|
601
609
  op << val
602
- next unless flag == :tag
603
-
604
- op << tagname("#{project}:#{op.first}")
605
- break
610
+ found = true
611
+ if flag == :tag
612
+ op << tagname("#{project}:#{op.first}")
613
+ break
614
+ end
606
615
  end
616
+ raise_error ArgumentError, 'target not specified', hint: flag unless found
607
617
  when :pull
608
618
  if !id
609
619
  id = tagmain
@@ -635,10 +645,17 @@ module Squared
635
645
 
636
646
  def network(flag, opts = [], target: nil)
637
647
  cmd, opts = docker_session('network', flag, opts: opts)
638
- OptionPartition.new(opts, OPT_DOCKER[:network].fetch(flag, []), cmd, project: self)
639
- .clear
648
+ op = OptionPartition.new(opts, OPT_DOCKER[:network].fetch(flag, []), cmd, project: self)
649
+ .clear
640
650
  from = symjoin 'network', flag
641
- list_image(flag, docker_output('ps -a'), from: from) { |id| success?(run(cmd.temp(target, id), from: from)) }
651
+ if flag == :create
652
+ op.add_quote(target)
653
+ run(from: from)
654
+ else
655
+ list_image(flag, docker_output('ps -a'), from: from) do |id|
656
+ success?(run(cmd.temp(target, id), from: from))
657
+ end
658
+ end
642
659
  end
643
660
 
644
661
  def build?
@@ -785,12 +802,20 @@ module Squared
785
802
  [cmd, status, no]
786
803
  end
787
804
 
788
- def list_image(flag, cmd = docker_output('image ls -a'), hint: nil, no: true, from: nil)
805
+ def list_image(flag, cmd = docker_output('image ls -a'), filter: nil, hint: nil, no: true, from: nil)
789
806
  pwd_set(from: from) do
790
807
  index = 1
791
808
  all = option('all', prefix: 'docker')
792
809
  y = from == :'image:rm' && option('y', prefix: 'docker')
793
- pat = /\b(?:#{dnsname(name)}|#{tagname(project)}|#{tagmain.split(':', 2).first})\b/
810
+ filter = env('DOCKER_FILTER', filter).to_s
811
+ pat = if OptionPartition.pattern?(filter)
812
+ Regexp.new(filter)
813
+ elsif filter.match?(/[:_-]$/)
814
+ /\b#{Regexp.escape(filter)}/
815
+ else
816
+ filter = filter.empty? ? '(?:[:_-]|$)' : "[:_-]#{filter}"
817
+ /\b(?:#{dnsname(name)}|#{tagname(project)}|#{tagmain.split(':', 2).first})#{filter}/
818
+ end
794
819
  IO.popen(cmd.temp('--format=json')).each do |line|
795
820
  data = JSON.parse(line)
796
821
  id = data['ID']
@@ -436,7 +436,7 @@ module Squared
436
436
  end
437
437
  if squash
438
438
  found = false
439
- git_spawn(git_output('log --format=%h'), stdout: false).each do |val|
439
+ git_spawn('log --format=%h', stdout: false).each do |val|
440
440
  if found
441
441
  squash = val.chomp
442
442
  break
@@ -1108,15 +1108,16 @@ module Squared
1108
1108
  pull(:autostash, sync: sync)
1109
1109
  end
1110
1110
 
1111
- def fetch(flag = nil, opts = [], sync: invoked_sync?('fetch', flag), remote: nil)
1111
+ def fetch(flag = nil, opts = [], sync: invoked_sync?('fetch', flag), remote: nil,
1112
+ banner: !sync || verbose? || task_invoked?('fetch'))
1112
1113
  opts = git_session('fetch', opts: opts).last
1113
1114
  opts << 'all' if flag == :all || option('all')
1114
1115
  append_pull(opts, collect_hash(OPT_GIT[:fetch]), flag: flag, from: :fetch, remote: remote,
1115
1116
  no: collect_hash(OPT_GIT[:no][:fetch]))
1116
1117
  if sync
1117
- source
1118
+ source(banner: banner)
1118
1119
  else
1119
- source(sync: false, **threadargs)
1120
+ source(sync: false, banner: banner, **threadargs)
1120
1121
  end
1121
1122
  end
1122
1123
 
@@ -1319,7 +1320,12 @@ module Squared
1319
1320
  OptionPartition.uniq!(args)
1320
1321
  end
1321
1322
  run_p(*Array(kwargs[:before]), sync: sync, from: :revbuild) if kwargs[:before]
1322
- if (cur = workspace.rev_entry(name)) && cur['revision'] == sha && !env('REVBUILD_FORCE')
1323
+ force = if (force = env('REVBUILD_FORCE', strict: true))
1324
+ force != '0' && force != 'false'
1325
+ elsif (force = ENV['GIT_FORCE'] || ENV['REVBUILD_FORCE'])
1326
+ split_escape(force).any? { |val| val == '1' || val == 'true' || val == name }
1327
+ end
1328
+ if !force && (cur = workspace.rev_entry(name)) && cur['revision'] == sha
1323
1329
  files = status_digest(*args, **kwargs)
1324
1330
  if cur['files'].size == files.size && cur['files'].find { |key, val| files[key] != val }.nil?
1325
1331
  workspace.rev_timeutc(name, 'build') unless (since = workspace.rev_timesince(name, 'build'))
@@ -1474,14 +1480,6 @@ module Squared
1474
1480
  op << '--no-index'
1475
1481
  patch = refs.pop
1476
1482
  append_pathspec(refs, parent: true)
1477
- if patch
1478
- patch = basepath patch
1479
- exit 1 if patch.exist? && !confirm_basic('Overwrite?', patch)
1480
- op << '>' << shell_quote(patch)
1481
- source(banner: false)
1482
- puts patch.read if patch.exist? && (stdin? || verbose?)
1483
- return
1484
- end
1485
1483
  else
1486
1484
  op << '--merge-base' if option('merge-base')
1487
1485
  case flag
@@ -1503,9 +1501,22 @@ module Squared
1503
1501
  op << "HEAD~#{n}"
1504
1502
  end
1505
1503
  end
1504
+ if (n = op.index('>'))
1505
+ patch = op.slice!(n, 2)[1]
1506
+ elsif !op.exist?(op.last)
1507
+ patch ||= op.pop
1508
+ end
1506
1509
  append_pathspec op.extras
1507
1510
  end
1508
- source(exception: op.arg?('exit-code'))
1511
+ if patch
1512
+ patch = basepath patch.delete_prefix('>')
1513
+ exit 1 if patch.exist? && !confirm_basic('Overwrite?', patch)
1514
+ op << '>' << shell_quote(patch)
1515
+ source(banner: false)
1516
+ puts patch.read if patch.exist? && (stdin? || verbose?)
1517
+ else
1518
+ source(exception: op.arg?('exit-code'))
1519
+ end
1509
1520
  end
1510
1521
 
1511
1522
  def commit(flag, opts = [], refs: [], ref: nil, squash: nil, pick: nil, message: nil, pass: false)
@@ -1961,23 +1972,23 @@ module Squared
1961
1972
  if io && banner == false
1962
1973
  from = nil
1963
1974
  banner = nil
1975
+ args = false
1964
1976
  else
1965
- if banner
1966
- banner = nil unless banner? && !multiple
1967
- args = true
1968
- end
1969
1977
  if from == false
1970
1978
  from = nil
1971
1979
  elsif !from && cmd.respond_to?(:drop)
1972
1980
  from = cmd.drop(1).find { |val| val.match?(/\A[a-z]{1,2}[a-z-]*\z/) }
1973
1981
  from &&= symjoin 'git', from
1974
1982
  end
1975
- banner &&= cmd.temp { |val| val.start_with?(/--(work-tree|git-dir)/) } if cmd.respond_to?(:temp)
1983
+ if banner
1984
+ banner = cmd.temp { |val| val.start_with?(/--(work-tree|git-dir)/) } if cmd.respond_to?(:temp)
1985
+ args = true
1986
+ end
1976
1987
  end
1977
1988
  timeout = session_timeout cmd if timeout.nil?
1978
1989
  cmd = session_done cmd
1979
- log&.info cmd
1980
- banner = if banner
1990
+ log&.info cmd unless args == false
1991
+ banner = if banner && banner? && !multiple
1981
1992
  format_banner(banner.is_a?(String) ? banner : cmd, hint: hint, strip: true)
1982
1993
  end
1983
1994
  on :first, from
@@ -2163,9 +2174,7 @@ module Squared
2163
2174
 
2164
2175
  def append_message(val = nil, target: @session)
2165
2176
  val = messageopt if val.to_s.empty?
2166
- return unless val
2167
-
2168
- target << quote_option('message', val)
2177
+ target << quote_option('message', val) if val
2169
2178
  end
2170
2179
 
2171
2180
  def append_head(val = nil, target: @session)
@@ -5,7 +5,7 @@ module Squared
5
5
  module Project
6
6
  class Node < Git
7
7
  OPT_NPM = {
8
- common: %w[dry-run=!? loglevel=b include-workspace-root=!? workspaces=!? w|workspace=v].freeze,
8
+ common: %w[dry-run=!? force=!? loglevel=b include-workspace-root=!? workspaces=!? w|workspace=v].freeze,
9
9
  install: %w[package-lock-only=!? prefer-dedupe=!? E|save-exact=!? before=q cpu=b libc=b os=b].freeze,
10
10
  install_a: %w[audit=! bin-links=! foreground-scripts=!? fund=! ignore-scripts=!? install-links=!?
11
11
  package-lock=! strict-peer-deps=!? include=b install-strategy=b omit=b].freeze,
@@ -106,7 +106,21 @@ module Squared
106
106
  tsc: %w[excludeDirectories excludeFiles customConditions lib moduleSuffixes plugins rootDirs typeRoots
107
107
  types].freeze
108
108
  }.freeze
109
- private_constant :OPT_NPM, :OPT_PNPM, :OPT_YARN, :OPT_BERRY, :OPT_TSC, :PASS_NODE
109
+ APP_SERVE = 'const t=require("http"),e=require("fs"),a=require("path"),i="$ROOT",o={avif:"image/avif",css:"te' \
110
+ 'xt/css",gif:"image/gif",htm:"text/html",html:"text/html",ico:"image/x-icon",jpeg:"image/jpeg",jp' \
111
+ 'g:"image/jpeg",js:"text/javascript",mjs:"application/javascript",json:"application/json",md:"tex' \
112
+ 't/markdown",m4a:"audio/x-m4a",mp3:"audio/mpeg",mp4:"video/mp4",otf:"font/otf",pdf:"application/p' \
113
+ 'df",png:"image/png",rss:"application/rss+xml",svg:"image/svg+xml",ttc:"font/collection",ttf:"fon' \
114
+ 't/ttf",txt:"text/plain",wasm:"application/wasm",webp:"image/webp",woff:"font/woff",woff2:"font/w' \
115
+ 'off2",xml:"application/xml",webmanifest:"application/manifest+json",yaml:"text/yaml",yml:"text/y' \
116
+ 'aml"};function n(t){return o[a.extname(t).slice(1)]||"application/octet-stream"}t.createServer((' \
117
+ 't,o)=>{let l=a.join(i,t.url.split("?")[0]);try{e.statSync(l).isDirectory()&&(l=a.join(l,"index.h' \
118
+ 'tml"))}catch{}e.readFile(l,(t,e)=>{console.error(`[${(new Date).toLocaleTimeString().padStart(11' \
119
+ ', 0)}] ${t?"\x1B[31m404\x1B[39m":"\x1B[1m200\x1B[22m"} ${l.slice(i.length)}`);if(t)return o.writ' \
120
+ 'eHead(404,{"Content-Type":"text/plain"}),void o.end("404 Not Found");o.writeHead(200,{"Content-T' \
121
+ 'ype":n(l)}),o.end(e)})}).listen({host:"$HOST",port:+"$PORT"},()=>{console.log("HTTP server liste' \
122
+ 'ning on http://$HOST:$PORT")});'
123
+ private_constant :OPT_NPM, :OPT_PNPM, :OPT_YARN, :OPT_BERRY, :OPT_TSC, :PASS_NODE, :APP_SERVE
110
124
 
111
125
  class << self
112
126
  def tasks
@@ -160,6 +174,7 @@ module Squared
160
174
  end
161
175
  @dependname = 'package.json'
162
176
  dependfile_set [@dependname]
177
+ serve_set kwargs[:serve]
163
178
  @tsfile = basepath! ts
164
179
  @pm = { __: kwargs[:init] }
165
180
  end
@@ -537,31 +552,36 @@ module Squared
537
552
  end
538
553
  yarn = dependtype(:yarn)
539
554
  if yarn > 0
540
- cmd = session('yarn', flag || 'install')
541
- append_loglevel
542
- if yarn == 1
543
- cmd << '--ignore-engines' if option('ignore-engines')
544
- cmd << '--ignore-scripts' if option('ignore-scripts')
545
- cmd << '--force' if option('force')
555
+ if !flag && yarn > 1 && prod?
556
+ cmd = session 'yarn', 'workspaces focus --all --production'
546
557
  else
547
- cmd << '--mode=skip-build' if option('ignore-scripts')
548
- cmd << '--check-cache' if !flag && option('force')
549
- end
550
- if nolockfile?('yarn')
551
- cmd << '--no-lockfile'
552
- elsif option('ci')
558
+ cmd = session('yarn', flag || 'install')
553
559
  if yarn == 1
554
- cmd << '--frozen-lockfile'
555
- elsif !flag
556
- cmd << '--immutable' << '--refresh-lockfile'
560
+ cmd << '--production' if prod?
561
+ cmd << '--ignore-engines' if option('ignore-engines')
562
+ cmd << '--ignore-scripts' if option('ignore-scripts')
563
+ cmd << '--force' if option('force')
564
+ else
565
+ cmd << '--mode=skip-build' if option('ignore-scripts')
566
+ cmd << '--check-cache' if !flag && option('force')
567
+ end
568
+ if nolockfile?('yarn')
569
+ cmd << '--no-lockfile'
570
+ elsif option('ci')
571
+ if yarn == 1
572
+ cmd << '--frozen-lockfile'
573
+ elsif !flag
574
+ cmd << '--immutable' << '--refresh-lockfile'
575
+ end
576
+ end
577
+ if add
578
+ cmd << '-W' if yarn == 1 && option('w', 'ignore-workspace-root-check', notequals: '0')
579
+ rm.call(cmd)
580
+ om.call(cmd)
581
+ cmd << '--exact' if exact
557
582
  end
558
583
  end
559
- if add
560
- cmd << '-W' if yarn == 1 && option('w', 'ignore-workspace-root-check', notequals: '0')
561
- rm.call(cmd)
562
- om.call(cmd)
563
- cmd << '--exact' if exact
564
- end
584
+ append_loglevel
565
585
  elsif pnpm?
566
586
  cmd = session('pnpm', flag || 'install')
567
587
  append_nocolor
@@ -572,6 +592,7 @@ module Squared
572
592
  cmd << '--save-exact' if exact
573
593
  option('allow-build') { |val| cmd << quote_option('allow-build', val) }
574
594
  else
595
+ cmd << '--prod' if prod?
575
596
  append_platform
576
597
  end
577
598
  option('public-hoist-pattern') do |val|
@@ -596,6 +617,8 @@ module Squared
596
617
  if omit
597
618
  cmd << "--omit=#{save || omit}"
598
619
  save = nil
620
+ elsif !add && prod?
621
+ cmd << '--include=prod'
599
622
  end
600
623
  unless ci
601
624
  if add
@@ -619,7 +642,7 @@ module Squared
619
642
  end
620
643
 
621
644
  def outdated(flag = nil, opts = [], sync: invoked_sync?('outdated', flag))
622
- cmd = session(pnpm? ? 'pnpm' : 'npm', 'outdated')
645
+ cmd = session(pnpm? && exist?('pnpm-lock.yaml') ? 'pnpm' : 'npm', 'outdated')
623
646
  dryrun = has_value?(opts, 'd', 'dry-run') || dryrun?
624
647
  unless dryrun
625
648
  log.info cmd.to_s
@@ -1148,6 +1171,30 @@ module Squared
1148
1171
  end
1149
1172
  end
1150
1173
 
1174
+ def serve(root, opts = [], bind: nil, port: 3000, **)
1175
+ var = {}
1176
+ if File.extname(root) =~ /[cm]?js/
1177
+ var['HOST'] = bind if bind
1178
+ var['PORT'] = port.to_s if port
1179
+ target = root
1180
+ root = File.dirname(target)
1181
+ else
1182
+ require 'tempfile'
1183
+ app = APP_SERVE.dup
1184
+ app.gsub!('$ROOT', root)
1185
+ app.gsub!('$HOST', bind || 'localhost')
1186
+ app.gsub!('$PORT', port.to_s)
1187
+ file = Tempfile.new([name, '.cjs'])
1188
+ file.write(app)
1189
+ file.close
1190
+ trap 'INT' do
1191
+ file.unlink
1192
+ end
1193
+ target = file.path
1194
+ end
1195
+ shell(var, session('node', shell_quote(target), *opts.map { |s| fill_option(s) }).done, chdir: root)
1196
+ end
1197
+
1151
1198
  def depend?
1152
1199
  @depend != false && (!@depend.nil? || outdated?)
1153
1200
  end
@@ -1438,6 +1485,10 @@ module Squared
1438
1485
  ret
1439
1486
  end
1440
1487
 
1488
+ def serve?
1489
+ @serve != false
1490
+ end
1491
+
1441
1492
  def nolockfile?(prefix = dependbin)
1442
1493
  option('package-lock', 'lockfile', prefix: prefix, equals: '0') || !option('no-lockfile', prefix: prefix).nil?
1443
1494
  end
@@ -12,8 +12,8 @@ module Squared
12
12
  installer=b o|outdir=p].freeze,
13
13
  venv: %w[clear copies symlinks system-site-packages upgrade upgrade-deps without-scm-ignore-files without-pip
14
14
  prompt=q].freeze,
15
- virtualenv: %w[always-copy clear copies download q|quiet never-download no-download no-periodic-update no-pip
16
- no-seed no-setuptools no-vcs-ignore read-only-app-data reset-app-data symlink-app-data symlinks
15
+ virtualenv: %w[always-copy clear copies download never-download no-download no-periodic-update no-pip no-seed
16
+ no-setuptools no-vcs-ignore q|quiet read-only-app-data reset-app-data symlink-app-data symlinks
17
17
  system-site-packages with-traceback without-pip upgrade-embed-wheels v|verbose=+ activators=q
18
18
  app-data=p creator=b discovery=b extra-search-dir=p pip=b prompt=q p|python=q seeder=b
19
19
  setuptools=b try-first-with=q].freeze
@@ -34,14 +34,16 @@ module Squared
34
34
  install: %w[break-system-packages compile dry-run force-reinstall I|ignore-installed no-compile
35
35
  no-warn-conflicts no-warn-script-location U|upgrade user prefix=p report=p root=p
36
36
  root-user-action=b t|target=p upgrade-strategy=b].freeze,
37
- install_a: %w[ignore-requires-python no-index pre extra-index-url=q f|find-links=q i|index-url=q no-binary=q
38
- only-binary=q].freeze,
39
- install_b: %w[build-constraint check-build-dependencies no-build-isolation no-clean no-deps prefer-binary
40
- require-hashes use-pep517 c|constraint=p group=q progress-bar=b r|requirement=p src=p].freeze,
37
+ install_a: %w[no-index pre prefer-binary all-releases=b extra-index-url=q f|find-links=q i|index-url=q
38
+ no-binary=q only-binary=q only-final=b].freeze,
39
+ install_b: %w[build-constraint check-build-dependencies no-build-isolation no-clean no-deps require-hashes
40
+ use-pep517 c|constraint=p group=q progress-bar=b r|requirement=p requirements-from-script=p
41
+ src=p].freeze,
41
42
  install_c: %w[C|config-settings=q e|editable=v].freeze,
43
+ install_d: %w[ignore-requires-python uploaded-prior-to=q].freeze,
42
44
  hash: %w[a|algorithm].freeze,
43
- list: %w[e|editable exclude-editable include-editable l|local no-index not-required o|outdated pre u|uptodate
44
- user exclude=b extra-index-url=q format=b f|find-links=q i|index-url=q path=p].freeze,
45
+ list: %w[e|editable exclude-editable include-editable l|local not-required o|outdated u|uptodate user
46
+ exclude=b format=b path=p].freeze,
45
47
  lock: %w[o|output=p].freeze,
46
48
  show: %w[f|files].freeze,
47
49
  uninstall: %w[break-system-packages y|yes r|requirement=p root-user-action=b].freeze,
@@ -91,7 +93,7 @@ module Squared
91
93
  debug: %w[platform].freeze,
92
94
  install: %w[C config-settings c constraint extra-index-url no-binary only-binary platform
93
95
  r requirement].freeze,
94
- list: %w[exclude extra-index-url].freeze
96
+ list: %w[exclude extra-index-url no-binary only-binary].freeze
95
97
  }.freeze
96
98
  }.freeze
97
99
  private_constant :DEP_PYTHON, :DIR_PYTHON, :OPT_PYTHON, :OPT_PIP, :OPT_POETRY, :OPT_PDM, :OPT_HATCH, :OPT_TWINE,
@@ -117,7 +119,8 @@ module Squared
117
119
  end
118
120
  end
119
121
 
120
- attr_reader :venv, :editable
122
+ attr_reader :venv
123
+ attr_accessor :editable
121
124
 
122
125
  def initialize(*, editable: '.', asdf: 'python', **kwargs)
123
126
  super
@@ -129,6 +132,7 @@ module Squared
129
132
  initialize_env(**kwargs)
130
133
  end
131
134
  dependfile_set DEP_PYTHON
135
+ serve_set kwargs[:serve]
132
136
  editable_set editable
133
137
  venv_set kwargs[:venv]
134
138
  end
@@ -136,10 +140,10 @@ module Squared
136
140
  subtasks({
137
141
  'venv' => %i[exec create remove show].freeze,
138
142
  'pip' => %i[upgrade uninstall wheel reinstall freeze].freeze,
139
- 'install' => %i[requirement target upgrade editable poetry].freeze,
143
+ 'install' => %i[upgrade requirement target editable user poetry].freeze,
140
144
  'outdated' => %i[major minor patch].freeze,
141
145
  'build' => %i[poetry pdm hatch meson python].freeze,
142
- 'publish' => %i[poetry pdm hatch twine].freeze,
146
+ 'publish' => %i[twine poetry pdm hatch].freeze,
143
147
  'run' => nil,
144
148
  'exec' => nil
145
149
  })
@@ -272,7 +276,7 @@ module Squared
272
276
  if args.empty?
273
277
  args = readline('Enter command', force: true).split(' ', 2)
274
278
  elsif args.size == 1 && option('interactive', notequals: '0', prefix: ref)
275
- args << readline('Enter arguments', force: false)
279
+ args << readline('Enter arguments', force: false) unless args.first.include?(' ')
276
280
  end
277
281
  venv_init
278
282
  run args.join(' ')
@@ -347,8 +351,12 @@ module Squared
347
351
  depend(flag, args.extras, target: path)
348
352
  end
349
353
  else
350
- next if flag == :poetry && !poetry?
351
-
354
+ case flag
355
+ when :user
356
+ next if venv
357
+ when :poetry
358
+ next unless poetry?
359
+ end
352
360
  task flag do |_, args|
353
361
  install flag, args.to_a
354
362
  end
@@ -373,8 +381,11 @@ module Squared
373
381
  end
374
382
  break if be
375
383
  when 'publish'
376
- next if (be = backend?(flag)) == false
377
-
384
+ if flag == :twine
385
+ next unless twine?
386
+ elsif (be = backend?(flag)) == false
387
+ next
388
+ end
378
389
  format_desc(action, flag, 'test?,opts*', after: case flag
379
390
  when :hatch then 'artifacts?'
380
391
  when :twine then 'dist?'
@@ -587,10 +598,10 @@ module Squared
587
598
  when :editable
588
599
  op << quote_option('e', op.pop || editable || '.')
589
600
  op.clear
590
- when :upgrade
601
+ when :user, :upgrade
591
602
  op.concat(packages)
592
603
  raise_error 'no packages listed', hint: flag if op.empty?
593
- op << '--upgrade'
604
+ op << "--#{flag}"
594
605
  op.append
595
606
  python_session('-m pip', *op.to_a.drop(1)) if workspace.windows?
596
607
  end
@@ -804,6 +815,10 @@ module Squared
804
815
  .yield_self { |val| ret || val }
805
816
  end
806
817
 
818
+ def serve(root, opts = [], bind: 'localhost', port: nil, **)
819
+ shell(python_session('-m http.server', port, basic_option('b', bind), opts: opts).first.done, chdir: root)
820
+ end
821
+
807
822
  def project
808
823
  return @project unless @project.frozen?
809
824
 
@@ -855,6 +870,10 @@ module Squared
855
870
  !venv.nil?
856
871
  end
857
872
 
873
+ def serve?
874
+ @serve != false
875
+ end
876
+
858
877
  private
859
878
 
860
879
  def pip_session(*cmd)
@@ -978,7 +997,7 @@ module Squared
978
997
 
979
998
  if found
980
999
  line.chomp!($1) if line =~ /(?<=[\d"'{}\[\]]|true|false)(\s*#.*)$/
981
- break if line.match?(/^\s*\[(?:[\w.\-" ]+|".+"|'.+')\]\s*$/)
1000
+ break if line.match?(/^\s*\[(?:[\w.\-"' ]+|".+"|'.+')\]\s*$/)
982
1001
 
983
1002
  if ch
984
1003
  val = line.rstrip
@@ -1066,6 +1085,7 @@ module Squared
1066
1085
  if pip_install?(flag)
1067
1086
  ret.concat(OPT_PIP[:install_a])
1068
1087
  ret.concat(OPT_PIP[:install_b]) unless flag == :index
1088
+ ret.concat(OPT_PIP[:install_d])
1069
1089
  case flag
1070
1090
  when :install
1071
1091
  ret.concat(OPT_PIP[:install_c] + OPT_PIP[:debug])
@@ -1074,6 +1094,8 @@ module Squared
1074
1094
  when :download, :index
1075
1095
  ret.concat(OPT_PIP[:debug])
1076
1096
  end
1097
+ elsif flag == :list
1098
+ ret.concat(OPT_PIP[:install_a])
1077
1099
  end
1078
1100
  ret
1079
1101
  end
@@ -1161,9 +1183,17 @@ module Squared
1161
1183
  if poetry?
1162
1184
  requires = read_pyproject 'tool.poetry', 'requires-poetry'
1163
1185
  args << "poetry#{requires}"
1186
+ elsif setuptools? && !virtualenv?
1187
+ args << 'setuptools' << 'wheel'
1164
1188
  end
1165
1189
  pip(:install, *args, banner: false) unless args.empty?
1166
- success?(ret, banner, !status) { |ret| puts(ret && dir.directory? ? "Success: #{dir}" : 'Failed') }
1190
+ success?(ret, banner, !status) { |out| puts(out && dir.directory? ? "Success: #{dir}" : 'Failed') }
1191
+ end
1192
+
1193
+ def venv_package?(val)
1194
+ return false unless venv
1195
+
1196
+ !Dir.glob("lib/**/site-packages/#{val}", base: venv).empty?
1167
1197
  end
1168
1198
 
1169
1199
  def pip_install?(flag)
@@ -1197,6 +1227,10 @@ module Squared
1197
1227
  dependtype == 1
1198
1228
  end
1199
1229
 
1230
+ def twine?
1231
+ venv_package?('twine')
1232
+ end
1233
+
1200
1234
  def virtualenv?
1201
1235
  @virtualenv ||= exist?('virtualenv.ini') || !ENV['VIRTUALENV_PYTHON'].nil?
1202
1236
  end