mirror of
https://github.com/jimeh/build-emacs-for-macos.git
synced 2026-02-19 10:46:39 +00:00
This serves as an alternative to Homebrew. It should be much more stable and cause less headaches over time for automated builds. There should be no change to the end user experience of using the build script, as it should still work with and use Homebrew by default. Additionally, Nix provides older Apple SDKs, allowing us to run against macOS 11.x SDKs. This allows the resulting Emacs.app builds to be compatible with macOS 11.x and later versions. In testing, this seems to be the case on macOS 11.x (x86_64) and macOS 12.x (arm64).
142 lines
3.4 KiB
Go
142 lines
3.4 KiB
Go
package sign
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/hashicorp/go-hclog"
|
|
)
|
|
|
|
// Emacs signs a Emacs.app application bundle with Apple's codesign utility,
|
|
// using correct default entitlements, and also pre-signing any *.eln files
|
|
// which are in the bundle, as codesign will not detect them as requiring
|
|
// signing even with the --deep flag.
|
|
func Emacs(ctx context.Context, appBundle string, opts *Options) error {
|
|
if !strings.HasSuffix(appBundle, ".app") {
|
|
return fmt.Errorf("%s is not a .app application bundle", appBundle)
|
|
}
|
|
|
|
appBundle, err := filepath.Abs(appBundle)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = os.Stat(appBundle)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
logger := hclog.FromContext(ctx).Named("sign")
|
|
logger.Info("preparing to sign Emacs.app", "app", appBundle)
|
|
|
|
newOpts := *opts
|
|
|
|
if newOpts.EntitlementsFile == "" {
|
|
if newOpts.Entitlements == nil {
|
|
e := Entitlements(DefaultEmacsEntitlements)
|
|
newOpts.Entitlements = &e
|
|
}
|
|
|
|
f, err2 := newOpts.Entitlements.TempFile()
|
|
if err2 != nil {
|
|
return err2
|
|
}
|
|
defer os.Remove(f)
|
|
|
|
newOpts.EntitlementsFile = f
|
|
newOpts.Entitlements = nil
|
|
}
|
|
|
|
err = signElnFiles(ctx, appBundle, &newOpts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = signCLIHelper(ctx, appBundle, &newOpts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Ensure app bundle is signed last, as modifications to the bundle after
|
|
// signing will invalidate the signature. Hence anything within it that
|
|
// needs to be separately signed, has to happen before signing the whole
|
|
// application bundle.
|
|
return Files(ctx, []string{appBundle}, &newOpts)
|
|
}
|
|
|
|
func signElnFiles(ctx context.Context, appBundle string, opts *Options) error {
|
|
logger := hclog.FromContext(ctx).Named("sign")
|
|
|
|
elnFiles, err := elnFiles(appBundle)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(elnFiles) == 0 {
|
|
return nil
|
|
}
|
|
|
|
logger.Info(fmt.Sprintf(
|
|
"found %d native-lisp *.eln files in %s to sign",
|
|
len(elnFiles), filepath.Base(appBundle),
|
|
))
|
|
for _, file := range elnFiles {
|
|
err := Files(ctx, []string{file}, opts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func signCLIHelper(ctx context.Context, appBundle string, opts *Options) error {
|
|
logger := hclog.FromContext(ctx).Named("sign")
|
|
|
|
cliHelper := filepath.Join(appBundle, "Contents", "MacOS", "bin", "emacs")
|
|
fi, err := os.Stat(cliHelper)
|
|
if err != nil && !os.IsNotExist(err) {
|
|
return err
|
|
} else if err == nil && fi.Mode().IsRegular() {
|
|
logger.Info(fmt.Sprintf(
|
|
"found Contents/MacOS/bin/emacs CLI helper script in %s to sign",
|
|
filepath.Base(appBundle),
|
|
))
|
|
|
|
err = Files(ctx, []string{cliHelper}, opts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// elnFiles finds all native-compilation *.eln files within a Emacs.app bundle,
|
|
// excluding any *.eln which should be automatically located by codesign when
|
|
// signing the Emacs.app bundle itself with the --deep flag. Essentially this
|
|
// only returns *.eln files which must be individually signed before signing the
|
|
// app bundle itself.
|
|
func elnFiles(emacsApp string) ([]string, error) {
|
|
var files []string
|
|
walkDirFunc := func(path string, d fs.DirEntry, _ error) error {
|
|
if d.Type().IsRegular() && strings.HasSuffix(path, ".eln") &&
|
|
!strings.Contains(path, ".app/Contents/Frameworks/") {
|
|
files = append(files, path)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
err := filepath.WalkDir(filepath.Join(emacsApp, "Contents"), walkDirFunc)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return files, nil
|
|
}
|