Class: Homebrew::Bundle::Uv Private

Inherits:
Extension show all
Defined in:
bundle/extensions/uv.rb

This class is part of a private API. This class may only be used in the Homebrew/brew repository. Third parties should avoid using this class if possible, as it may be removed or changed without warning.

Constant Summary collapse

WithOptions =

This constant is part of a private API. This constant may only be used in the Homebrew/brew repository. Third parties should avoid using this constant if possible, as it may be removed or changed without warning.

T.type_alias { T::Hash[Symbol, T.any(String, T::Array[String])] }
Tool =

This constant is part of a private API. This constant may only be used in the Homebrew/brew repository. Third parties should avoid using this constant if possible, as it may be removed or changed without warning.

T.type_alias { { name: String, with: T::Array[String], source: T.nilable(String) } }
Checkable =

This constant is part of a private API. This constant may only be used in the Homebrew/brew repository. Third parties should avoid using this constant if possible, as it may be removed or changed without warning.

T.type_alias { { name: String, options: WithOptions } }
ToolEntry =

This constant is part of a private API. This constant may only be used in the Homebrew/brew repository. Third parties should avoid using this constant if possible, as it may be removed or changed without warning.

T.type_alias { T.any(Tool, Checkable) }
SOURCE_REQUIREMENT_REGEX =

This constant is part of a private API. This constant may only be used in the Homebrew/brew repository. Third parties should avoid using this constant if possible, as it may be removed or changed without warning.

%r{\A(?:git\+|https?://)|\.git\z}
LOCAL_SOURCE_REGEX =

This constant is part of a private API. This constant may only be used in the Homebrew/brew repository. Third parties should avoid using this constant if possible, as it may be removed or changed without warning.

uv tool list reports a tool installed from a directory as an absolute file:// URL, and a hand-written Brewfile can name a path directly. uv tool install also takes either spelling behind a git+ prefix. None of them resolves on another machine, so none is accepted, and a tool installed from one is dumped without a source: rather than with one that would then fail to parse.

%r{\A(?:git\+)?(?:file://|\.{0,2}/)}

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Extension

add_supported?, check, cleanup!, cleanup_disable_description, cleanup_disable_env, cleanup_item_name, cleanup_items, cleanup_supported?, disable_predicate_method, dump, dump_disable_description, dump_disable_env, dump_disable_predicate_method, dump_disable_supported?, dump_output, dump_supported?, ensure_package_manager_installed!, #failure_reason, flag, inherited, install_supported?, install_verb, legacy_check_step, package_description, package_manager_env, package_manager_executable, package_manager_executable!, package_manager_installed?, package_manager_name, predicate_method, quote, remove_supported?, switch_description, with_package_manager_env

Methods included from Utils::Output::Mixin

#issue_reporting_message, #odebug, #odeprecated, #odie, #odisabled, #ofail, #oh1, #oh1_title, #ohai, #ohai_title, #onoe, #opoo, #opoo_once, #opoo_outside_github_actions, #opoo_without_github_actions_annotation, #pretty_cannot_install, #pretty_deprecated, #pretty_disabled, #pretty_duration, #pretty_install_status, #pretty_installed, #pretty_removed, #pretty_uninstalled, #pretty_unmarked, #pretty_upgradable, #pretty_warning

Methods inherited from PackageType

batch_installable?, check, #checkable_entries, dump, dump_output, dump_supported?, #exit_early_check, #failure_reason, #find_actionable, #full_check, inherited, install_batch!, install_supported?, install_verb

Class Method Details

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



32
# File 'bundle/extensions/uv.rb', line 32

def banner_name = "uv tools"

.check_label ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



29
# File 'bundle/extensions/uv.rb', line 29

def check_label = "uv Tool"

.cleanup_heading ⇒ String?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



70
71
72
# File 'bundle/extensions/uv.rb', line 70

def cleanup_heading
  banner_name
end

.continuation_constraint?(requirement) ⇒ Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:

  • (Boolean)


245
246
247
# File 'bundle/extensions/uv.rb', line 245

def continuation_constraint?(requirement)
  requirement.match?(/\A(?:<=|>=|!=|==|~=|<|>)\s*\S/)
end

.dump_entry(package) ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



332
333
334
335
336
337
338
# File 'bundle/extensions/uv.rb', line 332

def dump_entry(package)
  line = super
  source = dump_source(package)
  line = "#{line}, source: #{quote(source)}" if source.present?

  line
end

.dump_name(package) ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



85
86
87
# File 'bundle/extensions/uv.rb', line 85

def dump_name(package)
  package_name(T.cast(package, ToolEntry))
end

.dump_source(package) ⇒ String?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



95
96
97
# File 'bundle/extensions/uv.rb', line 95

def dump_source(package)
  package_source(T.cast(package, ToolEntry))
end

.dump_with(package) ⇒ Array<String>?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



90
91
92
# File 'bundle/extensions/uv.rb', line 90

def dump_with(package)
  package_with(T.cast(package, ToolEntry))
end

.entry(name, options = {}) ⇒ Dsl::Entry

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'bundle/extensions/uv.rb', line 35

def entry(name, options = {})
  unknown_options = options.keys - [:with, :source]
  raise "unknown options(#{unknown_options.inspect}) for uv" if unknown_options.present?

  with = options[:with]
  if !with.nil? && (!with.is_a?(Array) || with.any? { |requirement| !requirement.is_a?(String) })
    raise "options[:with](#{with.inspect}) should be an Array of String objects"
  end

  source = options.fetch(:source, nil)
  if !source.nil? && !source.is_a?(String)
    raise "options[:source](#{source.inspect}) should be a String object"
  end

  normalized_options = {}
  normalized_with = normalize_with(with || [])
  normalized_options[:with] = normalized_with if normalized_with.present?
  normalized_source = normalize_source(source)
  if normalized_source&.match?(LOCAL_SOURCE_REGEX)
    raise "options[:source](#{source.inspect}) is local to this machine so cannot be used in a Brewfile"
  end

  normalized_options[:source] = normalized_source if normalized_source.present?

  Dsl::Entry.new(:uv, name, normalized_options)
end

.install!(name, with: nil, source: nil, preinstall: true, no_upgrade: false, verbose: false, force: false, **_options) ⇒ Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

  • name (String)
  • with (Array<String>, nil) (defaults to: nil)
  • source (String, nil) (defaults to: nil)
  • preinstall (Boolean) (defaults to: true)
  • no_upgrade (Boolean) (defaults to: false)
  • verbose (Boolean) (defaults to: false)
  • force (Boolean) (defaults to: false)
  • _options (Homebrew::Bundle::EntryOption)

Returns:

  • (Boolean)


375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
# File 'bundle/extensions/uv.rb', line 375

def install!(name, with: nil, source: nil, preinstall: true, no_upgrade: false, verbose: false, force: false,
             **_options)
  _ = no_upgrade
  _ = force

  return true unless preinstall

  puts "Installing #{name} #{package_description}." if verbose
  return false unless install_package!(name, with:, source:, verbose:,
                                        upgrade: package_installed?(name, with:, source:))

  package = normalized_options(name, with: with || [], source:)
  installed_packages << package unless installed_packages.include?(package)
  packages << package unless packages.include?(package)
  true
end

.install_package!(name, with: nil, source: nil, verbose: false, upgrade: false) ⇒ Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

  • name (String)
  • with (Array<String>, nil) (defaults to: nil)
  • source (String, nil) (defaults to: nil)
  • verbose (Boolean) (defaults to: false)
  • upgrade (Boolean) (defaults to: false)

Returns:

  • (Boolean)


108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'bundle/extensions/uv.rb', line 108

def install_package!(name, with: nil, source: nil, verbose: false, upgrade: false)
  require "formula"
  require "utils/path"

  args = ["tool", "install", upgrade ? upgrade_requirement(name, source:) : source.presence || name]
  if upgrade
    args.push("--upgrade", "--python", tool_python(name))
  else
    # Find the newest installed Homebrew Python from opt/bin filenames without loading formulae.
    python = Formula.installed_formula_names.grep(/\Apython(?:@.+)?\z/)
                    .flat_map { |formula_name| Utils::Path.formula_opt_bin(formula_name).glob("python[0-9]*") }
                    .select { |path| path.file? && path.basename.to_s.match?(/\Apython\d+\.\d+\z/) }
                    .max_by { |path| Version.new(path.basename.to_s.delete_prefix("python")) }
    ENV["UV_PYTHON"] = python.to_s if python
  end

  normalize_with(with || []).each do |requirement|
    args << "--with"
    args << requirement
  end

  Bundle.system(package_manager_executable!.to_s, *args, verbose:)
end

.installed_packages ⇒ Array<Tool>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



133
134
135
# File 'bundle/extensions/uv.rb', line 133

def installed_packages
  @installed_packages ||= packages.dup
end

.name_with_extras(name, extras_raw) ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



213
214
215
216
217
218
219
220
# File 'bundle/extensions/uv.rb', line 213

def name_with_extras(name, extras_raw)
  return name if extras_raw.blank?

  extras = extras_raw.split(",").map(&:strip).reject(&:empty?).uniq.sort
  return name if extras.empty?

  "#{name}[#{extras.join(",")}]"
end

.normalize_constraint(requirement) ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



251
252
253
# File 'bundle/extensions/uv.rb', line 251

def normalize_constraint(requirement)
  requirement.strip.sub(/\A(<=|>=|!=|==|~=|<|>)\s+/, "\\1")
end

.normalize_name(name) ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'bundle/extensions/uv.rb', line 269

def normalize_name(name)
  match = name.strip.match(/\A(?<base>[^\[\]]+)(?:\[(?<extras>[^\]]+)\])?\z/)
  return name.strip unless match

  base = match[:base]
  return name.strip if base.nil?

  extras_raw = match[:extras]
  return base.strip if extras_raw.blank?

  extras = extras_raw.split(",").map(&:strip).reject(&:empty?).uniq.sort
  return base.strip if extras.empty?

  "#{base.strip}[#{extras.join(",")}]"
end

.normalize_source(source) ⇒ String?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



263
264
265
# File 'bundle/extensions/uv.rb', line 263

def normalize_source(source)
  source.presence&.strip
end

.normalize_with(with) ⇒ Array<String>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



257
258
259
# File 'bundle/extensions/uv.rb', line 257

def normalize_with(with)
  with.map(&:strip).reject(&:empty?).uniq.sort
end

.normalized_options(name, with:, source: nil) ⇒ Tool

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



298
299
300
301
302
303
304
# File 'bundle/extensions/uv.rb', line 298

def normalized_options(name, with:, source: nil)
  {
    name:   normalize_name(name),
    with:   normalize_with(with),
    source: normalize_source(source),
  }
end

.package_installed?(name, with: nil, source: nil) ⇒ Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:

  • (Boolean)


399
400
401
# File 'bundle/extensions/uv.rb', line 399

def package_installed?(name, with: nil, source: nil)
  installed_packages.include?(package_record(name, with:, source:))
end

.package_name(package) ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



308
309
310
# File 'bundle/extensions/uv.rb', line 308

def package_name(package)
  package[:name]
end

.package_outdated?(name, with: nil, source: nil) ⇒ Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:

  • (Boolean)


140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'bundle/extensions/uv.rb', line 140

def package_outdated?(name, with: nil, source: nil)
  output = SystemCommand.run!(
    package_manager_executable!,
    args:         ["pip", "install", "--dry-run", "--upgrade",
                   "--python", tool_python(name),
                   upgrade_requirement(name, source:), *normalize_with(with || [])],
    print_stderr: false,
  ).stderr
  return true if output.match?(/^Would (?:install|uninstall) \d+ packages?$/)
  return false if output.lines.any? { |line| line.chomp == "Would make no changes" }

  raise "Invalid uv upgrade plan for #{name}: #{output.inspect}"
end

.package_record(name, with: nil, source: nil) ⇒ Object

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



293
294
295
# File 'bundle/extensions/uv.rb', line 293

def package_record(name, with: nil, source: nil)
  normalized_options(name, with: with || [], source:)
end

.package_source(package) ⇒ String?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



324
325
326
327
328
# File 'bundle/extensions/uv.rb', line 324

def package_source(package)
  return package[:source] if package.key?(:source)

  T.cast(package[:options].fetch(:source, nil), T.nilable(String))
end

.package_with(package) ⇒ Array<String>?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



314
315
316
317
318
319
320
# File 'bundle/extensions/uv.rb', line 314

def package_with(package)
  if package.key?(:with)
    package[:with]
  else
    package[:options].fetch(:with, [])
  end
end

.packages ⇒ Array<Tool>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



75
76
77
78
79
80
81
82
# File 'bundle/extensions/uv.rb', line 75

def packages
  return @packages if @packages
  return [] unless (uv = package_manager_executable)

  @packages = parse_tool_list(
    command_output(uv, args: %w[tool list --show-with --show-extras --show-version-specifiers]),
  )
end

.parse_source(required_raw) ⇒ String?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



202
203
204
205
206
207
208
209
# File 'bundle/extensions/uv.rb', line 202

def parse_source(required_raw)
  source = normalize_source(required_raw)
  return if source.nil?
  return if source.match?(LOCAL_SOURCE_REGEX)
  return source if source.match?(SOURCE_REQUIREMENT_REGEX)

  nil
end

.parse_tool_list(output) ⇒ Array<Tool>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'bundle/extensions/uv.rb', line 171

def parse_tool_list(output)
  entries = T.let([], T::Array[Tool])
  @requirements = {}

  output.each_line do |line|
    match = line.match(/\A(?<name>[A-Za-z0-9]\S*)\s+v\S+/)
    next unless match

    name = match[:name]
    next if name.nil?

    extras_raw = line[/\[extras:\s*([^\]]+)\]/, 1]
    name = name_with_extras(name, extras_raw)
    with_raw = line[/\[with:\s*([^\]]+)\]/, 1]
    required_raw = line[/\[required:\s*([^\]]+)\]/, 1]
    if required_raw.present? && continuation_constraint?(required_raw)
      @requirements[name] = required_raw.strip
    end

    entries << {
      name:   name,
      with:   parse_with_requirements(with_raw),
      source: parse_source(required_raw),
    }
  end

  entries.sort_by { |entry| entry[:name].to_s }
end

.parse_with_requirements(with_raw) ⇒ Array<String>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'bundle/extensions/uv.rb', line 224

def parse_with_requirements(with_raw)
  return [] if with_raw.blank?

  entries = T.let([], T::Array[String])
  with_raw.split(", ").each do |token|
    requirement = token.strip
    next if requirement.empty?

    if continuation_constraint?(requirement) && entries.any?
      last_requirement = entries.pop
      entries << "#{last_requirement}, #{normalize_constraint(requirement)}" if last_requirement
    else
      entries << requirement
    end
  end

  entries.uniq.sort
end

.preinstall!(name, with: nil, source: nil, no_upgrade: false, verbose: false, **_options) ⇒ Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:

  • (Boolean)


350
351
352
353
354
355
356
357
358
359
360
361
# File 'bundle/extensions/uv.rb', line 350

def preinstall!(name, with: nil, source: nil, no_upgrade: false, verbose: false, **_options)
  ensure_package_manager_installed!(name, verbose:)

  if package_installed?(name, with:, source:)
    return true if !no_upgrade && package_outdated?(name, with:, source:)

    puts "Skipping install of #{name} #{package_description}. It is already installed." if verbose
    return false
  end

  true
end

.reset! ⇒ void

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

This method returns an undefined value.



63
64
65
66
67
# File 'bundle/extensions/uv.rb', line 63

def reset!
  @packages = T.let(nil, T.nilable(T::Array[Tool]))
  @installed_packages = T.let(nil, T.nilable(T::Array[Tool]))
  @requirements = T.let(nil, T.nilable(T::Hash[String, String]))
end

.tool_python(name) ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



164
165
166
167
# File 'bundle/extensions/uv.rb', line 164

def tool_python(name)
  File.join(command_output(package_manager_executable!, args: ["tool", "dir"]).strip,
            name.split("[", 2).first.to_s.downcase.gsub(/[-_.]+/, "-"), "bin", "python")
end

.type ⇒ Symbol

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



26
# File 'bundle/extensions/uv.rb', line 26

def type = :uv

.uninstall_package!(name, executable: Pathname.new("")) ⇒ Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:

  • (Boolean)


404
405
406
# File 'bundle/extensions/uv.rb', line 404

def uninstall_package!(name, executable: Pathname.new(""))
  Bundle.system(executable.to_s, "tool", "uninstall", name, verbose: false)
end

.upgrade_requirement(name, source:) ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



155
156
157
158
159
160
# File 'bundle/extensions/uv.rb', line 155

def upgrade_requirement(name, source:)
  return "#{name} @ #{source}" if source.present?

  packages
  "#{name}#{@requirements&.[](normalize_name(name))}"
end

Instance Method Details

#format_checkable(entries) ⇒ Array<Object>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



410
411
412
413
414
# File 'bundle/extensions/uv.rb', line 410

def format_checkable(entries)
  checkable_entries(entries).map do |entry|
    { name: entry.name, options: entry.options }
  end
end

#installed_and_up_to_date?(package, no_upgrade: false) ⇒ Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

  • package (Object)
  • no_upgrade (Boolean) (defaults to: false)

Returns:

  • (Boolean)


417
418
419
420
421
422
423
424
425
426
427
# File 'bundle/extensions/uv.rb', line 417

def installed_and_up_to_date?(package, no_upgrade: false)
  self.class.package_installed?(
    self.class.dump_name(package),
    with:   self.class.dump_with(package),
    source: self.class.dump_source(package),
  ) && (no_upgrade || !self.class.package_outdated?(
    self.class.dump_name(package),
    with:   self.class.dump_with(package),
    source: self.class.dump_source(package),
  ))
end