or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

dmg-building.mddmg-customization.mderror-handling.mdindex.mdlicense-management.mdvolume-operations.md
tile.json

volume-operations.mddocs/

Volume Operations

Low-level DMG file operations including mounting, unmounting, and executing tasks on mounted volumes. These utilities provide the foundation for DMG manipulation and content management using macOS hdiutil commands.

Capabilities

Volume Attachment and Execution

Safely attaches a DMG file, executes a task on the mounted volume, and ensures proper cleanup even if the task fails.

/**
 * Attach DMG file, execute task on mounted volume, then detach
 * Provides automatic cleanup even if the task throws an error
 * @param dmgPath - Path to the DMG file to attach
 * @param readWrite - Whether to mount in read-write mode (true) or read-only (false)  
 * @param task - Function to execute with the mounted volume path (e.g., "/Volumes/VolumeName")
 * @returns Promise resolving to the task result
 * @throws Error if DMG cannot be mounted or device not found
 */
function attachAndExecute<T>(
  dmgPath: string,
  readWrite: boolean,
  task: (volumePath: string) => Promise<T>
): Promise<T>;

Usage Examples:

import { attachAndExecute } from "dmg-builder";

// Read-only access to examine DMG contents
const fileList = await attachAndExecute(
  "/path/to/installer.dmg",
  false, // read-only
  async (volumePath) => {
    const fs = require("fs-extra");
    return await fs.readdir(volumePath);
  }
);

// Read-write access to modify DMG contents
await attachAndExecute(
  "/path/to/installer.dmg", 
  true, // read-write
  async (volumePath) => {
    const fs = require("fs-extra");
    await fs.writeFile(`${volumePath}/.DS_Store`, dsStoreData);
    await fs.copy("/source/files", `${volumePath}/ExtraFiles`);
  }
);

Volume Detachment

Safely detaches a mounted DMG volume with automatic retry logic for transient failures.

/**
 * Detach/unmount a DMG volume by device name
 * Includes retry logic for busy volumes with force unmount fallback
 * @param name - Device name to detach (e.g., "/dev/disk2")
 * @returns Promise resolving to hdiutil output or null
 * @throws Error if detachment fails after retries
 */
function detach(name: string): Promise<string | null>;

Usage Examples:

import { detach } from "dmg-builder";

// Detach a specific device
await detach("/dev/disk2");

// Manual volume management (not recommended - use attachAndExecute instead)
const attachResult = await hdiUtil(["attach", "-noverify", "/path/to/file.dmg"]);
const deviceMatch = /^(\/dev\/\w+)/.exec(attachResult || "");
if (deviceMatch) {
  try {
    // ... do work with mounted volume
  } finally {
    await detach(deviceMatch[1]);
  }
}

Path Utilities

Utility functions for locating DMG Builder resources and templates.

/**
 * Get path to DMG template directory containing default resources
 * @returns Absolute path to templates directory
 */
function getDmgTemplatePath(): string;

/**
 * Get path to DMG vendor directory containing Python scripts and dependencies
 * @returns Absolute path to vendor directory  
 */
function getDmgVendorPath(): string;

Usage Examples:

import { getDmgTemplatePath, getDmgVendorPath } from "dmg-builder";

// Access default background template
const templatePath = getDmgTemplatePath();
const backgroundPath = `${templatePath}/background.tiff`;

// Access Python dmgbuild scripts
const vendorPath = getDmgVendorPath();
const pythonScript = `${vendorPath}/run_dmgbuild.py`;

Background Image Processing

Utilities for processing and converting background images for DMG use.

/**
 * Transform background image to TIFF format if needed
 * Handles retina images by combining standard and @2x versions
 * @param file - Path to background image file
 * @param tmpDir - Temporary directory manager for intermediate files
 * @returns Promise resolving to path of processed TIFF file
 */
function transformBackgroundFileIfNeed(file: string, tmpDir: TmpDir): Promise<string>;

/**
 * Get image dimensions using macOS sips tool
 * @param background - Path to image file
 * @returns Promise resolving to object with width and height properties
 * @throws Error if sips command fails or cannot parse dimensions
 */
function getImageSizeUsingSips(background: string): Promise<{width: number, height: number}>;

Usage Examples:

import { transformBackgroundFileIfNeed, getImageSizeUsingSips } from "dmg-builder";
import { TmpDir } from "builder-util";

const tmpDir = new TmpDir("dmg-background");

// Convert PNG to TIFF and handle retina images
const backgroundPath = await transformBackgroundFileIfNeed(
  "/path/to/background.png",
  tmpDir
);

// Get dimensions for window sizing
const { width, height } = await getImageSizeUsingSips(backgroundPath);
console.log(`Background size: ${width}x${height}`);

String Serialization for AppleScript

Internal utility for serializing strings for AppleScript usage in DMG customization.

/**
 * Serialize string data for AppleScript resource format
 * Used internally for license button text and other DMG resources
 * @param data - String data to serialize
 * @returns Formatted string for AppleScript resource usage
 */
function serializeString(data: string): string;

Implementation Details

Volume Mount Path Detection

The attachAndExecute function uses intelligent mount path detection:

  1. Executes hdiutil attach with appropriate flags
  2. Parses device name from hdiutil output using regex /^(\/dev\/\w+)/
  3. Uses hdiutil info to find corresponding mount path in /Volumes/
  4. Supports multiple mount points per device (selects appropriate partition)

Retry Logic for Detachment

The detach function implements robust retry logic:

  1. First attempts normal detachment with -quiet flag
  2. For transient errors (codes 1, 16, 35, 256, 49153), waits 3 seconds then retries
  3. Final retry uses -force flag for stubborn volumes
  4. Throws error only after all retry attempts fail

Background Image Processing

Background processing handles macOS-specific requirements:

  • TIFF Requirement: DMG backgrounds must be in TIFF format for proper display
  • Retina Support: Automatically detects and combines image.png + image@2x.png using tiffutil -cathidpicheck
  • Format Detection: Uses file extension to determine if conversion is needed
  • Dimension Detection: Uses sips tool to extract pixel dimensions for window sizing

Error Conditions

Common error scenarios and handling:

  • Mount Failures: Device parsing failures, permission issues, corrupted DMG files
  • Detach Failures: Volume busy, files in use, permission issues
  • Image Processing: Invalid image formats, missing files, sips tool failures
  • Path Resolution: Missing template/vendor directories, incorrect installations

All functions include appropriate error messages and throw descriptive errors for debugging.