Skip to content
Snippets Groups Projects
livecheck.rb 3.77 KiB
Newer Older
Markus Reiter's avatar
Markus Reiter committed
# typed: true
# frozen_string_literal: true

require "cli/parser"
require "formula"
require "livecheck/livecheck"
require "livecheck/strategy"

module Homebrew
  extend T::Sig

  module_function

  WATCHLIST_PATH = (
    ENV["HOMEBREW_LIVECHECK_WATCHLIST"] ||
Joshua Peek's avatar
Joshua Peek committed
    "#{Dir.home}/.brew_livecheck_watchlist"
  sig { returns(CLI::Parser) }
  def livecheck_args
    Homebrew::CLI::Parser.new do
      usage_banner <<~EOS
Seeker's avatar
Seeker committed
        `livecheck` [<formulae>|<casks>]
Seeker's avatar
Seeker committed
        Check for newer versions of formulae and/or casks from upstream.
        If no formula or cask argument is passed, the list of formulae and
        casks to check is taken from `HOMEBREW_LIVECHECK_WATCHLIST` or
        `~/.brew_livecheck_watchlist`.
      EOS
      switch "--full-name",
Seeker's avatar
Seeker committed
             description: "Print formulae/casks with fully-qualified names."
      flag   "--tap=",
Seeker's avatar
Seeker committed
             description: "Check formulae/casks within the given tap, specified as <user>`/`<repo>."
      switch "--all",
Seeker's avatar
Seeker committed
             description: "Check all available formulae/casks."
      switch "--installed",
Seeker's avatar
Seeker committed
             description: "Check formulae/casks that are currently installed."
      switch "--newer-only",
Seeker's avatar
Seeker committed
             description: "Show the latest version only if it's newer than the formula/cask."
      switch "--json",
             description: "Output information in JSON format."
      switch "-q", "--quiet",
             description: "Suppress warnings, don't print a progress bar for JSON output."
      switch "--formula", "--formulae",
             description: "Only check formulae."
      switch "--cask", "--casks",
             description: "Only check casks."
      conflicts "--debug", "--json"
      conflicts "--tap=", "--all", "--installed"
      conflicts "--cask", "--formula"
    end
  end

  def livecheck
    args = livecheck_args.parse

    if args.debug? && args.verbose?
      puts args
      puts ENV["HOMEBREW_LIVECHECK_WATCHLIST"] if ENV["HOMEBREW_LIVECHECK_WATCHLIST"].present?
    end

    formulae_and_casks_to_check = if args.tap
      tap = Tap.fetch(args.tap)
      formulae = args.cask? ? [] : tap.formula_files.map { |path| Formulary.factory(path) }
      casks = args.formula? ? [] : tap.cask_files.map { |path| Cask::CaskLoader.load(path) }
      formulae + casks
    elsif args.installed?
Markus Reiter's avatar
Markus Reiter committed
      formulae = args.cask? ? [] : Formula.installed
      casks = args.formula? ? [] : Cask::Caskroom.casks
      formulae + casks
    elsif args.all?
Markus Reiter's avatar
Markus Reiter committed
      formulae = args.cask? ? [] : Formula.to_a
      casks = args.formula? ? [] : Cask::Cask.to_a
      formulae + casks
    elsif args.named.present?
      if args.formula?
        args.named.to_formulae
      elsif args.cask?
        args.named.to_casks
      else
        args.named.to_formulae_and_casks
      end
    elsif File.exist?(WATCHLIST_PATH)
      begin
Seeker's avatar
Seeker committed
        names = Pathname.new(WATCHLIST_PATH).read.lines
                        .reject { |line| line.start_with?("#") || line.blank? }
                        .map(&:strip)
Markus Reiter's avatar
Markus Reiter committed
        named_args = T.unsafe(CLI::NamedArgs).new(*names)
        named_args.to_formulae_and_casks.reject do |formula_or_cask|
          (args.formula? && !formula_or_cask.is_a?(Formula)) ||
            (args.cask? && !formula_or_cask.is_a?(Cask::Cask))
      rescue Errno::ENOENT => e
        onoe e
      end
    end.sort_by do |formula_or_cask|
      formula_or_cask.respond_to?(:token) ? formula_or_cask.token : formula_or_cask.name
    raise UsageError, "No formulae or casks to check." if formulae_and_casks_to_check.blank?
    options = {
      json:       args.json?,
      full_name:  args.full_name?,
      newer_only: args.newer_only?,
      quiet:      args.quiet?,
      debug:      args.debug?,
      verbose:    args.verbose?,
    }.compact

    Livecheck.run_checks(formulae_and_casks_to_check, **options)