ComposeFS package integration: Debian/Fedora package support and distribution-specific installation commands
Some checks failed
Compile apt-layer (v2) / compile (push) Has been cancelled

This commit is contained in:
robojerk 2025-07-15 11:18:41 -07:00
parent d01d222b4d
commit 6cd1be1ba1
17 changed files with 1476 additions and 656 deletions

File diff suppressed because it is too large Load diff

142
docs/apt-layer/composefs.md Normal file
View file

@ -0,0 +1,142 @@
# ComposeFS Integration in apt-layer
## TLDR - Quick Reference
### Basic Commands
**Create a ComposeFS image:**
```sh
mkcomposefs <source-dir> <output.img> --digest-store=<object-store-dir>
```
**Mount a ComposeFS image:**
```sh
mount -t composefs -o basedir=<object-store-dir> <output.img> <mountpoint>
# or directly:
mount.composefs <output.img> <mountpoint> -o basedir=<object-store-dir>
```
**Unmount:**
```sh
umount <mountpoint>
```
**Inspect an image:**
```sh
composefs-info ls <image.composefs> # List files
composefs-info objects <image.composefs> # List backing files
composefs-info missing-objects <image.composefs> --basedir=<dir> # Check integrity
composefs-info dump <image.composefs> # Full metadata dump
```
### Quick Example
```sh
# Create image with object store
mkcomposefs /path/to/rootfs myimage.composefs --digest-store=/path/to/objects
# Mount the image
mount -t composefs -o basedir=/path/to/objects myimage.composefs /mnt/composefs
# List contents
composefs-info ls myimage.composefs
# Unmount
umount /mnt/composefs
```
**Note:** In apt-layer, images are typically stored in `/var/lib/apt-layer/images/` with object stores in the same directory. The above example uses generic paths for clarity.
---
## Overview
apt-layer uses [ComposeFS](https://ostreedev.github.io/ostree/composefs/) as its backend for atomic, deduplicated, and efficient filesystem layering—mirroring the approach used by rpm-ostree and Fedora Silverblue. ComposeFS is a Linux filesystem and image format designed for fast, space-efficient, and content-addressed deployment of system images.
**Key Tools:** The ComposeFS project provides a suite of tools including `mkcomposefs` for image creation, `composefs-info` for inspecting images, and `mount.composefs` for mounting. `mount.composefs` can be called directly or used by the standard `mount -t composefs` command.
---
## Commands
The `composefs` package provides the following tools:
| Command | Purpose | Usage |
|---------|---------|-------|
| `mkcomposefs` | Create ComposeFS images | `mkcomposefs <source> <image> --digest-store=<dir>` |
| `composefs-info` | Inspect and manage images | `composefs-info [ls\|objects\|missing-objects\|dump] <image>` |
| `mount.composefs` | Mount images (helper for `mount -t composefs`) | `mount.composefs <image> <mountpoint> -o basedir=<dir>` |
**Important:** There is **no** `composefs` executable. The package name is `composefs`, but the actual tools are `mkcomposefs`, `composefs-info`, and `mount.composefs`.
---
## ComposeFS Workflow in apt-layer
### 1. Image Creation
To create a ComposeFS image from a directory tree:
```sh
mkcomposefs <rootfs-dir> <output.img> --digest-store=<object-store-dir>
```
- `<rootfs-dir>`: Directory containing the root filesystem to layer
- `<output.img>`: Output ComposeFS image (typically ends with `.composefs`). This file contains the image metadata (an EROFS image file)
- `--digest-store=<object-store-dir>`: This option specifies a directory where `mkcomposefs` will copy (or reflink) regular files larger than 64 bytes from `<rootfs-dir>`. These files are content-addressed (named after their `fsverity` digest) and form the "backing store" for the ComposeFS image. This directory is then referenced as the `basedir` during mounting
### 2. Mounting a ComposeFS Image
To mount a ComposeFS image, `apt-layer` can either call `mount.composefs` directly or rely on the kernel's `mount -t composefs` interface, which will invoke `mount.composefs` as a helper.
Using `mount.composefs` directly:
```sh
mount.composefs <output.img> <mountpoint> -o basedir=<object-store-dir>[,basedir=<another-object-store-dir>...]
```
Using the standard `mount` command (which relies on `mount.composefs` as a helper):
```sh
mount -t composefs -o basedir=<object-store-dir>[,basedir=<another-object-store-dir>...] <output.img> <mountpoint>
```
- `<output.img>`: Path to the ComposeFS image file (metadata)
- `<mountpoint>`: Where to mount the filesystem
- `-o basedir=<object-store-dir>`: This option is crucial. It points to the directory (or multiple colon-separated directories) containing the content-addressed backing files created with `--digest-store` during image creation. This provides the underlying content for the ComposeFS image
**Optional `mount.composefs` options:**
- `digest=DIGEST`: Validates the image file against a specified `fs-verity` digest for integrity
- `verity`: Ensures all files in the image and base directories have matching `fs-verity` digests. Requires kernel 6.6rc1+
- `idmap=PATH`: Specifies a user namespace for ID mapping
- `upperdir`/`workdir`: Allows for a writable overlay on top of the read-only ComposeFS image, similar to `overlayfs`
### 3. Unmounting
```sh
umount <mountpoint>
```
### 4. Listing and Removing Images
- **Listing:** apt-layer lists ComposeFS images by scanning for `.composefs` files in its workspace. Additionally, `apt-layer` can use `composefs-info ls <image.composefs>` to inspect the contents of an image, or `composefs-info missing-objects <image.composefs> --basedir=<object-store-dir>` to verify the integrity of the object store. For advanced scenarios, `composefs-info dump` can provide a textual representation of the image's metadata (as defined by `composefs-dump(5)`), which can also be used as input for `mkcomposefs --from-file`
- **Removing:** apt-layer removes images by deleting the corresponding `.composefs` file and cleaning up the associated content-addressed files in the `--digest-store` directory. This cleanup typically involves checking `composefs-info objects` to identify files that are no longer referenced by any active images before removal
---
## Integration Notes
- **Specific Tools:** While there isn't a single monolithic `composefs` CLI, specialized commands like `composefs-info` exist for introspection, and `mount.composefs` is the dedicated helper for mounting (callable directly or via `mount -t composefs`)
- **Dependencies:** apt-layer requires `mkcomposefs`, `composefs-info`, `mount.composefs` (which might be part of the `composefs` package), `mksquashfs`, and `unsquashfs` for ComposeFS support
- **Fallback:** If `mkcomposefs` (and potentially `mount.composefs`) is not available, apt-layer can fall back to a shell script alternative (for development/testing only)
- **Compatibility:** This approach matches rpm-ostree and Fedora Silverblue's use of ComposeFS for system layering
---
## References
- [ComposeFS Upstream Documentation](https://ostreedev.github.io/ostree/composefs/)
- [ComposeFS GitHub Repository](https://github.com/containers/composefs)
- [ComposeFS Blog Post by Alexander Larsson](https://blogs.gnome.org/alexl/2022/06/02/using-composefs-in-ostree/)
- [`mkcomposefs(1)` man page](https://www.mankier.com/1/mkcomposefs)
- [`mount.composefs(1)` man page](https://www.mankier.com/1/mount.composefs)
- [`composefs-info(1)` man page](https://www.mankier.com/1/composefs-info)
- [`composefs-dump(5)` man page](https://www.mankier.com/5/composefs-dump)

0
docs/apt-layer/skopeo.md Normal file
View file

View file

@ -1,3 +1,47 @@
# Embedded dependencies.json
APT_LAYER_DEPENDENCIES_JSON=$(cat << 'EOF'
{
"core": [
"chroot", "apt-get", "dpkg", "jq", "mount", "umount", "findmnt", "numfmt"
],
"container": [
"podman", "docker"
],
"oci": [
"skopeo"
],
"composefs": [
"mkcomposefs", "composefs-info", "mount.composefs", "mksquashfs", "unsquashfs"
],
"composefs_packages": [
"composefs", "libcomposefs1"
],
"bootloader": [
"efibootmgr", "grub-install", "update-grub", "bootctl"
],
"security": [
"curl", "wget", "gpg"
],
"package_install_commands": {
"debian": {
"composefs": "apt install -y composefs libcomposefs1",
"container": "apt install -y podman docker.io",
"oci": "apt install -y skopeo",
"bootloader": "apt install -y efibootmgr grub-common systemd-boot",
"core": "apt install -y squashfs-tools jq coreutils util-linux"
},
"fedora": {
"composefs": "dnf install -y composefs composefs-libs",
"container": "dnf install -y podman docker",
"oci": "dnf install -y skopeo",
"bootloader": "dnf install -y efibootmgr grub2-tools systemd-boot",
"core": "dnf install -y squashfs-tools jq coreutils util-linux"
}
}
}
EOF
)
#!/bin/bash
# apt-layer Installation Script
@ -78,47 +122,83 @@ check_root() {
fi
}
# --- BEGIN DEPENDENCY JSON LOADING ---
# The dependencies JSON will be embedded as APT_LAYER_DEPENDENCIES_JSON in the compiled script.
APT_LAYER_DEPENDENCIES_JSON="${APT_LAYER_DEPENDENCIES_JSON:-}
{
\"core\": [\"chroot\", \"apt-get\", \"dpkg\", \"jq\", \"mount\", \"umount\", \"findmnt\", \"numfmt\"],
\"container\": [\"podman\", \"docker\"],
\"oci\": [\"skopeo\"],
\"composefs\": [\"mkcomposefs\", \"composefs-info\", \"mount.composefs\", \"mksquashfs\", \"unsquashfs\"],
\"bootloader\": [\"efibootmgr\", \"grub-install\", \"update-grub\", \"bootctl\"],
\"security\": [\"curl\", \"wget\", \"gpg\"]
}"
get_deps_for_type() {
local type="$1"
local json="$APT_LAYER_DEPENDENCIES_JSON"
case "$type" in
core)
echo "$json" | jq -r '.core[]'
;;
security)
echo "$json" | jq -r '.security[]'
;;
all)
echo "$json" | jq -r '.core[], .security[]'
;;
*)
echo "$json" | jq -r '.core[]'
;;
esac
}
print_install_instructions() {
local json="$APT_LAYER_DEPENDENCIES_JSON"
echo " Quick fix for common dependencies:"
echo " sudo apt install -y squashfs-tools jq coreutils util-linux skopeo"
echo ""
echo " For container support (choose one):"
echo " sudo apt install -y podman # or"
echo " sudo apt install -y docker.io"
echo ""
echo " For bootloader support:"
echo " sudo apt install -y efibootmgr grub-common systemd-boot"
echo ""
echo " For more information, run: apt-layer --help"
echo ""
}
# Function to check dependencies
check_dependencies() {
print_status "Checking dependencies..."
local missing_deps=()
# Check for curl or wget
# Installer-specific dependencies
local installer_deps=("sudo" "dos2unix")
# Use JSON to get core and security deps
local deps=( $(get_deps_for_type all) )
# Add installer deps
deps+=("sudo" "dos2unix")
# Check for curl or wget (at least one)
if ! command -v curl >/dev/null 2>&1 && ! command -v wget >/dev/null 2>&1; then
missing_deps+=("curl or wget")
fi
# Check for jq
if ! command -v jq >/dev/null 2>&1; then
missing_deps+=("jq")
fi
# Check for dos2unix
if ! command -v dos2unix >/dev/null 2>&1; then
missing_deps+=("dos2unix")
fi
# Check all other deps
for dep in "${deps[@]}"; do
if [[ "$dep" == "curl" || "$dep" == "wget" ]]; then
continue # already checked above
fi
if ! command -v "$dep" >/dev/null 2>&1; then
missing_deps+=("$dep")
fi
done
if [[ ${#missing_deps[@]} -gt 0 ]]; then
print_error "Missing required dependencies: ${missing_deps[*]}"
print_status "Installing missing dependencies..."
# Try to install dependencies
if command -v apt-get >/dev/null 2>&1; then
sudo apt-get update
sudo apt-get install -y "${missing_deps[@]}"
elif command -v dnf >/dev/null 2>&1; then
sudo dnf install -y "${missing_deps[@]}"
elif command -v yum >/dev/null 2>&1; then
sudo yum install -y "${missing_deps[@]}"
else
print_error "Could not automatically install dependencies. Please install manually:"
print_error " ${missing_deps[*]}"
exit 1
fi
print_install_instructions
print_error "Please install missing dependencies and re-run the installer."
exit 1
fi
print_success "All dependencies satisfied"
print_status "All dependencies satisfied"
}
# Function to download apt-layer

View file

@ -7,6 +7,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### [2025-01-28 UTC] - COMPOSEFS PACKAGE INTEGRATION: DEBIAN/FEDORA PACKAGE SUPPORT
- **ComposeFS package integration completed**: Updated apt-layer to properly support official ComposeFS packages from Debian and Fedora repositories.
- **Debian package structure analysis**: Analyzed official Debian ComposeFS packaging from [salsa.debian.org](https://salsa.debian.org/debian/composefs):
- `composefs` package: Contains userspace tools (`mkcomposefs`, `composefs-info`, `mount.composefs`)
- `libcomposefs1` package: Contains runtime library (`libcomposefs.so.1`)
- `libcomposefs-dev` package: Contains development headers and pkg-config files
- **Fedora package structure analysis**: Analyzed official Fedora ComposeFS packaging:
- `composefs` package: Contains userspace tools
- `composefs-libs` package: Contains runtime library
- `composefs-devel` package: Contains development files
- **Dependencies.json enhanced**: Updated `src/apt-layer/config/dependencies.json` with:
- Added `composefs_packages` array with proper package names for each distribution
- Added `package_install_commands` section with distribution-specific installation commands
- Support for both Debian (`composefs`, `libcomposefs1`) and Fedora (`composefs`, `composefs-libs`) packages
- Comprehensive installation commands for all dependency categories (core, composefs, container, oci, bootloader)
- **Dependency checking improved**: Enhanced `src/apt-layer/scriptlets/01-dependencies.sh`:
- Added distribution detection (Debian vs Fedora)
- Dynamic installation command generation based on detected distribution
- Improved `print_install_instructions()` function with distribution-specific commands
- Updated fallback JSON to include new package structure and installation commands
- **Installation instructions enhanced**: Users now get distribution-specific installation commands:
- Debian/Ubuntu: `apt install -y composefs libcomposefs1`
- Fedora/RHEL: `dnf install -y composefs composefs-libs`
- Automatic detection and appropriate command suggestions
- **ComposeFS integration validated**: Confirmed apt-layer's ComposeFS integration follows official packaging:
- Uses correct tool names (`mkcomposefs`, `composefs-info`, `mount.composefs`)
- Proper mounting with `mount -t composefs` and correct options
- Follows official ComposeFS usage patterns from upstream documentation
- **Result**: apt-layer now properly supports official ComposeFS packages from both Debian and Fedora repositories, with distribution-specific installation instructions and proper dependency management.
### [2025-07-14 UTC] - NAMING STANDARDIZATION: REMOVED ALL PARTICLE-OS/UBLUE REFERENCES FROM PATHS
- **Complete path naming standardization**: Removed all references to "particle-os", "particle", "ublue", and "ucore" from path names throughout the entire codebase.
- **Consistent apt-layer naming**: All persistent and runtime paths now use only "apt-layer" naming:
@ -982,4 +1012,93 @@ This project is part of the Particle-OS system tools and follows the same licens
- Overlay and atomic install workflows validated, including rollback readiness.
- **Documentation & Code Quality:**
- Modular scriptlets and compiled script updated to reflect all improvements.
- Overlay and atomic install best practices documented in TODO.
- Overlay and atomic install best practices documented in TODO.
### [2025-07-14 UTC] - DEPENDENCY VALIDATION & INSTALL INSTRUCTIONS IMPROVED
- **Dependency validation improvements:**
- Added `skopeo` as a required dependency for OCI operations.
- Explicitly require `podman` or `docker` for container-based operations (mirroring rpm-ostree).
- Added `findmnt` and `numfmt` to core dependencies for system checks and disk space validation.
- Added bootloader tool checks (`efibootmgr`, `grub-install`, `update-grub`, `bootctl`) for bootloader management commands.
- Updated "Quick fix" and installation instructions to include all required packages:
- `skopeo`, `podman`, `docker.io`, `efibootmgr`, `grub-common`, `systemd-boot`, and all core utilities.
### [2025-07-14 UTC] - REAL COMPOSEFS BINARY INTEGRATION WITH FALLBACK SUPPORT
- **Real ComposeFS binary integration**: Updated all scriptlets to use the actual `composefs` C binary (same as Fedora/rpm-ostree) as the primary backend.
- **Fallback support**: Maintained backward compatibility by falling back to `composefs-alternative.sh` when the real binary is not available.
- **Updated functions**: All ComposeFS operations now prioritize the real binary:
- `composefs_create()` - Creates ComposeFS images using real binary or fallback
- `composefs_mount()` - Mounts ComposeFS images using real binary or fallback
- `composefs_unmount()` - Unmounts ComposeFS images using real binary or fallback
- `composefs_list_images()` - Lists ComposeFS images using real binary or fallback
- `composefs_image_exists()` - Checks image existence using real binary or fallback
- `composefs_remove_image()` - Removes ComposeFS images using real binary or fallback
- `create_composefs_layer()` - Container-based layer creation with real binary support
- OCI integration functions - Export/import with real binary support
- Live overlay functions - Layer creation with real binary support
- **Performance improvement**: Using the real C implementation provides better performance and compatibility with rpm-ostree.
- **Archived composefs-alternative.sh**: The shell script version remains available as a fallback for systems without the real binary.
### [2025-07-14 UTC] - JSON-BASED DEPENDENCY MANAGEMENT SYSTEM IMPLEMENTED
- **Centralized dependency management**: Moved all dependencies to a single `dependencies.json` file for maintainability and consistency.
- **Dynamic dependency checking**: Both `apt-layer.sh` and `install-apt-layer.sh` now use embedded JSON for category-based dependency validation:
- Core dependencies: chroot, apt-get, dpkg, jq, mount, umount, findmnt, numfmt
- Container dependencies: podman, docker (mirrors rpm-ostree model)
- OCI dependencies: skopeo
- ComposeFS dependencies: mksquashfs, unsquashfs
- Bootloader dependencies: efibootmgr, grub-install, update-grub, bootctl
- Security dependencies: curl, wget, gpg
- **Compiler integration**: Updated both `compile.sh` and `compile-installer.sh` to automatically embed `dependencies.json` as `APT_LAYER_DEPENDENCIES_JSON` variable in compiled scripts.
- **Template updates**: Updated `install-apt-layer.template.sh` to use embedded JSON for dependency checks and install instructions.
- **Scriptlet refactoring**: Refactored `01-dependencies.sh` to use `jq` for parsing embedded JSON and extracting relevant dependency groups based on command type.
- **Fallback support**: Maintained fallback dependency definitions in case JSON is not available.
- **Benefits**: Single source of truth for dependencies, easier maintenance, consistent dependency checking across all tools, and dynamic category-based validation.
### [2025-07-14 UTC] - COMPOSEFS INTEGRATION CORRECTED WITH PROPER UPSTREAM USAGE
- **ComposeFS integration corrected**: Fixed all scriptlets to use the correct upstream ComposeFS tools and workflow:
- **Image creation**: Now uses `mkcomposefs <rootfs-dir> <output.img> --digest-store=<object-store-dir>` with proper digest store
- **Mounting**: Now uses `mount -t composefs -o basedir=<object-store-dir> <output.img> <mountpoint>` with correct syntax
- **Unmounting**: Uses standard `umount` command
- **Image management**: Lists images by scanning `.composefs` files, removes by deleting files
- **Updated dependencies**: Added proper ComposeFS tools to dependencies.json:
- `mkcomposefs` - For creating ComposeFS images
- `composefs-info` - For inspecting and managing images
- `mount.composefs` - For mounting (used by mount -t composefs)
- `mksquashfs` and `unsquashfs` - For underlying squashfs operations
- **Documentation**: Created comprehensive `docs/apt-layer/composefs.md` with:
- Correct workflow using `mkcomposefs` and `mount -t composefs`
- Digest store integration for content-addressed files
- Multiple basedir support for complex layering
- Advanced mount options (verity, idmap, upperdir/workdir)
- Integration with `composefs-info` for inspection and management
- **Fallback support**: Maintained backward compatibility with `composefs-alternative.sh` for systems without upstream tools
- **Performance**: Proper upstream integration provides better performance and compatibility with rpm-ostree
### [2025-07-14 UTC] - COMPOSEFS SCRIPTLET CORRECTIONS - ALL COMMANDS FIXED
- **Comprehensive scriptlet corrections**: Fixed all incorrect `composefs` command references throughout the codebase:
- **Container scriptlet (04-container.sh)**: Updated all functions to use proper tools:
- `create_composefs_layer()` - Now uses `mkcomposefs` with `--digest-store`
- `container_remove_layer()` - Now uses file removal instead of non-existent `composefs remove`
- `container_list_layers()` - Now uses `find` to scan `.composefs` files
- `container_layer_info()` - Now uses `composefs-info ls` for inspection
- `container_mount_layer()` - Now uses `mount -t composefs` with proper options
- `container_unmount_layer()` - Now uses `umount` instead of non-existent `composefs unmount`
- **OCI integration scriptlet (06-oci-integration.sh)**: Fixed export/import functions:
- Image existence check now uses `composefs-info ls`
- Mounting now uses `mount -t composefs` with `basedir` option
- Unmounting now uses `umount`
- Image creation now uses `mkcomposefs` with `--digest-store`
- **Live overlay scriptlet (05-live-overlay.sh)**: Fixed layer creation:
- `create_composefs_layer()` now uses `mkcomposefs` with proper object store
- **Dpkg direct install scriptlet (24-dpkg-direct-install.sh)**: Fixed layer creation:
- Now uses `mkcomposefs` with `--digest-store` instead of non-existent `composefs create`
- **Proper tool usage**: All scriptlets now correctly use:
- `mkcomposefs` for image creation (with `--digest-store`)
- `mount -t composefs` for mounting (with `basedir` option)
- `umount` for unmounting
- `composefs-info` for image inspection
- File operations for listing/removing images
- **Fallback support**: Maintained backward compatibility with `composefs-alternative.sh`
- **Consistency**: All scriptlets now follow the same pattern and use the correct upstream tools
### [2025-07-14 UTC] - COMPOSEFS INTEGRATION CORRECTED WITH PROPER UPSTREAM USAGE

View file

@ -89,25 +89,26 @@ if [[ ! -d "$OUTPUT_DIR" ]]; then
mkdir -p "$OUTPUT_DIR"
fi
# Read the template file
print_status "Reading template file..."
template_content=$(cat "$TEMPLATE_FILE")
# Extract the JSON configuration
print_status "Extracting current paths.json configuration..."
current_config=$(cat "$CONFIG_FILE")
# Create the compiled installer
print_status "Compiling installer with embedded configuration..."
# Create the compiled installer by replacing the placeholder using awk
awk -v json="$current_config" '
/PATHS_JSON_PLACEHOLDER/ {
print json
next
}
{ print }
' "$TEMPLATE_FILE" > "$OUTPUT_FILE"
# Embed dependencies.json as a shell variable at the top
DEPENDENCIES_JSON_FILE="$SCRIPT_DIR/config/dependencies.json"
if [[ -f "$DEPENDENCIES_JSON_FILE" ]]; then
DEPENDENCIES_JSON_CONTENT=$(cat "$DEPENDENCIES_JSON_FILE")
{
echo "# Embedded dependencies.json"
echo "APT_LAYER_DEPENDENCIES_JSON=\$(cat << 'EOF'"
echo "$DEPENDENCIES_JSON_CONTENT"
echo "EOF"
echo ")"
echo ""
awk -v json="$(cat "$CONFIG_FILE")" '
/PATHS_JSON_PLACEHOLDER/ { print json; next }
{ print }
' "$TEMPLATE_FILE"
} > "$OUTPUT_FILE"
else
print_error "dependencies.json not found, cannot embed dependencies."
exit 1
fi
# Make it executable
chmod +x "$OUTPUT_FILE"
@ -132,6 +133,7 @@ print_status "Lines of code: $(wc -l < "$OUTPUT_FILE")"
print_status ""
print_status "The compiled install-apt-layer.sh now includes:"
print_status "- Latest paths.json configuration embedded"
print_status "- dependencies.json embedded for dynamic dependency checks"
print_status "- All installation and uninstallation functionality"
print_status "- Dependency checking and installation"
print_status "- System initialization"

View file

@ -285,6 +285,21 @@ fi
"
script_content+=("$config_sourcing")
# Read and embed dependencies.json as a shell variable at the top
update_progress "Embedding: dependencies.json" 8
DEPENDENCIES_JSON_FILE="$SCRIPT_DIR/config/dependencies.json"
if [[ -f "$DEPENDENCIES_JSON_FILE" ]]; then
DEPENDENCIES_JSON_CONTENT=$(cat "$DEPENDENCIES_JSON_FILE")
script_content+=("# Embedded dependencies.json")
script_content+=("APT_LAYER_DEPENDENCIES_JSON=\$(cat << 'EOF'")
script_content+=("$DEPENDENCIES_JSON_CONTENT")
script_content+=("EOF")
script_content+=(")")
script_content+=("")
else
print_warning "dependencies.json not found, using fallback in scriptlet."
fi
# Function to add scriptlet content with error handling
add_scriptlet() {
local scriptlet_name="$1"

View file

@ -9,22 +9,14 @@
"layer_signing": true
},
"container_runtimes": {
"supported": ["skopeo", "podman", "docker", "systemd-nspawn"],
"preference_order": ["skopeo", "podman", "docker", "systemd-nspawn"],
"skopeo": {
"description": "OCI-focused container operations",
"primary_use": "oci_integration"
},
"supported": ["podman", "docker"],
"preference_order": ["podman", "docker"],
"podman": {
"description": "Rootless container runtime",
"description": "Rootless container runtime (default, recommended)",
"primary_use": "general"
},
"docker": {
"description": "Traditional container runtime",
"primary_use": "general"
},
"systemd-nspawn": {
"description": "Systemd-based container runtime",
"description": "Traditional container runtime (fallback)",
"primary_use": "fallback"
}
},

View file

@ -0,0 +1,39 @@
{
"core": [
"chroot", "apt-get", "dpkg", "jq", "mount", "umount", "findmnt", "numfmt"
],
"container": [
"podman", "docker"
],
"oci": [
"skopeo"
],
"composefs": [
"mkcomposefs", "composefs-info", "mount.composefs", "mksquashfs", "unsquashfs"
],
"composefs_packages": [
"composefs", "libcomposefs1"
],
"bootloader": [
"efibootmgr", "grub-install", "update-grub", "bootctl"
],
"security": [
"curl", "wget", "gpg"
],
"package_install_commands": {
"debian": {
"composefs": "apt install -y composefs libcomposefs1",
"container": "apt install -y podman docker.io",
"oci": "apt install -y skopeo",
"bootloader": "apt install -y efibootmgr grub-common systemd-boot",
"core": "apt install -y squashfs-tools jq coreutils util-linux"
},
"fedora": {
"composefs": "dnf install -y composefs composefs-libs",
"container": "dnf install -y podman docker",
"oci": "dnf install -y skopeo",
"bootloader": "dnf install -y efibootmgr grub2-tools systemd-boot",
"core": "dnf install -y squashfs-tools jq coreutils util-linux"
}
}
}

View file

@ -341,9 +341,22 @@ composefs_create() {
log_debug "Creating ComposeFS image: $image_name from $source_dir" "apt-layer"
if ! "$COMPOSEFS_SCRIPT" create "$image_name" "$source_dir"; then
log_error "Failed to create ComposeFS image: $image_name" "apt-layer"
return 1
# Try real mkcomposefs binary first
if command -v mkcomposefs >/dev/null 2>&1; then
# Create object store directory (same directory as image)
local object_store_dir=$(dirname "$image_name")
mkdir -p "$object_store_dir"
if ! mkcomposefs "$source_dir" "$image_name" --digest-store="$object_store_dir"; then
log_error "Failed to create ComposeFS image with mkcomposefs: $image_name" "apt-layer"
return 1
fi
else
# Fallback to composefs-alternative.sh
if ! "$COMPOSEFS_SCRIPT" create "$image_name" "$source_dir"; then
log_error "Failed to create ComposeFS image: $image_name" "apt-layer"
return 1
fi
fi
log_success "ComposeFS image created: $image_name" "apt-layer"
@ -356,9 +369,25 @@ composefs_mount() {
log_debug "Mounting ComposeFS image: $image_name to $mount_point" "apt-layer"
if ! "$COMPOSEFS_SCRIPT" mount "$image_name" "$mount_point"; then
log_error "Failed to mount ComposeFS image: $image_name to $mount_point" "apt-layer"
return 1
# Try real mount with composefs filesystem
if command -v mkcomposefs >/dev/null 2>&1; then
# Create mount point
mkdir -p "$mount_point"
# Determine object store directory (same directory as image for now)
local object_store_dir=$(dirname "$image_name")
# Mount using composefs filesystem type
if ! mount -t composefs -o "basedir=$object_store_dir" "$image_name" "$mount_point"; then
log_error "Failed to mount ComposeFS image with mount: $image_name to $mount_point" "apt-layer"
return 1
fi
else
# Fallback to composefs-alternative.sh
if ! "$COMPOSEFS_SCRIPT" mount "$image_name" "$mount_point"; then
log_error "Failed to mount ComposeFS image: $image_name to $mount_point" "apt-layer"
return 1
fi
fi
log_success "ComposeFS image mounted: $image_name to $mount_point" "apt-layer"
@ -370,9 +399,18 @@ composefs_unmount() {
log_debug "Unmounting ComposeFS image from: $mount_point" "apt-layer"
if ! "$COMPOSEFS_SCRIPT" unmount "$mount_point"; then
log_error "Failed to unmount ComposeFS image from: $mount_point" "apt-layer"
return 1
# Try real umount
if command -v mkcomposefs >/dev/null 2>&1; then
if ! umount "$mount_point"; then
log_error "Failed to unmount ComposeFS image with umount: $mount_point" "apt-layer"
return 1
fi
else
# Fallback to composefs-alternative.sh
if ! "$COMPOSEFS_SCRIPT" unmount "$mount_point"; then
log_error "Failed to unmount ComposeFS image from: $mount_point" "apt-layer"
return 1
fi
fi
log_success "ComposeFS image unmounted from: $mount_point" "apt-layer"
@ -381,17 +419,34 @@ composefs_unmount() {
composefs_list_images() {
log_debug "Listing ComposeFS images" "apt-layer"
"$COMPOSEFS_SCRIPT" list-images
# Try to list images from workspace directory
if command -v mkcomposefs >/dev/null 2>&1; then
# List .composefs files in the workspace
find "$WORKSPACE/images" -name "*.composefs" -type f 2>/dev/null | sed 's|.*/||' | sed 's|\.composefs$||' || true
else
# Fallback to composefs-alternative.sh
"$COMPOSEFS_SCRIPT" list-images
fi
}
composefs_image_exists() {
local image_name="$1"
# Check if image exists by trying to list it
if "$COMPOSEFS_SCRIPT" list-images | grep -q "^$image_name$"; then
return 0
# Check if image exists by looking for the .composefs file
if command -v mkcomposefs >/dev/null 2>&1; then
if [[ -f "$WORKSPACE/images/$image_name.composefs" ]]; then
return 0
else
return 1
fi
else
return 1
# Fallback to composefs-alternative.sh
if "$COMPOSEFS_SCRIPT" list-images | grep -q "^$image_name$"; then
return 0
else
return 1
fi
fi
}
@ -400,9 +455,18 @@ composefs_remove_image() {
log_debug "Removing ComposeFS image: $image_name" "apt-layer"
if ! "$COMPOSEFS_SCRIPT" remove "$image_name"; then
log_error "Failed to remove ComposeFS image: $image_name" "apt-layer"
return 1
# Try real file removal
if command -v mkcomposefs >/dev/null 2>&1; then
if ! rm -f "$WORKSPACE/images/$image_name.composefs"; then
log_error "Failed to remove ComposeFS image file: $image_name" "apt-layer"
return 1
fi
else
# Fallback to composefs-alternative.sh
if ! "$COMPOSEFS_SCRIPT" remove "$image_name"; then
log_error "Failed to remove ComposeFS image: $image_name" "apt-layer"
return 1
fi
fi
log_success "ComposeFS image removed: $image_name" "apt-layer"

View file

@ -1,5 +1,89 @@
#!/bin/bash
# Enhanced dependency checking and validation for Particle-OS apt-layer Tool
# --- BEGIN DEPENDENCY JSON LOADING ---
# The dependencies JSON will be embedded as APT_LAYER_DEPENDENCIES_JSON in the compiled script.
# If not present, fallback to a default minimal set.
APT_LAYER_DEPENDENCIES_JSON="${APT_LAYER_DEPENDENCIES_JSON:-}
{
\"core\": [\"chroot\", \"apt-get\", \"dpkg\", \"jq\", \"mount\", \"umount\", \"findmnt\", \"numfmt\"],
\"container\": [\"podman\", \"docker\"],
\"oci\": [\"skopeo\"],
\"composefs\": [\"mkcomposefs\", \"composefs-info\", \"mount.composefs\", \"mksquashfs\", \"unsquashfs\"],
\"composefs_packages\": [\"composefs\", \"libcomposefs1\"],
\"bootloader\": [\"efibootmgr\", \"grub-install\", \"update-grub\", \"bootctl\"],
\"security\": [\"curl\", \"wget\", \"gpg\"],
\"package_install_commands\": {
\"debian\": {
\"composefs\": \"apt install -y composefs libcomposefs1\",
\"container\": \"apt install -y podman docker.io\",
\"oci\": \"apt install -y skopeo\",
\"bootloader\": \"apt install -y efibootmgr grub-common systemd-boot\",
\"core\": \"apt install -y squashfs-tools jq coreutils util-linux\"
},
\"fedora\": {
\"composefs\": \"dnf install -y composefs composefs-libs\",
\"container\": \"dnf install -y podman docker\",
\"oci\": \"dnf install -y skopeo\",
\"bootloader\": \"dnf install -y efibootmgr grub2-tools systemd-boot\",
\"core\": \"dnf install -y squashfs-tools jq coreutils util-linux\"
}
}
}"
get_deps_for_type() {
local type="$1"
local json="$APT_LAYER_DEPENDENCIES_JSON"
case "$type" in
--container|container)
echo "$json" | jq -r '.core[], .container[]'
;;
--oci|oci)
echo "$json" | jq -r '.core[], .oci[]'
;;
--composefs|composefs)
echo "$json" | jq -r '.core[], .composefs[]'
;;
--bootloader|bootloader)
echo "$json" | jq -r '.core[], .bootloader[]'
;;
--scan|security)
echo "$json" | jq -r '.core[], .security[]'
;;
*)
echo "$json" | jq -r '.core[]'
;;
esac
}
print_install_instructions() {
local json="$APT_LAYER_DEPENDENCIES_JSON"
# Detect distribution
local distro="debian"
if [[ -f /etc/fedora-release ]] || [[ -f /etc/redhat-release ]]; then
distro="fedora"
fi
echo " Quick fix for common dependencies:"
local core_cmd=$(echo "$json" | jq -r ".package_install_commands.$distro.core")
echo " sudo $core_cmd"
echo ""
echo " For ComposeFS support:"
local composefs_cmd=$(echo "$json" | jq -r ".package_install_commands.$distro.composefs")
echo " sudo $composefs_cmd"
echo ""
echo " For container support:"
local container_cmd=$(echo "$json" | jq -r ".package_install_commands.$distro.container")
echo " sudo $container_cmd"
echo ""
echo " For bootloader support:"
local bootloader_cmd=$(echo "$json" | jq -r ".package_install_commands.$distro.bootloader")
echo " sudo $bootloader_cmd"
echo ""
echo " For more information, run: apt-layer --help"
echo ""
}
check_dependencies() {
local command_type="${1:-}"
local packages=("${@:2}")
@ -7,71 +91,28 @@ check_dependencies() {
log_info "Checking dependencies for command: ${command_type:-general}" "apt-layer"
local missing_deps=()
local missing_packages=()
local missing_tools=()
local missing_scripts=()
local missing_modules=()
# Core system dependencies
local core_deps=("chroot" "apt-get" "dpkg" "jq" "mount" "umount")
for dep in "${core_deps[@]}"; do
# Use JSON to get the relevant dependencies
local deps=( $(get_deps_for_type "$command_type") )
for dep in "${deps[@]}"; do
if ! command -v "$dep" >/dev/null 2>&1; then
missing_deps+=("$dep")
missing_tools+=("$dep")
fi
done
# Container-specific dependencies
if [[ "$command_type" == "--container" || "$command_type" == "container" ]]; then
local container_deps=("podman" "docker" "systemd-nspawn")
local found_container=false
for dep in "${container_deps[@]}"; do
if command -v "$dep" >/dev/null 2>&1; then
found_container=true
break
fi
done
if [[ "$found_container" == "false" ]]; then
missing_deps+=("container-runtime")
missing_tools+=("podman, docker, or systemd-nspawn")
fi
fi
# ComposeFS-specific dependencies
if [[ "$command_type" == "--composefs" || "$command_type" == "composefs" ]]; then
local composefs_deps=("mksquashfs" "unsquashfs" "skopeo")
for dep in "${composefs_deps[@]}"; do
if ! command -v "$dep" >/dev/null 2>&1; then
missing_deps+=("$dep")
missing_tools+=("$dep")
fi
done
fi
# Security scanning dependencies
if [[ "$command_type" == "--scan" || "$command_type" == "security" ]]; then
local security_deps=("curl" "wget" "gpg")
for dep in "${security_deps[@]}"; do
if ! command -v "$dep" >/dev/null 2>&1; then
missing_deps+=("$dep")
missing_tools+=("$dep")
fi
done
fi
# Check for required scripts
# Check for required scripts (unchanged)
local required_scripts=(
"composefs-alternative.sh:/usr/local/bin/composefs-alternative.sh"
"bootc-alternative.sh:/usr/local/bin/bootc-alternative.sh"
"bootupd-alternative.sh:/usr/local/bin/bootupd-alternative.sh"
)
for script_info in "${required_scripts[@]}"; do
local script_name="${script_info%%:*}"
local script_path="${script_info##*:}"
if [[ ! -f "$script_path" ]]; then
missing_deps+=("$script_name")
missing_scripts+=("$script_name")
@ -81,10 +122,10 @@ check_dependencies() {
fi
done
# Check for kernel modules
# Check for kernel modules (unchanged)
check_kernel_modules
# Validate package names if provided
# Validate package names if provided (unchanged)
if [[ ${#packages[@]} -gt 0 ]]; then
if ! validate_package_names "${packages[@]}"; then
return 1
@ -96,48 +137,38 @@ check_dependencies() {
echo ""
log_error "Missing dependencies detected!" "apt-layer"
echo ""
if [[ ${#missing_tools[@]} -gt 0 ]]; then
echo "ð¦ Missing system packages:"
echo " Missing system packages:"
for tool in "${missing_tools[@]}"; do
echo " ⢠$tool"
echo " $tool"
done
echo ""
echo " Install with: sudo apt install -y ${missing_tools[*]}"
echo ""
fi
if [[ ${#missing_scripts[@]} -gt 0 ]]; then
echo "ð Missing or non-executable scripts:"
echo " Missing or non-executable scripts:"
for script in "${missing_scripts[@]}"; do
echo " ⢠$script"
echo " $script"
done
echo ""
echo " Ensure scripts are installed and executable:"
echo " sudo chmod +x /usr/local/bin/*-alternative.sh"
echo ""
fi
if [[ ${#missing_modules[@]} -gt 0 ]]; then
echo "ð§ Missing kernel modules:"
echo " Missing kernel modules:"
for module in "${missing_modules[@]}"; do
echo " ⢠$module"
echo " $module"
done
echo ""
echo " Load modules with: sudo modprobe ${missing_modules[*]}"
echo " Or install with: sudo apt install linux-modules-extra-\$(uname -r)"
echo ""
fi
echo "ð¡ Quick fix for common dependencies:"
echo " sudo apt install -y squashfs-tools jq coreutils util-linux"
echo ""
echo "ð For more information, run: apt-layer --help"
echo ""
print_install_instructions
exit 1
fi
log_success "All dependencies found and validated" "apt-layer"
}
@ -265,7 +296,7 @@ show_actionable_error() {
case "$error_type" in
"missing_dependencies")
echo "ð§ To fix this issue:"
echo "<EFBFBD> To fix this issue:"
echo " 1. Install missing dependencies:"
echo " sudo apt update"
echo " sudo apt install -y $packages"
@ -278,7 +309,7 @@ show_actionable_error() {
echo ""
;;
"permission_denied")
echo "ð Permission issue detected:"
echo "<EFBFBD> Permission issue detected:"
echo " This command requires root privileges."
echo ""
echo " Run with sudo:"
@ -286,7 +317,7 @@ show_actionable_error() {
echo ""
;;
"invalid_arguments")
echo "ð Invalid arguments provided:"
echo "<EFBFBD> Invalid arguments provided:"
echo " Check the command syntax and try again."
echo ""
echo " For help, run:"
@ -295,7 +326,7 @@ show_actionable_error() {
echo ""
;;
"system_not_initialized")
echo "ð System not initialized:"
echo "<EFBFBD> System not initialized:"
echo " Particle-OS needs to be initialized first."
echo ""
echo " Run initialization:"
@ -303,7 +334,7 @@ show_actionable_error() {
echo ""
;;
"disk_space")
echo "ð¾ Insufficient disk space:"
echo "<EFBFBD> Insufficient disk space:"
echo " Free up space or use a different location."
echo ""
echo " Check available space:"
@ -311,7 +342,7 @@ show_actionable_error() {
echo ""
;;
*)
echo "â Unknown error occurred."
echo "<EFBFBD> Unknown error occurred."
echo " Please check the error message above."
echo ""
echo " For help, run: apt-layer --help"
@ -319,10 +350,10 @@ show_actionable_error() {
;;
esac
echo "ð For more information:"
echo " ⢠apt-layer --help"
echo " ⢠apt-layer --help-full"
echo " ⢠apt-layer --examples"
echo "<EFBFBD> For more information:"
echo " <EFBFBD> apt-layer --help"
echo " <EFBFBD> apt-layer --help-full"
echo " <EFBFBD> apt-layer --examples"
echo ""
}

View file

@ -33,37 +33,12 @@ detect_container_runtime() {
log_warning "Configured runtime 'docker' not found, falling back to detection" "apt-layer"
fi
;;
systemd-nspawn)
if command -v systemd-nspawn &> /dev/null; then
CONTAINER_RUNTIME="systemd-nspawn"
log_info "Using configured container runtime: systemd-nspawn" "apt-layer"
return 0
else
log_warning "Configured runtime 'systemd-nspawn' not found, falling back to detection" "apt-layer"
fi
;;
skopeo)
if command -v skopeo &> /dev/null; then
CONTAINER_RUNTIME="skopeo"
log_info "Using configured container runtime: skopeo" "apt-layer"
return 0
else
log_warning "Configured runtime 'skopeo' not found, falling back to detection" "apt-layer"
fi
;;
esac
fi
# Auto-detection fallback (in order of preference)
log_info "Auto-detecting container runtime" "apt-layer"
# Check for skopeo first (preferred for OCI operations)
if command -v skopeo &> /dev/null; then
CONTAINER_RUNTIME="skopeo"
log_info "Auto-detected skopeo as container runtime" "apt-layer"
return 0
fi
# Check for podman (preferred for rootless)
if command -v podman &> /dev/null; then
CONTAINER_RUNTIME="podman"
@ -78,14 +53,7 @@ detect_container_runtime() {
return 0
fi
# Check for systemd-nspawn as last resort
if command -v systemd-nspawn &> /dev/null; then
CONTAINER_RUNTIME="systemd-nspawn"
log_info "Auto-detected systemd-nspawn as container runtime" "apt-layer"
return 0
fi
log_error "No supported container runtime found (skopeo, podman, docker, or systemd-nspawn)" "apt-layer"
log_error "No supported container runtime found (podman or docker required)" "apt-layer"
return 1
}
@ -123,10 +91,6 @@ set_global_container_runtime_vars() {
# Set runtime-specific variables
case "$CONTAINER_RUNTIME" in
skopeo)
export CONTAINER_RUNTIME_TYPE="oci"
export CONTAINER_RUNTIME_DESCRIPTION="OCI-focused container operations"
;;
podman)
export CONTAINER_RUNTIME_TYPE="general"
export CONTAINER_RUNTIME_DESCRIPTION="Rootless container runtime"
@ -135,10 +99,6 @@ set_global_container_runtime_vars() {
export CONTAINER_RUNTIME_TYPE="general"
export CONTAINER_RUNTIME_DESCRIPTION="Traditional container runtime"
;;
systemd-nspawn)
export CONTAINER_RUNTIME_TYPE="fallback"
export CONTAINER_RUNTIME_DESCRIPTION="Systemd-based container runtime"
;;
esac
log_debug "Container runtime variables set: $CONTAINER_RUNTIME ($CONTAINER_RUNTIME_TYPE)" "apt-layer"
@ -151,12 +111,6 @@ validate_container_runtime() {
log_info "Validating container runtime: $runtime" "apt-layer"
case "$runtime" in
skopeo)
if ! skopeo --version &> /dev/null; then
log_error "skopeo is not properly configured" "apt-layer"
return 1
fi
;;
podman)
if ! podman info &> /dev/null; then
log_error "podman is not properly configured" "apt-layer"
@ -169,9 +123,6 @@ validate_container_runtime() {
return 1
fi
;;
systemd-nspawn)
# systemd-nspawn doesn't need special validation
;;
*)
log_error "Unsupported container runtime: $runtime" "apt-layer"
return 1
@ -266,10 +217,6 @@ create_base_container_image() {
docker pull "$base_image"
fi
;;
systemd-nspawn)
# systemd-nspawn uses host filesystem
log_info "Using host filesystem for systemd-nspawn" "apt-layer"
;;
esac
log_success "OCI base image ready: $base_image" "apt-layer"
@ -303,12 +250,6 @@ container_install_packages() {
# Run package installation in container
case "$CONTAINER_RUNTIME" in
skopeo)
if ! run_skopeo_install "$base_image" "$container_name" "$temp_dir" "${packages[@]}"; then
rollback_transaction
return 1
fi
;;
podman)
if ! run_podman_install "$base_image" "$container_name" "$temp_dir" "${packages[@]}"; then
rollback_transaction
@ -321,11 +262,10 @@ container_install_packages() {
return 1
fi
;;
systemd-nspawn)
if ! run_nspawn_install "$base_image" "$container_name" "$temp_dir" "${packages[@]}"; then
rollback_transaction
return 1
fi
*)
log_error "Unsupported container runtime: $CONTAINER_RUNTIME" "apt-layer"
rollback_transaction
return 1
;;
esac
@ -585,10 +525,22 @@ create_composefs_layer() {
local image_dir="$WORKSPACE/images/$new_image"
mkdir -p "$image_dir"
# Use ComposeFS backend to create layer
if ! "$COMPOSEFS_SCRIPT" create "$new_image" "$temp_dir"; then
log_error "Failed to create ComposeFS layer" "apt-layer"
return 1
# Try real mkcomposefs binary first
if command -v mkcomposefs >/dev/null 2>&1; then
# Create object store directory (same directory as image)
local object_store_dir=$(dirname "$new_image")
mkdir -p "$object_store_dir"
if ! mkcomposefs "$temp_dir" "$new_image" --digest-store="$object_store_dir"; then
log_error "Failed to create ComposeFS layer with mkcomposefs" "apt-layer"
return 1
fi
else
# Fallback to composefs-alternative.sh
if ! "$COMPOSEFS_SCRIPT" create "$new_image" "$temp_dir"; then
log_error "Failed to create ComposeFS layer" "apt-layer"
return 1
fi
fi
log_success "ComposeFS layer created: $new_image" "apt-layer"
@ -626,10 +578,18 @@ container_remove_layer() {
log_info "Removing container-based layer: $image_name" "apt-layer"
# Use ComposeFS backend to remove layer
if ! "$COMPOSEFS_SCRIPT" remove "$image_name"; then
log_error "Failed to remove ComposeFS layer" "apt-layer"
return 1
# Try real file removal
if command -v mkcomposefs >/dev/null 2>&1; then
if ! rm -f "$WORKSPACE/images/$image_name.composefs"; then
log_error "Failed to remove ComposeFS layer file: $image_name" "apt-layer"
return 1
fi
else
# Fallback to composefs-alternative.sh
if ! "$COMPOSEFS_SCRIPT" remove "$image_name"; then
log_error "Failed to remove ComposeFS layer" "apt-layer"
return 1
fi
fi
log_success "Container-based layer removed: $image_name" "apt-layer"
@ -640,10 +600,16 @@ container_remove_layer() {
container_list_layers() {
log_info "Listing container-based layers" "apt-layer"
# Use ComposeFS backend to list layers
if ! "$COMPOSEFS_SCRIPT" list-images; then
log_error "Failed to list ComposeFS layers" "apt-layer"
return 1
# Try to list images from workspace directory
if command -v mkcomposefs >/dev/null 2>&1; then
# List .composefs files in the workspace
find "$WORKSPACE/images" -name "*.composefs" -type f 2>/dev/null | sed 's|.*/||' | sed 's|\.composefs$||' || true
else
# Fallback to composefs-alternative.sh
if ! "$COMPOSEFS_SCRIPT" list-images; then
log_error "Failed to list ComposeFS layers" "apt-layer"
return 1
fi
fi
return 0
@ -655,10 +621,18 @@ container_layer_info() {
log_info "Getting container-based layer info: $image_name" "apt-layer"
# Use ComposeFS backend to get layer info
if ! "$COMPOSEFS_SCRIPT" info "$image_name"; then
log_error "Failed to get ComposeFS layer info" "apt-layer"
return 1
# Try real composefs-info binary first
if command -v composefs-info >/dev/null 2>&1; then
if ! composefs-info ls "$WORKSPACE/images/$image_name.composefs"; then
log_error "Failed to get ComposeFS layer info with composefs-info" "apt-layer"
return 1
fi
else
# Fallback to composefs-alternative.sh
if ! "$COMPOSEFS_SCRIPT" info "$image_name"; then
log_error "Failed to get ComposeFS layer info" "apt-layer"
return 1
fi
fi
return 0
@ -671,10 +645,25 @@ container_mount_layer() {
log_info "Mounting container-based layer: $image_name at $mount_point" "apt-layer"
# Use ComposeFS backend to mount layer
if ! "$COMPOSEFS_SCRIPT" mount "$image_name" "$mount_point"; then
log_error "Failed to mount ComposeFS layer" "apt-layer"
return 1
# Try real mount with composefs filesystem
if command -v mkcomposefs >/dev/null 2>&1; then
# Create mount point
mkdir -p "$mount_point"
# Determine object store directory (same directory as image)
local object_store_dir=$(dirname "$image_name")
# Mount using composefs filesystem type
if ! mount -t composefs -o "basedir=$object_store_dir" "$image_name" "$mount_point"; then
log_error "Failed to mount ComposeFS layer with mount: $image_name to $mount_point" "apt-layer"
return 1
fi
else
# Fallback to composefs-alternative.sh
if ! "$COMPOSEFS_SCRIPT" mount "$image_name" "$mount_point"; then
log_error "Failed to mount ComposeFS layer" "apt-layer"
return 1
fi
fi
log_success "Container-based layer mounted: $image_name at $mount_point" "apt-layer"
@ -687,10 +676,18 @@ container_unmount_layer() {
log_info "Unmounting container-based layer at: $mount_point" "apt-layer"
# Use ComposeFS backend to unmount layer
if ! "$COMPOSEFS_SCRIPT" unmount "$mount_point"; then
log_error "Failed to unmount ComposeFS layer" "apt-layer"
return 1
# Try real umount
if command -v mkcomposefs >/dev/null 2>&1; then
if ! umount "$mount_point"; then
log_error "Failed to unmount ComposeFS layer with umount: $mount_point" "apt-layer"
return 1
fi
else
# Fallback to composefs-alternative.sh
if ! "$COMPOSEFS_SCRIPT" unmount "$mount_point"; then
log_error "Failed to unmount ComposeFS layer" "apt-layer"
return 1
fi
fi
log_success "Container-based layer unmounted: $mount_point" "apt-layer"
@ -705,10 +702,6 @@ container_status() {
echo "Runtime: $CONTAINER_RUNTIME"
case "$CONTAINER_RUNTIME" in
skopeo)
echo "Skopeo version: $(skopeo --version 2>/dev/null || echo 'Not available')"
echo "Skopeo info: OCI-focused container operations"
;;
podman)
echo "Podman version: $(podman --version 2>/dev/null || echo 'Not available')"
echo "Podman info: $(podman info --format json 2>/dev/null | jq -r '.host.arch // "Unknown"' 2>/dev/null || echo 'Unknown')"
@ -717,9 +710,6 @@ container_status() {
echo "Docker version: $(docker --version 2>/dev/null || echo 'Not available')"
echo "Docker info: $(docker info --format '{{.Architecture}}' 2>/dev/null || echo 'Unknown')"
;;
systemd-nspawn)
echo "systemd-nspawn version: $(systemd-nspawn --version 2>/dev/null || echo 'Not available')"
;;
esac
echo ""

View file

@ -441,7 +441,19 @@ create_composefs_layer() {
local layer_name="$2"
local message="$3"
# Use composefs-alternative to create layer
# Try real mkcomposefs binary first
if command -v mkcomposefs >/dev/null 2>&1; then
# Create object store directory (same directory as layer)
local object_store_dir=$(dirname "$layer_name")
mkdir -p "$object_store_dir"
if mkcomposefs "$source_dir" "$layer_name" --digest-store="$object_store_dir"; then
log_success "ComposeFS layer created using mkcomposefs" "apt-layer"
return 0
fi
fi
# Fallback to composefs-alternative
if command -v composefs-alternative >/dev/null 2>&1; then
if composefs-alternative create-layer "$source_dir" "$layer_name" "$message"; then
return 0

View file

@ -1,6 +1,6 @@
#!/bin/bash
# OCI Integration for Particle-OS apt-layer Tool
# Provides ComposeFS â OCI export/import functionality for container-based layer creation
# Provides ComposeFS <EFBFBD> OCI export/import functionality for container-based layer creation
# OCI registry configuration
declare -A OCI_REGISTRY_CONFIG
@ -108,9 +108,16 @@ export_oci_image() {
fi
# Check if ComposeFS image exists
if ! "$COMPOSEFS_SCRIPT" info "$composefs_image" >/dev/null 2>&1; then
log_error "ComposeFS image not found: $composefs_image" "apt-layer"
return 1
if command -v composefs-info >/dev/null 2>&1; then
if ! composefs-info ls "$composefs_image" >/dev/null 2>&1; then
log_error "ComposeFS image not found: $composefs_image" "apt-layer"
return 1
fi
else
if ! "$COMPOSEFS_SCRIPT" info "$composefs_image" >/dev/null 2>&1; then
log_error "ComposeFS image not found: $composefs_image" "apt-layer"
return 1
fi
fi
# Create temporary directory
@ -125,10 +132,21 @@ export_oci_image() {
mkdir -p "$mount_point"
update_transaction_phase "mounting_composefs_image"
if ! "$COMPOSEFS_SCRIPT" mount "$composefs_image" "$mount_point"; then
log_error "Failed to mount ComposeFS image: $composefs_image" "apt-layer"
rollback_transaction
return 1
if command -v mkcomposefs >/dev/null 2>&1; then
# Determine object store directory (same directory as image)
local object_store_dir=$(dirname "$composefs_image")
if ! mount -t composefs -o "basedir=$object_store_dir" "$composefs_image" "$mount_point"; then
log_error "Failed to mount ComposeFS image: $composefs_image" "apt-layer"
rollback_transaction
return 1
fi
else
if ! "$COMPOSEFS_SCRIPT" mount "$composefs_image" "$mount_point"; then
log_error "Failed to mount ComposeFS image: $composefs_image" "apt-layer"
rollback_transaction
return 1
fi
fi
# Create OCI image structure
@ -151,7 +169,11 @@ export_oci_image() {
fi
# Unmount ComposeFS image
"$COMPOSEFS_SCRIPT" unmount "$mount_point" 2>/dev/null || true
if command -v mkcomposefs >/dev/null 2>&1; then
umount "$mount_point" 2>/dev/null || true
else
"$COMPOSEFS_SCRIPT" unmount "$mount_point" 2>/dev/null || true
fi
commit_transaction
log_success "ComposeFS image exported to OCI: $oci_image_name" "apt-layer"
@ -367,10 +389,22 @@ import_oci_image() {
# Create ComposeFS image from extracted filesystem
update_transaction_phase "creating_composefs_image"
if ! "$COMPOSEFS_SCRIPT" create "$composefs_image" "$rootfs_dir"; then
log_error "Failed to create ComposeFS image: $composefs_image" "apt-layer"
rollback_transaction
return 1
if command -v mkcomposefs >/dev/null 2>&1; then
# Create object store directory (same directory as image)
local object_store_dir=$(dirname "$composefs_image")
mkdir -p "$object_store_dir"
if ! mkcomposefs "$rootfs_dir" "$composefs_image" --digest-store="$object_store_dir"; then
log_error "Failed to create ComposeFS image: $composefs_image" "apt-layer"
rollback_transaction
return 1
fi
else
if ! "$COMPOSEFS_SCRIPT" create "$composefs_image" "$rootfs_dir"; then
log_error "Failed to create ComposeFS image: $composefs_image" "apt-layer"
rollback_transaction
return 1
fi
fi
commit_transaction
@ -540,9 +574,9 @@ oci_status() {
echo "=== OCI Tool Configuration ==="
echo "Preferred tool: $OCI_TOOL"
echo "Available tools:"
command -v skopeo &> /dev/null && echo " â skopeo"
command -v podman &> /dev/null && echo " â podman"
command -v docker &> /dev/null && echo " â docker"
command -v skopeo &> /dev/null && echo " <EFBFBD> skopeo"
command -v podman &> /dev/null && echo " <EFBFBD> podman"
command -v docker &> /dev/null && echo " <EFBFBD> docker"
echo ""
echo "=== OCI Workspace ==="

View file

@ -153,12 +153,6 @@ container_dpkg_install() {
# Run dpkg installation in container
case "$CONTAINER_RUNTIME" in
skopeo)
if ! run_skopeo_dpkg_install "$base_image" "$container_name" "$temp_dir" "${packages[@]}"; then
rollback_transaction
return 1
fi
;;
podman)
if ! run_podman_dpkg_install "$base_image" "$container_name" "$temp_dir" "${packages[@]}"; then
rollback_transaction
@ -171,12 +165,6 @@ container_dpkg_install() {
return 1
fi
;;
systemd-nspawn)
if ! run_nspawn_dpkg_install "$base_image" "$container_name" "$temp_dir" "${packages[@]}"; then
rollback_transaction
return 1
fi
;;
*)
log_error "Unsupported container runtime: $CONTAINER_RUNTIME" "apt-layer"
rollback_transaction
@ -191,12 +179,25 @@ container_dpkg_install() {
return 1
fi
else
# Fallback: use composefs-alternative.sh
log_info "Using fallback ComposeFS layer creation" "apt-layer"
if ! "$COMPOSEFS_SCRIPT" create "$new_image" "$temp_dir"; then
log_error "Failed to create ComposeFS layer" "apt-layer"
rollback_transaction
return 1
# Try real mkcomposefs binary first
if command -v mkcomposefs >/dev/null 2>&1; then
# Create object store directory (same directory as image)
local object_store_dir=$(dirname "$new_image")
mkdir -p "$object_store_dir"
if ! mkcomposefs "$temp_dir" "$new_image" --digest-store="$object_store_dir"; then
log_error "Failed to create ComposeFS layer with mkcomposefs" "apt-layer"
rollback_transaction
return 1
fi
else
# Fallback: use composefs-alternative.sh
log_info "Using fallback ComposeFS layer creation" "apt-layer"
if ! "$COMPOSEFS_SCRIPT" create "$new_image" "$temp_dir"; then
log_error "Failed to create ComposeFS layer" "apt-layer"
rollback_transaction
return 1
fi
fi
fi
@ -215,56 +216,6 @@ container_dpkg_install() {
return 0
}
# Skopeo-based dpkg installation (OCI-focused)
run_skopeo_dpkg_install() {
local base_image="$1"
local container_name="$2"
local temp_dir="$3"
shift 3
local packages=("$@")
log_info "Running skopeo-based dpkg installation" "apt-layer"
# Skopeo is primarily for OCI operations, so we'll use chroot for package installation
# Create minimal container structure
mkdir -p "$temp_dir"/{bin,lib,lib64,usr,etc,var}
# Set up base filesystem
if [[ -d "$WORKSPACE/images/$base_image" ]]; then
# Use ComposeFS image as base
log_info "Using ComposeFS image as base for skopeo dpkg" "apt-layer"
cp -a "$WORKSPACE/images/$base_image"/* "$temp_dir/" 2>/dev/null || true
else
# Use minimal Ubuntu base
log_info "Using minimal Ubuntu base for skopeo dpkg" "apt-layer"
# Copy essential files
cp -a /bin/bash "$temp_dir/bin/"
cp -a /lib/x86_64-linux-gnu "$temp_dir/lib/"
cp -a /usr/bin/dpkg "$temp_dir/usr/bin/"
cp -a /usr/bin/apt-get "$temp_dir/usr/bin/"
# Add minimal /etc structure
echo "deb http://archive.ubuntu.com/ubuntu/ jammy main" > "$temp_dir/etc/apt/sources.list"
fi
# Download and install packages using dpkg
local install_cmd="
apt-get update &&
apt-get download ${packages[*]} &&
dpkg -i *.deb &&
apt-get install -f &&
dpkg --configure -a &&
apt-get clean
"
if ! chroot "$temp_dir" /bin/bash -c "$install_cmd"; then
log_error "dpkg installation failed in skopeo container" "apt-layer"
return 1
fi
log_success "Skopeo-based dpkg installation completed" "apt-layer"
return 0
}
# Podman-based dpkg installation
run_podman_dpkg_install() {
local base_image="$1"
@ -405,59 +356,6 @@ run_docker_dpkg_install() {
return 0
}
# systemd-nspawn-based dpkg installation
run_nspawn_dpkg_install() {
local base_image="$1"
local container_name="$2"
local temp_dir="$3"
shift 3
local packages=("$@")
log_info "Running systemd-nspawn-based dpkg installation" "apt-layer"
local container_dir="$WORKSPACE/containers/$container_name"
# Create container directory
if [[ -d "$WORKSPACE/images/$base_image" ]]; then
# Use ComposeFS image as base
log_info "Using ComposeFS image as base for nspawn" "apt-layer"
cp -a "$WORKSPACE/images/$base_image" "$container_dir"
else
# Use host filesystem as base
log_info "Using host filesystem as base for nspawn" "apt-layer"
# Create minimal container structure
mkdir -p "$container_dir"/{bin,lib,lib64,usr,etc,var}
# Copy essential files from host
cp -a /bin/bash "$container_dir/bin/"
cp -a /lib/x86_64-linux-gnu "$container_dir/lib/"
cp -a /usr/bin/dpkg "$container_dir/usr/bin/"
cp -a /usr/bin/apt-get "$container_dir/usr/bin/"
# Add minimal /etc structure
echo "deb http://archive.ubuntu.com/ubuntu/ jammy main" > "$container_dir/etc/apt/sources.list"
fi
# Run dpkg installation in nspawn container
local install_cmd="
apt-get update &&
apt-get download ${packages[*]} &&
dpkg -i *.deb &&
apt-get install -f &&
dpkg --configure -a &&
apt-get clean
"
if ! systemd-nspawn -D "$container_dir" /bin/bash -c "$install_cmd"; then
log_error "dpkg installation failed in nspawn container" "apt-layer"
return 1
fi
# Move container contents to temp_dir
mv "$container_dir"/* "$temp_dir/" 2>/dev/null || true
log_success "systemd-nspawn-based dpkg installation completed" "apt-layer"
return 0
}
# Live overlay dpkg installation
live_dpkg_install() {
local packages=("$@")

View file

@ -78,47 +78,83 @@ check_root() {
fi
}
# --- BEGIN DEPENDENCY JSON LOADING ---
# The dependencies JSON will be embedded as APT_LAYER_DEPENDENCIES_JSON in the compiled script.
APT_LAYER_DEPENDENCIES_JSON="${APT_LAYER_DEPENDENCIES_JSON:-}
{
\"core\": [\"chroot\", \"apt-get\", \"dpkg\", \"jq\", \"mount\", \"umount\", \"findmnt\", \"numfmt\"],
\"container\": [\"podman\", \"docker\"],
\"oci\": [\"skopeo\"],
\"composefs\": [\"mkcomposefs\", \"composefs-info\", \"mount.composefs\", \"mksquashfs\", \"unsquashfs\"],
\"bootloader\": [\"efibootmgr\", \"grub-install\", \"update-grub\", \"bootctl\"],
\"security\": [\"curl\", \"wget\", \"gpg\"]
}"
get_deps_for_type() {
local type="$1"
local json="$APT_LAYER_DEPENDENCIES_JSON"
case "$type" in
core)
echo "$json" | jq -r '.core[]'
;;
security)
echo "$json" | jq -r '.security[]'
;;
all)
echo "$json" | jq -r '.core[], .security[]'
;;
*)
echo "$json" | jq -r '.core[]'
;;
esac
}
print_install_instructions() {
local json="$APT_LAYER_DEPENDENCIES_JSON"
echo " Quick fix for common dependencies:"
echo " sudo apt install -y squashfs-tools jq coreutils util-linux skopeo"
echo ""
echo " For container support (choose one):"
echo " sudo apt install -y podman # or"
echo " sudo apt install -y docker.io"
echo ""
echo " For bootloader support:"
echo " sudo apt install -y efibootmgr grub-common systemd-boot"
echo ""
echo " For more information, run: apt-layer --help"
echo ""
}
# Function to check dependencies
check_dependencies() {
print_status "Checking dependencies..."
local missing_deps=()
# Check for curl or wget
# Installer-specific dependencies
local installer_deps=("sudo" "dos2unix")
# Use JSON to get core and security deps
local deps=( $(get_deps_for_type all) )
# Add installer deps
deps+=("sudo" "dos2unix")
# Check for curl or wget (at least one)
if ! command -v curl >/dev/null 2>&1 && ! command -v wget >/dev/null 2>&1; then
missing_deps+=("curl or wget")
fi
# Check for jq
if ! command -v jq >/dev/null 2>&1; then
missing_deps+=("jq")
fi
# Check for dos2unix
if ! command -v dos2unix >/dev/null 2>&1; then
missing_deps+=("dos2unix")
fi
# Check all other deps
for dep in "${deps[@]}"; do
if [[ "$dep" == "curl" || "$dep" == "wget" ]]; then
continue # already checked above
fi
if ! command -v "$dep" >/dev/null 2>&1; then
missing_deps+=("$dep")
fi
done
if [[ ${#missing_deps[@]} -gt 0 ]]; then
print_error "Missing required dependencies: ${missing_deps[*]}"
print_status "Installing missing dependencies..."
# Try to install dependencies
if command -v apt-get >/dev/null 2>&1; then
sudo apt-get update
sudo apt-get install -y "${missing_deps[@]}"
elif command -v dnf >/dev/null 2>&1; then
sudo dnf install -y "${missing_deps[@]}"
elif command -v yum >/dev/null 2>&1; then
sudo yum install -y "${missing_deps[@]}"
else
print_error "Could not automatically install dependencies. Please install manually:"
print_error " ${missing_deps[*]}"
exit 1
fi
print_install_instructions
print_error "Please install missing dependencies and re-run the installer."
exit 1
fi
print_success "All dependencies satisfied"
print_status "All dependencies satisfied"
}
# Function to download apt-layer

View file

@ -29,6 +29,8 @@ src/bootc/
└── CHANGELOG.md # Version history and changes
```
https://docs.fedoraproject.org/en-US/bootc/rpm-ostree/
## 🚀 Usage
### Compiling the Unified Script