Documentation
¶
Overview ¶
Package bakepkg provides a fluent API for building macOS installer packages (.pkg). It wraps native macOS tooling like pkgbuild, productbuild, and productsign, while adding advanced features like Gatekeeper quarantine stripping and Apple Notary API integration.
Package installer provides a fluent API for building macOS installer packages (.pkg). It wraps native macOS tooling like pkgbuild, productbuild, and productsign, while adding advanced features like Gatekeeper quarantine stripping and Apple Notary API integration.
The library handles two main types of packages:
- Flat Packages: A basic .pkg file that installs files to /Library/<Name>/<Version>/.
- Distribution Packages: A more complex .pkg that can include a custom user interface (Welcome, Readme, License), domain choices for per-user installation, and multiple internal component packages.
Script Generation:
Install scripts (postinstall, uninstall.sh) are auto-generated from templates. The postinstall script writes /etc/paths.d and /etc/manpaths.d entries so binaries and man pages are discoverable. If SymlinkBinaries is set, symlinks are created in /usr/local/bin/. An uninstall.sh script is included in the payload for clean removal.
When config files are detected (etc/ directory in payload), preupgrade and postupgrade scripts are also generated to back up and restore configuration during upgrades.
Basic Usage (Flat Package):
builder := installer.New().
WithIdentifier("com.example.tool").
WithName("MyTool").
WithVersion("1.0.0").
AddFile("build/mytool", "bin/mytool")
err := builder.Build("MyTool.pkg")
Advanced Usage (Distribution Package with UI and Signing):
builder := installer.New().
WithIdentifier("com.example.tool").
WithName("MyTool").
WithVersion("1.0.0").
AddFile("build/mytool", "bin/mytool").
WithSingleUser(true).
WithSymlinkBinaries(true).
WithDistributionUI(installer.Distribution{
Readme: "docs/README.md",
License: "docs/LICENSE.txt",
}).
WithSigning(installer.Signing{
Identity: "Developer ID Installer: Example (XYZ)",
Notarize: true,
})
err := builder.Build("MyTool-Signed.pkg")
Quarantine Stripping:
When files are downloaded or moved, macOS often attaches a "com.apple.quarantine" extended attribute. If these files are bundled into a package without stripping this attribute, the installed application may trigger "App is damaged" errors. This builder automatically runs 'xattr -d com.apple.quarantine' on all staged files to prevent this issue.
Index ¶
- Constants
- type Builder
- func (b *Builder) AddFile(src, dst string) *Builder
- func (b *Builder) Build(output string) error
- func (b *Builder) Validate() error
- func (b *Builder) WithDebug(debug bool) *Builder
- func (b *Builder) WithDistributionUI(ui Distribution) *Builder
- func (b *Builder) WithIdentifier(id string) *Builder
- func (b *Builder) WithLogger(infof func(format string, args ...any)) *Builder
- func (b *Builder) WithName(name string) *Builder
- func (b *Builder) WithScripts(scripts Scripts) *Builder
- func (b *Builder) WithSigning(signing Signing) *Builder
- func (b *Builder) WithSimulate(simulate bool) *Builder
- func (b *Builder) WithSingleUser(singleUser bool) *Builder
- func (b *Builder) WithSymlinkBinaries(symlink bool) *Builder
- func (b *Builder) WithVerbose(verbose bool) *Builder
- func (b *Builder) WithVersion(version string) *Builder
- type Distribution
- type Options
- type ScriptData
- type Scripts
- type Signing
Examples ¶
Constants ¶
const ( InstallLocationLibrary = "/Library" InstallLocationUserLibrary = "~/Library" )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
Builder orchestrates the creation of a macOS package. It uses a fluent interface for configuration.
func (*Builder) AddFile ¶
AddFile adds a file mapping to the package. src is the local file path, and dst is the target path. If dst is relative (doesn't start with /), it is inferred based on Name, Version, and InstallLocation.
func (*Builder) Build ¶
Build compiles the package according to the builder's configuration and writes it to the specified output path.
Example (Distribution) ¶
package main
import (
"al.essio.dev/cmd/bakepkg/installer"
"fmt"
"os"
)
func main() {
// Create dummy files and resources for this example
_ = os.MkdirAll("testdata/resources", 0755)
_ = os.WriteFile("testdata/app", []byte("binary data"), 0755)
_ = os.WriteFile("testdata/resources/readme.txt", []byte("readme content"), 0644)
defer os.RemoveAll("testdata")
// Configure the builder
builder := installer.New().
WithIdentifier("com.example.app").
WithName("MyApp").
WithVersion("2.5.0").
AddFile("testdata/app", "bin/myapp").
WithDistributionUI(installer.Distribution{
Readme: "testdata/resources/readme.txt",
}).
WithSimulate(true).
WithLogger(func(format string, args ...any) {
fmt.Printf(format+"\n", args...)
})
// Build the package
if err := builder.Build("awesome.pkg"); err != nil {
fmt.Printf("Build failed: %v\n", err)
}
}
Output:
Example (Flat) ¶
package main
import (
"al.essio.dev/cmd/bakepkg/installer"
"fmt"
"os"
)
func main() {
// Create dummy files to bundle for this example
_ = os.MkdirAll("testdata", 0755)
_ = os.WriteFile("testdata/hello", []byte("hello world"), 0755)
defer os.RemoveAll("testdata")
// Configure the builder — no explicit install location or scripts needed
builder := installer.New().
WithIdentifier("com.example.hello").
WithName("Hello").
WithVersion("1.0.0").
AddFile("testdata/hello", "bin/hello").
WithSimulate(true).
WithLogger(func(format string, args ...any) {
fmt.Printf(format+"\n", args...)
})
// Build the package — install location and scripts are auto-generated
if err := builder.Build("hello.pkg"); err != nil {
fmt.Printf("Build failed: %v\n", err)
}
}
Output:
func (*Builder) WithDebug ¶
WithDebug sets whether the builder should provide debug output (e.g., raw command output).
func (*Builder) WithDistributionUI ¶
func (b *Builder) WithDistributionUI(ui Distribution) *Builder
WithDistributionUI configures the Distribution XML UI elements (Welcome, Readme, License, Backgrounds).
func (*Builder) WithIdentifier ¶
WithIdentifier sets the package identifier (e.g., com.example.app).
func (*Builder) WithLogger ¶
WithLogger sets the logging function for the builder.
func (*Builder) WithName ¶
WithName sets the application name (required, used for install prefix and paths.d).
func (*Builder) WithScripts ¶
WithScripts configures custom install scripts for the package. When set, these override the auto-generated scripts.
func (*Builder) WithSigning ¶
WithSigning configures the Developer ID signing identity and optional Notarization credentials.
func (*Builder) WithSimulate ¶
WithSimulate sets whether the builder should simulate the build process without actually executing it.
func (*Builder) WithSingleUser ¶
WithSingleUser sets whether the package should support per-user installation. When true, a distribution package is generated with domain choices (enable_currentUserHome + enable_localSystem).
func (*Builder) WithSymlinkBinaries ¶
WithSymlinkBinaries sets whether the postinstall script should create symlinks in /usr/local/bin/ for each detected binary.
func (*Builder) WithVerbose ¶
WithVerbose sets whether the builder should provide verbose output.
func (*Builder) WithVersion ¶
WithVersion sets the package version (e.g., 1.0.0).
type Distribution ¶
type Distribution struct {
Readme string
License string
Welcome string
Background string
BackgroundDark string
}
Distribution defines the UI elements for a Distribution package. Providing any of these will automatically convert a flat package into a Distribution package.
type Options ¶
type Options struct {
Identifier string
Name string
Version string
InstallLocation string // computed internally: always /Library
Files map[string]string // Source -> Destination
Scripts Scripts
DistributionUI Distribution
Signing Signing
SingleUser bool
SymlinkBinaries bool
Verbose bool
Debug bool
Simulate bool
Infof func(format string, args ...any)
}
Options holds the configuration for the macOS package.
type ScriptData ¶
type ScriptData struct {
Identifier string
Name string
Version string
InstallPrefix string // e.g. /Library/MyTool/1.2.0
Binaries []string // auto-detected from files → bin/*
HasManPages bool
ManPrefix string // e.g. /Library/MyTool/1.2.0/share/man
HasConfig bool
ConfigDir string // e.g. /Library/MyTool/1.2.0/etc
SymlinkBinaries bool
}
ScriptData holds the template data model for script generation.