Skip to content

Conversation

@rhatdan
Copy link
Member

@rhatdan rhatdan commented Oct 16, 2025

Fixes #812

This commit adds a mechanism to create self-contained macOS installer packages (.pkg) that bundle Python and all dependencies, eliminating the need for users to install Python separately.

New Features:

  1. PyInstaller Spec File (ramalama.spec)

    • Configures PyInstaller to create standalone executable
    • Bundles all ramalama modules and dependencies
    • Includes configuration files, man pages, and shell completions
    • Creates macOS app bundle structure
  2. Build Script (scripts/build_macos_pkg.sh)

    • Automated build process for macOS .pkg installer
    • Uses PyInstaller to create standalone binary
    • Packages everything into macOS installer format
    • Includes post-install script for PATH configuration
    • Generates installer with welcome/readme/conclusion screens
  3. GitHub Actions Workflow (.github/workflows/build-macos-installer.yml)

    • Automatically builds macOS installer on release
    • Runs on macOS runners with proper dependencies
    • Uploads installer as release asset
    • Generates SHA256 checksums for verification
    • Can be triggered manually for testing
  4. Documentation (docs/MACOS_INSTALL.md)

    • Comprehensive installation guide for macOS users
    • Multiple installation methods documented
    • Troubleshooting section
    • Prerequisites and system requirements
    • Uninstallation instructions
  5. README Update

    • Added macOS installer as primary installation method
    • Links to detailed installation guide

Benefits:

  • No Python installation required for end users
  • Single-click installation experience
  • Includes all dependencies in one package
  • Follows macOS packaging best practices
  • Automatic PATH configuration
  • Professional installer UI with instructions

Installation:
Users can now download RamaLama-VERSION-macOS-Installer.pkg from GitHub Releases and install with a simple double-click or:
sudo installer -pkg RamaLama-*-macOS-Installer.pkg -target /

The installer places files in /usr/local/ following macOS conventions.

Summary by Sourcery

Provide a self-contained macOS installer for RamaLama that bundles Python and all dependencies, complete with automated build script, CI workflow, and user documentation

New Features:

  • Add PyInstaller spec file to build a standalone macOS executable that bundles Python, modules, configs, man pages, and shell completions
  • Introduce a shell script to automate creation of a self-contained .pkg installer with post-install PATH setup and macOS installer UI

CI:

  • Add GitHub Actions workflow to build, checksum, and optionally publish the macOS installer on release or manual trigger

Documentation:

  • Add a detailed macOS installation guide and update README to reference the new installer method

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Oct 16, 2025

Reviewer's Guide

This PR adds a complete self-contained macOS installer workflow by bundling Python and all dependencies into a .pkg, automating its build and release, and updating documentation to surface the new installer as the primary macOS installation method.

Sequence diagram for automated macOS installer build and release

sequenceDiagram
    participant Dev as Developer
    participant GH as GitHub Actions
    participant Runner as macos-latest runner
    participant PyInstaller
    participant Script as build_macos_pkg.sh
    participant Release as GitHub Release
    Dev->>GH: Push release or trigger workflow
    GH->>Runner: Start job
    Runner->>PyInstaller: Build standalone executable
    Runner->>Script: Run build_macos_pkg.sh
    Script->>Runner: Create .pkg installer
    Runner->>Release: Upload installer and checksum
    Dev->>Release: Download installer
Loading

Class diagram for PyInstaller spec and packaging structure

classDiagram
    class Analysis {
      +pathex
      +binaries
      +datas
      +hiddenimports
      +excludes
    }
    class PYZ {
      +pure
      +zipped_data
    }
    class EXE {
      +name
      +debug
      +console
      +upx
    }
    class BUNDLE {
      +name
      +icon
      +bundle_identifier
      +version
      +info_plist
    }
    Analysis --> PYZ
    PYZ --> EXE
    EXE --> BUNDLE
    BUNDLE : creates macOS app bundle
    class Package_Structure {
      +/usr/local/bin/ramalama
      +/usr/local/share/ramalama
      +/usr/local/share/man/man1
      +/usr/local/share/man/man5
      +/usr/local/share/man/man7
      +/usr/local/share/bash-completion/completions
      +/usr/local/share/fish/vendor_completions.d
      +/usr/local/share/zsh/site-functions
    }
Loading

File-Level Changes

Change Details Files
PyInstaller spec for bundling RamaLama with Python and assets into a macOS app bundle
  • Configured Analysis to include code, data files, man pages, and shell completions
  • Defined EXE and BUNDLE targets with macOS plist metadata
  • Excluded unnecessary modules to slim the bundle
ramalama.spec
macOS build script to generate installer package including pre/post-install steps
  • Cleaned previous builds and invoked PyInstaller to produce standalone executable
  • Structured package root with /usr/local/bin, share, man pages, and shell completions
  • Created postinstall script to ensure PATH configuration
  • Assembled .pkg via pkgbuild and productbuild using distribution XML and HTML assets
scripts/build_macos_pkg.sh
GitHub Actions workflow to automate building, checksum generation, and release uploads
  • Checked out code and set up Python 3.11 environment
  • Ran build script and located generated installer
  • Uploaded installer and SHA256 checksum as artifacts
  • Conditionally published assets to GitHub Releases
.github/workflows/build-macos-installer.yml
Added comprehensive macOS installation guide and updated README to highlight installer
  • Authored docs/MACOS_INSTALL.md with installation methods, troubleshooting, and uninstallation
  • Inserted quickstart installer instructions and link to macOS guide in README.md
docs/MACOS_INSTALL.md
README.md

Assessment against linked issues

Issue Objective Addressed Explanation
#812 Provide a self-contained installer for macOS that includes Python and all dependencies, allowing users to install and use ramalama without needing to set up Python manually.
#812 Document the macOS installer and update installation instructions to guide users through the new installation method.
#812 Automate the building and release of the macOS installer package, making it available for download on GitHub Releases.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @rhatdan, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the user experience for macOS users by introducing a self-contained installer package for RamaLama. This new .pkg installer simplifies the installation process by bundling Python and all its dependencies, eliminating the need for users to manually set up their Python environment. The changes include new build scripts, PyInstaller configuration, and comprehensive documentation, making RamaLama easier to install and manage on macOS.

Highlights

  • Self-contained macOS Installer: Introduces a new .pkg installer for macOS that bundles Python and all dependencies, removing the need for users to install Python separately for RamaLama.
  • Automated Build Process: A new build script (scripts/build_macos_pkg.sh) automates the creation of the macOS .pkg installer, encompassing PyInstaller execution, file packaging, and post-installation script generation for PATH configuration.
  • PyInstaller Configuration: A dedicated PyInstaller spec file (ramalama.spec) is added to configure the standalone executable, bundling all necessary modules, configuration files, man pages, and shell completions into a macOS app bundle structure.
  • Comprehensive macOS Documentation: A new docs/MACOS_INSTALL.md file provides a detailed guide for macOS users, covering installation methods, prerequisites, uninstallation, and troubleshooting.
  • README Update: The main README.md is updated to highlight the new macOS installer as the primary and recommended installation method, with a direct link to the detailed guide.
  • GitHub Actions Workflow: A new GitHub Actions workflow (.github/workflows/build-macos-installer.yml) is introduced to automatically build and upload the macOS installer as a release asset on new releases, with manual trigger capability.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/build-macos-installer.yml
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

Blocking issues:

  • An action sourced from a third-party repository on GitHub is not pinned to a full length commit SHA. Pinning an action to a full length commit SHA is currently the only way to use an action as an immutable release. Pinning to a particular SHA helps mitigate the risk of a bad actor adding a backdoor to the action's repository, as they would need to generate a SHA-1 collision for a valid Git object payload. (link)

General comments:

  • The hardcoded version in ramalama.spec (and BUNDLE info_plist) can drift out of sync—consider pulling the version dynamically from your version module instead of repeating it.
  • Modifying users’ ~/.zshrc and ~/.bash_profile in postinstall may feel intrusive—using /etc/paths.d or pkgutil to register /usr/local/bin is more in line with macOS conventions and avoids touching user files.
  • Right now build_macos_pkg.sh installs PyInstaller directly into the global Python—consider isolating build dependencies via a virtualenv, Homebrew, or GitHub Actions cache to avoid polluting the system environment.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The hardcoded version in ramalama.spec (and BUNDLE info_plist) can drift out of sync—consider pulling the version dynamically from your version module instead of repeating it.
- Modifying users’ ~/.zshrc and ~/.bash_profile in postinstall may feel intrusive—using /etc/paths.d or pkgutil to register /usr/local/bin is more in line with macOS conventions and avoids touching user files.
- Right now build_macos_pkg.sh installs PyInstaller directly into the global Python—consider isolating build dependencies via a virtualenv, Homebrew, or GitHub Actions cache to avoid polluting the system environment.

## Individual Comments

### Comment 1
<location> `scripts/build_macos_pkg.sh:35-37` </location>
<code_context>
+mkdir -p "$BUILD_DIR"
+
+# Install PyInstaller if not present
+if ! command -v pyinstaller &> /dev/null; then
+    echo "Installing PyInstaller..."
+    pip3 install pyinstaller
+fi
+
</code_context>

<issue_to_address>
**suggestion (bug_risk):** PyInstaller installation does not check for pip availability.

Check for pip3 before running the installation, and provide a clear error message if it's not available.
</issue_to_address>

### Comment 2
<location> `scripts/build_macos_pkg.sh:45-49` </location>
<code_context>
+pyinstaller ramalama.spec --clean --noconfirm
+
+# Verify build
+if [ ! -f "$PROJECT_ROOT/dist/ramalama" ]; then
+    echo "Error: PyInstaller build failed - executable not found"
+    exit 1
</code_context>

<issue_to_address>
**suggestion:** Executable existence check assumes a specific output path.

PyInstaller's output path can vary based on the spec file, sometimes producing a nested directory. Update the existence check to account for both flat files and directories.

```suggestion
# Verify build
if [ ! -e "$PROJECT_ROOT/dist/ramalama" ] && [ ! -d "$PROJECT_ROOT/dist/ramalama" ]; then
    echo "Error: PyInstaller build failed - executable or directory not found in dist/"
    exit 1
fi
```
</issue_to_address>

### Comment 3
<location> `scripts/build_macos_pkg.sh:97-105` </location>
<code_context>
+# Post-installation script for RamaLama
+
+# Ensure /usr/local/bin is in PATH
+if ! grep -q '/usr/local/bin' ~/.zshrc 2>/dev/null; then
+    echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.zshrc
+fi
+
</code_context>

<issue_to_address>
**suggestion:** Appending PATH to shell rc files may duplicate entries.

To avoid duplicate PATH entries, check if the exact export line exists before appending.

```suggestion
cat > "$SCRIPTS_DIR/postinstall" << 'EOF'
#!/bin/bash
# Post-installation script for RamaLama

# Ensure /usr/local/bin is in PATH
EXPORT_LINE='export PATH="/usr/local/bin:$PATH"'
if ! grep -Fxq "$EXPORT_LINE" ~/.zshrc 2>/dev/null; then
    echo "$EXPORT_LINE" >> ~/.zshrc
fi

```
</issue_to_address>

### Comment 4
<location> `ramalama.spec:20` </location>
<code_context>
+project_root = Path.cwd()
+
+# Collect all ramalama package files
+a = Analysis(
+    ['bin/ramalama'],
+    pathex=[str(project_root)],
</code_context>

<issue_to_address>
**issue (complexity):** Consider refactoring the spec file to use globbing, auto-discovery, and default arguments for improved readability and maintainability.

Here are a few simple refactors that will preserve every bit of functionality while cutting down on boilerplate:

1. Use glob to collect files instead of hard-coding every tuple  
2. Drop all Analysis/EXE/BUNDLE arguments that PyInstaller already defaults to  
3. Collapse your long hidden-imports list by walking the package

```python
from pathlib import Path
import pkgutil
import ramalama

def collect_datas(pattern: str, dest: str):
    return [(str(p), dest) for p in Path().glob(pattern)]

# 1. replace your datas=[… huge list …] with:
datas = (
    collect_datas("shortnames/shortnames.conf", "share/ramalama") +
    collect_datas("docs/ramalama.conf",          "share/ramalama") +
    collect_datas("inference-spec/**/*.json",    "share/ramalama/inference") +
    collect_datas("completions/**/*",            "") +
    collect_datas("docs/*.[157]",                "share/man")
)

# 3. auto-discover all submodules of ramalama
hiddenimports = [
    mod.name
    for _, mod, _ in pkgutil.walk_packages(ramalama.__path__, prefix="ramalama.")
] + ["argcomplete", "yaml", "jsonschema", "jinja2"]

a = Analysis(
    ["bin/ramalama"],
    pathex=[str(Path.cwd())],
    datas=datas,
    hiddenimports=hiddenimports,
    # 2. everything else is default, so we can drop binaries, hookspath, excludes if empty, etc.
)

# likewise trim EXE down to only non-defaults:
exe = EXE(pyz, a.scripts, name="ramalama", upx=True, console=True)

# and BUNDLE can lose icon=None, entitlements_file=None, etc.
app = BUNDLE(exe, name="ramalama.app", bundle_identifier="com.github.containers.ramalama")
```

That single-page spec is functionally identical but far easier to read and maintain.
</issue_to_address>

### Comment 5
<location> `.github/workflows/build-macos-installer.yml:75` </location>
<code_context>
        uses: softprops/action-gh-release@v1
</code_context>

<issue_to_address>
**security (yaml.github-actions.security.third-party-action-not-pinned-to-commit-sha):** An action sourced from a third-party repository on GitHub is not pinned to a full length commit SHA. Pinning an action to a full length commit SHA is currently the only way to use an action as an immutable release. Pinning to a particular SHA helps mitigate the risk of a bad actor adding a backdoor to the action's repository, as they would need to generate a SHA-1 collision for a valid Git object payload.

*Source: opengrep*
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a self-contained macOS installer package for RamaLama, bundling Python and all dependencies. It includes a PyInstaller spec file, a build script, a GitHub Actions workflow, and documentation. The changes aim to simplify the installation process for macOS users. I have provided comments addressing potential issues related to error handling and security.

Comment on lines 46 to 49
if [ ! -f "$PROJECT_ROOT/dist/ramalama" ]; then
echo "Error: PyInstaller build failed - executable not found"
exit 1
fi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

This check only verifies the existence of the executable but doesn't validate the integrity of the build process. It's critical to ensure that the PyInstaller build process completed successfully and didn't encounter any errors during the build. Without a more robust error check, a partially failed build could still produce an executable, leading to unexpected behavior.

Consider adding a check for the PyInstaller return code to ensure it is 0, indicating success.

Suggested change
if [ ! -f "$PROJECT_ROOT/dist/ramalama" ]; then
echo "Error: PyInstaller build failed - executable not found"
exit 1
fi
if [ ! -f "$PROJECT_ROOT/dist/ramalama" ] || [ $? -ne 0 ]; then
echo "Error: PyInstaller build failed - executable not found or build process failed"
exit 1
fi

Comment on lines +231 to +228
echo " 1. Sign the package (recommended for public distribution)"
echo " 2. Upload to GitHub Releases"
echo " 3. Optionally notarize with Apple"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The script provides instructions to sign the package for public distribution, which is a high security concern. However, it does not enforce or automate this step. An unsigned package will trigger Gatekeeper warnings, potentially deterring users from installing the application. It is important to ensure that the signing process is either automated or explicitly required before distribution.

Consider adding a check to verify that the package is signed before it is uploaded to GitHub Releases, or automate the signing process within the script.

@rhatdan rhatdan force-pushed the macos-installer-812 branch from 2fd7a59 to 2f99cc6 Compare October 16, 2025 17:37
Copy link
Member

@ashley-cui ashley-cui left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on a quick read of the code, the script:

  1. Builds ramalama using ramalama.spec with pyinstaller ramalama.spec
  2. Installs the built ramalama binary into /usr/local/bin/ramalama
  3. Installs manpages into /usr/local/share/man
  4. Installs conf files to /usr/local/share/ramalama/
  5. Installsinference-spec/schema/*.json to usr/local/share/ramalama/inference/and Installsinference-spec/engines/* to/usr/local/share/ramalama/inference/`
  6. Installs shell completions

If this is the correct way to build Python binaries, and the locations look right, then this is probably on the right track. I'm not fluent enough in the XML files to pick through all the options set there, but a quick glance at them looks correct. I don't think Ramalama needs entitlements, so we're probably good there, but if you run into any errors, that's the first place I'd check. The other thing is are there any other dependencies or other binaries we want to ship with ramalama?

Last thing, is that this pkginstaller is not signed. This means that the MacOS gatekeeper will flag the ramalama binary and refuse to run it, unless the user goes into settings and manually approves it. I think you'd definitely want to have a signed version in the future.

Comment on lines 35 to 38
if ! command -v pyinstaller &> /dev/null; then
echo "Installing PyInstaller..."
pip3 install pyinstaller
fi
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

personal preference but I wouldn't install build dependencies in the script, I would expect those to be installed beforehand.

Comment on lines +133 to +204
cat > "$BUILD_DIR/distribution.xml" << EOF
<?xml version="1.0" encoding="utf-8"?>
<installer-gui-script minSpecVersion="1">
<title>RamaLama</title>
<organization>com.github.containers</organization>
<domains enable_localSystem="true"/>
<options customize="never" require-scripts="false"/>
<welcome file="welcome.html"/>
<readme file="readme.html"/>
<license file="LICENSE"/>
<conclusion file="conclusion.html"/>
<choices-outline>
<line choice="default">
<line choice="com.github.containers.ramalama"/>
</line>
</choices-outline>
<choice id="default"/>
<choice id="com.github.containers.ramalama" visible="false">
<pkg-ref id="com.github.containers.ramalama"/>
</choice>
<pkg-ref id="com.github.containers.ramalama" version="$VERSION" onConclusion="none">$PKG_NAME</pkg-ref>
</installer-gui-script>
EOF

# Create welcome message
cat > "$BUILD_DIR/welcome.html" << 'EOF'
<!DOCTYPE html>
<html>
<head><title>Welcome to RamaLama</title></head>
<body>
<h1>Welcome to RamaLama Installer</h1>
<p>This installer will install RamaLama, a command-line tool for working with AI LLM models.</p>
<p>RamaLama makes working with AI models simple and straightforward.</p>
</body>
</html>
EOF

# Create readme
cat > "$BUILD_DIR/readme.html" << 'EOF'
<!DOCTYPE html>
<html>
<head><title>RamaLama Information</title></head>
<body>
<h1>About RamaLama</h1>
<p>RamaLama is a command-line tool that facilitates local management and serving of AI Models.</p>
<h2>Requirements</h2>
<ul>
<li>macOS 10.15 or later</li>
<li>Podman or Docker (recommended)</li>
</ul>
<h2>After Installation</h2>
<p>Run <code>ramalama --help</code> to get started.</p>
<p>For more information, visit: https://github.com/containers/ramalama</p>
</body>
</html>
EOF

# Create conclusion
cat > "$BUILD_DIR/conclusion.html" << 'EOF'
<!DOCTYPE html>
<html>
<head><title>Installation Complete</title></head>
<body>
<h1>Installation Complete!</h1>
<p>RamaLama has been successfully installed.</p>
<h2>Next Steps:</h2>
<ol>
<li>Restart your terminal or run: <code>source ~/.zshrc</code></li>
<li>Verify installation: <code>ramalama --version</code></li>
<li>Get help: <code>ramalama --help</code></li>
<li>Pull a model: <code>ramalama pull tinyllama</code></li>
<li>Run a chatbot: <code>ramalama run tinyllama</code></li>
</ol>
<p>Documentation: https://github.com/containers/ramalama</p>
</body>
</html>
EOF
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also personal preference but I feel like these XML files can live as their own files somewhere else, and just be pulled into the script, since having them here makes the script harder to read.

Comment on lines 162 to 167
Or disable Gatekeeper temporarily:

```bash
sudo spctl --master-disable
# Install the package
sudo spctl --master-enable
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bad thing to recommend.


### "Cannot verify developer" warning

macOS may show a security warning for unsigned packages. To bypass:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add a sentence on saying we're working on getting keys to sign it or something, we should not only ship unsigned pkgs.

release:
types: [published]
workflow_dispatch:
inputs:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would also need a inpt or something for manual dispatch, or else the manual run wouldn't know which release to upload the installer to, or what to checkout to build. Needs a followup later on the the script in checkout and upload too if you want to keep the manual dispatch.


## Method 1: Self-Contained Installer Package (Recommended)

The easiest way to install RamaLama on macOS is using our self-contained `.pkg` installer. This method includes Python and all dependencies, so you don't need to install anything else.
Copy link
Member

@ashley-cui ashley-cui Oct 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'd still need to install podman. We can either add podman to the pkginstaller, or document the dependency here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Podman and podman-machine are not fully required, only recommended, You can run most of RamaLama without using containers or even use Docker.

@rhatdan
Copy link
Member Author

rhatdan commented Oct 16, 2025

@mikebonnet PTAL

@rhatdan
Copy link
Member Author

rhatdan commented Oct 16, 2025

@benoitf PTAL

@rhatdan rhatdan force-pushed the macos-installer-812 branch from 2f99cc6 to e2f0bc5 Compare November 3, 2025 13:22
Fixes containers#812

This commit adds a mechanism to create self-contained macOS installer
packages (.pkg) that bundle Python and all dependencies, eliminating
the need for users to install Python separately.

**New Features:**

1. **PyInstaller Spec File** (ramalama.spec)
   - Configures PyInstaller to create standalone executable
   - Bundles all ramalama modules and dependencies
   - Includes configuration files, man pages, and shell completions
   - Creates macOS app bundle structure

2. **Build Script** (scripts/build_macos_pkg.sh)
   - Automated build process for macOS .pkg installer
   - Uses PyInstaller to create standalone binary
   - Packages everything into macOS installer format
   - Includes post-install script for PATH configuration
   - Generates installer with welcome/readme/conclusion screens

3. **GitHub Actions Workflow** (.github/workflows/build-macos-installer.yml)
   - Automatically builds macOS installer on release
   - Runs on macOS runners with proper dependencies
   - Uploads installer as release asset
   - Generates SHA256 checksums for verification
   - Can be triggered manually for testing

4. **Documentation** (docs/MACOS_INSTALL.md)
   - Comprehensive installation guide for macOS users
   - Multiple installation methods documented
   - Troubleshooting section
   - Prerequisites and system requirements
   - Uninstallation instructions

5. **README Update**
   - Added macOS installer as primary installation method
   - Links to detailed installation guide

**Benefits:**
- No Python installation required for end users
- Single-click installation experience
- Includes all dependencies in one package
- Follows macOS packaging best practices
- Automatic PATH configuration
- Professional installer UI with instructions

**Installation:**
Users can now download RamaLama-VERSION-macOS-Installer.pkg from
GitHub Releases and install with a simple double-click or:
  sudo installer -pkg RamaLama-*-macOS-Installer.pkg -target /

The installer places files in /usr/local/ following macOS conventions.

Signed-off-by: Daniel J Walsh <[email protected]>
@rhatdan rhatdan force-pushed the macos-installer-812 branch from e2f0bc5 to f16458d Compare November 3, 2025 13:29
@rhatdan
Copy link
Member Author

rhatdan commented Nov 3, 2025

@engelmi @mikebonnet @ieaves @olliewalsh @benoitf PTAL

I need help in getting this properly signed, but for now we can probably move forward with an unsigned version.

Bottom line on this, is this is all AI built, and I have never really done something like this on a MAC. I am a Linux guy.

@ieaves
Copy link
Collaborator

ieaves commented Nov 6, 2025

@rhatdan I believe we will need an apple developer account for the project in order to generate a signing key. Do we have one for the project yet? If not I can set it up and add the key as a secret in ci.

@rhatdan
Copy link
Member Author

rhatdan commented Nov 6, 2025

I have no idea, @ashley-cui @mikebonnet Thoughts?

@mikebonnet
Copy link
Collaborator

We don't have one yet, but I'll set one up.

@rhatdan
Copy link
Member Author

rhatdan commented Nov 6, 2025

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

provides binary/installer to ease the installation/onboarding of ramalama

4 participants