Skip to content

OpenSwiftUIProject/SPMManifestTool

Repository files navigation

SPMManifestTool

Utilities and templates for Swift Package Manager manifest files (Package.swift).

Features

EnvManager

A powerful environment variable manager designed for use in Swift Package Manager manifests, providing:

  • Domain-based variable lookup: Automatically searches for domain-prefixed environment variables
  • Multiple value types: Supports Bool, Int, and String
  • Debug output: Prints environment variable resolution for better visibility during builds
  • Clean API: Simplified environment variable usage with type-safe defaults
  • Temporary domains: Use withDomain() for scoped environment variable lookups
  • Configurable fallback: Control whether to fall back to raw key names with includeFallbackToRawKey

Installation

Copy the EnvManager implementation directly into your Package.swift file, or use the sync script to keep it updated.

Option 1: Manual Copy

Copy the contents of Templates/EnvManager.swift.template into your Package.swift file.

Option 2: Using Sync Script

Add markers to your Package.swift:

// swift-tools-version: 6.1

import Foundation
import PackageDescription

/* GENERATED BY SPMManifestTool BEGIN */
/* DO NOT EDIT */

/* GENERATED BY SPMManifestTool END */

// Rest of your Package.swift

Then run the sync script:

cd /path/to/SPMManifestTool
./Scripts/sync_env_manager.sh ../YourProject

Usage

Querying Environment Variables

Boolean Values

// By default, searches only: MYPROJECT_DEBUG
let debug = envBoolValue("DEBUG", default: false)

// Enable fallback to also search raw key: DEBUG
EnvManager.shared.includeFallbackToRawKey = true
let debugWithFallback = envBoolValue("DEBUG", default: false)
// Now searches: MYPROJECT_DEBUG, DEBUG

// Disable domain search for system variables
let isSPI = envBoolValue("SPI_BUILD", default: false, searchInDomain: false)

Environment variable format:

  • "1"true
  • "0"false
  • Any other value → falls back to default

Integer Values

// By default, searches only: MYPROJECT_TARGET_RELEASE
let releaseVersion = envIntValue("TARGET_RELEASE", default: 2024)

// Enable fallback to also search: TARGET_RELEASE
EnvManager.shared.includeFallbackToRawKey = true
let releaseWithFallback = envIntValue("TARGET_RELEASE", default: 2024)

String Values

// With default value (searches only domain-prefixed versions)
let customPath = envStringValue("CUSTOM_PATH", default: "/default/path")

// Optional (no default)
let optionalPath = envStringValue("OPTIONAL_PATH")
// Returns nil if not found

// Enable fallback to search raw key as well
EnvManager.shared.includeFallbackToRawKey = true
let pathWithFallback = envStringValue("CUSTOM_PATH", default: "/default/path")

Domain Prefixing

When searchInDomain: true (the default), EnvManager searches for environment variables in this order:

  1. DOMAIN1_KEY
  2. DOMAIN2_KEY (if multiple domains are registered)
  3. KEY (only if EnvManager.shared.includeFallbackToRawKey is true)

For example, with domain "MyProject" and key "DEBUG":

With includeFallbackToRawKey = false (default):

  1. Checks MYPROJECT_DEBUG
  2. Falls back to default value

With includeFallbackToRawKey = true:

  1. Checks MYPROJECT_DEBUG
  2. Checks DEBUG
  3. Falls back to default value

Controlling Fallback Behavior

By default, includeFallbackToRawKey is false, meaning EnvManager only searches domain-prefixed environment variables. You can enable fallback to raw key names globally:

// Default behavior - searches only: MYPROJECT_DEBUG
let debug = envBoolValue("DEBUG", default: false)

// Enable fallback globally
EnvManager.shared.includeFallbackToRawKey = true

// Now searches: MYPROJECT_DEBUG, DEBUG
let debugWithFallback = envBoolValue("DEBUG", default: false)

// Disable for specific lookups using searchInDomain: false
let systemVar = envBoolValue("SYSTEM_VAR", default: false, searchInDomain: false)
// Searches only: SYSTEM_VAR (ignores domains entirely)

This is useful when you want strict control over environment variable scoping. Set includeFallbackToRawKey = true if you want more flexible lookups that fall back to unprefixed keys.

Temporary Domains

Use withDomain() to temporarily add a domain for specific lookups:

let agVersion = EnvManager.shared.withDomain("TEMP") {
    envIntValue("TARGET_RELEASE", default: 2024)
}
// This searches in other registered domains and other TEMP_TARGET_RELEASE

Complete Example

// swift-tools-version: 6.1

import Foundation
import PackageDescription

/* EnvManager code */

// Register project domain
EnvManager.shared.register(domain: "MyProject")

// Enable fallback to raw key names for convenience
EnvManager.shared.includeFallbackToRawKey = true

// Query environment variables
let development = envBoolValue("DEVELOPMENT", default: false)
let releaseVersion = envIntValue("TARGET_RELEASE", default: 2024)

// Use them in your package configuration
var swiftSettings: [SwiftSetting] = [
    .swiftLanguageMode(.v5),
]

if development {
    swiftSettings.append(.unsafeFlags(["-warnings-as-errors"]))
}

let package = Package(
    name: "MyProject",
    products: [
        .library(name: "MyProject", targets: ["MyProject"]),
    ],
    targets: [
        .target(
            name: "MyProject",
            swiftSettings: swiftSettings
        ),
    ]
)

Debug Output

EnvManager automatically prints debug information during package resolution:

[Env] MYPROJECT_DEVELOPMENT no set -> false
[Env] MYPROJECT_TARGET_RELEASE not set -> 2024(default)

This helps you understand which environment variables are being used and their values.

Requirements

  • Swift 6.1 or later

License

MIT License. See LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published