Compare commits

...

45 Commits

Author SHA1 Message Date
3d6c7fff64 chore(release): 0.6.42 2023-07-31 18:42:33 +01:00
d08d1b9b5c feat: options for log-level and github source repository
Changes:

- Adds optional --log-level flag and lots of debug output when level is
  set to "debug"
- Adds optional --github-src-repo flag to specify a custom GitHub
  repository to download source tarball from.
- Resolve all current Rubocop complaints.
2023-07-31 18:39:38 +01:00
6e32219c24 chore(deps): add webp to Brewfile 2023-07-31 18:36:22 +01:00
d2548191f1 chore(release): 0.6.41 2023-01-16 23:52:25 +00:00
8ed16b27c0 ci(builds): add python to CI dependencies 2023-01-16 23:23:43 +00:00
14f7aa13d9 chore(release): 0.6.40 2023-01-08 22:39:03 +00:00
59ebbdaa2b Merge pull request #79 from jimeh/fix-nightly-builds 2023-01-08 22:38:16 +00:00
d98c14dde5 chore(deps): remove python CI dependency
Instead use default python version install on macOS to install dmgbuild.
2023-01-08 21:21:54 +00:00
590b0ac21a chore(deps): remove curl from Brewfile
Curl is part of macOS, and the curl homebrew formula is keg-only.
Meaning there's no reason to install it for our purposes.
2023-01-08 20:39:17 +00:00
8c84ef128f chore(release): 0.6.39 2022-12-04 20:33:32 +00:00
8b447b6237 feat(version): correctly handle Emacs 30.x builds 2022-12-04 20:32:55 +00:00
c3d19694e7 feat(deprecate): posix-spawn patch is no longer supported
Nor is it needed, as it was only an issue in master for a short period
of time.
2022-12-04 20:30:20 +00:00
cff89684c6 chore(release): 0.6.38 2022-12-01 22:35:08 +00:00
48a512fbce feat(patch): add round-undecorated-frame from emacs-plus for 29.x 2022-12-01 22:30:48 +00:00
a3530c02e8 feat(patch): add support for experimental poll patch from emacs-plus for 29.x 2022-12-01 22:30:42 +00:00
138ac74ba5 chore(release): 0.6.37 2022-12-01 22:09:38 +00:00
0ba971ef61 feat(tree-sitter): support new --with-tree-sitter configure flag 2022-12-01 22:08:29 +00:00
1ae8771b2c chore(release): 0.6.36 2022-10-08 14:41:30 +01:00
1f2868d4b3 fix(native-comp): support new configure flag format
Commit e245c4f226979ccb717cccc8f82b2b0a0f96bdac on Emacs' master branch
added support for optional flags to the --with-native-compilation
configure flag.

This change to output of ./configure --help broke the native comp
detection present in our build script.

This change adds support for the new configure flag format, while also
using it to specify AOT when enabled.

It is still backwards compatible with the configure script in older
commits.

Fixes #76
2022-10-08 14:38:37 +01:00
bfa5bcf79b chore(release): 0.6.35 2022-08-10 16:48:24 +01:00
02d85f899f Merge pull request #75 from jimeh/fix-libgccjit12-compatibility
fix(native-comp): compatibility with libgccjit 12 homebrew formula
2022-08-10 16:46:45 +01:00
aeb3a75e5c chore(patch): minor simplification to libgccjit patches
By matching more targeted sets of strings, it should hopefully make
these patches more future-proof.
2022-08-10 16:31:51 +01:00
Alice Rum
e0fd2b16eb fix(native-comp): compatibility with libgccjit 12 homebrew formula
Since the latest update of `libgccjit` in brew to version 12, emacs does
not build again. Problem is that now dylib exists in multiple locations,
and `MAC_CFLAGS` environment variable is not filled correctly in
`configure.ac`. This commit fixes the issue.
2022-08-10 16:30:10 +01:00
d24ac084b7 chore(release): 0.6.34 2022-07-27 23:25:28 +01:00
159a7333de Merge pull request #73 from jimeh/fix-emacs-28
fix(emacs-28): patch configure.ac to support latest libgccjit
2022-07-27 23:23:39 +01:00
b582523642 fix(emacs-28): patch configure.ac to support latest libgccjit
When building Emacs 28.x the build script will attempt to patch
configure.ac if needed to support the latest version of libgccjit which
renamed libgccjit.so to libgccjit.dylib.

Fixes #72
2022-07-27 23:18:58 +01:00
4f1e748df2 chore(release): 0.6.33 2022-04-30 19:37:01 +01:00
d984633991 chore(deps): update gon package to 0.2.5 2022-04-30 19:35:21 +01:00
616f74d624 chore(release): 0.6.32 2022-04-30 17:46:51 +01:00
d7963b7664 chore(helper): minor tweak to emacs helper launch script 2022-04-30 17:46:06 +01:00
a20a8456ab feat(deps): add sqlite brew dependency for Emacs 29.x 2022-04-30 17:45:21 +01:00
8ad3ff4f53 feat(dbus): add flag to explicitly disable dbus support
Fixes #69
2022-04-30 17:27:41 +01:00
e31f5aaf93 fix(native-comp): support libgccjit 11.3.0
The libgccjit shared library file was renamed from libgccjit.so to
libgccjit.0.dylib in 11.3.0.

Fixes #71
2022-04-30 17:13:50 +01:00
c2fb07fdb8 chore(release): 0.6.31 2022-02-25 10:33:12 +00:00
07e0e3dacd fix: set source-directory correctly
Fixes #68
2022-02-25 10:32:03 +00:00
efddb9ef92 chore(release): 0.6.30 2022-02-08 03:07:18 +00:00
f7f4c0433a Merge pull request #66 from jimeh/add-homebrew-site-lisp-path 2022-02-08 03:05:31 +00:00
cbd8cb27b6 fix(site-lisp): add Homebrew's site-lisp directory to locallisppath
This should allow mu4e to be loaded from the mu homebrew package, among
other homebrew packages that provides emacs site-lisp files.

Ref: https://github.com/jimeh/emacs-builds/issues/19
2022-02-08 00:44:09 +00:00
656b96510a chore(release): 0.6.29 2022-02-07 21:07:10 +00:00
084776db6b feat(cask): add support for pretest builds 2022-02-07 21:04:59 +00:00
1e6d6cc6cf chore(release): 0.6.28 2022-01-15 23:19:07 +00:00
68ef4c066c feat(build): add dbus dependency to enable support in Emacs builds
Dbus support is automatically enabled if available on the system.
2022-01-15 23:17:25 +00:00
d476fd33ec chore(release): 0.6.27 2021-12-05 12:57:03 +00:00
baa5930467 Merge pull request #63 from jimeh/add-pretest-build-support
feat(plan): add support for pretest and release candidate builds
2021-12-05 12:54:33 +00:00
743b10c751 feat(plan): add support for pretest and release candidate builds
Add support for naming release and builds accordingly when given a git
ref for a pretest (90 or above patch number) or release
candidate ("-rcX" at the end of the tag).
2021-12-05 12:52:08 +00:00
16 changed files with 1031 additions and 155 deletions

View File

@@ -1,9 +1,30 @@
AllCops: AllCops:
TargetRubyVersion: 2.3 TargetRubyVersion: 2.4
NewCops: enable NewCops: enable
Layout/LineLength: Layout/LineLength:
Max: 80 Max: 80
Style/AccessorGrouping:
Enabled: false
Style/Documentation: Style/Documentation:
Enabled: false Enabled: false
Metrics/AbcSize:
Enabled: false
Metrics/BlockLength:
Enabled: false
Metrics/ClassLength:
Enabled: false
Metrics/CyclomaticComplexity:
Enabled: false
Metrics/MethodLength:
Enabled: false
Metrics/PerceivedComplexity:
Enabled: false

View File

@@ -2,7 +2,7 @@
brew 'autoconf' brew 'autoconf'
brew 'coreutils' brew 'coreutils'
brew 'curl' brew 'dbus'
brew 'expat' brew 'expat'
brew 'gcc' brew 'gcc'
brew 'gmp' brew 'gmp'
@@ -22,5 +22,8 @@ brew 'make'
brew 'ncurses' brew 'ncurses'
brew 'nettle' brew 'nettle'
brew 'pkg-config' brew 'pkg-config'
brew 'sqlite'
brew 'texinfo' brew 'texinfo'
brew 'tree-sitter'
brew 'webp'
brew 'zlib' brew 'zlib'

View File

@@ -2,6 +2,111 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [0.6.42](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.41...v0.6.42) (2023-07-31)
### Features
* options for log-level and github source repository ([d08d1b9](https://github.com/jimeh/build-emacs-for-macos/commit/d08d1b9b5c4001302564dc8915884c465802f3b5))
### [0.6.41](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.40...v0.6.41) (2023-01-16)
### [0.6.40](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.39...v0.6.40) (2023-01-08)
### [0.6.39](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.38...v0.6.39) (2022-12-04)
### Features
* **deprecate:** posix-spawn patch is no longer supported ([c3d1969](https://github.com/jimeh/build-emacs-for-macos/commit/c3d19694e7e4d33d462c9917683c2d63f69002f5))
* **version:** correctly handle Emacs 30.x builds ([8b447b6](https://github.com/jimeh/build-emacs-for-macos/commit/8b447b6237fbbd94c4e72af8ee79969c7cfc9363))
### [0.6.38](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.37...v0.6.38) (2022-12-01)
### Features
* **patch:** add round-undecorated-frame from emacs-plus for 29.x ([48a512f](https://github.com/jimeh/build-emacs-for-macos/commit/48a512fbce79759caa987e2880585bd0bc937977))
* **patch:** add support for experimental poll patch from emacs-plus for 29.x ([a3530c0](https://github.com/jimeh/build-emacs-for-macos/commit/a3530c02e8260106f87d464e5cb398dcb2819460))
### [0.6.37](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.36...v0.6.37) (2022-12-01)
### Features
* **tree-sitter:** support new --with-tree-sitter configure flag ([0ba971e](https://github.com/jimeh/build-emacs-for-macos/commit/0ba971ef61a195c91e87aa381d5d3b044461b4f6))
### [0.6.36](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.35...v0.6.36) (2022-10-08)
### Bug Fixes
* **native-comp:** support new configure flag format ([1f2868d](https://github.com/jimeh/build-emacs-for-macos/commit/1f2868d4b3784e906665e9f3b6b9bba8fd72292f)), closes [#76](https://github.com/jimeh/build-emacs-for-macos/issues/76)
### [0.6.35](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.34...v0.6.35) (2022-08-10)
### Bug Fixes
* **native-comp:** compatibility with libgccjit 12 homebrew formula ([e0fd2b1](https://github.com/jimeh/build-emacs-for-macos/commit/e0fd2b16eb91ac5a98ed4ec31f4773ab22cbd470))
### [0.6.34](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.33...v0.6.34) (2022-07-27)
### Bug Fixes
* **emacs-28:** patch configure.ac to support latest libgccjit ([b582523](https://github.com/jimeh/build-emacs-for-macos/commit/b582523642ad4c5298f5a7890edd9b48c0433684)), closes [#72](https://github.com/jimeh/build-emacs-for-macos/issues/72)
### [0.6.33](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.32...v0.6.33) (2022-04-30)
### [0.6.32](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.31...v0.6.32) (2022-04-30)
### Features
* **dbus:** add flag to explicitly disable dbus support ([8ad3ff4](https://github.com/jimeh/build-emacs-for-macos/commit/8ad3ff4f53505408aa097527177032a1fd6008e0)), closes [#69](https://github.com/jimeh/build-emacs-for-macos/issues/69)
* **deps:** add sqlite brew dependency for Emacs 29.x ([a20a845](https://github.com/jimeh/build-emacs-for-macos/commit/a20a8456ab1e8de6357d5d121b9565ba65a6dd71))
### Bug Fixes
* **native-comp:** support libgccjit 11.3.0 ([e31f5aa](https://github.com/jimeh/build-emacs-for-macos/commit/e31f5aaf9355b674c2a86b8eda35f6513f344b72)), closes [#71](https://github.com/jimeh/build-emacs-for-macos/issues/71)
### [0.6.31](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.30...v0.6.31) (2022-02-25)
### Bug Fixes
* set source-directory correctly ([07e0e3d](https://github.com/jimeh/build-emacs-for-macos/commit/07e0e3dacddfbdb7a59aceaa2dc9cdf503ac2bcc)), closes [#68](https://github.com/jimeh/build-emacs-for-macos/issues/68)
### [0.6.30](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.29...v0.6.30) (2022-02-08)
### Bug Fixes
* **site-lisp:** add Homebrew's site-lisp directory to locallisppath ([cbd8cb2](https://github.com/jimeh/build-emacs-for-macos/commit/cbd8cb27b6ceff2e128c38cd1cc8f8380b9b4bfb))
### [0.6.29](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.28...v0.6.29) (2022-02-07)
### Features
* **cask:** add support for pretest builds ([084776d](https://github.com/jimeh/build-emacs-for-macos/commit/084776db6b7e61958088d7b2a2588e9889e60c21))
### [0.6.28](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.27...v0.6.28) (2022-01-15)
### Features
* **build:** add dbus dependency to enable support in Emacs builds ([68ef4c0](https://github.com/jimeh/build-emacs-for-macos/commit/68ef4c066c3fd1a7337198e8f773866088b4f481))
### [0.6.27](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.26...v0.6.27) (2021-12-05)
### Features
* **plan:** add support for pretest and release candidate builds ([743b10c](https://github.com/jimeh/build-emacs-for-macos/commit/743b10c751e146ec7569f39a475c20a0489955f4))
### [0.6.26](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.25...v0.6.26) (2021-11-27) ### [0.6.26](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.25...v0.6.26) (2021-11-27)

View File

@@ -7,6 +7,7 @@ require 'erb'
require 'etc' require 'etc'
require 'fileutils' require 'fileutils'
require 'json' require 'json'
require 'logger'
require 'net/http' require 'net/http'
require 'optparse' require 'optparse'
require 'pathname' require 'pathname'
@@ -18,33 +19,68 @@ require 'yaml'
class Error < StandardError; end class Error < StandardError; end
module Output module Output
def info(msg, newline: true) class << self
out "INFO: #{msg}", newline: newline LEVELS = {
end debug: Logger::DEBUG,
error: Logger::ERROR,
fatal: Logger::FATAL,
info: Logger::INFO,
unknown: Logger::UNKNOWN,
warn: Logger::WARN
}.freeze
def out(msg, newline: true) def log_level
if newline LEVELS.key(logger.level)
warn "==> #{msg}" end
else
$stderr.print "==> #{msg}" def log_level=(level)
logger.level = LEVELS.fetch(level&.to_sym)
end
def logger
@logger ||= Logger.new($stderr).tap do |logger|
logger.level = Logger::INFO
logger.formatter = proc do |severity, _datetime, _progname, msg|
"==> #{severity.upcase}: #{msg}"
end
end
end end
end end
def err(msg = nil) %i[debug info warn error].each do |severity|
define_method(severity) do |msg, newline: true|
logger.send(severity, format_msg(msg, newline: newline))
end
end
def fatal(msg = nil)
raise Error, msg raise Error, msg
end end
private
def logger
Output.logger
end
def format_msg(msg, newline: true)
msg = msg.join("\n") if msg.is_a?(Array)
msg = msg.strip
msg = "#{msg}\n" if newline
msg
end
end end
module System module System
include Output include Output
def run_cmd(*args) def run_cmd(*args)
out("CMD: #{args.join(' ')}") debug "executing: #{args.join(' ')}"
cmd(*args) cmd(*args)
end end
def cmd(*args) def cmd(*args)
system(*args) || err("Exit code: #{$CHILD_STATUS.exitstatus}") system(*args) || fatal("Exit code: #{$CHILD_STATUS.exitstatus}")
end end
end end
@@ -61,7 +97,7 @@ end
class OSVersion class OSVersion
def initialize def initialize
@version = `sw_vers -productVersion`.match( @version = `sw_vers -productVersion`.match(
/(?<major>\d+)(?:\.(?<minor>\d+)(:?\.(?<patch>\d+))?)?/ /(?<major>\d+)(?:\.(?<minor>\d+)(?:\.(?<patch>\d+))?)?/
) )
end end
@@ -86,8 +122,7 @@ class Build
include Output include Output
include System include System
EMACS_MIRROR_REPO = 'emacs-mirror/emacs' DEFAULT_GITHUB_REPO = 'emacs-mirror/emacs'
DOWNLOAD_URL = 'https://github.com/emacs-mirror/emacs/tarball/%s'
attr_reader :root_dir attr_reader :root_dir
attr_reader :source_dir attr_reader :source_dir
@@ -106,7 +141,7 @@ class Build
load_plan(options[:plan]) if options[:plan] load_plan(options[:plan]) if options[:plan]
unless meta[:sha] && meta[:date] unless meta[:sha] && meta[:date]
err 'Failed to get commit info from GitHub.' fatal 'Failed to get commit info from GitHub.'
end end
tarball = download_tarball(meta[:sha]) tarball = download_tarball(meta[:sha])
@@ -122,7 +157,9 @@ class Build
CLIHelperEmbedder.new(app).embed CLIHelperEmbedder.new(app).embed
CSourcesEmbedder.new(app, @source_dir).embed CSourcesEmbedder.new(app, @source_dir).embed
LibEmbedder.new(app, brew_dir, extra_libs, options[:relink_eln]).embed LibEmbedder.new(
app, brew_dir, extra_libs, relink_eln_files: options[:relink_eln]
).embed
GccLibEmbedder.new(app, gcc_info).embed if options[:native_comp] GccLibEmbedder.new(app, gcc_info).embed if options[:native_comp]
archive_build(build_dir) if options[:archive] archive_build(build_dir) if options[:archive]
@@ -131,6 +168,7 @@ class Build
private private
def load_plan(filename) def load_plan(filename)
debug "Loading plan from: #{filename}"
plan = YAML.safe_load(File.read(filename), [:Time]) plan = YAML.safe_load(File.read(filename), [:Time])
@ref = plan.dig('source', 'ref') @ref = plan.dig('source', 'ref')
@@ -163,6 +201,10 @@ class Build
@output_dir ||= (options[:output] || File.join(root_dir, 'builds')) @output_dir ||= (options[:output] || File.join(root_dir, 'builds'))
end end
def github_src_repo
@github_src_repo ||= options[:github_src_repo] || DEFAULT_GITHUB_REPO
end
def brew_dir def brew_dir
@brew_dir ||= `brew --prefix`.chomp @brew_dir ||= `brew --prefix`.chomp
end end
@@ -189,8 +231,8 @@ class Build
def download_tarball(sha) def download_tarball(sha)
FileUtils.mkdir_p(tarballs_dir) FileUtils.mkdir_p(tarballs_dir)
url = (DOWNLOAD_URL % sha) url = "https://github.com/#{github_src_repo}/tarball/#{sha}"
filename = "emacs-mirror-emacs-#{sha[0..6]}.tgz" filename = "#{github_src_repo.gsub(/[^a-zA-Z0-9-]+/, '-')}-#{sha[0..6]}.tgz"
target = File.join(tarballs_dir, filename) target = File.join(tarballs_dir, filename)
if File.exist?(target) if File.exist?(target)
@@ -212,7 +254,7 @@ class Build
log_args[1..-1] log_args[1..-1]
end end
out "CMD: #{log_args.join(' ')}" debug "executing: #{log_args.join(' ')}"
cmd(*args) cmd(*args)
target target
@@ -231,7 +273,7 @@ class Build
info 'Extracting tarball...' info 'Extracting tarball...'
result = run_cmd('tar', '-xzf', filename, '-C', sources_dir) result = run_cmd('tar', '-xzf', filename, '-C', sources_dir)
err 'Tarball extraction failed.' unless result fatal 'Tarball extraction failed.' unless result
patches.each { |patch| apply_patch(patch, target) } patches.each { |patch| apply_patch(patch, target) }
@@ -250,26 +292,53 @@ class Build
@supports_xwidgets ||= !!configure_help.match(/\s+--with-xwidgets\s+/) @supports_xwidgets ||= !!configure_help.match(/\s+--with-xwidgets\s+/)
end end
def supports_tree_sitter?
@supports_tree_sitter ||= !!configure_help.match(
/\s+--with-tree-sitter(\s|=).+/
)
end
def supports_native_comp? def supports_native_comp?
@supports_native_comp ||= !native_comp_configure_flag.nil? @supports_native_comp ||= !native_comp_configure_flag.nil?
end end
def native_comp_configure_match
@native_comp_configure_match ||= configure_help.match(
/\s+?(--with-native(?:comp|-compilation))(.+)?\s+?/
)
end
def native_comp_configure_flag def native_comp_configure_flag
@native_comp_configure_flag ||= configure_help.match( return @native_comp_configure_flag if @native_comp_configure_flag
/\s+(--with-native(?:comp|-compilation))\s+/
)&.[](1) return unless native_comp_configure_match&.[](1)
@native_comp_configure_flag = [
native_comp_configure_match[1],
native_comp_configure_flag_arg
].compact.join('=')
end
def native_comp_configure_flag_arg
return @native_comp_configure_flag_arg if @native_comp_configure_flag_arg
return if native_comp_configure_match&.[](2) != '[=TYPE]'
@native_comp_configure_flag_arg = \
(options[:native_full_aot] ? 'aot' : 'yes')
end end
def detect_native_comp def detect_native_comp
info 'Detecting native-comp support: ', newline: false info 'Detecting native-comp support...'
options[:native_comp] = supports_native_comp? options[:native_comp] = supports_native_comp?
puts options[:native_comp] ? 'Supported' : 'Not supported' info 'Native-comp is: ' \
"#{options[:native_comp] ? 'Supported' : 'Not supported'}"
end end
def verify_native_comp def verify_native_comp
return if supports_native_comp? return if supports_native_comp?
err 'This emacs source tree does not support native-comp' fatal 'This emacs source tree does not support native-comp'
end end
def autogen def autogen
@@ -288,7 +357,7 @@ class Build
if File.exist?(emacs_app) if File.exist?(emacs_app)
info 'Emacs.app already exists in ' \ info 'Emacs.app already exists in ' \
"\"#{target.gsub(root_dir + '/', '')}\", attempting to use." "\"#{target.gsub("#{root_dir}/", '')}\", attempting to use."
return emacs_app return emacs_app
end end
@@ -305,7 +374,7 @@ class Build
"-I#{File.join(gcc_info.libgccjit_root_dir, 'include')}", "-I#{File.join(gcc_info.libgccjit_root_dir, 'include')}",
'-O2', '-O2',
(options[:native_march] ? '-march=native' : nil), (options[:native_march] ? '-march=native' : nil),
ENV['CFLAGS'] ENV.fetch('CFLAGS', nil)
].compact.join(' ') ].compact.join(' ')
ENV['LDFLAGS'] = [ ENV['LDFLAGS'] = [
@@ -316,14 +385,14 @@ class Build
"-I#{File.join(gcc_info.libgccjit_root_dir, 'include')}", "-I#{File.join(gcc_info.libgccjit_root_dir, 'include')}",
# Ensure library re-linking and code signing will work after building. # Ensure library re-linking and code signing will work after building.
'-Wl,-headerpad_max_install_names', '-Wl,-headerpad_max_install_names',
ENV['LDFLAGS'] ENV.fetch('LDFLAGS', nil)
].compact.join(' ') ].compact.join(' ')
ENV['LIBRARY_PATH'] = [ ENV['LIBRARY_PATH'] = [
gcc_info.lib_dir, gcc_info.lib_dir,
gcc_info.darwin_lib_dir, gcc_info.darwin_lib_dir,
gcc_info.libgccjit_lib_dir, gcc_info.libgccjit_lib_dir,
ENV['LIBRARY_PATH'] ENV.fetch('LIBRARY_PATH', nil)
].compact.join(':') ].compact.join(':')
end end
@@ -337,7 +406,7 @@ class Build
File.join(brew_dir, 'opt/zlib/lib/pkgconfig'), File.join(brew_dir, 'opt/zlib/lib/pkgconfig'),
File.join(brew_dir, 'Homebrew/Library/Homebrew/os/mac/pkgconfig', File.join(brew_dir, 'Homebrew/Library/Homebrew/os/mac/pkgconfig',
OS.version.to_s), OS.version.to_s),
ENV['PKG_CONFIG_PATH'] ENV.fetch('PKG_CONFIG_PATH', nil)
].compact.join(':') ].compact.join(':')
ENV['PATH'] = [ ENV['PATH'] = [
@@ -346,11 +415,11 @@ class Build
File.join(brew_dir, 'opt/gnu-sed/libexec/gnubin'), File.join(brew_dir, 'opt/gnu-sed/libexec/gnubin'),
File.join(brew_dir, 'bin'), File.join(brew_dir, 'bin'),
File.join(brew_dir, 'opt/texinfo/bin'), File.join(brew_dir, 'opt/texinfo/bin'),
ENV['PATH'] ENV.fetch('PATH', nil)
].compact.join(':') ].compact.join(':')
ENV['LIBRARY_PATH'] = [ ENV['LIBRARY_PATH'] = [
ENV['LIBRARY_PATH'], ENV.fetch('LIBRARY_PATH', nil),
'/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib' '/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib'
].compact.join(':') ].compact.join(':')
@@ -359,15 +428,20 @@ class Build
'--with-modules', '--with-modules',
'--enable-locallisppath=' \ '--enable-locallisppath=' \
'/Library/Application Support/Emacs/${version}/site-lisp:' \ '/Library/Application Support/Emacs/${version}/site-lisp:' \
'/Library/Application Support/Emacs/site-lisp' '/Library/Application Support/Emacs/site-lisp:' \
'/usr/local/share/emacs/site-lisp'
] ]
if options[:xwidgets] && supports_xwidgets? if options[:xwidgets] && supports_xwidgets?
configure_flags << '--with-xwidgets' configure_flags << '--with-xwidgets'
end end
if options[:tree_sitter] && supports_tree_sitter?
configure_flags << '--with-tree-sitter'
end
configure_flags << native_comp_configure_flag if options[:native_comp] configure_flags << native_comp_configure_flag if options[:native_comp]
configure_flags << '--without-rsvg' if options[:rsvg] == false configure_flags << '--without-rsvg' if options[:rsvg] == false
configure_flags << '--without-dbus' if options[:dbus] == false
run_cmd './configure', *configure_flags run_cmd './configure', *configure_flags.compact
# Disable aligned_alloc on Mojave and below. See issue: # Disable aligned_alloc on Mojave and below. See issue:
# https://github.com/daviderestivo/homebrew-emacs-head/issues/15 # https://github.com/daviderestivo/homebrew-emacs-head/issues/15
@@ -384,8 +458,12 @@ class Build
make_flags << "BYTE_COMPILE_EXTRA_FLAGS=--eval '(setq comp-speed 2)'" make_flags << "BYTE_COMPILE_EXTRA_FLAGS=--eval '(setq comp-speed 2)'"
if options[:native_full_aot] if options[:native_full_aot]
info 'Using NATIVE_FULL_AOT=1' info 'Using native compile full AOT'
make_flags << 'NATIVE_FULL_AOT=1' # We do not need to supply the full AOT make arg if
# --with-native-compilation=aot configure flag is supported.
unless native_comp_configure_flag_arg
make_flags << 'NATIVE_FULL_AOT=1'
end
ENV.delete('NATIVE_FAST_BOOT') ENV.delete('NATIVE_FAST_BOOT')
else else
ENV.delete('NATIVE_FULL_AOT') ENV.delete('NATIVE_FULL_AOT')
@@ -393,11 +471,11 @@ class Build
end end
end end
run_cmd 'make', *make_flags run_cmd 'make', *make_flags.compact
run_cmd 'make', 'install' run_cmd 'make', 'install'
end end
err 'Build failed.' unless File.exist?(emacs_app) fatal 'Build failed.' unless File.exist?(emacs_app)
emacs_app emacs_app
end end
@@ -407,8 +485,8 @@ class Build
target_dir = File.join(output_dir, build_name) target_dir = File.join(output_dir, build_name)
if File.exist?(target_dir) if File.exist?(target_dir)
err "Output directory #{target_dir} already exists, " \ fatal "Output directory #{target_dir} already exists, " \
'please delete it and try again' 'please delete it and try again'
end end
info "Copying \"#{app_name}\" to: #{target_dir}" info "Copying \"#{app_name}\" to: #{target_dir}"
@@ -486,7 +564,8 @@ class Build
'MacOS/lib/emacs/**/native-lisp'].first 'MacOS/lib/emacs/**/native-lisp'].first
if source.nil? if source.nil?
err 'Failed to find native-lisp cache directory for symlink creation.' fatal 'Failed to find native-lisp cache directory for ' \
'symlink creation.'
end end
end end
@@ -502,7 +581,7 @@ class Build
contents_dir = File.join(app, 'Contents') contents_dir = File.join(app, 'Contents')
FileUtils.cd(contents_dir) do FileUtils.cd(contents_dir) do
filename = Dir['MacOS/Emacs.pdmp', 'MacOS/libexec/Emacs.pdmp'].first filename = Dir['MacOS/Emacs.pdmp', 'MacOS/libexec/Emacs.pdmp'].first
err "no Emacs.pdmp file found in #{app}" unless filename fatal "no Emacs.pdmp file found in #{app}" unless filename
info 'patching Emacs.pdmp to point at new native-lisp paths' info 'patching Emacs.pdmp to point at new native-lisp paths'
content = File.read(filename, mode: 'rb').gsub( content = File.read(filename, mode: 'rb').gsub(
@@ -514,7 +593,7 @@ class Build
"../native-lisp/#{sanitized_eln_version}/" "../native-lisp/#{sanitized_eln_version}/"
) )
File.open(filename, 'w') { |f| f.write(content) } File.write(filename, content)
end end
end end
@@ -546,7 +625,10 @@ class Build
build = File.basename(build_dir) build = File.basename(build_dir)
parent_dir = File.dirname(build_dir) parent_dir = File.dirname(build_dir)
if !File.exist?(archive_filename) if File.exist?(archive_filename)
info "#{filename} archive exists in " \
"#{target_dir}, skipping archving."
else
info "Creating #{filename} archive in \"#{target_dir}\"..." info "Creating #{filename} archive in \"#{target_dir}\"..."
FileUtils.cd(parent_dir) do FileUtils.cd(parent_dir) do
cmd('tar', '-cjf', archive_filename, build) cmd('tar', '-cjf', archive_filename, build)
@@ -556,9 +638,6 @@ class Build
FileUtils.rm_rf(build_dir) FileUtils.rm_rf(build_dir)
end end
end end
else
info "#{filename} archive exists in " \
"#{target_dir}, skipping archving."
end end
end end
@@ -574,7 +653,7 @@ class Build
.gsub('#define HAVE_ALLOCA_H 1', .gsub('#define HAVE_ALLOCA_H 1',
'#undef HAVE_ALLOCA_H') '#undef HAVE_ALLOCA_H')
File.open(filename, 'w') { |f| f.write(content) } File.write(filename, content)
end end
def meta def meta
@@ -583,9 +662,9 @@ class Build
ref_sha = options[:git_sha] || ref ref_sha = options[:git_sha] || ref
info "Fetching info for git ref: #{ref_sha}" info "Fetching info for git ref: #{ref_sha}"
commit_json = github_api_get( commit_json = github_api_get(
"/repos/#{EMACS_MIRROR_REPO}/commits/#{ref_sha}" "/repos/#{github_src_repo}/commits/#{ref_sha}"
) )
err "Failed to get commit info about: #{ref_sha}" if commit_json.nil? fatal "Failed to get commit info about: #{ref_sha}" if commit_json.nil?
commit = JSON.parse(commit_json) commit = JSON.parse(commit_json)
meta = { meta = {
@@ -615,31 +694,32 @@ class Build
end end
def effective_version def effective_version
@effective_version ||= begin @effective_version ||= case ref
case ref when /^emacs-26.*/
when /^emacs-26.*/ 'emacs-26'
'emacs-26' when /^emacs-27.*/
when /^emacs-27.*/ 'emacs-27'
'emacs-27' when /^emacs-28.*/
when /^emacs-28.*/ 'emacs-28'
'emacs-28' when /^emacs-29.*/
else 'emacs-29'
'emacs-29' else
end 'emacs-30'
end end
end end
def patches(opts = {}) def patches(opts = {})
p = [] p = []
if %w[emacs-26 emacs-27 emacs-28 emacs-29].include?(effective_version) if %w[emacs-26 emacs-27 emacs-28 emacs-29 emacs-30]
.include?(effective_version)
p << { p << {
url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \ url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \
"patches/#{effective_version}/fix-window-role.patch" "patches/#{effective_version}/fix-window-role.patch"
} }
end end
if %w[emacs-27 emacs-28 emacs-29].include?(effective_version) if %w[emacs-27 emacs-28 emacs-29 emacs-30].include?(effective_version)
p << { p << {
url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \ url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \
"patches/#{effective_version}/system-appearance.patch" "patches/#{effective_version}/system-appearance.patch"
@@ -660,15 +740,41 @@ class Build
end end
end end
if %w[emacs-28 emacs-29].include?(effective_version) if %w[emacs-29 emacs-30].include?(effective_version)
if options[:posix_spawn] p << {
url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \
"patches/#{effective_version}/round-undecorated-frame.patch"
}
if options[:poll]
p << { p << {
url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \ url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \
"patches/#{effective_version}/posix-spawn.patch" "patches/#{effective_version}/poll.patch"
} }
end end
end end
if effective_version == 'emacs-28'
p << {
replace: [
'configure.ac',
'grep libgccjit.so\$',
'grep -E \'libgccjit\.(so|dylib)$\''
],
allow_failure: true
}
end
if %w[emacs-28 emacs-29].include?(effective_version)
p << {
replace: [
'configure.ac',
'grep -E \'libgccjit\.(so|dylib)$\'',
'grep -E \'libgccjit\.(so|dylib)$\' | tail -1'
],
allow_failure: true
}
end
if effective_version == 'emacs-27' if effective_version == 'emacs-27'
p << { p << {
url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \ url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \
@@ -687,7 +793,7 @@ class Build
end end
def apply_patch(patch, target) def apply_patch(patch, target)
err "\"#{target}\" does not exist." unless File.exist?(target) fatal "\"#{target}\" does not exist." unless File.exist?(target)
if patch[:file] if patch[:file]
info 'Applying patch...' info 'Applying patch...'
@@ -715,20 +821,37 @@ class Build
end end
elsif patch[:replace] elsif patch[:replace]
err 'Patch replace input error' unless patch[:replace].size == 3 fatal 'Patch replace input error' unless patch[:replace].size == 3
file, before, after = patch[:replace] file, before, after = patch[:replace]
info "Applying patch to #{file}..."
filepath = File.join(target, file) filepath = File.join(target, file)
err "\"#{file}\" does not exist in #{target}" unless File.exist?(filepath) unless File.exist?(filepath)
if patch[:allow_failure]
info "File #{filepath} does not exist, skipping patch."
return
end
fatal "\"#{file}\" does not exist in #{target}"
end
f = File.open(filepath, 'rb') f = File.open(filepath, 'rb')
s = f.read s = f.read
sub = s.gsub!(before, after) sub = s.gsub!(before, after)
err "Replacement filed in #{file}" if sub.nil?
if sub.nil?
if patch[:allow_failure]
info 'Patch did not apply, skipping.'
return
end
fatal "Replacement failed in #{file}"
end
f.reopen(filepath, 'wb').write(s) f.reopen(filepath, 'wb').write(s)
f.close f.close
info "#{file} patched."
end end
end end
@@ -764,11 +887,15 @@ class AbstractEmbedder
attr_reader :app attr_reader :app
def initialize(app) def initialize(app)
err "#{app} does not exist" unless File.exist?(app) fatal "#{app} does not exist" unless File.exist?(app)
@app = app @app = app
end end
def relative_path(path)
Pathname.new(path).relative_path_from(Pathname.new(app)).to_s
end
def invocation_dir def invocation_dir
@invocation_dir ||= File.join(app, 'Contents', 'MacOS') @invocation_dir ||= File.join(app, 'Contents', 'MacOS')
end end
@@ -811,7 +938,8 @@ end
class CSourcesEmbedder < AbstractEmbedder class CSourcesEmbedder < AbstractEmbedder
PATH_PATCH = <<~ELISP PATH_PATCH = <<~ELISP
;; Allow Emacs to find bundled C sources. ;; Allow Emacs to find bundled C sources.
(setq source-directory (expand-file-name "..")) (setq source-directory
(expand-file-name ".." (file-name-directory load-file-name)))
ELISP ELISP
attr_reader :source_dir attr_reader :source_dir
@@ -823,12 +951,16 @@ class CSourcesEmbedder < AbstractEmbedder
end end
def embed def embed
info 'Embedding C source files into Emacs.app for documentation purposes' info 'Bundling C source files into Emacs.app for documentation purposes...'
src_dir = File.join(source_dir, 'src') src_dir = File.join(source_dir, 'src')
target_dir = File.join(resources_dir, 'src')
debug "Copying *.c and *.h files from '#{src_dir}' " \
"to: #{relative_path(target_dir)}"
Dir[File.join(src_dir, '**', '*.{c,h}')].each do |f| Dir[File.join(src_dir, '**', '*.{c,h}')].each do |f|
rel = f[src_dir.size + 1..-1] rel = f[src_dir.size + 1..-1]
target = File.join(resources_dir, 'src', rel) target = File.join(target_dir, rel)
FileUtils.mkdir_p(File.dirname(target)) FileUtils.mkdir_p(File.dirname(target))
cmd('cp', '-pRL', f, target) cmd('cp', '-pRL', f, target)
end end
@@ -836,6 +968,8 @@ class CSourcesEmbedder < AbstractEmbedder
return if File.exist?(site_start_el_file) && return if File.exist?(site_start_el_file) &&
File.read(site_start_el_file).include?(PATH_PATCH) File.read(site_start_el_file).include?(PATH_PATCH)
debug "Patching '#{relative_path(site_start_el_file)}' to allow Emacs to " \
'find bundled C sources'
File.open(site_start_el_file, 'a') do |f| File.open(site_start_el_file, 'a') do |f|
f.puts("\n#{PATH_PATCH}") f.puts("\n#{PATH_PATCH}")
end end
@@ -853,7 +987,7 @@ class LibEmbedder < AbstractEmbedder
attr_reader :extra_libs attr_reader :extra_libs
attr_reader :relink_eln_files attr_reader :relink_eln_files
def initialize(app, lib_source, extra_libs = [], relink_eln_files = true) def initialize(app, lib_source, extra_libs = [], relink_eln_files: true)
super(app) super(app)
@lib_source = lib_source @lib_source = lib_source
@@ -862,7 +996,7 @@ class LibEmbedder < AbstractEmbedder
end end
def embed def embed
info 'Embedding libraries into Emacs.app' info 'Bundling shared libraries into Emacs.app...'
binary = "#{bin}-bin" if File.exist?("#{bin}-bin") binary = "#{bin}-bin" if File.exist?("#{bin}-bin")
binary ||= bin binary ||= bin
@@ -878,7 +1012,7 @@ class LibEmbedder < AbstractEmbedder
copy_extra_libs(extra_libs, binary) if extra_libs.any? copy_extra_libs(extra_libs, binary) if extra_libs.any?
if relink_eln_files && eln_files.any? if relink_eln_files && eln_files.any?
info "Embedding libraries for #{eln_files.size} *.eln files " \ info "Bundling shared libraries for #{eln_files.size} *.eln files " \
'within Emacs.app' 'within Emacs.app'
eln_files.each { |f| copy_libs(f) } eln_files.each { |f| copy_libs(f) }
@@ -899,49 +1033,76 @@ class LibEmbedder < AbstractEmbedder
return if rpaths.include?(rpath) return if rpaths.include?(rpath)
while_writable(exe) do while_writable(exe) do
debug "Setting rpath for '#{relative_path(exe)}' to: #{rpath}"
cmd('install_name_tool', '-add_rpath', rpath, exe) cmd('install_name_tool', '-add_rpath', rpath, exe)
end end
end end
def copy_libs(exe) def copy_libs(exe)
exe_file = File.basename(exe) exe_filename = File.basename(exe)
copied_libs = []
debug "Bundling shared libraries for: #{relative_path(exe)}"
`otool -L "#{exe}"`.split("\n")[1..-1].each do |line| `otool -L "#{exe}"`.split("\n")[1..-1].each do |line|
# Parse otool -L output
match = line.match(%r{^\s+(.+/(lib[^/ ]+))\s}) match = line.match(%r{^\s+(.+/(lib[^/ ]+))\s})
next unless match && match[1].start_with?(lib_source) next unless match
lib_filepath = match[1]
lib_filename = File.basename(lib_filepath)
# Only bundle libraries from lib_source.
next unless lib_filepath.start_with?(lib_source)
unless File.exist?(lib_filepath)
warn "-- Shared library '#{lib_filepath}' does not exist, skipping"
next
end
copied = false
while_writable(exe) do while_writable(exe) do
if match[2] == exe_file if lib_filename == exe_filename
cmd('install_name_tool', '-id', id_name = File.join('@rpath', lib_filename)
File.join('@rpath', match[2].to_s), exe) debug "-- Setting install name to: #{id_name}"
cmd('install_name_tool', '-id', id_name, exe)
else else
cmd('install_name_tool', '-change', match[1], debug "-- Bundling shared library: #{lib_filepath}"
File.join('@rpath', match[2].to_s), exe) lib_target = File.join(lib_dir, lib_filename)
unless File.exist?(lib_target)
debug '-- -- Copying to: ' \
"#{relative_path(File.join(lib_dir, lib_filename))}"
FileUtils.mkdir_p(lib_dir)
cmd('cp', '-pRL', lib_filepath, lib_target)
copied_libs << lib_target
copied = true
end
change_target = File.join('@rpath', lib_filename)
debug "-- -- Relinking to: #{change_target}"
cmd('install_name_tool', '-change', lib_filepath, change_target, exe)
end end
end end
next if match[2] == exe_file || File.exist?(File.join(lib_dir, match[2])) next if lib_filename == exe_filename || !copied
FileUtils.mkdir_p(lib_dir)
cmd('cp', '-pRL', match[1], lib_dir)
copy_libs(File.join(lib_dir, match[2].to_s))
end end
copied_libs.each { |lib| copy_libs(lib) }
end end
def copy_extra_libs(extra_libs, exe) def copy_extra_libs(extra_libs, _exe)
extra_libs.each do |lib| extra_libs.each do |lib|
debug "Bundling extra shared library: #{lib}"
lib_file = File.basename(lib) lib_file = File.basename(lib)
target = "#{lib_dir}/#{lib_file}" target = "#{lib_dir}/#{lib_file}"
unless File.exist?(target) unless File.exist?(target)
FileUtils.mkdir_p(lib_dir) FileUtils.mkdir_p(lib_dir)
debug "-- Copying to: #{lib_file}"
cmd('cp', '-pRL', lib, lib_dir) cmd('cp', '-pRL', lib, lib_dir)
end end
while_writable(target) do
cmd('install_name_tool', '-id',
File.join('@rpath', lib_file), target)
end
copy_libs(target) copy_libs(target)
end end
end end
@@ -969,10 +1130,10 @@ class GccLibEmbedder < AbstractEmbedder
return return
end end
info 'Embedding libgccjit into Emacs.app' info 'Bundling libgccjit into Emacs.app'
if gcc_info.lib_dir.empty? if gcc_info.lib_dir.empty?
err "No suitable GCC lib dir found in #{gcc_info.root_dir}" fatal "No suitable GCC lib dir found in #{gcc_info.root_dir}"
end end
FileUtils.mkdir_p(File.dirname(target_dir)) FileUtils.mkdir_p(File.dirname(target_dir))
@@ -987,6 +1148,7 @@ class GccLibEmbedder < AbstractEmbedder
return if File.exist?(site_start_el_file) && return if File.exist?(site_start_el_file) &&
File.read(site_start_el_file).include?(env_setup) File.read(site_start_el_file).include?(env_setup)
debug 'Setting up site-start.el for self-contained native-comp Emacs.app'
File.open(site_start_el_file, 'a') do |f| File.open(site_start_el_file, 'a') do |f|
f.puts("\n#{env_setup}") f.puts("\n#{env_setup}")
end end
@@ -1124,7 +1286,8 @@ class GccInfo
def libgccjit_lib_dir def libgccjit_lib_dir
@libgccjit_lib_dir ||= Dir[ @libgccjit_lib_dir ||= Dir[
File.join(libgccjit_root_dir, 'lib/gcc/*/libgccjit.so*') File.join(libgccjit_root_dir, 'lib/gcc/*/libgccjit*.dylib'),
File.join(libgccjit_root_dir, 'lib/gcc/*/libgccjit.so*'),
] ]
.map { |path| File.dirname(path) } .map { |path| File.dirname(path) }
.select { |path| File.basename(path).match(/^\d+$/) } .select { |path| File.basename(path).match(/^\d+$/) }
@@ -1132,18 +1295,18 @@ class GccInfo
end end
def verify_libgccjit def verify_libgccjit
err 'gcc not installed' unless Dir.exist?(root_dir) fatal 'gcc not installed' unless Dir.exist?(root_dir)
err 'libgccjit not installed' unless Dir.exist?(libgccjit_root_dir) fatal 'libgccjit not installed' unless Dir.exist?(libgccjit_root_dir)
if libgccjit_lib_dir&.empty? if libgccjit_lib_dir.empty?
err "Detected libgccjit (#{libgccjit_root_dir}) does not have any " \ fatal "Detected libgccjit (#{libgccjit_root_dir}) does not have any " \
'libgccjit.so* files. Please try reinstalling libgccjit: ' \ 'libgccjit.so* files. Please try reinstalling libgccjit: ' \
'brew reinstall libgccjit' 'brew reinstall libgccjit'
end end
return if major_version == libgccjit_major_version return if major_version == libgccjit_major_version
err <<~TEXT fatal <<~TEXT
Detected GCC and libgccjit library paths do not belong to the same major Detected GCC and libgccjit library paths do not belong to the same major
version of GCC. Detected paths: version of GCC. Detected paths:
- #{lib_dir} - #{lib_dir}
@@ -1151,7 +1314,7 @@ class GccInfo
TEXT TEXT
end end
def get_binding def get_binding # rubocop:disable Naming/AccessorMethodName
binding binding
end end
@@ -1174,11 +1337,15 @@ if __FILE__ == $PROGRAM_NAME
native_march: false, native_march: false,
parallel: Etc.nprocessors, parallel: Etc.nprocessors,
rsvg: true, rsvg: true,
dbus: true,
xwidgets: true, xwidgets: true,
tree_sitter: true,
github_src_repo: nil,
github_auth: true, github_auth: true,
dist_include: ['COPYING'], dist_include: ['COPYING'],
archive: true, archive: true,
archive_keep: false archive_keep: false,
log_level: 'info'
} }
begin begin
@@ -1210,6 +1377,12 @@ if __FILE__ == $PROGRAM_NAME
cli_options[:xwidgets] = v cli_options[:xwidgets] = v
end end
opts.on('--[no-]tree-sitter',
'Enable/disable tree-sitter if supported' \
'(default: enabled)') do |v|
cli_options[:tree_sitter] = v
end
opts.on('--[no-]native-comp', opts.on('--[no-]native-comp',
'Enable/disable native-comp ' \ 'Enable/disable native-comp ' \
'(default: enabled if supported)') do |v| '(default: enabled if supported)') do |v|
@@ -1240,12 +1413,17 @@ if __FILE__ == $PROGRAM_NAME
cli_options[:rsvg] = v cli_options[:rsvg] = v
end end
opts.on('--[no-]dbus',
'Enable/disable dbus support (default: enabled)') do |v|
cli_options[:dbus] = v
end
opts.on('--no-titlebar', 'Apply no-titlebar patch (default: disabled)') do opts.on('--no-titlebar', 'Apply no-titlebar patch (default: disabled)') do
cli_options[:no_titlebar] = true cli_options[:no_titlebar] = true
end end
opts.on('--posix-spawn', 'Apply posix-spawn patch (default: disabled)') do opts.on('--posix-spawn', 'Apply posix-spawn patch (deprecated)') do
cli_options[:posix_spawn] = true warn '==> WARN: posix-spawn patch is deprecated as has no effect.'
end end
opts.on('--no-frame-refocus', opts.on('--no-frame-refocus',
@@ -1253,6 +1431,19 @@ if __FILE__ == $PROGRAM_NAME
cli_options[:no_frame_refocus] = true cli_options[:no_frame_refocus] = true
end end
opts.on('--[no-]poll',
'Enable/disable experimental use of poll() instead of select() ' \
'to support > 1024 file descriptors ' \
'(default: disabled)') do |v|
cli_options[:poll] = v
end
opts.on('--github-src-repo REPO',
'Specify a GitHub repo to download source tarballs from ' \
'(default: emacs-mirror/emacs)') do |v|
cli_options[:github_src_repo] = v
end
opts.on('--[no-]github-auth', opts.on('--[no-]github-auth',
'Make authenticated GitHub API requests if GITHUB_TOKEN ' \ 'Make authenticated GitHub API requests if GITHUB_TOKEN ' \
'environment variable is set.' \ 'environment variable is set.' \
@@ -1293,6 +1484,11 @@ if __FILE__ == $PROGRAM_NAME
cli_options[:archive_keep] = v cli_options[:archive_keep] = v
end end
opts.on('--log-level LEVEL',
'Build script log level (default: info)') do |v|
cli_options[:log_level] = v
end
opts.on( opts.on(
'--plan FILE', '--plan FILE',
'Follow given plan file, instead of using given git ref/sha' 'Follow given plan file, instead of using given git ref/sha'
@@ -1301,6 +1497,7 @@ if __FILE__ == $PROGRAM_NAME
end end
end.parse! end.parse!
Output.log_level = cli_options[:log_level]
work_dir = cli_options.delete(:work_dir) work_dir = cli_options.delete(:work_dir)
Build.new(work_dir, ARGV.shift, cli_options).build Build.new(work_dir, ARGV.shift, cli_options).build
rescue Error => e rescue Error => e

2
go.mod
View File

@@ -16,7 +16,7 @@ require (
github.com/hexops/gotextdiff v1.0.3 github.com/hexops/gotextdiff v1.0.3
github.com/jimeh/undent v1.1.0 github.com/jimeh/undent v1.1.0
github.com/mattn/go-isatty v0.0.13 // indirect github.com/mattn/go-isatty v0.0.13 // indirect
github.com/mitchellh/gon v0.2.3 github.com/mitchellh/gon v0.2.5
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
github.com/urfave/cli/v2 v2.3.0 github.com/urfave/cli/v2 v2.3.0

4
go.sum
View File

@@ -160,8 +160,8 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/gon v0.2.3 h1:fObN7hD14VacGG++t27GzTW6opP0lwI7TsgTPL55wBo= github.com/mitchellh/gon v0.2.5 h1:mVWtqTzV03W0avJqmqjk9M0qls3TDUXfc9ETJaPIOWY=
github.com/mitchellh/gon v0.2.3/go.mod h1:Ua18ZhqjZHg8VyqZo8kNHAY331ntV6nNJ9mT3s2mIo8= github.com/mitchellh/gon v0.2.5/go.mod h1:Ua18ZhqjZHg8VyqZo8kNHAY331ntV6nNJ9mT3s2mIo8=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
resolve_link() { resolve_link() {
"$(type -p greadlink readlink | head -1)" "$1" "$(command -v greadlink || command -v readlink)" "$1"
} }
abs_dirname() { abs_dirname() {

View File

@@ -393,9 +393,7 @@ func (s *Updater) renderCask(
filename := asset.GetName() filename := asset.GetName()
s.logger.Debug("processing asset", "filename", filename) s.logger.Debug("processing asset", "filename", filename)
if strings.HasSuffix(filename, ".sha256") { filename = strings.TrimSuffix(filename, ".sha256")
filename = strings.TrimSuffix(filename, ".sha256")
}
if _, ok := info.Assets[filename]; !ok { if _, ok := info.Assets[filename]; !ok {
info.Assets[filename] = &ReleaseAsset{ info.Assets[filename] = &ReleaseAsset{

View File

@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"io" "io"
"regexp" "regexp"
"strconv"
"strings" "strings"
"github.com/hashicorp/go-hclog" "github.com/hashicorp/go-hclog"
@@ -13,10 +14,13 @@ import (
"github.com/jimeh/build-emacs-for-macos/pkg/osinfo" "github.com/jimeh/build-emacs-for-macos/pkg/osinfo"
"github.com/jimeh/build-emacs-for-macos/pkg/release" "github.com/jimeh/build-emacs-for-macos/pkg/release"
"github.com/jimeh/build-emacs-for-macos/pkg/repository" "github.com/jimeh/build-emacs-for-macos/pkg/repository"
"github.com/jimeh/build-emacs-for-macos/pkg/sanitize"
"github.com/jimeh/build-emacs-for-macos/pkg/source" "github.com/jimeh/build-emacs-for-macos/pkg/source"
) )
var nonAlphaNum = regexp.MustCompile(`[^\w_-]+`) var gitTagMatcher = regexp.MustCompile(
`^emacs(-.*)?-((\d+\.\d+)(?:\.(\d+))?(-rc\d+)?(.+)?)$`,
)
type TestBuildType string type TestBuildType string
@@ -37,7 +41,7 @@ type Options struct {
Output io.Writer Output io.Writer
} }
func Create(ctx context.Context, opts *Options) (*Plan, error) { func Create(ctx context.Context, opts *Options) (*Plan, error) { //nolint:funlen
logger := hclog.FromContext(ctx).Named("plan") logger := hclog.FromContext(ctx).Named("plan")
repo, err := repository.NewGitHub(opts.EmacsRepo) repo, err := repository.NewGitHub(opts.EmacsRepo)
@@ -66,19 +70,36 @@ func Create(ctx context.Context, opts *Options) (*Plan, error) {
return nil, err return nil, err
} }
version := fmt.Sprintf( absoluteVersion := fmt.Sprintf(
"%s.%s.%s", "%s.%s.%s",
commitInfo.DateString(), commitInfo.DateString(),
commitInfo.ShortSHA(), commitInfo.ShortSHA(),
sanitizeString(opts.Ref), sanitize.String(opts.Ref),
) )
releaseName := fmt.Sprintf("Emacs.%s", version) version, channel, err := parseGitRef(opts.Ref)
if err != nil {
return nil, err
}
var releaseName string
switch channel {
case release.Stable, release.RC:
releaseName = "Emacs-" + version
case release.Pretest:
version += "-pretest"
absoluteVersion += "-pretest"
releaseName = "Emacs-" + version
default:
version = absoluteVersion
releaseName = "Emacs." + version
}
buildName := fmt.Sprintf( buildName := fmt.Sprintf(
"Emacs.%s.%s.%s", "Emacs.%s.%s.%s",
version, absoluteVersion,
sanitizeString(osInfo.Name+"-"+osInfo.DistinctVersion()), sanitize.String(osInfo.Name+"-"+osInfo.DistinctVersion()),
sanitizeString(osInfo.Arch), sanitize.String(osInfo.Arch),
) )
diskImage := buildName + ".dmg" diskImage := buildName + ".dmg"
@@ -97,7 +118,8 @@ func Create(ctx context.Context, opts *Options) (*Plan, error) {
OS: osInfo, OS: osInfo,
Release: &Release{ Release: &Release{
Name: releaseName, Name: releaseName,
Prerelease: true, Prerelease: channel != release.Stable,
Channel: channel,
}, },
Output: &Output{ Output: &Output{
Directory: opts.OutputDir, Directory: opts.OutputDir,
@@ -105,28 +127,18 @@ func Create(ctx context.Context, opts *Options) (*Plan, error) {
}, },
} }
// If given git ref is a stable release tag (emacs-23.2b, emacs-27.2, etc.)
// we modify release properties accordingly.
if v, err := release.GitRefToStableVersion(opts.Ref); err == nil {
plan.Release.Prerelease = false
plan.Release.Name, err = release.VersionToName(v)
if err != nil {
return nil, err
}
}
if opts.TestBuild != "" { if opts.TestBuild != "" {
testName := sanitizeString(opts.TestBuild) testName := sanitize.String(opts.TestBuild)
plan.Build.Name += ".test." + testName plan.Build.Name += ".test." + testName
plan.Release.Title = "Test Builds" plan.Release.Title = "Test Builds (" + testName + ")"
plan.Release.Name = "test-builds" plan.Release.Name = "test-builds"
plan.Release.Prerelease = true plan.Release.Prerelease = false
plan.Release.Draft = false plan.Release.Draft = true
if opts.TestBuildType == Draft { if opts.TestBuildType == Prerelease {
plan.Release.Prerelease = false plan.Release.Prerelease = true
plan.Release.Draft = true plan.Release.Draft = false
} }
index := strings.LastIndex(diskImage, ".") index := strings.LastIndex(diskImage, ".")
@@ -137,6 +149,35 @@ func Create(ctx context.Context, opts *Options) (*Plan, error) {
return plan, nil return plan, nil
} }
func sanitizeString(s string) string { func parseGitRef(ref string) (string, release.Channel, error) {
return nonAlphaNum.ReplaceAllString(s, "-") m := gitTagMatcher.FindStringSubmatch(ref)
if len(m) == 0 {
return "", release.Nightly, nil
}
if strings.Contains(m[1], "pretest") {
return m[2], release.Pretest, nil
}
if m[4] != "" {
n, err := strconv.Atoi(m[4])
if err != nil {
return "", "", err
}
if n >= 90 {
return m[2], release.Pretest, nil
}
}
if strings.HasPrefix(m[5], "-rc") {
return m[2], release.RC, nil
}
if m[2] == m[3] {
return m[2], release.Stable, nil
}
return "", "", nil
} }

421
pkg/plan/create_test.go Normal file
View File

@@ -0,0 +1,421 @@
package plan
import (
"testing"
"github.com/jimeh/build-emacs-for-macos/pkg/release"
"github.com/stretchr/testify/assert"
)
func Test_parseGitRef(t *testing.T) {
t.Parallel()
type args struct {
ref string
}
type want struct {
version string
channel release.Channel
err string
}
tests := []struct {
name string
args args
want want
}{
{
name: "master",
args: args{ref: "master"},
want: want{version: "", channel: release.Nightly, err: ""},
},
{
name: "emacs-28",
args: args{ref: "emacs-28"},
want: want{version: "", channel: release.Nightly, err: ""},
},
{
name: "emacs-27",
args: args{ref: "emacs-27"},
want: want{version: "", channel: release.Nightly, err: ""},
},
{
name: "emacs-26",
args: args{ref: "emacs-26"},
want: want{version: "", channel: release.Nightly, err: ""},
},
{
name: "emacs-24",
args: args{ref: "emacs-24"},
want: want{version: "", channel: release.Nightly, err: ""},
},
{
name: "feature/native-comp",
args: args{ref: "feature/native-comp"},
want: want{version: "", channel: release.Nightly, err: ""},
},
{
name: "feature/pgtk",
args: args{ref: "feature/pgtk"},
want: want{version: "", channel: release.Nightly, err: ""},
},
{
name: "emacs-19.34",
args: args{ref: "emacs-19.34"},
want: want{version: "19.34", channel: release.Stable, err: ""},
},
{
name: "emacs-20.4",
args: args{ref: "emacs-20.4"},
want: want{version: "20.4", channel: release.Stable, err: ""},
},
{
name: "emacs-22.3",
args: args{ref: "emacs-22.3"},
want: want{version: "22.3", channel: release.Stable, err: ""},
},
{
name: "emacs-23.4",
args: args{ref: "emacs-23.4"},
want: want{version: "23.4", channel: release.Stable, err: ""},
},
{
name: "emacs-24.0.97",
args: args{ref: "emacs-24.0.97"},
want: want{version: "24.0.97", channel: release.Pretest, err: ""},
},
{
name: "emacs-24.2",
args: args{ref: "emacs-24.2"},
want: want{version: "24.2", channel: release.Stable, err: ""},
},
{
name: "emacs-24.2.90",
args: args{ref: "emacs-24.2.90"},
want: want{version: "24.2.90", channel: release.Pretest, err: ""},
},
{
name: "emacs-24.2.93",
args: args{ref: "emacs-24.2.93"},
want: want{version: "24.2.93", channel: release.Pretest, err: ""},
},
{
name: "emacs-24.3",
args: args{ref: "emacs-24.3"},
want: want{version: "24.3", channel: release.Stable, err: ""},
},
{
name: "emacs-24.3-rc1",
args: args{ref: "emacs-24.3-rc1"},
want: want{version: "24.3-rc1", channel: release.RC, err: ""},
},
{
name: "emacs-24.3.90",
args: args{ref: "emacs-24.3.90"},
want: want{version: "24.3.90", channel: release.Pretest, err: ""},
},
{
name: "emacs-24.3.94",
args: args{ref: "emacs-24.3.94"},
want: want{version: "24.3.94", channel: release.Pretest, err: ""},
},
{
name: "emacs-24.4",
args: args{ref: "emacs-24.4"},
want: want{version: "24.4", channel: release.Stable, err: ""},
},
{
name: "emacs-24.4-rc1",
args: args{ref: "emacs-24.4-rc1"},
want: want{version: "24.4-rc1", channel: release.RC, err: ""},
},
{
name: "emacs-24.4.90",
args: args{ref: "emacs-24.4.90"},
want: want{version: "24.4.90", channel: release.Pretest, err: ""},
},
{
name: "emacs-24.4.91",
args: args{ref: "emacs-24.4.91"},
want: want{version: "24.4.91", channel: release.Pretest, err: ""},
},
{
name: "emacs-24.5",
args: args{ref: "emacs-24.5"},
want: want{version: "24.5", channel: release.Stable, err: ""},
},
{
name: "emacs-24.5-rc1",
args: args{ref: "emacs-24.5-rc1"},
want: want{version: "24.5-rc1", channel: release.RC, err: ""},
},
{
name: "emacs-24.5-rc3",
args: args{ref: "emacs-24.5-rc3"},
want: want{version: "24.5-rc3", channel: release.RC, err: ""},
},
{
name: "emacs-24.5-rc3-fixed",
args: args{ref: "emacs-24.5-rc3-fixed"},
want: want{version: "24.5-rc3-fixed", channel: release.RC, err: ""},
},
{
name: "emacs-25.0.90",
args: args{ref: "emacs-25.0.90"},
want: want{version: "25.0.90", channel: release.Pretest, err: ""},
},
{
name: "emacs-25.0.95",
args: args{ref: "emacs-25.0.95"},
want: want{version: "25.0.95", channel: release.Pretest, err: ""},
},
{
name: "emacs-25.1",
args: args{ref: "emacs-25.1"},
want: want{version: "25.1", channel: release.Stable, err: ""},
},
{
name: "emacs-25.1-rc1",
args: args{ref: "emacs-25.1-rc1"},
want: want{version: "25.1-rc1", channel: release.RC, err: ""},
},
{
name: "emacs-25.1-rc2",
args: args{ref: "emacs-25.1-rc2"},
want: want{version: "25.1-rc2", channel: release.RC, err: ""},
},
{
name: "emacs-25.1.90",
args: args{ref: "emacs-25.1.90"},
want: want{version: "25.1.90", channel: release.Pretest, err: ""},
},
{
name: "emacs-25.1.91",
args: args{ref: "emacs-25.1.91"},
want: want{version: "25.1.91", channel: release.Pretest, err: ""},
},
{
name: "emacs-25.2",
args: args{ref: "emacs-25.2"},
want: want{version: "25.2", channel: release.Stable, err: ""},
},
{
name: "emacs-25.2-rc1",
args: args{ref: "emacs-25.2-rc1"},
want: want{version: "25.2-rc1", channel: release.RC, err: ""},
},
{
name: "emacs-25.2-rc2",
args: args{ref: "emacs-25.2-rc2"},
want: want{version: "25.2-rc2", channel: release.RC, err: ""},
},
{
name: "emacs-26.0.90",
args: args{ref: "emacs-26.0.90"},
want: want{version: "26.0.90", channel: release.Pretest, err: ""},
},
{
name: "emacs-26.0.91",
args: args{ref: "emacs-26.0.91"},
want: want{version: "26.0.91", channel: release.Pretest, err: ""},
},
{
name: "emacs-26.1",
args: args{ref: "emacs-26.1"},
want: want{version: "26.1", channel: release.Stable, err: ""},
},
{
name: "emacs-26.1-rc1",
args: args{ref: "emacs-26.1-rc1"},
want: want{version: "26.1-rc1", channel: release.RC, err: ""},
},
{
name: "emacs-26.1.90",
args: args{ref: "emacs-26.1.90"},
want: want{version: "26.1.90", channel: release.Pretest, err: ""},
},
{
name: "emacs-26.1.92",
args: args{ref: "emacs-26.1.92"},
want: want{version: "26.1.92", channel: release.Pretest, err: ""},
},
{
name: "emacs-26.2",
args: args{ref: "emacs-26.2"},
want: want{version: "26.2", channel: release.Stable, err: ""},
},
{
name: "emacs-26.2.90",
args: args{ref: "emacs-26.2.90"},
want: want{version: "26.2.90", channel: release.Pretest, err: ""},
},
{
name: "emacs-26.3",
args: args{ref: "emacs-26.3"},
want: want{version: "26.3", channel: release.Stable, err: ""},
},
{
name: "emacs-26.3-rc1",
args: args{ref: "emacs-26.3-rc1"},
want: want{version: "26.3-rc1", channel: release.RC, err: ""},
},
{
name: "emacs-27.0.90",
args: args{ref: "emacs-27.0.90"},
want: want{version: "27.0.90", channel: release.Pretest, err: ""},
},
{
name: "emacs-27.0.91",
args: args{ref: "emacs-27.0.91"},
want: want{version: "27.0.91", channel: release.Pretest, err: ""},
},
{
name: "emacs-27.1",
args: args{ref: "emacs-27.1"},
want: want{version: "27.1", channel: release.Stable, err: ""},
},
{
name: "emacs-27.1-rc1",
args: args{ref: "emacs-27.1-rc1"},
want: want{version: "27.1-rc1", channel: release.RC, err: ""},
},
{
name: "emacs-27.1-rc2",
args: args{ref: "emacs-27.1-rc2"},
want: want{version: "27.1-rc2", channel: release.RC, err: ""},
},
{
name: "emacs-27.1.90",
args: args{ref: "emacs-27.1.90"},
want: want{version: "27.1.90", channel: release.Pretest, err: ""},
},
{
name: "emacs-27.1.91",
args: args{ref: "emacs-27.1.91"},
want: want{version: "27.1.91", channel: release.Pretest, err: ""},
},
{
name: "emacs-27.2",
args: args{ref: "emacs-27.2"},
want: want{version: "27.2", channel: release.Stable, err: ""},
},
{
name: "emacs-27.2-rc1",
args: args{ref: "emacs-27.2-rc1"},
want: want{version: "27.2-rc1", channel: release.RC, err: ""},
},
{
name: "emacs-27.2-rc2",
args: args{ref: "emacs-27.2-rc2"},
want: want{version: "27.2-rc2", channel: release.RC, err: ""},
},
{
name: "emacs-28.0.90",
args: args{ref: "emacs-28.0.90"},
want: want{version: "28.0.90", channel: release.Pretest, err: ""},
},
{
name: "emacs-pretest-21.0.100",
args: args{ref: "emacs-pretest-21.0.100"},
want: want{version: "21.0.100", channel: release.Pretest, err: ""},
},
{
name: "emacs-pretest-21.0.106",
args: args{ref: "emacs-pretest-21.0.106"},
want: want{version: "21.0.106", channel: release.Pretest, err: ""},
},
{
name: "emacs-pretest-21.0.90",
args: args{ref: "emacs-pretest-21.0.90"},
want: want{version: "21.0.90", channel: release.Pretest, err: ""},
},
{
name: "emacs-pretest-21.0.99",
args: args{ref: "emacs-pretest-21.0.99"},
want: want{version: "21.0.99", channel: release.Pretest, err: ""},
},
{
name: "emacs-pretest-22.0.90",
args: args{ref: "emacs-pretest-22.0.90"},
want: want{version: "22.0.90", channel: release.Pretest, err: ""},
},
{
name: "emacs-pretest-22.0.99",
args: args{ref: "emacs-pretest-22.0.99"},
want: want{version: "22.0.99", channel: release.Pretest, err: ""},
},
{
name: "emacs-pretest-22.0.990",
args: args{ref: "emacs-pretest-22.0.990"},
want: want{version: "22.0.990", channel: release.Pretest, err: ""},
},
{
name: "emacs-pretest-22.1.90",
args: args{ref: "emacs-pretest-22.1.90"},
want: want{version: "22.1.90", channel: release.Pretest, err: ""},
},
{
name: "emacs-pretest-22.2.90",
args: args{ref: "emacs-pretest-22.2.90"},
want: want{version: "22.2.90", channel: release.Pretest, err: ""},
},
{
name: "emacs-pretest-23.0.90",
args: args{ref: "emacs-pretest-23.0.90"},
want: want{version: "23.0.90", channel: release.Pretest, err: ""},
},
{
name: "emacs-pretest-23.1.90",
args: args{ref: "emacs-pretest-23.1.90"},
want: want{version: "23.1.90", channel: release.Pretest, err: ""},
},
{
name: "emacs-pretest-23.2.90",
args: args{ref: "emacs-pretest-23.2.90"},
want: want{version: "23.2.90", channel: release.Pretest, err: ""},
},
{
name: "emacs-pretest-23.2.91",
args: args{ref: "emacs-pretest-23.2.91"},
want: want{version: "23.2.91", channel: release.Pretest, err: ""},
},
{
name: "emacs-pretest-23.2.93",
args: args{ref: "emacs-pretest-23.2.93"},
want: want{version: "23.2.93", channel: release.Pretest, err: ""},
},
{
name: "emacs-pretest-23.2.93.1",
args: args{ref: "emacs-pretest-23.2.93.1"},
want: want{version: "23.2.93.1", channel: release.Pretest, err: ""},
},
{
name: "emacs-pretest-23.3.90",
args: args{ref: "emacs-pretest-23.3.90"},
want: want{version: "23.3.90", channel: release.Pretest, err: ""},
},
{
name: "emacs-pretest-24.0.05",
args: args{ref: "emacs-pretest-24.0.05"},
want: want{version: "24.0.05", channel: release.Pretest, err: ""},
},
{
name: "emacs-pretest-24.0.90",
args: args{ref: "emacs-pretest-24.0.90"},
want: want{version: "24.0.90", channel: release.Pretest, err: ""},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, gotChannel, err := parseGitRef(tt.args.ref)
assert.Equal(t, tt.want.version, got)
assert.Equal(t, tt.want.channel, gotChannel)
if tt.want.err == "" {
assert.NoError(t, err)
} else {
assert.EqualError(t, err, tt.want.err)
}
})
}
}

View File

@@ -7,6 +7,7 @@ import (
"os" "os"
"github.com/jimeh/build-emacs-for-macos/pkg/osinfo" "github.com/jimeh/build-emacs-for-macos/pkg/osinfo"
"github.com/jimeh/build-emacs-for-macos/pkg/release"
"github.com/jimeh/build-emacs-for-macos/pkg/source" "github.com/jimeh/build-emacs-for-macos/pkg/source"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -78,10 +79,11 @@ type Build struct {
} }
type Release struct { type Release struct {
Name string `yaml:"name" json:"name"` Name string `yaml:"name" json:"name"`
Title string `yaml:"title,omitempty" json:"title,omitempty"` Title string `yaml:"title,omitempty" json:"title,omitempty"`
Draft bool `yaml:"draft,omitempty" json:"draft,omitempty"` Draft bool `yaml:"draft,omitempty" json:"draft,omitempty"`
Prerelease bool `yaml:"prerelease,omitempty" json:"prerelease,omitempty"` Prerelease bool `yaml:"prerelease,omitempty" json:"prerelease,omitempty"`
Channel release.Channel `yaml:"channel,omitempty" json:"channel,omitempty"`
} }
type Output struct { type Output struct {

11
pkg/release/channel.go Normal file
View File

@@ -0,0 +1,11 @@
package release
type Channel string
// Release channels
const (
Stable Channel = "stable"
RC Channel = "release-candidate"
Pretest Channel = "pretest"
Nightly Channel = "nightly"
)

View File

@@ -4,6 +4,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"regexp" "regexp"
"strings"
) )
// Errors // Errors
@@ -18,7 +19,7 @@ var (
var ( var (
stableVersion = regexp.MustCompile(`^\d+\.\d+(?:[a-z]+)?$`) stableVersion = regexp.MustCompile(`^\d+\.\d+(?:[a-z]+)?$`)
stableGetRef = regexp.MustCompile(`^emacs-(\d+\.\d+(?:[a-z]+)?)$`) stableGitRef = regexp.MustCompile(`^emacs-(\d+\.\d+(?:[a-z]+)?)$`)
) )
func VersionToName(version string) (string, error) { func VersionToName(version string) (string, error) {
@@ -26,7 +27,8 @@ func VersionToName(version string) (string, error) {
return "", ErrEmptyVersion return "", ErrEmptyVersion
} }
if stableVersion.MatchString(version) { if stableVersion.MatchString(version) ||
strings.HasSuffix(version, "-pretest") {
return "Emacs-" + version, nil return "Emacs-" + version, nil
} }
@@ -34,7 +36,7 @@ func VersionToName(version string) (string, error) {
} }
func GitRefToStableVersion(ref string) (string, error) { func GitRefToStableVersion(ref string) (string, error) {
if m := stableGetRef.FindStringSubmatch(ref); len(m) > 1 { if m := stableGitRef.FindStringSubmatch(ref); len(m) > 1 {
return m[1], nil return m[1], nil
} }

View File

@@ -128,3 +128,15 @@ func (s *Repository) ActionRunURL(runID string) string {
return "" return ""
} }
} }
func (s *Repository) ReleaseURL(releaseName string) string {
if releaseName == "" {
return ""
}
switch s.Type {
case GitHub:
return GitHubBaseURL + s.Source + "/releases/tag/" + releaseName
default:
return ""
}
}

View File

@@ -0,0 +1,54 @@
package repository
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestRepository_ReleaseURL(t *testing.T) {
type fields struct {
Type Type
Source string
}
type args struct {
releaseName string
}
tests := []struct {
name string
fields fields
args args
want string
}{
{
name: "empty name",
fields: fields{Type: GitHub, Source: "foo/bar"},
args: args{releaseName: ""},
want: "",
},
{
name: "GitHub, foo/bar, v1.0.0",
fields: fields{Type: GitHub, Source: "foo/bar"},
args: args{releaseName: "v1.0.0"},
want: "https://github.com/foo/bar/releases/tag/v1.0.0",
},
{
name: "Not GitHub, foo/bar, v1.0.0",
fields: fields{Type: Type("oops"), Source: "foo/bar"},
args: args{releaseName: "v1.0.0"},
want: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
repo := &Repository{
Type: tt.fields.Type,
Source: tt.fields.Source,
}
got := repo.ReleaseURL(tt.args.releaseName)
assert.Equal(t, tt.want, got)
})
}
}

9
pkg/sanitize/string.go Normal file
View File

@@ -0,0 +1,9 @@
package sanitize
import "regexp"
var nonAlphaNum = regexp.MustCompile(`[^\w_-]+`)
func String(s string) string {
return nonAlphaNum.ReplaceAllString(s, "-")
}