Merge pull request #19410 from SMillerDev/feat/cask/shell_completion
feat: add cask shell completion
This commit is contained in:
		
						commit
						475ceb9657
					
				@ -22,6 +22,9 @@ require "cask/artifact/prefpane"
 | 
			
		||||
require "cask/artifact/qlplugin"
 | 
			
		||||
require "cask/artifact/mdimporter"
 | 
			
		||||
require "cask/artifact/screen_saver"
 | 
			
		||||
require "cask/artifact/bashcompletion"
 | 
			
		||||
require "cask/artifact/fishcompletion"
 | 
			
		||||
require "cask/artifact/zshcompletion"
 | 
			
		||||
require "cask/artifact/service"
 | 
			
		||||
require "cask/artifact/stage_only"
 | 
			
		||||
require "cask/artifact/suite"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										25
									
								
								Library/Homebrew/cask/artifact/bashcompletion.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Library/Homebrew/cask/artifact/bashcompletion.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "cask/artifact/shellcompletion"
 | 
			
		||||
 | 
			
		||||
module Cask
 | 
			
		||||
  module Artifact
 | 
			
		||||
    # Artifact corresponding to the `bash_completion` stanza.
 | 
			
		||||
    class BashCompletion < ShellCompletion
 | 
			
		||||
      sig { params(target: T.any(String, Pathname)).returns(Pathname) }
 | 
			
		||||
      def resolve_target(target)
 | 
			
		||||
        name = if File.extname(target).nil?
 | 
			
		||||
          target
 | 
			
		||||
        else
 | 
			
		||||
          new_name = File.basename(target, File.extname(target))
 | 
			
		||||
          odebug "Renaming completion #{target} to #{new_name}"
 | 
			
		||||
 | 
			
		||||
          new_name
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        config.bash_completion/name
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										25
									
								
								Library/Homebrew/cask/artifact/fishcompletion.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Library/Homebrew/cask/artifact/fishcompletion.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "cask/artifact/shellcompletion"
 | 
			
		||||
 | 
			
		||||
module Cask
 | 
			
		||||
  module Artifact
 | 
			
		||||
    # Artifact corresponding to the `fish_completion` stanza.
 | 
			
		||||
    class FishCompletion < ShellCompletion
 | 
			
		||||
      sig { params(target: T.any(String, Pathname)).returns(Pathname) }
 | 
			
		||||
      def resolve_target(target)
 | 
			
		||||
        name = if target.to_s.end_with? ".fish"
 | 
			
		||||
          target
 | 
			
		||||
        else
 | 
			
		||||
          new_name = "#{File.basename(target, File.extname(target))}.fish"
 | 
			
		||||
          odebug "Renaming completion #{target} to #{new_name}"
 | 
			
		||||
 | 
			
		||||
          new_name
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        config.fish_completion/name
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										20
									
								
								Library/Homebrew/cask/artifact/shellcompletion.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								Library/Homebrew/cask/artifact/shellcompletion.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "cask/artifact/symlinked"
 | 
			
		||||
 | 
			
		||||
module Cask
 | 
			
		||||
  module Artifact
 | 
			
		||||
    class ShellCompletion < Symlinked
 | 
			
		||||
      sig { params(cask: Cask, source: T.any(String, Pathname)).returns(ShellCompletion) }
 | 
			
		||||
      def self.from_args(cask, source)
 | 
			
		||||
        new(cask, source)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(_: T.any(String, Pathname)).returns(Pathname) }
 | 
			
		||||
      def resolve_target(_)
 | 
			
		||||
        raise CaskInvalidError, "Shell completion without shell info"
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										25
									
								
								Library/Homebrew/cask/artifact/zshcompletion.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Library/Homebrew/cask/artifact/zshcompletion.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "cask/artifact/shellcompletion"
 | 
			
		||||
 | 
			
		||||
module Cask
 | 
			
		||||
  module Artifact
 | 
			
		||||
    # Artifact corresponding to the `zsh_completion` stanza.
 | 
			
		||||
    class ZshCompletion < ShellCompletion
 | 
			
		||||
      sig { params(target: T.any(String, Pathname)).returns(Pathname) }
 | 
			
		||||
      def resolve_target(target)
 | 
			
		||||
        name = if target.to_s.start_with? "_"
 | 
			
		||||
          target
 | 
			
		||||
        else
 | 
			
		||||
          new_name = "_#{File.basename(target, File.extname(target))}"
 | 
			
		||||
          odebug "Renaming completion #{target} to #{new_name}"
 | 
			
		||||
 | 
			
		||||
          new_name
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        config.zsh_completion/name
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@ -176,6 +176,21 @@ module Cask
 | 
			
		||||
      @manpagedir ||= T.let(HOMEBREW_PREFIX/"share/man", T.nilable(Pathname))
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    sig { returns(Pathname) }
 | 
			
		||||
    def bash_completion
 | 
			
		||||
      @bash_completion ||= T.let(HOMEBREW_PREFIX/"etc/bash_completion.d", T.nilable(Pathname))
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    sig { returns(Pathname) }
 | 
			
		||||
    def zsh_completion
 | 
			
		||||
      @zsh_completion ||= T.let(HOMEBREW_PREFIX/"share/zsh/site-functions", T.nilable(Pathname))
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    sig { returns(Pathname) }
 | 
			
		||||
    def fish_completion
 | 
			
		||||
      @fish_completion ||= T.let(HOMEBREW_PREFIX/"share/fish/vendor_completions.d", T.nilable(Pathname))
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    sig { returns(T::Array[String]) }
 | 
			
		||||
    def languages
 | 
			
		||||
      [
 | 
			
		||||
 | 
			
		||||
@ -53,6 +53,9 @@ module Cask
 | 
			
		||||
      Artifact::Suite,
 | 
			
		||||
      Artifact::VstPlugin,
 | 
			
		||||
      Artifact::Vst3Plugin,
 | 
			
		||||
      Artifact::ZshCompletion,
 | 
			
		||||
      Artifact::FishCompletion,
 | 
			
		||||
      Artifact::BashCompletion,
 | 
			
		||||
      Artifact::Uninstall,
 | 
			
		||||
      Artifact::Zap,
 | 
			
		||||
    ].freeze
 | 
			
		||||
@ -449,6 +452,7 @@ module Cask
 | 
			
		||||
      @artifacts ||= ArtifactSet.new
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    sig { returns(Pathname) }
 | 
			
		||||
    def caskroom_path
 | 
			
		||||
      cask.caskroom_path
 | 
			
		||||
    end
 | 
			
		||||
@ -456,6 +460,7 @@ module Cask
 | 
			
		||||
    # The staged location for this cask, including version number.
 | 
			
		||||
    #
 | 
			
		||||
    # @api public
 | 
			
		||||
    sig { returns(Pathname) }
 | 
			
		||||
    def staged_path
 | 
			
		||||
      return @staged_path if @staged_path
 | 
			
		||||
 | 
			
		||||
@ -587,9 +592,15 @@ module Cask
 | 
			
		||||
      true
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    sig { returns(T.nilable(MacOSVersion)) }
 | 
			
		||||
    def os_version
 | 
			
		||||
      nil
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # The directory `app`s are installed into.
 | 
			
		||||
    #
 | 
			
		||||
    # @api public
 | 
			
		||||
    sig { returns(T.any(Pathname, String)) }
 | 
			
		||||
    def appdir
 | 
			
		||||
      return HOMEBREW_CASK_APPDIR_PLACEHOLDER if Cask.generating_hash?
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										4
									
								
								Library/Homebrew/extend/os/cask/dsl.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								Library/Homebrew/extend/os/cask/dsl.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "extend/os/mac/cask/dsl" if OS.mac?
 | 
			
		||||
@ -16,7 +16,12 @@ module OS
 | 
			
		||||
          return if artifacts.all?(::Cask::Artifact::Font)
 | 
			
		||||
 | 
			
		||||
          install_artifacts = artifacts.reject { |artifact| artifact.instance_of?(::Cask::Artifact::Zap) }
 | 
			
		||||
          return if install_artifacts.all?(::Cask::Artifact::Binary)
 | 
			
		||||
          return if install_artifacts.all? do |artifact|
 | 
			
		||||
            artifact.is_a?(::Cask::Artifact::Binary) ||
 | 
			
		||||
            artifact.is_a?(::Cask::Artifact::ShellCompletion) ||
 | 
			
		||||
            artifact.is_a?(::Cask::Artifact::Artifact) ||
 | 
			
		||||
            artifact.is_a?(::Cask::Artifact::Manpage)
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          raise ::Cask::CaskError, "macOS is required for this software."
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										23
									
								
								Library/Homebrew/extend/os/mac/cask/dsl.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								Library/Homebrew/extend/os/mac/cask/dsl.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "cask/macos"
 | 
			
		||||
 | 
			
		||||
module OS
 | 
			
		||||
  module Mac
 | 
			
		||||
    module Cask
 | 
			
		||||
      module DSL
 | 
			
		||||
        extend T::Helpers
 | 
			
		||||
 | 
			
		||||
        requires_ancestor { ::Cask::DSL }
 | 
			
		||||
 | 
			
		||||
        sig { returns(T.nilable(MacOSVersion)) }
 | 
			
		||||
        def os_version
 | 
			
		||||
          MacOS.full_version
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
Cask::DSL.prepend(OS::Mac::Cask::DSL)
 | 
			
		||||
							
								
								
									
										44
									
								
								Library/Homebrew/test/cask/artifact/bashcompletion_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								Library/Homebrew/test/cask/artifact/bashcompletion_spec.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
RSpec.describe Cask::Artifact::BashCompletion, :cask do
 | 
			
		||||
  let(:cask) { Cask::CaskLoader.load(cask_token) }
 | 
			
		||||
 | 
			
		||||
  context "with install" do
 | 
			
		||||
    let(:install_phase) do
 | 
			
		||||
      lambda do
 | 
			
		||||
        cask.artifacts.select { |a| a.is_a?(described_class) }.each do |artifact|
 | 
			
		||||
          artifact.install_phase(command: NeverSudoSystemCommand, force: false)
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    let(:source_path) { cask.staged_path.join("test.bash") }
 | 
			
		||||
    let(:target_path) { cask.config.bash_completion.join("test") }
 | 
			
		||||
    let(:full_source_path) { cask.staged_path.join("test.bash-completion") }
 | 
			
		||||
    let(:full_target_path) { cask.config.bash_completion.join("test") }
 | 
			
		||||
 | 
			
		||||
    before do
 | 
			
		||||
      InstallHelper.install_without_artifacts(cask)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    context "with completion" do
 | 
			
		||||
      let(:cask_token) { "with-shellcompletion" }
 | 
			
		||||
 | 
			
		||||
      it "links the completion to the proper directory" do
 | 
			
		||||
        install_phase.call
 | 
			
		||||
 | 
			
		||||
        expect(File).to be_identical target_path, source_path
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    context "with long completion" do
 | 
			
		||||
      let(:cask_token) { "with-shellcompletion-long" }
 | 
			
		||||
 | 
			
		||||
      it "links the completion to the proper directory" do
 | 
			
		||||
        install_phase.call
 | 
			
		||||
 | 
			
		||||
        expect(File).to be_identical full_target_path, full_source_path
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										44
									
								
								Library/Homebrew/test/cask/artifact/fishlcompletion_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								Library/Homebrew/test/cask/artifact/fishlcompletion_spec.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
RSpec.describe Cask::Artifact::FishCompletion, :cask do
 | 
			
		||||
  let(:cask) { Cask::CaskLoader.load(cask_token) }
 | 
			
		||||
 | 
			
		||||
  context "with install" do
 | 
			
		||||
    let(:install_phase) do
 | 
			
		||||
      lambda do
 | 
			
		||||
        cask.artifacts.select { |a| a.is_a?(described_class) }.each do |artifact|
 | 
			
		||||
          artifact.install_phase(command: NeverSudoSystemCommand, force: false)
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    let(:source_path) { cask.staged_path.join("test.fish") }
 | 
			
		||||
    let(:target_path) { cask.config.fish_completion.join("test.fish") }
 | 
			
		||||
    let(:full_source_path) { cask.staged_path.join("test.fish-completion") }
 | 
			
		||||
    let(:full_target_path) { cask.config.fish_completion.join("test.fish") }
 | 
			
		||||
 | 
			
		||||
    before do
 | 
			
		||||
      InstallHelper.install_without_artifacts(cask)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    context "with completion" do
 | 
			
		||||
      let(:cask_token) { "with-shellcompletion" }
 | 
			
		||||
 | 
			
		||||
      it "links the completion to the proper directory" do
 | 
			
		||||
        install_phase.call
 | 
			
		||||
 | 
			
		||||
        expect(File).to be_identical target_path, source_path
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    context "with long completion" do
 | 
			
		||||
      let(:cask_token) { "with-shellcompletion-long" }
 | 
			
		||||
 | 
			
		||||
      it "links the completion to the proper directory" do
 | 
			
		||||
        install_phase.call
 | 
			
		||||
 | 
			
		||||
        expect(File).to be_identical full_target_path, full_source_path
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										44
									
								
								Library/Homebrew/test/cask/artifact/zshcompletion_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								Library/Homebrew/test/cask/artifact/zshcompletion_spec.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
RSpec.describe Cask::Artifact::ZshCompletion, :cask do
 | 
			
		||||
  let(:cask) { Cask::CaskLoader.load(cask_token) }
 | 
			
		||||
 | 
			
		||||
  context "with install" do
 | 
			
		||||
    let(:install_phase) do
 | 
			
		||||
      lambda do
 | 
			
		||||
        cask.artifacts.select { |a| a.is_a?(described_class) }.each do |artifact|
 | 
			
		||||
          artifact.install_phase(command: NeverSudoSystemCommand, force: false)
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    let(:source_path) { cask.staged_path.join("_test") }
 | 
			
		||||
    let(:target_path) { cask.config.zsh_completion.join("_test") }
 | 
			
		||||
    let(:full_source_path) { cask.staged_path.join("test.zsh-completion") }
 | 
			
		||||
    let(:full_target_path) { cask.config.zsh_completion.join("_test") }
 | 
			
		||||
 | 
			
		||||
    before do
 | 
			
		||||
      InstallHelper.install_without_artifacts(cask)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    context "with completion" do
 | 
			
		||||
      let(:cask_token) { "with-shellcompletion" }
 | 
			
		||||
 | 
			
		||||
      it "links the completion to the proper directory" do
 | 
			
		||||
        install_phase.call
 | 
			
		||||
 | 
			
		||||
        expect(File).to be_identical target_path, source_path
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    context "with long completion" do
 | 
			
		||||
      let(:cask_token) { "with-shellcompletion-long" }
 | 
			
		||||
 | 
			
		||||
      it "links the completion to the proper directory" do
 | 
			
		||||
        install_phase.call
 | 
			
		||||
 | 
			
		||||
        expect(File).to be_identical full_target_path, full_source_path
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
cask "with-shellcompletion-long" do
 | 
			
		||||
  version "1.2.3"
 | 
			
		||||
  sha256 "957978d9b30adfda8e1f914ba8c8019e016545c8f7e16c6ab0234d189fac8146"
 | 
			
		||||
 | 
			
		||||
  url "file://#{TEST_FIXTURE_DIR}/cask/AppWithShellCompletion.zip"
 | 
			
		||||
  homepage "https://brew.sh/with-autodetected-manpage-section"
 | 
			
		||||
 | 
			
		||||
  bash_completion "test.bash-completion"
 | 
			
		||||
  fish_completion "test.fish-completion"
 | 
			
		||||
  zsh_completion "test.zsh-completion"
 | 
			
		||||
end
 | 
			
		||||
@ -0,0 +1,11 @@
 | 
			
		||||
cask "with-shellcompletion" do
 | 
			
		||||
  version "1.2.3"
 | 
			
		||||
  sha256 "957978d9b30adfda8e1f914ba8c8019e016545c8f7e16c6ab0234d189fac8146"
 | 
			
		||||
 | 
			
		||||
  url "file://#{TEST_FIXTURE_DIR}/cask/AppWithShellCompletion.zip"
 | 
			
		||||
  homepage "https://brew.sh/with-autodetected-manpage-section"
 | 
			
		||||
 | 
			
		||||
  bash_completion "test.bash"
 | 
			
		||||
  fish_completion "test.fish"
 | 
			
		||||
  zsh_completion "_test"
 | 
			
		||||
end
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user