Module: Homebrew::Livecheck Private
- Defined in:
- Library/Homebrew/livecheck/livecheck.rb,
Library/Homebrew/livecheck/strategy.rb,
Library/Homebrew/livecheck/strategy/git.rb,
Library/Homebrew/livecheck/strategy/gnu.rb,
Library/Homebrew/livecheck/strategy/npm.rb,
Library/Homebrew/livecheck/strategy/pypi.rb,
Library/Homebrew/livecheck/strategy/xorg.rb,
Library/Homebrew/livecheck/strategy/gnome.rb,
Library/Homebrew/livecheck/strategy/apache.rb,
Library/Homebrew/livecheck/strategy/hackage.rb,
Library/Homebrew/livecheck/strategy/bitbucket.rb,
Library/Homebrew/livecheck/strategy/launchpad.rb,
Library/Homebrew/livecheck/strategy/page_match.rb,
Library/Homebrew/livecheck/strategy/sourceforge.rb
Overview
This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.
The Livecheck module consists of methods used by the brew livecheck
command. These methods print the requested livecheck information
for formulae.
Defined Under Namespace
Modules: Strategy
Constant Summary collapse
- GITHUB_SPECIAL_CASES =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
%w[ api.github.com /latest mednafen camlp5 kotlin osrm-backend prometheus pyenv-virtualenv sysdig shairport-sync yuicompressor ].freeze
- UNSTABLE_VERSION_KEYWORDS =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
%w[ alpha beta bpo dev experimental prerelease preview rc ].freeze
Class Method Summary collapse
-
.checkable_urls(formula) ⇒ Array
private
Returns an Array containing the formula URLs that can be used by livecheck.
-
.formula_name(formula, args:) ⇒ String
private
Returns the fully-qualified name of a formula if the
full_name
argument is provided; returns the name otherwise. -
.latest_version(formula, args:) ⇒ Hash?
private
Identifies the latest version of the formula and returns a Hash containing the version information.
-
.livecheck_formulae(formulae_to_check, args) ⇒ nil
private
Executes the livecheck logic for each formula in the
formulae_to_check
array and prints the results. -
.preprocess_url(url) ⇒ String
private
Preprocesses and returns the URL used by livecheck.
-
.print_latest_version(info, args:) ⇒ nil
private
Formats and prints the livecheck result for a formula.
-
.skip_conditions(formula, args:) ⇒ Hash, ...
private
If a formula has to be skipped, it prints or returns a Hash contaning the reason for doing so; returns false otherwise.
- .status_hash(formula, status_str, messages = nil, args:) ⇒ Object private
Class Method Details
.checkable_urls(formula) ⇒ Array
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns an Array containing the formula URLs that can be used by livecheck.
297 298 299 300 301 302 303 304 305 306 307 |
# File 'Library/Homebrew/livecheck/livecheck.rb', line 297 def checkable_urls(formula) urls = [] urls << formula.head.url if formula.head if formula.stable urls << formula.stable.url urls.concat(formula.stable.mirrors) end urls << formula.homepage if formula.homepage urls.compact end |
.formula_name(formula, args:) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the fully-qualified name of a formula if the full_name
argument is
provided; returns the name otherwise.
204 205 206 |
# File 'Library/Homebrew/livecheck/livecheck.rb', line 204 def formula_name(formula, args:) args.full_name? ? formula.full_name : formula.name end |
.latest_version(formula, args:) ⇒ Hash?
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Identifies the latest version of the formula and returns a Hash containing the version information. Returns nil if a latest version couldn't be found.
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 |
# File 'Library/Homebrew/livecheck/livecheck.rb', line 341 def latest_version(formula, args:) has_livecheckable = formula.livecheckable? livecheck = formula.livecheck livecheck_regex = livecheck.regex livecheck_strategy = livecheck.strategy livecheck_url = livecheck.url urls = [livecheck_url] if livecheck_url.present? urls ||= checkable_urls(formula) if args.debug? puts puts "Formula: #{formula_name(formula, args: args)}" puts "Head only?: true" if formula.head_only? puts "Livecheckable?: #{has_livecheckable ? "Yes" : "No"}" end urls.each_with_index do |original_url, i| if args.debug? puts puts "URL: #{original_url}" end # Skip Gists until/unless we create a method of identifying revisions if original_url.include?("gist.github.com") odebug "Skipping: GitHub Gists are not supported" next end # Do not preprocess the URL when livecheck.strategy is set to :page_match url = if livecheck_strategy == :page_match original_url else preprocess_url(original_url) end strategies = Strategy.from_url(url, livecheck_regex.present?) strategy = Strategy.from_symbol(livecheck_strategy) strategy ||= strategies.first strategy_name = @livecheck_strategy_names[strategy] if args.debug? puts "URL (processed): #{url}" if url != original_url if strategies.present? && args.verbose? puts "Strategies: #{strategies.map { |s| @livecheck_strategy_names[s] }.join(", ")}" end puts "Strategy: #{strategy.blank? ? "None" : strategy_name}" puts "Regex: #{livecheck_regex.inspect}" if livecheck_regex.present? end if livecheck_strategy == :page_match && livecheck_regex.blank? odebug "#{strategy_name} strategy requires a regex" next end if livecheck_strategy.present? && !strategies.include?(strategy) odebug "#{strategy_name} strategy does not apply to this URL" next end next if strategy.blank? strategy_data = strategy.find_versions(url, livecheck_regex) match_version_map = strategy_data[:matches] regex = strategy_data[:regex] if strategy_data[:messages].is_a?(Array) && match_version_map.blank? puts strategy_data[:messages] unless args.json? next if i + 1 < urls.length return status_hash(formula, "error", strategy_data[:messages], args: args) end if args.debug? puts "URL (strategy): #{strategy_data[:url]}" if strategy_data[:url] != url puts "Regex (strategy): #{strategy_data[:regex].inspect}" if strategy_data[:regex] != livecheck_regex end match_version_map.delete_if do |_match, version| next true if version.blank? next false if has_livecheckable UNSTABLE_VERSION_KEYWORDS.any? do |rejection| version.to_s.include?(rejection) end end if args.debug? && match_version_map.present? puts puts "Matched Versions:" if args.verbose? match_version_map.each do |match, version| puts "#{match} => #{version.inspect}" end else puts match_version_map.values.join(", ") end end next if match_version_map.blank? version_info = { latest: Version.new(match_version_map.values.max), } if args.json? && args.verbose? version_info[:meta] = { url: { original: original_url, }, strategy: strategy.blank? ? nil : strategy_name, } version_info[:meta][:url][:processed] = url if url != original_url version_info[:meta][:url][:strategy] = strategy_data[:url] if strategy_data[:url] != url if strategies.present? version_info[:meta][:strategies] = strategies.map { |s| @livecheck_strategy_names[s] } end version_info[:meta][:regex] = regex.inspect if regex.present? end return version_info end nil end |
.livecheck_formulae(formulae_to_check, args) ⇒ nil
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Executes the livecheck logic for each formula in the formulae_to_check
array
and prints the results.
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 112 113 114 115 116 117 118 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 161 162 163 164 165 166 167 168 169 170 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 199 |
# File 'Library/Homebrew/livecheck/livecheck.rb', line 44 def livecheck_formulae(formulae_to_check, args) # Identify any non-homebrew/core taps in use for current formulae non_core_taps = {} formulae_to_check.each do |f| next if f.tap.blank? next if f.tap.name == CoreTap.instance.name next if non_core_taps[f.tap.name] non_core_taps[f.tap.name] = f.tap end non_core_taps = non_core_taps.sort.to_h # Load additional Strategy files from taps non_core_taps.each_value do |tap| tap_strategy_path = "#{tap.path}/livecheck/strategy" Dir["#{tap_strategy_path}/*.rb"].sort.each(&method(:require)) if Dir.exist?(tap_strategy_path) end # Cache demodulized strategy names, to avoid repeating this work @livecheck_strategy_names = {} Strategy.constants.sort.each do |strategy_symbol| strategy = Strategy.const_get(strategy_symbol) @livecheck_strategy_names[strategy] = strategy.name.demodulize end @livecheck_strategy_names.freeze has_a_newer_upstream_version = false if args.json? && !args.quiet? && $stderr.tty? total_formulae = if formulae_to_check == Formula formulae_to_check.count else formulae_to_check.length end Tty.with($stderr) do |stderr| stderr.puts Formatter.headline("Running checks", color: :blue) end progress = ProgressBar.create( total: total_formulae, progress_mark: "#", remainder_mark: ".", format: " %t: [%B] %c/%C ", output: $stderr, ) end formulae_checked = formulae_to_check.sort.map.with_index do |formula, i| if args.debug? && i.positive? puts <<~EOS ---------- EOS end skip_result = skip_conditions(formula, args: args) next skip_result if skip_result != false formula.head&.downloader&.shutup! # Use the `stable` version for comparison except for installed # head-only formulae. A formula with `stable` and `head` that's # installed using `--head` will still use the `stable` version for # comparison. current = if formula.head_only? formula.any_installed_version.version.commit else formula.stable.version end latest = if formula.head_only? formula.head.downloader.fetch_last_commit else version_info = latest_version(formula, args: args) version_info[:latest] if version_info.present? end if latest.blank? no_versions_msg = "Unable to get versions" raise TypeError, no_versions_msg unless args.json? next version_info if version_info.is_a?(Hash) && version_info[:status] && version_info[:messages] next status_hash(formula, "error", [no_versions_msg], args: args) end if (m = latest.to_s.match(/(.*)-release$/)) && !current.to_s.match(/.*-release$/) latest = Version.new(m[1]) end is_outdated = if formula.head_only? # A HEAD-only formula is considered outdated if the latest upstream # commit hash is different than the installed version's commit hash (current != latest) else (current < latest) end is_newer_than_upstream = formula.stable? && (current > latest) info = { formula: formula_name(formula, args: args), version: { current: current.to_s, latest: latest.to_s, outdated: is_outdated, newer_than_upstream: is_newer_than_upstream, }, meta: { livecheckable: formula.livecheckable?, }, } info[:meta][:head_only] = true if formula.head_only? info[:meta].merge!(version_info[:meta]) if version_info.present? && version_info.key?(:meta) next if args.newer_only? && !info[:version][:outdated] has_a_newer_upstream_version ||= true if args.json? progress&.increment info.except!(:meta) unless args.verbose? next info end print_latest_version(info, args: args) nil rescue => e Homebrew.failed = true if args.json? progress&.increment status_hash(formula, "error", [e.to_s], args: args) elsif !args.quiet? onoe "#{Tty.blue}#{formula_name(formula, args: args)}#{Tty.reset}: #{e}" nil end end if args.newer_only? && !has_a_newer_upstream_version && !args.debug? && !args.json? puts "No newer upstream versions." end return unless args.json? if progress progress.finish Tty.with($stderr) do |stderr| stderr.print "#{Tty.up}#{Tty.erase_line}" * 2 end end puts JSON.generate(formulae_checked.compact) end |
.preprocess_url(url) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Preprocesses and returns the URL used by livecheck.
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
# File 'Library/Homebrew/livecheck/livecheck.rb', line 311 def preprocess_url(url) # Check for GitHub repos on github.com, not AWS url = url.sub("github.s3.amazonaws.com", "github.com") if url.include?("github") # Use repo from GitHub or GitLab inferred from download URL if url.include?("github.com") && GITHUB_SPECIAL_CASES.none? { |sc| url.include? sc } if url.include? "archive" url = url.sub(%r{/archive/.*}, ".git") if url.include? "github" elsif url.include? "releases" url = url.sub(%r{/releases/.*}, ".git") elsif url.include? "downloads" url = "#{Pathname.new(url.sub(%r{/downloads(.*)}, "\\1")).dirname}.git" elsif !url.end_with?(".git") # Truncate the URL at the user/repo part, if possible %r{(?<github_repo_url>(?:[a-z]+://)?github.com/[^/]+/[^/#]+)} =~ url url = github_repo_url if github_repo_url.present? url.delete_suffix!("/") if url.end_with?("/") url += ".git" end elsif url.include?("/-/archive/") url = url.sub(%r{/-/archive/.*$}i, ".git") end url end |
.print_latest_version(info, args:) ⇒ nil
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Formats and prints the livecheck result for a formula.
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
# File 'Library/Homebrew/livecheck/livecheck.rb', line 276 def print_latest_version(info, args:) formula_s = "#{Tty.blue}#{info[:formula]}#{Tty.reset}" formula_s += " (guessed)" if !info[:meta][:livecheckable] && args.verbose? current_s = if info[:version][:newer_than_upstream] "#{Tty.red}#{info[:version][:current]}#{Tty.reset}" else info[:version][:current] end latest_s = if info[:version][:outdated] "#{Tty.green}#{info[:version][:latest]}#{Tty.reset}" else info[:version][:latest] end puts "#{formula_s} : #{current_s} ==> #{latest_s}" end |
.skip_conditions(formula, args:) ⇒ Hash, ...
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
If a formula has to be skipped, it prints or returns a Hash contaning the reason for doing so; returns false otherwise.
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 |
# File 'Library/Homebrew/livecheck/livecheck.rb', line 228 def skip_conditions(formula, args:) if formula.deprecated? && !formula.livecheckable? return status_hash(formula, "deprecated", args: args) if args.json? puts "#{Tty.red}#{formula_name(formula, args: args)}#{Tty.reset} : deprecated" unless args.quiet? return end if formula.versioned_formula? && !formula.livecheckable? return status_hash(formula, "versioned", args: args) if args.json? puts "#{Tty.red}#{formula_name(formula, args: args)}#{Tty.reset} : versioned" unless args.quiet? return end if formula.head_only? && !formula.any_version_installed? head_only_msg = "HEAD only formula must be installed to be livecheckable" return status_hash(formula, "error", [head_only_msg], args: args) if args.json? puts "#{Tty.red}#{formula_name(formula, args: args)}#{Tty.reset} : #{head_only_msg}" unless args.quiet? return end is_gist = formula.stable&.url&.include?("gist.github.com") if formula.livecheck.skip? || is_gist skip_msg = if formula.livecheck.skip_msg.is_a?(String) && formula.livecheck.skip_msg.present? formula.livecheck.skip_msg.to_s elsif is_gist "Stable URL is a GitHub Gist" else "" end return status_hash(formula, "skipped", (skip_msg.blank? ? nil : [skip_msg]), args: args) if args.json? unless args.quiet? puts "#{Tty.red}#{formula_name(formula, args: args)}#{Tty.reset} : skipped" \ "#{" - #{skip_msg}" if skip_msg.present?}" end return end false end |
.status_hash(formula, status_str, messages = nil, args:) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'Library/Homebrew/livecheck/livecheck.rb', line 208 def status_hash(formula, status_str, = nil, args:) status_hash = { formula: formula_name(formula, args: args), status: status_str, } status_hash[:messages] = if .is_a?(Array) if args.verbose? status_hash[:meta] = { livecheckable: formula.livecheckable?, } status_hash[:meta][:head_only] = true if formula.head_only? end status_hash end |