nip/docs/bootstrap-api.md

17 KiB

Bootstrap System API Documentation

Overview

This document describes the internal API of the NIP Bootstrap System. This is intended for developers who want to understand or extend the bootstrap functionality.

Architecture

┌─────────────────────────────────────────────────────────────┐
│                  Bootstrap Coordinator                       │
│                    (bootstrap.nim)                           │
└────────────────────┬────────────────────────────────────────┘
                     │
        ┌────────────┼────────────┬──────────────┐
        │            │            │              │
        ▼            ▼            ▼              ▼
┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐
│ Recipe   │  │Download  │  │Install   │  │ Tool     │
│ Manager  │  │ Manager  │  │ Manager  │  │ Adapters │
└──────────┘  └──────────┘  └──────────┘  └──────────┘

Module: recipe_parser.nim

Parses and validates KDL recipe files.

Types

PlatformArch

type PlatformArch* = enum
  paX86_64 = "x86_64"
  paAarch64 = "aarch64"
  paArmv7 = "armv7"

Supported CPU architectures.

RecipeBinary

type RecipeBinary* = object
  name*: string
  url*: string
  checksum*: string      # Format: "blake2b-<hash>"
  size*: int64           # bytes
  executable*: bool

Represents a standalone binary file.

RecipeArchive

type RecipeArchive* = object
  name*: string
  url*: string
  checksum*: string
  size*: int64
  extractTo*: string

Represents a compressed archive.

RecipePlatform

type RecipePlatform* = object
  arch*: PlatformArch
  os*: string            # "linux", "bsd", etc.
  binaries*: seq[RecipeBinary]
  archives*: seq[RecipeArchive]

Platform-specific binaries and archives.

RecipeDependency

type RecipeDependency* = object
  name*: string
  kind*: string          # "system", "nip", "optional"
  version*: string       # Optional version requirement
  required*: bool

System or package dependency.

RecipeInstall

type RecipeInstall* = object
  script*: string        # Path to installation script
  verifyScript*: string  # Path to verification script
  postInstall*: string   # Optional post-install script

Installation script configuration.

RecipeMetadata

type RecipeMetadata* = object
  author*: string
  license*: string
  updated*: string       # ISO date
  homepage*: string
  issues*: string

Recipe metadata.

Recipe

type Recipe* = object
  name*: string
  version*: string
  description*: string
  toolType*: string      # "nix", "pkgsrc", "gentoo"
  platforms*: seq[RecipePlatform]
  dependencies*: seq[RecipeDependency]
  install*: RecipeInstall
  metadata*: RecipeMetadata

Complete recipe definition.

Procedures

parseRecipe

proc parseRecipe*(kdlContent: string): Option[Recipe]

Parse a recipe from KDL string content.

Parameters:

  • kdlContent - KDL recipe content as string

Returns:

  • Option[Recipe] - Parsed recipe or none if parsing fails

Example:

let content = readFile("minimal-nix.kdl")
let recipeOpt = parseRecipe(content)
if recipeOpt.isSome():
  let recipe = recipeOpt.get()
  echo recipe.name

parseRecipeFile

proc parseRecipeFile*(filePath: string): Option[Recipe]

Parse a recipe from a file.

Parameters:

  • filePath - Path to recipe file

Returns:

  • Option[Recipe] - Parsed recipe or none if parsing fails

Example:

let recipeOpt = parseRecipeFile("recipes/nix/minimal-nix.kdl")

validateRecipe

proc validateRecipe*(recipe: Recipe): tuple[valid: bool, errors: seq[string]]

Validate a recipe structure.

Parameters:

  • recipe - Recipe to validate

Returns:

  • Tuple of (valid, errors) where valid is true if recipe is valid

Example:

let (valid, errors) = validateRecipe(recipe)
if not valid:
  for error in errors:
    echo "Error: ", error

selectPlatform

proc selectPlatform*(recipe: Recipe, targetArch: PlatformArch,
                     targetOs: string = "linux"): Option[RecipePlatform]

Select appropriate platform from recipe.

Parameters:

  • recipe - Recipe to select from
  • targetArch - Target architecture
  • targetOs - Target OS (default: "linux")

Returns:

  • Option[RecipePlatform] - Selected platform or none

Example:

let platformOpt = selectPlatform(recipe, paX86_64, "linux")

getCurrentPlatform

proc getCurrentPlatform*(): tuple[arch: PlatformArch, os: string]

Detect current system platform.

Returns:

  • Tuple of (arch, os)

Example:

let (arch, os) = getCurrentPlatform()
echo "Running on: ", arch, "/", os

Module: recipe_manager.nim

Manages recipe fetching, caching, and loading.

Types

RecipeManager

type RecipeManager* = ref object
  repoUrl*: string
  localCache*: string
  recipes*: Table[string, Recipe]
  lastUpdate*: Time

Manages recipe repository and caching.

RecipeFetchResult

type RecipeFetchResult* = object
  success*: bool
  message*: string
  recipesUpdated*: int

Result of recipe fetch operation.

Procedures

newRecipeManager

proc newRecipeManager*(repoUrl: string = DefaultRepoUrl,
                       cacheDir: string = ""): RecipeManager

Create a new RecipeManager.

Parameters:

  • repoUrl - Git repository URL (default: NexusToolKit repo)
  • cacheDir - Cache directory (default: XDG cache)

Returns:

  • RecipeManager instance

Example:

let manager = newRecipeManager()

fetchRecipes

proc fetchRecipes*(rm: RecipeManager): RecipeFetchResult

Fetch or update recipes from Git repository.

Parameters:

  • rm - RecipeManager instance

Returns:

  • RecipeFetchResult with status and message

Example:

let result = manager.fetchRecipes()
if result.success:
  echo "Updated ", result.recipesUpdated, " recipes"

loadRecipe

proc loadRecipe*(rm: RecipeManager, toolType: string): Option[Recipe]

Load and parse recipe for a tool type.

Parameters:

  • rm - RecipeManager instance
  • toolType - Tool type ("nix", "pkgsrc", "gentoo")

Returns:

  • Option[Recipe] - Loaded recipe or none

Example:

let recipeOpt = manager.loadRecipe("nix")
if recipeOpt.isSome():
  let recipe = recipeOpt.get()
  echo "Loaded: ", recipe.name

hasRecipe

proc hasRecipe*(rm: RecipeManager, toolType: string): bool

Check if recipe exists for a tool type.

Parameters:

  • rm - RecipeManager instance
  • toolType - Tool type to check

Returns:

  • bool - True if recipe exists

Example:

if manager.hasRecipe("nix"):
  echo "Nix recipe available"

listAvailableRecipes

proc listAvailableRecipes*(rm: RecipeManager): seq[string]

List all available recipe tool types.

Parameters:

  • rm - RecipeManager instance

Returns:

  • Sequence of tool type strings

Example:

for toolType in manager.listAvailableRecipes():
  echo "Available: ", toolType

Module: download_manager.nim

Manages file downloads with verification.

Types

DownloadResult

type DownloadResult* = object
  success*: bool
  filePath*: string
  message*: string
  bytesDownloaded*: int64
  duration*: Duration

Result of download operation.

DownloadManager

type DownloadManager* = ref object
  cacheDir*: string
  maxRetries*: int
  timeout*: Duration
  client*: HttpClient

Manages file downloads.

Procedures

newDownloadManager

proc newDownloadManager*(cacheDir: string = ""): DownloadManager

Create a new DownloadManager.

Parameters:

  • cacheDir - Cache directory (default: XDG cache)

Returns:

  • DownloadManager instance

Example:

let manager = newDownloadManager()
defer: manager.close()

close

proc close*(dm: DownloadManager)

Close the download manager and cleanup resources.

Parameters:

  • dm - DownloadManager instance

Example:

manager.close()

downloadFile

proc downloadFile*(dm: DownloadManager, url: string, destPath: string,
                   expectedChecksum: string = ""): DownloadResult

Download a file with checksum verification.

Parameters:

  • dm - DownloadManager instance
  • url - Download URL (HTTPS)
  • destPath - Destination file path
  • expectedChecksum - Expected Blake2b checksum (optional)

Returns:

  • DownloadResult with status and details

Example:

let result = manager.downloadFile(
  "https://example.com/file",
  "/tmp/file",
  "blake2b-abc123..."
)
if result.success:
  echo "Downloaded: ", result.bytesDownloaded, " bytes"

verifyChecksum

proc verifyChecksum*(filePath: string, expectedChecksum: string): bool

Verify file checksum using Blake2b.

Parameters:

  • filePath - Path to file
  • expectedChecksum - Expected checksum in format "blake2b-"

Returns:

  • bool - True if checksum matches

Example:

if verifyChecksum("/tmp/file", "blake2b-abc123..."):
  echo "Checksum verified"

getCachedFile

proc getCachedFile*(dm: DownloadManager, filename: string): string

Get path to cached file.

Parameters:

  • dm - DownloadManager instance
  • filename - Filename

Returns:

  • Full path to cached file

Example:

let path = manager.getCachedFile("nix-build")

Module: installation_manager.nim

Manages tool installation and rollback.

Types

InstallState

type InstallState* = enum
  isNotStarted = "not_started"
  isFetching = "fetching"
  isDownloading = "downloading"
  isVerifying = "verifying"
  isExtracting = "extracting"
  isInstalling = "installing"
  isVerifyingInstall = "verifying_install"
  isComplete = "complete"
  isFailed = "failed"

Installation state.

InstallResult

type InstallResult* = object
  success*: bool
  toolPath*: string
  version*: string
  message*: string
  errors*: seq[string]
  warnings*: seq[string]
  installTime*: Duration

Result of installation operation.

InstallationManager

type InstallationManager* = ref object
  toolsDir*: string
  tempDir*: string
  backupDir*: string

Manages tool installation.

Procedures

newInstallationManager

proc newInstallationManager*(toolsDir: string = ""): InstallationManager

Create a new InstallationManager.

Parameters:

  • toolsDir - Tools directory (default: XDG data)

Returns:

  • InstallationManager instance

Example:

let manager = newInstallationManager()

extractArchive

proc extractArchive*(im: InstallationManager, archivePath: string,
                     destDir: string): tuple[success: bool, message: string]

Extract archive to destination directory.

Parameters:

  • im - InstallationManager instance
  • archivePath - Path to archive file
  • destDir - Destination directory

Returns:

  • Tuple of (success, message)

Example:

let (success, msg) = manager.extractArchive(
  "/tmp/archive.tar.xz",
  "/opt/tool"
)

executeScript

proc executeScript*(im: InstallationManager, scriptPath: string,
                    workDir: string, env: Table[string, string] = initTable[string, string]()):
                    tuple[success: bool, output: string]

Execute installation script.

Parameters:

  • im - InstallationManager instance
  • scriptPath - Path to script
  • workDir - Working directory
  • env - Environment variables

Returns:

  • Tuple of (success, output)

Example:

let env = {"INSTALL_DIR": "/opt/tool"}.toTable
let (success, output) = manager.executeScript(
  "install.sh",
  "/opt/tool",
  env
)

verifyInstallation

proc verifyInstallation*(im: InstallationManager, toolType: string,
                         verifyScript: string, toolPath: string):
                         tuple[success: bool, message: string]

Verify tool installation.

Parameters:

  • im - InstallationManager instance
  • toolType - Tool type
  • verifyScript - Path to verification script
  • toolPath - Tool installation path

Returns:

  • Tuple of (success, message)

Example:

let (success, msg) = manager.verifyInstallation(
  "nix",
  "verify.sh",
  "/opt/nix"
)

backupTool

proc backupTool*(im: InstallationManager, toolType: string): bool

Backup existing tool installation.

Parameters:

  • im - InstallationManager instance
  • toolType - Tool type

Returns:

  • bool - True if backup succeeded

Example:

if manager.backupTool("nix"):
  echo "Backup created"

rollback

proc rollback*(im: InstallationManager, toolType: string): bool

Rollback failed installation.

Parameters:

  • im - InstallationManager instance
  • toolType - Tool type

Returns:

  • bool - True if rollback succeeded

Example:

if not installSuccess:
  discard manager.rollback("nix")

Module: bootstrap.nim

Main bootstrap coordinator.

Types

BuildToolType

type BuildToolType* = enum
  bttNix = "nix"
  bttPkgsrc = "pkgsrc"
  bttGentoo = "gentoo"

Supported build tool types.

BootstrapResult

type BootstrapResult* = object
  success*: bool
  toolPath*: string
  message*: string
  errors*: seq[string]
  warnings*: seq[string]

Result of bootstrap operation.

Procedures

isToolInstalled

proc isToolInstalled*(toolType: BuildToolType): bool

Check if a build tool is installed in NIP's directory.

Parameters:

  • toolType - Tool type to check

Returns:

  • bool - True if installed

Example:

if isToolInstalled(bttNix):
  echo "Nix is installed"

isSystemToolAvailable

proc isSystemToolAvailable*(toolType: BuildToolType): bool

Check if tool is available on the system.

Parameters:

  • toolType - Tool type to check

Returns:

  • bool - True if available

Example:

if isSystemToolAvailable(bttNix):
  echo "Nix is available on system"

handleMissingTool

proc handleMissingTool*(toolType: BuildToolType, autoBootstrap: bool = false): bool

Handle missing build tool - prompt user or auto-bootstrap.

Parameters:

  • toolType - Tool type
  • autoBootstrap - Auto-install without prompting

Returns:

  • bool - True if tool is now available

Example:

if not isToolInstalled(bttNix):
  if handleMissingTool(bttNix, autoBootstrap = true):
    echo "Nix installed successfully"

installMinimalTools

proc installMinimalTools*(toolType: BuildToolType): BootstrapResult

Install minimal build tools for the specified type.

Parameters:

  • toolType - Tool type to install

Returns:

  • BootstrapResult with status and details

Example:

let result = installMinimalTools(bttNix)
if result.success:
  echo "Installed to: ", result.toolPath

Usage Examples

Complete Installation Flow

import nimpak/build/[bootstrap, recipe_manager, download_manager, installation_manager]

# Initialize managers
let recipeManager = newRecipeManager()
let downloadManager = newDownloadManager()
let installManager = newInstallationManager()
defer: downloadManager.close()

# Fetch recipes
let fetchResult = recipeManager.fetchRecipes()
if not fetchResult.success:
  echo "Failed to fetch recipes"
  quit(1)

# Load recipe
let recipeOpt = recipeManager.loadRecipe("nix")
if recipeOpt.isNone():
  echo "Recipe not found"
  quit(1)

let recipe = recipeOpt.get()

# Select platform
let (arch, os) = getCurrentPlatform()
let platformOpt = selectPlatform(recipe, arch, os)
if platformOpt.isNone():
  echo "Platform not supported"
  quit(1)

let platform = platformOpt.get()

# Download binaries
for binary in platform.binaries:
  let destPath = downloadManager.getCachedFile(binary.name)
  let result = downloadManager.downloadFile(binary.url, destPath, binary.checksum)
  if not result.success:
    echo "Download failed: ", result.message
    quit(1)

# Install
let toolDir = "/opt/nix"
let env = {"INSTALL_DIR": toolDir}.toTable
let (success, output) = installManager.executeScript(
  recipe.install.script,
  toolDir,
  env
)

if success:
  echo "Installation successful"
else:
  echo "Installation failed: ", output

Error Handling

All procedures that can fail return either:

  • Option[T] - Use isSome() and get() to check and extract
  • tuple[success: bool, ...] - Check success field
  • Result object with success field

Always check return values and handle errors appropriately.

Thread Safety

The bootstrap system is not thread-safe. Do not use the same manager instances from multiple threads.

See Also