From c34b71655c16aeeb49ff1415e7edcd09b55da955 Mon Sep 17 00:00:00 2001 From: Sean Molenaar Date: Wed, 4 Dec 2024 22:49:14 +0100 Subject: [PATCH 1/2] feat: allow font install on linux Apply suggestions from code review Co-authored-by: Douglas Eichelberger <697964+dduugg@users.noreply.github.com> feat: add linux appdir Apply suggestions from code review Co-authored-by: Douglas Eichelberger <697964+dduugg@users.noreply.github.com> --- Library/Homebrew/cask/artifact/moved.rb | 6 +++- Library/Homebrew/cask/config.rb | 6 ++-- Library/Homebrew/cask/installer.rb | 16 ++++++++-- Library/Homebrew/cask/quarantine.rb | 2 ++ .../Homebrew/extend/os/cask/artifact/moved.rb | 5 ++++ Library/Homebrew/extend/os/cask/config.rb | 4 +++ Library/Homebrew/extend/os/cask/quarantine.rb | 4 +++ .../extend/os/linux/cask/artifact/moved.rb | 23 ++++++++++++++ .../Homebrew/extend/os/linux/cask/config.rb | 30 +++++++++++++++++++ .../extend/os/linux/cask/installer.rb | 2 ++ .../extend/os/linux/cask/quarantine.rb | 22 ++++++++++++++ .../extend/os/mac/cask/artifact/moved.rb | 25 ++++++++++++++++ Library/Homebrew/extend/os/mac/readall.rb | 2 +- Library/Homebrew/os/linux.rb | 12 ++++++++ Library/Homebrew/os/mac.rb | 1 + 15 files changed, 153 insertions(+), 7 deletions(-) create mode 100644 Library/Homebrew/extend/os/cask/artifact/moved.rb create mode 100644 Library/Homebrew/extend/os/cask/config.rb create mode 100644 Library/Homebrew/extend/os/cask/quarantine.rb create mode 100644 Library/Homebrew/extend/os/linux/cask/artifact/moved.rb create mode 100644 Library/Homebrew/extend/os/linux/cask/config.rb create mode 100644 Library/Homebrew/extend/os/linux/cask/quarantine.rb create mode 100644 Library/Homebrew/extend/os/mac/cask/artifact/moved.rb diff --git a/Library/Homebrew/cask/artifact/moved.rb b/Library/Homebrew/cask/artifact/moved.rb index d3c5331639b95..b80e0a6ef7538 100644 --- a/Library/Homebrew/cask/artifact/moved.rb +++ b/Library/Homebrew/cask/artifact/moved.rb @@ -180,7 +180,7 @@ def move_back(skip: false, force: false, adopt: false, command: nil, **options) def delete(target, force: false, successor: nil, command: nil, **_) ohai "Removing #{self.class.english_name} '#{target}'" - raise CaskError, "Cannot remove undeletable #{self.class.english_name}." if MacOS.undeletable?(target) + raise CaskError, "Cannot remove undeletable #{self.class.english_name}." if undeletable?(target) return unless Utils.path_occupied?(target) @@ -196,6 +196,10 @@ def delete(target, force: false, successor: nil, command: nil, **_) Utils.gain_permissions_remove(target, command:) end end + + def undeletable?(target); end end end end + +require "extend/os/cask/artifact/moved" diff --git a/Library/Homebrew/cask/config.rb b/Library/Homebrew/cask/config.rb index ae8c2539fb0aa..aa0d76dfb31dc 100644 --- a/Library/Homebrew/cask/config.rb +++ b/Library/Homebrew/cask/config.rb @@ -33,10 +33,10 @@ class Config T::Hash[Symbol, String], ) - sig { returns(T::Hash[Symbol, T.untyped]) } + sig { returns(T::Hash[Symbol, String]) } def self.defaults { - languages: LazyObject.new { MacOS.languages }, + languages: LazyObject.new { ::OS::Mac.languages }, }.merge(DEFAULT_DIRS).freeze end @@ -223,3 +223,5 @@ def to_json(*options) end end end + +require "extend/os/cask/config" diff --git a/Library/Homebrew/cask/installer.rb b/Library/Homebrew/cask/installer.rb index f826211a8e07b..e9bbdc497d93d 100644 --- a/Library/Homebrew/cask/installer.rb +++ b/Library/Homebrew/cask/installer.rb @@ -76,6 +76,7 @@ def fetch(quiet: nil, timeout: nil) satisfy_cask_and_formula_dependencies end + sig { void } def stage odebug "Cask::Installer#stage" @@ -88,6 +89,7 @@ def stage raise e end + sig { void } def install start_time = Time.now odebug "Cask::Installer#install" @@ -152,6 +154,7 @@ def check_deprecate_disable end end + sig { void } def check_conflicts return unless @cask.conflicts_with @@ -168,6 +171,7 @@ def check_conflicts end end + sig { void } def uninstall_existing_cask return unless @cask.installed? @@ -196,6 +200,7 @@ def download(quiet: nil, timeout: nil) timeout:) end + sig { void } def verify_has_sha odebug "Checking cask has checksum" return if @cask.sha256 != :no_check @@ -213,6 +218,12 @@ def primary_container end end + sig { returns(ArtifactSet) } + def artifacts + @cask.artifacts + end + + sig { params(to: Pathname).void } def extract_primary_container(to: @cask.staged_path) odebug "Extracting primary container" @@ -242,7 +253,6 @@ def extract_primary_container(to: @cask.staged_path) sig { params(predecessor: T.nilable(Cask)).void } def install_artifacts(predecessor: nil) - artifacts = @cask.artifacts already_installed_artifacts = [] odebug "Installing artifacts" @@ -301,6 +311,7 @@ def check_macos_requirements raise CaskError, @cask.depends_on.macos.message(type: :cask) end + sig { void } def check_arch_requirements return if @cask.depends_on.arch.nil? @@ -316,6 +327,7 @@ def check_arch_requirements "but you are running #{@current_arch}." end + sig { returns(T::Array[T.untyped]) } def cask_and_formula_dependencies return @cask_and_formula_dependencies if @cask_and_formula_dependencies @@ -489,8 +501,6 @@ def finalize_upgrade sig { params(clear: T::Boolean, successor: T.nilable(Cask)).void } def uninstall_artifacts(clear: false, successor: nil) - artifacts = @cask.artifacts - odebug "Uninstalling artifacts" odebug "#{::Utils.pluralize("artifact", artifacts.length, include_count: true)} defined", artifacts diff --git a/Library/Homebrew/cask/quarantine.rb b/Library/Homebrew/cask/quarantine.rb index 4a36a5128edac..ae680b0d2321a 100644 --- a/Library/Homebrew/cask/quarantine.rb +++ b/Library/Homebrew/cask/quarantine.rb @@ -266,3 +266,5 @@ def self.app_management_permissions_granted?(app:, command:) end end end + +require "extend/os/cask/quarantine" diff --git a/Library/Homebrew/extend/os/cask/artifact/moved.rb b/Library/Homebrew/extend/os/cask/artifact/moved.rb new file mode 100644 index 0000000000000..98d49e5904cbc --- /dev/null +++ b/Library/Homebrew/extend/os/cask/artifact/moved.rb @@ -0,0 +1,5 @@ +# typed: strict +# frozen_string_literal: true + +require "extend/os/mac/cask/artifact/moved" if OS.mac? +require "extend/os/linux/cask/artifact/moved" if OS.linux? diff --git a/Library/Homebrew/extend/os/cask/config.rb b/Library/Homebrew/extend/os/cask/config.rb new file mode 100644 index 0000000000000..cc7f21e1bd741 --- /dev/null +++ b/Library/Homebrew/extend/os/cask/config.rb @@ -0,0 +1,4 @@ +# typed: strict +# frozen_string_literal: true + +require "extend/os/linux/cask/config" if OS.linux? diff --git a/Library/Homebrew/extend/os/cask/quarantine.rb b/Library/Homebrew/extend/os/cask/quarantine.rb new file mode 100644 index 0000000000000..31671b65e5d35 --- /dev/null +++ b/Library/Homebrew/extend/os/cask/quarantine.rb @@ -0,0 +1,4 @@ +# typed: strict +# frozen_string_literal: true + +require "extend/os/linux/cask/quarantine" if OS.linux? diff --git a/Library/Homebrew/extend/os/linux/cask/artifact/moved.rb b/Library/Homebrew/extend/os/linux/cask/artifact/moved.rb new file mode 100644 index 0000000000000..3f6c420b474a9 --- /dev/null +++ b/Library/Homebrew/extend/os/linux/cask/artifact/moved.rb @@ -0,0 +1,23 @@ +# typed: strict +# frozen_string_literal: true + +module OS + module Linux + module Cask + module Artifact + module Moved + extend T::Helpers + + requires_ancestor { ::Cask::Artifact::Moved } + + sig { params(target: Pathname).returns(T::Boolean) } + def undeletable?(target) + !target.parent.writable? + end + end + end + end + end +end + +Cask::Artifact::Moved.prepend(OS::Linux::Cask::Config) diff --git a/Library/Homebrew/extend/os/linux/cask/config.rb b/Library/Homebrew/extend/os/linux/cask/config.rb new file mode 100644 index 0000000000000..756cc7bae142b --- /dev/null +++ b/Library/Homebrew/extend/os/linux/cask/config.rb @@ -0,0 +1,30 @@ +# typed: strict +# frozen_string_literal: true + +require "os/linux" + +module OS + module Linux + module Cask + module Config + module ClassMethods + DEFAULT_DIRS = T.let({ + vst_plugindir: "~/.vst", + vst3_plugindir: "~/.vst3", + fontdir: "#{ENV.fetch("XDG_DATA_HOME", "~/.local/share")}/fonts", + appdir: "~/.config/apps", + }.freeze, T::Hash[Symbol, String]) + + sig { returns(T::Hash[Symbol, String]) } + def defaults + { + languages: LazyObject.new { Linux.languages }, + }.merge(DEFAULT_DIRS).freeze + end + end + end + end + end +end + +Cask::Config.singleton_class.prepend(OS::Linux::Cask::Config::ClassMethods) diff --git a/Library/Homebrew/extend/os/linux/cask/installer.rb b/Library/Homebrew/extend/os/linux/cask/installer.rb index 536a08b1f5590..76ac45eb7f15b 100644 --- a/Library/Homebrew/extend/os/linux/cask/installer.rb +++ b/Library/Homebrew/extend/os/linux/cask/installer.rb @@ -13,6 +13,8 @@ module Installer sig { void } def check_stanza_os_requirements + return if artifacts.all?(::Cask::Artifact::Font) + raise ::Cask::CaskError, "macOS is required for this software." end end diff --git a/Library/Homebrew/extend/os/linux/cask/quarantine.rb b/Library/Homebrew/extend/os/linux/cask/quarantine.rb new file mode 100644 index 0000000000000..62d981ee3d94b --- /dev/null +++ b/Library/Homebrew/extend/os/linux/cask/quarantine.rb @@ -0,0 +1,22 @@ +# typed: strict +# frozen_string_literal: true + +module OS + module Linux + module Cask + module Quarantine + extend T::Helpers + + requires_ancestor { ::Cask::Quarantine } + + sig { returns(Symbol) } + def self.check_quarantine_support = :linux + + sig { returns(T::Boolean) } + def self.available? = false + end + end + end +end + +Cask::Quarantine.prepend(OS::Linux::Cask::Quarantine) diff --git a/Library/Homebrew/extend/os/mac/cask/artifact/moved.rb b/Library/Homebrew/extend/os/mac/cask/artifact/moved.rb new file mode 100644 index 0000000000000..700557e564b42 --- /dev/null +++ b/Library/Homebrew/extend/os/mac/cask/artifact/moved.rb @@ -0,0 +1,25 @@ +# typed: strict +# frozen_string_literal: true + +require "cask/macos" + +module OS + module Mac + module Cask + module Artifact + module Moved + extend T::Helpers + + requires_ancestor { ::Cask::Artifact::Moved } + + sig { params(target: Pathname).returns(T::Boolean) } + def undeletable?(target) + MacOS.undeletable?(target) + end + end + end + end + end +end + +Cask::Artifact::Moved.prepend(OS::Mac::Cask::Artifact::Moved) diff --git a/Library/Homebrew/extend/os/mac/readall.rb b/Library/Homebrew/extend/os/mac/readall.rb index 853654a24e6c9..23f71e403cce9 100644 --- a/Library/Homebrew/extend/os/mac/readall.rb +++ b/Library/Homebrew/extend/os/mac/readall.rb @@ -20,7 +20,7 @@ def valid_casks?(tap, os_name: nil, arch: ::Hardware::CPU.type) success = T.let(true, T::Boolean) tap.cask_files.each do |file| - cask = Cask::CaskLoader.load(file) + cask = ::Cask::CaskLoader.load(file) # Fine to have missing URLs for unsupported macOS macos_req = cask.depends_on.macos diff --git a/Library/Homebrew/os/linux.rb b/Library/Homebrew/os/linux.rb index e8f4832843707..4345e9a1f12e5 100644 --- a/Library/Homebrew/os/linux.rb +++ b/Library/Homebrew/os/linux.rb @@ -13,6 +13,8 @@ module Linux raise "Loaded OS::Linux on macOS!" if OS.mac? # rubocop:enable Homebrew/MoveToExtendOS + @languages = T.let([], T::Array[String]) + # Get the OS version. # # @api internal @@ -56,5 +58,15 @@ def self.wsl_version Version::NULL end end + + sig { returns(T::Array[String]) } + def self.languages + return @languages if @languages.present? + + os_langs = Utils.popen_read("localectl", "list-locales") + os_langs = os_langs.scan(/[^ \n"(),]+/).map { |item| item.split(".").first.tr("_", "-") } + + @languages = os_langs + end end end diff --git a/Library/Homebrew/os/mac.rb b/Library/Homebrew/os/mac.rb index dbb3ef6463912..c59bb0e50cd1b 100644 --- a/Library/Homebrew/os/mac.rb +++ b/Library/Homebrew/os/mac.rb @@ -69,6 +69,7 @@ def self.preferred_perl_version end end + sig { returns(T::Array[String]) } def self.languages return @languages if @languages From 32b9afd7cd825ddc3133bbd89aa085e9736bd45b Mon Sep 17 00:00:00 2001 From: Sean Molenaar Date: Sun, 19 Jan 2025 11:19:31 +0000 Subject: [PATCH 2/2] feat: add linux tests --- Library/Homebrew/os/linux.rb | 19 +++++++++++--- Library/Homebrew/test/os/linux_spec.rb | 36 ++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 Library/Homebrew/test/os/linux_spec.rb diff --git a/Library/Homebrew/os/linux.rb b/Library/Homebrew/os/linux.rb index 4345e9a1f12e5..e605ae5eb08d5 100644 --- a/Library/Homebrew/os/linux.rb +++ b/Library/Homebrew/os/linux.rb @@ -63,10 +63,23 @@ def self.wsl_version def self.languages return @languages if @languages.present? - os_langs = Utils.popen_read("localectl", "list-locales") - os_langs = os_langs.scan(/[^ \n"(),]+/).map { |item| item.split(".").first.tr("_", "-") } + locale_variables = ENV.keys.grep(/^(?:LC_\S+|LANG|LANGUAGE)\Z/).sort + ctl_ret = Utils.popen_read("localectl", "list-locales") + if ctl_ret.present? + list = ctl_ret.scan(/[^ \n"(),]+/) + elsif locale_variables.present? + keys = locale_variables.select { |var| ENV.fetch(var) } + list = keys.map { |key| ENV.fetch(key) } + else + list = ["en_US.utf8"] + end + + @languages = list.map { |item| item.split(".").first.tr("_", "-") } + end - @languages = os_langs + sig { returns(T.nilable(String)) } + def self.language + languages.first end end end diff --git a/Library/Homebrew/test/os/linux_spec.rb b/Library/Homebrew/test/os/linux_spec.rb new file mode 100644 index 0000000000000..70650c39ad543 --- /dev/null +++ b/Library/Homebrew/test/os/linux_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require "locale" +require "os/linux" + +RSpec.describe OS::Linux do + describe "::languages", :needs_linux do + it "returns a list of all languages" do + expect(described_class.languages).not_to be_empty + end + end + + describe "::language", :needs_linux do + it "returns the first item from #languages" do + expect(described_class.language).to eq(described_class.languages.first) + end + end + + describe "::'os_version'", :needs_linux do + it "returns the OS version" do + expect(described_class.os_version).not_to be_empty + end + end + + describe "::'wsl?'" do + it "returns the WSL state" do + expect(described_class.wsl?).to be(false) + end + end + + describe "::'wsl_version'", :needs_linux do + it "returns the WSL version" do + expect(described_class.wsl_version).to match(Version::NULL) + end + end +end