mirror of
https://github.com/jimeh/build-emacs-for-macos.git
synced 2026-02-19 13:06:38 +00:00
Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
3d6c7fff64
|
|||
|
d08d1b9b5c
|
|||
|
6e32219c24
|
|||
|
d2548191f1
|
|||
|
8ed16b27c0
|
|||
|
14f7aa13d9
|
|||
| 59ebbdaa2b | |||
|
d98c14dde5
|
|||
|
590b0ac21a
|
|||
|
8c84ef128f
|
|||
|
8b447b6237
|
|||
|
c3d19694e7
|
|||
|
cff89684c6
|
|||
|
48a512fbce
|
|||
|
a3530c02e8
|
|||
|
138ac74ba5
|
|||
|
0ba971ef61
|
|||
|
1ae8771b2c
|
|||
|
1f2868d4b3
|
|||
|
bfa5bcf79b
|
|||
| 02d85f899f | |||
|
aeb3a75e5c
|
|||
|
|
e0fd2b16eb
|
||
|
d24ac084b7
|
|||
| 159a7333de | |||
|
b582523642
|
|||
|
4f1e748df2
|
|||
|
d984633991
|
|||
|
616f74d624
|
|||
|
d7963b7664
|
|||
|
a20a8456ab
|
|||
|
8ad3ff4f53
|
|||
|
e31f5aaf93
|
|||
|
c2fb07fdb8
|
|||
|
07e0e3dacd
|
|||
|
efddb9ef92
|
|||
| f7f4c0433a | |||
|
cbd8cb27b6
|
|||
|
656b96510a
|
|||
|
084776db6b
|
|||
|
1e6d6cc6cf
|
|||
|
68ef4c066c
|
|||
|
d476fd33ec
|
|||
| baa5930467 | |||
|
743b10c751
|
|||
|
59f1bcd3e8
|
|||
| e767e284b7 | |||
|
8129a2e93b
|
|||
|
4ae288cae3
|
|||
|
3bd78d130a
|
|||
|
fb5362ce18
|
23
.rubocop.yml
23
.rubocop.yml
@@ -1,9 +1,30 @@
|
||||
AllCops:
|
||||
TargetRubyVersion: 2.3
|
||||
TargetRubyVersion: 2.4
|
||||
NewCops: enable
|
||||
|
||||
Layout/LineLength:
|
||||
Max: 80
|
||||
|
||||
Style/AccessorGrouping:
|
||||
Enabled: false
|
||||
|
||||
Style/Documentation:
|
||||
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
|
||||
|
||||
5
Brewfile
5
Brewfile
@@ -2,7 +2,7 @@
|
||||
|
||||
brew 'autoconf'
|
||||
brew 'coreutils'
|
||||
brew 'curl'
|
||||
brew 'dbus'
|
||||
brew 'expat'
|
||||
brew 'gcc'
|
||||
brew 'gmp'
|
||||
@@ -22,5 +22,8 @@ brew 'make'
|
||||
brew 'ncurses'
|
||||
brew 'nettle'
|
||||
brew 'pkg-config'
|
||||
brew 'sqlite'
|
||||
brew 'texinfo'
|
||||
brew 'tree-sitter'
|
||||
brew 'webp'
|
||||
brew 'zlib'
|
||||
|
||||
118
CHANGELOG.md
118
CHANGELOG.md
@@ -2,6 +2,124 @@
|
||||
|
||||
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)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **build:** re-link eln files by default again ([4ae288c](https://github.com/jimeh/build-emacs-for-macos/commit/4ae288cae34c5e1d291dad7b6b654fe37c4a221f))
|
||||
* **native-comp:** no longer require gcc homebrew formula ([3bd78d1](https://github.com/jimeh/build-emacs-for-macos/commit/3bd78d130a5419a6530a7d30e271569e501870fb)), closes [#53](https://github.com/jimeh/build-emacs-for-macos/issues/53)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **embed:** relink shared libraries with [@rpath](https://github.com/rpath) instead of [@executable](https://github.com/executable)_path ([fb5362c](https://github.com/jimeh/build-emacs-for-macos/commit/fb5362ce183ce43e52afcc0fc721cf2145f9c85b))
|
||||
|
||||
### [0.6.25](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.24...v0.6.25) (2021-11-25)
|
||||
|
||||
### [0.6.24](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.23...v0.6.24) (2021-11-24)
|
||||
|
||||
50
README.md
50
README.md
@@ -17,21 +17,10 @@ Use this script at your own risk.
|
||||
built from the `master` branch. This script allows you to choose any branch,
|
||||
tag, or git ref you want.
|
||||
|
||||
## Status
|
||||
## Binary Builds
|
||||
|
||||
As of writing (2021-04-25) it works for me on my machine. Your luck may vary.
|
||||
|
||||
I have successfully built:
|
||||
|
||||
- `emacs-27.1` release git tag
|
||||
- `master` branch (Emacs 28.x)
|
||||
- `feature/native-comp` branch (Emacs 28.x)
|
||||
|
||||
For reference, my machine is:
|
||||
|
||||
- 13-inch MacBook Pro (2020), 10th-gen 2.3 GHz Quad-Core Intel Core i7 (4c/8t)
|
||||
- macOS Big Sur 11.2.3 (20D91)
|
||||
- Xcode 12.4 (12D4e)
|
||||
Nightly and stable binary builds produced with this build script are available
|
||||
from [jimeh/emacs-builds](https://github.com/jimeh/emacs-builds).
|
||||
|
||||
## Limitations
|
||||
|
||||
@@ -41,14 +30,9 @@ The build produced does have some limitations:
|
||||
application will be that of the machine it was built on.
|
||||
- The minimum required macOS version of the built application will be the same
|
||||
as that of the machine it was built on.
|
||||
- The application is not signed, so running it on machines other than the one
|
||||
that built the application will yield warnings. If you want to make a signed
|
||||
Emacs.app, google is you friend for finding signing instructions.
|
||||
|
||||
## Binary Builds
|
||||
|
||||
Nightly and stable binary builds produced with this build script are available
|
||||
from [jimeh/emacs-builds](https://github.com/jimeh/emacs-builds).
|
||||
- The application is not signed automatically, but the CLI tool used to sign the
|
||||
nightly builds is available. Run `go run ./cmd/emacs-builder package --help`
|
||||
for details. More detailed instructions will come soon.
|
||||
|
||||
## Requirements
|
||||
|
||||
@@ -66,6 +50,26 @@ from [jimeh/emacs-builds](https://github.com/jimeh/emacs-builds).
|
||||
brew install ruby
|
||||
```
|
||||
|
||||
## Status
|
||||
|
||||
As of writing (2021-11-27) it works for me on my machine and for the nightly
|
||||
builds in [jimeh/emacs-builds](https://github.com/jimeh/emacs-builds). Your luck
|
||||
may vary.
|
||||
|
||||
I have successfully built:
|
||||
|
||||
- `emacs-28` release branch
|
||||
- `master` branch (Emacs 29.x)
|
||||
|
||||
For reference, my machine is:
|
||||
|
||||
- 13-inch MacBook Pro (2020), 10th-gen 2.3 GHz Quad-Core Intel Core i7 (4c/8t)
|
||||
- macOS Monterey 12.0.1 (21A559)
|
||||
- Xcode 13.1 (13A1030d)
|
||||
|
||||
Nightly builds are built with GitHub Actions on GitHub-hosted runners, using
|
||||
`macos-10.15`.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
@@ -81,7 +85,7 @@ Options:
|
||||
--[no-]native-comp Enable/disable native-comp (default: enabled if supported)
|
||||
--[no-]native-march Enable/disable -march=native CFLAG(default: disabled)
|
||||
--[no-]native-full-aot Enable/disable NATIVE_FULL_AOT / Ahead of Time compilation (default: disabled)
|
||||
--[no-]relink-eln-files Enable/disable re-linking shared libraries in bundled *.eln files (default: disabled)
|
||||
--[no-]relink-eln-files Enable/disable re-linking shared libraries in bundled *.eln files (default: enabled)
|
||||
--[no-]rsvg Enable/disable SVG image support via librsvg (default: enabled)
|
||||
--no-titlebar Apply no-titlebar patch (default: disabled)
|
||||
--posix-spawn Apply posix-spawn patch (default: disabled)
|
||||
|
||||
@@ -7,6 +7,7 @@ require 'erb'
|
||||
require 'etc'
|
||||
require 'fileutils'
|
||||
require 'json'
|
||||
require 'logger'
|
||||
require 'net/http'
|
||||
require 'optparse'
|
||||
require 'pathname'
|
||||
@@ -18,33 +19,68 @@ require 'yaml'
|
||||
class Error < StandardError; end
|
||||
|
||||
module Output
|
||||
def info(msg, newline: true)
|
||||
out "INFO: #{msg}", newline: newline
|
||||
end
|
||||
class << self
|
||||
LEVELS = {
|
||||
debug: Logger::DEBUG,
|
||||
error: Logger::ERROR,
|
||||
fatal: Logger::FATAL,
|
||||
info: Logger::INFO,
|
||||
unknown: Logger::UNKNOWN,
|
||||
warn: Logger::WARN
|
||||
}.freeze
|
||||
|
||||
def out(msg, newline: true)
|
||||
if newline
|
||||
warn "==> #{msg}"
|
||||
else
|
||||
$stderr.print "==> #{msg}"
|
||||
def log_level
|
||||
LEVELS.key(logger.level)
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
module System
|
||||
include Output
|
||||
|
||||
def run_cmd(*args)
|
||||
out("CMD: #{args.join(' ')}")
|
||||
debug "executing: #{args.join(' ')}"
|
||||
cmd(*args)
|
||||
end
|
||||
|
||||
def cmd(*args)
|
||||
system(*args) || err("Exit code: #{$CHILD_STATUS.exitstatus}")
|
||||
system(*args) || fatal("Exit code: #{$CHILD_STATUS.exitstatus}")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -61,7 +97,7 @@ end
|
||||
class OSVersion
|
||||
def initialize
|
||||
@version = `sw_vers -productVersion`.match(
|
||||
/(?<major>\d+)(?:\.(?<minor>\d+)(:?\.(?<patch>\d+))?)?/
|
||||
/(?<major>\d+)(?:\.(?<minor>\d+)(?:\.(?<patch>\d+))?)?/
|
||||
)
|
||||
end
|
||||
|
||||
@@ -86,8 +122,7 @@ class Build
|
||||
include Output
|
||||
include System
|
||||
|
||||
EMACS_MIRROR_REPO = 'emacs-mirror/emacs'
|
||||
DOWNLOAD_URL = 'https://github.com/emacs-mirror/emacs/tarball/%s'
|
||||
DEFAULT_GITHUB_REPO = 'emacs-mirror/emacs'
|
||||
|
||||
attr_reader :root_dir
|
||||
attr_reader :source_dir
|
||||
@@ -106,7 +141,7 @@ class Build
|
||||
load_plan(options[:plan]) if options[:plan]
|
||||
|
||||
unless meta[:sha] && meta[:date]
|
||||
err 'Failed to get commit info from GitHub.'
|
||||
fatal 'Failed to get commit info from GitHub.'
|
||||
end
|
||||
|
||||
tarball = download_tarball(meta[:sha])
|
||||
@@ -122,7 +157,9 @@ class Build
|
||||
|
||||
CLIHelperEmbedder.new(app).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]
|
||||
|
||||
archive_build(build_dir) if options[:archive]
|
||||
@@ -131,6 +168,7 @@ class Build
|
||||
private
|
||||
|
||||
def load_plan(filename)
|
||||
debug "Loading plan from: #{filename}"
|
||||
plan = YAML.safe_load(File.read(filename), [:Time])
|
||||
|
||||
@ref = plan.dig('source', 'ref')
|
||||
@@ -163,6 +201,10 @@ class Build
|
||||
@output_dir ||= (options[:output] || File.join(root_dir, 'builds'))
|
||||
end
|
||||
|
||||
def github_src_repo
|
||||
@github_src_repo ||= options[:github_src_repo] || DEFAULT_GITHUB_REPO
|
||||
end
|
||||
|
||||
def brew_dir
|
||||
@brew_dir ||= `brew --prefix`.chomp
|
||||
end
|
||||
@@ -189,8 +231,8 @@ class Build
|
||||
def download_tarball(sha)
|
||||
FileUtils.mkdir_p(tarballs_dir)
|
||||
|
||||
url = (DOWNLOAD_URL % sha)
|
||||
filename = "emacs-mirror-emacs-#{sha[0..6]}.tgz"
|
||||
url = "https://github.com/#{github_src_repo}/tarball/#{sha}"
|
||||
filename = "#{github_src_repo.gsub(/[^a-zA-Z0-9-]+/, '-')}-#{sha[0..6]}.tgz"
|
||||
target = File.join(tarballs_dir, filename)
|
||||
|
||||
if File.exist?(target)
|
||||
@@ -212,8 +254,8 @@ class Build
|
||||
log_args[1..-1]
|
||||
end
|
||||
|
||||
out "CMD: #{log_args.join(' ')}"
|
||||
system(*args) || err("Exit code: #{$CHILD_STATUS.exitstatus}")
|
||||
debug "executing: #{log_args.join(' ')}"
|
||||
cmd(*args)
|
||||
|
||||
target
|
||||
end
|
||||
@@ -231,7 +273,7 @@ class Build
|
||||
|
||||
info 'Extracting tarball...'
|
||||
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) }
|
||||
|
||||
@@ -250,26 +292,53 @@ class Build
|
||||
@supports_xwidgets ||= !!configure_help.match(/\s+--with-xwidgets\s+/)
|
||||
end
|
||||
|
||||
def supports_tree_sitter?
|
||||
@supports_tree_sitter ||= !!configure_help.match(
|
||||
/\s+--with-tree-sitter(\s|=).+/
|
||||
)
|
||||
end
|
||||
|
||||
def supports_native_comp?
|
||||
@supports_native_comp ||= !native_comp_configure_flag.nil?
|
||||
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
|
||||
@native_comp_configure_flag ||= configure_help.match(
|
||||
/\s+(--with-native(?:comp|-compilation))\s+/
|
||||
)&.[](1)
|
||||
return @native_comp_configure_flag if @native_comp_configure_flag
|
||||
|
||||
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
|
||||
|
||||
def detect_native_comp
|
||||
info 'Detecting native-comp support: ', newline: false
|
||||
info 'Detecting native-comp support...'
|
||||
options[:native_comp] = supports_native_comp?
|
||||
puts options[:native_comp] ? 'Supported' : 'Not supported'
|
||||
info 'Native-comp is: ' \
|
||||
"#{options[:native_comp] ? 'Supported' : 'Not supported'}"
|
||||
end
|
||||
|
||||
def verify_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
|
||||
|
||||
def autogen
|
||||
@@ -288,7 +357,7 @@ class Build
|
||||
|
||||
if File.exist?(emacs_app)
|
||||
info 'Emacs.app already exists in ' \
|
||||
"\"#{target.gsub(root_dir + '/', '')}\", attempting to use."
|
||||
"\"#{target.gsub("#{root_dir}/", '')}\", attempting to use."
|
||||
return emacs_app
|
||||
end
|
||||
|
||||
@@ -305,7 +374,7 @@ class Build
|
||||
"-I#{File.join(gcc_info.libgccjit_root_dir, 'include')}",
|
||||
'-O2',
|
||||
(options[:native_march] ? '-march=native' : nil),
|
||||
ENV['CFLAGS']
|
||||
ENV.fetch('CFLAGS', nil)
|
||||
].compact.join(' ')
|
||||
|
||||
ENV['LDFLAGS'] = [
|
||||
@@ -316,14 +385,14 @@ class Build
|
||||
"-I#{File.join(gcc_info.libgccjit_root_dir, 'include')}",
|
||||
# Ensure library re-linking and code signing will work after building.
|
||||
'-Wl,-headerpad_max_install_names',
|
||||
ENV['LDFLAGS']
|
||||
ENV.fetch('LDFLAGS', nil)
|
||||
].compact.join(' ')
|
||||
|
||||
ENV['LIBRARY_PATH'] = [
|
||||
gcc_info.lib_dir,
|
||||
gcc_info.darwin_lib_dir,
|
||||
gcc_info.libgccjit_lib_dir,
|
||||
ENV['LIBRARY_PATH']
|
||||
ENV.fetch('LIBRARY_PATH', nil)
|
||||
].compact.join(':')
|
||||
end
|
||||
|
||||
@@ -337,7 +406,7 @@ class Build
|
||||
File.join(brew_dir, 'opt/zlib/lib/pkgconfig'),
|
||||
File.join(brew_dir, 'Homebrew/Library/Homebrew/os/mac/pkgconfig',
|
||||
OS.version.to_s),
|
||||
ENV['PKG_CONFIG_PATH']
|
||||
ENV.fetch('PKG_CONFIG_PATH', nil)
|
||||
].compact.join(':')
|
||||
|
||||
ENV['PATH'] = [
|
||||
@@ -346,11 +415,11 @@ class Build
|
||||
File.join(brew_dir, 'opt/gnu-sed/libexec/gnubin'),
|
||||
File.join(brew_dir, 'bin'),
|
||||
File.join(brew_dir, 'opt/texinfo/bin'),
|
||||
ENV['PATH']
|
||||
ENV.fetch('PATH', nil)
|
||||
].compact.join(':')
|
||||
|
||||
ENV['LIBRARY_PATH'] = [
|
||||
ENV['LIBRARY_PATH'],
|
||||
ENV.fetch('LIBRARY_PATH', nil),
|
||||
'/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib'
|
||||
].compact.join(':')
|
||||
|
||||
@@ -359,15 +428,20 @@ class Build
|
||||
'--with-modules',
|
||||
'--enable-locallisppath=' \
|
||||
'/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?
|
||||
configure_flags << '--with-xwidgets'
|
||||
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 << '--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:
|
||||
# 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)'"
|
||||
|
||||
if options[:native_full_aot]
|
||||
info 'Using NATIVE_FULL_AOT=1'
|
||||
make_flags << 'NATIVE_FULL_AOT=1'
|
||||
info 'Using native compile full AOT'
|
||||
# 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')
|
||||
else
|
||||
ENV.delete('NATIVE_FULL_AOT')
|
||||
@@ -393,11 +471,11 @@ class Build
|
||||
end
|
||||
end
|
||||
|
||||
run_cmd 'make', *make_flags
|
||||
run_cmd 'make', *make_flags.compact
|
||||
run_cmd 'make', 'install'
|
||||
end
|
||||
|
||||
err 'Build failed.' unless File.exist?(emacs_app)
|
||||
fatal 'Build failed.' unless File.exist?(emacs_app)
|
||||
|
||||
emacs_app
|
||||
end
|
||||
@@ -407,8 +485,8 @@ class Build
|
||||
target_dir = File.join(output_dir, build_name)
|
||||
|
||||
if File.exist?(target_dir)
|
||||
err "Output directory #{target_dir} already exists, " \
|
||||
'please delete it and try again'
|
||||
fatal "Output directory #{target_dir} already exists, " \
|
||||
'please delete it and try again'
|
||||
end
|
||||
|
||||
info "Copying \"#{app_name}\" to: #{target_dir}"
|
||||
@@ -486,7 +564,8 @@ class Build
|
||||
'MacOS/lib/emacs/**/native-lisp'].first
|
||||
|
||||
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
|
||||
|
||||
@@ -502,7 +581,7 @@ class Build
|
||||
contents_dir = File.join(app, 'Contents')
|
||||
FileUtils.cd(contents_dir) do
|
||||
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'
|
||||
|
||||
content = File.read(filename, mode: 'rb').gsub(
|
||||
@@ -514,7 +593,7 @@ class Build
|
||||
"../native-lisp/#{sanitized_eln_version}/"
|
||||
)
|
||||
|
||||
File.open(filename, 'w') { |f| f.write(content) }
|
||||
File.write(filename, content)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -546,19 +625,19 @@ class Build
|
||||
build = File.basename(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}\"..."
|
||||
FileUtils.cd(parent_dir) do
|
||||
system('tar', '-cjf', archive_filename, build)
|
||||
cmd('tar', '-cjf', archive_filename, build)
|
||||
|
||||
if options[:archive_keep] == false
|
||||
info "Removing \"#{build}\" directory from #{parent_dir}"
|
||||
FileUtils.rm_rf(build_dir)
|
||||
end
|
||||
end
|
||||
else
|
||||
info "#{filename} archive exists in " \
|
||||
"#{target_dir}, skipping archving."
|
||||
end
|
||||
end
|
||||
|
||||
@@ -574,7 +653,7 @@ class Build
|
||||
.gsub('#define HAVE_ALLOCA_H 1',
|
||||
'#undef HAVE_ALLOCA_H')
|
||||
|
||||
File.open(filename, 'w') { |f| f.write(content) }
|
||||
File.write(filename, content)
|
||||
end
|
||||
|
||||
def meta
|
||||
@@ -583,9 +662,9 @@ class Build
|
||||
ref_sha = options[:git_sha] || ref
|
||||
info "Fetching info for git ref: #{ref_sha}"
|
||||
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)
|
||||
meta = {
|
||||
@@ -615,31 +694,32 @@ class Build
|
||||
end
|
||||
|
||||
def effective_version
|
||||
@effective_version ||= begin
|
||||
case ref
|
||||
when /^emacs-26.*/
|
||||
'emacs-26'
|
||||
when /^emacs-27.*/
|
||||
'emacs-27'
|
||||
when /^emacs-28.*/
|
||||
'emacs-28'
|
||||
else
|
||||
'emacs-29'
|
||||
end
|
||||
end
|
||||
@effective_version ||= case ref
|
||||
when /^emacs-26.*/
|
||||
'emacs-26'
|
||||
when /^emacs-27.*/
|
||||
'emacs-27'
|
||||
when /^emacs-28.*/
|
||||
'emacs-28'
|
||||
when /^emacs-29.*/
|
||||
'emacs-29'
|
||||
else
|
||||
'emacs-30'
|
||||
end
|
||||
end
|
||||
|
||||
def patches(opts = {})
|
||||
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 << {
|
||||
url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \
|
||||
"patches/#{effective_version}/fix-window-role.patch"
|
||||
}
|
||||
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 << {
|
||||
url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \
|
||||
"patches/#{effective_version}/system-appearance.patch"
|
||||
@@ -660,15 +740,41 @@ class Build
|
||||
end
|
||||
end
|
||||
|
||||
if %w[emacs-28 emacs-29].include?(effective_version)
|
||||
if options[:posix_spawn]
|
||||
if %w[emacs-29 emacs-30].include?(effective_version)
|
||||
p << {
|
||||
url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \
|
||||
"patches/#{effective_version}/round-undecorated-frame.patch"
|
||||
}
|
||||
if options[:poll]
|
||||
p << {
|
||||
url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \
|
||||
"patches/#{effective_version}/posix-spawn.patch"
|
||||
"patches/#{effective_version}/poll.patch"
|
||||
}
|
||||
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'
|
||||
p << {
|
||||
url: 'https://github.com/d12frosted/homebrew-emacs-plus/raw/master/' \
|
||||
@@ -687,7 +793,7 @@ class Build
|
||||
end
|
||||
|
||||
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]
|
||||
info 'Applying patch...'
|
||||
@@ -715,20 +821,37 @@ class Build
|
||||
end
|
||||
|
||||
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]
|
||||
info "Applying patch to #{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')
|
||||
s = f.read
|
||||
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.close
|
||||
info "#{file} patched."
|
||||
end
|
||||
end
|
||||
|
||||
@@ -764,29 +887,37 @@ class AbstractEmbedder
|
||||
attr_reader :app
|
||||
|
||||
def initialize(app)
|
||||
err "#{app} does not exist" unless File.exist?(app)
|
||||
fatal "#{app} does not exist" unless File.exist?(app)
|
||||
|
||||
@app = app
|
||||
end
|
||||
|
||||
def relative_path(path)
|
||||
Pathname.new(path).relative_path_from(Pathname.new(app)).to_s
|
||||
end
|
||||
|
||||
def invocation_dir
|
||||
File.join(app, 'Contents', 'MacOS')
|
||||
@invocation_dir ||= File.join(app, 'Contents', 'MacOS')
|
||||
end
|
||||
|
||||
def bin
|
||||
File.join(invocation_dir, 'Emacs')
|
||||
@bin ||= File.join(invocation_dir, 'Emacs')
|
||||
end
|
||||
|
||||
def bin_dir
|
||||
File.join(invocation_dir, 'bin')
|
||||
@bin_dir ||= File.join(invocation_dir, 'bin')
|
||||
end
|
||||
|
||||
def lib_dir
|
||||
File.join(invocation_dir, 'lib')
|
||||
@lib_dir ||= frameworks_dir
|
||||
end
|
||||
|
||||
def frameworks_dir
|
||||
@frameworks_dir ||= File.join(app, 'Contents', 'Frameworks')
|
||||
end
|
||||
|
||||
def resources_dir
|
||||
File.join(app, 'Contents', 'Resources')
|
||||
@resources_dir ||= File.join(app, 'Contents', 'Resources')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -807,7 +938,8 @@ end
|
||||
class CSourcesEmbedder < AbstractEmbedder
|
||||
PATH_PATCH = <<~ELISP
|
||||
;; 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
|
||||
|
||||
attr_reader :source_dir
|
||||
@@ -819,12 +951,16 @@ class CSourcesEmbedder < AbstractEmbedder
|
||||
end
|
||||
|
||||
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')
|
||||
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|
|
||||
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))
|
||||
cmd('cp', '-pRL', f, target)
|
||||
end
|
||||
@@ -832,6 +968,8 @@ class CSourcesEmbedder < AbstractEmbedder
|
||||
return if File.exist?(site_start_el_file) &&
|
||||
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|
|
||||
f.puts("\n#{PATH_PATCH}")
|
||||
end
|
||||
@@ -847,32 +985,37 @@ end
|
||||
class LibEmbedder < AbstractEmbedder
|
||||
attr_reader :lib_source
|
||||
attr_reader :extra_libs
|
||||
attr_reader :embed_eln_files
|
||||
attr_reader :relink_eln_files
|
||||
|
||||
def initialize(app, lib_source, extra_libs = [], embed_eln_files = true)
|
||||
def initialize(app, lib_source, extra_libs = [], relink_eln_files: true)
|
||||
super(app)
|
||||
|
||||
@lib_source = lib_source
|
||||
@extra_libs = extra_libs
|
||||
@embed_eln_files = embed_eln_files
|
||||
@relink_eln_files = relink_eln_files
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
FileUtils.cd(File.dirname(app)) do
|
||||
rel_path = Pathname.new(lib_dir).relative_path_from(
|
||||
Pathname.new(File.dirname(binary))
|
||||
).to_s
|
||||
rpath = File.join('@executable_path', rel_path)
|
||||
|
||||
set_rpath(binary, rpath)
|
||||
copy_libs(binary)
|
||||
copy_extra_libs(extra_libs, binary) if extra_libs.any?
|
||||
if eln_files.any?
|
||||
info "Embedding libraries for #{eln_files.size} *.eln files " \
|
||||
|
||||
if relink_eln_files && eln_files.any?
|
||||
info "Bundling shared libraries for #{eln_files.size} *.eln files " \
|
||||
'within Emacs.app'
|
||||
rel_path = Pathname.new(lib_dir).relative_path_from(
|
||||
Pathname.new(File.dirname(binary))
|
||||
).to_s
|
||||
eln_files.each { |f| copy_libs(f, rel_path) } if embed_eln_files
|
||||
|
||||
eln_files.each { |f| copy_libs(f) }
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -883,63 +1026,84 @@ class LibEmbedder < AbstractEmbedder
|
||||
@eln_files ||= Dir[File.join(app, 'Contents', '**', '*.eln')]
|
||||
end
|
||||
|
||||
def copy_libs(exe, rel_path = nil)
|
||||
exe_file = File.basename(exe)
|
||||
rel_path ||= Pathname.new(lib_dir).relative_path_from(
|
||||
Pathname.new(File.dirname(exe))
|
||||
).to_s
|
||||
def set_rpath(exe, rpath)
|
||||
return if rpath.nil? || rpath == ''
|
||||
|
||||
rpath = File.join('@executable_path', rel_path)
|
||||
rpaths = `otool -l "#{exe}" | grep -A 2 'cmd LC_RPATH' | grep 'path'`
|
||||
return if rpaths.include?(rpath)
|
||||
|
||||
unless rpaths.include?(rpath)
|
||||
while_writable(exe) do
|
||||
system('install_name_tool', '-add_rpath',
|
||||
File.join('@executable_path', rel_path), exe)
|
||||
end
|
||||
end
|
||||
|
||||
`otool -L "#{exe}"`.split("\n")[1..-1].each do |line|
|
||||
match = line.match(%r{^\s+(.+/(lib[^/ ]+))\s})
|
||||
next unless match && match[1].start_with?(lib_source)
|
||||
|
||||
while_writable(exe) do
|
||||
if match[2] == exe_file
|
||||
system('install_name_tool', '-id',
|
||||
File.join('@executable_path', rel_path, match[2].to_s), exe)
|
||||
else
|
||||
system('install_name_tool', '-change', match[1],
|
||||
File.join('@executable_path', rel_path, match[2].to_s), exe)
|
||||
end
|
||||
end
|
||||
|
||||
next if match[2] == exe_file || File.exist?(File.join(lib_dir, match[2]))
|
||||
|
||||
FileUtils.mkdir_p(lib_dir)
|
||||
cmd('cp', '-pRL', match[1], lib_dir)
|
||||
copy_libs(File.join(lib_dir, match[2].to_s), rel_path)
|
||||
while_writable(exe) do
|
||||
debug "Setting rpath for '#{relative_path(exe)}' to: #{rpath}"
|
||||
cmd('install_name_tool', '-add_rpath', rpath, exe)
|
||||
end
|
||||
end
|
||||
|
||||
def copy_extra_libs(extra_libs, exe, rel_path = nil)
|
||||
rel_path ||= Pathname.new(lib_dir).relative_path_from(
|
||||
Pathname.new(File.dirname(exe))
|
||||
).to_s
|
||||
def copy_libs(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|
|
||||
# Parse otool -L output
|
||||
match = line.match(%r{^\s+(.+/(lib[^/ ]+))\s})
|
||||
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
|
||||
if lib_filename == exe_filename
|
||||
id_name = File.join('@rpath', lib_filename)
|
||||
debug "-- Setting install name to: #{id_name}"
|
||||
cmd('install_name_tool', '-id', id_name, exe)
|
||||
else
|
||||
debug "-- Bundling shared library: #{lib_filepath}"
|
||||
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
|
||||
|
||||
next if lib_filename == exe_filename || !copied
|
||||
end
|
||||
|
||||
copied_libs.each { |lib| copy_libs(lib) }
|
||||
end
|
||||
|
||||
def copy_extra_libs(extra_libs, _exe)
|
||||
extra_libs.each do |lib|
|
||||
debug "Bundling extra shared library: #{lib}"
|
||||
lib_file = File.basename(lib)
|
||||
target = "#{lib_dir}/#{lib_file}"
|
||||
unless File.exist?(target)
|
||||
FileUtils.mkdir_p(lib_dir)
|
||||
debug "-- Copying to: #{lib_file}"
|
||||
cmd('cp', '-pRL', lib, lib_dir)
|
||||
end
|
||||
|
||||
while_writable(target) do
|
||||
system('install_name_tool', '-id',
|
||||
File.join('@executable_path', rel_path, lib_file), target)
|
||||
end
|
||||
|
||||
copy_libs(target, rel_path)
|
||||
copy_libs(target)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -966,10 +1130,10 @@ class GccLibEmbedder < AbstractEmbedder
|
||||
return
|
||||
end
|
||||
|
||||
info 'Embedding libgccjit into Emacs.app'
|
||||
info 'Bundling libgccjit into Emacs.app'
|
||||
|
||||
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
|
||||
|
||||
FileUtils.mkdir_p(File.dirname(target_dir))
|
||||
@@ -984,6 +1148,7 @@ class GccLibEmbedder < AbstractEmbedder
|
||||
return if File.exist?(site_start_el_file) &&
|
||||
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|
|
||||
f.puts("\n#{env_setup}")
|
||||
end
|
||||
@@ -1066,7 +1231,7 @@ class GccInfo
|
||||
end
|
||||
|
||||
def relative_lib_dir
|
||||
@relative_lib_dir ||= relative_dir(lib_dir, root_dir)
|
||||
@relative_lib_dir ||= relative_dir(lib_dir, File.join(root_dir, 'lib'))
|
||||
end
|
||||
|
||||
def darwin_lib_dir
|
||||
@@ -1081,7 +1246,9 @@ class GccInfo
|
||||
end
|
||||
|
||||
def relative_darwin_lib_dir
|
||||
@relative_darwin_lib_dir ||= relative_dir(darwin_lib_dir, root_dir)
|
||||
@relative_darwin_lib_dir ||= relative_dir(
|
||||
darwin_lib_dir, File.join(root_dir, 'lib')
|
||||
)
|
||||
end
|
||||
|
||||
# Sanitize folder name with full "MAJOR.MINOR.PATCH" version number to just
|
||||
@@ -1119,7 +1286,8 @@ class GccInfo
|
||||
|
||||
def libgccjit_lib_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) }
|
||||
.select { |path| File.basename(path).match(/^\d+$/) }
|
||||
@@ -1127,18 +1295,18 @@ class GccInfo
|
||||
end
|
||||
|
||||
def verify_libgccjit
|
||||
err 'gcc not installed' unless Dir.exist?(root_dir)
|
||||
err 'libgccjit not installed' unless Dir.exist?(libgccjit_root_dir)
|
||||
fatal 'gcc not installed' unless Dir.exist?(root_dir)
|
||||
fatal 'libgccjit not installed' unless Dir.exist?(libgccjit_root_dir)
|
||||
|
||||
if libgccjit_lib_dir&.empty?
|
||||
err "Detected libgccjit (#{libgccjit_root_dir}) does not have any " \
|
||||
'libgccjit.so* files. Please try reinstalling libgccjit: ' \
|
||||
'brew reinstall libgccjit'
|
||||
if libgccjit_lib_dir.empty?
|
||||
fatal "Detected libgccjit (#{libgccjit_root_dir}) does not have any " \
|
||||
'libgccjit.so* files. Please try reinstalling libgccjit: ' \
|
||||
'brew reinstall libgccjit'
|
||||
end
|
||||
|
||||
return if major_version == libgccjit_major_version
|
||||
|
||||
err <<~TEXT
|
||||
fatal <<~TEXT
|
||||
Detected GCC and libgccjit library paths do not belong to the same major
|
||||
version of GCC. Detected paths:
|
||||
- #{lib_dir}
|
||||
@@ -1146,7 +1314,7 @@ class GccInfo
|
||||
TEXT
|
||||
end
|
||||
|
||||
def get_binding
|
||||
def get_binding # rubocop:disable Naming/AccessorMethodName
|
||||
binding
|
||||
end
|
||||
|
||||
@@ -1165,15 +1333,19 @@ if __FILE__ == $PROGRAM_NAME
|
||||
cli_options = {
|
||||
work_dir: File.expand_path(__dir__),
|
||||
native_full_aot: false,
|
||||
relink_eln: false,
|
||||
relink_eln: true,
|
||||
native_march: false,
|
||||
parallel: Etc.nprocessors,
|
||||
rsvg: true,
|
||||
dbus: true,
|
||||
xwidgets: true,
|
||||
tree_sitter: true,
|
||||
github_src_repo: nil,
|
||||
github_auth: true,
|
||||
dist_include: ['COPYING'],
|
||||
archive: true,
|
||||
archive_keep: false
|
||||
archive_keep: false,
|
||||
log_level: 'info'
|
||||
}
|
||||
|
||||
begin
|
||||
@@ -1205,6 +1377,12 @@ if __FILE__ == $PROGRAM_NAME
|
||||
cli_options[:xwidgets] = v
|
||||
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',
|
||||
'Enable/disable native-comp ' \
|
||||
'(default: enabled if supported)') do |v|
|
||||
@@ -1225,7 +1403,7 @@ if __FILE__ == $PROGRAM_NAME
|
||||
|
||||
opts.on('--[no-]relink-eln-files',
|
||||
'Enable/disable re-linking shared libraries in bundled *.eln ' \
|
||||
'files (default: disabled)') do |v|
|
||||
'files (default: enabled)') do |v|
|
||||
cli_options[:relink_eln] = v
|
||||
end
|
||||
|
||||
@@ -1235,12 +1413,17 @@ if __FILE__ == $PROGRAM_NAME
|
||||
cli_options[:rsvg] = v
|
||||
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
|
||||
cli_options[:no_titlebar] = true
|
||||
end
|
||||
|
||||
opts.on('--posix-spawn', 'Apply posix-spawn patch (default: disabled)') do
|
||||
cli_options[:posix_spawn] = true
|
||||
opts.on('--posix-spawn', 'Apply posix-spawn patch (deprecated)') do
|
||||
warn '==> WARN: posix-spawn patch is deprecated as has no effect.'
|
||||
end
|
||||
|
||||
opts.on('--no-frame-refocus',
|
||||
@@ -1248,6 +1431,19 @@ if __FILE__ == $PROGRAM_NAME
|
||||
cli_options[:no_frame_refocus] = true
|
||||
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',
|
||||
'Make authenticated GitHub API requests if GITHUB_TOKEN ' \
|
||||
'environment variable is set.' \
|
||||
@@ -1288,6 +1484,11 @@ if __FILE__ == $PROGRAM_NAME
|
||||
cli_options[:archive_keep] = v
|
||||
end
|
||||
|
||||
opts.on('--log-level LEVEL',
|
||||
'Build script log level (default: info)') do |v|
|
||||
cli_options[:log_level] = v
|
||||
end
|
||||
|
||||
opts.on(
|
||||
'--plan FILE',
|
||||
'Follow given plan file, instead of using given git ref/sha'
|
||||
@@ -1296,6 +1497,7 @@ if __FILE__ == $PROGRAM_NAME
|
||||
end
|
||||
end.parse!
|
||||
|
||||
Output.log_level = cli_options[:log_level]
|
||||
work_dir = cli_options.delete(:work_dir)
|
||||
Build.new(work_dir, ARGV.shift, cli_options).build
|
||||
rescue Error => e
|
||||
|
||||
2
go.mod
2
go.mod
@@ -16,7 +16,7 @@ require (
|
||||
github.com/hexops/gotextdiff v1.0.3
|
||||
github.com/jimeh/undent v1.1.0
|
||||
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/stretchr/testify v1.7.0
|
||||
github.com/urfave/cli/v2 v2.3.0
|
||||
|
||||
4
go.sum
4
go.sum
@@ -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/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
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.3/go.mod h1:Ua18ZhqjZHg8VyqZo8kNHAY331ntV6nNJ9mT3s2mIo8=
|
||||
github.com/mitchellh/gon v0.2.5 h1:mVWtqTzV03W0avJqmqjk9M0qls3TDUXfc9ETJaPIOWY=
|
||||
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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
resolve_link() {
|
||||
"$(type -p greadlink readlink | head -1)" "$1"
|
||||
"$(command -v greadlink || command -v readlink)" "$1"
|
||||
}
|
||||
|
||||
abs_dirname() {
|
||||
|
||||
@@ -393,9 +393,7 @@ func (s *Updater) renderCask(
|
||||
filename := asset.GetName()
|
||||
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 {
|
||||
info.Assets[filename] = &ReleaseAsset{
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"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/release"
|
||||
"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"
|
||||
)
|
||||
|
||||
var nonAlphaNum = regexp.MustCompile(`[^\w_-]+`)
|
||||
var gitTagMatcher = regexp.MustCompile(
|
||||
`^emacs(-.*)?-((\d+\.\d+)(?:\.(\d+))?(-rc\d+)?(.+)?)$`,
|
||||
)
|
||||
|
||||
type TestBuildType string
|
||||
|
||||
@@ -37,7 +41,7 @@ type Options struct {
|
||||
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")
|
||||
|
||||
repo, err := repository.NewGitHub(opts.EmacsRepo)
|
||||
@@ -66,19 +70,36 @@ func Create(ctx context.Context, opts *Options) (*Plan, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
version := fmt.Sprintf(
|
||||
absoluteVersion := fmt.Sprintf(
|
||||
"%s.%s.%s",
|
||||
commitInfo.DateString(),
|
||||
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(
|
||||
"Emacs.%s.%s.%s",
|
||||
version,
|
||||
sanitizeString(osInfo.Name+"-"+osInfo.DistinctVersion()),
|
||||
sanitizeString(osInfo.Arch),
|
||||
absoluteVersion,
|
||||
sanitize.String(osInfo.Name+"-"+osInfo.DistinctVersion()),
|
||||
sanitize.String(osInfo.Arch),
|
||||
)
|
||||
diskImage := buildName + ".dmg"
|
||||
|
||||
@@ -97,7 +118,8 @@ func Create(ctx context.Context, opts *Options) (*Plan, error) {
|
||||
OS: osInfo,
|
||||
Release: &Release{
|
||||
Name: releaseName,
|
||||
Prerelease: true,
|
||||
Prerelease: channel != release.Stable,
|
||||
Channel: channel,
|
||||
},
|
||||
Output: &Output{
|
||||
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 != "" {
|
||||
testName := sanitizeString(opts.TestBuild)
|
||||
testName := sanitize.String(opts.TestBuild)
|
||||
|
||||
plan.Build.Name += ".test." + testName
|
||||
plan.Release.Title = "Test Builds"
|
||||
plan.Release.Title = "Test Builds (" + testName + ")"
|
||||
plan.Release.Name = "test-builds"
|
||||
|
||||
plan.Release.Prerelease = true
|
||||
plan.Release.Draft = false
|
||||
if opts.TestBuildType == Draft {
|
||||
plan.Release.Prerelease = false
|
||||
plan.Release.Draft = true
|
||||
plan.Release.Prerelease = false
|
||||
plan.Release.Draft = true
|
||||
if opts.TestBuildType == Prerelease {
|
||||
plan.Release.Prerelease = true
|
||||
plan.Release.Draft = false
|
||||
}
|
||||
|
||||
index := strings.LastIndex(diskImage, ".")
|
||||
@@ -137,6 +149,35 @@ func Create(ctx context.Context, opts *Options) (*Plan, error) {
|
||||
return plan, nil
|
||||
}
|
||||
|
||||
func sanitizeString(s string) string {
|
||||
return nonAlphaNum.ReplaceAllString(s, "-")
|
||||
func parseGitRef(ref string) (string, release.Channel, error) {
|
||||
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
421
pkg/plan/create_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"os"
|
||||
|
||||
"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"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
@@ -78,10 +79,11 @@ type Build struct {
|
||||
}
|
||||
|
||||
type Release struct {
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Title string `yaml:"title,omitempty" json:"title,omitempty"`
|
||||
Draft bool `yaml:"draft,omitempty" json:"draft,omitempty"`
|
||||
Prerelease bool `yaml:"prerelease,omitempty" json:"prerelease,omitempty"`
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Title string `yaml:"title,omitempty" json:"title,omitempty"`
|
||||
Draft bool `yaml:"draft,omitempty" json:"draft,omitempty"`
|
||||
Prerelease bool `yaml:"prerelease,omitempty" json:"prerelease,omitempty"`
|
||||
Channel release.Channel `yaml:"channel,omitempty" json:"channel,omitempty"`
|
||||
}
|
||||
|
||||
type Output struct {
|
||||
|
||||
11
pkg/release/channel.go
Normal file
11
pkg/release/channel.go
Normal 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"
|
||||
)
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Errors
|
||||
@@ -18,7 +19,7 @@ var (
|
||||
|
||||
var (
|
||||
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) {
|
||||
@@ -26,7 +27,8 @@ func VersionToName(version string) (string, error) {
|
||||
return "", ErrEmptyVersion
|
||||
}
|
||||
|
||||
if stableVersion.MatchString(version) {
|
||||
if stableVersion.MatchString(version) ||
|
||||
strings.HasSuffix(version, "-pretest") {
|
||||
return "Emacs-" + version, nil
|
||||
}
|
||||
|
||||
@@ -34,7 +36,7 @@ func VersionToName(version 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
|
||||
}
|
||||
|
||||
|
||||
@@ -128,3 +128,15 @@ func (s *Repository) ActionRunURL(runID string) string {
|
||||
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 ""
|
||||
}
|
||||
}
|
||||
|
||||
54
pkg/repository/repository_test.go
Normal file
54
pkg/repository/repository_test.go
Normal 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
9
pkg/sanitize/string.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package sanitize
|
||||
|
||||
import "regexp"
|
||||
|
||||
var nonAlphaNum = regexp.MustCompile(`[^\w_-]+`)
|
||||
|
||||
func String(s string) string {
|
||||
return nonAlphaNum.ReplaceAllString(s, "-")
|
||||
}
|
||||
@@ -14,6 +14,7 @@ var DefaultEmacsEntitlements = []string{
|
||||
"com.apple.security.cs.allow-jit",
|
||||
"com.apple.security.network.client",
|
||||
"com.apple.security.cs.disable-library-validation",
|
||||
"com.apple.security.cs.allow-dyld-environment-variables",
|
||||
"com.apple.security.automation.apple-events",
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ var entitlementsTestCases = []struct {
|
||||
"com.apple.security.cs.allow-jit",
|
||||
"com.apple.security.network.client",
|
||||
"com.apple.security.cs.disable-library-validation",
|
||||
"com.apple.security.cs.allow-dyld-environment-variables",
|
||||
"com.apple.security.automation.apple-events",
|
||||
},
|
||||
//nolint:lll
|
||||
@@ -64,6 +65,8 @@ var entitlementsTestCases = []struct {
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||
<true/>
|
||||
<key>com.apple.security.automation.apple-events</key>
|
||||
<true/>
|
||||
</dict>
|
||||
@@ -78,6 +81,7 @@ func TestDefaultEmacsEntitlements(t *testing.T) {
|
||||
"com.apple.security.cs.allow-jit",
|
||||
"com.apple.security.network.client",
|
||||
"com.apple.security.cs.disable-library-validation",
|
||||
"com.apple.security.cs.allow-dyld-environment-variables",
|
||||
"com.apple.security.automation.apple-events",
|
||||
},
|
||||
DefaultEmacsEntitlements,
|
||||
|
||||
Reference in New Issue
Block a user