mirror of
https://github.com/jimeh/build-emacs-for-macos.git
synced 2026-02-19 13:06:38 +00:00
245 lines
5.5 KiB
Ruby
Executable File
245 lines
5.5 KiB
Ruby
Executable File
#!/usr/bin/env ruby
|
|
require 'json'
|
|
require 'date'
|
|
require 'optparse'
|
|
|
|
|
|
#
|
|
# Config
|
|
#
|
|
|
|
DOWNLOAD_URL = "https://github.com/mirrors/emacs/tarball/%s"
|
|
LATEST_URL = "https://api.github.com/repos/mirrors/emacs/commits?sha=%s"
|
|
|
|
ROOT_DIR = File.expand_path('..', __FILE__)
|
|
TARBALL_DIR = "#{ROOT_DIR}/tarballs"
|
|
SOURCES_DIR = "#{ROOT_DIR}/sources"
|
|
BUILDS_DIR = "#{ROOT_DIR}/builds"
|
|
|
|
|
|
#
|
|
# Main
|
|
#
|
|
|
|
def main
|
|
opts = parse_options
|
|
|
|
ref = ARGV.shift
|
|
meta = get_ref_info(ref)
|
|
|
|
if meta['sha'] && meta['date']
|
|
tarball = download_tarball(meta['sha'])
|
|
source = extract_tarball(tarball, patches(opts))
|
|
app = compile_source(source)
|
|
|
|
archive_app(app, meta['sha'], meta['date'])
|
|
else
|
|
raise "\nERROR: Failed to get commit info from GitHub API."
|
|
end
|
|
end
|
|
|
|
|
|
#
|
|
# Patches
|
|
#
|
|
|
|
def patches(opts = {})
|
|
p = []
|
|
|
|
|
|
if opts[:srgb]
|
|
p << {
|
|
:replace => [ # sRGB patch for older version of nsterm.m.
|
|
"src/nsterm.m",
|
|
"*col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];",
|
|
"*col = [NSColor colorWithDeviceRed: r green: g blue: b alpha: 1.0];"
|
|
]
|
|
}
|
|
end
|
|
|
|
if opts[:srgb_244]
|
|
p << {
|
|
:replace => [
|
|
"src/nsterm.m",
|
|
"return [NSColor colorWithCalibratedRed: red",
|
|
"return [NSColor colorWithDeviceRed: red"
|
|
]
|
|
}
|
|
end
|
|
|
|
p
|
|
end
|
|
|
|
|
|
#
|
|
# Options
|
|
#
|
|
|
|
def parse_options
|
|
options = {:srgb => false, :srgb_244 => false}
|
|
|
|
OptionParser.new do |opts|
|
|
opts.banner = "Usage: ./build-emacs-for-osx [options] [branch/tag/sha]\n" +
|
|
"\n" +
|
|
"Branch, tag, and SHA are from the mirrors/emacs Github repo,\n" +
|
|
"available here: https://github.com/mirrors/emacs\n" +
|
|
"\n"
|
|
|
|
opts.on('--srgb', "Use sRGB patch (pre Emacs 24.4).") do
|
|
options[:srgb] = true
|
|
end
|
|
|
|
opts.on('--srgb-244', "Use sRGB patch for 24.3 -> 24.4 dev builds. sRGB patch not needed in final 24.4.") do
|
|
options[:srgb] = true
|
|
end
|
|
end.parse!
|
|
|
|
options
|
|
end
|
|
|
|
|
|
#
|
|
# Core Methods
|
|
#
|
|
|
|
def download_tarball(sha)
|
|
mkdir TARBALL_DIR
|
|
|
|
url = (DOWNLOAD_URL % sha)
|
|
|
|
filename = "mirrors-emacs-#{sha[0..6]}.tgz"
|
|
target = File.join(TARBALL_DIR, filename)
|
|
|
|
if !File.exist?(target)
|
|
puts "\nDownloading tarball from GitHub. This could take a while, " +
|
|
"please be patient."
|
|
system "curl -L \"#{url}\" -o \"#{target}\""
|
|
raise "\nERROR: Download failed." unless File.exist?(target)
|
|
else
|
|
puts "\nINFO: #{filename} already exists locally, attempting to use."
|
|
end
|
|
target
|
|
end
|
|
|
|
def extract_tarball(filename, patches = [])
|
|
mkdir SOURCES_DIR
|
|
|
|
dirname = File.basename(filename).gsub(/\.\w+$/, '')
|
|
target = "#{SOURCES_DIR}/#{dirname}"
|
|
|
|
if !File.exist?(target)
|
|
puts "\nExtracting tarball..."
|
|
system "tar -xzf \"#{filename}\" -C \"#{SOURCES_DIR}\""
|
|
raise "\nERROR: Tarball extraction failed." unless File.exist?(target)
|
|
patches.each do |patch|
|
|
apply_patch(patch, target)
|
|
end
|
|
else
|
|
puts "\nINFO: #{dirname} source tree exists, attempting to use."
|
|
end
|
|
target
|
|
end
|
|
|
|
def compile_source(source)
|
|
target = "#{source}/nextstep"
|
|
|
|
if !File.exist?("#{target}/Emacs.app")
|
|
puts "\nCompiling from source. This will take a while..."
|
|
|
|
if File.exist? "#{source}/autogen/copy_autogen"
|
|
system "cd \"#{source}\" && autogen/copy_autogen"
|
|
elsif File.exist? "#{source}/autogen.sh"
|
|
system "cd \"#{source}\" && ./autogen.sh"
|
|
end
|
|
|
|
system "cd \"#{source}\" && ./configure --with-ns"
|
|
system "cd \"#{source}\" && make"
|
|
system "cd \"#{source}\" && make install"
|
|
|
|
raise "\nERROR: Build failed." unless File.exist?("#{target}/Emacs.app")
|
|
else
|
|
puts "\nINFO: Emacs.app already exists in " +
|
|
"\"#{target.gsub(ROOT_DIR + '/', '')}\", attempting to use."
|
|
end
|
|
"#{target}/Emacs.app"
|
|
end
|
|
|
|
def archive_app(app, sha, date)
|
|
mkdir BUILDS_DIR
|
|
|
|
filename = "Emacs.app-#{date}-(#{sha[0..6]}).tbz"
|
|
target = "#{BUILDS_DIR}/#{filename}"
|
|
|
|
app_base = File.basename(app)
|
|
app_dir = File.dirname(app)
|
|
|
|
if !File.exist?(target)
|
|
puts "\nCreating #{filename} archive in \"#{BUILDS_DIR}\"..."
|
|
system "cd \"#{app_dir}\" && tar -cjf \"#{target}\" \"#{app_base}\""
|
|
else
|
|
puts "\nINFO: #{filename} archive exists in " +
|
|
"#{BUILDS_DIR.gsub(ROOT_DIR + '/', '')}, skipping archving."
|
|
end
|
|
end
|
|
|
|
|
|
#
|
|
# Helper Methods
|
|
#
|
|
|
|
def mkdir(dir)
|
|
system "mkdir -p \"#{dir}\""
|
|
end
|
|
|
|
def get_ref_info(ref = 'master')
|
|
response = `curl "#{LATEST_URL % ref}" 2>/dev/null`
|
|
meta = JSON.parse(response).first
|
|
return {
|
|
'sha' => meta['sha'],
|
|
'date' => Date.parse(meta['commit']['committer']['date'])
|
|
}
|
|
end
|
|
|
|
def apply_patch(patch, target)
|
|
raise "ERROR: \"#{target}\" does not exist." unless File.exist?(target)
|
|
if patch[:url]
|
|
system "mkdir -p \"#{target}/patches\""
|
|
|
|
patch_file = "#{target}/patches/patch-{num}.diff"
|
|
num = 1
|
|
while File.exist? patch_file.gsub('{num}', num.to_s.rjust(3, '0'))
|
|
num += 1
|
|
end
|
|
patch_file.gsub!('{num}', num.to_s.rjust(3, '0'))
|
|
|
|
puts "Downloading patch: #{url}"
|
|
system "curl -L# \"#{url}\" -o \"#{patch_file}\""
|
|
|
|
puts "Applying patch..."
|
|
system "cd \"#{target}\" && patch -f -p1 -i \"#{patch_file}\""
|
|
elsif patch[:replace]
|
|
raise "ERROR: Patch replace input error" unless patch[:replace].size == 3
|
|
file, before, after = patch[:replace]
|
|
filepath = File.join(target, file)
|
|
|
|
if !File.exist?(filepath)
|
|
raise "ERROR: \"#{file}\" does not exist in #{target}"
|
|
end
|
|
|
|
f = File.open(filepath, 'rb')
|
|
s = f.read
|
|
sub = s.gsub!(before, after)
|
|
raise "ERROR: Replacement filed in #{file}" if sub.nil?
|
|
|
|
f.reopen(filepath, 'wb').write(s)
|
|
f.close
|
|
end
|
|
end
|
|
|
|
|
|
#
|
|
# Run it!
|
|
#
|
|
|
|
main
|