Skip to content

Commit b5ed388

Browse files
committed
feat(icon): add support for Tahoe icons with --tahoe-icon-uri and --tahoe-icon-name options
1 parent 607076a commit b5ed388

File tree

2 files changed

+97
-28
lines changed

2 files changed

+97
-28
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ Options:
156156
--build-name NAME Override generated build name
157157
--dist-include x,y,z List of extra files to copy from Emacs source into build folder/archive (default: COPYING)
158158
--icon-uri URI Local path or URL to a .icns file to replace the default app icon
159+
--tahoe-icon-uri URI Local path or URL to an Assets.car file for macOS 26 icons. Requires --tahoe-icon-name.
160+
--tahoe-icon-name NAME Name of the icon in Assets.car to set as CFBundleIconName
159161
--[no-]self-sign Enable/disable self-signing of Emacs.app (default: enabled)
160162
--[no-]archive Enable/disable creating *.tbz archive (default: enabled)
161163
--[no-]archive-keep-build-dir

build-emacs-for-macos

Lines changed: 95 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,14 @@ class Build
229229

230230
handle_native_lisp(app)
231231

232-
IconEmbedder.new(app, options[:icon_uri]).embed if options[:icon_uri]
232+
if options[:icon_uri] || options[:tahoe_icon_uri] || options[:tahoe_icon_name]
233+
IconEmbedder.new(
234+
app,
235+
icon_uri: options[:icon_uri],
236+
tahoe_icon_uri: options[:tahoe_icon_uri],
237+
tahoe_icon_name: options[:tahoe_icon_name]
238+
).embed
239+
end
233240
CLIHelperEmbedder.new(app).embed
234241
CSourcesEmbedder.new(app, @source_dir).embed
235242
LibEmbedder.new(
@@ -1417,53 +1424,92 @@ end
14171424
class IconEmbedder < AbstractEmbedder
14181425
include Helpers
14191426

1420-
def initialize(app, icon_uri)
1427+
def initialize(app, icon_uri: nil, tahoe_icon_uri: nil, tahoe_icon_name: nil)
14211428
super(app)
1422-
14231429
@icon_uri = icon_uri
1430+
@tahoe_icon_uri = tahoe_icon_uri
1431+
@tahoe_icon_name = tahoe_icon_name
14241432
end
14251433

14261434
def embed
1427-
return if @icon_uri.nil? || @icon_uri.strip.empty?
1435+
handle_icns if present?(@icon_uri)
1436+
handle_tahoe if present?(@tahoe_icon_uri)
1437+
ensure
1438+
cleanup_tmpdir
1439+
end
14281440

1429-
source = resolve_source(@icon_uri)
1441+
private
14301442

1431-
unless File.extname(source).downcase == '.icns'
1432-
fatal 'Icon must be a .icns file'
1433-
end
1443+
def present?(val)
1444+
!val.nil? && !val.strip.empty?
1445+
end
14341446

1447+
def handle_icns
1448+
source = resolve_source(@icon_uri, '.icns', 'icon.icns')
14351449
target = File.join(resources_dir, 'Emacs.icns')
1436-
info 'Replacing application icon...'
1450+
info 'Replacing application icon (Emacs.icns)...'
14371451
run_cmd('cp', '-pRL', source, target)
1438-
ensure
1439-
cleanup_download_tmpdir(source)
1452+
source
14401453
end
14411454

1442-
private
1455+
def handle_tahoe
1456+
fatal '--tahoe-icon-name is required with --tahoe-icon-uri' \
1457+
unless present?(@tahoe_icon_name)
14431458

1444-
def resolve_source(uri)
1445-
if valid_url?(uri)
1446-
download_icon(uri)
1447-
else
1448-
path = File.expand_path(uri)
1449-
fatal "Icon file does not exist: #{path}" unless File.exist?(path)
1450-
path
1451-
end
1459+
source = resolve_source(@tahoe_icon_uri, '.car', 'Assets.car')
1460+
target = File.join(resources_dir, 'Assets.car')
1461+
info 'Placing Tahoe Assets.car into Resources...'
1462+
run_cmd('cp', '-pRL', source, target)
1463+
1464+
set_cf_bundle_icon_name(@tahoe_icon_name)
1465+
source
1466+
end
1467+
1468+
def set_cf_bundle_icon_name(name)
1469+
info 'Setting CFBundleIconName in Info.plist...'
1470+
info_plist = File.join(app, 'Contents', 'Info.plist')
1471+
fatal "Info.plist not found: #{info_plist}" unless File.exist?(info_plist)
1472+
1473+
# Use plutil which adds/replaces the key as needed
1474+
run_cmd(
1475+
'plutil', '-replace', 'CFBundleIconName', '-string',
1476+
name, info_plist
1477+
)
1478+
end
1479+
1480+
def resolve_source(uri, expected_ext, download_name)
1481+
file_path = if valid_url?(uri)
1482+
download_file(uri, download_name)
1483+
else
1484+
local = File.expand_path(uri)
1485+
unless File.exist?(local)
1486+
fatal "File does not exist: #{local}"
1487+
end
1488+
local
1489+
end
1490+
1491+
ext = File.extname(file_path).downcase
1492+
fatal "Unexpected file type: #{ext} (expected #{expected_ext})" \
1493+
unless ext == expected_ext
1494+
1495+
file_path
14521496
end
14531497

1454-
def download_icon(url)
1455-
@download_tmpdir = Dir.mktmpdir(%w[emacs-icon .tmp])
1456-
path = File.join(@download_tmpdir, 'icon.icns')
1457-
info "Downloading icon from: #{url}"
1498+
def tmpdir
1499+
@tmpdir ||= Dir.mktmpdir(%w[emacs-assets .tmp])
1500+
end
1501+
1502+
def download_file(url, name)
1503+
path = File.join(tmpdir, name)
1504+
info "Downloading asset from: #{url}"
14581505
run_cmd('curl', '-L#', url, '-o', path)
14591506
path
14601507
end
14611508

1462-
def cleanup_download_tmpdir(source)
1463-
return unless @download_tmpdir && source
1464-
return unless source.start_with?(@download_tmpdir)
1509+
def cleanup_tmpdir
1510+
return unless @tmpdir
14651511

1466-
FileUtils.rm_rf(@download_tmpdir)
1512+
FileUtils.rm_rf(@tmpdir)
14671513
end
14681514
end
14691515

@@ -2155,6 +2201,14 @@ class CLIOptions
21552201

21562202
def parse!(args)
21572203
parser.parse!(args)
2204+
2205+
if options[:tahoe_icon_uri] &&
2206+
(
2207+
options[:tahoe_icon_name].nil? ||
2208+
options[:tahoe_icon_name].strip.empty?
2209+
)
2210+
fatal '--tahoe-icon-name is required when --tahoe-icon-uri is specified'
2211+
end
21582212
rescue OptionParser::InvalidOption => e
21592213
fatal e.message
21602214
end
@@ -2182,6 +2236,8 @@ class CLIOptions
21822236
github_auth: true,
21832237
dist_include: ['COPYING', 'configure_output.txt'],
21842238
icon_uri: nil,
2239+
tahoe_icon_uri: nil,
2240+
tahoe_icon_name: nil,
21852241
self_sign: true,
21862242
archive: true,
21872243
archive_keep: false,
@@ -2383,6 +2439,17 @@ class CLIOptions
23832439
'Local path or URL to a .icns file to replace the default app icon'
23842440
) { |v| options[:icon_uri] = v }
23852441

2442+
opts.on(
2443+
'--tahoe-icon-uri URI',
2444+
'Local path or URL to an Assets.car file for macOS 26 icons. ' \
2445+
'Requires --tahoe-icon-name.'
2446+
) { |v| options[:tahoe_icon_uri] = v }
2447+
2448+
opts.on(
2449+
'--tahoe-icon-name NAME',
2450+
'Name of the icon in Assets.car to set as CFBundleIconName'
2451+
) { |v| options[:tahoe_icon_name] = v }
2452+
23862453
opts.on(
23872454
'--[no-]self-sign',
23882455
'Enable/disable self-signing of Emacs.app (default: enabled)'

0 commit comments

Comments
 (0)