Skip to content

Commit 9dcac65

Browse files
committed
feat: add appimage support for linux
1 parent 0ac4836 commit 9dcac65

File tree

10 files changed

+147
-20
lines changed

10 files changed

+147
-20
lines changed

Library/Homebrew/cask/artifact.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# frozen_string_literal: true
33

44
require "cask/artifact/app"
5+
require "cask/artifact/appimage"
56
require "cask/artifact/artifact" # generic 'artifact' stanza
67
require "cask/artifact/audio_unit_plugin"
78
require "cask/artifact/binary"
@@ -53,5 +54,9 @@ module Artifact
5354
::Cask::Artifact::VstPlugin,
5455
::Cask::Artifact::Vst3Plugin,
5556
].freeze
57+
58+
LINUX_ONLY_ARTIFACTS = [
59+
::Cask::Artifact::AppImage,
60+
].freeze
5661
end
5762
end
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# typed: strict
2+
# frozen_string_literal: true
3+
4+
require "cask/artifact/symlinked"
5+
6+
module Cask
7+
module Artifact
8+
class AppImage < Symlinked
9+
sig { params(target: T.any(String, Pathname)).returns(Pathname) }
10+
def resolve_target(target)
11+
config.appimagedir/target
12+
end
13+
end
14+
end
15+
end

Library/Homebrew/cask/cask.rb

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,17 +164,67 @@ def font?
164164
end
165165

166166
sig { returns(T::Boolean) }
167-
def supports_macos? = true
167+
def supports_macos?
168+
return true if font?
169+
170+
if @dsl.on_system_blocks_exist?
171+
any_loaded = false
172+
begin
173+
OnSystem::VALID_OS_ARCH_TAGS.each do |bottle_tag|
174+
next unless bottle_tag.macos?
175+
176+
Homebrew::SimulateSystem.with_tag(bottle_tag) do
177+
refresh
178+
179+
any_loaded = true
180+
return false if artifacts.any? do |artifact|
181+
::Cask::Artifact::LINUX_ONLY_ARTIFACTS.include?(artifact.class)
182+
end
183+
end
184+
end
185+
rescue CaskInvalidError => e
186+
# Invalid cask for macOS
187+
odebug e.message
188+
ensure
189+
refresh
190+
end
191+
192+
return false unless any_loaded
193+
end
194+
195+
true
196+
end
168197

169198
sig { returns(T::Boolean) }
170199
def supports_linux?
171200
return true if font?
172201

173-
return false if artifacts.any? do |artifact|
174-
::Cask::Artifact::MACOS_ONLY_ARTIFACTS.include?(artifact.class)
202+
if @dsl.on_system_blocks_exist?
203+
any_loaded = false
204+
begin
205+
OnSystem::VALID_OS_ARCH_TAGS.each do |bottle_tag|
206+
next unless bottle_tag.linux?
207+
208+
Homebrew::SimulateSystem.with_tag(bottle_tag) do
209+
refresh
210+
211+
any_loaded = true
212+
return false if artifacts.any? do |artifact|
213+
::Cask::Artifact::MACOS_ONLY_ARTIFACTS.include?(artifact.class)
214+
end
215+
end
216+
end
217+
rescue CaskInvalidError => e
218+
# Invalid cask for Linux
219+
ensure
220+
refresh
221+
end
222+
223+
return false unless any_loaded
175224
end
176225

177-
@dsl.os.present?
226+
# Only assume Linux support if there is an explicit `on_system` stanza
227+
@dsl.on_system_blocks_exist?
178228
end
179229

180230
# The caskfile is needed during installation when there are

Library/Homebrew/cask/config.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class Config
1616
DEFAULT_DIRS = T.let(
1717
{
1818
appdir: "/Applications",
19+
appimagedir: "~/Applications",
1920
keyboard_layoutdir: "/Library/Keyboard Layouts",
2021
colorpickerdir: "~/Library/ColorPickers",
2122
prefpanedir: "~/Library/PreferencePanes",
@@ -49,6 +50,7 @@ def self.from_args(args)
4950
args = T.unsafe(args)
5051
new(explicit: {
5152
appdir: args.appdir,
53+
appimagedir: args.appimagedir,
5254
keyboard_layoutdir: args.keyboard_layoutdir,
5355
colorpickerdir: args.colorpickerdir,
5456
prefpanedir: args.prefpanedir,

Library/Homebrew/cask/dsl.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class DSL
3838
ORDINARY_ARTIFACT_CLASSES = [
3939
Artifact::Installer,
4040
Artifact::App,
41+
Artifact::AppImage,
4142
Artifact::Artifact,
4243
Artifact::AudioUnitPlugin,
4344
Artifact::Binary,

Library/Homebrew/cli/parser.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ def self.global_cask_options
6666
description: "Target location for Applications " \
6767
"(default: `#{Cask::Config::DEFAULT_DIRS[:appdir]}`).",
6868
}],
69+
[:flag, "--appimagedir=", {
70+
description: "Target location for AppImages " \
71+
"(default: `#{Cask::Config::DEFAULT_DIRS[:appimagedir]}`).",
72+
}],
6973
[:flag, "--keyboard-layoutdir=", {
7074
description: "Target location for Keyboard Layouts " \
7175
"(default: `#{Cask::Config::DEFAULT_DIRS[:keyboard_layoutdir]}`).",

Library/Homebrew/dev-cmd/generate-cask-ci-matrix.rb

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -127,33 +127,61 @@ def run
127127

128128
sig { params(cask: Cask::Cask).returns(T::Hash[T::Hash[Symbol, T.any(Symbol, String)], Float]) }
129129
def filter_runners(cask)
130-
filtered_macos_runners = RUNNERS.select do |runner, _|
131-
runner[:symbol] != :linux &&
130+
filtered_runners = if cask.supports_macos?
131+
filtered_macos_runners = MACOS_RUNNERS.select do |runner, _|
132132
cask.depends_on.macos.present? &&
133133
cask.depends_on.macos.allows?(MacOSVersion.from_symbol(T.must(runner[:symbol]).to_sym))
134-
end
134+
end
135+
136+
return MACOS_RUNNERS.dup if filtered_macos_runners.none?
135137

136-
filtered_runners = if filtered_macos_runners.any?
137138
filtered_macos_runners
138-
else
139-
RUNNERS.dup
140139
end
141140

142-
filtered_runners = filtered_runners.merge(LINUX_RUNNERS) if cask.supports_linux?
143-
144141
archs = architectures(cask:)
142+
odebug "Architectures macOS: #{archs}" if archs.any?
145143
filtered_runners.select! do |runner, _|
146144
archs.include?(runner.fetch(:arch))
147145
end
148146

147+
odebug "Filtered runners: #{filtered_runners.keys.map { |r| r[:name] }}" if filtered_runners.any?
148+
if cask.supports_linux?
149+
filtered_linux_runners = LINUX_RUNNERS.dup
150+
151+
archs = architectures(cask:, os: :linux, arch: :intel)
152+
filtered_linux_runners.select! do |runner, _|
153+
archs.include?(runner.fetch(:arch))
154+
end
155+
156+
filtered_runners.merge!(filtered_linux_runners)
157+
end
158+
159+
odebug "Architectures linux: #{archs}" if archs.any?
160+
odebug "Filtered runners: #{filtered_runners.keys.map { |r| r[:name] }}" if filtered_runners.any?
161+
149162
filtered_runners
150163
end
151164

152-
sig { params(cask: Cask::Cask).returns(T::Array[Symbol]) }
153-
def architectures(cask:)
154-
return RUNNERS.keys.map { |r| r.fetch(:arch).to_sym }.uniq.sort if cask.depends_on.arch.blank?
165+
sig { params(cask: Cask::Cask, os: Symbol, arch: Symbol).returns(T::Array[Symbol]) }
166+
def architectures(cask:, os: :macos, arch: :arm)
167+
architectures = []
168+
begin
169+
tag = Utils::Bottles::Tag.new(system: os, arch: arch)
170+
Homebrew::SimulateSystem.with_tag(tag) do
171+
cask.refresh
172+
173+
if cask.depends_on.arch.blank?
174+
architectures = RUNNERS.keys.map { |r| r.fetch(:arch).to_sym }.uniq.sort
175+
next
176+
end
177+
178+
architectures = cask.depends_on.arch.map { |arch| arch[:type] }
179+
end
180+
rescue ::Cask::CaskInvalidError
181+
# Can't read cask for this system-arch combination.
182+
end
155183

156-
cask.depends_on.arch.map { |arch| arch[:type] }.uniq.sort
184+
architectures
157185
end
158186

159187
sig {
@@ -255,7 +283,7 @@ def generate_matrix(tap, labels: [], cask_names: [], skip_install: false, new_ca
255283
native_runner_arch = arch == runner.fetch(:arch)
256284
# we don't need to run simulated archs on Linux
257285
next if runner.fetch(:symbol) == :linux && !native_runner_arch
258-
# we don't need to run simulated archs on macOS
286+
# we don't need to run simulated archs on macOS Sequoia
259287
next if runner.fetch(:symbol) == :sequoia && !native_runner_arch
260288

261289
# If it's just a single OS test then we can just use the two real arch runners.

Library/Homebrew/extend/os/cask/installer.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
# frozen_string_literal: true
33

44
require "extend/os/linux/cask/installer" if OS.linux?
5+
require "extend/os/mac/cask/installer" if OS.mac?

Library/Homebrew/extend/os/linux/cask/installer.rb

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ module Installer
1111

1212
sig { void }
1313
def check_stanza_os_requirements
14-
return unless artifacts.any? do |artifact|
15-
::Cask::Artifact::MACOS_ONLY_ARTIFACTS.include?(artifact.class)
16-
end
14+
return unless @cask.supports_linux?
1715

1816
raise ::Cask::CaskError, "macOS is required for this software."
1917
end
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# typed: strict
2+
# frozen_string_literal: true
3+
4+
module OS
5+
module Mac
6+
module Cask
7+
module Installer
8+
extend T::Helpers
9+
10+
requires_ancestor { ::Cask::Installer }
11+
12+
sig { void }
13+
def check_stanza_os_requirements
14+
return unless @cask.supports_macos?
15+
16+
raise ::Cask::CaskError, "Linux is required for this software."
17+
end
18+
end
19+
end
20+
end
21+
end
22+
23+
Cask::Installer.prepend(OS::Mac::Cask::Installer)

0 commit comments

Comments
 (0)