Class: Homebrew::FormulaCreator Private

Inherits:
Object
  • Object
show all
Includes:
Utils::Output::Mixin
Defined in:
formula_creator.rb

Overview

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.

Class for generating a formula from a template.

Instance Attribute Summary collapse

Instance Method Summary collapse

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

Constructor Details

#initialize(url:, name: nil, version: nil, tap: nil, mode: nil, license: nil, fetch: false, head: false) ⇒ 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.

Parameters:

  • url (String)
  • name (String, nil) (defaults to: nil)
  • version (String, nil) (defaults to: nil)
  • tap (String, nil) (defaults to: nil)
  • mode (Symbol, nil) (defaults to: nil)
  • license (String, nil) (defaults to: nil)
  • fetch (Boolean) (defaults to: false)
  • head (Boolean) (defaults to: false)


31
32
33
34
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'formula_creator.rb', line 31

def initialize(url:, name: nil, version: nil, tap: nil, mode: nil, license: nil, fetch: false, head: false)
  @url = url
  @mode = mode
  @license = license
  @fetch = fetch

  tap = if tap.blank?
    CoreTap.instance
  else
    Tap.fetch(tap)
  end
  @tap = T.let(tap, Tap)

  if (match_github = url.match(%r{github\.com/(?<user>[^/]+)/(?<repo>[^/]+).*})) &&
     (user = match_github[:user]) && (repository = match_github[:repo])
    if repository.end_with?(".git")
      # e.g. https://github.com/Homebrew/brew.git
      repository.delete_suffix!(".git")
      head = true
    end
    odebug "github: #{user} #{repository} head:#{head}"
    if name.blank?
      name = repository
      odebug "name from github: #{name}"
    end
  elsif name.blank?
    stem = Pathname.new(url).stem
    name = if stem.start_with?("index.cgi") && stem.include?("=")
      # special cases first
      # gitweb URLs e.g. http://www.codesrc.com/gitweb/index.cgi?p=libzipper.git;a=summary
      stem.rpartition("=").last
    else
      # e.g. http://digit-labs.org/files/tools/synscan/releases/synscan-5.02.tar.gz
      pathver = Version.parse(stem).to_s
      stem.sub(/[-_.]?#{Regexp.escape(pathver)}$/, "")
    end
    odebug "name from url: #{name}"
  end
  @name = T.let(name, String)
  @head = head

  @version = T.let(version.blank? ? Version::NULL : Version.new(version), Version)
  @version_in_url = T.let(false, T::Boolean)

  if @version.present?
    odebug "version from user: #{@version}"
  else
    @version_in_url = Version.detect(url).present?
    odebug "version in url: #{@version_in_url}"
  end

  if fetch && user && repository
    github = GitHub.repository(user, repository)

    if @version.blank? && !@version_in_url && !head
      begin
        tag = GitHub.get_latest_release(user, repository).fetch("tag_name")
        @url = "https://github.com/#{user}/#{repository}/archive/refs/tags/#{tag}.tar.gz"
        odebug "github: url changed to source archive #{@url}"

        # detect(@url) removes v prefix from tags, and new(tag) doesn't
        tag_version = Version.new(tag.delete_prefix("v"))
        if Version.detect(@url) == tag_version
          @version_in_url = true
        else
          @version = tag_version
          odebug "github: version #{@version} from tag"
        end
        odebug "version in url (github): #{@version_in_url}"
      rescue GitHub::API::HTTPNotFoundError
        odebug "github: latest_release lookup failed: #{url}"
      end
    end
  end
  @github = T.let(github, T.untyped)

  @sha256 = T.let(nil, T.nilable(String))
  @desc = T.let("", String)
  @homepage = T.let(nil, T.nilable(String))
  @license = T.let(nil, T.nilable(String))
end

Instance Attribute Details

#head ⇒ Boolean (readonly)

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:

  • (Boolean)


25
26
27
# File 'formula_creator.rb', line 25

def head
  @head
end

#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.

Returns:



16
17
18
# File 'formula_creator.rb', line 16

def name
  @name
end

#url ⇒ String (readonly)

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:



22
23
24
# File 'formula_creator.rb', line 22

def url
  @url
end

#version ⇒ Version (readonly)

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:



19
20
21
# File 'formula_creator.rb', line 19

def version
  @version
end

Instance Method Details

#verify_tap_available! ⇒ 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.



114
115
116
# File 'formula_creator.rb', line 114

def verify_tap_available!
  raise TapUnavailableError, @tap.name unless @tap.installed?
end

#write_formula! ⇒ Pathname

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:

Raises:

  • (ArgumentError)


119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'formula_creator.rb', line 119

def write_formula!
  raise ArgumentError, "name is blank!" if @name.blank?
  raise ArgumentError, "tap is blank!" if @tap.blank?

  path = @tap.new_formula_path(@name)
  raise "#{path} already exists" if path.exist?

  if @version.blank? && !@version_in_url
    odie "Version cannot be determined from URL. Explicitly set the version with `--set-version` instead."
  end

  if @fetch
    unless @head
      r = Resource.new
      r.url(@url)
      r.owner = self
      filepath = r.fetch
      html_doctype_prefix = "<!doctype html"
      # Number of bytes to read from file start to ensure it is not HTML.
      # HTML may start with arbitrary number of whitespace lines.
      bytes_to_read = 100
      if File.read(filepath, bytes_to_read).strip.downcase.start_with?(html_doctype_prefix)
        raise "Downloaded URL is not archive"
      end

      # The missing-checksum warning during the fetch above has already
      # hashed the file, so reuse its digest.
      @sha256 = T.let(Downloadable.verification_cache.sha256(filepath), T.nilable(String))
    end

    if @github
      # Convert null to empty string. Strip trailing dot if present.
      @desc = @github["description"].to_s.delete_suffix(".")
      @homepage = @github["homepage"].presence || "https://github.com/#{@github["full_name"]}"
      @license = @github["license"]["spdx_id"] if @github["license"]
    end
  end

  path.dirname.mkpath
  path.write ERB.new(template, trim_mode: "<>").result(binding)
  path
end