Add bump-unversioned-casks command.
				
					
				
			This commit is contained in:
		
							parent
							
								
									ff28d7c69b
								
							
						
					
					
						commit
						b57a448f2a
					
				@ -40,6 +40,10 @@ module Cask
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def time_file_size
 | 
			
		||||
      downloader.resolved_time_file_size
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def clear_cache
 | 
			
		||||
      downloader.clear_cache
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -30,7 +30,8 @@ module Cask
 | 
			
		||||
    def initialize(cask, command: SystemCommand, force: false,
 | 
			
		||||
                   skip_cask_deps: false, binaries: true, verbose: false,
 | 
			
		||||
                   require_sha: false, upgrade: false,
 | 
			
		||||
                   installed_as_dependency: false, quarantine: true)
 | 
			
		||||
                   installed_as_dependency: false, quarantine: true,
 | 
			
		||||
                   verify_download_integrity: true)
 | 
			
		||||
      @cask = cask
 | 
			
		||||
      @command = command
 | 
			
		||||
      @force = force
 | 
			
		||||
@ -42,6 +43,7 @@ module Cask
 | 
			
		||||
      @upgrade = upgrade
 | 
			
		||||
      @installed_as_dependency = installed_as_dependency
 | 
			
		||||
      @quarantine = quarantine
 | 
			
		||||
      @verify_download_integrity = verify_download_integrity
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    attr_predicate :binaries?, :force?, :skip_cask_deps?, :require_sha?,
 | 
			
		||||
@ -150,13 +152,10 @@ module Cask
 | 
			
		||||
      s.freeze
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    sig { returns(Pathname) }
 | 
			
		||||
    def download
 | 
			
		||||
      return @downloaded_path if @downloaded_path
 | 
			
		||||
 | 
			
		||||
      odebug "Downloading"
 | 
			
		||||
      @downloaded_path = Download.new(@cask, quarantine: quarantine?).fetch
 | 
			
		||||
      odebug "Downloaded to -> #{@downloaded_path}"
 | 
			
		||||
      @downloaded_path
 | 
			
		||||
      @download ||= Download.new(@cask, quarantine: quarantine?)
 | 
			
		||||
                            .fetch(verify_download_integrity: @verify_download_integrity)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def verify_has_sha
 | 
			
		||||
@ -171,15 +170,15 @@ module Cask
 | 
			
		||||
 | 
			
		||||
    def primary_container
 | 
			
		||||
      @primary_container ||= begin
 | 
			
		||||
        download
 | 
			
		||||
        UnpackStrategy.detect(@downloaded_path, type: @cask.container&.type, merge_xattrs: true)
 | 
			
		||||
        downloaded_path = download
 | 
			
		||||
        UnpackStrategy.detect(downloaded_path, type: @cask.container&.type, merge_xattrs: true)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def extract_primary_container
 | 
			
		||||
    def extract_primary_container(to: @cask.staged_path)
 | 
			
		||||
      odebug "Extracting primary container"
 | 
			
		||||
 | 
			
		||||
      odebug "Using container class #{primary_container.class} for #{@downloaded_path}"
 | 
			
		||||
      odebug "Using container class #{primary_container.class} for #{primary_container.path}"
 | 
			
		||||
 | 
			
		||||
      basename = CGI.unescape(File.basename(@cask.url.path))
 | 
			
		||||
 | 
			
		||||
@ -191,16 +190,16 @@ module Cask
 | 
			
		||||
          FileUtils.chmod_R "+rw", tmpdir/nested_container, force: true, verbose: verbose?
 | 
			
		||||
 | 
			
		||||
          UnpackStrategy.detect(tmpdir/nested_container, merge_xattrs: true)
 | 
			
		||||
                        .extract_nestedly(to: @cask.staged_path, verbose: verbose?)
 | 
			
		||||
                        .extract_nestedly(to: to, verbose: verbose?)
 | 
			
		||||
        end
 | 
			
		||||
      else
 | 
			
		||||
        primary_container.extract_nestedly(to: @cask.staged_path, basename: basename, verbose: verbose?)
 | 
			
		||||
        primary_container.extract_nestedly(to: to, basename: basename, verbose: verbose?)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      return unless quarantine?
 | 
			
		||||
      return unless Quarantine.available?
 | 
			
		||||
 | 
			
		||||
      Quarantine.propagate(from: @downloaded_path, to: @cask.staged_path)
 | 
			
		||||
      Quarantine.propagate(from: primary_container.path, to: to)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def install_artifacts
 | 
			
		||||
 | 
			
		||||
@ -72,9 +72,10 @@ module Homebrew
 | 
			
		||||
    new_version = Cask::DSL::Version.new(new_version)
 | 
			
		||||
    new_base_url = args.url
 | 
			
		||||
    new_hash = args.sha256
 | 
			
		||||
    new_hash = :no_check if new_hash == ":no_check"
 | 
			
		||||
 | 
			
		||||
    old_version = cask.version
 | 
			
		||||
    old_hash = cask.sha256.to_s
 | 
			
		||||
    old_hash = cask.sha256
 | 
			
		||||
 | 
			
		||||
    tap_full_name = cask.tap&.full_name
 | 
			
		||||
    default_remote_branch = cask.tap.path.git_origin_branch if cask.tap
 | 
			
		||||
@ -95,7 +96,7 @@ module Homebrew
 | 
			
		||||
    elsif old_version.latest?
 | 
			
		||||
      opoo "No --url= argument specified!" unless new_base_url
 | 
			
		||||
    elsif new_version.latest?
 | 
			
		||||
      opoo "Ignoring specified --sha256= argument." if new_hash
 | 
			
		||||
      opoo "Ignoring specified --sha256= argument." if new_hash && new_check != :no_check
 | 
			
		||||
    elsif Version.new(new_version) < Version.new(old_version)
 | 
			
		||||
      odie <<~EOS
 | 
			
		||||
        You need to bump this cask manually since changing the
 | 
			
		||||
@ -136,7 +137,9 @@ module Homebrew
 | 
			
		||||
      ]
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    if !new_version.latest? && (new_hash.nil? || cask.languages.present?)
 | 
			
		||||
    if new_version.latest?
 | 
			
		||||
      new_hash = :no_check
 | 
			
		||||
    elsif new_hash.nil? || cask.languages.present?
 | 
			
		||||
      tmp_contents = Utils::Inreplace.inreplace_pairs(cask.sourcefile_path,
 | 
			
		||||
                                                      replacement_pairs.uniq.compact,
 | 
			
		||||
                                                      read_only_run: true,
 | 
			
		||||
@ -172,15 +175,14 @@ module Homebrew
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    replacement_pairs << if old_version.latest?
 | 
			
		||||
    p old_hash
 | 
			
		||||
 | 
			
		||||
    replacement_pairs << if old_version.latest? || new_version.latest? || new_hash == :no_check
 | 
			
		||||
      hash_regex = old_hash == :no_check ? ":no_check" : "[\"']#{Regexp.escape(old_hash.to_s)}[\"']"
 | 
			
		||||
 | 
			
		||||
      [
 | 
			
		||||
        "sha256 :no_check",
 | 
			
		||||
        "sha256 \"#{new_hash}\"",
 | 
			
		||||
      ]
 | 
			
		||||
    elsif new_version.latest?
 | 
			
		||||
      [
 | 
			
		||||
        "sha256 \"#{old_hash}\"",
 | 
			
		||||
        "sha256 :no_check",
 | 
			
		||||
        /sha256\s+#{hash_regex}/m,
 | 
			
		||||
        "sha256 #{new_hash == :no_check ? ":no_check" : "\"#{new_hash}\""}",
 | 
			
		||||
      ]
 | 
			
		||||
    else
 | 
			
		||||
      [
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										201
									
								
								Library/Homebrew/dev-cmd/bump-unversioned-casks.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								Library/Homebrew/dev-cmd/bump-unversioned-casks.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,201 @@
 | 
			
		||||
# typed: false
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "cask/download"
 | 
			
		||||
require "cask/installer"
 | 
			
		||||
require "cask/cask_loader"
 | 
			
		||||
require "cli/parser"
 | 
			
		||||
require "tap"
 | 
			
		||||
 | 
			
		||||
module Homebrew
 | 
			
		||||
  extend T::Sig
 | 
			
		||||
 | 
			
		||||
  extend SystemCommand::Mixin
 | 
			
		||||
 | 
			
		||||
  sig { returns(CLI::Parser) }
 | 
			
		||||
  def self.bump_unversioned_casks_args
 | 
			
		||||
    Homebrew::CLI::Parser.new do
 | 
			
		||||
      usage_banner <<~EOS
 | 
			
		||||
        `bump-unversioned-casks` [<options>] [<tap>]
 | 
			
		||||
 | 
			
		||||
        Check all casks with unversioned URLs in a given <tap> for updates.
 | 
			
		||||
      EOS
 | 
			
		||||
      switch "-n", "--dry-run",
 | 
			
		||||
             description: "List what would be done, but do not actually do anything."
 | 
			
		||||
      flag  "--limit=",
 | 
			
		||||
            description: "Maximum number of casks to update."
 | 
			
		||||
      flag   "--state-file=",
 | 
			
		||||
             description: "File for keeping track of state."
 | 
			
		||||
 | 
			
		||||
      named 1
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  sig { void }
 | 
			
		||||
  def self.bump_unversioned_casks
 | 
			
		||||
    args = bump_unversioned_casks_args.parse
 | 
			
		||||
 | 
			
		||||
    state_file = if args.state_file.present?
 | 
			
		||||
      Pathname(args.state_file).expand_path
 | 
			
		||||
    else
 | 
			
		||||
      HOMEBREW_CACHE/"bump_unversioned_casks.json"
 | 
			
		||||
    end
 | 
			
		||||
    state_file.dirname.mkpath
 | 
			
		||||
 | 
			
		||||
    tap = Tap.fetch(args.named.first)
 | 
			
		||||
 | 
			
		||||
    old_state = state_file.exist? ? JSON.parse(state_file.read) : {}
 | 
			
		||||
 | 
			
		||||
    new_state = {}
 | 
			
		||||
 | 
			
		||||
    cask_files = tap.cask_files
 | 
			
		||||
    unversioned_cask_files = cask_files.select do |cask_file|
 | 
			
		||||
      url = cask_file.each_line do |line|
 | 
			
		||||
        url = line[/\s*url\s+"([^"]+)"\s*/, 1]
 | 
			
		||||
        break url if url
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      url.present? && url.exclude?('#{')
 | 
			
		||||
    end.sort
 | 
			
		||||
 | 
			
		||||
    unversioned_casks = unversioned_cask_files.map { |path| Cask::CaskLoader.load(path) }
 | 
			
		||||
 | 
			
		||||
    ohai "Static Casks:"
 | 
			
		||||
    puts "Total:      #{unversioned_casks.count}"
 | 
			
		||||
    puts "Single-App: #{unversioned_casks.count { |c| single_app_cask?(c) }}"
 | 
			
		||||
    puts "Single-Pkg: #{unversioned_casks.count { |c| single_pkg_cask?(c) }}"
 | 
			
		||||
 | 
			
		||||
    limit = args.limit.presence&.to_i || unversioned_casks.count
 | 
			
		||||
 | 
			
		||||
    unversioned_casks.shuffle.each do |cask|
 | 
			
		||||
      ohai "Checking #{cask.full_name}"
 | 
			
		||||
 | 
			
		||||
      unless single_app_cask?(cask)
 | 
			
		||||
        opoo "Skipping, not a single-app cask."
 | 
			
		||||
        next
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      download = Cask::Download.new(cask)
 | 
			
		||||
      time, file_size = begin
 | 
			
		||||
        download.time_file_size
 | 
			
		||||
      rescue
 | 
			
		||||
        opoo "Skipping, cannot get time and file size."
 | 
			
		||||
        next
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      odebug "Time: #{time.inspect}"
 | 
			
		||||
      odebug "Size: #{file_size.inspect}"
 | 
			
		||||
 | 
			
		||||
      last_state = old_state.fetch(cask.full_name, {})
 | 
			
		||||
      last_check_time = last_state["check_time"]&.yield_self { |t| Time.parse(t) }
 | 
			
		||||
 | 
			
		||||
      check_time = Time.now
 | 
			
		||||
      if last_check_time && check_time < (last_check_time + 1.day)
 | 
			
		||||
        opoo "Skipping, already checked within the last 24 hours."
 | 
			
		||||
        next
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      last_sha256 = last_state["sha256"]
 | 
			
		||||
      last_time = last_state["time"]&.yield_self { |t| Time.parse(t) }
 | 
			
		||||
      last_file_size = last_state["file_size"]
 | 
			
		||||
 | 
			
		||||
      next if last_time == time && last_file_size == file_size
 | 
			
		||||
 | 
			
		||||
      installer = Cask::Installer.new(cask, verify_download_integrity: false)
 | 
			
		||||
 | 
			
		||||
      begin
 | 
			
		||||
        cached_download = installer.download
 | 
			
		||||
      rescue => e
 | 
			
		||||
        onoe e
 | 
			
		||||
        next
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sha256 = cached_download.sha256
 | 
			
		||||
 | 
			
		||||
      if last_sha256 != sha256 && (version = guess_cask_version(cask, installer))
 | 
			
		||||
        odebug "Version: #{version.inspect}"
 | 
			
		||||
 | 
			
		||||
        if cask.version == version
 | 
			
		||||
          oh1 "Cask #{cask} is up-to-date at #{version}"
 | 
			
		||||
        else
 | 
			
		||||
          bump_cask_pr_args = [
 | 
			
		||||
            "bump-cask-pr",
 | 
			
		||||
            "--version", version.to_s,
 | 
			
		||||
            "--sha256", ":no_check",
 | 
			
		||||
            "--message", "Automatic update via `brew bump-unversioned-casks`.",
 | 
			
		||||
            cask.sourcefile_path
 | 
			
		||||
          ]
 | 
			
		||||
 | 
			
		||||
          if args.dry_run?
 | 
			
		||||
            bump_cask_pr_args << "--dry-run"
 | 
			
		||||
            oh1 "Would bump #{cask} from #{cask.version} to #{version}"
 | 
			
		||||
          else
 | 
			
		||||
            oh1 "Bumping #{cask} from #{cask.version} to #{version}"
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          begin
 | 
			
		||||
            system_command! HOMEBREW_BREW_FILE, args: bump_cask_pr_args
 | 
			
		||||
          rescue ErrorDuringExecution => e
 | 
			
		||||
            onoe e
 | 
			
		||||
            Homebrew.failed = true
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      unless args.dry_run?
 | 
			
		||||
        new_state[cask.full_name] = {
 | 
			
		||||
          "sha256"     => sha256,
 | 
			
		||||
          "check_time" => check_time.iso8601,
 | 
			
		||||
          "time"       => time&.iso8601,
 | 
			
		||||
          "file_size"  => file_size,
 | 
			
		||||
        }
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      break if (limit -= 1).zero?
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    state_file.atomic_write JSON.pretty_generate(old_state.merge(new_state))
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  sig { params(cask: Cask::Cask, installer: Cask::Installer).returns(T.nilable(String)) }
 | 
			
		||||
  def self.guess_cask_version(cask, installer)
 | 
			
		||||
    apps = cask.artifacts.select { |a| a.is_a?(Cask::Artifact::App) }
 | 
			
		||||
    return if apps.count != 1
 | 
			
		||||
 | 
			
		||||
    Dir.mktmpdir do |dir|
 | 
			
		||||
      dir = Pathname(dir)
 | 
			
		||||
 | 
			
		||||
      installer.extract_primary_container(to: dir)
 | 
			
		||||
 | 
			
		||||
      plists = apps.flat_map do |app|
 | 
			
		||||
        Pathname.glob(dir/"**"/app.source.basename/"Contents"/"Info.plist")
 | 
			
		||||
      end
 | 
			
		||||
      next if plists.empty?
 | 
			
		||||
 | 
			
		||||
      plist = plists.first
 | 
			
		||||
 | 
			
		||||
      system_command! "plutil", args: ["-convert", "xml1", plist]
 | 
			
		||||
      plist = Plist.parse_xml(plist.read)
 | 
			
		||||
 | 
			
		||||
      short_version = plist["CFBundleShortVersionString"]
 | 
			
		||||
      version = plist["CFBundleVersion"]
 | 
			
		||||
 | 
			
		||||
      return "#{short_version},#{version}" if cask.version.include?(",")
 | 
			
		||||
 | 
			
		||||
      return cask.version.to_s if [short_version, version].include?(cask.version.to_s)
 | 
			
		||||
 | 
			
		||||
      return short_version if short_version&.match(/\A\d+(\.\d+)+\Z/)
 | 
			
		||||
      return version if version&.match(/\A\d+(\.\d+)+\Z/)
 | 
			
		||||
 | 
			
		||||
      short_version || version
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def self.single_app_cask?(cask)
 | 
			
		||||
    cask.artifacts.count { |a| a.is_a?(Cask::Artifact::App) } == 1
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def self.single_pkg_cask?(cask)
 | 
			
		||||
    cask.artifacts.count { |a| a.is_a?(Cask::Artifact::Pkg) } == 1
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@ -356,7 +356,7 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
 | 
			
		||||
 | 
			
		||||
      ohai "Downloading #{url}"
 | 
			
		||||
 | 
			
		||||
      resolved_url, _, url_time = resolve_url_basename_time(url)
 | 
			
		||||
      resolved_url, _, url_time, = resolve_url_basename_time_file_size(url)
 | 
			
		||||
 | 
			
		||||
      fresh = if cached_location.exist? && url_time
 | 
			
		||||
        url_time <= cached_location.mtime
 | 
			
		||||
@ -398,14 +398,19 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
 | 
			
		||||
    rm_rf(temporary_path)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def resolved_time_file_size
 | 
			
		||||
    _, _, time, file_size = resolve_url_basename_time_file_size(url)
 | 
			
		||||
    [time, file_size]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def resolved_url_and_basename
 | 
			
		||||
    resolved_url, basename, = resolve_url_basename_time(url)
 | 
			
		||||
    resolved_url, basename, = resolve_url_basename_time_file_size(url)
 | 
			
		||||
    [resolved_url, basename]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def resolve_url_basename_time(url)
 | 
			
		||||
  def resolve_url_basename_time_file_size(url)
 | 
			
		||||
    @resolved_info_cache ||= {}
 | 
			
		||||
    return @resolved_info_cache[url] if @resolved_info_cache.include?(url)
 | 
			
		||||
 | 
			
		||||
@ -458,9 +463,15 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
 | 
			
		||||
           .map { |t| t.match?(/^\d+$/) ? Time.at(t.to_i) : Time.parse(t) }
 | 
			
		||||
           .last
 | 
			
		||||
 | 
			
		||||
    file_size =
 | 
			
		||||
      lines.map { |line| line[/^Content-Length:\s*(\d+)/i, 1] }
 | 
			
		||||
           .compact
 | 
			
		||||
           .map(&:to_i)
 | 
			
		||||
           .last
 | 
			
		||||
 | 
			
		||||
    basename = filenames.last || parse_basename(redirect_url)
 | 
			
		||||
 | 
			
		||||
    @resolved_info_cache[url] = [redirect_url, basename, time]
 | 
			
		||||
    @resolved_info_cache[url] = [redirect_url, basename, time, file_size]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def _fetch(url:, resolved_url:)
 | 
			
		||||
@ -526,7 +537,7 @@ class CurlApacheMirrorDownloadStrategy < CurlDownloadStrategy
 | 
			
		||||
    @combined_mirrors = [*@mirrors, *backup_mirrors]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def resolve_url_basename_time(url)
 | 
			
		||||
  def resolve_url_basename_time_file_size(url)
 | 
			
		||||
    if url == self.url
 | 
			
		||||
      super("#{apache_mirrors["preferred"]}#{apache_mirrors["path_info"]}")
 | 
			
		||||
    else
 | 
			
		||||
 | 
			
		||||
@ -736,11 +736,12 @@ module GitHub
 | 
			
		||||
        EOS
 | 
			
		||||
        user_message = args.message
 | 
			
		||||
        if user_message
 | 
			
		||||
          pr_message += <<~EOS
 | 
			
		||||
          pr_message = <<~EOS
 | 
			
		||||
            #{user_message}
 | 
			
		||||
 | 
			
		||||
            ---
 | 
			
		||||
 | 
			
		||||
            #{user_message}
 | 
			
		||||
            #{pr_message}
 | 
			
		||||
          EOS
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -18,6 +18,7 @@ bump
 | 
			
		||||
bump-cask-pr
 | 
			
		||||
bump-formula-pr
 | 
			
		||||
bump-revision
 | 
			
		||||
bump-unversioned-casks
 | 
			
		||||
cask
 | 
			
		||||
cat
 | 
			
		||||
cleanup
 | 
			
		||||
 | 
			
		||||
@ -899,6 +899,17 @@ present, "revision 1" will be added.
 | 
			
		||||
* `--message`:
 | 
			
		||||
  Append *`message`* to the default commit message.
 | 
			
		||||
 | 
			
		||||
### `bump-unversioned-casks` [*`options`*] [*`tap`*]
 | 
			
		||||
 | 
			
		||||
Check all casks with unversioned URLs in a given *`tap`* for updates.
 | 
			
		||||
 | 
			
		||||
* `-n`, `--dry-run`:
 | 
			
		||||
  List what would be done, but do not actually do anything.
 | 
			
		||||
* `--limit`:
 | 
			
		||||
  Maximum number of casks to update.
 | 
			
		||||
* `--state-file`:
 | 
			
		||||
  File for keeping track of state.
 | 
			
		||||
 | 
			
		||||
### `cat` *`formula`*|*`cask`*
 | 
			
		||||
 | 
			
		||||
Display the source of a *`formula`* or *`cask`*.
 | 
			
		||||
 | 
			
		||||
@ -1245,6 +1245,21 @@ Print what would be done rather than doing it\.
 | 
			
		||||
\fB\-\-message\fR
 | 
			
		||||
Append \fImessage\fR to the default commit message\.
 | 
			
		||||
.
 | 
			
		||||
.SS "\fBbump\-unversioned\-casks\fR [\fIoptions\fR] [\fItap\fR]"
 | 
			
		||||
Check all casks with unversioned URLs in a given \fItap\fR for updates\.
 | 
			
		||||
.
 | 
			
		||||
.TP
 | 
			
		||||
\fB\-n\fR, \fB\-\-dry\-run\fR
 | 
			
		||||
List what would be done, but do not actually do anything\.
 | 
			
		||||
.
 | 
			
		||||
.TP
 | 
			
		||||
\fB\-\-limit\fR
 | 
			
		||||
Maximum number of casks to update\.
 | 
			
		||||
.
 | 
			
		||||
.TP
 | 
			
		||||
\fB\-\-state\-file\fR
 | 
			
		||||
File for keeping track of state\.
 | 
			
		||||
.
 | 
			
		||||
.SS "\fBcat\fR \fIformula\fR|\fIcask\fR"
 | 
			
		||||
Display the source of a \fIformula\fR or \fIcask\fR\.
 | 
			
		||||
.
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user