An open API service indexing awesome lists of open source software.

https://github.com/alexykn/sps2

atomic package manager for macos
https://github.com/alexykn/sps2

macos package-manager rust state-management

Last synced: 12 months ago
JSON representation

atomic package manager for macos

Awesome Lists containing this project

README

          

# sps2

A modern, atomic package manager for macOS ARM64 with rollback capabilities and hermetic builds.

## Early Development Notice

**This project is in the early stages of development.** It is not yet recommended for production use. The API, package format, and internal architecture are still subject to change. There is no public package repository yet.

### Current Status

- ✅ **Working**: `install`, `uninstall`, `rollback`, `history`, `list`, `vulndb update`, `check-health`
- 🚧 **In Progress**: `draft` and `build` (functional but incomplete)
- ⚠️ **Untested**: `update`, `upgrade`, `info`, `search`, `reposync`, `cleanup`, `audit`, `self-update`

## Features

- 🔄 **Atomic Updates** - All package operations are atomic with instant rollback
- 📦 **Content-Addressed Storage** - Deduplication via BLAKE3 hashing
- 🏗️ **Hermetic Builds** - Reproducible builds in isolated environments
- 🔐 **Security First** - Minisign signatures, SBOM generation, CVE scanning
- 🚀 **Fast & Parallel** - Concurrent downloads and installations
- 🎯 **Single Prefix** - Clean design with everything in `/opt/pm/live/`
- 🐍 **Python-Style Versions** - Familiar version constraints (`>=1.2.0,<2.0.0`)
- 📝 **YAML Recipes** - Declarative, staged build definitions

## Installation

### Prerequisites

- macOS with Apple Silicon
- Rust 1.87.0 or later
- SQLite 3.x
- sudo access for `/opt/pm` directory

### Build from Source

```bash
# Clone the repository
git clone https://github.com/yourusername/sps2.git
cd sps2

# Build the project
cargo build --release

# Run setup script (requires sudo)
sudo ./setup.sh

# Add to PATH in your shell config
echo 'export PATH="/opt/pm/live/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc

# Verify installation
sps2 --version
```

## Quick Start

### Installing Packages

**Some working .sp packages in the test_build/ dir. Layout is messy, will eventually clean that up.**

```bash
# Install from repository (when available)
sps2 install jq

# Install specific version
sps2 install "jq==1.7"

# Install with version constraints
sps2 install "curl>=8.0.0,<9.0.0"

# Install from local .sp file
sps2 install ./package-1.0.0-1.arm64.sp

# Build and install
sps2 build my-package.yml

# Build without installing
sps2 build my-package.yml -o ./packages/
```

### Generating Build Recipes

Use the `draft` command to automatically generate recipes:

```bash
# From a Git repository
sps2 draft -g "https://github.com/BurntSushi/ripgrep"

# From a source archive URL
sps2 draft -u "https://example.com/package-1.0.tar.gz"

# From a local directory
sps2 draft -p ./my-project

# From a local archive
sps2 draft -a ./my-archive.tar.gz

# Specify output file
sps2 draft -g "https://github.com/helix-editor/helix" -o helix.yml
```

### Building Packages

Example recipe for ripgrep (generated by `draft`):

```yaml
metadata:
name: ripgrep
version: "14.1.1"
description: "Line-oriented search tool that recursively searches for regex patterns"
license: "MIT"
homepage: "https://github.com/BurntSushi/ripgrep"

environment:
network: true # Cargo needs network for dependencies

source:
git:
url: "https://github.com/BurntSushi/ripgrep"
ref: "14.1.1"

build:
system: cargo
args: ["--release"]
```

Build with various options:

```bash
# Basic build
sps2 build ripgrep.yml

# Build with custom output directory
sps2 build ripgrep.yml -o ./packages/

# Build with maximum compression
sps2 build ripgrep.yml --max

# Build with custom job count
sps2 build ripgrep.yml -j 8
```

### Managing Packages

```bash
# List installed packages
sps2 list

# Example output:
# ┌─────────┬─────────┬───────────┬─────────────┐
# │ Package ┆ Version ┆ Status ┆ Description │
# ╞═════════╪═════════╪═══════════╪═════════════╡
# │ bat ┆ 0.25.0 ┆ Installed ┆ - │
# ├╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌┤
# │ helix ┆ 25.1.1 ┆ Installed ┆ - │
# ├╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌┤
# │ ripgrep ┆ 14.1.1 ┆ Installed ┆ - │
# └─────────┴─────────┴───────────┴─────────────┘

# Show package info
sps2 info jq

# Search for packages
sps2 search rust

# Update packages (respects version constraints)
sps2 update

# Upgrade to latest versions
sps2 upgrade curl

# Uninstall packages
sps2 uninstall jq
```

### State Management

```bash
# View state history
sps2 history

# Example output:
# ┌────────────────────────┬─────────┬───────────┬──────────────────┬──────────┐
# │ State ID ┆ Current ┆ Operation ┆ Created ┆ Packages │
# ╞════════════════════════╪═════════╪═══════════╪══════════════════╪══════════╡
# │ 48b6f85f-78bb-4dc5-... ┆ * ┆ install ┆ 2025-06-13 16:12 ┆ 4 │
# ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┤
# │ a7be49ca-a976-4f75-... ┆ ┆ install ┆ 2025-06-13 16:11 ┆ 3 │
# └────────────────────────┴─────────┴───────────┴──────────────────┴──────────┘

# Rollback to previous state
sps2 rollback

# Rollback to specific state
sps2 rollback 48b6f85f-78bb-4dc5-9487-a8a60e97423b

# Clean up orphaned packages and old states
sps2 cleanup

# Check system health
sps2 check-health
```

### Security Features

```bash
# Update vulnerability database
sps2 vulndb update

# Show vulnerability database statistics
sps2 vulndb stats

# Audit installed packages for vulnerabilities
sps2 audit

# Audit specific package
sps2 audit --package curl

# Fail on critical vulnerabilities
sps2 audit --fail-on-critical
```

### Repository Management

```bash
# Sync repository index
sps2 reposync

# Update sps2 itself
sps2 self-update
```

## How It Works

sps2 uses an innovative atomic update system:

1. **Content-Addressed Store** - All package files are stored by their BLAKE3 hash
2. **State Directories** - Each system state is a complete filesystem tree
3. **Atomic Swaps** - Updates use APFS clones and atomic renames
4. **Instant Rollback** - Previous states are preserved and can be restored instantly

### Directory Structure

```
/opt/pm/
├── live/ # Current active state (add /opt/pm/live/bin to PATH)
├── store/ # Content-addressed package storage
├── states/ # Historical states for rollback
└── state.sqlite # Package database
```

## Building Your Own Packages

sps2 uses YAML format for package recipes with declarative, staged build definitions. See [Build Script Documentation](BUILD_SCRIPT_DOCUMENTATION.md)

### Example: Rust Application (Helix Editor)

```yaml
metadata:
name: helix
version: "25.1.1"
description: "A post-modern modal text editor"
license: "MIT"
homepage: "https://github.com/helix-editor/helix"

environment:
network: true # Cargo needs network access

source:
git:
url: "https://github.com/helix-editor/helix"
ref: "25.1.1"

build:
system: cargo
args: ["--release"]
```

### Example: Meson Project (pkgconf)

```yaml
metadata:
name: pkgconf
version: "2.4.3"
description: "A system for managing library compile/link flags"
license: "ISC"
homepage: "https://github.com/pkgconf/pkgconf"

source:
git:
url: "https://github.com/pkgconf/pkgconf"
ref: "pkgconf-2.4.3"

build:
system: meson
args: ["--buildtype=release"]
```

### Example: Building from Source Archive

```yaml
# sps2 build recipe for curl
#
# This recipe builds curl from source archive.
# It enables support for OpenSSL, zlib, and nghttp2 (for HTTP/2).

metadata:
name: curl
version: "8.14.1"
description: "Command-line tool for transferring data with URLs"
license: "MIT"
homepage: "https://curl.se"
dependencies:
runtime:
- openssl
- zlib
- nghttp2
- brotli
- libssh2
- libidn2
- libpsl

environment:
defaults: true # Optimized flags for macOS ARM64

source:
fetch:
url: "https://github.com/curl/curl/releases/download/curl-8_14_1/curl-8.14.1.tar.bz2"
checksum:
sha256: "2893f7b7614192c2a4d8289f3d0009798a7c5f5d895011b5e4c0cf910c4a8b1e"

build:
system: cmake
args:
- "-DCMAKE_BUILD_TYPE=Release"
- "-GNinja"
- "-DBUILD_SHARED_LIBS=ON"
- "-DBUILD_STATIC_LIBS=OFF"
- "-DCURL_USE_OPENSSL=ON"
- "-DCURL_ZLIB=ON"
- "-DUSE_NGHTTP2=ON"
- "-DENABLE_IPV6=ON"
- "-DCURL_USE_LIBSSH2=ON"
- "-DUSE_LIBIDN2=ON"
- "-DCURL_BROTLI=ON"
- "-DCURL_USE_LIBPSL=ON"
- "-DBUILD_TESTING=OFF"
- "-DENABLE_CURL_MANUAL=OFF"

post:
patch_rpaths:
style: homebrew # curl needs absolute paths

install:
auto: true
```

## Developer Tools

### Store List (sls) - Debugging Content-Addressed Storage

The `sls` utility is a specialized debugging tool for exploring sps2's content-addressed storage system. It provides ls-like functionality for both the object store and package metadata.

#### Basic Usage

```bash
# List all hash prefix directories (00-ff)
sls

# List objects with a specific hash prefix
sls ff

# List a specific object by partial hash
sls ffff5aa9

# Show full hash without filename mapping
sls --hash ff
```

#### Object Store Exploration

```bash
# Long format with permissions and sizes
sls -l ff

# Example output:
# -r--r--r-- 2.11 KiB ffff5aa98bd51ec0 -> include/c++/15/fenv.h (gcc:15.1.0)
# -r--r--r-- 6.46 KiB ffff1d26e56791c5 -> share/man/man3/SSL_config.3ossl (openssl:3.5.0)

# Recursive listing of entire store
sls -R

# Find all files from a specific package
sls -R | grep "bat:0.25.0"

# Find all Python files
sls -R | grep "\.py "

# Find files by name pattern using ripgrep
sls -R | rg "libcurl.*dylib"

# Find all files from multiple packages
sls -R | rg "(gcc|clang|llvm):"
```

#### Package Directory Exploration

```bash
# List all packages with their names and versions
sls -p

# Example output:
# 0543d3aaf01da99f -> bat:0.25.0
# 098b0c7c800fd65f -> autoconf:2.72.0
# 0c0be36a37e74b78 -> cmake:4.0.3

# List specific package by hash prefix
sls -p 0543

# Long format for packages (shows metadata files)
sls -p -l

# Find packages by name pattern
sls -p | grep "python"

# Find all compiler packages using ripgrep
sls -p | rg "(gcc|clang|llvm|rust)"
```

- **Object Storage**: Files stored by hash in `/opt/pm/store/objects/[first-2-chars]/[full-64-char-hash]`
- **Package Storage**: Package Metadata stored in `/opt/pm/store/packages/[package-hash]/` with files:
- `manifest.toml` - Package metadata and file list
- `files.json` - Detailed file information
- `sbom.spdx.json` - Software Bill of Materials
- **Deduplication**: Multiple packages can reference the same file hash (content deduplication)

## Contributing

We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.

## Documentation

- [Architecture Overview](ARCHITECTURE.md) - Detailed system design
- [Build Script Documentation](BUILD_SCRIPT_DOCUMENTATION.md) - YAML recipe format reference
- [Contributing Guide](CONTRIBUTING.md) - How to contribute
- [Code of Conduct](CODE_OF_CONDUCT.md) - Community guidelines

## Security

- Packages are signed with [Minisign](https://jedisct1.github.io/minisign/) // TODO
- All downloads are verified against BLAKE3 hashes [BLAKE3](https://github.com/BLAKE3-team/BLAKE3)
- SBOM (Software Bill of Materials) generated for every package
- Offline CVE scanning via integrated vulnerability database

## License

BSD 3-Clause License. See [LICENSE.md](LICENSE.md) for details.

## Acknowledgments

sps2 stands on the shoulders of giants:

- [moss & boulder](https://github.com/AerynOS/os-tools) AerynOS - atomic updates, content-addressed storage, stateful package management
- [Homebrew](https://brew.sh/) - Inspiration for macOS-native packaging
- [Ansible](https://www.ansible.com/) - Inspiration for YAML format and shell/command distinction
- [Starlark](https://github.com/bazelbuild/starlark) - Previously used for build recipes

---

*Building the future of package management on macOS, one atomic update at a time.*